Skip to content

Commit

Permalink
Update secp256k1 submodule (#107)
Browse files Browse the repository at this point in the history
Use secp256k1 v0.6.0
  • Loading branch information
sstone authored Nov 20, 2024
1 parent 0ff2c5b commit 9d080e9
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "native/secp256k1"]
path = native/secp256k1
url = https://github.com/jonasnick/secp256k1.git
url = https://github.com/bitcoin-core/secp256k1.git
8 changes: 8 additions & 0 deletions jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

74 changes: 71 additions & 3 deletions jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,9 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
if (jpubkeys == NULL)
return NULL;

count = (*penv)->GetArrayLength(penv, jpubkeys);
CHECKRESULT(count < 1, "pubkey array cannot be empty")
pubkeys = calloc(count, sizeof(secp256k1_pubkey *));
count = (*penv)->GetArrayLength(penv, jpubkeys);
CHECKRESULT(count < 1, "pubkey array cannot be empty")
pubkeys = calloc(count, sizeof(secp256k1_pubkey *));

for (i = 0; i < count; i++)
{
Expand Down Expand Up @@ -907,6 +907,74 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
return jnonce;
}

JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256k1_1musig_1nonce_1gen_1counter(JNIEnv *penv, jclass clazz, jlong jctx, jlong jcounter, jbyteArray jseckey, jbyteArray jmsg32, jbyteArray jkeyaggcache, jbyteArray jextra_input32)
{
secp256k1_context *ctx = (secp256k1_context *)jctx;
int result = 0;
size_t size;
secp256k1_musig_pubnonce pubnonce;
secp256k1_musig_secnonce secnonce;
jbyte *seckey;
unsigned char msg32[32];
secp256k1_keypair keypair;
secp256k1_musig_keyagg_cache keyaggcache;
unsigned char extra_input32[32];
jbyteArray jnonce;
jbyte *nonce_ptr = NULL;
unsigned char nonce[fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE + fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE];

if (jctx == 0)
return NULL;

if (jseckey == NULL)
return NULL;

seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
result = secp256k1_keypair_create(ctx, &keypair, seckey);
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
CHECKRESULT(!result, "secp256k1_keypair_create failed");

size = (*penv)->GetArrayLength(penv, jseckey);
CHECKRESULT(size != 32, "invalid private key size");
copy_bytes_from_java(penv, jseckey, size, seckey);

if (jmsg32 != NULL)
{
size = (*penv)->GetArrayLength(penv, jmsg32);
CHECKRESULT(size != 32, "invalid message size");
copy_bytes_from_java(penv, jmsg32, size, msg32);
}

if (jkeyaggcache != NULL)
{
size = (*penv)->GetArrayLength(penv, jkeyaggcache);
CHECKRESULT(size != sizeof(secp256k1_musig_keyagg_cache), "invalid keyagg cache size");
copy_bytes_from_java(penv, jkeyaggcache, size, keyaggcache.data);
}

if (jextra_input32 != NULL)
{
size = (*penv)->GetArrayLength(penv, jextra_input32);
CHECKRESULT(size != 32, "invalid extra input size");
copy_bytes_from_java(penv, jextra_input32, size, extra_input32);
}

result = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, jcounter,
&keypair,
jmsg32 == NULL ? NULL : msg32, jkeyaggcache == NULL ? NULL : &keyaggcache, jextra_input32 == NULL ? NULL : extra_input32);
CHECKRESULT(!result, "secp256k1_musig_nonce_gen failed");

memcpy(nonce, secnonce.data, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE);
result = secp256k1_musig_pubnonce_serialize(ctx, nonce + fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE, &pubnonce);
CHECKRESULT(!result, "secp256k1_musig_pubnonce_serialize failed");

jnonce = (*penv)->NewByteArray(penv, sizeof(nonce));
nonce_ptr = (*penv)->GetByteArrayElements(penv, jnonce, 0);
memcpy(nonce_ptr, nonce, sizeof(nonce));
(*penv)->ReleaseByteArrayElements(penv, jnonce, nonce_ptr, 0);
return jnonce;
}

void free_nonces(secp256k1_musig_pubnonce **nonces, size_t count)
{
size_t i;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ public class Secp256k1CFunctions {

public static native int secp256k1_schnorrsig_verify(long ctx, byte[] sig, byte[] msg, byte[] pubkey);

public static native byte[] secp256k1_musig_nonce_gen(long ctx, byte[] session_id32, byte[] seckey, byte[] pubkey, byte[] msg32, byte[] keyagg_cache, byte[] extra_input32);
public static native byte[] secp256k1_musig_nonce_gen(long ctx, byte[] session_rand32, byte[] seckey, byte[] pubkey, byte[] msg32, byte[] keyagg_cache, byte[] extra_input32);

public static native byte[] secp256k1_musig_nonce_gen_counter(long ctx, long nonrepeating_cnt, byte[] seckey, byte[] msg32, byte[] keyagg_cache, byte[] extra_input32);

public static native byte[] secp256k1_musig_nonce_agg(long ctx, byte[][] nonces);

Expand Down
8 changes: 6 additions & 2 deletions jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,12 @@ public object NativeSecp256k1 : Secp256k1 {
return Secp256k1CFunctions.secp256k1_schnorrsig_sign(Secp256k1Context.getContext(), data, sec, auxrand32)
}

override fun musigNonceGen(sessionId32: ByteArray, privkey: ByteArray?, aggpubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
return Secp256k1CFunctions.secp256k1_musig_nonce_gen(Secp256k1Context.getContext(), sessionId32, privkey, aggpubkey, msg32, keyaggCache, extraInput32)
override fun musigNonceGen(sessionRandom32: ByteArray, privkey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
return Secp256k1CFunctions.secp256k1_musig_nonce_gen(Secp256k1Context.getContext(), sessionRandom32, privkey, pubkey, msg32, keyaggCache, extraInput32)
}

override fun musigNonceGenCounter(nonRepeatingCounter: ULong, privkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
return Secp256k1CFunctions.secp256k1_musig_nonce_gen_counter(Secp256k1Context.getContext(), nonRepeatingCounter.toLong(), privkey, msg32, keyaggCache, extraInput32)
}

override fun musigNonceAgg(pubnonces: Array<ByteArray>): ByteArray {
Expand Down
2 changes: 1 addition & 1 deletion native/secp256k1
Submodule secp256k1 updated 88 files
+6 −3 .cirrus.yml
+1 −1 .github/actions/install-homebrew-valgrind/action.yml
+5 −0 .github/actions/run-in-docker-action/action.yml
+109 −36 .github/workflows/ci.yml
+2 −0 .gitignore
+51 −2 CHANGELOG.md
+101 −66 CMakeLists.txt
+1 −0 CONTRIBUTING.md
+14 −0 Makefile.am
+6 −4 README.md
+16 −0 build-aux/m4/bitcoin_secp.m4
+6 −4 ci/ci.sh
+1 −1 ci/linux-debian.Dockerfile
+0 −12 cmake/AllTargetsCompileOptions.cmake
+2 −2 cmake/CheckArm32Assembly.cmake
+18 −0 cmake/CheckMemorySanitizer.cmake
+55 −45 configure.ac
+15 −12 doc/musig.md
+3 −2 doc/release-process.md
+5 −8 examples/CMakeLists.txt
+11 −13 examples/ecdh.c
+11 −13 examples/ecdsa.c
+121 −0 examples/ellswift.c
+80 −34 examples/musig.c
+14 −17 examples/schnorr.c
+33 −43 include/secp256k1.h
+1 −1 include/secp256k1_ellswift.h
+8 −20 include/secp256k1_extrakeys.h
+180 −110 include/secp256k1_musig.h
+2 −2 include/secp256k1_recovery.h
+1 −1 include/secp256k1_schnorrsig.h
+3 −3 src/CMakeLists.txt
+1 −1 src/bench_ecmult.c
+7 −0 src/checkmem.h
+11 −5 src/ctime_tests.c
+2 −2 src/ecmult_const_impl.h
+108 −13 src/ecmult_gen.h
+2 −2 src/ecmult_gen_compute_table.h
+79 −55 src/ecmult_gen_compute_table_impl.h
+264 −53 src/ecmult_gen_impl.h
+10 −20 src/ecmult_impl.h
+3 −8 src/field.h
+0 −7 src/field_10x26_impl.h
+0 −7 src/field_5x52_impl.h
+4 −9 src/field_impl.h
+9 −1 src/group.h
+25 −17 src/group_impl.h
+3 −0 src/hash.h
+14 −5 src/hash_impl.h
+12 −1 src/hsort.h
+39 −30 src/hsort_impl.h
+4 −6 src/modinv32_impl.h
+4 −6 src/modinv64_impl.h
+5 −2 src/modules/ecdh/main_impl.h
+3 −3 src/modules/ecdh/tests_impl.h
+3 −1 src/modules/ellswift/main_impl.h
+26 −26 src/modules/ellswift/tests_impl.h
+0 −2 src/modules/extrakeys/Makefile.am.include
+0 −35 src/modules/extrakeys/main_impl.h
+18 −212 src/modules/extrakeys/tests_impl.h
+3 −11 src/modules/musig/keyagg.h
+26 −45 src/modules/musig/keyagg_impl.h
+0 −1 src/modules/musig/main_impl.h
+0 −1 src/modules/musig/session.h
+222 −134 src/modules/musig/session_impl.h
+208 −100 src/modules/musig/tests_impl.h
+5 −5 src/modules/musig/vectors.h
+4 −4 src/modules/recovery/tests_impl.h
+4 −2 src/modules/schnorrsig/main_impl.h
+3 −3 src/modules/schnorrsig/tests_exhaustive_impl.h
+30 −30 src/modules/schnorrsig/tests_impl.h
+49 −28 src/precompute_ecmult_gen.c
+1,767 −9,734 src/precomputed_ecmult_gen.c
+2 −2 src/precomputed_ecmult_gen.h
+4 −4 src/scalar.h
+47 −32 src/scalar_4x64_impl.h
+7 −17 src/scalar_8x32_impl.h
+4 −0 src/scalar_impl.h
+19 −14 src/scalar_low_impl.h
+2 −0 src/scratch.h
+39 −6 src/secp256k1.c
+11 −11 src/testrand.h
+22 −22 src/testrand_impl.h
+502 −338 src/tests.c
+6 −6 src/tests_exhaustive.c
+123 −4 src/testutil.h
+66 −9 src/util.h
+8 −1 tools/check-abi.sh
20 changes: 17 additions & 3 deletions src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,29 @@ public interface Secp256k1 {
* This nonce must never be persisted or reused across signing sessions.
* All optional arguments exist to enrich the quality of the randomness used, which is critical for security.
*
* @param sessionId32 unique 32-byte session ID.
* @param sessionRandom32 unique 32-byte random data that must not be reused to generate other nonces
* @param privkey (optional) signer's private key.
* @param aggpubkey aggregated public key of all participants in the signing session.
* @param pubkey signer's public key
* @param msg32 (optional) 32-byte message that will be signed, if already known.
* @param keyaggCache (optional) key aggregation cache data from the signing session.
* @param extraInput32 (optional) additional 32-byte random data.
* @return serialized version of the secret nonce and the corresponding public nonce.
*/
public fun musigNonceGen(sessionId32: ByteArray, privkey: ByteArray?, aggpubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray
public fun musigNonceGen(sessionRandom32: ByteArray, privkey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray

/**
* Alternative counter-based method for generating nonce.
* This nonce must never be persisted or reused across signing sessions.
* All optional arguments exist to enrich the quality of the randomness used, which is critical for security.
*
* @param nonRepeatingCounter non-repeating counter that must never be reused with the same private key
* @param privkey signer's private key.
* @param msg32 (optional) 32-byte message that will be signed, if already known.
* @param keyaggCache (optional) key aggregation cache data from the signing session.
* @param extraInput32 (optional) additional 32-byte random data.
* @return serialized version of the secret nonce and the corresponding public nonce.
*/
public fun musigNonceGenCounter(nonRepeatingCounter: ULong, privkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray

/**
* Aggregate public nonces from all participants of a signing session.
Expand Down
34 changes: 30 additions & 4 deletions src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ public object Secp256k1Native : Secp256k1 {
}
}

override fun musigNonceGen(sessionId32: ByteArray, privkey: ByteArray?, aggpubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
require(sessionId32.size == 32)
override fun musigNonceGen(sessionRandom32: ByteArray, privkey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
require(sessionRandom32.size == 32)
privkey?.let { require(it.size == 32) }
msg32?.let { require(it.size == 32) }
keyaggCache?.let { require(it.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE) }
Expand All @@ -301,17 +301,20 @@ public object Secp256k1Native : Secp256k1 {
val nonce = memScoped {
val secnonce = alloc<secp256k1_musig_secnonce>()
val pubnonce = alloc<secp256k1_musig_pubnonce>()
val nPubkey = allocPublicKey(aggpubkey)
val nPubkey = allocPublicKey(pubkey)
val nKeyAggCache = keyaggCache?.let {
val n = alloc<secp256k1_musig_keyagg_cache>()
memcpy(n.ptr, toNat(it), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
n
}
// we make a native copy of sessionRandom32, which will be zeroed by secp256k1_musig_nonce_gen
val sessionRand32 = allocArray<UByteVar>(32)
memcpy(sessionRand32.pointed.ptr, toNat(sessionRandom32), 32u)
secp256k1_musig_nonce_gen(
ctx,
secnonce.ptr,
pubnonce.ptr,
toNat(sessionId32),
sessionRand32,
privkey?.let { toNat(it) },
nPubkey.ptr,
msg32?.let { toNat(it) },
Expand All @@ -324,6 +327,29 @@ public object Secp256k1Native : Secp256k1 {
return nonce
}

override fun musigNonceGenCounter(nonRepeatingCounter: ULong, privkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
require(privkey.size ==32)
msg32?.let { require(it.size == 32) }
keyaggCache?.let { require(it.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE) }
extraInput32?.let { require(it.size == 32) }
val nonce = memScoped {
val secnonce = alloc<secp256k1_musig_secnonce>()
val pubnonce = alloc<secp256k1_musig_pubnonce>()
val nKeypair = alloc<secp256k1_keypair>()
secp256k1_keypair_create(ctx, nKeypair.ptr, toNat(privkey))
val nKeyAggCache = keyaggCache?.let {
val n = alloc<secp256k1_musig_keyagg_cache>()
memcpy(n.ptr, toNat(it), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
n
}
secp256k1_musig_nonce_gen_counter(ctx, secnonce.ptr, pubnonce.ptr, nonRepeatingCounter, nKeypair.ptr, msg32?.let { toNat(it) },nKeyAggCache?.ptr, extraInput32?.let { toNat(it) }).requireSuccess("secp256k1_musig_nonce_gen_counter() failed")
val nPubnonce = allocArray<UByteVar>(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
secp256k1_musig_pubnonce_serialize(ctx, nPubnonce, pubnonce.ptr).requireSuccess("secp256k1_musig_pubnonce_serialize failed")
secnonce.ptr.readBytes(Secp256k1.MUSIG2_SECRET_NONCE_SIZE) + nPubnonce.readBytes(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
}
return nonce
}

override fun musigNonceAgg(pubnonces: Array<ByteArray>): ByteArray {
require(pubnonces.isNotEmpty())
pubnonces.forEach { require(it.size == Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE) }
Expand Down
10 changes: 10 additions & 0 deletions tests/src/commonTest/kotlin/fr/acinq/secp256k1/Musig2Test.kt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ class Musig2Test {
}
}

@Test
fun `generate secret nonce from counter`() {
val sk = Hex.decode("EEC1CB7D1B7254C5CAB0D9C61AB02E643D464A59FE6C96A7EFE871F07C5AEF54")
val nonce = Secp256k1.musigNonceGenCounter(0UL, sk, null, null, null)
val secnonce = nonce.copyOfRange(0, Secp256k1.MUSIG2_SECRET_NONCE_SIZE)
val pubnonce = nonce.copyOfRange(Secp256k1.MUSIG2_SECRET_NONCE_SIZE, Secp256k1.MUSIG2_SECRET_NONCE_SIZE + Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
assertContentEquals(secnonce.copyOfRange(4, 4 + 64), Hex.decode("842F1380CD17A198FC3DAD3B7DA7492941F46976F2702FF7C66F24F472036AF1DA3F952DDE4A2DA6B6325707CE87A4E3616D06FC5F81A9C99386D20A99CECF99"))
assertContentEquals(pubnonce, Hex.decode("03A5B9B6907942EACDDA49A366016EC2E62404A1BF4AB6D4DB82067BC3ADF086D7033205DB9EB34D5C7CE02848CAC68A83ED73E3883477F563F23CE9A11A7721EC64"))
}

@Test
fun `aggregate nonces`() {
val tests = TestHelpers.readResourceAsJson("musig2/nonce_agg_vectors.json")
Expand Down

0 comments on commit 9d080e9

Please sign in to comment.