diff --git a/src/c_kzg_4844.c b/src/c_kzg_4844.c index 2eaf7ee..d0f146d 100644 --- a/src/c_kzg_4844.c +++ b/src/c_kzg_4844.c @@ -30,6 +30,7 @@ // Macros /////////////////////////////////////////////////////////////////////////////// +/** Returns C_KZG_BADARGS if the condition is not met. */ #define CHECK(cond) \ if (!(cond)) return C_KZG_BADARGS @@ -47,12 +48,24 @@ // Constants /////////////////////////////////////////////////////////////////////////////// -// clang-format off - /** The Fiat-Shamir protocol domains. */ static const char *FIAT_SHAMIR_PROTOCOL_DOMAIN = "FSBLOBVERIFY_V1_"; static const char *RANDOM_CHALLENGE_KZG_BATCH_DOMAIN = "RCKZGBATCH___V1_"; +/** Length of the domain strings above. */ +static const size_t DOMAIN_STR_LENGTH = 16; + +/** The number of bytes in a g1 point. */ +static const size_t BYTES_PER_G1 = 48; + +/** The number of bytes in a g2 point. */ +static const size_t BYTES_PER_G2 = 96; + +/** The number of g2 points in a trusted setup. */ +static const size_t TRUSTED_SETUP_NUM_G2_POINTS = 65; + +// clang-format off + /** Deserialized form of the G1 identity/infinity point. */ static const g1_t G1_IDENTITY = { {0L, 0L, 0L, 0L, 0L, 0L}, @@ -89,7 +102,7 @@ static const g2_t G2_GENERATOR = { * * For element `{A, B, C, D}`, the field element value is * `A + B * 2^64 + C * 2^128 + D * 2^192`. This format may be converted to - * an `fr_t` type via the #blst_fr_from_uint64 function. + * an `fr_t` type via the blst_fr_from_uint64() function. * * The decimal values may be calculated with the following Python code: * @code{.py} @@ -157,7 +170,7 @@ static const fr_t FR_ONE = { /////////////////////////////////////////////////////////////////////////////// /** - * Wrapped `malloc()` that reports failures to allocate. + * Wrapped malloc() that reports failures to allocate. * * @remark Will return C_KZG_BADARGS if the requested size is zero. * @@ -172,7 +185,7 @@ static C_KZG_RET c_kzg_malloc(void **out, size_t size) { } /** - * Wrapped `calloc()` that reports failures to allocate. + * Wrapped calloc() that reports failures to allocate. * * @remark Will return C_KZG_BADARGS if the requested size is zero. * @@ -190,7 +203,7 @@ static C_KZG_RET c_kzg_calloc(void **out, size_t count, size_t size) { /** * Allocate memory for an array of G1 group elements. * - * @remark Free the space later using `c_kzg_free()`. + * @remark Free the space later using c_kzg_free(). * * @param[out] x Pointer to the allocated space * @param[in] n The number of G1 elements to be allocated @@ -202,7 +215,7 @@ static C_KZG_RET new_g1_array(g1_t **x, size_t n) { /** * Allocate memory for an array of G2 group elements. * - * @remark Free the space later using `c_kzg_free()`. + * @remark Free the space later using c_kzg_free(). * * @param[out] x Pointer to the allocated space * @param[in] n The number of G2 elements to be allocated @@ -214,7 +227,7 @@ static C_KZG_RET new_g2_array(g2_t **x, size_t n) { /** * Allocate memory for an array of field elements. * - * @remark Free the space later using `c_kzg_free()`. + * @remark Free the space later using c_kzg_free(). * * @param[out] x Pointer to the allocated space * @param[in] n The number of field elements to be allocated @@ -360,16 +373,31 @@ out: /** * Multiply a G1 group element by a field element. * - * @param[out] out [@p b]@p a + * @param[out] out @p a * @p b * @param[in] a The G1 group element * @param[in] b The multiplier */ static void g1_mul(g1_t *out, const g1_t *a, const fr_t *b) { blst_scalar s; blst_scalar_from_fr(&s, b); + /* The last argument is the number of bits in the scalar */ blst_p1_mult(out, a, s.b, 8 * sizeof(blst_scalar)); } +/** + * Multiply a G2 group element by a field element. + * + * @param[out] out @p a * @p b + * @param[in] a The G2 group element + * @param[in] b The multiplier + */ +static void g2_mul(g2_t *out, const g2_t *a, const fr_t *b) { + blst_scalar s; + blst_scalar_from_fr(&s, b); + /* The last argument is the number of bits in the scalar */ + blst_p2_mult(out, a, s.b, 8 * sizeof(blst_scalar)); +} + /** * Subtraction of G1 group elements. * @@ -396,19 +424,6 @@ static void g2_sub(g2_t *out, const g2_t *a, const g2_t *b) { blst_p2_add_or_double(out, a, &bneg); } -/** - * Multiply a G2 group element by a field element. - * - * @param[out] out [@p b]@p a - * @param[in] a The G2 group element - * @param[in] b The multiplier - */ -static void g2_mul(g2_t *out, const g2_t *a, const fr_t *b) { - blst_scalar s; - blst_scalar_from_fr(&s, b); - blst_p2_mult(out, a, s.b, 8 * sizeof(blst_scalar)); -} - /** * Perform pairings and test whether the outcomes are equal in G_T. * @@ -429,8 +444,10 @@ static bool pairings_verify( blst_p1_affine aa1, bb1; blst_p2_affine aa2, bb2; - // As an optimisation, we want to invert one of the pairings, - // so we negate one of the points. + /* + * As an optimisation, we want to invert one of the pairings, + * so we negate one of the points. + */ g1_t a1neg = *a1; blst_p1_cneg(&a1neg, true); @@ -528,46 +545,29 @@ static bool is_power_of_two(uint64_t n) { return (n & (n - 1)) == 0; } -/** - * Reverse the bits in a byte. - * - * From - * https://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64BitsDiv - * - * @param[in] a A byte - * @return A byte that is bit-reversed with respect to @p a - */ -#define rev_byte(a) ((((a)&0xff) * 0x0202020202ULL & 0x010884422010ULL) % 1023) - -/** - * Reverse the bits in a 32 bit word. - * - * @param[in] a A 32 bit unsigned integer - * @return A 32 bit unsigned integer that is bit-reversed with respect to @p a - */ -#define rev_4byte(a) \ - (rev_byte(a) << 24 | rev_byte((a) >> 8) << 16 | rev_byte((a) >> 16) << 8 | \ - rev_byte((a) >> 24) << 0) - /** * Reverse the bit order in a 32 bit integer. * * @param[in] a The integer to be reversed * @return An integer with the bits of @p a reversed */ -static uint32_t reverse_bits(uint32_t a) { - // This simply wraps the macro above to enforce the type check. - return rev_4byte(a); +static uint32_t reverse_bits(uint32_t n) { + uint32_t result = 0; + for (int i = 0; i < 32; ++i) { + result <<= 1; + result |= (n & 1); + n >>= 1; + } + return result; } /** * Reorder an array in reverse bit order of its indices. * - * @remark This means that input[n] == output[n'], - * where input and output denote the input and output array - * and n' is obtained from n by bit-reversing n. - * As opposed to reverse_bits, this bit-reversal operates on log2(@p - * n)-bit numbers. + * @remark This means that input[n] == output[n'], where input and output + * denote the input and output array and n' is obtained from n by + * bit-reversing n. As opposed to reverse_bits, this bit-reversal + * operates on log2(@p n)-bit numbers. * * @remark Operates in-place on the array. * @remark Can handle arrays of any type: provide the element size in @p size. @@ -584,15 +584,13 @@ static C_KZG_RET bit_reversal_permutation( CHECK(is_power_of_two(n)); CHECK(log2_pow2(n) != 0); - // Pointer arithmetic on `void *` is naughty, so cast to something - // definite byte *v = values; byte tmp[size]; int unused_bit_len = 32 - log2_pow2(n); for (uint32_t i = 0; i < n; i++) { uint32_t r = reverse_bits(i) >> unused_bit_len; if (r > i) { - // Swap the two elements + /* Swap the two elements */ memcpy(tmp, v + (i * size), size); memcpy(v + (i * size), v + (r * size), size); memcpy(v + (r * size), tmp, size); @@ -644,9 +642,10 @@ static C_KZG_RET bytes_to_bls_field(fr_t *out, const Bytes32 *b) { * @param[in] b The proof/commitment bytes */ static C_KZG_RET validate_kzg_g1(g1_t *out, const Bytes48 *b) { - /* Convert the bytes to a p1 point */ blst_p1_affine p1_affine; - /* The uncompress routine also checks that the point is on the curve */ + + /* Convert the bytes to a p1 point */ + /* The uncompress routine checks that the point is on the curve */ if (blst_p1_uncompress(&p1_affine, b->bytes) != BLST_SUCCESS) return C_KZG_BADARGS; blst_p1_from_affine(out, &p1_affine); @@ -697,8 +696,11 @@ static C_KZG_RET blob_to_polynomial(Polynomial *p, const Blob *blob) { return C_KZG_OK; } -/* Input size to the Fiat-Shamir challenge computation */ -static const int CHALLENGE_INPUT_SIZE = 32 + BYTES_PER_BLOB + 48; +/* Input size to the Fiat-Shamir challenge computation. */ +static const size_t CHALLENGE_INPUT_SIZE = DOMAIN_STR_LENGTH + + sizeof(uint64_t) + sizeof(uint64_t) + + BYTES_PER_BLOB + + BYTES_PER_COMMITMENT; /** * Return the Fiat-Shamir challenge required to verify `blob` and `commitment`. @@ -719,13 +721,14 @@ static void compute_challenge( uint8_t *offset = bytes; /* Copy domain separator */ - memcpy(offset, FIAT_SHAMIR_PROTOCOL_DOMAIN, 16); - offset += 16; + memcpy(offset, FIAT_SHAMIR_PROTOCOL_DOMAIN, DOMAIN_STR_LENGTH); + offset += DOMAIN_STR_LENGTH; + + /* Copy polynomial degree (16-bytes, little-endian) */ bytes_from_uint64(offset, FIELD_ELEMENTS_PER_BLOB); - offset += 8; - /* Set all other bytes of this 16-byte (little-endian) field to zero */ + offset += sizeof(uint64_t); bytes_from_uint64(offset, 0); - offset += 8; + offset += sizeof(uint64_t); /* Copy blob */ memcpy(offset, blob->bytes, BYTES_PER_BLOB); @@ -778,7 +781,7 @@ static void g1_lincomb_naive( * * For the benefit of future generations (since Blst has no documentation to * speak of), there are two ways to pass the arrays of scalars and points - * into `blst_p1s_mult_pippenger()`. + * into blst_p1s_mult_pippenger(). * * 1. Pass `points` as an array of pointers to the points, and pass * `scalars` as an array of pointers to the scalars, each of length @p len. @@ -795,11 +798,11 @@ static C_KZG_RET g1_lincomb_fast( blst_p1_affine *p_affine = NULL; blst_scalar *scalars = NULL; - // Tunable parameter: must be at least 2 since Blst fails for 0 or 1 + /* Tunable parameter: must be at least 2 since blst fails for 0 or 1 */ if (len < 8) { g1_lincomb_naive(out, p, coeffs, len); } else { - // Blst's implementation of the Pippenger method + /* blst's implementation of the Pippenger method */ size_t scratch_size = blst_p1s_mult_pippenger_scratch_sizeof(len); ret = c_kzg_malloc(&scratch, scratch_size); if (ret != C_KZG_OK) goto out; @@ -808,16 +811,16 @@ static C_KZG_RET g1_lincomb_fast( ret = c_kzg_calloc((void **)&scalars, len, sizeof(blst_scalar)); if (ret != C_KZG_OK) goto out; - // Transform the points to affine representation + /* Transform the points to affine representation */ const blst_p1 *p_arg[2] = {p, NULL}; blst_p1s_to_affine(p_affine, p_arg, len); - // Transform the field elements to 256-bit scalars + /* Transform the field elements to 256-bit scalars */ for (uint64_t i = 0; i < len; i++) { blst_scalar_from_fr(&scalars[i], &coeffs[i]); } - // Call the Pippenger implementation + /* Call the Pippenger implementation */ const byte *scalars_arg[2] = {(byte *)scalars, NULL}; const blst_p1_affine *points_arg[2] = {p_affine, NULL}; blst_p1s_mult_pippenger( @@ -861,7 +864,7 @@ static void compute_powers(fr_t *out, fr_t *x, uint64_t n) { * @param[out] out The result of the evaluation * @param[in] p The polynomial in evaluation form * @param[in] x The point to evaluate the polynomial at - * @param[in] s The settings struct containing the roots of unity + * @param[in] s The trusted setup */ static C_KZG_RET evaluate_polynomial_in_evaluation_form( fr_t *out, const Polynomial *p, const fr_t *x, const KZGSettings *s @@ -879,10 +882,12 @@ static C_KZG_RET evaluate_polynomial_in_evaluation_form( if (ret != C_KZG_OK) goto out; for (i = 0; i < FIELD_ELEMENTS_PER_BLOB; i++) { - // if the point to evaluate at is one of the evaluation points by which - // the polynomial is given, we can just return the result directly. Note - // that special-casing this is neccessary, as the formula below would - // divide by zero otherwise. + /* + * If the point to evaluate at is one of the evaluation points by which + * the polynomial is given, we can just return the result directly. + * Note that special-casing this is necessary, as the formula below + * would divide by zero otherwise. + */ if (fr_equal(x, &roots_of_unity[i])) { *out = p->evals[i]; ret = C_KZG_OK; @@ -921,8 +926,7 @@ out: * * @param[out] out The resulting commitment * @param[in] p The polynomial to commit to - * @param[in] s The settings struct containing the commitment key - * (i.e. the trusted setup) + * @param[in] s The trusted setup */ static C_KZG_RET poly_to_kzg_commitment( g1_t *out, const Polynomial *p, const KZGSettings *s @@ -937,8 +941,7 @@ static C_KZG_RET poly_to_kzg_commitment( * * @param[out] out The resulting commitment * @param[in] blob The blob representing the polynomial to be committed to - * @param[in] s The settings struct containing the commitment key (i.e. - * the trusted setup) + * @param[in] s The trusted setup */ C_KZG_RET blob_to_kzg_commitment( KZGCommitment *out, const Blob *blob, const KZGSettings *s @@ -962,20 +965,18 @@ static C_KZG_RET verify_kzg_proof_impl( const fr_t *z, const fr_t *y, const g1_t *proof, - const KZGSettings *ks + const KZGSettings *s ); /** * Verify a KZG proof claiming that `p(z) == y`. * - * @param[out] ok `true` if the proof is valid, `false` if not - * @param[in] commitment The KZG commitment corresponding to polynomial - * p(x) + * @param[out] ok True if the proofs are valid, otherwise false + * @param[in] commitment The KZG commitment corresponding to poly p(x) * @param[in] z The evaluation point * @param[in] y The claimed evaluation result * @param[in] kzg_proof The KZG proof - * @param[in] s The settings struct containing the commitment - * verification key (i.e. trusted setup) + * @param[in] s The trusted setup */ C_KZG_RET verify_kzg_proof( bool *ok, @@ -1018,8 +1019,7 @@ C_KZG_RET verify_kzg_proof( * @param[in] y The claimed value of the polynomial at @p x * @param[in] proof A proof of the value of the polynomial at the * point @p x - * @param[in] ks The settings containing the secrets, previously - * initialised with #new_kzg_settings + * @param[in] s The trusted setup */ static C_KZG_RET verify_kzg_proof_impl( bool *out, @@ -1027,18 +1027,21 @@ static C_KZG_RET verify_kzg_proof_impl( const fr_t *z, const fr_t *y, const g1_t *proof, - const KZGSettings *ks + const KZGSettings *s ) { - g2_t x_g2, s_minus_x; - g1_t y_g1, commitment_minus_y; - g2_mul(&x_g2, &G2_GENERATOR, z); - g2_sub(&s_minus_x, &ks->g2_values[1], &x_g2); - g1_mul(&y_g1, &G1_GENERATOR, y); - g1_sub(&commitment_minus_y, commitment, &y_g1); + g2_t x_g2, X_minus_z; + g1_t y_g1, P_minus_y; - *out = pairings_verify( - &commitment_minus_y, &G2_GENERATOR, proof, &s_minus_x - ); + /* Calculate: X_minus_z */ + g2_mul(&x_g2, &G2_GENERATOR, z); + g2_sub(&X_minus_z, &s->g2_values[1], &x_g2); + + /* Calculate: P_minus_y */ + g1_mul(&y_g1, &G1_GENERATOR, y); + g1_sub(&P_minus_y, commitment, &y_g1); + + /* Verify: P - y = Q * (X - z) */ + *out = pairings_verify(&P_minus_y, &G2_GENERATOR, proof, &X_minus_z); return C_KZG_OK; } @@ -1060,8 +1063,7 @@ static C_KZG_RET compute_kzg_proof_impl( * point z * @param[in] blob The blob (polynomial) to generate a proof for * @param[in] z The generator z-value for the evaluation points - * @param[in] s The settings containing the secrets, previously - * initialised with #new_kzg_settings + * @param[in] s The trusted setup */ C_KZG_RET compute_kzg_proof( KZGProof *proof_out, @@ -1095,8 +1097,7 @@ out: * point z * @param[in] polynomial The polynomial in Lagrange form * @param[in] z The evaluation point - * @param[in] s The settings containing the secrets, previously - * initialised with #new_kzg_settings + * @param[in] s The trusted setup */ static C_KZG_RET compute_kzg_proof_impl( KZGProof *proof_out, @@ -1143,7 +1144,7 @@ static C_KZG_RET compute_kzg_proof_impl( blst_fr_mul(&q.evals[i], &q.evals[i], &inverses[i]); } - if (m != 0) { // ω_{m-1} == z + if (m != 0) { /* ω_{m-1} == z */ q.evals[--m] = FR_ZERO; for (i = 0; i < FIELD_ELEMENTS_PER_BLOB; i++) { if (i == m) continue; @@ -1223,12 +1224,11 @@ out: * Given a blob and its proof, verify that it corresponds to the provided * commitment. * - * @param[out] ok `true` if the proof is valid, `false` if not - * @param[in] blob Blob to verify - * @param[in] commitment_bytes Commitment to verify - * @param[in] proof_bytes Proof used for verification - * @param[in] s The settings struct containing the commitment - * verification key (i.e. the trusted setup) + * @param[out] ok True if the proofs are valid, otherwise false + * @param[in] blob Blob to verify + * @param[in] commitment_bytes Commitment to verify + * @param[in] proof_bytes Proof used for verification + * @param[in] s The trusted setup */ C_KZG_RET verify_blob_kzg_proof( bool *ok, @@ -1266,18 +1266,18 @@ C_KZG_RET verify_blob_kzg_proof( } /** + * Compute random linear combination challenge scalars for batch verification. * - * - * @param[out] r_powers_out - * @param[in] commitments_g1 - * @param[in] evaluation_challenges_fr - * @param[in] ys_fr - * @param[in] proofs_g1 + * @param[out] r_powers_out The output challenges + * @param[in] commitments_g1 The input commitments + * @param[in] zs_fr The input evaluation points + * @param[in] ys_fr The input evaluation results + * @param[in] proofs_g1 The input proofs */ static C_KZG_RET compute_r_powers( fr_t *r_powers_out, const g1_t *commitments_g1, - const fr_t *evaluation_challenges_fr, + const fr_t *zs_fr, const fr_t *ys_fr, const g1_t *proofs_g1, size_t n @@ -1287,9 +1287,10 @@ static C_KZG_RET compute_r_powers( Bytes32 r_bytes; fr_t r; - size_t input_size = 32 + - n * (BYTES_PER_COMMITMENT + - 2 * BYTES_PER_FIELD_ELEMENT + BYTES_PER_PROOF); + size_t input_size = DOMAIN_STR_LENGTH + sizeof(uint64_t) + + sizeof(uint64_t) + + (n * (BYTES_PER_COMMITMENT + + 2 * BYTES_PER_FIELD_ELEMENT + BYTES_PER_PROOF)); ret = c_kzg_malloc((void **)&bytes, input_size); if (ret != C_KZG_OK) goto out; @@ -1297,23 +1298,31 @@ static C_KZG_RET compute_r_powers( uint8_t *offset = bytes; /* Copy domain separator */ - memcpy(offset, RANDOM_CHALLENGE_KZG_BATCH_DOMAIN, 16); - offset += 16; + memcpy(offset, RANDOM_CHALLENGE_KZG_BATCH_DOMAIN, DOMAIN_STR_LENGTH); + offset += DOMAIN_STR_LENGTH; + + /* Copy degree of the polynomial */ bytes_from_uint64(offset, FIELD_ELEMENTS_PER_BLOB); - offset += 8; + offset += sizeof(uint64_t); + + /* Copy number of commitments */ bytes_from_uint64(offset, n); - offset += 8; + offset += sizeof(uint64_t); for (size_t i = 0; i < n; i++) { + /* Copy commitment */ bytes_from_g1((Bytes48 *)offset, &commitments_g1[i]); offset += BYTES_PER_COMMITMENT; - bytes_from_bls_field((Bytes32 *)offset, &evaluation_challenges_fr[i]); + /* Copy z */ + bytes_from_bls_field((Bytes32 *)offset, &zs_fr[i]); offset += BYTES_PER_FIELD_ELEMENT; + /* Copy y */ bytes_from_bls_field((Bytes32 *)offset, &ys_fr[i]); offset += BYTES_PER_FIELD_ELEMENT; + /* Copy proof */ bytes_from_g1((Bytes48 *)offset, &proofs_g1[i]); offset += BYTES_PER_PROOF; } @@ -1327,8 +1336,6 @@ static C_KZG_RET compute_r_powers( /* Make sure we wrote the entire buffer */ assert(offset == bytes + input_size); - ret = C_KZG_OK; - out: c_kzg_free(bytes); return ret; @@ -1344,25 +1351,18 @@ out: * * @remark This function only works for `n > 0`. * - * @param[out] ok `true` if the proofs are valid, - * `false` if not - * @param[in] commitments_g1 Array of commitments to verify - * @param[in] evaluation_challenges_fr Array of evaluation of points for the - * KZG proofs - * @param[in] ys_fr Array of evaluation results for the - * KZG proofs - * @param[in] proofs_g1 Array of proofs used for verification - * @param[in] n The number of - * blobs/commitments/proofs in the - * arrays - * @param[in] s The settings struct containing the - * commitment verification key (i.e. the - * trusted setup) + * @param[out] ok True if the proofs are valid, otherwise false + * @param[in] commitments_g1 Array of commitments to verify + * @param[in] zs_fr Array of evaluation points for the KZG proofs + * @param[in] ys_fr Array of evaluation results for the KZG proofs + * @param[in] proofs_g1 Array of proofs used for verification + * @param[in] n The number of blobs/commitments/proofs + * @param[in] s The trusted setup */ static C_KZG_RET verify_kzg_proof_batch( bool *ok, const g1_t *commitments_g1, - const fr_t *evaluation_challenges_fr, + const fr_t *zs_fr, const fr_t *ys_fr, const g1_t *proofs_g1, size_t n, @@ -1388,7 +1388,7 @@ static C_KZG_RET verify_kzg_proof_batch( /* Compute the random lincomb challenges */ ret = compute_r_powers( - r_powers, commitments_g1, evaluation_challenges_fr, ys_fr, proofs_g1, n + r_powers, commitments_g1, zs_fr, ys_fr, proofs_g1, n ); if (ret != C_KZG_OK) goto out; @@ -1401,16 +1401,14 @@ static C_KZG_RET verify_kzg_proof_batch( g1_mul(&ys_encrypted, &G1_GENERATOR, &ys_fr[i]); /* Get C_i - [y_i] */ g1_sub(&C_minus_y[i], &commitments_g1[i], &ys_encrypted); - /* Get r^i * z_i */ - blst_fr_mul(&r_times_z[i], &r_powers[i], &evaluation_challenges_fr[i]); + blst_fr_mul(&r_times_z[i], &r_powers[i], &zs_fr[i]); } /* Get \sum r^i z_i Proof_i */ g1_lincomb_naive(&proof_z_lincomb, proofs_g1, r_times_z, n); /* Get \sum r^i (C_i - [y_i]) */ g1_lincomb_naive(&C_minus_y_lincomb, C_minus_y, r_powers, n); - /* Get C_minus_y_lincomb + proof_z_lincomb */ blst_p1_add_or_double(&rhs_g1, &C_minus_y_lincomb, &proof_z_lincomb); @@ -1419,13 +1417,10 @@ static C_KZG_RET verify_kzg_proof_batch( &proof_lincomb, &s->g2_values[1], &rhs_g1, &G2_GENERATOR ); - ret = C_KZG_OK; - out: c_kzg_free(r_powers); c_kzg_free(C_minus_y); c_kzg_free(r_times_z); - return ret; } @@ -1439,14 +1434,12 @@ out: * * @remark This function accepts if called with `n==0`. * - * @param[out] ok `true` if the proofs are valid, `false` if not + * @param[out] ok True if the proofs are valid, otherwise false * @param[in] blobs Array of blobs to verify * @param[in] commitments_bytes Array of commitments to verify * @param[in] proofs_bytes Array of proofs used for verification - * @param[in] n The number of blobs/commitments/proofs in the - * arrays - * @param[in] s The settings struct containing the commitment - * verification key (i.e. the trusted setup) + * @param[in] n The number of blobs/commitments/proofs + * @param[in] s The trusted setup */ C_KZG_RET verify_blob_kzg_proof_batch( bool *ok, @@ -1482,11 +1475,13 @@ C_KZG_RET verify_blob_kzg_proof_batch( if (ret != C_KZG_OK) goto out; for (size_t i = 0; i < n; i++) { + /* Convert each commitment to a g1 point */ ret = bytes_to_kzg_commitment( &commitments_g1[i], &commitments_bytes[i] ); if (ret != C_KZG_OK) goto out; + /* Convert each blob from bytes to a poly */ ret = blob_to_polynomial(&polynomials[i], &blobs[i]); if (ret != C_KZG_OK) goto out; @@ -1513,7 +1508,6 @@ out: c_kzg_free(evaluation_challenges_fr); c_kzg_free(ys_fr); c_kzg_free(polynomials); - return ret; } @@ -1521,15 +1515,6 @@ out: // Trusted Setup Functions /////////////////////////////////////////////////////////////////////////////// -/** - * Discrete fourier transforms over arrays of G1 group elements. - * - * Also known as [number theoretic - * transforms](https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general)#Number-theoretic_transform). - * - * @remark Functions here work only for lengths that are a power of two. - */ - /** * Fast Fourier Transform. * @@ -1552,7 +1537,7 @@ static void fft_g1_fast( uint64_t n ) { uint64_t half = n / 2; - if (half > 0) { // Tunable parameter + if (half > 0) { /* Tunable parameter */ fft_g1_fast(out, in, stride * 2, roots, roots_stride * 2, half); fft_g1_fast( out + half, in + stride, stride * 2, roots, roots_stride * 2, half @@ -1578,11 +1563,9 @@ static void fft_g1_fast( * * @param[out] out The results (array of length @p n) * @param[in] in The input data (array of length @p n) - * @param[in] inverse `false` for forward transform, `true` for inverse - * transform + * @param[in] inverse False for forward transform, true for inverse transform * @param[in] n Length of the FFT, must be a power of two - * @param[in] fs Pointer to previously initialised FFTSettings - * structure with `max_width` at least @p n + * @param[in] fs The FFTSettings */ static C_KZG_RET fft_g1( g1_t *out, const g1_t *in, bool inverse, uint64_t n, const FFTSettings *fs @@ -1643,7 +1626,7 @@ static C_KZG_RET expand_root_of_unity( * * @remark As with all functions prefixed `new_`, this allocates memory that * needs to be reclaimed by calling the corresponding `free_` function. In - * this case, #free_fft_settings. + * this case, free_fft_settings(). * * @remark These settings may be used for FFTs on both field elements and G1 * group elements. @@ -1666,7 +1649,7 @@ static C_KZG_RET new_fft_settings(FFTSettings *fs, unsigned int max_scale) { )); blst_fr_from_uint64(&root_of_unity, SCALE2_ROOT_OF_UNITY[max_scale]); - // Allocate space for the roots of unity + /* Allocate space for the roots of unity */ ret = new_fr_array(&fs->expanded_roots_of_unity, fs->max_width + 1); if (ret != C_KZG_OK) goto out_error; ret = new_fr_array(&fs->reverse_roots_of_unity, fs->max_width + 1); @@ -1674,19 +1657,19 @@ static C_KZG_RET new_fft_settings(FFTSettings *fs, unsigned int max_scale) { ret = new_fr_array(&fs->roots_of_unity, fs->max_width); if (ret != C_KZG_OK) goto out_error; - // Populate the roots of unity + /* Populate the roots of unity */ ret = expand_root_of_unity( fs->expanded_roots_of_unity, &root_of_unity, fs->max_width ); if (ret != C_KZG_OK) goto out_error; - // Populate reverse roots of unity + /* Populate reverse roots of unity */ for (uint64_t i = 0; i <= fs->max_width; i++) { fs->reverse_roots_of_unity[i] = fs->expanded_roots_of_unity[fs->max_width - i]; } - // Permute the roots of unity + /* Permute the roots of unity */ memcpy( fs->roots_of_unity, fs->expanded_roots_of_unity, @@ -1708,7 +1691,7 @@ out_success: } /** - * Free the memory that was previously allocated by #new_fft_settings. + * Free the memory that was previously allocated by new_fft_settings(). * * @remark It's a NOP if `fs` is NULL. * @@ -1716,7 +1699,6 @@ out_success: */ static void free_fft_settings(FFTSettings *fs) { if (fs == NULL) return; - c_kzg_free(fs->expanded_roots_of_unity); c_kzg_free(fs->reverse_roots_of_unity); c_kzg_free(fs->roots_of_unity); @@ -1724,24 +1706,23 @@ static void free_fft_settings(FFTSettings *fs) { } /** - * Free the memory that was previously allocated by #new_kzg_settings. + * Free the memory that was previously allocated by new_kzg_settings(). * * @remark It's a NOP if `ks` is NULL. * * @param[in] ks The settings to be freed */ -static void free_kzg_settings(KZGSettings *ks) { - if (ks == NULL) return; - - c_kzg_free(ks->fs); - c_kzg_free(ks->g1_values); - c_kzg_free(ks->g2_values); +static void free_kzg_settings(KZGSettings *s) { + if (s == NULL) return; + c_kzg_free(s->fs); + c_kzg_free(s->g1_values); + c_kzg_free(s->g2_values); } /** * Load trusted setup into a KZGSettings. * - * @remark Free after use with #free_trusted_setup. + * @remark Free after use with free_trusted_setup(). * * @param[out] out Pointer to the stored trusted setup data * @param[in] g1_bytes Array of G1 elements @@ -1773,12 +1754,14 @@ C_KZG_RET load_trusted_setup( if (ret != C_KZG_OK) goto out_error; for (i = 0; i < n1; i++) { - ret = validate_kzg_g1(&g1_projective[i], (Bytes48 *)&g1_bytes[48 * i]); + ret = validate_kzg_g1( + &g1_projective[i], (Bytes48 *)&g1_bytes[BYTES_PER_G1 * i] + ); if (ret != C_KZG_OK) goto out_error; } for (i = 0; i < n2; i++) { - blst_p2_uncompress(&g2_affine, &g2_bytes[96 * i]); + blst_p2_uncompress(&g2_affine, &g2_bytes[BYTES_PER_G2 * i]); blst_p2_from_affine(&out->g2_values[i], &g2_affine); } @@ -1788,7 +1771,7 @@ C_KZG_RET load_trusted_setup( ret = c_kzg_malloc((void **)&out->fs, sizeof(FFTSettings)); if (ret != C_KZG_OK) goto out_error; - ret = new_fft_settings((FFTSettings *)out->fs, max_scale); + ret = new_fft_settings(out->fs, max_scale); if (ret != C_KZG_OK) goto out_error; ret = fft_g1(out->g1_values, g1_projective, true, n1, out->fs); if (ret != C_KZG_OK) goto out_error; @@ -1813,37 +1796,46 @@ out_success: * the first two numbers are in decimal and the remainder are hexstrings * and any whitespace can be used as separators. * - * @remark See also #load_trusted_setup. + * @remark See also load_trusted_setup(). + * @remark The input file will not be closed. * * @param[out] out Pointer to the loaded trusted setup data - * @param[in] in File handle for input - will not be closed + * @param[in] in File handle for input */ C_KZG_RET load_trusted_setup_file(KZGSettings *out, FILE *in) { - uint64_t i; int num_matches; + uint64_t i; + uint8_t g1_bytes[FIELD_ELEMENTS_PER_BLOB * BYTES_PER_G1]; + uint8_t g2_bytes[TRUSTED_SETUP_NUM_G2_POINTS * BYTES_PER_G2]; + /* Read the number of g1 points */ num_matches = fscanf(in, "%" SCNu64, &i); CHECK(num_matches == 1); CHECK(i == FIELD_ELEMENTS_PER_BLOB); + + /* Read the number of g2 points */ num_matches = fscanf(in, "%" SCNu64, &i); CHECK(num_matches == 1); - CHECK(i == 65); + CHECK(i == TRUSTED_SETUP_NUM_G2_POINTS); - uint8_t g1_bytes[FIELD_ELEMENTS_PER_BLOB * 48]; - uint8_t g2_bytes[65 * 96]; - - for (i = 0; i < FIELD_ELEMENTS_PER_BLOB * 48; i++) { + /* Read all of the g1 points, byte by byte */ + for (i = 0; i < FIELD_ELEMENTS_PER_BLOB * BYTES_PER_G1; i++) { num_matches = fscanf(in, "%2hhx", &g1_bytes[i]); CHECK(num_matches == 1); } - for (i = 0; i < 65 * 96; i++) { + /* Read all of the g2 points, byte by byte */ + for (i = 0; i < TRUSTED_SETUP_NUM_G2_POINTS * BYTES_PER_G2; i++) { num_matches = fscanf(in, "%2hhx", &g2_bytes[i]); CHECK(num_matches == 1); } return load_trusted_setup( - out, g1_bytes, FIELD_ELEMENTS_PER_BLOB, g2_bytes, 65 + out, + g1_bytes, + FIELD_ELEMENTS_PER_BLOB, + g2_bytes, + TRUSTED_SETUP_NUM_G2_POINTS ); } @@ -1856,7 +1848,6 @@ C_KZG_RET load_trusted_setup_file(KZGSettings *out, FILE *in) { */ void free_trusted_setup(KZGSettings *s) { if (s == NULL) return; - - free_fft_settings((FFTSettings *)s->fs); + free_fft_settings(s->fs); free_kzg_settings(s); }