mirror of
https://github.com/eth-act/ere.git
synced 2026-04-03 03:00:17 -04:00
Support multiple proof kind (#161)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -15552,6 +15552,7 @@ dependencies = [
|
||||
"indexmap 2.10.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum 0.27.2",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
|
||||
16
README.md
16
README.md
@@ -82,7 +82,7 @@ ere-sp1 = { git = "https://github.com/eth-act/ere.git", tag = "v0.0.12" }
|
||||
```rust
|
||||
// main.rs
|
||||
use ere_sp1::{EreSP1, RV32_IM_SUCCINCT_ZKVM_ELF};
|
||||
use zkvm_interface::{Compiler, Input, ProverResourceType, zkVM};
|
||||
use zkvm_interface::{Compiler, Input, ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let guest_directory = std::path::Path::new("workspace/guest");
|
||||
@@ -99,13 +99,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
io.write(42u32);
|
||||
|
||||
// Execute
|
||||
let _report = zkvm.execute(&io)?;
|
||||
let (public_values, report) = zkvm.execute(&io)?;
|
||||
|
||||
// Prove
|
||||
let (proof, _report) = zkvm.prove(&io)?;
|
||||
let (public_values, proof, report) = zkvm.prove(&io, ProofKind::Compressed)?;
|
||||
|
||||
// Verify
|
||||
zkvm.verify(&proof)?;
|
||||
let public_values = zkvm.verify(&proof)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -129,7 +129,7 @@ ere-dockerized = { git = "https://github.com/eth-act/ere.git", tag = "v0.0.12" }
|
||||
```rust
|
||||
// main.rs
|
||||
use ere_dockerized::{EreDockerizedCompiler, EreDockerizedzkVM, ErezkVM};
|
||||
use zkvm_interface::{Compiler, Input, ProverResourceType, zkVM};
|
||||
use zkvm_interface::{Compiler, Input, ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let guest_directory = std::path::Path::new("workspace/guest");
|
||||
@@ -146,13 +146,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
io.write(42u32);
|
||||
|
||||
// Execute
|
||||
let _report = zkvm.execute(&io)?;
|
||||
let (public_values, report) = zkvm.execute(&io)?;
|
||||
|
||||
// Prove
|
||||
let (proof, _report) = zkvm.prove(&io)?;
|
||||
let (public_values, proof, report) = zkvm.prove(&io, ProofKind::Compressed)?;
|
||||
|
||||
// Verify
|
||||
zkvm.verify(&proof)?;
|
||||
let public_values = zkvm.verify(&proof)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -131,6 +131,10 @@ impl DockerRunCmd {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn env(self, key: impl AsRef<str>, value: impl AsRef<str>) -> Self {
|
||||
self.option("env", format!("{}={}", key.as_ref(), value.as_ref()))
|
||||
}
|
||||
|
||||
/// Mounts `/var/run/docker.sock` to allow Docker-out-of-Docker (DooD).
|
||||
pub fn mount_docker_socket(self) -> Self {
|
||||
self.volume(DOCKER_SOCKET, DOCKER_SOCKET)
|
||||
@@ -152,7 +156,7 @@ impl DockerRunCmd {
|
||||
pub fn inherit_env(self, key: impl AsRef<str>) -> Self {
|
||||
let key = key.as_ref();
|
||||
match env::var(key) {
|
||||
Ok(val) => self.option("env", format!("{key}={val}")),
|
||||
Ok(val) => self.env(key, val),
|
||||
Err(_) => self,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
//! ```rust,no_run
|
||||
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
//! use ere_dockerized::{EreDockerizedCompiler, EreDockerizedzkVM, ErezkVM};
|
||||
//! use zkvm_interface::{Compiler, Input, ProverResourceType, zkVM};
|
||||
//! use zkvm_interface::{Compiler, Input, ProofKind, ProverResourceType, zkVM};
|
||||
//! use std::path::Path;
|
||||
//!
|
||||
//! // The zkVM we plan to use
|
||||
@@ -52,7 +52,7 @@
|
||||
//! println!("Execution cycles: {}", execution_report.total_num_cycles);
|
||||
//!
|
||||
//! // Generate proof
|
||||
//! let (public_values, proof, proving_report) = zkvm.prove(&inputs)?;
|
||||
//! let (public_values, proof, proving_report) = zkvm.prove(&inputs, ProofKind::Compressed)?;
|
||||
//! println!("Proof generated in: {:?}", proving_report.proving_time);
|
||||
//!
|
||||
//! // Verify proof
|
||||
@@ -83,8 +83,8 @@ use std::{
|
||||
use tempfile::TempDir;
|
||||
use tracing::error;
|
||||
use zkvm_interface::{
|
||||
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType,
|
||||
PublicValues, zkVM, zkVMError,
|
||||
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind,
|
||||
ProverResourceType, PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/crate_version.rs"));
|
||||
@@ -258,7 +258,7 @@ impl ErezkVM {
|
||||
&self,
|
||||
program: &SerializedProgram,
|
||||
resource: &ProverResourceType,
|
||||
) -> Result<String, CommonError> {
|
||||
) -> Result<ServerContainer, CommonError> {
|
||||
let port = self.server_port().to_string();
|
||||
let name = format!("ere-server-{self}-{port}");
|
||||
let gpu = matches!(resource, ProverResourceType::Gpu);
|
||||
@@ -295,11 +295,9 @@ impl ErezkVM {
|
||||
if gpu {
|
||||
cmd = match self {
|
||||
ErezkVM::OpenVM => cmd.gpus("all"),
|
||||
// SP1's and Risc0's GPU proving requires Docker to start GPU prover
|
||||
// service, to give the client access to the prover service, we need
|
||||
// to use the host networking driver.
|
||||
// The `--cuda` flags will be set when the GPU prover service is
|
||||
// spin up, so we don't need to set here.
|
||||
// SP1 runs docker command to spin up the server to do GPU
|
||||
// proving, to give the client access to the prover service, we
|
||||
// need to use the host networking driver.
|
||||
ErezkVM::SP1 => cmd.mount_docker_socket().network("host"),
|
||||
ErezkVM::Risc0 => cmd.gpus("all").inherit_env("RISC0_DEFAULT_PROVER_NUM_GPUS"),
|
||||
ErezkVM::Zisk => cmd.gpus("all"),
|
||||
@@ -307,13 +305,41 @@ impl ErezkVM {
|
||||
}
|
||||
}
|
||||
|
||||
let tempdir = TempDir::new()
|
||||
.map_err(|err| CommonError::io(err, "Failed to create temporary directory"))?;
|
||||
|
||||
// zkVM specific options needed for proving Groth16 proof.
|
||||
cmd = match self {
|
||||
// Risc0 and SP1 runs docker command to prove Groth16 proof, and
|
||||
// they pass the input by mounting temporary directory. Here we
|
||||
// create a temporary directory and mount it on the top level, so
|
||||
// the volume could be shared, and override `TMPDIR` so we don't
|
||||
// need to mount the whole `/tmp`.
|
||||
ErezkVM::Risc0 => cmd
|
||||
.mount_docker_socket()
|
||||
.env("TMPDIR", tempdir.path().to_string_lossy())
|
||||
.volume(tempdir.path(), tempdir.path()),
|
||||
ErezkVM::SP1 => {
|
||||
let groth16_circuit_path = home_dir().join(".sp1").join("circuits").join("groth16");
|
||||
cmd.mount_docker_socket()
|
||||
.env(
|
||||
"SP1_GROTH16_CIRCUIT_PATH",
|
||||
groth16_circuit_path.to_string_lossy(),
|
||||
)
|
||||
.env("TMPDIR", tempdir.path().to_string_lossy())
|
||||
.volume(tempdir.path(), tempdir.path())
|
||||
.volume(&groth16_circuit_path, &groth16_circuit_path)
|
||||
}
|
||||
_ => cmd,
|
||||
};
|
||||
|
||||
let args = iter::empty()
|
||||
.chain(["--port", &port])
|
||||
.chain(resource.to_args());
|
||||
cmd.spawn(args, &program.0)
|
||||
.map_err(CommonError::DockerRunCmd)?;
|
||||
|
||||
Ok(name)
|
||||
Ok(ServerContainer { name, tempdir })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,22 +443,29 @@ impl Compiler for EreDockerizedCompiler {
|
||||
}
|
||||
}
|
||||
|
||||
struct ServerContainer {
|
||||
name: String,
|
||||
#[allow(dead_code)]
|
||||
tempdir: TempDir,
|
||||
}
|
||||
|
||||
impl Drop for ServerContainer {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = stop_docker_container(&self.name) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EreDockerizedzkVM {
|
||||
zkvm: ErezkVM,
|
||||
program: SerializedProgram,
|
||||
resource: ProverResourceType,
|
||||
server_container_name: String,
|
||||
#[allow(dead_code)]
|
||||
server_container: ServerContainer,
|
||||
client: zkVMClient,
|
||||
}
|
||||
|
||||
impl Drop for EreDockerizedzkVM {
|
||||
fn drop(&mut self) {
|
||||
if let Err(err) = stop_docker_container(&self.server_container_name) {
|
||||
error!("{err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EreDockerizedzkVM {
|
||||
pub fn new(
|
||||
zkvm: ErezkVM,
|
||||
@@ -441,7 +474,7 @@ impl EreDockerizedzkVM {
|
||||
) -> Result<Self, zkVMError> {
|
||||
zkvm.build_docker_image(matches!(resource, ProverResourceType::Gpu))?;
|
||||
|
||||
let server_container_name = zkvm.spawn_server(&program, &resource)?;
|
||||
let server_container = zkvm.spawn_server(&program, &resource)?;
|
||||
|
||||
let url = Url::parse(&format!("http://127.0.0.1:{}", zkvm.server_port())).unwrap();
|
||||
let client = block_on(zkVMClient::new(url)).map_err(zkVMError::other)?;
|
||||
@@ -450,7 +483,7 @@ impl EreDockerizedzkVM {
|
||||
zkvm,
|
||||
program,
|
||||
resource,
|
||||
server_container_name,
|
||||
server_container,
|
||||
client,
|
||||
})
|
||||
}
|
||||
@@ -484,19 +517,21 @@ impl zkVM for EreDockerizedzkVM {
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError> {
|
||||
let serialized_input = self
|
||||
.zkvm
|
||||
.serialize_inputs(inputs)
|
||||
.map_err(|err| DockerizedError::Prove(ProveError::Common(err)))?;
|
||||
|
||||
let (public_values, proof, report) = block_on(self.client.prove(serialized_input))
|
||||
.map_err(|err| DockerizedError::Prove(ProveError::Client(err)))?;
|
||||
let (public_values, proof, report) =
|
||||
block_on(self.client.prove(serialized_input, proof_kind))
|
||||
.map_err(|err| DockerizedError::Prove(ProveError::Client(err)))?;
|
||||
|
||||
Ok((public_values, proof, report))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
let public_values = block_on(self.client.verify(proof))
|
||||
.map_err(|err| DockerizedError::Verify(VerifyError::Client(err)))?;
|
||||
|
||||
@@ -530,6 +565,10 @@ fn workspace_dir() -> PathBuf {
|
||||
dir.canonicalize().unwrap()
|
||||
}
|
||||
|
||||
fn home_dir() -> PathBuf {
|
||||
PathBuf::from(std::env::var("HOME").expect("env `$HOME` should be set"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
macro_rules! test_compile {
|
||||
|
||||
@@ -14,8 +14,8 @@ use std::{
|
||||
};
|
||||
use tempfile::TempDir;
|
||||
use zkvm_interface::{
|
||||
Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType, PublicValues,
|
||||
zkVM, zkVMError,
|
||||
Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType,
|
||||
PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
@@ -72,7 +72,12 @@ impl zkVM for EreJolt {
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
|
||||
if proof_kind != ProofKind::Compressed {
|
||||
panic!("Only Compressed proof kind is supported.");
|
||||
}
|
||||
|
||||
let (_tempdir, program) = program(&self.elf)?;
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
@@ -89,13 +94,17 @@ impl zkVM for EreJolt {
|
||||
|
||||
Ok((
|
||||
public_values,
|
||||
proof_bytes,
|
||||
Proof::Compressed(proof_bytes),
|
||||
ProgramProvingReport::new(elapsed),
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, proof_bytes: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
let proof = EreJoltProof::deserialize_compressed(&mut Cursor::new(proof_bytes))
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
let Proof::Compressed(proof) = proof else {
|
||||
return Err(zkVMError::other("Only Compressed proof kind is supported."));
|
||||
};
|
||||
|
||||
let proof = EreJoltProof::deserialize_compressed(&mut Cursor::new(proof))
|
||||
.map_err(|err| JoltError::Verify(VerifyError::Serialization(err)))?;
|
||||
|
||||
verify_generic(proof, self.verifier_preprocessing.clone()).map_err(JoltError::Verify)?;
|
||||
|
||||
@@ -16,8 +16,8 @@ use miden_verifier::verify as miden_verify;
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
use std::{env, io::Read, time::Instant};
|
||||
use zkvm_interface::{
|
||||
Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType, PublicValues,
|
||||
zkVM, zkVMError,
|
||||
Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType,
|
||||
PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
@@ -83,7 +83,12 @@ impl zkVM for EreMiden {
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError> {
|
||||
if proof_kind != ProofKind::Compressed {
|
||||
panic!("Only Compressed proof kind is supported.");
|
||||
}
|
||||
|
||||
let (stack_inputs, advice_inputs) = generate_miden_inputs(inputs)?;
|
||||
let mut host = Self::setup_host()?;
|
||||
|
||||
@@ -112,12 +117,16 @@ impl zkVM for EreMiden {
|
||||
|
||||
Ok((
|
||||
public_values,
|
||||
proof_bytes,
|
||||
Proof::Compressed(proof_bytes),
|
||||
ProgramProvingReport::new(start.elapsed()),
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
let Proof::Compressed(proof) = proof else {
|
||||
return Err(zkVMError::other("Only Compressed proof kind is supported."));
|
||||
};
|
||||
|
||||
let bundle: MidenProofBundle = bincode::deserialize(proof)
|
||||
.map_err(|e| MidenError::Verify(VerifyError::BundleDeserialization(e)))?;
|
||||
|
||||
@@ -162,7 +171,7 @@ mod tests {
|
||||
compiler::{MidenAsm, MidenProgram},
|
||||
};
|
||||
use test_utils::host::testing_guest_directory;
|
||||
use zkvm_interface::{Compiler, Input, ProverResourceType, zkVM};
|
||||
use zkvm_interface::{Compiler, Input, ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
fn load_miden_program(guest_name: &str) -> MidenProgram {
|
||||
MidenAsm
|
||||
@@ -184,7 +193,7 @@ mod tests {
|
||||
inputs.write(const_b);
|
||||
|
||||
// Prove
|
||||
let (prover_public_values, proof, _) = zkvm.prove(&inputs).unwrap();
|
||||
let (prover_public_values, proof, _) = zkvm.prove(&inputs, ProofKind::default()).unwrap();
|
||||
|
||||
// Verify
|
||||
let verifier_public_values = zkvm.verify(&proof).unwrap();
|
||||
@@ -211,7 +220,7 @@ mod tests {
|
||||
inputs.write(n_iterations);
|
||||
|
||||
// Prove
|
||||
let (prover_public_values, proof, _) = zkvm.prove(&inputs).unwrap();
|
||||
let (prover_public_values, proof, _) = zkvm.prove(&inputs, ProofKind::default()).unwrap();
|
||||
|
||||
// Verify
|
||||
let verifier_public_values = zkvm.verify(&proof).unwrap();
|
||||
|
||||
@@ -9,8 +9,8 @@ use serde::de::DeserializeOwned;
|
||||
use std::{io::Read, time::Instant};
|
||||
use tracing::info;
|
||||
use zkvm_interface::{
|
||||
Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType, PublicValues,
|
||||
zkVM, zkVMError,
|
||||
Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, ProverResourceType,
|
||||
PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
@@ -47,7 +47,12 @@ impl zkVM for EreNexus {
|
||||
fn prove(
|
||||
&self,
|
||||
_inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
|
||||
if proof_kind != ProofKind::Compressed {
|
||||
panic!("Only Compressed proof kind is supported.");
|
||||
}
|
||||
|
||||
let prover: Stwo<Local> = Stwo::new_from_bytes(&self.program)
|
||||
.map_err(|e| NexusError::Prove(ProveError::Client(e.into())))
|
||||
.map_err(zkVMError::from)?;
|
||||
@@ -68,10 +73,18 @@ impl zkVM for EreNexus {
|
||||
// TODO: Public values
|
||||
let public_values = Vec::new();
|
||||
|
||||
Ok((public_values, bytes, ProgramProvingReport::new(elapsed)))
|
||||
Ok((
|
||||
public_values,
|
||||
Proof::Compressed(bytes),
|
||||
ProgramProvingReport::new(elapsed),
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
let Proof::Compressed(proof) = proof else {
|
||||
return Err(zkVMError::other("Only Compressed proof kind is supported."));
|
||||
};
|
||||
|
||||
info!("Verifying proof...");
|
||||
|
||||
let proof: nexus_sdk::stwo::seq::Proof = bincode::deserialize(proof)
|
||||
|
||||
@@ -19,8 +19,8 @@ use openvm_transpiler::{elf::Elf, openvm_platform::memory::MEM_SIZE};
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::{env, io::Read, path::PathBuf, sync::Arc, time::Instant};
|
||||
use zkvm_interface::{
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType,
|
||||
PublicValues, zkVM, zkVMError,
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind,
|
||||
ProverResourceType, PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
@@ -128,7 +128,12 @@ impl zkVM for EreOpenVM {
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
|
||||
if proof_kind != ProofKind::Compressed {
|
||||
panic!("Only Compressed proof kind is supported.");
|
||||
}
|
||||
|
||||
let mut stdin = StdIn::default();
|
||||
serialize_inputs(&mut stdin, inputs);
|
||||
|
||||
@@ -164,13 +169,17 @@ impl zkVM for EreOpenVM {
|
||||
|
||||
Ok((
|
||||
public_values,
|
||||
proof_bytes,
|
||||
Proof::Compressed(proof_bytes),
|
||||
ProgramProvingReport::new(elapsed),
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, mut proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
let proof = VmStarkProof::<SC>::decode(&mut proof)
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
let Proof::Compressed(proof) = proof else {
|
||||
return Err(zkVMError::other("Only Compressed proof kind is supported."));
|
||||
};
|
||||
|
||||
let proof = VmStarkProof::<SC>::decode(&mut proof.as_slice())
|
||||
.map_err(|e| OpenVMError::from(VerifyError::DeserializeProof(e)))?;
|
||||
|
||||
CpuSdk::verify_proof(&self.agg_vk, self.app_commit, &proof)
|
||||
@@ -232,7 +241,7 @@ mod tests {
|
||||
use test_utils::host::{
|
||||
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
|
||||
};
|
||||
use zkvm_interface::{Compiler, ProverResourceType, zkVM};
|
||||
use zkvm_interface::{Compiler, ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
fn basic_program() -> OpenVMProgram {
|
||||
static PROGRAM: OnceLock<OpenVMProgram> = OnceLock::new();
|
||||
@@ -287,7 +296,7 @@ mod tests {
|
||||
BasicProgramIo::invalid_type(),
|
||||
BasicProgramIo::invalid_data(),
|
||||
] {
|
||||
zkvm.prove(&inputs).unwrap_err();
|
||||
zkvm.prove(&inputs, ProofKind::default()).unwrap_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ use std::{
|
||||
time::{self, Instant},
|
||||
};
|
||||
use zkvm_interface::{
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType,
|
||||
PublicValues, zkVM, zkVMError,
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind,
|
||||
ProverResourceType, PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
@@ -71,7 +71,12 @@ impl zkVM for ErePico {
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
|
||||
if proof_kind != ProofKind::Compressed {
|
||||
panic!("Only Compressed proof kind is implemented.");
|
||||
}
|
||||
|
||||
let client = self.client();
|
||||
|
||||
let mut stdin = client.new_stdin_builder();
|
||||
@@ -91,12 +96,18 @@ impl zkVM for ErePico {
|
||||
|
||||
Ok((
|
||||
public_values,
|
||||
proof_bytes,
|
||||
Proof::Compressed(proof_bytes),
|
||||
ProgramProvingReport::new(elapsed),
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
let Proof::Compressed(proof) = proof else {
|
||||
return Err(zkVMError::other(
|
||||
"Only Compressed proof kind is implemented.",
|
||||
));
|
||||
};
|
||||
|
||||
let client = self.client();
|
||||
|
||||
let proof: PicoProofWithPublicValues = bincode::deserialize(proof)
|
||||
@@ -172,7 +183,7 @@ mod tests {
|
||||
use test_utils::host::{
|
||||
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
|
||||
};
|
||||
use zkvm_interface::{Compiler, ProverResourceType, zkVM};
|
||||
use zkvm_interface::{Compiler, ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
static BASIC_PROGRAM: OnceLock<PicoProgram> = OnceLock::new();
|
||||
|
||||
@@ -228,7 +239,7 @@ mod tests {
|
||||
BasicProgramIo::invalid_type,
|
||||
BasicProgramIo::invalid_data,
|
||||
] {
|
||||
panic::catch_unwind(|| zkvm.prove(&inputs_gen())).unwrap_err();
|
||||
panic::catch_unwind(|| zkvm.prove(&inputs_gen(), ProofKind::default())).unwrap_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
|
||||
use crate::{compiler::Risc0Program, 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,
|
||||
ProverOpts, Receipt, default_executor, default_prover,
|
||||
};
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::{env, io::Read, ops::RangeInclusive, rc::Rc, time::Instant};
|
||||
use zkvm_interface::{
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType,
|
||||
PublicValues, zkVM, zkVMError,
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind,
|
||||
ProverResourceType, PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
@@ -45,33 +44,6 @@ const DEFAULT_KECCAK_PO2: usize = 17;
|
||||
/// [`KECCAK_PO2_RANGE`]: https://github.com/risc0/risc0/blob/v3.0.3/risc0/circuit/keccak/src/lib.rs#L29.
|
||||
const KECCAK_PO2_RANGE: RangeInclusive<usize> = 14..=18;
|
||||
|
||||
#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
|
||||
pub struct Risc0ProofWithPublicValues {
|
||||
/// The aggregated proof generated by the Risc0 zkVM.
|
||||
pub receipt: SuccinctReceipt<ReceiptClaim>,
|
||||
/// The public values generated by the Risc0 zkVM.
|
||||
pub journal: Journal,
|
||||
}
|
||||
|
||||
impl From<Receipt> for Risc0ProofWithPublicValues {
|
||||
fn from(receipt: Receipt) -> Self {
|
||||
match receipt.inner {
|
||||
// We always use `ProverOpts::succinct()`.
|
||||
InnerReceipt::Succinct(inner) => Self {
|
||||
receipt: inner,
|
||||
journal: receipt.journal,
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Risc0ProofWithPublicValues> for Receipt {
|
||||
fn from(Risc0ProofWithPublicValues { receipt, journal }: Risc0ProofWithPublicValues) -> Self {
|
||||
Receipt::new(InnerReceipt::Succinct(receipt), journal.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EreRisc0 {
|
||||
program: Risc0Program,
|
||||
resource: ProverResourceType,
|
||||
@@ -138,6 +110,7 @@ impl zkVM for EreRisc0 {
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError> {
|
||||
let prover = match self.resource {
|
||||
ProverResourceType::Cpu => Rc::new(ExternalProver::new("ipc", "r0vm")),
|
||||
@@ -171,15 +144,22 @@ impl zkVM for EreRisc0 {
|
||||
.build()
|
||||
.map_err(zkVMError::other)?;
|
||||
|
||||
let opts = match proof_kind {
|
||||
ProofKind::Compressed => ProverOpts::succinct(),
|
||||
ProofKind::Groth16 => ProverOpts::groth16(),
|
||||
};
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
let prove_info = prover
|
||||
.prove_with_opts(env, &self.program.elf, &ProverOpts::succinct())
|
||||
.prove_with_opts(env, &self.program.elf, &opts)
|
||||
.map_err(zkVMError::other)?;
|
||||
let proving_time = now.elapsed();
|
||||
|
||||
let public_values = prove_info.receipt.journal.bytes.clone();
|
||||
let proof = borsh::to_vec(&Risc0ProofWithPublicValues::from(prove_info.receipt))
|
||||
.map_err(zkVMError::other)?;
|
||||
let proof = Proof::new(
|
||||
proof_kind,
|
||||
borsh::to_vec(&prove_info.receipt).map_err(zkVMError::other)?,
|
||||
);
|
||||
|
||||
Ok((
|
||||
public_values,
|
||||
@@ -188,10 +168,20 @@ impl zkVM for EreRisc0 {
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
let receipt: Receipt = borsh::from_slice::<Risc0ProofWithPublicValues>(proof)
|
||||
.map_err(zkVMError::other)?
|
||||
.into();
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
let proof_kind = proof.kind();
|
||||
|
||||
let receipt: Receipt = borsh::from_slice(proof.as_bytes()).map_err(zkVMError::other)?;
|
||||
|
||||
if !matches!(
|
||||
(proof_kind, &receipt.inner),
|
||||
(ProofKind::Compressed, InnerReceipt::Succinct(_))
|
||||
| (ProofKind::Groth16, InnerReceipt::Groth16(_))
|
||||
) {
|
||||
return Err(zkVMError::other(format!(
|
||||
"Invalid inner receipt kind, expected {proof_kind:?}",
|
||||
)))?;
|
||||
}
|
||||
|
||||
receipt
|
||||
.verify(self.program.image_id)
|
||||
@@ -245,7 +235,7 @@ mod tests {
|
||||
use test_utils::host::{
|
||||
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
|
||||
};
|
||||
use zkvm_interface::{Compiler, Input, ProverResourceType, zkVM};
|
||||
use zkvm_interface::{Compiler, Input, ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
static BASIC_PROGRAM: OnceLock<Risc0Program> = OnceLock::new();
|
||||
|
||||
@@ -301,7 +291,7 @@ mod tests {
|
||||
BasicProgramIo::invalid_type(),
|
||||
BasicProgramIo::invalid_data(),
|
||||
] {
|
||||
zkvm.prove(&inputs).unwrap_err();
|
||||
zkvm.prove(&inputs, ProofKind::default()).unwrap_err();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,11 @@ syntax = "proto3";
|
||||
|
||||
package api;
|
||||
|
||||
enum ProofKind {
|
||||
Compressed = 0;
|
||||
Groth16 = 1;
|
||||
}
|
||||
|
||||
service ZkvmService {
|
||||
rpc Execute(ExecuteRequest) returns (ExecuteResponse) {}
|
||||
rpc Prove(ProveRequest) returns (ProveResponse) {}
|
||||
@@ -19,6 +24,7 @@ message ExecuteResponse {
|
||||
|
||||
message ProveRequest {
|
||||
bytes input = 1;
|
||||
ProofKind proof_kind = 2;
|
||||
}
|
||||
|
||||
message ProveResponse {
|
||||
@@ -29,6 +35,7 @@ message ProveResponse {
|
||||
|
||||
message VerifyRequest {
|
||||
bytes proof = 1;
|
||||
ProofKind proof_kind = 2;
|
||||
}
|
||||
|
||||
message VerifyResponse {
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
// This file is @generated by prost-build.
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ExecuteRequest {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub input: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ExecuteResponse {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub public_values: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub report: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ProveRequest {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub input: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ProveResponse {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub public_values: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes = "vec", tag = "2")]
|
||||
pub proof: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(bytes = "vec", tag = "3")]
|
||||
pub report: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct VerifyRequest {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub proof: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct VerifyResponse {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub public_values: ::prost::alloc::vec::Vec<u8>,
|
||||
}
|
||||
pub use twirp;
|
||||
#[twirp::async_trait::async_trait]
|
||||
pub trait ZkvmService: Send + Sync {
|
||||
async fn execute(
|
||||
&self,
|
||||
req: twirp::Request<ExecuteRequest>,
|
||||
) -> twirp::Result<twirp::Response<ExecuteResponse>>;
|
||||
async fn prove(
|
||||
&self,
|
||||
req: twirp::Request<ProveRequest>,
|
||||
) -> twirp::Result<twirp::Response<ProveResponse>>;
|
||||
async fn verify(
|
||||
&self,
|
||||
req: twirp::Request<VerifyRequest>,
|
||||
) -> twirp::Result<twirp::Response<VerifyResponse>>;
|
||||
}
|
||||
#[twirp::async_trait::async_trait]
|
||||
impl<T> ZkvmService for std::sync::Arc<T>
|
||||
where
|
||||
T: ZkvmService + Sync + Send,
|
||||
{
|
||||
async fn execute(
|
||||
&self,
|
||||
req: twirp::Request<ExecuteRequest>,
|
||||
) -> twirp::Result<twirp::Response<ExecuteResponse>> {
|
||||
T::execute(&*self, req).await
|
||||
}
|
||||
async fn prove(
|
||||
&self,
|
||||
req: twirp::Request<ProveRequest>,
|
||||
) -> twirp::Result<twirp::Response<ProveResponse>> {
|
||||
T::prove(&*self, req).await
|
||||
}
|
||||
async fn verify(
|
||||
&self,
|
||||
req: twirp::Request<VerifyRequest>,
|
||||
) -> twirp::Result<twirp::Response<VerifyResponse>> {
|
||||
T::verify(&*self, req).await
|
||||
}
|
||||
}
|
||||
pub fn router<T>(api: T) -> twirp::Router
|
||||
where
|
||||
T: ZkvmService + Clone + Send + Sync + 'static,
|
||||
{
|
||||
twirp::details::TwirpRouterBuilder::new("/api.ZkvmService", api)
|
||||
.route(
|
||||
"/Execute",
|
||||
|api: T, req: twirp::Request<ExecuteRequest>| async move {
|
||||
api.execute(req).await
|
||||
},
|
||||
)
|
||||
.route(
|
||||
"/Prove",
|
||||
|api: T, req: twirp::Request<ProveRequest>| async move {
|
||||
api.prove(req).await
|
||||
},
|
||||
)
|
||||
.route(
|
||||
"/Verify",
|
||||
|api: T, req: twirp::Request<VerifyRequest>| async move {
|
||||
api.verify(req).await
|
||||
},
|
||||
)
|
||||
.build()
|
||||
}
|
||||
#[twirp::async_trait::async_trait]
|
||||
impl ZkvmService for twirp::client::Client {
|
||||
async fn execute(
|
||||
&self,
|
||||
req: twirp::Request<ExecuteRequest>,
|
||||
) -> twirp::Result<twirp::Response<ExecuteResponse>> {
|
||||
self.request("api.ZkvmService/Execute", req).await
|
||||
}
|
||||
async fn prove(
|
||||
&self,
|
||||
req: twirp::Request<ProveRequest>,
|
||||
) -> twirp::Result<twirp::Response<ProveResponse>> {
|
||||
self.request("api.ZkvmService/Prove", req).await
|
||||
}
|
||||
async fn verify(
|
||||
&self,
|
||||
req: twirp::Request<VerifyRequest>,
|
||||
) -> twirp::Result<twirp::Response<VerifyResponse>> {
|
||||
self.request("api.ZkvmService/Verify", req).await
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub mod handler {
|
||||
use super::*;
|
||||
pub struct ZkvmServiceHandler {
|
||||
inner: std::sync::Arc<dyn ZkvmService>,
|
||||
}
|
||||
impl ZkvmServiceHandler {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new<M: ZkvmService + 'static>(inner: M) -> Self {
|
||||
Self {
|
||||
inner: std::sync::Arc::new(inner),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[twirp::async_trait::async_trait]
|
||||
impl twirp::client::DirectHandler for ZkvmServiceHandler {
|
||||
fn service(&self) -> &str {
|
||||
"api.ZkvmService"
|
||||
}
|
||||
async fn handle(
|
||||
&self,
|
||||
method: &str,
|
||||
req: twirp::reqwest::Request,
|
||||
) -> twirp::Result<twirp::reqwest::Response> {
|
||||
match method {
|
||||
"Execute" => {
|
||||
twirp::details::encode_response(
|
||||
self
|
||||
.inner
|
||||
.execute(twirp::details::decode_request(req).await?)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
"Prove" => {
|
||||
twirp::details::encode_response(
|
||||
self
|
||||
.inner
|
||||
.prove(twirp::details::decode_request(req).await?)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
"Verify" => {
|
||||
twirp::details::encode_response(
|
||||
self
|
||||
.inner
|
||||
.verify(twirp::details::decode_request(req).await?)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
Err(
|
||||
twirp::bad_route(
|
||||
format!(
|
||||
"unknown rpc `{method}` for service `{}`, url: {:?}",
|
||||
"api.ZkvmService",
|
||||
req.url(),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,9 @@ use anyhow::{Context, Error, bail};
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::time::sleep;
|
||||
use twirp::{Client, Request, reqwest};
|
||||
use zkvm_interface::{ProgramExecutionReport, ProgramProvingReport, Proof, PublicValues};
|
||||
use zkvm_interface::{
|
||||
ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, PublicValues,
|
||||
};
|
||||
|
||||
pub use twirp::url::Url;
|
||||
|
||||
@@ -71,10 +73,14 @@ impl zkVMClient {
|
||||
pub async fn prove(
|
||||
&self,
|
||||
input: SerializedInput,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, ProgramProvingReport), Error> {
|
||||
let input = bincode::serialize(&input).with_context(|| "Failed to serialize input")?;
|
||||
|
||||
let request = Request::new(ProveRequest { input });
|
||||
let request = Request::new(ProveRequest {
|
||||
input,
|
||||
proof_kind: proof_kind as i32,
|
||||
});
|
||||
|
||||
let response = self
|
||||
.client
|
||||
@@ -91,12 +97,13 @@ impl zkVMClient {
|
||||
let report: ProgramProvingReport = bincode::deserialize(&report)
|
||||
.with_context(|| "Failed to deserialize proving report")?;
|
||||
|
||||
Ok((public_values, proof, report))
|
||||
Ok((public_values, Proof::new(proof_kind, proof), report))
|
||||
}
|
||||
|
||||
pub async fn verify(&self, proof: &[u8]) -> Result<PublicValues, Error> {
|
||||
pub async fn verify(&self, proof: &Proof) -> Result<PublicValues, Error> {
|
||||
let request = Request::new(VerifyRequest {
|
||||
proof: proof.to_vec(),
|
||||
proof: proof.as_bytes().to_vec(),
|
||||
proof_kind: proof.kind() as i32,
|
||||
});
|
||||
|
||||
let response = self
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
pub(crate) mod api;
|
||||
pub mod client;
|
||||
pub mod input;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) mod api {
|
||||
include!(concat!(env!("OUT_DIR"), "/api.rs"));
|
||||
}
|
||||
|
||||
#[cfg(feature = "server")]
|
||||
pub mod server;
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
input::SerializedInput,
|
||||
};
|
||||
use twirp::{Request, Response, async_trait::async_trait, invalid_argument};
|
||||
use zkvm_interface::zkVM;
|
||||
use zkvm_interface::{Proof, ProofKind, zkVM};
|
||||
|
||||
pub use api::router;
|
||||
|
||||
@@ -55,15 +55,18 @@ impl<T: 'static + zkVM + Send + Sync> ZkvmService for zkVMServer<T> {
|
||||
let input = bincode::deserialize::<SerializedInput>(&request.input)
|
||||
.map_err(|_| invalid_argument("failed to deserialize input"))?
|
||||
.into();
|
||||
let proof_kind = ProofKind::from_repr(request.proof_kind as usize).ok_or_else(|| {
|
||||
invalid_argument(format!("invalid proof kind: {}", request.proof_kind))
|
||||
})?;
|
||||
|
||||
let (public_values, proof, report) = self
|
||||
.zkvm
|
||||
.prove(&input)
|
||||
.prove(&input, proof_kind)
|
||||
.map_err(|err| invalid_argument(format!("failed to prove: {err:?}")))?;
|
||||
|
||||
Ok(Response::new(ProveResponse {
|
||||
public_values,
|
||||
proof,
|
||||
proof: proof.as_bytes().to_vec(),
|
||||
report: bincode::serialize(&report).unwrap(),
|
||||
}))
|
||||
}
|
||||
@@ -74,9 +77,13 @@ impl<T: 'static + zkVM + Send + Sync> ZkvmService for zkVMServer<T> {
|
||||
) -> twirp::Result<Response<VerifyResponse>> {
|
||||
let request = request.into_body();
|
||||
|
||||
let proof_kind = ProofKind::from_repr(request.proof_kind as usize).ok_or_else(|| {
|
||||
invalid_argument(format!("invalid proof kind: {}", request.proof_kind))
|
||||
})?;
|
||||
|
||||
let public_values = self
|
||||
.zkvm
|
||||
.verify(&request.proof)
|
||||
.verify(&Proof::new(proof_kind, request.proof))
|
||||
.map_err(|err| invalid_argument(format!("failed to verify: {err:?}")))?;
|
||||
|
||||
Ok(Response::new(VerifyResponse { public_values }))
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::{path::PathBuf, process::ExitStatus};
|
||||
|
||||
use sp1_sdk::SP1ProofMode;
|
||||
use thiserror::Error;
|
||||
use zkvm_interface::zkVMError;
|
||||
use zkvm_interface::{ProofKind, zkVMError};
|
||||
|
||||
impl From<SP1Error> for zkVMError {
|
||||
fn from(value: SP1Error) -> Self {
|
||||
@@ -80,6 +81,9 @@ pub enum VerifyError {
|
||||
#[error("Deserialising proof failed: {0}")]
|
||||
Bincode(#[from] bincode::Error),
|
||||
|
||||
#[error("Invalid proof kind, expected: {}, got: {}", 0.to_string(), 1.to_string() )]
|
||||
InvalidProofKind(ProofKind, SP1ProofMode),
|
||||
|
||||
#[error("SP1 SDK verification failed: {0}")]
|
||||
Client(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
}
|
||||
|
||||
@@ -6,14 +6,14 @@ use crate::{
|
||||
};
|
||||
use serde::de::DeserializeOwned;
|
||||
use sp1_sdk::{
|
||||
CpuProver, CudaProver, NetworkProver, Prover, ProverClient, SP1ProofWithPublicValues,
|
||||
SP1ProvingKey, SP1Stdin, SP1VerifyingKey,
|
||||
CpuProver, CudaProver, NetworkProver, Prover, ProverClient, SP1ProofMode,
|
||||
SP1ProofWithPublicValues, SP1ProvingKey, SP1Stdin, SP1VerifyingKey,
|
||||
};
|
||||
use std::{io::Read, time::Instant};
|
||||
use tracing::info;
|
||||
use zkvm_interface::{
|
||||
Input, InputItem, NetworkProverConfig, ProgramExecutionReport, ProgramProvingReport, Proof,
|
||||
ProverResourceType, PublicValues, zkVM, zkVMError,
|
||||
ProofKind, ProverResourceType, PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
@@ -52,17 +52,17 @@ impl ProverType {
|
||||
.run()
|
||||
.map_err(|e| SP1Error::Execute(ExecuteError::Client(e.into())))
|
||||
}
|
||||
|
||||
fn prove(
|
||||
&self,
|
||||
pk: &SP1ProvingKey,
|
||||
input: &SP1Stdin,
|
||||
mode: SP1ProofMode,
|
||||
) -> Result<SP1ProofWithPublicValues, SP1Error> {
|
||||
match self {
|
||||
ProverType::Cpu(cpu_prover) => cpu_prover.prove(pk, input).compressed().run(),
|
||||
ProverType::Gpu(cuda_prover) => cuda_prover.prove(pk, input).compressed().run(),
|
||||
ProverType::Network(network_prover) => {
|
||||
network_prover.prove(pk, input).compressed().run()
|
||||
}
|
||||
ProverType::Cpu(cpu_prover) => cpu_prover.prove(pk, input).mode(mode).run(),
|
||||
ProverType::Gpu(cuda_prover) => cuda_prover.prove(pk, input).mode(mode).run(),
|
||||
ProverType::Network(network_prover) => network_prover.prove(pk, input).mode(mode).run(),
|
||||
}
|
||||
.map_err(|e| SP1Error::Prove(ProveError::Client(e.into())))
|
||||
}
|
||||
@@ -168,33 +168,56 @@ impl zkVM for EreSP1 {
|
||||
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &zkvm_interface::Input,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, zkvm_interface::ProgramProvingReport), zkVMError> {
|
||||
info!("Generating proof…");
|
||||
|
||||
let mut stdin = SP1Stdin::new();
|
||||
serialize_inputs(&mut stdin, inputs);
|
||||
|
||||
let mode = match proof_kind {
|
||||
ProofKind::Compressed => SP1ProofMode::Compressed,
|
||||
ProofKind::Groth16 => SP1ProofMode::Groth16,
|
||||
};
|
||||
|
||||
let client = Self::create_client(&self.resource);
|
||||
let start = std::time::Instant::now();
|
||||
let proof_with_inputs = client.prove(&self.pk, &stdin)?;
|
||||
let proof = client.prove(&self.pk, &stdin, mode)?;
|
||||
let proving_time = start.elapsed();
|
||||
|
||||
let bytes = bincode::serialize(&proof_with_inputs)
|
||||
.map_err(|err| SP1Error::Prove(ProveError::Bincode(err)))?;
|
||||
let public_values = proof.public_values.to_vec();
|
||||
let proof = Proof::new(
|
||||
proof_kind,
|
||||
bincode::serialize(&proof).map_err(|err| SP1Error::Prove(ProveError::Bincode(err)))?,
|
||||
);
|
||||
|
||||
Ok((
|
||||
proof_with_inputs.public_values.to_vec(),
|
||||
bytes,
|
||||
public_values,
|
||||
proof,
|
||||
ProgramProvingReport::new(proving_time),
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
info!("Verifying proof…");
|
||||
|
||||
let proof: SP1ProofWithPublicValues = bincode::deserialize(proof)
|
||||
let proof_kind = proof.kind();
|
||||
|
||||
let proof: SP1ProofWithPublicValues = bincode::deserialize(proof.as_bytes())
|
||||
.map_err(|err| SP1Error::Verify(VerifyError::Bincode(err)))?;
|
||||
let inner_proof_kind = SP1ProofMode::from(&proof.proof);
|
||||
|
||||
if !matches!(
|
||||
(proof_kind, inner_proof_kind),
|
||||
(ProofKind::Compressed, SP1ProofMode::Compressed)
|
||||
| (ProofKind::Groth16, SP1ProofMode::Groth16)
|
||||
) {
|
||||
return Err(SP1Error::Verify(VerifyError::InvalidProofKind(
|
||||
proof_kind,
|
||||
inner_proof_kind,
|
||||
)))?;
|
||||
}
|
||||
|
||||
let client = Self::create_client(&self.resource);
|
||||
client.verify(&proof, &self.vk).map_err(zkVMError::from)?;
|
||||
@@ -235,7 +258,7 @@ mod tests {
|
||||
use test_utils::host::{
|
||||
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
|
||||
};
|
||||
use zkvm_interface::{Compiler, NetworkProverConfig, ProverResourceType, zkVM};
|
||||
use zkvm_interface::{Compiler, NetworkProverConfig, ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
static BASIC_PROGRAM: OnceLock<Vec<u8>> = OnceLock::new();
|
||||
|
||||
@@ -296,7 +319,7 @@ mod tests {
|
||||
BasicProgramIo::invalid_type,
|
||||
BasicProgramIo::invalid_data,
|
||||
] {
|
||||
panic::catch_unwind(|| zkvm.prove(&inputs_gen())).unwrap_err();
|
||||
panic::catch_unwind(|| zkvm.prove(&inputs_gen(), ProofKind::default())).unwrap_err();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{io, path::PathBuf, process::ExitStatus};
|
||||
use thiserror::Error;
|
||||
use zkm_sdk::ZKMProofKind;
|
||||
use zkvm_interface::zkVMError;
|
||||
use zkvm_interface::{ProofKind, zkVMError};
|
||||
|
||||
impl From<ZirenError> for zkVMError {
|
||||
fn from(value: ZirenError) -> Self {
|
||||
@@ -78,8 +78,8 @@ pub enum VerifyError {
|
||||
#[error("Deserialising proof with `bincode` failed: {0}")]
|
||||
Bincode(#[from] bincode::Error),
|
||||
|
||||
#[error("Expect to get Compressed proof, but got: {}", 0.to_string())]
|
||||
InvalidProofKind(ZKMProofKind),
|
||||
#[error("Invalid proof kind, expected: {}, got: {}", 0.to_string(), 1.to_string() )]
|
||||
InvalidProofKind(ProofKind, ZKMProofKind),
|
||||
|
||||
#[error("Ziren verification failed: {0}")]
|
||||
Client(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
|
||||
|
||||
@@ -12,8 +12,8 @@ use zkm_sdk::{
|
||||
ZKMVerifyingKey,
|
||||
};
|
||||
use zkvm_interface::{
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType,
|
||||
PublicValues, zkVM, zkVMError,
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind,
|
||||
ProverResourceType, PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
@@ -64,38 +64,55 @@ impl zkVM for EreZiren {
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError> {
|
||||
info!("Generating proof…");
|
||||
|
||||
let mut stdin = ZKMStdin::new();
|
||||
serialize_inputs(&mut stdin, inputs);
|
||||
|
||||
let inner_proof_kind = match proof_kind {
|
||||
ProofKind::Compressed => ZKMProofKind::Compressed,
|
||||
ProofKind::Groth16 => ZKMProofKind::Groth16,
|
||||
};
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
let proof = CpuProver::new()
|
||||
.prove(&self.pk, stdin, ZKMProofKind::Compressed)
|
||||
.prove(&self.pk, stdin, inner_proof_kind)
|
||||
.map_err(|err| ZirenError::Prove(ProveError::Client(err.into())))?;
|
||||
let proving_time = start.elapsed();
|
||||
|
||||
let bytes = bincode::serialize(&proof)
|
||||
.map_err(|err| ZirenError::Prove(ProveError::Bincode(err)))?;
|
||||
let public_values = proof.public_values.to_vec();
|
||||
let proof = Proof::new(
|
||||
proof_kind,
|
||||
bincode::serialize(&proof)
|
||||
.map_err(|err| ZirenError::Prove(ProveError::Bincode(err)))?,
|
||||
);
|
||||
|
||||
Ok((
|
||||
proof.public_values.to_vec(),
|
||||
bytes,
|
||||
public_values,
|
||||
proof,
|
||||
ProgramProvingReport::new(proving_time),
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
info!("Verifying proof…");
|
||||
|
||||
let proof: ZKMProofWithPublicValues = bincode::deserialize(proof)
|
||||
.map_err(|err| ZirenError::Verify(VerifyError::Bincode(err)))?;
|
||||
let proof_kind = proof.kind();
|
||||
|
||||
let proof_kind = ZKMProofKind::from(&proof.proof);
|
||||
if !matches!(proof_kind, ZKMProofKind::Compressed) {
|
||||
let proof: ZKMProofWithPublicValues = bincode::deserialize(proof.as_bytes())
|
||||
.map_err(|err| ZirenError::Verify(VerifyError::Bincode(err)))?;
|
||||
let inner_proof_kind = ZKMProofKind::from(&proof.proof);
|
||||
|
||||
if !matches!(
|
||||
(proof_kind, inner_proof_kind),
|
||||
(ProofKind::Compressed, ZKMProofKind::Compressed)
|
||||
| (ProofKind::Groth16, ZKMProofKind::Groth16)
|
||||
) {
|
||||
return Err(ZirenError::Verify(VerifyError::InvalidProofKind(
|
||||
proof_kind,
|
||||
inner_proof_kind,
|
||||
)))?;
|
||||
}
|
||||
|
||||
@@ -137,7 +154,7 @@ mod tests {
|
||||
use test_utils::host::{
|
||||
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
|
||||
};
|
||||
use zkvm_interface::{Compiler, ProverResourceType, zkVM};
|
||||
use zkvm_interface::{Compiler, ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
static BASIC_PROGRAM: OnceLock<Vec<u8>> = OnceLock::new();
|
||||
|
||||
@@ -202,7 +219,7 @@ mod tests {
|
||||
BasicProgramIo::invalid_type,
|
||||
BasicProgramIo::invalid_data,
|
||||
] {
|
||||
panic::catch_unwind(|| zkvm.prove(&inputs_gen())).unwrap_err();
|
||||
panic::catch_unwind(|| zkvm.prove(&inputs_gen(), ProofKind::default())).unwrap_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::{
|
||||
use strum::{EnumIter, IntoEnumIterator};
|
||||
use tempfile::tempdir;
|
||||
use tracing::{error, info};
|
||||
use zkvm_interface::{Proof, ProverResourceType, PublicValues};
|
||||
use zkvm_interface::{ProverResourceType, PublicValues};
|
||||
|
||||
/// Merkle root of ROM trace generated by `cargo-zisk rom-setup`.
|
||||
pub type RomDigest = [u64; 4];
|
||||
@@ -379,7 +379,7 @@ impl ZiskServer {
|
||||
}
|
||||
|
||||
/// Send prove request to server and wait for proof to be created.
|
||||
pub fn prove(&mut self, input: &[u8]) -> Result<(PublicValues, Proof), ZiskError> {
|
||||
pub fn prove(&mut self, input: &[u8]) -> Result<(PublicValues, Vec<u8>), ZiskError> {
|
||||
// Prefix that ZisK server will add to the file name of the proof.
|
||||
// We use constant because the file will be save to a temporary dir,
|
||||
// so there will be no conflict.
|
||||
|
||||
@@ -12,8 +12,8 @@ use std::{
|
||||
time::Instant,
|
||||
};
|
||||
use zkvm_interface::{
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProverResourceType,
|
||||
PublicValues, zkVM, zkVMError,
|
||||
Input, InputItem, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind,
|
||||
ProverResourceType, PublicValues, zkVM, zkVMError,
|
||||
};
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
@@ -85,7 +85,12 @@ impl zkVM for EreZisk {
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, ProgramProvingReport), zkVMError> {
|
||||
if proof_kind != ProofKind::Compressed {
|
||||
panic!("Only Compressed proof kind is supported.");
|
||||
}
|
||||
|
||||
let mut server = self.server()?;
|
||||
let server = server.as_mut().expect("server initialized");
|
||||
|
||||
@@ -97,12 +102,16 @@ impl zkVM for EreZisk {
|
||||
|
||||
Ok((
|
||||
public_values,
|
||||
proof,
|
||||
Proof::Compressed(proof),
|
||||
ProgramProvingReport::new(proving_time),
|
||||
))
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &[u8]) -> Result<PublicValues, zkVMError> {
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError> {
|
||||
let Proof::Compressed(proof) = proof else {
|
||||
return Err(zkVMError::other("Only Compressed proof kind is supported."));
|
||||
};
|
||||
|
||||
Ok(self.sdk.verify(proof)?)
|
||||
}
|
||||
|
||||
@@ -142,7 +151,7 @@ mod tests {
|
||||
use test_utils::host::{
|
||||
BasicProgramIo, run_zkvm_execute, run_zkvm_prove, testing_guest_directory,
|
||||
};
|
||||
use zkvm_interface::{Compiler, ProverResourceType, zkVM};
|
||||
use zkvm_interface::{Compiler, ProofKind, ProverResourceType, zkVM};
|
||||
|
||||
/// It fails if multiple servers created concurrently using the same port,
|
||||
/// so we have a lock to avoid that.
|
||||
@@ -206,7 +215,7 @@ mod tests {
|
||||
BasicProgramIo::invalid_type(),
|
||||
BasicProgramIo::invalid_data(),
|
||||
] {
|
||||
zkvm.prove(&inputs).unwrap_err();
|
||||
zkvm.prove(&inputs, ProofKind::default()).unwrap_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::guest::{BasicProgramCore, BasicStruct};
|
||||
use rand::{Rng, rng};
|
||||
use std::{fmt::Debug, io::Read, marker::PhantomData, path::PathBuf};
|
||||
use zkvm_interface::{Input, PublicValues, zkVM};
|
||||
use zkvm_interface::{Input, ProofKind, PublicValues, zkVM};
|
||||
|
||||
fn workspace() -> PathBuf {
|
||||
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
@@ -36,7 +36,7 @@ pub fn run_zkvm_execute(zkvm: &impl zkVM, io: &impl Io) -> PublicValues {
|
||||
|
||||
pub fn run_zkvm_prove(zkvm: &impl zkVM, io: &impl Io) -> PublicValues {
|
||||
let (prover_public_values, proof, _report) = zkvm
|
||||
.prove(&io.inputs())
|
||||
.prove(&io.inputs(), ProofKind::default())
|
||||
.expect("prove should not fail with valid input");
|
||||
|
||||
let verifier_public_values = zkvm
|
||||
|
||||
@@ -10,6 +10,7 @@ auto_impl.workspace = true
|
||||
erased-serde.workspace = true
|
||||
indexmap = { workspace = true, features = ["serde"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
strum = { workspace = true, features = ["derive"] }
|
||||
thiserror.workspace = true
|
||||
|
||||
# Optional dependencies
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
#![allow(clippy::double_parens)]
|
||||
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
use std::{io::Read, path::Path};
|
||||
use strum::{EnumDiscriminants, EnumIs, EnumTryAs, FromRepr};
|
||||
use thiserror::Error;
|
||||
|
||||
mod input;
|
||||
@@ -13,7 +15,6 @@ pub use reports::{ProgramExecutionReport, ProgramProvingReport};
|
||||
mod network;
|
||||
pub use network::NetworkProverConfig;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Compiler trait for compiling programs into an opaque sequence of bytes.
|
||||
pub trait Compiler {
|
||||
type Error: std::error::Error + Send + Sync + 'static;
|
||||
@@ -97,7 +98,39 @@ 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>;
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, EnumDiscriminants, EnumIs, EnumTryAs)]
|
||||
#[strum_discriminants(derive(Default, FromRepr))]
|
||||
#[strum_discriminants(name(ProofKind))]
|
||||
pub enum Proof {
|
||||
/// Compressed proof in contant size regardless of the cycle count.
|
||||
#[strum_discriminants(default)]
|
||||
Compressed(Vec<u8>),
|
||||
/// Groth16 proof that internally verifies a Compressed proof.
|
||||
Groth16(Vec<u8>),
|
||||
}
|
||||
|
||||
impl Proof {
|
||||
/// Construct [`Proof`] from [`ProofKind`] and bytes.
|
||||
pub fn new(proof_kind: ProofKind, bytes: Vec<u8>) -> Self {
|
||||
match proof_kind {
|
||||
ProofKind::Compressed => Self::Compressed(bytes),
|
||||
ProofKind::Groth16 => Self::Groth16(bytes),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns [`ProofKind`].
|
||||
pub fn kind(&self) -> ProofKind {
|
||||
ProofKind::from(self)
|
||||
}
|
||||
|
||||
/// Returns inner proof as bytes.
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
match self {
|
||||
Self::Compressed(bytes) => bytes,
|
||||
Self::Groth16(bytes) => bytes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[auto_impl::auto_impl(&, Arc, Box)]
|
||||
@@ -118,12 +151,13 @@ pub trait zkVM {
|
||||
fn prove(
|
||||
&self,
|
||||
inputs: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> Result<(PublicValues, Proof, ProgramProvingReport), 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>;
|
||||
fn verify(&self, proof: &Proof) -> Result<PublicValues, zkVMError>;
|
||||
|
||||
/// Returns the name of the zkVM
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
@@ -34,6 +34,9 @@ ENV PATH=/usr/local/cargo/bin:$PATH
|
||||
# Copy Risc0 SDK
|
||||
COPY --from=build_stage /root/.risc0/extensions /root/.risc0/extensions
|
||||
|
||||
# Add Docker CLI (only needed for Groth16 proof kind)
|
||||
COPY --from=docker:cli /usr/local/bin/docker /usr/local/bin/docker
|
||||
|
||||
# Copy ere-server
|
||||
COPY --from=build_stage /ere/bin/ere-server /ere/bin/ere-server
|
||||
|
||||
|
||||
Reference in New Issue
Block a user