Compare commits

...

1 Commits

Author SHA1 Message Date
sstone
61df0e8a9a
Set a "noop" illegal callback
The default "illegal" callback calls abort, which will crash the JVM or native app. We check arguments before calling secp256k1 so it should
never happen, except when trying to create a partial musig2 signature with an secret nonce that does not match the private key.

Methods that could be used to verify that the secret nonce does match the private key are not exported, hence the choice to set a custom callback.
2024-04-15 19:35:39 +02:00
3 changed files with 35 additions and 2 deletions

View File

@ -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;
}
/*

View File

@ -9,8 +9,11 @@ import secp256k1.*
public object Secp256k1Native : Secp256k1 {
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())
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<ByteVar>?, _: 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

View File

@ -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