Skip to content

Commit

Permalink
Add LOG_EXPANSION_FACTOR constant (#515)
Browse files Browse the repository at this point in the history
  • Loading branch information
b-wagn authored Oct 15, 2024
1 parent 4106b76 commit 80d3e0d
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 44 deletions.
2 changes: 2 additions & 0 deletions src/common/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "common/utils.h"
#include "common/alloc.h"

#include <assert.h> /* For assert */
#include <stddef.h> /* For size_t */
#include <stdlib.h> /* For NULL */
#include <string.h> /* For memcpy */
Expand Down Expand Up @@ -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) {
Expand Down
9 changes: 8 additions & 1 deletion src/eip7594/cell.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions src/eip7594/eip7594.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down Expand Up @@ -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.
*/
Expand All @@ -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;
}
Expand Down
41 changes: 22 additions & 19 deletions src/eip7594/fk20.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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++) {
Expand All @@ -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);
Expand Down
7 changes: 5 additions & 2 deletions src/eip7594/recovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
50 changes: 31 additions & 19 deletions src/setup/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -228,57 +237,60 @@ 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;
goto out;
}

/* 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 */
Expand All @@ -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);
Expand Down

0 comments on commit 80d3e0d

Please sign in to comment.