From 9b078c753b03c260a9bd4e6a5684e083281d4f67 Mon Sep 17 00:00:00 2001 From: Matteo Nardelli Date: Mon, 27 Nov 2023 13:37:08 +0000 Subject: [PATCH] Review generate_shares function to use names as in the IETF proposal --- include/secp256k1_frost.h | 42 ++++---- src/modules/frost/main_impl.h | 181 +++++++++++++++++++--------------- 2 files changed, 125 insertions(+), 98 deletions(-) diff --git a/include/secp256k1_frost.h b/include/secp256k1_frost.h index c50166fbd2..f0a5aef06f 100644 --- a/include/secp256k1_frost.h +++ b/include/secp256k1_frost.h @@ -179,29 +179,29 @@ SECP256K1_API void secp256k1_frost_keypair_destroy(secp256k1_frost_keypair *keyp * secp256k1_frost_keygen_dkg_begin() is performed by each participant to initialize a Pedersen * * This function assumes there is an additional layer which performs the - * distribution of shares to their intended participants. + * distribution of secret_key_shares to their intended participants. * - * Note that while secp256k1_frost_keygen_dkg_begin() returns Shares, these shares + * Note that while secp256k1_frost_keygen_dkg_begin() returns Shares, these secret_key_shares * should be sent *after* participants have exchanged commitments via * secp256k1_frost_keygen_dkg_commitment_validate(). So, the caller of - * secp256k1_frost_keygen_dkg_begin() should store shares until after + * secp256k1_frost_keygen_dkg_begin() should store secret_key_shares until after * secp256k1_frost_keygen_dkg_commitment_validate() is complete, and then - * exchange shares via secp256k1_frost_keygen_dkg_finalize(). + * exchange secret_key_shares via secp256k1_frost_keygen_dkg_finalize(). * * Returns 1 on success, 0 on failure. * Args: ctx: pointer to a context object, initialized for signing. - * Out: dkg_commitment: pointer to a secp256k1_frost_vss_commitments to store the DKG first phase result. - * shares: pointer to an array of num_shares shares - * In: num_participants: number of participants and shares that will be produced. - * threshold: validity threshold for signatures. - * generator_index: index of the participant running the DKG. - * context: pointer to a char array containing DKG context tag. - * context_length: length of the char array with the DKG context. + * Out: vss_commitments: pointer to a secp256k1_frost_vss_commitments to store the DKG first phase result. + * secret_key_shares: pointer to an array of num_shares secret_key_shares + * In: num_participants: number of participants and secret_key_shares that will be produced. + * threshold: validity threshold for signatures. + * generator_index: index of the participant running the DKG. + * context: pointer to a char array containing DKG context tag. + * context_length: length of the char array with the DKG context. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_dkg_begin( const secp256k1_context *ctx, - secp256k1_frost_vss_commitments *dkg_commitment, - secp256k1_frost_keygen_secret_share *shares, + secp256k1_frost_vss_commitments *vss_commitments, + secp256k1_frost_keygen_secret_share *secret_key_shares, uint32_t num_participants, uint32_t threshold, uint32_t generator_index, @@ -257,20 +257,20 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_dkg_finali /* * secp256k1_frost_keygen_with_dealer() allows to create keygen for each participant. * This function is intended to be executed by a trusted dealer that generates and - * distributes the secret shares. + * distributes the secret secret_key_shares. * * Returns 1 on success, 0 on failure. * Args: ctx: pointer to a context object, initialized for signing. - * Out: share_commitment: pointer to a secp256k1_frost_vss_commitments to store the dealer commitments. - * shares: pointer to an array of num_shares shares - * keypair: pointer to a frost_keypair to store the generated keypairs. - * In: num_participants: number of participants and shares that will be produced. - * threshold: validity threshold for signatures. + * Out: vss_commitments: pointer to a secp256k1_frost_vss_commitments to store the dealer commitments. + * secret_key_shares: pointer to an array of num_shares secret_key_shares + * keypair: pointer to a frost_keypair to store the generated keypairs. + * In: num_participants: number of participants and secret_key_shares that will be produced. + * threshold: validity threshold for signatures. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_with_dealer( const secp256k1_context *ctx, - secp256k1_frost_vss_commitments *share_commitment, - secp256k1_frost_keygen_secret_share *shares, + secp256k1_frost_vss_commitments *vss_commitments, + secp256k1_frost_keygen_secret_share *secret_key_shares, secp256k1_frost_keypair *keypairs, uint32_t num_participants, uint32_t threshold diff --git a/src/modules/frost/main_impl.h b/src/modules/frost/main_impl.h index c630b9ffdd..a79960b5e3 100644 --- a/src/modules/frost/main_impl.h +++ b/src/modules/frost/main_impl.h @@ -446,87 +446,114 @@ SECP256K1_API void secp256k1_frost_keypair_destroy(secp256k1_frost_keypair *keyp } /* - * Generate coefficients for Shamir Secret Sharing. + * Generate random coefficients for Shamir Secret Sharing. * * Returns: 1: on success; 0: on failure - * Args: ctx: a secp256k1 context object, initialized for verification. - * Out: dkg_commitments: pointer to shamir_coefficients where coefficients will be stored. - * coefficients: pointer to shamir_coefficients where coefficients will be stored. + * Out: coefficients: pointer to shamir_coefficients where coefficients will be stored. * In: generator_index: index of participant generating coefficients. - * secret: secret to be used as known term of the Shamir polynomial - * num_participants: number of participants to the secret sharing * threshold: min number of participants needed to reconstruct the secret. */ -static SECP256K1_WARN_UNUSED_RESULT int generate_coefficients(const secp256k1_context *ctx, - secp256k1_frost_vss_commitments *dkg_commitments, - shamir_coefficients *coefficients, - uint32_t generator_index, const secp256k1_scalar *secret, - uint32_t threshold) { +static SECP256K1_WARN_UNUSED_RESULT int generate_random_coefficients(shamir_coefficients *coefficients, + uint32_t generator_index, + uint32_t threshold) { uint32_t c_idx; - secp256k1_gej coefficient_cmt; const uint32_t num_coefficients = threshold - 1; coefficients->index = generator_index; - dkg_commitments->index = generator_index; - - /* Compute the commitment of the secret term (saved as commitment[0]) */ - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &coefficient_cmt, secret); - serialize_point(&coefficient_cmt, dkg_commitments->coefficient_commitments[0].data); - for (c_idx = 0; c_idx < num_coefficients; c_idx++) { /* Generate random coefficients */ if (initialize_random_scalar(&(coefficients->coefficients[c_idx])) == 0) { return 0; } + } + return 1; +} + +/* + * Commit to Verifiable Secret Shares + * + * Args: ctx: a secp256k1 context object, initialized for verification. + * Out: vss_commitments: pointer to shamir_coefficients where coefficients will be stored. + * In: coefficients: pointer to shamir_coefficients where coefficients will be stored. + * secret: secret to be used as known term of the Shamir polynomial + * threshold: min number of participants needed to reconstruct the secret. + */ +static void vss_commit(const secp256k1_context *ctx, + secp256k1_frost_vss_commitments *vss_commitments, + const shamir_coefficients *coefficients, + const secp256k1_scalar *secret, + uint32_t threshold) { + uint32_t c_idx; + secp256k1_gej coefficient_cmt; + const uint32_t num_coefficients = threshold - 1; + + vss_commitments->index = coefficients->index; + + /* Compute the commitment of the secret term (saved as commitment[0]) */ + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &coefficient_cmt, secret); + serialize_point(&coefficient_cmt, vss_commitments->coefficient_commitments[0].data); + for (c_idx = 0; c_idx < num_coefficients; c_idx++) { /* Compute the commitment of each random coefficient (saved as commitment[1...]) */ secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &coefficient_cmt, &(coefficients->coefficients[c_idx])); - serialize_point(&coefficient_cmt, dkg_commitments->coefficient_commitments[c_idx + 1].data); + serialize_point(&coefficient_cmt, vss_commitments->coefficient_commitments[c_idx + 1].data); } - return 1; } + /* - * Evaluate Shamir polynomial for each participant. + * Evaluate the Shamir polynomial f(x) at a particular point x using Horner's method. + * + * Out: value: Scalar result of the polynomial evaluated at input x. + * In: coefficients: pointer to shamir_coefficients + * secret: secret to be used as known term of the Shamir polynomial + * x: input at which to evaluate the polynomial (treated as a Scalar) + */ +static void polynomial_evaluate(secp256k1_scalar *value, + const shamir_coefficients *coefficients, const secp256k1_scalar *secret, + uint32_t x) { + secp256k1_scalar scalar_x; + uint32_t c_idx; + + secp256k1_scalar_set_int(&scalar_x, x); + secp256k1_scalar_set_int(value, 0); + for (c_idx = coefficients->num_coefficients; c_idx > 0; c_idx--) { + secp256k1_scalar_add(value, value, &(coefficients->coefficients[c_idx - 1])); + secp256k1_scalar_mul(value, value, &scalar_x); + } + + /* The secret is the *constant* term in the polynomial used for secret sharing, + * this is typical in schemes that build upon Shamir Secret Sharing. */ + secp256k1_scalar_add(value, value, secret); +} + +/* + * Shard secret for each participant by evaluating the Shamir polynomial. * * Returns: 1: on success; 0: on failure - * Out: shares: pointer to shamir_coefficients where coefficients will be stored (expected to be already allocated). - * In: coefficients: pointer to shamir_coefficients where coefficients will be stored. - * generator_index: index of participant generating coefficients. - * num_participants: number of participants to the secret sharing - * coefficients: pointer to shamir_coefficients. - * secret: secret to be used as known term of the Shamir polynomial. + * Out: secret_key_shares: pointer to shamir_coefficients where coefficients will be stored (expected to be already allocated). + * In: generator_index: index of participant generating coefficients. + * num_participants: number of participants to the secret sharing + * coefficients: pointer to shamir_coefficients. + * secret: secret to be used as known term of the Shamir polynomial. */ -static void evaluate_shamir_polynomial(secp256k1_frost_keygen_secret_share *shares, - uint32_t generator_index, uint32_t num_participants, - const shamir_coefficients *coefficients, const secp256k1_scalar *secret) { - /* For each participant, evaluate the polynomial and save in shares: +static void secret_share_shard(secp256k1_frost_keygen_secret_share *secret_key_shares, + uint32_t generator_index, uint32_t num_participants, + const shamir_coefficients *coefficients, const secp256k1_scalar *secret) { + /* For each participant, evaluate the polynomial and save in secret_key_shares: * {generator_index, participant_index, f(participant_index)} */ uint32_t index; for (index = 1; index < num_participants + 1; index++) { - /* Evaluate the polynomial with `secret` as the constant term - * and `coefficients` as the other coefficients at the point x=share_index - * using Horner's method */ - secp256k1_scalar scalar_index; secp256k1_scalar value; - uint32_t c_idx; - - secp256k1_scalar_set_int(&scalar_index, index); - secp256k1_scalar_set_int(&value, 0); - for (c_idx = coefficients->num_coefficients; c_idx > 0; c_idx--) { - secp256k1_scalar_add(&value, &value, &(coefficients->coefficients[c_idx - 1])); - secp256k1_scalar_mul(&value, &value, &scalar_index); - } - /* The secret is the *constant* term in the polynomial used for secret sharing, - * this is typical in schemes that build upon Shamir Secret Sharing. */ - secp256k1_scalar_add(&value, &value, secret); - secp256k1_scalar_get_b32(shares[index - 1].value, &value); + polynomial_evaluate(&value, coefficients, secret, index); - shares[index - 1].generator_index = generator_index; - shares[index - 1].receiver_index = index; + /* Save share in secret_key_shares */ + secp256k1_scalar_get_b32(secret_key_shares[index - 1].value, &value); + secret_key_shares[index - 1].generator_index = generator_index; + secret_key_shares[index - 1].receiver_index = index; } } @@ -536,16 +563,16 @@ static void evaluate_shamir_polynomial(secp256k1_frost_keygen_secret_share *shar * * Returns 1 on success, 0 on failure. * Args: ctx: pointer to a context object, initialized for signing. - * Out: coefficients: commitments to the Shamir polynomial coefficients. - * shares: array containing the polynomial computed for each participant (expected to be allocated) - * In: num_participants: number of shares and commitments. - * threshold: Signature threshold - * generator_index: participant index. - * secret: Secret value to use as constant term of the polynomial + * Out: vss_coefficients: commitments to the Shamir polynomial coefficients. + * secret_key_shares: array containing the polynomial computed for each participant (expected to be allocated) + * In: num_participants: number of secret_key_shares and commitments. + * threshold: Signature threshold + * generator_index: participant index. + * secret: Secret value to use as constant term of the polynomial */ static SECP256K1_WARN_UNUSED_RESULT int generate_shares(const secp256k1_context *ctx, - secp256k1_frost_vss_commitments *dkg_commitments, - secp256k1_frost_keygen_secret_share *shares, + secp256k1_frost_vss_commitments *vss_commitments, + secp256k1_frost_keygen_secret_share *secret_key_shares, uint32_t num_participants, uint32_t threshold, uint32_t generator_index, const secp256k1_scalar *secret) { @@ -553,10 +580,10 @@ static SECP256K1_WARN_UNUSED_RESULT int generate_shares(const secp256k1_context shamir_coefficients *coefficients; coefficients = shamir_coefficients_create(threshold); - ret_coefficients = generate_coefficients(ctx, dkg_commitments, coefficients, generator_index, secret, threshold); + ret_coefficients = generate_random_coefficients(coefficients, generator_index, threshold); if (ret_coefficients == 1) { - evaluate_shamir_polynomial(shares, generator_index, - num_participants, coefficients, secret); + secret_share_shard(secret_key_shares, generator_index, num_participants, coefficients, secret); + vss_commit(ctx, vss_commitments, coefficients, secret, threshold); } shamir_coefficients_destroy(coefficients); @@ -627,8 +654,8 @@ static SECP256K1_WARN_UNUSED_RESULT int is_valid_zkp(const secp256k1_context *ct /* TODO: to improve testability of this function, it should be deterministic. */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_dkg_begin(const secp256k1_context *ctx, - secp256k1_frost_vss_commitments *dkg_commitment, - secp256k1_frost_keygen_secret_share *shares, + secp256k1_frost_vss_commitments *vss_commitments, + secp256k1_frost_keygen_secret_share *secret_key_shares, uint32_t num_participants, uint32_t threshold, uint32_t generator_index, @@ -637,18 +664,18 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_dkg_begin( secp256k1_scalar secret, r, z, challenge; secp256k1_gej s_pub, zkp_r; - if (ctx == NULL || dkg_commitment == NULL || shares == NULL || context == NULL) { + if (ctx == NULL || vss_commitments == NULL || secret_key_shares == NULL || context == NULL) { return 0; } if (threshold < 1 || num_participants < 1 || threshold > num_participants) { return 0; } - dkg_commitment->index = generator_index; + vss_commitments->index = generator_index; if (initialize_random_scalar(&secret) == 0) { return 0; } - if (generate_shares(ctx, dkg_commitment, shares, num_participants, + if (generate_shares(ctx, vss_commitments, secret_key_shares, num_participants, threshold, generator_index, &secret) == 0) { return 0; } @@ -658,7 +685,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_dkg_begin( } secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &s_pub, &secret); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &zkp_r, &r); - serialize_point(&zkp_r, dkg_commitment->zkp_r); + serialize_point(&zkp_r, vss_commitments->zkp_r); if (generate_dkg_challenge(&challenge, generator_index, context, context_length, &s_pub, &zkp_r) == 0) { return 0; } @@ -666,7 +693,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_dkg_begin( /* z = r + secret * H(context, G^secret, G^r) */ secp256k1_scalar_mul(&z, &secret, &challenge); secp256k1_scalar_add(&z, &r, &z); - secp256k1_scalar_get_b32(dkg_commitment->zkp_z, &z); + secp256k1_scalar_get_b32(vss_commitments->zkp_z, &z); /* Cleaning context */ secp256k1_scalar_set_int(&secret, 0); @@ -774,8 +801,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_dkg_finali SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_with_dealer( const secp256k1_context *ctx, - secp256k1_frost_vss_commitments *share_commitment, - secp256k1_frost_keygen_secret_share *shares, + secp256k1_frost_vss_commitments *vss_commitments, + secp256k1_frost_keygen_secret_share *secret_key_shares, secp256k1_frost_keypair *keypairs, uint32_t num_participants, uint32_t threshold) { @@ -784,11 +811,11 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_with_deale secp256k1_gej group_public_key; uint32_t generator_index, index; - if (ctx == NULL || share_commitment == NULL || shares == NULL || keypairs == NULL) { + if (ctx == NULL || vss_commitments == NULL || secret_key_shares == NULL || keypairs == NULL) { return 0; } - /* We use generator_index=0 as we are generating shares with a dealer */ + /* We use generator_index=0 as we are generating secret_key_shares with a dealer */ generator_index = 0; /* Parameter checking */ @@ -797,14 +824,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_with_deale } /* Initialization */ - share_commitment->index = generator_index; + vss_commitments->index = generator_index; if (initialize_random_scalar(&secret) == 0) { return 0; } secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &group_public_key, &secret); - /* Generate shares */ - if (generate_shares(ctx, share_commitment, shares, num_participants, + /* Generate secret_key_shares */ + if (generate_shares(ctx, vss_commitments, secret_key_shares, num_participants, threshold, generator_index, &secret) == 0) { return 0; } @@ -814,13 +841,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_frost_keygen_with_deale secp256k1_scalar share_value; secp256k1_gej pubkey; - secp256k1_scalar_set_b32(&share_value, shares[index].value, NULL); + secp256k1_scalar_set_b32(&share_value, secret_key_shares[index].value, NULL); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubkey, &share_value); serialize_point(&pubkey, keypairs[index].public_keys.public_key); - memcpy(&keypairs[index].secret, &shares[index].value, SCALAR_SIZE); + memcpy(&keypairs[index].secret, &secret_key_shares[index].value, SCALAR_SIZE); serialize_point(&group_public_key, keypairs[index].public_keys.group_public_key); - keypairs[index].public_keys.index = shares[index].receiver_index; + keypairs[index].public_keys.index = secret_key_shares[index].receiver_index; keypairs[index].public_keys.max_participants = num_participants; } return 1;