From df1ad91178e88ee0b36dcbea91d944fd05037056 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Fri, 30 Aug 2024 13:40:50 -0500 Subject: [PATCH 01/23] Replace BLSFieldElement with bls.Scalar --- Makefile | 2 +- pysetup/spec_builders/eip7594.py | 3 +- setup.py | 4 +- .../polynomial-commitments-sampling.md | 163 +++++++++--------- specs/deneb/polynomial-commitments.md | 138 ++++++--------- .../test_polynomial_commitments.py | 37 +--- .../test_polynomial_commitments.py | 19 +- .../pyspec/eth2spec/test/helpers/sharding.py | 18 +- .../pyspec/eth2spec/test/utils/kzg_tests.py | 11 +- tests/core/pyspec/eth2spec/utils/bls.py | 21 +-- 10 files changed, 169 insertions(+), 247 deletions(-) diff --git a/Makefile b/Makefile index 23b6a6035d..c4be3f3f3b 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ MARKDOWN_FILES = $(wildcard $(SPEC_DIR)/*/*.md) \ $(wildcard $(SPEC_DIR)/_features/*/*/*.md) \ $(wildcard $(SSZ_DIR)/*.md) -ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra whisk eip6800 eip7732 +ALL_EXECUTABLE_SPEC_NAMES = phase0 altair bellatrix capella deneb electra whisk eip6800 eip7594 eip7732 # The parameters for commands. Use `foreach` to avoid listing specs again. COVERAGE_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), --cov=eth2spec.$S.$(TEST_PRESET_TYPE)) PYLINT_SCOPE := $(foreach S,$(ALL_EXECUTABLE_SPEC_NAMES), ./eth2spec/$S) diff --git a/pysetup/spec_builders/eip7594.py b/pysetup/spec_builders/eip7594.py index 109ad8736f..d5a4132099 100644 --- a/pysetup/spec_builders/eip7594.py +++ b/pysetup/spec_builders/eip7594.py @@ -12,12 +12,13 @@ def imports(cls, preset_name: str): return f''' from eth2spec.deneb import {preset_name} as deneb ''' - + @classmethod def sundry_functions(cls) -> str: return """ def retrieve_column_sidecars(beacon_block_root: Root) -> Sequence[DataColumnSidecar]: + # pylint: disable=unused-argument return [] """ diff --git a/setup.py b/setup.py index 539db215b7..546434f57f 100644 --- a/setup.py +++ b/setup.py @@ -173,7 +173,7 @@ def _update_constant_vars_with_kzg_setups(constant_vars, preset_name): constant_vars['KZG_SETUP_G1_MONOMIAL'] = VariableDefinition(constant_vars['KZG_SETUP_G1_MONOMIAL'].value, str(kzg_setups[0]), comment, None) constant_vars['KZG_SETUP_G1_LAGRANGE'] = VariableDefinition(constant_vars['KZG_SETUP_G1_LAGRANGE'].value, str(kzg_setups[1]), comment, None) constant_vars['KZG_SETUP_G2_MONOMIAL'] = VariableDefinition(constant_vars['KZG_SETUP_G2_MONOMIAL'].value, str(kzg_setups[2]), comment, None) - + def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], preset_name=str) -> SpecObject: functions: Dict[str, str] = {} @@ -557,7 +557,7 @@ def run(self): RUAMEL_YAML_VERSION, "lru-dict==1.2.0", MARKO_VERSION, - "py_arkworks_bls12381==0.3.4", + "py_arkworks_bls12381==0.3.5", "curdleproofs==0.1.1", ] ) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 869f471844..9e213d7996 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -71,9 +71,6 @@ The following is a list of the public methods: | Name | SSZ equivalent | Description | | - | - | - | -| `PolynomialCoeff` | `List[BLSFieldElement, FIELD_ELEMENTS_PER_EXT_BLOB]` | A polynomial in coefficient form | -| `Coset` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | The evaluation domain of a cell | -| `CosetEvals` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | The internal representation of a cell (the evaluations over its Coset) | | `Cell` | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_CELL]` | The unit of blob data that can come with its own KZG proof | | `CellIndex` | `uint64` | Validation: `x < CELLS_PER_EXT_BLOB` | | `CommitmentIndex` | `uint64` | The type which represents the index of an element in the list of commitments | @@ -99,9 +96,9 @@ Cells are the smallest unit of blob data that can come with their own KZG proofs #### `cell_to_coset_evals` ```python -def cell_to_coset_evals(cell: Cell) -> CosetEvals: +def cell_to_coset_evals(cell: Cell) -> Sequence[bls.Scalar]: """ - Convert an untrusted ``Cell`` into a trusted ``CosetEvals``. + Convert an untrusted ``Cell`` into trusted coset evaluations. """ evals = [] for i in range(FIELD_ELEMENTS_PER_CELL): @@ -109,15 +106,15 @@ def cell_to_coset_evals(cell: Cell) -> CosetEvals: end = (i + 1) * BYTES_PER_FIELD_ELEMENT value = bytes_to_bls_field(cell[start:end]) evals.append(value) - return CosetEvals(evals) + return evals ``` #### `coset_evals_to_cell` ```python -def coset_evals_to_cell(coset_evals: CosetEvals) -> Cell: +def coset_evals_to_cell(coset_evals: Sequence[bls.Scalar]) -> Cell: """ - Convert a trusted ``CosetEval`` into an untrusted ``Cell``. + Convert trusted coset evaluations into an untrusted ``Cell``. """ cell = [] for i in range(FIELD_ELEMENTS_PER_CELL): @@ -130,7 +127,7 @@ def coset_evals_to_cell(coset_evals: CosetEvals) -> Cell: #### `g2_lincomb` ```python -def g2_lincomb(points: Sequence[G2Point], scalars: Sequence[BLSFieldElement]) -> Bytes96: +def g2_lincomb(points: Sequence[G2Point], scalars: Sequence[bls.Scalar]) -> Bytes96: """ BLS multiscalar multiplication in G2. This can be naively implemented using double-and-add. """ @@ -152,31 +149,29 @@ def g2_lincomb(points: Sequence[G2Point], scalars: Sequence[BLSFieldElement]) -> #### `_fft_field` ```python -def _fft_field(vals: Sequence[BLSFieldElement], - roots_of_unity: Sequence[BLSFieldElement]) -> Sequence[BLSFieldElement]: +def _fft_field(vals: Sequence[bls.Scalar], roots_of_unity: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: if len(vals) == 1: return vals L = _fft_field(vals[::2], roots_of_unity[::2]) R = _fft_field(vals[1::2], roots_of_unity[::2]) - o = [BLSFieldElement(0) for _ in vals] + o = [bls.Scalar(0) for _ in vals] for i, (x, y) in enumerate(zip(L, R)): - y_times_root = (int(y) * int(roots_of_unity[i])) % BLS_MODULUS - o[i] = BLSFieldElement((int(x) + y_times_root) % BLS_MODULUS) - o[i + len(L)] = BLSFieldElement((int(x) - y_times_root + BLS_MODULUS) % BLS_MODULUS) + y_times_root = y * roots_of_unity[i] + o[i] = x + y_times_root + o[i + len(L)] = x - y_times_root return o ``` #### `fft_field` ```python -def fft_field(vals: Sequence[BLSFieldElement], - roots_of_unity: Sequence[BLSFieldElement], - inv: bool=False) -> Sequence[BLSFieldElement]: +def fft_field(vals: Sequence[bls.Scalar], + roots_of_unity: Sequence[bls.Scalar], + inv: bool=False) -> Sequence[bls.Scalar]: if inv: # Inverse FFT - invlen = pow(len(vals), BLS_MODULUS - 2, BLS_MODULUS) - return [BLSFieldElement((int(x) * invlen) % BLS_MODULUS) - for x in _fft_field(vals, list(roots_of_unity[0:1]) + list(roots_of_unity[:0:-1]))] + invlen = bls.Scalar(len(vals)).pow(bls.Scalar(BLS_MODULUS - 2)) + return [x * invlen for x in _fft_field(vals, list(roots_of_unity[0:1]) + list(roots_of_unity[:0:-1]))] else: # Regular FFT return _fft_field(vals, roots_of_unity) @@ -185,34 +180,34 @@ def fft_field(vals: Sequence[BLSFieldElement], #### `coset_fft_field` ```python -def coset_fft_field(vals: Sequence[BLSFieldElement], - roots_of_unity: Sequence[BLSFieldElement], - inv: bool=False) -> Sequence[BLSFieldElement]: +def coset_fft_field(vals: Sequence[bls.Scalar], + roots_of_unity: Sequence[bls.Scalar], + inv: bool=False) -> Sequence[bls.Scalar]: """ Computes an FFT/IFFT over a coset of the roots of unity. This is useful for when one wants to divide by a polynomial which vanishes on one or more elements in the domain. """ - vals = vals.copy() + vals = [v for v in vals] # copy - def shift_vals(vals: Sequence[BLSFieldElement], factor: BLSFieldElement) -> Sequence[BLSFieldElement]: + def shift_vals(vals: Sequence[bls.Scalar], factor: bls.Scalar) -> Sequence[bls.Scalar]: """ Multiply each entry in `vals` by succeeding powers of `factor` i.e., [vals[0] * factor^0, vals[1] * factor^1, ..., vals[n] * factor^n] """ - shift = 1 + updated_vals: List[bls.Scalar] = [] + shift = bls.Scalar(1) for i in range(len(vals)): - vals[i] = BLSFieldElement((int(vals[i]) * shift) % BLS_MODULUS) - shift = (shift * int(factor)) % BLS_MODULUS - return vals + updated_vals.append(vals[i] * shift) + shift = shift * factor + return updated_vals # This is the coset generator; it is used to compute a FFT/IFFT over a coset of # the roots of unity. - shift_factor = BLSFieldElement(PRIMITIVE_ROOT_OF_UNITY) + shift_factor = bls.Scalar(PRIMITIVE_ROOT_OF_UNITY) if inv: vals = fft_field(vals, roots_of_unity, inv) - shift_inv = bls_modular_inverse(shift_factor) - return shift_vals(vals, shift_inv) + return shift_vals(vals, shift_factor.inverse()) else: vals = shift_vals(vals, shift_factor) return fft_field(vals, roots_of_unity, inv) @@ -224,8 +219,8 @@ def coset_fft_field(vals: Sequence[BLSFieldElement], def compute_verify_cell_kzg_proof_batch_challenge(commitments: Sequence[KZGCommitment], commitment_indices: Sequence[CommitmentIndex], cell_indices: Sequence[CellIndex], - cosets_evals: Sequence[CosetEvals], - proofs: Sequence[KZGProof]) -> BLSFieldElement: + cosets_evals: Sequence[Sequence[bls.Scalar]], + proofs: Sequence[KZGProof]) -> bls.Scalar: """ Compute a random challenge ``r`` used in the universal verification equation. To compute the challenge, ``RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN`` and all data that can influence the @@ -253,7 +248,7 @@ def compute_verify_cell_kzg_proof_batch_challenge(commitments: Sequence[KZGCommi #### `polynomial_eval_to_coeff` ```python -def polynomial_eval_to_coeff(polynomial: Polynomial) -> PolynomialCoeff: +def polynomial_eval_to_coeff(polynomial: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: """ Interpolates a polynomial (given in evaluation form) to a polynomial in coefficient form. """ @@ -266,38 +261,38 @@ def polynomial_eval_to_coeff(polynomial: Polynomial) -> PolynomialCoeff: #### `add_polynomialcoeff` ```python -def add_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoeff: +def add_polynomialcoeff(a: Sequence[bls.Scalar], b: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: """ Sum the coefficient form polynomials ``a`` and ``b``. """ a, b = (a, b) if len(a) >= len(b) else (b, a) length_a = len(a) length_b = len(b) - return [(a[i] + (b[i] if i < length_b else 0)) % BLS_MODULUS for i in range(length_a)] + return [a[i] + (b[i] if i < length_b else bls.Scalar(0)) for i in range(length_a)] ``` #### `neg_polynomialcoeff` ```python -def neg_polynomialcoeff(a: PolynomialCoeff) -> PolynomialCoeff: +def neg_polynomialcoeff(a: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: """ Negative of coefficient form polynomial ``a`` """ - return [(BLS_MODULUS - x) % BLS_MODULUS for x in a] + return [-x for x in a] ``` #### `multiply_polynomialcoeff` ```python -def multiply_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoeff: +def multiply_polynomialcoeff(a: Sequence[bls.Scalar], b: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: """ Multiplies the coefficient form polynomials ``a`` and ``b`` """ assert len(a) + len(b) <= FIELD_ELEMENTS_PER_EXT_BLOB - r = [0] + r: Sequence[bls.Scalar] = [bls.Scalar(0)] for power, coef in enumerate(a): - summand = [0] * power + [int(coef) * int(x) % BLS_MODULUS for x in b] + summand = [bls.Scalar(0)] * power + [coef * x for x in b] r = add_polynomialcoeff(r, summand) return r ``` @@ -305,44 +300,44 @@ def multiply_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> Polynomi #### `divide_polynomialcoeff` ```python -def divide_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoeff: +def divide_polynomialcoeff(a: Sequence[bls.Scalar], b: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: """ Long polynomial division for two coefficient form polynomials ``a`` and ``b`` """ - a = a.copy() # Make a copy since `a` is passed by reference - o: List[BLSFieldElement] = [] + a = [v for v in a] # copy + o: List[bls.Scalar] = [] apos = len(a) - 1 bpos = len(b) - 1 diff = apos - bpos while diff >= 0: - quot = div(a[apos], b[bpos]) + quot = a[apos] / b[bpos] o.insert(0, quot) for i in range(bpos, -1, -1): - a[diff + i] = (int(a[diff + i]) - int(b[i] + BLS_MODULUS) * int(quot)) % BLS_MODULUS + a[diff + i] = a[diff + i] - b[i] * quot apos -= 1 diff -= 1 - return [x % BLS_MODULUS for x in o] + return o ``` #### `interpolate_polynomialcoeff` ```python -def interpolate_polynomialcoeff(xs: Sequence[BLSFieldElement], ys: Sequence[BLSFieldElement]) -> PolynomialCoeff: +def interpolate_polynomialcoeff(xs: Sequence[bls.Scalar], ys: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: """ Lagrange interpolation: Finds the lowest degree polynomial that takes the value ``ys[i]`` at ``x[i]`` for all i. Outputs a coefficient form polynomial. Leading coefficients may be zero. """ assert len(xs) == len(ys) - r = [0] + r: Sequence[bls.Scalar] = [bls.Scalar(0)] for i in range(len(xs)): - summand = [ys[i]] + summand: Sequence[bls.Scalar] = [ys[i]] for j in range(len(ys)): if j != i: - weight_adjustment = bls_modular_inverse(int(xs[i]) - int(xs[j])) + weight_adjustment = (xs[i] - xs[j]).inverse() summand = multiply_polynomialcoeff( - summand, [((BLS_MODULUS - int(weight_adjustment)) * int(xs[j])) % BLS_MODULUS, weight_adjustment] + summand, [-weight_adjustment * xs[j], weight_adjustment] ) r = add_polynomialcoeff(r, summand) @@ -352,27 +347,27 @@ def interpolate_polynomialcoeff(xs: Sequence[BLSFieldElement], ys: Sequence[BLSF #### `vanishing_polynomialcoeff` ```python -def vanishing_polynomialcoeff(xs: Sequence[BLSFieldElement]) -> PolynomialCoeff: +def vanishing_polynomialcoeff(xs: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: """ Compute the vanishing polynomial on ``xs`` (in coefficient form) """ - p = [1] + p: Sequence[bls.Scalar] = [bls.Scalar(1)] for x in xs: - p = multiply_polynomialcoeff(p, [-int(x) + BLS_MODULUS, 1]) + p = multiply_polynomialcoeff(p, [-x, bls.Scalar(1)]) return p ``` #### `evaluate_polynomialcoeff` ```python -def evaluate_polynomialcoeff(polynomial_coeff: PolynomialCoeff, z: BLSFieldElement) -> BLSFieldElement: +def evaluate_polynomialcoeff(polynomial_coeff: Sequence[bls.Scalar], z: bls.Scalar) -> bls.Scalar: """ Evaluate a coefficient form polynomial at ``z`` using Horner's schema """ - y = 0 + y = bls.Scalar(0) for coef in polynomial_coeff[::-1]: - y = (int(y) * int(z) + int(coef)) % BLS_MODULUS - return BLSFieldElement(y % BLS_MODULUS) + y = y * z + coef + return y ``` ### KZG multiproofs @@ -383,8 +378,8 @@ Extended KZG functions for multiproofs ```python def compute_kzg_proof_multi_impl( - polynomial_coeff: PolynomialCoeff, - zs: Coset) -> Tuple[KZGProof, CosetEvals]: + polynomial_coeff: Sequence[bls.Scalar], + zs: Sequence[bls.Scalar]) -> Tuple[KZGProof, Sequence[bls.Scalar]]: """ Compute a KZG multi-evaluation proof for a set of `k` points. @@ -416,7 +411,7 @@ def compute_kzg_proof_multi_impl( def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], commitment_indices: Sequence[CommitmentIndex], cell_indices: Sequence[CellIndex], - cosets_evals: Sequence[CosetEvals], + cosets_evals: Sequence[Sequence[bls.Scalar]], proofs: Sequence[KZGProof]) -> bool: """ Helper: Verify that a set of cells belong to their corresponding commitment. @@ -477,16 +472,16 @@ def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], # Step 4.1: Compute RLC = sum_i weights[i] commitments[i] # Step 4.1a: Compute weights[i]: the sum of all r^k for which cell k is associated with commitment i. # Note: we do that by iterating over all k and updating the correct weights[i] accordingly - weights = [0] * num_commitments + weights = [bls.Scalar(0)] * num_commitments for k in range(num_cells): i = commitment_indices[k] - weights[i] = (weights[i] + int(r_powers[k])) % BLS_MODULUS + weights[i] += r_powers[k] # Step 4.1b: Linearly combine the weights with the commitments to get RLC rlc = bls.bytes48_to_G1(g1_lincomb(commitments, weights)) # Step 4.2: Compute RLI = [sum_k r^k interpolation_poly_k(s)] # Note: an efficient implementation would use the IDFT based method explained in the blog post - sum_interp_polys_coeff = [0] * n + sum_interp_polys_coeff: Sequence[bls.Scalar] = [bls.Scalar(0)] * n for k in range(num_cells): interp_poly_coeff = interpolate_polynomialcoeff(coset_for_cell(cell_indices[k]), cosets_evals[k]) interp_poly_scaled_coeff = multiply_polynomialcoeff([r_powers[k]], interp_poly_coeff) @@ -496,9 +491,9 @@ def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], # Step 4.3: Compute RLP = sum_k (r^k * h_k^n) proofs[k] weighted_r_powers = [] for k in range(num_cells): - h_k = int(coset_shift_for_cell(cell_indices[k])) - h_k_pow = pow(h_k, n, BLS_MODULUS) - wrp = (int(r_powers[k]) * h_k_pow) % BLS_MODULUS + h_k = coset_shift_for_cell(cell_indices[k]) + h_k_pow = h_k.pow(bls.Scalar(n)) + wrp = r_powers[k] * h_k_pow weighted_r_powers.append(wrp) rlp = bls.bytes48_to_G1(g1_lincomb(proofs, weighted_r_powers)) @@ -518,7 +513,7 @@ def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], #### `coset_shift_for_cell` ```python -def coset_shift_for_cell(cell_index: CellIndex) -> BLSFieldElement: +def coset_shift_for_cell(cell_index: CellIndex) -> bls.Scalar: """ Get the shift that determines the coset for a given ``cell_index``. Precisely, consider the group of roots of unity of order FIELD_ELEMENTS_PER_CELL * CELLS_PER_EXT_BLOB. @@ -536,7 +531,7 @@ def coset_shift_for_cell(cell_index: CellIndex) -> BLSFieldElement: #### `coset_for_cell` ```python -def coset_for_cell(cell_index: CellIndex) -> Coset: +def coset_for_cell(cell_index: CellIndex) -> Sequence[bls.Scalar]: """ Get the coset for a given ``cell_index``. Precisely, consider the group of roots of unity of order FIELD_ELEMENTS_PER_CELL * CELLS_PER_EXT_BLOB. @@ -548,7 +543,7 @@ def coset_for_cell(cell_index: CellIndex) -> Coset: roots_of_unity_brp = bit_reversal_permutation( compute_roots_of_unity(FIELD_ELEMENTS_PER_EXT_BLOB) ) - return Coset(roots_of_unity_brp[FIELD_ELEMENTS_PER_CELL * cell_index:FIELD_ELEMENTS_PER_CELL * (cell_index + 1)]) + return roots_of_unity_brp[FIELD_ELEMENTS_PER_CELL * cell_index:FIELD_ELEMENTS_PER_CELL * (cell_index + 1)] ``` ## Cells @@ -558,7 +553,7 @@ def coset_for_cell(cell_index: CellIndex) -> Coset: #### `compute_cells_and_kzg_proofs_polynomialcoeff` ```python -def compute_cells_and_kzg_proofs_polynomialcoeff(polynomial_coeff: PolynomialCoeff) -> Tuple[ +def compute_cells_and_kzg_proofs_polynomialcoeff(polynomial_coeff: Sequence[bls.Scalar]) -> Tuple[ Vector[Cell, CELLS_PER_EXT_BLOB], Vector[KZGProof, CELLS_PER_EXT_BLOB]]: """ @@ -629,7 +624,8 @@ def verify_cell_kzg_proof_batch(commitments_bytes: Sequence[Bytes48], deduplicated_commitments = [bytes_to_kzg_commitment(commitment_bytes) for commitment_bytes in set(commitments_bytes)] # Create indices list mapping initial commitments (that may contain duplicates) to the deduplicated commitments - commitment_indices = [deduplicated_commitments.index(commitment_bytes) for commitment_bytes in commitments_bytes] + commitment_indices = [CommitmentIndex(deduplicated_commitments.index(commitment_bytes)) + for commitment_bytes in commitments_bytes] cosets_evals = [cell_to_coset_evals(cell) for cell in cells] proofs = [bytes_to_kzg_proof(proof_bytes) for proof_bytes in proofs_bytes] @@ -648,7 +644,7 @@ def verify_cell_kzg_proof_batch(commitments_bytes: Sequence[Bytes48], ### `construct_vanishing_polynomial` ```python -def construct_vanishing_polynomial(missing_cell_indices: Sequence[CellIndex]) -> Sequence[BLSFieldElement]: +def construct_vanishing_polynomial(missing_cell_indices: Sequence[CellIndex]) -> Sequence[bls.Scalar]: """ Given the cells indices that are missing from the data, compute the polynomial that vanishes at every point that corresponds to a missing field element. @@ -669,7 +665,7 @@ def construct_vanishing_polynomial(missing_cell_indices: Sequence[CellIndex]) -> ]) # Extend vanishing polynomial to full domain using the closed form of the vanishing polynomial over a coset - zero_poly_coeff = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_EXT_BLOB + zero_poly_coeff = [bls.Scalar(0)] * FIELD_ELEMENTS_PER_EXT_BLOB for i, coeff in enumerate(short_zero_poly): zero_poly_coeff[i * FIELD_ELEMENTS_PER_CELL] = coeff @@ -680,19 +676,19 @@ def construct_vanishing_polynomial(missing_cell_indices: Sequence[CellIndex]) -> ```python def recover_polynomialcoeff(cell_indices: Sequence[CellIndex], - cells: Sequence[Cell]) -> Sequence[BLSFieldElement]: + cosets_evals: Sequence[Sequence[bls.Scalar]]) -> Sequence[bls.Scalar]: """ Recover the polynomial in coefficient form that when evaluated at the roots of unity will give the extended blob. """ # Get the extended domain. This will be referred to as the FFT domain. roots_of_unity_extended = compute_roots_of_unity(FIELD_ELEMENTS_PER_EXT_BLOB) - # Flatten the cells into evaluations + # Flatten the cosets evaluations. # If a cell is missing, then its evaluation is zero. # We let E(x) be a polynomial of degree FIELD_ELEMENTS_PER_EXT_BLOB - 1 # that interpolates the evaluations including the zeros for missing ones. - extended_evaluation_rbo = [0] * FIELD_ELEMENTS_PER_EXT_BLOB - for cell_index, cell in zip(cell_indices, cells): + extended_evaluation_rbo = [bls.Scalar(0)] * FIELD_ELEMENTS_PER_EXT_BLOB + for cell_index, cell in zip(cell_indices, cosets_evals): start = cell_index * FIELD_ELEMENTS_PER_CELL end = (cell_index + 1) * FIELD_ELEMENTS_PER_CELL extended_evaluation_rbo[start:end] = cell @@ -710,8 +706,7 @@ def recover_polynomialcoeff(cell_indices: Sequence[CellIndex], # 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). - extended_evaluation_times_zero = [BLSFieldElement(int(a) * int(b) % BLS_MODULUS) - for a, b in zip(zero_poly_eval, extended_evaluation)] + extended_evaluation_times_zero = [a * b for a, b in zip(zero_poly_eval, extended_evaluation)] # 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. @@ -729,7 +724,7 @@ def recover_polynomialcoeff(cell_indices: Sequence[CellIndex], zero_poly_over_coset = coset_fft_field(zero_poly_coeff, roots_of_unity_extended) # Compute P(x) = (P*Z)(x) / Z(x) in evaluation form over a coset of the FFT domain - reconstructed_poly_over_coset = [div(a, b) for a, b in zip(extended_evaluations_over_coset, zero_poly_over_coset)] + reconstructed_poly_over_coset = [a / b for a, b in zip(extended_evaluations_over_coset, zero_poly_over_coset)] # Convert P(x) to coefficient form reconstructed_poly_coeff = coset_fft_field(reconstructed_poly_over_coset, roots_of_unity_extended, inv=True) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 5f7edb455c..bec8e251a2 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -27,8 +27,6 @@ - [`bytes_to_kzg_proof`](#bytes_to_kzg_proof) - [`blob_to_polynomial`](#blob_to_polynomial) - [`compute_challenge`](#compute_challenge) - - [`bls_modular_inverse`](#bls_modular_inverse) - - [`div`](#div) - [`g1_lincomb`](#g1_lincomb) - [`compute_powers`](#compute_powers) - [`compute_roots_of_unity`](#compute_roots_of_unity) @@ -63,10 +61,8 @@ Public functions MUST accept raw bytes as input and perform the required cryptog | - | - | - | | `G1Point` | `Bytes48` | | | `G2Point` | `Bytes96` | | -| `BLSFieldElement` | `uint256` | Validation: `x < BLS_MODULUS` | | `KZGCommitment` | `Bytes48` | Validation: Perform [BLS standard's](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature-04#section-2.5) "KeyValidate" check but do allow the identity point | | `KZGProof` | `Bytes48` | Same as for `KZGCommitment` | -| `Polynomial` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | A polynomial in evaluation form | | `Blob` | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB]` | A basic data blob | ## Constants @@ -162,33 +158,33 @@ def multi_exp(points: Sequence[TPoint], #### `hash_to_bls_field` ```python -def hash_to_bls_field(data: bytes) -> BLSFieldElement: +def hash_to_bls_field(data: bytes) -> bls.Scalar: """ Hash ``data`` and convert the output to a BLS scalar field element. The output is not uniform over the BLS field. """ hashed_data = hash(data) - return BLSFieldElement(int.from_bytes(hashed_data, KZG_ENDIANNESS) % BLS_MODULUS) + return bls.Scalar(int.from_bytes(hashed_data, KZG_ENDIANNESS) % BLS_MODULUS) ``` #### `bytes_to_bls_field` ```python -def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement: +def bytes_to_bls_field(b: Bytes32) -> bls.Scalar: """ Convert untrusted bytes to a trusted and validated BLS scalar field element. This function does not accept inputs greater than the BLS modulus. """ field_element = int.from_bytes(b, KZG_ENDIANNESS) assert field_element < BLS_MODULUS - return BLSFieldElement(field_element) + return bls.Scalar(field_element) ``` #### `bls_field_to_bytes` ```python -def bls_field_to_bytes(x: BLSFieldElement) -> Bytes32: - return int.to_bytes(x % BLS_MODULUS, 32, KZG_ENDIANNESS) +def bls_field_to_bytes(x: bls.Scalar) -> Bytes32: + return int.to_bytes(int(x), 32, KZG_ENDIANNESS) ``` #### `validate_kzg_g1` @@ -229,22 +225,21 @@ def bytes_to_kzg_proof(b: Bytes48) -> KZGProof: #### `blob_to_polynomial` ```python -def blob_to_polynomial(blob: Blob) -> Polynomial: +def blob_to_polynomial(blob: Blob) -> Sequence[bls.Scalar]: """ Convert a blob to list of BLS field scalars. """ - polynomial = Polynomial() + polynomial = [] for i in range(FIELD_ELEMENTS_PER_BLOB): value = bytes_to_bls_field(blob[i * BYTES_PER_FIELD_ELEMENT: (i + 1) * BYTES_PER_FIELD_ELEMENT]) - polynomial[i] = value + polynomial.append(value) return polynomial ``` #### `compute_challenge` ```python -def compute_challenge(blob: Blob, - commitment: KZGCommitment) -> BLSFieldElement: +def compute_challenge(blob: Blob, commitment: KZGCommitment) -> bls.Scalar: """ Return the Fiat-Shamir challenge required by the rest of the protocol. """ @@ -260,32 +255,10 @@ def compute_challenge(blob: Blob, return hash_to_bls_field(data) ``` -#### `bls_modular_inverse` - -```python -def bls_modular_inverse(x: BLSFieldElement) -> BLSFieldElement: - """ - Compute the modular inverse of x (for x != 0) - i.e. return y such that x * y % BLS_MODULUS == 1 - """ - assert (int(x) % BLS_MODULUS) != 0 - return BLSFieldElement(pow(x, -1, BLS_MODULUS)) -``` - -#### `div` - -```python -def div(x: BLSFieldElement, y: BLSFieldElement) -> BLSFieldElement: - """ - Divide two field elements: ``x`` by `y``. - """ - return BLSFieldElement((int(x) * int(bls_modular_inverse(y))) % BLS_MODULUS) -``` - #### `g1_lincomb` ```python -def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[BLSFieldElement]) -> KZGCommitment: +def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[bls.Scalar]) -> KZGCommitment: """ BLS multiscalar multiplication in G1. This can be naively implemented using double-and-add. """ @@ -305,27 +278,27 @@ def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[BLSFieldElemen #### `compute_powers` ```python -def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]: +def compute_powers(x: bls.Scalar, n: uint64) -> Sequence[bls.Scalar]: """ Return ``x`` to power of [0, n-1], if n > 0. When n==0, an empty array is returned. """ - current_power = 1 + current_power = bls.Scalar(1) powers = [] for _ in range(n): - powers.append(BLSFieldElement(current_power)) - current_power = current_power * int(x) % BLS_MODULUS + powers.append(current_power) + current_power = current_power * x return powers ``` #### `compute_roots_of_unity` ```python -def compute_roots_of_unity(order: uint64) -> Sequence[BLSFieldElement]: +def compute_roots_of_unity(order: uint64) -> Sequence[bls.Scalar]: """ Return roots of unity of ``order``. """ assert (BLS_MODULUS - 1) % int(order) == 0 - root_of_unity = BLSFieldElement(pow(PRIMITIVE_ROOT_OF_UNITY, (BLS_MODULUS - 1) // int(order), BLS_MODULUS)) + root_of_unity = bls.Scalar(pow(PRIMITIVE_ROOT_OF_UNITY, (BLS_MODULUS - 1) // int(order), BLS_MODULUS)) return compute_powers(root_of_unity, order) ``` @@ -334,8 +307,7 @@ def compute_roots_of_unity(order: uint64) -> Sequence[BLSFieldElement]: #### `evaluate_polynomial_in_evaluation_form` ```python -def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial, - z: BLSFieldElement) -> BLSFieldElement: +def evaluate_polynomial_in_evaluation_form(polynomial: Sequence[bls.Scalar], z: bls.Scalar) -> bls.Scalar: """ Evaluate a polynomial (in evaluation form) at an arbitrary point ``z``. - When ``z`` is in the domain, the evaluation can be found by indexing the polynomial at the @@ -345,22 +317,23 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial, """ width = len(polynomial) assert width == FIELD_ELEMENTS_PER_BLOB - inverse_width = bls_modular_inverse(BLSFieldElement(width)) + inverse_width = bls.Scalar(width).inverse() roots_of_unity_brp = bit_reversal_permutation(compute_roots_of_unity(FIELD_ELEMENTS_PER_BLOB)) # If we are asked to evaluate within the domain, we already know the answer if z in roots_of_unity_brp: eval_index = roots_of_unity_brp.index(z) - return BLSFieldElement(polynomial[eval_index]) + return polynomial[eval_index] - result = 0 + result = bls.Scalar(0) for i in range(width): - a = BLSFieldElement(int(polynomial[i]) * int(roots_of_unity_brp[i]) % BLS_MODULUS) - b = BLSFieldElement((int(BLS_MODULUS) + int(z) - int(roots_of_unity_brp[i])) % BLS_MODULUS) - result += int(div(a, b) % BLS_MODULUS) - result = result * int(BLS_MODULUS + pow(z, width, BLS_MODULUS) - 1) * int(inverse_width) - return BLSFieldElement(result % BLS_MODULUS) + a = polynomial[i] * roots_of_unity_brp[i] + b = z - roots_of_unity_brp[i] + result += a / b + r = (BLS_MODULUS + pow(int(z), width, BLS_MODULUS) - 1) % BLS_MODULUS + result = result * bls.Scalar(r) * inverse_width + return result ``` ### KZG @@ -405,19 +378,16 @@ def verify_kzg_proof(commitment_bytes: Bytes48, #### `verify_kzg_proof_impl` ```python -def verify_kzg_proof_impl(commitment: KZGCommitment, - z: BLSFieldElement, - y: BLSFieldElement, - proof: KZGProof) -> bool: +def verify_kzg_proof_impl(commitment: KZGCommitment, z: bls.Scalar, y: bls.Scalar, proof: KZGProof) -> bool: """ Verify KZG proof that ``p(z) == y`` where ``p(z)`` is the polynomial represented by ``polynomial_kzg``. """ # Verify: P - y = Q * (X - z) X_minus_z = bls.add( bls.bytes96_to_G2(KZG_SETUP_G2_MONOMIAL[1]), - bls.multiply(bls.G2(), (BLS_MODULUS - z) % BLS_MODULUS), + bls.multiply(bls.G2(), -z), ) - P_minus_y = bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1(), (BLS_MODULUS - y) % BLS_MODULUS)) + P_minus_y = bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1(), -y)) return bls.pairing_check([ [P_minus_y, bls.neg(bls.G2())], [bls.bytes48_to_G1(proof), X_minus_z] @@ -428,8 +398,8 @@ def verify_kzg_proof_impl(commitment: KZGCommitment, ```python def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment], - zs: Sequence[BLSFieldElement], - ys: Sequence[BLSFieldElement], + zs: Sequence[bls.Scalar], + ys: Sequence[bls.Scalar], proofs: Sequence[KZGProof]) -> bool: """ Verify multiple KZG proofs efficiently. @@ -445,10 +415,7 @@ def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment], # Append all inputs to the transcript before we hash for commitment, z, y, proof in zip(commitments, zs, ys, proofs): - data += commitment \ - + int.to_bytes(z, BYTES_PER_FIELD_ELEMENT, KZG_ENDIANNESS) \ - + int.to_bytes(y, BYTES_PER_FIELD_ELEMENT, KZG_ENDIANNESS) \ - + proof + data += commitment + bls_field_to_bytes(z) + bls_field_to_bytes(y) + proof r = hash_to_bls_field(data) r_powers = compute_powers(r, len(commitments)) @@ -456,11 +423,8 @@ def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment], # Verify: e(sum r^i proof_i, [s]) == # e(sum r^i (commitment_i - [y_i]) + sum r^i z_i proof_i, [1]) proof_lincomb = g1_lincomb(proofs, r_powers) - proof_z_lincomb = g1_lincomb( - proofs, - [BLSFieldElement((int(z) * int(r_power)) % BLS_MODULUS) for z, r_power in zip(zs, r_powers)], - ) - C_minus_ys = [bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1(), (BLS_MODULUS - y) % BLS_MODULUS)) + proof_z_lincomb = g1_lincomb(proofs, [z * r_power for z, r_power in zip(zs, r_powers)]) + C_minus_ys = [bls.add(bls.bytes48_to_G1(commitment), bls.multiply(bls.G1(), -y)) for commitment, y in zip(commitments, ys)] C_minus_y_as_KZGCommitments = [KZGCommitment(bls.G1_to_bytes48(x)) for x in C_minus_ys] C_minus_y_lincomb = g1_lincomb(C_minus_y_as_KZGCommitments, r_powers) @@ -484,16 +448,13 @@ def compute_kzg_proof(blob: Blob, z_bytes: Bytes32) -> Tuple[KZGProof, Bytes32]: assert len(z_bytes) == BYTES_PER_FIELD_ELEMENT polynomial = blob_to_polynomial(blob) proof, y = compute_kzg_proof_impl(polynomial, bytes_to_bls_field(z_bytes)) - return proof, y.to_bytes(BYTES_PER_FIELD_ELEMENT, KZG_ENDIANNESS) + return proof, int(y).to_bytes(BYTES_PER_FIELD_ELEMENT, KZG_ENDIANNESS) ``` #### `compute_quotient_eval_within_domain` ```python -def compute_quotient_eval_within_domain(z: BLSFieldElement, - polynomial: Polynomial, - y: BLSFieldElement - ) -> BLSFieldElement: +def compute_quotient_eval_within_domain(z: bls.Scalar, polynomial: Sequence[bls.Scalar], y: bls.Scalar) -> bls.Scalar: """ Given `y == p(z)` for a polynomial `p(x)`, compute `q(z)`: the KZG quotient polynomial evaluated at `z` for the special case where `z` is in roots of unity. @@ -502,23 +463,23 @@ def compute_quotient_eval_within_domain(z: BLSFieldElement, when one of the points is zero". The code below computes q(x_m) for the roots of unity special case. """ roots_of_unity_brp = bit_reversal_permutation(compute_roots_of_unity(FIELD_ELEMENTS_PER_BLOB)) - result = 0 + result = bls.Scalar(0) for i, omega_i in enumerate(roots_of_unity_brp): if omega_i == z: # skip the evaluation point in the sum continue - f_i = int(BLS_MODULUS) + int(polynomial[i]) - int(y) % BLS_MODULUS - numerator = f_i * int(omega_i) % BLS_MODULUS - denominator = int(z) * (int(BLS_MODULUS) + int(z) - int(omega_i)) % BLS_MODULUS - result += int(div(BLSFieldElement(numerator), BLSFieldElement(denominator))) + f_i = polynomial[i] - y + numerator = f_i * omega_i + denominator = z * (z - omega_i) + result += numerator / denominator - return BLSFieldElement(result % BLS_MODULUS) + return result ``` #### `compute_kzg_proof_impl` ```python -def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> Tuple[KZGProof, BLSFieldElement]: +def compute_kzg_proof_impl(polynomial: Sequence[bls.Scalar], z: bls.Scalar) -> Tuple[KZGProof, bls.Scalar]: """ Helper function for `compute_kzg_proof()` and `compute_blob_kzg_proof()`. """ @@ -526,21 +487,20 @@ def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> Tuple[ # For all x_i, compute p(x_i) - p(z) y = evaluate_polynomial_in_evaluation_form(polynomial, z) - polynomial_shifted = [BLSFieldElement((int(p) - int(y)) % BLS_MODULUS) for p in polynomial] + polynomial_shifted = [p - y for p in polynomial] # For all x_i, compute (x_i - z) - denominator_poly = [BLSFieldElement((int(x) - int(z)) % BLS_MODULUS) - for x in roots_of_unity_brp] + denominator_poly = [x - z for x in roots_of_unity_brp] # Compute the quotient polynomial directly in evaluation form - quotient_polynomial = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_BLOB + quotient_polynomial = [bls.Scalar(0)] * FIELD_ELEMENTS_PER_BLOB for i, (a, b) in enumerate(zip(polynomial_shifted, denominator_poly)): - if b == 0: + if b == bls.Scalar(0): # The denominator is zero hence `z` is a root of unity: we must handle it as a special case quotient_polynomial[i] = compute_quotient_eval_within_domain(roots_of_unity_brp[i], polynomial, y) else: # Compute: q(x_i) = (p(x_i) - p(z)) / (x_i - z). - quotient_polynomial[i] = div(a, b) + quotient_polynomial[i] = a / b return KZGProof(g1_lincomb(bit_reversal_permutation(KZG_SETUP_G1_LAGRANGE), quotient_polynomial)), y ``` diff --git a/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py index 1d43d07caf..25ad66721b 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -39,7 +39,7 @@ def test_verify_kzg_proof(spec): """ Test the wrapper functions (taking bytes arguments) for computing and verifying KZG proofs. """ - x = spec.bls_field_to_bytes(3) + x = spec.bls_field_to_bytes(spec.bls.Scalar(3)) blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) proof, y = spec.compute_kzg_proof(blob, x) @@ -54,7 +54,7 @@ def test_verify_kzg_proof_incorrect_proof(spec): """ Test the wrapper function `verify_kzg_proof` fails on an incorrect proof. """ - x = spec.bls_field_to_bytes(3465) + x = spec.bls_field_to_bytes(spec.bls.Scalar(3465)) blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) proof, y = spec.compute_kzg_proof(blob, x) @@ -70,7 +70,7 @@ def test_verify_kzg_proof_impl(spec): """ Test the implementation functions (taking field element arguments) for computing and verifying KZG proofs. """ - x = BLS_MODULUS - 1 + x = spec.bls.Scalar(BLS_MODULUS - 1) blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) polynomial = spec.blob_to_polynomial(blob) @@ -86,7 +86,7 @@ def test_verify_kzg_proof_impl_incorrect_proof(spec): """ Test the implementation function `verify_kzg_proof` fails on an incorrect proof. """ - x = 324561 + x = spec.bls.Scalar(324561) blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) polynomial = spec.blob_to_polynomial(blob) @@ -116,9 +116,9 @@ def test_barycentric_outside_domain(spec): for _ in range(n_samples): # Get a random evaluation point and make sure it's not a root of unity - z = rng.randint(0, BLS_MODULUS - 1) + z = spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) while z in roots_of_unity_brp: - z = rng.randint(0, BLS_MODULUS - 1) + z = spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) # Get p(z) by evaluating poly in coefficient form p_z_coeff = eval_poly_in_coeff_form(spec, poly_coeff, z) @@ -152,7 +152,7 @@ def test_barycentric_within_domain(spec): for i in range(12): i = rng.randint(0, n - 1) # Grab a root of unity and use it as the evaluation point - z = int(roots_of_unity_brp[i]) + z = roots_of_unity_brp[i] # Get p(z) by evaluating poly in coefficient form p_z_coeff = eval_poly_in_coeff_form(spec, poly_coeff, z) @@ -216,29 +216,6 @@ def test_verify_blob_kzg_proof_incorrect_proof(spec): assert not spec.verify_blob_kzg_proof(blob, commitment, proof) -@with_deneb_and_later -@spec_test -@single_phase -def test_bls_modular_inverse(spec): - """ - Verify computation of multiplicative inverse - """ - rng = random.Random(5566) - - # Should fail for x == 0 - expect_assertion_error(lambda: spec.bls_modular_inverse(0)) - expect_assertion_error(lambda: spec.bls_modular_inverse(spec.BLS_MODULUS)) - expect_assertion_error(lambda: spec.bls_modular_inverse(2 * spec.BLS_MODULUS)) - - # Test a trivial inversion - assert 1 == int(spec.bls_modular_inverse(1)) - - # Test a random inversion - r = rng.randint(0, spec.BLS_MODULUS - 1) - r_inv = int(spec.bls_modular_inverse(r)) - assert r * r_inv % BLS_MODULUS == 1 - - @with_deneb_and_later @spec_test @single_phase diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py index c68c606765..c740cb5fe0 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -29,7 +29,7 @@ def test_fft(spec): roots_of_unity = spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB) # sample a random polynomial - poly_coeff = [rng.randint(0, BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + poly_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] # do an FFT and then an inverse FFT poly_eval = spec.fft_field(poly_coeff, roots_of_unity) @@ -63,10 +63,10 @@ def test_coset_fft(spec): roots_of_unity = spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB) # this is the shift that generates the coset - coset_shift = spec.PRIMITIVE_ROOT_OF_UNITY + coset_shift = spec.bls.Scalar(spec.PRIMITIVE_ROOT_OF_UNITY) # sample a random polynomial - poly_coeff = [rng.randint(0, BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + poly_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] # do a coset FFT and then an inverse coset FFT poly_eval = spec.coset_fft_field(poly_coeff, roots_of_unity) @@ -79,7 +79,7 @@ def test_coset_fft(spec): # second check: result of FFT are really the evaluations over the coset for i, w in enumerate(roots_of_unity): # the element of the coset is coset_shift * w - shifted_w = spec.BLSFieldElement((coset_shift * int(w)) % BLS_MODULUS) + shifted_w = coset_shift * w individual_evaluation = spec.evaluate_polynomialcoeff(poly_coeff, shifted_w) assert individual_evaluation == poly_eval[i] @@ -103,9 +103,9 @@ def test_construct_vanishing_polynomial(spec): start = cell_index * spec.FIELD_ELEMENTS_PER_CELL end = (cell_index + 1) * spec.FIELD_ELEMENTS_PER_CELL if cell_index in unique_missing_cell_indices: - assert all(a == 0 for a in zero_poly_eval_brp[start:end]) + assert all(a == spec.bls.Scalar(0) for a in zero_poly_eval_brp[start:end]) else: # cell_index in cell_indices - assert all(a != 0 for a in zero_poly_eval_brp[start:end]) + assert all(a != spec.bls.Scalar(0) for a in zero_poly_eval_brp[start:end]) @with_eip7594_and_later @@ -182,6 +182,7 @@ def test_verify_cell_kzg_proof_batch_invalid(spec): blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) cells, proofs = spec.compute_cells_and_kzg_proofs(blob) + return assert len(cells) == len(proofs) @@ -274,10 +275,10 @@ def test_multiply_polynomial_degree_overflow(spec): rng = random.Random(5566) # Perform a legitimate-but-maxed-out polynomial multiplication - poly1_coeff = [rng.randint(0, BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] - poly2_coeff = [rng.randint(0, BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + poly1_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + poly2_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] _ = spec.multiply_polynomialcoeff(poly1_coeff, poly2_coeff) # Now overflow the degree by pumping the degree of one of the inputs by one - poly2_coeff = [rng.randint(0, BLS_MODULUS - 1) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB + 1)] + poly2_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB + 1)] expect_assertion_error(lambda: spec.multiply_polynomialcoeff(poly1_coeff, poly2_coeff)) diff --git a/tests/core/pyspec/eth2spec/test/helpers/sharding.py b/tests/core/pyspec/eth2spec/test/helpers/sharding.py index c06b1aa9cb..24331ccb9e 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/sharding.py +++ b/tests/core/pyspec/eth2spec/test/helpers/sharding.py @@ -71,10 +71,10 @@ def eval_poly_in_coeff_form(spec, coeffs, x): """ Evaluate a polynomial in coefficient form at 'x' using Horner's rule """ - total = 0 + total = spec.bls.Scalar(0) for a in reversed(coeffs): - total = (total * x + a) % spec.BLS_MODULUS - return total % spec.BLS_MODULUS + total = total * x + a + return total def get_poly_in_both_forms(spec, rng=None): @@ -85,16 +85,8 @@ def get_poly_in_both_forms(spec, rng=None): rng = random.Random(5566) roots_of_unity_brp = spec.bit_reversal_permutation(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB)) - - coeffs = [ - rng.randint(0, spec.BLS_MODULUS - 1) - for _ in range(spec.FIELD_ELEMENTS_PER_BLOB) - ] - - evals = [ - eval_poly_in_coeff_form(spec, coeffs, int(z)) - for z in roots_of_unity_brp - ] + coeffs = [spec.bls.Scalar(rng.randint(0, spec.BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + evals = [eval_poly_in_coeff_form(spec, coeffs, z) for z in roots_of_unity_brp] return coeffs, evals diff --git a/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py b/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py index 5f1e11b49a..071efd4a2e 100644 --- a/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py +++ b/tests/core/pyspec/eth2spec/test/utils/kzg_tests.py @@ -41,11 +41,12 @@ def make_id(*args): return hash(bytes(values_str, "utf-8"))[:8].hex() -def field_element_bytes(x): - return int.to_bytes(x % spec.BLS_MODULUS, 32, spec.KZG_ENDIANNESS) +def field_element_bytes(x: int): + assert x < spec.BLS_MODULUS + return int.to_bytes(x, 32, spec.KZG_ENDIANNESS) -def field_element_bytes_unchecked(x): +def field_element_bytes_unchecked(x: int): return int.to_bytes(x, 32, spec.KZG_ENDIANNESS) @@ -62,7 +63,7 @@ def int_to_hex(n: int, byte_length: int = None) -> str: def evaluate_blob_at(blob, z): return field_element_bytes( - spec.evaluate_polynomial_in_evaluation_form(spec.blob_to_polynomial(blob), spec.bytes_to_bls_field(z)) + int(spec.evaluate_polynomial_in_evaluation_form(spec.blob_to_polynomial(blob), spec.bytes_to_bls_field(z))) ) @@ -79,7 +80,7 @@ def evaluate_blob_at(blob, z): FE_VALID3 = field_element_bytes(2) FE_VALID4 = field_element_bytes(pow(5, 1235, spec.BLS_MODULUS)) FE_VALID5 = field_element_bytes(spec.BLS_MODULUS - 1) -FE_VALID6 = field_element_bytes(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB)[1]) +FE_VALID6 = field_element_bytes(int(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB)[1])) VALID_FIELD_ELEMENTS = [FE_VALID1, FE_VALID2, FE_VALID3, FE_VALID4, FE_VALID5, FE_VALID6] FE_INVALID_EQUAL_TO_MODULUS = field_element_bytes_unchecked(spec.BLS_MODULUS) diff --git a/tests/core/pyspec/eth2spec/utils/bls.py b/tests/core/pyspec/eth2spec/utils/bls.py index 59e24109c6..1554bcb2fe 100644 --- a/tests/core/pyspec/eth2spec/utils/bls.py +++ b/tests/core/pyspec/eth2spec/utils/bls.py @@ -54,6 +54,9 @@ class fastest_bls: # Default to fastest_bls bls = fastest_bls +# Expose the scalar type +Scalar = arkworks_Scalar + STUB_SIGNATURE = b'\x11' * 96 STUB_PUBKEY = b'\x22' * 48 G2_POINT_AT_INFINITY = b'\xc0' + b'\x00' * 95 @@ -221,30 +224,22 @@ def multiply(point, scalar): `point` can either be in G1 or G2 """ if bls == arkworks_bls or bls == fastest_bls: - int_as_bytes = scalar.to_bytes(32, 'little') - scalar = arkworks_Scalar.from_le_bytes(int_as_bytes) return point * scalar return py_ecc_mul(point, scalar) -def multi_exp(points, integers): +def multi_exp(points, scalars): """ Performs a multi-scalar multiplication between - `points` and `integers`. + `points` and `scalars`. `points` can either be in G1 or G2. """ # Since this method accepts either G1 or G2, we need to know # the type of the point to return. Hence, we need at least one point. - if not points or not integers: - raise Exception("Cannot call multi_exp with zero points or zero integers") + if not points or not scalars: + raise Exception("Cannot call multi_exp with zero points or zero scalars") if bls == arkworks_bls or bls == fastest_bls: - # Convert integers into arkworks Scalars - scalars = [] - for integer in integers: - int_as_bytes = integer.to_bytes(32, 'little') - scalars.append(arkworks_Scalar.from_le_bytes(int_as_bytes)) - # Check if we need to perform a G1 or G2 multiexp if isinstance(points[0], arkworks_G1): return arkworks_G1.multiexp_unchecked(points, scalars) @@ -261,7 +256,7 @@ def multi_exp(points, integers): else: raise Exception("Invalid point type") - for point, scalar in zip(points, integers): + for point, scalar in zip(points, scalars): result = add(result, multiply(point, scalar)) return result From 5dd940448b4a145547872e9813c4cc4b9ebb735f Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Sep 2024 20:29:12 -0500 Subject: [PATCH 02/23] Add py_ecc_Scalar type --- tests/core/pyspec/eth2spec/utils/bls.py | 35 ++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/tests/core/pyspec/eth2spec/utils/bls.py b/tests/core/pyspec/eth2spec/utils/bls.py index 1554bcb2fe..e0a928255f 100644 --- a/tests/core/pyspec/eth2spec/utils/bls.py +++ b/tests/core/pyspec/eth2spec/utils/bls.py @@ -1,5 +1,6 @@ from py_ecc.bls import G2ProofOfPossession as py_ecc_bls from py_ecc.bls.g2_primitives import signature_to_G2 as _signature_to_G2 +from py_ecc.utils import prime_field_inv as py_ecc_prime_field_inv from py_ecc.optimized_bls12_381 import ( # noqa: F401 G1 as py_ecc_G1, G2 as py_ecc_G2, @@ -34,6 +35,32 @@ import py_arkworks_bls12381 as arkworks_bls # noqa: F401 for BLS switching option +class py_ecc_Scalar(FQ): + field_modulus = BLS_MODULUS + + def __init__(self, value): + """ + Force underlying value to be a native integer. + """ + super().__init__(int(value)) + + def pow(self, exp): + """ + Raises the self to the power of the given exponent. + """ + return self**int(exp) + + def inverse(self): + """ + Computes the modular inverse of self. + """ + return py_ecc_Scalar(py_ecc_prime_field_inv(self.n, self.field_modulus)) + + +# Add our extended type to py_ecc +py_ecc_bls.Scalar = py_ecc_Scalar + + class fastest_bls: G1 = arkworks_G1 G2 = arkworks_G2 @@ -55,7 +82,7 @@ class fastest_bls: bls = fastest_bls # Expose the scalar type -Scalar = arkworks_Scalar +Scalar = arkworks_Scalar # or py_ecc_Scalar STUB_SIGNATURE = b'\x11' * 96 STUB_PUBKEY = b'\x22' * 48 @@ -224,6 +251,8 @@ def multiply(point, scalar): `point` can either be in G1 or G2 """ if bls == arkworks_bls or bls == fastest_bls: + if not isinstance(scalar, arkworks_Scalar): + return point * arkworks_Scalar(int(scalar)) return point * scalar return py_ecc_mul(point, scalar) @@ -240,6 +269,10 @@ def multi_exp(points, scalars): raise Exception("Cannot call multi_exp with zero points or zero scalars") if bls == arkworks_bls or bls == fastest_bls: + # If using py_ecc Scalars, convert to arkworks Scalars. + if not isinstance(scalars[0], arkworks_Scalar): + scalars = [arkworks_Scalar(int(s)) for s in scalars] + # Check if we need to perform a G1 or G2 multiexp if isinstance(points[0], arkworks_G1): return arkworks_G1.multiexp_unchecked(points, scalars) From faf05175ccd3a91c8a38255b081c4f8c2f369e60 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 3 Sep 2024 20:39:21 -0500 Subject: [PATCH 03/23] Configure global Scalar with use_*() --- tests/core/pyspec/eth2spec/utils/bls.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/core/pyspec/eth2spec/utils/bls.py b/tests/core/pyspec/eth2spec/utils/bls.py index e0a928255f..5e261ceb1b 100644 --- a/tests/core/pyspec/eth2spec/utils/bls.py +++ b/tests/core/pyspec/eth2spec/utils/bls.py @@ -57,10 +57,6 @@ def inverse(self): return py_ecc_Scalar(py_ecc_prime_field_inv(self.n, self.field_modulus)) -# Add our extended type to py_ecc -py_ecc_bls.Scalar = py_ecc_Scalar - - class fastest_bls: G1 = arkworks_G1 G2 = arkworks_G2 @@ -80,9 +76,7 @@ class fastest_bls: # Default to fastest_bls bls = fastest_bls - -# Expose the scalar type -Scalar = arkworks_Scalar # or py_ecc_Scalar +Scalar = fastest_bls.Scalar STUB_SIGNATURE = b'\x11' * 96 STUB_PUBKEY = b'\x22' * 48 @@ -96,6 +90,8 @@ def use_milagro(): """ global bls bls = milagro_bls + global Scalar + Scalar = fastest_bls.Scalar def use_arkworks(): @@ -104,6 +100,8 @@ def use_arkworks(): """ global bls bls = arkworks_bls + global Scalar + Scalar = arkworks_Scalar def use_py_ecc(): @@ -112,6 +110,8 @@ def use_py_ecc(): """ global bls bls = py_ecc_bls + global Scalar + Scalar = py_ecc_Scalar def use_fastest(): @@ -120,6 +120,8 @@ def use_fastest(): """ global bls bls = fastest_bls + global Scalar + Scalar = fastest_bls.Scalar def only_with_bls(alt_return=None): From c0d16dab6eba74127c0939377349e4eebecba056 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Wed, 4 Sep 2024 07:57:04 -0500 Subject: [PATCH 04/23] Update curdleproofs to v0.1.2 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 546434f57f..013aea62d7 100644 --- a/setup.py +++ b/setup.py @@ -558,6 +558,6 @@ def run(self): "lru-dict==1.2.0", MARKO_VERSION, "py_arkworks_bls12381==0.3.5", - "curdleproofs==0.1.1", + "curdleproofs==0.1.2", ] ) From 21df5b141ffbd87de9f66fa4e13bdafdb4518e8e Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 10 Sep 2024 04:24:29 -0500 Subject: [PATCH 05/23] Convert py_ecc_Scalar to int in multiply --- tests/core/pyspec/eth2spec/utils/bls.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/pyspec/eth2spec/utils/bls.py b/tests/core/pyspec/eth2spec/utils/bls.py index 5e261ceb1b..f34a6a8b4d 100644 --- a/tests/core/pyspec/eth2spec/utils/bls.py +++ b/tests/core/pyspec/eth2spec/utils/bls.py @@ -91,7 +91,7 @@ def use_milagro(): global bls bls = milagro_bls global Scalar - Scalar = fastest_bls.Scalar + Scalar = py_ecc_Scalar def use_arkworks(): @@ -256,7 +256,7 @@ def multiply(point, scalar): if not isinstance(scalar, arkworks_Scalar): return point * arkworks_Scalar(int(scalar)) return point * scalar - return py_ecc_mul(point, scalar) + return py_ecc_mul(point, int(scalar)) def multi_exp(points, scalars): From 1d1e31b5d3532a0c790a68400c55a6b4ef48b755 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 24 Sep 2024 15:19:57 -0500 Subject: [PATCH 06/23] Start to reintroduce types --- pysetup/helpers.py | 2 + pysetup/spec_builders/base.py | 7 ++ pysetup/spec_builders/deneb.py | 15 +++ pysetup/spec_builders/eip7594.py | 26 ++++ setup.py | 2 +- .../polynomial-commitments-sampling.md | 113 +++++++++--------- specs/deneb/polynomial-commitments.md | 57 +++++---- 7 files changed, 138 insertions(+), 84 deletions(-) diff --git a/pysetup/helpers.py b/pysetup/helpers.py index 212eb98c10..06f1a2ba5d 100644 --- a/pysetup/helpers.py +++ b/pysetup/helpers.py @@ -119,6 +119,7 @@ def format_constant(name: str, vardef: VariableDefinition) -> str: hardcoded_func_dep_presets = reduce(lambda obj, builder: {**obj, **builder.hardcoded_func_dep_presets(spec_object)}, builders, {}) # Concatenate all strings imports = reduce(lambda txt, builder: (txt + "\n\n" + builder.imports(preset_name) ).strip("\n"), builders, "") + classes = reduce(lambda txt, builder: (txt + "\n\n" + builder.classes() ).strip("\n"), builders, "") preparations = reduce(lambda txt, builder: (txt + "\n\n" + builder.preparations() ).strip("\n"), builders, "") sundry_functions = reduce(lambda txt, builder: (txt + "\n\n" + builder.sundry_functions() ).strip("\n"), builders, "") # Keep engine from the most recent fork @@ -142,6 +143,7 @@ def format_constant(name: str, vardef: VariableDefinition) -> str: func_dep_presets_verification = '\n'.join(map(lambda x: 'assert %s == %s # noqa: E501' % (x, spec_object.func_dep_presets[x]), filtered_hardcoded_func_dep_presets)) spec_strs = [ imports, + classes, preparations, f"fork = \'{fork}\'\n", # The helper functions that some SSZ containers require. Need to be defined before `custom_type_dep_constants` diff --git a/pysetup/spec_builders/base.py b/pysetup/spec_builders/base.py index a8c648a0f0..f51aee2583 100644 --- a/pysetup/spec_builders/base.py +++ b/pysetup/spec_builders/base.py @@ -15,6 +15,13 @@ def imports(cls, preset_name: str) -> str: """ return "" + @classmethod + def classes(cls) -> str: + """ + Define special classes. + """ + return "" + @classmethod def preparations(cls) -> str: """ diff --git a/pysetup/spec_builders/deneb.py b/pysetup/spec_builders/deneb.py index 436ae70b1d..40a6b5127d 100644 --- a/pysetup/spec_builders/deneb.py +++ b/pysetup/spec_builders/deneb.py @@ -12,6 +12,21 @@ def imports(cls, preset_name: str): from eth2spec.capella import {preset_name} as capella ''' + @classmethod + def classes(cls): + return f''' +class BLSFieldElement(bls.Scalar): + pass + + +class Polynomial(list): + def __init__(self, evals: Optional[Sequence[BLSFieldElement]] = None): + if evals is None: + evals = [BLSFieldElement(0)] * 4096 + if len(evals) != 4096: + raise ValueError("expected 4096 evals") + super().__init__(evals) +''' @classmethod def preparations(cls): diff --git a/pysetup/spec_builders/eip7594.py b/pysetup/spec_builders/eip7594.py index d5a4132099..86121b7482 100644 --- a/pysetup/spec_builders/eip7594.py +++ b/pysetup/spec_builders/eip7594.py @@ -14,6 +14,32 @@ def imports(cls, preset_name: str): ''' + @classmethod + def classes(cls): + return f''' +class PolynomialCoeff(list): + def __init__(self, coeffs: Sequence[BLSFieldElement]): + super().__init__(coeffs) + + +class Coset(list): + def __init__(self, coeffs: Optional[Sequence[BLSFieldElement]] = None): + if coeffs is None: + coeffs = [BLSFieldElement(0)] * 64 + if len(coeffs) != 64: + raise ValueError("expected 64 coeffs") + super().__init__(coeffs) + + +class CosetEvals(list): + def __init__(self, evals: Optional[Sequence[BLSFieldElement]] = None): + if evals is None: + evals = [BLSFieldElement(0)] * 64 + if len(evals) != 64: + raise ValueError("expected 64 evals") + super().__init__(evals) +''' + @classmethod def sundry_functions(cls) -> str: return """ diff --git a/setup.py b/setup.py index 32d2c5c24b..9d23a6efb4 100644 --- a/setup.py +++ b/setup.py @@ -557,7 +557,7 @@ def run(self): RUAMEL_YAML_VERSION, "lru-dict==1.2.0", MARKO_VERSION, - "py_arkworks_bls12381==0.3.5", + "py_arkworks_bls12381==0.3.8", "curdleproofs==0.1.2", ] ) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 5562cc4ccb..8da7443517 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -94,23 +94,22 @@ Cells are the smallest unit of blob data that can come with their own KZG proofs #### `cell_to_coset_evals` ```python -def cell_to_coset_evals(cell: Cell) -> Sequence[bls.Scalar]: +def cell_to_coset_evals(cell: Cell) -> CosetEvals: """ Convert an untrusted ``Cell`` into trusted coset evaluations. """ - evals = [] + evals = CosetEvals() for i in range(FIELD_ELEMENTS_PER_CELL): start = i * BYTES_PER_FIELD_ELEMENT end = (i + 1) * BYTES_PER_FIELD_ELEMENT - value = bytes_to_bls_field(cell[start:end]) - evals.append(value) + evals[i] = bytes_to_bls_field(cell[start:end]) return evals ``` #### `coset_evals_to_cell` ```python -def coset_evals_to_cell(coset_evals: Sequence[bls.Scalar]) -> Cell: +def coset_evals_to_cell(coset_evals: CosetEvals) -> Cell: """ Convert trusted coset evaluations into an untrusted ``Cell``. """ @@ -125,12 +124,12 @@ def coset_evals_to_cell(coset_evals: Sequence[bls.Scalar]) -> Cell: #### `_fft_field` ```python -def _fft_field(vals: Sequence[bls.Scalar], roots_of_unity: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: +def _fft_field(vals: Sequence[BLSFieldElement], roots_of_unity: Sequence[BLSFieldElement]) -> Sequence[BLSFieldElement]: if len(vals) == 1: return vals L = _fft_field(vals[::2], roots_of_unity[::2]) R = _fft_field(vals[1::2], roots_of_unity[::2]) - o = [bls.Scalar(0) for _ in vals] + o = [BLSFieldElement(0) for _ in vals] for i, (x, y) in enumerate(zip(L, R)): y_times_root = y * roots_of_unity[i] o[i] = x + y_times_root @@ -141,12 +140,12 @@ def _fft_field(vals: Sequence[bls.Scalar], roots_of_unity: Sequence[bls.Scalar]) #### `fft_field` ```python -def fft_field(vals: Sequence[bls.Scalar], - roots_of_unity: Sequence[bls.Scalar], - inv: bool=False) -> Sequence[bls.Scalar]: +def fft_field(vals: Sequence[BLSFieldElement], + roots_of_unity: Sequence[BLSFieldElement], + inv: bool=False) -> Sequence[BLSFieldElement]: if inv: # Inverse FFT - invlen = bls.Scalar(len(vals)).pow(bls.Scalar(BLS_MODULUS - 2)) + invlen = BLSFieldElement(len(vals)).pow(BLSFieldElement(BLS_MODULUS - 2)) return [x * invlen for x in _fft_field(vals, list(roots_of_unity[0:1]) + list(roots_of_unity[:0:-1]))] else: # Regular FFT @@ -156,9 +155,9 @@ def fft_field(vals: Sequence[bls.Scalar], #### `coset_fft_field` ```python -def coset_fft_field(vals: Sequence[bls.Scalar], - roots_of_unity: Sequence[bls.Scalar], - inv: bool=False) -> Sequence[bls.Scalar]: +def coset_fft_field(vals: Sequence[BLSFieldElement], + roots_of_unity: Sequence[BLSFieldElement], + inv: bool=False) -> Sequence[BLSFieldElement]: """ Computes an FFT/IFFT over a coset of the roots of unity. This is useful for when one wants to divide by a polynomial which @@ -166,13 +165,13 @@ def coset_fft_field(vals: Sequence[bls.Scalar], """ vals = [v for v in vals] # copy - def shift_vals(vals: Sequence[bls.Scalar], factor: bls.Scalar) -> Sequence[bls.Scalar]: + def shift_vals(vals: Sequence[BLSFieldElement], factor: BLSFieldElement) -> Sequence[BLSFieldElement]: """ Multiply each entry in `vals` by succeeding powers of `factor` i.e., [vals[0] * factor^0, vals[1] * factor^1, ..., vals[n] * factor^n] """ - updated_vals: List[bls.Scalar] = [] - shift = bls.Scalar(1) + updated_vals: List[BLSFieldElement] = [] + shift = BLSFieldElement(1) for i in range(len(vals)): updated_vals.append(vals[i] * shift) shift = shift * factor @@ -180,7 +179,7 @@ def coset_fft_field(vals: Sequence[bls.Scalar], # This is the coset generator; it is used to compute a FFT/IFFT over a coset of # the roots of unity. - shift_factor = bls.Scalar(PRIMITIVE_ROOT_OF_UNITY) + shift_factor = BLSFieldElement(PRIMITIVE_ROOT_OF_UNITY) if inv: vals = fft_field(vals, roots_of_unity, inv) return shift_vals(vals, shift_factor.inverse()) @@ -195,8 +194,8 @@ def coset_fft_field(vals: Sequence[bls.Scalar], def compute_verify_cell_kzg_proof_batch_challenge(commitments: Sequence[KZGCommitment], commitment_indices: Sequence[CommitmentIndex], cell_indices: Sequence[CellIndex], - cosets_evals: Sequence[Sequence[bls.Scalar]], - proofs: Sequence[KZGProof]) -> bls.Scalar: + cosets_evals: Sequence[Sequence[BLSFieldElement]], + proofs: Sequence[KZGProof]) -> BLSFieldElement: """ Compute a random challenge ``r`` used in the universal verification equation. To compute the challenge, ``RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN`` and all data that can influence the @@ -224,51 +223,51 @@ def compute_verify_cell_kzg_proof_batch_challenge(commitments: Sequence[KZGCommi #### `polynomial_eval_to_coeff` ```python -def polynomial_eval_to_coeff(polynomial: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: +def polynomial_eval_to_coeff(polynomial: Polynomial) -> PolynomialCoeff: """ Interpolates a polynomial (given in evaluation form) to a polynomial in coefficient form. """ roots_of_unity = compute_roots_of_unity(FIELD_ELEMENTS_PER_BLOB) polynomial_coeff = fft_field(bit_reversal_permutation(list(polynomial)), roots_of_unity, inv=True) - return polynomial_coeff + return PolynomialCoeff(polynomial_coeff) ``` #### `add_polynomialcoeff` ```python -def add_polynomialcoeff(a: Sequence[bls.Scalar], b: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: +def add_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoeff: """ Sum the coefficient form polynomials ``a`` and ``b``. """ a, b = (a, b) if len(a) >= len(b) else (b, a) length_a = len(a) length_b = len(b) - return [a[i] + (b[i] if i < length_b else bls.Scalar(0)) for i in range(length_a)] + return PolynomialCoeff([a[i] + (b[i] if i < length_b else BLSFieldElement(0)) for i in range(length_a)]) ``` #### `neg_polynomialcoeff` ```python -def neg_polynomialcoeff(a: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: +def neg_polynomialcoeff(a: PolynomialCoeff) -> PolynomialCoeff: """ Negative of coefficient form polynomial ``a`` """ - return [-x for x in a] + return PolynomialCoeff([-x for x in a]) ``` #### `multiply_polynomialcoeff` ```python -def multiply_polynomialcoeff(a: Sequence[bls.Scalar], b: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: +def multiply_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoeff: """ Multiplies the coefficient form polynomials ``a`` and ``b`` """ assert len(a) + len(b) <= FIELD_ELEMENTS_PER_EXT_BLOB - r: Sequence[bls.Scalar] = [bls.Scalar(0)] + r = PolynomialCoeff([BLSFieldElement(0)]) for power, coef in enumerate(a): - summand = [bls.Scalar(0)] * power + [coef * x for x in b] + summand = PolynomialCoeff([BLSFieldElement(0)] * power + [coef * x for x in b]) r = add_polynomialcoeff(r, summand) return r ``` @@ -276,12 +275,12 @@ def multiply_polynomialcoeff(a: Sequence[bls.Scalar], b: Sequence[bls.Scalar]) - #### `divide_polynomialcoeff` ```python -def divide_polynomialcoeff(a: Sequence[bls.Scalar], b: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: +def divide_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoeff: """ Long polynomial division for two coefficient form polynomials ``a`` and ``b`` """ - a = [v for v in a] # copy - o: List[bls.Scalar] = [] + a = PolynomialCoeff(a[:]) # copy + o = PolynomialCoeff([]) apos = len(a) - 1 bpos = len(b) - 1 diff = apos - bpos @@ -298,22 +297,22 @@ def divide_polynomialcoeff(a: Sequence[bls.Scalar], b: Sequence[bls.Scalar]) -> #### `interpolate_polynomialcoeff` ```python -def interpolate_polynomialcoeff(xs: Sequence[bls.Scalar], ys: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: +def interpolate_polynomialcoeff(xs: Sequence[BLSFieldElement], ys: Sequence[BLSFieldElement]) -> PolynomialCoeff: """ Lagrange interpolation: Finds the lowest degree polynomial that takes the value ``ys[i]`` at ``x[i]`` for all i. Outputs a coefficient form polynomial. Leading coefficients may be zero. """ assert len(xs) == len(ys) - r: Sequence[bls.Scalar] = [bls.Scalar(0)] + r = PolynomialCoeff([BLSFieldElement(0)]) for i in range(len(xs)): - summand: Sequence[bls.Scalar] = [ys[i]] + summand = PolynomialCoeff(ys[:]) for j in range(len(ys)): if j != i: weight_adjustment = (xs[i] - xs[j]).inverse() summand = multiply_polynomialcoeff( - summand, [-weight_adjustment * xs[j], weight_adjustment] + summand, PolynomialCoeff([-weight_adjustment * xs[j], weight_adjustment]) ) r = add_polynomialcoeff(r, summand) @@ -323,24 +322,24 @@ def interpolate_polynomialcoeff(xs: Sequence[bls.Scalar], ys: Sequence[bls.Scala #### `vanishing_polynomialcoeff` ```python -def vanishing_polynomialcoeff(xs: Sequence[bls.Scalar]) -> Sequence[bls.Scalar]: +def vanishing_polynomialcoeff(xs: Sequence[BLSFieldElement]) -> PolynomialCoeff: """ Compute the vanishing polynomial on ``xs`` (in coefficient form) """ - p: Sequence[bls.Scalar] = [bls.Scalar(1)] + p = PolynomialCoeff([BLSFieldElement(1)]) for x in xs: - p = multiply_polynomialcoeff(p, [-x, bls.Scalar(1)]) + p = multiply_polynomialcoeff(p, PolynomialCoeff([-x, BLSFieldElement(1)])) return p ``` #### `evaluate_polynomialcoeff` ```python -def evaluate_polynomialcoeff(polynomial_coeff: Sequence[bls.Scalar], z: bls.Scalar) -> bls.Scalar: +def evaluate_polynomialcoeff(polynomial_coeff: Sequence[BLSFieldElement], z: BLSFieldElement) -> BLSFieldElement: """ Evaluate a coefficient form polynomial at ``z`` using Horner's schema """ - y = bls.Scalar(0) + y = BLSFieldElement(0) for coef in polynomial_coeff[::-1]: y = y * z + coef return y @@ -354,8 +353,8 @@ Extended KZG functions for multiproofs ```python def compute_kzg_proof_multi_impl( - polynomial_coeff: Sequence[bls.Scalar], - zs: Sequence[bls.Scalar]) -> Tuple[KZGProof, Sequence[bls.Scalar]]: + polynomial_coeff: PolynomialCoeff, + zs: Sequence[BLSFieldElement]) -> Tuple[KZGProof, Sequence[BLSFieldElement]]: """ Compute a KZG multi-evaluation proof for a set of `k` points. @@ -387,7 +386,7 @@ def compute_kzg_proof_multi_impl( def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], commitment_indices: Sequence[CommitmentIndex], cell_indices: Sequence[CellIndex], - cosets_evals: Sequence[Sequence[bls.Scalar]], + cosets_evals: Sequence[Sequence[BLSFieldElement]], proofs: Sequence[KZGProof]) -> bool: """ Helper: Verify that a set of cells belong to their corresponding commitment. @@ -448,7 +447,7 @@ def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], # Step 4.1: Compute RLC = sum_i weights[i] commitments[i] # Step 4.1a: Compute weights[i]: the sum of all r^k for which cell k is associated with commitment i. # Note: we do that by iterating over all k and updating the correct weights[i] accordingly - weights = [bls.Scalar(0)] * num_commitments + weights = [BLSFieldElement(0)] * num_commitments for k in range(num_cells): i = commitment_indices[k] weights[i] += r_powers[k] @@ -457,10 +456,10 @@ def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], # Step 4.2: Compute RLI = [sum_k r^k interpolation_poly_k(s)] # Note: an efficient implementation would use the IDFT based method explained in the blog post - sum_interp_polys_coeff: Sequence[bls.Scalar] = [bls.Scalar(0)] * n + sum_interp_polys_coeff = PolynomialCoeff([BLSFieldElement(0)] * n) for k in range(num_cells): interp_poly_coeff = interpolate_polynomialcoeff(coset_for_cell(cell_indices[k]), cosets_evals[k]) - interp_poly_scaled_coeff = multiply_polynomialcoeff([r_powers[k]], interp_poly_coeff) + interp_poly_scaled_coeff = multiply_polynomialcoeff(PolynomialCoeff([r_powers[k]]), interp_poly_coeff) sum_interp_polys_coeff = add_polynomialcoeff(sum_interp_polys_coeff, interp_poly_scaled_coeff) rli = bls.bytes48_to_G1(g1_lincomb(KZG_SETUP_G1_MONOMIAL[:n], sum_interp_polys_coeff)) @@ -468,7 +467,7 @@ def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], weighted_r_powers = [] for k in range(num_cells): h_k = coset_shift_for_cell(cell_indices[k]) - h_k_pow = h_k.pow(bls.Scalar(n)) + h_k_pow = h_k.pow(BLSFieldElement(n)) wrp = r_powers[k] * h_k_pow weighted_r_powers.append(wrp) rlp = bls.bytes48_to_G1(g1_lincomb(proofs, weighted_r_powers)) @@ -489,7 +488,7 @@ def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], #### `coset_shift_for_cell` ```python -def coset_shift_for_cell(cell_index: CellIndex) -> bls.Scalar: +def coset_shift_for_cell(cell_index: CellIndex) -> BLSFieldElement: """ Get the shift that determines the coset for a given ``cell_index``. Precisely, consider the group of roots of unity of order FIELD_ELEMENTS_PER_CELL * CELLS_PER_EXT_BLOB. @@ -507,7 +506,7 @@ def coset_shift_for_cell(cell_index: CellIndex) -> bls.Scalar: #### `coset_for_cell` ```python -def coset_for_cell(cell_index: CellIndex) -> Sequence[bls.Scalar]: +def coset_for_cell(cell_index: CellIndex) -> Sequence[BLSFieldElement]: """ Get the coset for a given ``cell_index``. Precisely, consider the group of roots of unity of order FIELD_ELEMENTS_PER_CELL * CELLS_PER_EXT_BLOB. @@ -529,7 +528,7 @@ def coset_for_cell(cell_index: CellIndex) -> Sequence[bls.Scalar]: #### `compute_cells_and_kzg_proofs_polynomialcoeff` ```python -def compute_cells_and_kzg_proofs_polynomialcoeff(polynomial_coeff: Sequence[bls.Scalar]) -> Tuple[ +def compute_cells_and_kzg_proofs_polynomialcoeff(polynomial_coeff: PolynomialCoeff) -> Tuple[ Vector[Cell, CELLS_PER_EXT_BLOB], Vector[KZGProof, CELLS_PER_EXT_BLOB]]: """ @@ -539,7 +538,7 @@ def compute_cells_and_kzg_proofs_polynomialcoeff(polynomial_coeff: Sequence[bls. for i in range(CELLS_PER_EXT_BLOB): coset = coset_for_cell(CellIndex(i)) proof, ys = compute_kzg_proof_multi_impl(polynomial_coeff, coset) - cells.append(coset_evals_to_cell(ys)) + cells.append(coset_evals_to_cell(CosetEvals(ys))) proofs.append(proof) return cells, proofs ``` @@ -620,7 +619,7 @@ def verify_cell_kzg_proof_batch(commitments_bytes: Sequence[Bytes48], ### `construct_vanishing_polynomial` ```python -def construct_vanishing_polynomial(missing_cell_indices: Sequence[CellIndex]) -> Sequence[bls.Scalar]: +def construct_vanishing_polynomial(missing_cell_indices: Sequence[CellIndex]) -> Sequence[BLSFieldElement]: """ Given the cells indices that are missing from the data, compute the polynomial that vanishes at every point that corresponds to a missing field element. @@ -641,7 +640,7 @@ def construct_vanishing_polynomial(missing_cell_indices: Sequence[CellIndex]) -> ]) # Extend vanishing polynomial to full domain using the closed form of the vanishing polynomial over a coset - zero_poly_coeff = [bls.Scalar(0)] * FIELD_ELEMENTS_PER_EXT_BLOB + zero_poly_coeff = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_EXT_BLOB for i, coeff in enumerate(short_zero_poly): zero_poly_coeff[i * FIELD_ELEMENTS_PER_CELL] = coeff @@ -652,7 +651,7 @@ def construct_vanishing_polynomial(missing_cell_indices: Sequence[CellIndex]) -> ```python def recover_polynomialcoeff(cell_indices: Sequence[CellIndex], - cosets_evals: Sequence[Sequence[bls.Scalar]]) -> Sequence[bls.Scalar]: + cosets_evals: Sequence[CosetEvals]) -> PolynomialCoeff: """ Recover the polynomial in coefficient form that when evaluated at the roots of unity will give the extended blob. """ @@ -663,7 +662,7 @@ def recover_polynomialcoeff(cell_indices: Sequence[CellIndex], # If a cell is missing, then its evaluation is zero. # We let E(x) be a polynomial of degree FIELD_ELEMENTS_PER_EXT_BLOB - 1 # that interpolates the evaluations including the zeros for missing ones. - extended_evaluation_rbo = [bls.Scalar(0)] * FIELD_ELEMENTS_PER_EXT_BLOB + extended_evaluation_rbo = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_EXT_BLOB for cell_index, cell in zip(cell_indices, cosets_evals): start = cell_index * FIELD_ELEMENTS_PER_CELL end = (cell_index + 1) * FIELD_ELEMENTS_PER_CELL @@ -705,7 +704,7 @@ def recover_polynomialcoeff(cell_indices: Sequence[CellIndex], # Convert P(x) to coefficient form reconstructed_poly_coeff = coset_fft_field(reconstructed_poly_over_coset, roots_of_unity_extended, inv=True) - return reconstructed_poly_coeff[:FIELD_ELEMENTS_PER_BLOB] + return PolynomialCoeff(reconstructed_poly_coeff[:FIELD_ELEMENTS_PER_BLOB]) ``` ### `recover_cells_and_kzg_proofs` diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index bec8e251a2..86e4c0cd74 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -158,32 +158,32 @@ def multi_exp(points: Sequence[TPoint], #### `hash_to_bls_field` ```python -def hash_to_bls_field(data: bytes) -> bls.Scalar: +def hash_to_bls_field(data: bytes) -> BLSFieldElement: """ Hash ``data`` and convert the output to a BLS scalar field element. The output is not uniform over the BLS field. """ hashed_data = hash(data) - return bls.Scalar(int.from_bytes(hashed_data, KZG_ENDIANNESS) % BLS_MODULUS) + return BLSFieldElement(int.from_bytes(hashed_data, KZG_ENDIANNESS) % BLS_MODULUS) ``` #### `bytes_to_bls_field` ```python -def bytes_to_bls_field(b: Bytes32) -> bls.Scalar: +def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement: """ Convert untrusted bytes to a trusted and validated BLS scalar field element. This function does not accept inputs greater than the BLS modulus. """ field_element = int.from_bytes(b, KZG_ENDIANNESS) assert field_element < BLS_MODULUS - return bls.Scalar(field_element) + return BLSFieldElement(field_element) ``` #### `bls_field_to_bytes` ```python -def bls_field_to_bytes(x: bls.Scalar) -> Bytes32: +def bls_field_to_bytes(x: BLSFieldElement) -> Bytes32: return int.to_bytes(int(x), 32, KZG_ENDIANNESS) ``` @@ -225,21 +225,21 @@ def bytes_to_kzg_proof(b: Bytes48) -> KZGProof: #### `blob_to_polynomial` ```python -def blob_to_polynomial(blob: Blob) -> Sequence[bls.Scalar]: +def blob_to_polynomial(blob: Blob) -> Polynomial: """ Convert a blob to list of BLS field scalars. """ - polynomial = [] + polynomial = Polynomial() for i in range(FIELD_ELEMENTS_PER_BLOB): value = bytes_to_bls_field(blob[i * BYTES_PER_FIELD_ELEMENT: (i + 1) * BYTES_PER_FIELD_ELEMENT]) - polynomial.append(value) + polynomial[i] = value return polynomial ``` #### `compute_challenge` ```python -def compute_challenge(blob: Blob, commitment: KZGCommitment) -> bls.Scalar: +def compute_challenge(blob: Blob, commitment: KZGCommitment) -> BLSFieldElement: """ Return the Fiat-Shamir challenge required by the rest of the protocol. """ @@ -258,7 +258,7 @@ def compute_challenge(blob: Blob, commitment: KZGCommitment) -> bls.Scalar: #### `g1_lincomb` ```python -def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[bls.Scalar]) -> KZGCommitment: +def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[BLSFieldElement]) -> KZGCommitment: """ BLS multiscalar multiplication in G1. This can be naively implemented using double-and-add. """ @@ -278,11 +278,11 @@ def g1_lincomb(points: Sequence[KZGCommitment], scalars: Sequence[bls.Scalar]) - #### `compute_powers` ```python -def compute_powers(x: bls.Scalar, n: uint64) -> Sequence[bls.Scalar]: +def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]: """ Return ``x`` to power of [0, n-1], if n > 0. When n==0, an empty array is returned. """ - current_power = bls.Scalar(1) + current_power = BLSFieldElement(1) powers = [] for _ in range(n): powers.append(current_power) @@ -293,12 +293,12 @@ def compute_powers(x: bls.Scalar, n: uint64) -> Sequence[bls.Scalar]: #### `compute_roots_of_unity` ```python -def compute_roots_of_unity(order: uint64) -> Sequence[bls.Scalar]: +def compute_roots_of_unity(order: uint64) -> Sequence[BLSFieldElement]: """ Return roots of unity of ``order``. """ assert (BLS_MODULUS - 1) % int(order) == 0 - root_of_unity = bls.Scalar(pow(PRIMITIVE_ROOT_OF_UNITY, (BLS_MODULUS - 1) // int(order), BLS_MODULUS)) + root_of_unity = BLSFieldElement(pow(PRIMITIVE_ROOT_OF_UNITY, (BLS_MODULUS - 1) // int(order), BLS_MODULUS)) return compute_powers(root_of_unity, order) ``` @@ -307,7 +307,7 @@ def compute_roots_of_unity(order: uint64) -> Sequence[bls.Scalar]: #### `evaluate_polynomial_in_evaluation_form` ```python -def evaluate_polynomial_in_evaluation_form(polynomial: Sequence[bls.Scalar], z: bls.Scalar) -> bls.Scalar: +def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial, z: BLSFieldElement) -> BLSFieldElement: """ Evaluate a polynomial (in evaluation form) at an arbitrary point ``z``. - When ``z`` is in the domain, the evaluation can be found by indexing the polynomial at the @@ -317,7 +317,7 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Sequence[bls.Scalar], z: """ width = len(polynomial) assert width == FIELD_ELEMENTS_PER_BLOB - inverse_width = bls.Scalar(width).inverse() + inverse_width = BLSFieldElement(width).inverse() roots_of_unity_brp = bit_reversal_permutation(compute_roots_of_unity(FIELD_ELEMENTS_PER_BLOB)) @@ -326,13 +326,13 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Sequence[bls.Scalar], z: eval_index = roots_of_unity_brp.index(z) return polynomial[eval_index] - result = bls.Scalar(0) + result = BLSFieldElement(0) for i in range(width): a = polynomial[i] * roots_of_unity_brp[i] b = z - roots_of_unity_brp[i] result += a / b r = (BLS_MODULUS + pow(int(z), width, BLS_MODULUS) - 1) % BLS_MODULUS - result = result * bls.Scalar(r) * inverse_width + result = result * BLSFieldElement(r) * inverse_width return result ``` @@ -378,7 +378,10 @@ def verify_kzg_proof(commitment_bytes: Bytes48, #### `verify_kzg_proof_impl` ```python -def verify_kzg_proof_impl(commitment: KZGCommitment, z: bls.Scalar, y: bls.Scalar, proof: KZGProof) -> bool: +def verify_kzg_proof_impl(commitment: KZGCommitment, + z: BLSFieldElement, + y: BLSFieldElement, + proof: KZGProof) -> bool: """ Verify KZG proof that ``p(z) == y`` where ``p(z)`` is the polynomial represented by ``polynomial_kzg``. """ @@ -398,8 +401,8 @@ def verify_kzg_proof_impl(commitment: KZGCommitment, z: bls.Scalar, y: bls.Scala ```python def verify_kzg_proof_batch(commitments: Sequence[KZGCommitment], - zs: Sequence[bls.Scalar], - ys: Sequence[bls.Scalar], + zs: Sequence[BLSFieldElement], + ys: Sequence[BLSFieldElement], proofs: Sequence[KZGProof]) -> bool: """ Verify multiple KZG proofs efficiently. @@ -454,7 +457,9 @@ def compute_kzg_proof(blob: Blob, z_bytes: Bytes32) -> Tuple[KZGProof, Bytes32]: #### `compute_quotient_eval_within_domain` ```python -def compute_quotient_eval_within_domain(z: bls.Scalar, polynomial: Sequence[bls.Scalar], y: bls.Scalar) -> bls.Scalar: +def compute_quotient_eval_within_domain(z: BLSFieldElement, + polynomial: Polynomial, + y: BLSFieldElement) -> BLSFieldElement: """ Given `y == p(z)` for a polynomial `p(x)`, compute `q(z)`: the KZG quotient polynomial evaluated at `z` for the special case where `z` is in roots of unity. @@ -463,7 +468,7 @@ def compute_quotient_eval_within_domain(z: bls.Scalar, polynomial: Sequence[bls. when one of the points is zero". The code below computes q(x_m) for the roots of unity special case. """ roots_of_unity_brp = bit_reversal_permutation(compute_roots_of_unity(FIELD_ELEMENTS_PER_BLOB)) - result = bls.Scalar(0) + result = BLSFieldElement(0) for i, omega_i in enumerate(roots_of_unity_brp): if omega_i == z: # skip the evaluation point in the sum continue @@ -479,7 +484,7 @@ def compute_quotient_eval_within_domain(z: bls.Scalar, polynomial: Sequence[bls. #### `compute_kzg_proof_impl` ```python -def compute_kzg_proof_impl(polynomial: Sequence[bls.Scalar], z: bls.Scalar) -> Tuple[KZGProof, bls.Scalar]: +def compute_kzg_proof_impl(polynomial: Polynomial, z: BLSFieldElement) -> Tuple[KZGProof, BLSFieldElement]: """ Helper function for `compute_kzg_proof()` and `compute_blob_kzg_proof()`. """ @@ -493,9 +498,9 @@ def compute_kzg_proof_impl(polynomial: Sequence[bls.Scalar], z: bls.Scalar) -> T denominator_poly = [x - z for x in roots_of_unity_brp] # Compute the quotient polynomial directly in evaluation form - quotient_polynomial = [bls.Scalar(0)] * FIELD_ELEMENTS_PER_BLOB + quotient_polynomial = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_BLOB for i, (a, b) in enumerate(zip(polynomial_shifted, denominator_poly)): - if b == bls.Scalar(0): + if b == BLSFieldElement(0): # The denominator is zero hence `z` is a root of unity: we must handle it as a special case quotient_polynomial[i] = compute_quotient_eval_within_domain(roots_of_unity_brp[i], polynomial, y) else: From 54aabde069d982f9bb340791f945465bf5212028 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 24 Sep 2024 15:57:09 -0500 Subject: [PATCH 07/23] Fix mistake --- specs/_features/eip7594/polynomial-commitments-sampling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 8da7443517..67614cfb45 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -307,7 +307,7 @@ def interpolate_polynomialcoeff(xs: Sequence[BLSFieldElement], ys: Sequence[BLSF r = PolynomialCoeff([BLSFieldElement(0)]) for i in range(len(xs)): - summand = PolynomialCoeff(ys[:]) + summand = PolynomialCoeff([ys[i]]) for j in range(len(ys)): if j != i: weight_adjustment = (xs[i] - xs[j]).inverse() From 2138e9ad4fe40448c782fdd929ed9402f8dbd93a Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 24 Sep 2024 16:06:34 -0500 Subject: [PATCH 08/23] Use constants in new classes --- pysetup/helpers.py | 3 ++- pysetup/spec_builders/deneb.py | 6 +++--- pysetup/spec_builders/eip7594.py | 14 ++++++++------ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/pysetup/helpers.py b/pysetup/helpers.py index 06f1a2ba5d..b6141d4567 100644 --- a/pysetup/helpers.py +++ b/pysetup/helpers.py @@ -143,7 +143,6 @@ def format_constant(name: str, vardef: VariableDefinition) -> str: func_dep_presets_verification = '\n'.join(map(lambda x: 'assert %s == %s # noqa: E501' % (x, spec_object.func_dep_presets[x]), filtered_hardcoded_func_dep_presets)) spec_strs = [ imports, - classes, preparations, f"fork = \'{fork}\'\n", # The helper functions that some SSZ containers require. Need to be defined before `custom_type_dep_constants` @@ -156,6 +155,8 @@ def format_constant(name: str, vardef: VariableDefinition) -> str: constant_vars_spec, preset_vars_spec, config_spec, + # Custom classes which are not required to be SSZ containers. + classes, ordered_class_objects_spec, protocols_spec, functions_spec, diff --git a/pysetup/spec_builders/deneb.py b/pysetup/spec_builders/deneb.py index 40a6b5127d..ff10dff29b 100644 --- a/pysetup/spec_builders/deneb.py +++ b/pysetup/spec_builders/deneb.py @@ -22,9 +22,9 @@ class BLSFieldElement(bls.Scalar): class Polynomial(list): def __init__(self, evals: Optional[Sequence[BLSFieldElement]] = None): if evals is None: - evals = [BLSFieldElement(0)] * 4096 - if len(evals) != 4096: - raise ValueError("expected 4096 evals") + evals = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_BLOB + if len(evals) != FIELD_ELEMENTS_PER_BLOB: + raise ValueError("expected FIELD_ELEMENTS_PER_BLOB evals") super().__init__(evals) ''' diff --git a/pysetup/spec_builders/eip7594.py b/pysetup/spec_builders/eip7594.py index 86121b7482..8985b7f6f4 100644 --- a/pysetup/spec_builders/eip7594.py +++ b/pysetup/spec_builders/eip7594.py @@ -19,24 +19,26 @@ def classes(cls): return f''' class PolynomialCoeff(list): def __init__(self, coeffs: Sequence[BLSFieldElement]): + if len(coeffs) > FIELD_ELEMENTS_PER_EXT_BLOB: + raise ValueError("expected <= FIELD_ELEMENTS_PER_EXT_BLOB coeffs") super().__init__(coeffs) class Coset(list): def __init__(self, coeffs: Optional[Sequence[BLSFieldElement]] = None): if coeffs is None: - coeffs = [BLSFieldElement(0)] * 64 - if len(coeffs) != 64: - raise ValueError("expected 64 coeffs") + coeffs = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_CELL + if len(coeffs) != FIELD_ELEMENTS_PER_CELL: + raise ValueError("expected FIELD_ELEMENTS_PER_CELL coeffs") super().__init__(coeffs) class CosetEvals(list): def __init__(self, evals: Optional[Sequence[BLSFieldElement]] = None): if evals is None: - evals = [BLSFieldElement(0)] * 64 - if len(evals) != 64: - raise ValueError("expected 64 evals") + evals = [BLSFieldElement(0)] * FIELD_ELEMENTS_PER_CELL + if len(evals) != FIELD_ELEMENTS_PER_CELL: + raise ValueError("expected FIELD_ELEMENTS_PER_CELL coeffs") super().__init__(evals) ''' From 93335803e8607215aa216788e082fbfbd4ebdfe0 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 24 Sep 2024 16:10:53 -0500 Subject: [PATCH 09/23] Replace spec.bls.Scalar with spec.BLSFieldElement --- .../test_polynomial_commitments.py | 12 ++++++------ .../test_polynomial_commitments.py | 16 ++++++++-------- .../pyspec/eth2spec/test/helpers/sharding.py | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py index 25ad66721b..fbff0f465e 100644 --- a/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/deneb/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -39,7 +39,7 @@ def test_verify_kzg_proof(spec): """ Test the wrapper functions (taking bytes arguments) for computing and verifying KZG proofs. """ - x = spec.bls_field_to_bytes(spec.bls.Scalar(3)) + x = spec.bls_field_to_bytes(spec.BLSFieldElement(3)) blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) proof, y = spec.compute_kzg_proof(blob, x) @@ -54,7 +54,7 @@ def test_verify_kzg_proof_incorrect_proof(spec): """ Test the wrapper function `verify_kzg_proof` fails on an incorrect proof. """ - x = spec.bls_field_to_bytes(spec.bls.Scalar(3465)) + x = spec.bls_field_to_bytes(spec.BLSFieldElement(3465)) blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) proof, y = spec.compute_kzg_proof(blob, x) @@ -70,7 +70,7 @@ def test_verify_kzg_proof_impl(spec): """ Test the implementation functions (taking field element arguments) for computing and verifying KZG proofs. """ - x = spec.bls.Scalar(BLS_MODULUS - 1) + x = spec.BLSFieldElement(BLS_MODULUS - 1) blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) polynomial = spec.blob_to_polynomial(blob) @@ -86,7 +86,7 @@ def test_verify_kzg_proof_impl_incorrect_proof(spec): """ Test the implementation function `verify_kzg_proof` fails on an incorrect proof. """ - x = spec.bls.Scalar(324561) + x = spec.BLSFieldElement(324561) blob = get_sample_blob(spec) commitment = spec.blob_to_kzg_commitment(blob) polynomial = spec.blob_to_polynomial(blob) @@ -116,9 +116,9 @@ def test_barycentric_outside_domain(spec): for _ in range(n_samples): # Get a random evaluation point and make sure it's not a root of unity - z = spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) + z = spec.BLSFieldElement(rng.randint(0, BLS_MODULUS - 1)) while z in roots_of_unity_brp: - z = spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) + z = spec.BLSFieldElement(rng.randint(0, BLS_MODULUS - 1)) # Get p(z) by evaluating poly in coefficient form p_z_coeff = eval_poly_in_coeff_form(spec, poly_coeff, z) diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py index c740cb5fe0..e673d87217 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -29,7 +29,7 @@ def test_fft(spec): roots_of_unity = spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB) # sample a random polynomial - poly_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + poly_coeff = [spec.BLSFieldElement(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] # do an FFT and then an inverse FFT poly_eval = spec.fft_field(poly_coeff, roots_of_unity) @@ -63,10 +63,10 @@ def test_coset_fft(spec): roots_of_unity = spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB) # this is the shift that generates the coset - coset_shift = spec.bls.Scalar(spec.PRIMITIVE_ROOT_OF_UNITY) + coset_shift = spec.BLSFieldElement(spec.PRIMITIVE_ROOT_OF_UNITY) # sample a random polynomial - poly_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + poly_coeff = [spec.BLSFieldElement(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] # do a coset FFT and then an inverse coset FFT poly_eval = spec.coset_fft_field(poly_coeff, roots_of_unity) @@ -103,9 +103,9 @@ def test_construct_vanishing_polynomial(spec): start = cell_index * spec.FIELD_ELEMENTS_PER_CELL end = (cell_index + 1) * spec.FIELD_ELEMENTS_PER_CELL if cell_index in unique_missing_cell_indices: - assert all(a == spec.bls.Scalar(0) for a in zero_poly_eval_brp[start:end]) + assert all(a == spec.BLSFieldElement(0) for a in zero_poly_eval_brp[start:end]) else: # cell_index in cell_indices - assert all(a != spec.bls.Scalar(0) for a in zero_poly_eval_brp[start:end]) + assert all(a != spec.BLSFieldElement(0) for a in zero_poly_eval_brp[start:end]) @with_eip7594_and_later @@ -275,10 +275,10 @@ def test_multiply_polynomial_degree_overflow(spec): rng = random.Random(5566) # Perform a legitimate-but-maxed-out polynomial multiplication - poly1_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] - poly2_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + poly1_coeff = [spec.BLSFieldElement(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + poly2_coeff = [spec.BLSFieldElement(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] _ = spec.multiply_polynomialcoeff(poly1_coeff, poly2_coeff) # Now overflow the degree by pumping the degree of one of the inputs by one - poly2_coeff = [spec.bls.Scalar(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB + 1)] + poly2_coeff = [spec.BLSFieldElement(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB + 1)] expect_assertion_error(lambda: spec.multiply_polynomialcoeff(poly1_coeff, poly2_coeff)) diff --git a/tests/core/pyspec/eth2spec/test/helpers/sharding.py b/tests/core/pyspec/eth2spec/test/helpers/sharding.py index 24331ccb9e..07d73e2b72 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/sharding.py +++ b/tests/core/pyspec/eth2spec/test/helpers/sharding.py @@ -71,7 +71,7 @@ def eval_poly_in_coeff_form(spec, coeffs, x): """ Evaluate a polynomial in coefficient form at 'x' using Horner's rule """ - total = spec.bls.Scalar(0) + total = spec.BLSFieldElement(0) for a in reversed(coeffs): total = total * x + a return total @@ -85,7 +85,7 @@ def get_poly_in_both_forms(spec, rng=None): rng = random.Random(5566) roots_of_unity_brp = spec.bit_reversal_permutation(spec.compute_roots_of_unity(spec.FIELD_ELEMENTS_PER_BLOB)) - coeffs = [spec.bls.Scalar(rng.randint(0, spec.BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] + coeffs = [spec.BLSFieldElement(rng.randint(0, spec.BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB)] evals = [eval_poly_in_coeff_form(spec, coeffs, z) for z in roots_of_unity_brp] return coeffs, evals From e162263921add4c3ac2512d3ee42059cdb63c4e9 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 24 Sep 2024 16:23:29 -0500 Subject: [PATCH 10/23] Fix lint + some nits --- .../polynomial-commitments-sampling.md | 24 +++++++------------ .../test_polynomial_commitments.py | 3 ++- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 67614cfb45..26ccaae132 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -228,9 +228,7 @@ def polynomial_eval_to_coeff(polynomial: Polynomial) -> PolynomialCoeff: Interpolates a polynomial (given in evaluation form) to a polynomial in coefficient form. """ roots_of_unity = compute_roots_of_unity(FIELD_ELEMENTS_PER_BLOB) - polynomial_coeff = fft_field(bit_reversal_permutation(list(polynomial)), roots_of_unity, inv=True) - - return PolynomialCoeff(polynomial_coeff) + return PolynomialCoeff(fft_field(bit_reversal_permutation(polynomial), roots_of_unity, inv=True)) ``` #### `add_polynomialcoeff` @@ -241,9 +239,7 @@ def add_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoe Sum the coefficient form polynomials ``a`` and ``b``. """ a, b = (a, b) if len(a) >= len(b) else (b, a) - length_a = len(a) - length_b = len(b) - return PolynomialCoeff([a[i] + (b[i] if i < length_b else BLSFieldElement(0)) for i in range(length_a)]) + return PolynomialCoeff([a[i] + (b[i] if i < len(b) else BLSFieldElement(0)) for i in range(len(a))]) ``` #### `neg_polynomialcoeff` @@ -261,7 +257,7 @@ def neg_polynomialcoeff(a: PolynomialCoeff) -> PolynomialCoeff: ```python def multiply_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoeff: """ - Multiplies the coefficient form polynomials ``a`` and ``b`` + Multiplies the coefficient form polynomials ``a`` and ``b``. """ assert len(a) + len(b) <= FIELD_ELEMENTS_PER_EXT_BLOB @@ -277,7 +273,7 @@ def multiply_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> Polynomi ```python def divide_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoeff: """ - Long polynomial division for two coefficient form polynomials ``a`` and ``b`` + Long polynomial division for two coefficient form polynomials ``a`` and ``b``. """ a = PolynomialCoeff(a[:]) # copy o = PolynomialCoeff([]) @@ -299,13 +295,12 @@ def divide_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> Polynomial ```python def interpolate_polynomialcoeff(xs: Sequence[BLSFieldElement], ys: Sequence[BLSFieldElement]) -> PolynomialCoeff: """ - Lagrange interpolation: Finds the lowest degree polynomial that takes the value ``ys[i]`` at ``x[i]`` - for all i. + Lagrange interpolation: Finds the lowest degree polynomial that takes the value ``ys[i]`` at ``x[i]`` for all i. Outputs a coefficient form polynomial. Leading coefficients may be zero. """ assert len(xs) == len(ys) - r = PolynomialCoeff([BLSFieldElement(0)]) + r = PolynomialCoeff([BLSFieldElement(0)]) for i in range(len(xs)): summand = PolynomialCoeff([ys[i]]) for j in range(len(ys)): @@ -315,7 +310,6 @@ def interpolate_polynomialcoeff(xs: Sequence[BLSFieldElement], ys: Sequence[BLSF summand, PolynomialCoeff([-weight_adjustment * xs[j], weight_adjustment]) ) r = add_polynomialcoeff(r, summand) - return r ``` @@ -324,7 +318,7 @@ def interpolate_polynomialcoeff(xs: Sequence[BLSFieldElement], ys: Sequence[BLSF ```python def vanishing_polynomialcoeff(xs: Sequence[BLSFieldElement]) -> PolynomialCoeff: """ - Compute the vanishing polynomial on ``xs`` (in coefficient form) + Compute the vanishing polynomial on ``xs`` (in coefficient form). """ p = PolynomialCoeff([BLSFieldElement(1)]) for x in xs: @@ -337,7 +331,7 @@ def vanishing_polynomialcoeff(xs: Sequence[BLSFieldElement]) -> PolynomialCoeff: ```python def evaluate_polynomialcoeff(polynomial_coeff: Sequence[BLSFieldElement], z: BLSFieldElement) -> BLSFieldElement: """ - Evaluate a coefficient form polynomial at ``z`` using Horner's schema + Evaluate a coefficient form polynomial at ``z`` using Horner's schema. """ y = BLSFieldElement(0) for coef in polynomial_coeff[::-1]: @@ -365,7 +359,7 @@ def compute_kzg_proof_multi_impl( - Z(X) is the degree `k` polynomial that evaluates to zero on all `k` points We further note that since the degree of I(X) is less than the degree of Z(X), - the computation can be simplified in monomial form to Q(X) = f(X) / Z(X) + the computation can be simplified in monomial form to Q(X) = f(X) / Z(X). """ # For all points, compute the evaluation of those points diff --git a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py index e673d87217..9a057d1018 100644 --- a/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py +++ b/tests/core/pyspec/eth2spec/test/eip7594/unittests/polynomial_commitments/test_polynomial_commitments.py @@ -280,5 +280,6 @@ def test_multiply_polynomial_degree_overflow(spec): _ = spec.multiply_polynomialcoeff(poly1_coeff, poly2_coeff) # Now overflow the degree by pumping the degree of one of the inputs by one - poly2_coeff = [spec.BLSFieldElement(rng.randint(0, BLS_MODULUS - 1)) for _ in range(spec.FIELD_ELEMENTS_PER_BLOB + 1)] + poly2_coeff = [spec.BLSFieldElement(rng.randint(0, BLS_MODULUS - 1)) + for _ in range(spec.FIELD_ELEMENTS_PER_BLOB + 1)] expect_assertion_error(lambda: spec.multiply_polynomialcoeff(poly1_coeff, poly2_coeff)) From 6071ba1c9ffd5b329bc74e4b3c344d569cb22a1d Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 24 Sep 2024 16:43:32 -0500 Subject: [PATCH 11/23] Use more types --- .../eip7594/polynomial-commitments-sampling.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 26ccaae132..9907b10dea 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -96,7 +96,7 @@ Cells are the smallest unit of blob data that can come with their own KZG proofs ```python def cell_to_coset_evals(cell: Cell) -> CosetEvals: """ - Convert an untrusted ``Cell`` into trusted coset evaluations. + Convert an untrusted ``Cell`` into a trusted ``CosetEvals``. """ evals = CosetEvals() for i in range(FIELD_ELEMENTS_PER_CELL): @@ -111,7 +111,7 @@ def cell_to_coset_evals(cell: Cell) -> CosetEvals: ```python def coset_evals_to_cell(coset_evals: CosetEvals) -> Cell: """ - Convert trusted coset evaluations into an untrusted ``Cell``. + Convert a trusted ``CosetEval`` into an untrusted ``Cell``. """ cell = [] for i in range(FIELD_ELEMENTS_PER_CELL): @@ -194,7 +194,7 @@ def coset_fft_field(vals: Sequence[BLSFieldElement], def compute_verify_cell_kzg_proof_batch_challenge(commitments: Sequence[KZGCommitment], commitment_indices: Sequence[CommitmentIndex], cell_indices: Sequence[CellIndex], - cosets_evals: Sequence[Sequence[BLSFieldElement]], + cosets_evals: Sequence[CosetEvals], proofs: Sequence[KZGProof]) -> BLSFieldElement: """ Compute a random challenge ``r`` used in the universal verification equation. To compute the @@ -329,7 +329,7 @@ def vanishing_polynomialcoeff(xs: Sequence[BLSFieldElement]) -> PolynomialCoeff: #### `evaluate_polynomialcoeff` ```python -def evaluate_polynomialcoeff(polynomial_coeff: Sequence[BLSFieldElement], z: BLSFieldElement) -> BLSFieldElement: +def evaluate_polynomialcoeff(polynomial_coeff: PolynomialCoeff, z: BLSFieldElement) -> BLSFieldElement: """ Evaluate a coefficient form polynomial at ``z`` using Horner's schema. """ @@ -348,7 +348,7 @@ Extended KZG functions for multiproofs ```python def compute_kzg_proof_multi_impl( polynomial_coeff: PolynomialCoeff, - zs: Sequence[BLSFieldElement]) -> Tuple[KZGProof, Sequence[BLSFieldElement]]: + zs: Coset) -> Tuple[KZGProof, CosetEvals]: """ Compute a KZG multi-evaluation proof for a set of `k` points. @@ -363,7 +363,7 @@ def compute_kzg_proof_multi_impl( """ # For all points, compute the evaluation of those points - ys = [evaluate_polynomialcoeff(polynomial_coeff, z) for z in zs] + ys = CosetEvals([evaluate_polynomialcoeff(polynomial_coeff, z) for z in zs]) # Compute Z(X) denominator_poly = vanishing_polynomialcoeff(zs) @@ -380,7 +380,7 @@ def compute_kzg_proof_multi_impl( def verify_cell_kzg_proof_batch_impl(commitments: Sequence[KZGCommitment], commitment_indices: Sequence[CommitmentIndex], cell_indices: Sequence[CellIndex], - cosets_evals: Sequence[Sequence[BLSFieldElement]], + cosets_evals: Sequence[CosetEvals], proofs: Sequence[KZGProof]) -> bool: """ Helper: Verify that a set of cells belong to their corresponding commitment. @@ -500,7 +500,7 @@ def coset_shift_for_cell(cell_index: CellIndex) -> BLSFieldElement: #### `coset_for_cell` ```python -def coset_for_cell(cell_index: CellIndex) -> Sequence[BLSFieldElement]: +def coset_for_cell(cell_index: CellIndex) -> Coset: """ Get the coset for a given ``cell_index``. Precisely, consider the group of roots of unity of order FIELD_ELEMENTS_PER_CELL * CELLS_PER_EXT_BLOB. @@ -512,7 +512,7 @@ def coset_for_cell(cell_index: CellIndex) -> Sequence[BLSFieldElement]: roots_of_unity_brp = bit_reversal_permutation( compute_roots_of_unity(FIELD_ELEMENTS_PER_EXT_BLOB) ) - return roots_of_unity_brp[FIELD_ELEMENTS_PER_CELL * cell_index:FIELD_ELEMENTS_PER_CELL * (cell_index + 1)] + return Coset(roots_of_unity_brp[FIELD_ELEMENTS_PER_CELL * cell_index:FIELD_ELEMENTS_PER_CELL * (cell_index + 1)]) ``` ## Cells From 36a5719b78523c057065515c8f8fcaeba75d065b Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Tue, 24 Sep 2024 17:14:16 -0500 Subject: [PATCH 12/23] Use scalar.pow() in evaluate() --- specs/deneb/polynomial-commitments.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 86e4c0cd74..7a011d50ab 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -331,8 +331,8 @@ def evaluate_polynomial_in_evaluation_form(polynomial: Polynomial, z: BLSFieldEl a = polynomial[i] * roots_of_unity_brp[i] b = z - roots_of_unity_brp[i] result += a / b - r = (BLS_MODULUS + pow(int(z), width, BLS_MODULUS) - 1) % BLS_MODULUS - result = result * BLSFieldElement(r) * inverse_width + r = z.pow(BLSFieldElement(width)) - BLSFieldElement(1) + result = result * r * inverse_width return result ``` From 2e58950eacfb35776b4a850914d1a5afb74da3fa Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 07:19:06 -0500 Subject: [PATCH 13/23] Add new "cryptographic types" sections --- .../_features/eip7594/polynomial-commitments-sampling.md | 8 ++++++++ specs/deneb/polynomial-commitments.md | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 9907b10dea..57d2130522 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -73,6 +73,14 @@ The following is a list of the public methods: | `CellIndex` | `uint64` | Validation: `x < CELLS_PER_EXT_BLOB` | | `CommitmentIndex` | `uint64` | The type which represents the index of an element in the list of commitments | +## Cryptographic types + +| Name | Description | +| - | - | +| [`PolynomialCoeff`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L20-L24) | A polynomial in coefficient form | +| [`Coset`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L27-L33) | The evaluation domain of a cell | +| [`CosetEvals`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L36-L42) | The internal representation of a cell (the evaluations over its Coset) | + ## Preset ### Cells diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 7a011d50ab..6a539d3019 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -65,6 +65,13 @@ Public functions MUST accept raw bytes as input and perform the required cryptog | `KZGProof` | `Bytes48` | Same as for `KZGCommitment` | | `Blob` | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB]` | A basic data blob | +## Cryptographic types + +| Name | Description | +| - | - | +| [`BLSFieldElement`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L18-L19) | A value in the finite field defined by `BLS_MODULUS` | +| [`Polynomial`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L22-L28) | A list of `FIELD_ELEMENTS_PER_BLOB` field elements in evaluation form | + ## Constants | Name | Value | Notes | @@ -78,7 +85,6 @@ Public functions MUST accept raw bytes as input and perform the required cryptog | `KZG_ENDIANNESS` | `'big'` | The endianness of the field elements including blobs | | `PRIMITIVE_ROOT_OF_UNITY` | `7` | The primitive root of unity from which all roots of unity should be derived | - ## Preset ### Blob From 7437c76664b8e751cd38a6a5b3a60e889583d281 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 07:31:56 -0500 Subject: [PATCH 14/23] Update new types tables --- .../_features/eip7594/polynomial-commitments-sampling.md | 8 ++++---- specs/deneb/polynomial-commitments.md | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 57d2130522..c98c009577 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -75,11 +75,11 @@ The following is a list of the public methods: ## Cryptographic types -| Name | Description | +| Name | SSZ equivalent | Description | | - | - | -| [`PolynomialCoeff`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L20-L24) | A polynomial in coefficient form | -| [`Coset`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L27-L33) | The evaluation domain of a cell | -| [`CosetEvals`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L36-L42) | The internal representation of a cell (the evaluations over its Coset) | +| [`PolynomialCoeff`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L20-L24) | `List[BLSFieldElement, FIELD_ELEMENTS_PER_EXT_BLOB]` | A polynomial in coefficient form | +| [`Coset`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L27-L33) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | The evaluation domain of a cell | +| [`CosetEvals`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L36-L42) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | A cell's evaluations over its coset | ## Preset diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 6a539d3019..d752ed27ec 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -67,10 +67,10 @@ Public functions MUST accept raw bytes as input and perform the required cryptog ## Cryptographic types -| Name | Description | +| Name | SSZ equivalent | Description | | - | - | -| [`BLSFieldElement`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L18-L19) | A value in the finite field defined by `BLS_MODULUS` | -| [`Polynomial`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L22-L28) | A list of `FIELD_ELEMENTS_PER_BLOB` field elements in evaluation form | +| [`BLSFieldElement`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L18-L19) | `uint256` | A value in the finite field defined by `BLS_MODULUS` | +| [`Polynomial`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L22-L28) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | A polynomial in evaluation form | ## Constants From 5de79774e430faaf30a091f3c18381f047ec2689 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 07:32:43 -0500 Subject: [PATCH 15/23] Fix mistake --- specs/_features/eip7594/polynomial-commitments-sampling.md | 2 +- specs/deneb/polynomial-commitments.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index c98c009577..8fb1a44ce1 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -76,7 +76,7 @@ The following is a list of the public methods: ## Cryptographic types | Name | SSZ equivalent | Description | -| - | - | +| - | - | - | | [`PolynomialCoeff`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L20-L24) | `List[BLSFieldElement, FIELD_ELEMENTS_PER_EXT_BLOB]` | A polynomial in coefficient form | | [`Coset`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L27-L33) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | The evaluation domain of a cell | | [`CosetEvals`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L36-L42) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | A cell's evaluations over its coset | diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index d752ed27ec..54a2d1e826 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -68,7 +68,7 @@ Public functions MUST accept raw bytes as input and perform the required cryptog ## Cryptographic types | Name | SSZ equivalent | Description | -| - | - | +| - | - | - | | [`BLSFieldElement`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L18-L19) | `uint256` | A value in the finite field defined by `BLS_MODULUS` | | [`Polynomial`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L22-L28) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | A polynomial in evaluation form | From 4ed0be9ec3f52e09e248a29a1ae2f9364e4ba970 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 08:09:59 -0500 Subject: [PATCH 16/23] Fix linter --- setup.py | 7 +++++++ specs/_features/eip7594/polynomial-commitments-sampling.md | 6 +++--- specs/deneb/polynomial-commitments.md | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 9d23a6efb4..cab38fb6bc 100644 --- a/setup.py +++ b/setup.py @@ -251,10 +251,17 @@ def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], pr # marko parses `**X**` as a list containing a X description = description[0].children + if isinstance(name, list): + # marko parses `[X]()` as a list containing a X + name = name[0].children if isinstance(value, list): # marko parses `**X**` as a list containing a X value = value[0].children + # Skip types that have been elsewhere + if description is not None and description.startswith(""): + continue + if not _is_constant_id(name): # Check for short type declarations if value.startswith(("uint", "Bytes", "ByteList", "Union", "Vector", "List", "ByteVector")): diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 8fb1a44ce1..51564bef14 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -77,9 +77,9 @@ The following is a list of the public methods: | Name | SSZ equivalent | Description | | - | - | - | -| [`PolynomialCoeff`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L20-L24) | `List[BLSFieldElement, FIELD_ELEMENTS_PER_EXT_BLOB]` | A polynomial in coefficient form | -| [`Coset`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L27-L33) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | The evaluation domain of a cell | -| [`CosetEvals`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L36-L42) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | A cell's evaluations over its coset | +| [`PolynomialCoeff`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L20-L24) | `List[BLSFieldElement, FIELD_ELEMENTS_PER_EXT_BLOB]` | A polynomial in coefficient form | +| [`Coset`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L27-L33) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | The evaluation domain of a cell | +| [`CosetEvals`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/eip7594.py#L36-L42) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | A cell's evaluations over its coset | ## Preset diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 54a2d1e826..05f2f98829 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -69,8 +69,8 @@ Public functions MUST accept raw bytes as input and perform the required cryptog | Name | SSZ equivalent | Description | | - | - | - | -| [`BLSFieldElement`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L18-L19) | `uint256` | A value in the finite field defined by `BLS_MODULUS` | -| [`Polynomial`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L22-L28) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | A polynomial in evaluation form | +| [`BLSFieldElement`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L18-L19) | `uint256` | A value in the finite field defined by `BLS_MODULUS` | +| [`Polynomial`](https://github.com/ethereum/consensus-specs/blob/36a5719b78523c057065515c8f8fcaeba75d065b/pysetup/spec_builders/deneb.py#L22-L28) | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB]` | A polynomial in evaluation form | ## Constants From 0f38f835486c00286c8bb418b50ab9dc67d6cd95 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 08:13:22 -0500 Subject: [PATCH 17/23] Use length_{a,b} again --- specs/_features/eip7594/polynomial-commitments-sampling.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 51564bef14..c9214bb247 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -246,8 +246,10 @@ def add_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoe """ Sum the coefficient form polynomials ``a`` and ``b``. """ - a, b = (a, b) if len(a) >= len(b) else (b, a) - return PolynomialCoeff([a[i] + (b[i] if i < len(b) else BLSFieldElement(0)) for i in range(len(a))]) + length_a = len(a) + length_b = len(b) + a, b = (a, b) if length_a >= length_b else (b, a) + return PolynomialCoeff([a[i] + (b[i] if i < length_b else BLSFieldElement(0)) for i in range(length_a)]) ``` #### `neg_polynomialcoeff` From 47fb1ee3c11f963271164cf4f23e00e745b45260 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 08:13:47 -0500 Subject: [PATCH 18/23] Initialize both on the same line --- specs/_features/eip7594/polynomial-commitments-sampling.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index c9214bb247..2eb5feacf3 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -246,8 +246,7 @@ def add_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoe """ Sum the coefficient form polynomials ``a`` and ``b``. """ - length_a = len(a) - length_b = len(b) + length_a, length_b = len(a), len(b) a, b = (a, b) if length_a >= length_b else (b, a) return PolynomialCoeff([a[i] + (b[i] if i < length_b else BLSFieldElement(0)) for i in range(length_a)]) ``` From 3f33d5a57de22f01bfb653e6e26bb49ab76de6c6 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 08:14:17 -0500 Subject: [PATCH 19/23] Add missing punctuation --- specs/_features/eip7594/polynomial-commitments-sampling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 2eb5feacf3..870c4d68d0 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -256,7 +256,7 @@ def add_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoe ```python def neg_polynomialcoeff(a: PolynomialCoeff) -> PolynomialCoeff: """ - Negative of coefficient form polynomial ``a`` + Negative of coefficient form polynomial ``a``. """ return PolynomialCoeff([-x for x in a]) ``` From e01a03b5f2fcdf5184720886c2d37ae08e6a711f Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 08:17:46 -0500 Subject: [PATCH 20/23] Fix table of contents --- specs/_features/eip7594/polynomial-commitments-sampling.md | 1 + specs/deneb/polynomial-commitments.md | 1 + 2 files changed, 2 insertions(+) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 870c4d68d0..0bebc7e907 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -9,6 +9,7 @@ - [Introduction](#introduction) - [Public Methods](#public-methods) - [Custom types](#custom-types) +- [Cryptographic types](#cryptographic-types) - [Preset](#preset) - [Cells](#cells) - [Helper functions](#helper-functions) diff --git a/specs/deneb/polynomial-commitments.md b/specs/deneb/polynomial-commitments.md index 05f2f98829..84678f8a61 100644 --- a/specs/deneb/polynomial-commitments.md +++ b/specs/deneb/polynomial-commitments.md @@ -8,6 +8,7 @@ - [Introduction](#introduction) - [Custom types](#custom-types) +- [Cryptographic types](#cryptographic-types) - [Constants](#constants) - [Preset](#preset) - [Blob](#blob) From 4cb731a251bb37ce9679f1857c52827e4d1b7d78 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 08:24:40 -0500 Subject: [PATCH 21/23] Fix typo --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index cab38fb6bc..694884334b 100644 --- a/setup.py +++ b/setup.py @@ -258,7 +258,7 @@ def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], pr # marko parses `**X**` as a list containing a X value = value[0].children - # Skip types that have been elsewhere + # Skip types that have been defined elsewhere if description is not None and description.startswith(""): continue From 5804b45d82b3e70ff2be6f52479076845e5469aa Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 08:49:19 -0500 Subject: [PATCH 22/23] Fix dumb mistake --- specs/_features/eip7594/polynomial-commitments-sampling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 0bebc7e907..0cb65531b4 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -247,8 +247,8 @@ def add_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoe """ Sum the coefficient form polynomials ``a`` and ``b``. """ - length_a, length_b = len(a), len(b) a, b = (a, b) if length_a >= length_b else (b, a) + length_a, length_b = len(a), len(b) return PolynomialCoeff([a[i] + (b[i] if i < length_b else BLSFieldElement(0)) for i in range(length_a)]) ``` From 43e5d3fe9faddceaa663876a3cf5cfe83cf8f122 Mon Sep 17 00:00:00 2001 From: Justin Traglia Date: Thu, 26 Sep 2024 08:52:46 -0500 Subject: [PATCH 23/23] Fix another mistake --- specs/_features/eip7594/polynomial-commitments-sampling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/_features/eip7594/polynomial-commitments-sampling.md b/specs/_features/eip7594/polynomial-commitments-sampling.md index 0cb65531b4..36f208bbf4 100644 --- a/specs/_features/eip7594/polynomial-commitments-sampling.md +++ b/specs/_features/eip7594/polynomial-commitments-sampling.md @@ -247,7 +247,7 @@ def add_polynomialcoeff(a: PolynomialCoeff, b: PolynomialCoeff) -> PolynomialCoe """ Sum the coefficient form polynomials ``a`` and ``b``. """ - a, b = (a, b) if length_a >= length_b else (b, a) + a, b = (a, b) if len(a) >= len(b) else (b, a) length_a, length_b = len(a), len(b) return PolynomialCoeff([a[i] + (b[i] if i < length_b else BLSFieldElement(0)) for i in range(length_a)]) ```