From fb3443a169bd1406b6f30a46cce3680f48da7efc Mon Sep 17 00:00:00 2001 From: Han Date: Wed, 8 Oct 2025 20:04:31 +0800 Subject: [PATCH] Add crate `ere-compiler` (#159) --- Cargo.lock | 21 +++++++ Cargo.toml | 2 + crates/ere-compiler/Cargo.toml | 44 +++++++++++++ crates/ere-compiler/src/main.rs | 106 ++++++++++++++++++++++++++++++++ crates/ere-server/Cargo.toml | 2 +- crates/ere-server/src/main.rs | 4 +- 6 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 crates/ere-compiler/Cargo.toml create mode 100644 crates/ere-compiler/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 6276490..3a1d37e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3658,6 +3658,27 @@ dependencies = [ "zkvm-interface", ] +[[package]] +name = "ere-compiler" +version = "0.0.13" +dependencies = [ + "anyhow", + "bincode 1.3.3", + "clap", + "ere-jolt", + "ere-miden", + "ere-nexus", + "ere-openvm", + "ere-pico", + "ere-risc0", + "ere-sp1", + "ere-ziren", + "ere-zisk", + "serde", + "tracing-subscriber 0.3.19", + "zkvm-interface", +] + [[package]] name = "ere-dockerized" version = "0.0.13" diff --git a/Cargo.toml b/Cargo.toml index 7750f0d..5509f82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ members = [ "crates/zkvm-interface", # CLI and dockerized zkVM "crates/ere-cli", + "crates/ere-compiler", "crates/ere-dockerized", "crates/ere-server", ] @@ -104,6 +105,7 @@ zkvm-interface = { path = "crates/zkvm-interface" } build-utils = { path = "crates/build-utils" } compile-utils = { path = "crates/compile-utils" } test-utils = { path = "crates/test-utils" } +ere-compiler = { path = "crates/ere-compiler" } ere-cli = { path = "crates/ere-cli", default-features = false } ere-dockerized = { path = "crates/ere-dockerized" } ere-server = { path = "crates/ere-server" } diff --git a/crates/ere-compiler/Cargo.toml b/crates/ere-compiler/Cargo.toml new file mode 100644 index 0000000..be99738 --- /dev/null +++ b/crates/ere-compiler/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "ere-compiler" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true + +[dependencies] +anyhow.workspace = true +bincode.workspace = true +clap = { workspace = true, features = ["derive"] } +serde.workspace = true +tracing-subscriber = { workspace = true, features = ["env-filter"] } + +# Local dependencies +ere-jolt = { workspace = true, optional = true } +ere-miden = { workspace = true, optional = true } +ere-nexus = { workspace = true, optional = true } +ere-openvm = { workspace = true, optional = true } +ere-pico = { workspace = true, optional = true } +ere-risc0 = { workspace = true, optional = true } +ere-sp1 = { workspace = true, optional = true } +ere-ziren = { workspace = true, optional = true } +ere-zisk = { workspace = true, optional = true } +zkvm-interface.workspace = true + +[dev-dependencies] + +[features] +default = [] + +# zkVM +jolt = ["dep:ere-jolt"] +miden = ["dep:ere-miden"] +nexus = ["dep:ere-nexus"] +openvm = ["dep:ere-openvm"] +pico = ["dep:ere-pico"] +risc0 = ["dep:ere-risc0"] +sp1 = ["dep:ere-sp1"] +ziren = ["dep:ere-ziren"] +zisk = ["dep:ere-zisk"] + +[lints] +workspace = true diff --git a/crates/ere-compiler/src/main.rs b/crates/ere-compiler/src/main.rs new file mode 100644 index 0000000..6ad0716 --- /dev/null +++ b/crates/ere-compiler/src/main.rs @@ -0,0 +1,106 @@ +use anyhow::{Context, Error}; +use clap::Parser; +use serde::Serialize; +use std::{env, fs::File, path::PathBuf}; +use tracing_subscriber::EnvFilter; +use zkvm_interface::Compiler; + +// Compile-time check to ensure exactly one zkVM feature is enabled for `ere-compiler` +const _: () = { + assert!( + (cfg!(feature = "jolt") as u8 + + cfg!(feature = "miden") as u8 + + cfg!(feature = "nexus") as u8 + + cfg!(feature = "openvm") as u8 + + cfg!(feature = "pico") as u8 + + cfg!(feature = "risc0") as u8 + + cfg!(feature = "sp1") as u8 + + cfg!(feature = "ziren") as u8 + + cfg!(feature = "zisk") as u8) + == 1, + "Exactly one zkVM feature must be enabled for `ere-compiler`" + ); +}; + +#[derive(Parser)] +#[command(author, version)] +struct Args { + /// Path to the guest program + #[arg(long)] + guest_path: PathBuf, + /// Path where the compiled program will be written + #[arg(long)] + output_path: PathBuf, +} + +fn main() -> Result<(), Error> { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .init(); + + let args = Args::parse(); + + let program = compile(args.guest_path)?; + + let output = File::create(args.output_path).with_context(|| "Failed to create output")?; + bincode::serialize_into(output, &program).with_context(|| "Failed to serialize program")?; + + Ok(()) +} + +fn compile(guest_path: PathBuf) -> Result { + #[cfg(feature = "jolt")] + let result = if use_stock_rust() { + ere_jolt::compiler::RustRv32ima.compile(&guest_path) + } else { + ere_jolt::compiler::RustRv32imaCustomized.compile(&guest_path) + }; + + #[cfg(feature = "miden")] + let result = ere_miden::compiler::MidenAsm.compile(&guest_path); + + #[cfg(feature = "nexus")] + let result = ere_nexus::compiler::RustRv32i.compile(&guest_path); + + #[cfg(feature = "openvm")] + let result = if use_stock_rust() { + ere_openvm::compiler::RustRv32ima.compile(&guest_path) + } else { + ere_openvm::compiler::RustRv32imaCustomized.compile(&guest_path) + }; + + #[cfg(feature = "pico")] + let result = if use_stock_rust() { + ere_pico::compiler::RustRv32ima.compile(&guest_path) + } else { + ere_pico::compiler::RustRv32imaCustomized.compile(&guest_path) + }; + + #[cfg(feature = "risc0")] + let result = if use_stock_rust() { + ere_risc0::compiler::RustRv32ima.compile(&guest_path) + } else { + ere_risc0::compiler::RustRv32imaCustomized.compile(&guest_path) + }; + + #[cfg(feature = "sp1")] + let result = if use_stock_rust() { + ere_sp1::compiler::RustRv32ima.compile(&guest_path) + } else { + ere_sp1::compiler::RustRv32imaCustomized.compile(&guest_path) + }; + + #[cfg(feature = "ziren")] + let result = ere_ziren::compiler::RustMips32r2Customized.compile(&guest_path); + + #[cfg(feature = "zisk")] + let result = ere_zisk::compiler::RustRv64imaCustomized.compile(&guest_path); + + 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() +} diff --git a/crates/ere-server/Cargo.toml b/crates/ere-server/Cargo.toml index 4439252..4afb860 100644 --- a/crates/ere-server/Cargo.toml +++ b/crates/ere-server/Cargo.toml @@ -14,7 +14,7 @@ tokio.workspace = true twirp.workspace = true # Server -clap = { workspace = true, optional = true } +clap = { workspace = true, features = ["derive"], optional = true } tower-http = { workspace = true, features = ["catch-panic"], optional = true } tracing = { workspace = true, optional = true } tracing-subscriber = { workspace = true, features = ["env-filter"], optional = true } diff --git a/crates/ere-server/src/main.rs b/crates/ere-server/src/main.rs index 0fc8ffb..43d2866 100644 --- a/crates/ere-server/src/main.rs +++ b/crates/ere-server/src/main.rs @@ -17,7 +17,7 @@ use twirp::{ }; use zkvm_interface::{ProverResourceType, zkVM}; -// Compile-time check to ensure exactly one backend feature is enabled for CLI mode +// Compile-time check to ensure exactly one zkVM feature is enabled for `ere-server` const _: () = { if cfg!(feature = "server") { assert!( @@ -31,7 +31,7 @@ const _: () = { + cfg!(feature = "ziren") as u8 + cfg!(feature = "zisk") as u8) == 1, - "Exactly one zkVM backend feature must be enabled for CLI mode" + "Exactly one zkVM feature must be enabled for `ere-server`" ); } };