Skip to content

Native proof verification#3

Merged
lucadonnoh merged 3 commits into
mainfrom
native-verification
May 25, 2026
Merged

Native proof verification#3
lucadonnoh merged 3 commits into
mainfrom
native-verification

Conversation

@lucadonnoh

Copy link
Copy Markdown
Member

No description provided.

@vercel

vercel Bot commented Apr 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
native-rollups Ready Ready Preview Apr 21, 2026 1:51pm

Request Review


<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Abstract

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This abstract makes it sound like native proof verification is relevant only to rollups, which it is not.

There is a whole (IMO useless) project that tries to build infra for onchain proof verification: https://zkverify.io and they have all sorts of usecases in mind. I think your EIP should have a similar scope, maybe slightly skewed towards rollups usecase.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An additional point here: with native zkVM proof verification, rollups can drop the SNARK final wraps that introduce additional dependencies and quantum attack vector. STARKs could be verified on L1.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree -- one thing to keep in mind, that Luca already knows, is the potential bandwidth cost with STARK proofs. +1 to your previous comment on analysing the starkware design

Comment thread src/native_verification.md Outdated
| 5 | reth | SP1 |
| 6 | reth | Zisk |

This works for L1 execution proofs where the set of guest programs is small and known in advance. But it cannot accommodate arbitrary rollup programs: adding a new guest program requires assigning new `ProofType` values and updating every client.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I don't think it's a good design for 8025. ZK Catalog experience shows that guest programs will be updated / patched all the time, so the set is not really small and not really known in advance.

In the Lighthouse table that you mention, ProofType readable versioning breaks into real mess the moment ethrex releases a next version.

One more argument for clear and explicit (guest, backend) separation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @frisitano for visibility (maybe better to continue discussions on eth r&d discord though)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we need to improve the encoding of ProofType. I think the proposed decomposition into a prover, guest and version subfields is natural and reasonable imo. Currently, the Ethereum specs are undefined, and the specific ProofType definition only exists in zkboost. I think the natural home for this would be an execution-proof-APIs repository that defines the API currently implemented in zkboost, in addition to the new ProofType structure. Currently, we don't have an execution-proof-APIs repo (we should make one), so in the absence of that, the definition can live in CL specs for now. @kevaundray, would you be able to create the Discord thread you proposed and tag @sergeyshemyakov, me, Han, and Ignacio so we can discuss this and assign responsibility for opening the PR to formalise it, please?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will go ahead and create the execution-proof-APIs repo and reply here with a link so we can collaborate.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/native_verification.md Outdated

> This section is a very early work in progress. The design is not settled.

The proof must reach a builder through the mempool, but needs no long-term availability. The proposed approach is an **ephemeral sidecar**: the proof travels alongside the transaction like an [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) blob sidecar, but the builder strips it before block inclusion, folds it into the recursive L1 block proof, and discards it. Validators see only the transaction body (the `proofs` list and `public_values_hash`) plus the L1 block proof; they never need the raw proof bytes. The L1 block proof thus recursively covers every proof-carrying transaction in the block (post-quantum proofs may be large enough that L1 is limited to one proof per slot).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discarding proofs only works if L1 block proving is mandatory. Otherwise the proofs must persist somewhere so all other validators can attest to the correctness of verification.
Could the proofs be put in blobs / designated blobspace?

Propagation might indeed be a problem for big enough proofs, network bandwidth could be easily congested with 1-2 proof carrying transactions in a block (in addition to L1 proofs). It might also be hard to price proof carrying transactions adequately, because the EL is unaware of proof length. Could it be added to the PROOF_TX_TYPE somehow?

@@ -0,0 +1,380 @@
# Native proof verification

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW Starknet's Shinobi upgrade also introduces in-protocol STARK proof verification, maybe we could research it deeper.


On the prover side, the [honest prover guide](https://github.com/ethereum/consensus-specs/blob/master/specs/_features/eip8025/prover.md) specializes the same way: extract `NewPayloadRequest` from the beacon block and call `request_proofs` with this prover's own `program_hash` (one entry of `NATIVE_EVM_PROGRAM_HASHES` drawn from [ethrex](https://github.com/lambdaclass/ethrex), [reth](https://github.com/paradigmxyz/reth), or any other accepted implementation).

## Program hash stability (open problem)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the trickiest scenarios is what happens when a zk program has a soundness bug discovered post-deployment. How do we invalidate claims that depended on the buggy version without rolling back L1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And does it mean we are gonna still see waiting periods for possibly most of the governed rollups?

Comment on lines +300 to +307
| Project | Proof system | Core SLOC | Retired SLOC | % retired |
|---|---|---:|---:|---:|
| Arbitrum | Optimistic, WASM VM | 19,034 | 8,181 | 43.0% |
| Base | Optimistic, MIPS VM | 17,426 | 8,907 | 51.1% |
| ZKsync Era | Validity, EraVM | 10,823 | 2,379 | 22.0% |
| Linea | Validity, direct EVM | 8,111 | 2,460 | 30.3% |
| Lighter | Validity, no VM (custom circuits) | 5,417 | 1,699 | 31.4% |
| **Total** | | **60,811** | **23,626** | **38.9%** |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to see somewhere what the lines of code are being deleted here


On the prover side, the [honest prover guide](https://github.com/ethereum/consensus-specs/blob/master/specs/_features/eip8025/prover.md) specializes the same way: extract `NewPayloadRequest` from the beacon block and call `request_proofs` with this prover's own `program_hash` (one entry of `NATIVE_EVM_PROGRAM_HASHES` drawn from [ethrex](https://github.com/lambdaclass/ethrex), [reth](https://github.com/paradigmxyz/reth), or any other accepted implementation).

## Program hash stability (open problem)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it is worth adding a small section alongside "Program hash stability" to discuss onchain public-values reconstruction as a related open problem

@l2beat l2beat deleted a comment from coolify-l2beat Bot May 4, 2026
Comment thread src/execute_precompile.md
Together, the EL check (contract reconstructs expected root and matches `PROOFROOT`, see [Root computation](#root-computation)) and the CL check (valid proof for that root) guarantee that the L2 state transition was executed correctly.

**`chain_id` and proof binding.** The `chain_id` is part of [`StatelessInput.chain_config`](https://github.com/ethereum/execution-specs/blob/projects/zkevm/src/ethereum/forks/amsterdam/stateless.py#L82) but not part of [`NewPayloadRequest`](https://github.com/ethereum/execution-specs/blob/projects/zkevm/src/ethereum/forks/amsterdam/execution_engine/types.py#L63) or the block header. If the public output were only the `new_payload_request_root`, the prover could freely choose `chain_id` as a private input, enabling cross-chain transaction replay: for typed transactions ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) and later), [`recover_sender`](https://github.com/ethereum/execution-specs/blob/projects/zkevm/src/ethereum/forks/amsterdam/transactions.py#L656) uses the transaction's own `tx.chain_id` for signature recovery, not `block_env.chain_id`, so transactions from any chain would execute successfully. By including `chain_config` in `StatelessValidationResult` ([PR #2342](https://github.com/ethereum/execution-specs/pull/2342)), the proof attests to which `chain_id` was used, and the contract can verify it matches its stored value by reconstructing the full `StatelessValidationResult` before hashing.
**`chain_id` and proof binding.** The `chain_id` is part of [`StatelessInput.chain_config`](https://github.com/ethereum/execution-specs/blob/projects/zkevm/src/ethereum/forks/amsterdam/stateless.py#L82) but not part of [`NewPayloadRequest`](https://github.com/ethereum/execution-specs/blob/projects/zkevm/src/ethereum/forks/amsterdam/execution_engine/types.py#L63) or the block header. If the public output were only the `new_payload_request_root`, the prover could freely choose `chain_id` as a private input, enabling cross-chain transaction replay: for typed transactions ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) and later), [`recover_sender`](https://github.com/ethereum/execution-specs/blob/projects/zkevm/src/ethereum/forks/amsterdam/transactions.py#L665) uses the transaction's own `tx.chain_id` for signature recovery, not `block_env.chain_id`, so transactions from any chain would execute successfully. By including `chain_config` in `StatelessValidationResult` ([PR #2342](https://github.com/ethereum/execution-specs/pull/2342)), the proof attests to which `chain_id` was used, and the contract can verify it matches its stored value by reconstructing the full `StatelessValidationResult` before hashing.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks okay to me, just noting: https://hackmd.io/@jsign/eth-zkevm-chainconfig-statelessinput for reference as we may change chain-config in the future

Leave EIP-8025's existing surface untouched and add verify_proof as the
generic primitive, with verify_execution_proof reimplemented as a thin
wrapper over it. Drop the has_valid_proof / verify_new_payload_request_header
machinery. Broaden the abstract and motivation from rollups to any onchain
application that verifies ZK proofs.
@lucadonnoh lucadonnoh force-pushed the native-verification branch from ae84eec to b265e2b Compare May 25, 2026 13:46
@lucadonnoh lucadonnoh marked this pull request as ready for review May 25, 2026 13:46
@lucadonnoh lucadonnoh merged commit 0be40a5 into main May 25, 2026
1 check passed
@coolify-l2beat

Copy link
Copy Markdown

The preview deployment for native-rollups-previews failed. 🔴

Open Build Logs | Open Application Logs

Last updated at: 2026-05-25 13:48:08 CET

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants