diff --git a/Cargo.lock b/Cargo.lock index 100b994..d14d125 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3933,7 +3933,7 @@ name = "ere-risc0" version = "0.0.15" dependencies = [ "anyhow", - "borsh", + "bincode 2.0.1", "ere-build-utils", "ere-compile-utils", "ere-io", diff --git a/Cargo.toml b/Cargo.toml index 84b9b18..9efc3da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,6 @@ anyhow = "1.0.98" auto_impl = "1.3.0" bincode = { version = "2.0.1", default-features = false } blake3 = "1.8.2" -borsh = "1.5.7" bytemuck = "1.23.1" cargo_metadata = "0.19.0" clap = "4.5.42" diff --git a/README.md b/README.md index 28afe37..884f42e 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ ere-sp1 = { git = "https://github.com/eth-act/ere.git", tag = "v0.0.12" } use ere_sp1::{EreSP1, RV32_IM_SUCCINCT_ZKVM_ELF}; use ere_zkvm_interface::{ compiler::Compiler, - zkvm::{ProofKind, ProverResourceType, zkVM}, + zkvm::{Input, ProofKind, ProverResourceType, zkVM}, }; fn main() -> Result<(), Box> { @@ -98,7 +98,7 @@ fn main() -> Result<(), Box> { let zkvm = EreSP1::new(program, ProverResourceType::Cpu)?; // Serialize input - let input = 42u32.to_le_bytes(); + let input = Input::new(42u32.to_le_bytes().to_vec()); // Execute let (public_values, report) = zkvm.execute(&input)?; @@ -133,7 +133,7 @@ ere-dockerized = { git = "https://github.com/eth-act/ere.git", tag = "v0.0.12" } use ere_dockerized::{CompilerKind, DockerizedCompiler, DockerizedzkVM, zkVMKind}; use ere_zkvm_interface::{ compiler::Compiler, - zkvm::{ProofKind, ProverResourceType, zkVM}, + zkvm::{Input, ProofKind, ProverResourceType, zkVM}, }; fn main() -> Result<(), Box> { @@ -151,7 +151,7 @@ fn main() -> Result<(), Box> { let zkvm = DockerizedzkVM::new(zkVMKind::SP1, program, ProverResourceType::Cpu)?; // Serialize input - let input = 42u32.to_le_bytes(); + let input = Input::new(42u32.to_le_bytes().to_vec()); // Execute let (public_values, report) = zkvm.execute(&input)?; diff --git a/crates/dockerized/server/proto/api.proto b/crates/dockerized/server/proto/api.proto index 02d3b0a..229eeb9 100644 --- a/crates/dockerized/server/proto/api.proto +++ b/crates/dockerized/server/proto/api.proto @@ -14,7 +14,8 @@ service ZkvmService { } message ExecuteRequest { - bytes input = 1; + bytes input_stdin = 1; + optional bytes input_proofs = 2; } message ExecuteResponse { @@ -30,8 +31,9 @@ message ExecuteOk { } message ProveRequest { - bytes input = 1; - ProofKind proof_kind = 2; + bytes input_stdin = 1; + optional bytes input_proofs = 2; + ProofKind proof_kind = 3; } message ProveResponse { diff --git a/crates/dockerized/server/src/client.rs b/crates/dockerized/server/src/client.rs index 0577633..2e84037 100644 --- a/crates/dockerized/server/src/client.rs +++ b/crates/dockerized/server/src/client.rs @@ -4,7 +4,7 @@ use crate::api::{ verify_response::Result as VerifyResult, }; use ere_zkvm_interface::zkvm::{ - ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, PublicValues, + Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, PublicValues, }; use std::time::{Duration, Instant}; use thiserror::Error; @@ -56,9 +56,12 @@ impl zkVMClient { pub async fn execute( &self, - input: Vec, + input: &Input, ) -> Result<(PublicValues, ProgramExecutionReport), Error> { - let request = Request::new(ExecuteRequest { input }); + let request = Request::new(ExecuteRequest { + input_stdin: input.stdin.clone(), + input_proofs: input.proofs.clone(), + }); let response = self.client.execute(request).await?; @@ -75,11 +78,12 @@ impl zkVMClient { pub async fn prove( &self, - input: Vec, + input: &Input, proof_kind: ProofKind, ) -> Result<(PublicValues, Proof, ProgramProvingReport), Error> { let request = Request::new(ProveRequest { - input, + input_stdin: input.stdin.clone(), + input_proofs: input.proofs.clone(), proof_kind: proof_kind as i32, }); diff --git a/crates/dockerized/server/src/server.rs b/crates/dockerized/server/src/server.rs index 5f37468..9798b80 100644 --- a/crates/dockerized/server/src/server.rs +++ b/crates/dockerized/server/src/server.rs @@ -6,7 +6,7 @@ use crate::api::{ }; use anyhow::Context; use ere_zkvm_interface::zkvm::{ - ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, PublicValues, zkVM, + Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, PublicValues, zkVM, }; use std::sync::Arc; use twirp::{ @@ -31,7 +31,7 @@ impl zkVMServer { async fn execute( &self, - input: Vec, + input: Input, ) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { let zkvm = Arc::clone(&self.zkvm); tokio::task::spawn_blocking(move || zkvm.execute(&input)) @@ -41,7 +41,7 @@ impl zkVMServer { async fn prove( &self, - input: Vec, + input: Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { let zkvm = Arc::clone(&self.zkvm); @@ -64,9 +64,12 @@ impl ZkvmService for zkVMServer { &self, request: Request, ) -> twirp::Result> { - let request = request.into_body(); + let ExecuteRequest { + input_stdin: stdin, + input_proofs: proofs, + } = request.into_body(); - let input = request.input; + let input = Input { stdin, proofs }; let result = match self.execute(input).await { Ok((public_values, report)) => ExecuteResult::Ok(ExecuteOk { @@ -86,11 +89,15 @@ impl ZkvmService for zkVMServer { &self, request: Request, ) -> twirp::Result> { - let request = request.into_body(); + let ProveRequest { + input_stdin: stdin, + input_proofs: proofs, + proof_kind, + } = request.into_body(); - let input = request.input; - let proof_kind = ProofKind::from_repr(request.proof_kind as usize) - .ok_or_else(|| invalid_proof_kind_err(request.proof_kind))?; + let input = Input { stdin, proofs }; + let proof_kind = ProofKind::from_repr(proof_kind as usize) + .ok_or_else(|| invalid_proof_kind_err(proof_kind))?; let result = match self.prove(input, proof_kind).await { Ok((public_values, proof, report)) => ProveResult::Ok(ProveOk { diff --git a/crates/dockerized/src/lib.rs b/crates/dockerized/src/lib.rs index e695cd0..547e1f8 100644 --- a/crates/dockerized/src/lib.rs +++ b/crates/dockerized/src/lib.rs @@ -29,7 +29,7 @@ //! use ere_dockerized::{CompilerKind, DockerizedCompiler, DockerizedzkVM, zkVMKind}; //! use ere_zkvm_interface::{ //! compiler::Compiler, -//! zkvm::{ProofKind, ProverResourceType, zkVM}, +//! zkvm::{Input, ProofKind, ProverResourceType, zkVM}, //! }; //! use std::path::Path; //! @@ -49,7 +49,7 @@ //! let zkvm = DockerizedzkVM::new(zkvm_kind, program, resource)?; //! //! // Serialize input -//! let input = 42u32.to_le_bytes(); +//! let input = Input::new(42u32.to_le_bytes().to_vec()); //! //! // Execute program //! let (public_values, execution_report) = zkvm.execute(&input)?; diff --git a/crates/dockerized/src/zkvm.rs b/crates/dockerized/src/zkvm.rs index 8180481..8720420 100644 --- a/crates/dockerized/src/zkvm.rs +++ b/crates/dockerized/src/zkvm.rs @@ -16,7 +16,7 @@ use ere_server::client::{Url, zkVMClient}; use ere_zkvm_interface::{ CommonError, zkvm::{ - ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, + Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, }, }; @@ -308,23 +308,20 @@ impl DockerizedzkVM { } impl zkVM for DockerizedzkVM { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { - let input = input.to_vec(); - self.with_retry(|client| block_on(client.execute(input.clone()))) + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + self.with_retry(|client| block_on(client.execute(input))) } fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { - let input = input.to_vec(); - self.with_retry(|client| block_on(client.prove(input.clone(), proof_kind))) + self.with_retry(|client| block_on(client.prove(input, proof_kind))) } fn verify(&self, proof: &Proof) -> anyhow::Result { - let proof = proof.clone(); - self.with_retry(|client| block_on(client.verify(&proof))) + self.with_retry(|client| block_on(client.verify(proof))) } fn name(&self) -> &'static str { @@ -354,7 +351,7 @@ mod test { use ere_test_utils::{ host::*, io::serde::bincode::BincodeLegacy, program::basic::BasicProgram, }; - use ere_zkvm_interface::zkvm::{ProofKind, ProverResourceType, zkVM}; + use ere_zkvm_interface::zkvm::{Input, ProofKind, ProverResourceType, zkVM}; fn zkvm( zkvm_kind: zkVMKind, @@ -409,8 +406,8 @@ mod test { "basic", [BasicProgram::::valid_test_case().into_output_sha256()], [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input() + Input::default(), + BasicProgram::::invalid_test_case().input() ] ); } @@ -423,8 +420,8 @@ mod test { "basic", [BasicProgram::::valid_test_case()], [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input() + Input::default(), + BasicProgram::::invalid_test_case().input() ] ); } @@ -437,8 +434,8 @@ mod test { "basic", [BasicProgram::::valid_test_case()], [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input() + Input::default(), + BasicProgram::::invalid_test_case().input() ] ); } @@ -451,8 +448,8 @@ mod test { "basic", [BasicProgram::::valid_test_case().into_output_sha256()], [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input() + Input::default(), + BasicProgram::::invalid_test_case().input() ] ); } @@ -465,8 +462,8 @@ mod test { "basic", [BasicProgram::::valid_test_case()], [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input() + Input::default(), + BasicProgram::::invalid_test_case().input() ] ); } @@ -479,8 +476,8 @@ mod test { "basic", [BasicProgram::::valid_test_case()], [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input() + Input::default(), + BasicProgram::::invalid_test_case().input() ] ); } @@ -493,8 +490,8 @@ mod test { "basic", [BasicProgram::::valid_test_case()], [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input() + Input::default(), + BasicProgram::::invalid_test_case().input() ] ); } @@ -507,8 +504,8 @@ mod test { "basic", [BasicProgram::::valid_test_case()], [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input() + Input::default(), + BasicProgram::::invalid_test_case().input() ] ); } @@ -521,8 +518,8 @@ mod test { "basic_rust", [BasicProgram::::valid_test_case()], [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input() + Input::default(), + BasicProgram::::invalid_test_case().input() ] ); } diff --git a/crates/test-utils/src/host.rs b/crates/test-utils/src/host.rs index 3861200..2c6a876 100644 --- a/crates/test-utils/src/host.rs +++ b/crates/test-utils/src/host.rs @@ -1,7 +1,10 @@ use crate::program::Program; use core::ops::Deref; use ere_io::Io; -use ere_zkvm_interface::zkvm::{ProofKind, PublicValues, zkVM}; +use ere_zkvm_interface::{ + Input, + zkvm::{ProofKind, PublicValues, zkVM}, +}; use sha2::{Digest, Sha256}; use std::{marker::PhantomData, path::PathBuf}; @@ -18,7 +21,7 @@ pub fn testing_guest_directory(zkvm_name: &str, program: &str) -> PathBuf { pub fn run_zkvm_execute(zkvm: &impl zkVM, test_case: &impl TestCase) -> PublicValues { let (public_values, _report) = zkvm - .execute(&test_case.serialized_input()) + .execute(&test_case.input()) .expect("execute should not fail with valid input"); test_case.assert_output(&public_values); @@ -28,7 +31,7 @@ pub fn run_zkvm_execute(zkvm: &impl zkVM, test_case: &impl TestCase) -> PublicVa pub fn run_zkvm_prove(zkvm: &impl zkVM, test_case: &impl TestCase) -> PublicValues { let (prover_public_values, proof, _report) = zkvm - .prove(&test_case.serialized_input(), ProofKind::default()) + .prove(&test_case.input(), ProofKind::default()) .expect("prove should not fail with valid input"); let verifier_public_values = zkvm @@ -46,7 +49,7 @@ pub fn run_zkvm_prove(zkvm: &impl zkVM, test_case: &impl TestCase) -> PublicValu /// [`Program::Input`], and is able to assert if the [`PublicValues`] returned /// by [`zkVM`] methods is correct or not. pub trait TestCase { - fn serialized_input(&self) -> Vec; + fn input(&self) -> Input; fn assert_output(&self, public_values: &[u8]); } @@ -80,8 +83,8 @@ impl Deref for ProgramTestCase

{ } impl TestCase for ProgramTestCase

{ - fn serialized_input(&self) -> Vec { - P::Io::serialize_input(&self.input).unwrap() + fn input(&self) -> Input { + Input::new(P::Io::serialize_input(&self.input).unwrap()) } fn assert_output(&self, public_values: &[u8]) { @@ -112,8 +115,8 @@ where P: Program, D: Digest, { - fn serialized_input(&self) -> Vec { - self.test_case.serialized_input() + fn input(&self) -> Input { + self.test_case.input() } fn assert_output(&self, public_values: &[u8]) { diff --git a/crates/zkvm-interface/Cargo.toml b/crates/zkvm-interface/Cargo.toml index 9b3e3ea..884d6b4 100644 --- a/crates/zkvm-interface/Cargo.toml +++ b/crates/zkvm-interface/Cargo.toml @@ -8,6 +8,7 @@ license.workspace = true [dependencies] anyhow.workspace = true auto_impl.workspace = true +bincode = { workspace = true, features = ["alloc", "serde"] } indexmap = { workspace = true, features = ["serde"] } serde = { workspace = true, features = ["derive"] } strum = { workspace = true, features = ["derive"] } diff --git a/crates/zkvm-interface/src/zkvm.rs b/crates/zkvm-interface/src/zkvm.rs index c5e3028..f973d64 100644 --- a/crates/zkvm-interface/src/zkvm.rs +++ b/crates/zkvm-interface/src/zkvm.rs @@ -1,5 +1,6 @@ #![allow(non_camel_case_types)] +use bincode::error::{DecodeError, EncodeError}; use serde::{Serialize, de::DeserializeOwned}; mod error; @@ -12,6 +13,63 @@ pub use proof::{Proof, ProofKind}; pub use report::{ProgramExecutionReport, ProgramProvingReport}; pub use resource::{NetworkProverConfig, ProverResourceType}; +/// Input for the prover to execute/prove a guest program. +#[derive(Clone, Debug, Default)] +pub struct Input { + pub stdin: Vec, + /// Serialized proofs to be verified in guest program for proof composition. + pub proofs: Option>, +} + +impl Input { + /// Creates a new `Input` with the given stdin. + pub fn new(stdin: Vec) -> Self { + Self { + stdin, + proofs: None, + } + } + + /// Returns a reference to the stdin as a byte slice. + pub fn stdin(&self) -> &[u8] { + &self.stdin + } + + /// Deserializes and returns the proofs if present. + /// + /// # Returns + /// + /// - `None` if no proofs are set + /// - `Some(Ok(..))` if the proofs were successfully deserialized + /// - `Some(Err(..))` if deserialization failed + pub fn proofs(&self) -> Option, DecodeError>> { + self.proofs.as_ref().map(|proofs| { + bincode::serde::decode_from_slice(proofs, bincode::config::legacy()) + .map(|(proofs, _)| proofs) + }) + } + + /// Serializes the given proofs and returns a new `Input` with them set. + /// + /// Consumes `self` and returns an error if serialization fails. + pub fn with_proofs(mut self, proofs: &[T]) -> Result { + self.proofs = Some(bincode::serde::encode_to_vec( + proofs, + bincode::config::legacy(), + )?); + Ok(self) + } + + /// Sets serialized proofs and returns a new `Input`. + /// + /// The proofs must be serialized using [`bincode::serde`] with + /// [`bincode::config::legacy`] configuration. + pub fn with_serialized_proofs(mut self, proofs: Vec) -> Self { + self.proofs = Some(proofs); + self + } +} + /// Public values committed/revealed by guest program. /// /// Use [`zkVM::deserialize_from`] to deserialize object from the bytes. @@ -29,12 +87,12 @@ pub type PublicValues = Vec; #[auto_impl::auto_impl(&, Arc, Box)] pub trait zkVM { /// Executes the program with the given input. - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)>; + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)>; /// Creates a proof of the program execution with given input. fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)>; diff --git a/crates/zkvm-interface/src/zkvm/error.rs b/crates/zkvm-interface/src/zkvm/error.rs index a2ed7f1..f53d0e4 100644 --- a/crates/zkvm-interface/src/zkvm/error.rs +++ b/crates/zkvm-interface/src/zkvm/error.rs @@ -48,6 +48,9 @@ pub enum CommonError { stderr: String, }, + #[error("Unsupported input: {0}")] + UnsupportedInput(String), + #[error("Unsupported proof kind {unsupported:?}, expect one of {supported:?}")] UnsupportedProofKind { unsupported: ProofKind, @@ -134,6 +137,10 @@ impl CommonError { } } + pub fn unsupported_input(reason: impl AsRef) -> Self { + Self::UnsupportedInput(reason.as_ref().to_string()) + } + pub fn unsupported_proof_kind( unsupported: ProofKind, supported: impl IntoIterator, diff --git a/crates/zkvm/airbender/src/zkvm.rs b/crates/zkvm/airbender/src/zkvm.rs index f348d0e..bb03d38 100644 --- a/crates/zkvm/airbender/src/zkvm.rs +++ b/crates/zkvm/airbender/src/zkvm.rs @@ -2,7 +2,7 @@ use crate::{program::AirbenderProgram, zkvm::sdk::AirbenderSdk}; use airbender_execution_utils::ProgramProof; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, zkVMProgramDigest, }; use std::time::Instant; @@ -28,9 +28,13 @@ impl EreAirbender { } impl zkVM for EreAirbender { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } + let start = Instant::now(); - let (public_values, cycles) = self.sdk.execute(input)?; + let (public_values, cycles) = self.sdk.execute(input.stdin())?; let execution_duration = start.elapsed(); Ok(( @@ -45,9 +49,12 @@ impl zkVM for EreAirbender { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } if proof_kind != ProofKind::Compressed { bail!(CommonError::unsupported_proof_kind( proof_kind, @@ -55,7 +62,7 @@ impl zkVM for EreAirbender { )) } let start = Instant::now(); - let (public_values, proof) = self.sdk.prove(input)?; + let (public_values, proof) = self.sdk.prove(input.stdin())?; let proving_time = start.elapsed(); let proof_bytes = bincode::serde::encode_to_vec(&proof, bincode::config::legacy()) @@ -112,7 +119,7 @@ mod tests { }; use ere_zkvm_interface::{ compiler::Compiler, - zkvm::{ProofKind, ProverResourceType, zkVM}, + zkvm::{Input, ProofKind, ProverResourceType, zkVM}, }; use std::sync::OnceLock; @@ -142,8 +149,8 @@ mod tests { let zkvm = EreAirbender::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.execute(&input).unwrap_err(); } @@ -164,8 +171,8 @@ mod tests { let zkvm = EreAirbender::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.prove(&input, ProofKind::default()).unwrap_err(); } diff --git a/crates/zkvm/jolt/src/compiler/rust_rv64imac.rs b/crates/zkvm/jolt/src/compiler/rust_rv64imac.rs index f93910a..c350dc5 100644 --- a/crates/zkvm/jolt/src/compiler/rust_rv64imac.rs +++ b/crates/zkvm/jolt/src/compiler/rust_rv64imac.rs @@ -60,6 +60,7 @@ mod tests { use crate::{compiler::RustRv64imac, zkvm::EreJolt}; use ere_test_utils::host::testing_guest_directory; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{ProverResourceType, zkVM}, }; @@ -77,6 +78,6 @@ mod tests { let program = RustRv64imac.compile(&guest_directory).unwrap(); let zkvm = EreJolt::new(program, ProverResourceType::Cpu).unwrap(); - zkvm.execute(&[]).unwrap(); + zkvm.execute(&Input::default()).unwrap(); } } diff --git a/crates/zkvm/jolt/src/zkvm.rs b/crates/zkvm/jolt/src/zkvm.rs index d719554..6f37bd5 100644 --- a/crates/zkvm/jolt/src/zkvm.rs +++ b/crates/zkvm/jolt/src/zkvm.rs @@ -4,7 +4,7 @@ use crate::{ }; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, }; use jolt_ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -32,9 +32,13 @@ impl EreJolt { } impl zkVM for EreJolt { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } + let start = Instant::now(); - let (public_values, total_num_cycles) = self.sdk.execute(input)?; + let (public_values, total_num_cycles) = self.sdk.execute(input.stdin())?; let execution_duration = start.elapsed(); Ok(( @@ -49,17 +53,21 @@ impl zkVM for EreJolt { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } if proof_kind != ProofKind::Compressed { bail!(CommonError::unsupported_proof_kind( proof_kind, [ProofKind::Compressed] )) } + let start = Instant::now(); - let (public_values, proof) = self.sdk.prove(input)?; + let (public_values, proof) = self.sdk.prove(input.stdin())?; let proving_time = start.elapsed(); let mut proof_bytes = Vec::new(); @@ -108,6 +116,7 @@ mod tests { program::basic::BasicProgram, }; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{ProofKind, ProverResourceType, zkVM}, }; @@ -144,8 +153,8 @@ mod tests { let zkvm = EreJolt::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.execute(&input).unwrap_err(); } @@ -170,8 +179,8 @@ mod tests { let _guard = PROVE_LOCK.lock().unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.prove(&input, ProofKind::default()).unwrap_err(); } diff --git a/crates/zkvm/miden/src/zkvm.rs b/crates/zkvm/miden/src/zkvm.rs index 918b269..20116ca 100644 --- a/crates/zkvm/miden/src/zkvm.rs +++ b/crates/zkvm/miden/src/zkvm.rs @@ -1,7 +1,7 @@ use crate::program::{MidenProgram, MidenProgramInfo, MidenSerdeWrapper}; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, zkVMProgramDigest, }; use miden_core::{ @@ -56,9 +56,13 @@ impl EreMiden { } impl zkVM for EreMiden { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } + let stack_inputs = StackInputs::default(); - let advice_inputs = AdviceInputs::default().with_stack(bytes_to_felts(input)?); + let advice_inputs = AdviceInputs::default().with_stack(bytes_to_felts(input.stdin())?); let mut host = Self::setup_host()?; let start = Instant::now(); @@ -84,9 +88,12 @@ impl zkVM for EreMiden { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } if proof_kind != ProofKind::Compressed { bail!(CommonError::unsupported_proof_kind( proof_kind, @@ -95,7 +102,7 @@ impl zkVM for EreMiden { } let stack_inputs = StackInputs::default(); - let advice_inputs = AdviceInputs::default().with_stack(bytes_to_felts(input)?); + let advice_inputs = AdviceInputs::default().with_stack(bytes_to_felts(input.stdin())?); let mut host = Self::setup_host()?; let proving_options = ProvingOptions::with_128_bit_security(HashFunction::Blake3_256); @@ -191,6 +198,7 @@ mod tests { }; use ere_test_utils::host::testing_guest_directory; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{ProofKind, ProverResourceType, zkVM}, }; @@ -213,7 +221,9 @@ mod tests { let input = felts_to_bytes(&[const_a, const_b]); // Prove - let (prover_public_values, proof, _) = zkvm.prove(&input, ProofKind::default()).unwrap(); + let (prover_public_values, proof, _) = zkvm + .prove(&Input::new(input), ProofKind::default()) + .unwrap(); // Verify let verifier_public_values = zkvm.verify(&proof).unwrap(); @@ -235,7 +245,9 @@ mod tests { let input = felts_to_bytes(&[Felt::from(0u32), Felt::from(1u32), Felt::from(n_iterations)]); // Prove - let (prover_public_values, proof, _) = zkvm.prove(&input, ProofKind::default()).unwrap(); + let (prover_public_values, proof, _) = zkvm + .prove(&Input::new(input), ProofKind::default()) + .unwrap(); // Verify let verifier_public_values = zkvm.verify(&proof).unwrap(); @@ -251,10 +263,10 @@ mod tests { let program = load_miden_program("add"); let zkvm = EreMiden::new(program, ProverResourceType::Cpu).unwrap(); - let empty_inputs = Vec::new(); + let empty_inputs = Input::new(Vec::new()); assert!(zkvm.execute(&empty_inputs).is_err()); - let insufficient_inputs = felts_to_bytes(&[Felt::from(5u32)]); + let insufficient_inputs = Input::new(felts_to_bytes(&[Felt::from(5u32)])); assert!(zkvm.execute(&insufficient_inputs).is_err()); } } diff --git a/crates/zkvm/nexus/src/zkvm.rs b/crates/zkvm/nexus/src/zkvm.rs index 6ca5608..f2eb61b 100644 --- a/crates/zkvm/nexus/src/zkvm.rs +++ b/crates/zkvm/nexus/src/zkvm.rs @@ -1,7 +1,7 @@ use crate::program::NexusProgram; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, }; use nexus_core::nvm::{self, ElfFile}; @@ -40,15 +40,19 @@ impl EreNexus { } impl zkVM for EreNexus { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } + let elf = ElfFile::from_bytes(self.program.elf()).map_err(Error::ParseElf)?; // Nexus sdk does not provide a trace, so we need to use core `nvm` // Encoding is copied directly from `prove_with_input` - let mut private_encoded = if input.is_empty() { + let mut private_encoded = if input.stdin().is_empty() { Vec::new() } else { - postcard::to_stdvec_cobs(&input) + postcard::to_stdvec_cobs(&input.stdin()) .map_err(|err| CommonError::serialize("input", "postcard", err))? }; @@ -79,9 +83,12 @@ impl zkVM for EreNexus { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } if proof_kind != ProofKind::Compressed { bail!(CommonError::unsupported_proof_kind( proof_kind, @@ -94,7 +101,9 @@ impl zkVM for EreNexus { let prover = Stwo::new(&elf).map_err(Error::Prove)?; let start = Instant::now(); - let (view, proof) = prover.prove_with_input(&input, &()).map_err(Error::Prove)?; + let (view, proof) = prover + .prove_with_input(&input.stdin(), &()) + .map_err(Error::Prove)?; let proving_time = start.elapsed(); let public_values = view @@ -164,6 +173,7 @@ mod tests { program::basic::BasicProgram, }; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{ProofKind, ProverResourceType, zkVM}, }; @@ -195,8 +205,8 @@ mod tests { let zkvm = EreNexus::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.execute(&input).unwrap_err(); } @@ -217,8 +227,8 @@ mod tests { let zkvm = EreNexus::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.prove(&input, ProofKind::default()).unwrap_err(); } diff --git a/crates/zkvm/openvm/src/compiler/rust_rv32ima.rs b/crates/zkvm/openvm/src/compiler/rust_rv32ima.rs index af0a3ad..7cec88c 100644 --- a/crates/zkvm/openvm/src/compiler/rust_rv32ima.rs +++ b/crates/zkvm/openvm/src/compiler/rust_rv32ima.rs @@ -61,6 +61,7 @@ mod tests { use crate::{compiler::RustRv32ima, zkvm::EreOpenVM}; use ere_test_utils::host::testing_guest_directory; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{ProverResourceType, zkVM}, }; @@ -78,6 +79,6 @@ mod tests { let program = RustRv32ima.compile(&guest_directory).unwrap(); let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap(); - zkvm.execute(&[]).unwrap(); + zkvm.execute(&Input::default()).unwrap(); } } diff --git a/crates/zkvm/openvm/src/zkvm.rs b/crates/zkvm/openvm/src/zkvm.rs index 33a4d29..f4d53b4 100644 --- a/crates/zkvm/openvm/src/zkvm.rs +++ b/crates/zkvm/openvm/src/zkvm.rs @@ -1,7 +1,7 @@ use crate::program::OpenVMProgram; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, zkVMProgramDigest, }; use openvm_circuit::arch::instructions::exe::VmExe; @@ -122,9 +122,13 @@ impl EreOpenVM { } impl zkVM for EreOpenVM { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } + let mut stdin = StdIn::default(); - stdin.write_bytes(input); + stdin.write_bytes(input.stdin()); let start = Instant::now(); let public_values = self @@ -143,9 +147,12 @@ impl zkVM for EreOpenVM { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } if proof_kind != ProofKind::Compressed { bail!(CommonError::unsupported_proof_kind( proof_kind, @@ -154,7 +161,7 @@ impl zkVM for EreOpenVM { } let mut stdin = StdIn::default(); - stdin.write_bytes(input); + stdin.write_bytes(input.stdin()); let now = std::time::Instant::now(); let (proof, app_commit) = match self.resource { @@ -255,7 +262,7 @@ mod tests { }; use ere_zkvm_interface::{ compiler::Compiler, - zkvm::{ProofKind, ProverResourceType, zkVM}, + zkvm::{Input, ProofKind, ProverResourceType, zkVM}, }; use std::sync::OnceLock; @@ -285,8 +292,8 @@ mod tests { let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.execute(&input).unwrap_err(); } @@ -307,8 +314,8 @@ mod tests { let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.prove(&input, ProofKind::default()).unwrap_err(); } diff --git a/crates/zkvm/pico/src/compiler/rust_rv32ima.rs b/crates/zkvm/pico/src/compiler/rust_rv32ima.rs index da44e24..920e22c 100644 --- a/crates/zkvm/pico/src/compiler/rust_rv32ima.rs +++ b/crates/zkvm/pico/src/compiler/rust_rv32ima.rs @@ -52,6 +52,7 @@ mod tests { use crate::{compiler::RustRv32ima, zkvm::ErePico}; use ere_test_utils::host::testing_guest_directory; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{ProverResourceType, zkVM}, }; @@ -69,6 +70,6 @@ mod tests { let program = RustRv32ima.compile(&guest_directory).unwrap(); let zkvm = ErePico::new(program, ProverResourceType::Cpu).unwrap(); - zkvm.execute(&[]).unwrap(); + zkvm.execute(&Input::default()).unwrap(); } } diff --git a/crates/zkvm/pico/src/zkvm.rs b/crates/zkvm/pico/src/zkvm.rs index e79f6ba..0556be8 100644 --- a/crates/zkvm/pico/src/zkvm.rs +++ b/crates/zkvm/pico/src/zkvm.rs @@ -4,7 +4,7 @@ use crate::{ }; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, zkVMProgramDigest, }; use pico_p3_field::PrimeField32; @@ -44,9 +44,13 @@ impl ErePico { } impl zkVM for ErePico { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } + let mut stdin = EmulatorStdinBuilder::default(); - stdin.write_slice(input); + stdin.write_slice(input.stdin()); let ((total_num_cycles, region_cycles, public_values), execution_duration) = panic::catch_unwind(|| { @@ -69,9 +73,12 @@ impl zkVM for ErePico { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } if proof_kind != ProofKind::Compressed { bail!(CommonError::unsupported_proof_kind( proof_kind, @@ -80,7 +87,7 @@ impl zkVM for ErePico { } let mut stdin = EmulatorStdinBuilder::default(); - stdin.write_slice(input); + stdin.write_slice(input.stdin()); let ((public_values, proof), proving_time) = panic::catch_unwind(|| { let client = self.client(); @@ -188,7 +195,7 @@ mod tests { }; use ere_zkvm_interface::{ compiler::Compiler, - zkvm::{ProofKind, ProverResourceType, zkVM}, + zkvm::{Input, ProofKind, ProverResourceType, zkVM}, }; use std::sync::OnceLock; @@ -218,8 +225,8 @@ mod tests { let zkvm = ErePico::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.execute(&input).unwrap_err(); } @@ -240,8 +247,8 @@ mod tests { let zkvm = ErePico::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.prove(&input, ProofKind::default()).unwrap_err(); } diff --git a/crates/zkvm/risc0/Cargo.toml b/crates/zkvm/risc0/Cargo.toml index d259ec5..bb8955e 100644 --- a/crates/zkvm/risc0/Cargo.toml +++ b/crates/zkvm/risc0/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true [dependencies] anyhow.workspace = true -borsh.workspace = true +bincode.workspace = true serde = { workspace = true, features = ["derive"] } thiserror.workspace = true tracing.workspace = true diff --git a/crates/zkvm/risc0/src/compiler/rust_rv32ima.rs b/crates/zkvm/risc0/src/compiler/rust_rv32ima.rs index 18b8183..b1f0858 100644 --- a/crates/zkvm/risc0/src/compiler/rust_rv32ima.rs +++ b/crates/zkvm/risc0/src/compiler/rust_rv32ima.rs @@ -64,6 +64,7 @@ mod tests { use crate::{compiler::RustRv32ima, zkvm::EreRisc0}; use ere_test_utils::host::testing_guest_directory; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{ProverResourceType, zkVM}, }; @@ -81,6 +82,6 @@ mod tests { let program = RustRv32ima.compile(&guest_directory).unwrap(); let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap(); - zkvm.execute(&[]).unwrap(); + zkvm.execute(&Input::default()).unwrap(); } } diff --git a/crates/zkvm/risc0/src/zkvm.rs b/crates/zkvm/risc0/src/zkvm.rs index b82e08a..ce6490a 100644 --- a/crates/zkvm/risc0/src/zkvm.rs +++ b/crates/zkvm/risc0/src/zkvm.rs @@ -1,12 +1,12 @@ use crate::program::Risc0Program; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, zkVMProgramDigest, }; use risc0_zkvm::{ - DEFAULT_MAX_PO2, DefaultProver, Digest, ExecutorEnv, ExternalProver, InnerReceipt, ProverOpts, - Receipt, default_executor, default_prover, + AssumptionReceipt, DEFAULT_MAX_PO2, DefaultProver, Digest, ExecutorEnv, ExternalProver, + InnerReceipt, ProverOpts, Receipt, default_executor, default_prover, }; use std::{env, ops::RangeInclusive, rc::Rc, time::Instant}; @@ -82,13 +82,10 @@ impl EreRisc0 { } impl zkVM for EreRisc0 { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + let env = self.input_to_env(input)?; + let executor = default_executor(); - let env = ExecutorEnv::builder() - .write_slice(&(input.len() as u32).to_le_bytes()) - .write_slice(input) - .build() - .map_err(Error::BuildExecutorEnv)?; let start = Instant::now(); let session_info = executor @@ -109,9 +106,11 @@ impl zkVM for EreRisc0 { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + let env = self.input_to_env(input)?; + let prover = match self.resource { ProverResourceType::Cpu => Rc::new(ExternalProver::new("ipc", "r0vm")), ProverResourceType::Gpu => { @@ -135,14 +134,6 @@ impl zkVM for EreRisc0 { } }; - let env = ExecutorEnv::builder() - .write_slice(&(input.len() as u32).to_le_bytes()) - .write_slice(input) - .segment_limit_po2(self.segment_po2 as _) - .keccak_max_po2(self.keccak_po2 as _) - .and_then(|builder| builder.build()) - .map_err(Error::BuildExecutorEnv)?; - let opts = match proof_kind { ProofKind::Compressed => ProverOpts::succinct(), ProofKind::Groth16 => ProverOpts::groth16(), @@ -157,8 +148,8 @@ impl zkVM for EreRisc0 { let public_values = prove_info.receipt.journal.bytes.clone(); let proof = Proof::new( proof_kind, - borsh::to_vec(&prove_info.receipt) - .map_err(|err| CommonError::serialize("proof", "borsh", err))?, + bincode::serde::encode_to_vec(&prove_info.receipt, bincode::config::legacy()) + .map_err(|err| CommonError::serialize("proof", "bincode", err))?, ); Ok(( @@ -171,8 +162,9 @@ impl zkVM for EreRisc0 { fn verify(&self, proof: &Proof) -> anyhow::Result { let proof_kind = proof.kind(); - let receipt: Receipt = borsh::from_slice(proof.as_bytes()) - .map_err(|err| CommonError::deserialize("proof", "borsh", err))?; + let (receipt, _): (Receipt, _) = + bincode::serde::decode_from_slice(proof.as_bytes(), bincode::config::legacy()) + .map_err(|err| CommonError::deserialize("proof", "bincode", err))?; if !matches!( (proof_kind, &receipt.inner), @@ -215,6 +207,23 @@ impl zkVMProgramDigest for EreRisc0 { } } +impl EreRisc0 { + fn input_to_env(&self, input: &Input) -> Result, Error> { + let mut env = ExecutorEnv::builder(); + env.segment_limit_po2(self.segment_po2 as _) + .keccak_max_po2(self.keccak_po2 as _) + .expect("keccak_po2 in valid range"); + env.write_slice(&(input.stdin().len() as u32).to_le_bytes()) + .write_slice(input.stdin()); + if let Some(receipts) = input.proofs() { + for receipt in receipts.map_err(Error::DeserializeInputProofs)? { + env.add_assumption(AssumptionReceipt::Proven(receipt)); + } + } + env.build().map_err(Error::BuildExecutorEnv) + } +} + #[cfg(test)] mod tests { use crate::{compiler::RustRv32imaCustomized, program::Risc0Program, zkvm::EreRisc0}; @@ -224,6 +233,7 @@ mod tests { program::basic::BasicProgram, }; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{ProofKind, ProverResourceType, zkVM}, }; @@ -255,8 +265,8 @@ mod tests { let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.execute(&input).unwrap_err(); } @@ -277,8 +287,8 @@ mod tests { let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.prove(&input, ProofKind::default()).unwrap_err(); } @@ -293,7 +303,7 @@ mod tests { for i in 1..=16_u32 { let zkvm = EreRisc0::new(program.clone(), ProverResourceType::Cpu).unwrap(); - let input = i.to_le_bytes(); + let input = Input::new(i.to_le_bytes().to_vec()); if i.is_power_of_two() { zkvm.execute(&input) diff --git a/crates/zkvm/risc0/src/zkvm/error.rs b/crates/zkvm/risc0/src/zkvm/error.rs index e6b21bb..8119b79 100644 --- a/crates/zkvm/risc0/src/zkvm/error.rs +++ b/crates/zkvm/risc0/src/zkvm/error.rs @@ -4,6 +4,9 @@ use thiserror::Error; #[derive(Debug, Error)] pub enum Error { + #[error("Deserialize proofs in Input failed: {0:?}")] + DeserializeInputProofs(bincode::error::DecodeError), + // Execute #[error("Failed to build `ExecutorEnv`: {0}")] BuildExecutorEnv(anyhow::Error), diff --git a/crates/zkvm/sp1/src/compiler/rust_rv32ima.rs b/crates/zkvm/sp1/src/compiler/rust_rv32ima.rs index 9858529..ebc73e8 100644 --- a/crates/zkvm/sp1/src/compiler/rust_rv32ima.rs +++ b/crates/zkvm/sp1/src/compiler/rust_rv32ima.rs @@ -52,6 +52,7 @@ mod tests { use crate::{compiler::RustRv32ima, zkvm::EreSP1}; use ere_test_utils::host::testing_guest_directory; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{ProverResourceType, zkVM}, }; @@ -69,6 +70,6 @@ mod tests { let program = RustRv32ima.compile(&guest_directory).unwrap(); let zkvm = EreSP1::new(program, ProverResourceType::Cpu).unwrap(); - zkvm.execute(&[]).unwrap(); + zkvm.execute(&Input::default()).unwrap(); } } diff --git a/crates/zkvm/sp1/src/zkvm.rs b/crates/zkvm/sp1/src/zkvm.rs index 4393d54..b5b419c 100644 --- a/crates/zkvm/sp1/src/zkvm.rs +++ b/crates/zkvm/sp1/src/zkvm.rs @@ -1,7 +1,7 @@ use crate::{program::SP1Program, zkvm::sdk::Prover}; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, zkVMProgramDigest, }; use sp1_sdk::{SP1ProofMode, SP1ProofWithPublicValues, SP1ProvingKey, SP1Stdin, SP1VerifyingKey}; @@ -61,9 +61,8 @@ impl EreSP1 { } impl zkVM for EreSP1 { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { - let mut stdin = SP1Stdin::new(); - stdin.write_slice(input); + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + let stdin = input_to_stdin(input)?; let prover = self.prover()?; @@ -83,13 +82,12 @@ impl zkVM for EreSP1 { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { info!("Generating proof…"); - let mut stdin = SP1Stdin::new(); - stdin.write_slice(input); + let stdin = input_to_stdin(input)?; let mode = match proof_kind { ProofKind::Compressed => SP1ProofMode::Compressed, @@ -169,6 +167,17 @@ impl zkVMProgramDigest for EreSP1 { } } +fn input_to_stdin(input: &Input) -> Result { + let mut stdin = SP1Stdin::new(); + stdin.write_slice(input.stdin()); + if let Some(proofs) = input.proofs() { + for (proof, vk) in proofs.map_err(Error::DeserializeInputProofs)? { + stdin.write_proof(proof, vk); + } + } + Ok(stdin) +} + fn panic_msg(err: Box) -> String { None.or_else(|| err.downcast_ref::().cloned()) .or_else(|| err.downcast_ref::<&'static str>().map(ToString::to_string)) @@ -184,6 +193,7 @@ mod tests { program::basic::BasicProgram, }; use ere_zkvm_interface::{ + Input, compiler::Compiler, zkvm::{NetworkProverConfig, ProofKind, ProverResourceType, zkVM}, }; @@ -215,8 +225,8 @@ mod tests { let zkvm = EreSP1::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.execute(&input).unwrap_err(); } @@ -237,8 +247,8 @@ mod tests { let zkvm = EreSP1::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.prove(&input, ProofKind::default()).unwrap_err(); } diff --git a/crates/zkvm/sp1/src/zkvm/error.rs b/crates/zkvm/sp1/src/zkvm/error.rs index 16f4ef2..18017eb 100644 --- a/crates/zkvm/sp1/src/zkvm/error.rs +++ b/crates/zkvm/sp1/src/zkvm/error.rs @@ -10,6 +10,9 @@ pub enum Error { #[error("Prover RwLock posioned, panic not catched properly")] RwLockPosioned, + #[error("Deserialize proofs in Input failed: {0:?}")] + DeserializeInputProofs(bincode::error::DecodeError), + // Execute #[error("SP1 execution failed: {0}")] Execute(#[source] anyhow::Error), diff --git a/crates/zkvm/ziren/src/zkvm.rs b/crates/zkvm/ziren/src/zkvm.rs index 799fc1d..00e7a2f 100644 --- a/crates/zkvm/ziren/src/zkvm.rs +++ b/crates/zkvm/ziren/src/zkvm.rs @@ -1,7 +1,7 @@ use crate::program::ZirenProgram; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, zkVMProgramDigest, }; use std::{panic, time::Instant}; @@ -37,9 +37,8 @@ impl EreZiren { } impl zkVM for EreZiren { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { - let mut stdin = ZKMStdin::new(); - stdin.write_slice(input); + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + let stdin = input_to_stdin(input)?; let start = Instant::now(); let (public_inputs, exec_report) = CpuProver::new() @@ -59,13 +58,12 @@ impl zkVM for EreZiren { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { info!("Generating proof…"); - let mut stdin = ZKMStdin::new(); - stdin.write_slice(input); + let stdin = input_to_stdin(input)?; let inner_proof_kind = match proof_kind { ProofKind::Compressed => ZKMProofKind::Compressed, @@ -135,6 +133,17 @@ impl zkVMProgramDigest for EreZiren { } } +fn input_to_stdin(input: &Input) -> Result { + let mut stdin = ZKMStdin::new(); + stdin.write_slice(input.stdin()); + if let Some(proofs) = input.proofs() { + for (proof, vk) in proofs.map_err(Error::DeserializeInputProofs)? { + stdin.write_proof(proof, vk); + } + } + Ok(stdin) +} + fn panic_msg(err: Box) -> String { None.or_else(|| err.downcast_ref::().cloned()) .or_else(|| err.downcast_ref::<&'static str>().map(ToString::to_string)) @@ -151,7 +160,7 @@ mod tests { }; use ere_zkvm_interface::{ compiler::Compiler, - zkvm::{ProofKind, ProverResourceType, zkVM}, + zkvm::{Input, ProofKind, ProverResourceType, zkVM}, }; use std::sync::OnceLock; @@ -181,8 +190,8 @@ mod tests { let zkvm = EreZiren::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.execute(&input).unwrap_err(); } @@ -203,8 +212,8 @@ mod tests { let zkvm = EreZiren::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.prove(&input, ProofKind::default()).unwrap_err(); } diff --git a/crates/zkvm/ziren/src/zkvm/error.rs b/crates/zkvm/ziren/src/zkvm/error.rs index 8c450ff..fe2f5bf 100644 --- a/crates/zkvm/ziren/src/zkvm/error.rs +++ b/crates/zkvm/ziren/src/zkvm/error.rs @@ -8,6 +8,9 @@ pub enum Error { #[error("Ziren execution failed: {0}")] Execute(#[source] anyhow::Error), + #[error("Deserialize proofs in Input failed: {0:?}")] + DeserializeInputProofs(bincode::error::DecodeError), + // Prove #[error("Ziren proving failed: {0}")] Prove(#[source] anyhow::Error), diff --git a/crates/zkvm/zisk/src/zkvm.rs b/crates/zkvm/zisk/src/zkvm.rs index 491f76f..66803c6 100644 --- a/crates/zkvm/zisk/src/zkvm.rs +++ b/crates/zkvm/zisk/src/zkvm.rs @@ -4,7 +4,7 @@ use crate::{ }; use anyhow::bail; use ere_zkvm_interface::zkvm::{ - CommonError, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, + CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType, PublicValues, zkVM, zkVMProgramDigest, }; use std::{ @@ -68,9 +68,13 @@ impl EreZisk { } impl zkVM for EreZisk { - fn execute(&self, input: &[u8]) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } + let start = Instant::now(); - let (public_values, total_num_cycles) = self.sdk.execute(input)?; + let (public_values, total_num_cycles) = self.sdk.execute(input.stdin())?; let execution_duration = start.elapsed(); Ok(( @@ -85,9 +89,12 @@ impl zkVM for EreZisk { fn prove( &self, - input: &[u8], + input: &Input, proof_kind: ProofKind, ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + if input.proofs.is_some() { + bail!(CommonError::unsupported_input("no dedicated proofs stream")) + } if proof_kind != ProofKind::Compressed { bail!(CommonError::unsupported_proof_kind( proof_kind, @@ -99,7 +106,7 @@ impl zkVM for EreZisk { let server = server.as_mut().expect("server initialized"); let start = Instant::now(); - let (public_values, proof) = server.prove(input)?; + let (public_values, proof) = server.prove(input.stdin())?; let proving_time = start.elapsed(); Ok(( @@ -147,7 +154,7 @@ mod tests { }; use ere_zkvm_interface::{ compiler::Compiler, - zkvm::{ProofKind, ProverResourceType, zkVM}, + zkvm::{Input, ProofKind, ProverResourceType, zkVM}, }; use std::sync::{Mutex, OnceLock}; @@ -181,8 +188,8 @@ mod tests { let zkvm = EreZisk::new(program, ProverResourceType::Cpu).unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.execute(&input).unwrap_err(); } @@ -207,8 +214,8 @@ mod tests { let _guard = PROVE_LOCK.lock().unwrap(); for input in [ - Vec::new(), - BasicProgram::::invalid_test_case().serialized_input(), + Input::default(), + BasicProgram::::invalid_test_case().input(), ] { zkvm.prove(&input, ProofKind::default()).unwrap_err(); }