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

Integrate new CosetEvals type #3701

Merged
merged 17 commits into from
Apr 22, 2024
Merged
11 changes: 5 additions & 6 deletions specs/_features/eip7594/das-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ We define the following Python custom types for type hinting and readability:

| Name | SSZ equivalent | Description |
| - | - | - |
| `DataColumn` | `List[Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK]` | The data of each column in EIP-7594 |
| `ExtendedMatrix` | `List[Cell, MAX_BLOBS_PER_BLOCK * NUMBER_OF_COLUMNS]` | The full data of one-dimensional erasure coding extended blobs (in row major format) |
| `DataColumn` | `List[CellBytes, MAX_BLOB_COMMITMENTS_PER_BLOCK]` | The data of each column in EIP-7594 |
| `ExtendedMatrix` | `List[CellBytes, MAX_BLOBS_PER_BLOCK * NUMBER_OF_COLUMNS]` | The full data of one-dimensional erasure coding extended blobs (in row major format) |

## Configuration

Expand Down Expand Up @@ -131,7 +131,7 @@ def compute_extended_matrix(blobs: Sequence[Blob]) -> ExtendedMatrix:
#### `recover_matrix`

```python
def recover_matrix(cells_dict: Dict[Tuple[BlobIndex, CellID], Cell], blob_count: uint64) -> ExtendedMatrix:
def recover_matrix(cells_dict: Dict[Tuple[BlobIndex, CellID], CellBytes], blob_count: uint64) -> ExtendedMatrix:
"""
Return the recovered ``ExtendedMatrix``.

Expand All @@ -141,12 +141,11 @@ def recover_matrix(cells_dict: Dict[Tuple[BlobIndex, CellID], Cell], blob_count:
extended_matrix = []
for blob_index in range(blob_count):
cell_ids = [cell_id for b_index, cell_id in cells_dict.keys() if b_index == blob_index]
cells = [cells_dict[(blob_index, cell_id)] for cell_id in cell_ids]
cells_bytes = [[bls_field_to_bytes(element) for element in cell] for cell in cells]
cells_bytes = [cells_dict[(blob_index, cell_id)] for cell_id in cell_ids]

full_polynomial = recover_polynomial(cell_ids, cells_bytes)
cells_from_full_polynomial = [
full_polynomial[i * FIELD_ELEMENTS_PER_CELL:(i + 1) * FIELD_ELEMENTS_PER_CELL]
cell_to_bytes(full_polynomial[i * FIELD_ELEMENTS_PER_CELL:(i + 1) * FIELD_ELEMENTS_PER_CELL])
for i in range(CELLS_PER_BLOB)
]
extended_matrix.extend(cells_from_full_polynomial)
Expand Down
42 changes: 32 additions & 10 deletions specs/_features/eip7594/polynomial-commitments-sampling.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Public functions MUST accept raw bytes as input and perform the required cryptog
| - | - | - |
| `PolynomialCoeff` | `List[BLSFieldElement, FIELD_ELEMENTS_PER_EXT_BLOB]` | A polynomial in coefficient form |
| `Cell` | `Vector[BLSFieldElement, FIELD_ELEMENTS_PER_CELL]` | The unit of blob data that can come with their own KZG proofs |
| `CellBytes` | `ByteVector[BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_CELL]` | The flattened bytes representation of a cell |
| `CellID` | `uint64` | Cell identifier |
| `RowIndex` | `uint64` | Row identifier |
| `ColumnIndex` | `uint64` | Column identifier |
Expand Down Expand Up @@ -94,11 +95,28 @@ Cells are the smallest unit of blob data that can come with their own KZG proofs
#### `bytes_to_cell`

```python
def bytes_to_cell(cell_bytes: Vector[Bytes32, FIELD_ELEMENTS_PER_CELL]) -> Cell:
def bytes_to_cell(cell_bytes: CellBytes) -> Cell:
"""
Convert untrusted bytes into a Cell.
"""
return [bytes_to_bls_field(element) for element in cell_bytes]
cell = Cell()
jtraglia marked this conversation as resolved.
Show resolved Hide resolved
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_bytes[start:end])
cell[i] = value
return cell
jtraglia marked this conversation as resolved.
Show resolved Hide resolved
```

```python
def cell_to_bytes(cell: Cell) -> CellBytes:
"""
Convert a Cell into bytes.
"""
cell_bytes = []
for i in range(FIELD_ELEMENTS_PER_CELL):
cell_bytes += bls_field_to_bytes(cell[i])
return CellBytes(cell_bytes)
```

### Linear combinations
Expand Down Expand Up @@ -374,7 +392,7 @@ def coset_for_cell(cell_id: CellID) -> Cell:

```python
def compute_cells_and_proofs(blob: Blob) -> Tuple[
Vector[Cell, CELLS_PER_BLOB],
Vector[CellBytes, CELLS_PER_BLOB],
Vector[KZGProof, CELLS_PER_BLOB]]:
"""
Compute all the cell proofs for one blob. This is an inefficient O(n^2) algorithm,
Expand All @@ -392,7 +410,7 @@ def compute_cells_and_proofs(blob: Blob) -> Tuple[
for i in range(CELLS_PER_BLOB):
coset = coset_for_cell(i)
proof, ys = compute_kzg_proof_multi_impl(polynomial_coeff, coset)
cells.append(ys)
cells.append(cell_to_bytes(ys))
proofs.append(proof)

return cells, proofs
Expand All @@ -401,7 +419,7 @@ def compute_cells_and_proofs(blob: Blob) -> Tuple[
#### `compute_cells`

```python
def compute_cells(blob: Blob) -> Vector[Cell, CELLS_PER_BLOB]:
def compute_cells(blob: Blob) -> Vector[CellBytes, CELLS_PER_BLOB]:
"""
Compute the cell data for a blob (without computing the proofs).

Expand All @@ -413,8 +431,12 @@ def compute_cells(blob: Blob) -> Vector[Cell, CELLS_PER_BLOB]:
extended_data = fft_field(polynomial_coeff + [0] * FIELD_ELEMENTS_PER_BLOB,
compute_roots_of_unity(FIELD_ELEMENTS_PER_EXT_BLOB))
extended_data_rbo = bit_reversal_permutation(extended_data)
return [extended_data_rbo[i * FIELD_ELEMENTS_PER_CELL:(i + 1) * FIELD_ELEMENTS_PER_CELL]
for i in range(CELLS_PER_BLOB)]
cells = []
for cell_id in range(CELLS_PER_BLOB):
start = cell_id * FIELD_ELEMENTS_PER_CELL
end = (cell_id + 1) * FIELD_ELEMENTS_PER_CELL
cells.append(cell_to_bytes(extended_data_rbo[start:end]))
return cells
```

### Cell verification
Expand All @@ -424,7 +446,7 @@ def compute_cells(blob: Blob) -> Vector[Cell, CELLS_PER_BLOB]:
```python
def verify_cell_proof(commitment_bytes: Bytes48,
cell_id: CellID,
cell_bytes: Vector[Bytes32, FIELD_ELEMENTS_PER_CELL],
cell_bytes: CellBytes,
proof_bytes: Bytes48) -> bool:
"""
Check a cell proof
Expand All @@ -446,7 +468,7 @@ def verify_cell_proof(commitment_bytes: Bytes48,
def verify_cell_proof_batch(row_commitments_bytes: Sequence[Bytes48],
row_indices: Sequence[RowIndex],
column_indices: Sequence[ColumnIndex],
cells_bytes: Sequence[Vector[Bytes32, FIELD_ELEMENTS_PER_CELL]],
cells_bytes: Sequence[CellBytes],
proofs_bytes: Sequence[Bytes48]) -> bool:
"""
Verify a set of cells, given their corresponding proofs and their coordinates (row_id, column_id) in the blob
Expand Down Expand Up @@ -592,7 +614,7 @@ def recover_original_data(eval_shifted_extended_evaluation: Sequence[BLSFieldEle

```python
def recover_polynomial(cell_ids: Sequence[CellID],
cells_bytes: Sequence[Vector[Bytes32, FIELD_ELEMENTS_PER_CELL]]) -> Polynomial:
cells_bytes: Sequence[CellBytes]) -> Polynomial:
"""
Recover original polynomial from FIELD_ELEMENTS_PER_EXT_BLOB evaluations, half of which can be missing. This
algorithm uses FFTs to recover cells faster than using Lagrange implementation, as can be seen here:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test_compute_extended_matrix(spec):
for blob_index, row in enumerate(rows):
extended_blob = []
for cell in row:
extended_blob.extend(cell)
extended_blob.extend(spec.bytes_to_cell(cell))
blob_part = extended_blob[0:len(extended_blob) // 2]
blob = b''.join([spec.bls_field_to_bytes(x) for x in blob_part])
assert blob == input_blobs[blob_index]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,10 @@ def test_verify_cell_proof(spec):
commitment = spec.blob_to_kzg_commitment(blob)
cells, proofs = spec.compute_cells_and_proofs(blob)

cells_bytes = [[spec.bls_field_to_bytes(element) for element in cell] for cell in cells]

cell_id = 0
assert spec.verify_cell_proof(commitment, cell_id, cells_bytes[cell_id], proofs[cell_id])
assert spec.verify_cell_proof(commitment, cell_id, cells[cell_id], proofs[cell_id])
cell_id = 1
assert spec.verify_cell_proof(commitment, cell_id, cells_bytes[cell_id], proofs[cell_id])
assert spec.verify_cell_proof(commitment, cell_id, cells[cell_id], proofs[cell_id])


@with_eip7594_and_later
Expand All @@ -51,15 +49,14 @@ def test_verify_cell_proof_batch(spec):
blob = get_sample_blob(spec)
commitment = spec.blob_to_kzg_commitment(blob)
cells, proofs = spec.compute_cells_and_proofs(blob)
cells_bytes = [[spec.bls_field_to_bytes(element) for element in cell] for cell in cells]

assert len(cells) == len(proofs)

assert spec.verify_cell_proof_batch(
row_commitments_bytes=[commitment],
row_indices=[0, 0],
column_indices=[0, 4],
cells_bytes=[cells_bytes[0], cells_bytes[4]],
cells_bytes=[cells[0], cells[4]],
proofs_bytes=[proofs[0], proofs[4]],
)

Expand All @@ -80,7 +77,6 @@ def test_recover_polynomial(spec):

# Extend data with Reed-Solomon and split the extended data in cells
cells = spec.compute_cells(blob)
cells_bytes = [[spec.bls_field_to_bytes(element) for element in cell] for cell in cells]

# Compute the cells we will be recovering from
cell_ids = []
Expand All @@ -91,16 +87,16 @@ def test_recover_polynomial(spec):
j = rng.randint(0, spec.CELLS_PER_BLOB - 1)
cell_ids.append(j)
# Now the cells themselves
known_cells_bytes = [cells_bytes[cell_id] for cell_id in cell_ids]
known_cells = [cells[cell_id] for cell_id in cell_ids]

# Recover the data
recovered_data = spec.recover_polynomial(cell_ids, known_cells_bytes)
recovered_data = spec.recover_polynomial(cell_ids, known_cells)

# Check that the original data match the non-extended portion of the recovered data
assert original_polynomial == recovered_data[:len(recovered_data) // 2]

# Now flatten the cells and check that they match the entirety of the recovered data
flattened_cells = [x for xs in cells for x in xs]
flattened_cells = [x for xs in cells for x in spec.bytes_to_cell(xs)]
assert flattened_cells == recovered_data


Expand Down
Loading