Simplify and cleanup C code (#212)

This commit is contained in:
Justin Traglia 2023-03-16 13:35:22 +00:00 committed by GitHub
parent 0fb17c2063
commit 2ba8f35dc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 189 additions and 198 deletions

View File

@ -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);
}