diff --git a/specs/eip4844/polynomial-commitments.md b/specs/eip4844/polynomial-commitments.md index 6ffc7f0c5..b18122b03 100644 --- a/specs/eip4844/polynomial-commitments.md +++ b/specs/eip4844/polynomial-commitments.md @@ -21,7 +21,7 @@ - [BLS12-381 helpers](#bls12-381-helpers) - [`bytes_to_bls_field`](#bytes_to_bls_field) - [`blob_to_polynomial`](#blob_to_polynomial) - - [`hash_to_bls_field`](#hash_to_bls_field) + - [`compute_challenges`](#compute_challenges) - [`bls_modular_inverse`](#bls_modular_inverse) - [`div`](#div) - [`g1_lincomb`](#g1_lincomb) @@ -41,7 +41,6 @@ - ## Introduction This document specifies basic polynomial operations and KZG polynomial commitment operations as they are needed for the EIP-4844 specification. The implementations are not optimized for performance, but readability. All practical implementations should optimize the polynomial operations. @@ -163,31 +162,44 @@ def blob_to_polynomial(blob: Blob) -> Polynomial: return polynomial ``` -#### `hash_to_bls_field` +#### `compute_challenges` ```python -def hash_to_bls_field(polys: Sequence[Polynomial], - comms: Sequence[KZGCommitment]) -> BLSFieldElement: +def compute_challenges(polynomials: Sequence[Polynomial], + commitments: Sequence[KZGCommitment]) -> BLSFieldElement: """ - Compute 32-byte hash of serialized polynomials and commitments concatenated. - This hash is then converted to a BLS field element, where the result is not uniform over the BLS field. - Return the BLS field element. + Return the Fiat-Shamir challenges required by the rest of the protocol. + The Fiat-Shamir logic works as per the following pseudocode: + + hashed_data = hash(DOMAIN_SEPARATOR, polynomials, commitments) + r = hash(hashed_data, 0) + r_powers = [r, r**2, r**3, ...] + eval_challenge = hash(hashed_data, 1) + + Then return `r_powers` and `eval_challenge` after converting them to BLS field elements. + The resulting field elements are not uniform over the BLS field. """ # Append the number of polynomials and the degree of each polynomial as a domain separator - num_polys = int.to_bytes(len(polys), 8, ENDIANNESS) + num_polynomials = int.to_bytes(len(polynomials), 8, ENDIANNESS) degree_poly = int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, ENDIANNESS) - data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly + num_polys + data = FIAT_SHAMIR_PROTOCOL_DOMAIN + degree_poly + num_polynomials # Append each polynomial which is composed by field elements - for poly in polys: + for poly in polynomials: for field_element in poly: data += int.to_bytes(field_element, BYTES_PER_FIELD_ELEMENT, ENDIANNESS) # Append serialized G1 points - for commitment in comms: + for commitment in commitments: data += commitment - return bytes_to_bls_field(hash(data)) + # Transcript has been prepared: time to create the challenges + hashed_data = hash(data) + r = hash(hashed_data + b'\x00') + r_powers = compute_powers(bytes_to_bls_field(r), len(commitments)) + eval_challenge = hash(hashed_data + b'\x01') + + return r_powers, bytes_to_bls_field(eval_challenge) ``` #### `bls_modular_inverse` @@ -234,7 +246,8 @@ def poly_lincomb(polys: Sequence[Polynomial], Given a list of ``polynomials``, interpret it as a 2D matrix and compute the linear combination of each column with `scalars`: return the resulting polynomials. """ - result = [0] * len(polys[0]) + assert len(polys) == len(scalars) + result = [0] * FIELD_ELEMENTS_PER_BLOB for v, s in zip(polys, scalars): for i, x in enumerate(v): result[i] = (result[i] + int(s) * int(x)) % BLS_MODULUS @@ -256,6 +269,7 @@ def compute_powers(x: BLSFieldElement, n: uint64) -> Sequence[BLSFieldElement]: return powers ``` + ### Polynomials #### `evaluate_polynomial_in_evaluation_form` @@ -367,14 +381,15 @@ def compute_aggregated_poly_and_commitment( """ Return (1) the aggregated polynomial, (2) the aggregated KZG commitment, and (3) the polynomial evaluation random challenge. + This function should also work with blobs == [] and kzg_commitments == [] """ + assert len(blobs) == len(kzg_commitments) + # Convert blobs to polynomials polynomials = [blob_to_polynomial(blob) for blob in blobs] - # Generate random linear combination challenges - r = hash_to_bls_field(polynomials, kzg_commitments) - r_powers = compute_powers(r, len(kzg_commitments)) - evaluation_challenge = int(r_powers[-1]) * r % BLS_MODULUS + # Generate random linear combination and evaluation challenges + r_powers, evaluation_challenge = compute_challenges(polynomials, kzg_commitments) # Create aggregated polynomial in evaluation form aggregated_poly = Polynomial(poly_lincomb(polynomials, r_powers)) @@ -390,6 +405,7 @@ def compute_aggregated_poly_and_commitment( ```python def compute_aggregate_kzg_proof(blobs: Sequence[Blob]) -> KZGProof: """ + Given a list of blobs, return the aggregated KZG proof that is used to verify them against their commitments. Public method. """ commitments = [blob_to_kzg_commitment(blob) for blob in blobs] @@ -407,6 +423,8 @@ def verify_aggregate_kzg_proof(blobs: Sequence[Blob], expected_kzg_commitments: Sequence[KZGCommitment], kzg_aggregated_proof: KZGProof) -> bool: """ + Given a list of blobs and an aggregated KZG proof, verify that they correspond to the provided commitments. + Public method. """ aggregated_poly, aggregated_poly_commitment, evaluation_challenge = compute_aggregated_poly_and_commitment( diff --git a/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py b/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py index 634daca2d..d9e3877c3 100644 --- a/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py +++ b/tests/core/pyspec/eth2spec/test/eip4844/unittests/validator/test_validator.py @@ -25,6 +25,12 @@ def _run_validate_blobs_sidecar_test(spec, state, blob_count): spec.validate_blobs_sidecar(block.slot, block.hash_tree_root(), expected_commitments, blobs_sidecar) +@with_eip4844_and_later +@spec_state_test +def test_validate_blobs_sidecar_zero_blobs(spec, state): + _run_validate_blobs_sidecar_test(spec, state, blob_count=0) + + @with_eip4844_and_later @spec_state_test def test_validate_blobs_sidecar_one_blob(spec, state):