17 KiB
Ere – Unified zkVM Interface & Toolkit
Compile. Execute. Prove. Verify.
One ergonomic Rust API, multiple zero‑knowledge virtual machines.
Table of Contents
- Table of Contents
- Supported Rust Versions (MSRV)
- Overview
- Architecture
- Supported zkVMs
- Examples
- Environment Variables
- Directory Layout
- Contributing
- Disclaimer
- License
Supported Rust Versions (MSRV)
The current MSRV (minimum supported rust version) is 1.88.
Overview
This repository contains the following crates:
- Traits
ere-zkvm-interface-CompilerandzkVMtraits for zkVM host operationsere-platform-trait-Platformtrait for guest program
- Per-zkVM implementations for
ere-zkvm-interface(host) - Per-zkVM implementations for
ere-platform-trait(guest) ere-dockerized- Docker wrapper implementation forere-zkvm-interfaceof all zkVMsere-io- Serialization utilities for host/guest IO communication- Internal crates
ere-compiler- Cli to runCompilerused byere-dockerizedere-server- Server and client forzkVMoperations used byere-dockerizedere-build-utils- Build-time utilitiesere-compile-utils- Compilation utilitiesere-test-utils- Testing utilities
Architecture
The Interface
ere-zkvm-interface provides traits for host:
-
CompilerCompile a guest program into a zkVM-specific artifact (typically a RISC-V ELF, or a wrapper with preprocessing data).
-
zkVMExecute, prove and verify that artifact. A zkVM instance is created for specific artifact that comes from the
Compiler.
ere-platform-trait provides traits for guest program:
-
PlatformProvides platform dependent methods for IO read/write and cycle tracking. It also re-exports the runtime SDK of the zkVM, that is guaranteed to match the same version with the zkVM host when
ere-{zkvm}andere-platform-{zkvm}have the same version.
Communication between Host and Guest
Host and guest communicate through raw bytes. Serialization/deserialization can be done in any way as long as they agree with each other.
Reading Private Values from Host
The Input structure holds stdin as raw bytes. There are 2 ways to use it:
-
Input::new().with_prefixed_stdin(data)forPlatform::read_whole_input()The
Platformtrait provides a unified interface to read the whole stdin. However, some zkVMs don't provide access to the stdin length, so we require it to have a length prefix.The method
Input::with_prefixed_stdinautomatically adds a LE u32 length prefix to the stdin. In the guest,Platform::read_whole_inputwill return only the actual data.Without the length prefix, the
Platform::read_whole_inputwill cause guest panic at runtime. -
Input::new().with_stdin(data)for zkVM-specific stdin APIsThe method
Input::with_stdinsets stdin without modification. Use this when you need direct access to zkVM-specific stdin APIs (e.g.,sp1_zkvm::io::read,risc0_zkvm::guest::env::read), such as streaming reads or partial data consumption.
Writing Public Values to Host
Public values written in the guest program (via Platform::write_whole_output() or zkVM-specific output APIs) are returned as raw bytes to the host after zkVM::execute, zkVM::prove and zkVM::verify methods.
Different zkVMs handles public values in different approaches:
| zkVM | Size Limit | Note |
|---|---|---|
| Airbender | 32 bytes | Padded to 32 bytes with zeros |
| Jolt | 4096 bytes (Configurable) | |
| Miden | 16 words | Word = Goldilocks field element |
| Nexus | unlimited | Size configured automatically |
| OpenVM | 32 bytes | Padded to 32 bytes with zeros |
| Pico | unlimited | Hashed internally |
| Risc0 | unlimited | Hashed internally |
| SP1 | unlimited | Hashed internally |
| Ziren | unlimited | Hashed internally |
| Zisk | 256 bytes |
For zkVMs with size limits on public values, OutputHashedPlatform<P, D> serves as a wrapper that hashes outputs before calling the inner P::write_whole_output. This enables the same guest program to run across all zkVMs regardless of their size constraints:
OutputHashedPlatform::<OpenVMPlatform, Sha256>::write_whole_output(&large_output);
Supported zkVMs
| zkVM | Version | GPU |
|---|---|---|
| Airbender | 0.5.2 |
Yes |
| Jolt | 6dcd401 |
No |
| Miden | 0.20.4 |
No |
| Nexus | 0.3.6 |
No |
| OpenVM | 1.4.3 |
Yes |
| Pico | 1.2.2 |
No |
| Risc0 | 3.0.4 |
Yes |
| SP1 | 6.0.0 |
Yes |
| Ziren | 1.2.3 |
No |
| Zisk | 0.15.0 |
Yes |
Examples
With SDK Installation
Install the required zkVM SDKs locally for better performance and debugging.
1. Install SDKs
Install the SP1 SDK as an example
bash scripts/sdk_installers/install_sp1_sdk.sh
2. Create Guest Program
# guest/Cargo.toml
[workspace]
[package]
name = "guest"
edition = "2024"
[dependencies]
ere-platform-sp1 = { git = "https://github.com/eth-act/ere.git" }
// guest/src/main.rs
#![no_main]
use ere_platform_sp1::{sp1_zkvm, Platform, SP1Platform};
sp1_zkvm::entrypoint!(main);
type P = SP1Platform;
pub fn main() {
// Read serialized input and deserialize it.
let input = P::read_whole_input();
let n = u64::from_le_bytes(input.as_slice().try_into().unwrap());
// Compute nth fib.
let fib_n = fib(n);
// Write serialized output.
let output = [input, fib_n.to_le_bytes().to_vec()].concat();
P::write_whole_output(&output);
}
fn fib(n: u64) -> u64 {
let mut a = 0;
let mut b = 1;
for _ in 0..n {
let c = a + b;
a = b;
b = c;
}
a
}
3. Create Host
# host/Cargo.toml
[workspace]
[package]
name = "host"
edition = "2024"
[dependencies]
ere-zkvm-interface = { git = "https://github.com/eth-act/ere.git" }
ere-sp1 = { git = "https://github.com/eth-act/ere.git" }
// host/src/main.rs
use ere_sp1::{compiler::RustRv32imaCustomized, zkvm::EreSP1};
use ere_zkvm_interface::{
compiler::Compiler,
zkvm::{Input, ProofKind, ProverResource, zkVM},
};
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let guest_directory = Path::new("path/to/guest");
// Compile guest program with SP1 customized toolchain
let compiler = RustRv32imaCustomized;
let program = compiler.compile(guest_directory)?;
// Create zkVM instance (setup/preprocessing happens here)
let zkvm = EreSP1::new(program, ProverResource::Cpu)?;
// Prepare input
// Use `with_prefixed_stdin` when guest uses `Platform::read_whole_input()`
let input = Input::new().with_prefixed_stdin(10u64.to_le_bytes().to_vec());
let expected_output = [input, 55u64.to_le_bytes()].concat();
// Execute
let (public_values, report) = zkvm.execute(&input)?;
assert_eq!(public_values, expected_output);
println!("Execution cycles: {}", report.total_num_cycles);
// Prove
let (public_values, proof, report) = zkvm.prove(&input, ProofKind::default())?;
assert_eq!(public_values, expected_output);
println!("Proving time: {:?}", report.proving_time);
// Verify
let public_values = zkvm.verify(&proof)?;
assert_eq!(public_values, expected_output);
println!("Proof verified successfully!");
Ok(())
}
Docker-Only Setup
Use Docker for zkVM operations without installing SDKs locally. Only requires Docker to be installed.
1. Create Guest Program
We use the same guest program created above.
2. Create Host
# host/Cargo.toml
[workspace]
[package]
name = "host"
edition = "2024"
[dependencies]
ere-zkvm-interface = { git = "https://github.com/eth-act/ere.git" }
ere-dockerized = { git = "https://github.com/eth-act/ere.git" }
// host/src/main.rs
use ere_dockerized::{CompilerKind, DockerizedCompiler, DockerizedzkVM, zkVMKind};
use ere_zkvm_interface::{
compiler::Compiler,
zkvm::{Input, ProofKind, ProverResource, zkVM},
};
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let guest_directory = Path::new("path/to/guest");
// Compile guest program with SP1 customized toolchain (builds Docker images if needed)
let compiler =
DockerizedCompiler::new(zkVMKind::SP1, CompilerKind::RustCustomized, guest_directory)?;
let program = compiler.compile(guest_directory)?;
// Create zkVM instance (builds Docker images if needed)
// It spawns a container that runs a gRPC server handling zkVM operations
let zkvm = DockerizedzkVM::new(zkVMKind::SP1, program, ProverResource::Cpu)?;
// Prepare input
// Use `with_prefixed_stdin` when guest uses `Platform::read_whole_input()`
let input = Input::new().with_prefixed_stdin(10u64.to_le_bytes().to_vec());
let expected_output = [input, 55u64.to_le_bytes()].concat();
// Execute
let (public_values, report) = zkvm.execute(&input)?;
assert_eq!(public_values, expected_output);
println!("Execution cycles: {}", report.total_num_cycles);
// Prove
let (public_values, proof, report) = zkvm.prove(&input, ProofKind::default())?;
assert_eq!(public_values, expected_output);
println!("Proving time: {:?}", report.proving_time);
// Verify
let public_values = zkvm.verify(&proof)?;
assert_eq!(public_values, expected_output);
println!("Proof verified successfully!");
Ok(())
}
Environment Variables
| Variable | Description | Default |
|---|---|---|
ERE_IMAGE_REGISTRY |
Specifies docker image registry of the images. When specified, it will try to pull image from the registry and possibly skip building. | `` |
ERE_FORCE_REBUILD_DOCKER_IMAGE |
Force to rebuild docker images locally even they exist, it also prevents pulling image from registry. | false |
ERE_GPU_DEVICES |
Specifies which GPU devices to use when running Docker containers for GPU-enabled zkVMs. The value is passed to Docker's --gpus flag. |
all |
ERE_DOCKER_NETWORK |
Specifies the Docker network being used (if any) so spawned ere-server-* containers will join that network. |
`` |
Example usage:
# Use all GPUs (default)
ere prove ...
# Use specific GPU devices
ERE_GPU_DEVICES="device=0" ere prove ...
# Use multiple specific GPUs
ERE_GPU_DEVICES="device=0,1" ere prove ...
# Can also signal to use any available GPUs
ERE_GPU_DEVICES="4" ere prove ...
Directory Layout
ere/
├── crates/ # Rust crates
│ ├── zkvm-interface/ # ere-zkvm-interface
│ │ └── platform/ # ere-platform-trait
│ ├── zkvm/
│ │ └── {zkvm}/ # ere-{zkvm}
│ │ └── platform/ # ere-platform-{zkvm}
│ ├── dockerized/ # ere-dockerized
│ │ ├── compiler/ # ere-compiler
│ │ └── server/ # ere-server
│ ├── io/ # ere-io
│ ├── build-utils/ # ere-build-utils
│ ├── compile-utils/ # ere-compile-utils
│ └── test-utils/ # ere-test-utils
│
├── docker/ # Dockerfile used by ere-dockerized
│ ├── Dockerfile.base # ere-base
│ └── {zkvm}/
│ ├── Dockerfile.base # ere-base-{zkvm}
│ ├── Dockerfile.compiler # ere-compiler-{zkvm}
│ └── Dockerfile.server # ere-server-{zkvm}
│
├── scripts/ # SDK installation scripts per zkVM
└── tests/ # Guest programs per zkVM for integration test
Contributing
PRs and issues are welcome!
Disclaimer
zkVMs evolve quickly; expect breaking changes. Although the API is generic, its primary target is zkEVMs, which may for example, guide the default set of precompiles.
License
Licensed under either of
- MIT license (LICENSE‑MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE‑APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.