concrete error

This commit is contained in:
Kevaundray Wedderburn
2025-05-20 14:43:12 +01:00
parent 87f6e976dc
commit 2a3caedc19
9 changed files with 84 additions and 44 deletions

View File

@@ -0,0 +1,13 @@
use zkvm_interface::zkVMError;
impl From<JoltError> for zkVMError {
fn from(value: JoltError) -> Self {
zkVMError::Other(Box::new(value))
}
}
#[derive(Debug, thiserror::Error)]
pub enum JoltError {
#[error("Proof verification failed")]
ProofVerificationFailed,
}

View File

@@ -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<zkvm_interface::ProgramExecutionReport, Self::Error> {
) -> Result<zkvm_interface::ProgramExecutionReport, zkVMError> {
// TODO: check ProgramSummary
let summary = self
.program
@@ -72,7 +67,7 @@ impl zkVM for EreJolt {
fn prove(
&self,
inputs: &zkvm_interface::Input,
) -> Result<(Vec<u8>, zkvm_interface::ProgramProvingReport), Self::Error> {
) -> Result<(Vec<u8>, 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)
}
}
}

View File

@@ -1,4 +1,11 @@
use thiserror::Error;
use zkvm_interface::zkVMError;
impl From<OpenVMError> for zkVMError {
fn from(value: OpenVMError) -> Self {
zkVMError::Other(Box::new(value))
}
}
#[derive(Debug, Error)]
pub enum OpenVMError {

View File

@@ -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<zkvm_interface::ProgramExecutionReport, Self::Error> {
) -> Result<zkvm_interface::ProgramExecutionReport, zkVMError> {
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<u8>, zkvm_interface::ProgramProvingReport), Self::Error> {
) -> Result<(Vec<u8>, 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)
}
}

View File

@@ -1,5 +1,12 @@
use std::{io, path::PathBuf, process::ExitStatus};
use thiserror::Error;
use zkvm_interface::zkVMError;
impl From<PicoError> for zkVMError {
fn from(value: PicoError) -> Self {
zkVMError::Other(Box::new(value))
}
}
#[derive(Debug, Error)]
pub enum PicoError {

View File

@@ -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<zkvm_interface::ProgramExecutionReport, Self::Error> {
) -> Result<zkvm_interface::ProgramExecutionReport, zkVMError> {
todo!("pico currently does not have an execute method exposed via the SDK")
}
fn prove(
&self,
inputs: &zkvm_interface::Input,
) -> Result<(Vec<u8>, zkvm_interface::ProgramProvingReport), Self::Error> {
) -> Result<(Vec<u8>, 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();

View File

@@ -1,6 +1,13 @@
use std::{path::PathBuf, process::ExitStatus};
use thiserror::Error;
use zkvm_interface::zkVMError;
impl From<SP1Error> for zkVMError {
fn from(value: SP1Error) -> Self {
zkVMError::Other(Box::new(value))
}
}
#[derive(Debug, Error)]
pub enum SP1Error {

View File

@@ -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: &<RV32_IM_SUCCINCT_ZKVM_ELF as Compiler>::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<SP1ProofWithPublicValues, ProveError> {
) -> Result<SP1ProofWithPublicValues, SP1Error> {
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<zkvm_interface::ProgramExecutionReport, Self::Error> {
) -> Result<zkvm_interface::ProgramExecutionReport, zkVMError> {
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<u8>, zkvm_interface::ProgramProvingReport), Self::Error> {
) -> Result<(Vec<u8>, 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)
}
}

View File

@@ -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<dyn zkVM>
#[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<dyn std::error::Error + Send + Sync + 'static>),
}
#[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<ProgramExecutionReport, Self::Error>;
fn execute(&self, inputs: &Input) -> Result<ProgramExecutionReport, zkVMError>;
/// Creates a proof for a given program
fn prove(&self, inputs: &Input) -> Result<(Vec<u8>, ProgramProvingReport), Self::Error>;
fn prove(&self, inputs: &Input) -> Result<(Vec<u8>, 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