Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor improvements of recovery and compute_cells_and_kzg_proofs code. #493

Merged
merged 2 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions src/eip7594/eip7594.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,13 @@ static const char *RANDOM_CHALLENGE_DOMAIN_VERIFY_CELL_KZG_PROOF_BATCH = "RCKZGC
////////////////////////////////////////////////////////////////////////////////////////////////////

/**
* Given a blob, get all of its cells and proofs.
* Given a blob, compute all of its cells and proofs.
*
* @param[out] cells An array of CELLS_PER_EXT_BLOB cells
* @param[out] proofs An array of CELLS_PER_EXT_BLOB proofs
* @param[in] blob The blob to get cells/proofs for
* @param[in] s The trusted setup
*
* @remark Up to half of these cells may be lost.
* @remark Use recover_cells_and_kzg_proofs for recovery.
* @remark If cells is NULL, they won't be computed.
* @remark If proofs is NULL, they won't be computed.
* @remark Will return an error if both cells & proofs are NULL.
Expand All @@ -81,8 +79,9 @@ C_KZG_RET compute_cells_and_kzg_proofs(

/*
* Convert the blob to a polynomial in lagrange form. Note that only the first 4096 fields of
* the polynomial will be set. The upper 4096 fields will remain zero. This is required because
* the polynomial will be evaluated with 8192 roots of unity.
* the polynomial will be set. The upper 4096 fields will remain zero. The extra space is
* required because the polynomial will be evaluated to the extended domain (8192 roots of
* unity).
*/
ret = blob_to_polynomial(poly_lagrange, blob);
if (ret != C_KZG_OK) goto out;
Expand Down Expand Up @@ -155,9 +154,9 @@ C_KZG_RET compute_cells_and_kzg_proofs(
*
* @param[out] recovered_cells An array of CELLS_PER_EXT_BLOB cells
* @param[out] recovered_proofs An array of CELLS_PER_EXT_BLOB proofs
* @param[in] cell_indices The cell indices for the cells
* @param[in] cells The cells to check
* @param[in] num_cells The number of cells provided
* @param[in] cell_indices The cell indices for the available cells
* @param[in] cells The available cells we recover from
* @param[in] num_cells The number of available cells provided
* @param[in] s The trusted setup
*
* @remark Recovery is faster if there are fewer missing cells.
Expand Down Expand Up @@ -206,25 +205,25 @@ C_KZG_RET recover_cells_and_kzg_proofs(
recovered_cells_fr[i] = FR_NULL;
}

/* Update with existing cells */
/* Populate recovered_cells_fr with available cells at the right places */
for (size_t i = 0; i < num_cells; i++) {
size_t index = cell_indices[i] * FIELD_ELEMENTS_PER_CELL;
for (size_t j = 0; j < FIELD_ELEMENTS_PER_CELL; j++) {
fr_t *field = &recovered_cells_fr[index + j];
fr_t *ptr = &recovered_cells_fr[index + j];

/*
* Check if the field has already been set. If it has, there was a duplicate cell index
* and we can return an error. The compiler will optimize this and the overhead is
* practically zero.
*/
if (!fr_is_null(field)) {
if (!fr_is_null(ptr)) {
ret = C_KZG_BADARGS;
goto out;
}

/* Convert the untrusted bytes to a field element */
/* Convert the untrusted input bytes to a field element */
size_t offset = j * BYTES_PER_FIELD_ELEMENT;
ret = bytes_to_bls_field(field, (const Bytes32 *)&cells[i].bytes[offset]);
ret = bytes_to_bls_field(ptr, (const Bytes32 *)&cells[i].bytes[offset]);
if (ret != C_KZG_OK) goto out;
}
}
Expand Down Expand Up @@ -630,13 +629,15 @@ C_KZG_RET verify_cell_kzg_proof_batch(
/* Scale each cell's data points */
for (size_t i = 0; i < num_cells; i++) {
for (size_t j = 0; j < FIELD_ELEMENTS_PER_CELL; j++) {
fr_t field, scaled;
fr_t cell_fr, scaled_fr;
size_t offset = j * BYTES_PER_FIELD_ELEMENT;
ret = bytes_to_bls_field(&field, (const Bytes32 *)&cells[i].bytes[offset]);
ret = bytes_to_bls_field(&cell_fr, (const Bytes32 *)&cells[i].bytes[offset]);
if (ret != C_KZG_OK) goto out;
blst_fr_mul(&scaled, &field, &r_powers[i]);
blst_fr_mul(&scaled_fr, &cell_fr, &r_powers[i]);
size_t index = cell_indices[i] * FIELD_ELEMENTS_PER_CELL + j;
blst_fr_add(&aggregated_column_cells[index], &aggregated_column_cells[index], &scaled);
blst_fr_add(
&aggregated_column_cells[index], &aggregated_column_cells[index], &scaled_fr
);

/* Mark the cell as being used */
is_cell_used[index] = true;
Expand Down
9 changes: 5 additions & 4 deletions src/eip7594/poly.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,12 @@ void shift_poly(fr_t *p, size_t len, const fr_t *shift_factor) {
/**
* Bit reverses and converts a polynomial in lagrange form to monomial form.
*
* @param[out] monomial The result, an array of `len` fields
* @param[in] lagrange The input poly, an array of `len` fields
* @param[in] len The length of both polynomials
* @param[in] s The trusted setup
* @param[out] monomial_out The result, an array of `len` fields
* @param[in] lagrange The input poly, an array of `len` fields
* @param[in] len The length of both polynomials
* @param[in] s The trusted setup
*
* @remark `monomial_out` and `lagrange` can point to the same memory.
* @remark This method converts a lagrange-form polynomial to a monomial-form polynomial, by inverse
* FFTing the bit-reverse-permuted lagrange polynomial.
*/
Expand Down
62 changes: 39 additions & 23 deletions src/eip7594/recovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@
* @param[in,out] poly_len The length of poly
* @param[in] roots The array of roots
* @param[in] roots_len The number of roots
* @param[in] s The trusted setup
*
* @remark These do not have to be roots of unity. They are roots of a polynomial.
* @remark `poly_len` must be at least `roots_len + 1` in length.
* @remark The `poly` array must be at least `roots_len + 1` in length.
*/
static C_KZG_RET compute_vanishing_polynomial_from_roots(
fr_t *poly, size_t *poly_len, const fr_t *roots, size_t roots_len
Expand Down Expand Up @@ -83,7 +82,7 @@ static C_KZG_RET compute_vanishing_polynomial_from_roots(
* then the i'th root of unity from `roots_of_unity` will be zero on the polynomial
* computed, along with every `CELLS_PER_EXT_BLOB` spaced root of unity in the domain.
*
* @param[in,out] vanishing_poly The vanishing polynomial
* @param[in,out] vanishing_poly The output vanishing polynomial
* @param[in] missing_cell_indices The array of missing cell indices
* @param[in] len_missing_cells The number of missing cell indices
* @param[in] s The trusted setup
Expand Down Expand Up @@ -135,7 +134,7 @@ static C_KZG_RET vanishing_polynomial_for_missing_cells(
);
if (ret != C_KZG_OK) goto out;

/* Zero out all the coefficients */
/* Zero out all the coefficients of the output poly */
for (size_t i = 0; i < FIELD_ELEMENTS_PER_EXT_BLOB; i++) {
vanishing_poly[i] = FR_ZERO;
}
Expand Down Expand Up @@ -188,18 +187,19 @@ static bool is_in_array(const uint64_t *arr, size_t arr_size, uint64_t value) {
}

/**
* Given a dataset with up to half the entries missing, return the reconstructed original. Assumes
* that the inverse FFT of the original data has the upper half of its values equal to zero.
* Given a set of cells with up to half the entries missing, return the reconstructed
* original. Assumes that the inverse FFT of the original data has the upper half of its values
* equal to zero.
*
* @param[out] reconstructed_data_out Preallocated array for recovered cells
* @param[in] cell_indices The cell indices you have
* @param[in] num_cells The number of cells that you have
* @param[in] cells The cells that you have
* @param[out] reconstructed_data_out Array of size FIELD_ELEMENTS_PER_EXT_BLOB to recover cells
* @param[in] cell_indices An array with the available cell indices we have
* @param[in] num_cells The size of the `cell_indices` array
* @param[in] cells An array of size FIELD_ELEMENTS_PER_EXT_BLOB with the cells
* @param[in] s The trusted setup
*
* @remark `recovered` and `cells` can point to the same memory.
* @remark The array of cells must be 2n length and in the correct order.
* @remark Missing cells should be equal to FR_NULL.
* @remark `reconstructed_data_out` and `cells` can point to the same memory.
* @remark The array `cells` must be in the correct order (according to cell_indices).
* @remark Missing cells in `cells` should be equal to FR_NULL.
*/
C_KZG_RET recover_cells(
fr_t *reconstructed_data_out,
Expand Down Expand Up @@ -260,7 +260,10 @@ C_KZG_RET recover_cells(
/* Check that we have enough cells */
assert(len_missing <= CELLS_PER_EXT_BLOB / 2);

/* Compute Z(x) in monomial form */
/*
* Compute Z(x) in monomial form.
* Z(x) is the polynomial which vanishes on all of the evaluations which are missing.
*/
ret = vanishing_polynomial_for_missing_cells(
vanishing_poly_coeff, missing_cell_indices, len_missing, s
);
Expand All @@ -270,7 +273,12 @@ C_KZG_RET recover_cells(
ret = fr_fft(vanishing_poly_eval, vanishing_poly_coeff, FIELD_ELEMENTS_PER_EXT_BLOB, s);
if (ret != C_KZG_OK) goto out;

/* Compute (E*Z)(x) = E(x) * Z(x) in evaluation form over the FFT domain */
/*
* Compute (E*Z)(x) = E(x) * Z(x) in evaluation form over the FFT domain.
*
* Note: over the FFT domain, the polynomials (E*Z)(x) and (P*Z)(x) agree, where
* P(x) is the polynomial we want to reconstruct (degree FIELD_ELEMENTS_PER_BLOB - 1).
*/
for (size_t i = 0; i < FIELD_ELEMENTS_PER_EXT_BLOB; i++) {
if (fr_is_null(&cells_brp[i])) {
extended_evaluation_times_zero[i] = FR_ZERO;
Expand All @@ -279,7 +287,14 @@ C_KZG_RET recover_cells(
}
}

/* Convert (E*Z)(x) to monomial form */
/*
* Convert (E*Z)(x) to monomial form.
*
* We know that (E*Z)(x) and (P*Z)(x) agree over the FFT domain,
* and we know that (P*Z)(x) has degree at most FIELD_ELEMENTS_PER_EXT_BLOB - 1.
* Thus, an inverse FFT of the evaluations of (E*Z)(x) (= evaluations of (P*Z)(x))
* yields the coefficient form of (P*Z)(x).
*/
ret = fr_ifft(
extended_evaluation_times_zero_coeffs,
extended_evaluation_times_zero,
Expand All @@ -289,10 +304,10 @@ C_KZG_RET recover_cells(
if (ret != C_KZG_OK) goto out;

/*
* Polynomial division by convolution: Q3 = Q1 / Q2 where
* Q1 = (D * Z_r,I)(k * x)
* Q2 = Z_r,I(k * x)
* Q3 = D(k * x)
* Next step is to divide the polynomial (P*Z)(x) by polynomial Z(x) to get P(x).
* We do this in evaluation form over a coset of the FFT domain to avoid division by 0.
*
* Convert (P*Z)(x) to evaluation form over a coset of the FFT domain.
*/
ret = coset_fft(
extended_evaluations_over_coset,
Expand All @@ -302,12 +317,13 @@ C_KZG_RET recover_cells(
);
if (ret != C_KZG_OK) goto out;

/* Convert Z(x) to evaluation form over a coset of the FFT domain */
ret = coset_fft(
vanishing_poly_over_coset, vanishing_poly_coeff, FIELD_ELEMENTS_PER_EXT_BLOB, s
);
if (ret != C_KZG_OK) goto out;

/* The result of the division is Q3 */
/* Compute P(x) = (P*Z)(x) / Z(x) in evaluation form over a coset of the FFT domain */
for (size_t i = 0; i < FIELD_ELEMENTS_PER_EXT_BLOB; i++) {
fr_div(
&extended_evaluations_over_coset[i],
Expand All @@ -321,14 +337,14 @@ C_KZG_RET recover_cells(
* polynomial as reconstructed_poly_over_coset in the spec.
*/

/* Convert the evaluations back to coefficents */
/* Convert P(x) to coefficient form */
ret = coset_ifft(
reconstructed_poly_coeff, extended_evaluations_over_coset, FIELD_ELEMENTS_PER_EXT_BLOB, s
);
if (ret != C_KZG_OK) goto out;

/*
* After unscaling the reconstructed polynomial, we have D(x) which evaluates to our original
* After unscaling the reconstructed polynomial, we have P(x) which evaluates to our original
* data at the roots of unity. Next, we evaluate the polynomial to get the original data.
*/
ret = fr_fft(reconstructed_data_out, reconstructed_poly_coeff, FIELD_ELEMENTS_PER_EXT_BLOB, s);
Expand Down
Loading