From 80d3e0df2de7f1c29fcec4adce058ce41c5d137d Mon Sep 17 00:00:00 2001 From: Benedikt Wagner <113296072+b-wagn@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:13:09 +0200 Subject: [PATCH] Add LOG_EXPANSION_FACTOR constant (#515) --- src/common/utils.c | 2 ++ src/eip7594/cell.h | 9 +++++++- src/eip7594/eip7594.c | 6 ++--- src/eip7594/fk20.c | 41 ++++++++++++++++++---------------- src/eip7594/recovery.c | 7 ++++-- src/setup/setup.c | 50 ++++++++++++++++++++++++++---------------- 6 files changed, 71 insertions(+), 44 deletions(-) diff --git a/src/common/utils.c b/src/common/utils.c index 8ae13ab4..95c74f46 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -17,6 +17,7 @@ #include "common/utils.h" #include "common/alloc.h" +#include /* For assert */ #include /* For size_t */ #include /* For NULL */ #include /* For memcpy */ @@ -116,6 +117,7 @@ C_KZG_RET bit_reversal_permutation(void *values, size_t size, size_t n) { /* Reorder elements */ uint64_t unused_bit_len = 64 - log2_pow2(n); + assert(unused_bit_len <= 63); for (size_t i = 0; i < n; i++) { uint64_t r = reverse_bits(i) >> unused_bit_len; if (r > i) { diff --git a/src/eip7594/cell.h b/src/eip7594/cell.h index 07ac8df0..259ae157 100644 --- a/src/eip7594/cell.h +++ b/src/eip7594/cell.h @@ -30,8 +30,15 @@ /** The number of bytes in a single cell. */ #define BYTES_PER_CELL (FIELD_ELEMENTS_PER_CELL * BYTES_PER_FIELD_ELEMENT) +/** + * The logarithm (base 2) of the expansion factor of our Reed-Solomon code. + * In other words, this defines the rate of the Reed-Solomon code (blob / extended blob). + * Note that our codebase is not guaranteed to work anymore if this is changed. + */ +#define LOG_EXPANSION_FACTOR 1 + /** The number of field elements in an extended blob. */ -#define FIELD_ELEMENTS_PER_EXT_BLOB (FIELD_ELEMENTS_PER_BLOB * 2) +#define FIELD_ELEMENTS_PER_EXT_BLOB (FIELD_ELEMENTS_PER_BLOB << LOG_EXPANSION_FACTOR) /** The number of cells in a blob. */ #define CELLS_PER_BLOB (FIELD_ELEMENTS_PER_BLOB / FIELD_ELEMENTS_PER_CELL) diff --git a/src/eip7594/eip7594.c b/src/eip7594/eip7594.c index 2d69fa3e..efcc7b84 100644 --- a/src/eip7594/eip7594.c +++ b/src/eip7594/eip7594.c @@ -111,7 +111,7 @@ C_KZG_RET compute_cells_and_kzg_proofs( ret = poly_lagrange_to_monomial(poly_monomial, poly_lagrange, FIELD_ELEMENTS_PER_BLOB, s); if (ret != C_KZG_OK) goto out; - /* Ensure the upper half of the field elements are still zero */ + /* Ensure that only the first FIELD_ELEMENTS_PER_BLOB elements can be non-zero */ for (size_t i = FIELD_ELEMENTS_PER_BLOB; i < FIELD_ELEMENTS_PER_EXT_BLOB; i++) { assert(fr_equal(&poly_monomial[i], &FR_ZERO)); } @@ -180,7 +180,7 @@ C_KZG_RET compute_cells_and_kzg_proofs( * @param[in] num_cells The number of available cells provided * @param[in] s The trusted setup * - * @remark At least 50% of CELLS_PER_EXT_BLOB cells must be provided. + * @remark At least CELLS_PER_BLOB cells must be provided. * @remark Recovery is faster if there are fewer missing cells. * @remark If recovered_proofs is NULL, they will not be recomputed. */ @@ -203,7 +203,7 @@ C_KZG_RET recover_cells_and_kzg_proofs( } /* Check if it's possible to recover */ - if (num_cells < CELLS_PER_EXT_BLOB / 2) { + if (num_cells < CELLS_PER_BLOB) { ret = C_KZG_BADARGS; goto out; } diff --git a/src/eip7594/fk20.c b/src/eip7594/fk20.c index 15b007ae..a7fa7ce8 100644 --- a/src/eip7594/fk20.c +++ b/src/eip7594/fk20.c @@ -60,7 +60,7 @@ static void toeplitz_coeffs_stride(fr_t *out, const fr_t *in, size_t offset) { */ C_KZG_RET compute_fk20_cell_proofs(g1_t *out, const fr_t *p, const KZGSettings *s) { C_KZG_RET ret; - size_t k, k2; + size_t circulant_domain_size; blst_scalar *scalars = NULL; fr_t **coeffs = NULL; @@ -71,18 +71,21 @@ C_KZG_RET compute_fk20_cell_proofs(g1_t *out, const fr_t *p, const KZGSettings * limb_t *scratch = NULL; bool precompute = s->wbits != 0; - /* Initialize length variables */ - k = FIELD_ELEMENTS_PER_BLOB / FIELD_ELEMENTS_PER_CELL; - k2 = k * 2; + /* + * Note: this constant 2 is not related to `LOG_EXPANSION_FACTOR`. + * Instead, it is related to circulant matrices used in FK20, see + * Section 2.2 and 3.2 in https://eprint.iacr.org/2023/033.pdf. + */ + circulant_domain_size = CELLS_PER_BLOB * 2; /* Do allocations */ - ret = new_fr_array(&toeplitz_coeffs, k2); + ret = new_fr_array(&toeplitz_coeffs, circulant_domain_size); if (ret != C_KZG_OK) goto out; - ret = new_fr_array(&toeplitz_coeffs_fft, k2); + ret = new_fr_array(&toeplitz_coeffs_fft, circulant_domain_size); if (ret != C_KZG_OK) goto out; - ret = new_g1_array(&h_ext_fft, k2); + ret = new_g1_array(&h_ext_fft, circulant_domain_size); if (ret != C_KZG_OK) goto out; - ret = new_g1_array(&h, k2); + ret = new_g1_array(&h, circulant_domain_size); if (ret != C_KZG_OK) goto out; if (precompute) { @@ -94,30 +97,30 @@ C_KZG_RET compute_fk20_cell_proofs(g1_t *out, const fr_t *p, const KZGSettings * } /* Allocate 2d array for coefficients by column */ - ret = c_kzg_calloc((void **)&coeffs, k2, sizeof(void *)); + ret = c_kzg_calloc((void **)&coeffs, circulant_domain_size, sizeof(void *)); if (ret != C_KZG_OK) goto out; - for (size_t i = 0; i < k2; i++) { - ret = new_fr_array(&coeffs[i], k); + for (size_t i = 0; i < circulant_domain_size; i++) { + ret = new_fr_array(&coeffs[i], CELLS_PER_BLOB); if (ret != C_KZG_OK) goto out; } /* Initialize values to zero */ - for (size_t i = 0; i < k2; i++) { + for (size_t i = 0; i < circulant_domain_size; i++) { h_ext_fft[i] = G1_IDENTITY; } /* Compute toeplitz coefficients and organize by column */ for (size_t i = 0; i < FIELD_ELEMENTS_PER_CELL; i++) { toeplitz_coeffs_stride(toeplitz_coeffs, p, i); - ret = fr_fft(toeplitz_coeffs_fft, toeplitz_coeffs, k2, s); + ret = fr_fft(toeplitz_coeffs_fft, toeplitz_coeffs, circulant_domain_size, s); if (ret != C_KZG_OK) goto out; - for (size_t j = 0; j < k2; j++) { + for (size_t j = 0; j < circulant_domain_size; j++) { coeffs[j][i] = toeplitz_coeffs_fft[j]; } } /* Compute h_ext_fft via MSM */ - for (size_t i = 0; i < k2; i++) { + for (size_t i = 0; i < circulant_domain_size; i++) { if (precompute) { /* Transform the field elements to 255-bit scalars */ for (size_t j = 0; j < FIELD_ELEMENTS_PER_CELL; j++) { @@ -144,21 +147,21 @@ C_KZG_RET compute_fk20_cell_proofs(g1_t *out, const fr_t *p, const KZGSettings * } } - ret = g1_ifft(h, h_ext_fft, k2, s); + ret = g1_ifft(h, h_ext_fft, circulant_domain_size, s); if (ret != C_KZG_OK) goto out; /* Zero the second half of h */ - for (size_t i = k; i < k2; i++) { + for (size_t i = CELLS_PER_BLOB; i < circulant_domain_size; i++) { h[i] = G1_IDENTITY; } - ret = g1_fft(out, h, k2, s); + ret = g1_fft(out, h, circulant_domain_size, s); if (ret != C_KZG_OK) goto out; out: c_kzg_free(scalars); if (coeffs != NULL) { - for (size_t i = 0; i < k2; i++) { + for (size_t i = 0; i < circulant_domain_size; i++) { c_kzg_free(coeffs[i]); } c_kzg_free(coeffs); diff --git a/src/eip7594/recovery.c b/src/eip7594/recovery.c index fa20306e..68b481c2 100644 --- a/src/eip7594/recovery.c +++ b/src/eip7594/recovery.c @@ -254,8 +254,11 @@ C_KZG_RET recover_cells( } } - /* Check that we have enough cells */ - assert(len_missing <= CELLS_PER_EXT_BLOB / 2); + /* + * Check that we have enough cells to recover. + * Concretely, we need to have at least CELLS_PER_BLOB many cells. + */ + assert(CELLS_PER_EXT_BLOB - len_missing >= CELLS_PER_BLOB); /* * Compute Z(x) in monomial form. diff --git a/src/setup/setup.c b/src/setup/setup.c index a34232f2..3a14dda0 100644 --- a/src/setup/setup.c +++ b/src/setup/setup.c @@ -74,6 +74,9 @@ * for (size_t i = 0; i < 4; i++) * printf("%#018llxL,\n", root_of_unity.l[i]); * @endcode + * + * @remark this constant is tied to LOG_EXPANSION_FACTOR = 1, i.e., if the expansion + * factor changes, this constant is no longer correct. */ static const fr_t ROOT_OF_UNITY = { 0xa33d279ff0ccffc9L, 0x41fac79f59e91972L, 0x065d227fead1139bL, 0x71db41abda03e055L @@ -197,23 +200,29 @@ void free_trusted_setup(KZGSettings *s) { */ static C_KZG_RET toeplitz_part_1(g1_t *out, const g1_t *x, size_t n, const KZGSettings *s) { C_KZG_RET ret; - size_t n2 = n * 2; + + /* + * Note: this constant 2 is not related to `LOG_EXPANSION_FACTOR`. + * Instead, it is related to circulant matrices used in FK20, see + * Section 2.2 and 3.2 in https://eprint.iacr.org/2023/033.pdf. + */ + size_t circulant_domain_size = n * 2; g1_t *x_ext; /* Create extended array of points */ - ret = new_g1_array(&x_ext, n2); + ret = new_g1_array(&x_ext, circulant_domain_size); if (ret != C_KZG_OK) goto out; /* Copy x & extend with zero */ for (size_t i = 0; i < n; i++) { x_ext[i] = x[i]; } - for (size_t i = n; i < n2; i++) { + for (size_t i = n; i < circulant_domain_size; i++) { x_ext[i] = G1_IDENTITY; } /* Peform forward transformation */ - ret = g1_fft(out, x_ext, n2, s); + ret = g1_fft(out, x_ext, circulant_domain_size, s); if (ret != C_KZG_OK) goto out; out: @@ -228,15 +237,18 @@ static C_KZG_RET toeplitz_part_1(g1_t *out, const g1_t *x, size_t n, const KZGSe */ static C_KZG_RET init_fk20_multi_settings(KZGSettings *s) { C_KZG_RET ret; - size_t n, k, k2; + size_t circulant_domain_size; g1_t *x = NULL; g1_t *points = NULL; blst_p1_affine *p_affine = NULL; bool precompute = s->wbits != 0; - n = FIELD_ELEMENTS_PER_EXT_BLOB / 2; - k = n / FIELD_ELEMENTS_PER_CELL; - k2 = 2 * k; + /* + * Note: this constant 2 is not related to `LOG_EXPANSION_FACTOR`. + * Instead, it is related to circulant matrices used in FK20, see + * Section 2.2 and 3.2 in https://eprint.iacr.org/2023/033.pdf. + */ + circulant_domain_size = 2 * CELLS_PER_BLOB; if (FIELD_ELEMENTS_PER_CELL >= NUM_G2_POINTS) { ret = C_KZG_BADARGS; @@ -244,41 +256,41 @@ static C_KZG_RET init_fk20_multi_settings(KZGSettings *s) { } /* Allocate space for arrays */ - ret = new_g1_array(&x, k); + ret = new_g1_array(&x, CELLS_PER_BLOB); if (ret != C_KZG_OK) goto out; - ret = new_g1_array(&points, k2); + ret = new_g1_array(&points, circulant_domain_size); if (ret != C_KZG_OK) goto out; /* Allocate space for array of pointers, this is a 2D array */ - ret = c_kzg_calloc((void **)&s->x_ext_fft_columns, k2, sizeof(void *)); + ret = c_kzg_calloc((void **)&s->x_ext_fft_columns, circulant_domain_size, sizeof(void *)); if (ret != C_KZG_OK) goto out; - for (size_t i = 0; i < k2; i++) { + for (size_t i = 0; i < circulant_domain_size; i++) { ret = new_g1_array(&s->x_ext_fft_columns[i], FIELD_ELEMENTS_PER_CELL); if (ret != C_KZG_OK) goto out; } for (size_t offset = 0; offset < FIELD_ELEMENTS_PER_CELL; offset++) { /* Compute x, sections of the g1 values */ - size_t start = n - FIELD_ELEMENTS_PER_CELL - 1 - offset; - for (size_t i = 0; i < k - 1; i++) { + size_t start = FIELD_ELEMENTS_PER_BLOB - FIELD_ELEMENTS_PER_CELL - 1 - offset; + for (size_t i = 0; i < CELLS_PER_BLOB - 1; i++) { size_t j = start - i * FIELD_ELEMENTS_PER_CELL; x[i] = s->g1_values_monomial[j]; } - x[k - 1] = G1_IDENTITY; + x[CELLS_PER_BLOB - 1] = G1_IDENTITY; /* Compute points, the fft of an extended x */ - ret = toeplitz_part_1(points, x, k, s); + ret = toeplitz_part_1(points, x, CELLS_PER_BLOB, s); if (ret != C_KZG_OK) goto out; /* Reorganize from rows into columns */ - for (size_t row = 0; row < k2; row++) { + for (size_t row = 0; row < circulant_domain_size; row++) { s->x_ext_fft_columns[row][offset] = points[row]; } } if (precompute) { /* Allocate space for precomputed tables */ - ret = c_kzg_calloc((void **)&s->tables, k2, sizeof(void *)); + ret = c_kzg_calloc((void **)&s->tables, circulant_domain_size, sizeof(void *)); if (ret != C_KZG_OK) goto out; /* Allocate space for points in affine representation */ @@ -290,7 +302,7 @@ static C_KZG_RET init_fk20_multi_settings(KZGSettings *s) { s->wbits, FIELD_ELEMENTS_PER_CELL ); - for (size_t i = 0; i < k2; i++) { + for (size_t i = 0; i < circulant_domain_size; i++) { /* Transform the points to affine representation */ const blst_p1 *p_arg[2] = {s->x_ext_fft_columns[i], NULL}; blst_p1s_to_affine(p_affine, p_arg, FIELD_ELEMENTS_PER_CELL);