Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

In batch cell verification, take commitment for each cell #3834

Merged
merged 13 commits into from
Jul 10, 2024
8 changes: 3 additions & 5 deletions specs/_features/eip7594/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,17 @@ class DataColumnIdentifier(Container):
```python
def verify_data_column_sidecar_kzg_proofs(sidecar: DataColumnSidecar) -> bool:
"""
Verify if the proofs are correct
Verify if the proofs are correct.
"""
assert sidecar.index < NUMBER_OF_COLUMNS
assert len(sidecar.column) == len(sidecar.kzg_commitments) == len(sidecar.kzg_proofs)

row_indices = [RowIndex(i) for i in range(len(sidecar.column))]
column_indices = [sidecar.index] * len(sidecar.column)

# KZG batch verifies that the cells match the corresponding commitments and proofs
return verify_cell_kzg_proof_batch(
row_commitments_bytes=sidecar.kzg_commitments,
row_indices=row_indices, # all rows
column_indices=column_indices, # specific column
commitments_bytes=sidecar.kzg_commitments,
column_indices=column_indices,
cells=sidecar.column,
proofs_bytes=sidecar.kzg_proofs,
)
Expand Down
39 changes: 24 additions & 15 deletions specs/_features/eip7594/polynomial-commitments-sampling.md
Original file line number Diff line number Diff line change
Expand Up @@ -481,12 +481,18 @@ def verify_cell_kzg_proof_batch_impl(row_commitments: Sequence[KZGCommitment],
cosets_evals: Sequence[CosetEvals],
proofs: Sequence[KZGProof]) -> bool:
"""
Verify a set of cells, given their corresponding proofs and their coordinates (row_index, column_index) in the blob
matrix. The i-th cell is in row row_indices[i] and in column column_indices[i].
The list of all commitments is provided in row_commitments_bytes.
Helper: Verify that a set of cells belong to their corresponding commitment.
This function is the internal implementation of verify_cell_kzg_proof_batch.
Given a list of ``row_commitments`` and four lists representing tuples of (``row_index``,
``column_index``, ``evals``, ``proof``), the function verifies ``proof`` which shows that
``evals`` are the evaluations of the polynomial associated with ``row_commitments[row_index]``,
evaluated over the domain specified by ``column_index``.
This function is the internal implementation of ``verify_cell_kzg_proof_batch``.
"""
assert len(row_indices) == len(column_indices) == len(cosets_evals) == len(proofs)
for row_index in row_indices:
assert row_index < len(row_commitments)

# The verification equation that we will check is pairing (LL, LR) = pairing (RL, [1]), where
# LL = sum_k r^k proofs[k],
Expand Down Expand Up @@ -670,36 +676,39 @@ def verify_cell_kzg_proof(commitment_bytes: Bytes48,
#### `verify_cell_kzg_proof_batch`

```python
def verify_cell_kzg_proof_batch(row_commitments_bytes: Sequence[Bytes48],
row_indices: Sequence[RowIndex],
def verify_cell_kzg_proof_batch(commitments_bytes: Sequence[Bytes48],
column_indices: Sequence[ColumnIndex],
jtraglia marked this conversation as resolved.
Show resolved Hide resolved
cells: Sequence[Cell],
proofs_bytes: Sequence[Bytes48]) -> bool:
"""
Verify a set of cells, given their corresponding proofs and their coordinates (row_index, column_index) in the blob
matrix. The i-th cell is in row = row_indices[i] and in column = column_indices[i].
The list of all commitments is provided in row_commitments_bytes.
Verify that a set of cells belong to their corresponding commitments.
Given four lists representing tuples of (``commitment``, ``column_index``, ``cell``, ``proof``),
the function verifies ``proof`` which shows that ``cell`` are the evaluations of the polynomial
associated with ``commitment``, evaluated over the domain specified by ``column_index``.
This function implements the universal verification equation that has been introduced here:
https://ethresear.ch/t/a-universal-verification-equation-for-data-availability-sampling/13240
Public method.
"""

assert len(cells) == len(proofs_bytes) == len(row_indices) == len(column_indices)
for commitment_bytes in row_commitments_bytes:
assert len(commitments_bytes) == len(cells) == len(proofs_bytes) == len(column_indices)
for commitment_bytes in commitments_bytes:
assert len(commitment_bytes) == BYTES_PER_COMMITMENT
for row_index in row_indices:
assert row_index < len(row_commitments_bytes)
for column_index in column_indices:
assert column_index < CELLS_PER_EXT_BLOB
for cell in cells:
assert len(cell) == BYTES_PER_CELL
for proof_bytes in proofs_bytes:
assert len(proof_bytes) == BYTES_PER_PROOF

# Get objects from bytes
row_commitments = [bytes_to_kzg_commitment(commitment_bytes) for commitment_bytes in row_commitments_bytes]
# Create the list of unique commitments we are dealing with
deduplicated_commitments = list(set(commitments_bytes))
row_commitments = [bytes_to_kzg_commitment(commitment_bytes) for commitment_bytes in deduplicated_commitments]
# Create indices list mapping initial commitments (that potentially contains duplicates) to the unique commitments.
row_indices = [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]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,7 @@ def test_verify_cell_kzg_proof(spec):
def test_verify_cell_kzg_proof_batch_zero_cells(spec):
# Verify with zero cells should return true
assert spec.verify_cell_kzg_proof_batch(
row_commitments_bytes=[],
row_indices=[],
commitments_bytes=[],
column_indices=[],
cells=[],
proofs_bytes=[],
Expand All @@ -149,8 +148,7 @@ def test_verify_cell_kzg_proof_batch(spec):
assert len(cells) == len(proofs)

assert spec.verify_cell_kzg_proof_batch(
row_commitments_bytes=[commitment],
row_indices=[0, 0],
commitments_bytes=[commitment, commitment],
column_indices=[0, 4],
cells=[cells[0], cells[4]],
proofs_bytes=[proofs[0], proofs[4]],
Expand Down Expand Up @@ -178,11 +176,11 @@ def test_verify_cell_kzg_proof_batch(spec):
column_indices = [0, 4, 0, 1, 2]
cells = [all_cells[i][j] for (i, j) in zip(row_indices, column_indices)]
proofs = [all_proofs[i][j] for (i, j) in zip(row_indices, column_indices)]
commitments = [all_commitments[i] for i in row_indices]

# do the check
assert spec.verify_cell_kzg_proof_batch(
row_commitments_bytes=all_commitments,
row_indices=row_indices,
commitments_bytes=commitments,
column_indices=column_indices,
cells=cells,
proofs_bytes=proofs,
Expand All @@ -202,8 +200,7 @@ def test_verify_cell_kzg_proof_batch_invalid(spec):
assert len(cells) == len(proofs)

assert not spec.verify_cell_kzg_proof_batch(
row_commitments_bytes=[commitment],
row_indices=[0, 0],
commitments_bytes=[commitment, commitment],
column_indices=[0, 4],
cells=[cells[0], cells[5]], # Note: this is where it should go wrong
proofs_bytes=[proofs[0], proofs[4]],
Expand Down Expand Up @@ -231,14 +228,14 @@ def test_verify_cell_kzg_proof_batch_invalid(spec):
column_indices = [0, 4, 0, 1, 2]
cells = [all_cells[i][j] for (i, j) in zip(row_indices, column_indices)]
proofs = [all_proofs[i][j] for (i, j) in zip(row_indices, column_indices)]
commitments = [all_commitments[i] for i in row_indices]

# let's change one of the cells. Then it should not verify
cells[1] = all_cells[1][3]

# do the check
assert not spec.verify_cell_kzg_proof_batch(
row_commitments_bytes=all_commitments,
row_indices=row_indices,
commitments_bytes=commitments,
column_indices=column_indices,
cells=cells,
proofs_bytes=proofs,
Expand Down
8 changes: 3 additions & 5 deletions tests/formats/kzg_7594/verify_cell_kzg_proof_batch.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
# Test format: Verify cell KZG proof batch

Use the cell KZG `proofs` to verify that the KZG `row_commitments` for the given `cells` are correct.
Use the cell KZG `proofs` to verify that the KZG `commitments` for the given `cells` are correct.

## Test case format

The test data is declared in a `data.yaml` file:

```yaml
input:
row_commitments: List[Bytes48] -- the KZG commitments
row_indices: List[RowIndex] -- the commitment index for each cell
commitments: List[Bytes48] -- the KZG commitments for each cell
column_indices: List[ColumnIndex] -- the column index for each cell
jtraglia marked this conversation as resolved.
Show resolved Hide resolved
cells: List[Cell] -- the cells
proofs: List[Bytes48] -- the KZG proof for each cell
output: bool -- true (all proofs are correct) or false (some proofs incorrect)
```
- `Bytes48` is a 48-byte hexadecimal string, prefixed with `0x`.
- `RowIndex` is an unsigned 64-bit integer.
- `ColumnIndex` is an unsigned 64-bit integer.
- `Cell` is a 2048-byte hexadecimal string, prefixed with `0x`.

All byte(s) fields are encoded as strings, hexadecimal encoding, prefixed with `0x`.

## Condition

The `verify_cell_kzg_proof_batch` handler should verify that `row_commitments` are correct KZG commitments to `cells` by using the cell KZG proofs `proofs`, and the result should match the expected `output`. If any of the commitments or proofs are invalid (e.g. not on the curve or not in the G1 subgroup of the BLS curve), any cell is invalid (e.g. incorrect length or one of the 32-byte blocks does not represent a BLS field element), or any `cell_index` is invalid (e.g. greater than the number of cells for an extended blob), it should error, i.e. the output should be `null`.
The `verify_cell_kzg_proof_batch` handler should verify that `commitments` are correct KZG commitments to `cells` by using the cell KZG proofs `proofs`, and the result should match the expected `output`. If any of the commitments or proofs are invalid (e.g. not on the curve or not in the G1 subgroup of the BLS curve), any cell is invalid (e.g. incorrect length or one of the 32-byte blocks does not represent a BLS field element), or any `cell_index` is invalid (e.g. greater than the number of cells for an extended blob), it should error, i.e. the output should be `null`.
Loading