# Nebra OP components Our current zk rollup setup consists of the following components: - Unmodified op-batcher, op-node and an unmodified OP-compatible execution client. - Custom op-proposer. Unlike existing versions, which only processes finalized L2 blocks to avoid dealing with reorgs (which adds ~12.8m to end-to-end latency due to Casper FFG finality), ours handles the reorgs on L1/L2. It connects to a configurable number of proving servers and load-balances the proof requests between them according to their weights. - Proving server forked from op-succinct. - SP1 zkVM programs which are based on kona library, forked from op-succinct. - Custom L2OutputOracle contract on L1 – updated to work with our op-proposer. - Tweaked OptimismPortal contract – adjusted to allow proving and finalizing withdrawal transactions within the same block (for better UX) - this change is optional. ## Demo Please follow for running a local demo: https://github.com/NebraZKP/nebra-op/blob/nebra-op/nebra-op-book/src/running-demo.md https://github.com/NebraZKP/nebra-op/blob/nebra-op/nebra-op-book/src/tuning-proposer.md # Overview of the ZK rollup design Nebra OP functions mostly identically to optimistic rollups with the following differences: In optimistic rollups, proposer (proposer is a separate role which is typically merged with sequencer) is responsible for submitting output roots without a proof - however, challengers can submit a fault proof in a case if proposer submitted a faulty output root within the finalization period (typically 7 days). The fault proofs are based on an on-chain MIPS virtual machine (called Cannon) - the state transition function is written in Rust (or Go) and compiled into MIPS. In Nebra OP, proposer submits output roots alongside validity proof (ZKP). The state transaction function is written in Rust and compiled into RISCV instructions, and fed into a RISCV zkVM which can prove execution of an arbitrary RISCV program. Currently, we use `kona` as OP state transaction function and SP1 as zkVM, but these modules are interchangeable. Nebra OP doesn't have challengers and finalization is instant. ZK rollups and optimistic rollups use different sets of contracts: ZK rollups use L2OutputOracle instead of DisputeGameFactory and OptimismPortal instead of OptimismPortal2. When it comes to sending deposit or withdrawal transactions, OP-compatible libraries (e.g. viem) work seamlessly with both variants. # Proofs structure Current proof structure is the same as in op-succinct. Namely, there 2 types of proofs: - span proof: proves execution of a range of blocks - agg proof: verifies N adjacent span proofs ## Integration The main challange is that Nebra OP ZKP verification requires access to Ethereum block hashes. Each ZKP is associated with a specific Ethereum block hash, and verifying it involves checking that the hash corresponds to a real Ethereum block. If Axelar doesn't have access to Ethereum block hashes, then it would necessary to implement this functionality. The next milestone is verifying Groth16 proofs on Axelar. However, since Axelar contract can be written in Rust, we expect it to be quick. zkVM is going to produce Groth16 proofs. However, in order to verify these proofs using a generic Groth16 verifier, we would need to know the Groth16 public inputs and Groth16 verification key, which are not the same as zkVM public inputs and verification key. We'll need to write a zkVM verifier - which is going to be a wrapper around Groth16 verifier. Or, ideally, since Axelar is programmable in Rust, we can reuse the existing code inside zkVM codebase. Once the ZKPs verification is fully implemented, we can start writing the Gateway and Verifier contract on Axelar network ## Current performance - Proving of 1 L2 gas takes about ~25-60 cycles on SP1 4.1.0 with kona, including L2 block derivation - On m8g.16xlarge, proving of 1M cycles takes roughly 6-8s - On m7i.16xlarge, proving of 1M cycles takes roughly 8-10s If we assume that the hourly price of m8g.16xlarge is $3.44/h, then the price of 1 MGas is roughly ~$0.13-$0.45