*Chuck Norris doesn’t generate KZG proofs. The universe simply aligns to match his calculations.*
# About KZG commitment and KZG proof
:::danger
**TO REWRITE**
This document states that there is one proof per blob (blob proof).
It was true **before** Fulu.
After Fulu, there is **one proof per cell** (cell proof).
:::
## Introduction
Earlier, we saw that a blob-carrying block includes both a KZG commitment and a KZG proof.
[Example](https://beaconcha.in/slot/10433465#blobs):

This block is associated with `5` blobs, each of which contains a KZG commitment and a KZG proof.
In this section, we'll briefly discuss the problem that KZG commitments and proofs aim to solve. However, we won’t go into the technical details of how they work, as this involves concepts such as elliptic curves, elliptic curve pairings, the Power of Tau ceremony, and other prime field arithmetic. As a user, it’s perfectly fine to treat these KZG tools as a black box.
For readers interested in delving deeper into the internals of KZG commitments and proofs, I recommend the following resources:
- All the short videos on the [zkMarek Youtube channel](https://www.youtube.com/@zkmarek/videos),
- The [Moon math manual](https://github.com/LeastAuthority/moonmath-manual) up to Chapter 5 (Elliptic Curves). Although the manual primarily targets ZK-SNARKs, the first chapters are also relevant for understanding the KZG tools we use,
- [KZG polynomials commitments](https://dankradfeist.de/ethereum/2020/06/16/kate-polynomial-commitments.html) by Dankrad Feist.
## What problem are we attempting to solve?
### Pre peerDAS (EIP-4844 - Proto Danksharding)
Imagine a beacon block containing blob-carrying transactions. We need a way for the block to commit to these blobs (i.e., to link the block with the blobs). A simple approach to handle this would be to store the hash of each blob in the beacon block. A block associated with `5` blobs would then contain `5` hashes, one for each blob.
When a beacon node receives a blob, it would be straightforward to check which block the blob is committed to. If all the blobs listed in the block are available, the block can be considered available.
However, this simple method no longer works when beacon nodes store data columns instead of blobs.
### With PeerDAS
With peerDAS enabled, a beacon node no longer receives full blobs via gossip. Instead, it receives data columns. Each cell in a data column represents `1/128th` of an extended blob.
To ensure data integrity, the beacon node must verify that each cell in the data columns genuinely belongs to a blob.
When building a block containing some blob carrying transactions, for each blob, the block builder creates a KZG commmitment and a KZG proof.
KZK commitments are added into the beacon block body:
```Python=
class BeaconBlockBody(Container):
...
blob_kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK] # [New in Deneb:EIP4844]
```
[Source](https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md#extended-containers)
At the same time, the block builder creates `128` data column sidecars.
A data column sidecar is the following structure:
```Python=
class DataColumnSidecar(Container):
index: ColumnIndex # Index of column in extended matrix
column: List[Cell, MAX_BLOB_COMMITMENTS_PER_BLOCK]
kzg_commitments: List[KZGCommitment, MAX_BLOB_COMMITMENTS_PER_BLOCK]
kzg_proofs: List[KZGProof, MAX_BLOB_COMMITMENTS_PER_BLOCK]
signed_block_header: SignedBeaconBlockHeader
kzg_commitments_inclusion_proof: Vector[Bytes32, KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH]
```
[Source](https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7594/das-core.md#datacolumnsidecar)
We won't enter into too much details here (you can read the links given earlier for more information), but we can simply admit that the KZG commitment is a `48 Bytes` piece of data. A blob has exactly one unique `48 Bytes` KZG commitment.
The same applies for the KZG proof (`48 Bytes` piece of data, unique for each blob).
Here’s how the process works:
**Step 1**: The block builder constructs a block containing (for example) `6` blobs.

**Step 2**: Using [polynomial erasure coding](https://hackmd.io/uImjdfxFT2-xA793rvaNIw), the block builder extends each blob into an extended blob.

**Step 3**: The extended blobs are divided into `128` cells each, which are then grouped into `128` data columns. Each data column contains `6` cells, one from each extended blob.


**Step 4**: The block builder wraps each of the `128` data columns into data column sidecars, and send them to the corresponding `data_column_sidecar_<n>` topic, where `n=0..127`.


:::warning
The key point here is that KZG commitments and proofs are fixed for a given blob. The exact same KZG commitments and proofs are sent for data column sidecar `#2` as for data column sidecar `#125`, even though the content of the data columns differs between sidecar `#2` and sidecar `#125`.
:::
**Step 5**: When a node receives a data column with index `i`, it must ensure that each cell in the received data column indeed corresponds to the `i`th cell of the committed blobs before declaring the corresponding block as available.
**Example:**
If a node receives a column containing `6` cells with a column index of `4`, then before declaring the block as available, the node must verify the following:
- Cell `#0` of the received data column corresponds to cell `#4` of blob `#0`.
- Cell `#1` of the received data column corresponds to cell `#4` of blob `#1`.
- ...
- Cell `#5` of the received data column corresponds to cell `#4` of blob `#5`.
:::success
✨ **Good news!** Verifying whether a cell truly belongs to a blob—without needing to retrieve the entire blob—is precisely what KZG commitments and KZG proofs are designed to do. ✨
:::
When a node receives a data column sidecar, it first ensures that each KZG commitment (one per blob) in the sidecar matches the corresponding commitments in the associated block. It then runs a function to verify the KZG proof for each data column cell.
To verify a specific KZG proof, this function requires the following parameters:
- The content of the data column cell itself,
- The index of the data column,
- The KZG commitment of the blob to which the cell belongs, and
- The KZG proof of the blob to which the cell belongs.
This function returns a boolean value. If the cell's content is consistent with the index, the blob's KZG commitment, and its proof, then the function return `True`. In this case, the beacon node can be confident that the cell indeed belongs to the blob associated with that KZG commitment. Since the commitment has already been verified against the block, the beacon node can ensure that the blob is correctly linked to the block.
In practice, KZG proof are not verified cell by cell, but by batch.
```Python=
def verify_data_column_sidecar_kzg_proofs(sidecar: DataColumnSidecar) -> bool:
"""
Verify if the KZG proofs are correct.
"""
# The column index also represents the cell index
cell_indices = [CellIndex(sidecar.index)] * len(sidecar.column)
# Batch verify that the cells match the corresponding commitments and proofs
return verify_cell_kzg_proof_batch(
commitments_bytes=sidecar.kzg_commitments,
cell_indices=cell_indices,
cells=sidecar.column,
proofs_bytes=sidecar.kzg_proofs,
)
```
[Source](https://github.com/ethereum/consensus-specs/blob/dev/specs/_features/eip7594/p2p-interface.md#verify_data_column_sidecar_kzg_proofs)
## Why Use KZG Commitments and Proofs Instead of Traditional Merkle Proofs?
It’s worth noting that the same goal could technically be achieved using Merkle proofs instead of KZG commitments and proofs.
For instance, we could provide a Merkle proof for each cell and require a beacon node receiving a data column sidecar to verify the Merkle proof against the content of the cell. This would work.
However, there are significant drawbacks to this approach:
1. We would need one Merkle proof per cell—resulting in `128` Merkle proofs per blob and `768` Merkle proofs for `6` blobs.
2. The size of a Merkle proof is proportional to the log of the vector being proven.
3. Merkle proofs would differ between non-extended blobs and extended blobs.
Advantages of Using KZG Commitments and Proofs:
1. Only one KZG commitment and one KZG proof are required per blob.
2. Both the KZG commitment and KZG proof have a fixed size of `48 B`, regardless of the size of the blob.
3. The same KZG commitment and proof apply to both non-extended and extended blobs.
Although KZG commitments and proofs are mathematically more complex, they require orders of magnitude less storage compared to the equivalent solution using only Merkle proofs.