From 461970682f56a8e15fc71ecab18d4537e50441fc Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Sun, 10 Mar 2024 14:22:23 +0000 Subject: [PATCH] fixup! split counter mode from musig_nonce_gen --- examples/musig.c | 8 +- include/secp256k1_musig.h | 75 +++++++++++++-- src/ctime_tests.c | 16 +++- src/modules/musig/session_impl.h | 63 +++++++++---- src/modules/musig/tests_impl.h | 151 +++++++++++++++++++++++-------- 5 files changed, 240 insertions(+), 73 deletions(-) diff --git a/examples/musig.c b/examples/musig.c index 7569f919a4..731634c51c 100644 --- a/examples/musig.c +++ b/examples/musig.c @@ -102,11 +102,11 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr for (i = 0; i < N_SIGNERS; i++) { unsigned char seckey[32]; - unsigned char session_id[32]; + unsigned char session_secrand[32]; /* Create random session ID. It is absolutely necessary that the session ID * is unique for every call of secp256k1_musig_nonce_gen. Otherwise * it's trivial for an attacker to extract the secret key! */ - if (!fill_random(session_id, sizeof(session_id))) { + if (!fill_random(session_secrand, sizeof(session_secrand))) { return 0; } if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) { @@ -114,7 +114,7 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr } /* Initialize session and create secret nonce for signing and public * nonce to send to the other signers. */ - if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, &signer[i].pubkey, msg32, NULL, NULL)) { + if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) { return 0; } pubnonces[i] = &signer[i].pubnonce; @@ -132,7 +132,7 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr return 0; } /* partial_sign will clear the secnonce by setting it to 0. That's because - * you must _never_ reuse the secnonce (or use the same session_id to + * you must _never_ reuse the secnonce (or use the same session_secrand to * create a secnonce). If you do, you effectively reuse the nonce and * leak the secret key. */ if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) { diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index 585c68e51b..a79c0184a5 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -8,6 +8,7 @@ extern "C" { #endif #include +#include /** This module implements BIP 327 "MuSig2 for BIP340-compatible * Multi-Signatures" @@ -317,12 +318,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea * MuSig differs from regular Schnorr signing in that implementers _must_ take * special care to not reuse a nonce. This can be ensured by following these rules: * - * 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE + * 1. Each call to this function must have a UNIQUE session_secrand32 that must NOT BE * REUSED in subsequent calls to this function. - * If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM - * AND KEPT SECRET (even from other signers). If you do provide a seckey, - * session_id32 can instead be a counter (that must never repeat!). However, - * it is recommended to always choose session_id32 uniformly at random. + * If you do not provide a seckey, session_secrand32 _must_ be UNIFORMLY RANDOM + * AND KEPT SECRET (even from other signers). * 2. If you already know the seckey, message or aggregate public key * cache, they can be optionally provided to derive the nonce and increase * misuse-resistance. The extra_input32 argument can be used to provide @@ -338,9 +337,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea * Args: ctx: pointer to a context object (not secp256k1_context_static) * Out: secnonce: pointer to a structure to store the secret nonce * pubnonce: pointer to a structure to store the public nonce - * In: session_id32: a 32-byte session_id32 as explained above. Must be unique to this - * call to secp256k1_musig_nonce_gen and must be uniformly random - * unless you really know what you are doing. + * In: + * session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this + * call to secp256k1_musig_nonce_gen and must be uniformly random. * seckey: the 32-byte secret key that will later be used for signing, if * already known (can be NULL) * pubkey: public key of the signer creating the nonce. The secnonce @@ -358,7 +357,7 @@ SECP256K1_API int secp256k1_musig_nonce_gen( const secp256k1_context *ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, - const unsigned char *session_id32, + const unsigned char *session_secrand32, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, @@ -366,6 +365,64 @@ SECP256K1_API int secp256k1_musig_nonce_gen( const unsigned char *extra_input32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6); + +/** Alternative way to generate a nonce and start a signing session + * + * This function outputs a secret nonce that will be required for signing and a + * corresponding public nonce that is intended to be sent to other signers. + * + * This function differs from `secp256k1_musig_nonce_gen` by accepting a + * non-repeating counter value instead of a secret random value. This requires + * the seckey argument to be mandatory. + * + * MuSig differs from regular Schnorr signing in that implementers _must_ take + * special care to not reuse a nonce. This can be ensured by following these rules: + * + * 1. The nonrepeating_cnt argument must be a counter value that never + * repeats, i.e., you must never call `secp256k1_musig_nonce_gen_counter` + * twice with the same seckey and nonrepeating_cnt value. + * 2. If you already know the seckey, message or aggregate public key + * cache, they can be optionally provided to derive the nonce and increase + * misuse-resistance. The extra_input32 argument can be used to provide + * additional data that does not repeat in normal scenarios, such as the + * current time. + * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility + * that it is used more than once for signing. + * + * Remember that nonce reuse will leak the secret key! + * Note that using the same seckey for multiple MuSig sessions is fine. + * + * Returns: 0 if the arguments are invalid and 1 otherwise + * Args: ctx: pointer to a context object (not secp256k1_context_static) + * Out: secnonce: pointer to a structure to store the secret nonce + * pubnonce: pointer to a structure to store the public nonce + * In: + * nonrepeating_cnt: the value of a counter as explained above. Must be + * unique to this call to secp256k1_musig_nonce_gen. + * seckey: the 32-byte secret key that will later be used for signing + * pubkey: public key of the signer creating the nonce. The secnonce + * output of this function cannot be used to sign for any + * other public key. + * msg32: the 32-byte message that will later be signed, if already known + * (can be NULL) + * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate + * (and potentially tweaked) public key if already known + * (can be NULL) + * extra_input32: an optional 32-byte array that is input to the nonce + * derivation function (can be NULL) + */ +SECP256K1_API int secp256k1_musig_nonce_gen_counter( + const secp256k1_context *ctx, + secp256k1_musig_secnonce *secnonce, + secp256k1_musig_pubnonce *pubnonce, + uint64_t nonrepeating_cnt, + const unsigned char *seckey, + const secp256k1_pubkey *pubkey, + const unsigned char *msg32, + const secp256k1_musig_keyagg_cache *keyagg_cache, + const unsigned char *extra_input32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6); + /** Aggregates the nonces of all signers into a single nonce * * This can be done by an untrusted party to reduce the communication diff --git a/src/ctime_tests.c b/src/ctime_tests.c index e29ab9b066..2999804a89 100644 --- a/src/ctime_tests.c +++ b/src/ctime_tests.c @@ -190,7 +190,8 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) { secp256k1_pubkey pk; const secp256k1_pubkey *pk_ptr[1]; secp256k1_xonly_pubkey agg_pk; - unsigned char session_id[32]; + unsigned char session_secrand[32]; + uint64_t nonrepeating_cnt = 0; secp256k1_musig_secnonce secnonce; secp256k1_musig_pubnonce pubnonce; const secp256k1_musig_pubnonce *pubnonce_ptr[1]; @@ -203,20 +204,25 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) { pk_ptr[0] = &pk; pubnonce_ptr[0] = &pubnonce; SECP256K1_CHECKMEM_DEFINE(key, 32); - memcpy(session_id, key, sizeof(session_id)); - session_id[0] = session_id[0] + 1; + memcpy(session_secrand, key, sizeof(session_secrand)); + session_secrand[0] = session_secrand[0] + 1; memcpy(extra_input, key, sizeof(extra_input)); extra_input[0] = extra_input[0] + 2; CHECK(secp256k1_keypair_create(ctx, &keypair, key)); CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair)); CHECK(secp256k1_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1)); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); - SECP256K1_CHECKMEM_UNDEFINE(session_id, sizeof(session_id)); + SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand)); SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input)); - ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, &pk, msg, &cache, extra_input); + ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + ret = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, nonrepeating_cnt, key, &pk, msg, &cache, extra_input); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); + CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1)); /* Make sure that previous tests don't undefine msg. It's not used as a secret here. */ SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg)); diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index 7658e69cd6..b0ea45d888 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -341,7 +341,7 @@ static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha) sha->bytes = 64; } -static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_id, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { +static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { secp256k1_sha256 sha; unsigned char rand[32]; unsigned char i; @@ -349,13 +349,13 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c if (seckey32 != NULL) { secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); - secp256k1_sha256_write(&sha, session_id, 32); + secp256k1_sha256_write(&sha, session_secrand, 32); secp256k1_sha256_finalize(&sha, rand); for (i = 0; i < 32; i++) { rand[i] ^= seckey32[i]; } } else { - memcpy(rand, session_id, sizeof(rand)); + memcpy(rand, session_secrand, sizeof(rand)); } /* Subtract one from `sizeof` to avoid hashing the implicit null byte */ @@ -379,7 +379,7 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c } } -int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *session_id32, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { +int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *input_nonce, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { secp256k1_keyagg_cache_internal cache_i; secp256k1_scalar k[2]; secp256k1_ge nonce_pt[2]; @@ -392,24 +392,12 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn int pk_serialize_success; int ret = 1; - VERIFY_CHECK(ctx != NULL); ARG_CHECK(secnonce != NULL); memset(secnonce, 0, sizeof(*secnonce)); ARG_CHECK(pubnonce != NULL); memset(pubnonce, 0, sizeof(*pubnonce)); - ARG_CHECK(session_id32 != NULL); ARG_CHECK(pubkey != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - if (seckey == NULL) { - /* Check in constant time that the session_id is not 0 as a - * defense-in-depth measure that may protect against a faulty RNG. */ - unsigned char acc = 0; - for (i = 0; i < 32; i++) { - acc |= session_id32[i]; - } - ret &= !!acc; - memset(&acc, 0, sizeof(acc)); - } /* Check that the seckey is valid to be able to sign for it later. */ if (seckey != NULL) { @@ -439,7 +427,7 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn (void) pk_serialize_success; #endif - secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); + secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0])); VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1])); VERIFY_CHECK(!secp256k1_scalar_eq(&k[0], &k[1])); @@ -458,6 +446,47 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn return ret; } +int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *session_secrand32, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + int ret = 1; + unsigned char acc = 0; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(session_secrand32 != NULL); + + /* Check in constant time that the session_secrand32 is not 0 as a + * defense-in-depth measure that may protect against a faulty RNG. */ + for (i = 0; i < 32; i++) { + acc |= session_secrand32[i]; + } + ret &= !!acc; + memset(&acc, 0, sizeof(acc)); + + /* We can declassify because branching on ret is only relevant when this + * function called with an invalid session_secrand32 argument */ + secp256k1_declassify(ctx, &ret, sizeof(ret)); + if (ret == 0) { + secp256k1_musig_secnonce_invalidate(ctx, secnonce, 1); + return 0; + } + + return secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, session_secrand32, seckey, pubkey, msg32, keyagg_cache, extra_input32); +} + +int secp256k1_musig_nonce_gen_counter(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, uint64_t nonrepeating_cnt, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { + unsigned char buf[32] = { 0 }; + int i; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK((seckey != NULL)); + + for (i = 0; i < 8; ++i) { + buf[7 - i] = (nonrepeating_cnt >> (i * 8)) & 0xFF; + } + + return secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, pubkey, msg32, keyagg_cache, extra_input32); +} + static int secp256k1_musig_sum_nonces(const secp256k1_context* ctx, secp256k1_gej *summed_nonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { size_t i; int j; diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index 62b7d6ab20..e32a357d0c 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -47,7 +47,7 @@ static void musig_simple_test(void) { unsigned char msg[32]; secp256k1_xonly_pubkey agg_pk; secp256k1_musig_keyagg_cache keyagg_cache; - unsigned char session_id[2][32]; + unsigned char session_secrand[2][32]; secp256k1_musig_secnonce secnonce[2]; secp256k1_pubkey pk[2]; const secp256k1_pubkey *pk_ptr[2]; @@ -59,14 +59,19 @@ static void musig_simple_test(void) { secp256k1_testrand256(msg); for (i = 0; i < 2; i++) { - secp256k1_testrand256(session_id[i]); secp256k1_testrand256(sk[i]); pk_ptr[i] = &pk[i]; pubnonce_ptr[i] = &pubnonce[i]; partial_sig_ptr[i] = &partial_sig[i]; CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[i], &pubnonce[i], session_id[i], sk[i], &pk[i], NULL, NULL, NULL) == 1); + if (i == 0) { + secp256k1_testrand256(session_secrand[i]); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[i], &pubnonce[i], session_secrand[i], sk[i], &pk[i], NULL, NULL, NULL) == 1); + } else { + uint64_t nonrepeating_cnt = 0; + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[i], &pubnonce[i], nonrepeating_cnt, sk[i], &pk[i], NULL, NULL, NULL) == 1); + } } CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); @@ -125,7 +130,8 @@ static void musig_api_tests(void) { secp256k1_keypair invalid_keypair; unsigned char max64[64]; unsigned char zeros132[132] = { 0 }; - unsigned char session_id[2][32]; + unsigned char session_secrand[2][32]; + unsigned char nonrepeating_cnt = 0; secp256k1_musig_secnonce secnonce[2]; secp256k1_musig_secnonce secnonce_tmp; secp256k1_musig_secnonce invalid_secnonce; @@ -178,7 +184,7 @@ static void musig_api_tests(void) { inf_pubnonce_ptr[i] = &inf_pubnonce[i]; partial_sig_ptr[i] = &partial_sig[i]; invalid_partial_sig_ptr[i] = &partial_sig[i]; - secp256k1_testrand256(session_id[i]); + secp256k1_testrand256(session_secrand[i]); secp256k1_testrand256(sk[i]); CHECK(create_keypair_and_pk(&keypair[i], &pk[i], sk[i])); } @@ -243,33 +249,55 @@ static void musig_api_tests(void) { } } - /** Session creation **/ - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, NULL, &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], NULL, session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + /** Session creation with nonce_gen **/ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, NULL, &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], NULL, session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64)); CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - /* no seckey and session_id is 0 */ - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros132, NULL, &pk[0], msg, &keyagg_cache, max64) == 0); + /* session_secrand = 0 is disallowed because it indicates a faulty RNG */ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros132, sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1); + /* invalid seckey */ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], NULL, msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64)); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, NULL, max64) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64)); + CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); + + /* Every in-argument except session_secrand and pubkey can be NULL */ + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], NULL, &pk[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk[1], &pk[1], NULL, NULL, NULL) == 1); + + /** Session creation with nonce_gen_counter **/ + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen_counter(STATIC_CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, NULL, &pubnonce[0], nonrepeating_cnt, sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], NULL, nonrepeating_cnt, sk[0], &pk[0], msg, &keyagg_cache, max64)); CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - /* session_id 0 is fine when a seckey is provided */ - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros132, sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1); + /* using nonce_gen_counter requires sk */ + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, NULL, &pk[0], msg, &keyagg_cache, max64)); /* invalid seckey */ - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, max64, &pk[0], msg, &keyagg_cache, max64) == 0); CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], NULL, msg, &keyagg_cache, max64)); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64)); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, NULL, max64) == 1); - CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, sk[0], NULL, msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, sk[0], &invalid_pk, msg, &keyagg_cache, max64)); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, sk[0], &pk[0], msg, NULL, max64) == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, sk[0], &pk[0], msg, &invalid_keyagg_cache, max64)); CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); + + /* Every in-argument except session_secrand, sk and pubkey can be NULL */ + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[0], &pubnonce[0], nonrepeating_cnt, sk[0], &pk[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce[1], &pubnonce[1], nonrepeating_cnt, sk[1], &pk[1], NULL, NULL, NULL) == 1); - /* Every in-argument except session_id and pubkey can be NULL */ - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], NULL, NULL, NULL) == 1); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_id[1], sk[1], &pk[1], NULL, NULL, NULL) == 1); /** Serialize and parse public nonces **/ CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, NULL, &pubnonce[0])); @@ -436,7 +464,7 @@ static void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_by static void musig_nonce_test(void) { unsigned char *args[6]; - unsigned char session_id[32]; + unsigned char session_secrand[32]; unsigned char sk[32]; unsigned char pk[33]; unsigned char msg[32]; @@ -445,7 +473,7 @@ static void musig_nonce_test(void) { int i, j; secp256k1_scalar k[6][2]; - secp256k1_testrand_bytes_test(session_id, sizeof(session_id)); + secp256k1_testrand_bytes_test(session_secrand, sizeof(session_secrand)); secp256k1_testrand_bytes_test(sk, sizeof(sk)); secp256k1_testrand_bytes_test(pk, sizeof(pk)); secp256k1_testrand_bytes_test(msg, sizeof(msg)); @@ -453,14 +481,14 @@ static void musig_nonce_test(void) { secp256k1_testrand_bytes_test(extra_input, sizeof(extra_input)); /* Check that a bitflip in an argument results in different nonces. */ - args[0] = session_id; + args[0] = session_secrand; args[1] = msg; args[2] = sk; args[3] = pk; args[4] = agg_pk; args[5] = extra_input; for (i = 0; i < COUNT; i++) { - musig_nonce_bitflip(args, 0, sizeof(session_id)); + musig_nonce_bitflip(args, 0, sizeof(session_secrand)); musig_nonce_bitflip(args, 1, sizeof(msg)); musig_nonce_bitflip(args, 2, sizeof(sk)); musig_nonce_bitflip(args, 3, sizeof(pk)); @@ -469,11 +497,11 @@ static void musig_nonce_test(void) { } /* Check that if any argument is NULL, a different nonce is produced than if * any other argument is NULL. */ - memcpy(msg, session_id, sizeof(msg)); - memcpy(sk, session_id, sizeof(sk)); - memcpy(pk, session_id, sizeof(session_id)); - memcpy(agg_pk, session_id, sizeof(agg_pk)); - memcpy(extra_input, session_id, sizeof(extra_input)); + memcpy(msg, session_secrand, sizeof(msg)); + memcpy(sk, session_secrand, sizeof(sk)); + memcpy(pk, session_secrand, sizeof(session_secrand)); + memcpy(agg_pk, session_secrand, sizeof(agg_pk)); + memcpy(extra_input, session_secrand, sizeof(extra_input)); secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]); secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]); secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]); @@ -530,7 +558,7 @@ static void sha256_tag_test(void) { * keys and keyagg_cache. */ static void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_keyagg_cache *keyagg_cache) { secp256k1_pubkey pk[2]; - unsigned char session_id[2][32]; + unsigned char session_secrand[2][32]; unsigned char msg[32]; secp256k1_musig_secnonce secnonce[2]; secp256k1_musig_pubnonce pubnonce[2]; @@ -547,14 +575,14 @@ static void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const pubnonce_ptr[i] = &pubnonce[i]; partial_sig_ptr[i] = &partial_sig[i]; - secp256k1_testrand256(session_id[i]); + secp256k1_testrand256(session_secrand[i]); } CHECK(create_keypair_and_pk(&keypair[0], &pk[0], sk0) == 1); CHECK(create_keypair_and_pk(&keypair[1], &pk[1], sk1) == 1); secp256k1_testrand256(msg); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk0, &pk[0], NULL, NULL, NULL) == 1); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_id[1], sk1, &pk[1], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_secrand[0], sk0, &pk[0], NULL, NULL, NULL) == 1); + CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_secrand[1], sk1, &pk[1], NULL, NULL, NULL) == 1); CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, keyagg_cache) == 1); @@ -1004,6 +1032,51 @@ static void musig_test_vectors_sigagg(void) { } } +/* Since the BIP doesn't provide static test vectors for nonce_gen_counter, we define a static test here */ +static void musig_test_static_nonce_gen_counter(void) { + secp256k1_musig_secnonce secnonce; + secp256k1_musig_pubnonce pubnonce; + unsigned char pubnonce66[66]; + secp256k1_pubkey pk; + uint64_t nonrepeating_cnt = 0; + unsigned char sk[32] = { + 0xEE, 0xC1, 0xCB, 0x7D, 0x1B, 0x72, 0x54, 0xC5, + 0xCA, 0xB0, 0xD9, 0xC6, 0x1A, 0xB0, 0x2E, 0x64, + 0x3D, 0x46, 0x4A, 0x59, 0xFE, 0x6C, 0x96, 0xA7, + 0xEF, 0xE8, 0x71, 0xF0, 0x7C, 0x5A, 0xEF, 0x54, + }; + unsigned char expected_secnonce[64] = { + 0x84, 0x2F, 0x13, 0x80, 0xCD, 0x17, 0xA1, 0x98, + 0xFC, 0x3D, 0xAD, 0x3B, 0x7D, 0xA7, 0x49, 0x29, + 0x41, 0xF4, 0x69, 0x76, 0xF2, 0x70, 0x2F, 0xF7, + 0xC6, 0x6F, 0x24, 0xF4, 0x72, 0x03, 0x6A, 0xF1, + 0xDA, 0x3F, 0x95, 0x2D, 0xDE, 0x4A, 0x2D, 0xA6, + 0xB6, 0x32, 0x57, 0x07, 0xCE, 0x87, 0xA4, 0xE3, + 0x61, 0x6D, 0x06, 0xFC, 0x5F, 0x81, 0xA9, 0xC9, + 0x93, 0x86, 0xD2, 0x0A, 0x99, 0xCE, 0xCF, 0x99, + }; + unsigned char expected_pubnonce[66] = { + 0x03, 0xA5, 0xB9, 0xB6, 0x90, 0x79, 0x42, 0xEA, + 0xCD, 0xDA, 0x49, 0xA3, 0x66, 0x01, 0x6E, 0xC2, + 0xE6, 0x24, 0x04, 0xA1, 0xBF, 0x4A, 0xB6, 0xD4, + 0xDB, 0x82, 0x06, 0x7B, 0xC3, 0xAD, 0xF0, 0x86, + 0xD7, 0x03, 0x32, 0x05, 0xDB, 0x9E, 0xB3, 0x4D, + 0x5C, 0x7C, 0xE0, 0x28, 0x48, 0xCA, 0xC6, 0x8A, + 0x83, 0xED, 0x73, 0xE3, 0x88, 0x34, 0x77, 0xF5, + 0x63, 0xF2, 0x3C, 0xE9, 0xA1, 0x1A, 0x77, 0x21, + 0xEC, 0x64, + }; + + CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk)); + CHECK(secp256k1_musig_nonce_gen_counter(CTX, &secnonce, &pubnonce, nonrepeating_cnt, sk, &pk, NULL, NULL, NULL) == 1); + + CHECK(secp256k1_memcmp_var(&secnonce.data[4], expected_secnonce, 2*32) == 0); + CHECK(secp256k1_memcmp_var(&secnonce.data[4+2*32], &pk, sizeof(pk)) == 0); + + CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce66, &pubnonce) == 1); + CHECK(secp256k1_memcmp_var(pubnonce66, expected_pubnonce, sizeof(pubnonce66)) == 0); +} + static void run_musig_tests(void) { int i; @@ -1024,6 +1097,8 @@ static void run_musig_tests(void) { musig_test_vectors_signverify(); musig_test_vectors_tweak(); musig_test_vectors_sigagg(); + + musig_test_static_nonce_gen_counter(); } #endif