diff --git a/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c b/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c index cf9053c..e5df78c 100644 --- a/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c +++ b/jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c @@ -44,6 +44,11 @@ void JNI_ThrowByName(JNIEnv *penv, const char *name, const char *msg) } \ } +static void secp256k1_noop_illegal_callback_fn(const char* str, void* data) { + (void)str; + (void)data; +} + /* * Class: fr_acinq_bitcoin_Secp256k1Bindings * Method: secp256k1_context_create @@ -51,7 +56,9 @@ void JNI_ThrowByName(JNIEnv *penv, const char *name, const char *msg) */ JNIEXPORT jlong JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1context_1create(JNIEnv *penv, jclass clazz, jint flags) { - return (jlong)secp256k1_context_create(flags); + jlong ctx = (jlong)secp256k1_context_create(flags); + secp256k1_context_set_illegal_callback(ctx, &secp256k1_noop_illegal_callback_fn, NULL); + return ctx; } /* diff --git a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt index 48468fe..b6182bd 100644 --- a/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt +++ b/src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt @@ -9,8 +9,11 @@ import 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()) + val c = 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") + val callback = staticCFunction { _: CPointer?, _: COpaquePointer? -> } + secp256k1_context_set_illegal_callback(c, callback, null) + c } private fun Int.requireSuccess(message: String): Int = if (this != 1) throw Secp256k1Exception(message) else this diff --git a/tests/src/commonTest/kotlin/fr/acinq/secp256k1/Secp256k1Test.kt b/tests/src/commonTest/kotlin/fr/acinq/secp256k1/Secp256k1Test.kt index 5cc71f8..5ea7450 100644 --- a/tests/src/commonTest/kotlin/fr/acinq/secp256k1/Secp256k1Test.kt +++ b/tests/src/commonTest/kotlin/fr/acinq/secp256k1/Secp256k1Test.kt @@ -520,6 +520,29 @@ class Secp256k1Test { -1 ) } + assertFails { + val privkeys = listOf( + "0101010101010101010101010101010101010101010101010101010101010101", + "0202020202020202020202020202020202020202020202020202020202020202", + ).map { Hex.decode(it) }.toTypedArray() + val pubkeys = privkeys.map { Secp256k1.pubkeyCreate(it) } + + val sessionId = Hex.decode("0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F") + val nonces = pubkeys.map { Secp256k1.musigNonceGen(sessionId, null, it, null, null, null) } + val secnonces = nonces.map { it.copyOfRange(0, 132) } + val pubnonces = nonces.map { it.copyOfRange(132, 132 + 66) } + val aggnonce = Secp256k1.musigNonceAgg(pubnonces.toTypedArray()) + + val keyaggCaches = (0 until 2).map { ByteArray(Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE) } + val aggpubkey = Secp256k1.musigPubkeyAgg(pubkeys.toTypedArray(), keyaggCaches[0]) + assertContentEquals(aggpubkey, Secp256k1.musigPubkeyAgg(pubkeys.toTypedArray(), keyaggCaches[1])) + assertContentEquals(keyaggCaches[0], keyaggCaches[1]) + val msg32 = Hex.decode("0303030303030303030303030303030303030303030303030303030303030303") + val sessions = (0 until 2).map { Secp256k1.musigNonceProcess(aggnonce, msg32, keyaggCaches[it]) } + + // we sign with the wrong secret nonce. it should fail (i.e. trigger an exception) but not crash the JVM + Secp256k1.musigPartialSign(secnonces[1], privkeys[0], keyaggCaches[0], sessions[0]) + } } @Test