Skip to content

Commit ff4714e

Browse files
authored
Merge pull request BlockstreamResearch#105 from jonasnick/update-musig
MuSig state machine simplifictions, API improvements and taproot tweaking
2 parents 0d71b6c + 3fb4d6d commit ff4714e

File tree

6 files changed

+628
-407
lines changed

6 files changed

+628
-407
lines changed

.travis.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ env:
2222
- WIDEMUL=int64 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
2323
- WIDEMUL=int128 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
2424
- WIDEMUL=int64 RECOVERY=yes
25-
- WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes
25+
- WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
2626
- WIDEMUL=int128
27-
- WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes
27+
- WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
2828
- WIDEMUL=int128 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
2929
- WIDEMUL=int128 ASM=x86_64
3030
- BIGNUM=no
@@ -33,10 +33,10 @@ env:
3333
- BUILD=distcheck WITH_VALGRIND=no CTIMETEST=no BENCH=no
3434
- CPPFLAGS=-DDETERMINISTIC
3535
- CFLAGS=-O0 CTIMETEST=no
36-
- CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes CTIMETEST=no
36+
- CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=no
3737
- ECMULTGENPRECISION=2
3838
- ECMULTGENPRECISION=8
39-
- RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes EXTRAFLAGS="--disable-openssl-tests" BUILD=
39+
- RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes EXTRAFLAGS="--disable-openssl-tests" BUILD=
4040
matrix:
4141
fast_finish: true
4242
include:
@@ -84,7 +84,7 @@ matrix:
8484
- libc6-dbg:i386
8585
# S390x build (big endian system)
8686
- compiler: gcc
87-
env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes CTIMETEST=
87+
env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=
8888
arch: s390x
8989

9090
# We use this to install macOS dependencies instead of the built in `homebrew` plugin,

include/secp256k1_musig.h

+107-55
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,25 @@ extern "C" {
2020
*/
2121

2222
/** Data structure containing auxiliary data generated in `pubkey_combine` and
23-
* required for `session_*_initialize`.
23+
* required for `session_*_init`.
2424
* Fields:
25-
* magic: Set during initialization in `pubkey_combine` in order to allow
26-
* detecting an uninitialized object.
27-
* pk_hash: The 32-byte hash of the original public keys
28-
* is_negated: Whether the MuSig-aggregated point was negated when
29-
* converting it to the combined xonly pubkey.
25+
* magic: Set during initialization in `pubkey_combine` to allow
26+
* detecting an uninitialized object.
27+
* pk_hash: The 32-byte hash of the original public keys
28+
* pk_parity: Whether the MuSig-aggregated point was negated when
29+
* converting it to the combined xonly pubkey.
30+
* is_tweaked: Whether the combined pubkey was tweaked
31+
* tweak: If is_tweaked, array with the 32-byte tweak
32+
* internal_key_parity: If is_tweaked, the parity of the combined pubkey
33+
* before tweaking
3034
*/
3135
typedef struct {
3236
uint64_t magic;
3337
unsigned char pk_hash[32];
34-
int is_negated;
38+
int pk_parity;
39+
int is_tweaked;
40+
unsigned char tweak[32];
41+
int internal_key_parity;
3542
} secp256k1_musig_pre_session;
3643

3744
/** Data structure containing data related to a signing session resulting in a single
@@ -45,49 +52,49 @@ typedef struct {
4552
* structure.
4653
*
4754
* Fields:
48-
* combined_pk: MuSig-computed combined xonly public key
55+
* magic: Set in `musig_session_init` to allow detecting an
56+
* uninitialized object.
57+
* round: Current round of the session
4958
* pre_session: Auxiliary data created in `pubkey_combine`
59+
* combined_pk: MuSig-computed combined xonly public key
5060
* n_signers: Number of signers
51-
* combined_nonce: Summed combined public nonce (undefined if `nonce_is_set` is false)
52-
* nonce_is_set: Whether the above nonce has been set
53-
* nonce_is_negated: If `nonce_is_set`, whether the above nonce was negated after
54-
* summing the participants' nonces. Needed to ensure the nonce's y
55-
* coordinate is even.
5661
* msg: The 32-byte message (hash) to be signed
57-
* msg_is_set: Whether the above message has been set
62+
* is_msg_set: Whether the above message has been set
5863
* has_secret_data: Whether this session object has a signers' secret data; if this
5964
* is `false`, it may still be used for verification purposes.
6065
* seckey: If `has_secret_data`, the signer's secret key
6166
* secnonce: If `has_secret_data`, the signer's secret nonce
6267
* nonce: If `has_secret_data`, the signer's public nonce
63-
* nonce_commitments_hash: If `has_secret_data` and `nonce_commitments_hash_is_set`,
64-
* the hash of all signers' commitments
65-
* nonce_commitments_hash_is_set: If `has_secret_data`, whether the
66-
* nonce_commitments_hash has been set
68+
* nonce_commitments_hash: If `has_secret_data` and round >= 1, the hash of all
69+
* signers' commitments
70+
* combined_nonce: If round >= 2, the summed combined public nonce
71+
* combined_nonce_parity: If round >= 2, the parity of the Y coordinate of above
72+
* nonce.
6773
*/
6874
typedef struct {
69-
secp256k1_xonly_pubkey combined_pk;
75+
uint64_t magic;
76+
int round;
7077
secp256k1_musig_pre_session pre_session;
78+
secp256k1_xonly_pubkey combined_pk;
7179
uint32_t n_signers;
72-
secp256k1_pubkey combined_nonce;
73-
int nonce_is_set;
74-
int nonce_is_negated;
80+
int is_msg_set;
7581
unsigned char msg[32];
76-
int msg_is_set;
7782
int has_secret_data;
7883
unsigned char seckey[32];
7984
unsigned char secnonce[32];
80-
secp256k1_pubkey nonce;
85+
secp256k1_xonly_pubkey nonce;
86+
int partial_nonce_parity;
8187
unsigned char nonce_commitments_hash[32];
82-
int nonce_commitments_hash_is_set;
88+
secp256k1_xonly_pubkey combined_nonce;
89+
int combined_nonce_parity;
8390
} secp256k1_musig_session;
8491

8592
/** Data structure containing data on all signers in a single session.
8693
*
8794
* The workflow for this structure is as follows:
8895
*
89-
* 1. This structure is initialized with `musig_session_initialize` or
90-
* `musig_session_initialize_verifier`, which set the `index` field, and zero out
96+
* 1. This structure is initialized with `musig_session_init` or
97+
* `musig_session_init_verifier`, which set the `index` field, and zero out
9198
* all other fields. The public session is initialized with the signers'
9299
* nonce_commitments.
93100
*
@@ -112,7 +119,7 @@ typedef struct {
112119
typedef struct {
113120
int present;
114121
uint32_t index;
115-
secp256k1_pubkey nonce;
122+
secp256k1_xonly_pubkey nonce;
116123
unsigned char nonce_commitment[32];
117124
} secp256k1_musig_session_signer_data;
118125

@@ -129,7 +136,8 @@ typedef struct {
129136
unsigned char data[32];
130137
} secp256k1_musig_partial_signature;
131138

132-
/** Computes a combined public key and the hash of the given public keys
139+
/** Computes a combined public key and the hash of the given public keys.
140+
* Different orders of `pubkeys` result in different `combined_pk`s.
133141
*
134142
* Returns: 1 if the public keys were successfully combined, 0 otherwise
135143
* Args: ctx: pointer to a context object initialized for verification
@@ -138,11 +146,11 @@ typedef struct {
138146
* multiexponentiation. If NULL, an inefficient algorithm is used.
139147
* Out: combined_pk: the MuSig-combined xonly public key (cannot be NULL)
140148
* pre_session: if non-NULL, pointer to a musig_pre_session struct to be used in
141-
* `musig_session_initialize`.
149+
* `musig_session_init` or `musig_pubkey_tweak_add`.
142150
* In: pubkeys: input array of public keys to combine. The order is important;
143151
* a different order will result in a different combined public
144152
* key (cannot be NULL)
145-
* n_pubkeys: length of pubkeys array
153+
* n_pubkeys: length of pubkeys array. Must be greater than 0.
146154
*/
147155
SECP256K1_API int secp256k1_musig_pubkey_combine(
148156
const secp256k1_context* ctx,
@@ -153,6 +161,42 @@ SECP256K1_API int secp256k1_musig_pubkey_combine(
153161
size_t n_pubkeys
154162
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
155163

164+
/** Tweak an x-only public key by adding the generator multiplied with tweak32
165+
* to it. The resulting output_pubkey with the given internal_pubkey and tweak
166+
* passes `secp256k1_xonly_pubkey_tweak_test`.
167+
*
168+
* This function is only useful before initializing a signing session. If you
169+
* are only computing a public key, but not intending to create a signature for
170+
* it, you can just use `secp256k1_xonly_pubkey_tweak_add`. Can only be called
171+
* once with a given pre_session.
172+
*
173+
* Returns: 0 if the arguments are invalid or the resulting public key would be
174+
* invalid (only when the tweak is the negation of the corresponding
175+
* secret key). 1 otherwise.
176+
* Args: ctx: pointer to a context object initialized for verification
177+
* (cannot be NULL)
178+
* pre_session: pointer to a `musig_pre_session` struct initialized in
179+
* `musig_pubkey_combine` (cannot be NULL)
180+
* Out: output_pubkey: pointer to a public key to store the result. Will be set
181+
* to an invalid value if this function returns 0 (cannot
182+
* be NULL)
183+
* In: internal_pubkey: pointer to the `combined_pk` from
184+
* `musig_pubkey_combine` to which the tweak is applied.
185+
* (cannot be NULL).
186+
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
187+
* according to secp256k1_ec_seckey_verify, this function
188+
* returns 0. For uniformly random 32-byte arrays the
189+
* chance of being invalid is negligible (around 1 in
190+
* 2^128) (cannot be NULL).
191+
*/
192+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_tweak_add(
193+
const secp256k1_context* ctx,
194+
secp256k1_musig_pre_session *pre_session,
195+
secp256k1_pubkey *output_pubkey,
196+
const secp256k1_xonly_pubkey *internal_pubkey,
197+
const unsigned char *tweak32
198+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
199+
156200
/** Initializes a signing session for a signer
157201
*
158202
* Returns: 1: session is successfully initialized
@@ -172,14 +216,16 @@ SECP256K1_API int secp256k1_musig_pubkey_combine(
172216
* because it reduces nonce misuse resistance. If NULL, must be
173217
* set with `musig_session_get_public_nonce`.
174218
* combined_pk: the combined xonly public key of all signers (cannot be NULL)
175-
* pre_session: pointer to a musig_pre_session struct from
176-
* `musig_pubkey_combine` (cannot be NULL)
219+
* pre_session: pointer to a musig_pre_session struct after initializing
220+
* it with `musig_pubkey_combine` and optionally provided to
221+
* `musig_pubkey_tweak_add` (cannot be NULL).
177222
* n_signers: length of signers array. Number of signers participating in
178223
* the MuSig. Must be greater than 0 and at most 2^32 - 1.
179-
* my_index: index of this signer in the signers array
224+
* my_index: index of this signer in the signers array. Must be less
225+
* than `n_signers`.
180226
* seckey: the signer's 32-byte secret key (cannot be NULL)
181227
*/
182-
SECP256K1_API int secp256k1_musig_session_initialize(
228+
SECP256K1_API int secp256k1_musig_session_init(
183229
const secp256k1_context* ctx,
184230
secp256k1_musig_session *session,
185231
secp256k1_musig_session_signer_data *signers,
@@ -193,28 +239,33 @@ SECP256K1_API int secp256k1_musig_session_initialize(
193239
const unsigned char *seckey
194240
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(11);
195241

196-
/** Gets the signer's public nonce given a list of all signers' data with commitments
242+
/** Gets the signer's public nonce given a list of all signers' data with
243+
* commitments. Called by participating signers after
244+
* `secp256k1_musig_session_init` and after all nonce commitments have
245+
* been collected
197246
*
198247
* Returns: 1: public nonce is written in nonce
199248
* 0: signer data is missing commitments or session isn't initialized
200249
* for signing
201250
* Args: ctx: pointer to a context object (cannot be NULL)
202251
* session: the signing session to get the nonce from (cannot be NULL)
203252
* signers: an array of signers' data initialized with
204-
* `musig_session_initialize`. Array length must equal to
253+
* `musig_session_init`. Array length must equal to
205254
* `n_commitments` (cannot be NULL)
206-
* Out: nonce: the nonce (cannot be NULL)
207-
* In: commitments: array of 32-byte nonce commitments (cannot be NULL)
255+
* Out: nonce32: filled with a 32-byte public nonce which is supposed to be
256+
* sent to the other signers and then used in `musig_set nonce`
257+
* (cannot be NULL)
258+
* In: commitments: array of pointers to 32-byte nonce commitments (cannot be NULL)
208259
* n_commitments: the length of commitments and signers array. Must be the total
209260
* number of signers participating in the MuSig.
210261
* msg32: the 32-byte message to be signed. Must be NULL if already
211-
* set with `musig_session_initialize` otherwise can not be NULL.
262+
* set with `musig_session_init` otherwise can not be NULL.
212263
*/
213264
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_public_nonce(
214265
const secp256k1_context* ctx,
215266
secp256k1_musig_session *session,
216267
secp256k1_musig_session_signer_data *signers,
217-
secp256k1_pubkey *nonce,
268+
unsigned char *nonce32,
218269
const unsigned char *const *commitments,
219270
size_t n_commitments,
220271
const unsigned char *msg32
@@ -234,13 +285,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_publi
234285
* pre_session: pointer to a musig_pre_session struct from
235286
* `musig_pubkey_combine` (cannot be NULL)
236287
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be NULL)
237-
* commitments: array of 32-byte nonce commitments. Array length must equal to
238-
* `n_signers` (cannot be NULL)
288+
* commitments: array of pointers to 32-byte nonce commitments. Array
289+
* length must equal to `n_signers` (cannot be NULL)
239290
* n_signers: length of signers and commitments array. Number of signers
240291
* participating in the MuSig. Must be greater than 0 and at most
241292
* 2^32 - 1.
242293
*/
243-
SECP256K1_API int secp256k1_musig_session_initialize_verifier(
294+
SECP256K1_API int secp256k1_musig_session_init_verifier(
244295
const secp256k1_context* ctx,
245296
secp256k1_musig_session *session,
246297
secp256k1_musig_session_signer_data *signers,
@@ -259,13 +310,13 @@ SECP256K1_API int secp256k1_musig_session_initialize_verifier(
259310
* Args: ctx: pointer to a context object (cannot be NULL)
260311
* signer: pointer to the signer data to update (cannot be NULL). Must have
261312
* been used with `musig_session_get_public_nonce` or initialized
262-
* with `musig_session_initialize_verifier`.
263-
* In: nonce: signer's alleged public nonce (cannot be NULL)
313+
* with `musig_session_init_verifier`.
314+
* In: nonce32: signer's alleged public nonce (cannot be NULL)
264315
*/
265316
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce(
266317
const secp256k1_context* ctx,
267318
secp256k1_musig_session_signer_data *signer,
268-
const secp256k1_pubkey *nonce
319+
const unsigned char *nonce32
269320
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
270321

271322
/** Updates a session with the combined public nonce of all signers. The combined
@@ -281,8 +332,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce(
281332
* (cannot be NULL)
282333
* n_signers: the length of the signers array. Must be the total number of
283334
* signers participating in the MuSig.
284-
* Out: nonce_is_negated: a pointer to an integer that indicates if the combined
285-
* public nonce had to be negated.
335+
* Out: nonce_parity: if non-NULL, a pointer to an integer that indicates the
336+
* parity of the combined public nonce. Used for adaptor
337+
* signatures.
286338
* adaptor: point to add to the combined public nonce. If NULL, nothing is
287339
* added to the combined nonce.
288340
*/
@@ -291,7 +343,7 @@ SECP256K1_API int secp256k1_musig_session_combine_nonces(
291343
secp256k1_musig_session *session,
292344
const secp256k1_musig_session_signer_data *signers,
293345
size_t n_signers,
294-
int *nonce_is_negated,
346+
int *nonce_parity,
295347
const secp256k1_pubkey *adaptor
296348
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
297349

@@ -369,7 +421,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif
369421
*
370422
* Returns: 1: all partial signatures have values in range. Does NOT mean the
371423
* resulting signature verifies.
372-
* 0: some partial signature had s/r out of range
424+
* 0: some partial signature are missing or had s or r out of range
373425
* Args: ctx: pointer to a context object (cannot be NULL)
374426
* session: initialized session for which the combined nonce has been
375427
* computed (cannot be NULL)
@@ -395,14 +447,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combi
395447
* In: partial_sig: partial signature to tweak with secret adaptor (cannot be NULL)
396448
* sec_adaptor32: 32-byte secret adaptor to add to the partial signature (cannot
397449
* be NULL)
398-
* nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces`
450+
* nonce_parity: the `nonce_parity` output of `musig_session_combine_nonces`
399451
*/
400452
SECP256K1_API int secp256k1_musig_partial_sig_adapt(
401453
const secp256k1_context* ctx,
402454
secp256k1_musig_partial_signature *adaptor_sig,
403455
const secp256k1_musig_partial_signature *partial_sig,
404456
const unsigned char *sec_adaptor32,
405-
int nonce_is_negated
457+
int nonce_parity
406458
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
407459

408460
/** Extracts a secret adaptor from a MuSig, given all parties' partial
@@ -418,15 +470,15 @@ SECP256K1_API int secp256k1_musig_partial_sig_adapt(
418470
* In: sig64: complete 2-of-2 signature (cannot be NULL)
419471
* partial_sigs: array of partial signatures (cannot be NULL)
420472
* n_partial_sigs: number of elements in partial_sigs array
421-
* nonce_is_negated: the `nonce_is_negated` output of `musig_session_combine_nonces`
473+
* nonce_parity: the `nonce_parity` output of `musig_session_combine_nonces`
422474
*/
423475
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor(
424476
const secp256k1_context* ctx,
425477
unsigned char *sec_adaptor32,
426478
const unsigned char *sig64,
427479
const secp256k1_musig_partial_signature *partial_sigs,
428480
size_t n_partial_sigs,
429-
int nonce_is_negated
481+
int nonce_parity
430482
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
431483

432484
#ifdef __cplusplus

0 commit comments

Comments
 (0)