diff --git a/crates/ere-jolt/src/error.rs b/crates/ere-jolt/src/error.rs new file mode 100644 index 0000000..be6c073 --- /dev/null +++ b/crates/ere-jolt/src/error.rs @@ -0,0 +1,13 @@ +use zkvm_interface::zkVMError; + +impl From for zkVMError { + fn from(value: JoltError) -> Self { + zkVMError::Other(Box::new(value)) + } +} + +#[derive(Debug, thiserror::Error)] +pub enum JoltError { + #[error("Proof verification failed")] + ProofVerificationFailed, +} diff --git a/crates/ere-jolt/src/lib.rs b/crates/ere-jolt/src/lib.rs index 5f42809..cbaa0ca 100644 --- a/crates/ere-jolt/src/lib.rs +++ b/crates/ere-jolt/src/lib.rs @@ -1,3 +1,4 @@ +use error::JoltError; use jolt_core::host::Program; use jolt_methods::{preprocess_prover, preprocess_verifier, prove_generic, verify_generic}; use jolt_sdk::host::DEFAULT_TARGET_DIR; @@ -7,20 +8,16 @@ use utils::{ }; use zkvm_interface::{ Compiler, Input, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM, + zkVMError, }; +mod error; mod jolt_methods; mod utils; #[allow(non_camel_case_types)] pub struct JOLT_TARGET; -#[derive(Debug, thiserror::Error)] -pub enum JoltError { - #[error("Proof verification failed")] - ProofVerificationFailed, -} - impl Compiler for JOLT_TARGET { type Error = JoltError; @@ -53,12 +50,10 @@ impl EreJolt { } } impl zkVM for EreJolt { - type Error = JoltError; - fn execute( &self, inputs: &zkvm_interface::Input, - ) -> Result { + ) -> Result { // TODO: check ProgramSummary let summary = self .program @@ -72,7 +67,7 @@ impl zkVM for EreJolt { fn prove( &self, inputs: &zkvm_interface::Input, - ) -> Result<(Vec, zkvm_interface::ProgramProvingReport), Self::Error> { + ) -> Result<(Vec, zkvm_interface::ProgramProvingReport), zkVMError> { // TODO: make this stateful and do in setup since its expensive and should be done once per program; let preprocessed_key = preprocess_prover(&self.program); @@ -86,7 +81,7 @@ impl zkVM for EreJolt { Ok((proof_with_public_inputs, ProgramProvingReport::new(elapsed))) } - fn verify(&self, proof_with_public_inputs: &[u8]) -> Result<(), Self::Error> { + fn verify(&self, proof_with_public_inputs: &[u8]) -> Result<(), zkVMError> { let preprocessed_verifier = preprocess_verifier(&self.program); let (public_inputs, proof) = deserialize_public_input_with_proof(proof_with_public_inputs).unwrap(); @@ -102,7 +97,7 @@ impl zkVM for EreJolt { if valid { Ok(()) } else { - Err(JoltError::ProofVerificationFailed) + Err(JoltError::ProofVerificationFailed).map_err(zkVMError::from) } } } diff --git a/crates/ere-openvm/src/error.rs b/crates/ere-openvm/src/error.rs index 5f32748..c21a4df 100644 --- a/crates/ere-openvm/src/error.rs +++ b/crates/ere-openvm/src/error.rs @@ -1,4 +1,11 @@ use thiserror::Error; +use zkvm_interface::zkVMError; + +impl From for zkVMError { + fn from(value: OpenVMError) -> Self { + zkVMError::Other(Box::new(value)) + } +} #[derive(Debug, Error)] pub enum OpenVMError { diff --git a/crates/ere-openvm/src/lib.rs b/crates/ere-openvm/src/lib.rs index f5721eb..f47f356 100644 --- a/crates/ere-openvm/src/lib.rs +++ b/crates/ere-openvm/src/lib.rs @@ -12,7 +12,7 @@ use openvm_stark_sdk::config::{ }; use openvm_transpiler::elf::Elf; use zkvm_interface::{ - Compiler, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM, + Compiler, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM, zkVMError, }; mod error; @@ -56,12 +56,10 @@ impl EreOpenVM { } } impl zkVM for EreOpenVM { - type Error = OpenVMError; - fn execute( &self, inputs: &zkvm_interface::Input, - ) -> Result { + ) -> Result { let sdk = Sdk::new(); let vm_cfg = SdkVmConfig::builder() .system(Default::default()) @@ -72,7 +70,8 @@ impl zkVM for EreOpenVM { let exe = sdk .transpile(self.program.clone(), vm_cfg.transpiler()) - .map_err(|e| CompileError::Client(e.into()))?; + .map_err(|e| CompileError::Client(e.into())) + .map_err(OpenVMError::from)?; let mut stdin = StdIn::default(); for input in inputs.chunked_iter() { @@ -81,7 +80,8 @@ impl zkVM for EreOpenVM { let _outputs = sdk .execute(exe.clone(), vm_cfg.clone(), stdin) - .map_err(|e| CompileError::Client(e.into()))?; + .map_err(|e| CompileError::Client(e.into())) + .map_err(OpenVMError::from)?; Ok(ProgramExecutionReport::default()) } @@ -89,7 +89,7 @@ impl zkVM for EreOpenVM { fn prove( &self, inputs: &zkvm_interface::Input, - ) -> Result<(Vec, zkvm_interface::ProgramProvingReport), Self::Error> { + ) -> Result<(Vec, zkvm_interface::ProgramProvingReport), zkVMError> { // TODO: We need a stateful version in order to not spend a lot of time // TODO doing things like computing the pk and vk. @@ -103,7 +103,8 @@ impl zkVM for EreOpenVM { let app_exe = sdk .transpile(self.program.clone(), vm_cfg.transpiler()) - .map_err(|e| CompileError::Client(e.into()))?; + .map_err(|e| CompileError::Client(e.into())) + .map_err(OpenVMError::from)?; let mut stdin = StdIn::default(); for input in inputs.chunked_iter() { @@ -131,7 +132,7 @@ impl zkVM for EreOpenVM { Ok((proof_bytes, ProgramProvingReport::new(elapsed))) } - fn verify(&self, mut proof: &[u8]) -> Result<(), Self::Error> { + fn verify(&self, mut proof: &[u8]) -> Result<(), zkVMError> { let sdk = Sdk::new(); let vm_cfg = SdkVmConfig::builder() .system(Default::default()) @@ -150,6 +151,7 @@ impl zkVM for EreOpenVM { sdk.verify_app_proof(&app_vk, &proof) .map(|_payload| ()) .map_err(|e| OpenVMError::Verify(VerifyError::Client(e.into()))) + .map_err(zkVMError::from) } } diff --git a/crates/ere-pico/src/error.rs b/crates/ere-pico/src/error.rs index 0bbd52c..3eb1096 100644 --- a/crates/ere-pico/src/error.rs +++ b/crates/ere-pico/src/error.rs @@ -1,5 +1,12 @@ use std::{io, path::PathBuf, process::ExitStatus}; use thiserror::Error; +use zkvm_interface::zkVMError; + +impl From for zkVMError { + fn from(value: PicoError) -> Self { + zkVMError::Other(Box::new(value)) + } +} #[derive(Debug, Error)] pub enum PicoError { diff --git a/crates/ere-pico/src/lib.rs b/crates/ere-pico/src/lib.rs index bbd3bd0..eb21080 100644 --- a/crates/ere-pico/src/lib.rs +++ b/crates/ere-pico/src/lib.rs @@ -1,6 +1,6 @@ use pico_sdk::client::DefaultProverClient; use std::process::Command; -use zkvm_interface::{Compiler, ProgramProvingReport, ProverResourceType, zkVM}; +use zkvm_interface::{Compiler, ProgramProvingReport, ProverResourceType, zkVM, zkVMError}; mod error; use error::PicoError; @@ -62,19 +62,17 @@ impl ErePico { } } impl zkVM for ErePico { - type Error = PicoError; - fn execute( &self, _inputs: &zkvm_interface::Input, - ) -> Result { + ) -> Result { todo!("pico currently does not have an execute method exposed via the SDK") } fn prove( &self, inputs: &zkvm_interface::Input, - ) -> Result<(Vec, zkvm_interface::ProgramProvingReport), Self::Error> { + ) -> Result<(Vec, zkvm_interface::ProgramProvingReport), zkVMError> { let client = DefaultProverClient::new(&self.program); let mut stdin = client.new_stdin_builder(); @@ -103,7 +101,7 @@ impl zkVM for ErePico { Ok((proof_serialized, ProgramProvingReport::new(elapsed))) } - fn verify(&self, _proof: &[u8]) -> Result<(), Self::Error> { + fn verify(&self, _proof: &[u8]) -> Result<(), zkVMError> { let client = DefaultProverClient::new(&self.program); let _vk = client.riscv_vk(); diff --git a/crates/ere-sp1/src/error.rs b/crates/ere-sp1/src/error.rs index 9310e91..b69c9d8 100644 --- a/crates/ere-sp1/src/error.rs +++ b/crates/ere-sp1/src/error.rs @@ -1,6 +1,13 @@ use std::{path::PathBuf, process::ExitStatus}; use thiserror::Error; +use zkvm_interface::zkVMError; + +impl From for zkVMError { + fn from(value: SP1Error) -> Self { + zkVMError::Other(Box::new(value)) + } +} #[derive(Debug, Error)] pub enum SP1Error { diff --git a/crates/ere-sp1/src/lib.rs b/crates/ere-sp1/src/lib.rs index a354333..46e3d0d 100644 --- a/crates/ere-sp1/src/lib.rs +++ b/crates/ere-sp1/src/lib.rs @@ -7,7 +7,7 @@ use sp1_sdk::{ }; use tracing::info; use zkvm_interface::{ - Compiler, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM, + Compiler, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM, zkVMError, }; mod compile; @@ -35,7 +35,7 @@ impl ProverType { &self, program: &::Program, input: &SP1Stdin, - ) -> Result<(sp1_sdk::SP1PublicValues, sp1_sdk::ExecutionReport), ExecuteError> { + ) -> Result<(sp1_sdk::SP1PublicValues, sp1_sdk::ExecutionReport), SP1Error> { let cpu_executor_builder = match self { ProverType::Cpu(cpu_prover) => cpu_prover.execute(program, input), ProverType::Gpu(cuda_prover) => cuda_prover.execute(program, input), @@ -43,25 +43,25 @@ impl ProverType { cpu_executor_builder .run() - .map_err(|e| ExecuteError::Client(e.into())) + .map_err(|e| SP1Error::Execute(ExecuteError::Client(e.into()))) } fn prove( &self, pk: &SP1ProvingKey, input: &SP1Stdin, - ) -> Result { + ) -> Result { match self { ProverType::Cpu(cpu_prover) => cpu_prover.prove(pk, input).core().run(), ProverType::Gpu(cuda_prover) => cuda_prover.prove(pk, input).core().run(), } - .map_err(|e| ProveError::Client(e.into())) + .map_err(|e| SP1Error::Prove(ProveError::Client(e.into()))) } fn verify( &self, proof: &SP1ProofWithPublicValues, vk: &SP1VerifyingKey, - ) -> Result<(), error::SP1Error> { + ) -> Result<(), SP1Error> { match self { ProverType::Cpu(cpu_prover) => cpu_prover.verify(proof, vk), ProverType::Gpu(cuda_prover) => cuda_prover.verify(proof, vk), @@ -113,12 +113,10 @@ impl EreSP1 { } impl zkVM for EreSP1 { - type Error = SP1Error; - fn execute( &self, inputs: &zkvm_interface::Input, - ) -> Result { + ) -> Result { let mut stdin = SP1Stdin::new(); for input in inputs.chunked_iter() { stdin.write_slice(input); @@ -138,7 +136,7 @@ impl zkVM for EreSP1 { fn prove( &self, inputs: &zkvm_interface::Input, - ) -> Result<(Vec, zkvm_interface::ProgramProvingReport), Self::Error> { + ) -> Result<(Vec, zkvm_interface::ProgramProvingReport), zkVMError> { info!("Generating proof…"); let mut stdin = SP1Stdin::new(); @@ -156,7 +154,7 @@ impl zkVM for EreSP1 { Ok((bytes, ProgramProvingReport::new(proving_time))) } - fn verify(&self, proof: &[u8]) -> Result<(), Self::Error> { + fn verify(&self, proof: &[u8]) -> Result<(), zkVMError> { info!("Verifying proof…"); let proof: SP1ProofWithPublicValues = bincode::deserialize(proof) @@ -164,7 +162,7 @@ impl zkVM for EreSP1 { self.client .verify(&proof, &self.vk) - .map_err(|e| SP1Error::Verify(VerifyError::Client(e.into()))) + .map_err(zkVMError::from) } } diff --git a/crates/zkvm-interface/src/lib.rs b/crates/zkvm-interface/src/lib.rs index 794cbfd..a5687ee 100644 --- a/crates/zkvm-interface/src/lib.rs +++ b/crates/zkvm-interface/src/lib.rs @@ -1,6 +1,7 @@ use indexmap::IndexMap; use serde::{Deserialize, Serialize}; use std::{path::Path, time::Duration}; +use thiserror::Error; mod input; pub use input::Input; @@ -23,25 +24,37 @@ pub enum ProverResourceType { Gpu, } +/// An error that can occur during prove, execute or verification +/// of a zkVM. +/// +/// Note: We use a concrete error type here, so that downstream crates +/// can do patterns such as Vec +#[allow(non_camel_case_types)] +#[derive(Debug, Error)] +pub enum zkVMError { + // TODO: We can add more variants as time goes by. + // TODO: for now, we use this catch-all as a way to prototype faster + #[error(transparent)] + Other(#[from] Box), +} + #[allow(non_camel_case_types)] #[auto_impl::auto_impl(&, Arc, Box)] /// zkVM trait to abstract away the differences between each zkVM pub trait zkVM { - type Error: std::error::Error + Send + Sync + 'static; - /// Executes the given program with the inputs accumulated in the Input struct. /// For RISCV programs, `program_bytes` will be the ELF binary - fn execute(&self, inputs: &Input) -> Result; + fn execute(&self, inputs: &Input) -> Result; /// Creates a proof for a given program - fn prove(&self, inputs: &Input) -> Result<(Vec, ProgramProvingReport), Self::Error>; + fn prove(&self, inputs: &Input) -> Result<(Vec, ProgramProvingReport), zkVMError>; /// Verifies a proof for the given program /// TODO: Pass public inputs too and check that they match if they come with the /// TODO: proof, or append them if they do not. /// TODO: We can also just have this return the public inputs, but then the user needs /// TODO: ensure they check it for correct #[must_use] - fn verify(&self, proof: &[u8]) -> Result<(), Self::Error>; + fn verify(&self, proof: &[u8]) -> Result<(), zkVMError>; } /// ProgramExecutionReport produces information about a particular program