Skip to content

Commit 9d080e9

Browse files
authored
Update secp256k1 submodule (#107)
Use secp256k1 v0.6.0
1 parent 0ff2c5b commit 9d080e9

File tree

9 files changed

+147
-15
lines changed

9 files changed

+147
-15
lines changed

.gitmodules

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[submodule "native/secp256k1"]
22
path = native/secp256k1
3-
url = https://github.com/jonasnick/secp256k1.git
3+
url = https://github.com/bitcoin-core/secp256k1.git

jni/c/headers/java/fr_acinq_secp256k1_Secp256k1CFunctions.h

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jni/c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c

+71-3
Original file line numberDiff line numberDiff line change
@@ -549,9 +549,9 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
549549
if (jpubkeys == NULL)
550550
return NULL;
551551

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

556556
for (i = 0; i < count; i++)
557557
{
@@ -907,6 +907,74 @@ JNIEXPORT jbyteArray JNICALL Java_fr_acinq_secp256k1_Secp256k1CFunctions_secp256
907907
return jnonce;
908908
}
909909

910+
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)
911+
{
912+
secp256k1_context *ctx = (secp256k1_context *)jctx;
913+
int result = 0;
914+
size_t size;
915+
secp256k1_musig_pubnonce pubnonce;
916+
secp256k1_musig_secnonce secnonce;
917+
jbyte *seckey;
918+
unsigned char msg32[32];
919+
secp256k1_keypair keypair;
920+
secp256k1_musig_keyagg_cache keyaggcache;
921+
unsigned char extra_input32[32];
922+
jbyteArray jnonce;
923+
jbyte *nonce_ptr = NULL;
924+
unsigned char nonce[fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE + fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_PUBLIC_NONCE_SIZE];
925+
926+
if (jctx == 0)
927+
return NULL;
928+
929+
if (jseckey == NULL)
930+
return NULL;
931+
932+
seckey = (*penv)->GetByteArrayElements(penv, jseckey, 0);
933+
result = secp256k1_keypair_create(ctx, &keypair, seckey);
934+
(*penv)->ReleaseByteArrayElements(penv, jseckey, seckey, 0);
935+
CHECKRESULT(!result, "secp256k1_keypair_create failed");
936+
937+
size = (*penv)->GetArrayLength(penv, jseckey);
938+
CHECKRESULT(size != 32, "invalid private key size");
939+
copy_bytes_from_java(penv, jseckey, size, seckey);
940+
941+
if (jmsg32 != NULL)
942+
{
943+
size = (*penv)->GetArrayLength(penv, jmsg32);
944+
CHECKRESULT(size != 32, "invalid message size");
945+
copy_bytes_from_java(penv, jmsg32, size, msg32);
946+
}
947+
948+
if (jkeyaggcache != NULL)
949+
{
950+
size = (*penv)->GetArrayLength(penv, jkeyaggcache);
951+
CHECKRESULT(size != sizeof(secp256k1_musig_keyagg_cache), "invalid keyagg cache size");
952+
copy_bytes_from_java(penv, jkeyaggcache, size, keyaggcache.data);
953+
}
954+
955+
if (jextra_input32 != NULL)
956+
{
957+
size = (*penv)->GetArrayLength(penv, jextra_input32);
958+
CHECKRESULT(size != 32, "invalid extra input size");
959+
copy_bytes_from_java(penv, jextra_input32, size, extra_input32);
960+
}
961+
962+
result = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, jcounter,
963+
&keypair,
964+
jmsg32 == NULL ? NULL : msg32, jkeyaggcache == NULL ? NULL : &keyaggcache, jextra_input32 == NULL ? NULL : extra_input32);
965+
CHECKRESULT(!result, "secp256k1_musig_nonce_gen failed");
966+
967+
memcpy(nonce, secnonce.data, fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE);
968+
result = secp256k1_musig_pubnonce_serialize(ctx, nonce + fr_acinq_secp256k1_Secp256k1CFunctions_SECP256K1_MUSIG_SECRET_NONCE_SIZE, &pubnonce);
969+
CHECKRESULT(!result, "secp256k1_musig_pubnonce_serialize failed");
970+
971+
jnonce = (*penv)->NewByteArray(penv, sizeof(nonce));
972+
nonce_ptr = (*penv)->GetByteArrayElements(penv, jnonce, 0);
973+
memcpy(nonce_ptr, nonce, sizeof(nonce));
974+
(*penv)->ReleaseByteArrayElements(penv, jnonce, nonce_ptr, 0);
975+
return jnonce;
976+
}
977+
910978
void free_nonces(secp256k1_musig_pubnonce **nonces, size_t count)
911979
{
912980
size_t i;

jni/src/main/java/fr/acinq/secp256k1/Secp256k1CFunctions.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ public class Secp256k1CFunctions {
8989

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

92-
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);
92+
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);
93+
94+
public static native byte[] secp256k1_musig_nonce_gen_counter(long ctx, long nonrepeating_cnt, byte[] seckey, byte[] msg32, byte[] keyagg_cache, byte[] extra_input32);
9395

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

jni/src/main/kotlin/fr/acinq/secp256k1/NativeSecp256k1.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,12 @@ public object NativeSecp256k1 : Secp256k1 {
9292
return Secp256k1CFunctions.secp256k1_schnorrsig_sign(Secp256k1Context.getContext(), data, sec, auxrand32)
9393
}
9494

95-
override fun musigNonceGen(sessionId32: ByteArray, privkey: ByteArray?, aggpubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
96-
return Secp256k1CFunctions.secp256k1_musig_nonce_gen(Secp256k1Context.getContext(), sessionId32, privkey, aggpubkey, msg32, keyaggCache, extraInput32)
95+
override fun musigNonceGen(sessionRandom32: ByteArray, privkey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
96+
return Secp256k1CFunctions.secp256k1_musig_nonce_gen(Secp256k1Context.getContext(), sessionRandom32, privkey, pubkey, msg32, keyaggCache, extraInput32)
97+
}
98+
99+
override fun musigNonceGenCounter(nonRepeatingCounter: ULong, privkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
100+
return Secp256k1CFunctions.secp256k1_musig_nonce_gen_counter(Secp256k1Context.getContext(), nonRepeatingCounter.toLong(), privkey, msg32, keyaggCache, extraInput32)
97101
}
98102

99103
override fun musigNonceAgg(pubnonces: Array<ByteArray>): ByteArray {

native/secp256k1

Submodule secp256k1 updated 88 files

src/commonMain/kotlin/fr/acinq/secp256k1/Secp256k1.kt

+17-3
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,29 @@ public interface Secp256k1 {
159159
* This nonce must never be persisted or reused across signing sessions.
160160
* All optional arguments exist to enrich the quality of the randomness used, which is critical for security.
161161
*
162-
* @param sessionId32 unique 32-byte session ID.
162+
* @param sessionRandom32 unique 32-byte random data that must not be reused to generate other nonces
163163
* @param privkey (optional) signer's private key.
164-
* @param aggpubkey aggregated public key of all participants in the signing session.
164+
* @param pubkey signer's public key
165165
* @param msg32 (optional) 32-byte message that will be signed, if already known.
166166
* @param keyaggCache (optional) key aggregation cache data from the signing session.
167167
* @param extraInput32 (optional) additional 32-byte random data.
168168
* @return serialized version of the secret nonce and the corresponding public nonce.
169169
*/
170-
public fun musigNonceGen(sessionId32: ByteArray, privkey: ByteArray?, aggpubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray
170+
public fun musigNonceGen(sessionRandom32: ByteArray, privkey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray
171+
172+
/**
173+
* Alternative counter-based method for generating nonce.
174+
* This nonce must never be persisted or reused across signing sessions.
175+
* All optional arguments exist to enrich the quality of the randomness used, which is critical for security.
176+
*
177+
* @param nonRepeatingCounter non-repeating counter that must never be reused with the same private key
178+
* @param privkey signer's private key.
179+
* @param msg32 (optional) 32-byte message that will be signed, if already known.
180+
* @param keyaggCache (optional) key aggregation cache data from the signing session.
181+
* @param extraInput32 (optional) additional 32-byte random data.
182+
* @return serialized version of the secret nonce and the corresponding public nonce.
183+
*/
184+
public fun musigNonceGenCounter(nonRepeatingCounter: ULong, privkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray
171185

172186
/**
173187
* Aggregate public nonces from all participants of a signing session.

src/nativeMain/kotlin/fr/acinq/secp256k1/Secp256k1Native.kt

+30-4
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,8 @@ public object Secp256k1Native : Secp256k1 {
291291
}
292292
}
293293

294-
override fun musigNonceGen(sessionId32: ByteArray, privkey: ByteArray?, aggpubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
295-
require(sessionId32.size == 32)
294+
override fun musigNonceGen(sessionRandom32: ByteArray, privkey: ByteArray?, pubkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
295+
require(sessionRandom32.size == 32)
296296
privkey?.let { require(it.size == 32) }
297297
msg32?.let { require(it.size == 32) }
298298
keyaggCache?.let { require(it.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE) }
@@ -301,17 +301,20 @@ public object Secp256k1Native : Secp256k1 {
301301
val nonce = memScoped {
302302
val secnonce = alloc<secp256k1_musig_secnonce>()
303303
val pubnonce = alloc<secp256k1_musig_pubnonce>()
304-
val nPubkey = allocPublicKey(aggpubkey)
304+
val nPubkey = allocPublicKey(pubkey)
305305
val nKeyAggCache = keyaggCache?.let {
306306
val n = alloc<secp256k1_musig_keyagg_cache>()
307307
memcpy(n.ptr, toNat(it), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
308308
n
309309
}
310+
// we make a native copy of sessionRandom32, which will be zeroed by secp256k1_musig_nonce_gen
311+
val sessionRand32 = allocArray<UByteVar>(32)
312+
memcpy(sessionRand32.pointed.ptr, toNat(sessionRandom32), 32u)
310313
secp256k1_musig_nonce_gen(
311314
ctx,
312315
secnonce.ptr,
313316
pubnonce.ptr,
314-
toNat(sessionId32),
317+
sessionRand32,
315318
privkey?.let { toNat(it) },
316319
nPubkey.ptr,
317320
msg32?.let { toNat(it) },
@@ -324,6 +327,29 @@ public object Secp256k1Native : Secp256k1 {
324327
return nonce
325328
}
326329

330+
override fun musigNonceGenCounter(nonRepeatingCounter: ULong, privkey: ByteArray, msg32: ByteArray?, keyaggCache: ByteArray?, extraInput32: ByteArray?): ByteArray {
331+
require(privkey.size ==32)
332+
msg32?.let { require(it.size == 32) }
333+
keyaggCache?.let { require(it.size == Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE) }
334+
extraInput32?.let { require(it.size == 32) }
335+
val nonce = memScoped {
336+
val secnonce = alloc<secp256k1_musig_secnonce>()
337+
val pubnonce = alloc<secp256k1_musig_pubnonce>()
338+
val nKeypair = alloc<secp256k1_keypair>()
339+
secp256k1_keypair_create(ctx, nKeypair.ptr, toNat(privkey))
340+
val nKeyAggCache = keyaggCache?.let {
341+
val n = alloc<secp256k1_musig_keyagg_cache>()
342+
memcpy(n.ptr, toNat(it), Secp256k1.MUSIG2_PUBLIC_KEYAGG_CACHE_SIZE.toULong())
343+
n
344+
}
345+
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")
346+
val nPubnonce = allocArray<UByteVar>(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
347+
secp256k1_musig_pubnonce_serialize(ctx, nPubnonce, pubnonce.ptr).requireSuccess("secp256k1_musig_pubnonce_serialize failed")
348+
secnonce.ptr.readBytes(Secp256k1.MUSIG2_SECRET_NONCE_SIZE) + nPubnonce.readBytes(Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
349+
}
350+
return nonce
351+
}
352+
327353
override fun musigNonceAgg(pubnonces: Array<ByteArray>): ByteArray {
328354
require(pubnonces.isNotEmpty())
329355
pubnonces.forEach { require(it.size == Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE) }

tests/src/commonTest/kotlin/fr/acinq/secp256k1/Musig2Test.kt

+10
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ class Musig2Test {
9090
}
9191
}
9292

93+
@Test
94+
fun `generate secret nonce from counter`() {
95+
val sk = Hex.decode("EEC1CB7D1B7254C5CAB0D9C61AB02E643D464A59FE6C96A7EFE871F07C5AEF54")
96+
val nonce = Secp256k1.musigNonceGenCounter(0UL, sk, null, null, null)
97+
val secnonce = nonce.copyOfRange(0, Secp256k1.MUSIG2_SECRET_NONCE_SIZE)
98+
val pubnonce = nonce.copyOfRange(Secp256k1.MUSIG2_SECRET_NONCE_SIZE, Secp256k1.MUSIG2_SECRET_NONCE_SIZE + Secp256k1.MUSIG2_PUBLIC_NONCE_SIZE)
99+
assertContentEquals(secnonce.copyOfRange(4, 4 + 64), Hex.decode("842F1380CD17A198FC3DAD3B7DA7492941F46976F2702FF7C66F24F472036AF1DA3F952DDE4A2DA6B6325707CE87A4E3616D06FC5F81A9C99386D20A99CECF99"))
100+
assertContentEquals(pubnonce, Hex.decode("03A5B9B6907942EACDDA49A366016EC2E62404A1BF4AB6D4DB82067BC3ADF086D7033205DB9EB34D5C7CE02848CAC68A83ED73E3883477F563F23CE9A11A7721EC64"))
101+
}
102+
93103
@Test
94104
fun `aggregate nonces`() {
95105
val tests = TestHelpers.readResourceAsJson("musig2/nonce_agg_vectors.json")

0 commit comments

Comments
 (0)