From 8d3847df2895a8acd86f397920ffd93264bd5328 Mon Sep 17 00:00:00 2001 From: Han Date: Fri, 29 Aug 2025 09:21:46 +0800 Subject: [PATCH] zkVM output for `ere-dockerized` (#112) --- crates/ere-dockerized/src/input.rs | 4 +-- crates/ere-dockerized/src/lib.rs | 13 +++++++--- crates/ere-dockerized/src/output.rs | 26 +++++++++++++++++++ crates/ere-jolt/src/lib.rs | 1 + crates/ere-nexus/src/lib.rs | 1 + crates/ere-openvm/src/lib.rs | 12 +++------ crates/ere-pico/src/lib.rs | 5 ++-- crates/ere-risc0/src/lib.rs | 39 ++++++----------------------- crates/ere-risc0/src/output.rs | 23 +++++++++++++++++ crates/ere-sp1/src/lib.rs | 11 +++----- crates/ere-zisk/src/lib.rs | 12 ++++----- crates/test-utils/src/host.rs | 9 ++++--- 12 files changed, 89 insertions(+), 67 deletions(-) create mode 100644 crates/ere-dockerized/src/output.rs create mode 100644 crates/ere-risc0/src/output.rs diff --git a/crates/ere-dockerized/src/input.rs b/crates/ere-dockerized/src/input.rs index 4a0ea22..0d1bed0 100644 --- a/crates/ere-dockerized/src/input.rs +++ b/crates/ere-dockerized/src/input.rs @@ -10,9 +10,9 @@ impl ErezkVM { ) -> Result, CommonError> { match self { // Issue for tracking: https://github.com/eth-act/ere/issues/4. - Self::Jolt => unimplemented!(), + Self::Jolt => todo!(), // Issue for tracking: https://github.com/eth-act/ere/issues/63. - Self::Nexus => unimplemented!(), + Self::Nexus => todo!(), // FIXME: Instead of using `openvm::serde::to_vec`, we use Risc0's // serializer, because OpenVM uses the same one, to avoid the // duplicated extern symbol they export. diff --git a/crates/ere-dockerized/src/lib.rs b/crates/ere-dockerized/src/lib.rs index 27d6a26..2b2354a 100644 --- a/crates/ere-dockerized/src/lib.rs +++ b/crates/ere-dockerized/src/lib.rs @@ -84,6 +84,7 @@ include!(concat!(env!("OUT_DIR"), "/zkvm_sdk_version_impl.rs")); pub mod docker; pub mod error; pub mod input; +pub mod output; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ErezkVM { @@ -215,6 +216,10 @@ impl EreDockerizedCompiler { mount_directory: mount_directory.as_ref().to_path_buf(), } } + + pub fn zkvm(&self) -> ErezkVM { + self.zkvm + } } /// Wrapper for serialized program. @@ -472,8 +477,8 @@ impl zkVM for EreDockerizedzkVM { self.zkvm.sdk_version() } - fn deserialize_from(&self, _reader: R) -> Result { - todo!() + fn deserialize_from(&self, reader: R) -> Result { + self.zkvm.deserialize_from(reader) } } @@ -508,7 +513,7 @@ mod test { let zkvm = EreDockerizedzkVM::new(zkvm, program, ProverResourceType::Cpu).unwrap(); - let io = BasicProgramIo::valid(); + let io = BasicProgramIo::valid().into_output_hashed_io(); run_zkvm_execute(&zkvm, &io); run_zkvm_prove(&zkvm, &io); } @@ -556,7 +561,7 @@ mod test { let zkvm = EreDockerizedzkVM::new(zkvm, program, ProverResourceType::Cpu).unwrap(); - let io = BasicProgramIo::valid(); + let io = BasicProgramIo::valid().into_output_hashed_io(); run_zkvm_execute(&zkvm, &io); run_zkvm_prove(&zkvm, &io); } diff --git a/crates/ere-dockerized/src/output.rs b/crates/ere-dockerized/src/output.rs new file mode 100644 index 0000000..86e5470 --- /dev/null +++ b/crates/ere-dockerized/src/output.rs @@ -0,0 +1,26 @@ +use crate::ErezkVM; +use serde::de::DeserializeOwned; +use std::io::Read; +use zkvm_interface::zkVMError; + +#[path = "../../ere-risc0/src/output.rs"] +mod ere_risc0_output; + +impl ErezkVM { + pub fn deserialize_from( + &self, + reader: R, + ) -> Result { + match self { + // Issue for tracking: https://github.com/eth-act/ere/issues/4. + Self::Jolt => todo!(), + // Issue for tracking: https://github.com/eth-act/ere/issues/63. + Self::Nexus => todo!(), + Self::OpenVM => unimplemented!("no native serialization in this platform"), + Self::Pico => bincode::deserialize_from(reader).map_err(zkVMError::other), + Self::Risc0 => ere_risc0_output::deserialize_from(reader), + Self::SP1 => bincode::deserialize_from(reader).map_err(zkVMError::other), + Self::Zisk => unimplemented!("no native serialization in this platform"), + } + } +} diff --git a/crates/ere-jolt/src/lib.rs b/crates/ere-jolt/src/lib.rs index 82bc40b..aea83b6 100644 --- a/crates/ere-jolt/src/lib.rs +++ b/crates/ere-jolt/src/lib.rs @@ -153,6 +153,7 @@ impl zkVM for EreJolt { } fn deserialize_from(&self, _reader: R) -> Result { + // Issue for tracking: https://github.com/eth-act/ere/issues/4. todo!() } } diff --git a/crates/ere-nexus/src/lib.rs b/crates/ere-nexus/src/lib.rs index bec5e4a..7a77f84 100644 --- a/crates/ere-nexus/src/lib.rs +++ b/crates/ere-nexus/src/lib.rs @@ -149,6 +149,7 @@ impl zkVM for EreNexus { } fn deserialize_from(&self, _reader: R) -> Result { + // Issue for tracking: https://github.com/eth-act/ere/issues/63. todo!() } } diff --git a/crates/ere-openvm/src/lib.rs b/crates/ere-openvm/src/lib.rs index 0a8b231..b3d93d8 100644 --- a/crates/ere-openvm/src/lib.rs +++ b/crates/ere-openvm/src/lib.rs @@ -231,9 +231,7 @@ impl zkVM for EreOpenVM { } fn deserialize_from(&self, _: R) -> Result { - Err(zkVMError::other( - "public values de/serialization is not supported", - )) + unimplemented!("no native serialization in this platform") } } @@ -270,7 +268,7 @@ mod tests { use super::*; use std::sync::OnceLock; use test_utils::host::{ - BasicProgramIo, Io, run_zkvm_execute, run_zkvm_prove, testing_guest_directory, + BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory, }; fn basic_program() -> OpenVMProgram { @@ -296,8 +294,7 @@ mod tests { let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap(); let io = BasicProgramIo::valid().into_output_hashed_io(); - let public_values = run_zkvm_execute(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_execute(&zkvm, &io); } #[test] @@ -320,8 +317,7 @@ mod tests { let zkvm = EreOpenVM::new(program, ProverResourceType::Cpu).unwrap(); let io = BasicProgramIo::valid().into_output_hashed_io(); - let public_values = run_zkvm_prove(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_prove(&zkvm, &io); } #[test] diff --git a/crates/ere-pico/src/lib.rs b/crates/ere-pico/src/lib.rs index 285d5a9..06dc7ec 100644 --- a/crates/ere-pico/src/lib.rs +++ b/crates/ere-pico/src/lib.rs @@ -164,7 +164,7 @@ fn serialize_inputs(stdin: &mut EmulatorStdinBuilder, KoalaBearPoseidon2 mod tests { use super::*; use std::{panic, sync::OnceLock}; - use test_utils::host::{BasicProgramIo, Io, run_zkvm_execute, testing_guest_directory}; + use test_utils::host::{BasicProgramIo, run_zkvm_execute, testing_guest_directory}; static BASIC_PRORGAM: OnceLock> = OnceLock::new(); @@ -190,8 +190,7 @@ mod tests { let zkvm = ErePico::new(program, ProverResourceType::Cpu); let io = BasicProgramIo::valid(); - let public_values = run_zkvm_execute(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_execute(&zkvm, &io); } #[test] diff --git a/crates/ere-risc0/src/lib.rs b/crates/ere-risc0/src/lib.rs index 93604a4..e96a5e1 100644 --- a/crates/ere-risc0/src/lib.rs +++ b/crates/ere-risc0/src/lib.rs @@ -3,17 +3,14 @@ use crate::{ compile::{Risc0Program, compile_risc0_program}, error::Risc0Error, + output::deserialize_from, }; use borsh::{BorshDeserialize, BorshSerialize}; use risc0_zkvm::{ DEFAULT_MAX_PO2, DefaultProver, ExecutorEnv, ExecutorEnvBuilder, ExternalProver, InnerReceipt, Journal, ProverOpts, Receipt, ReceiptClaim, SuccinctReceipt, default_executor, default_prover, - serde::{Deserializer, WordRead}, -}; -use serde::{ - Deserialize, Serialize, - de::{DeserializeOwned, Error}, }; +use serde::{Deserialize, Serialize, de::DeserializeOwned}; use std::{env, io::Read, ops::RangeInclusive, path::Path, rc::Rc, time::Instant}; use zkvm_interface::{ Compiler, Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, @@ -24,6 +21,7 @@ include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs")); mod compile; mod error; +mod output; /// Default logarithmic segment size from [`DEFAULT_SEGMENT_LIMIT_PO2`]. /// @@ -233,28 +231,7 @@ impl zkVM for EreRisc0 { } fn deserialize_from(&self, reader: R) -> Result { - struct WordReadAdapter(R); - - impl WordRead for WordReadAdapter { - fn read_words(&mut self, words: &mut [u32]) -> risc0_zkvm::serde::Result<()> { - let bytes = bytemuck::cast_slice_mut(words); - self.0 - .read_exact(bytes) - .map_err(risc0_zkvm::serde::Error::custom) - } - - fn read_padded_bytes(&mut self, bytes: &mut [u8]) -> risc0_zkvm::serde::Result<()> { - let mut padded_bytes = vec![0u8; bytes.len().next_multiple_of(4) - bytes.len()]; - self.0 - .read_exact(bytes) - .map_err(risc0_zkvm::serde::Error::custom)?; - self.0 - .read_exact(&mut padded_bytes) - .map_err(risc0_zkvm::serde::Error::custom) - } - } - - T::deserialize(&mut Deserializer::new(WordReadAdapter(reader))).map_err(zkVMError::other) + deserialize_from(reader) } } @@ -283,7 +260,7 @@ mod tests { use super::*; use std::sync::OnceLock; use test_utils::host::{ - BasicProgramIo, Io, run_zkvm_execute, run_zkvm_prove, testing_guest_directory, + BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory, }; static BASIC_PRORGAM: OnceLock = OnceLock::new(); @@ -304,8 +281,7 @@ mod tests { let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap(); let io = BasicProgramIo::valid(); - let public_values = run_zkvm_execute(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_execute(&zkvm, &io); } #[test] @@ -328,8 +304,7 @@ mod tests { let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap(); let io = BasicProgramIo::valid(); - let public_values = run_zkvm_prove(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_prove(&zkvm, &io); } #[test] diff --git a/crates/ere-risc0/src/output.rs b/crates/ere-risc0/src/output.rs new file mode 100644 index 0000000..21df0f1 --- /dev/null +++ b/crates/ere-risc0/src/output.rs @@ -0,0 +1,23 @@ +use risc0_zkvm::serde::{Deserializer, Error, WordRead}; +use serde::de::{DeserializeOwned, Error as _}; +use std::io::Read; +use zkvm_interface::zkVMError; + +pub fn deserialize_from(reader: R) -> Result { + struct WordReadAdapter(R); + + impl WordRead for WordReadAdapter { + fn read_words(&mut self, words: &mut [u32]) -> Result<(), Error> { + let bytes = bytemuck::cast_slice_mut(words); + self.0.read_exact(bytes).map_err(Error::custom) + } + + fn read_padded_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> { + let mut padded_bytes = vec![0u8; bytes.len().next_multiple_of(4) - bytes.len()]; + self.0.read_exact(bytes).map_err(Error::custom)?; + self.0.read_exact(&mut padded_bytes).map_err(Error::custom) + } + } + + T::deserialize(&mut Deserializer::new(WordReadAdapter(reader))).map_err(zkVMError::other) +} diff --git a/crates/ere-sp1/src/lib.rs b/crates/ere-sp1/src/lib.rs index e067dc9..b0a8dbe 100644 --- a/crates/ere-sp1/src/lib.rs +++ b/crates/ere-sp1/src/lib.rs @@ -253,7 +253,7 @@ mod tests { use crate::compile::compile; use std::{panic, sync::OnceLock}; use test_utils::host::{ - BasicProgramIo, Io, run_zkvm_execute, run_zkvm_prove, testing_guest_directory, + BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory, }; static BASIC_PRORGAM: OnceLock> = OnceLock::new(); @@ -274,8 +274,7 @@ mod tests { let zkvm = EreSP1::new(program, ProverResourceType::Cpu); let io = BasicProgramIo::valid(); - let public_values = run_zkvm_execute(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_execute(&zkvm, &io); } #[test] @@ -307,8 +306,7 @@ mod tests { let zkvm = EreSP1::new(program, ProverResourceType::Cpu); let io = BasicProgramIo::valid(); - let public_values = run_zkvm_prove(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_prove(&zkvm, &io); } #[test] @@ -348,7 +346,6 @@ mod tests { let zkvm = EreSP1::new(program, ProverResourceType::Network(network_config)); let io = BasicProgramIo::valid(); - let public_values = run_zkvm_prove(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_prove(&zkvm, &io); } } diff --git a/crates/ere-zisk/src/lib.rs b/crates/ere-zisk/src/lib.rs index a2d94d6..52b21fe 100644 --- a/crates/ere-zisk/src/lib.rs +++ b/crates/ere-zisk/src/lib.rs @@ -337,8 +337,8 @@ impl zkVM for EreZisk { SDK_VERSION } - fn deserialize_from(&self, _reader: R) -> Result { - todo!() + fn deserialize_from(&self, _: R) -> Result { + unimplemented!("no native serialization in this platform") } } @@ -601,7 +601,7 @@ mod tests { use super::*; use std::sync::OnceLock; use test_utils::host::{ - BasicProgramIo, Io, run_zkvm_execute, run_zkvm_prove, testing_guest_directory, + BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory, }; static BASIC_PRORGAM: OnceLock> = OnceLock::new(); @@ -622,8 +622,7 @@ mod tests { let zkvm = EreZisk::new(program, ProverResourceType::Cpu); let io = BasicProgramIo::valid().into_output_hashed_io(); - let public_values = run_zkvm_execute(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_execute(&zkvm, &io); } #[test] @@ -646,8 +645,7 @@ mod tests { let zkvm = EreZisk::new(program, ProverResourceType::Cpu); let io = BasicProgramIo::valid().into_output_hashed_io(); - let public_values = run_zkvm_prove(&zkvm, &io); - assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + run_zkvm_prove(&zkvm, &io); } #[test] diff --git a/crates/test-utils/src/host.rs b/crates/test-utils/src/host.rs index 52faab5..227d25e 100644 --- a/crates/test-utils/src/host.rs +++ b/crates/test-utils/src/host.rs @@ -29,8 +29,7 @@ pub fn run_zkvm_execute(zkvm: &impl zkVM, io: &impl Io) -> PublicValues { .execute(&io.inputs()) .expect("execute should not fail with valid input"); - // TODO: Uncomment when most zkVMs implement the returning of public values: - // assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); + assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs()); public_values } @@ -46,8 +45,10 @@ pub fn run_zkvm_prove(zkvm: &impl zkVM, io: &impl Io) -> PublicValues { assert_eq!(prover_public_values, verifier_public_values); - // TODO: Uncomment when most zkVMs implement the returning of public values: - // assert_eq!(io.deserialize_outputs(&zkvm, &verifier_public_values), io.outputs()); + assert_eq!( + io.deserialize_outputs(&zkvm, &verifier_public_values), + io.outputs() + ); verifier_public_values }