Skip to content

Commit

Permalink
Return aggregated VSS when aggregating shares
Browse files Browse the repository at this point in the history
  • Loading branch information
jesseposner committed Nov 7, 2024
1 parent 5f76404 commit 4442867
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 99 deletions.
7 changes: 4 additions & 3 deletions examples/frost.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_se
const secp256k1_pubkey *vss_commitments[N_SIGNERS];
const unsigned char *ids[N_SIGNERS];
const unsigned char *poks[N_SIGNERS];
secp256k1_pubkey agg_vss_commitment[THRESHOLD];

for (i = 0; i < N_SIGNERS; i++) {
vss_commitments[i] = signer[i].vss_commitment;
Expand All @@ -100,20 +101,20 @@ int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_se
assigned_shares[j] = &shares[j][i];
}
/* Each participant aggregates the shares they received. */
if (!secp256k1_frost_share_agg(ctx, &signer_secrets[i].agg_share, assigned_shares, vss_commitments, poks, N_SIGNERS, THRESHOLD, signer[i].id)) {
if (!secp256k1_frost_share_agg(ctx, &signer_secrets[i].agg_share, agg_vss_commitment, assigned_shares, vss_commitments, poks, N_SIGNERS, THRESHOLD, signer[i].id)) {
return 0;
}
for (j = 0; j < N_SIGNERS; j++) {
/* Each participant verifies their shares. share_agg calls this
* internally, so it is only neccessary to call this function if
* share_agg returns an error, to determine which participant(s)
* submitted faulty data. */
if (!secp256k1_frost_share_verify(ctx, THRESHOLD, signer[i].id, assigned_shares[j], &vss_commitments[j])) {
if (!secp256k1_frost_share_verify(ctx, THRESHOLD, signer[i].id, assigned_shares[j], vss_commitments[j])) {
return 0;
}
/* Each participant generates public verification shares that are
* used for verifying partial signatures. */
if (!secp256k1_frost_compute_pubshare(ctx, &signer[j].pubshare, THRESHOLD, signer[j].id, vss_commitments, N_SIGNERS)) {
if (!secp256k1_frost_compute_pubshare(ctx, &signer[j].pubshare, THRESHOLD, signer[j].id, agg_vss_commitment, N_SIGNERS)) {
return 0;
}
}
Expand Down
50 changes: 26 additions & 24 deletions include/secp256k1_frost.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,29 +237,31 @@ SECP256K1_API int secp256k1_frost_shares_gen(
*
* Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
* the resulting signature verifies).
* Args: ctx: pointer to a context object
* Out: agg_share: the aggregated share
* In: shares: all key generation shares for the partcipant's index
* vss_commitments: coefficient commitments of all participants ordered by
* the IDs of the participants
* pok64s: proofs of knowledge for the shares ordered by the IDs of
* the participants
* n_shares: the total number of shares
* threshold: the minimum number of shares required to produce a
* signature
* id33: the 33-byte ID of the participant whose shares are being
* aggregated
* Args: ctx: pointer to a context object
* Out: agg_share: the aggregated share
* In: shares: all key generation shares for the partcipant's index
* agg_vss_commitment: the aggregated coefficient commitment
* vss_commitments: coefficient commitment of each participant ordered by
* the IDs of the participants
* pok64s: proofs of knowledge for the shares ordered by the IDs of
* the participants
* n_shares: the total number of shares
* threshold: the minimum number of shares required to produce a
* signature
* id33: the 33-byte ID of the participant whose shares are being
* aggregated
*/
SECP256K1_API int secp256k1_frost_share_agg(
const secp256k1_context *ctx,
secp256k1_frost_share *agg_share,
secp256k1_pubkey *agg_vss_commitment,
const secp256k1_frost_share * const *shares,
const secp256k1_pubkey * const *vss_commitments,
const unsigned char * const *pok64s,
size_t n_shares,
size_t threshold,
const unsigned char *id33
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(8);
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(9);

/** Verifies a share received during a key generation session
*
Expand All @@ -281,28 +283,28 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_share_verify(
size_t threshold,
const unsigned char *id33,
const secp256k1_frost_share *share,
const secp256k1_pubkey * const *vss_commitment
const secp256k1_pubkey *vss_commitment
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);

/** Computes a public verification share used for verifying partial signatures
*
* Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object
* Out: pubshare: pointer to a struct to store the public verification
* share
* In: threshold: the minimum number of signers required to produce a
* signature
* id33: the 33-byte participant ID of the participant whose
* partial signature will be verified with the pubshare
* vss_commitments: coefficient commitments of all participants
* n_participants: the total number of participants
* Args: ctx: pointer to a context object
* Out: pubshare: pointer to a struct to store the public verification
* share
* In: threshold: the minimum number of signers required to produce a
* signature
* id33: the 33-byte participant ID of the participant whose
* partial signature will be verified with the pubshare
* agg_vss_commitment: the output of `secp256k1_frost_share_agg`
* n_participants: the total number of participants
*/
SECP256K1_API int secp256k1_frost_compute_pubshare(
const secp256k1_context *ctx,
secp256k1_pubkey *pubshare,
size_t threshold,
const unsigned char *id33,
const secp256k1_pubkey * const *vss_commitments,
const secp256k1_pubkey *agg_vss_commitment,
size_t n_participants
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);

Expand Down
7 changes: 4 additions & 3 deletions src/ctime_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
const unsigned char *pok_ptr[2];
secp256k1_pubkey pubshare[2];
const secp256k1_pubkey *pubshares_ptr[2];
secp256k1_pubkey agg_vss_commitment[2];

id_ptr[0] = id[0];
id_ptr[1] = id[1];
Expand Down Expand Up @@ -438,12 +439,12 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
SECP256K1_CHECKMEM_DEFINE(&vss_commitment[1][1], sizeof(secp256k1_pubkey));
SECP256K1_CHECKMEM_DEFINE(pok[0], 64);
SECP256K1_CHECKMEM_DEFINE(pok[1], 64);
ret = secp256k1_frost_share_agg(ctx, &agg_share, share_ptr, vss_ptr, pok_ptr, 2, 2, id_ptr[0]);
ret = secp256k1_frost_share_agg(ctx, &agg_share, agg_vss_commitment, share_ptr, vss_ptr, pok_ptr, 2, 2, id_ptr[0]);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
SECP256K1_CHECKMEM_UNDEFINE(&agg_share, sizeof(&agg_share));
CHECK(secp256k1_frost_compute_pubshare(ctx, &pubshare[0], 2, id_ptr[0], vss_ptr, 2));
CHECK(secp256k1_frost_compute_pubshare(ctx, &pubshare[1], 2, id_ptr[1], vss_ptr, 2));
CHECK(secp256k1_frost_compute_pubshare(ctx, &pubshare[0], 2, id_ptr[0], agg_vss_commitment, 2));
CHECK(secp256k1_frost_compute_pubshare(ctx, &pubshare[1], 2, id_ptr[1], agg_vss_commitment, 2));
CHECK(secp256k1_frost_pubkey_gen(ctx, &cache, pubshares_ptr, 2, id_ptr));
/* nonce_gen */
SECP256K1_CHECKMEM_UNDEFINE(session_id, sizeof(session_id));
Expand Down
95 changes: 69 additions & 26 deletions src/modules/frost/keygen_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ typedef struct {
const secp256k1_context *ctx;
secp256k1_scalar idx;
secp256k1_scalar idxn;
const secp256k1_pubkey * const* vss_commitment;
const secp256k1_pubkey *vss_commitment;
} secp256k1_frost_verify_share_ecmult_data;

typedef struct {
Expand All @@ -245,9 +245,15 @@ typedef struct {
size_t n_pubshares;
} secp256k1_frost_interpolate_pubkey_ecmult_data;

typedef struct {
const secp256k1_context *ctx;
size_t idxn;
const secp256k1_pubkey * const* vss_commitments;
} secp256k1_frost_vss_agg_ecmult_data;

static int secp256k1_frost_verify_share_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
secp256k1_frost_verify_share_ecmult_data *ctx = (secp256k1_frost_verify_share_ecmult_data *) data;
if (!secp256k1_pubkey_load(ctx->ctx, pt, *(ctx->vss_commitment)+idx)) {
if (!secp256k1_pubkey_load(ctx->ctx, pt, &ctx->vss_commitment[idx])) {
return 0;
}
*sc = ctx->idxn;
Expand Down Expand Up @@ -288,8 +294,20 @@ static int secp256k1_frost_interpolate_pubkey_ecmult_callback(secp256k1_scalar *
return 1;
}

static int secp256k1_frost_vss_agg_pubkey_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
secp256k1_frost_vss_agg_ecmult_data *ctx = (secp256k1_frost_vss_agg_ecmult_data *) data;

if (!secp256k1_pubkey_load(ctx->ctx, pt, &ctx->vss_commitments[idx][ctx->idxn])) {
return 0;
}

*sc = secp256k1_scalar_one;

return 1;
}

/* See RFC 9591 */
static int secp256k1_frost_vss_verify_internal(const secp256k1_context* ctx, size_t threshold, const unsigned char *id33, const secp256k1_scalar *share, const secp256k1_pubkey * const* vss_commitment) {
static int secp256k1_frost_vss_verify_internal(const secp256k1_context* ctx, size_t threshold, const unsigned char *id33, const secp256k1_scalar *share, const secp256k1_pubkey *vss_commitment) {
secp256k1_scalar share_neg;
secp256k1_gej tmpj, snj;
secp256k1_ge sng;
Expand Down Expand Up @@ -319,7 +337,7 @@ static int secp256k1_frost_vss_verify_internal(const secp256k1_context* ctx, siz
return secp256k1_gej_is_infinity(&tmpj);
}

int secp256k1_frost_share_verify(const secp256k1_context* ctx, size_t threshold, const unsigned char *id33, const secp256k1_frost_share *share, const secp256k1_pubkey * const* vss_commitment) {
int secp256k1_frost_share_verify(const secp256k1_context* ctx, size_t threshold, const unsigned char *id33, const secp256k1_frost_share *share, const secp256k1_pubkey *vss_commitment) {
secp256k1_scalar share_i;

VERIFY_CHECK(ctx != NULL);
Expand All @@ -335,51 +353,73 @@ int secp256k1_frost_share_verify(const secp256k1_context* ctx, size_t threshold,
return secp256k1_frost_vss_verify_internal(ctx, threshold, id33, &share_i, vss_commitment);
}

int secp256k1_frost_compute_pubshare(const secp256k1_context* ctx, secp256k1_pubkey *pubshare, size_t threshold, const unsigned char *id33, const secp256k1_pubkey * const* vss_commitments, size_t n_participants) {
secp256k1_gej pkj;
int secp256k1_frost_compute_pubshare(const secp256k1_context* ctx, secp256k1_pubkey *pubshare, size_t threshold, const unsigned char *id33, const secp256k1_pubkey *agg_vss_commitment, size_t n_participants) {
secp256k1_gej tmpj;
secp256k1_ge tmp;
secp256k1_frost_compute_pubshare_ecmult_data compute_pubshare_ecmult_data;
secp256k1_frost_verify_share_ecmult_data verify_share_ecmult_data;

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(pubshare != NULL);
memset(pubshare, 0, sizeof(*pubshare));
ARG_CHECK(id33 != NULL);
ARG_CHECK(vss_commitments != NULL);
ARG_CHECK(agg_vss_commitment != NULL);
ARG_CHECK(n_participants > 1);
ARG_CHECK(threshold > 1);

if (threshold > n_participants) {
return 0;
}

/* Use an EC multi-multiplication to compute the following equation:
* agg_share_i*G = (
* idx^0*vss_commitment[0][0] + ...
* + idx^(t - 1)*vss_commitment[0][t - 1]
* ) + ...
* + (
* idx^0*vss_commitment[n - 1][0] + ...
* + idx^(t - 1)*vss_commitment[n - 1][t - 1]
* )*/
compute_pubshare_ecmult_data.ctx = ctx;
compute_pubshare_ecmult_data.vss_commitments = vss_commitments;
compute_pubshare_ecmult_data.threshold = threshold;
/* Use an EC multi-multiplication to verify the following equation:
* agg_share_i * G = idx^0*agg_vss_commitment[0]
* + ...
* + idx^(threshold - 1)*agg_vss_commitment[threshold - 1]*/
verify_share_ecmult_data.ctx = ctx;
verify_share_ecmult_data.vss_commitment = agg_vss_commitment;
/* Evaluate the public polynomial at the idx */
if (!secp256k1_frost_compute_indexhash(&compute_pubshare_ecmult_data.idx, id33)) {
if (!secp256k1_frost_compute_indexhash(&verify_share_ecmult_data.idx, id33)) {
return 0;
}
secp256k1_scalar_set_int(&compute_pubshare_ecmult_data.idxn, 1);
secp256k1_scalar_set_int(&verify_share_ecmult_data.idxn, 1);
/* TODO: add scratch */
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &pkj, NULL, secp256k1_frost_compute_pubshare_ecmult_callback, (void *) &compute_pubshare_ecmult_data, n_participants*threshold)) {
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &tmpj, NULL, secp256k1_frost_verify_share_ecmult_callback, (void *) &verify_share_ecmult_data, threshold)) {
return 0;
}
secp256k1_ge_set_gej(&tmp, &pkj);
secp256k1_ge_set_gej(&tmp, &tmpj);
secp256k1_pubkey_save(pubshare, &tmp);

return 1;
}

int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_share *agg_share, const secp256k1_frost_share * const* shares, const secp256k1_pubkey * const* vss_commitments, const unsigned char * const *pok64s, size_t n_shares, size_t threshold, const unsigned char *id33) {
static int secp256k1_frost_vss_agg(const secp256k1_context* ctx, secp256k1_pubkey *agg_vss_commitment, const secp256k1_pubkey * const *vss_commitments, size_t n_participants, size_t threshold) {
secp256k1_gej tmpj;
secp256k1_ge tmp;
secp256k1_frost_vss_agg_ecmult_data vss_agg_ecmult_data;

VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(agg_vss_commitment != NULL);
ARG_CHECK(vss_commitments != NULL);
ARG_CHECK(n_participants > 1);
ARG_CHECK(threshold > 1);

vss_agg_ecmult_data.ctx = ctx;
vss_agg_ecmult_data.vss_commitments = vss_commitments;

for (vss_agg_ecmult_data.idxn = 0; vss_agg_ecmult_data.idxn < threshold; vss_agg_ecmult_data.idxn++) {
/* TODO: add scratch */
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &tmpj, NULL, secp256k1_frost_vss_agg_pubkey_ecmult_callback, (void *) &vss_agg_ecmult_data, n_participants)) {
return 0;
}
secp256k1_ge_set_gej(&tmp, &tmpj);
secp256k1_pubkey_save(&agg_vss_commitment[vss_agg_ecmult_data.idxn], &tmp);
}

return 1;
}

int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_share *agg_share, secp256k1_pubkey *agg_vss_commitment, const secp256k1_frost_share * const* shares, const secp256k1_pubkey * const* vss_commitments, const unsigned char * const *pok64s, size_t n_shares, size_t threshold, const unsigned char *id33) {
secp256k1_scalar acc;
size_t i;
int ret = 1;
Expand Down Expand Up @@ -422,10 +462,13 @@ int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_shar
return 0;
}
/* Verify share against commitments */
ret &= secp256k1_frost_vss_verify_internal(ctx, threshold, id33, &share_i, &vss_commitments[i]);
ret &= secp256k1_frost_vss_verify_internal(ctx, threshold, id33, &share_i, vss_commitments[i]);
secp256k1_scalar_add(&acc, &acc, &share_i);
}
secp256k1_frost_share_save(agg_share, &acc);
if (!secp256k1_frost_vss_agg(ctx, agg_vss_commitment, vss_commitments, n_shares, threshold)) {
return 0;
}

return ret;
}
Expand Down
Loading

0 comments on commit 4442867

Please sign in to comment.