Skip to content

Commit 959f4f0

Browse files
committed
Add API documentation
1 parent 7d11b73 commit 959f4f0

File tree

1 file changed

+222
-8
lines changed

1 file changed

+222
-8
lines changed

include/secp256k1_frost.h

+222-8
Original file line numberDiff line numberDiff line change
@@ -14,54 +14,133 @@ extern "C" {
1414
1515
* This module implements a modified version of Flexible Round-Optimized
1616
* 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.
1831
*/
1932

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.
2334
*
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.
2836
*/
2937
typedef struct {
3038
unsigned char data[32];
3139
} secp256k1_frost_share;
3240

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+
*/
3356
typedef struct {
3457
unsigned char data[68];
3558
} secp256k1_frost_secnonce;
3659

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+
*/
3766
typedef struct {
3867
unsigned char data[134];
3968
} secp256k1_frost_pubnonce;
4069

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+
*/
4177
typedef struct {
4278
unsigned char data[132];
4379
} secp256k1_frost_aggnonce;
4480

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+
*/
4587
typedef struct {
4688
unsigned char data[133];
4789
} secp256k1_frost_session;
4890

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+
*/
4996
typedef struct {
5097
unsigned char data[36];
5198
} secp256k1_frost_partial_sig;
5299

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+
*/
53107
SECP256K1_API int secp256k1_frost_pubnonce_serialize(
54108
const secp256k1_context* ctx,
55109
unsigned char *out66,
56110
const secp256k1_frost_pubnonce* nonce
57111
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
58112

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+
*/
59120
SECP256K1_API int secp256k1_frost_aggnonce_serialize(
60121
const secp256k1_context* ctx,
61122
unsigned char *out66,
62123
const secp256k1_frost_aggnonce* nonce
63124
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
64125

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+
*/
65144
SECP256K1_API int secp256k1_frost_share_gen(
66145
const secp256k1_context *ctx,
67146
secp256k1_pubkey *pubcoeff,
@@ -71,6 +150,34 @@ SECP256K1_API int secp256k1_frost_share_gen(
71150
const secp256k1_keypair *keypair
72151
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(6);
73152

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+
*/
74181
SECP256K1_API int secp256k1_frost_share_agg(
75182
const secp256k1_context* ctx,
76183
secp256k1_frost_share *agg_share,
@@ -83,6 +190,49 @@ SECP256K1_API int secp256k1_frost_share_agg(
83190
uint16_t idx
84191
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
85192

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+
*/
86236
SECP256K1_API int secp256k1_frost_nonce_gen(
87237
const secp256k1_context* ctx,
88238
secp256k1_frost_secnonce *secnonce,
@@ -95,13 +245,47 @@ SECP256K1_API int secp256k1_frost_nonce_gen(
95245
const unsigned char *extra_input32
96246
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
97247

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+
*/
98264
SECP256K1_API int secp256k1_frost_nonce_agg(
99265
const secp256k1_context* ctx,
100266
secp256k1_frost_aggnonce *aggnonce,
101267
const secp256k1_frost_pubnonce * const* pubnonces,
102268
uint16_t n_pubnonces
103269
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
104270

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+
*/
105289
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_nonce_process(
106290
const secp256k1_context* ctx,
107291
secp256k1_frost_session *session,
@@ -113,6 +297,24 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_nonce_process(
113297
uint16_t idx
114298
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
115299

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+
*/
116318
SECP256K1_API int secp256k1_frost_partial_sign(
117319
const secp256k1_context* ctx,
118320
secp256k1_frost_partial_sig *partial_sig,
@@ -121,6 +323,18 @@ SECP256K1_API int secp256k1_frost_partial_sign(
121323
const secp256k1_frost_session *session
122324
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
123325

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+
*/
124338
SECP256K1_API int secp256k1_frost_partial_sig_agg(
125339
const secp256k1_context* ctx,
126340
unsigned char *sig64,

0 commit comments

Comments
 (0)