Skip to content

Commit e6fa5ea

Browse files
authored
Merge pull request #313 from LedgerHQ/musig2-fixes
Improvements from code review
2 parents 3d2f0e0 + 3a7100e commit e6fa5ea

File tree

7 files changed

+85
-58
lines changed

7 files changed

+85
-58
lines changed

src/common/wallet.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ typedef struct policy_node_ext_info_s {
290290
DEFINE_REL_PTR(uint16, uint16_t)
291291

292292
typedef struct {
293-
int16_t n; // number of key indexes
293+
uint16_t n; // number of key indexes
294294
rptr_uint16_t key_indexes; // pointer to an array of exactly n key indexes
295295
} musig_aggr_key_info_t;
296296

@@ -323,14 +323,14 @@ typedef struct {
323323
union {
324324
// type == 0
325325
struct {
326-
int16_t key_index; // index of the key (common between V1 and V2)
326+
uint16_t key_index; // index of the key (common between V1 and V2)
327327
} k;
328328
// type == 1
329329
struct {
330330
rptr_musig_aggr_key_info_t musig_info; // only used in V2
331331
} m;
332332
};
333-
int16_t
333+
uint16_t
334334
keyexpr_index; // index of the key expression in the descriptor template, in parsing order
335335
} policy_node_keyexpr_t;
336336

@@ -377,8 +377,8 @@ typedef struct {
377377
// 12 bytes
378378
typedef struct {
379379
struct policy_node_s base; // type is TOKEN_MULTI or TOKEN_SORTEDMULTI
380-
int16_t k; // threshold
381-
int16_t n; // number of keys
380+
uint16_t k; // threshold
381+
uint16_t n; // number of keys
382382
rptr_policy_node_keyexpr_t keys; // pointer to array of exactly n key expressions
383383
} policy_node_multisig_t;
384384

@@ -395,8 +395,8 @@ typedef struct policy_node_scriptlist_s {
395395
// 12 bytes, (+ 8 bytes for every script)
396396
typedef struct {
397397
struct policy_node_s base; // type is TOKEN_THRESH
398-
int16_t k; // threshold
399-
int16_t n; // number of child scripts
398+
uint16_t k; // threshold
399+
uint16_t n; // number of child scripts
400400
rptr_policy_node_scriptlist_t
401401
scriptlist; // pointer to array of exactly n pointers to child scripts
402402
} policy_node_thresh_t;

src/handler/lib/policy.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,9 @@ __attribute__((warn_unused_result)) static int get_derived_pubkey(
489489
qsort(keys, musig_info->n, sizeof(plain_pk_t), compare_plain_pk);
490490

491491
musig_keyagg_context_t musig_ctx;
492-
musig_key_agg(keys, musig_info->n, &musig_ctx);
492+
if (0 > musig_key_agg(keys, musig_info->n, &musig_ctx)) {
493+
return -1;
494+
}
493495

494496
// compute the aggregated extended pubkey
495497
memset(&ext_pubkey, 0, sizeof(ext_pubkey));

src/handler/sign_psbt.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,9 @@ static bool fill_keyexpr_info_if_internal(dispatcher_context_t *dc,
659659
qsort(keys, musig_info->n, sizeof(plain_pk_t), compare_plain_pk);
660660

661661
musig_keyagg_context_t musig_ctx;
662-
musig_key_agg(keys, musig_info->n, &musig_ctx);
662+
if (0 > musig_key_agg(keys, musig_info->n, &musig_ctx)) {
663+
return false;
664+
}
663665

664666
// compute the aggregated extended pubkey
665667
memset(&keyexpr_info->pubkey, 0, sizeof(keyexpr_info->pubkey));

src/handler/sign_psbt/musig_signing.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ bool produce_and_yield_pubnonce(dispatcher_context_t *dc,
270270
musig_secnonce_t secnonce;
271271
musig_pubnonce_t pubnonce;
272272
if (0 > musig_nonce_gen(rand_i_j,
273+
sizeof(rand_i_j),
273274
keyexpr_info->internal_pubkey.compressed_pubkey,
274275
musig_per_input_info.agg_key_tweaked.compressed_pubkey + 1,
275276
&secnonce,
@@ -401,6 +402,7 @@ bool __attribute__((noinline)) sign_sighash_musig_and_yield(dispatcher_context_t
401402
musig_pubnonce_t pubnonce;
402403

403404
if (0 > musig_nonce_gen(rand_i_j,
405+
sizeof(rand_i_j),
404406
keyexpr_info->internal_pubkey.compressed_pubkey,
405407
musig_per_input_info.agg_key_tweaked.compressed_pubkey + 1,
406408
&secnonce,

src/musig/musig.c

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ static int point_negate(const point_t *P, point_t *out) {
7373
set_point_infinite(out);
7474
return 0;
7575
}
76-
memmove(out->x, P->x, 32);
76+
memmove(out->x, P->x, sizeof(out->x));
7777

78-
if (CX_OK != cx_math_sub_no_throw(out->y, secp256k1_p, P->y, 32)) return -1;
78+
if (CX_OK != cx_math_sub_no_throw(out->y, secp256k1_p, P->y, sizeof(out->y))) return -1;
7979

8080
out->prefix = 4;
8181
return 0;
@@ -114,9 +114,9 @@ static bool is_array_zero(const uint8_t buffer[], size_t buffer_len) {
114114
return acc == 0;
115115
}
116116

117-
int cpoint_ext(const uint8_t x[static 33], point_t *out) {
117+
static int cpoint_ext(const uint8_t x[static sizeof(plain_pk_t)], point_t *out) {
118118
// Check if the point is at infinity (all bytes zero)
119-
if (is_array_zero(x, 33)) {
119+
if (is_array_zero(x, sizeof(plain_pk_t))) {
120120
set_point_infinite(out);
121121
return 0;
122122
}
@@ -135,15 +135,17 @@ static void musig_get_second_key(const plain_pk_t pubkeys[], size_t n_keys, plai
135135
memset(out, 0, sizeof(plain_pk_t));
136136
}
137137

138-
static void musig_hash_keys(const plain_pk_t pubkeys[], size_t n_keys, uint8_t out[static 32]) {
138+
static void musig_hash_keys(const plain_pk_t pubkeys[],
139+
size_t n_keys,
140+
uint8_t out[static CX_SHA256_SIZE]) {
139141
cx_sha256_t hash_context;
140142
crypto_tr_tagged_hash_init(&hash_context,
141143
BIP0327_keyagg_list_tag,
142144
sizeof(BIP0327_keyagg_list_tag));
143145
for (size_t i = 0; i < n_keys; i++) {
144146
crypto_hash_update(&hash_context.header, pubkeys[i], sizeof(plain_pk_t));
145147
}
146-
crypto_hash_digest(&hash_context.header, out, 32);
148+
crypto_hash_digest(&hash_context.header, out, CX_SHA256_SIZE);
147149
}
148150

149151
static void musig_key_agg_coeff_internal(const plain_pk_t pubkeys[],
@@ -207,13 +209,20 @@ int musig_key_agg(const plain_pk_t pubkeys[], size_t n_keys, musig_keyagg_contex
207209

208210
point_add(&ctx->Q, &P, &ctx->Q);
209211
}
212+
213+
if (is_point_infinite(&ctx->Q)) {
214+
PRINTF("Musig key aggregation resulted in an infinite point\n");
215+
return -1;
216+
}
217+
210218
memset(ctx->tacc, 0, sizeof(ctx->tacc));
211219
memset(ctx->gacc, 0, sizeof(ctx->gacc));
212220
ctx->gacc[31] = 1;
213221
return 0;
214222
}
215223

216224
static void musig_nonce_hash(const uint8_t *rand,
225+
size_t rand_len,
217226
const plain_pk_t pk,
218227
const xonly_pk_t aggpk,
219228
uint8_t i,
@@ -226,7 +235,7 @@ static void musig_nonce_hash(const uint8_t *rand,
226235
crypto_tr_tagged_hash_init(&hash_context, BIP0327_nonce_tag, sizeof(BIP0327_nonce_tag));
227236

228237
// rand
229-
crypto_hash_update(&hash_context.header, rand, 32);
238+
crypto_hash_update(&hash_context.header, rand, rand_len);
230239

231240
// len(pk) + pk
232241
crypto_hash_update_u8(&hash_context.header, sizeof(plain_pk_t));
@@ -252,19 +261,26 @@ static void musig_nonce_hash(const uint8_t *rand,
252261

253262
// same as nonce_gen_internal from the reference, removing the optional arguments sk, msg and
254263
// extra_in, and making aggpk compulsory
255-
int musig_nonce_gen(const uint8_t rand[32],
264+
int musig_nonce_gen(const uint8_t *rand,
265+
size_t rand_len,
256266
const plain_pk_t pk,
257267
const xonly_pk_t aggpk,
258268
musig_secnonce_t *secnonce,
259269
musig_pubnonce_t *pubnonce) {
260270
uint8_t msg[] = {0x00};
261271

262-
musig_nonce_hash(rand, pk, aggpk, 0, msg, 1, NULL, 0, secnonce->k_1);
272+
musig_nonce_hash(rand, rand_len, pk, aggpk, 0, msg, 1, NULL, 0, secnonce->k_1);
263273
if (CX_OK != cx_math_modm_no_throw(secnonce->k_1, 32, secp256k1_n, 32)) return -1;
264-
musig_nonce_hash(rand, pk, aggpk, 1, msg, 1, NULL, 0, secnonce->k_2);
274+
musig_nonce_hash(rand, rand_len, pk, aggpk, 1, msg, 1, NULL, 0, secnonce->k_2);
265275
if (CX_OK != cx_math_modm_no_throw(secnonce->k_2, 32, secp256k1_n, 32)) return -1;
266276

267-
memcpy(secnonce->pk, pk, 33);
277+
if (is_array_zero(secnonce->k_1, sizeof(secnonce->k_1)) ||
278+
is_array_zero(secnonce->k_2, sizeof(secnonce->k_2))) {
279+
// this can only happen with negligible probability
280+
return -1;
281+
}
282+
283+
memcpy(secnonce->pk, pk, sizeof(secnonce->pk));
268284

269285
point_t R_s1, R_s2;
270286

@@ -283,17 +299,17 @@ int musig_nonce_agg(const musig_pubnonce_t pubnonces[], size_t n_keys, musig_pub
283299
set_point_infinite(&R_j);
284300
for (size_t i = 0; i < n_keys; i++) {
285301
point_t R_ij;
286-
if (0 > cpoint(&pubnonces[i].raw[(j - 1) * 33], &R_ij)) {
302+
if (0 > cpoint(&pubnonces[i].raw[(j - 1) * sizeof(plain_pk_t)], &R_ij)) {
287303
PRINTF("Musig2 nonce aggregation: invalid contribution from cosigner %d\n", i);
288304
return -i - 1;
289305
}
290306
point_add(&R_j, &R_ij, &R_j);
291307
}
292308

293309
if (is_point_infinite(&R_j)) {
294-
memset(&out->raw[(j - 1) * 33], 0, 33);
310+
memset(&out->raw[(j - 1) * sizeof(plain_pk_t)], 0, sizeof(plain_pk_t));
295311
} else {
296-
crypto_get_compressed_pubkey(R_j.raw, &out->raw[(j - 1) * 33]);
312+
crypto_get_compressed_pubkey(R_j.raw, &out->raw[(j - 1) * sizeof(plain_pk_t)]);
297313
}
298314
}
299315
return 0;
@@ -362,14 +378,18 @@ static int musig_get_session_values(const musig_session_context_t *session_ctx,
362378
point_t *Q,
363379
uint8_t gacc[static 32],
364380
uint8_t tacc[static 32],
365-
uint8_t b[static 32],
381+
uint8_t b[static CX_SHA256_SIZE],
366382
point_t *R,
367-
uint8_t e[static 32]) {
383+
uint8_t e[static CX_SHA256_SIZE]) {
368384
cx_sha256_t hash_context;
369385

370386
// Perform key aggregation and tweaking
371387
musig_keyagg_context_t keyagg_ctx;
372-
musig_key_agg(session_ctx->pubkeys, session_ctx->n_keys, &keyagg_ctx);
388+
389+
if (0 > musig_key_agg(session_ctx->pubkeys, session_ctx->n_keys, &keyagg_ctx)) {
390+
return -1;
391+
}
392+
373393
for (size_t i = 0; i < session_ctx->n_tweaks; i++) {
374394
if (0 > apply_tweak(&keyagg_ctx, session_ctx->tweaks[i], session_ctx->is_xonly[i])) {
375395
return -1;
@@ -383,10 +403,12 @@ static int musig_get_session_values(const musig_session_context_t *session_ctx,
383403

384404
// Calculate b
385405
crypto_tr_tagged_hash_init(&hash_context, BIP0327_noncecoef_tag, sizeof(BIP0327_noncecoef_tag));
386-
crypto_hash_update(&hash_context.header, session_ctx->aggnonce->raw, 66);
387-
crypto_hash_update(&hash_context.header, Q->x, 32);
406+
crypto_hash_update(&hash_context.header,
407+
session_ctx->aggnonce->raw,
408+
sizeof(session_ctx->aggnonce->raw));
409+
crypto_hash_update(&hash_context.header, Q->x, sizeof(Q->x));
388410
crypto_hash_update(&hash_context.header, session_ctx->msg, session_ctx->msg_len);
389-
crypto_hash_digest(&hash_context.header, b, 32);
411+
crypto_hash_digest(&hash_context.header, b, CX_SHA256_SIZE);
390412

391413
// Calculate R
392414
point_t R_1, R_2;
@@ -411,10 +433,10 @@ static int musig_get_session_values(const musig_session_context_t *session_ctx,
411433

412434
// Calculate e
413435
crypto_tr_tagged_hash_init(&hash_context, BIP0340_challenge_tag, sizeof(BIP0340_challenge_tag));
414-
crypto_hash_update(&hash_context.header, R->x, 32);
415-
crypto_hash_update(&hash_context.header, Q->x, 32);
436+
crypto_hash_update(&hash_context.header, R->x, sizeof(R->x));
437+
crypto_hash_update(&hash_context.header, Q->x, sizeof(Q->x));
416438
crypto_hash_update(&hash_context.header, session_ctx->msg, session_ctx->msg_len);
417-
crypto_hash_digest(&hash_context.header, e, 32);
439+
crypto_hash_digest(&hash_context.header, e, CX_SHA256_SIZE);
418440
return 0;
419441
}
420442

@@ -448,9 +470,9 @@ int musig_sign(musig_secnonce_t *secnonce,
448470
point_t Q;
449471
uint8_t gacc[32];
450472
uint8_t tacc[32];
451-
uint8_t b[32];
473+
uint8_t b[CX_SHA256_SIZE];
452474
point_t R;
453-
uint8_t e[32];
475+
uint8_t e[CX_SHA256_SIZE];
454476

455477
int diff;
456478

@@ -460,8 +482,8 @@ int musig_sign(musig_secnonce_t *secnonce,
460482

461483
uint8_t k_1[32];
462484
uint8_t k_2[32];
463-
memcpy(k_1, secnonce->k_1, 32);
464-
memcpy(k_2, secnonce->k_2, 32);
485+
memcpy(k_1, secnonce->k_1, sizeof(k_1));
486+
memcpy(k_2, secnonce->k_2, sizeof(k_2));
465487

466488
// paranoia: since reusing nonces is catastrophic, we make sure that they are zeroed out and
467489
// work with a local copy instead
@@ -522,7 +544,7 @@ int musig_sign(musig_secnonce_t *secnonce,
522544
plain_pk_t pk;
523545
crypto_get_compressed_pubkey(secrets.P.raw, pk);
524546

525-
if (memcmp(pk, secnonce->pk, 33) != 0) {
547+
if (memcmp(pk, secnonce->pk, sizeof(pk)) != 0) {
526548
err = true;
527549
PRINTF("Public key does not match nonce_gen argument\n");
528550
break;

src/musig/musig.h

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@ typedef uint8_t xonly_pk_t[32];
1414

1515
// An uncompressed pubkey, encoded as 04||x||y, where x and y are 32-byte big-endian coordinates.
1616
// If the first byte (prefix) is 0, encodes the point at infinity.
17-
typedef struct {
18-
union {
19-
uint8_t raw[65];
20-
struct {
21-
uint8_t prefix; // 0 for the point at infinity, otherwise 4.
22-
uint8_t x[32];
23-
uint8_t y[32];
24-
};
25-
};
17+
typedef union {
18+
uint8_t raw[65];
19+
struct {
20+
uint8_t prefix; // 0 for the point at infinity, otherwise 4.
21+
uint8_t x[32];
22+
uint8_t y[32];
23+
} __attribute__((packed));
2624
} point_t;
2725

2826
typedef struct musig_keyagg_context_s {
@@ -37,14 +35,12 @@ typedef struct musig_secnonce_s {
3735
uint8_t pk[33];
3836
} musig_secnonce_t;
3937

40-
typedef struct musig_pubnonce_s {
41-
union {
42-
struct {
43-
uint8_t R_s1[33];
44-
uint8_t R_s2[33];
45-
};
46-
uint8_t raw[66];
47-
};
38+
typedef union {
39+
struct {
40+
uint8_t R_s1[33];
41+
uint8_t R_s2[33];
42+
} __attribute__((packed));
43+
uint8_t raw[66];
4844
} musig_pubnonce_t;
4945

5046
typedef struct musig_session_context_s {
@@ -83,6 +79,8 @@ int musig_key_agg(const plain_pk_t pubkeys[], size_t n_keys, musig_keyagg_contex
8379
*
8480
* @param[in] rand
8581
* The randomness to use.
82+
* @param[in] rand_len
83+
* The length of the randomness.
8684
* @param[in] pk
8785
* The 33-byte public key of the signer.
8886
* @param[in] aggpk
@@ -94,7 +92,8 @@ int musig_key_agg(const plain_pk_t pubkeys[], size_t n_keys, musig_keyagg_contex
9492
*
9593
* @return 0 on success, a negative number in case of error.
9694
*/
97-
int musig_nonce_gen(const uint8_t rand[32],
95+
int musig_nonce_gen(const uint8_t *rand,
96+
size_t rand_len,
9897
const plain_pk_t pk,
9998
const xonly_pk_t aggpk,
10099
musig_secnonce_t *secnonce,

src/musig/musig_sessions.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,12 @@ const musig_psbt_session_t *musigsession_round2_initialize(
132132

133133
void musigsession_commit(musig_signing_state_t *musig_signing_state) {
134134
uint8_t acc = 0;
135-
for (size_t i = 0; i < sizeof(musig_signing_state->_round1); i++) {
135+
for (size_t i = 0; i < sizeof(musig_signing_state->_round1._id); i++) {
136136
acc |= musig_signing_state->_round1._id[i];
137137
}
138138
// If round 1 was not executed, then there is nothing to store.
139-
// This assumes that musigsession_initialize_signing_state, therefore the field is zeroed out
140-
// if it wasn't used.
139+
// This assumes that musigsession_initialize_signing_state zeroes the id, therefore the field is
140+
// zeroed out if and only if it wasn't used.
141141
if (acc != 0) {
142142
musigsession_store(musig_signing_state->_round1._id, &musig_signing_state->_round1);
143143
}

0 commit comments

Comments
 (0)