Skip to content

Commit 9fa15f5

Browse files
committed
frost trusted dealer: nonce generation
This commits adds nonce generation, as well as serialization and parsing.
1 parent 3787674 commit 9fa15f5

File tree

11 files changed

+413
-29
lines changed

11 files changed

+413
-29
lines changed

include/secp256k1_frost.h

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ extern "C" {
1818
*
1919
* The module also supports BIP-341 ("Taproot") and BIP-32 ("ordinary") public
2020
* key tweaking.
21+
*
22+
* Following the convention used in the MuSig module, the API uses the singular
23+
* term "nonce" to refer to the two "nonces" used by the FROST scheme.
2124
*/
2225

2326
/** Opaque data structures
@@ -46,6 +49,61 @@ typedef struct {
4649
unsigned char data[36];
4750
} secp256k1_frost_share;
4851

52+
/** Opaque data structure that holds a signer's _secret_ nonce.
53+
*
54+
* Guaranteed to be 68 bytes in size.
55+
*
56+
* WARNING: This structure MUST NOT be copied or read or written to directly.
57+
* A signer who is online throughout the whole process and can keep this
58+
* structure in memory can use the provided API functions for a safe standard
59+
* workflow. See
60+
* https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ for
61+
* more details about the risks associated with serializing or deserializing
62+
* this structure.
63+
*
64+
* We repeat, copying this data structure can result in nonce reuse which will
65+
* leak the secret signing key.
66+
*/
67+
typedef struct {
68+
unsigned char data[68];
69+
} secp256k1_frost_secnonce;
70+
71+
/** Opaque data structure that holds a signer's public nonce.
72+
*
73+
* Guaranteed to be 132 bytes in size. It can be safely copied/moved.
74+
* Serialized and parsed with `frost_pubnonce_serialize` and
75+
* `frost_pubnonce_parse`.
76+
*/
77+
typedef struct {
78+
unsigned char data[132];
79+
} secp256k1_frost_pubnonce;
80+
81+
/** Parse a signer's public nonce.
82+
*
83+
* Returns: 1 when the nonce could be parsed, 0 otherwise.
84+
* Args: ctx: pointer to a context object
85+
* Out: nonce: pointer to a nonce object
86+
* In: in66: pointer to the 66-byte nonce to be parsed
87+
*/
88+
SECP256K1_API int secp256k1_frost_pubnonce_parse(
89+
const secp256k1_context *ctx,
90+
secp256k1_frost_pubnonce *nonce,
91+
const unsigned char *in66
92+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
93+
94+
/** Serialize a signer's public nonce
95+
*
96+
* Returns: 1 when the nonce could be serialized, 0 otherwise
97+
* Args: ctx: pointer to a context object
98+
* Out: out66: pointer to a 66-byte array to store the serialized nonce
99+
* In: nonce: pointer to the nonce
100+
*/
101+
SECP256K1_API int secp256k1_frost_pubnonce_serialize(
102+
const secp256k1_context *ctx,
103+
unsigned char *out66,
104+
const secp256k1_frost_pubnonce *nonce
105+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
106+
49107
/** Serialize a FROST share
50108
*
51109
* Returns: 1 when the share could be serialized, 0 otherwise
@@ -271,6 +329,61 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_pubkey_xonly_twea
271329
const unsigned char *tweak32
272330
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
273331

332+
/** Starts a signing session by generating a nonce
333+
*
334+
* This function outputs a secret nonce that will be required for signing and a
335+
* corresponding public nonce that is intended to be sent to other signers.
336+
*
337+
* FROST, like MuSig, differs from regular Schnorr signing in that
338+
* implementers _must_ take special care to not reuse a nonce. This can be
339+
* ensured by following these rules:
340+
*
341+
* 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE
342+
* REUSED in subsequent calls to this function.
343+
* If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM
344+
* AND KEPT SECRET (even from other signers). If you do provide a seckey,
345+
* session_id32 can instead be a counter (that must never repeat!). However,
346+
* it is recommended to always choose session_id32 uniformly at random.
347+
* 2. If you already know the seckey, message or group public key, they
348+
* can be optionally provided to derive the nonce and increase
349+
* misuse-resistance. The extra_input32 argument can be used to provide
350+
* additional data that does not repeat in normal scenarios, such as the
351+
* current time.
352+
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
353+
* that it is used more than once for signing.
354+
*
355+
* Remember that nonce reuse will leak the secret share!
356+
* Note that using the same agg_share for multiple FROST sessions is fine.
357+
*
358+
* Returns: 0 if the arguments are invalid and 1 otherwise
359+
* Args: ctx: pointer to a context object (not secp256k1_context_static)
360+
* Out: secnonce: pointer to a structure to store the secret nonce
361+
* pubnonce: pointer to a structure to store the public nonce
362+
* In: session_id32: a 32-byte session_id32 as explained above. Must be
363+
* unique to this call to secp256k1_frost_nonce_gen and
364+
* must be uniformly random unless you really know what you
365+
* are doing.
366+
* agg_share: the aggregated share that will later be used for
367+
* signing, if already known (can be NULL)
368+
* msg32: the 32-byte message that will later be signed, if
369+
* already known (can be NULL)
370+
* keygen_cache: pointer to the keygen_cache that was used to create the group
371+
* (and potentially tweaked) public key if already known
372+
* (can be NULL)
373+
* extra_input32: an optional 32-byte array that is input to the nonce
374+
* derivation function (can be NULL)
375+
*/
376+
SECP256K1_API int secp256k1_frost_nonce_gen(
377+
const secp256k1_context *ctx,
378+
secp256k1_frost_secnonce *secnonce,
379+
secp256k1_frost_pubnonce *pubnonce,
380+
const unsigned char *session_id32,
381+
const secp256k1_frost_share *agg_share,
382+
const unsigned char *msg32,
383+
const secp256k1_frost_keygen_cache *keygen_cache,
384+
const unsigned char *extra_input32
385+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
386+
274387
#ifdef __cplusplus
275388
}
276389
#endif

src/group.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,20 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
185185

186186
/** Convert a group element that is not infinity to a 64-byte array. The output
187187
* array is platform-dependent. */
188-
static void secp256k1_ge_to_bytes(unsigned char *buf, secp256k1_ge *a);
188+
static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a);
189189

190190
/** Convert a 64-byte array into group element. This function assumes that the
191191
* provided buffer correctly encodes a group element. */
192192
static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf);
193193

194+
/** Convert a group element (that is allowed to be infinity) to a 64-byte
195+
* array. The output array is platform-dependent. */
196+
static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge);
197+
198+
/** Convert a 64-byte array into a group element. This function assumes that the
199+
* provided buffer is the output of secp256k1_ge_to_bytes_ext. */
200+
static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data);
201+
194202
/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve.
195203
*
196204
* In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the

src/group_impl.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -965,7 +965,7 @@ static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp25
965965
return secp256k1_fe_is_square_var(&r);
966966
}
967967

968-
static void secp256k1_ge_to_bytes(unsigned char *buf, secp256k1_ge *a) {
968+
static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a) {
969969
secp256k1_ge_storage s;
970970

971971
/* We require that the secp256k1_ge_storage type is exactly 64 bytes.
@@ -985,4 +985,21 @@ static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) {
985985
secp256k1_ge_from_storage(r, &s);
986986
}
987987

988+
static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge) {
989+
if (secp256k1_ge_is_infinity(ge)) {
990+
memset(data, 0, 64);
991+
} else {
992+
secp256k1_ge_to_bytes(data, ge);
993+
}
994+
}
995+
996+
static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data) {
997+
unsigned char zeros[64] = { 0 };
998+
if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) {
999+
secp256k1_ge_set_infinity(ge);
1000+
} else {
1001+
secp256k1_ge_from_bytes(ge, data);
1002+
}
1003+
}
1004+
9881005
#endif /* SECP256K1_GROUP_IMPL_H */

src/modules/frost/Makefile.am.include

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ include_HEADERS += include/secp256k1_frost.h
22
noinst_HEADERS += src/modules/frost/main_impl.h
33
noinst_HEADERS += src/modules/frost/keygen.h
44
noinst_HEADERS += src/modules/frost/keygen_impl.h
5+
noinst_HEADERS += src/modules/frost/session.h
6+
noinst_HEADERS += src/modules/frost/session_impl.h

src/modules/frost/keygen.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,8 @@ typedef struct {
2222
int parity_acc;
2323
} secp256k1_keygen_cache_internal;
2424

25+
static int secp256k1_keygen_cache_load(const secp256k1_context* ctx, secp256k1_keygen_cache_internal *cache_i, const secp256k1_frost_keygen_cache *cache);
26+
27+
static int secp256k1_frost_share_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_frost_share* share);
28+
2529
#endif

src/modules/frost/main_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88
#define SECP256K1_MODULE_FROST_MAIN
99

1010
#include "keygen_impl.h"
11+
#include "session_impl.h"
1112

1213
#endif

src/modules/frost/session.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**********************************************************************
2+
* Copyright (c) 2021-2024 Jesse Posner *
3+
* Distributed under the MIT software license, see the accompanying *
4+
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
5+
**********************************************************************/
6+
7+
#ifndef SECP256K1_MODULE_FROST_SESSION_H
8+
#define SECP256K1_MODULE_FROST_SESSION_H
9+
10+
#include "../../../include/secp256k1.h"
11+
#include "../../../include/secp256k1_frost.h"
12+
13+
#endif

0 commit comments

Comments
 (0)