ZK Proof System

Table of Contents

Overview

The ZK proof system is a succinct proof system that verifies a super root state transition across all chains in the interop set through a single cryptographic proof. It consists of two components:

  • ZK Program: an off-chain circuit that re-executes the derivation and state transitions for all chains in the interop set and produces a succinct proof of correctness.
  • On-chain Verifier: a smart contract (see IZKVerifier) that checks the proof and the committed public values in a single call.

This is the ZK analogue of SuperFaultDisputeGame. The program proves the Super Root State Transition for every timestamp from startingProposal.l2SequenceNumber + 1 to l2SequenceNumber: local-safe derivation for each chain, followed by consolidation. This is the same statement that the Super Fault Dispute Game bisects over, proven in a single on-chain call.

In a standalone deployment (single chain), the interop set contains exactly one chain. The program is identical; the SuperRootProof preimage carries one entry. No separate standalone mode exists.

ZK Program

The ZK program is the circuit executed off-chain to generate a proof. It takes a set of public values as inputs and verifies that executing the derivation and state transitions for every chain in the interop set, starting from startingProposal.root and using L1 data up to l1Head, produces the super root rootClaim at timestamp l2SequenceNumber.

rootClaim is the consolidated (cross-safe) super root, i.e. the verified super root returned by superroot_atTimestamp. L1 data is bound to the game only through the range proofs, each of which MUST commit to the game's l1Head.

Inputs

The following public values are committed to by the ZK proof. They are constructed on-chain from game state, ABI-encoded in table order (5 × 32 bytes), and passed to the verifier:

FieldTypeDescription
l1Headbytes32L1 block hash at which the L1 state was sampled. Authenticates all observed L1 data.
startingProposal.rootbytes32Super root hash of the parent game's claim, or the anchor state if parentIndex == type(uint32).max. Starting point for all chain state transitions.
rootClaimbytes32The super root hash being asserted by this game. It commits to the output roots of all chains in the interop set at l2SequenceNumber.
l2SequenceNumberuint256Super root timestamp corresponding to rootClaim. Constrained to uint64 range.
proveraddressAddress of the proof submitter (msg.sender in prove()). Binds the proof to a specific submission.

l2ChainId is intentionally absent. Chain scoping is provided by the SuperRootProof preimage committed to by rootClaim and startingProposal.root. In a standalone (single-chain) deployment, the preimage contains exactly one chain entry; no separate field is needed.

Output

The program produces a proof that commits to the public values. A proof that passes on-chain verification means: executing the derivation logic for every chain in the interop set from the state committed to in startingProposal.root, under the L1 data observed at l1Head, yields exactly the super root rootClaim at timestamp l2SequenceNumber.

Absolute Prestate

The absolutePrestate is a bytes32 value that uniquely identifies the ZK program version being proven. Two different programs MUST NOT share the same absolutePrestate.

It serves as the program identity in IZKVerifier.verify and is injected into each game instance via the CWIA game args.

For SP1 deployments, absolutePrestate is the verification key of the aggregation program (see SP1 (PLONK)). The aggregation program pins the range program's verification key, and the range program pins the log-commitment program's verification key, so absolutePrestate commits transitively to all three programs. It also commits to the rollup configs, L1 config and dependency set compiled into the programs. The chain set in a proof MUST equal the compiled dependency set. No rollup config hash appears in the public values.

Program updates (e.g. a bug fix, a new hard fork, a chain config change or a dependency set change) MUST produce a new absolutePrestate. OPCM manages absolutePrestate per deployment; updates require governance.

Reference Implementation

SP1 (PLONK)

The initial reference implementation uses SP1 by Succinct with the PLONK backend.

The ZK program consists of three SP1 programs:

ProgramRole
log-commitmentCommits to the logs under each input receipts root, so that initiating messages can be checked without loading the block's receipts.
super-rangeRange mode: derives the local-safe blocks of one or more chains for a span of timestamps against l1Head. Consolidation mode: validates cross-chain messages for a span of timestamps, using verified log-commitment proofs, and computes the resulting super roots.
super-aggregationVerifies all range and consolidation proofs against the pinned super-range verification key, checks that every (timestamp, chain) of the claim is covered exactly once, checks that the super roots chain from startingProposal.root to rootClaim, and commits the five public values.

The log-commitment and super-range proofs are SP1 compressed proofs. Only the super-aggregation proof is a PLONK proof, and it is the proof submitted on-chain. It is verified by the SP1PlonkAdapter.

Proof Generation

Proofs are generated off-chain by a prover that:

  1. Reads l1Head, startingProposal (startingRootHash() and startingSequenceNumber()), rootClaim, l2SequenceNumber, absolutePrestate and verifier from the game.
  2. Fetches the verified super root for every timestamp from startingProposal.l2SequenceNumber to l2SequenceNumber via superroot_atTimestamp, trusting a response only when its current_l1 is above verified_required_l1. If the super root at l2SequenceNumber differs from rootClaim, or verified_required_l1 is above l1Head, the claim is unprovable. If the super root at startingProposal.l2SequenceNumber differs from startingProposal.root, the parent is invalid and the game loses through iZKG-005, so an honest prover does not attempt it.
  3. Collects the L1 data (including blobs) and the L2 witness data for every chain.
  4. Generates the log-commitment, range, consolidation and aggregation proofs.
  5. Submits the aggregation proof via ZKDisputeGame.prove(proofBytes) from the address committed to as prover.

Proof generation is permissionless: any party may generate and submit a proof. In practice the proposer or a third-party proving service will act as prover.

Invariants

iZKVM-001: Private Inputs Must Be Anchored to Public Values

The ZK program receives private inputs (block and transaction data for all chains) that are known only to the prover and never seen by the on-chain verifier. The ZK program MUST verify that all private inputs are directly derived from or cryptographically linked to the public values (e.g. by hashing block data and comparing against l1Head, or verifying that blocks form a chain rooted at startingProposal.root). The ZK program MUST NOT trust any private input without an explicit check against a public value.

Impact

Severity: Critical

A violation means a malicious prover can supply manipulated private inputs that lead to a proof that verifies on-chain but represents an invalid state transition, and enable finalization of a fraudulent super root.

iZKVM-002: Super Root Preimage Must Commit to All Chain Outputs

The ZK program MUST verify the output root of every chain listed in the SuperRootProof preimage and MUST produce a rootClaim that is the hash of that complete preimage. Omitting any chain from the proof or producing a partial preimage hash MUST cause the program to fail.

Impact

Severity: Critical

A violation would allow a proof to finalize a super root that does not faithfully represent all chains in the interop set. Funds that do not exist on L2 could be withdrawn, or the state of a chain could be suppressed from the commitment.