Fusion zkRollup
Fusion is an experimental progressive Ethereum zkRollup written in Rust and focuses on performance, modularity, and applying cutting-edge Verifiable Computation proof systems.
Fusion is conceptually based on the original zkRollup. We use Zokrates for all circuits which provides high level abstractions for all algorithms and multiple backends. Currently the prover builds a Groth16 SNARK for each transaction in parallel, and there is no batching. Together with ZoKrates we are experimenting with Nova recursive proofs to enable incredibly fast transaction batching and compression.
See the end of this document for the full list of roadmap items, ideas, and concrete tasks.
Tool Suite
This repository contains the entire Fusion tool suite:
circuits
: the SNARK state and signature verification ZoKrates code.fusion-prover
: the prover that takes a signed transaction and builds a SNARK of state changes and signature.fusion-sequencer
: the Fusion node. Receives L2 transactions via RPC, builds blocks, and sends them for verification on L1.l1-verifier
: the Fusion contracts deployed on L1. These contracts provide block verification and canonical state root updates for L2 nodes.fusion-wallet
: a simple CLI interface to sign/send Fusion transactions.
Cloning the repository
git clone --recurse-submodules https://github.com/leonardoalt/fusion.git
If you already cloned the repository without submodules, you can run the command below to initialize it:
git submodule update --init --recursive
Dependencies
Fusion requires the following installed:
Building the circuits
ZoKrates' latest release 0.8.7 is specifically required for this step.
cd circuits && make && make verifier
Note: the current circuits require at least 16GB of RAM to compile.
Building the L1 SNARK verifier
This step requires the circuit step above.
cd l1-verifier && make
Building the sequencer (has prover as dependency)
This step requires the L1 verifier step above.
cargo build --release --bin fusion-sequencer
Running
The easiest way to see everything running is via Rust tests with
cargo test --release -- --nocapture
For more details see the tests in fusion-sequencer
.
If you want to run it in production style, you may want to follow this list:
- Set
eth_private_key
infusion.toml
to the private key that will deploy the contract and submit L2 blocks. - Set
eth_rpc_url
infusion.toml
to an Ethereum RPC endpoint. Since we are usinganvil
here, this is usuallyhttp://localhost:8545
. - Run
source ./scripts/run_anvil_and_deploy_contract
which startsanvil
and deploys the contract. - Set
fusion_l1_contract
infusion.toml
with the address of the deployed contract. - Run
./scripts/run_node
to start the node. - You can run
./scripts/listen_to_node
to check the ongoing output from the node. - Now you can also run
./scripts/send_random_tx
to send transactions. - To stop everything, run
./scripts/kill_node
and./scripts/kill_anvil
.
State
The state is a balanced Sparse Merkle Tree similar to this one. The tree has 256 levels besides the root. This implies that it has 2^256 leaves. Each leaf has an index, from 0 (left most) to 2^256 - 1 (right most). The path from the root to a leaf can be represented by the binary representation of the leaf's index: when walking down the tree, 0 means the path goes left, 1 means it goes right.
The tree also contains some optimizations, such as:
- For the sparse branches of tree, we keep all nodes as 0, instead of
hash(hash(...(0)))
(such as in the Ethereum Beacon Chain Deposit Contract). - When merging two nodes, we apply:
merge(0, 0) = 0
merge(L, 0) = L, if L != 0
merge(0, R) = R, if R != 0
merge(L, R) = hash(L, R), if L != 0 and R != 0
- The rules above may lead to collisions if the contents of two leaves are the same. To avoid that, we hash the leaf's contents together with its unique index.
The used hash is Poseidon in order to be SNARK friendly.
Signature and Addresses
Since we need to verify signatures inside zkSNARKs, we use EdDSA with the Baby Jubjub Elliptic Curve.
A public key (PK) consists of a curve point where x
and y
are elements of
the field used by Baby Jubjub. The PK can be compressed into 256 bits, which
does not necessarily fit in the field.
Given a public key (x, y)
, its Fusion address consists of poseidon(x, y)
.
This means that Fusion accounts are not compatible with Ethereum accounts.
Execution
There are no VM and smart contracts at the moment.
Modularity
Fusion is designed to be highly modular and extensible. For example, here are a few things that can be modified quite easily:
- the sequencer's block building strategy
- the RPC node
- the L2 state data structures
- the proving backend (see branch
nova
) - the signature algorithm
This enables fast experimental iterations on all fronts which can quickly turn into progress.
Roadmap (and TODO items)
v1. Batch proofs - production after this!
Done
- L2 RPC node
- L2 sequencer
- State verification circuit
- State verification prover
- Baby Jubjub signature verification circuit
- Baby Jubjub signature verification prover
- Transaction verification circuit
- Transaction verification prover
- L1 verifier
- L2 block verification using L1 verifier
- Baby Jubjub CLI wallet
- L2 enter via L1 deposit
- L2 exit via L1 withdraw
TODO
- Transaction fees
- Compress transaction proofs into a batch proof (in progress using Nova)
- Separate mempool from sequencer
- Reconstruct L2 state from scratch by re-playing block submissions to L1 verifier
- Multi-key Merkle proofs
- Forced transactions
- Sequencer auction
v2. Execution
TODO
- Integrate an extremely simple VM. Options:
- Subset of the EVM. Expand whatever idea is chosen from the previous item with EVM opcodes.
- Full EVM. At this point I hope ZoKrates+SuperNova has good performance so I can write everything in a high level.