Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dive into Scroll ZkEVM

Dive into Scroll ZkEVM

Cheng JIANG

August 20, 2023
Tweet

More Decks by Cheng JIANG

Other Decks in Research

Transcript

  1. Dive into Scroll ZkEVM 1 Dive into Scroll ZkEVM Author:

    CJ, 2023/08/19, Shanghai, China Summary Why is ZkEVM necessary? Why could ZkEVM work? Comparison with existing solutions Architecture diagram and components Arithmeticization Circuits Lookup Table Desmystifying EVM bytecode Circuit example Code walkthrough References Why is ZkEVM necessary? Ethereum has over 450,000 validators, and each validator needs to verify every single transaction within executed blocks, leading to energy wastage. Ethereum requires a higher TPS (transactions per second), and ZkVM has the potential to enable verifiable computation. It's a natural step to consider implementing ZkEVM to increase Ethereum's TPS. Ethereum ultimately aims to fully integrate zero-knowledge proofs (zk-SNARKs) to enhance its scalability and privacy. ZkEVM contributes to this goal. Due to Ethereum's slow iteration speed, there remains a market demand for specialized and customized EVM solutions. Why could ZkEVM work? ZkRollup definition The rollup can be expressed using the following formula: Here, represents the previous state, represents transactions, represents the STF (state transition function), and represents the new state. Currently, most rollups are of the smart contract rollups. These types of rollups involve moving the state transition process of the chain to layer 2 but storing computed result (new state root) and the data required for computation (transactions) on L1. By using transactions and the old state root, it becomes possible to verify whether the new state root is correct, thereby validating the outcome of the "outsourced computation". In the design of Rollup, the data on Layer 2 is considered to be non-essential and replaceable. The primary focus is on ensuring the correctness of the data on Layer 1. This principle is also a key reason why ZkEVM can function effectively. It suffices to ensure the correctness of data on L1. σ = ′ γ(σ,T) σ T γ σ′
  2. Dive into Scroll ZkEVM 2 ZkRollup is a Finite State

    Machine The EVM is a finite state machine composed of several components: Stack Memory Storage Program Counter Gas Each transaction represents a state transition process. The inputs to this process are the user-provided calldata. These inputs drive the state machine to transit to the next state. The core of ZkRollup is the EVM, so it is also a Finite State Machine itself. Finite State Machine makes Verifiable Computation possible While outsourcing computation to an untrusted finite state machine, as long as we ensure: The previous state has been acknowledged as correct. The input to the current STF (state transition function) is accurate. The process of the current ST (state transition) is correct. All data used for state transition can be accessed. Then the computation becomes verifiable. Since ZkRollup is an untrusted finite state machine, we can similarly ensure: ✅ The previous state root has been acknowledged as correct (validated by a validity proof or passed the challenge period of a fraud proof).
  3. Dive into Scroll ZkEVM 3 ✅ The input transactions are

    valid (signatures, hashes, etc., can be successfully verified). ✅ The previous state can be correctly loaded correctly. ✅ The EVM can execute state transitions according to the specification, ensuring strict consistency of reads and writes to prevent corruption. Because the previous state root has been acknowledged as correct, combining it with Merkle proofs as inputs can prove the correctness of storage reads during this state transition. Additionally, due to the guaranteed read-write consistency and EVM specification, the data flow throughout the execution process is correct. As a result, the computed new state root should be correct and can be put onto L1 regardless of the state of the ZkRollup node itself, Comparison with existing solutions Project EVM compatibility VM Zk Framework Verifier Starknet Language Cairo VM eStark TODO ZkSync Era Language Sync VM Boojum (plonky2) Plonk Scroll Bytecode (modified MPT & Hash) EVM Halo2 Shplonk PSE Bytecode EVM Halo2 N/A Polygon ZkEVM Bytecode (TODO) Miden VM plonky2 FFlonk Linea Bytecode TODO Gnark TODO Architecture diagram and components
  4. Dive into Scroll ZkEVM 5 Lookup Table Certain validation of

    the state machine is rather complex. For instance, verifying a signature requires ECDSA circuit constraints. However, ECDSA involves hash functions dependent on bitwise operations, and integrating such hash functions directly into the main circuit could result in an excessively large circuit size, thereby slowing down proof generation. To address this issue, Lookup Tables are utilized. Sub-circuits are used to constrain the correctness of these tables, thus avoiding the inclusion of non-ZK-friendly circuits, often referred to as "Overhead." These sub-circuits also generate separate proofs. In the Aggregation Circuit, the correctness of all proofs are verified and a final proof is generated, thereby reducing verification costs and proof size. ZkEVM requires many Lookup Tables, including but not limited to the following: Fixed tables: Used for constraining bitwise operations, range checks, etc. 0 Tag 1 2 3 FixedTableTag Range16 0..16 0 0 Range32 0..32 0 0 Range64 0..64 0 0 Range256 0..256 0 0 Range512 0..512 0 0 Range1024 0..1024 0 0 SignByte value=0..256 if (value as i8 \< 0) 0xff else 0 0 BitwiseAnd lhs=0..256 rhs=0..256 $lhs AND $rhs BitwiseOr lhs=0..256 rhs=0..256 $lhs OR $rhs BitwiseXor lhs=0..256 rhs=0..256 $lhs XOR $rhs ResponsibleOpcode $execution_state $responsible_opcode $auxiliary Bytecode table: Dependent on keccak tables, these are used to verify that the executing opcode indeed belongs to a certain segment of bytecode. 0,1 CodeHash{Lo,Hi} 2 Tag 3 Index 4 IsCode 5 Value BytecodeFieldTag $codeHash{Lo,Hi} Length 0 0 $value $codeHash{Lo,Hi} Byte $index $isCode $value ... ... ... ... ... $codeHash{Lo,Hi} Byte $index $isCode $value MPT Table: Prove that reads/updates of account nonces, balances, or storage slots are correct. Address MPTProofType Key{Lo,Hi} ValuePrev{Lo,Hi} Value{Lo,Hi} RootPrev{Lo,Hi} Root{Lo,H $addr NonceMod 0,0 $noncePrev,0 $nonceCur,0 $rootPrev{Lo,Hi} $root{Lo,H $addr BalanceMod 0,0 $balancePrev{Lo,Hi} $balanceCur{Lo,Hi} $rootPrev{Lo,Hi} $root{Lo,H $addr CodeHashMod 0,0 $codeHashPrev{Lo,Hi} $codeHashCur{Lo,Hi} $rootPrev{Lo,Hi} $root{Lo,H $addr NonExistingAccountProof 0,0 0,0 0,0 $rootPrev{Lo,Hi} $root{Lo,H $addr AccountDeleteMod 0,0 0,0 0,0 $rootPrev{Lo,Hi} $root{Lo,H $addr StorageMod $key{Lo,Hi} $valuePrev{Lo,Hi} $valueCur{Lo,Hi} $rootPrev{Lo,Hi} $root{Lo,H $addr NonExistingStorageProof $key{Lo,Hi} 0,0 0,0 $rootPrev{Lo,Hi} $root{Lo,H ECDSA signature table: Utilized to validate the correctness of transaction signatures. Keccak table: Ensuring the correctness of hashes, such as codeHash, blockHash, txHash and MPT nodeHash.
  5. Dive into Scroll ZkEVM 6 IsEnabled InputRLC InputLen Output{Lo,Hi} bool

    $input_rlc $input_length $output{Lo,Hi} RW table: Constraining the read-write consistency for stack, memory, and storage. 0 Rwc 1 IsWrite 2 Tag k0 3 Id k1 4 Address k2 5 FieldTag k3 6,7 k4 Target $counter true TxAccessListAccount $txID $address $counter true TxAccessListAccountStorage $txID $address $s $counter $isWrite TxRefund $txID AccountFieldTag $counter $isWrite Account $address Nonce $counter $isWrite Account $address Balance $counter $isWrite Account $address CodeHash CallContext constant CallContextFieldTag (ro) $counter false CallContext $callID RwCounterEndOfReversion $counter false CallContext $callID CallerId $counter false CallContext $callID TxId $counter false CallContext $callID Depth $counter false CallContext $callID CallerAddress $counter false CallContext $callID CalleeAddress $counter false CallContext $callID CallDataOffset $counter false CallContext $callID CallDataLength $counter false CallContext $callID ReturnDataOffset $counter false CallContext $callID ReturnDataLength $counter false CallContext $callID Value $counter false CallContext $callID IsSuccess $counter false CallContext $callID IsPersistent $counter false CallContext $callID IsStatic CallContext last callee CallContextFieldTag (rw) $counter $isWrite CallContext $callID LastCalleeId $counter $isWrite CallContext $callID LastCalleeReturnDataOffset $counter $isWrite CallContext $callID LastCalleeReturnDataLength CallContext state CallContextFieldTag (rw) $counter $isWrite CallContext $callID IsRoot $counter $isWrite CallContext $callID IsCreate $counter $isWrite CallContext $callID CodeHash $counter $isWrite CallContext $callID ProgramCounter $counter $isWrite CallContext $callID StackPointer $counter $isWrite CallContext $callID GasLeft $counter $isWrite CallContext $callID MemorySize
  6. Dive into Scroll ZkEVM 7 $counter $isWrite CallContext $callID ReversibleWriteCounter

    $counter $isWrite Stack $callID $stackPointer $counter $isWrite Memory $callID $memoryAddress $counter $isWrite AccountStorage $txID $address $s TxLogTag $counter true TxLog $txID $logID,0 Address $counter true TxLog $txID $logID,$topicIndex Topic $counter true TxLog $txID $logID,$byteIndex Data $counter true TxLog $txID $logID,0 TopicLength $counter true TxLog $txID $logID,0 DataLength TxReceiptTag $counter false TxReceipt $txID PostStateOrStatus $counter false TxReceipt $txID CumulativeGasUsed $counter false TxReceipt $txID LogLength RLP table: Ensuring the correctness of RLP encoding. Tx table: Ensuring the correctness of transactions. 0 TxId 1 Tag 2 Index Value{Lo,Hi} TxContextFieldTag $TxID Nonce 0 $value,0 $TxID Gas 0 $value,0 $TxID GasPrice 0 $value{Lo,Hi} $TxID CallerAddress 0 $value{Lo,Hi} $TxID CalleeAddress 0 $value{Lo,Hi} $TxID IsCreate 0 $value,0 $TxID Value 0 $value{Lo,Hi} $TxID CallDataLength 0 $value,0 $TxID CallDataGasCost 0 $value,0 $TxID TxSignHash 0 $value{Lo,Hi} $TxID TxInvalid 0 $value,0 $TxID AccessListGasCost 0 $value,0 $TxID CallData $ByteIndex $value,0 $TxID Pad 0 0,0 Block table: Ensuring the correctness of block. 0 Tag 1 Index 2 Value{Lo,Hi} BlockContextFieldTag Coinbase 0 $value{Lo,Hi} GasLimit 0 $value,0 BlockNumber 0 $value,0 Time 0 $value,0 Difficulty 0 $value{Lo,Hi}
  7. Dive into Scroll ZkEVM 8 BaseFee 0 $value{Lo,Hi} ChainID 0

    $value,0 BlockHash 0..256 $value{Lo,Hi} Public inputs table: Utilized to validate the correctness of the whole public inputs (block, transactions etc…) Circuits
  8. Dive into Scroll ZkEVM 10 Circuit example The process of

    validating the execution of a state machine is labor-intensive. For instance, when validating the ADD opcode, several tasks are involved. Firstly, we must verify that this opcode belongs to the [pc, pc+1] segment of the current executing contract bytecode. This task can be accomplished through a lookup operation using a pre-generated bytecode table. In addition, we also need to restrict the bytecode and its corresponding Merkle proof to be able to compute the previous state root. Subsequently, we need to confirm that after the execution of this opcode, critical parameters such as the program counter, stack pointer, and gas have been updated correctly. Finally, we must ensure that the action carried out by this opcode aligns with expectations. For instance, ADD modifies the stack, the top two elements of the stack should be cleared, and the result should be pushed back onto the stack's top. These validations of stack data operations are executed through lookup tables to guarantee consistency in data operations. Similarly, for Memory and Storage, read and write consistency need to be guaranteed. Lookup tables are used to constrain these operations, ensuring that the value read during the next operation matches the value previously written.
  9. Dive into Scroll ZkEVM 11 The detailed process is as

    follows. 1. Verify that the opcode is ADD and belongs to the bytecode segment [pc, pc+1] opId === OpcodeId(0x01) for ADD lookup(bytecode table, 1, pc) === ADD 2. Confirm the correct context switch: rwc’ = rwc + 3 sp’ = sp + 1 pc’ = pc + 1 gas’ = gasgas + 3 3. Switch to use AddGadget 4. Validate the execution process of the ADD opcode lookup(Stack, rw table, sp) == 0x40 lookup(Stack, rw table, sp+ 1) == 0x80 lookup(Stack, rw table, sp’) == 0xc0 Code walkthrough ZkEVM Circuits Generate public inputs codedb statedb rw table
  10. Dive into Scroll ZkEVM 12 Gadgets Add Scroll Prover Prover

    Verifier References Solidity Inline Assembly & Yul Demystifying EVM Opcodes ZkEVM Specs zkEVM Audit Education Sessions 1/4 -Circuit Arithmetization for ZKP zkEVM Audit Education Sessions 3/4 - Architecture and Workflow Scroll Docs EVM illustrated ZkEVM Overview The zkevm circuits walkthrough