Skip to content

Commit

Permalink
Introduce high-level logic of new efficient transaction validation
Browse files Browse the repository at this point in the history
To validate a 4844 transaction in the mempool, the verifier checks that each provided KZG commitment matches the
polynomial represented by the corresponding blob data.

     | d_1 | d_2 | d_3 | ... | d_4096 |    -> commitment

Before this patch, to do this validation, we reconstructed the commitment from the blob data (d_i above), and checked
it against the provided commitment. This was expensive because computing a commitment from blob data (even using
Lagrange basis) involves N scalar multiplications, where N is the number of field elements per blob.

Initial benchmarking showed that this was about 40ms for N=4096 which was deemed too expensive. For more details see:
             https://hackmd.io/@protolambda/eip-4844-implementer-notes#Optimizations
             protolambda/go-ethereum#4

In this patch, we speed this up by providing a KZG proof for each commitment. The verifier can check that proof to
ensure that the KZG commitment matches the polynomial represented by the corresponding blob data.

     | d_1 | d_2 | d_3 | ... | d_4096 |    -> commitment, proof

To do so, we evaluate the blob data polynomial at a random point `x` to get a value `y`. We then use the KZG proof to
ensure that the commited polynomial (i.e. the commitment) also evaluates to `y` at `x`. If the check passes, it means
that the KZG commitment matches the polynomial represented by the blob data.

This is significantly faster since evaluating the blob data polynomial at a random point using the Barycentric formula
can be done efficiently with only field operations (see https://hackmd.io/@vbuterin/barycentric_evaluation). Then,
verifying a KZG proof takes two pairing operations (which take about 0.6ms each). This brings the total verification
cost to about 2 ms per blob.

With some additional optimizations (using linear combination tricks as the ones linked above) we can batch all the
blobs together into a single efficient verification, and hence verify the entire transaction in 2.5 ms. The same
techniques can be used to efficiently verify blocks on the consensus side.
  • Loading branch information
asn-d6 committed May 11, 2022
1 parent f73343a commit 87ab964
Showing 1 changed file with 14 additions and 3 deletions.
17 changes: 14 additions & 3 deletions EIPS/eip-4844.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ class BlobTransactionNetworkWrapper(Container):
tx: SignedBlobTransaction
# KZGCommitment = Bytes48
blob_kzgs: List[KZGCommitment, MAX_TX_WRAP_KZG_COMMITMENTS]
# KZGProofs = Bytes48
blob_proofs: List[KZGProof, MAX_TX_WRAP_KZG_COMMITMENTS]
# BLSFieldElement = uint256
blobs: List[Vector[BLSFieldElement, FIELD_ELEMENTS_PER_BLOB], LIMIT_BLOBS_PER_TX]
```
Expand All @@ -355,10 +357,19 @@ def validate_blob_transaction_wrapper(wrapper: BlobTransactionNetworkWrapper):
versioned_hashes = wrapper.tx.message.blob_versioned_hashes
commitments = wrapper.blob_kzgs
blobs = wrapper.blobs
assert len(versioned_hashes) == len(commitments) == len(blobs)
for versioned_hash, commitment, blob in zip(versioned_hashes, commitments, blobs):
proofs = wrapper.blob_proofs

assert len(versioned_hashes) == len(commitments) == len(blobs) == len(proofs)
for versioned_hash, commitment, blob, proof in zip(versioned_hashes, commitments, blobs, proofs):
# note: assert blob is not malformatted
assert commitment == blob_to_kzg(blob)

# Get `x` point using Fiat-Shamir
x = hash_to_bls_field(commitment)
# Evaluate blob polynomial at `x`
y = evaluate_polynomial_in_evaluation_form(blob, x)
# Check that blob polynomial matches the `commitment` by verifying provided proof
assert verify_kzg_proof(commitment, x, y, proof)
# Finally check that the `versioned_hash` matches the `commitment`
assert versioned_hash == kzg_to_versioned_hash(commitment)
```

Expand Down

0 comments on commit 87ab964

Please sign in to comment.