diff --git a/jni/build.gradle.kts b/jni/build.gradle.kts index d3faf6e..f2244d9 100644 --- a/jni/build.gradle.kts +++ b/jni/build.gradle.kts @@ -11,6 +11,7 @@ kotlin { val commonMain by sourceSets.getting { dependencies { + api(rootProject) implementation(kotlin("stdlib-common")) } } diff --git a/jni/src/androidMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt b/jni/src/androidMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt index b1b2584..511b840 100644 --- a/jni/src/androidMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt +++ b/jni/src/androidMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt @@ -1,12 +1,16 @@ package fr.acinq.secp256k1.jni +import fr.acinq.secp256k1.Secp256k1 +import org.bitcoin.NativeSecp256k1 + public actual object NativeSecp256k1Loader { @JvmStatic @Synchronized @Throws(Exception::class) - actual fun load() { + actual fun load(): Secp256k1 { System.loadLibrary("secp256k1-jni") + return NativeSecp256k1 } } diff --git a/jni/src/commonMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt b/jni/src/commonMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt index a50fc0d..3403b02 100644 --- a/jni/src/commonMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt +++ b/jni/src/commonMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt @@ -1,10 +1,10 @@ package fr.acinq.secp256k1.jni -import kotlin.jvm.JvmStatic +import fr.acinq.secp256k1.Secp256k1 public expect object NativeSecp256k1Loader { - public fun load() + public fun load(): Secp256k1 } diff --git a/jni/src/commonMain/kotlin/org/bitcoin/NativeSecp256k1.kt b/jni/src/commonMain/kotlin/org/bitcoin/NativeSecp256k1.kt index 300dc12..c4f6217 100644 --- a/jni/src/commonMain/kotlin/org/bitcoin/NativeSecp256k1.kt +++ b/jni/src/commonMain/kotlin/org/bitcoin/NativeSecp256k1.kt @@ -16,6 +16,9 @@ */ package org.bitcoin +import fr.acinq.secp256k1.PubKeyFormat +import fr.acinq.secp256k1.Secp256k1 +import fr.acinq.secp256k1.SigFormat import org.bitcoin.NativeSecp256k1Util.AssertFailException import java.math.BigInteger import java.nio.ByteBuffer @@ -37,7 +40,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock * or point the JVM to the folder containing it with -Djava.library.path * */ -public object NativeSecp256k1 { +internal object NativeSecp256k1 : Secp256k1 { private val rwl = ReentrantReadWriteLock() private val r: Lock = rwl.readLock() private val w: Lock = rwl.writeLock() @@ -71,9 +74,8 @@ public object NativeSecp256k1 { * @return true if the signature is valid * @throws AssertFailException in case of failure */ - @JvmStatic @Throws(AssertFailException::class) - public fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean { + override fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean { require(data.size == 32 && signature.size <= 520 && pub.size <= 520) val byteBuff = pack(data, signature, pub) r.lock() @@ -98,9 +100,8 @@ public object NativeSecp256k1 { * @return a signature, or an empty array is signing failed * @throws AssertFailException in case of failure */ - @JvmStatic @Throws(AssertFailException::class) - public fun sign(data: ByteArray, sec: ByteArray, compact: Boolean): ByteArray { + override fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray { require(data.size == 32 && sec.size <= 32) val byteBuff = pack(data, sec) val retByteArray: Array @@ -108,7 +109,7 @@ public object NativeSecp256k1 { retByteArray = try { secp256k1_ecdsa_sign( byteBuff, - compact, + format == SigFormat.COMPACT, Secp256k1Context.getContext() ) } finally { @@ -125,9 +126,8 @@ public object NativeSecp256k1 { return if (retVal == 0) ByteArray(0) else sigArr } - @JvmStatic @Throws(AssertFailException::class) - public fun signatureNormalize(sig: ByteArray, compact: Boolean): Pair { + override fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair { require(sig.size == 64 || sig.size in 70..73) val byteBuff = pack(sig) val retByteArray: Array @@ -136,7 +136,7 @@ public object NativeSecp256k1 { secp256k1_ecdsa_normalize( byteBuff, sig.size, - compact, + format == SigFormat.COMPACT, Secp256k1Context.getContext() ) } finally { @@ -160,8 +160,7 @@ public object NativeSecp256k1 { * @param seckey ECDSA Secret key, 32 bytes * @return true if seckey is valid */ - @JvmStatic - public fun secKeyVerify(seckey: ByteArray): Boolean { + override fun secKeyVerify(seckey: ByteArray): Boolean { require(seckey.size == 32) val byteBuff = pack(seckey) r.lock() @@ -183,9 +182,8 @@ public object NativeSecp256k1 { * @return the corresponding public key (uncompressed) */ //TODO add a 'compressed' arg - @JvmStatic @Throws(AssertFailException::class) - public fun computePubkey(seckey: ByteArray, compressed: Boolean): ByteArray { + override fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray { require(seckey.size == 32) val byteBuff = pack(seckey) val retByteArray: Array @@ -193,7 +191,7 @@ public object NativeSecp256k1 { retByteArray = try { secp256k1_ec_pubkey_create( byteBuff, - compressed, + format == PubKeyFormat.COMPRESSED, Secp256k1Context.getContext() ) } finally { @@ -211,9 +209,8 @@ public object NativeSecp256k1 { * @return the input public key (uncompressed) if valid, or an empty array * @throws AssertFailException in case of failure */ - @JvmStatic @Throws(AssertFailException::class) - public fun parsePubkey(pubkey: ByteArray, compressed: Boolean): ByteArray { + override fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray { require(pubkey.size == 33 || pubkey.size == 65) val byteBuff = pack(pubkey) val retByteArray: Array @@ -223,7 +220,7 @@ public object NativeSecp256k1 { byteBuff, Secp256k1Context.getContext(), pubkey.size, - compressed + format == PubKeyFormat.COMPRESSED ) } finally { r.unlock() @@ -231,7 +228,11 @@ public object NativeSecp256k1 { val pubArr = retByteArray[0] BigInteger(byteArrayOf(retByteArray[1][0])).toInt() val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals(pubArr.size, if (compressed) 33 else 65, "Got bad pubkey length.") + NativeSecp256k1Util.assertEquals( + pubArr.size, + format.maxSize, + "Got bad pubkey length." + ) return if (retVal == 0) ByteArray(0) else pubArr } @@ -239,9 +240,8 @@ public object NativeSecp256k1 { * libsecp256k1 Cleanup - This destroys the secp256k1 context object * This should be called at the end of the program for proper cleanup of the context. */ - @JvmStatic @Synchronized - public fun cleanup() { + override fun cleanup() { w.lock() try { secp256k1_destroy_context(Secp256k1Context.getContext()) @@ -250,9 +250,8 @@ public object NativeSecp256k1 { } } - @JvmStatic @Throws(AssertFailException::class) - public fun privKeyNegate(privkey: ByteArray): ByteArray { + override fun privKeyNegate(privkey: ByteArray): ByteArray { require(privkey.size == 32) val byteBuff = pack(privkey) val retByteArray: Array @@ -285,9 +284,8 @@ public object NativeSecp256k1 { * @return privkey * tweak * @throws AssertFailException in case of failure */ - @JvmStatic @Throws(AssertFailException::class) - public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray { + override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray { require(privkey.size == 32) val byteBuff = pack(privkey, tweak) val retByteArray: Array @@ -320,9 +318,8 @@ public object NativeSecp256k1 { * @return privkey + tweak * @throws AssertFailException in case of failure */ - @JvmStatic @Throws(AssertFailException::class) - public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray { + override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray { require(privkey.size == 32) val byteBuff = pack(privkey, tweak) val retByteArray: Array @@ -343,9 +340,8 @@ public object NativeSecp256k1 { return privArr } - @JvmStatic @Throws(AssertFailException::class) - public fun pubKeyNegate(pubkey: ByteArray): ByteArray { + override fun pubKeyNegate(pubkey: ByteArray): ByteArray { require(pubkey.size == 33 || pubkey.size == 65) val byteBuff = pack(pubkey) val retByteArray: Array @@ -375,9 +371,8 @@ public object NativeSecp256k1 { * @return pubkey + tweak * @throws AssertFailException in case of failure */ - @JvmStatic @Throws(AssertFailException::class) - public fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray { + override fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray { require(pubkey.size == 33 || pubkey.size == 65) val byteBuff = pack(pubkey, tweak) val retByteArray: Array @@ -407,9 +402,8 @@ public object NativeSecp256k1 { * @return pubkey * tweak * @throws AssertFailException in case of failure */ - @JvmStatic @Throws(AssertFailException::class) - public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray { + override fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray { require(pubkey.size == 33 || pubkey.size == 65) val byteBuff = pack(pubkey, tweak) val retByteArray: Array @@ -431,9 +425,8 @@ public object NativeSecp256k1 { return pubArr } - @JvmStatic @Throws(AssertFailException::class) - public fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray { + override fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray { require(pubkey1.size == 33 || pubkey1.size == 65) require(pubkey2.size == 33 || pubkey2.size == 65) val byteBuff = pack(pubkey1, pubkey2) @@ -465,9 +458,8 @@ public object NativeSecp256k1 { * @return ecdh(sedckey, pubkey) * @throws AssertFailException in case of failure */ - @JvmStatic @Throws(AssertFailException::class) - public fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray { + override fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray { require(seckey.size <= 32 && pubkey.size <= 65) val byteBuff = pack(seckey, pubkey) val retByteArray: Array @@ -488,9 +480,8 @@ public object NativeSecp256k1 { return resArr } - @JvmStatic @Throws(AssertFailException::class) - public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, compressed: Boolean): ByteArray { + override fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray { require(sig.size == 64) require(message.size == 32) val byteBuff = pack(sig, message) @@ -501,14 +492,18 @@ public object NativeSecp256k1 { byteBuff, Secp256k1Context.getContext(), recid, - compressed + format == PubKeyFormat.COMPRESSED ) } finally { r.unlock() } val resArr = retByteArray[0] val retVal = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() - NativeSecp256k1Util.assertEquals(resArr.size, if (compressed) 33 else 65, "Got bad result length.") + NativeSecp256k1Util.assertEquals( + resArr.size, + format.maxSize, + "Got bad result length." + ) NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") return resArr } @@ -520,10 +515,9 @@ public object NativeSecp256k1 { * @return true if successful * @throws AssertFailException in case of failure */ - @JvmStatic @Synchronized @Throws(AssertFailException::class) - public fun randomize(seed: ByteArray): Boolean { + override fun randomize(seed: ByteArray): Boolean { require(seed.size == 32) val byteBuff = pack(seed) w.lock() diff --git a/jni/src/commonMain/kotlin/org/bitcoin/NativeSecp256k1Util.kt b/jni/src/commonMain/kotlin/org/bitcoin/NativeSecp256k1Util.kt index 40c689e..e1f7fe0 100644 --- a/jni/src/commonMain/kotlin/org/bitcoin/NativeSecp256k1Util.kt +++ b/jni/src/commonMain/kotlin/org/bitcoin/NativeSecp256k1Util.kt @@ -15,7 +15,6 @@ */ package org.bitcoin -import kotlin.jvm.Throws import java.lang.Exception internal object NativeSecp256k1Util { diff --git a/jni/src/commonMain/kotlin/org/bitcoin/Secp256k1Context.kt b/jni/src/commonMain/kotlin/org/bitcoin/Secp256k1Context.kt index 0cbb769..13deb5b 100644 --- a/jni/src/commonMain/kotlin/org/bitcoin/Secp256k1Context.kt +++ b/jni/src/commonMain/kotlin/org/bitcoin/Secp256k1Context.kt @@ -15,8 +15,6 @@ */ package org.bitcoin -import kotlin.jvm.JvmStatic - /** * This class holds the context reference used in native methods * to handle ECDSA operations. @@ -35,6 +33,7 @@ public object Secp256k1Context { init { //static initializer isEnabled = true - context = secp256k1_init_context() + context = + secp256k1_init_context() } } diff --git a/jni/src/jvmMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt b/jni/src/jvmMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt index 9678781..10f5710 100644 --- a/jni/src/jvmMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt +++ b/jni/src/jvmMain/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt @@ -1,5 +1,7 @@ package fr.acinq.secp256k1.jni +import fr.acinq.secp256k1.Secp256k1 +import org.bitcoin.NativeSecp256k1 import java.io.* import java.util.* @@ -24,12 +26,13 @@ public actual object NativeSecp256k1Loader { @JvmStatic @Synchronized @Throws(Exception::class) - public actual fun load() { + public actual fun load(): Secp256k1 { // only cleanup before the first extract if (!extracted) { cleanup() } loadSecp256k1NativeLibrary() + return NativeSecp256k1 } private val tempDir: File diff --git a/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt b/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt index 43bd632..89159db 100644 --- a/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt +++ b/src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt @@ -18,60 +18,49 @@ package fr.acinq.secp256k1 import kotlin.jvm.JvmStatic -public enum class SigFormat(internal val size: Int) { COMPACT(64), DER(72) } +public enum class SigFormat(public val maxSize: Int) { COMPACT(64), DER(72) } -public enum class PubKeyFormat(internal val size: Int) { COMPRESSED(33), UNCOMPRESSED(65) } +public enum class PubKeyFormat(public val maxSize: Int) { COMPRESSED(33), UNCOMPRESSED(65) } -public expect object Secp256k1 { +public interface Secp256k1 { - @JvmStatic public fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean - @JvmStatic public fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray - @JvmStatic public fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair - @JvmStatic public fun secKeyVerify(seckey: ByteArray): Boolean - @JvmStatic public fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray - @JvmStatic public fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray - @JvmStatic public fun cleanup() - @JvmStatic public fun privKeyNegate(privkey: ByteArray): ByteArray - @JvmStatic public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray - @JvmStatic public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray - @JvmStatic public fun pubKeyNegate(pubkey: ByteArray): ByteArray - @JvmStatic public fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray - @JvmStatic public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray - @JvmStatic public fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray - @JvmStatic public fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray - @JvmStatic public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray - @JvmStatic public fun randomize(seed: ByteArray): Boolean -} \ No newline at end of file + + public companion object : Secp256k1 by getSecpk256k1() { + @JvmStatic public fun get(): Secp256k1 = this + } +} + +internal expect fun getSecpk256k1(): Secp256k1 diff --git a/src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt b/src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt deleted file mode 100644 index 6c9031d..0000000 --- a/src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020 ACINQ SAS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package fr.acinq.secp256k1 - -import org.bitcoin.NativeSecp256k1 -import java.lang.IllegalStateException - -public actual object Secp256k1 { - - init { - try { - val cls = Class.forName("fr.acinq.secp256k1.jni.NativeSecp256k1Loader") - val load = cls.getMethod("load") - load.invoke(null) - } catch (ex: ClassNotFoundException) { - throw IllegalStateException("Could not load native Secp256k1 JNI library. Have you added the JNI dependency?", ex) - } - } - - public actual fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean = NativeSecp256k1.verify(data, signature, pub) - - public actual fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray = NativeSecp256k1.sign(data, sec, format == SigFormat.COMPACT) - - public actual fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair = NativeSecp256k1.signatureNormalize(sig, format == SigFormat.COMPACT) - - public actual fun secKeyVerify(seckey: ByteArray): Boolean = NativeSecp256k1.secKeyVerify(seckey) - - public actual fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray = NativeSecp256k1.computePubkey(seckey, format == PubKeyFormat.COMPRESSED) - - public actual fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray = NativeSecp256k1.parsePubkey(pubkey, format == PubKeyFormat.COMPRESSED) - - public actual fun cleanup(): Unit = NativeSecp256k1.cleanup() - - public actual fun privKeyNegate(privkey: ByteArray): ByteArray = NativeSecp256k1.privKeyNegate(privkey) - - public actual fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray = NativeSecp256k1.privKeyTweakMul(privkey, tweak) - - public actual fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray = NativeSecp256k1.privKeyTweakAdd(privkey, tweak) - - public actual fun pubKeyNegate(pubkey: ByteArray): ByteArray = NativeSecp256k1.pubKeyNegate(pubkey) - - public actual fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray = NativeSecp256k1.pubKeyTweakAdd(pubkey, tweak) - - public actual fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray = NativeSecp256k1.pubKeyTweakMul(pubkey, tweak) - - public actual fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray = NativeSecp256k1.pubKeyAdd(pubkey1, pubkey2) - - public actual fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray = NativeSecp256k1.createECDHSecret(seckey, pubkey) - - public actual fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray = NativeSecp256k1.ecdsaRecover(sig, message, recid, format == PubKeyFormat.COMPRESSED) - - public actual fun randomize(seed: ByteArray): Boolean = NativeSecp256k1.randomize(seed) - -} diff --git a/src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1Jvm.kt b/src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1Jvm.kt new file mode 100644 index 0000000..6bd80ef --- /dev/null +++ b/src/jvmMain/kotlin/fr/acinq/secp256k1/Secp256k1Jvm.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2020 ACINQ SAS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package fr.acinq.secp256k1 + +import java.lang.IllegalStateException + + +internal actual fun getSecpk256k1(): Secp256k1 { + try { + val cls = Class.forName("fr.acinq.secp256k1.jni.NativeSecp256k1Loader") + val load = cls.getMethod("load") + return load.invoke(null) as Secp256k1 + } catch (ex: ClassNotFoundException) { + throw IllegalStateException("Could not load native Secp256k1 JNI library. Have you added the JNI dependency?", ex) + } +} diff --git a/src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1.kt b/src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1.kt deleted file mode 100644 index 9c39f10..0000000 --- a/src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1.kt +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * Copyright 2014-2016 the libsecp256k1 contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.bitcoin - -import org.bitcoin.NativeSecp256k1Util.AssertFailException -import java.math.BigInteger -import java.nio.ByteBuffer -import java.nio.ByteOrder -import java.util.concurrent.locks.Lock -import java.util.concurrent.locks.ReentrantReadWriteLock - -/** - * - * This class holds native methods to handle ECDSA verification. - * - * - * You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1 - * - * - * To build secp256k1 for use with bitcoinj, run - * `./configure --enable-jni --enable-experimental --enable-module-ecdh` - * and `make` then copy `.libs/libsecp256k1.so` to your system library path - * or point the JVM to the folder containing it with -Djava.library.path - * - */ -public object NativeSecp256k1 { - private val rwl = ReentrantReadWriteLock() - private val r: Lock = rwl.readLock() - private val w: Lock = rwl.writeLock() - private val nativeECDSABuffer = ThreadLocal() - - private fun pack(vararg buffers: ByteArray): ByteBuffer { - var size = 0 - for (i in buffers.indices) { - size += buffers[i].size - } - - val byteBuff = nativeECDSABuffer.get()?.takeIf { it.capacity() >= size } - ?: ByteBuffer.allocateDirect(size).also { - it.order(ByteOrder.nativeOrder()) - nativeECDSABuffer.set(it) - } - byteBuff.rewind() - for (i in buffers.indices) { - byteBuff.put(buffers[i]) - } - return byteBuff - } - - /** - * Verifies the given secp256k1 signature in native code. - * Calling when enabled == false is undefined (probably library not loaded) - * - * @param data The data which was signed, must be exactly 32 bytes - * @param signature The signature - * @param pub The public key which did the signing - * @return true if the signature is valid - * @throws AssertFailException in case of failure - */ - @JvmStatic - @Throws(AssertFailException::class) - public fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean { - require(data.size == 32 && signature.size <= 520 && pub.size <= 520) - val byteBuff = pack(data, signature, pub) - r.lock() - return try { - secp256k1_ecdsa_verify( - byteBuff, - Secp256k1Context.getContext(), - signature.size, - pub.size - ) == 1 - } finally { - r.unlock() - } - } - - /** - * libsecp256k1 Create an ECDSA signature. - * - * @param data Message hash, 32 bytes - * @param sec Secret key, 32 bytes - * @param compact True for compact signature, false for DER - * @return a signature, or an empty array is signing failed - * @throws AssertFailException in case of failure - */ - @JvmStatic - @Throws(AssertFailException::class) - public fun sign(data: ByteArray, sec: ByteArray, compact: Boolean): ByteArray { - require(data.size == 32 && sec.size <= 32) - val byteBuff = pack(data, sec) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_ecdsa_sign( - byteBuff, - compact, - Secp256k1Context.getContext() - ) - } finally { - r.unlock() - } - val sigArr = retByteArray[0] - val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals( - sigArr.size, - sigLen, - "Got bad signature length." - ) - return if (retVal == 0) ByteArray(0) else sigArr - } - - @JvmStatic - @Throws(AssertFailException::class) - public fun signatureNormalize(sig: ByteArray, compact: Boolean): Pair { - require(sig.size == 64 || sig.size in 70..73) - val byteBuff = pack(sig) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_ecdsa_normalize( - byteBuff, - sig.size, - compact, - Secp256k1Context.getContext() - ) - } finally { - r.unlock() - } - val sigArr = retByteArray[0] - val sigLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - val retBool = BigInteger(byteArrayOf(retByteArray[1][2])).toInt() - NativeSecp256k1Util.assertEquals( - sigArr.size, - sigLen, - "Got bad signature length." - ) - return (if (retVal == 0) ByteArray(0) else sigArr) to (retBool == 1) - } - - /** - * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid - * - * @param seckey ECDSA Secret key, 32 bytes - * @return true if seckey is valid - */ - @JvmStatic - public fun secKeyVerify(seckey: ByteArray): Boolean { - require(seckey.size == 32) - val byteBuff = pack(seckey) - r.lock() - return try { - secp256k1_ec_seckey_verify( - byteBuff, - Secp256k1Context.getContext() - ) == 1 - } finally { - r.unlock() - } - } - - /** - * libsecp256k1 Compute Pubkey - computes public key from secret key - * - * @param seckey ECDSA Secret key, 32 bytes - * @throws AssertFailException if parameters are not valid - * @return the corresponding public key (uncompressed) - */ - //TODO add a 'compressed' arg - @JvmStatic - @Throws(AssertFailException::class) - public fun computePubkey(seckey: ByteArray, compressed: Boolean): ByteArray { - require(seckey.size == 32) - val byteBuff = pack(seckey) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_ec_pubkey_create( - byteBuff, - compressed, - Secp256k1Context.getContext() - ) - } finally { - r.unlock() - } - val pubArr = retByteArray[0] - val pubLen = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals(pubArr.size, pubLen, "Got bad pubkey length.") - return if (retVal == 0) ByteArray(0) else pubArr - } - - /** - * @param pubkey public key - * @return the input public key (uncompressed) if valid, or an empty array - * @throws AssertFailException in case of failure - */ - @JvmStatic - @Throws(AssertFailException::class) - public fun parsePubkey(pubkey: ByteArray, compressed: Boolean): ByteArray { - require(pubkey.size == 33 || pubkey.size == 65) - val byteBuff = pack(pubkey) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_ec_pubkey_parse( - byteBuff, - Secp256k1Context.getContext(), - pubkey.size, - compressed - ) - } finally { - r.unlock() - } - val pubArr = retByteArray[0] - BigInteger(byteArrayOf(retByteArray[1][0])).toInt() - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals( - pubArr.size, - if (compressed) 33 else 65, - "Got bad pubkey length." - ) - return if (retVal == 0) ByteArray(0) else pubArr - } - - /** - * libsecp256k1 Cleanup - This destroys the secp256k1 context object - * This should be called at the end of the program for proper cleanup of the context. - */ - @JvmStatic - @Synchronized - public fun cleanup() { - w.lock() - try { - secp256k1_destroy_context(Secp256k1Context.getContext()) - } finally { - w.unlock() - } - } - - @JvmStatic - @Throws(AssertFailException::class) - public fun privKeyNegate(privkey: ByteArray): ByteArray { - require(privkey.size == 32) - val byteBuff = pack(privkey) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_privkey_negate( - byteBuff, - Secp256k1Context.getContext() - ) - } finally { - r.unlock() - } - val privArr = retByteArray[0] - val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals( - privArr.size, - privLen, - "Got bad privkey length." - ) - NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") - return privArr - } - - /** - * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it - * - * @param privkey 32-byte seckey - * @param tweak some bytes to tweak with - * @return privkey * tweak - * @throws AssertFailException in case of failure - */ - @JvmStatic - @Throws(AssertFailException::class) - public fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray { - require(privkey.size == 32) - val byteBuff = pack(privkey, tweak) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_privkey_tweak_mul( - byteBuff, - Secp256k1Context.getContext() - ) - } finally { - r.unlock() - } - val privArr = retByteArray[0] - val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals( - privArr.size, - privLen, - "Got bad privkey length." - ) - NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") - return privArr - } - - /** - * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it - * - * @param privkey 32-byte seckey - * @param tweak some bytes to tweak with - * @return privkey + tweak - * @throws AssertFailException in case of failure - */ - @JvmStatic - @Throws(AssertFailException::class) - public fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray { - require(privkey.size == 32) - val byteBuff = pack(privkey, tweak) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_privkey_tweak_add( - byteBuff, - Secp256k1Context.getContext() - ) - } finally { - r.unlock() - } - val privArr = retByteArray[0] - val privLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals(privArr.size, privLen, "Got bad pubkey length.") - NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") - return privArr - } - - @JvmStatic - @Throws(AssertFailException::class) - public fun pubKeyNegate(pubkey: ByteArray): ByteArray { - require(pubkey.size == 33 || pubkey.size == 65) - val byteBuff = pack(pubkey) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_pubkey_negate( - byteBuff, - Secp256k1Context.getContext(), - pubkey.size - ) - } finally { - r.unlock() - } - val pubArr = retByteArray[0] - val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals(pubArr.size, pubLen, "Got bad pubkey length.") - NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") - return pubArr - } - - /** - * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it - * - * @param tweak some bytes to tweak with - * @param pubkey 32-byte seckey - * @return pubkey + tweak - * @throws AssertFailException in case of failure - */ - @JvmStatic - @Throws(AssertFailException::class) - public fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray { - require(pubkey.size == 33 || pubkey.size == 65) - val byteBuff = pack(pubkey, tweak) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_pubkey_tweak_add( - byteBuff, - Secp256k1Context.getContext(), - pubkey.size - ) - } finally { - r.unlock() - } - val pubArr = retByteArray[0] - val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals(pubArr.size, pubLen, "Got bad pubkey length.") - NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") - return pubArr - } - - /** - * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it - * - * @param tweak some bytes to tweak with - * @param pubkey 32-byte seckey - * @return pubkey * tweak - * @throws AssertFailException in case of failure - */ - @JvmStatic - @Throws(AssertFailException::class) - public fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray { - require(pubkey.size == 33 || pubkey.size == 65) - val byteBuff = pack(pubkey, tweak) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_pubkey_tweak_mul( - byteBuff, - Secp256k1Context.getContext(), - pubkey.size - ) - } finally { - r.unlock() - } - val pubArr = retByteArray[0] - val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals(pubArr.size, pubLen, "Got bad pubkey length.") - NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") - return pubArr - } - - @JvmStatic - @Throws(AssertFailException::class) - public fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray { - require(pubkey1.size == 33 || pubkey1.size == 65) - require(pubkey2.size == 33 || pubkey2.size == 65) - val byteBuff = pack(pubkey1, pubkey2) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_ec_pubkey_add( - byteBuff, - Secp256k1Context.getContext(), - pubkey1.size, - pubkey2.size - ) - } finally { - r.unlock() - } - val pubArr = retByteArray[0] - val pubLen: Int = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() and 0xFF - val retVal = BigInteger(byteArrayOf(retByteArray[1][1])).toInt() - NativeSecp256k1Util.assertEquals(pubkey1.size, pubLen, "Got bad pubkey length.") - NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") - return pubArr - } - - /** - * libsecp256k1 create ECDH secret - constant time ECDH calculation - * - * @param seckey byte array of secret key used in exponentiaion - * @param pubkey byte array of public key used in exponentiaion - * @return ecdh(sedckey, pubkey) - * @throws AssertFailException in case of failure - */ - @JvmStatic - @Throws(AssertFailException::class) - public fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray { - require(seckey.size <= 32 && pubkey.size <= 65) - val byteBuff = pack(seckey, pubkey) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_ecdh( - byteBuff, - Secp256k1Context.getContext(), - pubkey.size - ) - } finally { - r.unlock() - } - val resArr = retByteArray[0] - val retVal = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() - NativeSecp256k1Util.assertEquals(resArr.size, 32, "Got bad result length.") - NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") - return resArr - } - - @JvmStatic - @Throws(AssertFailException::class) - public fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, compressed: Boolean): ByteArray { - require(sig.size == 64) - require(message.size == 32) - val byteBuff = pack(sig, message) - val retByteArray: Array - r.lock() - retByteArray = try { - secp256k1_ecdsa_recover( - byteBuff, - Secp256k1Context.getContext(), - recid, - compressed - ) - } finally { - r.unlock() - } - val resArr = retByteArray[0] - val retVal = BigInteger(byteArrayOf(retByteArray[1][0])).toInt() - NativeSecp256k1Util.assertEquals( - resArr.size, - if (compressed) 33 else 65, - "Got bad result length." - ) - NativeSecp256k1Util.assertEquals(retVal, 1, "Failed return value check.") - return resArr - } - - /** - * libsecp256k1 randomize - updates the context randomization - * - * @param seed 32-byte random seed - * @return true if successful - * @throws AssertFailException in case of failure - */ - @JvmStatic - @Synchronized - @Throws(AssertFailException::class) - public fun randomize(seed: ByteArray): Boolean { - require(seed.size == 32) - val byteBuff = pack(seed) - w.lock() - return try { - secp256k1_context_randomize( - byteBuff, - Secp256k1Context.getContext() - ) == 1 - } finally { - w.unlock() - } - } - - @JvmStatic private external fun secp256k1_context_randomize(byteBuff: ByteBuffer, context: Long): Int - @JvmStatic private external fun secp256k1_privkey_negate(byteBuff: ByteBuffer, context: Long): Array - @JvmStatic private external fun secp256k1_privkey_tweak_add(byteBuff: ByteBuffer, context: Long): Array - @JvmStatic private external fun secp256k1_privkey_tweak_mul(byteBuff: ByteBuffer, context: Long): Array - @JvmStatic private external fun secp256k1_pubkey_negate(byteBuff: ByteBuffer, context: Long, pubLen: Int): Array - @JvmStatic private external fun secp256k1_pubkey_tweak_add(byteBuff: ByteBuffer, context: Long, pubLen: Int): Array - @JvmStatic private external fun secp256k1_pubkey_tweak_mul(byteBuff: ByteBuffer, context: Long, pubLen: Int): Array - @JvmStatic private external fun secp256k1_destroy_context(context: Long) - @JvmStatic private external fun secp256k1_ecdsa_verify(byteBuff: ByteBuffer, context: Long, sigLen: Int, pubLen: Int): Int - @JvmStatic private external fun secp256k1_ecdsa_sign(byteBuff: ByteBuffer, compact: Boolean, context: Long): Array - @JvmStatic private external fun secp256k1_ecdsa_normalize(byteBuff: ByteBuffer, sigLen: Int, compact: Boolean, context: Long): Array - @JvmStatic private external fun secp256k1_ec_seckey_verify(byteBuff: ByteBuffer, context: Long): Int - @JvmStatic private external fun secp256k1_ec_pubkey_create(byteBuff: ByteBuffer, compressed: Boolean, context: Long): Array - @JvmStatic private external fun secp256k1_ec_pubkey_parse(byteBuff: ByteBuffer, context: Long, inputLen: Int, compressed: Boolean): Array - @JvmStatic private external fun secp256k1_ec_pubkey_add(byteBuff: ByteBuffer, context: Long, lent1: Int, len2: Int): Array - @JvmStatic private external fun secp256k1_ecdh(byteBuff: ByteBuffer, context: Long, inputLen: Int): Array - @JvmStatic private external fun secp256k1_ecdsa_recover(byteBuff: ByteBuffer, context: Long, recid: Int, compressed: Boolean): Array -} \ No newline at end of file diff --git a/src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1Util.kt b/src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1Util.kt deleted file mode 100644 index 40c689e..0000000 --- a/src/jvmMain/kotlin/org/bitcoin/NativeSecp256k1Util.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2014-2016 the libsecp256k1 contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.bitcoin - -import kotlin.jvm.Throws -import java.lang.Exception - -internal object NativeSecp256k1Util { - @Throws(AssertFailException::class) - fun assertEquals(val1: Int, val2: Int, message: String) { - if (val1 != val2) throw AssertFailException("FAIL: $message") - } - - class AssertFailException(message: String?) : Exception(message) -} \ No newline at end of file diff --git a/src/jvmMain/kotlin/org/bitcoin/Secp256k1Context.kt b/src/jvmMain/kotlin/org/bitcoin/Secp256k1Context.kt deleted file mode 100644 index 13deb5b..0000000 --- a/src/jvmMain/kotlin/org/bitcoin/Secp256k1Context.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014-2016 the libsecp256k1 contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.bitcoin - -/** - * This class holds the context reference used in native methods - * to handle ECDSA operations. - */ -public object Secp256k1Context { - @JvmStatic - public val isEnabled: Boolean //true if the library is loaded - private val context: Long //ref to pointer to context obj - - @JvmStatic - public fun getContext(): Long { - return if (!isEnabled) -1 else context //sanity check - } - - @JvmStatic private external fun secp256k1_init_context(): Long - - init { //static initializer - isEnabled = true - context = - secp256k1_init_context() - } -} diff --git a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt similarity index 82% rename from src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt rename to src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt index a63af12..5f124ff 100644 --- a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt +++ b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt @@ -5,7 +5,7 @@ import platform.posix.size_tVar import secp256k1.* @OptIn(ExperimentalUnsignedTypes::class) -public actual object Secp256k1 { +public object Secp256k1Native : Secp256k1 { private val ctx: CPointer by lazy { secp256k1_context_create((SECP256K1_FLAGS_TYPE_CONTEXT or SECP256K1_FLAGS_BIT_CONTEXT_SIGN or SECP256K1_FLAGS_BIT_CONTEXT_VERIFY).toUInt()) @@ -28,7 +28,7 @@ public actual object Secp256k1 { } private fun MemScope.serializeSignature(signature: secp256k1_ecdsa_signature, format: SigFormat): ByteArray { - val natOutput = allocArray(format.size) + val natOutput = allocArray(format.maxSize) when (format) { SigFormat.DER -> { val outputLen = alloc() @@ -65,7 +65,7 @@ public actual object Secp256k1 { return pinned.addressOf(0) } - public actual fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean { + public override fun verify(data: ByteArray, signature: ByteArray, pub: ByteArray): Boolean { require(data.size == 32) require(pub.size == 33 || pub.size == 65) memScoped { @@ -76,7 +76,7 @@ public actual object Secp256k1 { } } - public actual fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray { + public override fun sign(data: ByteArray, sec: ByteArray, format: SigFormat): ByteArray { require(sec.size == 32) require(data.size == 32) memScoped { @@ -89,7 +89,7 @@ public actual object Secp256k1 { } } - public actual fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair { + public override fun signatureNormalize(sig: ByteArray, format: SigFormat): Pair { require(sig.size == 64 || sig.size in 70..73) memScoped { val nSig = allocSignature(sig) @@ -98,7 +98,7 @@ public actual object Secp256k1 { } } - public actual fun secKeyVerify(seckey: ByteArray): Boolean { + public override fun secKeyVerify(seckey: ByteArray): Boolean { require(seckey.size == 32) memScoped { val nSec = toNat(seckey) @@ -106,30 +106,30 @@ public actual object Secp256k1 { } } - public actual fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray { + public override fun computePubkey(seckey: ByteArray, format: PubKeyFormat): ByteArray { require(seckey.size == 32) memScoped { val nSec = toNat(seckey) val nPubkey = alloc() val result = secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nSec) if (result == 0) return ByteArray(0) - return serializePubkey(nPubkey, format.size) + return serializePubkey(nPubkey, format.maxSize) } } - public actual fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray { + public override fun parsePubkey(pubkey: ByteArray, format: PubKeyFormat): ByteArray { require(pubkey.size == 33 || pubkey.size == 65) memScoped { val nPubkey = allocPublicKey(pubkey) - return serializePubkey(nPubkey, format.size) + return serializePubkey(nPubkey, format.maxSize) } } - public actual fun cleanup() { + public override fun cleanup() { secp256k1_context_destroy(ctx) } - public actual fun privKeyNegate(privkey: ByteArray): ByteArray { + public override fun privKeyNegate(privkey: ByteArray): ByteArray { require(privkey.size == 32) memScoped { val negated = privkey.copyOf() @@ -139,7 +139,7 @@ public actual object Secp256k1 { } } - public actual fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray { + public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray { require(privkey.size == 32) memScoped { val multiplied = privkey.copyOf() @@ -150,7 +150,7 @@ public actual object Secp256k1 { } } - public actual fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray { + public override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray { require(privkey.size == 32) memScoped { val added = privkey.copyOf() @@ -161,7 +161,7 @@ public actual object Secp256k1 { } } - public actual fun pubKeyNegate(pubkey: ByteArray): ByteArray { + public override fun pubKeyNegate(pubkey: ByteArray): ByteArray { require(pubkey.size == 33 || pubkey.size == 65) memScoped { val nPubkey = allocPublicKey(pubkey) @@ -170,7 +170,7 @@ public actual object Secp256k1 { } } - public actual fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray { + public override fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray { require(pubkey.size == 33 || pubkey.size == 65) memScoped { val nPubkey = allocPublicKey(pubkey) @@ -180,7 +180,7 @@ public actual object Secp256k1 { } } - public actual fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray { + public override fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray { require(pubkey.size == 33 || pubkey.size == 65) memScoped { val nPubkey = allocPublicKey(pubkey) @@ -190,7 +190,7 @@ public actual object Secp256k1 { } } - public actual fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray { + public override fun pubKeyAdd(pubkey1: ByteArray, pubkey2: ByteArray): ByteArray { require(pubkey1.size == 33 || pubkey1.size == 65) require(pubkey2.size == 33 || pubkey2.size == 65) memScoped { @@ -202,7 +202,7 @@ public actual object Secp256k1 { } } - public actual fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray { + public override fun createECDHSecret(seckey: ByteArray, pubkey: ByteArray): ByteArray { require(seckey.size == 32) require(pubkey.size == 33 || pubkey.size == 65) memScoped { @@ -214,7 +214,7 @@ public actual object Secp256k1 { } } - public actual fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray { + public override fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int, format: PubKeyFormat): ByteArray { require(sig.size == 64) require(message.size == 32) memScoped { @@ -224,11 +224,11 @@ public actual object Secp256k1 { val nMessage = toNat(message) val pubkey = alloc() secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess() - return serializePubkey(pubkey, format.size) + return serializePubkey(pubkey, format.maxSize) } } - public actual fun randomize(seed: ByteArray): Boolean { + public override fun randomize(seed: ByteArray): Boolean { require(seed.size == 32) memScoped { val nSeed = toNat(seed) @@ -236,3 +236,5 @@ public actual object Secp256k1 { } } } + +internal actual fun getSecpk256k1(): Secp256k1 = Secp256k1Native