frost trusted dealer: share generation
This commit adds trusted share generation, as well as share serialization and parsing.
This commit is contained in:
parent
6f47d2eb22
commit
8969cee21c
@ -17,6 +17,84 @@ extern "C" {
|
||||
* (https://crysp.uwaterloo.ca/software/frost/).
|
||||
*/
|
||||
|
||||
/** Opaque data structures
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. If you
|
||||
* need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use the corresponding serialization and parsing functions.
|
||||
*/
|
||||
|
||||
/** Opaque data structure that holds a signer's _secret_ share.
|
||||
*
|
||||
* Guaranteed to be 36 bytes in size. Serialized and parsed with
|
||||
* `frost_share_serialize` and `frost_share_parse`.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[36];
|
||||
} secp256k1_frost_share;
|
||||
|
||||
/** Serialize a FROST share
|
||||
*
|
||||
* Returns: 1 when the share could be serialized, 0 otherwise
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: out32: pointer to a 32-byte array to store the serialized share
|
||||
* In: share: pointer to the share
|
||||
*/
|
||||
SECP256K1_API int secp256k1_frost_share_serialize(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *out32,
|
||||
const secp256k1_frost_share *share
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse a FROST share.
|
||||
*
|
||||
* Returns: 1 when the share could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: share: pointer to a share object
|
||||
* In: in32: pointer to the 32-byte share to be parsed
|
||||
*/
|
||||
SECP256K1_API int secp256k1_frost_share_parse(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_frost_share *share,
|
||||
const unsigned char *in32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Creates key generation shares
|
||||
*
|
||||
* To generate a key, a trusted dealer generates a share for each other
|
||||
* participant.
|
||||
*
|
||||
* Each participant _must_ have a secure channel with the trusted dealer with
|
||||
* which they can transmit shares to each other.
|
||||
*
|
||||
* A new seed32 _must_ be used for each key generation session. The trusted
|
||||
* dealer must NOT REUSE their respective seed32 again for subsequent key
|
||||
* generation sessions. If a trusted dealer fails to complete this session or
|
||||
* start a new session to generate a new key, they must NOT REUSE their
|
||||
* respective seed32 again, but instead generate a new one. It is recommended
|
||||
* to always choose seed32 uniformly at random to avoid their reuse.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid, 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: shares: pointer to the key generation shares
|
||||
* pubshares: pointer to the public verification shares
|
||||
* pk: pointer to the x-only public key
|
||||
* In: seed32: a 32-byte seed as explained above
|
||||
* threshold: the minimum number of signers required to produce a
|
||||
* signature
|
||||
* n_participants: the total number of participants
|
||||
*/
|
||||
SECP256K1_API int secp256k1_frost_shares_trusted_gen(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_frost_share *shares,
|
||||
secp256k1_pubkey *pubshares,
|
||||
secp256k1_xonly_pubkey *pk,
|
||||
const unsigned char *seed32,
|
||||
size_t threshold,
|
||||
size_t n_participants
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,2 +1,4 @@
|
||||
include_HEADERS += include/secp256k1_frost.h
|
||||
noinst_HEADERS += src/modules/frost/main_impl.h
|
||||
noinst_HEADERS += src/modules/frost/keygen.h
|
||||
noinst_HEADERS += src/modules/frost/keygen_impl.h
|
||||
|
13
src/modules/frost/keygen.h
Normal file
13
src/modules/frost/keygen.h
Normal file
@ -0,0 +1,13 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2021-2023 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_KEYGEN_H
|
||||
#define SECP256K1_MODULE_FROST_KEYGEN_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_frost.h"
|
||||
|
||||
#endif
|
146
src/modules/frost/keygen_impl.h
Normal file
146
src/modules/frost/keygen_impl.h
Normal file
@ -0,0 +1,146 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2021-2023 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_KEYGEN_IMPL_H
|
||||
#define SECP256K1_MODULE_FROST_KEYGEN_IMPL_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
#include "../../../include/secp256k1_frost.h"
|
||||
|
||||
#include "keygen.h"
|
||||
#include "../../ecmult.h"
|
||||
#include "../../field.h"
|
||||
#include "../../group.h"
|
||||
#include "../../hash.h"
|
||||
#include "../../scalar.h"
|
||||
|
||||
static const unsigned char secp256k1_frost_share_magic[4] = { 0xa1, 0x6a, 0x42, 0x03 };
|
||||
|
||||
static void secp256k1_frost_share_save(secp256k1_frost_share* share, secp256k1_scalar *s) {
|
||||
memcpy(&share->data[0], secp256k1_frost_share_magic, 4);
|
||||
secp256k1_scalar_get_b32(&share->data[4], s);
|
||||
}
|
||||
|
||||
static int secp256k1_frost_share_load(const secp256k1_context* ctx, secp256k1_scalar *s, const secp256k1_frost_share* share) {
|
||||
int overflow;
|
||||
|
||||
/* The magic is non-secret so it can be declassified to allow branching. */
|
||||
secp256k1_declassify(ctx, &share->data[0], 4);
|
||||
ARG_CHECK(secp256k1_memcmp_var(&share->data[0], secp256k1_frost_share_magic, 4) == 0);
|
||||
secp256k1_scalar_set_b32(s, &share->data[4], &overflow);
|
||||
/* Parsed shares cannot overflow */
|
||||
VERIFY_CHECK(!overflow);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_frost_share_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_frost_share* share) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(out32 != NULL);
|
||||
ARG_CHECK(share != NULL);
|
||||
memcpy(out32, &share->data[4], 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_frost_share_parse(const secp256k1_context* ctx, secp256k1_frost_share* share, const unsigned char *in32) {
|
||||
secp256k1_scalar tmp;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(share != NULL);
|
||||
ARG_CHECK(in32 != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, in32, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_frost_share_save(share, &tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_frost_shares_trusted_gen(const secp256k1_context *ctx, secp256k1_frost_share *shares, secp256k1_pubkey *pubshares, secp256k1_xonly_pubkey *pk, const unsigned char *seed32, size_t threshold, size_t n_participants) {
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge rp;
|
||||
unsigned char polygen[32];
|
||||
size_t i, j;
|
||||
int ret = 1;
|
||||
int pk_parity = 0;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(shares != NULL);
|
||||
for (i = 0; i < n_participants; i++) {
|
||||
memset(&shares[i], 0, sizeof(shares[i]));
|
||||
}
|
||||
ARG_CHECK(pubshares != NULL);
|
||||
ARG_CHECK(pk != NULL);
|
||||
ARG_CHECK(seed32 != NULL);
|
||||
ARG_CHECK(threshold > 1);
|
||||
ARG_CHECK(n_participants >= threshold);
|
||||
|
||||
/* Commit to threshold, n_participants, and seed */
|
||||
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/trusted-shares-polygen", sizeof("FROST/trusted-shares-polygen") - 1);
|
||||
secp256k1_sha256_write(&sha, seed32, 32);
|
||||
secp256k1_write_be64(&polygen[0], threshold);
|
||||
secp256k1_write_be64(&polygen[8], n_participants);
|
||||
secp256k1_sha256_write(&sha, polygen, 16);
|
||||
secp256k1_sha256_finalize(&sha, polygen);
|
||||
|
||||
/* Derive share */
|
||||
/* See draft-irtf-cfrg-frost-08#appendix-C.1 */
|
||||
for (i = 0; i < n_participants; i++) {
|
||||
secp256k1_scalar share_i, idx;
|
||||
|
||||
secp256k1_scalar_clear(&share_i);
|
||||
|
||||
for (j = 0; j < threshold; j++) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_scalar coeff_i;
|
||||
|
||||
secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/trusted-shares-coeffgen", sizeof("FROST/trusted-shares-coeffgen") - 1);
|
||||
secp256k1_sha256_write(&sha, polygen, 32);
|
||||
secp256k1_write_be64(&buf[0], j);
|
||||
secp256k1_sha256_write(&sha, buf, 8);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_scalar_set_b32(&coeff_i, buf, NULL);
|
||||
|
||||
/* Horner's method to evaluate polynomial to derive shares */
|
||||
secp256k1_scalar_add(&share_i, &share_i, &coeff_i);
|
||||
if (j < threshold - 1) {
|
||||
secp256k1_scalar_set_int(&idx, i + 1);
|
||||
secp256k1_scalar_mul(&share_i, &share_i, &idx);
|
||||
}
|
||||
|
||||
/* Compute x-only public key for constant term */
|
||||
if (i == 0 && j == threshold - 1) {
|
||||
/* Compute commitment to constant term */
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &coeff_i);
|
||||
secp256k1_ge_set_gej(&rp, &rj);
|
||||
/* The commitment is non-secret so it can be declassified to
|
||||
* allow branching. */
|
||||
secp256k1_declassify(ctx, &rp, sizeof(rp));
|
||||
secp256k1_fe_normalize_var(&rp.y);
|
||||
pk_parity = secp256k1_extrakeys_ge_even_y(&rp);
|
||||
secp256k1_xonly_pubkey_save(pk, &rp);
|
||||
}
|
||||
}
|
||||
|
||||
if (pk_parity == 1) {
|
||||
secp256k1_scalar_negate(&share_i, &share_i);
|
||||
}
|
||||
secp256k1_frost_share_save(&shares[i], &share_i);
|
||||
/* Compute pubshare */
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &share_i);
|
||||
secp256k1_ge_set_gej(&rp, &rj);
|
||||
secp256k1_pubkey_save(&pubshares[i], &rp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
@ -7,4 +7,6 @@
|
||||
#ifndef SECP256K1_MODULE_FROST_MAIN
|
||||
#define SECP256K1_MODULE_FROST_MAIN
|
||||
|
||||
#include "keygen_impl.h"
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user