Skip to content

Commit 90a578a

Browse files
authored
fix(secp256k1): Exposing EC Secp256K1 (#89)
1 parent 2865b24 commit 90a578a

File tree

3 files changed

+134
-2
lines changed

3 files changed

+134
-2
lines changed

base-asymmetric-encryption/src/commonMain/kotlin/io/iohk/atala/prism/apollo/utils/KMMECSecp256k1PrivateKey.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ class KMMECSecp256k1PrivateKey : Encodable {
3232
return raw
3333
}
3434

35+
/**
36+
* Sign the provided data with EC Secp256K1
37+
* @param data data that you want to sign
38+
* @return signature
39+
*/
40+
fun sign(data: ByteArray): ByteArray {
41+
val secp256k1Lib = Secp256k1Lib()
42+
return secp256k1Lib.sign(raw, data)
43+
}
44+
45+
/**
46+
* Verify provided signature with the public key that is generated using the private key
47+
* @param signature that we need to verify
48+
* @param data that was used in signature
49+
* @return true when valid, false when invalid
50+
*/
51+
fun verify(signature: ByteArray, data: ByteArray): Boolean {
52+
val secp256k1Lib = Secp256k1Lib()
53+
return secp256k1Lib.verify(getPublicKey().raw, signature, data)
54+
}
55+
3556
companion object : KMMECSecp256k1PrivateKeyCommonStaticInterface {
3657
override fun secp256k1FromByteArray(d: ByteArray): KMMECSecp256k1PrivateKey {
3758
return KMMECSecp256k1PrivateKey(d)

base-asymmetric-encryption/src/commonMain/kotlin/io/iohk/atala/prism/apollo/utils/KMMECSecp256k1PublicKey.kt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@ package io.iohk.atala.prism.apollo.utils
22

33
import com.ionspin.kotlin.bignum.integer.BigInteger
44
import com.ionspin.kotlin.bignum.integer.Sign
5+
import io.iohk.atala.prism.apollo.secp256k1.Secp256k1Lib
56
import kotlin.js.ExperimentalJsExport
67
import kotlin.js.JsExport
78
import kotlin.js.JsName
89

10+
@OptIn(ExperimentalJsExport::class)
11+
@JsExport
912
interface KMMECSecp256k1PublicKeyCommonStaticInterface {
13+
/**
14+
* Check if key point is on the Secp256k1 curve or not
15+
* @param point public key point
16+
* @return true if point on curve, false if not.
17+
* @exception ClassCastException This method fails in JS. To be further investigated.
18+
*/
1019
fun isPointOnSecp256k1Curve(point: KMMECPoint): Boolean {
1120
val x = BigInteger.fromByteArray(point.x, Sign.POSITIVE)
1221
val y = BigInteger.fromByteArray(point.y, Sign.POSITIVE)
@@ -55,8 +64,6 @@ class KMMECSecp256k1PublicKey {
5564
this.raw = raw
5665
}
5766

58-
companion object : KMMECSecp256k1PublicKeyCommonStaticInterface
59-
6067
fun getCurvePoint(): KMMECPoint {
6168
if (raw.size != 65) {
6269
throw IllegalArgumentException("Public key should be 65 bytes long")
@@ -69,4 +76,17 @@ class KMMECSecp256k1PublicKey {
6976

7077
return KMMECPoint(x, y)
7178
}
79+
80+
/**
81+
* Verify provided signature
82+
* @param signature that we need to verify
83+
* @param data that was used in signature
84+
* @return true when valid, false when invalid
85+
*/
86+
fun verify(signature: ByteArray, data: ByteArray): Boolean {
87+
val secp256k1Lib = Secp256k1Lib()
88+
return secp256k1Lib.verify(raw, signature, data)
89+
}
90+
91+
companion object : KMMECSecp256k1PublicKeyCommonStaticInterface
7292
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package io.iohk.atala.prism.apollo.utils
2+
3+
import io.iohk.atala.prism.apollo.base64.base64UrlDecodedBytes
4+
import io.iohk.atala.prism.apollo.base64.base64UrlEncoded
5+
import kotlin.test.Test
6+
import kotlin.test.assertEquals
7+
import kotlin.test.assertNotNull
8+
import kotlin.test.assertTrue
9+
10+
class KMMECSecp256k1KeysTests {
11+
@Test
12+
fun testSigning() {
13+
val privateKeyBase64 = "N_JFgvYaReyRXwassz5FHg33A4I6dczzdXrjdHGksmg"
14+
val base64ByteArray = privateKeyBase64.base64UrlDecodedBytes
15+
val privateKey = KMMECSecp256k1PrivateKey.secp256k1FromByteArray(base64ByteArray)
16+
val message = "Test"
17+
val signature = privateKey.sign(message.encodeToByteArray())
18+
assertEquals("MEUCIQCFeGlhJrH-9R70X4JzrurWs52SwuxCnJ8ky6riFwMOrwIgT7zlLo7URMHW5tiMgG73IOw2Dm3XyLl1iqW1-t5NFWQ", signature.base64UrlEncoded)
19+
}
20+
21+
@Test
22+
fun testVerifyingFromPrivateKey() {
23+
val privateKeyBase64 = "N_JFgvYaReyRXwassz5FHg33A4I6dczzdXrjdHGksmg"
24+
val base64ByteArray = privateKeyBase64.base64UrlDecodedBytes
25+
val privateKey = KMMECSecp256k1PrivateKey.secp256k1FromByteArray(base64ByteArray)
26+
val message = "Test"
27+
val signature = privateKey.sign(message.encodeToByteArray())
28+
assertEquals("MEUCIQCFeGlhJrH-9R70X4JzrurWs52SwuxCnJ8ky6riFwMOrwIgT7zlLo7URMHW5tiMgG73IOw2Dm3XyLl1iqW1-t5NFWQ", signature.base64UrlEncoded)
29+
assertTrue(privateKey.verify(signature, message.encodeToByteArray()))
30+
}
31+
32+
@Test
33+
fun testVerifyingFromPublicKey() {
34+
val privateKeyBase64 = "N_JFgvYaReyRXwassz5FHg33A4I6dczzdXrjdHGksmg"
35+
val base64ByteArray = privateKeyBase64.base64UrlDecodedBytes
36+
val privateKey = KMMECSecp256k1PrivateKey.secp256k1FromByteArray(base64ByteArray)
37+
val message = "Test"
38+
val signature = privateKey.sign(message.encodeToByteArray())
39+
assertEquals("MEUCIQCFeGlhJrH-9R70X4JzrurWs52SwuxCnJ8ky6riFwMOrwIgT7zlLo7URMHW5tiMgG73IOw2Dm3XyLl1iqW1-t5NFWQ", signature.base64UrlEncoded)
40+
val publicKey = privateKey.getPublicKey()
41+
assertTrue(publicKey.verify(signature, message.encodeToByteArray()))
42+
}
43+
44+
@Test
45+
fun getPublicKeyFromPrivateKey() {
46+
val privateKeyBase64 = "N_JFgvYaReyRXwassz5FHg33A4I6dczzdXrjdHGksmg"
47+
val base64ByteArray = privateKeyBase64.base64UrlDecodedBytes
48+
val privateKey = KMMECSecp256k1PrivateKey.secp256k1FromByteArray(base64ByteArray)
49+
assertEquals("BD-l4lrQ6Go-oN5XtdpY6o5dyf2V2v5EbMAvRjVGJpE1gYVURJfxKMpNPnKlLr4MOLNVaYvBNOoy9L50E8jVx8Q", privateKey.getPublicKey().raw.base64UrlEncoded)
50+
}
51+
52+
@Test
53+
fun testIsPointOnSecp256k1Curve() {
54+
val point = KMMECPoint(
55+
"P6XiWtDoaj6g3le12ljqjl3J_ZXa_kRswC9GNUYmkTU".base64UrlDecodedBytes,
56+
"gYVURJfxKMpNPnKlLr4MOLNVaYvBNOoy9L50E8jVx8Q".base64UrlDecodedBytes
57+
)
58+
try {
59+
val publicKey = KMMECSecp256k1PublicKey.secp256k1FromByteCoordinates(
60+
point.x,
61+
point.y
62+
)
63+
assertNotNull(publicKey)
64+
assertTrue(true)
65+
} catch (ex: Exception) {
66+
assertTrue(false)
67+
}
68+
}
69+
70+
@Test
71+
fun testGetCurvePoint() {
72+
val publicKey = KMMECSecp256k1PublicKey("BD-l4lrQ6Go-oN5XtdpY6o5dyf2V2v5EbMAvRjVGJpE1gYVURJfxKMpNPnKlLr4MOLNVaYvBNOoy9L50E8jVx8Q".base64UrlDecodedBytes)
73+
val point = publicKey.getCurvePoint()
74+
assertEquals("P6XiWtDoaj6g3le12ljqjl3J_ZXa_kRswC9GNUYmkTU", point.x.base64UrlEncoded)
75+
assertEquals("gYVURJfxKMpNPnKlLr4MOLNVaYvBNOoy9L50E8jVx8Q", point.y.base64UrlEncoded)
76+
}
77+
78+
@Test
79+
fun testECSecp256K1FromByteCoordinates() {
80+
try {
81+
val publicKey = KMMECSecp256k1PublicKey.secp256k1FromByteCoordinates(
82+
"P6XiWtDoaj6g3le12ljqjl3J_ZXa_kRswC9GNUYmkTU".base64UrlDecodedBytes,
83+
"gYVURJfxKMpNPnKlLr4MOLNVaYvBNOoy9L50E8jVx8Q".base64UrlDecodedBytes
84+
)
85+
assertNotNull(publicKey)
86+
assertTrue(true)
87+
} catch (ex: Exception) {
88+
assertTrue(false)
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)