Skip to content

Commit 4442867

Browse files
committed
Return aggregated VSS when aggregating shares
1 parent 5f76404 commit 4442867

File tree

5 files changed

+150
-99
lines changed

5 files changed

+150
-99
lines changed

examples/frost.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_se
7575
const secp256k1_pubkey *vss_commitments[N_SIGNERS];
7676
const unsigned char *ids[N_SIGNERS];
7777
const unsigned char *poks[N_SIGNERS];
78+
secp256k1_pubkey agg_vss_commitment[THRESHOLD];
7879

7980
for (i = 0; i < N_SIGNERS; i++) {
8081
vss_commitments[i] = signer[i].vss_commitment;
@@ -100,20 +101,20 @@ int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_se
100101
assigned_shares[j] = &shares[j][i];
101102
}
102103
/* Each participant aggregates the shares they received. */
103-
if (!secp256k1_frost_share_agg(ctx, &signer_secrets[i].agg_share, assigned_shares, vss_commitments, poks, N_SIGNERS, THRESHOLD, signer[i].id)) {
104+
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)) {
104105
return 0;
105106
}
106107
for (j = 0; j < N_SIGNERS; j++) {
107108
/* Each participant verifies their shares. share_agg calls this
108109
* internally, so it is only neccessary to call this function if
109110
* share_agg returns an error, to determine which participant(s)
110111
* submitted faulty data. */
111-
if (!secp256k1_frost_share_verify(ctx, THRESHOLD, signer[i].id, assigned_shares[j], &vss_commitments[j])) {
112+
if (!secp256k1_frost_share_verify(ctx, THRESHOLD, signer[i].id, assigned_shares[j], vss_commitments[j])) {
112113
return 0;
113114
}
114115
/* Each participant generates public verification shares that are
115116
* used for verifying partial signatures. */
116-
if (!secp256k1_frost_compute_pubshare(ctx, &signer[j].pubshare, THRESHOLD, signer[j].id, vss_commitments, N_SIGNERS)) {
117+
if (!secp256k1_frost_compute_pubshare(ctx, &signer[j].pubshare, THRESHOLD, signer[j].id, agg_vss_commitment, N_SIGNERS)) {
117118
return 0;
118119
}
119120
}

include/secp256k1_frost.h

+26-24
Original file line numberDiff line numberDiff line change
@@ -237,29 +237,31 @@ SECP256K1_API int secp256k1_frost_shares_gen(
237237
*
238238
* Returns: 0 if the arguments are invalid, 1 otherwise (which does NOT mean
239239
* the resulting signature verifies).
240-
* Args: ctx: pointer to a context object
241-
* Out: agg_share: the aggregated share
242-
* In: shares: all key generation shares for the partcipant's index
243-
* vss_commitments: coefficient commitments of all participants ordered by
244-
* the IDs of the participants
245-
* pok64s: proofs of knowledge for the shares ordered by the IDs of
246-
* the participants
247-
* n_shares: the total number of shares
248-
* threshold: the minimum number of shares required to produce a
249-
* signature
250-
* id33: the 33-byte ID of the participant whose shares are being
251-
* aggregated
240+
* Args: ctx: pointer to a context object
241+
* Out: agg_share: the aggregated share
242+
* In: shares: all key generation shares for the partcipant's index
243+
* agg_vss_commitment: the aggregated coefficient commitment
244+
* vss_commitments: coefficient commitment of each participant ordered by
245+
* the IDs of the participants
246+
* pok64s: proofs of knowledge for the shares ordered by the IDs of
247+
* the participants
248+
* n_shares: the total number of shares
249+
* threshold: the minimum number of shares required to produce a
250+
* signature
251+
* id33: the 33-byte ID of the participant whose shares are being
252+
* aggregated
252253
*/
253254
SECP256K1_API int secp256k1_frost_share_agg(
254255
const secp256k1_context *ctx,
255256
secp256k1_frost_share *agg_share,
257+
secp256k1_pubkey *agg_vss_commitment,
256258
const secp256k1_frost_share * const *shares,
257259
const secp256k1_pubkey * const *vss_commitments,
258260
const unsigned char * const *pok64s,
259261
size_t n_shares,
260262
size_t threshold,
261263
const unsigned char *id33
262-
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(8);
264+
) 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);
263265

264266
/** Verifies a share received during a key generation session
265267
*
@@ -281,28 +283,28 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_share_verify(
281283
size_t threshold,
282284
const unsigned char *id33,
283285
const secp256k1_frost_share *share,
284-
const secp256k1_pubkey * const *vss_commitment
286+
const secp256k1_pubkey *vss_commitment
285287
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
286288

287289
/** Computes a public verification share used for verifying partial signatures
288290
*
289291
* Returns: 0 if the arguments are invalid, 1 otherwise
290-
* Args: ctx: pointer to a context object
291-
* Out: pubshare: pointer to a struct to store the public verification
292-
* share
293-
* In: threshold: the minimum number of signers required to produce a
294-
* signature
295-
* id33: the 33-byte participant ID of the participant whose
296-
* partial signature will be verified with the pubshare
297-
* vss_commitments: coefficient commitments of all participants
298-
* n_participants: the total number of participants
292+
* Args: ctx: pointer to a context object
293+
* Out: pubshare: pointer to a struct to store the public verification
294+
* share
295+
* In: threshold: the minimum number of signers required to produce a
296+
* signature
297+
* id33: the 33-byte participant ID of the participant whose
298+
* partial signature will be verified with the pubshare
299+
* agg_vss_commitment: the output of `secp256k1_frost_share_agg`
300+
* n_participants: the total number of participants
299301
*/
300302
SECP256K1_API int secp256k1_frost_compute_pubshare(
301303
const secp256k1_context *ctx,
302304
secp256k1_pubkey *pubshare,
303305
size_t threshold,
304306
const unsigned char *id33,
305-
const secp256k1_pubkey * const *vss_commitments,
307+
const secp256k1_pubkey *agg_vss_commitment,
306308
size_t n_participants
307309
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
308310

src/ctime_tests.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
385385
const unsigned char *pok_ptr[2];
386386
secp256k1_pubkey pubshare[2];
387387
const secp256k1_pubkey *pubshares_ptr[2];
388+
secp256k1_pubkey agg_vss_commitment[2];
388389

389390
id_ptr[0] = id[0];
390391
id_ptr[1] = id[1];
@@ -438,12 +439,12 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
438439
SECP256K1_CHECKMEM_DEFINE(&vss_commitment[1][1], sizeof(secp256k1_pubkey));
439440
SECP256K1_CHECKMEM_DEFINE(pok[0], 64);
440441
SECP256K1_CHECKMEM_DEFINE(pok[1], 64);
441-
ret = secp256k1_frost_share_agg(ctx, &agg_share, share_ptr, vss_ptr, pok_ptr, 2, 2, id_ptr[0]);
442+
ret = secp256k1_frost_share_agg(ctx, &agg_share, agg_vss_commitment, share_ptr, vss_ptr, pok_ptr, 2, 2, id_ptr[0]);
442443
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
443444
CHECK(ret == 1);
444445
SECP256K1_CHECKMEM_UNDEFINE(&agg_share, sizeof(&agg_share));
445-
CHECK(secp256k1_frost_compute_pubshare(ctx, &pubshare[0], 2, id_ptr[0], vss_ptr, 2));
446-
CHECK(secp256k1_frost_compute_pubshare(ctx, &pubshare[1], 2, id_ptr[1], vss_ptr, 2));
446+
CHECK(secp256k1_frost_compute_pubshare(ctx, &pubshare[0], 2, id_ptr[0], agg_vss_commitment, 2));
447+
CHECK(secp256k1_frost_compute_pubshare(ctx, &pubshare[1], 2, id_ptr[1], agg_vss_commitment, 2));
447448
CHECK(secp256k1_frost_pubkey_gen(ctx, &cache, pubshares_ptr, 2, id_ptr));
448449
/* nonce_gen */
449450
SECP256K1_CHECKMEM_UNDEFINE(session_id, sizeof(session_id));

src/modules/frost/keygen_impl.h

+69-26
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ typedef struct {
227227
const secp256k1_context *ctx;
228228
secp256k1_scalar idx;
229229
secp256k1_scalar idxn;
230-
const secp256k1_pubkey * const* vss_commitment;
230+
const secp256k1_pubkey *vss_commitment;
231231
} secp256k1_frost_verify_share_ecmult_data;
232232

233233
typedef struct {
@@ -245,9 +245,15 @@ typedef struct {
245245
size_t n_pubshares;
246246
} secp256k1_frost_interpolate_pubkey_ecmult_data;
247247

248+
typedef struct {
249+
const secp256k1_context *ctx;
250+
size_t idxn;
251+
const secp256k1_pubkey * const* vss_commitments;
252+
} secp256k1_frost_vss_agg_ecmult_data;
253+
248254
static int secp256k1_frost_verify_share_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
249255
secp256k1_frost_verify_share_ecmult_data *ctx = (secp256k1_frost_verify_share_ecmult_data *) data;
250-
if (!secp256k1_pubkey_load(ctx->ctx, pt, *(ctx->vss_commitment)+idx)) {
256+
if (!secp256k1_pubkey_load(ctx->ctx, pt, &ctx->vss_commitment[idx])) {
251257
return 0;
252258
}
253259
*sc = ctx->idxn;
@@ -288,8 +294,20 @@ static int secp256k1_frost_interpolate_pubkey_ecmult_callback(secp256k1_scalar *
288294
return 1;
289295
}
290296

297+
static int secp256k1_frost_vss_agg_pubkey_ecmult_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
298+
secp256k1_frost_vss_agg_ecmult_data *ctx = (secp256k1_frost_vss_agg_ecmult_data *) data;
299+
300+
if (!secp256k1_pubkey_load(ctx->ctx, pt, &ctx->vss_commitments[idx][ctx->idxn])) {
301+
return 0;
302+
}
303+
304+
*sc = secp256k1_scalar_one;
305+
306+
return 1;
307+
}
308+
291309
/* See RFC 9591 */
292-
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) {
310+
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) {
293311
secp256k1_scalar share_neg;
294312
secp256k1_gej tmpj, snj;
295313
secp256k1_ge sng;
@@ -319,7 +337,7 @@ static int secp256k1_frost_vss_verify_internal(const secp256k1_context* ctx, siz
319337
return secp256k1_gej_is_infinity(&tmpj);
320338
}
321339

322-
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) {
340+
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) {
323341
secp256k1_scalar share_i;
324342

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

338-
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) {
339-
secp256k1_gej pkj;
356+
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) {
357+
secp256k1_gej tmpj;
340358
secp256k1_ge tmp;
341-
secp256k1_frost_compute_pubshare_ecmult_data compute_pubshare_ecmult_data;
359+
secp256k1_frost_verify_share_ecmult_data verify_share_ecmult_data;
342360

343361
VERIFY_CHECK(ctx != NULL);
362+
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
344363
ARG_CHECK(pubshare != NULL);
345364
memset(pubshare, 0, sizeof(*pubshare));
346365
ARG_CHECK(id33 != NULL);
347-
ARG_CHECK(vss_commitments != NULL);
366+
ARG_CHECK(agg_vss_commitment != NULL);
348367
ARG_CHECK(n_participants > 1);
349368
ARG_CHECK(threshold > 1);
350369

351370
if (threshold > n_participants) {
352371
return 0;
353372
}
354373

355-
/* Use an EC multi-multiplication to compute the following equation:
356-
* agg_share_i*G = (
357-
* idx^0*vss_commitment[0][0] + ...
358-
* + idx^(t - 1)*vss_commitment[0][t - 1]
359-
* ) + ...
360-
* + (
361-
* idx^0*vss_commitment[n - 1][0] + ...
362-
* + idx^(t - 1)*vss_commitment[n - 1][t - 1]
363-
* )*/
364-
compute_pubshare_ecmult_data.ctx = ctx;
365-
compute_pubshare_ecmult_data.vss_commitments = vss_commitments;
366-
compute_pubshare_ecmult_data.threshold = threshold;
374+
/* Use an EC multi-multiplication to verify the following equation:
375+
* agg_share_i * G = idx^0*agg_vss_commitment[0]
376+
* + ...
377+
* + idx^(threshold - 1)*agg_vss_commitment[threshold - 1]*/
378+
verify_share_ecmult_data.ctx = ctx;
379+
verify_share_ecmult_data.vss_commitment = agg_vss_commitment;
367380
/* Evaluate the public polynomial at the idx */
368-
if (!secp256k1_frost_compute_indexhash(&compute_pubshare_ecmult_data.idx, id33)) {
381+
if (!secp256k1_frost_compute_indexhash(&verify_share_ecmult_data.idx, id33)) {
369382
return 0;
370383
}
371-
secp256k1_scalar_set_int(&compute_pubshare_ecmult_data.idxn, 1);
384+
secp256k1_scalar_set_int(&verify_share_ecmult_data.idxn, 1);
372385
/* TODO: add scratch */
373-
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)) {
386+
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, NULL, &tmpj, NULL, secp256k1_frost_verify_share_ecmult_callback, (void *) &verify_share_ecmult_data, threshold)) {
374387
return 0;
375388
}
376-
secp256k1_ge_set_gej(&tmp, &pkj);
389+
secp256k1_ge_set_gej(&tmp, &tmpj);
377390
secp256k1_pubkey_save(pubshare, &tmp);
378391

379392
return 1;
380393
}
381394

382-
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) {
395+
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) {
396+
secp256k1_gej tmpj;
397+
secp256k1_ge tmp;
398+
secp256k1_frost_vss_agg_ecmult_data vss_agg_ecmult_data;
399+
400+
VERIFY_CHECK(ctx != NULL);
401+
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
402+
ARG_CHECK(agg_vss_commitment != NULL);
403+
ARG_CHECK(vss_commitments != NULL);
404+
ARG_CHECK(n_participants > 1);
405+
ARG_CHECK(threshold > 1);
406+
407+
vss_agg_ecmult_data.ctx = ctx;
408+
vss_agg_ecmult_data.vss_commitments = vss_commitments;
409+
410+
for (vss_agg_ecmult_data.idxn = 0; vss_agg_ecmult_data.idxn < threshold; vss_agg_ecmult_data.idxn++) {
411+
/* TODO: add scratch */
412+
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)) {
413+
return 0;
414+
}
415+
secp256k1_ge_set_gej(&tmp, &tmpj);
416+
secp256k1_pubkey_save(&agg_vss_commitment[vss_agg_ecmult_data.idxn], &tmp);
417+
}
418+
419+
return 1;
420+
}
421+
422+
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) {
383423
secp256k1_scalar acc;
384424
size_t i;
385425
int ret = 1;
@@ -422,10 +462,13 @@ int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_shar
422462
return 0;
423463
}
424464
/* Verify share against commitments */
425-
ret &= secp256k1_frost_vss_verify_internal(ctx, threshold, id33, &share_i, &vss_commitments[i]);
465+
ret &= secp256k1_frost_vss_verify_internal(ctx, threshold, id33, &share_i, vss_commitments[i]);
426466
secp256k1_scalar_add(&acc, &acc, &share_i);
427467
}
428468
secp256k1_frost_share_save(agg_share, &acc);
469+
if (!secp256k1_frost_vss_agg(ctx, agg_vss_commitment, vss_commitments, n_shares, threshold)) {
470+
return 0;
471+
}
429472

430473
return ret;
431474
}

0 commit comments

Comments
 (0)