2 Commits

Author SHA1 Message Date
Fabrice Drouin
1a4c8b37cb Release 0.12.0 (#95) 2023-12-13 16:40:32 +01:00
Fabrice Drouin
f242b4ffe8 Check arguments passed to secp256k1 methods (#94)
* Check arguments passed to secp256k1 methods

Illegal arguments will trigger an internal callback that prints to stderr and calls abort.
We already check arguments in our JNI and kotlin native code but had missed 2 checks (recid in ecdsaRecover, empty arrays in pubkeyCombine).

* Implement the same "tweak" checks in the native code and JNI code

The native code was missing checks on the "tweak" size (which must be 32 bytes)
2023-12-13 13:42:14 +01:00
5 changed files with 645 additions and 855 deletions

View File

@@ -22,7 +22,7 @@ buildscript {
allprojects { allprojects {
group = "fr.acinq.secp256k1" group = "fr.acinq.secp256k1"
version = "0.12.0-SNAPSHOT" version = "0.12.0"
repositories { repositories {
google() google()

File diff suppressed because it is too large Load Diff

View File

@@ -166,17 +166,7 @@ public interface Secp256k1 {
internal expect fun getSecpk256k1(): Secp256k1 internal expect fun getSecpk256k1(): Secp256k1
public open class Secp256k1Exception : RuntimeException { public class Secp256k1Exception : RuntimeException {
public constructor() : super()
public constructor(message: String?) : super(message)
}
public class Secp256k1ErrorCallbackException : Secp256k1Exception {
public constructor() : super()
public constructor(message: String?) : super(message)
}
public class Secp256k1IllegalCallbackException : Secp256k1Exception {
public constructor() : super() public constructor() : super()
public constructor(message: String?) : super(message) public constructor(message: String?) : super(message)
} }

View File

@@ -4,67 +4,15 @@ import kotlinx.cinterop.*
import platform.posix.size_tVar import platform.posix.size_tVar
import secp256k1.* import secp256k1.*
private typealias Secp256k1CallbackHandler = (String) -> Unit @OptIn(ExperimentalUnsignedTypes::class)
@OptIn(ExperimentalStdlibApi::class)
private class CallbackHandler(ctx: CPointer<secp256k1_context>) : AutoCloseable {
var illegalCallBackMessage: String? = null
val illegalHandler: Secp256k1CallbackHandler = { x: String -> illegalCallBackMessage = x }
val illegalCallbackRef = StableRef.create(illegalHandler)
var errorCallBackMessage: String? = null
val errorHandler: Secp256k1CallbackHandler = { x: String -> errorCallBackMessage = x }
val errorCallbackRef = StableRef.create(errorHandler)
init {
secp256k1_context_set_error_callback(
ctx, staticCFunction { buffer: CPointer<ByteVar>?, data: COpaquePointer? ->
if (data != null) {
val callback = data.asStableRef<Secp256k1CallbackHandler>().get()
callback(buffer?.toKString() ?: "error callback triggered")
}
},
errorCallbackRef.asCPointer()
)
secp256k1_context_set_illegal_callback(
ctx, staticCFunction { buffer: CPointer<ByteVar>?, data: COpaquePointer? ->
if (data != null) {
val callback = data.asStableRef<Secp256k1CallbackHandler>().get()
callback(buffer?.toKString() ?: "illegal callback triggered")
}
},
illegalCallbackRef.asCPointer()
)
}
fun checkForErrors() {
errorCallBackMessage?.let { throw Secp256k1ErrorCallbackException(it) }
illegalCallBackMessage?.let { throw Secp256k1IllegalCallbackException(it) }
}
override fun close() {
// StableRef instances have to be disposed of manually
illegalCallbackRef.dispose()
errorCallbackRef.dispose()
}
}
@OptIn(ExperimentalUnsignedTypes::class, ExperimentalStdlibApi::class)
public object Secp256k1Native : Secp256k1 { public object Secp256k1Native : Secp256k1 {
private val ctx: CPointer<secp256k1_context> by lazy { private val ctx: CPointer<secp256k1_context> by lazy {
secp256k1_context_create((SECP256K1_FLAGS_TYPE_CONTEXT or SECP256K1_FLAGS_BIT_CONTEXT_SIGN or SECP256K1_FLAGS_BIT_CONTEXT_VERIFY).toUInt()) secp256k1_context_create((SECP256K1_FLAGS_TYPE_CONTEXT or SECP256K1_FLAGS_BIT_CONTEXT_SIGN or SECP256K1_FLAGS_BIT_CONTEXT_VERIFY).toUInt())
?: error("Could not create secp256k1 context") ?: error("Could not create secp256k1 context")
} }
private fun Int.requireSuccess(message: String): Int { private fun Int.requireSuccess(message: String): Int = if (this != 1) throw Secp256k1Exception(message) else this
return if (this != 1) throw Secp256k1Exception(message) else this
}
private fun Int.requireSuccess(callbackHandler: CallbackHandler, message: String): Int {
callbackHandler.checkForErrors()
return if (this != 1) throw Secp256k1Exception(message) else this
}
private fun MemScope.allocSignature(input: ByteArray): secp256k1_ecdsa_signature { private fun MemScope.allocSignature(input: ByteArray): secp256k1_ecdsa_signature {
val sig = alloc<secp256k1_ecdsa_signature>() val sig = alloc<secp256k1_ecdsa_signature>()
@@ -110,209 +58,173 @@ public object Secp256k1Native : Secp256k1 {
public override fun verify(signature: ByteArray, message: ByteArray, pubkey: ByteArray): Boolean { public override fun verify(signature: ByteArray, message: ByteArray, pubkey: ByteArray): Boolean {
require(message.size == 32) require(message.size == 32)
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nPubkey = allocPublicKey(pubkey)
val nPubkey = allocPublicKey(pubkey) val nMessage = toNat(message)
val nMessage = toNat(message) val nSig = allocSignature(signature)
val nSig = allocSignature(signature) return secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr) == 1
val verify = secp256k1_ecdsa_verify(ctx, nSig.ptr, nMessage, nPubkey.ptr)
callbackHandler.checkForErrors()
return verify == 1
}
} }
} }
public override fun sign(message: ByteArray, privkey: ByteArray): ByteArray { public override fun sign(message: ByteArray, privkey: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
require(message.size == 32) require(message.size == 32)
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nPrivkey = toNat(privkey)
val nPrivkey = toNat(privkey) val nMessage = toNat(message)
val nMessage = toNat(message) val nSig = alloc<secp256k1_ecdsa_signature>()
val nSig = alloc<secp256k1_ecdsa_signature>() secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess("secp256k1_ecdsa_sign() failed")
secp256k1_ecdsa_sign(ctx, nSig.ptr, nMessage, nPrivkey, null, null).requireSuccess(callbackHandler, "secp256k1_ecdsa_sign() failed") return serializeSignature(nSig)
return serializeSignature(nSig)
}
} }
} }
public override fun signatureNormalize(sig: ByteArray): Pair<ByteArray, Boolean> { public override fun signatureNormalize(sig: ByteArray): Pair<ByteArray, Boolean> {
require(sig.size >= 64) { "invalid signature ${Hex.encode(sig)}" } require(sig.size >= 64){ "invalid signature ${Hex.encode(sig)}" }
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nSig = allocSignature(sig)
val nSig = allocSignature(sig) val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr)
val isHighS = secp256k1_ecdsa_signature_normalize(ctx, nSig.ptr, nSig.ptr) return Pair(serializeSignature(nSig), isHighS == 1)
callbackHandler.checkForErrors()
return Pair(serializeSignature(nSig), isHighS == 1)
}
} }
} }
public override fun secKeyVerify(privkey: ByteArray): Boolean { public override fun secKeyVerify(privkey: ByteArray): Boolean {
if (privkey.size != 32) return false if (privkey.size != 32) return false
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nPrivkey = toNat(privkey)
val nPrivkey = toNat(privkey) return secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1
val result = secp256k1_ec_seckey_verify(ctx, nPrivkey) == 1
callbackHandler.checkForErrors()
return result
}
} }
} }
public override fun pubkeyCreate(privkey: ByteArray): ByteArray { public override fun pubkeyCreate(privkey: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nPrivkey = toNat(privkey)
val nPrivkey = toNat(privkey) val nPubkey = alloc<secp256k1_pubkey>()
val nPubkey = alloc<secp256k1_pubkey>() secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess("secp256k1_ec_pubkey_create() failed")
secp256k1_ec_pubkey_create(ctx, nPubkey.ptr, nPrivkey).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_create() failed") return serializePubkey(nPubkey)
return serializePubkey(nPubkey)
}
} }
} }
public override fun pubkeyParse(pubkey: ByteArray): ByteArray { public override fun pubkeyParse(pubkey: ByteArray): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nPubkey = allocPublicKey(pubkey)
val nPubkey = allocPublicKey(pubkey) return serializePubkey(nPubkey)
val result = serializePubkey(nPubkey)
callbackHandler.checkForErrors()
return result
}
} }
} }
public override fun privKeyNegate(privkey: ByteArray): ByteArray { public override fun privKeyNegate(privkey: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val negated = privkey.copyOf()
val negated = privkey.copyOf() val negPriv = toNat(negated)
val negPriv = toNat(negated) secp256k1_ec_seckey_negate(ctx, negPriv).requireSuccess("secp256k1_ec_seckey_negate() failed")
secp256k1_ec_seckey_negate(ctx, negPriv).requireSuccess(callbackHandler, "secp256k1_ec_seckey_negate() failed") return negated
return negated
}
} }
} }
public override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray { public override fun privKeyTweakAdd(privkey: ByteArray, tweak: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
CallbackHandler(ctx).use { callbackHandler -> require(tweak.size == 32)
memScoped { memScoped {
val added = privkey.copyOf() val added = privkey.copyOf()
val natAdd = toNat(added) val natAdd = toNat(added)
val natTweak = toNat(tweak) val natTweak = toNat(tweak)
secp256k1_ec_seckey_tweak_add(ctx, natAdd, natTweak).requireSuccess(callbackHandler, "secp256k1_ec_seckey_tweak_add() failed") secp256k1_ec_seckey_tweak_add(ctx, natAdd, natTweak).requireSuccess("secp256k1_ec_seckey_tweak_add() failed")
return added return added
}
} }
} }
public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray { public override fun privKeyTweakMul(privkey: ByteArray, tweak: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
CallbackHandler(ctx).use { callbackHandler -> require(tweak.size == 32)
memScoped { memScoped {
val multiplied = privkey.copyOf() val multiplied = privkey.copyOf()
val natMul = toNat(multiplied) val natMul = toNat(multiplied)
val natTweak = toNat(tweak) val natTweak = toNat(tweak)
secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess(callbackHandler, "secp256k1_ec_privkey_tweak_mul() failed") secp256k1_ec_privkey_tweak_mul(ctx, natMul, natTweak).requireSuccess("secp256k1_ec_privkey_tweak_mul() failed")
return multiplied return multiplied
}
} }
} }
public override fun pubKeyNegate(pubkey: ByteArray): ByteArray { public override fun pubKeyNegate(pubkey: ByteArray): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nPubkey = allocPublicKey(pubkey)
val nPubkey = allocPublicKey(pubkey) secp256k1_ec_pubkey_negate(ctx, nPubkey.ptr).requireSuccess("secp256k1_ec_pubkey_negate() failed")
secp256k1_ec_pubkey_negate(ctx, nPubkey.ptr).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_negate() failed") return serializePubkey(nPubkey)
return serializePubkey(nPubkey)
}
} }
} }
public override fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray { public override fun pubKeyTweakAdd(pubkey: ByteArray, tweak: ByteArray): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler -> require(tweak.size == 32)
memScoped { memScoped {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
val nTweak = toNat(tweak) val nTweak = toNat(tweak)
secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_tweak_add() failed") secp256k1_ec_pubkey_tweak_add(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_add() failed")
return serializePubkey(nPubkey) return serializePubkey(nPubkey)
}
} }
} }
public override fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray { public override fun pubKeyTweakMul(pubkey: ByteArray, tweak: ByteArray): ByteArray {
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler -> require(tweak.size == 32)
memScoped { memScoped {
val nPubkey = allocPublicKey(pubkey) val nPubkey = allocPublicKey(pubkey)
val nTweak = toNat(tweak) val nTweak = toNat(tweak)
secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_tweak_mul() failed") secp256k1_ec_pubkey_tweak_mul(ctx, nPubkey.ptr, nTweak).requireSuccess("secp256k1_ec_pubkey_tweak_mul() failed")
return serializePubkey(nPubkey) return serializePubkey(nPubkey)
}
} }
} }
public override fun pubKeyCombine(pubkeys: Array<ByteArray>): ByteArray { public override fun pubKeyCombine(pubkeys: Array<ByteArray>): ByteArray {
require(pubkeys.isNotEmpty())
pubkeys.forEach { require(it.size == 33 || it.size == 65) } pubkeys.forEach { require(it.size == 33 || it.size == 65) }
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nPubkeys = pubkeys.map { allocPublicKey(it).ptr }
val nPubkeys = pubkeys.map { allocPublicKey(it).ptr } val combined = alloc<secp256k1_pubkey>()
val combined = alloc<secp256k1_pubkey>() secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess("secp256k1_ec_pubkey_combine() failed")
secp256k1_ec_pubkey_combine(ctx, combined.ptr, nPubkeys.toCValues(), pubkeys.size.convert()).requireSuccess(callbackHandler, "secp256k1_ec_pubkey_combine() failed") return serializePubkey(combined)
return serializePubkey(combined)
}
} }
} }
public override fun ecdh(privkey: ByteArray, pubkey: ByteArray): ByteArray { public override fun ecdh(privkey: ByteArray, pubkey: ByteArray): ByteArray {
require(privkey.size == 32) require(privkey.size == 32)
require(pubkey.size == 33 || pubkey.size == 65) require(pubkey.size == 33 || pubkey.size == 65)
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nPubkey = allocPublicKey(pubkey)
val nPubkey = allocPublicKey(pubkey) val nPrivkey = toNat(privkey)
val nPrivkey = toNat(privkey) val output = allocArray<UByteVar>(32)
val output = allocArray<UByteVar>(32) secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess("secp256k1_ecdh() failed")
secp256k1_ecdh(ctx, output, nPubkey.ptr, nPrivkey, null, null).requireSuccess(callbackHandler, "secp256k1_ecdh() failed") return output.readBytes(32)
return output.readBytes(32)
}
} }
} }
public override fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray { public override fun ecdsaRecover(sig: ByteArray, message: ByteArray, recid: Int): ByteArray {
require(sig.size == 64) require(sig.size == 64)
require(message.size == 32) require(message.size == 32)
// we do not check that recid is valid, which should trigger our illegal callback handler to throw a Secp256k1IllegalCallbackException require(recid in 0..3)
// require(recid in 0..3) memScoped {
val nSig = toNat(sig)
CallbackHandler(ctx).use { callbackHandler -> val rSig = alloc<secp256k1_ecdsa_recoverable_signature>()
memScoped { secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, rSig.ptr, nSig, recid).requireSuccess("secp256k1_ecdsa_recoverable_signature_parse_compact() failed")
val nSig = toNat(sig) val nMessage = toNat(message)
val rSig = alloc<secp256k1_ecdsa_recoverable_signature>() val pubkey = alloc<secp256k1_pubkey>()
secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, rSig.ptr, nSig, recid).requireSuccess(callbackHandler, "secp256k1_ecdsa_recoverable_signature_parse_compact() failed") secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess("secp256k1_ecdsa_recover() failed")
val nMessage = toNat(message) return serializePubkey(pubkey)
val pubkey = alloc<secp256k1_pubkey>()
secp256k1_ecdsa_recover(ctx, pubkey.ptr, rSig.ptr, nMessage).requireSuccess(callbackHandler, "secp256k1_ecdsa_recover() failed")
return serializePubkey(pubkey)
}
} }
} }
public override fun compact2der(sig: ByteArray): ByteArray { public override fun compact2der(sig: ByteArray): ByteArray {
require(sig.size == 64) require(sig.size == 64)
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nSig = allocSignature(sig)
val nSig = allocSignature(sig) val natOutput = allocArray<UByteVar>(73)
val natOutput = allocArray<UByteVar>(73) val len = alloc<size_tVar>()
val len = alloc<size_tVar>() len.value = 73.convert()
len.value = 73.convert() secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, len.ptr, nSig.ptr).requireSuccess("secp256k1_ecdsa_signature_serialize_der() failed")
secp256k1_ecdsa_signature_serialize_der(ctx, natOutput, len.ptr, nSig.ptr).requireSuccess(callbackHandler, "secp256k1_ecdsa_signature_serialize_der() failed") return natOutput.readBytes(len.value.toInt())
return natOutput.readBytes(len.value.toInt())
}
} }
} }
@@ -320,15 +232,13 @@ public object Secp256k1Native : Secp256k1 {
require(signature.size == 64) require(signature.size == 64)
require(data.size == 32) require(data.size == 32)
require(pub.size == 32) require(pub.size == 32)
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nPub = toNat(pub)
val nPub = toNat(pub) val pubkey = alloc<secp256k1_xonly_pubkey>()
val pubkey = alloc<secp256k1_xonly_pubkey>() secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess("secp256k1_xonly_pubkey_parse() failed")
secp256k1_xonly_pubkey_parse(ctx, pubkey.ptr, nPub).requireSuccess(callbackHandler, "secp256k1_xonly_pubkey_parse() failed") val nData = toNat(data)
val nData = toNat(data) val nSig = toNat(signature)
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
}
} }
} }
@@ -336,17 +246,15 @@ public object Secp256k1Native : Secp256k1 {
require(sec.size == 32) require(sec.size == 32)
require(data.size == 32) require(data.size == 32)
auxrand32?.let { require(it.size == 32) } auxrand32?.let { require(it.size == 32) }
CallbackHandler(ctx).use { callbackHandler -> memScoped {
memScoped { val nSec = toNat(sec)
val nSec = toNat(sec) val nData = toNat(data)
val nData = toNat(data) val nAuxrand32 = auxrand32?.let { toNat(it) }
val nAuxrand32 = auxrand32?.let { toNat(it) } val nSig = allocArray<UByteVar>(64)
val nSig = allocArray<UByteVar>(64) val keypair = alloc<secp256k1_keypair>()
val keypair = alloc<secp256k1_keypair>() secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess("secp256k1_keypair_create() failed")
secp256k1_keypair_create(ctx, keypair.ptr, nSec).requireSuccess(callbackHandler, "secp256k1_keypair_create() failed") secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess("secp256k1_ecdsa_sign() failed")
secp256k1_schnorrsig_sign32(ctx, nSig, nData, keypair.ptr, nAuxrand32).requireSuccess(callbackHandler, "secp256k1_ecdsa_sign() failed") return nSig.readBytes(64)
return nSig.readBytes(64)
}
} }
} }

View File

@@ -275,11 +275,6 @@ class Secp256k1Test {
val pub0 = Secp256k1.ecdsaRecover(sig, message, 0) val pub0 = Secp256k1.ecdsaRecover(sig, message, 0)
val pub1 = Secp256k1.ecdsaRecover(sig, message, 1) val pub1 = Secp256k1.ecdsaRecover(sig, message, 1)
assertTrue(pub.contentEquals(pub0) || pub.contentEquals(pub1)) assertTrue(pub.contentEquals(pub0) || pub.contentEquals(pub1))
// this is a special case, ecdsaRecover explicitly does not check that recid is valid, which triggers our illegal callback handler
assertFailsWith(Secp256k1IllegalCallbackException::class) {
Secp256k1.ecdsaRecover(sig, message, 4)
}
} }
@Test @Test
@@ -357,6 +352,38 @@ class Secp256k1Test {
} }
} }
@Test
fun testInvalidArguments() {
assertFails {
Secp256k1.pubkeyCreate(ByteArray(32))
}
assertFails {
Secp256k1.pubkeyCreate(Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
}
assertFails {
Secp256k1.pubkeyParse(ByteArray(33))
}
assertFails {
Secp256k1.pubkeyParse(Hex.decode("03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
}
assertFails {
Secp256k1.pubKeyCombine(arrayOf())
}
assertFails {
Secp256k1.pubKeyCombine(arrayOf(ByteArray(0)))
}
assertFails {
Secp256k1.signSchnorr(ByteArray(0), Hex.decode("0101010101010101010101010101010101010101010101010101010101010101"), null)
}
assertFails {
Secp256k1.ecdsaRecover(
Hex.decode("01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"),
Hex.decode("0202020202020202020202020202020202020202020202020202020202020202"),
-1
)
}
}
@Test @Test
fun fuzzEcdsaSignVerify() { fun fuzzEcdsaSignVerify() {
val random = Random.Default val random = Random.Default