@@ -14,54 +14,133 @@ extern "C" {
14
14
15
15
* This module implements a modified version of Flexible Round-Optimized
16
16
* Schnorr Threshold Signatures (FROST) by Chelsea Komlo and Ian Goldberg
17
- * (https://crysp.uwaterloo.ca/software/frost/).
17
+ * (https://crysp.uwaterloo.ca/software/frost/). Signatures are compatible with
18
+ * BIP-340 ("Schnorr"). There's an example C source file in the module's
19
+ * directory (examples/frost.c) that demonstrates how it can be used.
20
+ *
21
+ * Following the convention used in the MuSig module, the API uses the singular
22
+ * term "nonce" to refer to the two "nonces" used by the FROST scheme.
23
+ */
24
+
25
+ /** Opaque data structures
26
+ *
27
+ * The exact representation of data inside is implementation defined and not
28
+ * guaranteed to be portable between different platforms or versions. If you
29
+ * need to convert to a format suitable for storage, transmission, or
30
+ * comparison, use the corresponding serialization and parsing functions.
18
31
*/
19
32
20
- /** A FROST secret share. Created with `secp256k1_frost_share_gen` for a
21
- * specific set of signers. Secret shares should *never* be reused across
22
- * multiple signer sets.
33
+ /** Opaque data structure that holds the y-coordinate of a polynomial share.
23
34
*
24
- * This data structure is guaranteed to be a 32-byte byte array; it is a
25
- * separate type from ordinary secret keys to help prevent API users confusing
26
- * shares with complete keys or using the non-FROST API in place of the FROST
27
- * API, which would result in mysteriously invalid signatures being produced.
35
+ * Guaranteed to be 32 bytes in size. It can be safely copied/moved.
28
36
*/
29
37
typedef struct {
30
38
unsigned char data [32 ];
31
39
} secp256k1_frost_share ;
32
40
41
+ /** Opaque data structure that holds a signer's _secret_ nonce.
42
+ *
43
+ * Guaranteed to be 68 bytes in size.
44
+ *
45
+ * WARNING: This structure MUST NOT be copied or read or written to directly. A
46
+ * signer who is online throughout the whole process and can keep this
47
+ * structure in memory can use the provided API functions for a safe standard
48
+ * workflow. See
49
+ * https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ for
50
+ * more details about the risks associated with serializing or deserializing
51
+ * this structure.
52
+ *
53
+ * We repeat, copying this data structure can result in nonce reuse which will
54
+ * leak the secret signing key.
55
+ */
33
56
typedef struct {
34
57
unsigned char data [68 ];
35
58
} secp256k1_frost_secnonce ;
36
59
60
+ /* TODO: add `frost_pubnonce_parse` */
61
+ /** Opaque data structure that holds a signer's public nonce.
62
+ *
63
+ * Guaranteed to be 134 bytes in size. It can be safely copied/moved. Serialized
64
+ * and parsed with `frost_pubnonce_serialize` and `frost_pubnonce_parse`.
65
+ */
37
66
typedef struct {
38
67
unsigned char data [134 ];
39
68
} secp256k1_frost_pubnonce ;
40
69
70
+ /* TODO: add `frost_aggnonce_parse` */
71
+ /** Opaque data structure that holds an aggregate public nonce.
72
+ *
73
+ * Guaranteed to be 132 bytes in size. It can be safely copied/moved.
74
+ * Serialized and parsed with `frost_aggnonce_serialize` and
75
+ * `frost_aggnonce_parse`.
76
+ */
41
77
typedef struct {
42
78
unsigned char data [132 ];
43
79
} secp256k1_frost_aggnonce ;
44
80
81
+ /** Opaque data structure that holds a FROST session.
82
+ *
83
+ * This structure is not required to be kept secret for the signing protocol to
84
+ * be secure. Guaranteed to be 133 bytes in size. It can be safely
85
+ * copied/moved. No serialization and parsing functions.
86
+ */
45
87
typedef struct {
46
88
unsigned char data [133 ];
47
89
} secp256k1_frost_session ;
48
90
91
+ /** Opaque data structure that holds a partial MuSig signature.
92
+ *
93
+ * Guaranteed to be 36 bytes in size. Serialized and parsed with
94
+ * `frost_partial_sig_serialize` and `frost_partial_sig_parse`.
95
+ */
49
96
typedef struct {
50
97
unsigned char data [36 ];
51
98
} secp256k1_frost_partial_sig ;
52
99
100
+ /** Serialize a signer's public nonce
101
+ *
102
+ * Returns: 1 when the nonce could be serialized, 0 otherwise
103
+ * Args: ctx: a secp256k1 context object
104
+ * Out: out66: pointer to a 66-byte array to store the serialized nonce
105
+ * In: nonce: pointer to the nonce
106
+ */
53
107
SECP256K1_API int secp256k1_frost_pubnonce_serialize (
54
108
const secp256k1_context * ctx ,
55
109
unsigned char * out66 ,
56
110
const secp256k1_frost_pubnonce * nonce
57
111
) SECP256K1_ARG_NONNULL (1 ) SECP256K1_ARG_NONNULL (2 ) SECP256K1_ARG_NONNULL (3 );
58
112
113
+ /** Serialize an aggregate public nonce
114
+ *
115
+ * Returns: 1 when the nonce could be serialized, 0 otherwise
116
+ * Args: ctx: a secp256k1 context object
117
+ * Out: out66: pointer to a 66-byte array to store the serialized nonce
118
+ * In: nonce: pointer to the nonce
119
+ */
59
120
SECP256K1_API int secp256k1_frost_aggnonce_serialize (
60
121
const secp256k1_context * ctx ,
61
122
unsigned char * out66 ,
62
123
const secp256k1_frost_aggnonce * nonce
63
124
) SECP256K1_ARG_NONNULL (1 ) SECP256K1_ARG_NONNULL (2 ) SECP256K1_ARG_NONNULL (3 );
64
125
126
+ /** Derives polynomial shares and their coefficient commitments
127
+ *
128
+ * The shares are derived deterministically from the input parameters. The
129
+ * private key belonging to the keypair will be used as the first coefficient
130
+ * of the polynomial used to generate the shares and commitments.
131
+ *
132
+ * Returns: 0 if the arguments are invalid, 1 otherwise
133
+ * Args: ctx: pointer to a context object initialized for verification
134
+ * Out: pubcoeff: the coefficient commitments. The length of this array
135
+ * should be equal to the threshold.
136
+ * shares: the polynomial shares. The length of this array should be
137
+ * equal to n_participants.
138
+ * In: threshold: the minimum number of shares required to produce a
139
+ * signature
140
+ * n_participants: the total number of shares to be generated
141
+ * keypair: pointer to a keypair used to generate the polynomial that
142
+ * derives the shares
143
+ */
65
144
SECP256K1_API int secp256k1_frost_share_gen (
66
145
const secp256k1_context * ctx ,
67
146
secp256k1_pubkey * pubcoeff ,
@@ -71,6 +150,34 @@ SECP256K1_API int secp256k1_frost_share_gen(
71
150
const secp256k1_keypair * keypair
72
151
) SECP256K1_ARG_NONNULL (1 ) SECP256K1_ARG_NONNULL (2 ) SECP256K1_ARG_NONNULL (3 ) SECP256K1_ARG_NONNULL (6 );
73
152
153
+ /** Aggregates shares
154
+ *
155
+ * As part of the key generation protocol, each participant receives a shares
156
+ * from each participant, including a share they "receive" from themselves.
157
+ * This function verifies those shares against their verifiable secret sharing
158
+ * ("VSS") commitments, aggregates the shares, and then aggregates the
159
+ * commitments to each participants first polynomial coefficient to derive the
160
+ * aggregate public key.
161
+ *
162
+ * This function outputs a vss_hash, which is a sha256 image of coefficient
163
+ * commitments of all participants. pubcoeffs must be sorted by participant
164
+ * index, otherwise the vss_hash generated will be invalid.
165
+ *
166
+ * Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
167
+ * the resulting signature verifies).
168
+ * Args: ctx: pointer to a context object
169
+ * Out: agg_share: the aggregated share
170
+ * agg_pk: the aggregated x-only public key
171
+ * vss_hash: sha256 image of the coefficient commitments
172
+ * In: shares: all polynomial shares for the partcipant's index
173
+ * pubcoeffs: coefficient commitments of all participants ordered by
174
+ * index
175
+ * n_shares: the total number of shares
176
+ * threshold: the minimum number of shares required to produce a
177
+ * signature
178
+ * idx: the index of the participant whose shares are being
179
+ * aggregated
180
+ */
74
181
SECP256K1_API int secp256k1_frost_share_agg (
75
182
const secp256k1_context * ctx ,
76
183
secp256k1_frost_share * agg_share ,
@@ -83,6 +190,49 @@ SECP256K1_API int secp256k1_frost_share_agg(
83
190
uint16_t idx
84
191
) SECP256K1_ARG_NONNULL (1 ) SECP256K1_ARG_NONNULL (2 ) SECP256K1_ARG_NONNULL (3 ) SECP256K1_ARG_NONNULL (4 ) SECP256K1_ARG_NONNULL (5 ) SECP256K1_ARG_NONNULL (6 );
85
192
193
+ /** Starts a signing session by generating a nonce
194
+ *
195
+ * This function outputs a secret nonce that will be required for signing and a
196
+ * corresponding public nonce that is intended to be sent to other signers.
197
+ *
198
+ * FROST, like MuSig, differs from regular Schnorr signing in that
199
+ * implementers _must_ take special care to not reuse a nonce. This can be
200
+ * ensured by following these rules:
201
+ *
202
+ * 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE
203
+ * REUSED in subsequent calls to this function.
204
+ * If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM
205
+ * AND KEPT SECRET (even from other signers). If you do provide a seckey,
206
+ * session_id32 can instead be a counter (that must never repeat!). However,
207
+ * it is recommended to always choose session_id32 uniformly at random.
208
+ * 2. If you already know the seckey, message or aggregate public key
209
+ * cache, they can be optionally provided to derive the nonce and increase
210
+ * misuse-resistance. The extra_input32 argument can be used to provide
211
+ * additional data that does not repeat in normal scenarios, such as the
212
+ * current time.
213
+ * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
214
+ * that it is used more than once for signing.
215
+ *
216
+ * Remember that nonce reuse will leak the secret key!
217
+ * Note that using the same agg_share for multiple FROST sessions is fine.
218
+ *
219
+ * Returns: 0 if the arguments are invalid and 1 otherwise
220
+ * Args: ctx: pointer to a context object, initialized for signing
221
+ * Out: secnonce: pointer to a structure to store the secret nonce
222
+ * pubnonce: pointer to a structure to store the public nonce
223
+ * In: session_id32: a 32-byte session_id32 as explained above. Must be
224
+ * unique to this call to secp256k1_frost_nonce_gen and
225
+ * must be uniformly random unless you really know what you
226
+ * are doing.
227
+ * idx: the index of the participant who is generating the nonce
228
+ * agg_share: the aggregated share that will later be used for
229
+ * signing, if already known (can be NULL)
230
+ * msg32: the 32-byte message that will later be signed, if
231
+ * already known (can be NULL)
232
+ * agg_pk: the FROST-aggregated public key
233
+ * extra_input32: an optional 32-byte array that is input to the nonce
234
+ * derivation function (can be NULL)
235
+ */
86
236
SECP256K1_API int secp256k1_frost_nonce_gen (
87
237
const secp256k1_context * ctx ,
88
238
secp256k1_frost_secnonce * secnonce ,
@@ -95,13 +245,47 @@ SECP256K1_API int secp256k1_frost_nonce_gen(
95
245
const unsigned char * extra_input32
96
246
) SECP256K1_ARG_NONNULL (1 ) SECP256K1_ARG_NONNULL (2 ) SECP256K1_ARG_NONNULL (3 ) SECP256K1_ARG_NONNULL (4 );
97
247
248
+ /** Aggregates the nonces of all signers into a single nonce
249
+ *
250
+ * This can be done by an untrusted party to reduce the communication
251
+ * between signers. Instead of everyone sending nonces to everyone else, there
252
+ * can be one party receiving all nonces, aggregating the nonces with this
253
+ * function and then sending only the aggregate nonce back to the signers.
254
+ *
255
+ * Returns: 0 if the arguments are invalid, 1 otherwise
256
+ * Args: ctx: pointer to a context object
257
+ * Out: aggnonce: pointer to an aggregate public nonce object for
258
+ * musig_nonce_process
259
+ * In: pubnonces: array of pointers to public nonces sent by the
260
+ * signers
261
+ * n_pubnonces: number of elements in the pubnonces array. Must be
262
+ * greater than 0.
263
+ */
98
264
SECP256K1_API int secp256k1_frost_nonce_agg (
99
265
const secp256k1_context * ctx ,
100
266
secp256k1_frost_aggnonce * aggnonce ,
101
267
const secp256k1_frost_pubnonce * const * pubnonces ,
102
268
uint16_t n_pubnonces
103
269
) SECP256K1_ARG_NONNULL (1 ) SECP256K1_ARG_NONNULL (2 ) SECP256K1_ARG_NONNULL (3 );
104
270
271
+ /** Takes the public nonces of all signers and computes a session that is
272
+ * required for signing and verification of partial signatures.
273
+ *
274
+ * Returns: 0 if the arguments are invalid or if some signer sent invalid
275
+ * pubnonces, 1 otherwise
276
+ * Args: ctx: pointer to a context object, initialized for
277
+ * verification
278
+ * Out: session: pointer to a struct to store the session
279
+ * In: aggnonce: pointer to an aggregate public nonce object that is the
280
+ * output of frost_nonce_agg
281
+ * pubnonces: array of pointers to public nonces sent by the signers
282
+ * n_pubnonces: number of elements in the pubnonces array. Must be
283
+ * greater than 0.
284
+ * msg32: the 32-byte message to sign
285
+ * agg_pk: the FROST-aggregated public key
286
+ * idx: the index of the participant who will use the session
287
+ * for signing
288
+ */
105
289
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_nonce_process (
106
290
const secp256k1_context * ctx ,
107
291
secp256k1_frost_session * session ,
@@ -113,6 +297,24 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_nonce_process(
113
297
uint16_t idx
114
298
) SECP256K1_ARG_NONNULL (1 ) SECP256K1_ARG_NONNULL (2 ) SECP256K1_ARG_NONNULL (3 ) SECP256K1_ARG_NONNULL (4 ) SECP256K1_ARG_NONNULL (6 ) SECP256K1_ARG_NONNULL (7 );
115
299
300
+ /** Produces a partial signature
301
+ *
302
+ * This function overwrites the given secnonce with zeros and will abort if given a
303
+ * secnonce that is all zeros. This is a best effort attempt to protect against nonce
304
+ * reuse. However, this is of course easily defeated if the secnonce has been
305
+ * copied (or serialized). Remember that nonce reuse will leak the secret key!
306
+ *
307
+ * Returns: 0 if the arguments are invalid or the provided secnonce has already
308
+ * been used for signing, 1 otherwise
309
+ * Args: ctx: pointer to a context object
310
+ * Out: partial_sig: pointer to struct to store the partial signature
311
+ * In/Out: secnonce: pointer to the secnonce struct created in
312
+ * frost_nonce_gen that has been never used in a
313
+ * partial_sign call before
314
+ * In: agg_share: the aggregated share
315
+ * session: pointer to the session that was created with
316
+ * frost_nonce_process
317
+ */
116
318
SECP256K1_API int secp256k1_frost_partial_sign (
117
319
const secp256k1_context * ctx ,
118
320
secp256k1_frost_partial_sig * partial_sig ,
@@ -121,6 +323,18 @@ SECP256K1_API int secp256k1_frost_partial_sign(
121
323
const secp256k1_frost_session * session
122
324
) SECP256K1_ARG_NONNULL (1 ) SECP256K1_ARG_NONNULL (2 ) SECP256K1_ARG_NONNULL (3 ) SECP256K1_ARG_NONNULL (4 ) SECP256K1_ARG_NONNULL (5 );
123
325
326
+ /** Aggregates partial signatures
327
+ *
328
+ * Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
329
+ * the resulting signature verifies).
330
+ * Args: ctx: pointer to a context object
331
+ * Out: sig64: complete (but possibly invalid) Schnorr signature
332
+ * In: session: pointer to the session that was created with
333
+ * frost_nonce_process
334
+ * partial_sigs: array of pointers to partial signatures to aggregate
335
+ * n_sigs: number of elements in the partial_sigs array. Must be
336
+ * greater than 0.
337
+ */
124
338
SECP256K1_API int secp256k1_frost_partial_sig_agg (
125
339
const secp256k1_context * ctx ,
126
340
unsigned char * sig64 ,
0 commit comments