Skip to content

Commit c4862f6

Browse files
Merge #215: musig: include pubkey in secnonce and compare when signing
a1ec2bb musig: add test for signing with wrong secnonce for a keypair (Jonas Nick) bd57a01 musig: include pubkey in secnonce and compare when signing (Jonas Nick) Pull request description: Builds on #211. This PR implements a defense-in-depth measure that is specified in BIP-MuSig2. In fact, it revealed a bug in the `scriptless_atomic_swap` test. ACKs for top commit: real-or-random: ACK a1ec2bb Tree-SHA512: dfd54a07c13648e6a7163962bb516cc4ec3a25e4534da2c14a593e2da0f3779eb9b84bfa12ffd94676bb3f6ab86a323e7ec7dee938fd870f36882fee0181ca05
2 parents 4f57024 + a1ec2bb commit c4862f6

File tree

3 files changed

+90
-51
lines changed

3 files changed

+90
-51
lines changed

include/secp256k1_musig.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ typedef struct {
4343

4444
/** Opaque data structure that holds a signer's _secret_ nonce.
4545
*
46-
* Guaranteed to be 68 bytes in size.
46+
* Guaranteed to be 132 bytes in size.
4747
*
4848
* WARNING: This structure MUST NOT be copied or read or written to directly. A
4949
* signer who is online throughout the whole process and can keep this
@@ -57,7 +57,7 @@ typedef struct {
5757
* leak the secret signing key.
5858
*/
5959
typedef struct {
60-
unsigned char data[68];
60+
unsigned char data[132];
6161
} secp256k1_musig_secnonce;
6262

6363
/** Opaque data structure that holds a signer's public nonce.
@@ -351,7 +351,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
351351
* unless you really know what you are doing.
352352
* seckey: the 32-byte secret key that will later be used for signing, if
353353
* already known (can be NULL)
354-
* pubkey: public key of the signer creating the nonce
354+
* pubkey: public key of the signer creating the nonce. The secnonce
355+
* output of this function cannot be used to sign for any
356+
* other public key.
355357
* msg32: the 32-byte message that will later be signed, if already known
356358
* (can be NULL)
357359
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
@@ -432,13 +434,20 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process(
432434
* reuse. However, this is of course easily defeated if the secnonce has been
433435
* copied (or serialized). Remember that nonce reuse will leak the secret key!
434436
*
437+
* For signing to succeed, the secnonce provided to this function must have
438+
* been generated for the provided keypair. This means that when signing for a
439+
* keypair consisting of a seckey and pubkey, the secnonce must have been
440+
* created by calling musig_nonce_gen with that pubkey. Otherwise, the
441+
* illegal_callback is called.
442+
*
435443
* Returns: 0 if the arguments are invalid or the provided secnonce has already
436444
* been used for signing, 1 otherwise
437445
* Args: ctx: pointer to a context object
438446
* Out: partial_sig: pointer to struct to store the partial signature
439447
* In/Out: secnonce: pointer to the secnonce struct created in
440448
* musig_nonce_gen that has been never used in a
441-
* partial_sign call before
449+
* partial_sign call before and has been created for the
450+
* keypair
442451
* In: keypair: pointer to keypair to sign the message with
443452
* keyagg_cache: pointer to the keyagg_cache that was output when the
444453
* aggregate public key for this session

src/modules/musig/session_impl.h

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,19 @@
2222

2323
static const unsigned char secp256k1_musig_secnonce_magic[4] = { 0x22, 0x0e, 0xdc, 0xf1 };
2424

25-
static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, secp256k1_scalar *k) {
25+
static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, const secp256k1_scalar *k, secp256k1_ge *pk) {
2626
memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4);
2727
secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]);
2828
secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]);
29+
secp256k1_point_save(&secnonce->data[68], pk);
2930
}
3031

31-
static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_musig_secnonce *secnonce) {
32+
static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_ge *pk, secp256k1_musig_secnonce *secnonce) {
3233
int is_zero;
3334
ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0);
3435
secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL);
3536
secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL);
37+
secp256k1_point_load(pk, &secnonce->data[68]);
3638
/* We make very sure that the nonce isn't invalidated by checking the values
3739
* in addition to the magic. */
3840
is_zero = secp256k1_scalar_is_zero(&k[0]) & secp256k1_scalar_is_zero(&k[1]);
@@ -44,10 +46,12 @@ static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1
4446
/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */
4547
static void secp256k1_musig_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, int flag) {
4648
secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag);
47-
/* The flag argument is usually classified. So, above code makes the magic
48-
* classified. However, we need the magic to be declassified to be able to
49-
* compare it during secnonce_load. */
49+
/* The flag argument is usually classified. So, the line above makes the
50+
* magic and public key classified. However, we need both to be
51+
* declassified. Note that we don't declassify the entire object, because if
52+
* flag is 0, then k[0] and k[1] have not been zeroed. */
5053
secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_musig_secnonce_magic));
54+
secp256k1_declassify(ctx, &secnonce->data[68], 64);
5155
}
5256

5357
static const unsigned char secp256k1_musig_pubnonce_magic[4] = { 0xf5, 0x7a, 0x3d, 0xa0 };
@@ -355,6 +359,8 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn
355359
size_t pk_ser_len = sizeof(pk_ser);
356360
unsigned char aggpk_ser[32];
357361
unsigned char *aggpk_ser_ptr = NULL;
362+
secp256k1_ge pk;
363+
int pk_serialize_success;
358364
int ret = 1;
359365

360366
VERIFY_CHECK(ctx != NULL);
@@ -393,16 +399,19 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn
393399
VERIFY_CHECK(ret_tmp);
394400
aggpk_ser_ptr = aggpk_ser;
395401
}
396-
if (!secp256k1_ec_pubkey_serialize(ctx, pk_ser, &pk_ser_len, pubkey, SECP256K1_EC_COMPRESSED)) {
402+
if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
397403
return 0;
398404
}
405+
pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, SECP256K1_EC_COMPRESSED);
406+
/* A pubkey cannot be the point at infinity */
407+
VERIFY_CHECK(pk_serialize_success);
399408
VERIFY_CHECK(pk_ser_len == sizeof(pk_ser));
400409

401410
secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32);
402411
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0]));
403412
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1]));
404413
VERIFY_CHECK(!secp256k1_scalar_eq(&k[0], &k[1]));
405-
secp256k1_musig_secnonce_save(secnonce, k);
414+
secp256k1_musig_secnonce_save(secnonce, k, &pk);
406415
secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret);
407416

408417
for (i = 0; i < 2; i++) {
@@ -562,7 +571,7 @@ static void secp256k1_musig_partial_sign_clear(secp256k1_scalar *sk, secp256k1_s
562571

563572
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_partial_sig *partial_sig, secp256k1_musig_secnonce *secnonce, const secp256k1_keypair *keypair, const secp256k1_musig_keyagg_cache *keyagg_cache, const secp256k1_musig_session *session) {
564573
secp256k1_scalar sk;
565-
secp256k1_ge pk;
574+
secp256k1_ge pk, keypair_pk;
566575
secp256k1_scalar k[2];
567576
secp256k1_scalar mu, s;
568577
secp256k1_keyagg_cache_internal cache_i;
@@ -573,7 +582,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p
573582

574583
ARG_CHECK(secnonce != NULL);
575584
/* Fails if the magic doesn't match */
576-
ret = secp256k1_musig_secnonce_load(ctx, k, secnonce);
585+
ret = secp256k1_musig_secnonce_load(ctx, k, &pk, secnonce);
577586
/* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls
578587
* of this function to fail */
579588
memset(secnonce, 0, sizeof(*secnonce));
@@ -587,10 +596,12 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p
587596
ARG_CHECK(keyagg_cache != NULL);
588597
ARG_CHECK(session != NULL);
589598

590-
if (!secp256k1_keypair_load(ctx, &sk, &pk, keypair)) {
599+
if (!secp256k1_keypair_load(ctx, &sk, &keypair_pk, keypair)) {
591600
secp256k1_musig_partial_sign_clear(&sk, k);
592601
return 0;
593602
}
603+
ARG_CHECK(secp256k1_fe_equal_var(&pk.x, &keypair_pk.x)
604+
&& secp256k1_fe_equal_var(&pk.y, &keypair_pk.y));
594605
if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) {
595606
secp256k1_musig_partial_sign_clear(&sk, k);
596607
return 0;

0 commit comments

Comments
 (0)