diff --git a/examples/frost.c b/examples/frost.c index 8a028cc46..8a7e3b3bb 100644 --- a/examples/frost.c +++ b/examples/frost.c @@ -75,10 +75,12 @@ int create_shares(const secp256k1_context* ctx, struct signer_secrets *signer_se secp256k1_frost_share shares[N_SIGNERS][N_SIGNERS]; const secp256k1_pubkey *vss_commitments[N_SIGNERS]; const unsigned char *ids[N_SIGNERS]; + const unsigned char *poks[N_SIGNERS]; for (i = 0; i < N_SIGNERS; i++) { vss_commitments[i] = signer[i].vss_commitment; ids[i] = signer[i].id; + poks[i] = signer[i].pok; } for (i = 0; i < N_SIGNERS; i++) { @@ -99,7 +101,7 @@ 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, pk, assigned_shares, vss_commitments, N_SIGNERS, THRESHOLD, signer[i].id)) { + if (!secp256k1_frost_share_agg(ctx, &signer_secrets[i].agg_share, pk, assigned_shares, vss_commitments, poks, N_SIGNERS, THRESHOLD, signer[i].id)) { return 0; } for (j = 0; j < N_SIGNERS; j++) { diff --git a/include/secp256k1_frost.h b/include/secp256k1_frost.h index f6764fa7e..459cea029 100644 --- a/include/secp256k1_frost.h +++ b/include/secp256k1_frost.h @@ -255,10 +255,11 @@ SECP256K1_API int secp256k1_frost_share_agg( secp256k1_xonly_pubkey *agg_pk, 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 * diff --git a/src/ctime_tests.c b/src/ctime_tests.c index d0e0a5a78..44071b4d3 100644 --- a/src/ctime_tests.c +++ b/src/ctime_tests.c @@ -383,6 +383,7 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) { unsigned char id[2][33]; const unsigned char *id_ptr[2]; size_t size = 33; + const unsigned char *pok_ptr[2]; id_ptr[0] = id[0]; id_ptr[1] = id[1]; @@ -406,6 +407,8 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) { share_ptr[1] = &shares[1][0]; vss_ptr[0] = vss_commitment[0]; vss_ptr[1] = vss_commitment[1]; + pok_ptr[0] = pok[0]; + pok_ptr[1] = pok[1]; CHECK(secp256k1_keypair_create(ctx, &keypair, key)); CHECK(secp256k1_keypair_create(ctx, &keypair2, key2)); @@ -431,7 +434,8 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) { SECP256K1_CHECKMEM_DEFINE(&vss_commitment[1][0], sizeof(secp256k1_pubkey)); SECP256K1_CHECKMEM_DEFINE(&vss_commitment[1][1], sizeof(secp256k1_pubkey)); SECP256K1_CHECKMEM_DEFINE(pok[0], 64); - ret = secp256k1_frost_share_agg(ctx, &agg_share, &agg_pk, share_ptr, vss_ptr, 2, 2, id_ptr[0]); + SECP256K1_CHECKMEM_DEFINE(pok[1], 64); + ret = secp256k1_frost_share_agg(ctx, &agg_share, &agg_pk, share_ptr, vss_ptr, pok_ptr, 2, 2, id_ptr[0]); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); /* nonce_gen */ diff --git a/src/modules/frost/keygen_impl.h b/src/modules/frost/keygen_impl.h index fadd27f28..5a1d194ee 100644 --- a/src/modules/frost/keygen_impl.h +++ b/src/modules/frost/keygen_impl.h @@ -385,7 +385,7 @@ int secp256k1_frost_compute_pubshare(const secp256k1_context* ctx, secp256k1_pub return 1; } -int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_share *agg_share, secp256k1_xonly_pubkey *agg_pk, const secp256k1_frost_share * const* shares, const secp256k1_pubkey * const* vss_commitments, size_t n_shares, size_t threshold, const unsigned char *id33) { +int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_share *agg_share, secp256k1_xonly_pubkey *agg_pk, 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_frost_pubkey_combine_ecmult_data pubkey_combine_ecmult_data; secp256k1_gej pkj; secp256k1_ge pkp; @@ -393,6 +393,8 @@ int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_shar secp256k1_scalar acc; size_t i; int ret = 1; + secp256k1_sha256 sha; + unsigned char buf[32]; VERIFY_CHECK(ctx != NULL); ARG_CHECK(agg_share != NULL); @@ -400,6 +402,7 @@ int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_shar ARG_CHECK(agg_pk != NULL); memset(agg_pk, 0, sizeof(*agg_pk)); ARG_CHECK(shares != NULL); + ARG_CHECK(pok64s != NULL); ARG_CHECK(vss_commitments != NULL); ARG_CHECK(id33 != NULL); ARG_CHECK(n_shares > 1); @@ -409,6 +412,20 @@ int secp256k1_frost_share_agg(const secp256k1_context* ctx, secp256k1_frost_shar return 0; } + /* Verify proofs-of-knowledge */ + secp256k1_sha256_initialize_tagged(&sha, (unsigned char*)"FROST/KeygenPoK", sizeof("FROST/KeygenPoK") - 1); + secp256k1_sha256_finalize(&sha, buf); + for (i = 0; i < n_shares; i++) { + secp256k1_xonly_pubkey pk; + + if (!secp256k1_xonly_pubkey_from_pubkey(ctx, &pk, NULL, &vss_commitments[i][0])) { + return 0; + } + if (!secp256k1_schnorrsig_verify(ctx, pok64s[i], buf, 32, &pk)) { + return 0; + } + } + secp256k1_scalar_clear(&acc); for (i = 0; i < n_shares; i++) { secp256k1_scalar share_i; diff --git a/src/modules/frost/tests_impl.h b/src/modules/frost/tests_impl.h index ab256c7a1..27719d3c3 100644 --- a/src/modules/frost/tests_impl.h +++ b/src/modules/frost/tests_impl.h @@ -58,6 +58,7 @@ void frost_simple_test(void) { int i, j; unsigned char id[5][33]; const unsigned char *id_ptr[5]; + const unsigned char *pok_ptr[5]; for (i = 0; i < 5; i++) { secp256k1_testrand256(buf[i]); @@ -66,6 +67,7 @@ void frost_simple_test(void) { pubnonce_ptr[i] = &pubnonce[i]; partial_sig_ptr[i] = &partial_sig[i]; id_ptr[i] = id[i]; + pok_ptr[i] = pok[i]; CHECK(frost_create_pk(id[i], sk[i])); } @@ -78,7 +80,7 @@ void frost_simple_test(void) { CHECK(secp256k1_frost_share_verify(CTX, 3, id_ptr[i], share_ptr[j], &vss_ptr[j]) == 1); CHECK(secp256k1_frost_compute_pubshare(CTX, &pubshare[j], 3, id_ptr[j], vss_ptr, 5) == 1); } - CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 3, id_ptr[i]) == 1); + CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, pok_ptr, 5, 3, id_ptr[i]) == 1); } secp256k1_testrand256(msg); @@ -177,6 +179,8 @@ void frost_api_tests(void) { int i, j; unsigned char id[5][33]; const unsigned char *id_ptr[5]; + const unsigned char *pok_ptr[5]; + const unsigned char *invalid_pok_ptr[5]; /** setup **/ memset(max64, 0xff, sizeof(max64)); @@ -205,6 +209,8 @@ void frost_api_tests(void) { partial_sig_ptr[i] = &partial_sig[i]; invalid_partial_sig_ptr[i] = &partial_sig[i]; id_ptr[i] = id[i]; + pok_ptr[i] = pok[i]; + invalid_pok_ptr[i] = pok[i]; secp256k1_testrand256(session_id[i]); secp256k1_testrand256(seed[i]); secp256k1_testrand256(sk[i]); @@ -212,6 +218,7 @@ void frost_api_tests(void) { } invalid_pubnonce_ptr[0] = &invalid_pubnonce; invalid_partial_sig_ptr[0] = &invalid_partial_sig; + invalid_pok_ptr[0] = max64; for (i = 0; i < 5; i++) { for (j = 0; j < 3; j++) { invalid_vss_commitment[i][j] = invalid_vss_pk; @@ -257,41 +264,48 @@ void frost_api_tests(void) { invalid_share_ptr[j] = &shares[j][i]; } invalid_share_ptr[0] = &invalid_share; - - CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 3, id_ptr[i]) == 1); - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, NULL, &agg_pk, share_ptr, vss_ptr, 5, 3, id_ptr[i])); - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], NULL, share_ptr, vss_ptr, 5, 3, id_ptr[i])); + CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, pok_ptr, 5, 3, id_ptr[i]) == 1); + CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, invalid_pok_ptr, 5, 3, id_ptr[i]) == 0); + CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); + CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, NULL, &agg_pk, share_ptr, vss_ptr, pok_ptr, 5, 3, id_ptr[i])); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], NULL, share_ptr, vss_ptr, pok_ptr, 5, 3, id_ptr[i])); CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, NULL, vss_ptr, 5, 3, id_ptr[i])); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, NULL, vss_ptr, pok_ptr, 5, 3, id_ptr[i])); + CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); + CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, NULL, pok_ptr, 5, 3, id_ptr[i])); + CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); + CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, invalid_vss_ptr, pok_ptr, 5, 3, id_ptr[i])); + CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); + CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, NULL, 5, 3, id_ptr[i])); CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, NULL, 5, 3, id_ptr[i])); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, pok_ptr, 5, 3, NULL)); CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); - /* TODO: fix test */ - /* CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, invalid_vss_ptr, 5, 3, id_ptr[i])); */ - /* CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); */ - /* CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); */ - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 3, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, invalid_share_ptr, vss_ptr, pok_ptr, 5, 3, id_ptr[i])); CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, invalid_share_ptr, vss_ptr, 5, 3, id_ptr[i])); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, pok_ptr, 0, 3, id_ptr[i])); CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 0, 3, id_ptr[i])); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, NULL, vss_ptr, pok_ptr, 0, 3, id_ptr[i])); CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, NULL, vss_ptr, 0, 3, id_ptr[i])); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, pok_ptr, 5, 0, id_ptr[i])); CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 0, id_ptr[i])); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, NULL, pok_ptr, 5, 0, id_ptr[i])); CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); - CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, NULL, 5, 0, id_ptr[i])); + CHECK_ILLEGAL(CTX, secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, NULL, 5, 0, id_ptr[i])); CHECK(frost_memcmp_and_randomize(agg_share[i].data, zeros68, sizeof(agg_share[i].data)) == 0); CHECK(frost_memcmp_and_randomize(agg_pk.data, zeros68, sizeof(agg_pk.data)) == 0); - CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, 5, 3, id_ptr[i]) == 1); + CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &agg_pk, share_ptr, vss_ptr, pok_ptr, 5, 3, id_ptr[i]) == 1); } /* Share verification */ @@ -701,6 +715,7 @@ void frost_tweak_test(void) { int i, j; unsigned char id[5][33]; const unsigned char *id_ptr[5]; + const unsigned char *pok_ptr[5]; /* Key Setup */ for (i = 0; i < 5; i++) { @@ -708,6 +723,7 @@ void frost_tweak_test(void) { secp256k1_testrand256(sk[i]); vss_ptr[i] = vss_commitment[i]; id_ptr[i] = id[i]; + pok_ptr[i] = pok[i]; CHECK(frost_create_pk(id[i], sk[i])); } @@ -720,7 +736,7 @@ void frost_tweak_test(void) { CHECK(secp256k1_frost_share_verify(CTX, 3, id_ptr[i], share_ptr[j], &vss_ptr[j]) == 1); CHECK(secp256k1_frost_compute_pubshare(CTX, &pubshare[j], 3, id_ptr[j], vss_ptr, 5) == 1); } - CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &P_xonly[0], share_ptr, vss_ptr, 5, 3, id_ptr[i]) == 1); + CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], &P_xonly[0], share_ptr, vss_ptr, pok_ptr, 5, 3, id_ptr[i]) == 1); } frost_tweak_test_helper(&P_xonly[0], &agg_share[0], &agg_share[1], &agg_share[2], NULL, id_ptr, &pubshare[0], &pubshare[1], &pubshare[2]); @@ -768,10 +784,12 @@ void frost_dkg_test_helper(secp256k1_frost_share *agg_share, secp256k1_xonly_pub secp256k1_frost_share shares[5][5]; const secp256k1_frost_share *share_ptr[5]; int i, j; + const unsigned char *pok_ptr[5]; for (i = 0; i < 5; i++) { secp256k1_testrand256(seed[i]); vss_ptr[i] = vss_commitment[i]; + pok_ptr[i] = pok[i]; } for (i = 0; i < 5; i++) { CHECK(secp256k1_frost_shares_gen(CTX, shares[i], vss_commitment[i], pok[i], seed[i], 3, 5, ids33) == 1); @@ -780,7 +798,7 @@ void frost_dkg_test_helper(secp256k1_frost_share *agg_share, secp256k1_xonly_pub for (j = 0; j < 5; j++) { share_ptr[j] = &shares[j][i]; } - CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], agg_pk, share_ptr, vss_ptr, 5, 3, ids33[i]) == 1); + CHECK(secp256k1_frost_share_agg(CTX, &agg_share[i], agg_pk, share_ptr, vss_ptr, pok_ptr, 5, 3, ids33[i]) == 1); } }