zkVK methods return public values (#106)

This commit is contained in:
Han
2025-08-27 14:27:56 +08:00
committed by GitHub
parent 63107268a1
commit 44044a1858
28 changed files with 655 additions and 337 deletions

82
Cargo.lock generated
View File

@@ -99,7 +99,7 @@ dependencies = [
"itoa",
"k256",
"paste",
"rand 0.9.1",
"rand 0.9.2",
"ruint",
"serde",
"tiny-keccak",
@@ -1062,19 +1062,6 @@ dependencies = [
"syn 2.0.101",
]
[[package]]
name = "bonsai-sdk"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21055e2f49cbbdbfe9f8f96d597c5527b0c6ab7933341fdc2f147180e48a988e"
dependencies = [
"duplicate",
"maybe-async",
"reqwest",
"serde",
"thiserror 2.0.12",
]
[[package]]
name = "borsh"
version = "1.5.7"
@@ -2046,17 +2033,6 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "duplicate"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97af9b5f014e228b33e77d75ee0e6e87960124f0f4b16337b586a6bec91867b1"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"proc-macro2-diagnostics",
]
[[package]]
name = "ecdsa"
version = "0.16.9"
@@ -2299,6 +2275,7 @@ dependencies = [
"jolt",
"jolt-core",
"jolt-sdk",
"serde",
"tempfile",
"test-utils",
"thiserror 2.0.12",
@@ -2313,6 +2290,7 @@ dependencies = [
"bincode",
"build-utils",
"nexus-sdk",
"serde",
"test-utils",
"thiserror 2.0.12",
"toml",
@@ -2346,6 +2324,7 @@ dependencies = [
"build-utils",
"pico-sdk",
"pico-vm",
"serde",
"test-utils",
"thiserror 2.0.12",
"zkvm-interface",
@@ -2374,6 +2353,7 @@ version = "0.0.11"
dependencies = [
"bincode",
"build-utils",
"serde",
"sp1-sdk",
"tempfile",
"test-utils",
@@ -3973,17 +3953,6 @@ dependencies = [
"rawpointer",
]
[[package]]
name = "maybe-async"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
]
[[package]]
name = "memchr"
version = "2.7.4"
@@ -6989,19 +6958,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "proc-macro2-diagnostics"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
"version_check",
"yansi",
]
[[package]]
name = "proptest"
version = "1.6.0"
@@ -7162,7 +7118,7 @@ dependencies = [
"bytes",
"getrandom 0.3.3",
"lru-slab",
"rand 0.9.1",
"rand 0.9.2",
"ring",
"rustc-hash 2.1.1",
"rustls",
@@ -7245,9 +7201,9 @@ dependencies = [
[[package]]
name = "rand"
version = "0.9.1"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
@@ -7590,7 +7546,7 @@ dependencies = [
"elf",
"lazy_static",
"postcard",
"rand 0.9.1",
"rand 0.9.2",
"risc0-zkp",
"risc0-zkvm-platform",
"ruint",
@@ -7686,7 +7642,7 @@ dependencies = [
"hex",
"lazy-regex",
"metal",
"rand 0.9.1",
"rand 0.9.2",
"rayon",
"risc0-circuit-recursion-sys",
"risc0-core",
@@ -7730,7 +7686,7 @@ dependencies = [
"num-traits",
"paste",
"postcard",
"rand 0.9.1",
"rand 0.9.2",
"rayon",
"ringbuffer",
"risc0-binfmt",
@@ -7836,7 +7792,7 @@ dependencies = [
"ndarray",
"parking_lot",
"paste",
"rand 0.9.1",
"rand 0.9.2",
"rand_core 0.9.3",
"rayon",
"risc0-core",
@@ -7857,7 +7813,6 @@ dependencies = [
"addr2line",
"anyhow",
"bincode",
"bonsai-sdk",
"borsh",
"bytemuck",
"bytes",
@@ -7874,7 +7829,7 @@ dependencies = [
"num-traits",
"object",
"prost 0.13.5",
"rand 0.9.1",
"rand 0.9.2",
"rayon",
"risc0-binfmt",
"risc0-build",
@@ -8015,7 +7970,7 @@ dependencies = [
"primitive-types",
"proptest",
"rand 0.8.5",
"rand 0.9.1",
"rand 0.9.2",
"rlp",
"ruint-macro",
"serde",
@@ -9401,6 +9356,7 @@ dependencies = [
name = "test-utils"
version = "0.0.11"
dependencies = [
"rand 0.9.2",
"serde",
"zkvm-interface",
]
@@ -10072,7 +10028,7 @@ checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
dependencies = [
"getrandom 0.3.3",
"js-sys",
"rand 0.9.1",
"rand 0.9.2",
"wasm-bindgen",
]
@@ -10670,12 +10626,6 @@ dependencies = [
"hashlink",
]
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "yoke"
version = "0.8.0"

View File

@@ -38,6 +38,7 @@ clap = "4.5.42"
dashmap = "6.1.0"
erased-serde = "0.4.6"
indexmap = "2.10.0"
rand = "0.9.2"
serde = "1.0.219"
serde_json = "1.0.142"
serde_yaml = "0.9.34"

View File

@@ -48,6 +48,9 @@ enum Commands {
/// Path to the serialized input bytes file
#[arg(long)]
input_path: PathBuf,
/// Path where the public values will be written
#[arg(long)]
public_values_path: PathBuf,
/// Path where the execution report will be written
#[arg(long)]
report_path: PathBuf,
@@ -60,6 +63,9 @@ enum Commands {
/// Path to the serialized input bytes file
#[arg(long)]
input_path: PathBuf,
/// Path where the public values will be written
#[arg(long)]
public_values_path: PathBuf,
/// Path where the proof will be written
#[arg(long)]
proof_path: PathBuf,
@@ -78,6 +84,9 @@ enum Commands {
/// Path to the proof
#[arg(long)]
proof_path: PathBuf,
/// Path where the public values will be written
#[arg(long)]
public_values_path: PathBuf,
},
}
@@ -96,19 +105,29 @@ fn main() -> Result<(), Error> {
Commands::Execute {
program_path,
input_path,
public_values_path,
report_path,
} => execute(program_path, input_path, report_path),
} => execute(program_path, input_path, public_values_path, report_path),
Commands::Prove {
program_path,
input_path,
public_values_path,
proof_path,
report_path,
resource,
} => prove(program_path, resource, input_path, proof_path, report_path),
} => prove(
program_path,
resource,
input_path,
public_values_path,
proof_path,
report_path,
),
Commands::Verify {
program_path,
proof_path,
} => verify(program_path, proof_path),
public_values_path,
} => verify(program_path, proof_path, public_values_path),
}
}
@@ -145,32 +164,61 @@ fn prove(
program_path: PathBuf,
resource: ProverResourceType,
input_path: PathBuf,
public_values_path: PathBuf,
proof_path: PathBuf,
report_path: PathBuf,
) -> Result<(), Error> {
let zkvm = construct_zkvm(program_path, resource)?;
let input = serde::read_input(&input_path)?;
let (proof, report) = zkvm.prove(&input).with_context(|| "Failed to prove")?;
let (public_values, proof, report) = zkvm.prove(&input).with_context(|| "Failed to prove")?;
fs::write(&public_values_path, &public_values).with_context(|| {
format!(
"Failed to write public values to {}",
public_values_path.display()
)
})?;
fs::write(&proof_path, proof)
.with_context(|| format!("Failed to write proof to {}", proof_path.display()))?;
serde::write(&report_path, &report, "report")?;
Ok(())
}
fn execute(program_path: PathBuf, input_path: PathBuf, report_path: PathBuf) -> Result<(), Error> {
fn execute(
program_path: PathBuf,
input_path: PathBuf,
public_values_path: PathBuf,
report_path: PathBuf,
) -> Result<(), Error> {
let zkvm = construct_zkvm(program_path, ProverResourceType::Cpu)?;
let input = serde::read_input(&input_path)?;
let report = zkvm.execute(&input).with_context(|| "Failed to execute")?;
let (public_values, report) = zkvm.execute(&input).with_context(|| "Failed to execute")?;
fs::write(&public_values_path, &public_values).with_context(|| {
format!(
"Failed to write public values to {}",
public_values_path.display()
)
})?;
serde::write(&report_path, &report, "report")?;
Ok(())
}
fn verify(program_path: PathBuf, proof_path: PathBuf) -> Result<(), Error> {
fn verify(
program_path: PathBuf,
proof_path: PathBuf,
public_values_path: PathBuf,
) -> Result<(), Error> {
let zkvm = construct_zkvm(program_path, ProverResourceType::Cpu)?;
let proof = fs::read(&proof_path)
.with_context(|| format!("Failed to read proof from {}", proof_path.display()))?;
zkvm.verify(&proof)
let public_values = zkvm
.verify(&proof)
.with_context(|| "Failed to verify proof")?;
fs::write(&public_values_path, &public_values).with_context(|| {
format!(
"Failed to write public values to {}",
public_values_path.display()
)
})?;
Ok(())
}

View File

@@ -62,18 +62,20 @@ use crate::{
docker::{DockerBuildCmd, DockerRunCmd, docker_image_exists},
error::{CommonError, CompileError, DockerizedError, ExecuteError, ProveError, VerifyError},
};
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use std::{
env,
fmt::{self, Display, Formatter},
fs, iter,
fs,
io::Read,
iter,
path::{Path, PathBuf},
str::FromStr,
};
use tempfile::TempDir;
use zkvm_interface::{
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM,
zkVMError,
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType,
PublicValues, zkVM, zkVMError,
};
include!(concat!(env!("OUT_DIR"), "/crate_version.rs"));
@@ -288,7 +290,7 @@ impl EreDockerizedzkVM {
}
impl zkVM for EreDockerizedzkVM {
fn execute(&self, inputs: &Input) -> Result<ProgramExecutionReport, zkVMError> {
fn execute(&self, inputs: &Input) -> Result<(PublicValues, ProgramExecutionReport), zkVMError> {
let tempdir = TempDir::new()
.map_err(|err| CommonError::io(err, "Failed to create temporary directory"))
.map_err(|err| DockerizedError::Execute(ExecuteError::Common(err)))?;
@@ -317,12 +319,17 @@ impl zkVM for EreDockerizedzkVM {
"/workspace/program",
"--input-path",
"/workspace/input",
"--public-values-path",
"/workspace/public_values",
"--report-path",
"/workspace/report",
])
.map_err(CommonError::DockerRunCmd)
.map_err(|err| DockerizedError::Execute(ExecuteError::Common(err)))?;
let public_values = fs::read(tempdir.path().join("public_values"))
.map_err(|err| CommonError::io(err, "Failed to read public_values"))
.map_err(|err| DockerizedError::Execute(ExecuteError::Common(err)))?;
let report_bytes = fs::read(tempdir.path().join("report"))
.map_err(|err| CommonError::io(err, "Failed to read report"))
.map_err(|err| DockerizedError::Execute(ExecuteError::Common(err)))?;
@@ -330,10 +337,13 @@ impl zkVM for EreDockerizedzkVM {
let report = bincode::deserialize(&report_bytes)
.map_err(|err| CommonError::serilization(err, "Failed to deserialize report"))
.map_err(|err| DockerizedError::Prove(ProveError::Common(err)))?;
Ok(report)
Ok((public_values, report))
}
fn prove(&self, inputs: &Input) -> Result<(Vec<u8>, ProgramProvingReport), zkVMError> {
fn prove(
&self,
inputs: &Input,
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError> {
let tempdir = TempDir::new()
.map_err(|err| CommonError::io(err, "Failed to create temporary directory"))
.map_err(|err| DockerizedError::Prove(ProveError::Common(err)))?;
@@ -391,6 +401,8 @@ impl zkVM for EreDockerizedzkVM {
"/workspace/program",
"--input-path",
"/workspace/input",
"--public-values-path",
"/workspace/public_values",
"--proof-path",
"/workspace/proof",
"--report-path",
@@ -401,6 +413,9 @@ impl zkVM for EreDockerizedzkVM {
.map_err(CommonError::DockerRunCmd)
.map_err(|err| DockerizedError::Prove(ProveError::Common(err)))?;
let public_values = fs::read(tempdir.path().join("public_values"))
.map_err(|err| CommonError::io(err, "Failed to read public_values"))
.map_err(|err| DockerizedError::Prove(ProveError::Common(err)))?;
let proof = fs::read(tempdir.path().join("proof"))
.map_err(|err| CommonError::io(err, "Failed to read proof"))
.map_err(|err| DockerizedError::Prove(ProveError::Common(err)))?;
@@ -410,10 +425,10 @@ impl zkVM for EreDockerizedzkVM {
let report = bincode::deserialize(&report_bytes)
.map_err(|err| CommonError::serilization(err, "Failed to deserialize report"))
.map_err(|err| DockerizedError::Prove(ProveError::Common(err)))?;
Ok((proof, report))
Ok((public_values, proof, report))
}
fn verify(&self, proof: &[u8]) -> Result<(), zkVMError> {
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
let tempdir = TempDir::new()
.map_err(|err| CommonError::io(err, "Failed to create temporary directory"))
.map_err(|err| DockerizedError::Verify(VerifyError::Common(err)))?;
@@ -436,11 +451,17 @@ impl zkVM for EreDockerizedzkVM {
"/workspace/program",
"--proof-path",
"/workspace/proof",
"--public-values-path",
"/workspace/public_values",
])
.map_err(CommonError::DockerRunCmd)
.map_err(|err| DockerizedError::Verify(VerifyError::Common(err)))?;
Ok(())
let public_values = fs::read(tempdir.path().join("public_values"))
.map_err(|err| CommonError::io(err, "Failed to read public_values"))
.map_err(|err| DockerizedError::Verify(VerifyError::Common(err)))?;
Ok(public_values)
}
fn name(&self) -> &'static str {
@@ -450,6 +471,10 @@ impl zkVM for EreDockerizedzkVM {
fn sdk_version(&self) -> &'static str {
self.zkvm.sdk_version()
}
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, _reader: R) -> Result<T, zkVMError> {
todo!()
}
}
fn workspace_dir() -> PathBuf {
@@ -463,7 +488,7 @@ fn workspace_dir() -> PathBuf {
mod test {
use crate::{EreDockerizedCompiler, EreDockerizedzkVM, ErezkVM, workspace_dir};
use test_utils::host::{
BasicProgramInputGen, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
};
use zkvm_interface::{Compiler, ProverResourceType};
@@ -483,9 +508,9 @@ mod test {
let zkvm = EreDockerizedzkVM::new(zkvm, program, ProverResourceType::Cpu).unwrap();
let inputs = BasicProgramInputGen::valid();
run_zkvm_execute(&zkvm, &inputs);
run_zkvm_prove(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_execute(&zkvm, &io);
run_zkvm_prove(&zkvm, &io);
}
#[test]
@@ -499,9 +524,9 @@ mod test {
let zkvm = EreDockerizedzkVM::new(zkvm, program, ProverResourceType::Cpu).unwrap();
let inputs = BasicProgramInputGen::valid();
run_zkvm_execute(&zkvm, &inputs);
run_zkvm_prove(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_execute(&zkvm, &io);
run_zkvm_prove(&zkvm, &io);
}
#[test]
@@ -515,9 +540,9 @@ mod test {
let zkvm = EreDockerizedzkVM::new(zkvm, program, ProverResourceType::Cpu).unwrap();
let inputs = BasicProgramInputGen::valid();
run_zkvm_execute(&zkvm, &inputs);
run_zkvm_prove(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_execute(&zkvm, &io);
run_zkvm_prove(&zkvm, &io);
}
#[test]
@@ -531,8 +556,8 @@ mod test {
let zkvm = EreDockerizedzkVM::new(zkvm, program, ProverResourceType::Cpu).unwrap();
let inputs = BasicProgramInputGen::valid();
run_zkvm_execute(&zkvm, &inputs);
run_zkvm_prove(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_execute(&zkvm, &io);
run_zkvm_prove(&zkvm, &io);
}
}

View File

@@ -6,6 +6,7 @@ rust-version.workspace = true
license.workspace = true
[dependencies]
serde.workspace = true
tempfile.workspace = true
thiserror.workspace = true
toml.workspace = true

View File

@@ -9,11 +9,17 @@ use jolt::{JoltHyperKZGProof, JoltProverPreprocessing, JoltVerifierPreprocessing
use jolt_core::host::Program;
use jolt_methods::{preprocess_prover, preprocess_verifier, prove_generic, verify_generic};
use jolt_sdk::host::DEFAULT_TARGET_DIR;
use std::{env::set_current_dir, fs, io::Cursor, path::Path};
use serde::de::DeserializeOwned;
use std::{
env::set_current_dir,
fs,
io::{Cursor, Read},
path::Path,
};
use tempfile::TempDir;
use zkvm_interface::{
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM,
zkVMError,
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType,
PublicValues, zkVM, zkVMError,
};
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
@@ -87,7 +93,7 @@ impl zkVM for EreJolt {
fn execute(
&self,
_inputs: &Input,
) -> Result<zkvm_interface::ProgramExecutionReport, zkVMError> {
) -> Result<(PublicValues, zkvm_interface::ProgramExecutionReport), zkVMError> {
let (_tempdir, program) = program(&self.elf)?;
// TODO: Check how to pass private input to jolt, issue for tracking:
@@ -95,13 +101,16 @@ impl zkVM for EreJolt {
let summary = program.clone().trace_analyze::<jolt::F>(&[]);
let trace_len = summary.trace_len();
Ok(ProgramExecutionReport::new(trace_len as u64))
// TODO: Public values
let public_values = Vec::new();
Ok((public_values, ProgramExecutionReport::new(trace_len as u64)))
}
fn prove(
&self,
inputs: &Input,
) -> Result<(Vec<u8>, zkvm_interface::ProgramProvingReport), zkVMError> {
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
let (_tempdir, program) = program(&self.elf)?;
let now = std::time::Instant::now();
@@ -113,16 +122,26 @@ impl zkVM for EreJolt {
.serialize_compressed(&mut proof_bytes)
.map_err(|err| JoltError::Prove(ProveError::Serialization(err)))?;
Ok((proof_bytes, ProgramProvingReport::new(elapsed)))
// TODO: Public values
let public_values = Vec::new();
Ok((
public_values,
proof_bytes,
ProgramProvingReport::new(elapsed),
))
}
fn verify(&self, proof_bytes: &[u8]) -> Result<(), zkVMError> {
fn verify(&self, proof_bytes: &[u8]) -> Result<PublicValues, zkVMError> {
let proof = EreJoltProof::deserialize_compressed(&mut Cursor::new(proof_bytes))
.map_err(|err| JoltError::Verify(VerifyError::Serialization(err)))?;
verify_generic(proof, self.verifier_preprocessing.clone()).map_err(JoltError::Verify)?;
Ok(())
// TODO: Public values
let public_values = Vec::new();
Ok(public_values)
}
fn name(&self) -> &'static str {
@@ -132,6 +151,10 @@ impl zkVM for EreJolt {
fn sdk_version(&self) -> &'static str {
SDK_VERSION
}
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, _reader: R) -> Result<T, zkVMError> {
todo!()
}
}
/// Create `jolt::host::Program` by storing the compiled `elf` to a temporary

View File

@@ -7,6 +7,7 @@ license.workspace = true
[dependencies]
bincode.workspace = true
serde.workspace = true
thiserror.workspace = true
toml.workspace = true
tracing.workspace = true

View File

@@ -1,17 +1,19 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![allow(clippy::uninlined_format_args)]
use std::io::Read;
use std::path::{Path, PathBuf};
use std::time::Instant;
use nexus_sdk::compile::cargo::CargoPackager;
use nexus_sdk::compile::{Compile, Compiler as NexusCompiler};
use nexus_sdk::stwo::seq::{Proof, Stwo};
use nexus_sdk::stwo::seq::Stwo;
use nexus_sdk::{Local, Prover, Verifiable};
use serde::de::DeserializeOwned;
use tracing::info;
use zkvm_interface::{
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM,
zkVMError,
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType,
PublicValues, zkVM, zkVMError,
};
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
@@ -69,19 +71,22 @@ impl zkVM for EreNexus {
fn execute(
&self,
_inputs: &Input,
) -> Result<zkvm_interface::ProgramExecutionReport, zkVMError> {
) -> Result<(PublicValues, zkvm_interface::ProgramExecutionReport), zkVMError> {
// TODO: Serialize inputs by `postcard` and make sure there is no double serailization.
// Issue for tracking: https://github.com/eth-act/ere/issues/63.
// TODO: Execute and get cycle count
Ok(ProgramExecutionReport::default())
// TODO: Public values
let public_values = Vec::new();
Ok((public_values, ProgramExecutionReport::default()))
}
fn prove(
&self,
_inputs: &Input,
) -> Result<(Vec<u8>, zkvm_interface::ProgramProvingReport), zkVMError> {
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
let prover: Stwo<Local> = Stwo::new_from_file(&self.program.to_string_lossy().to_string())
.map_err(|e| NexusError::Prove(ProveError::Client(e.into())))
.map_err(zkVMError::from)?;
@@ -99,13 +104,16 @@ impl zkVM for EreNexus {
let bytes = bincode::serialize(&proof)
.map_err(|err| NexusError::Prove(ProveError::Bincode(err)))?;
Ok((bytes, ProgramProvingReport::new(elapsed)))
// TODO: Public values
let public_values = Vec::new();
Ok((public_values, bytes, ProgramProvingReport::new(elapsed)))
}
fn verify(&self, proof: &[u8]) -> Result<(), zkVMError> {
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
info!("Verifying proof...");
let proof: Proof = bincode::deserialize(proof)
let proof: nexus_sdk::stwo::seq::Proof = bincode::deserialize(proof)
.map_err(|err| NexusError::Verify(VerifyError::Bincode(err)))?;
let prover: Stwo<Local> = Stwo::new_from_file(&self.program.to_string_lossy().to_string())
@@ -125,7 +133,11 @@ impl zkVM for EreNexus {
.map_err(zkVMError::from)?;
info!("Verify Succeeded!");
Ok(())
// TODO: Public values
let public_values = Vec::new();
Ok(public_values)
}
fn name(&self) -> &'static str {
@@ -135,6 +147,10 @@ impl zkVM for EreNexus {
fn sdk_version(&self) -> &'static str {
SDK_VERSION
}
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, _reader: R) -> Result<T, zkVMError> {
todo!()
}
}
#[cfg(test)]

View File

@@ -13,11 +13,11 @@ use openvm_sdk::{
};
use openvm_stark_sdk::config::FriParameters;
use openvm_transpiler::{elf::Elf, openvm_platform::memory::MEM_SIZE};
use serde::{Deserialize, Serialize};
use std::{fs, path::Path, sync::Arc, time::Instant};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use std::{fs, io::Read, path::Path, sync::Arc, time::Instant};
use zkvm_interface::{
Compiler, Input, InputItem, ProgramExecutionReport, ProgramProvingReport, ProverResourceType,
zkVM, zkVMError,
Compiler, Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof,
ProverResourceType, PublicValues, zkVM, zkVMError,
};
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
@@ -128,7 +128,10 @@ impl EreOpenVM {
}
impl zkVM for EreOpenVM {
fn execute(&self, inputs: &Input) -> Result<zkvm_interface::ProgramExecutionReport, zkVMError> {
fn execute(
&self,
inputs: &Input,
) -> Result<(PublicValues, zkvm_interface::ProgramExecutionReport), zkVMError> {
let sdk = self
.sdk()
.map_err(|e| OpenVMError::from(ExecuteError::from(e)))?;
@@ -141,16 +144,22 @@ impl zkVM for EreOpenVM {
.execute(self.app_exe.clone(), stdin)
.map_err(|e| OpenVMError::from(ExecuteError::Execute(e)))?;
Ok(ProgramExecutionReport {
execution_duration: start.elapsed(),
..Default::default()
})
// TODO: Public values
let public_values = Vec::new();
Ok((
public_values,
ProgramExecutionReport {
execution_duration: start.elapsed(),
..Default::default()
},
))
}
fn prove(
&self,
inputs: &Input,
) -> Result<(Vec<u8>, zkvm_interface::ProgramProvingReport), zkVMError> {
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
let sdk = self
.sdk()
.map_err(|e| OpenVMError::from(ProveError::from(e)))?;
@@ -175,17 +184,27 @@ impl zkVM for EreOpenVM {
.encode_to_vec()
.map_err(|e| OpenVMError::from(ProveError::SerializeProof(e)))?;
Ok((proof_bytes, ProgramProvingReport::new(elapsed)))
// TODO: Public values
let public_values = Vec::new();
Ok((
public_values,
proof_bytes,
ProgramProvingReport::new(elapsed),
))
}
fn verify(&self, mut proof: &[u8]) -> Result<(), zkVMError> {
fn verify(&self, mut proof: &[u8]) -> Result<PublicValues, zkVMError> {
let proof = VmStarkProof::<SC>::decode(&mut proof)
.map_err(|e| OpenVMError::from(VerifyError::DeserializeProof(e)))?;
Sdk::verify_proof(&self.agg_vk, self.app_commit, &proof)
.map_err(|e| OpenVMError::Verify(VerifyError::Verify(e)))?;
Ok(())
// TODO: Public values
let public_values = Vec::new();
Ok(public_values)
}
fn name(&self) -> &'static str {
@@ -195,6 +214,10 @@ impl zkVM for EreOpenVM {
fn sdk_version(&self) -> &'static str {
SDK_VERSION
}
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, _reader: R) -> Result<T, zkVMError> {
todo!()
}
}
fn serialize_inputs(stdin: &mut StdIn, inputs: &Input) {
@@ -213,7 +236,7 @@ mod tests {
use super::*;
use std::sync::OnceLock;
use test_utils::host::{
BasicProgramInputGen, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
};
fn basic_program() -> OpenVMProgram {
@@ -242,8 +265,8 @@ mod tests {
fn test_execute() {
let zkvm = basic_program_ere_openvm();
let inputs = BasicProgramInputGen::valid();
run_zkvm_execute(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_execute(&zkvm, &io);
}
#[test]
@@ -251,9 +274,9 @@ mod tests {
let zkvm = basic_program_ere_openvm();
for inputs in [
BasicProgramInputGen::empty(),
BasicProgramInputGen::invalid_string(),
BasicProgramInputGen::invalid_type(),
BasicProgramIo::empty(),
BasicProgramIo::invalid_type(),
BasicProgramIo::invalid_data(),
] {
zkvm.execute(&inputs).unwrap_err();
}
@@ -263,8 +286,8 @@ mod tests {
fn test_prove() {
let zkvm = basic_program_ere_openvm();
let inputs = BasicProgramInputGen::valid();
run_zkvm_prove(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_prove(&zkvm, &io);
}
#[test]
@@ -272,9 +295,9 @@ mod tests {
let zkvm = basic_program_ere_openvm();
for inputs in [
BasicProgramInputGen::empty(),
BasicProgramInputGen::invalid_string(),
BasicProgramInputGen::invalid_type(),
BasicProgramIo::empty(),
BasicProgramIo::invalid_type(),
BasicProgramIo::invalid_data(),
] {
zkvm.prove(&inputs).unwrap_err();
}

View File

@@ -7,6 +7,7 @@ license.workspace = true
[dependencies]
bincode.workspace = true
serde.workspace = true
thiserror.workspace = true
# Pico dependencies

View File

@@ -2,10 +2,11 @@
use pico_sdk::client::DefaultProverClient;
use pico_vm::emulator::stdin::EmulatorStdinBuilder;
use std::{path::Path, process::Command, time::Instant};
use serde::de::DeserializeOwned;
use std::{io::Read, path::Path, process::Command, time::Instant};
use zkvm_interface::{
Compiler, Input, InputItem, ProgramExecutionReport, ProgramProvingReport, ProverResourceType,
zkVM, zkVMError,
Compiler, Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof,
ProverResourceType, PublicValues, zkVM, zkVMError,
};
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
@@ -69,7 +70,7 @@ impl ErePico {
}
}
impl zkVM for ErePico {
fn execute(&self, inputs: &Input) -> Result<ProgramExecutionReport, zkVMError> {
fn execute(&self, inputs: &Input) -> Result<(PublicValues, ProgramExecutionReport), zkVMError> {
let client = DefaultProverClient::new(&self.program);
let mut stdin = client.new_stdin_builder();
@@ -78,17 +79,23 @@ impl zkVM for ErePico {
let start = Instant::now();
let emulation_result = client.emulate(stdin);
Ok(ProgramExecutionReport {
total_num_cycles: emulation_result.0,
execution_duration: start.elapsed(),
..Default::default()
})
// TODO: Public values
let public_values = Vec::new();
Ok((
public_values,
ProgramExecutionReport {
total_num_cycles: emulation_result.0,
execution_duration: start.elapsed(),
..Default::default()
},
))
}
fn prove(
&self,
inputs: &Input,
) -> Result<(Vec<u8>, zkvm_interface::ProgramProvingReport), zkVMError> {
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
let client = DefaultProverClient::new(&self.program);
let mut stdin = client.new_stdin_builder();
@@ -113,13 +120,23 @@ impl zkVM for ErePico {
bincode::serialize_into(&mut proof_serialized, p).unwrap();
}
Ok((proof_serialized, ProgramProvingReport::new(elapsed)))
// TODO: Public values
let public_values = Vec::new();
Ok((
public_values,
proof_serialized,
ProgramProvingReport::new(elapsed),
))
}
fn verify(&self, _proof: &[u8]) -> Result<(), zkVMError> {
fn verify(&self, _proof: &[u8]) -> Result<PublicValues, zkVMError> {
let client = DefaultProverClient::new(&self.program);
let _vk = client.riscv_vk();
todo!("Verification method missing from sdk")
// TODO: Verification method missing from sdk
// TODO: Public values
let public_values = Vec::new();
Ok(public_values)
}
fn name(&self) -> &'static str {
@@ -129,6 +146,10 @@ impl zkVM for ErePico {
fn sdk_version(&self) -> &'static str {
SDK_VERSION
}
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, _reader: R) -> Result<T, zkVMError> {
todo!()
}
}
fn serialize_inputs(stdin: &mut EmulatorStdinBuilder<Vec<u8>>, inputs: &Input) {
@@ -146,7 +167,7 @@ fn serialize_inputs(stdin: &mut EmulatorStdinBuilder<Vec<u8>>, inputs: &Input) {
mod tests {
use super::*;
use std::{panic, sync::OnceLock};
use test_utils::host::{BasicProgramInputGen, run_zkvm_execute, testing_guest_directory};
use test_utils::host::{BasicProgramIo, run_zkvm_execute, testing_guest_directory};
static BASIC_PRORGAM: OnceLock<Vec<u8>> = OnceLock::new();
@@ -171,8 +192,8 @@ mod tests {
let program = basic_program();
let zkvm = ErePico::new(program, ProverResourceType::Cpu);
let inputs = BasicProgramInputGen::valid();
run_zkvm_execute(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_execute(&zkvm, &io);
}
#[test]
@@ -181,9 +202,9 @@ mod tests {
let zkvm = ErePico::new(program, ProverResourceType::Cpu);
for inputs_gen in [
BasicProgramInputGen::empty,
BasicProgramInputGen::invalid_string,
BasicProgramInputGen::invalid_type,
BasicProgramIo::empty,
BasicProgramIo::invalid_type,
BasicProgramIo::invalid_data,
] {
panic::catch_unwind(|| zkvm.execute(&inputs_gen()).unwrap_err()).unwrap_err();
}

View File

@@ -15,7 +15,7 @@ tracing.workspace = true
# Risc0 dependencies
risc0-build = { workspace = true, features = ["unstable"] }
risc0-zkvm = { workspace = true, default-features = true, features = ["unstable"] }
risc0-zkvm = { workspace = true, features = ["client", "unstable"] }
# Local dependencies
zkvm-interface.workspace = true

View File

@@ -9,11 +9,11 @@ use risc0_zkvm::{
DEFAULT_MAX_PO2, DefaultProver, ExecutorEnv, ExecutorEnvBuilder, ExternalProver, InnerReceipt,
Journal, ProverOpts, Receipt, ReceiptClaim, SuccinctReceipt, default_executor, default_prover,
};
use serde::{Deserialize, Serialize};
use std::{env, ops::RangeInclusive, path::Path, rc::Rc, time::Instant};
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, ProverResourceType,
zkVM, zkVMError,
Compiler, Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof,
ProverResourceType, PublicValues, zkVM, zkVMError,
};
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
@@ -130,7 +130,7 @@ impl EreRisc0 {
}
impl zkVM for EreRisc0 {
fn execute(&self, inputs: &Input) -> Result<ProgramExecutionReport, zkVMError> {
fn execute(&self, inputs: &Input) -> Result<(PublicValues, ProgramExecutionReport), zkVMError> {
let executor = default_executor();
let mut env = ExecutorEnv::builder();
serialize_inputs(&mut env, inputs).map_err(zkVMError::other)?;
@@ -140,14 +140,24 @@ impl zkVM for EreRisc0 {
let session_info = executor
.execute(env, &self.program.elf)
.map_err(zkVMError::other)?;
Ok(ProgramExecutionReport {
total_num_cycles: session_info.cycles() as u64,
execution_duration: start.elapsed(),
..Default::default()
})
// TODO: Public values
let public_values = Vec::new();
Ok((
public_values,
ProgramExecutionReport {
total_num_cycles: session_info.cycles() as u64,
execution_duration: start.elapsed(),
..Default::default()
},
))
}
fn prove(&self, inputs: &Input) -> Result<(Vec<u8>, ProgramProvingReport), zkVMError> {
fn prove(
&self,
inputs: &Input,
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError> {
let prover = match self.resource {
ProverResourceType::Cpu => Rc::new(ExternalProver::new("ipc", "r0vm")),
ProverResourceType::Gpu => {
@@ -188,17 +198,30 @@ impl zkVM for EreRisc0 {
let proof = borsh::to_vec(&Risc0ProofWithPublicValues::from(prove_info.receipt))
.map_err(zkVMError::other)?;
Ok((proof, ProgramProvingReport::new(proving_time)))
// TODO: Public values
let public_values = Vec::new();
Ok((
public_values,
proof,
ProgramProvingReport::new(proving_time),
))
}
fn verify(&self, proof: &[u8]) -> Result<(), zkVMError> {
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
let receipt: Receipt = borsh::from_slice::<Risc0ProofWithPublicValues>(proof)
.map_err(zkVMError::other)?
.into();
receipt
.verify(self.program.image_id)
.map_err(zkVMError::other)
.map_err(zkVMError::other)?;
// TODO: Public values
let public_values = Vec::new();
Ok(public_values)
}
fn name(&self) -> &'static str {
@@ -208,6 +231,10 @@ impl zkVM for EreRisc0 {
fn sdk_version(&self) -> &'static str {
SDK_VERSION
}
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, _reader: R) -> Result<T, zkVMError> {
todo!()
}
}
fn serialize_inputs(env: &mut ExecutorEnvBuilder, inputs: &Input) -> Result<(), anyhow::Error> {
@@ -235,7 +262,7 @@ mod tests {
use super::*;
use std::sync::OnceLock;
use test_utils::host::{
BasicProgramInputGen, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
};
static BASIC_PRORGAM: OnceLock<Risc0Program> = OnceLock::new();
@@ -255,8 +282,8 @@ mod tests {
let program = basic_program();
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
let inputs = BasicProgramInputGen::valid();
run_zkvm_execute(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_execute(&zkvm, &io);
}
#[test]
@@ -265,9 +292,9 @@ mod tests {
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
for inputs in [
BasicProgramInputGen::empty(),
BasicProgramInputGen::invalid_string(),
BasicProgramInputGen::invalid_type(),
BasicProgramIo::empty(),
BasicProgramIo::invalid_type(),
BasicProgramIo::invalid_data(),
] {
zkvm.execute(&inputs).unwrap_err();
}
@@ -278,8 +305,8 @@ mod tests {
let program = basic_program();
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
let inputs = BasicProgramInputGen::valid();
run_zkvm_prove(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_prove(&zkvm, &io);
}
#[test]
@@ -288,9 +315,9 @@ mod tests {
let zkvm = EreRisc0::new(program, ProverResourceType::Cpu).unwrap();
for inputs in [
BasicProgramInputGen::empty(),
BasicProgramInputGen::invalid_string(),
BasicProgramInputGen::invalid_type(),
BasicProgramIo::empty(),
BasicProgramIo::invalid_type(),
BasicProgramIo::invalid_data(),
] {
zkvm.prove(&inputs).unwrap_err();
}

View File

@@ -7,6 +7,7 @@ version.workspace = true
[dependencies]
bincode.workspace = true
serde.workspace = true
tempfile.workspace = true
thiserror.workspace = true
toml.workspace = true

View File

@@ -18,7 +18,7 @@ pub fn stock_rust_compile(
);
let target_name = "riscv32ima-unknown-none-elf";
let plus_toolchain = format!("+{}", toolchain);
let plus_toolchain = format!("+{toolchain}");
let args = [
plus_toolchain.as_str(),

View File

@@ -1,7 +1,8 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
use std::{path::Path, time::Instant};
use std::{io::Read, path::Path, time::Instant};
use serde::de::DeserializeOwned;
use sp1_sdk::{
CpuProver, CudaProver, NetworkProver, Prover, ProverClient, SP1ProofWithPublicValues,
SP1ProvingKey, SP1Stdin, SP1VerifyingKey,
@@ -9,7 +10,7 @@ use sp1_sdk::{
use tracing::info;
use zkvm_interface::{
Compiler, Input, InputItem, NetworkProverConfig, ProgramExecutionReport, ProgramProvingReport,
ProverResourceType, zkVM, zkVMError,
Proof, ProverResourceType, PublicValues, zkVM, zkVMError,
};
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
@@ -163,24 +164,31 @@ impl EreSP1 {
}
impl zkVM for EreSP1 {
fn execute(&self, inputs: &Input) -> Result<zkvm_interface::ProgramExecutionReport, zkVMError> {
fn execute(
&self,
inputs: &Input,
) -> Result<(PublicValues, zkvm_interface::ProgramExecutionReport), zkVMError> {
let mut stdin = SP1Stdin::new();
serialize_inputs(&mut stdin, inputs);
let client = Self::create_client(&self.resource);
let start = Instant::now();
let (_, exec_report) = client.execute(&self.program, &stdin)?;
Ok(ProgramExecutionReport {
total_num_cycles: exec_report.total_instruction_count(),
region_cycles: exec_report.cycle_tracker.into_iter().collect(),
execution_duration: start.elapsed(),
})
let (public_values, exec_report) = client.execute(&self.program, &stdin)?;
Ok((
public_values.to_vec(),
ProgramExecutionReport {
total_num_cycles: exec_report.total_instruction_count(),
region_cycles: exec_report.cycle_tracker.into_iter().collect(),
execution_duration: start.elapsed(),
},
))
}
fn prove(
&self,
inputs: &zkvm_interface::Input,
) -> Result<(Vec<u8>, zkvm_interface::ProgramProvingReport), zkVMError> {
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
info!("Generating proof…");
let mut stdin = SP1Stdin::new();
@@ -194,17 +202,25 @@ impl zkVM for EreSP1 {
let bytes = bincode::serialize(&proof_with_inputs)
.map_err(|err| SP1Error::Prove(ProveError::Bincode(err)))?;
Ok((bytes, ProgramProvingReport::new(proving_time)))
Ok((
proof_with_inputs.public_values.to_vec(),
bytes,
ProgramProvingReport::new(proving_time),
))
}
fn verify(&self, proof: &[u8]) -> Result<(), zkVMError> {
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
info!("Verifying proof…");
let proof: SP1ProofWithPublicValues = bincode::deserialize(proof)
.map_err(|err| SP1Error::Verify(VerifyError::Bincode(err)))?;
let client = Self::create_client(&self.resource);
client.verify(&proof, &self.vk).map_err(zkVMError::from)
client.verify(&proof, &self.vk).map_err(zkVMError::from)?;
let public_values_bytes = proof.public_values.as_slice().to_vec();
Ok(public_values_bytes)
}
fn name(&self) -> &'static str {
@@ -214,6 +230,10 @@ impl zkVM for EreSP1 {
fn sdk_version(&self) -> &'static str {
SDK_VERSION
}
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, reader: R) -> Result<T, zkVMError> {
bincode::deserialize_from(reader).map_err(zkVMError::other)
}
}
fn serialize_inputs(stdin: &mut SP1Stdin, inputs: &Input) {
@@ -233,7 +253,7 @@ mod tests {
use crate::compile::compile;
use std::{panic, sync::OnceLock};
use test_utils::host::{
BasicProgramInputGen, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
BasicProgramIo, Io, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
};
static BASIC_PRORGAM: OnceLock<Vec<u8>> = OnceLock::new();
@@ -253,8 +273,9 @@ mod tests {
let program = basic_program();
let zkvm = EreSP1::new(program, ProverResourceType::Cpu);
let inputs = BasicProgramInputGen::valid();
run_zkvm_execute(&zkvm, &inputs);
let io = BasicProgramIo::valid();
let public_values = run_zkvm_execute(&zkvm, &io);
assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs());
}
#[test]
@@ -263,7 +284,7 @@ mod tests {
let program = compile(&guest_directory, &"nightly".to_string()).unwrap();
let zkvm = EreSP1::new(program, ProverResourceType::Cpu);
run_zkvm_execute(&zkvm, &Input::new());
zkvm.execute(&Input::new()).unwrap();
}
#[test]
@@ -272,9 +293,9 @@ mod tests {
let zkvm = EreSP1::new(program, ProverResourceType::Cpu);
for inputs in [
BasicProgramInputGen::empty(),
BasicProgramInputGen::invalid_string(),
BasicProgramInputGen::invalid_type(),
BasicProgramIo::empty(),
BasicProgramIo::invalid_type(),
BasicProgramIo::invalid_data(),
] {
zkvm.execute(&inputs).unwrap_err();
}
@@ -285,8 +306,9 @@ mod tests {
let program = basic_program();
let zkvm = EreSP1::new(program, ProverResourceType::Cpu);
let inputs = BasicProgramInputGen::valid();
run_zkvm_prove(&zkvm, &inputs);
let io = BasicProgramIo::valid();
let public_values = run_zkvm_prove(&zkvm, &io);
assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs());
}
#[test]
@@ -300,9 +322,9 @@ mod tests {
// Note that we iterate on methods because `InputItem::Object` doesn't
// implement `RefUnwindSafe`.
for inputs_gen in [
BasicProgramInputGen::empty,
BasicProgramInputGen::invalid_string,
BasicProgramInputGen::invalid_type,
BasicProgramIo::empty,
BasicProgramIo::invalid_type,
BasicProgramIo::invalid_data,
] {
panic::catch_unwind(|| zkvm.prove(&inputs_gen())).unwrap_err();
}
@@ -325,7 +347,8 @@ mod tests {
let program = basic_program();
let zkvm = EreSP1::new(program, ProverResourceType::Network(network_config));
let inputs = BasicProgramInputGen::valid();
run_zkvm_prove(&zkvm, &inputs);
let io = BasicProgramIo::valid();
let public_values = run_zkvm_prove(&zkvm, &io);
assert_eq!(io.deserialize_outputs(&zkvm, &public_values), io.outputs());
}
}

View File

@@ -6,10 +6,10 @@ use crate::{
};
use blake3::Hash;
use dashmap::{DashMap, Entry};
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use std::{
fs,
io::{self, BufRead, Write},
io::{self, BufRead, Read, Write},
os::unix::fs::symlink,
path::{Path, PathBuf},
process::{Command, Stdio},
@@ -19,8 +19,8 @@ use std::{
use tempfile::{TempDir, tempdir};
use tracing::info;
use zkvm_interface::{
Compiler, Input, InputItem, ProgramExecutionReport, ProgramProvingReport, ProverResourceType,
zkVM, zkVMError,
Compiler, Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof,
ProverResourceType, PublicValues, zkVM, zkVMError,
};
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
@@ -74,7 +74,7 @@ impl EreZisk {
}
impl zkVM for EreZisk {
fn execute(&self, inputs: &Input) -> Result<ProgramExecutionReport, zkVMError> {
fn execute(&self, inputs: &Input) -> Result<(PublicValues, ProgramExecutionReport), zkVMError> {
// Write ELF and serialized input to file.
let input_bytes = serialize_inputs(inputs)
@@ -122,14 +122,23 @@ impl zkVM for EreZisk {
})
.ok_or(ZiskError::Execute(ExecuteError::TotalStepsNotFound))?;
Ok(ProgramExecutionReport {
total_num_cycles,
execution_duration,
..Default::default()
})
// TODO: Public values
let public_values = Vec::new();
Ok((
public_values,
ProgramExecutionReport {
total_num_cycles,
execution_duration,
..Default::default()
},
))
}
fn prove(&self, inputs: &Input) -> Result<(Vec<u8>, ProgramProvingReport), zkVMError> {
fn prove(
&self,
inputs: &Input,
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError> {
// Make sure proving key setup is done.
check_setup()?;
@@ -246,10 +255,17 @@ impl zkVM for EreZisk {
let bytes = bincode::serialize(&proof_with_public_values)
.map_err(|err| ZiskError::Prove(ProveError::Bincode(err)))?;
Ok((bytes, ProgramProvingReport::new(proving_time)))
// TODO: Public values
let public_values = Vec::new();
Ok((
public_values,
bytes,
ProgramProvingReport::new(proving_time),
))
}
fn verify(&self, bytes: &[u8]) -> Result<(), zkVMError> {
fn verify(&self, bytes: &[u8]) -> Result<PublicValues, zkVMError> {
// Run ELF specific setup
let rom_digest = rom_setup(&self.elf)?;
@@ -301,7 +317,10 @@ impl zkVM for EreZisk {
}))?
}
Ok(())
// TODO: Public values
let public_values = Vec::new();
Ok(public_values)
}
fn name(&self) -> &'static str {
@@ -311,6 +330,10 @@ impl zkVM for EreZisk {
fn sdk_version(&self) -> &'static str {
SDK_VERSION
}
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, _reader: R) -> Result<T, zkVMError> {
todo!()
}
}
/// Serialize `Input` into sequence of bytes.
@@ -528,7 +551,7 @@ mod tests {
use super::*;
use std::sync::OnceLock;
use test_utils::host::{
BasicProgramInputGen, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
};
static BASIC_PRORGAM: OnceLock<Vec<u8>> = OnceLock::new();
@@ -548,8 +571,8 @@ mod tests {
let program = basic_program();
let zkvm = EreZisk::new(program, ProverResourceType::Cpu);
let inputs = BasicProgramInputGen::valid();
run_zkvm_execute(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_execute(&zkvm, &io);
}
#[test]
@@ -558,9 +581,9 @@ mod tests {
let zkvm = EreZisk::new(program, ProverResourceType::Cpu);
for inputs in [
BasicProgramInputGen::empty(),
BasicProgramInputGen::invalid_string(),
BasicProgramInputGen::invalid_type(),
BasicProgramIo::empty(),
BasicProgramIo::invalid_type(),
BasicProgramIo::invalid_data(),
] {
zkvm.execute(&inputs).unwrap_err();
}
@@ -571,8 +594,8 @@ mod tests {
let program = basic_program();
let zkvm = EreZisk::new(program, ProverResourceType::Cpu);
let inputs = BasicProgramInputGen::valid();
run_zkvm_prove(&zkvm, &inputs);
let io = BasicProgramIo::valid();
run_zkvm_prove(&zkvm, &io);
}
#[test]
@@ -581,9 +604,9 @@ mod tests {
let zkvm = EreZisk::new(program, ProverResourceType::Cpu);
for inputs in [
BasicProgramInputGen::empty(),
BasicProgramInputGen::invalid_string(),
BasicProgramInputGen::invalid_type(),
BasicProgramIo::empty(),
BasicProgramIo::invalid_type(),
BasicProgramIo::invalid_data(),
] {
zkvm.prove(&inputs).unwrap_err();
}

View File

@@ -6,6 +6,7 @@ rust-version.workspace = true
license.workspace = true
[dependencies]
rand = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] }
# Local dependencies
@@ -16,4 +17,4 @@ workspace = true
[features]
default = []
host = ["dep:zkvm-interface"]
host = ["dep:rand", "dep:zkvm-interface"]

View File

@@ -1,8 +1,9 @@
use alloc::vec::Vec;
use core::iter;
use serde::{Deserialize, Serialize};
#[derive(Default, Serialize, Deserialize)]
pub const BASIC_PROGRAM_BYTES_LENGTH: usize = 32;
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct BasicStruct {
pub a: u8,
pub b: u16,
@@ -12,17 +13,26 @@ pub struct BasicStruct {
}
impl BasicStruct {
/// Performs some computation (Xoring all fields as bytes into `[u8; 32]`).
pub fn output(&self) -> [u8; 32] {
let mut output = [0; 32];
iter::empty()
.chain(self.a.to_le_bytes())
.chain(self.b.to_le_bytes())
.chain(self.c.to_le_bytes())
.chain(self.d.to_le_bytes())
.chain(self.e.iter().copied())
.enumerate()
.for_each(|(idx, byte)| output[idx % output.len()] ^= byte);
output
#[cfg(feature = "host")]
pub fn random(mut rng: impl rand::Rng) -> Self {
let n = rng.random_range(16..32);
BasicStruct {
a: rng.random(),
b: rng.random(),
c: rng.random(),
d: rng.random(),
e: rng.random_iter().take(n).collect(),
}
}
/// Performs some computation (Wrapping add all fields by 1).
pub fn output(&self) -> Self {
Self {
a: self.a.wrapping_add(1),
b: self.b.wrapping_add(1),
c: self.c.wrapping_add(1),
d: self.d.wrapping_add(1),
e: self.e.iter().map(|byte| byte.wrapping_add(1)).collect(),
}
}
}

View File

@@ -1,6 +1,7 @@
use crate::guest::BasicStruct;
use std::path::PathBuf;
use zkvm_interface::{Input, zkVM};
use crate::guest::{BASIC_PROGRAM_BYTES_LENGTH, BasicStruct};
use rand::{Rng, rng};
use std::{fmt::Debug, io::Read, path::PathBuf};
use zkvm_interface::{Input, PublicValues, zkVM};
fn workspace() -> PathBuf {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
@@ -13,61 +14,112 @@ pub fn testing_guest_directory(zkvm_name: &str, program: &str) -> PathBuf {
workspace().join("tests").join(zkvm_name).join(program)
}
pub fn run_zkvm_execute(zkvm: &impl zkVM, inputs: &Input) {
let _report = zkvm
.execute(inputs)
.expect("execute should not fail with valid input");
pub trait Io {
type Output: Debug + PartialEq;
// TODO: Check output are expected.
fn inputs(&self) -> Input;
fn outputs(&self) -> Self::Output;
fn deserialize_outputs(&self, zkvm: &impl zkVM, bytes: &[u8]) -> Self::Output;
}
pub fn run_zkvm_prove(zkvm: &impl zkVM, inputs: &Input) {
let (proof, _report) = zkvm
.prove(inputs)
pub fn run_zkvm_execute(zkvm: &impl zkVM, io: &impl Io) -> PublicValues {
let (public_values, _report) = zkvm
.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());
public_values
}
pub fn run_zkvm_prove(zkvm: &impl zkVM, io: &impl Io) -> PublicValues {
let (prover_public_values, proof, _report) = zkvm
.prove(&io.inputs())
.expect("prove should not fail with valid input");
zkvm.verify(&proof)
let verifier_public_values = zkvm
.verify(&proof)
.expect("verify should not fail with valid input");
// TODO: Check output are expected.
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());
verifier_public_values
}
/// The basic program takes 2 inputs:
/// - `Vec<u8>` that supposed to be "Hello world"
/// - `BasicStruct`
/// - `Vec<u8>` - random bytes
/// - [`BasicStruct`] - structure filled with random values
///
/// Outputs `[u8; 32]` which computed by xoring fields of `BasicStruct`.
pub struct BasicProgramInputGen;
/// Commit 2 outputs:
/// - `Vec<u8>` that should be reverse of the input random bytes.
/// - [`BasicStruct`] that should be computed by [`BasicStruct::output`].
#[derive(Clone)]
pub struct BasicProgramIo {
bytes: Vec<u8>,
basic_struct: BasicStruct,
}
impl BasicProgramInputGen {
pub fn valid() -> Input {
impl Io for BasicProgramIo {
type Output = (Vec<u8>, BasicStruct);
fn inputs(&self) -> Input {
let mut inputs = Input::new();
inputs.write_bytes("Hello world".as_bytes().to_vec());
inputs.write(BasicStruct {
a: 0xff,
b: 0x7777,
c: 0xffffffff,
d: 0x7777777777777777,
e: (0..u8::MAX).collect(),
});
inputs.write_bytes(self.bytes.clone());
inputs.write(self.basic_struct.clone());
inputs
}
pub fn invalid_string() -> Input {
let mut inputs = Input::new();
inputs.write_bytes("Unexpected string".as_bytes().to_vec());
inputs.write(BasicStruct::default());
inputs
fn outputs(&self) -> Self::Output {
(
self.bytes.iter().rev().copied().collect(),
self.basic_struct.output(),
)
}
pub fn invalid_type() -> Input {
let mut inputs = Input::new();
inputs.write(BasicStruct::default());
inputs.write_bytes("Hello world".as_bytes().to_vec());
inputs
fn deserialize_outputs(&self, zkvm: &impl zkVM, mut bytes: &[u8]) -> Self::Output {
let mut rev_bytes = vec![0; self.bytes.len()];
bytes.read_exact(&mut rev_bytes).unwrap();
let basic_struct_output = zkvm.deserialize_from(bytes).unwrap();
(rev_bytes, basic_struct_output)
}
}
impl BasicProgramIo {
pub fn valid() -> Self {
let rng = &mut rng();
Self {
bytes: rng.random_iter().take(BASIC_PROGRAM_BYTES_LENGTH).collect(),
basic_struct: BasicStruct::random(rng),
}
}
/// Empty input that should trigger deserialization failure in guest
/// program.
pub fn empty() -> Input {
Input::new()
}
/// Input with invalid type that should trigger deserialization
/// failure in guest program.
pub fn invalid_type() -> Input {
let mut inputs = Input::new();
inputs.write(0u64);
inputs.write_bytes(vec![0, 1, 2, 3]);
inputs
}
/// Input with invalid data that should trigger assertion failure in guest
/// program.
pub fn invalid_data() -> Input {
let mut inputs = Input::new();
inputs.write_bytes(vec![0; BASIC_PROGRAM_BYTES_LENGTH + 1]);
inputs.write(BasicStruct::default());
inputs
}
}

View File

@@ -1,7 +1,7 @@
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
use serde::{Serialize, de::DeserializeOwned};
use std::path::Path;
use std::{io::Read, path::Path};
use thiserror::Error;
mod input;
@@ -90,6 +90,15 @@ impl zkVMError {
}
}
/// Public values committed/revealed by guest program.
///
/// Use [`zkVM::deserialize_from`] to deserialize object from the bytes.
pub type PublicValues = Vec<u8>;
/// Proof generated by [`zkVM::prove`], that also includes the [`PublicValues`]
/// for [`zkVM::verify`] to work.
pub type Proof = Vec<u8>;
#[allow(non_camel_case_types)]
#[auto_impl::auto_impl(&, Arc, Box)]
/// zkVM trait to abstract away the differences between each zkVM.
@@ -103,21 +112,35 @@ impl zkVMError {
/// implementation will have their own construction function.
pub trait zkVM {
/// Executes the program with the provided inputs.
fn execute(&self, inputs: &Input) -> Result<ProgramExecutionReport, zkVMError>;
fn execute(&self, inputs: &Input) -> Result<(PublicValues, ProgramExecutionReport), zkVMError>;
/// Creates a proof of the program execution with given inputs.
fn prove(&self, inputs: &Input) -> Result<(Vec<u8>, ProgramProvingReport), zkVMError>;
fn prove(
&self,
inputs: &Input,
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError>;
/// Verifies a proof of the program used to create this zkVM instance.
/// 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<(), zkVMError>;
/// Verifies a proof of the program used to create this zkVM instance, then
/// returns the public values extracted from the proof.
#[must_use = "Public values must be used"]
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError>;
/// Returns the name of the zkVM
fn name(&self) -> &'static str;
/// Returns the version of the zkVM SDK (e.g. 0.1.0)
fn sdk_version(&self) -> &'static str;
/// Deserializes an object from a [`Read`]er.
///
/// If a guest program has multiple objects committed/revealed, one can do
/// the following to extract them in sequence:
///
/// ```ignore
/// let public_values = zkvm.verify(&proof)?;
/// let mut reader = public_values.as_slice();
/// let v0: T = zkvm.deserialize_from(&mut reader)?;
/// let v1: U = zkvm.deserialize_from(&mut reader)?;
/// ```
fn deserialize_from<R: Read, T: DeserializeOwned>(&self, reader: R) -> Result<T, zkVMError>;
}

View File

@@ -6,5 +6,6 @@ edition = "2021"
[workspace]
[dependencies]
bincode = "1.3.3"
openvm = { git = "https://github.com/openvm-org/openvm.git", features = ["std"], tag = "v1.2.0" }
test-utils = { path = "../../../crates/test-utils" }

View File

@@ -1,16 +1,30 @@
use core::array::from_fn;
use openvm::io::{read, read_vec, reveal_u32};
use test_utils::guest::BasicStruct;
use test_utils::guest::{BasicStruct, BASIC_PROGRAM_BYTES_LENGTH};
fn main() {
// Read `Hello world` bytes.
// Read `bytes`.
let bytes = read_vec();
assert_eq!(String::from_utf8_lossy(&bytes), "Hello world");
// Read `BasicStruct`.
// Read `basic_struct`.
let basic_struct = read::<BasicStruct>();
let output = basic_struct.output();
output.chunks(4).enumerate().for_each(|(idx, bytes)| {
reveal_u32(u32::from_le_bytes(bytes.try_into().unwrap()), idx);
});
// Check `bytes` length is as expected.
assert_eq!(bytes.len(), BASIC_PROGRAM_BYTES_LENGTH);
// Do some computation on `basic_struct`.
let basic_struct_output = basic_struct.output();
// Write reversed `bytes` and `basic_struct_output`
let public_values = core::iter::empty()
.chain(bytes.into_iter().rev())
.chain(bincode::serialize(&basic_struct_output).unwrap())
.collect::<Vec<_>>();
public_values
.chunks(4)
.enumerate()
.for_each(|(idx, bytes)| {
let bytes = from_fn(|i| bytes.get(i).copied().unwrap_or_default());
reveal_u32(u32::from_le_bytes(bytes), idx);
});
}

View File

@@ -1,19 +1,24 @@
#![no_main]
use pico_sdk::io::{commit, read_as, read_vec};
use test_utils::guest::BasicStruct;
use pico_sdk::io::{commit, commit_bytes, read_as, read_vec};
use test_utils::guest::{BasicStruct, BASIC_PROGRAM_BYTES_LENGTH};
pico_sdk::entrypoint!(main);
pub fn main() {
// Read `Hello world` bytes.
// Read `bytes`.
let bytes = read_vec();
assert_eq!(String::from_utf8_lossy(&bytes), "Hello world");
// Read `BasicStruct`.
// Read `basic_struct`.
let basic_struct = read_as::<BasicStruct>();
let output = basic_struct.output();
// Write `output`
commit(&output);
// Check `bytes` length is as expected.
assert_eq!(bytes.len(), BASIC_PROGRAM_BYTES_LENGTH);
// Do some computation on `basic_struct`.
let basic_struct_output = basic_struct.output();
// Write reversed `bytes` and `basic_struct_output`
commit_bytes(&bytes.into_iter().rev().collect::<Vec<_>>());
commit(&basic_struct_output);
}

View File

@@ -7,4 +7,5 @@ edition = "2021"
[dependencies]
risc0-zkvm = { version = "3.0.1", default-features = false, features = ["std", "unstable"] }
risc0-zkvm-platform = { version = "=2.0.4" }
test-utils = { path = "../../../crates/test-utils" }

View File

@@ -1,15 +1,20 @@
use risc0_zkvm::guest::env;
use test_utils::guest::BasicStruct;
use test_utils::guest::{BasicStruct, BASIC_PROGRAM_BYTES_LENGTH};
fn main() {
// Read `Hello world` bytes.
// Read `bytes`.
let bytes = env::read_frame();
assert_eq!(String::from_utf8_lossy(&bytes), "Hello world");
// Read `BasicStruct`.
// Read `basic_struct`.
let basic_struct = env::read::<BasicStruct>();
let output = basic_struct.output();
// Write `output`
env::commit(&output);
// Check `bytes` length is as expected.
assert_eq!(bytes.len(), BASIC_PROGRAM_BYTES_LENGTH);
// Do some computation on `basic_struct`.
let basic_struct_output = basic_struct.output();
// Write reversed `bytes` and `basic_struct_output`
env::commit_slice(&bytes.into_iter().rev().collect::<Vec<_>>());
env::commit(&basic_struct_output);
}

View File

@@ -1,18 +1,23 @@
#![no_main]
use test_utils::guest::BasicStruct;
use test_utils::guest::{BasicStruct, BASIC_PROGRAM_BYTES_LENGTH};
sp1_zkvm::entrypoint!(main);
pub fn main() {
// Read `Hello world` bytes.
// Read `bytes`.
let bytes = sp1_zkvm::io::read_vec();
assert_eq!(String::from_utf8_lossy(&bytes), "Hello world");
// Read `BasicStruct`.
// Read `basic_struct`.
let basic_struct = sp1_zkvm::io::read::<BasicStruct>();
let output = basic_struct.output();
// Write `output`
sp1_zkvm::io::commit(&output);
// Check `bytes` length is as expected.
assert_eq!(bytes.len(), BASIC_PROGRAM_BYTES_LENGTH);
// Do some computation on `basic_struct`.
let basic_struct_output = basic_struct.output();
// Write reversed `bytes` and `basic_struct_output`
sp1_zkvm::io::commit_slice(&bytes.into_iter().rev().collect::<Vec<_>>());
sp1_zkvm::io::commit(&basic_struct_output);
}

View File

@@ -1,6 +1,7 @@
#![no_main]
use test_utils::guest::BasicStruct;
use core::array::from_fn;
use test_utils::guest::{BasicStruct, BASIC_PROGRAM_BYTES_LENGTH};
ziskos::entrypoint!(main);
@@ -8,15 +9,31 @@ fn main() {
let input = ziskos::read_input();
let mut input = input.as_slice();
// Read `Hello world` bytes.
// Read `bytes`.
let bytes: Vec<u8> = bincode::deserialize_from(&mut input).unwrap();
assert_eq!(String::from_utf8_lossy(&bytes), "Hello world");
// Read `BasicStruct`.
// Read `basic_struct`.
let basic_struct: BasicStruct = bincode::deserialize_from(&mut input).unwrap();
let output = basic_struct.output();
output.chunks(4).enumerate().for_each(|(idx, bytes)| {
ziskos::set_output(idx, u32::from_le_bytes(bytes.try_into().unwrap()));
});
// Check input is fully read.
assert!(input.is_empty());
// Check `bytes` length is as expected.
assert_eq!(bytes.len(), BASIC_PROGRAM_BYTES_LENGTH);
// Do some computation on `basic_struct`.
let basic_struct_output = basic_struct.output();
// Write reversed `bytes` and `basic_struct_output`
let public_values = core::iter::empty()
.chain(bytes.into_iter().rev())
.chain(bincode::serialize(&basic_struct_output).unwrap())
.collect::<Vec<_>>();
public_values
.chunks(4)
.enumerate()
.for_each(|(idx, bytes)| {
let bytes = from_fn(|i| bytes.get(i).copied().unwrap_or_default());
ziskos::set_output(idx, u32::from_le_bytes(bytes));
});
}