diff --git a/cryptography/build.gradle.kts b/cryptography/build.gradle.kts index 30692ee5a..388dacebd 100644 --- a/cryptography/build.gradle.kts +++ b/cryptography/build.gradle.kts @@ -119,8 +119,8 @@ kotlin { implementation(project(":utils")) implementation(project(":secure-random")) implementation(project(":hashing")) - implementation("com.ionspin.kotlin:bignum:0.3.7") implementation(project(":base64")) + implementation("com.ionspin.kotlin:bignum:0.3.7") implementation("org.kotlincrypto.macs:hmac-sha2:0.3.0") } } @@ -134,9 +134,7 @@ kotlin { } val jvmMain by getting { dependencies { - dependencies { - api("fr.acinq.secp256k1:secp256k1-kmp:0.9.0") - } + api("fr.acinq.secp256k1:secp256k1-kmp:0.9.0") implementation("fr.acinq.secp256k1:secp256k1-kmp-jni-jvm:0.9.0") implementation("com.google.guava:guava:30.1-jre") implementation("org.bouncycastle:bcprov-jdk15on:1.68") diff --git a/cryptography/src/androidMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt b/cryptography/src/androidMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt index bbeb7829b..c3ec24a43 100644 --- a/cryptography/src/androidMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt +++ b/cryptography/src/androidMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt @@ -6,10 +6,14 @@ import io.iohk.atala.prism.apollo.hashing.SHA256 actual class Secp256k1Lib { actual fun createPublicKey(privateKey: ByteArray, compressed: Boolean): ByteArray { val pubKey = Secp256k1.pubkeyCreate(privateKey) - if (compressed) { - return Secp256k1.pubKeyCompress(pubKey) + if (Secp256k1Helper.validatePublicKey(pubKey)) { + if (compressed) { + return Secp256k1.pubKeyCompress(pubKey) + } + return pubKey + } else { + throw Secp256k1Exception("invalid public key") } - return pubKey } actual fun derivePrivateKey( diff --git a/cryptography/src/commonMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Helper.kt b/cryptography/src/commonMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Helper.kt new file mode 100644 index 000000000..93a9cb646 --- /dev/null +++ b/cryptography/src/commonMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Helper.kt @@ -0,0 +1,21 @@ +package io.iohk.atala.prism.apollo.secp256k1 + +import com.ionspin.kotlin.bignum.integer.BigInteger +import com.ionspin.kotlin.bignum.integer.Sign + +class Secp256k1Helper { + companion object { + fun validatePublicKey(pubKey: ByteArray): Boolean { + val x = BigInteger.fromByteArray(pubKey.sliceArray(1..32), Sign.POSITIVE) + val y = BigInteger.fromByteArray(pubKey.sliceArray(33..64), Sign.POSITIVE) + val b = BigInteger(7) + val p = BigInteger.parseString("115792089237316195423570985008687907853269984665640564039457584007908834671663", 10) + return ((y * y - x * x * x - b) mod p) == BigInteger.ZERO + } + } +} + +public class Secp256k1Exception : RuntimeException { + public constructor() : super() + public constructor(message: String?) : super(message) +} diff --git a/cryptography/src/iosMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt b/cryptography/src/iosMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt index 4757e0fe4..df9c5fb9f 100644 --- a/cryptography/src/iosMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt +++ b/cryptography/src/iosMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt @@ -1,15 +1,20 @@ package io.iohk.atala.prism.apollo.secp256k1 +import fr.acinq.secp256k1.Secp256k1Exception import fr.acinq.secp256k1.Secp256k1Native import io.iohk.atala.prism.apollo.hashing.SHA256 actual class Secp256k1Lib { actual fun createPublicKey(privateKey: ByteArray, compressed: Boolean): ByteArray { - val publicKey = Secp256k1Native.pubkeyCreate(privateKey) - if (compressed) { - return Secp256k1().publicKeyCompress(publicKey) + val pubKey = Secp256k1Native.pubkeyCreate(privateKey) + if (Secp256k1Helper.validatePublicKey(pubKey)) { + if (compressed) { + return Secp256k1Native.pubKeyCompress(pubKey) + } + return pubKey + } else { + throw Secp256k1Exception("invalid public key") } - return publicKey } actual fun derivePrivateKey( diff --git a/cryptography/src/jvmMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt b/cryptography/src/jvmMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt index bbeb7829b..c3ec24a43 100644 --- a/cryptography/src/jvmMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt +++ b/cryptography/src/jvmMain/kotlin/io/iohk/atala/prism/apollo/secp256k1/Secp256k1Lib.kt @@ -6,10 +6,14 @@ import io.iohk.atala.prism.apollo.hashing.SHA256 actual class Secp256k1Lib { actual fun createPublicKey(privateKey: ByteArray, compressed: Boolean): ByteArray { val pubKey = Secp256k1.pubkeyCreate(privateKey) - if (compressed) { - return Secp256k1.pubKeyCompress(pubKey) + if (Secp256k1Helper.validatePublicKey(pubKey)) { + if (compressed) { + return Secp256k1.pubKeyCompress(pubKey) + } + return pubKey + } else { + throw Secp256k1Exception("invalid public key") } - return pubKey } actual fun derivePrivateKey( diff --git a/secp256k1-kmp/build.gradle.kts b/secp256k1-kmp/build.gradle.kts index 701449d9a..2adec75aa 100644 --- a/secp256k1-kmp/build.gradle.kts +++ b/secp256k1-kmp/build.gradle.kts @@ -11,7 +11,11 @@ plugins { kotlin { explicitApi() - val commonMain by sourceSets.getting + val commonMain by sourceSets.getting { + dependencies { + api("com.ionspin.kotlin:bignum:0.3.7") + } + } jvm { compilations.all { diff --git a/secp256k1-kmp/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt b/secp256k1-kmp/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt index 99018ce35..df629313f 100644 --- a/secp256k1-kmp/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt +++ b/secp256k1-kmp/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt @@ -141,15 +141,17 @@ public interface Secp256k1 { * Serialize a public key to compact form (33 bytes). */ public fun pubKeyCompress(pubkey: ByteArray): ByteArray { - return when { - pubkey.size == 33 && (pubkey[0] == 2.toByte() || pubkey[0] == 3.toByte()) -> pubkey - pubkey.size == 65 && pubkey[0] == 4.toByte() -> { - val compressed = pubkey.copyOf(33) - compressed[0] = if (pubkey.last() % 2 == 0) 2.toByte() else 3.toByte() - compressed + val pubKey = + when { + pubkey.size == 33 && (pubkey[0] == 2.toByte() || pubkey[0] == 3.toByte()) -> pubkey + pubkey.size == 65 && pubkey[0] == 4.toByte() -> { + val compressed = pubkey.copyOf(33) + compressed[0] = if (pubkey.last() % 2 == 0) 2.toByte() else 3.toByte() + compressed + } + else -> throw Secp256k1Exception("invalid public key") } - else -> throw Secp256k1Exception("invalid public key") - } + return pubKey } /** diff --git a/secp256k1-kmp/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt b/secp256k1-kmp/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt index 65292da45..e91afb378 100644 --- a/secp256k1-kmp/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt +++ b/secp256k1-kmp/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt @@ -233,7 +233,7 @@ public object Secp256k1Native : Secp256k1 { secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess("secp256k1_xonly_pubkey_parse() failed") val nData = toNat(data) val nSig = toNat(signature) - return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32, pubkey.ptr) == 1 + return secp256k1_schnorrsig_verify(ctx, nSig, nData, 32u, pubkey.ptr) == 1 } } @@ -252,7 +252,7 @@ public object Secp256k1Native : Secp256k1 { return nSig.readBytes(64) } } - + public override fun cleanup() { secp256k1_context_destroy(ctx) }