frost: nonce generation
This commits adds nonce generation, as well as serialization and parsing.
This commit is contained in:
parent
197fb7efb9
commit
f606507120
@ -15,6 +15,9 @@ extern "C" {
|
|||||||
* This module implements a variant of Flexible Round-Optimized Schnorr
|
* This module implements a variant of Flexible Round-Optimized Schnorr
|
||||||
* Threshold Signatures (FROST) by Chelsea Komlo and Ian Goldberg
|
* Threshold Signatures (FROST) by Chelsea Komlo and Ian Goldberg
|
||||||
* (https://crysp.uwaterloo.ca/software/frost/).
|
* (https://crysp.uwaterloo.ca/software/frost/).
|
||||||
|
*
|
||||||
|
* Following the convention used in the MuSig module, the API uses the singular
|
||||||
|
* term "nonce" to refer to the two "nonces" used by the FROST scheme.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Opaque data structures
|
/** Opaque data structures
|
||||||
@ -34,6 +37,61 @@ typedef struct {
|
|||||||
unsigned char data[36];
|
unsigned char data[36];
|
||||||
} secp256k1_frost_share;
|
} secp256k1_frost_share;
|
||||||
|
|
||||||
|
/** Opaque data structure that holds a signer's _secret_ nonce.
|
||||||
|
*
|
||||||
|
* Guaranteed to be 68 bytes in size.
|
||||||
|
*
|
||||||
|
* WARNING: This structure MUST NOT be copied or read or written to directly.
|
||||||
|
* A signer who is online throughout the whole process and can keep this
|
||||||
|
* structure in memory can use the provided API functions for a safe standard
|
||||||
|
* workflow. See
|
||||||
|
* https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ for
|
||||||
|
* more details about the risks associated with serializing or deserializing
|
||||||
|
* this structure.
|
||||||
|
*
|
||||||
|
* We repeat, copying this data structure can result in nonce reuse which will
|
||||||
|
* leak the secret signing key.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned char data[68];
|
||||||
|
} secp256k1_frost_secnonce;
|
||||||
|
|
||||||
|
/** Opaque data structure that holds a signer's public nonce.
|
||||||
|
*
|
||||||
|
* Guaranteed to be 132 bytes in size. It can be safely copied/moved.
|
||||||
|
* Serialized and parsed with `frost_pubnonce_serialize` and
|
||||||
|
* `frost_pubnonce_parse`.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned char data[132];
|
||||||
|
} secp256k1_frost_pubnonce;
|
||||||
|
|
||||||
|
/** Parse a signer's public nonce.
|
||||||
|
*
|
||||||
|
* Returns: 1 when the nonce could be parsed, 0 otherwise.
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: nonce: pointer to a nonce object
|
||||||
|
* In: in66: pointer to the 66-byte nonce to be parsed
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_frost_pubnonce_parse(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_frost_pubnonce *nonce,
|
||||||
|
const unsigned char *in66
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
|
/** Serialize a signer's public nonce
|
||||||
|
*
|
||||||
|
* Returns: 1 when the nonce could be serialized, 0 otherwise
|
||||||
|
* Args: ctx: pointer to a context object
|
||||||
|
* Out: out66: pointer to a 66-byte array to store the serialized nonce
|
||||||
|
* In: nonce: pointer to the nonce
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_frost_pubnonce_serialize(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
unsigned char *out66,
|
||||||
|
const secp256k1_frost_pubnonce *nonce
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||||
|
|
||||||
/** Serialize a FROST share
|
/** Serialize a FROST share
|
||||||
*
|
*
|
||||||
* Returns: 1 when the share could be serialized, 0 otherwise
|
* Returns: 1 when the share could be serialized, 0 otherwise
|
||||||
@ -181,6 +239,59 @@ SECP256K1_API int secp256k1_frost_compute_pubshare(
|
|||||||
size_t n_participants
|
size_t n_participants
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||||
|
|
||||||
|
/** Starts a signing session by generating a nonce
|
||||||
|
*
|
||||||
|
* This function outputs a secret nonce that will be required for signing and a
|
||||||
|
* corresponding public nonce that is intended to be sent to other signers.
|
||||||
|
*
|
||||||
|
* FROST, like MuSig, differs from regular Schnorr signing in that
|
||||||
|
* implementers _must_ take special care to not reuse a nonce. This can be
|
||||||
|
* ensured by following these rules:
|
||||||
|
*
|
||||||
|
* 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE
|
||||||
|
* REUSED in subsequent calls to this function.
|
||||||
|
* If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM
|
||||||
|
* AND KEPT SECRET (even from other signers). If you do provide a seckey,
|
||||||
|
* session_id32 can instead be a counter (that must never repeat!). However,
|
||||||
|
* it is recommended to always choose session_id32 uniformly at random.
|
||||||
|
* 2. If you already know the seckey, message or aggregate public key, they
|
||||||
|
* can be optionally provided to derive the nonce and increase
|
||||||
|
* misuse-resistance. The extra_input32 argument can be used to provide
|
||||||
|
* additional data that does not repeat in normal scenarios, such as the
|
||||||
|
* current time.
|
||||||
|
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
|
||||||
|
* that it is used more than once for signing.
|
||||||
|
*
|
||||||
|
* Remember that nonce reuse will leak the secret key!
|
||||||
|
* Note that using the same agg_share for multiple FROST sessions is fine.
|
||||||
|
*
|
||||||
|
* Returns: 0 if the arguments are invalid and 1 otherwise
|
||||||
|
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
||||||
|
* Out: secnonce: pointer to a structure to store the secret nonce
|
||||||
|
* pubnonce: pointer to a structure to store the public nonce
|
||||||
|
* In: session_id32: a 32-byte session_id32 as explained above. Must be
|
||||||
|
* unique to this call to secp256k1_frost_nonce_gen and
|
||||||
|
* must be uniformly random unless you really know what you
|
||||||
|
* are doing.
|
||||||
|
* agg_share: the aggregated share that will later be used for
|
||||||
|
* signing, if already known (can be NULL)
|
||||||
|
* msg32: the 32-byte message that will later be signed, if
|
||||||
|
* already known (can be NULL)
|
||||||
|
* agg_pk: the FROST-aggregated public key (can be NULL)
|
||||||
|
* extra_input32: an optional 32-byte array that is input to the nonce
|
||||||
|
* derivation function (can be NULL)
|
||||||
|
*/
|
||||||
|
SECP256K1_API int secp256k1_frost_nonce_gen(
|
||||||
|
const secp256k1_context *ctx,
|
||||||
|
secp256k1_frost_secnonce *secnonce,
|
||||||
|
secp256k1_frost_pubnonce *pubnonce,
|
||||||
|
const unsigned char *session_id32,
|
||||||
|
const secp256k1_frost_share *agg_share,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const secp256k1_xonly_pubkey *agg_pk,
|
||||||
|
const unsigned char *extra_input32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -202,6 +202,10 @@ static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf);
|
|||||||
*/
|
*/
|
||||||
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
|
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
|
||||||
|
|
||||||
|
static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge);
|
||||||
|
|
||||||
|
static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data);
|
||||||
|
|
||||||
/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
|
/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
|
||||||
static void secp256k1_ge_verify(const secp256k1_ge *a);
|
static void secp256k1_ge_verify(const secp256k1_ge *a);
|
||||||
#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a)
|
#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a)
|
||||||
|
@ -914,6 +914,23 @@ static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
|
|||||||
return secp256k1_fe_is_square_var(&yz);
|
return secp256k1_fe_is_square_var(&yz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge) {
|
||||||
|
if (secp256k1_ge_is_infinity(ge)) {
|
||||||
|
memset(data, 0, 64);
|
||||||
|
} else {
|
||||||
|
secp256k1_ge_to_bytes(data, ge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data) {
|
||||||
|
unsigned char zeros[64] = { 0 };
|
||||||
|
if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) {
|
||||||
|
secp256k1_ge_set_infinity(ge);
|
||||||
|
} else {
|
||||||
|
secp256k1_ge_from_bytes(ge, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
|
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
|
||||||
#ifdef EXHAUSTIVE_TEST_ORDER
|
#ifdef EXHAUSTIVE_TEST_ORDER
|
||||||
secp256k1_gej out;
|
secp256k1_gej out;
|
||||||
|
@ -2,3 +2,5 @@ include_HEADERS += include/secp256k1_frost.h
|
|||||||
noinst_HEADERS += src/modules/frost/main_impl.h
|
noinst_HEADERS += src/modules/frost/main_impl.h
|
||||||
noinst_HEADERS += src/modules/frost/keygen.h
|
noinst_HEADERS += src/modules/frost/keygen.h
|
||||||
noinst_HEADERS += src/modules/frost/keygen_impl.h
|
noinst_HEADERS += src/modules/frost/keygen_impl.h
|
||||||
|
noinst_HEADERS += src/modules/frost/session.h
|
||||||
|
noinst_HEADERS += src/modules/frost/session_impl.h
|
||||||
|
@ -10,4 +10,8 @@
|
|||||||
#include "../../../include/secp256k1.h"
|
#include "../../../include/secp256k1.h"
|
||||||
#include "../../../include/secp256k1_frost.h"
|
#include "../../../include/secp256k1_frost.h"
|
||||||
|
|
||||||
|
#include "../../scalar.h"
|
||||||
|
|
||||||
|
static int secp256k1_frost_share_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_frost_share* share);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,5 +8,6 @@
|
|||||||
#define SECP256K1_MODULE_FROST_MAIN
|
#define SECP256K1_MODULE_FROST_MAIN
|
||||||
|
|
||||||
#include "keygen_impl.h"
|
#include "keygen_impl.h"
|
||||||
|
#include "session_impl.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
10
src/modules/frost/session.h
Normal file
10
src/modules/frost/session.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2021-2024 Jesse Posner *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SECP256K1_MODULE_FROST_SESSION_H
|
||||||
|
#define SECP256K1_MODULE_FROST_SESSION_H
|
||||||
|
|
||||||
|
#endif
|
233
src/modules/frost/session_impl.h
Normal file
233
src/modules/frost/session_impl.h
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/**********************************************************************
|
||||||
|
* Copyright (c) 2021-2024 Jesse Posner *
|
||||||
|
* Distributed under the MIT software license, see the accompanying *
|
||||||
|
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef SECP256K1_MODULE_FROST_SESSION_IMPL_H
|
||||||
|
#define SECP256K1_MODULE_FROST_SESSION_IMPL_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../../../include/secp256k1.h"
|
||||||
|
#include "../../../include/secp256k1_extrakeys.h"
|
||||||
|
#include "../../../include/secp256k1_frost.h"
|
||||||
|
|
||||||
|
#include "keygen.h"
|
||||||
|
#include "session.h"
|
||||||
|
#include "../../eckey.h"
|
||||||
|
#include "../../hash.h"
|
||||||
|
#include "../../scalar.h"
|
||||||
|
#include "../../util.h"
|
||||||
|
|
||||||
|
static const unsigned char secp256k1_frost_secnonce_magic[4] = { 0x84, 0x7d, 0x46, 0x25 };
|
||||||
|
|
||||||
|
static void secp256k1_frost_secnonce_save(secp256k1_frost_secnonce *secnonce, secp256k1_scalar *k) {
|
||||||
|
memcpy(&secnonce->data[0], secp256k1_frost_secnonce_magic, 4);
|
||||||
|
secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]);
|
||||||
|
secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int secp256k1_frost_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_frost_secnonce *secnonce) {
|
||||||
|
int is_zero;
|
||||||
|
ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_frost_secnonce_magic, 4) == 0);
|
||||||
|
secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL);
|
||||||
|
secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL);
|
||||||
|
/* We make very sure that the nonce isn't invalidated by checking the values
|
||||||
|
* in addition to the magic. */
|
||||||
|
is_zero = secp256k1_scalar_is_zero(&k[0]) & secp256k1_scalar_is_zero(&k[1]);
|
||||||
|
secp256k1_declassify(ctx, &is_zero, sizeof(is_zero));
|
||||||
|
ARG_CHECK(!is_zero);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If flag is true, invalidate the secnonce; otherwise leave it. Constant-time. */
|
||||||
|
static void secp256k1_frost_secnonce_invalidate(const secp256k1_context* ctx, secp256k1_frost_secnonce *secnonce, int flag) {
|
||||||
|
secp256k1_memczero(secnonce->data, sizeof(secnonce->data), flag);
|
||||||
|
/* The flag argument is usually classified. So, above code makes the magic
|
||||||
|
* classified. However, we need the magic to be declassified to be able to
|
||||||
|
* compare it during secnonce_load. */
|
||||||
|
secp256k1_declassify(ctx, secnonce->data, sizeof(secp256k1_frost_secnonce_magic));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned char secp256k1_frost_pubnonce_magic[4] = { 0x8b, 0xcf, 0xe2, 0xc2 };
|
||||||
|
|
||||||
|
/* Requires that none of the provided group elements is infinity. Works for both
|
||||||
|
* frost_pubnonce and frost_aggnonce. */
|
||||||
|
static void secp256k1_frost_pubnonce_save(secp256k1_frost_pubnonce* nonce, secp256k1_ge* ge) {
|
||||||
|
int i;
|
||||||
|
memcpy(&nonce->data[0], secp256k1_frost_pubnonce_magic, 4);
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_point_save_ext(nonce->data + 4+64*i, &ge[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Works for both frost_pubnonce and frost_aggnonce. Returns 1 unless the nonce
|
||||||
|
* wasn't properly initialized */
|
||||||
|
static int secp256k1_frost_pubnonce_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_frost_pubnonce* nonce) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_frost_pubnonce_magic, 4) == 0);
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_point_load_ext(&ge[i], nonce->data + 4+64*i);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_frost_pubnonce_serialize(const secp256k1_context* ctx, unsigned char *out66, const secp256k1_frost_pubnonce* nonce) {
|
||||||
|
secp256k1_ge ge[2];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(out66 != NULL);
|
||||||
|
memset(out66, 0, 66);
|
||||||
|
ARG_CHECK(nonce != NULL);
|
||||||
|
|
||||||
|
if (!secp256k1_frost_pubnonce_load(ctx, ge, nonce)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
int ret;
|
||||||
|
size_t size = 33;
|
||||||
|
ret = secp256k1_eckey_pubkey_serialize(&ge[i], &out66[33*i], &size, 1);
|
||||||
|
#ifdef VERIFY
|
||||||
|
/* serialize must succeed because the point was just loaded */
|
||||||
|
VERIFY_CHECK(ret && size == 33);
|
||||||
|
#else
|
||||||
|
(void) ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_frost_pubnonce_parse(const secp256k1_context* ctx, secp256k1_frost_pubnonce* nonce, const unsigned char *in66) {
|
||||||
|
secp256k1_ge ge[2];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(nonce != NULL);
|
||||||
|
ARG_CHECK(in66 != NULL);
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
if (!secp256k1_eckey_pubkey_parse(&ge[i], &in66[33*i], 33)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!secp256k1_ge_is_in_correct_subgroup(&ge[i])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* The group elements can not be infinity because they were just parsed */
|
||||||
|
secp256k1_frost_pubnonce_save(nonce, ge);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void secp256k1_nonce_function_frost(secp256k1_scalar *k, const unsigned char *session_id, const unsigned char *msg32, const unsigned char *key32, const unsigned char *pk32, const unsigned char *extra_input32) {
|
||||||
|
secp256k1_sha256 sha;
|
||||||
|
unsigned char seed[32];
|
||||||
|
unsigned char i;
|
||||||
|
enum { n_extra_in = 4 };
|
||||||
|
const unsigned char *extra_in[n_extra_in];
|
||||||
|
|
||||||
|
/* TODO: this doesn't have the same sidechannel resistance as the BIP340
|
||||||
|
* nonce function because the seckey feeds directly into SHA. */
|
||||||
|
|
||||||
|
/* Subtract one from `sizeof` to avoid hashing the implicit null byte */
|
||||||
|
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/nonce", sizeof("FROST/nonce") - 1);
|
||||||
|
secp256k1_sha256_write(&sha, session_id, 32);
|
||||||
|
extra_in[0] = msg32;
|
||||||
|
extra_in[1] = key32;
|
||||||
|
extra_in[2] = pk32;
|
||||||
|
extra_in[3] = extra_input32;
|
||||||
|
for (i = 0; i < n_extra_in; i++) {
|
||||||
|
unsigned char len;
|
||||||
|
if (extra_in[i] != NULL) {
|
||||||
|
len = 32;
|
||||||
|
secp256k1_sha256_write(&sha, &len, 1);
|
||||||
|
secp256k1_sha256_write(&sha, extra_in[i], 32);
|
||||||
|
} else {
|
||||||
|
len = 0;
|
||||||
|
secp256k1_sha256_write(&sha, &len, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
secp256k1_sha256_finalize(&sha, seed);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
unsigned char buf[32];
|
||||||
|
secp256k1_sha256_initialize(&sha);
|
||||||
|
secp256k1_sha256_write(&sha, seed, 32);
|
||||||
|
secp256k1_sha256_write(&sha, &i, sizeof(i));
|
||||||
|
secp256k1_sha256_finalize(&sha, buf);
|
||||||
|
secp256k1_scalar_set_b32(&k[i], buf, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int secp256k1_frost_nonce_gen(const secp256k1_context* ctx, secp256k1_frost_secnonce *secnonce, secp256k1_frost_pubnonce *pubnonce, const unsigned char *session_id32, const secp256k1_frost_share *share, const unsigned char *msg32, const secp256k1_xonly_pubkey *pk, const unsigned char *extra_input32) {
|
||||||
|
secp256k1_scalar k[2];
|
||||||
|
secp256k1_ge nonce_pt[2];
|
||||||
|
int i;
|
||||||
|
unsigned char pk_ser[32];
|
||||||
|
unsigned char *pk_ser_ptr = NULL;
|
||||||
|
unsigned char sk_ser[32];
|
||||||
|
unsigned char *sk_ser_ptr = NULL;
|
||||||
|
int sk_serialize_success;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
VERIFY_CHECK(ctx != NULL);
|
||||||
|
ARG_CHECK(secnonce != NULL);
|
||||||
|
memset(secnonce, 0, sizeof(*secnonce));
|
||||||
|
ARG_CHECK(pubnonce != NULL);
|
||||||
|
memset(pubnonce, 0, sizeof(*pubnonce));
|
||||||
|
ARG_CHECK(session_id32 != NULL);
|
||||||
|
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||||
|
if (share == NULL) {
|
||||||
|
/* Check in constant time that the session_id is not 0 as a
|
||||||
|
* defense-in-depth measure that may protect against a faulty RNG. */
|
||||||
|
unsigned char acc = 0;
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
acc |= session_id32[i];
|
||||||
|
}
|
||||||
|
ret &= !!acc;
|
||||||
|
memset(&acc, 0, sizeof(acc));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (share != NULL) {
|
||||||
|
/* Check that the share is valid to be able to sign for it later. */
|
||||||
|
secp256k1_scalar sk;
|
||||||
|
|
||||||
|
ret &= secp256k1_frost_share_load(ctx, &sk, share);
|
||||||
|
secp256k1_scalar_clear(&sk);
|
||||||
|
|
||||||
|
sk_serialize_success = secp256k1_frost_share_serialize(ctx, sk_ser, share);
|
||||||
|
sk_ser_ptr = sk_ser;
|
||||||
|
#ifdef VERIFY
|
||||||
|
VERIFY_CHECK(sk_serialize_success);
|
||||||
|
#else
|
||||||
|
(void) sk_serialize_success;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pk != NULL) {
|
||||||
|
if (!secp256k1_xonly_pubkey_serialize(ctx, pk_ser, pk)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pk_ser_ptr = pk_ser;
|
||||||
|
}
|
||||||
|
secp256k1_nonce_function_frost(k, session_id32, msg32, sk_ser_ptr, pk_ser_ptr, extra_input32);
|
||||||
|
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0]));
|
||||||
|
VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1]));
|
||||||
|
VERIFY_CHECK(!secp256k1_scalar_eq(&k[0], &k[1]));
|
||||||
|
secp256k1_frost_secnonce_save(secnonce, k);
|
||||||
|
secp256k1_frost_secnonce_invalidate(ctx, secnonce, !ret);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
secp256k1_gej nonce_ptj;
|
||||||
|
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]);
|
||||||
|
secp256k1_ge_set_gej(&nonce_pt[i], &nonce_ptj);
|
||||||
|
secp256k1_declassify(ctx, &nonce_pt[i], sizeof(nonce_pt));
|
||||||
|
secp256k1_scalar_clear(&k[i]);
|
||||||
|
}
|
||||||
|
/* nonce_pt won't be infinity because k != 0 with overwhelming probability */
|
||||||
|
secp256k1_frost_pubnonce_save(pubnonce, nonce_pt);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -27,12 +27,6 @@ typedef struct {
|
|||||||
int parity_acc;
|
int parity_acc;
|
||||||
} secp256k1_keyagg_cache_internal;
|
} secp256k1_keyagg_cache_internal;
|
||||||
|
|
||||||
/* point_save_ext and point_load_ext are identical to point_save and point_load
|
|
||||||
* except that they allow saving and loading the point at infinity */
|
|
||||||
static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge);
|
|
||||||
|
|
||||||
static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data);
|
|
||||||
|
|
||||||
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache);
|
static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache);
|
||||||
|
|
||||||
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk);
|
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk);
|
||||||
|
@ -17,23 +17,6 @@
|
|||||||
#include "../../hash.h"
|
#include "../../hash.h"
|
||||||
#include "../../util.h"
|
#include "../../util.h"
|
||||||
|
|
||||||
static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge) {
|
|
||||||
if (secp256k1_ge_is_infinity(ge)) {
|
|
||||||
memset(data, 0, 64);
|
|
||||||
} else {
|
|
||||||
secp256k1_ge_to_bytes(data, ge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data) {
|
|
||||||
unsigned char zeros[64] = { 0 };
|
|
||||||
if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) {
|
|
||||||
secp256k1_ge_set_infinity(ge);
|
|
||||||
} else {
|
|
||||||
secp256k1_ge_from_bytes(ge, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf };
|
static const unsigned char secp256k1_musig_keyagg_cache_magic[4] = { 0xf4, 0xad, 0xbb, 0xdf };
|
||||||
|
|
||||||
/* A keyagg cache consists of
|
/* A keyagg cache consists of
|
||||||
|
Loading…
x
Reference in New Issue
Block a user