2 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
Fabrice Drouin
eb92fccbd6 Build a universal JNI binary for macos (#106)
Universal libraries embed both arm64 and x64 binaries.
2024-03-12 10:09:34 +01:00
8 changed files with 46 additions and 17 deletions

View File

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

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

@@ -17,6 +17,7 @@ if [ "$TARGET" == "linux" ]; then
CC_OPTS="-fPIC"
elif [ "$TARGET" == "darwin" ]; then
OUTFILE=libsecp256k1-jni.dylib
CC_OPTS="-arch arm64 -arch x86_64"
elif [ "$TARGET" == "mingw" ]; then
OUTFILE=secp256k1-jni.dll
CC=x86_64-w64-mingw32-gcc

View File

@@ -12,12 +12,8 @@ dependencies {
val copyJni by tasks.creating(Sync::class) {
onlyIf { org.gradle.internal.os.OperatingSystem.current().isMacOsX }
dependsOn(":jni:jvm:buildNativeHost")
val arch = when (System.getProperty("os.arch")) {
"aarch64" -> "aarch64"
else -> "x86_64"
}
from(rootDir.resolve("jni/jvm/build/darwin/libsecp256k1-jni.dylib"))
into(buildDir.resolve("jniResources/fr/acinq/secp256k1/jni/native/darwin-$arch"))
into(buildDir.resolve("jniResources/fr/acinq/secp256k1/jni/native/darwin"))
}
(tasks["processResources"] as ProcessResources).apply {

View File

@@ -19,7 +19,8 @@ internal object OSInfo {
private const val PPC = "ppc"
private const val PPC64 = "ppc64"
@JvmStatic val nativeSuffix: String get() = "$os-$arch"
// on macos we build a universal library that contains arm64 and x64 binaries
@JvmStatic val nativeSuffix: String get() = if (os == "darwin") os else "$os-$arch"
@JvmStatic val os: String get() = translateOSName(System.getProperty("os.name"))

View File

@@ -12,22 +12,20 @@ cd "$(dirname "$0")"
cd secp256k1
if [ "$TARGET" == "mingw" ]; then
CONF_OPTS="CFLAGS=-fPIC --host=x86_64-w64-mingw32"
CFLAGS="-fPIC"
CONF_OPTS=" --host=x86_64-w64-mingw32"
elif [ "$TARGET" == "linux" ]; then
CONF_OPTS="CFLAGS=-fPIC"
CFLAGS="-fPIC"
elif [ "$TARGET" == "darwin" ]; then
CONF_OPTS=""
CFLAGS="-arch arm64 -arch x86_64"
LDFLAGS="-arch arm64 -arch x86_64"
else
echo "Unknown TARGET=$TARGET"
exit 1
fi
./autogen.sh
if [ "$TARGET" == "darwin" ]; then
CFLAGS="-arch arm64 -arch x86_64" ./configure $CONF_OPTS --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
else
./configure $CONF_OPTS --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
fi
CFLAGS="$CFLAGS" LDFLAGS="$LDFLAGS" ./configure $CONF_OPTS --enable-experimental --enable-module_ecdh --enable-module-recovery --enable-module-schnorrsig --enable-module-musig --enable-benchmark=no --enable-shared=no --enable-exhaustive-tests=no --enable-tests=no
make clean
make

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