Zeth is an open-source ZK block prover for Ethereum and Optimism built on the RISC Zero zkVM.
Zeth makes it possible to prove that a given block is valid (i.e., is the result of applying the given list of transactions to the parent block) without relying on the validator or sync committees. This is because Zeth does all the work needed to construct a new block from within the zkVM, including:
- Verifying transaction signatures.
- Verifying account & storage state against the parent block’s state root.
- Applying transactions.
- Paying the block reward.
- Updating the state root.
- Etc.
After constructing the new block, Zeth calculates and outputs the block hash. By running this process within the zkVM, we obtain a ZK proof that the new block is valid. For Optimism, our validity proof ensures that the block is correctly derived from the available data posted to Ethereum.
Zeth is experimental and may still contain bugs.
Zeth primarily requires the availability of Ethereum/Optimism RPC provider(s) data. Two complementary types of providers are supported:
- RPC provider.
This fetches data from a Web2 RPC provider, such as Alchemy.
Specified using the
--eth-rpc-url=<RPC_URL>
and--op-rpc-url=<RPC_URL>
parameters. - Cached RPC provider.
This fetches RPC data from a local file when possible, and falls back to a Web2 RPC provider when necessary.
It amends the local file with results from the Web2 provider so that subsequent runs don't require additional Web2 RPC calls.
Specified using the
--cache[=<CACHE>]
parameter.
Install the cargo risczero
tool and the risc0
toolchain:
cargo install cargo-risczero
cargo risczero install
Clone the repository and build with cargo
using one of the following commands:
- CPU Proving (slow):
cargo build --release
- GPU Proving (apple/metal)
cargo build -F metal --release
- GPU Proving (nvidia/cuda)
cargo build -F cuda --release
If you wish to use the --release
profile when building Zeth,
check out https://docs.docker.com/engine/install/ for a guide on how to install docker, which is required for reproducible builds of the zkVM binaries in Zeth.
Run the built binary (instead of using cargo run
) using:
RUST_LOG=info ./target/release/zeth
Zeth currently has four main modes of execution:
RUST_LOG=info ./target/release/zeth help
Usage: zeth <COMMAND>
Commands:
build Build blocks natively outside the zkVM
run Run the block creation process inside the executor
prove Provably create blocks inside the zkVM
verify Verify a block creation receipt
op-info Output debug information about an optimism block
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
For every command, the --network
parameter can be set to either ethereum
or optimism
for provable construction
of single blocks from either chain on its own.
To provably derive Optimism blocks using the data posted on the Ethereum chain, use --network=optimism-derived
,
but optimism-derived
is not supported by the run
and op-info
commands.
This command only natively builds blocks and does not generate any proofs.
RUST_LOG=info ./target/release/zeth build --help
Build blocks natively outside the zkVM
Usage: zeth build [OPTIONS] --block-number=<BLOCK_NUMBER>
Options:
-w, --network=<NETWORK> Network name (ethereum/optimism/optimism-derived) [default: ethereum]
-e, --eth-rpc-url=<ETH_RPC_URL> URL of the Ethereum RPC node
-o, --op-rpc-url=<OP_RPC_URL> URL of the Optimism RPC node
-c, --cache[=<CACHE>] Use a local directory as a cache for RPC calls. Accepts a custom directory. [default: cache_rpc]
-b, --block-number=<BLOCK_NUMBER> Block number to begin from
-n, --block-count=<BLOCK_COUNT> Number of blocks to provably derive [default: 1]
-m, --composition[=<COMPOSITION>] Compose separate block derivation proofs together. Accepts a custom number of blocks to process per derivation call. (optimism-derived network only) [default: 1]
-h, --help Print help
When run in this mode, Zeth does all the work needed to construct an Ethereum block and verifies the correctness of the result using the RPC provider. No proofs are generated.
With --network=optimism-derived
, the derivation proof creation is done without proof composition by default,
requiring the derivation to be carried out inside a single zkVM execution.
Examples
The host/testdata
and host/testdata/derivation
directories come preloaded with a few cache files that you can use
out of the box without the need to explicitly specify an RPC URL:
RUST_LOG=info ./target/release/zeth build \
--network=ethereum \
--cache=host/testdata \
--block-number=16424130
RUST_LOG=info ./target/release/zeth build \
--network=optimism \
--cache=host/testdata \
--block-number=107728767
RUST_LOG=info ./target/release/zeth build \
--network=optimism-derived \
--cache=host/testdata/derivation \
--block-number=109279674 \
--block-count=4
Composition The optimism derivation proof (--network=optimism-derived
) can alternatively be created using proof composition by
setting the --composition
parameter to the number of op blocks per rolled up proof.
In the following example, 2 derivation proofs of 2 sequential blocks each are composed to obtain the final derivation
proof for the 4 sequential blocks:
RUST_LOG=info ./target/release/zeth build \
--network=optimism-derived \
--cache=host/testdata/derivation \
--block-number=109279674 \
--block-count=4 \
--composition=2
This command only invokes the RISC-V emulator and does not generate any proofs.
RUST_LOG=info ./target/release/zeth run --help
Run the block creation process inside the executor
Usage: zeth run [OPTIONS] --block-number=<BLOCK_NUMBER>
Options:
-w, --network=<NETWORK> Network name (ethereum/optimism/optimism-derived) [default: ethereum]
-e, --eth-rpc-url=<ETH_RPC_URL> URL of the Ethereum RPC node
-o, --op-rpc-url=<OP_RPC_URL> URL of the Optimism RPC node
-c, --cache[=<CACHE>] Use a local directory as a cache for RPC calls. Accepts a custom directory. [default: cache_rpc]
-b, --block-number=<BLOCK_NUMBER> Block number to begin from
-n, --block-count=<BLOCK_COUNT> Number of blocks to provably derive [default: 1]
-x, --execution-po2=<LOCAL_EXEC> The maximum segment cycle count as a power of 2 [default: 20]
-p, --profile Whether to profile the zkVM execution
-h, --help Print help
Local executor mode. When run in this mode, Zeth does all the work needed to construct an Ethereum block from within the zkVM's non-proving emulator. Correctness of the result is checked using the RPC provider. This is useful for measuring the size of the computation (number of execution segments and cycles). No proofs are generated.
Examples The below examples will invoke the executor, which will take a bit more time, and output the number of cycles required for execution/proving inside the zkVM:
RUST_LOG=info ./target/release/zeth run \
--cache=host/testdata \
--network=ethereum \
--block-number=16424130
RUST_LOG=info ./target/release/zeth run \
--cache=host/testdata \
--network=optimism \
--block-number=107728767
The run
command does not support proof composition (required by --network=optimism-derived
) because receipts are required for this process inside the
executor.
Alternatively, one can call the prove
command in dev mode (RISC0_DEV_MODE=true
) for the same functionality, as
demonstrated in the next section.
This command generates a ZK proof, unless dev mode is enabled through the environment variable RISC0_DEV_MODE=true
.
RUST_LOG=info ./target/release/zeth prove --help
Provably create blocks inside the zkVM
Usage: zeth prove [OPTIONS] --block-number=<BLOCK_NUMBER>
Options:
-w, --network=<NETWORK> Network name (ethereum/optimism/optimism-derived) [default: ethereum]
-e, --eth-rpc-url=<ETH_RPC_URL> URL of the Ethereum RPC node
-o, --op-rpc-url=<OP_RPC_URL> URL of the Optimism RPC node
-c, --cache[=<CACHE>] Use a local directory as a cache for RPC calls. Accepts a custom directory. [default: cache_rpc]
-b, --block-number=<BLOCK_NUMBER> Block number to begin from
-n, --block-count=<BLOCK_COUNT> Number of blocks to provably derive [default: 1]
-x, --execution-po2=<LOCAL_EXEC> The maximum segment cycle count as a power of 2 [default: 20]
-p, --profile Whether to profile the zkVM execution
-m, --composition[=<COMPOSITION>] Compose separate block derivation proofs together. Accepts a custom number of blocks to process per derivation call. (optimism-derived network only) [default: 1]
-s, --submit-to-bonsai Prove remotely using Bonsai
-h, --help Print help
Proving on Bonsai.
To run in this mode, add the parameter --submit-to-bonsai
.
When run in this mode, Zeth submits a proving task to the Bonsai proving service,
which then constructs the blocks entirely from within the zkVM.
This mode checks the correctness of the result on your machine using the RPC provider(s).
It also outputs the Bonsai session UUID, and polls Bonsai until the proof is complete.
To use this feature, first set the BONSAI_API_URL
and BONSAI_API_KEY
environment variables before executing zeth
to submit jobs to Bonsai.
Need a Bonsai API key? Sign up today.
Examples The below examples will invoke the prover, which will take a potentially significant time to generate a ZK proof locally:
RUST_LOG=info ./target/release/zeth prove \
--cache=host/testdata \
--network=ethereum \
--block-number=16424130
RUST_LOG=info ./target/release/zeth prove \
--cache=host/testdata \
--network=optimism \
--block-number=107728767
RUST_LOG=info ./target/release/zeth prove \
--network=optimism-derived \
--cache=host/testdata/derivation \
--block-number=109279674 \
--block-count=4
Composition Alternatively, we can run composition in dev mode, which should only as much time as required by the executor, using the following command:
RISC0_DEV_MODE=true RUST_LOG=info ./target/release/zeth prove \
--network=optimism-derived \
--cache=host/testdata/derivation \
--block-number=109279674 \
--block-count=4 \
--composition=2
NOTE Proving in dev mode only generates dummy receipts that do not attest to the validity of the computation and are not verifiable outside of dev mode!
This command verifies a ZK proof generated on Bonsai.
RUST_LOG=info ./target/release/zeth verify --help
Verify a block creation receipt
Usage: zeth verify [OPTIONS] --block-number=<BLOCK_NUMBER> --bonsai-receipt-uuid=<BONSAI_RECEIPT_UUID>
Options:
-w, --network=<NETWORK>
Network name (ethereum/optimism/optimism-derived) [default: ethereum]
-e, --eth-rpc-url=<ETH_RPC_URL>
URL of the Ethereum RPC node
-o, --op-rpc-url=<OP_RPC_URL>
URL of the Optimism RPC node
-c, --cache[=<CACHE>]
Use a local directory as a cache for RPC calls. Accepts a custom directory. [default: cache_rpc]
-b, --block-number=<BLOCK_NUMBER>
Block number to begin from
-n, --block-count=<BLOCK_COUNT>
Number of blocks to provably derive [default: 1]
-b, --bonsai-receipt-uuid=<BONSAI_RECEIPT_UUID>
Verify the receipt from the provided Bonsai Session UUID
-h, --help
Print help
This command first natively builds the specified block(s), and then validates the correctness of the receipt generated
on Bonsai specified by the --bonsai-receipt-uuid=BONSAI_SESSION_UUID
parameter, where BONSAI_SESSION_UUID
is the
session UUID returned when proving using --submit-to-bonsai
.
RUST_LOG=info ./target/release/zeth op-info --help
Output debug information about an optimism block
Usage: zeth op-info [OPTIONS] --block-number=<BLOCK_NUMBER>
Options:
-w, --network=<NETWORK> Network name (ethereum/optimism/optimism-derived) [default: ethereum]
-e, --eth-rpc-url=<ETH_RPC_URL> URL of the Ethereum RPC node
-o, --op-rpc-url=<OP_RPC_URL> URL of the Optimism RPC node
-c, --cache[=<CACHE>] Use a local directory as a cache for RPC calls. Accepts a custom directory. [default: cache_rpc]
-b, --block-number=<BLOCK_NUMBER> Block number to begin from
-n, --block-count=<BLOCK_COUNT> Number of blocks to provably derive [default: 1]
-h, --help Print help
This command only outputs debug information for development use.
Check out these resources and say hi on our Discord: