Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update secp256k1 submodule #107

Merged
merged 6 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`() {
t-bast marked this conversation as resolved.
Show resolved Hide resolved
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
Loading