diff --git a/.github/workflows/test-common.yml b/.github/workflows/test-common.yml
index 83f2581..492f478 100644
--- a/.github/workflows/test-common.yml
+++ b/.github/workflows/test-common.yml
@@ -16,23 +16,29 @@ jobs:
strategy:
fail-fast: false
matrix:
+ crate:
+ - ere-zkvm-interface
+ - ere-io
+ - ere-dockerized
+ - ere-compiler
+ - ere-server
+ - ere-build-utils
+ - ere-compile-utils
+ - ere-test-utils
include:
- - crate: ere-zkvm-interface
- run_test: true
+ # Test disabled (Test in per-zkVM workflows)
- crate: ere-dockerized
- run_test: false # They are run in per-zkVM workflows
- - crate: ere-io
- run_test: true
- - crate: ere-build-utils
- run_test: true
- - crate: ere-compile-utils
- run_test: true
- - crate: ere-test-utils
- run_test: true
+ skip_test: true
+ # Clippy only lib (Binary clippy in per-zkVM workflows)
+ - crate: ere-compiler
+ clippy_only_lib: true
+ - crate: ere-server
+ clippy_only_lib: true
steps:
- name: Checkout repository
uses: actions/checkout@v4
+ # Needed to run test of ere-server
- name: Install protoc
run: |
sudo apt-get update
@@ -47,11 +53,11 @@ jobs:
uses: Swatinem/rust-cache@v2
- name: Run cargo clippy
- run: cargo clippy --all-targets --package ${{ matrix.crate }} -- -D warnings
+ run: cargo clippy ${{ matrix.clippy_only_lib == true && '--lib' || '--all-targets' }} --package ${{ matrix.crate }} -- -D warnings
- name: Run cargo test on documentation
run: cargo test --doc --package ${{ matrix.crate }}
- name: Run cargo test
- if: ${{ matrix.run_test }}
- run: cargo test --release --package ${{ matrix.crate }}
+ if: ${{ matrix.skip_test != true }}
+ run: cargo test --lib --release --package ${{ matrix.crate }}
diff --git a/.github/workflows/test-zkvm.yml b/.github/workflows/test-zkvm.yml
index df6a0c9..da5f50b 100644
--- a/.github/workflows/test-zkvm.yml
+++ b/.github/workflows/test-zkvm.yml
@@ -243,11 +243,6 @@ jobs:
- name: Free up disk space
run: bash .github/scripts/free-up-disk-space.sh
- - name: Install protoc
- run: |
- sudo apt-get update
- sudo apt-get install -y protobuf-compiler
-
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
diff --git a/Cargo.lock b/Cargo.lock
index d14d125..a18913b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3969,6 +3969,7 @@ dependencies = [
"prost 0.13.5",
"prost-build 0.13.5",
"serde",
+ "tempfile",
"thiserror 2.0.12",
"tokio",
"tower-http",
diff --git a/Cargo.toml b/Cargo.toml
index 9efc3da..5a2f3c5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -38,7 +38,7 @@ resolver = "2"
[workspace.package]
version = "0.0.15"
edition = "2024"
-rust-version = "1.85"
+rust-version = "1.88"
license = "MIT OR Apache-2.0"
[workspace.lints]
diff --git a/README.md b/README.md
index 884f42e..56c21da 100644
--- a/README.md
+++ b/README.md
@@ -13,154 +13,368 @@
## Table of Contents
-* [Features](#features)
-* [Supported zkVMs](#supported-zkvms)
-* [Quick Start](#quick-start)
+- [Table of Contents](#table-of-contents)
+- [Supported Rust Versions (MSRV)](#supported-rust-versions-msrv)
+- [Overview](#overview)
+- [Architecture](#architecture)
+ - [The Interface](#the-interface)
+ - [Communication between Host and Guest](#communication-between-host-and-guest)
+ - [Reading Private Values from Host](#reading-private-values-from-host)
+ - [Writing Public Values to Host](#writing-public-values-to-host)
+- [Supported zkVMs](#supported-zkvms)
+- [Examples](#examples)
+ - [With SDK Installation](#with-sdk-installation)
+ - [1. Install SDKs](#1-install-sdks)
+ - [2. Create Guest Program](#2-create-guest-program)
+ - [3. Create Host](#3-create-host)
+ - [Docker-Only Setup](#docker-only-setup)
+ - [1. Create Guest Program](#1-create-guest-program)
+ - [2. Create Host](#2-create-host)
+- [Directory Layout](#directory-layout)
+- [Contributing](#contributing)
+- [Disclaimer](#disclaimer)
+- [License](#license)
- * [Option 1: With SDK Installation](#option-1-with-sdk-installation)
- * [Option 2: Docker-Only Setup](#option-2-docker-only-setup)
-* [Directory Layout](#directory-layout)
-* [Architecture](#architecture)
+## Supported Rust Versions (MSRV)
- * [The Interface](#the-interface)
- * [Backend Crates](#backend-crates)
- * [Input Handling](#input-handling)
-* [Contributing](#contributing)
-* [Disclaimer](#disclaimer)
-* [License](#license)
+The current MSRV (minimum supported rust version) is 1.88.
-## Features
+## Overview
-* **Unified Rust API** for compiling, executing, proving & verifying zkVM programs
-* **Pluggable back‑ends** – easily switch between different zkVMs
-* **SDK bootstrap scripts** for every supported zkVM
-* **End‑to‑end test suite** covering compilation → proof → verification for each backend
+This repository contains the following crates:
+
+- Traits
+ - [`ere-zkvm-interface`] - `Compiler` and `zkVM` traits for zkVM host operations
+ - [`ere-platform-trait`] - `Platform` trait for guest program
+- Per-zkVM implementations for [`ere-zkvm-interface`] (host)
+ - [`ere-airbender`]
+ - [`ere-jolt`]
+ - [`ere-miden`]
+ - [`ere-nexus`]
+ - [`ere-openvm`]
+ - [`ere-pico`]
+ - [`ere-risc0`]
+ - [`ere-sp1`]
+ - [`ere-ziren`]
+ - [`ere-zisk`]
+- Per-zkVM implementations for [`ere-platform-trait`] (guest)
+ - [`ere-platform-airbender`]
+ - [`ere-platform-jolt`]
+ - [`ere-platform-nexus`]
+ - [`ere-platform-openvm`]
+ - [`ere-platform-pico`]
+ - [`ere-platform-risc0`]
+ - [`ere-platform-sp1`]
+ - [`ere-platform-ziren`]
+ - [`ere-platform-zisk`]
+- [`ere-dockerized`] - Docker wrapper implementation for [`ere-zkvm-interface`] of all zkVMs
+- [`ere-io`] - Serialization utilities for host/guest IO communication
+- Internal crates
+ - [`ere-compiler`] - Cli to run `Compiler` used by [`ere-dockerized`]
+ - [`ere-server`] - Server and client for `zkVM` operations used by [`ere-dockerized`]
+ - [`ere-build-utils`] - Build-time utilities
+ - [`ere-compile-utils`] - Compilation utilities
+ - [`ere-test-utils`] - Testing utilities
+
+[`ere-zkvm-interface`]: https://github.com/eth-act/ere/tree/master/crates/zkvm-interface
+[`ere-platform-trait`]: https://github.com/eth-act/ere/tree/master/crates/zkvm-interface/platform
+[`ere-airbender`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/airbender
+[`ere-platform-airbender`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/airbender/platform
+[`ere-jolt`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/jolt
+[`ere-platform-jolt`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/jolt/platform
+[`ere-miden`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/miden
+[`ere-nexus`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/nexus
+[`ere-platform-nexus`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/nexus/platform
+[`ere-openvm`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/openvm
+[`ere-platform-openvm`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/openvm/platform
+[`ere-pico`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/pico
+[`ere-platform-pico`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/pico/platform
+[`ere-risc0`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/risc0
+[`ere-platform-risc0`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/risc0/platform
+[`ere-sp1`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/sp1
+[`ere-platform-sp1`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/sp1/platform
+[`ere-ziren`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/ziren
+[`ere-platform-ziren`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/ziren/platform
+[`ere-zisk`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/zisk
+[`ere-platform-zisk`]: https://github.com/eth-act/ere/tree/master/crates/zkvm/zisk/platform
+[`ere-dockerized`]: https://github.com/eth-act/ere/tree/master/crates/dockerized
+[`ere-compiler`]: https://github.com/eth-act/ere/tree/master/crates/dockerized/compiler
+[`ere-server`]: https://github.com/eth-act/ere/tree/master/crates/dockerized/server
+[`ere-io`]: https://github.com/eth-act/ere/tree/master/crates/io
+[`ere-build-utils`]: https://github.com/eth-act/ere/tree/master/crates/build-utils
+[`ere-compile-utils`]: https://github.com/eth-act/ere/tree/master/crates/compile-utils
+[`ere-test-utils`]: https://github.com/eth-act/ere/tree/master/crates/test-utils
+
+## Architecture
+
+### The Interface
+
+`ere-zkvm-interface` provides traits for host:
+
+- `Compiler`
+
+ Compile a guest program into a zkVM-specific artifact (typically a RISC-V ELF, or a wrapper with preprocessing data).
+
+- `zkVM`
+
+ Execute, 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:
+
+- `Platform`
+
+ Provides 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}` and `ere-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:
+
+1. `Input::new().with_prefixed_stdin(data)` for `Platform::read_whole_input()`
+
+ The `Platform` trait 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_stdin` automatically adds a LE u32 length prefix to the stdin. In the guest, `Platform::read_whole_input` will return only the actual data.
+
+ Without the length prefix, the `Platform::read_whole_input` will cause guest panic at runtime.
+
+2. `Input::new().with_stdin(data)` for zkVM-specific stdin APIs
+
+ The method `Input::with_stdin` sets 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
` 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:
+
+```rust
+OutputHashedPlatform::::write_whole_output(&large_output);
+```
## Supported zkVMs
-- SP1
-- OpenVM
-- Risc Zero
-- Jolt
-- Pico
-- Zisk
-- Nexus
-- Miden
+| zkVM | Version | GPU |
+| --------- | ---------------------------------------------------------------------- | --- |
+| Airbender | [`0.5.1`](https://github.com/matter-labs/zksync-airbender/tree/v0.5.1) | Yes |
+| Jolt | [`0.3.0-alpha`](https://github.com/a16z/jolt/tree/v0.3.0-alpha) | No |
+| Miden | [`0.19.1`](https://github.com/0xMiden/miden-vm/tree/v0.19.1) | No |
+| Nexus | [`0.3.5`](https://github.com/nexus-xyz/nexus-zkvm/tree/v0.3.5) | No |
+| OpenVM | [`1.4.1`](https://github.com/openvm-org/openvm/tree/v1.4.1) | Yes |
+| Pico | [`1.1.8`](https://github.com/brevis-network/pico/tree/v1.1.8) | No |
+| Risc0 | [`3.0.4`](https://github.com/risc0/risc0/tree/v3.0.4) | Yes |
+| SP1 | [`5.2.3`](https://github.com/succinctlabs/sp1/tree/v5.2.3) | Yes |
+| Ziren | [`1.2.2`](https://github.com/ProjectZKM/Ziren/tree/v1.2.2) | No |
+| Zisk | [`0.13.0`](https://github.com/0xPolygonHermez/zisk/tree/v0.13.0) | Yes |
-## Prerequisites
+## Examples
-The following dependencies are required:
-
-- `protobuf-compiler`
-
-## Quick Start
-
-This guide assumes you have Rust and Cargo installed. If not, please refer to the [Rust installation guide](https://www.rust-lang.org/tools/install).
-Choose your setup approach:
-
-### Option 1: With SDK Installation
+### 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
bash scripts/sdk_installers/install_sp1_sdk.sh
```
-#### 2. Add Dependencies
+#### 2. Create Guest Program
```toml
-# Cargo.toml
+# guest/Cargo.toml
+
+[workspace]
+
+[package]
+name = "guest"
+edition = "2024"
+
[dependencies]
-ere-zkvm-interface = { git = "https://github.com/eth-act/ere.git", tag = "v0.0.12" }
-ere-sp1 = { git = "https://github.com/eth-act/ere.git", tag = "v0.0.12" }
+ere-platform-sp1 = { git = "https://github.com/eth-act/ere.git" }
```
-#### 3. Compile & Prove Example
+```rust
+// 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
+
+```toml
+# 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" }
+```
```rust
-// main.rs
-use ere_sp1::{EreSP1, RV32_IM_SUCCINCT_ZKVM_ELF};
+// host/src/main.rs
+
+use ere_sp1::{compiler::RustRv32imaCustomized, zkvm::EreSP1};
use ere_zkvm_interface::{
compiler::Compiler,
zkvm::{Input, ProofKind, ProverResourceType, zkVM},
};
+use std::path::Path;
fn main() -> Result<(), Box> {
- let guest_directory = std::path::Path::new("workspace/guest");
+ let guest_directory = Path::new("path/to/guest");
- // Compile guest
- let compiler = RV32_IM_SUCCINCT_ZKVM_ELF;
+ // Compile guest program with SP1 customized toolchain
+ let compiler = RustRv32imaCustomized;
let program = compiler.compile(guest_directory)?;
- // Create zkVM instance
+ // Create zkVM instance (setup/preprocessing happens here)
let zkvm = EreSP1::new(program, ProverResourceType::Cpu)?;
- // Serialize input
- let input = Input::new(42u32.to_le_bytes().to_vec());
+ // 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::Compressed)?;
+ 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(())
}
```
-### Option 2: Docker-Only Setup
+### Docker-Only Setup
Use Docker for zkVM operations without installing SDKs locally. Only requires Docker to be installed.
-#### 1. Add Dependencies
+#### 1. Create Guest Program
+
+We use the same guest program created above.
+
+#### 2. Create Host
```toml
-# Cargo.toml
+# host/Cargo.toml
+
+[workspace]
+
+[package]
+name = "host"
+edition = "2024"
+
[dependencies]
-ere-zkvm-interface = { git = "https://github.com/eth-act/ere.git", tag = "v0.0.12" }
-ere-dockerized = { git = "https://github.com/eth-act/ere.git", tag = "v0.0.12" }
+ere-zkvm-interface = { git = "https://github.com/eth-act/ere.git" }
+ere-dockerized = { git = "https://github.com/eth-act/ere.git" }
```
-#### 2. Compile & Prove Example
-
```rust
-// main.rs
+// host/src/main.rs
+
use ere_dockerized::{CompilerKind, DockerizedCompiler, DockerizedzkVM, zkVMKind};
use ere_zkvm_interface::{
compiler::Compiler,
zkvm::{Input, ProofKind, ProverResourceType, zkVM},
};
+use std::path::Path;
fn main() -> Result<(), Box> {
- let guest_directory = std::path::Path::new("workspace/guest");
+ let guest_directory = Path::new("path/to/guest");
- // Compile guest
- let compiler = DockerizedCompiler::new(
- zkVMKind::SP1,
- CompilerKind::RustCustomized,
- std::path::Path::new("workspace"),
- );
+ // 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
+ // 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, ProverResourceType::Cpu)?;
- // Serialize input
- let input = Input::new(42u32.to_le_bytes().to_vec());
+ // 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::Compressed)?;
+ 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(())
}
@@ -169,31 +383,32 @@ fn main() -> Result<(), Box> {
## Directory Layout
```
-crates/
- zkvm-interface/ ← core traits & types
- zkvm/{backend}/ ← backend adapters (sp1, openvm, …)
-tests/ ← guest programs & integration tests
-scripts/sdk_installers/ ← SDK install helpers
-docker/ ← Dockerfiles & build contexts
+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
```
-## Architecture
-
-### The Interface
-
-`ere-zkvm-interface` exposes two core traits:
-
-* **Compiler** – compile a guest project into the correct zkVM artifact. For most this will be a RISCV ELF binary or some type that wraps it and includes extra metadata such as a proving and verifying key.
-* **zkVM** – execute, prove & verify that artifact. A zkVM instance is created for specific `program`, where the `program` comes from the `Compiler`.
-
-### Backend Crates
-
-Each `ere-{backend}` crate implements the above traits for its zkVM.
-
-### Input Handling
-
-The input is opaque to `zkVM` and will be passed as is, de/serialization needed to be handled by guest/host themselves.
-
## Contributing
PRs and issues are welcome!
diff --git a/crates/dockerized/server/Cargo.toml b/crates/dockerized/server/Cargo.toml
index ca3ad7c..6ed4aff 100644
--- a/crates/dockerized/server/Cargo.toml
+++ b/crates/dockerized/server/Cargo.toml
@@ -34,16 +34,16 @@ ere-zisk = { workspace = true, features = ["zkvm"], optional = true }
ere-zkvm-interface = { workspace = true, features = ["clap"] }
[dev-dependencies]
+prost-build.workspace = true
+tempfile.workspace = true
+twirp-build.workspace = true
[lints]
workspace = true
-[build-dependencies]
-prost-build.workspace = true
-twirp-build.workspace = true
-
[features]
-default = []
+default = ["client"]
+client = []
server = ["dep:clap", "dep:tower-http", "dep:tracing", "dep:tracing-subscriber", "tokio/macros", "tokio/rt-multi-thread", "tokio/signal"]
# zkVM
diff --git a/crates/dockerized/server/build.rs b/crates/dockerized/server/build.rs
deleted file mode 100644
index 4c0c556..0000000
--- a/crates/dockerized/server/build.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-fn main() -> Result<(), Box> {
- prost_build::Config::new()
- .type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]") // enable support for JSON encoding
- .service_generator(twirp_build::service_generator())
- .compile_protos(&["./proto/api.proto"], &["./proto"])
- .expect("error compiling protos");
- Ok(())
-}
diff --git a/crates/dockerized/server/src/api.rs b/crates/dockerized/server/src/api.rs
new file mode 100644
index 0000000..c070e95
--- /dev/null
+++ b/crates/dockerized/server/src/api.rs
@@ -0,0 +1,278 @@
+// This file is @generated by prost-build.
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ExecuteRequest {
+ #[prost(bytes = "vec", tag = "1")]
+ pub input_stdin: ::prost::alloc::vec::Vec,
+ #[prost(bytes = "vec", optional, tag = "2")]
+ pub input_proofs: ::core::option::Option<::prost::alloc::vec::Vec>,
+}
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ExecuteResponse {
+ #[prost(oneof = "execute_response::Result", tags = "1, 2")]
+ pub result: ::core::option::Option,
+}
+/// Nested message and enum types in `ExecuteResponse`.
+pub mod execute_response {
+ #[derive(serde::Serialize, serde::Deserialize)]
+ #[derive(Clone, PartialEq, ::prost::Oneof)]
+ pub enum Result {
+ #[prost(message, tag = "1")]
+ Ok(super::ExecuteOk),
+ #[prost(string, tag = "2")]
+ Err(::prost::alloc::string::String),
+ }
+}
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ExecuteOk {
+ #[prost(bytes = "vec", tag = "1")]
+ pub public_values: ::prost::alloc::vec::Vec,
+ #[prost(bytes = "vec", tag = "2")]
+ pub report: ::prost::alloc::vec::Vec,
+}
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ProveRequest {
+ #[prost(bytes = "vec", tag = "1")]
+ pub input_stdin: ::prost::alloc::vec::Vec,
+ #[prost(bytes = "vec", optional, tag = "2")]
+ pub input_proofs: ::core::option::Option<::prost::alloc::vec::Vec>,
+ #[prost(enumeration = "ProofKind", tag = "3")]
+ pub proof_kind: i32,
+}
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ProveResponse {
+ #[prost(oneof = "prove_response::Result", tags = "1, 2")]
+ pub result: ::core::option::Option,
+}
+/// Nested message and enum types in `ProveResponse`.
+pub mod prove_response {
+ #[derive(serde::Serialize, serde::Deserialize)]
+ #[derive(Clone, PartialEq, ::prost::Oneof)]
+ pub enum Result {
+ #[prost(message, tag = "1")]
+ Ok(super::ProveOk),
+ #[prost(string, tag = "2")]
+ Err(::prost::alloc::string::String),
+ }
+}
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct ProveOk {
+ #[prost(bytes = "vec", tag = "1")]
+ pub public_values: ::prost::alloc::vec::Vec,
+ #[prost(bytes = "vec", tag = "2")]
+ pub proof: ::prost::alloc::vec::Vec,
+ #[prost(bytes = "vec", tag = "3")]
+ pub report: ::prost::alloc::vec::Vec,
+}
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct VerifyRequest {
+ #[prost(bytes = "vec", tag = "1")]
+ pub proof: ::prost::alloc::vec::Vec,
+ #[prost(enumeration = "ProofKind", tag = "2")]
+ pub proof_kind: i32,
+}
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct VerifyResponse {
+ #[prost(oneof = "verify_response::Result", tags = "1, 2")]
+ pub result: ::core::option::Option,
+}
+/// Nested message and enum types in `VerifyResponse`.
+pub mod verify_response {
+ #[derive(serde::Serialize, serde::Deserialize)]
+ #[derive(Clone, PartialEq, ::prost::Oneof)]
+ pub enum Result {
+ #[prost(message, tag = "1")]
+ Ok(super::VerifyOk),
+ #[prost(string, tag = "2")]
+ Err(::prost::alloc::string::String),
+ }
+}
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct VerifyOk {
+ #[prost(bytes = "vec", tag = "1")]
+ pub public_values: ::prost::alloc::vec::Vec,
+}
+#[derive(serde::Serialize, serde::Deserialize)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
+#[repr(i32)]
+pub enum ProofKind {
+ Compressed = 0,
+ Groth16 = 1,
+}
+impl ProofKind {
+ /// String value of the enum field names used in the ProtoBuf definition.
+ ///
+ /// The values are not transformed in any way and thus are considered stable
+ /// (if the ProtoBuf definition does not change) and safe for programmatic use.
+ pub fn as_str_name(&self) -> &'static str {
+ match self {
+ Self::Compressed => "Compressed",
+ Self::Groth16 => "Groth16",
+ }
+ }
+ /// Creates an enum from field names used in the ProtoBuf definition.
+ pub fn from_str_name(value: &str) -> ::core::option::Option {
+ match value {
+ "Compressed" => Some(Self::Compressed),
+ "Groth16" => Some(Self::Groth16),
+ _ => None,
+ }
+ }
+}
+pub use twirp;
+#[twirp::async_trait::async_trait]
+pub trait ZkvmService: Send + Sync {
+ async fn execute(
+ &self,
+ req: twirp::Request,
+ ) -> twirp::Result>;
+ async fn prove(
+ &self,
+ req: twirp::Request,
+ ) -> twirp::Result>;
+ async fn verify(
+ &self,
+ req: twirp::Request,
+ ) -> twirp::Result>;
+}
+#[twirp::async_trait::async_trait]
+impl ZkvmService for std::sync::Arc
+where
+ T: ZkvmService + Sync + Send,
+{
+ async fn execute(
+ &self,
+ req: twirp::Request,
+ ) -> twirp::Result> {
+ T::execute(&*self, req).await
+ }
+ async fn prove(
+ &self,
+ req: twirp::Request,
+ ) -> twirp::Result> {
+ T::prove(&*self, req).await
+ }
+ async fn verify(
+ &self,
+ req: twirp::Request,
+ ) -> twirp::Result> {
+ T::verify(&*self, req).await
+ }
+}
+pub fn router(api: T) -> twirp::Router
+where
+ T: ZkvmService + Clone + Send + Sync + 'static,
+{
+ twirp::details::TwirpRouterBuilder::new("/api.ZkvmService", api)
+ .route(
+ "/Execute",
+ |api: T, req: twirp::Request| async move {
+ api.execute(req).await
+ },
+ )
+ .route(
+ "/Prove",
+ |api: T, req: twirp::Request| async move {
+ api.prove(req).await
+ },
+ )
+ .route(
+ "/Verify",
+ |api: T, req: twirp::Request| async move {
+ api.verify(req).await
+ },
+ )
+ .build()
+}
+#[twirp::async_trait::async_trait]
+impl ZkvmService for twirp::client::Client {
+ async fn execute(
+ &self,
+ req: twirp::Request,
+ ) -> twirp::Result> {
+ self.request("api.ZkvmService/Execute", req).await
+ }
+ async fn prove(
+ &self,
+ req: twirp::Request,
+ ) -> twirp::Result> {
+ self.request("api.ZkvmService/Prove", req).await
+ }
+ async fn verify(
+ &self,
+ req: twirp::Request,
+ ) -> twirp::Result> {
+ self.request("api.ZkvmService/Verify", req).await
+ }
+}
+#[allow(dead_code)]
+pub mod handler {
+ use super::*;
+ pub struct ZkvmServiceHandler {
+ inner: std::sync::Arc,
+ }
+ impl ZkvmServiceHandler {
+ #[allow(clippy::new_ret_no_self)]
+ pub fn new(inner: M) -> Self {
+ Self {
+ inner: std::sync::Arc::new(inner),
+ }
+ }
+ }
+ #[twirp::async_trait::async_trait]
+ impl twirp::client::DirectHandler for ZkvmServiceHandler {
+ fn service(&self) -> &str {
+ "api.ZkvmService"
+ }
+ async fn handle(
+ &self,
+ method: &str,
+ req: twirp::reqwest::Request,
+ ) -> twirp::Result {
+ match method {
+ "Execute" => {
+ twirp::details::encode_response(
+ self
+ .inner
+ .execute(twirp::details::decode_request(req).await?)
+ .await?,
+ )
+ }
+ "Prove" => {
+ twirp::details::encode_response(
+ self
+ .inner
+ .prove(twirp::details::decode_request(req).await?)
+ .await?,
+ )
+ }
+ "Verify" => {
+ twirp::details::encode_response(
+ self
+ .inner
+ .verify(twirp::details::decode_request(req).await?)
+ .await?,
+ )
+ }
+ _ => {
+ Err(
+ twirp::bad_route(
+ format!(
+ "unknown rpc `{method}` for service `{}`, url: {:?}",
+ "api.ZkvmService", req.url()
+ ),
+ ),
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/crates/dockerized/server/src/lib.rs b/crates/dockerized/server/src/lib.rs
index d2cef53..cd102fd 100644
--- a/crates/dockerized/server/src/lib.rs
+++ b/crates/dockerized/server/src/lib.rs
@@ -1,9 +1,11 @@
-pub mod client;
+#[rustfmt::skip]
+pub mod api;
-#[allow(dead_code)]
-pub(crate) mod api {
- include!(concat!(env!("OUT_DIR"), "/api.rs"));
-}
+#[cfg(feature = "client")]
+pub mod client;
#[cfg(feature = "server")]
pub mod server;
+
+#[cfg(test)]
+mod test;
diff --git a/crates/dockerized/server/src/test.rs b/crates/dockerized/server/src/test.rs
new file mode 100644
index 0000000..85d4891
--- /dev/null
+++ b/crates/dockerized/server/src/test.rs
@@ -0,0 +1,28 @@
+use std::{env, fs, path::PathBuf};
+
+/// To sync generated `api.rs`, run:
+///
+/// ```
+/// cargo test --package ere-server --no-default-features --lib -- test::api_generation --exact
+/// ```
+#[test]
+fn api_generation() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+
+ prost_build::Config::new()
+ .out_dir(tempdir.path())
+ .type_attribute(".", "#[derive(serde::Serialize, serde::Deserialize)]") // enable support for JSON encoding
+ .service_generator(twirp_build::service_generator())
+ .compile_protos(&[dir.join("proto").join("api.proto")], &[dir.join("proto")])
+ .unwrap();
+
+ let latest = tempdir.path().join("api.rs");
+ let current = dir.join("src").join("api.rs");
+
+ // If it's in CI env, don't overwrite but only check if it's up-to-date.
+ if env::var_os("GITHUB_ACTIONS").is_none() {
+ fs::copy(&latest, ¤t).unwrap();
+ }
+ assert_eq!(fs::read(&latest).unwrap(), fs::read(¤t).unwrap());
+}
diff --git a/crates/dockerized/src/lib.rs b/crates/dockerized/src/lib.rs
index 547e1f8..8d3363a 100644
--- a/crates/dockerized/src/lib.rs
+++ b/crates/dockerized/src/lib.rs
@@ -49,7 +49,7 @@
//! let zkvm = DockerizedzkVM::new(zkvm_kind, program, resource)?;
//!
//! // Serialize input
-//! let input = Input::new(42u32.to_le_bytes().to_vec());
+//! let input = Input::new().with_stdin(42u32.to_le_bytes().to_vec());
//!
//! // Execute program
//! let (public_values, execution_report) = zkvm.execute(&input)?;
diff --git a/crates/dockerized/src/zkvm.rs b/crates/dockerized/src/zkvm.rs
index 8720420..80c20d3 100644
--- a/crates/dockerized/src/zkvm.rs
+++ b/crates/dockerized/src/zkvm.rs
@@ -406,7 +406,7 @@ mod test {
"basic",
[BasicProgram::::valid_test_case().into_output_sha256()],
[
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input()
]
);
@@ -420,7 +420,7 @@ mod test {
"basic",
[BasicProgram::::valid_test_case()],
[
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input()
]
);
@@ -434,7 +434,7 @@ mod test {
"basic",
[BasicProgram::::valid_test_case()],
[
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input()
]
);
@@ -448,7 +448,7 @@ mod test {
"basic",
[BasicProgram::::valid_test_case().into_output_sha256()],
[
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input()
]
);
@@ -462,7 +462,7 @@ mod test {
"basic",
[BasicProgram::::valid_test_case()],
[
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input()
]
);
@@ -476,7 +476,7 @@ mod test {
"basic",
[BasicProgram::::valid_test_case()],
[
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input()
]
);
@@ -490,7 +490,7 @@ mod test {
"basic",
[BasicProgram::::valid_test_case()],
[
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input()
]
);
@@ -504,7 +504,7 @@ mod test {
"basic",
[BasicProgram::::valid_test_case()],
[
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input()
]
);
@@ -518,7 +518,7 @@ mod test {
"basic_rust",
[BasicProgram::::valid_test_case()],
[
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input()
]
);
diff --git a/crates/io/src/lib.rs b/crates/io/src/lib.rs
index 6c603b9..f45efec 100644
--- a/crates/io/src/lib.rs
+++ b/crates/io/src/lib.rs
@@ -4,11 +4,11 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![no_std]
+extern crate alloc;
+
use alloc::vec::Vec;
use core::{error::Error, fmt::Debug};
-extern crate alloc;
-
#[cfg(feature = "serde")]
pub mod serde;
diff --git a/crates/test-utils/src/guest.rs b/crates/test-utils/src/guest.rs
deleted file mode 100644
index 03670de..0000000
--- a/crates/test-utils/src/guest.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub use sha2::Sha256;
diff --git a/crates/test-utils/src/host.rs b/crates/test-utils/src/host.rs
index 2c6a876..7fdbecc 100644
--- a/crates/test-utils/src/host.rs
+++ b/crates/test-utils/src/host.rs
@@ -84,7 +84,7 @@ impl Deref for ProgramTestCase {
impl TestCase for ProgramTestCase {
fn input(&self) -> Input {
- Input::new(P::Io::serialize_input(&self.input).unwrap())
+ Input::new().with_prefixed_stdin(P::Io::serialize_input(&self.input).unwrap())
}
fn assert_output(&self, public_values: &[u8]) {
diff --git a/crates/test-utils/src/lib.rs b/crates/test-utils/src/lib.rs
index fc23969..ff5c2f2 100644
--- a/crates/test-utils/src/lib.rs
+++ b/crates/test-utils/src/lib.rs
@@ -2,7 +2,6 @@
extern crate alloc;
-pub mod guest;
pub mod program;
#[cfg(feature = "host")]
diff --git a/crates/test-utils/src/program.rs b/crates/test-utils/src/program.rs
index 5a8a47e..6f6dd27 100644
--- a/crates/test-utils/src/program.rs
+++ b/crates/test-utils/src/program.rs
@@ -1,5 +1,6 @@
use ere_io::Io;
-use ere_platform_trait::Platform;
+use ere_platform_trait::{OutputHashedPlatform, Platform};
+use sha2::Sha256;
pub mod basic;
@@ -16,4 +17,8 @@ pub trait Program {
let output_bytes = Self::Io::serialize_output(&output).unwrap();
P::write_whole_output(&output_bytes);
}
+
+ fn run_output_sha256() {
+ Self::run::>()
+ }
}
diff --git a/crates/zkvm-interface/platform/src/lib.rs b/crates/zkvm-interface/platform/src/lib.rs
index 2d17ce4..30365dd 100644
--- a/crates/zkvm-interface/platform/src/lib.rs
+++ b/crates/zkvm-interface/platform/src/lib.rs
@@ -3,15 +3,20 @@
extern crate alloc;
use alloc::vec::Vec;
+use core::{marker::PhantomData, ops::Deref};
-pub mod output_hasher;
+pub use digest::Digest;
/// Platform dependent methods.
pub trait Platform {
/// Reads the whole input at once from host.
///
+ /// The stdin passed must have a LE u32 length prefix, because some zkVMs
+ /// don't provide access to the stdin length.
+ /// Use `Input::new().with_prefixed_stdin(stdin)` for convenience.
+ ///
/// Note that this function should only be called once.
- fn read_whole_input() -> Vec;
+ fn read_whole_input() -> impl Deref;
/// Writes the whole output at once to host.
///
@@ -54,3 +59,78 @@ pub trait Platform {
t
}
}
+
+/// Wrapper for `Platform` implementation that hashes output before calling
+/// the inner `P::write_whole_output`.
+pub struct OutputHashedPlatform(PhantomData<(P, D)>);
+
+impl
Platform for OutputHashedPlatform
+where
+ P: Platform,
+ D: Digest,
+{
+ #[inline]
+ fn read_whole_input() -> impl Deref {
+ P::read_whole_input()
+ }
+
+ #[inline]
+ fn write_whole_output(output: &[u8]) {
+ P::write_whole_output(&D::digest(output));
+ }
+
+ #[inline]
+ fn print(message: &str) {
+ P::print(message);
+ }
+
+ #[inline]
+ fn cycle_count() -> u64 {
+ P::cycle_count()
+ }
+
+ #[inline]
+ fn cycle_scope_start(name: &str) {
+ P::cycle_scope_start(name)
+ }
+
+ #[inline]
+ fn cycle_scope_end(name: &str) {
+ P::cycle_scope_end(name)
+ }
+
+ #[inline]
+ fn cycle_scope(name: &str, f: impl FnOnce() -> T) -> T {
+ P::cycle_scope(name, f)
+ }
+}
+
+/// Stdin with a LE u32 length prefix.
+///
+/// Dereferencing it returns slice to the actual data.
+pub struct LengthPrefixedStdin(Vec);
+
+impl Deref for LengthPrefixedStdin {
+ type Target = [u8];
+
+ fn deref(&self) -> &Self::Target {
+ &self.0[4..]
+ }
+}
+
+impl LengthPrefixedStdin {
+ pub fn new(stdin: Vec) -> Self {
+ assert!(
+ stdin.len() >= 4,
+ "stdin must have a LE u32 length prefix; use Input::with_prefixed_length(stdin) on the host side"
+ );
+ let len = u32::from_le_bytes(stdin[..4].try_into().unwrap()) as usize;
+ assert_eq!(
+ len,
+ stdin.len() - 4,
+ "Length mismatch: stdin length prefix indicated {len} bytes, but got {} bytes; use Input::with_prefixed_length(stdin) on the host side",
+ stdin.len() - 4
+ );
+ Self(stdin)
+ }
+}
diff --git a/crates/zkvm-interface/platform/src/output_hasher.rs b/crates/zkvm-interface/platform/src/output_hasher.rs
deleted file mode 100644
index 58c4b7b..0000000
--- a/crates/zkvm-interface/platform/src/output_hasher.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-use core::{marker::PhantomData, ops::Deref};
-use digest::{
- Digest, Output, OutputSizeUser,
- generic_array::{ArrayLength, GenericArray},
-};
-
-pub use digest;
-
-/// A hasher that given the output, returns a hash of it.
-pub trait OutputHasher {
- type Hash<'a>: Deref;
-
- fn output_hash(output: &[u8]) -> Self::Hash<'_>;
-}
-
-/// A hasher that given the output, returns a fixed-size hash of it.
-pub trait FixedOutputHasher: OutputHasher + OutputSizeUser {}
-
-impl FixedOutputHasher for T {}
-
-/// A marker used to mark [`IdentityOutput`] to accept unsized output.
-pub struct Unsized;
-
-/// [`OutputHasher`] implementation that returns output as is.
-///
-/// By setting generic `U = Unsized` it takes output with any size.
-///
-/// By setting generic `U = typenum::U{SIZE}` it expects the output to match
-/// the `SIZE`.
-pub struct IdentityOutput(PhantomData);
-
-impl OutputHasher for IdentityOutput {
- type Hash<'a> = &'a [u8];
-
- fn output_hash(output: &[u8]) -> Self::Hash<'_> {
- output
- }
-}
-
-impl + 'static> OutputSizeUser for IdentityOutput {
- type OutputSize = U;
-}
-
-impl + 'static> OutputHasher for IdentityOutput {
- type Hash<'a> = GenericArray;
-
- fn output_hash(output: &[u8]) -> Self::Hash<'_> {
- assert!(
- output.len() == Self::output_size(),
- "output length should be equal to {}",
- Self::output_size()
- );
- let mut hash = Output::::default();
- hash.copy_from_slice(output);
- hash
- }
-}
-
-/// [`OutputHasher`] implementation that returns output with 0s padding.
-///
-/// By setting generic `U = typenum::U{SIZE}` it expects the output to be less
-/// than or equal to the `SIZE`.
-pub struct PaddedOutput(PhantomData);
-
-impl + 'static> OutputSizeUser for PaddedOutput {
- type OutputSize = U;
-}
-
-impl + 'static> OutputHasher for PaddedOutput {
- type Hash<'a> = GenericArray;
-
- fn output_hash(output: &[u8]) -> Self::Hash<'_> {
- assert!(
- output.len() <= Self::output_size(),
- "output length should be less than or equal to {}",
- Self::output_size()
- );
- let mut hash = Output::::default();
- hash[..output.len()].copy_from_slice(output);
- hash
- }
-}
-
-impl OutputHasher for D {
- type Hash<'a> = Output;
-
- fn output_hash(output: &[u8]) -> Self::Hash<'_> {
- D::digest(output)
- }
-}
diff --git a/crates/zkvm-interface/src/zkvm.rs b/crates/zkvm-interface/src/zkvm.rs
index f973d64..0b48e33 100644
--- a/crates/zkvm-interface/src/zkvm.rs
+++ b/crates/zkvm-interface/src/zkvm.rs
@@ -22,10 +22,10 @@ pub struct Input {
}
impl Input {
- /// Creates a new `Input` with the given stdin.
- pub fn new(stdin: Vec) -> Self {
+ /// Creates a new `Input` with the empty stdin.
+ pub fn new() -> Self {
Self {
- stdin,
+ stdin: Vec::new(),
proofs: None,
}
}
@@ -49,6 +49,23 @@ impl Input {
})
}
+ /// Sets stdin and returns a new `Input`.
+ pub fn with_stdin(mut self, stdin: Vec) -> Self {
+ self.stdin = stdin;
+ self
+ }
+
+ /// Sets stdin with a LE u32 length prefix and returns a new `Input`.
+ ///
+ /// The `Platform::read_whole_input` requires stdin to have a LE u32 length
+ /// prefix for efficiency reason.
+ pub fn with_prefixed_stdin(mut self, stdin: Vec) -> Self {
+ self.stdin = Vec::with_capacity(4 + stdin.len());
+ self.stdin.extend((stdin.len() as u32).to_le_bytes());
+ self.stdin.extend(stdin);
+ self
+ }
+
/// Serializes the given proofs and returns a new `Input` with them set.
///
/// Consumes `self` and returns an error if serialization fails.
diff --git a/crates/zkvm/airbender/platform/src/lib.rs b/crates/zkvm/airbender/platform/src/lib.rs
index d405c2f..4fdd496 100644
--- a/crates/zkvm/airbender/platform/src/lib.rs
+++ b/crates/zkvm/airbender/platform/src/lib.rs
@@ -3,42 +3,39 @@
extern crate alloc;
use alloc::vec::Vec;
-use core::{array, iter::repeat_with, marker::PhantomData};
-use ere_platform_trait::output_hasher::FixedOutputHasher;
+use core::{array, iter::repeat_with, ops::Deref};
pub use airbender_riscv_common as riscv_common;
-pub use ere_platform_trait::{
- Platform,
- output_hasher::{IdentityOutput, PaddedOutput, digest::typenum::U32},
-};
+pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
/// Airbender [`Platform`] implementation.
///
-/// Because Airbender only support public values up to 32 bytes, so
-/// - If the guest has output bytes more than 32 bytes, it should use a
-/// cryptographic hash function for the generic `H` (for example `Sha256`).
-/// - If the guest has output bytes less than 32 bytes, it should use
-/// [`PaddedOutput`] for the generic `H`
-pub struct AirbenderPlatform(PhantomData);
+/// Note that the maximum output size is 32 bytes, and output less than 32
+/// bytes will be padded to 32 bytes.
+pub struct AirbenderPlatform;
-impl> Platform for AirbenderPlatform {
- fn read_whole_input() -> Vec {
+impl Platform for AirbenderPlatform {
+ fn read_whole_input() -> impl Deref {
let len = riscv_common::csr_read_word() as usize;
repeat_with(riscv_common::csr_read_word)
.take(len.div_ceil(4))
.flat_map(u32::to_le_bytes)
.take(len)
- .collect()
+ .collect::>()
}
fn write_whole_output(output: &[u8]) {
- let hash = H::output_hash(output);
- let words = array::from_fn(|i| u32::from_le_bytes(array::from_fn(|j| hash[4 * i + j])));
+ assert!(
+ output.len() <= 32,
+ "Maximum output size is 32 bytes, got {} bytes",
+ output.len()
+ );
+ let words = array::from_fn(|i| u32::from_le_bytes(array::from_fn(|j| output[4 * i + j])));
riscv_common::zksync_os_finish_success(&words);
}
- fn print(message: &str) {
+ fn print(_message: &str) {
#[cfg(feature = "uart")]
- core::fmt::Write::write_str(&mut riscv_common::QuasiUART::new(), message).unwrap();
+ core::fmt::Write::write_str(&mut riscv_common::QuasiUART::new(), _message).unwrap();
}
}
diff --git a/crates/zkvm/airbender/src/lib.rs b/crates/zkvm/airbender/src/lib.rs
index a53c4ec..30576af 100644
--- a/crates/zkvm/airbender/src/lib.rs
+++ b/crates/zkvm/airbender/src/lib.rs
@@ -1,3 +1,48 @@
+//! Airbender [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # Requirements
+//!
+//! To install all requirements, run [`install_airbender_sdk.sh`] from the Ere
+//! repository at the same git revision as your `ere-airbender` dependency.
+//!
+//! To install `airbender-cli` with GPU proving support, make sure CUDA 12.9 is
+//! installed, and run [`install_airbender_sdk.sh`] with env `CUDA=1` set.
+//!
+//! ## `Compiler` requirements
+//!
+//! The `Compiler` implementation requires external tools installed and
+//! available in `PATH`:
+//!
+//! - `rust-objcopy` - Used by compiler to convert ELF to binary
+//!
+//! ## `zkVM` requirements
+//!
+//! The `zkVM` implementation requires external tools installed and available in
+//! `PATH`:
+//!
+//! - Installation via [`install_airbender_sdk.sh`] - `airbender-cli` used by
+//! `zkVM::execute` and `zkVM::prove`
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target |
+//! | ------------- | :------: | ----------------------------- |
+//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | Yes |
+//! | `Network` | No |
+//!
+//! [`install_airbender_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_airbender_sdk.sh
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/airbender/src/zkvm.rs b/crates/zkvm/airbender/src/zkvm.rs
index bb03d38..501b513 100644
--- a/crates/zkvm/airbender/src/zkvm.rs
+++ b/crates/zkvm/airbender/src/zkvm.rs
@@ -149,7 +149,7 @@ mod tests {
let zkvm = EreAirbender::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.execute(&input).unwrap_err();
@@ -171,7 +171,7 @@ mod tests {
let zkvm = EreAirbender::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.prove(&input, ProofKind::default()).unwrap_err();
diff --git a/crates/zkvm/airbender/src/zkvm/sdk.rs b/crates/zkvm/airbender/src/zkvm/sdk.rs
index d14d202..59675a2 100644
--- a/crates/zkvm/airbender/src/zkvm/sdk.rs
+++ b/crates/zkvm/airbender/src/zkvm/sdk.rs
@@ -4,7 +4,7 @@ use airbender_execution_utils::{
universal_circuit_verifier_vk, verify_recursion_log_23_layer,
};
use ere_zkvm_interface::zkvm::{CommonError, PublicValues};
-use std::{array, fs, io::BufRead, iter, process::Command};
+use std::{array, fs, io::BufRead, process::Command};
use tempfile::tempdir;
/// Verification key hash chain.
@@ -217,8 +217,8 @@ impl AirbenderSdk {
/// Encode input with length prefixed to hex string for `airbender-cli`.
fn encode_input(input: &[u8]) -> String {
- iter::once((input.len() as u32).to_le_bytes().as_slice())
- .chain(input.chunks(4))
+ input
+ .chunks(4)
.map(|chunk| {
let mut bytes = [0u8; 4];
bytes[..chunk.len()].copy_from_slice(chunk);
diff --git a/crates/zkvm/jolt/platform/src/lib.rs b/crates/zkvm/jolt/platform/src/lib.rs
index 6f23650..8fc441a 100644
--- a/crates/zkvm/jolt/platform/src/lib.rs
+++ b/crates/zkvm/jolt/platform/src/lib.rs
@@ -2,14 +2,9 @@
extern crate alloc;
-use alloc::vec::Vec;
-use core::{marker::PhantomData, slice};
-use ere_platform_trait::output_hasher::OutputHasher;
+use core::{marker::PhantomData, ops::Deref};
-pub use ere_platform_trait::{
- Platform,
- output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
-};
+pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
pub use jolt_sdk as jolt;
// FIXME: Because the crate `jolt-common` is not `no_std` compatible, so we have
@@ -70,30 +65,37 @@ impl JoltMemoryConfig for DefaulJoltMemoryConfig {
}
/// Jolt [`Platform`] implementation.
-pub struct JoltPlatform(PhantomData<(C, H)>);
+pub struct JoltPlatform(PhantomData);
-impl Platform for JoltPlatform {
- fn read_whole_input() -> Vec {
+impl Platform for JoltPlatform {
+ fn read_whole_input() -> impl Deref {
let memory_layout = C::memory_layout();
let input_ptr = memory_layout.input_start as *const u8;
let max_input_len = memory_layout.max_input_size as usize;
- let input_slice = unsafe { slice::from_raw_parts(input_ptr, max_input_len) };
- let (input, _) = jolt::postcard::take_from_bytes(input_slice).unwrap();
- input
+ assert!(max_input_len > 4);
+ let len_bytes = unsafe { core::slice::from_raw_parts(input_ptr, 4) };
+ let len = u32::from_le_bytes(len_bytes.try_into().unwrap()) as usize;
+ assert!(
+ len <= max_input_len - 4,
+ "Maximum input size is {} bytes, got {len}",
+ max_input_len - 4,
+ );
+ unsafe { core::slice::from_raw_parts(input_ptr.add(4), len) }.to_vec()
}
fn write_whole_output(output: &[u8]) {
- let hash = H::output_hash(output);
let memory_layout = C::memory_layout();
let output_ptr = memory_layout.output_start as *mut u8;
let max_output_len = memory_layout.max_output_size as usize;
- let output_slice = unsafe { core::slice::from_raw_parts_mut(output_ptr, max_output_len) };
- jolt::postcard::to_slice(&*hash, output_slice).unwrap_or_else(|err| match err {
- jolt::postcard::Error::SerializeBufferFull => {
- panic!("Maximum output size is {max_output_len} bytes")
- }
- err => panic!("`postcard::to_slice` failed: {err:?}"),
- });
+ let len = output.len();
+ assert!(
+ len <= max_output_len - 4,
+ "Maximum output size is {} bytes, got {len}",
+ max_output_len - 4,
+ );
+ let output_slice = unsafe { core::slice::from_raw_parts_mut(output_ptr, len + 4) };
+ output_slice[..4].copy_from_slice(&(output.len() as u32).to_le_bytes());
+ output_slice[4..].copy_from_slice(&output);
}
fn print(message: &str) {
diff --git a/crates/zkvm/jolt/src/compiler/rust_rv64imac.rs b/crates/zkvm/jolt/src/compiler/rust_rv64imac.rs
index c350dc5..3099aed 100644
--- a/crates/zkvm/jolt/src/compiler/rust_rv64imac.rs
+++ b/crates/zkvm/jolt/src/compiler/rust_rv64imac.rs
@@ -78,6 +78,6 @@ mod tests {
let program = RustRv64imac.compile(&guest_directory).unwrap();
let zkvm = EreJolt::new(program, ProverResourceType::Cpu).unwrap();
- zkvm.execute(&Input::default()).unwrap();
+ zkvm.execute(&Input::new()).unwrap();
}
}
diff --git a/crates/zkvm/jolt/src/lib.rs b/crates/zkvm/jolt/src/lib.rs
index a53c4ec..fe4f694 100644
--- a/crates/zkvm/jolt/src/lib.rs
+++ b/crates/zkvm/jolt/src/lib.rs
@@ -1,3 +1,36 @@
+//! Jolt [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # Requirements
+//!
+//! To install all requirements, run [`install_jolt_sdk.sh`] from the Ere
+//! repository at the same git revision as your `ere-jolt` dependency.
+//!
+//! ## `Compiler` requirements
+//!
+//! - `jolt`
+//! - Install custom Rust toolchain via `jolt install-toolchain` - Used by `RustRv64imaCustomized`
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target | Note |
+//! | ------------------------- | :------: | ------------------------------ | ------------------ |
+//! | `RustRv64imacCustomized` | Rust | `riscv64imac-jolt-zkvm-elf` | With `std` support |
+//! | `RustRv64imac` | Rust | `riscv64imac-unknown-none-elf` | |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | No |
+//! | `Network` | No |
+//!
+//! [`install_jolt_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_jolt_sdk.sh
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/jolt/src/zkvm.rs b/crates/zkvm/jolt/src/zkvm.rs
index 6f37bd5..14d99fb 100644
--- a/crates/zkvm/jolt/src/zkvm.rs
+++ b/crates/zkvm/jolt/src/zkvm.rs
@@ -153,7 +153,7 @@ mod tests {
let zkvm = EreJolt::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.execute(&input).unwrap_err();
@@ -179,7 +179,7 @@ mod tests {
let _guard = PROVE_LOCK.lock().unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.prove(&input, ProofKind::default()).unwrap_err();
diff --git a/crates/zkvm/jolt/src/zkvm/error.rs b/crates/zkvm/jolt/src/zkvm/error.rs
index f6a7f3e..58c6c5f 100644
--- a/crates/zkvm/jolt/src/zkvm/error.rs
+++ b/crates/zkvm/jolt/src/zkvm/error.rs
@@ -7,6 +7,9 @@ pub enum Error {
#[error(transparent)]
CommonError(#[from] CommonError),
+ #[error("Output is expected to have length prefix")]
+ InvalidOutput,
+
// Execute
#[error("Execution panics")]
ExecutionPanic,
diff --git a/crates/zkvm/jolt/src/zkvm/sdk.rs b/crates/zkvm/jolt/src/zkvm/sdk.rs
index b48d6c3..30b5614 100644
--- a/crates/zkvm/jolt/src/zkvm/sdk.rs
+++ b/crates/zkvm/jolt/src/zkvm/sdk.rs
@@ -1,6 +1,6 @@
use crate::zkvm::Error;
-use core::cmp::min;
-use ere_zkvm_interface::zkvm::{CommonError, PublicValues};
+use core::{array::from_fn, cmp::min};
+use ere_zkvm_interface::zkvm::PublicValues;
use jolt_ark_serialize::{self as ark_serialize, CanonicalDeserialize, CanonicalSerialize};
use jolt_common::constants::{
DEFAULT_MAX_INPUT_SIZE, DEFAULT_MAX_OUTPUT_SIZE, DEFAULT_MAX_TRACE_LENGTH, DEFAULT_MEMORY_SIZE,
@@ -14,7 +14,6 @@ use jolt_sdk::{
F, Jolt, JoltDevice, JoltProverPreprocessing, JoltRV64IMAC, JoltVerifierPreprocessing,
MemoryConfig, MemoryLayout, PCS,
guest::program::{decode, trace},
- postcard,
};
#[derive(CanonicalSerialize, CanonicalDeserialize)]
@@ -64,25 +63,20 @@ impl JoltSdk {
}
pub fn execute(&self, input: &[u8]) -> Result<(PublicValues, u64), Error> {
- let (cycles, _, io) = trace(
- &self.elf,
- None,
- &serialize_input(input)?,
- &self.memory_config,
- );
+ let (cycles, _, io) = trace(&self.elf, None, input, &self.memory_config);
if io.panic {
return Err(Error::ExecutionPanic);
}
- let public_values = deserialize_output(&io.outputs)?;
+ let public_values = extract_public_values(&io.outputs)?;
Ok((public_values, cycles.len() as _))
}
pub fn prove(&self, input: &[u8]) -> Result<(PublicValues, JoltProof), Error> {
- let (proof, io, _) = JoltRV64IMAC::prove(&self.pk, &self.elf, &serialize_input(input)?);
+ let (proof, io, _) = JoltRV64IMAC::prove(&self.pk, &self.elf, input);
if io.panic {
return Err(Error::ExecutionPanic);
}
- let public_values = deserialize_output(&io.outputs)?;
+ let public_values = extract_public_values(&io.outputs)?;
let proof = JoltProof {
proof,
inputs: io.inputs,
@@ -103,28 +97,26 @@ impl JoltSdk {
},
None,
)?;
- let public_values = deserialize_output(&proof.outputs)?;
+ let public_values = extract_public_values(&proof.outputs)?;
Ok(public_values)
}
}
-fn serialize_input(bytes: &[u8]) -> Result, Error> {
- Ok(postcard::to_stdvec(bytes)
- .map_err(|err| CommonError::serialize("input", "postcard", err))?)
-}
-
-fn deserialize_output(output: &[u8]) -> Result, Error> {
+// Note taht for execute the bytes are padded to size of multiple of 8, but for
+// prove the bytes are truncated.
+fn extract_public_values(output: &[u8]) -> Result, Error> {
Ok(if output.is_empty() {
Vec::new()
} else {
- let (len, bytes) = postcard::take_from_bytes::(output)
- .map_err(|err| CommonError::deserialize("output", "postcard", err))?;
- let mut output = vec![0; len as usize];
- // For execute the bytes are padded to size of multiple of 8, but for
- // prove the bytes are truncated if there are trailing zeros, so here we
- // take the min.
- let len = min(bytes.len(), output.len());
- output[..len].copy_from_slice(&bytes[..len]);
- output
+ let len = u32::from_le_bytes(from_fn(|i| output.get(i).copied().unwrap_or(0))) as usize;
+ if output.len() > (len + 4).next_multiple_of(8) {
+ return Err(Error::InvalidOutput);
+ }
+ let mut public_values = vec![0; len];
+ if let Some((_, output)) = output.split_at_checked(4) {
+ let len = min(len, output.len());
+ public_values[..len].copy_from_slice(&output[..len]);
+ }
+ public_values
})
}
diff --git a/crates/zkvm/miden/src/lib.rs b/crates/zkvm/miden/src/lib.rs
index a53c4ec..8f342df 100644
--- a/crates/zkvm/miden/src/lib.rs
+++ b/crates/zkvm/miden/src/lib.rs
@@ -1,3 +1,23 @@
+//! Miden [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target |
+//! | ---------- | :------------: | ---------- |
+//! | `MidenAsm` | Miden Assembly | Miden MAST |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | No |
+//! | `Network` | No |
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/miden/src/zkvm.rs b/crates/zkvm/miden/src/zkvm.rs
index 20116ca..64d3f89 100644
--- a/crates/zkvm/miden/src/zkvm.rs
+++ b/crates/zkvm/miden/src/zkvm.rs
@@ -175,7 +175,7 @@ pub fn felts_to_bytes(felts: &[Felt]) -> Vec {
/// Convert bytes into Miden field elements.
pub fn bytes_to_felts(bytes: &[u8]) -> Result, Error> {
- if bytes.len() % 8 != 0 {
+ if !bytes.len().is_multiple_of(8) {
let err = anyhow::anyhow!(
"Invalid bytes length {}, expected multiple of 8",
bytes.len()
@@ -218,11 +218,11 @@ mod tests {
let const_b = Felt::ONE / Felt::ONE.double();
let expected_sum = const_a + const_b;
- let input = felts_to_bytes(&[const_a, const_b]);
+ let stdin = felts_to_bytes(&[const_a, const_b]);
// Prove
let (prover_public_values, proof, _) = zkvm
- .prove(&Input::new(input), ProofKind::default())
+ .prove(&Input::new().with_stdin(stdin), ProofKind::default())
.unwrap();
// Verify
@@ -242,11 +242,11 @@ mod tests {
let n_iterations = 50u32;
let expected_fib = Felt::try_from(12_586_269_025u64).unwrap();
- let input = felts_to_bytes(&[Felt::from(0u32), Felt::from(1u32), Felt::from(n_iterations)]);
+ let stdin = felts_to_bytes(&[Felt::from(0u32), Felt::from(1u32), Felt::from(n_iterations)]);
// Prove
let (prover_public_values, proof, _) = zkvm
- .prove(&Input::new(input), ProofKind::default())
+ .prove(&Input::new().with_stdin(stdin), ProofKind::default())
.unwrap();
// Verify
@@ -263,10 +263,10 @@ mod tests {
let program = load_miden_program("add");
let zkvm = EreMiden::new(program, ProverResourceType::Cpu).unwrap();
- let empty_inputs = Input::new(Vec::new());
+ let empty_inputs = Input::new();
assert!(zkvm.execute(&empty_inputs).is_err());
- let insufficient_inputs = Input::new(felts_to_bytes(&[Felt::from(5u32)]));
+ let insufficient_inputs = Input::new().with_stdin(felts_to_bytes(&[Felt::from(5u32)]));
assert!(zkvm.execute(&insufficient_inputs).is_err());
}
}
diff --git a/crates/zkvm/nexus/platform/src/lib.rs b/crates/zkvm/nexus/platform/src/lib.rs
index 872be8a..7053a1b 100644
--- a/crates/zkvm/nexus/platform/src/lib.rs
+++ b/crates/zkvm/nexus/platform/src/lib.rs
@@ -2,27 +2,22 @@
extern crate alloc;
-use alloc::vec::Vec;
-use core::marker::PhantomData;
-use ere_platform_trait::output_hasher::OutputHasher;
+use core::ops::Deref;
+use ere_platform_trait::LengthPrefixedStdin;
-pub use ere_platform_trait::{
- Platform,
- output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
-};
+pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
pub use nexus_rt;
/// Nexus [`Platform`] implementation.
-pub struct NexusPlatform(PhantomData);
+pub struct NexusPlatform;
-impl Platform for NexusPlatform {
- fn read_whole_input() -> Vec {
- nexus_rt::read_private_input().unwrap()
+impl Platform for NexusPlatform {
+ fn read_whole_input() -> impl Deref {
+ LengthPrefixedStdin::new(nexus_rt::read_private_input().unwrap())
}
fn write_whole_output(output: &[u8]) {
- let hash = H::output_hash(output);
- nexus_rt::write_public_output(&*hash).unwrap()
+ nexus_rt::write_public_output(output).unwrap()
}
fn print(message: &str) {
diff --git a/crates/zkvm/nexus/src/lib.rs b/crates/zkvm/nexus/src/lib.rs
index a53c4ec..9883687 100644
--- a/crates/zkvm/nexus/src/lib.rs
+++ b/crates/zkvm/nexus/src/lib.rs
@@ -1,3 +1,23 @@
+//! Nexus [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target |
+//! | ------------ | :------: | --------------------------- |
+//! | `RustRv32i` | Rust | `riscv32i-unknown-none-elf` |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | No |
+//! | `Network` | No |
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/nexus/src/zkvm.rs b/crates/zkvm/nexus/src/zkvm.rs
index f2eb61b..fd14799 100644
--- a/crates/zkvm/nexus/src/zkvm.rs
+++ b/crates/zkvm/nexus/src/zkvm.rs
@@ -205,7 +205,7 @@ mod tests {
let zkvm = EreNexus::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.execute(&input).unwrap_err();
@@ -227,7 +227,7 @@ mod tests {
let zkvm = EreNexus::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.prove(&input, ProofKind::default()).unwrap_err();
diff --git a/crates/zkvm/openvm/platform/src/lib.rs b/crates/zkvm/openvm/platform/src/lib.rs
index f3bac3d..2871417 100644
--- a/crates/zkvm/openvm/platform/src/lib.rs
+++ b/crates/zkvm/openvm/platform/src/lib.rs
@@ -2,33 +2,30 @@
extern crate alloc;
-use alloc::vec::Vec;
-use core::{marker::PhantomData, ops::Deref};
-use ere_platform_trait::output_hasher::FixedOutputHasher;
+use core::{array::from_fn, ops::Deref};
+use ere_platform_trait::LengthPrefixedStdin;
-pub use ere_platform_trait::{
- Platform,
- output_hasher::{IdentityOutput, PaddedOutput, digest::typenum::U32},
-};
+pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
pub use openvm;
/// OpenVM [`Platform`] implementation.
///
-/// Because OpenVM only support public values up to 32 bytes, so
-/// - If the guest has output bytes more than 32 bytes, it should use a
-/// cryptographic hash function for the generic `H` (for example `Sha256`).
-/// - If the guest has output bytes less than 32 bytes, it should use
-/// [`PaddedOutput`] for the generic `H`
-pub struct OpenVMPlatform(PhantomData);
+/// Note that the maximum output size is 32 bytes, and output less than 32
+/// bytes will be padded to 32 bytes.
+pub struct OpenVMPlatform;
-impl> Platform for OpenVMPlatform {
- fn read_whole_input() -> Vec {
- openvm::io::read_vec()
+impl Platform for OpenVMPlatform {
+ fn read_whole_input() -> impl Deref {
+ LengthPrefixedStdin::new(openvm::io::read_vec())
}
fn write_whole_output(output: &[u8]) {
- let hash = H::output_hash(output).deref().try_into().unwrap();
- openvm::io::reveal_bytes32(hash);
+ assert!(
+ output.len() <= 32,
+ "Maximum output size is 32 bytes, got {} bytes",
+ output.len()
+ );
+ openvm::io::reveal_bytes32(from_fn(|i| output.get(i).copied().unwrap_or(0)));
}
fn print(message: &str) {
diff --git a/crates/zkvm/openvm/src/compiler/rust_rv32ima.rs b/crates/zkvm/openvm/src/compiler/rust_rv32ima.rs
index 7cec88c..99eda60 100644
--- a/crates/zkvm/openvm/src/compiler/rust_rv32ima.rs
+++ b/crates/zkvm/openvm/src/compiler/rust_rv32ima.rs
@@ -79,6 +79,6 @@ mod tests {
let program = RustRv32ima.compile(&guest_directory).unwrap();
let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap();
- zkvm.execute(&Input::default()).unwrap();
+ zkvm.execute(&Input::new()).unwrap();
}
}
diff --git a/crates/zkvm/openvm/src/lib.rs b/crates/zkvm/openvm/src/lib.rs
index a53c4ec..1db3bb0 100644
--- a/crates/zkvm/openvm/src/lib.rs
+++ b/crates/zkvm/openvm/src/lib.rs
@@ -1,3 +1,40 @@
+//! OpenVM [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # Requirements
+//!
+//! To install all requirements, run [`install_openvm_sdk.sh`] from the Ere
+//! repository at the same git revision as your `ere-openvm` dependency.
+//!
+//! To use with GPU proving support, make sure CUDA 12.9 is installed, and turn
+//! on the `cuda` feature.
+//!
+//! ## `zkVM` requirements
+//!
+//! - `cargo-openvm`
+//! - Setup via `cargo openvm setup` - Setup aggregation keys used by
+//! `zkVM::prove`
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target | Note |
+//! | ----------------------- | :------: | ----------------------------- | ------------------ |
+//! | `RustRv32imaCustomized` | Rust | `riscv32im-risc0-zkvm-elf` | With `std` support |
+//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` | |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | Yes |
+//! | `Network` | No |
+//!
+//! [`install_openvm_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_openvm_sdk.sh
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/openvm/src/zkvm.rs b/crates/zkvm/openvm/src/zkvm.rs
index f4d53b4..cbd6a5b 100644
--- a/crates/zkvm/openvm/src/zkvm.rs
+++ b/crates/zkvm/openvm/src/zkvm.rs
@@ -292,7 +292,7 @@ mod tests {
let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.execute(&input).unwrap_err();
@@ -314,7 +314,7 @@ mod tests {
let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.prove(&input, ProofKind::default()).unwrap_err();
diff --git a/crates/zkvm/pico/platform/src/lib.rs b/crates/zkvm/pico/platform/src/lib.rs
index ad6f451..9684382 100644
--- a/crates/zkvm/pico/platform/src/lib.rs
+++ b/crates/zkvm/pico/platform/src/lib.rs
@@ -2,27 +2,23 @@
extern crate alloc;
-use alloc::{format, vec::Vec};
-use core::marker::PhantomData;
-use ere_platform_trait::output_hasher::OutputHasher;
+use alloc::format;
+use core::ops::Deref;
+use ere_platform_trait::LengthPrefixedStdin;
-pub use ere_platform_trait::{
- Platform,
- output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
-};
+pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
pub use pico_sdk;
/// Pico [`Platform`] implementation.
-pub struct PicoPlatform(PhantomData);
+pub struct PicoPlatform;
-impl Platform for PicoPlatform {
- fn read_whole_input() -> Vec {
- pico_sdk::io::read_vec()
+impl Platform for PicoPlatform {
+ fn read_whole_input() -> impl Deref {
+ LengthPrefixedStdin::new(pico_sdk::io::read_vec())
}
fn write_whole_output(output: &[u8]) {
- let hash = H::output_hash(output);
- pico_sdk::io::commit_bytes(&hash);
+ pico_sdk::io::commit_bytes(output);
}
fn print(message: &str) {
diff --git a/crates/zkvm/pico/src/compiler/rust_rv32ima.rs b/crates/zkvm/pico/src/compiler/rust_rv32ima.rs
index 920e22c..08ab6ec 100644
--- a/crates/zkvm/pico/src/compiler/rust_rv32ima.rs
+++ b/crates/zkvm/pico/src/compiler/rust_rv32ima.rs
@@ -70,6 +70,6 @@ mod tests {
let program = RustRv32ima.compile(&guest_directory).unwrap();
let zkvm = ErePico::new(program, ProverResourceType::Cpu).unwrap();
- zkvm.execute(&Input::default()).unwrap();
+ zkvm.execute(&Input::new()).unwrap();
}
}
diff --git a/crates/zkvm/pico/src/lib.rs b/crates/zkvm/pico/src/lib.rs
index a53c4ec..45b7415 100644
--- a/crates/zkvm/pico/src/lib.rs
+++ b/crates/zkvm/pico/src/lib.rs
@@ -1,3 +1,35 @@
+//! Pico [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # Requirements
+//!
+//! To install all requirements, run [`install_pico_sdk.sh`] from the Ere
+//! repository at the same git revision as your `ere-pico` dependency.
+//!
+//! ## `Compiler` requirements
+//!
+//! - `cargo-pico` - Used by `RustRv32imaCustomized`
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target | Note |
+//! | ----------------------- | :------: | ----------------------------- | ------------------ |
+//! | `RustRv32imaCustomized` | Rust | `riscv32im-risc0-zkvm-elf` | With `std` support |
+//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` | |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | No |
+//! | `Network` | No |
+//!
+//! [`install_pico_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_pico_sdk.sh
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/pico/src/zkvm.rs b/crates/zkvm/pico/src/zkvm.rs
index 0556be8..98eab7c 100644
--- a/crates/zkvm/pico/src/zkvm.rs
+++ b/crates/zkvm/pico/src/zkvm.rs
@@ -225,7 +225,7 @@ mod tests {
let zkvm = ErePico::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.execute(&input).unwrap_err();
@@ -247,7 +247,7 @@ mod tests {
let zkvm = ErePico::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.prove(&input, ProofKind::default()).unwrap_err();
diff --git a/crates/zkvm/risc0/platform/src/lib.rs b/crates/zkvm/risc0/platform/src/lib.rs
index ea7295b..a345663 100644
--- a/crates/zkvm/risc0/platform/src/lib.rs
+++ b/crates/zkvm/risc0/platform/src/lib.rs
@@ -2,35 +2,30 @@
extern crate alloc;
-use alloc::{vec, vec::Vec};
-use core::marker::PhantomData;
-use ere_platform_trait::output_hasher::OutputHasher;
+use alloc::vec;
+use core::{ops::Deref, slice};
use risc0_zkvm::guest::env::Write;
-pub use ere_platform_trait::{
- Platform,
- output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
-};
+pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
pub use risc0_zkvm;
/// Risc0 [`Platform`] implementation.
-pub struct Risc0Platform(PhantomData);
+pub struct Risc0Platform;
-impl Platform for Risc0Platform {
- fn read_whole_input() -> Vec {
+impl Platform for Risc0Platform {
+ fn read_whole_input() -> impl Deref {
let len = {
let mut bytes = [0; 4];
risc0_zkvm::guest::env::read_slice(&mut bytes);
- u32::from_le_bytes(bytes)
+ u32::from_le_bytes(bytes) as usize
};
- let mut input = vec![0u8; len as usize];
+ let mut input = vec![0u8; len];
risc0_zkvm::guest::env::read_slice(&mut input);
input
}
fn write_whole_output(output: &[u8]) {
- let hash = H::output_hash(output);
- risc0_zkvm::guest::env::commit_slice(&hash);
+ risc0_zkvm::guest::env::commit_slice(output);
}
fn print(message: &str) {
diff --git a/crates/zkvm/risc0/src/compiler/rust_rv32ima.rs b/crates/zkvm/risc0/src/compiler/rust_rv32ima.rs
index b1f0858..e02dbf3 100644
--- a/crates/zkvm/risc0/src/compiler/rust_rv32ima.rs
+++ b/crates/zkvm/risc0/src/compiler/rust_rv32ima.rs
@@ -82,6 +82,6 @@ mod tests {
let program = RustRv32ima.compile(&guest_directory).unwrap();
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
- zkvm.execute(&Input::default()).unwrap();
+ zkvm.execute(&Input::new()).unwrap();
}
}
diff --git a/crates/zkvm/risc0/src/lib.rs b/crates/zkvm/risc0/src/lib.rs
index a53c4ec..c349271 100644
--- a/crates/zkvm/risc0/src/lib.rs
+++ b/crates/zkvm/risc0/src/lib.rs
@@ -1,3 +1,48 @@
+//! Risc0 [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # Requirements
+//!
+//! To install all requirements, run [`install_risc0_sdk.sh`] from the Ere
+//! repository at the same git revision as your `ere-risc0` dependency.
+//!
+//! To install `r0vm-cuda` (with GPU proving support), make sure CUDA 12.9 is
+//! installed, run [`install_risc0_sdk.sh`] with env `CUDA=1` set.
+//!
+//! ## `Compiler` requirements
+//!
+//! - [`rzup`]
+//! - Installation via `rzup install` - Custom Rust toolchain used by `RustRv32imaCustomized`
+//!
+//! ## `zkVM` requirements
+//!
+//! - [`rzup`]
+//! - Installation via `rzup install`
+//! - `r0vm-cuda` - Used by `zkVM::prove` if `ProverResourceType::Gpu` is
+//! selected
+//! - `docker` - Used by `zkVM::prove` if `ProofKind::Groth16` is selected
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target | Note |
+//! | ----------------------- | :------: | ----------------------------- | ------------------ |
+//! | `RustRv32imaCustomized` | Rust | `riscv32im-risc0-zkvm-elf` | With `std` support |
+//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` | |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | Yes |
+//! | `Network` | No |
+//!
+//! [`install_risc0_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_risc0_sdk.sh
+//! [`rzup`]: https://risczero.com/install
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/risc0/src/zkvm.rs b/crates/zkvm/risc0/src/zkvm.rs
index ce6490a..35f2a2a 100644
--- a/crates/zkvm/risc0/src/zkvm.rs
+++ b/crates/zkvm/risc0/src/zkvm.rs
@@ -213,8 +213,7 @@ impl EreRisc0 {
env.segment_limit_po2(self.segment_po2 as _)
.keccak_max_po2(self.keccak_po2 as _)
.expect("keccak_po2 in valid range");
- env.write_slice(&(input.stdin().len() as u32).to_le_bytes())
- .write_slice(input.stdin());
+ env.write_slice(input.stdin());
if let Some(receipts) = input.proofs() {
for receipt in receipts.map_err(Error::DeserializeInputProofs)? {
env.add_assumption(AssumptionReceipt::Proven(receipt));
@@ -265,7 +264,7 @@ mod tests {
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.execute(&input).unwrap_err();
@@ -287,7 +286,7 @@ mod tests {
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.prove(&input, ProofKind::default()).unwrap_err();
@@ -303,7 +302,7 @@ mod tests {
for i in 1..=16_u32 {
let zkvm = EreRisc0::new(program.clone(), ProverResourceType::Cpu).unwrap();
- let input = Input::new(i.to_le_bytes().to_vec());
+ let input = Input::new().with_stdin(i.to_le_bytes().to_vec());
if i.is_power_of_two() {
zkvm.execute(&input)
diff --git a/crates/zkvm/sp1/platform/src/lib.rs b/crates/zkvm/sp1/platform/src/lib.rs
index 83d1802..bf5b26a 100644
--- a/crates/zkvm/sp1/platform/src/lib.rs
+++ b/crates/zkvm/sp1/platform/src/lib.rs
@@ -2,27 +2,23 @@
extern crate alloc;
-use alloc::{format, vec::Vec};
-use core::marker::PhantomData;
-use ere_platform_trait::output_hasher::OutputHasher;
+use alloc::format;
+use core::ops::Deref;
+use ere_platform_trait::LengthPrefixedStdin;
-pub use ere_platform_trait::{
- Platform,
- output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
-};
+pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
pub use sp1_zkvm;
/// SP1 [`Platform`] implementation.
-pub struct SP1Platform(PhantomData);
+pub struct SP1Platform;
-impl Platform for SP1Platform {
- fn read_whole_input() -> Vec {
- sp1_zkvm::io::read_vec()
+impl Platform for SP1Platform {
+ fn read_whole_input() -> impl Deref {
+ LengthPrefixedStdin::new(sp1_zkvm::io::read_vec())
}
fn write_whole_output(output: &[u8]) {
- let hash = H::output_hash(output);
- sp1_zkvm::io::commit_slice(&hash);
+ sp1_zkvm::io::commit_slice(output);
}
fn print(message: &str) {
diff --git a/crates/zkvm/sp1/src/compiler/rust_rv32ima.rs b/crates/zkvm/sp1/src/compiler/rust_rv32ima.rs
index ebc73e8..8350c6d 100644
--- a/crates/zkvm/sp1/src/compiler/rust_rv32ima.rs
+++ b/crates/zkvm/sp1/src/compiler/rust_rv32ima.rs
@@ -70,6 +70,6 @@ mod tests {
let program = RustRv32ima.compile(&guest_directory).unwrap();
let zkvm = EreSP1::new(program, ProverResourceType::Cpu).unwrap();
- zkvm.execute(&Input::default()).unwrap();
+ zkvm.execute(&Input::new()).unwrap();
}
}
diff --git a/crates/zkvm/sp1/src/lib.rs b/crates/zkvm/sp1/src/lib.rs
index a53c4ec..ebabc57 100644
--- a/crates/zkvm/sp1/src/lib.rs
+++ b/crates/zkvm/sp1/src/lib.rs
@@ -1,3 +1,41 @@
+//! SP1 [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # Requirements
+//!
+//! To install all requirements, run [`install_sp1_sdk.sh`] from the Ere
+//! repository at the same git revision as your `ere-sp1` dependency.
+//!
+//! ## `Compiler` requirements
+//!
+//! - Installation via [`sp1up`] - Custom Rust toolchain used by `RustRv32imaCustomized`
+//! - `cargo-prove` - Used by `RustRv32imaCustomized`
+//!
+//! ## `zkVM` requirements
+//!
+//! - `docker` - Used by `zkVM::prove` if `ProverResourceType::Gpu` is selected
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target | Note |
+//! | ----------------------- | :------: | ----------------------------- | ------------------ |
+//! | `RustRv32imaCustomized` | Rust | `riscv32im-succinct-zkvm-elf` | With `std` support |
+//! | `RustRv32ima` | Rust | `riscv32ima-unknown-none-elf` | |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | Yes |
+//! | `Network` | Yes |
+//!
+//! [`install_sp1_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_sp1_sdk.sh
+//! [`sp1up`]: https://sp1up.succinct.xyz
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/sp1/src/zkvm.rs b/crates/zkvm/sp1/src/zkvm.rs
index b5b419c..5c3307e 100644
--- a/crates/zkvm/sp1/src/zkvm.rs
+++ b/crates/zkvm/sp1/src/zkvm.rs
@@ -225,7 +225,7 @@ mod tests {
let zkvm = EreSP1::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.execute(&input).unwrap_err();
@@ -247,7 +247,7 @@ mod tests {
let zkvm = EreSP1::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.prove(&input, ProofKind::default()).unwrap_err();
diff --git a/crates/zkvm/ziren/platform/src/lib.rs b/crates/zkvm/ziren/platform/src/lib.rs
index 14d3c5a..8506c02 100644
--- a/crates/zkvm/ziren/platform/src/lib.rs
+++ b/crates/zkvm/ziren/platform/src/lib.rs
@@ -2,27 +2,22 @@
extern crate alloc;
-use alloc::vec::Vec;
-use core::marker::PhantomData;
-use ere_platform_trait::output_hasher::OutputHasher;
+use core::ops::Deref;
+use ere_platform_trait::LengthPrefixedStdin;
-pub use ere_platform_trait::{
- Platform,
- output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
-};
+pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
pub use zkm_zkvm;
/// Ziren [`Platform`] implementation.
-pub struct ZirenPlatform(PhantomData);
+pub struct ZirenPlatform;
-impl Platform for ZirenPlatform {
- fn read_whole_input() -> Vec {
- zkm_zkvm::io::read_vec()
+impl Platform for ZirenPlatform {
+ fn read_whole_input() -> impl Deref {
+ LengthPrefixedStdin::new(zkm_zkvm::io::read_vec())
}
fn write_whole_output(output: &[u8]) {
- let hash = H::output_hash(output);
- zkm_zkvm::io::commit_slice(&hash);
+ zkm_zkvm::io::commit_slice(output);
}
fn print(message: &str) {
diff --git a/crates/zkvm/ziren/src/lib.rs b/crates/zkvm/ziren/src/lib.rs
index a53c4ec..922540f 100644
--- a/crates/zkvm/ziren/src/lib.rs
+++ b/crates/zkvm/ziren/src/lib.rs
@@ -1,3 +1,34 @@
+//! Ziren [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # Requirements
+//!
+//! To install all requirements, run [`install_ziren_sdk.sh`] from the Ere
+//! repository at the same git revision as your `ere-ziren` dependency.
+//!
+//! ## `Compiler` requirements
+//!
+//! - Installation via [`install_ziren_sdk.sh`] - Custom Rust toolchain used by `RustMips32r2Customized`
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target | Note |
+//! | ------------------------ | :------: | --------------------- | ------------------ |
+//! | `RustMips32r2Customized` | Rust | `mipsel-zkm-zkvm-elf` | With `std` support |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | No |
+//! | `Network` | No |
+//!
+//! [`install_ziren_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_ziren_sdk.sh
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/ziren/src/zkvm.rs b/crates/zkvm/ziren/src/zkvm.rs
index 00e7a2f..dd4ea3a 100644
--- a/crates/zkvm/ziren/src/zkvm.rs
+++ b/crates/zkvm/ziren/src/zkvm.rs
@@ -190,7 +190,7 @@ mod tests {
let zkvm = EreZiren::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.execute(&input).unwrap_err();
@@ -212,7 +212,7 @@ mod tests {
let zkvm = EreZiren::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.prove(&input, ProofKind::default()).unwrap_err();
diff --git a/crates/zkvm/zisk/platform/src/lib.rs b/crates/zkvm/zisk/platform/src/lib.rs
index 5edb89c..a798c2e 100644
--- a/crates/zkvm/zisk/platform/src/lib.rs
+++ b/crates/zkvm/zisk/platform/src/lib.rs
@@ -2,32 +2,31 @@
extern crate alloc;
-use alloc::vec::Vec;
-use core::{array::from_fn, marker::PhantomData};
-use ere_platform_trait::output_hasher::OutputHasher;
+use core::{array::from_fn, ops::Deref};
+use ere_platform_trait::LengthPrefixedStdin;
use ziskos::ziskos_definitions::ziskos_config::UART_ADDR;
-pub use ere_platform_trait::{
- Platform,
- output_hasher::{IdentityOutput, PaddedOutput, digest::typenum},
-};
+pub use ere_platform_trait::{Digest, OutputHashedPlatform, Platform};
pub use ziskos;
/// ZisK [`Platform`] implementation.
///
/// Note that the maximum output size is 256 bytes, and output size will be
/// padded to multiple of 4.
-pub struct ZiskPlatform(PhantomData);
+pub struct ZiskPlatform;
-impl Platform for ZiskPlatform {
- fn read_whole_input() -> Vec {
- ziskos::read_input()
+impl Platform for ZiskPlatform {
+ fn read_whole_input() -> impl Deref {
+ LengthPrefixedStdin::new(ziskos::read_input())
}
fn write_whole_output(output: &[u8]) {
- let hash = H::output_hash(output);
- assert!(hash.len() <= 256, "Maximum output size is 256 bytes");
- hash.chunks(4).enumerate().for_each(|(idx, chunk)| {
+ assert!(
+ output.len() <= 256,
+ "Maximum output size is 256 bytes, got {}",
+ output.len()
+ );
+ output.chunks(4).enumerate().for_each(|(idx, chunk)| {
let value = u32::from_le_bytes(from_fn(|i| chunk.get(i).copied().unwrap_or_default()));
ziskos::set_output(idx, value)
});
diff --git a/crates/zkvm/zisk/src/lib.rs b/crates/zkvm/zisk/src/lib.rs
index a53c4ec..87288ed 100644
--- a/crates/zkvm/zisk/src/lib.rs
+++ b/crates/zkvm/zisk/src/lib.rs
@@ -1,3 +1,47 @@
+//! ZisK [`Compiler`] and [`zkVM`] implementation.
+//!
+//! # Requirements
+//!
+//! To install all requirements, run [`install_zisk_sdk.sh`] from the Ere
+//! repository at the same git revision as your `ere-zisk` dependency.
+//!
+//! To install `cargo-zisk-cuda` (with GPU proving support), make sure CUDA 12.9
+//! is installed, run [`install_zisk_sdk.sh`] with env `CUDA=1` set.
+//!
+//! ## `Compiler` requirements
+//!
+//! - Installation via [`ziskup`] - Custom Rust toolchain used by `RustRv64imaCustomized`
+//! - Installation via [`install_tamago.sh`] - Custom Go toolchain used by `GoCustomized`
+//!
+//! ## `zkVM` requirements
+//!
+//! - Installation via [`ziskup`]
+//! - `cargo-zisk-cuda` - Used by `zkVM::prove` if `ProverResourceType::Gpu` is
+//! selected
+//!
+//! # `Compiler` implementation
+//!
+//! ## Available compilers
+//!
+//! | Compiler | Language | Target | Note |
+//! | ----------------------- | :------: | -------------------------- | ------------------ |
+//! | `RustRv64imaCustomized` | Rust | `riscv64ima-zisk-zkvm-elf` | With `std` support |
+//! | `GoCustomized` | Go | `riscv64` | |
+//!
+//! # `zkVM` implementation
+//!
+//! ## Supported `ProverResourceType`
+//!
+//! | Resource | Supported |
+//! | --------- | :-------: |
+//! | `Cpu` | Yes |
+//! | `Gpu` | Yes |
+//! | `Network` | No |
+//!
+//! [`install_zisk_sdk.sh`]: https://github.com/eth-act/ere/blob/master/scripts/sdk_installers/install_zisk_sdk.sh
+//! [`install_tamago.sh`]: https://github.com/eth-act/ere/blob/master/scripts/install_tamago.sh
+//! [`ziskup`]: https://raw.githubusercontent.com/0xPolygonHermez/zisk/main/ziskup/install.sh
+
#![cfg_attr(
all(not(test), feature = "compiler", feature = "zkvm"),
warn(unused_crate_dependencies)
diff --git a/crates/zkvm/zisk/src/zkvm.rs b/crates/zkvm/zisk/src/zkvm.rs
index 66803c6..90030be 100644
--- a/crates/zkvm/zisk/src/zkvm.rs
+++ b/crates/zkvm/zisk/src/zkvm.rs
@@ -188,7 +188,7 @@ mod tests {
let zkvm = EreZisk::new(program, ProverResourceType::Cpu).unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.execute(&input).unwrap_err();
@@ -214,7 +214,7 @@ mod tests {
let _guard = PROVE_LOCK.lock().unwrap();
for input in [
- Input::default(),
+ Input::new(),
BasicProgram::::invalid_test_case().input(),
] {
zkvm.prove(&input, ProofKind::default()).unwrap_err();
diff --git a/tests/airbender/basic/src/main.rs b/tests/airbender/basic/src/main.rs
index ec5d8fb..cddc3bf 100644
--- a/tests/airbender/basic/src/main.rs
+++ b/tests/airbender/basic/src/main.rs
@@ -7,7 +7,6 @@
use ere_platform_airbender::AirbenderPlatform;
use ere_test_utils::{
- guest::Sha256,
io::serde::bincode::BincodeLegacy,
program::{basic::BasicProgram, Program},
};
@@ -16,5 +15,5 @@ mod airbender_rt;
#[inline(never)]
fn main() {
- BasicProgram::::run::>();
+ BasicProgram::::run_output_sha256::();
}
diff --git a/tests/openvm/basic/src/main.rs b/tests/openvm/basic/src/main.rs
index 45a4dfb..2f85037 100644
--- a/tests/openvm/basic/src/main.rs
+++ b/tests/openvm/basic/src/main.rs
@@ -1,10 +1,9 @@
use ere_platform_openvm::OpenVMPlatform;
use ere_test_utils::{
- guest::Sha256,
io::serde::bincode::BincodeLegacy,
program::{basic::BasicProgram, Program},
};
fn main() {
- BasicProgram::::run::>();
+ BasicProgram::::run_output_sha256::();
}
diff --git a/tests/openvm/stock_nightly_no_std/src/main.rs b/tests/openvm/stock_nightly_no_std/src/main.rs
index 416cedc..3d4155a 100644
--- a/tests/openvm/stock_nightly_no_std/src/main.rs
+++ b/tests/openvm/stock_nightly_no_std/src/main.rs
@@ -1,10 +1,12 @@
#![no_std]
#![no_main]
+
extern crate alloc;
use alloc::vec::Vec;
-use core::sync::atomic::Ordering;
use core::sync::atomic::AtomicU16;
+use core::sync::atomic::Ordering;
+
mod openvm_rt;
fn main() {
diff --git a/tests/pico/stock_nightly_no_std/src/main.rs b/tests/pico/stock_nightly_no_std/src/main.rs
index 920e413..2b3aa9f 100644
--- a/tests/pico/stock_nightly_no_std/src/main.rs
+++ b/tests/pico/stock_nightly_no_std/src/main.rs
@@ -1,10 +1,11 @@
#![no_std]
#![no_main]
+
extern crate alloc;
use alloc::vec::Vec;
-use core::sync::atomic::Ordering;
use core::sync::atomic::AtomicU16;
+use core::sync::atomic::Ordering;
mod pico_rt;
diff --git a/tests/risc0/allocs_alignment/src/main.rs b/tests/risc0/allocs_alignment/src/main.rs
index c2b3d16..2b8a33e 100644
--- a/tests/risc0/allocs_alignment/src/main.rs
+++ b/tests/risc0/allocs_alignment/src/main.rs
@@ -1,9 +1,9 @@
-use ere_platform_risc0::{Platform, Risc0Platform};
-
-type P = Risc0Platform;
+use ere_platform_risc0::risc0_zkvm::guest::env::read_slice;
fn main() {
- let alignment = u32::from_le_bytes(P::read_whole_input().try_into().unwrap()) as usize;
+ let mut alignment = [0; 4];
+ read_slice(&mut alignment);
+ let alignment = u32::from_le_bytes(alignment) as usize;
let layout = std::alloc::Layout::from_size_align(1, alignment).unwrap();
let ptr = unsafe { std::alloc::alloc(layout) };
diff --git a/tests/risc0/stock_nightly_no_std/src/main.rs b/tests/risc0/stock_nightly_no_std/src/main.rs
index 338be42..717ed0c 100644
--- a/tests/risc0/stock_nightly_no_std/src/main.rs
+++ b/tests/risc0/stock_nightly_no_std/src/main.rs
@@ -1,10 +1,11 @@
#![no_std]
#![no_main]
+
extern crate alloc;
use alloc::vec::Vec;
-use core::sync::atomic::Ordering;
use core::sync::atomic::AtomicU16;
+use core::sync::atomic::Ordering;
mod risc0_rt;
diff --git a/tests/sp1/stock_nightly_no_std/src/main.rs b/tests/sp1/stock_nightly_no_std/src/main.rs
index 73a2e98..1f39bce 100644
--- a/tests/sp1/stock_nightly_no_std/src/main.rs
+++ b/tests/sp1/stock_nightly_no_std/src/main.rs
@@ -1,10 +1,11 @@
#![no_std]
#![no_main]
+
extern crate alloc;
use alloc::vec::Vec;
-use core::sync::atomic::Ordering;
use core::sync::atomic::AtomicU16;
+use core::sync::atomic::Ordering;
mod sp1;