Skip to content

EspressoSystems/zkrollup-integration

Repository files navigation

zkrollup-integration

Tools for zkRollups to integrate with Espresso.

When a zk-rollup integrates with a shared finality gadget, it will receive streams of finalized blocks containing transactions from all participating rollups. As part of (batched) state update on L1, provers for a zk-rollup periodically submit a validity proof attesting to the correctness of a new rollup state. A rollup state corresponds to a specific finalized block. Solely proving valid state transition on the rollup VM against a list of transactions from the block (a.k.a "VM proof") is insufficient. With a decentralized finality gadget, the validity proof needs to encapsulate a proof of consensus on the new finalized block commitment (a.k.a "(consensus) light client proof"). With a shared finality gadget, the proof needs to further encapsulate correct "filtering of rollup-specific transactions" from the overall block (a.k.a. "derivation proof"). This repo provides circuits for the derivation proof and the consistency among the three (sub-)proofs.1

Note

Espresso uses a non-executing consensus, thus the consensus state doesn't embed post-execution rollup states: the consensus nodes only agree on the committed block payload (thus the total ordering among txs) and its availability. The validity of updated rollup/VM states, after executing those newly committed txs, is left to the rollup prover (aka batcher).

Terminology wise:

  • a block is abstractly referring to a list of new txs/state transitions; concretely manifests as:
    • BlockPayload: the actual payload that contains the raw tx data
      • instead of full block replication at each node, we use Verifiable Information Dispersal (VID) schemes where each replica stores a chunk.
        • our concrete instantiation of VID relies on KZG polynomial commitment, thus requires structured reference string (SRS) from a trusted setup
      • all replicas unequivocally refer to the payload by a PayloadCommitment, a cryptographic commitment to the entire payload sent to every replica alongside their designated chunk
    • BlockHeader: the summarized new consensus state and chain metadata (for consensus nodes)
      • BlockCommitment: a short cryptographic commitment to the BlockHeader
      • BlockMerkleCommitment: the root of BlockMerkleTree that accumulates all block commitments up to the current BlockHeight, enabling efficient historical block header lookup via BlockMerkleTreeProof
      • PayloadCommitment is a part of BlockHeader
      • NsTable described below is a part of BlockHeader
  • each rollup occupies a namespace (distinguished by a unique namespace ID) in a block
    • NsTable is the compact encoding of a namespace table mapping namespace id to their range in BlockPayload
    • NsProof is a namespace proof, attesting that some subset of bytes is the complete range of data designated to a particular namespace in a BlockPayload identified by its PayloadCommitment given a NsTable
  • a light client is an agent that can verify the latest finalized consensus state without running a full node
    • an off-chain light client usually receive the block header and the quorum certificate (QC)
    • an on-chain light client stores a pruned LightClientState, a strict subset of fields in BlockHeader, verified through light client proof (the simplest form is using the QC from consensus, but we use a more EVM and SNARK-friendly light client protocol).

Circuit Spec

Generally speaking, we are proving that a list of rollup's transactions are correctly derived from finalized Espresso blocks.

Public Inputs

  • rollup_txs_commit: [u8; 32]: commitment to the transactions designated to the rollup ns_id, also one of the public inputs from the VM execution proof
    • the concrete commitment scheme depends on the VM prover design, we use Sha256(rollup_txs) in the demo
  • ns_id: u32: namespace ID of this rollup
  • bmt_commitment: BlockMerkleCommitment: root of the newest Espresso block commitment tree, accumulated all historical Espresso block commitments
  • vid_pp_hash: [u8; 32]: Sha256 of VidPublicParam for the VID scheme

Private Inputs

  • rollup_txs: Vec<u8>: the byte representation of all transactions specific to rollup with ns_id filtered from a batch of Espresso blocks
  • vid_param: VidParam: public parameter for Espresso's VID scheme
  • block_derivation_proofs: Vec<(Range, BlockDerivationProof)>: a list of (range, proof) pairs, one for each block, where proof proves that rollup_txs[range] is the complete subset of namespace-specific transactions filtered from the Espresso block. Each BlockDerivationProof contains the following:
    • block_header: BlockHeader: block header of the original Espresso block containing the block height, the namespace table ns_table, and a commitment payload_commitment to the entire Espresso block payload (which contains transactions from all rollups)
    • bmt_proof: BlockMerkleTreeProof: a proof that the given block is in the block Merkle tree committed by bmt_commitment
    • vid_common: VidCommon: auxiliary information for the namespace proof ns_proof verification during which its consistency against payload_commitment is checked
    • ns_proof: NsProof: a namespace proof that proves some subslice of bytes (i.e. rollup_txs[range]) is the complete subset for the namespace ns_id from the overall Espresso block payload committed in block_header

Relations

  1. Recompute the payload commitment using the "VM execution prover" way: rollup_txs_commit == Sha256(rollup_txs)
  • note: by marking this as a public input, the verifier can cross-check it with the public inputs from the "vm proof", thus ensuring the same batch of transactions is used in rollup_txs here and in the generation of the "vm proof"
  1. Correct derivations for the namespace/rollup from committed Espresso blocks
    • First the ranges in block_derivation_proofs should be non-overlapping and cover the whole payload, i.e. range[i].end == range[i+1].start && range[i].start == 0 && range[-1].end == rollup_txs.len().
    • For each BlockDerivationProof, we check
      • the block_header is in the block Merkle tree, by checking the proof bmt_proof against the block Merkle tree commitment bmt_commitment
      • Namespace ID ns_id of this rollup is contained in the namespace table block_header.ns_table, and given the specified range in the Espresso block and a namespace proof NsProof, checks whether the slice of rollup's transactions rollup_txs matches the specified slice in the Espresso block payload committed by block_header.payload_commitment

Read our doc for a more detailed description; read our blog on Derivation Pipeline for rollup integration.

Getting Started

To enter the development shell: nix develop

Requirements

SP1 stack

To build the ELF executable for your program and generate the proof, you will have to run outside the nix dev-shell. For contract developments, you can enter nix shell to use necessary tools.

# this will first rebuild the program to elf, then generate plonky3 proof and verify it
just sp1-prove

# this will generate a proof for solidity, and creates fixture for contract verifier
just sp1-prove --evm

Footnotes

  1. Circuits for VM proof are usually offered by zk-rollup project themselves (e.g. Polygon's CDK, Scroll's zkEVM); circuit (written using jellyfish's constraint system) for Espresso's light client proof can be found here.

About

Tools for zkRollups to integrate with Espresso

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published