mirror of
https://github.com/eth-act/ere.git
synced 2026-02-19 11:54:42 -05:00
Introduce CompilerKind and refactor ere-dockerized (#221)
This commit is contained in:
8
.github/workflows/test-zkvm.yml
vendored
8
.github/workflows/test-zkvm.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
uses: tj-actions/changed-files@v46
|
||||
with:
|
||||
files: |
|
||||
docker/base/Dockerfile.base
|
||||
docker/Dockerfile.base
|
||||
docker/${{ inputs.zkvm }}/**
|
||||
scripts/sdk_installers/install_${{ inputs.zkvm }}_sdk.sh
|
||||
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: docker/base/Dockerfile.base
|
||||
file: docker/Dockerfile.base
|
||||
push: true
|
||||
tags: ${{ steps.image_meta.outputs.base_image }}
|
||||
|
||||
@@ -123,7 +123,7 @@ jobs:
|
||||
tags: ${{ steps.image_meta.outputs.compiler_zkvm_image }}
|
||||
build-args: |
|
||||
BASE_ZKVM_IMAGE=${{ steps.image_meta.outputs.base_zkvm_image }}
|
||||
|
||||
|
||||
- name: Build ere-server-${{ inputs.zkvm }} image
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
uses: docker/build-push-action@v6
|
||||
@@ -290,4 +290,4 @@ jobs:
|
||||
- name: Run cargo test for ere-${{ inputs.zkvm }} via ere-dockerized
|
||||
run: |
|
||||
cargo test --release --package ere-dockerized \
|
||||
-- ${{ inputs.zkvm }} ${{ inputs.skip_prove_test && '--skip prove' || '' }}
|
||||
-- ${{ inputs.zkvm }} ${{ inputs.skip_prove_test && '--skip prove' || '' }} --test-threads=1
|
||||
|
||||
58
Cargo.lock
generated
58
Cargo.lock
generated
@@ -3622,7 +3622,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-airbender"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode 2.0.1",
|
||||
@@ -3639,14 +3639,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-build-utils"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.19.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ere-compile-utils"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_metadata 0.19.2",
|
||||
@@ -3656,7 +3656,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-compiler"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode 2.0.1",
|
||||
@@ -3678,13 +3678,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-dockerized"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ere-build-utils",
|
||||
"ere-compiler",
|
||||
"ere-server",
|
||||
"ere-test-utils",
|
||||
"ere-zkvm-interface",
|
||||
"paste",
|
||||
"serde",
|
||||
"tempfile",
|
||||
"thiserror 2.0.12",
|
||||
@@ -3694,7 +3696,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-io-serde"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"bincode 2.0.1",
|
||||
"serde",
|
||||
@@ -3702,7 +3704,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-jolt"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ark-serialize 0.5.0",
|
||||
@@ -3720,7 +3722,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-miden"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ere-build-utils",
|
||||
@@ -3738,7 +3740,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-nexus"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode 2.0.1",
|
||||
@@ -3757,7 +3759,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-openvm"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ere-build-utils",
|
||||
@@ -3778,7 +3780,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-pico"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode 2.0.1",
|
||||
@@ -3796,7 +3798,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-airbender"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-platform-trait",
|
||||
"riscv_common",
|
||||
@@ -3804,7 +3806,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-jolt"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-platform-trait",
|
||||
"jolt-sdk",
|
||||
@@ -3813,7 +3815,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-nexus"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-platform-trait",
|
||||
"nexus-rt",
|
||||
@@ -3821,7 +3823,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-openvm"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-platform-trait",
|
||||
"openvm",
|
||||
@@ -3829,7 +3831,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-pico"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-platform-trait",
|
||||
"pico-sdk",
|
||||
@@ -3837,7 +3839,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-risc0"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-platform-trait",
|
||||
"risc0-zkvm",
|
||||
@@ -3845,7 +3847,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-sp1"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-platform-trait",
|
||||
"sp1-zkvm",
|
||||
@@ -3853,14 +3855,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-trait"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-ziren"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-platform-trait",
|
||||
"zkm-zkvm",
|
||||
@@ -3868,7 +3870,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-platform-zisk"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-platform-trait",
|
||||
"ziskos",
|
||||
@@ -3876,7 +3878,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-risc0"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"borsh",
|
||||
@@ -3896,7 +3898,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-server"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode 2.0.1",
|
||||
@@ -3926,7 +3928,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-sp1"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode 2.0.1",
|
||||
@@ -3943,7 +3945,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-test-utils"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"ere-io-serde",
|
||||
"ere-platform-trait",
|
||||
@@ -3955,7 +3957,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-ziren"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode 2.0.1",
|
||||
@@ -3971,7 +3973,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-zisk"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"blake3",
|
||||
@@ -3989,7 +3991,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ere-zkvm-interface"
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"auto_impl",
|
||||
|
||||
@@ -24,8 +24,8 @@ members = [
|
||||
"crates/zkvm/zisk",
|
||||
"crates/zkvm/zisk/platform",
|
||||
# Dockerized zkVM
|
||||
"crates/dockerized",
|
||||
"crates/dockerized/compiler",
|
||||
"crates/dockerized/dockerized",
|
||||
"crates/dockerized/server",
|
||||
# Utils
|
||||
"crates/io-serde",
|
||||
@@ -36,7 +36,7 @@ members = [
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.14"
|
||||
version = "0.0.15"
|
||||
edition = "2024"
|
||||
rust-version = "1.85"
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -56,6 +56,7 @@ dashmap = "6.1.0"
|
||||
digest = { version = "0.10.7", default-features = false }
|
||||
eyre = "0.6.12"
|
||||
indexmap = "2.10.0"
|
||||
paste = "1.0.15"
|
||||
postcard = { version = "1.0.8", default-features = false }
|
||||
prost = "0.13"
|
||||
prost-build = "0.13"
|
||||
@@ -155,8 +156,8 @@ ere-platform-sp1 = { path = "crates/zkvm/sp1/platform" }
|
||||
ere-platform-ziren = { path = "crates/zkvm/ziren/platform" }
|
||||
ere-platform-zisk = { path = "crates/zkvm/zisk/platform" }
|
||||
|
||||
ere-dockerized = { path = "crates/dockerized" }
|
||||
ere-compiler = { path = "crates/dockerized/compiler" }
|
||||
ere-dockerized = { path = "crates/dockerized/dockerized" }
|
||||
ere-server = { path = "crates/dockerized/server" }
|
||||
|
||||
ere-io-serde = { path = "crates/io-serde" }
|
||||
|
||||
10
README.md
10
README.md
@@ -130,7 +130,7 @@ ere-dockerized = { git = "https://github.com/eth-act/ere.git", tag = "v0.0.12" }
|
||||
|
||||
```rust
|
||||
// main.rs
|
||||
use ere_dockerized::{EreDockerizedCompiler, EreDockerizedzkVM, ErezkVM};
|
||||
use ere_dockerized::{CompilerKind, DockerizedCompiler, DockerizedzkVM, zkVMKind};
|
||||
use ere_zkvm_interface::{
|
||||
compiler::Compiler,
|
||||
zkvm::{ProofKind, ProverResourceType, zkVM},
|
||||
@@ -140,11 +140,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let guest_directory = std::path::Path::new("workspace/guest");
|
||||
|
||||
// Compile guest
|
||||
let compiler = EreDockerizedCompiler::new(ErezkVM::SP1, std::path::Path::new("workspace"));
|
||||
let compiler = DockerizedCompiler::new(
|
||||
zkVMKind::SP1,
|
||||
CompilerKind::RustCustomized,
|
||||
std::path::Path::new("workspace"),
|
||||
);
|
||||
let program = compiler.compile(guest_directory)?;
|
||||
|
||||
// Create zkVM instance
|
||||
let zkvm = EreDockerizedzkVM::new(ErezkVM::SP1, program, ProverResourceType::Cpu)?;
|
||||
let zkvm = DockerizedzkVM::new(zkVMKind::SP1, program, ProverResourceType::Cpu)?;
|
||||
|
||||
// Serialize input
|
||||
let input = 42u32.to_le_bytes();
|
||||
|
||||
@@ -73,12 +73,12 @@ impl CommonError {
|
||||
|
||||
pub fn read_file(id: impl AsRef<str>, path: impl AsRef<Path>, err: io::Error) -> Self {
|
||||
let (id, path) = (id.as_ref(), path.as_ref().display());
|
||||
Self::io(format!("Failed to write {id} to {path}"), err)
|
||||
Self::io(format!("Failed to read {id} from {path}"), err)
|
||||
}
|
||||
|
||||
pub fn write_file(id: impl AsRef<str>, path: impl AsRef<Path>, err: io::Error) -> Self {
|
||||
let (id, path) = (id.as_ref(), path.as_ref().display());
|
||||
Self::io(format!("Failed to read {id} from {path}"), err)
|
||||
Self::io(format!("Failed to write {id} to {path}"), err)
|
||||
}
|
||||
|
||||
pub fn deserialize(
|
||||
|
||||
@@ -16,8 +16,12 @@ tracing.workspace = true
|
||||
# Local dependencies
|
||||
ere-zkvm-interface = { workspace = true, features = ["clap"] }
|
||||
ere-server.workspace = true
|
||||
ere-compiler.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
paste.workspace = true
|
||||
|
||||
# Local dependencies
|
||||
ere-test-utils = { workspace = true, features = ["host"] }
|
||||
|
||||
[build-dependencies]
|
||||
@@ -45,7 +45,7 @@ fn generate_zkvm_sdk_version_impl() {
|
||||
.map(detect_sdk_version);
|
||||
|
||||
let zkvm_sdk_version_impl = format!(
|
||||
r#"impl crate::ErezkVM {{
|
||||
r#"impl crate::zkVMKind {{
|
||||
pub fn sdk_version(&self) -> &'static str {{
|
||||
match self {{
|
||||
Self::Airbender => "{airbender_version}",
|
||||
48
crates/dockerized/compiler/src/lib.rs
Normal file
48
crates/dockerized/compiler/src/lib.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
/// Compiler kind to use to compile the guest.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum CompilerKind {
|
||||
/// Stock Rust compiler
|
||||
Rust,
|
||||
/// Rust compiler with customized toolchain
|
||||
RustCustomized,
|
||||
/// Go compiler with customized toolchain
|
||||
GoCustomized,
|
||||
/// Miden assembly compiler
|
||||
MidenAsm,
|
||||
}
|
||||
|
||||
impl CompilerKind {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Rust => "rust",
|
||||
Self::RustCustomized => "rust-customized",
|
||||
Self::GoCustomized => "go-customized",
|
||||
Self::MidenAsm => "miden-asm",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for CompilerKind {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s {
|
||||
"rust" => Self::Rust,
|
||||
"rust-customized" => Self::RustCustomized,
|
||||
"go-customized" => Self::GoCustomized,
|
||||
"miden-asm" => Self::MidenAsm,
|
||||
_ => return Err(format!("Unsupported compiler kind {s}")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for CompilerKind {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
use anyhow::{Context, Error};
|
||||
use anyhow::{Context, Error, bail};
|
||||
use clap::Parser;
|
||||
use ere_compiler::CompilerKind;
|
||||
use ere_zkvm_interface::compiler::Compiler;
|
||||
use serde::Serialize;
|
||||
use std::{env, fs::File, path::PathBuf};
|
||||
use std::{fs::File, path::PathBuf};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
// Compile-time check to ensure exactly one zkVM feature is enabled for `ere-compiler`
|
||||
@@ -26,6 +27,9 @@ const _: () = {
|
||||
#[derive(Parser)]
|
||||
#[command(author, version)]
|
||||
struct Args {
|
||||
/// Compiler kind to use
|
||||
#[arg(long, value_parser = <CompilerKind as std::str::FromStr>::from_str)]
|
||||
compiler_kind: CompilerKind,
|
||||
/// Path to the guest program
|
||||
#[arg(long)]
|
||||
guest_path: PathBuf,
|
||||
@@ -41,7 +45,7 @@ fn main() -> Result<(), Error> {
|
||||
|
||||
let args = Args::parse();
|
||||
|
||||
let program = compile(args.guest_path)?;
|
||||
let program = compile(args.guest_path, args.compiler_kind)?;
|
||||
|
||||
let mut output = File::create(args.output_path).with_context(|| "Failed to create output")?;
|
||||
bincode::serde::encode_into_std_write(&program, &mut output, bincode::config::legacy())
|
||||
@@ -50,62 +54,140 @@ fn main() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile(guest_path: PathBuf) -> Result<impl Serialize, Error> {
|
||||
fn compile(guest_path: PathBuf, compiler_kind: CompilerKind) -> Result<impl Serialize, Error> {
|
||||
#[cfg(feature = "airbender")]
|
||||
let result = ere_airbender::compiler::RustRv32ima.compile(&guest_path);
|
||||
let result = {
|
||||
use ere_airbender::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::Rust | CompilerKind::RustCustomized => RustRv32ima.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::Rust, CompilerKind::RustCustomized]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "jolt")]
|
||||
let result = if use_stock_rust() {
|
||||
ere_jolt::compiler::RustRv64imac.compile(&guest_path)
|
||||
} else {
|
||||
ere_jolt::compiler::RustRv64imacCustomized.compile(&guest_path)
|
||||
let result = {
|
||||
use ere_jolt::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::Rust => RustRv64imac.compile(&guest_path),
|
||||
CompilerKind::RustCustomized => RustRv64imacCustomized.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::Rust, CompilerKind::RustCustomized]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "miden")]
|
||||
let result = ere_miden::compiler::MidenAsm.compile(&guest_path);
|
||||
let result = {
|
||||
use ere_miden::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::MidenAsm => MidenAsm.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::MidenAsm]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "nexus")]
|
||||
let result = ere_nexus::compiler::RustRv32i.compile(&guest_path);
|
||||
let result = {
|
||||
use ere_nexus::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::Rust | CompilerKind::RustCustomized => RustRv32i.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::Rust, CompilerKind::RustCustomized]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "openvm")]
|
||||
let result = if use_stock_rust() {
|
||||
ere_openvm::compiler::RustRv32ima.compile(&guest_path)
|
||||
} else {
|
||||
ere_openvm::compiler::RustRv32imaCustomized.compile(&guest_path)
|
||||
let result = {
|
||||
use ere_openvm::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::Rust => RustRv32ima.compile(&guest_path),
|
||||
CompilerKind::RustCustomized => RustRv32imaCustomized.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::Rust, CompilerKind::RustCustomized]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "pico")]
|
||||
let result = if use_stock_rust() {
|
||||
ere_pico::compiler::RustRv32ima.compile(&guest_path)
|
||||
} else {
|
||||
ere_pico::compiler::RustRv32imaCustomized.compile(&guest_path)
|
||||
let result = {
|
||||
use ere_pico::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::Rust => RustRv32ima.compile(&guest_path),
|
||||
CompilerKind::RustCustomized => RustRv32imaCustomized.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::Rust, CompilerKind::RustCustomized]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "risc0")]
|
||||
let result = if use_stock_rust() {
|
||||
ere_risc0::compiler::RustRv32ima.compile(&guest_path)
|
||||
} else {
|
||||
ere_risc0::compiler::RustRv32imaCustomized.compile(&guest_path)
|
||||
let result = {
|
||||
use ere_risc0::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::Rust => RustRv32ima.compile(&guest_path),
|
||||
CompilerKind::RustCustomized => RustRv32imaCustomized.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::Rust, CompilerKind::RustCustomized]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "sp1")]
|
||||
let result = if use_stock_rust() {
|
||||
ere_sp1::compiler::RustRv32ima.compile(&guest_path)
|
||||
} else {
|
||||
ere_sp1::compiler::RustRv32imaCustomized.compile(&guest_path)
|
||||
let result = {
|
||||
use ere_sp1::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::Rust => RustRv32ima.compile(&guest_path),
|
||||
CompilerKind::RustCustomized => RustRv32imaCustomized.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::Rust, CompilerKind::RustCustomized]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "ziren")]
|
||||
let result = ere_ziren::compiler::RustMips32r2Customized.compile(&guest_path);
|
||||
let result = {
|
||||
use ere_ziren::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::RustCustomized => RustMips32r2Customized.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::RustCustomized]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(feature = "zisk")]
|
||||
let result = ere_zisk::compiler::RustRv64imaCustomized.compile(&guest_path);
|
||||
let result = {
|
||||
use ere_zisk::compiler::*;
|
||||
match compiler_kind {
|
||||
CompilerKind::RustCustomized => RustRv64imaCustomized.compile(&guest_path),
|
||||
CompilerKind::GoCustomized => GoCustomized.compile(&guest_path),
|
||||
_ => bail!(unsupported_compiler_kind_err(
|
||||
compiler_kind,
|
||||
[CompilerKind::RustCustomized, CompilerKind::GoCustomized]
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
result.with_context(|| "Failed to compile program")
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
/// Returns whether to use stock Rust compiler instead of customized compiler.
|
||||
fn use_stock_rust() -> bool {
|
||||
env::var_os("ERE_RUST_TOOLCHAIN").is_some()
|
||||
fn unsupported_compiler_kind_err(
|
||||
compiler_kind: CompilerKind,
|
||||
supported: impl IntoIterator<Item = CompilerKind>,
|
||||
) -> anyhow::Error {
|
||||
let supported = supported.into_iter().collect::<Vec<_>>();
|
||||
anyhow::anyhow!("Unsupported compiler kind {compiler_kind:?}, expect one of {supported:?}",)
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
use ere_server::client::{self, TwirpErrorResponse};
|
||||
use std::{io, path::PathBuf};
|
||||
use thiserror::Error;
|
||||
|
||||
impl From<client::Error> for Error {
|
||||
fn from(value: client::Error) -> Self {
|
||||
match value {
|
||||
client::Error::zkVM(err) => Self::zkVM(err),
|
||||
client::Error::ConnectionTimeout => Self::ConnectionTimeout,
|
||||
client::Error::Rpc(err) => Self::Rpc(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum Error {
|
||||
#[error(
|
||||
"Guest directory must be in mounting directory, mounting_directory: {mounting_directory}, guest_directory: {guest_directory}"
|
||||
)]
|
||||
GuestNotInMountingDirecty {
|
||||
mounting_directory: PathBuf,
|
||||
guest_directory: PathBuf,
|
||||
},
|
||||
#[error("{context}: {source}")]
|
||||
Io {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
context: String,
|
||||
},
|
||||
#[error("Failed to execute `docker image`: {0}")]
|
||||
DockerImageCmd(io::Error),
|
||||
#[error("Failed to execute `docker build`: {0}")]
|
||||
DockerBuildCmd(io::Error),
|
||||
#[error("Failed to execute `docker run`: {0}")]
|
||||
DockerRunCmd(io::Error),
|
||||
#[error("Failed to execute `docker container`: {0}")]
|
||||
DockerContainerCmd(io::Error),
|
||||
#[error("zkVM method error: {0}")]
|
||||
zkVM(String),
|
||||
#[error("Connection to zkVM server timeout after 5 minutes")]
|
||||
ConnectionTimeout,
|
||||
#[error("RPC to zkVM server error: {0}")]
|
||||
Rpc(TwirpErrorResponse),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn io(source: io::Error, context: impl ToString) -> Self {
|
||||
Self::Io {
|
||||
source,
|
||||
context: context.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,770 +0,0 @@
|
||||
//! # Ere Dockerized
|
||||
//!
|
||||
//! A Docker-based wrapper for other zkVM crates `ere-{zkvm}`.
|
||||
//!
|
||||
//! This crate provides a unified interface to dockerize the `Compiler` and
|
||||
//! `zkVM` implementation of other zkVM crates `ere-{zkvm}`, it requires only
|
||||
//! `docker` to be installed, but no zkVM specific SDK.
|
||||
//!
|
||||
//! ## Docker image building
|
||||
//!
|
||||
//! It builds 4 Docker images in sequence if they don't exist:
|
||||
//! 1. `ere-base:{version}` - Base image with common dependencies
|
||||
//! 2. `ere-base-{zkvm}:{version}` - zkVM-specific base image with the zkVM SDK
|
||||
//! 3. `ere-compiler-{zkvm}:{version}` - Compiler image with the `ere-compiler`
|
||||
//! binary built with the selected zkVM feature
|
||||
//! 4. `ere-server-{zkvm}:{version}` - Server image with the `ere-server` binary
|
||||
//! built with the selected zkVM feature
|
||||
//!
|
||||
//! When [`ProverResourceType::Gpu`] is selected, the image with GPU support
|
||||
//! will be built and tagged with specific suffix.
|
||||
//!
|
||||
//! To force rebuild all images, set the environment variable
|
||||
//! `ERE_FORCE_REBUILD_DOCKER_IMAGE` to non-empty value.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! use ere_dockerized::{EreDockerizedCompiler, EreDockerizedzkVM, ErezkVM};
|
||||
//! use ere_zkvm_interface::{
|
||||
//! compiler::Compiler,
|
||||
//! zkvm::{ProofKind, ProverResourceType, zkVM},
|
||||
//! };
|
||||
//! use std::path::Path;
|
||||
//!
|
||||
//! // The zkVM we plan to use
|
||||
//! let zkvm = ErezkVM::SP1;
|
||||
//!
|
||||
//! // Compile a guest program
|
||||
//! let compiler = EreDockerizedCompiler::new(zkvm, "mounting/directory")?;
|
||||
//! let guest_path = Path::new("relative/path/to/guest/program");
|
||||
//! let program = compiler.compile(&guest_path)?;
|
||||
//!
|
||||
//! // Create zkVM instance
|
||||
//! let resource = ProverResourceType::Cpu;
|
||||
//! let zkvm = EreDockerizedzkVM::new(zkvm, program, resource)?;
|
||||
//!
|
||||
//! // Serialize input
|
||||
//! let input = 42u32.to_le_bytes();
|
||||
//!
|
||||
//! // Execute program
|
||||
//! let (public_values, execution_report) = zkvm.execute(&input)?;
|
||||
//! println!("Execution cycles: {}", execution_report.total_num_cycles);
|
||||
//!
|
||||
//! // Generate proof
|
||||
//! let (public_values, proof, proving_report) = zkvm.prove(&input, ProofKind::Compressed)?;
|
||||
//! println!("Proof generated in: {:?}", proving_report.proving_time);
|
||||
//!
|
||||
//! // Verify proof
|
||||
//! let public_values = zkvm.verify(&proof)?;
|
||||
//! println!("Proof verified successfully!");
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
|
||||
use crate::{
|
||||
cuda::cuda_arch,
|
||||
docker::{DockerBuildCmd, DockerRunCmd, docker_image_exists, stop_docker_container},
|
||||
};
|
||||
use ere_server::client::{Url, zkVMClient};
|
||||
use ere_zkvm_interface::{
|
||||
compiler::Compiler,
|
||||
zkvm::{
|
||||
ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType,
|
||||
PublicValues, zkVM,
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
env,
|
||||
fmt::{self, Display, Formatter},
|
||||
fs, iter,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
use tempfile::TempDir;
|
||||
use tracing::error;
|
||||
|
||||
mod cuda;
|
||||
mod docker;
|
||||
mod error;
|
||||
|
||||
pub use error::Error;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/crate_version.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/zkvm_sdk_version_impl.rs"));
|
||||
|
||||
/// Offset of port used for `ere-server` for [`ErezkVM`]s.
|
||||
const ERE_SERVER_PORT_OFFSET: u16 = 4174;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ErezkVM {
|
||||
Airbender,
|
||||
Jolt,
|
||||
Miden,
|
||||
Nexus,
|
||||
OpenVM,
|
||||
Pico,
|
||||
Risc0,
|
||||
SP1,
|
||||
Ziren,
|
||||
Zisk,
|
||||
}
|
||||
|
||||
impl ErezkVM {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Airbender => "airbender",
|
||||
Self::Jolt => "jolt",
|
||||
Self::Miden => "miden",
|
||||
Self::Nexus => "nexus",
|
||||
Self::OpenVM => "openvm",
|
||||
Self::Pico => "pico",
|
||||
Self::Risc0 => "risc0",
|
||||
Self::SP1 => "sp1",
|
||||
Self::Ziren => "ziren",
|
||||
Self::Zisk => "zisk",
|
||||
}
|
||||
}
|
||||
|
||||
/// Tag of images in format of `{version}{suffix}`.
|
||||
fn image_tag(&self, version: &str, gpu: bool) -> String {
|
||||
let suffix = match (gpu, self) {
|
||||
// Only the following zkVMs requires CUDA setup in the base image
|
||||
// when GPU support is required.
|
||||
(true, Self::Airbender | Self::OpenVM | Self::Risc0 | Self::Zisk) => "-cuda",
|
||||
_ => "",
|
||||
};
|
||||
format!("{version}{suffix}")
|
||||
}
|
||||
|
||||
pub fn base_image(&self, version: &str, gpu: bool) -> String {
|
||||
format!("ere-base:{}", self.image_tag(version, gpu))
|
||||
}
|
||||
|
||||
pub fn base_zkvm_image(&self, version: &str, gpu: bool) -> String {
|
||||
format!("ere-base-{self}:{}", self.image_tag(version, gpu))
|
||||
}
|
||||
|
||||
pub fn compiler_zkvm_image(&self, version: &str) -> String {
|
||||
format!("ere-compiler-{self}:{}", self.image_tag(version, false))
|
||||
}
|
||||
|
||||
pub fn server_zkvm_image(&self, version: &str, gpu: bool) -> String {
|
||||
format!("ere-server-{self}:{}", self.image_tag(version, gpu))
|
||||
}
|
||||
|
||||
/// This method builds 4 Docker images in sequence:
|
||||
/// 1. `ere-base:{version}`: Base image with common dependencies
|
||||
/// 2. `ere-base-{zkvm}:{version}`: zkVM-specific base image with the zkVM SDK
|
||||
/// 3. `ere-compiler-{zkvm}:{version}` - Compiler image with the `ere-compiler`
|
||||
/// binary built with the selected zkVM feature
|
||||
/// 4. `ere-server-{zkvm}:{version}` - Server image with the `ere-server` binary
|
||||
/// built with the selected zkVM feature
|
||||
///
|
||||
/// When [`ProverResourceType::Gpu`] is selected, the image with GPU support
|
||||
/// will be built and tagged with specific suffix.
|
||||
///
|
||||
/// Images are cached and only rebuilt if they don't exist or if the
|
||||
/// `ERE_FORCE_REBUILD_DOCKER_IMAGE` environment variable is set.
|
||||
pub fn build_docker_image(&self, gpu: bool) -> Result<(), Error> {
|
||||
let workspace_dir = workspace_dir();
|
||||
let docker_dir = workspace_dir.join("docker");
|
||||
|
||||
let force_rebuild = env::var_os("ERE_FORCE_REBUILD_DOCKER_IMAGE").is_some();
|
||||
|
||||
// Build `ere-base`
|
||||
if force_rebuild || !docker_image_exists(self.base_image(CRATE_VERSION, gpu))? {
|
||||
let mut cmd = DockerBuildCmd::new()
|
||||
.file(docker_dir.join("base").join("Dockerfile.base"))
|
||||
.tag(self.base_image(CRATE_VERSION, gpu))
|
||||
.tag(self.base_image("latest", gpu));
|
||||
|
||||
if gpu {
|
||||
cmd = cmd.build_arg("CUDA", "1");
|
||||
}
|
||||
|
||||
cmd.exec(&workspace_dir).map_err(Error::DockerBuildCmd)?;
|
||||
}
|
||||
|
||||
// Build `ere-base-{zkvm}`
|
||||
if force_rebuild || !docker_image_exists(self.base_zkvm_image(CRATE_VERSION, gpu))? {
|
||||
let mut cmd = DockerBuildCmd::new()
|
||||
.file(docker_dir.join(self.as_str()).join("Dockerfile.base"))
|
||||
.tag(self.base_zkvm_image(CRATE_VERSION, gpu))
|
||||
.tag(self.base_zkvm_image("latest", gpu))
|
||||
.build_arg("BASE_IMAGE", self.base_image(CRATE_VERSION, gpu))
|
||||
.build_arg_from_env("RUSTFLAGS");
|
||||
|
||||
if gpu {
|
||||
cmd = cmd.build_arg("CUDA", "1");
|
||||
|
||||
let cuda_arch = cuda_arch();
|
||||
match self {
|
||||
Self::Airbender | Self::OpenVM | Self::Risc0 | Self::Zisk => {
|
||||
if let Some(cuda_arch) = cuda_arch {
|
||||
cmd = cmd.build_arg("CUDA_ARCH", cuda_arch)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
cmd.exec(&workspace_dir).map_err(Error::DockerBuildCmd)?;
|
||||
}
|
||||
|
||||
// Build `ere-compiler-{zkvm}`
|
||||
if force_rebuild || !docker_image_exists(self.compiler_zkvm_image(CRATE_VERSION))? {
|
||||
DockerBuildCmd::new()
|
||||
.file(docker_dir.join(self.as_str()).join("Dockerfile.compiler"))
|
||||
.tag(self.compiler_zkvm_image(CRATE_VERSION))
|
||||
.tag(self.compiler_zkvm_image("latest"))
|
||||
.build_arg("BASE_ZKVM_IMAGE", self.base_zkvm_image(CRATE_VERSION, gpu))
|
||||
.exec(&workspace_dir)
|
||||
.map_err(Error::DockerBuildCmd)?;
|
||||
}
|
||||
|
||||
// Build `ere-server-{zkvm}`
|
||||
if force_rebuild || !docker_image_exists(self.server_zkvm_image(CRATE_VERSION, gpu))? {
|
||||
let mut cmd = DockerBuildCmd::new()
|
||||
.file(docker_dir.join(self.as_str()).join("Dockerfile.server"))
|
||||
.tag(self.server_zkvm_image(CRATE_VERSION, gpu))
|
||||
.tag(self.server_zkvm_image("latest", gpu))
|
||||
.build_arg("BASE_ZKVM_IMAGE", self.base_zkvm_image(CRATE_VERSION, gpu))
|
||||
.build_arg_from_env("RUSTFLAGS");
|
||||
|
||||
if gpu {
|
||||
cmd = cmd.build_arg("CUDA", "1");
|
||||
}
|
||||
|
||||
cmd.exec(&workspace_dir).map_err(Error::DockerBuildCmd)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn server_port(&self) -> u16 {
|
||||
ERE_SERVER_PORT_OFFSET + *self as u16
|
||||
}
|
||||
|
||||
fn spawn_server(
|
||||
&self,
|
||||
program: &SerializedProgram,
|
||||
resource: &ProverResourceType,
|
||||
) -> Result<ServerContainer, Error> {
|
||||
let port = self.server_port().to_string();
|
||||
let name = format!("ere-server-{self}-{port}");
|
||||
let gpu = matches!(resource, ProverResourceType::Gpu);
|
||||
let mut cmd = DockerRunCmd::new(self.server_zkvm_image(CRATE_VERSION, gpu))
|
||||
.rm()
|
||||
.inherit_env("RUST_LOG")
|
||||
.inherit_env("NO_COLOR")
|
||||
.publish(&port, &port)
|
||||
.name(&name);
|
||||
|
||||
// zkVM specific options
|
||||
cmd = match self {
|
||||
Self::Risc0 => cmd
|
||||
.inherit_env("RISC0_SEGMENT_PO2")
|
||||
.inherit_env("RISC0_KECCAK_PO2"),
|
||||
// ZisK uses shared memory to exchange data between processes, it
|
||||
// requires at least 8G shared memory, here we set 16G for safety.
|
||||
Self::Zisk => cmd
|
||||
.option("shm-size", "16G")
|
||||
.option("ulimit", "memlock=-1:-1")
|
||||
.inherit_env("ZISK_PORT")
|
||||
.inherit_env("ZISK_CHUNK_SIZE_BITS")
|
||||
.inherit_env("ZISK_UNLOCK_MAPPED_MEMORY")
|
||||
.inherit_env("ZISK_MINIMAL_MEMORY")
|
||||
.inherit_env("ZISK_PREALLOCATE")
|
||||
.inherit_env("ZISK_SHARED_TABLES")
|
||||
.inherit_env("ZISK_MAX_STREAMS")
|
||||
.inherit_env("ZISK_NUMBER_THREADS_WITNESS")
|
||||
.inherit_env("ZISK_MAX_WITNESS_STORED"),
|
||||
_ => cmd,
|
||||
};
|
||||
|
||||
// zkVM specific options when using GPU
|
||||
if gpu {
|
||||
cmd = match self {
|
||||
Self::Airbender => cmd.gpus("all"),
|
||||
Self::OpenVM => cmd.gpus("all"),
|
||||
// SP1 runs docker command to spin up the server to do GPU
|
||||
// proving, to give the client access to the prover service, we
|
||||
// need to use the host networking driver.
|
||||
Self::SP1 => cmd.mount_docker_socket().network("host"),
|
||||
Self::Risc0 => cmd.gpus("all").inherit_env("RISC0_DEFAULT_PROVER_NUM_GPUS"),
|
||||
Self::Zisk => cmd.gpus("all"),
|
||||
_ => cmd,
|
||||
}
|
||||
}
|
||||
|
||||
let tempdir =
|
||||
TempDir::new().map_err(|err| Error::io(err, "Failed to create temporary directory"))?;
|
||||
|
||||
// zkVM specific options needed for proving Groth16 proof.
|
||||
cmd = match self {
|
||||
// Risc0 and SP1 runs docker command to prove Groth16 proof, and
|
||||
// they pass the input by mounting temporary directory. Here we
|
||||
// create a temporary directory and mount it on the top level, so
|
||||
// the volume could be shared, and override `TMPDIR` so we don't
|
||||
// need to mount the whole `/tmp`.
|
||||
Self::Risc0 => cmd
|
||||
.mount_docker_socket()
|
||||
.env("TMPDIR", tempdir.path().to_string_lossy())
|
||||
.volume(tempdir.path(), tempdir.path()),
|
||||
Self::SP1 => {
|
||||
let groth16_circuit_path = home_dir().join(".sp1").join("circuits").join("groth16");
|
||||
cmd.mount_docker_socket()
|
||||
.env(
|
||||
"SP1_GROTH16_CIRCUIT_PATH",
|
||||
groth16_circuit_path.to_string_lossy(),
|
||||
)
|
||||
.env("TMPDIR", tempdir.path().to_string_lossy())
|
||||
.volume(tempdir.path(), tempdir.path())
|
||||
.volume(&groth16_circuit_path, &groth16_circuit_path)
|
||||
}
|
||||
_ => cmd,
|
||||
};
|
||||
|
||||
let args = iter::empty()
|
||||
.chain(["--port", &port])
|
||||
.chain(resource.to_args());
|
||||
cmd.spawn(args, &program.0).map_err(Error::DockerRunCmd)?;
|
||||
|
||||
Ok(ServerContainer { name, tempdir })
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ErezkVM {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s {
|
||||
"airbender" => Self::Airbender,
|
||||
"jolt" => Self::Jolt,
|
||||
"miden" => Self::Miden,
|
||||
"nexus" => Self::Nexus,
|
||||
"openvm" => Self::OpenVM,
|
||||
"pico" => Self::Pico,
|
||||
"risc0" => Self::Risc0,
|
||||
"sp1" => Self::SP1,
|
||||
"ziren" => Self::Ziren,
|
||||
"zisk" => Self::Zisk,
|
||||
_ => return Err(format!("Unsupported zkvm {s}")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ErezkVM {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EreDockerizedCompiler {
|
||||
zkvm: ErezkVM,
|
||||
mount_directory: PathBuf,
|
||||
}
|
||||
|
||||
impl EreDockerizedCompiler {
|
||||
pub fn new(zkvm: ErezkVM, mount_directory: impl AsRef<Path>) -> Result<Self, Error> {
|
||||
zkvm.build_docker_image(false)?;
|
||||
Ok(Self {
|
||||
zkvm,
|
||||
mount_directory: mount_directory.as_ref().to_path_buf(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn zkvm(&self) -> ErezkVM {
|
||||
self.zkvm
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper for serialized program.
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct SerializedProgram(Vec<u8>);
|
||||
|
||||
impl Compiler for EreDockerizedCompiler {
|
||||
type Error = Error;
|
||||
type Program = SerializedProgram;
|
||||
|
||||
fn compile(&self, guest_directory: &Path) -> Result<Self::Program, Self::Error> {
|
||||
let guest_relative_path = guest_directory
|
||||
.strip_prefix(&self.mount_directory)
|
||||
.map_err(|_| Error::GuestNotInMountingDirecty {
|
||||
mounting_directory: self.mount_directory.to_path_buf(),
|
||||
guest_directory: guest_directory.to_path_buf(),
|
||||
})?;
|
||||
let guest_path_in_docker = PathBuf::from("/guest").join(guest_relative_path);
|
||||
|
||||
let tempdir =
|
||||
TempDir::new().map_err(|err| Error::io(err, "Failed to create temporary directory"))?;
|
||||
|
||||
let mut cmd = DockerRunCmd::new(self.zkvm.compiler_zkvm_image(CRATE_VERSION))
|
||||
.rm()
|
||||
.inherit_env("RUST_LOG")
|
||||
.inherit_env("NO_COLOR")
|
||||
.inherit_env("ERE_RUST_TOOLCHAIN")
|
||||
.volume(&self.mount_directory, "/guest")
|
||||
.volume(tempdir.path(), "/output");
|
||||
|
||||
cmd = match self.zkvm {
|
||||
// OpenVM allows to select Rust toolchain for guest compilation.
|
||||
ErezkVM::OpenVM => cmd.inherit_env("OPENVM_RUST_TOOLCHAIN"),
|
||||
_ => cmd,
|
||||
};
|
||||
|
||||
cmd.exec([
|
||||
"--guest-path",
|
||||
guest_path_in_docker.to_string_lossy().as_ref(),
|
||||
"--output-path",
|
||||
"/output/program",
|
||||
])
|
||||
.map_err(Error::DockerRunCmd)?;
|
||||
|
||||
let program_path = tempdir.path().join("program");
|
||||
let program = fs::read(&program_path).map_err(|err| {
|
||||
Error::io(
|
||||
err,
|
||||
format!(
|
||||
"Failed to read compiled program at {}",
|
||||
program_path.display()
|
||||
),
|
||||
)
|
||||
})?;
|
||||
Ok(SerializedProgram(program))
|
||||
}
|
||||
}
|
||||
|
||||
struct ServerContainer {
|
||||
name: String,
|
||||
#[allow(dead_code)]
|
||||
tempdir: TempDir,
|
||||
}
|
||||
|
||||
impl Drop for ServerContainer {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = stop_docker_container(&self.name) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EreDockerizedzkVM {
|
||||
zkvm: ErezkVM,
|
||||
program: SerializedProgram,
|
||||
resource: ProverResourceType,
|
||||
#[allow(dead_code)]
|
||||
server_container: ServerContainer,
|
||||
client: zkVMClient,
|
||||
}
|
||||
|
||||
impl EreDockerizedzkVM {
|
||||
pub fn new(
|
||||
zkvm: ErezkVM,
|
||||
program: SerializedProgram,
|
||||
resource: ProverResourceType,
|
||||
) -> Result<Self, Error> {
|
||||
zkvm.build_docker_image(matches!(resource, ProverResourceType::Gpu))?;
|
||||
|
||||
let server_container = zkvm.spawn_server(&program, &resource)?;
|
||||
|
||||
let url = Url::parse(&format!("http://127.0.0.1:{}", zkvm.server_port())).unwrap();
|
||||
let client = block_on(zkVMClient::new(url))?;
|
||||
|
||||
Ok(Self {
|
||||
zkvm,
|
||||
program,
|
||||
resource,
|
||||
server_container,
|
||||
client,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn zkvm(&self) -> ErezkVM {
|
||||
self.zkvm
|
||||
}
|
||||
|
||||
pub fn program(&self) -> &SerializedProgram {
|
||||
&self.program
|
||||
}
|
||||
|
||||
pub fn resource(&self) -> &ProverResourceType {
|
||||
&self.resource
|
||||
}
|
||||
}
|
||||
|
||||
impl zkVM for EreDockerizedzkVM {
|
||||
fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> {
|
||||
let (public_values, report) =
|
||||
block_on(self.client.execute(input.to_vec())).map_err(Error::from)?;
|
||||
|
||||
Ok((public_values, report))
|
||||
}
|
||||
|
||||
fn prove(
|
||||
&self,
|
||||
input: &[u8],
|
||||
proof_kind: ProofKind,
|
||||
) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> {
|
||||
let (public_values, proof, report) =
|
||||
block_on(self.client.prove(input.to_vec(), proof_kind)).map_err(Error::from)?;
|
||||
|
||||
Ok((public_values, proof, report))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &Proof) -> anyhow::Result<PublicValues> {
|
||||
let public_values = block_on(self.client.verify(proof)).map_err(Error::from)?;
|
||||
|
||||
Ok(public_values)
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
self.zkvm.as_str()
|
||||
}
|
||||
|
||||
fn sdk_version(&self) -> &'static str {
|
||||
self.zkvm.sdk_version()
|
||||
}
|
||||
}
|
||||
|
||||
fn block_on<T>(future: impl Future<Output = T>) -> T {
|
||||
match tokio::runtime::Handle::try_current() {
|
||||
Ok(handle) => tokio::task::block_in_place(|| handle.block_on(future)),
|
||||
Err(_) => tokio::runtime::Runtime::new().unwrap().block_on(future),
|
||||
}
|
||||
}
|
||||
|
||||
fn workspace_dir() -> PathBuf {
|
||||
let mut dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
dir.pop();
|
||||
dir.pop();
|
||||
dir.pop();
|
||||
dir.canonicalize().unwrap()
|
||||
}
|
||||
|
||||
fn home_dir() -> PathBuf {
|
||||
PathBuf::from(std::env::var("HOME").expect("env `$HOME` should be set"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{
|
||||
EreDockerizedCompiler, EreDockerizedzkVM, ErezkVM, Error, SerializedProgram, workspace_dir,
|
||||
};
|
||||
use ere_test_utils::{host::*, program::basic::BasicProgramInput};
|
||||
use ere_zkvm_interface::{
|
||||
compiler::Compiler,
|
||||
zkvm::{ProofKind, ProverResourceType, zkVM},
|
||||
};
|
||||
use std::sync::{Mutex, MutexGuard, OnceLock};
|
||||
|
||||
macro_rules! test_compile {
|
||||
($zkvm:ident, $program:literal) => {
|
||||
use super::*;
|
||||
|
||||
fn program() -> &'static SerializedProgram {
|
||||
static PROGRAM: OnceLock<SerializedProgram> = OnceLock::new();
|
||||
PROGRAM.get_or_init(|| {
|
||||
let zkvm = ErezkVM::$zkvm;
|
||||
let guest_directory = testing_guest_directory(zkvm.as_str(), $program);
|
||||
EreDockerizedCompiler::new(zkvm, workspace_dir())
|
||||
.unwrap()
|
||||
.compile(&guest_directory)
|
||||
.unwrap()
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn zkvm() -> (MutexGuard<'static, ()>, EreDockerizedzkVM) {
|
||||
static LOCK: Mutex<()> = Mutex::new(());
|
||||
let guard = LOCK.lock().unwrap();
|
||||
let zkvm = ErezkVM::$zkvm;
|
||||
let zkvm = EreDockerizedzkVM::new(zkvm, program().clone(), ProverResourceType::Cpu)
|
||||
.unwrap();
|
||||
(guard, zkvm)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compile() {
|
||||
let program = program();
|
||||
|
||||
assert!(!program.0.is_empty(), "Program should not be empty");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_execute {
|
||||
($zkvm:ident, $valid_test_case:expr, $invalid_test_cases:expr) => {
|
||||
#[test]
|
||||
fn test_execute() {
|
||||
let (_guard, zkvm) = zkvm();
|
||||
|
||||
// Valid test case
|
||||
run_zkvm_execute(&zkvm, &$valid_test_case);
|
||||
|
||||
// Invalid test cases
|
||||
for input in $invalid_test_cases {
|
||||
let err = zkvm.execute(&input).unwrap_err();
|
||||
assert!(matches!(err.downcast::<Error>().unwrap(), Error::zkVM(_)),);
|
||||
}
|
||||
|
||||
drop(zkvm);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test_prove {
|
||||
($zkvm:ident, $valid_test_case:expr, $invalid_test_cases:expr) => {
|
||||
#[test]
|
||||
fn test_prove() {
|
||||
let (_guard, zkvm) = zkvm();
|
||||
|
||||
// Valid test case
|
||||
run_zkvm_prove(&zkvm, &$valid_test_case);
|
||||
|
||||
// Invalid test cases
|
||||
for input in $invalid_test_cases {
|
||||
let err = zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
assert!(matches!(err.downcast::<Error>().unwrap(), Error::zkVM(_)),);
|
||||
}
|
||||
|
||||
drop(zkvm);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod airbender {
|
||||
test_compile!(Airbender, "basic");
|
||||
test_execute!(
|
||||
Airbender,
|
||||
BasicProgramInput::valid().into_output_sha256(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
test_prove!(
|
||||
Airbender,
|
||||
BasicProgramInput::valid().into_output_sha256(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod jolt {
|
||||
test_compile!(Jolt, "basic");
|
||||
test_execute!(
|
||||
Jolt,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
test_prove!(
|
||||
Jolt,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod miden {
|
||||
test_compile!(Miden, "fib");
|
||||
}
|
||||
|
||||
mod nexus {
|
||||
test_compile!(Nexus, "basic");
|
||||
test_execute!(
|
||||
Nexus,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
test_prove!(
|
||||
Nexus,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod openvm {
|
||||
test_compile!(OpenVM, "basic");
|
||||
test_execute!(
|
||||
OpenVM,
|
||||
BasicProgramInput::valid().into_output_sha256(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
test_prove!(
|
||||
OpenVM,
|
||||
BasicProgramInput::valid().into_output_sha256(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod pico {
|
||||
test_compile!(Pico, "basic");
|
||||
test_execute!(
|
||||
Pico,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
test_prove!(
|
||||
Pico,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod risc0 {
|
||||
test_compile!(Risc0, "basic");
|
||||
test_execute!(
|
||||
Risc0,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
test_prove!(
|
||||
Risc0,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod sp1 {
|
||||
test_compile!(SP1, "basic");
|
||||
test_execute!(
|
||||
SP1,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
test_prove!(
|
||||
SP1,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod ziren {
|
||||
test_compile!(Ziren, "basic");
|
||||
test_execute!(
|
||||
Ziren,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
test_prove!(
|
||||
Ziren,
|
||||
BasicProgramInput::valid(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod zisk {
|
||||
test_compile!(Zisk, "basic_rust");
|
||||
test_execute!(
|
||||
Zisk,
|
||||
BasicProgramInput::valid().into_output_sha256(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
test_prove!(
|
||||
Zisk,
|
||||
BasicProgramInput::valid().into_output_sha256(),
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
}
|
||||
236
crates/dockerized/src/compiler.rs
Normal file
236
crates/dockerized/src/compiler.rs
Normal file
@@ -0,0 +1,236 @@
|
||||
use crate::{
|
||||
CompilerKind, base_image, base_zkvm_image, compiler_zkvm_image,
|
||||
util::{
|
||||
docker::{DockerBuildCmd, DockerRunCmd, docker_image_exists, force_rebuild},
|
||||
workspace_dir,
|
||||
},
|
||||
zkVMKind,
|
||||
};
|
||||
use ere_zkvm_interface::{CommonError, compiler::Compiler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use tempfile::TempDir;
|
||||
use tracing::info;
|
||||
|
||||
mod error;
|
||||
|
||||
pub use error::Error;
|
||||
|
||||
/// This method builds 3 Docker images in sequence:
|
||||
/// 1. `ere-base:{version}` - Base image with common dependencies
|
||||
/// 2. `ere-base-{zkvm}:{version}` - zkVM-specific base image with the zkVM SDK
|
||||
/// 3. `ere-compiler-{zkvm}:{version}` - Compiler image with the `ere-compiler`
|
||||
/// binary built with the selected zkVM feature
|
||||
///
|
||||
/// Images are cached and only rebuilt if they don't exist or if the
|
||||
/// `ERE_FORCE_REBUILD_DOCKER_IMAGE` environment variable is set.
|
||||
fn build_compiler_image(zkvm_kind: zkVMKind) -> Result<(), Error> {
|
||||
let workspace_dir = workspace_dir();
|
||||
let docker_dir = workspace_dir.join("docker");
|
||||
let docker_zkvm_dir = docker_dir.join(zkvm_kind.as_str());
|
||||
|
||||
let force_rebuild = force_rebuild();
|
||||
let base_image = base_image(zkvm_kind, false);
|
||||
let base_zkvm_image = base_zkvm_image(zkvm_kind, false);
|
||||
let compiler_zkvm_image = compiler_zkvm_image(zkvm_kind);
|
||||
|
||||
// Build `ere-base`
|
||||
if force_rebuild || !docker_image_exists(&base_image)? {
|
||||
info!("Building image {base_image}...");
|
||||
|
||||
DockerBuildCmd::new()
|
||||
.file(docker_dir.join("Dockerfile.base"))
|
||||
.tag(&base_image)
|
||||
.exec(&workspace_dir)?;
|
||||
}
|
||||
|
||||
// Build `ere-base-{zkvm_kind}`
|
||||
if force_rebuild || !docker_image_exists(&base_zkvm_image)? {
|
||||
info!("Building image {base_zkvm_image}...");
|
||||
|
||||
DockerBuildCmd::new()
|
||||
.file(docker_zkvm_dir.join("Dockerfile.base"))
|
||||
.tag(&base_zkvm_image)
|
||||
.build_arg("BASE_IMAGE", &base_image)
|
||||
.build_arg_from_env("RUSTFLAGS")
|
||||
.exec(&workspace_dir)?;
|
||||
}
|
||||
|
||||
// Build `ere-compiler-{zkvm_kind}`
|
||||
if force_rebuild || !docker_image_exists(&compiler_zkvm_image)? {
|
||||
info!("Building image {compiler_zkvm_image}...");
|
||||
|
||||
DockerBuildCmd::new()
|
||||
.file(docker_zkvm_dir.join("Dockerfile.compiler"))
|
||||
.tag(&compiler_zkvm_image)
|
||||
.build_arg("BASE_ZKVM_IMAGE", &base_zkvm_image)
|
||||
.exec(&workspace_dir)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Wrapper for serialized program.
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct SerializedProgram(pub(crate) Vec<u8>);
|
||||
|
||||
pub struct DockerizedCompiler {
|
||||
zkvm_kind: zkVMKind,
|
||||
compiler_kind: CompilerKind,
|
||||
mount_directory: PathBuf,
|
||||
}
|
||||
|
||||
impl DockerizedCompiler {
|
||||
pub fn new(
|
||||
zkvm_kind: zkVMKind,
|
||||
compiler_kind: CompilerKind,
|
||||
mount_directory: impl AsRef<Path>,
|
||||
) -> Result<Self, Error> {
|
||||
build_compiler_image(zkvm_kind)?;
|
||||
Ok(Self {
|
||||
zkvm_kind,
|
||||
compiler_kind,
|
||||
mount_directory: mount_directory.as_ref().to_path_buf(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn zkvm_kind(&self) -> zkVMKind {
|
||||
self.zkvm_kind
|
||||
}
|
||||
|
||||
pub fn compiler_kind(&self) -> CompilerKind {
|
||||
self.compiler_kind
|
||||
}
|
||||
}
|
||||
|
||||
impl Compiler for DockerizedCompiler {
|
||||
type Error = Error;
|
||||
type Program = SerializedProgram;
|
||||
|
||||
fn compile(&self, guest_directory: &Path) -> Result<Self::Program, Self::Error> {
|
||||
let guest_relative_path = guest_directory
|
||||
.strip_prefix(&self.mount_directory)
|
||||
.map_err(|_| Error::GuestNotInMountingDirecty {
|
||||
mounting_directory: self.mount_directory.to_path_buf(),
|
||||
guest_directory: guest_directory.to_path_buf(),
|
||||
})?;
|
||||
let guest_path_in_docker = PathBuf::from("/guest").join(guest_relative_path);
|
||||
|
||||
let tempdir = TempDir::new().map_err(CommonError::tempdir)?;
|
||||
|
||||
let mut cmd = DockerRunCmd::new(compiler_zkvm_image(self.zkvm_kind))
|
||||
.rm()
|
||||
.inherit_env("RUST_LOG")
|
||||
.inherit_env("NO_COLOR")
|
||||
.inherit_env("ERE_RUST_TOOLCHAIN")
|
||||
.volume(&self.mount_directory, "/guest")
|
||||
.volume(tempdir.path(), "/output");
|
||||
|
||||
cmd = match self.zkvm_kind {
|
||||
// OpenVM allows to select Rust toolchain for guest compilation.
|
||||
zkVMKind::OpenVM => cmd.inherit_env("OPENVM_RUST_TOOLCHAIN"),
|
||||
_ => cmd,
|
||||
};
|
||||
|
||||
cmd.exec([
|
||||
"--compiler-kind",
|
||||
self.compiler_kind.as_str(),
|
||||
"--guest-path",
|
||||
guest_path_in_docker.to_string_lossy().as_ref(),
|
||||
"--output-path",
|
||||
"/output/program",
|
||||
])?;
|
||||
|
||||
let program_path = tempdir.path().join("program");
|
||||
let program = fs::read(&program_path)
|
||||
.map_err(|err| CommonError::read_file("program", &program_path, err))?;
|
||||
Ok(SerializedProgram(program))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test {
|
||||
use crate::{
|
||||
CompilerKind,
|
||||
compiler::{DockerizedCompiler, SerializedProgram},
|
||||
util::workspace_dir,
|
||||
zkVMKind,
|
||||
};
|
||||
use ere_test_utils::host::testing_guest_directory;
|
||||
use ere_zkvm_interface::compiler::Compiler;
|
||||
|
||||
pub fn compile(
|
||||
zkvm_kind: zkVMKind,
|
||||
compiler_kind: CompilerKind,
|
||||
program: &'static str,
|
||||
) -> SerializedProgram {
|
||||
DockerizedCompiler::new(zkvm_kind, compiler_kind, workspace_dir())
|
||||
.unwrap()
|
||||
.compile(&testing_guest_directory(zkvm_kind.as_str(), program))
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
macro_rules! test_compile {
|
||||
($zkvm_kind:ident, $compiler_kind:ident, $program:literal) => {
|
||||
paste::paste! {
|
||||
#[test]
|
||||
fn [<test_compile_ $compiler_kind:snake>]() {
|
||||
let zkvm_kind = crate::zkVMKind::$zkvm_kind;
|
||||
let compiler_kind = crate::CompilerKind::$compiler_kind;
|
||||
let program = crate::compiler::test::compile(zkvm_kind, compiler_kind, $program);
|
||||
|
||||
assert!(!program.0.is_empty(), "Program should not be empty");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod airbender {
|
||||
test_compile!(Airbender, Rust, "basic");
|
||||
}
|
||||
|
||||
mod jolt {
|
||||
test_compile!(Jolt, RustCustomized, "basic");
|
||||
test_compile!(Jolt, Rust, "stock_nightly_no_std");
|
||||
}
|
||||
|
||||
mod miden {
|
||||
test_compile!(Miden, MidenAsm, "fib");
|
||||
}
|
||||
|
||||
mod nexus {
|
||||
test_compile!(Nexus, Rust, "basic");
|
||||
}
|
||||
|
||||
mod openvm {
|
||||
test_compile!(OpenVM, RustCustomized, "basic");
|
||||
test_compile!(OpenVM, Rust, "stock_nightly_no_std");
|
||||
}
|
||||
|
||||
mod pico {
|
||||
test_compile!(Pico, RustCustomized, "basic");
|
||||
test_compile!(Pico, Rust, "stock_nightly_no_std");
|
||||
}
|
||||
|
||||
mod risc0 {
|
||||
test_compile!(Risc0, RustCustomized, "basic");
|
||||
test_compile!(Risc0, Rust, "stock_nightly_no_std");
|
||||
}
|
||||
|
||||
mod sp1 {
|
||||
test_compile!(SP1, RustCustomized, "basic");
|
||||
test_compile!(SP1, Rust, "stock_nightly_no_std");
|
||||
}
|
||||
|
||||
mod ziren {
|
||||
test_compile!(Ziren, RustCustomized, "basic");
|
||||
}
|
||||
|
||||
mod zisk {
|
||||
test_compile!(Zisk, RustCustomized, "basic_rust");
|
||||
test_compile!(Zisk, GoCustomized, "basic_go");
|
||||
}
|
||||
}
|
||||
16
crates/dockerized/src/compiler/error.rs
Normal file
16
crates/dockerized/src/compiler/error.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use ere_zkvm_interface::CommonError;
|
||||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
CommonError(#[from] CommonError),
|
||||
#[error(
|
||||
"Guest directory must be in mounting directory, mounting_directory: {mounting_directory}, guest_directory: {guest_directory}"
|
||||
)]
|
||||
GuestNotInMountingDirecty {
|
||||
mounting_directory: PathBuf,
|
||||
guest_directory: PathBuf,
|
||||
},
|
||||
}
|
||||
179
crates/dockerized/src/lib.rs
Normal file
179
crates/dockerized/src/lib.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
//! # Ere Dockerized
|
||||
//!
|
||||
//! A Docker-based wrapper for other zkVM crates `ere-{zkvm}`.
|
||||
//!
|
||||
//! This crate provides a unified interface to dockerize the `Compiler` and
|
||||
//! `zkVM` implementation of other zkVM crates `ere-{zkvm}`, it requires only
|
||||
//! `docker` to be installed, but no zkVM specific SDK.
|
||||
//!
|
||||
//! ## Docker image building
|
||||
//!
|
||||
//! It builds 4 Docker images in sequence if they don't exist:
|
||||
//! 1. `ere-base:{version}` - Base image with common dependencies
|
||||
//! 2. `ere-base-{zkvm}:{version}` - zkVM-specific base image with the zkVM SDK
|
||||
//! 3. `ere-compiler-{zkvm}:{version}` - Compiler image with the `ere-compiler`
|
||||
//! binary built with the selected zkVM feature
|
||||
//! 4. `ere-server-{zkvm}:{version}` - Server image with the `ere-server` binary
|
||||
//! built with the selected zkVM feature
|
||||
//!
|
||||
//! When [`ProverResourceType::Gpu`] is selected, the image with GPU support
|
||||
//! will be built and tagged with specific suffix.
|
||||
//!
|
||||
//! To force rebuild all images, set the environment variable
|
||||
//! `ERE_FORCE_REBUILD_DOCKER_IMAGE` to non-empty value.
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! use ere_dockerized::{CompilerKind, DockerizedCompiler, DockerizedzkVM, zkVMKind};
|
||||
//! use ere_zkvm_interface::{
|
||||
//! compiler::Compiler,
|
||||
//! zkvm::{ProofKind, ProverResourceType, zkVM},
|
||||
//! };
|
||||
//! use std::path::Path;
|
||||
//!
|
||||
//! // The zkVM we plan to use
|
||||
//! let zkvm_kind = zkVMKind::SP1;
|
||||
//!
|
||||
//! // The compiler we plan to use
|
||||
//! let compiler_kind = CompilerKind::RustCustomized;
|
||||
//!
|
||||
//! // Compile a guest program
|
||||
//! let compiler = DockerizedCompiler::new(zkvm_kind, compiler_kind, "mounting/directory")?;
|
||||
//! let guest_path = Path::new("relative/path/to/guest/program");
|
||||
//! let program = compiler.compile(&guest_path)?;
|
||||
//!
|
||||
//! // Create zkVM instance
|
||||
//! let resource = ProverResourceType::Cpu;
|
||||
//! let zkvm = DockerizedzkVM::new(zkvm_kind, program, resource)?;
|
||||
//!
|
||||
//! // Serialize input
|
||||
//! let input = 42u32.to_le_bytes();
|
||||
//!
|
||||
//! // Execute program
|
||||
//! let (public_values, execution_report) = zkvm.execute(&input)?;
|
||||
//! println!("Execution cycles: {}", execution_report.total_num_cycles);
|
||||
//!
|
||||
//! // Generate proof
|
||||
//! let (public_values, proof, proving_report) = zkvm.prove(&input, ProofKind::Compressed)?;
|
||||
//! println!("Proof generated in: {:?}", proving_report.proving_time);
|
||||
//!
|
||||
//! // Verify proof
|
||||
//! let public_values = zkvm.verify(&proof)?;
|
||||
//! println!("Proof verified successfully!");
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
mod util;
|
||||
|
||||
pub mod compiler;
|
||||
pub mod zkvm;
|
||||
|
||||
pub use crate::{
|
||||
compiler::{DockerizedCompiler, SerializedProgram},
|
||||
zkvm::DockerizedzkVM,
|
||||
};
|
||||
pub use ere_compiler::CompilerKind;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/crate_version.rs"));
|
||||
include!(concat!(env!("OUT_DIR"), "/zkvm_sdk_version_impl.rs"));
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum zkVMKind {
|
||||
Airbender,
|
||||
Jolt,
|
||||
Miden,
|
||||
Nexus,
|
||||
OpenVM,
|
||||
Pico,
|
||||
Risc0,
|
||||
SP1,
|
||||
Ziren,
|
||||
Zisk,
|
||||
}
|
||||
|
||||
impl zkVMKind {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Airbender => "airbender",
|
||||
Self::Jolt => "jolt",
|
||||
Self::Miden => "miden",
|
||||
Self::Nexus => "nexus",
|
||||
Self::OpenVM => "openvm",
|
||||
Self::Pico => "pico",
|
||||
Self::Risc0 => "risc0",
|
||||
Self::SP1 => "sp1",
|
||||
Self::Ziren => "ziren",
|
||||
Self::Zisk => "zisk",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for zkVMKind {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(match s {
|
||||
"airbender" => Self::Airbender,
|
||||
"jolt" => Self::Jolt,
|
||||
"miden" => Self::Miden,
|
||||
"nexus" => Self::Nexus,
|
||||
"openvm" => Self::OpenVM,
|
||||
"pico" => Self::Pico,
|
||||
"risc0" => Self::Risc0,
|
||||
"sp1" => Self::SP1,
|
||||
"ziren" => Self::Ziren,
|
||||
"zisk" => Self::Zisk,
|
||||
_ => return Err(format!("Unsupported zkvm kind {s}")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for zkVMKind {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// Tag of images in format of `{version}{suffix}`.
|
||||
fn image_tag(zkvm_kind: zkVMKind, gpu: bool) -> String {
|
||||
let suffix = match (zkvm_kind, gpu) {
|
||||
// Only the following zkVMs requires CUDA setup in the base image
|
||||
// when GPU support is required.
|
||||
(zkVMKind::Airbender | zkVMKind::OpenVM | zkVMKind::Risc0 | zkVMKind::Zisk, true) => {
|
||||
"-cuda"
|
||||
}
|
||||
_ => "",
|
||||
};
|
||||
format!("{CRATE_VERSION}{suffix}")
|
||||
}
|
||||
|
||||
fn base_image(zkvm_kind: zkVMKind, gpu: bool) -> String {
|
||||
let image_tag = image_tag(zkvm_kind, gpu);
|
||||
format!("ere-base:{image_tag}")
|
||||
}
|
||||
|
||||
fn base_zkvm_image(zkvm_kind: zkVMKind, gpu: bool) -> String {
|
||||
let image_tag = image_tag(zkvm_kind, gpu);
|
||||
format!("ere-base-{zkvm_kind}:{image_tag}")
|
||||
}
|
||||
|
||||
fn server_zkvm_image(zkvm_kind: zkVMKind, gpu: bool) -> String {
|
||||
let image_tag = image_tag(zkvm_kind, gpu);
|
||||
format!("ere-server-{zkvm_kind}:{image_tag}")
|
||||
}
|
||||
|
||||
fn compiler_zkvm_image(zkvm_kind: zkVMKind) -> String {
|
||||
let image_tag = image_tag(zkvm_kind, false);
|
||||
format!("ere-compiler-{zkvm_kind}:{image_tag}")
|
||||
}
|
||||
15
crates/dockerized/src/util.rs
Normal file
15
crates/dockerized/src/util.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub mod cuda;
|
||||
pub mod docker;
|
||||
|
||||
pub fn workspace_dir() -> PathBuf {
|
||||
let mut dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
dir.pop();
|
||||
dir.pop();
|
||||
dir.canonicalize().unwrap()
|
||||
}
|
||||
|
||||
pub fn home_dir() -> PathBuf {
|
||||
PathBuf::from(std::env::var("HOME").expect("env `$HOME` should be set"))
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
use crate::error::Error;
|
||||
use ere_zkvm_interface::CommonError;
|
||||
use std::{
|
||||
env,
|
||||
fmt::{self, Display, Formatter},
|
||||
io::{self, Write},
|
||||
io::Write,
|
||||
path::Path,
|
||||
process::{Child, Command, Stdio},
|
||||
};
|
||||
use tracing::debug;
|
||||
|
||||
pub const DOCKER_SOCKET: &str = "/var/run/docker.sock";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CmdOption(String, Option<String>);
|
||||
struct CmdOption(String, Option<String>);
|
||||
|
||||
impl CmdOption {
|
||||
pub fn new(key: impl AsRef<str>, value: impl AsRef<str>) -> Self {
|
||||
@@ -78,7 +79,7 @@ impl DockerBuildCmd {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exec(self, context: impl AsRef<Path>) -> Result<(), io::Error> {
|
||||
pub fn exec(self, context: impl AsRef<Path>) -> Result<(), CommonError> {
|
||||
let mut cmd = Command::new("docker");
|
||||
cmd.arg("build");
|
||||
for option in self.options {
|
||||
@@ -86,12 +87,14 @@ impl DockerBuildCmd {
|
||||
}
|
||||
cmd.arg(context.as_ref().to_string_lossy().to_string());
|
||||
|
||||
let status = cmd.status()?;
|
||||
debug!("Docker build with command: {cmd:?}");
|
||||
|
||||
let status = cmd
|
||||
.status()
|
||||
.map_err(|err| CommonError::command(&cmd, err))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(io::Error::other(format!(
|
||||
"Command {cmd:?} failed with status: {status}",
|
||||
)));
|
||||
Err(CommonError::command_exit_non_zero(&cmd, status, None))?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -177,7 +180,7 @@ impl DockerRunCmd {
|
||||
mut self,
|
||||
commands: impl IntoIterator<Item: AsRef<str>>,
|
||||
stdin: &[u8],
|
||||
) -> Result<Child, io::Error> {
|
||||
) -> Result<Child, CommonError> {
|
||||
self = self.flag("interactive");
|
||||
|
||||
let mut cmd = Command::new("docker");
|
||||
@@ -190,15 +193,25 @@ impl DockerRunCmd {
|
||||
cmd.arg(command.as_ref());
|
||||
}
|
||||
|
||||
let mut child = cmd.stdin(Stdio::piped()).spawn()?;
|
||||
debug!("Docker run with command: {cmd:?}");
|
||||
|
||||
let mut child = cmd
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()
|
||||
.map_err(|err| CommonError::command(&cmd, err))?;
|
||||
|
||||
// Write all to stdin then drop to close the pipe.
|
||||
child.stdin.take().unwrap().write_all(stdin)?;
|
||||
child
|
||||
.stdin
|
||||
.take()
|
||||
.unwrap()
|
||||
.write_all(stdin)
|
||||
.map_err(|err| CommonError::command(&cmd, err))?;
|
||||
|
||||
Ok(child)
|
||||
}
|
||||
|
||||
pub fn exec(self, commands: impl IntoIterator<Item: AsRef<str>>) -> Result<(), io::Error> {
|
||||
pub fn exec(self, commands: impl IntoIterator<Item: AsRef<str>>) -> Result<(), CommonError> {
|
||||
let mut cmd = Command::new("docker");
|
||||
cmd.arg("run");
|
||||
for option in self.options {
|
||||
@@ -209,43 +222,61 @@ impl DockerRunCmd {
|
||||
cmd.arg(command.as_ref());
|
||||
}
|
||||
|
||||
let status = cmd.status()?;
|
||||
debug!("Docker run with command: {cmd:?}");
|
||||
|
||||
let status = cmd
|
||||
.status()
|
||||
.map_err(|err| CommonError::command(&cmd, err))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(io::Error::other(format!(
|
||||
"Command {cmd:?} failed with status: {status}",
|
||||
)));
|
||||
Err(CommonError::command_exit_non_zero(&cmd, status, None))?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop_docker_container(container_name: impl AsRef<str>) -> Result<(), Error> {
|
||||
let output = Command::new("docker")
|
||||
pub fn stop_docker_container(container_name: impl AsRef<str>) -> Result<(), CommonError> {
|
||||
let mut cmd = Command::new("docker");
|
||||
let output = cmd
|
||||
.args(["container", "stop", container_name.as_ref()])
|
||||
.output()
|
||||
.map_err(Error::DockerContainerCmd)?;
|
||||
.map_err(|err| CommonError::command(&cmd, err))?;
|
||||
|
||||
if String::from_utf8_lossy(&output.stdout).starts_with("Error") {
|
||||
return Err(Error::DockerContainerCmd(io::Error::other(format!(
|
||||
"Failed to stop container {}",
|
||||
container_name.as_ref()
|
||||
))));
|
||||
if !output.status.success() {
|
||||
Err(CommonError::command_exit_non_zero(
|
||||
&cmd,
|
||||
output.status,
|
||||
Some(&output),
|
||||
))?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn docker_image_exists(image: impl AsRef<str>) -> Result<bool, Error> {
|
||||
let output = Command::new("docker")
|
||||
pub fn docker_image_exists(image: impl AsRef<str>) -> Result<bool, CommonError> {
|
||||
let mut cmd = Command::new("docker");
|
||||
let output = cmd
|
||||
.args(["images", "--quiet", image.as_ref()])
|
||||
.output()
|
||||
.map_err(Error::DockerImageCmd)?;
|
||||
.map_err(|err| CommonError::command(&cmd, err))?;
|
||||
|
||||
if !output.status.success() {
|
||||
Err(CommonError::command_exit_non_zero(
|
||||
&cmd,
|
||||
output.status,
|
||||
Some(&output),
|
||||
))?
|
||||
}
|
||||
|
||||
// If image exists, image id will be printed hence stdout will be non-empty.
|
||||
Ok(!output.stdout.is_empty())
|
||||
}
|
||||
|
||||
pub fn force_rebuild() -> bool {
|
||||
env::var_os("ERE_FORCE_REBUILD_DOCKER_IMAGE").is_some()
|
||||
}
|
||||
|
||||
fn to_string(s: impl AsRef<str>) -> String {
|
||||
s.as_ref().to_string()
|
||||
}
|
||||
467
crates/dockerized/src/zkvm.rs
Normal file
467
crates/dockerized/src/zkvm.rs
Normal file
@@ -0,0 +1,467 @@
|
||||
use crate::{
|
||||
base_image, base_zkvm_image,
|
||||
compiler::SerializedProgram,
|
||||
server_zkvm_image,
|
||||
util::{
|
||||
cuda::cuda_arch,
|
||||
docker::{
|
||||
DockerBuildCmd, DockerRunCmd, docker_image_exists, force_rebuild, stop_docker_container,
|
||||
},
|
||||
home_dir, workspace_dir,
|
||||
},
|
||||
zkVMKind,
|
||||
};
|
||||
use ere_server::client::{Url, zkVMClient};
|
||||
use ere_zkvm_interface::{
|
||||
CommonError,
|
||||
zkvm::{
|
||||
ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType,
|
||||
PublicValues, zkVM,
|
||||
},
|
||||
};
|
||||
use std::iter;
|
||||
use tempfile::TempDir;
|
||||
use tracing::{error, info};
|
||||
|
||||
mod error;
|
||||
|
||||
pub use error::Error;
|
||||
|
||||
/// This method builds 3 Docker images in sequence:
|
||||
/// 1. `ere-base:{version}` - Base image with common dependencies
|
||||
/// 2. `ere-base-{zkvm}:{version}` - zkVM-specific base image with the zkVM SDK
|
||||
/// 3. `ere-server-{zkvm}:{version}` - Server image with the `ere-server` binary
|
||||
/// built with the selected zkVM feature
|
||||
///
|
||||
/// When [`ProverResourceType::Gpu`] is selected, the image with GPU support
|
||||
/// will be built and tagged with specific suffix.
|
||||
///
|
||||
/// Images are cached and only rebuilt if they don't exist or if the
|
||||
/// `ERE_FORCE_REBUILD_DOCKER_IMAGE` environment variable is set.
|
||||
fn build_server_image(zkvm_kind: zkVMKind, gpu: bool) -> Result<(), Error> {
|
||||
let workspace_dir = workspace_dir();
|
||||
let docker_dir = workspace_dir.join("docker");
|
||||
let docker_zkvm_dir = docker_dir.join(zkvm_kind.as_str());
|
||||
|
||||
let force_rebuild = force_rebuild();
|
||||
let base_image = base_image(zkvm_kind, gpu);
|
||||
let base_zkvm_image = base_zkvm_image(zkvm_kind, gpu);
|
||||
let server_zkvm_image = server_zkvm_image(zkvm_kind, gpu);
|
||||
|
||||
// Build `ere-base`
|
||||
if force_rebuild || !docker_image_exists(&base_image)? {
|
||||
info!("Building image {base_image}...");
|
||||
|
||||
let mut cmd = DockerBuildCmd::new()
|
||||
.file(docker_dir.join("Dockerfile.base"))
|
||||
.tag(&base_image);
|
||||
|
||||
if gpu {
|
||||
cmd = cmd.build_arg("CUDA", "1");
|
||||
}
|
||||
|
||||
cmd.exec(&workspace_dir)?;
|
||||
}
|
||||
|
||||
// Build `ere-base-{zkvm_kind}`
|
||||
if force_rebuild || !docker_image_exists(&base_zkvm_image)? {
|
||||
info!("Building image {base_zkvm_image}...");
|
||||
|
||||
let mut cmd = DockerBuildCmd::new()
|
||||
.file(docker_zkvm_dir.join("Dockerfile.base"))
|
||||
.tag(&base_zkvm_image)
|
||||
.build_arg("BASE_IMAGE", &base_image)
|
||||
.build_arg_from_env("RUSTFLAGS");
|
||||
|
||||
if gpu {
|
||||
cmd = cmd.build_arg("CUDA", "1");
|
||||
|
||||
match zkvm_kind {
|
||||
zkVMKind::Airbender | zkVMKind::OpenVM | zkVMKind::Risc0 | zkVMKind::Zisk => {
|
||||
if let Some(cuda_arch) = cuda_arch() {
|
||||
cmd = cmd.build_arg("CUDA_ARCH", cuda_arch)
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
cmd.exec(&workspace_dir)?;
|
||||
}
|
||||
|
||||
// Build `ere-server-{zkvm_kind}`
|
||||
if force_rebuild || !docker_image_exists(&server_zkvm_image)? {
|
||||
info!("Building image {server_zkvm_image}...");
|
||||
|
||||
let mut cmd = DockerBuildCmd::new()
|
||||
.file(docker_zkvm_dir.join("Dockerfile.server"))
|
||||
.tag(&server_zkvm_image)
|
||||
.build_arg("BASE_ZKVM_IMAGE", &base_zkvm_image)
|
||||
.build_arg_from_env("RUSTFLAGS");
|
||||
|
||||
if gpu {
|
||||
cmd = cmd.build_arg("CUDA", "1");
|
||||
}
|
||||
|
||||
cmd.exec(&workspace_dir)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct ServerContainer {
|
||||
name: String,
|
||||
port: u16,
|
||||
#[allow(dead_code)]
|
||||
tempdir: TempDir,
|
||||
}
|
||||
|
||||
impl Drop for ServerContainer {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = stop_docker_container(&self.name) {
|
||||
error!("Failed to stop docker container: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerContainer {
|
||||
/// Offset of port used for `ere-server`.
|
||||
const PORT_OFFSET: u16 = 4174;
|
||||
|
||||
fn new(
|
||||
zkvm_kind: zkVMKind,
|
||||
program: &SerializedProgram,
|
||||
resource: &ProverResourceType,
|
||||
) -> Result<Self, Error> {
|
||||
let port = Self::PORT_OFFSET + zkvm_kind as u16;
|
||||
|
||||
let name = format!("ere-server-{zkvm_kind}-{port}");
|
||||
let gpu = matches!(resource, ProverResourceType::Gpu);
|
||||
let mut cmd = DockerRunCmd::new(server_zkvm_image(zkvm_kind, gpu))
|
||||
.rm()
|
||||
.inherit_env("RUST_LOG")
|
||||
.inherit_env("NO_COLOR")
|
||||
.publish(port.to_string(), port.to_string())
|
||||
.name(&name);
|
||||
|
||||
// zkVM specific options
|
||||
cmd = match zkvm_kind {
|
||||
zkVMKind::Risc0 => cmd
|
||||
.inherit_env("RISC0_SEGMENT_PO2")
|
||||
.inherit_env("RISC0_KECCAK_PO2"),
|
||||
// ZisK uses shared memory to exchange data between processes, it
|
||||
// requires at least 8G shared memory, here we set 16G for safety.
|
||||
zkVMKind::Zisk => cmd
|
||||
.option("shm-size", "16G")
|
||||
.option("ulimit", "memlock=-1:-1")
|
||||
.inherit_env("ZISK_PORT")
|
||||
.inherit_env("ZISK_CHUNK_SIZE_BITS")
|
||||
.inherit_env("ZISK_UNLOCK_MAPPED_MEMORY")
|
||||
.inherit_env("ZISK_MINIMAL_MEMORY")
|
||||
.inherit_env("ZISK_PREALLOCATE")
|
||||
.inherit_env("ZISK_SHARED_TABLES")
|
||||
.inherit_env("ZISK_MAX_STREAMS")
|
||||
.inherit_env("ZISK_NUMBER_THREADS_WITNESS")
|
||||
.inherit_env("ZISK_MAX_WITNESS_STORED"),
|
||||
_ => cmd,
|
||||
};
|
||||
|
||||
// zkVM specific options when using GPU
|
||||
if gpu {
|
||||
cmd = match zkvm_kind {
|
||||
zkVMKind::Airbender => cmd.gpus("all"),
|
||||
zkVMKind::OpenVM => cmd.gpus("all"),
|
||||
// SP1 runs docker command to spin up the server to do GPU
|
||||
// proving, to give the client access to the prover service, we
|
||||
// need to use the host networking driver.
|
||||
zkVMKind::SP1 => cmd.mount_docker_socket().network("host"),
|
||||
zkVMKind::Risc0 => cmd.gpus("all").inherit_env("RISC0_DEFAULT_PROVER_NUM_GPUS"),
|
||||
zkVMKind::Zisk => cmd.gpus("all"),
|
||||
_ => cmd,
|
||||
}
|
||||
}
|
||||
|
||||
let tempdir = TempDir::new().map_err(CommonError::tempdir)?;
|
||||
|
||||
// zkVM specific options needed for proving Groth16 proof.
|
||||
cmd = match zkvm_kind {
|
||||
// Risc0 and SP1 runs docker command to prove Groth16 proof, and
|
||||
// they pass the input by mounting temporary directory. Here we
|
||||
// create a temporary directory and mount it on the top level, so
|
||||
// the volume could be shared, and override `TMPDIR` so we don't
|
||||
// need to mount the whole `/tmp`.
|
||||
zkVMKind::Risc0 => cmd
|
||||
.mount_docker_socket()
|
||||
.env("TMPDIR", tempdir.path().to_string_lossy())
|
||||
.volume(tempdir.path(), tempdir.path()),
|
||||
zkVMKind::SP1 => {
|
||||
let groth16_circuit_path = home_dir().join(".sp1").join("circuits").join("groth16");
|
||||
cmd.mount_docker_socket()
|
||||
.env(
|
||||
"SP1_GROTH16_CIRCUIT_PATH",
|
||||
groth16_circuit_path.to_string_lossy(),
|
||||
)
|
||||
.env("TMPDIR", tempdir.path().to_string_lossy())
|
||||
.volume(tempdir.path(), tempdir.path())
|
||||
.volume(&groth16_circuit_path, &groth16_circuit_path)
|
||||
}
|
||||
_ => cmd,
|
||||
};
|
||||
|
||||
cmd.spawn(
|
||||
iter::empty()
|
||||
.chain(["--port", &port.to_string()])
|
||||
.chain(resource.to_args()),
|
||||
&program.0,
|
||||
)?;
|
||||
|
||||
Ok(ServerContainer {
|
||||
name,
|
||||
port,
|
||||
tempdir,
|
||||
})
|
||||
}
|
||||
|
||||
fn endpoint(&self) -> Url {
|
||||
Url::parse(&format!("http://127.0.0.1:{}", self.port)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DockerizedzkVM {
|
||||
zkvm_kind: zkVMKind,
|
||||
program: SerializedProgram,
|
||||
resource: ProverResourceType,
|
||||
#[allow(dead_code)]
|
||||
server_container: ServerContainer,
|
||||
client: zkVMClient,
|
||||
}
|
||||
|
||||
impl DockerizedzkVM {
|
||||
pub fn new(
|
||||
zkvm_kind: zkVMKind,
|
||||
program: SerializedProgram,
|
||||
resource: ProverResourceType,
|
||||
) -> Result<Self, Error> {
|
||||
build_server_image(zkvm_kind, matches!(resource, ProverResourceType::Gpu))?;
|
||||
|
||||
let server_container = ServerContainer::new(zkvm_kind, &program, &resource)?;
|
||||
let client = block_on(zkVMClient::new(server_container.endpoint()))?;
|
||||
|
||||
Ok(Self {
|
||||
zkvm_kind,
|
||||
program,
|
||||
resource,
|
||||
server_container,
|
||||
client,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn zkvm_kind(&self) -> zkVMKind {
|
||||
self.zkvm_kind
|
||||
}
|
||||
|
||||
pub fn program(&self) -> &SerializedProgram {
|
||||
&self.program
|
||||
}
|
||||
|
||||
pub fn resource(&self) -> &ProverResourceType {
|
||||
&self.resource
|
||||
}
|
||||
}
|
||||
|
||||
impl zkVM for DockerizedzkVM {
|
||||
fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> {
|
||||
let (public_values, report) =
|
||||
block_on(self.client.execute(input.to_vec())).map_err(Error::from)?;
|
||||
|
||||
Ok((public_values, report))
|
||||
}
|
||||
|
||||
fn prove(
|
||||
&self,
|
||||
input: &[u8],
|
||||
proof_kind: ProofKind,
|
||||
) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> {
|
||||
let (public_values, proof, report) =
|
||||
block_on(self.client.prove(input.to_vec(), proof_kind)).map_err(Error::from)?;
|
||||
|
||||
Ok((public_values, proof, report))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &Proof) -> anyhow::Result<PublicValues> {
|
||||
let public_values = block_on(self.client.verify(proof)).map_err(Error::from)?;
|
||||
|
||||
Ok(public_values)
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
self.zkvm_kind.as_str()
|
||||
}
|
||||
|
||||
fn sdk_version(&self) -> &'static str {
|
||||
self.zkvm_kind.sdk_version()
|
||||
}
|
||||
}
|
||||
|
||||
fn block_on<T>(future: impl Future<Output = T>) -> T {
|
||||
match tokio::runtime::Handle::try_current() {
|
||||
Ok(handle) => tokio::task::block_in_place(|| handle.block_on(future)),
|
||||
Err(_) => tokio::runtime::Runtime::new().unwrap().block_on(future),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{
|
||||
CompilerKind,
|
||||
compiler::test::compile,
|
||||
zkVMKind,
|
||||
zkvm::{DockerizedzkVM, Error},
|
||||
};
|
||||
use ere_test_utils::{host::*, program::basic::BasicProgramInput};
|
||||
use ere_zkvm_interface::zkvm::{ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
fn zkvm(
|
||||
zkvm_kind: zkVMKind,
|
||||
compiler_kind: CompilerKind,
|
||||
program: &'static str,
|
||||
) -> DockerizedzkVM {
|
||||
let program = compile(zkvm_kind, compiler_kind, program).clone();
|
||||
DockerizedzkVM::new(zkvm_kind, program, ProverResourceType::Cpu).unwrap()
|
||||
}
|
||||
|
||||
macro_rules! test {
|
||||
($zkvm_kind:ident, $compiler_kind:ident, $program:literal, $valid_test_cases:expr, $invalid_test_cases:expr) => {
|
||||
#[test]
|
||||
fn test_execute() {
|
||||
let zkvm = zkvm(zkVMKind::$zkvm_kind, CompilerKind::$compiler_kind, $program);
|
||||
|
||||
// Valid test cases
|
||||
for test_case in $valid_test_cases {
|
||||
run_zkvm_execute(&zkvm, &test_case);
|
||||
}
|
||||
|
||||
// Invalid test cases
|
||||
for input in $invalid_test_cases {
|
||||
let err = zkvm.execute(&input).unwrap_err();
|
||||
assert!(matches!(err.downcast::<Error>().unwrap(), Error::zkVM(_)));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prove() {
|
||||
let zkvm = zkvm(zkVMKind::$zkvm_kind, CompilerKind::$compiler_kind, $program);
|
||||
|
||||
// Valid test cases
|
||||
for test_case in $valid_test_cases {
|
||||
run_zkvm_prove(&zkvm, &test_case);
|
||||
}
|
||||
|
||||
// Invalid test cases
|
||||
for input in $invalid_test_cases {
|
||||
let err = zkvm.prove(&input, ProofKind::default()).unwrap_err();
|
||||
assert!(matches!(err.downcast::<Error>().unwrap(), Error::zkVM(_)));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mod airbender {
|
||||
use super::*;
|
||||
test!(
|
||||
Airbender,
|
||||
Rust,
|
||||
"basic",
|
||||
[BasicProgramInput::valid().into_output_sha256()],
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod jolt {
|
||||
use super::*;
|
||||
test!(
|
||||
Jolt,
|
||||
RustCustomized,
|
||||
"basic",
|
||||
[BasicProgramInput::valid()],
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod nexus {
|
||||
use super::*;
|
||||
test!(
|
||||
Nexus,
|
||||
Rust,
|
||||
"basic",
|
||||
[BasicProgramInput::valid()],
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod openvm {
|
||||
use super::*;
|
||||
test!(
|
||||
OpenVM,
|
||||
RustCustomized,
|
||||
"basic",
|
||||
[BasicProgramInput::valid().into_output_sha256()],
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod pico {
|
||||
use super::*;
|
||||
test!(
|
||||
Pico,
|
||||
RustCustomized,
|
||||
"basic",
|
||||
[BasicProgramInput::valid()],
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod risc0 {
|
||||
use super::*;
|
||||
test!(
|
||||
Risc0,
|
||||
RustCustomized,
|
||||
"basic",
|
||||
[BasicProgramInput::valid()],
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod sp1 {
|
||||
use super::*;
|
||||
test!(
|
||||
SP1,
|
||||
RustCustomized,
|
||||
"basic",
|
||||
[BasicProgramInput::valid()],
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod ziren {
|
||||
use super::*;
|
||||
test!(
|
||||
Ziren,
|
||||
RustCustomized,
|
||||
"basic",
|
||||
[BasicProgramInput::valid()],
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
|
||||
mod zisk {
|
||||
use super::*;
|
||||
test!(
|
||||
Zisk,
|
||||
RustCustomized,
|
||||
"basic_rust",
|
||||
[BasicProgramInput::valid().into_output_sha256()],
|
||||
[Vec::new(), BasicProgramInput::invalid().serialized_input()]
|
||||
);
|
||||
}
|
||||
}
|
||||
26
crates/dockerized/src/zkvm/error.rs
Normal file
26
crates/dockerized/src/zkvm/error.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use ere_server::client::{self, TwirpErrorResponse};
|
||||
use ere_zkvm_interface::CommonError;
|
||||
use thiserror::Error;
|
||||
|
||||
impl From<client::Error> for Error {
|
||||
fn from(value: client::Error) -> Self {
|
||||
match value {
|
||||
client::Error::zkVM(err) => Self::zkVM(err),
|
||||
client::Error::ConnectionTimeout => Self::ConnectionTimeout,
|
||||
client::Error::Rpc(err) => Self::Rpc(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
CommonError(#[from] CommonError),
|
||||
#[error("zkVM method error: {0}")]
|
||||
zkVM(String),
|
||||
#[error("Connection to zkVM server timeout after 5 minutes")]
|
||||
ConnectionTimeout,
|
||||
#[error("RPC to zkVM server error: {0}")]
|
||||
Rpc(TwirpErrorResponse),
|
||||
}
|
||||
@@ -80,12 +80,12 @@ impl CommonError {
|
||||
|
||||
pub fn read_file(id: impl AsRef<str>, path: impl AsRef<Path>, err: io::Error) -> Self {
|
||||
let (id, path) = (id.as_ref(), path.as_ref().display());
|
||||
Self::io(format!("Failed to write {id} to {path}"), err)
|
||||
Self::io(format!("Failed to read {id} from {path}"), err)
|
||||
}
|
||||
|
||||
pub fn write_file(id: impl AsRef<str>, path: impl AsRef<Path>, err: io::Error) -> Self {
|
||||
let (id, path) = (id.as_ref(), path.as_ref().display());
|
||||
Self::io(format!("Failed to read {id} from {path}"), err)
|
||||
Self::io(format!("Failed to write {id} to {path}"), err)
|
||||
}
|
||||
|
||||
pub fn serialize(
|
||||
|
||||
@@ -14,11 +14,11 @@ toml.workspace = true
|
||||
|
||||
# OpenVM dependencies
|
||||
openvm-build.workspace = true
|
||||
openvm-circuit.workspace = true
|
||||
openvm-continuations.workspace = true
|
||||
openvm-sdk = { workspace = true, features = ["nightly-features"] }
|
||||
openvm-stark-sdk.workspace = true
|
||||
openvm-transpiler.workspace = true
|
||||
openvm-circuit = { workspace = true, optional = true }
|
||||
openvm-continuations = { workspace = true, optional = true }
|
||||
openvm-sdk = { workspace = true, features = ["nightly-features"], optional = true }
|
||||
openvm-stark-sdk = { workspace = true, optional = true }
|
||||
openvm-transpiler = { workspace = true, optional = true }
|
||||
|
||||
# Local dependencies
|
||||
ere-compile-utils = { workspace = true, optional = true }
|
||||
@@ -33,7 +33,13 @@ ere-build-utils.workspace = true
|
||||
[features]
|
||||
default = ["compiler", "zkvm"]
|
||||
compiler = ["dep:ere-compile-utils"]
|
||||
zkvm = []
|
||||
zkvm = [
|
||||
"dep:openvm-circuit",
|
||||
"dep:openvm-continuations",
|
||||
"dep:openvm-sdk",
|
||||
"dep:openvm-stark-sdk",
|
||||
"dep:openvm-transpiler",
|
||||
]
|
||||
cuda = ["openvm-sdk/cuda"]
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
use ere_compile_utils::CommonError;
|
||||
use openvm_sdk::config::{AppConfig, DEFAULT_APP_LOG_BLOWUP, DEFAULT_LEAF_LOG_BLOWUP, SdkVmConfig};
|
||||
use openvm_stark_sdk::config::FriParameters;
|
||||
use std::{fs, path::Path};
|
||||
|
||||
mod error;
|
||||
@@ -11,30 +9,14 @@ pub use error::Error;
|
||||
pub use rust_rv32ima::RustRv32ima;
|
||||
pub use rust_rv32ima_customized::RustRv32imaCustomized;
|
||||
|
||||
fn read_app_config(app_config_path: impl AsRef<Path>) -> Result<AppConfig<SdkVmConfig>, Error> {
|
||||
Ok(if app_config_path.as_ref().exists() {
|
||||
let toml = fs::read_to_string(app_config_path.as_ref())
|
||||
.map_err(|err| CommonError::read_file("app_config", &app_config_path, err))?;
|
||||
toml::from_str(&toml).map_err(|err| CommonError::deserialize("app_config", "toml", err))?
|
||||
} else {
|
||||
// The default `AppConfig` copied from https://github.com/openvm-org/openvm/blob/v1.4.1/crates/cli/src/default.rs#L35.
|
||||
AppConfig {
|
||||
app_fri_params: FriParameters::standard_with_100_bits_conjectured_security(
|
||||
DEFAULT_APP_LOG_BLOWUP,
|
||||
)
|
||||
.into(),
|
||||
// By default it supports RISCV32IM with IO but no precompiles.
|
||||
app_vm_config: SdkVmConfig::builder()
|
||||
.system(Default::default())
|
||||
.rv32i(Default::default())
|
||||
.rv32m(Default::default())
|
||||
.io(Default::default())
|
||||
.build(),
|
||||
leaf_fri_params: FriParameters::standard_with_100_bits_conjectured_security(
|
||||
DEFAULT_LEAF_LOG_BLOWUP,
|
||||
)
|
||||
.into(),
|
||||
compiler_options: Default::default(),
|
||||
}
|
||||
})
|
||||
fn read_app_config(app_config_path: impl AsRef<Path>) -> Result<Option<String>, Error> {
|
||||
if !app_config_path.as_ref().exists() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let value = fs::read_to_string(app_config_path.as_ref())
|
||||
.map_err(|err| CommonError::read_file("app_config", &app_config_path, err))?;
|
||||
toml::from_str::<toml::Value>(&value)
|
||||
.map_err(|err| CommonError::deserialize("app_config", "toml", err))?;
|
||||
Ok(Some(value))
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use openvm_sdk::config::{AppConfig, SdkVmConfig};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// OpenVM program that contains ELF of compiled guest and app config.
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct OpenVMProgram {
|
||||
pub(crate) elf: Vec<u8>,
|
||||
pub(crate) app_config: AppConfig<SdkVmConfig>,
|
||||
pub(crate) app_config: Option<String>,
|
||||
}
|
||||
|
||||
impl OpenVMProgram {
|
||||
@@ -13,7 +12,7 @@ impl OpenVMProgram {
|
||||
&self.elf
|
||||
}
|
||||
|
||||
pub fn app_config(&self) -> &AppConfig<SdkVmConfig> {
|
||||
&self.app_config
|
||||
pub fn app_config(&self) -> Option<&str> {
|
||||
self.app_config.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ use openvm_sdk::{
|
||||
CpuSdk, F, SC, StdIn,
|
||||
codec::{Decode, Encode},
|
||||
commit::AppExecutionCommit,
|
||||
config::{AppConfig, SdkVmConfig},
|
||||
config::{AppConfig, DEFAULT_APP_LOG_BLOWUP, DEFAULT_LEAF_LOG_BLOWUP, SdkVmConfig},
|
||||
fs::read_object_from_file,
|
||||
keygen::{AggProvingKey, AggVerifyingKey, AppProvingKey},
|
||||
};
|
||||
use openvm_stark_sdk::openvm_stark_backend::p3_field::PrimeField32;
|
||||
use openvm_stark_sdk::{config::FriParameters, openvm_stark_backend::p3_field::PrimeField32};
|
||||
use openvm_transpiler::{elf::Elf, openvm_platform::memory::MEM_SIZE};
|
||||
use std::{env, path::PathBuf, sync::Arc, time::Instant};
|
||||
|
||||
@@ -49,7 +49,31 @@ impl EreOpenVM {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let sdk = CpuSdk::new(program.app_config().clone()).map_err(Error::SdkInit)?;
|
||||
let app_config = if let Some(value) = program.app_config() {
|
||||
toml::from_str(value).map_err(Error::InvalidAppConfig)?
|
||||
} else {
|
||||
// The default `AppConfig` copied from https://github.com/openvm-org/openvm/blob/v1.4.1/crates/cli/src/default.rs#L35.
|
||||
AppConfig {
|
||||
app_fri_params: FriParameters::standard_with_100_bits_conjectured_security(
|
||||
DEFAULT_APP_LOG_BLOWUP,
|
||||
)
|
||||
.into(),
|
||||
// By default it supports RISCV32IM with IO but no precompiles.
|
||||
app_vm_config: SdkVmConfig::builder()
|
||||
.system(Default::default())
|
||||
.rv32i(Default::default())
|
||||
.rv32m(Default::default())
|
||||
.io(Default::default())
|
||||
.build(),
|
||||
leaf_fri_params: FriParameters::standard_with_100_bits_conjectured_security(
|
||||
DEFAULT_LEAF_LOG_BLOWUP,
|
||||
)
|
||||
.into(),
|
||||
compiler_options: Default::default(),
|
||||
}
|
||||
};
|
||||
|
||||
let sdk = CpuSdk::new(app_config.clone()).map_err(Error::SdkInit)?;
|
||||
|
||||
let elf = Elf::decode(program.elf(), MEM_SIZE as u32).map_err(Error::ElfDecode)?;
|
||||
|
||||
@@ -69,7 +93,7 @@ impl EreOpenVM {
|
||||
.app_commit();
|
||||
|
||||
Ok(Self {
|
||||
app_config: program.app_config,
|
||||
app_config,
|
||||
app_exe,
|
||||
app_pk,
|
||||
agg_pk,
|
||||
|
||||
@@ -8,6 +8,9 @@ pub enum Error {
|
||||
CommonError(#[from] CommonError),
|
||||
|
||||
// Common
|
||||
#[error("Invalid AppConfig: {0}")]
|
||||
InvalidAppConfig(toml::de::Error),
|
||||
|
||||
#[error("Initialize SDK failed: {0}")]
|
||||
SdkInit(SdkError),
|
||||
|
||||
|
||||
@@ -44,13 +44,6 @@ ENV RUSTUP_HOME=/usr/local/rustup \
|
||||
|
||||
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain ${RUST_VERSION} --no-modify-path
|
||||
|
||||
# Copy the TamaGo installer script from the workspace context
|
||||
COPY --chmod=755 scripts/install_tamago.sh /tmp/install_tamago.sh
|
||||
|
||||
# Run the TamaGo installation script.
|
||||
RUN /tmp/install_tamago.sh && \
|
||||
rm /tmp/install_tamago.sh
|
||||
|
||||
# Add a non-root user for subsequent stages or use in derived images
|
||||
# This is generally best practice.
|
||||
ARG USERNAME=ere_user
|
||||
@@ -1,16 +1,11 @@
|
||||
ARG BASE_IMAGE=ere-base:latest
|
||||
ARG BASE_CUDA_IMAGE=ere-base:latest-cuda
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
FROM $BASE_IMAGE AS base
|
||||
FROM $BASE_CUDA_IMAGE AS base_cuda
|
||||
FROM base${CUDA:+_cuda}
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
# Set default toolchain to nightly
|
||||
RUN rustup default nightly
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
# Default to build for RTX 50 series
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features airbender \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
ARG BASE_ZKVM_IMAGE=ere-base-airbender:latest
|
||||
ARG BASE_ZKVM_CUDA_IMAGE=ere-base-airbender:latest-cuda
|
||||
ARG RUNTIME_IMAGE=ubuntu:24.04
|
||||
ARG RUNTIME_CUDA_IMAGE=nvidia/cuda:12.9.1-runtime-ubuntu24.04
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
FROM $BASE_ZKVM_IMAGE AS base
|
||||
FROM $BASE_ZKVM_CUDA_IMAGE AS base_cuda
|
||||
FROM base${CUDA:+_cuda} AS build_stage
|
||||
FROM $BASE_ZKVM_IMAGE AS build_stage
|
||||
|
||||
COPY . /ere
|
||||
|
||||
@@ -19,7 +16,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features airbender${CUDA:+,cuda} \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime
|
||||
FROM $RUNTIME_CUDA_IMAGE AS runtime_cuda
|
||||
|
||||
@@ -5,9 +5,6 @@ FROM $BASE_IMAGE
|
||||
# The ere-base image provides Rust, Cargo (with a default nightly), and common tools.
|
||||
# We operate as root for SDK installation.
|
||||
|
||||
# Set default toolchain to 1.88.0
|
||||
RUN rustup default 1.88.0
|
||||
|
||||
# Copy the Jolt SDK (CLI) installer script from the workspace context
|
||||
COPY --chmod=755 scripts/sdk_installers/install_jolt_sdk.sh /tmp/install_jolt_sdk.sh
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features jolt \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features jolt \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features miden \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features miden \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features nexus \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features nexus \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
ARG BASE_IMAGE=ere-base:latest
|
||||
ARG BASE_CUDA_IMAGE=ere-base:latest-cuda
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
FROM $BASE_IMAGE AS base
|
||||
FROM $BASE_CUDA_IMAGE AS base_cuda
|
||||
FROM base${CUDA:+_cuda}
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
# The ere-base image provides Rust, Cargo, and common tools.
|
||||
# We operate as root for SDK installation.
|
||||
@@ -14,6 +8,7 @@ FROM base${CUDA:+_cuda}
|
||||
# Set default toolchain to nightly
|
||||
RUN rustup default nightly
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
# Default to build for RTX 50 series
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features openvm \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
ARG BASE_ZKVM_IMAGE=ere-base-openvm:latest
|
||||
ARG BASE_ZKVM_CUDA_IMAGE=ere-base-openvm:latest-cuda
|
||||
ARG RUNTIME_IMAGE=ubuntu:24.04
|
||||
ARG RUNTIME_CUDA_IMAGE=nvidia/cuda:12.9.1-runtime-ubuntu24.04
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
FROM $BASE_ZKVM_IMAGE AS base
|
||||
FROM $BASE_ZKVM_CUDA_IMAGE AS base_cuda
|
||||
FROM base${CUDA:+_cuda} AS build_stage
|
||||
FROM $BASE_ZKVM_IMAGE AS build_stage
|
||||
|
||||
COPY . /ere
|
||||
|
||||
@@ -19,7 +16,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features openvm${CUDA:+,cuda} \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime
|
||||
FROM $RUNTIME_CUDA_IMAGE AS runtime_cuda
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features pico \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features pico \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
ARG BASE_IMAGE=ere-base:latest
|
||||
ARG BASE_CUDA_IMAGE=ere-base:latest-cuda
|
||||
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
FROM $BASE_IMAGE AS base
|
||||
FROM $BASE_CUDA_IMAGE AS base_cuda
|
||||
FROM base${CUDA:+_cuda}
|
||||
|
||||
ARG CUDA
|
||||
ARG RUSTFLAGS
|
||||
|
||||
# Install protoc with same version as https://github.com/risc0/risc0/blob/v3.0.3/bento/dockerfiles/agent.dockerfile#L24-L26.
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features risc0 \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
ARG BASE_ZKVM_IMAGE=ere-base-risc0:latest
|
||||
ARG BASE_ZKVM_CUDA_IMAGE=ere-base-risc0:latest-cuda
|
||||
ARG RUNTIME_IMAGE=ubuntu:24.04
|
||||
ARG RUNTIME_CUDA_IMAGE=nvidia/cuda:12.9.1-runtime-ubuntu24.04
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
FROM $BASE_ZKVM_IMAGE AS base
|
||||
FROM $BASE_ZKVM_CUDA_IMAGE AS base_cuda
|
||||
FROM base${CUDA:+_cuda} AS build_stage
|
||||
FROM $BASE_ZKVM_IMAGE AS build_stage
|
||||
|
||||
COPY . /ere
|
||||
|
||||
@@ -19,7 +16,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features risc0${CUDA:+,cuda} \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime
|
||||
FROM $RUNTIME_CUDA_IMAGE AS runtime_cuda
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features sp1 \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features sp1 \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features ziren \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features ziren \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
ARG BASE_IMAGE=ere-base:latest
|
||||
ARG BASE_CUDA_IMAGE=ere-base:latest-cuda
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
FROM $BASE_IMAGE AS base
|
||||
FROM $BASE_CUDA_IMAGE AS base_cuda
|
||||
FROM base${CUDA:+_cuda}
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
# The ere-base image provides Rust, Cargo, and common tools.
|
||||
# ZisK requires Ubuntu 22.04 or higher (ere-base uses 24.04 by default).
|
||||
# We operate as root for SDK and dependency installation.
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
# Install ZisK system dependencies (for Ubuntu)
|
||||
@@ -68,4 +63,11 @@ ENV PATH=/root/.zisk/bin:$PATH
|
||||
# Verify cargo-zisk is accessible
|
||||
RUN echo "Verifying ZisK installation in Dockerfile ..." && cargo-zisk --version
|
||||
|
||||
# Copy the TamaGo installer script from the workspace context
|
||||
COPY --chmod=755 scripts/install_tamago.sh /tmp/install_tamago.sh
|
||||
|
||||
# Run the TamaGo installation script.
|
||||
RUN /tmp/install_tamago.sh && \
|
||||
rm /tmp/install_tamago.sh
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
|
||||
@@ -9,7 +9,7 @@ WORKDIR /ere
|
||||
|
||||
RUN cargo build --release --package ere-compiler --bin ere-compiler --features zisk \
|
||||
&& mkdir bin && mv target/release/ere-compiler bin/ere-compiler \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime_stage
|
||||
|
||||
@@ -28,6 +28,12 @@ ENV RUSTUP_HOME=/usr/local/rustup \
|
||||
CARGO_HOME=/usr/local/cargo \
|
||||
PATH=/usr/local/cargo/bin:$PATH
|
||||
|
||||
# Copy TamaGo
|
||||
COPY --from=build_stage /root/.tamago /root/.tamago
|
||||
|
||||
# Add TamaGo to path
|
||||
ENV PATH=/root/.tamago/bin:$PATH
|
||||
|
||||
# Copy ZisK SDK
|
||||
COPY --from=build_stage /root/.zisk/toolchains /root/.zisk/toolchains
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
ARG BASE_ZKVM_IMAGE=ere-base-zisk:latest
|
||||
ARG BASE_ZKVM_CUDA_IMAGE=ere-base-zisk:latest-cuda
|
||||
ARG RUNTIME_IMAGE=ubuntu:24.04
|
||||
ARG RUNTIME_CUDA_IMAGE=nvidia/cuda:12.9.1-runtime-ubuntu24.04
|
||||
|
||||
# Whether to enable CUDA feature or not.
|
||||
ARG CUDA
|
||||
|
||||
FROM $BASE_ZKVM_IMAGE AS base
|
||||
FROM $BASE_ZKVM_CUDA_IMAGE AS base_cuda
|
||||
FROM base${CUDA:+_cuda} AS build_stage
|
||||
FROM $BASE_ZKVM_IMAGE AS build_stage
|
||||
|
||||
COPY . /ere
|
||||
|
||||
@@ -19,7 +16,7 @@ ARG RUSTFLAGS
|
||||
|
||||
RUN cargo build --release --package ere-server --bin ere-server --features zisk${CUDA:+,cuda} \
|
||||
&& mkdir bin && mv target/release/ere-server bin/ere-server \
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/src $CARGO_HOME/registry/cache
|
||||
&& cargo clean && rm -rf $CARGO_HOME/registry/
|
||||
|
||||
FROM $RUNTIME_IMAGE AS runtime
|
||||
FROM $RUNTIME_CUDA_IMAGE AS runtime_cuda
|
||||
|
||||
Reference in New Issue
Block a user