Skip to content

Commit 2017bbe

Browse files
committed
fixup! split counter mode from musig_nonce_gen
1 parent dfd9849 commit 2017bbe

File tree

5 files changed

+239
-73
lines changed

5 files changed

+239
-73
lines changed

examples/musig.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,19 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr
102102

103103
for (i = 0; i < N_SIGNERS; i++) {
104104
unsigned char seckey[32];
105-
unsigned char session_id[32];
105+
unsigned char session_secrand[32];
106106
/* Create random session ID. It is absolutely necessary that the session ID
107107
* is unique for every call of secp256k1_musig_nonce_gen. Otherwise
108108
* it's trivial for an attacker to extract the secret key! */
109-
if (!fill_random(session_id, sizeof(session_id))) {
109+
if (!fill_random(session_secrand, sizeof(session_secrand))) {
110110
return 0;
111111
}
112112
if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
113113
return 0;
114114
}
115115
/* Initialize session and create secret nonce for signing and public
116116
* nonce to send to the other signers. */
117-
if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, &signer[i].pubkey, msg32, NULL, NULL)) {
117+
if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) {
118118
return 0;
119119
}
120120
pubnonces[i] = &signer[i].pubnonce;
@@ -132,7 +132,7 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr
132132
return 0;
133133
}
134134
/* partial_sign will clear the secnonce by setting it to 0. That's because
135-
* you must _never_ reuse the secnonce (or use the same session_id to
135+
* you must _never_ reuse the secnonce (or use the same session_secrand to
136136
* create a secnonce). If you do, you effectively reuse the nonce and
137137
* leak the secret key. */
138138
if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) {

include/secp256k1_musig.h

+65-9
Original file line numberDiff line numberDiff line change
@@ -317,12 +317,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
317317
* MuSig differs from regular Schnorr signing in that implementers _must_ take
318318
* special care to not reuse a nonce. This can be ensured by following these rules:
319319
*
320-
* 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE
320+
* 1. Each call to this function must have a UNIQUE session_secrand32 that must NOT BE
321321
* REUSED in subsequent calls to this function.
322-
* If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM
323-
* AND KEPT SECRET (even from other signers). If you do provide a seckey,
324-
* session_id32 can instead be a counter (that must never repeat!). However,
325-
* it is recommended to always choose session_id32 uniformly at random.
322+
* If you do not provide a seckey, session_secrand32 _must_ be UNIFORMLY RANDOM
323+
* AND KEPT SECRET (even from other signers).
326324
* 2. If you already know the seckey, message or aggregate public key
327325
* cache, they can be optionally provided to derive the nonce and increase
328326
* misuse-resistance. The extra_input32 argument can be used to provide
@@ -338,9 +336,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
338336
* Args: ctx: pointer to a context object (not secp256k1_context_static)
339337
* Out: secnonce: pointer to a structure to store the secret nonce
340338
* pubnonce: pointer to a structure to store the public nonce
341-
* In: session_id32: a 32-byte session_id32 as explained above. Must be unique to this
342-
* call to secp256k1_musig_nonce_gen and must be uniformly random
343-
* unless you really know what you are doing.
339+
* In:
340+
* session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this
341+
* call to secp256k1_musig_nonce_gen and must be uniformly random.
344342
* seckey: the 32-byte secret key that will later be used for signing, if
345343
* already known (can be NULL)
346344
* pubkey: public key of the signer creating the nonce. The secnonce
@@ -358,14 +356,72 @@ SECP256K1_API int secp256k1_musig_nonce_gen(
358356
const secp256k1_context *ctx,
359357
secp256k1_musig_secnonce *secnonce,
360358
secp256k1_musig_pubnonce *pubnonce,
361-
const unsigned char *session_id32,
359+
const unsigned char *session_secrand32,
362360
const unsigned char *seckey,
363361
const secp256k1_pubkey *pubkey,
364362
const unsigned char *msg32,
365363
const secp256k1_musig_keyagg_cache *keyagg_cache,
366364
const unsigned char *extra_input32
367365
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6);
368366

367+
368+
/** Alternative way to generate a nonce and start a signing session
369+
*
370+
* This function outputs a secret nonce that will be required for signing and a
371+
* corresponding public nonce that is intended to be sent to other signers.
372+
*
373+
* This function differs from `secp256k1_musig_nonce_gen` by accepting a
374+
* non-repeating counter value instead of a secret random value. This requires
375+
* the seckey argument to be mandatory.
376+
*
377+
* MuSig differs from regular Schnorr signing in that implementers _must_ take
378+
* special care to not reuse a nonce. This can be ensured by following these rules:
379+
*
380+
* 1. The nonrepeating_cnt argument must be a counter value that never
381+
* repeats, i.e., you must never call `secp256k1_musig_nonce_gen_counter`
382+
* twice with the same seckey and nonrepeating_cnt value.
383+
* 2. If you already know the seckey, message or aggregate public key
384+
* cache, they can be optionally provided to derive the nonce and increase
385+
* misuse-resistance. The extra_input32 argument can be used to provide
386+
* additional data that does not repeat in normal scenarios, such as the
387+
* current time.
388+
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
389+
* that it is used more than once for signing.
390+
*
391+
* Remember that nonce reuse will leak the secret key!
392+
* Note that using the same seckey for multiple MuSig sessions is fine.
393+
*
394+
* Returns: 0 if the arguments are invalid and 1 otherwise
395+
* Args: ctx: pointer to a context object (not secp256k1_context_static)
396+
* Out: secnonce: pointer to a structure to store the secret nonce
397+
* pubnonce: pointer to a structure to store the public nonce
398+
* In:
399+
* nonrepeating_cnt: the value of a counter as explained above. Must be
400+
* unique to this call to secp256k1_musig_nonce_gen.
401+
* seckey: the 32-byte secret key that will later be used for signing
402+
* pubkey: public key of the signer creating the nonce. The secnonce
403+
* output of this function cannot be used to sign for any
404+
* other public key.
405+
* msg32: the 32-byte message that will later be signed, if already known
406+
* (can be NULL)
407+
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
408+
* (and potentially tweaked) public key if already known
409+
* (can be NULL)
410+
* extra_input32: an optional 32-byte array that is input to the nonce
411+
* derivation function (can be NULL)
412+
*/
413+
SECP256K1_API int secp256k1_musig_nonce_gen_counter(
414+
const secp256k1_context *ctx,
415+
secp256k1_musig_secnonce *secnonce,
416+
secp256k1_musig_pubnonce *pubnonce,
417+
uint64_t nonrepeating_cnt,
418+
const unsigned char *seckey,
419+
const secp256k1_pubkey *pubkey,
420+
const unsigned char *msg32,
421+
const secp256k1_musig_keyagg_cache *keyagg_cache,
422+
const unsigned char *extra_input32
423+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
424+
369425
/** Aggregates the nonces of all signers into a single nonce
370426
*
371427
* This can be done by an untrusted party to reduce the communication

src/ctime_tests.c

+11-5
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
190190
secp256k1_pubkey pk;
191191
const secp256k1_pubkey *pk_ptr[1];
192192
secp256k1_xonly_pubkey agg_pk;
193-
unsigned char session_id[32];
193+
unsigned char session_secrand[32];
194+
uint64_t nonrepeating_cnt = 0;
194195
secp256k1_musig_secnonce secnonce;
195196
secp256k1_musig_pubnonce pubnonce;
196197
const secp256k1_musig_pubnonce *pubnonce_ptr[1];
@@ -203,20 +204,25 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
203204
pk_ptr[0] = &pk;
204205
pubnonce_ptr[0] = &pubnonce;
205206
SECP256K1_CHECKMEM_DEFINE(key, 32);
206-
memcpy(session_id, key, sizeof(session_id));
207-
session_id[0] = session_id[0] + 1;
207+
memcpy(session_secrand, key, sizeof(session_secrand));
208+
session_secrand[0] = session_secrand[0] + 1;
208209
memcpy(extra_input, key, sizeof(extra_input));
209210
extra_input[0] = extra_input[0] + 2;
210211

211212
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
212213
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair));
213214
CHECK(secp256k1_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1));
215+
214216
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
215-
SECP256K1_CHECKMEM_UNDEFINE(session_id, sizeof(session_id));
217+
SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand));
216218
SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input));
217-
ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, &pk, msg, &cache, extra_input);
219+
ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input);
220+
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
221+
CHECK(ret == 1);
222+
ret = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, nonrepeating_cnt, key, &pk, msg, &cache, extra_input);
218223
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
219224
CHECK(ret == 1);
225+
220226
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1));
221227
/* Make sure that previous tests don't undefine msg. It's not used as a secret here. */
222228
SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg));

src/modules/musig/session_impl.h

+46-17
Original file line numberDiff line numberDiff line change
@@ -341,21 +341,21 @@ static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha)
341341
sha->bytes = 64;
342342
}
343343

344-
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) {
344+
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) {
345345
secp256k1_sha256 sha;
346346
unsigned char rand[32];
347347
unsigned char i;
348348
unsigned char msg_present;
349349

350350
if (seckey32 != NULL) {
351351
secp256k1_nonce_function_musig_sha256_tagged_aux(&sha);
352-
secp256k1_sha256_write(&sha, session_id, 32);
352+
secp256k1_sha256_write(&sha, session_secrand, 32);
353353
secp256k1_sha256_finalize(&sha, rand);
354354
for (i = 0; i < 32; i++) {
355355
rand[i] ^= seckey32[i];
356356
}
357357
} else {
358-
memcpy(rand, session_id, sizeof(rand));
358+
memcpy(rand, session_secrand, sizeof(rand));
359359
}
360360

361361
/* 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
379379
}
380380
}
381381

382-
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) {
382+
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) {
383383
secp256k1_keyagg_cache_internal cache_i;
384384
secp256k1_scalar k[2];
385385
secp256k1_ge nonce_pt[2];
@@ -392,24 +392,12 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn
392392
int pk_serialize_success;
393393
int ret = 1;
394394

395-
VERIFY_CHECK(ctx != NULL);
396395
ARG_CHECK(secnonce != NULL);
397396
memset(secnonce, 0, sizeof(*secnonce));
398397
ARG_CHECK(pubnonce != NULL);
399398
memset(pubnonce, 0, sizeof(*pubnonce));
400-
ARG_CHECK(session_id32 != NULL);
401399
ARG_CHECK(pubkey != NULL);
402400
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
403-
if (seckey == NULL) {
404-
/* Check in constant time that the session_id is not 0 as a
405-
* defense-in-depth measure that may protect against a faulty RNG. */
406-
unsigned char acc = 0;
407-
for (i = 0; i < 32; i++) {
408-
acc |= session_id32[i];
409-
}
410-
ret &= !!acc;
411-
memset(&acc, 0, sizeof(acc));
412-
}
413401

414402
/* Check that the seckey is valid to be able to sign for it later. */
415403
if (seckey != NULL) {
@@ -439,7 +427,7 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn
439427
(void) pk_serialize_success;
440428
#endif
441429

442-
secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32);
430+
secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32);
443431
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0]));
444432
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1]));
445433
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
458446
return ret;
459447
}
460448

449+
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) {
450+
int ret = 1;
451+
unsigned char acc = 0;
452+
int i;
453+
454+
VERIFY_CHECK(ctx != NULL);
455+
ARG_CHECK(session_secrand32 != NULL);
456+
457+
/* Check in constant time that the session_secrand32 is not 0 as a
458+
* defense-in-depth measure that may protect against a faulty RNG. */
459+
for (i = 0; i < 32; i++) {
460+
acc |= session_secrand32[i];
461+
}
462+
ret &= !!acc;
463+
memset(&acc, 0, sizeof(acc));
464+
465+
/* We can declassify because branching on ret is only relevant when this
466+
* function called with an invalid session_secrand32 argument */
467+
secp256k1_declassify(ctx, &ret, sizeof(ret));
468+
if (ret == 0) {
469+
secp256k1_musig_secnonce_invalidate(ctx, secnonce, 1);
470+
return 0;
471+
}
472+
473+
return secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, session_secrand32, seckey, pubkey, msg32, keyagg_cache, extra_input32);
474+
}
475+
476+
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) {
477+
unsigned char buf[32] = { 0 };
478+
int i;
479+
480+
VERIFY_CHECK(ctx != NULL);
481+
ARG_CHECK((seckey != NULL));
482+
483+
for (i = 0; i < 8; ++i) {
484+
buf[7 - i] = (nonrepeating_cnt >> (i * 8)) & 0xFF;
485+
}
486+
487+
return secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, pubkey, msg32, keyagg_cache, extra_input32);
488+
}
489+
461490
static int secp256k1_musig_sum_nonces(const secp256k1_context* ctx, secp256k1_gej *summed_nonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) {
462491
size_t i;
463492
int j;

0 commit comments

Comments
 (0)