mirror of
https://github.com/eth-act/ere.git
synced 2026-04-03 03:00:17 -04:00
feat: Add ere-zisk with only compile and execute utility. (#27)
* feat: add `ere-zisk` and `compile` functionality * fix: use `FixintEncoding` for `Input::as_bytes` to make it deterministic * feat: implement `zkVM::execute` * fix: make `install_zisk_sdk.sh` work with docker * chore: add comment why use `#[should_panic]` * feat: use command `cargo-zisk ...` for `compile`, `execute`, `prove` and `verify` * ci * fix: invalid proof
This commit is contained in:
19
crates/ere-zisk/Cargo.toml
Normal file
19
crates/ere-zisk/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "ere-zisk"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
zkvm-interface = { workspace = true }
|
||||
thiserror = "2"
|
||||
toml = "0.8"
|
||||
tracing = "0.1"
|
||||
tempfile = "3.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
bincode = "1.3"
|
||||
|
||||
[lib]
|
||||
name = "ere_zisk"
|
||||
path = "src/lib.rs"
|
||||
158
crates/ere-zisk/src/compile.rs
Normal file
158
crates/ere-zisk/src/compile.rs
Normal file
@@ -0,0 +1,158 @@
|
||||
use crate::error::CompileError;
|
||||
use std::{
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
use toml::Value as TomlValue;
|
||||
use tracing::info;
|
||||
|
||||
/// Compile the guest crate and return raw ELF bytes.
|
||||
pub fn compile_zisk_program(program_crate_path: &Path) -> Result<PathBuf, CompileError> {
|
||||
info!("Compiling ZisK program at {}", program_crate_path.display());
|
||||
|
||||
if !program_crate_path.exists() || !program_crate_path.is_dir() {
|
||||
return Err(CompileError::InvalidProgramPath(
|
||||
program_crate_path.to_path_buf(),
|
||||
));
|
||||
}
|
||||
|
||||
let guest_manifest_path = program_crate_path.join("Cargo.toml");
|
||||
if !guest_manifest_path.exists() {
|
||||
return Err(CompileError::CargoTomlMissing {
|
||||
program_dir: program_crate_path.to_path_buf(),
|
||||
manifest_path: guest_manifest_path.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
// ── read + parse Cargo.toml ───────────────────────────────────────────
|
||||
let manifest_content =
|
||||
fs::read_to_string(&guest_manifest_path).map_err(|e| CompileError::ReadFile {
|
||||
path: guest_manifest_path.clone(),
|
||||
source: e,
|
||||
})?;
|
||||
|
||||
let manifest_toml: TomlValue =
|
||||
manifest_content
|
||||
.parse::<TomlValue>()
|
||||
.map_err(|e| CompileError::ParseCargoToml {
|
||||
path: guest_manifest_path.clone(),
|
||||
source: e,
|
||||
})?;
|
||||
|
||||
let program_name = manifest_toml
|
||||
.get("package")
|
||||
.and_then(|p| p.get("name"))
|
||||
.and_then(|n| n.as_str())
|
||||
.ok_or_else(|| CompileError::MissingPackageName {
|
||||
path: guest_manifest_path.clone(),
|
||||
})?;
|
||||
|
||||
info!("Parsed program name: {program_name}");
|
||||
|
||||
// ── build ─────────────────────────────────────────────────────────────
|
||||
let status = Command::new("cargo-zisk")
|
||||
.current_dir(program_crate_path)
|
||||
.args(["build", "--release"])
|
||||
.status()
|
||||
.map_err(|e| CompileError::CargoZiskBuild {
|
||||
cwd: program_crate_path.to_path_buf(),
|
||||
source: e,
|
||||
})?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(CompileError::CargoZiskBuildFailed {
|
||||
status,
|
||||
path: program_crate_path.to_path_buf(),
|
||||
});
|
||||
}
|
||||
|
||||
let elf_path = program_crate_path
|
||||
.join("target")
|
||||
.join("riscv64ima-zisk-zkvm-elf")
|
||||
.join("release")
|
||||
.join(program_name);
|
||||
let elf_path = elf_path
|
||||
.canonicalize()
|
||||
.map_err(|e| CompileError::ElfNotFound {
|
||||
path: elf_path,
|
||||
source: e,
|
||||
})?;
|
||||
|
||||
// FIXME: This currently uses global build directory `${HOME}/.zisk/zisk/emulator-asm`
|
||||
// which causes `compile_zisk_program` to panic if ran in parallel.
|
||||
// We should create a temporary directory and copy only necessary
|
||||
// data to setup each ELF.
|
||||
let status = Command::new("cargo-zisk")
|
||||
.current_dir(program_crate_path)
|
||||
.arg("rom-setup")
|
||||
.arg("-e")
|
||||
.arg(&elf_path)
|
||||
.status()
|
||||
.map_err(|e| CompileError::CargoZiskRomSetup { source: e })?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(CompileError::CargoZiskRomSetupFailed {
|
||||
status,
|
||||
path: program_crate_path.to_path_buf(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(elf_path)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use zkvm_interface::Compiler;
|
||||
|
||||
use crate::RV64_IMA_ZISK_ZKVM_ELF;
|
||||
|
||||
use super::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
// TODO: for now, we just get one test file
|
||||
// TODO: but this should get the whole directory and compile each test
|
||||
fn get_compile_test_guest_program_path() -> PathBuf {
|
||||
let workspace_dir = env!("CARGO_WORKSPACE_DIR");
|
||||
PathBuf::from(workspace_dir)
|
||||
.join("tests")
|
||||
.join("zisk")
|
||||
.join("compile")
|
||||
.join("basic")
|
||||
.canonicalize()
|
||||
.expect("Failed to find or canonicalize test guest program at <CARGO_WORKSPACE_DIR>/tests/compile/zisk")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compile_zisk_program() {
|
||||
let test_guest_path = get_compile_test_guest_program_path();
|
||||
|
||||
match compile_zisk_program(&test_guest_path) {
|
||||
Ok(elf_path) => {
|
||||
assert!(
|
||||
fs::metadata(elf_path).unwrap().len() != 0,
|
||||
"ELF bytes should not be empty."
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("compile failed for dedicated guest: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compile_trait() {
|
||||
let test_guest_path = get_compile_test_guest_program_path();
|
||||
match RV64_IMA_ZISK_ZKVM_ELF::compile(&test_guest_path) {
|
||||
Ok(elf_path) => {
|
||||
assert!(
|
||||
fs::metadata(elf_path).unwrap().len() != 0,
|
||||
"ELF bytes should not be empty."
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("compile_zisk_program direct call failed for dedicated guest: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
121
crates/ere-zisk/src/error.rs
Normal file
121
crates/ere-zisk/src/error.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
use std::{io, path::PathBuf, process::ExitStatus};
|
||||
use thiserror::Error;
|
||||
use zkvm_interface::zkVMError;
|
||||
|
||||
impl From<ZiskError> for zkVMError {
|
||||
fn from(value: ZiskError) -> Self {
|
||||
zkVMError::Other(Box::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ZiskError {
|
||||
#[error(transparent)]
|
||||
Compile(#[from] CompileError),
|
||||
|
||||
#[error(transparent)]
|
||||
Execute(#[from] ExecuteError),
|
||||
|
||||
#[error(transparent)]
|
||||
Prove(#[from] ProveError),
|
||||
|
||||
#[error(transparent)]
|
||||
Verify(#[from] VerifyError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CompileError {
|
||||
#[error("Program path does not exist or is not a directory: {0}")]
|
||||
InvalidProgramPath(PathBuf),
|
||||
#[error(
|
||||
"Cargo.toml not found in program directory: {program_dir}. Expected at: {manifest_path}"
|
||||
)]
|
||||
CargoTomlMissing {
|
||||
program_dir: PathBuf,
|
||||
manifest_path: PathBuf,
|
||||
},
|
||||
#[error("Could not find `[package].name` in guest Cargo.toml at {path}")]
|
||||
MissingPackageName { path: PathBuf },
|
||||
#[error("Compiled ELF not found at expected path: {path}")]
|
||||
ElfNotFound {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("Failed to read file at {path}: {source}")]
|
||||
ReadFile {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("Failed to parse guest Cargo.toml at {path}: {source}")]
|
||||
ParseCargoToml {
|
||||
path: PathBuf,
|
||||
#[source]
|
||||
source: toml::de::Error,
|
||||
},
|
||||
#[error("Failed to execute `cargo-zisk build --release` in {cwd}: {source}")]
|
||||
CargoZiskBuild {
|
||||
cwd: PathBuf,
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("`cargo-zisk build --release` failed with status: {status} for program at {path}")]
|
||||
CargoZiskBuildFailed { status: ExitStatus, path: PathBuf },
|
||||
#[error("Failed to execute `cargo-zisk rom-setup`: {source}")]
|
||||
CargoZiskRomSetup {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("`cargo-zisk rom-setup` failed with status: {status} for program at {path}")]
|
||||
CargoZiskRomSetupFailed { status: ExitStatus, path: PathBuf },
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ExecuteError {
|
||||
#[error("IO failure: {0}")]
|
||||
Io(io::Error),
|
||||
#[error("Failed to serialize input: {0}")]
|
||||
SerializeInput(Box<dyn std::error::Error + Send + Sync>),
|
||||
#[error("Failed to execute `ziskemu`: {source}")]
|
||||
Ziskemu {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("`ziskemu` failed with status: {status}")]
|
||||
ZiskemuFailed { status: ExitStatus },
|
||||
#[error("Total steps not found in report")]
|
||||
TotalStepsNotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ProveError {
|
||||
#[error("IO failure: {0}")]
|
||||
Io(io::Error),
|
||||
#[error("Failed to serialize input: {0}")]
|
||||
SerializeInput(Box<dyn std::error::Error + Send + Sync>),
|
||||
#[error("Failed to execute `cargo prove`: {source}")]
|
||||
CargoZiskProve {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("`cargo prove` failed with status: {status}")]
|
||||
CargoZiskProveFailed { status: ExitStatus },
|
||||
#[error("Serialising proof with `bincode` failed: {0}")]
|
||||
Bincode(#[from] bincode::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum VerifyError {
|
||||
#[error("IO failure: {0}")]
|
||||
Io(io::Error),
|
||||
#[error("Deserialising proof with `bincode` failed: {0}")]
|
||||
Bincode(#[from] bincode::Error),
|
||||
#[error("Failed to execute `cargo-zisk verify`: {source}")]
|
||||
CargoZiskVerify {
|
||||
#[source]
|
||||
source: io::Error,
|
||||
},
|
||||
#[error("Invalid proof: {0}")]
|
||||
InvalidProof(String),
|
||||
}
|
||||
339
crates/ere-zisk/src/lib.rs
Normal file
339
crates/ere-zisk/src/lib.rs
Normal file
@@ -0,0 +1,339 @@
|
||||
use crate::{
|
||||
compile::compile_zisk_program,
|
||||
error::{ExecuteError, ProveError, VerifyError, ZiskError},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
fs,
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
time,
|
||||
};
|
||||
use tempfile::tempdir;
|
||||
use zkvm_interface::{
|
||||
Compiler, Input, ProgramExecutionReport, ProgramProvingReport, ProverResourceType, zkVM,
|
||||
zkVMError,
|
||||
};
|
||||
|
||||
mod compile;
|
||||
mod error;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct RV64_IMA_ZISK_ZKVM_ELF;
|
||||
|
||||
impl Compiler for RV64_IMA_ZISK_ZKVM_ELF {
|
||||
type Error = ZiskError;
|
||||
|
||||
/// Path to compiled ELF.
|
||||
type Program = PathBuf;
|
||||
|
||||
fn compile(path_to_program: &Path) -> Result<Self::Program, Self::Error> {
|
||||
compile_zisk_program(path_to_program).map_err(ZiskError::Compile)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ZiskProofWithPublicValues {
|
||||
/// The raw aggregated proof generated by the ZisK zkVM.
|
||||
pub proof: Vec<u8>,
|
||||
/// The public values generated by the ZisK zkVM.
|
||||
pub public_values: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct EreZisk {
|
||||
elf_path: PathBuf,
|
||||
resource: ProverResourceType,
|
||||
}
|
||||
|
||||
impl EreZisk {
|
||||
pub fn new(elf_path: PathBuf, resource: ProverResourceType) -> Self {
|
||||
Self { elf_path, resource }
|
||||
}
|
||||
}
|
||||
|
||||
impl EreZisk {}
|
||||
|
||||
impl zkVM for EreZisk {
|
||||
fn execute(&self, input: &Input) -> Result<ProgramExecutionReport, zkVMError> {
|
||||
let input_bytes = input
|
||||
.iter()
|
||||
.try_fold(Vec::new(), |mut acc, item| {
|
||||
acc.extend(item.as_bytes().map_err(ExecuteError::SerializeInput)?);
|
||||
Ok(acc)
|
||||
})
|
||||
.map_err(ZiskError::Execute)?;
|
||||
|
||||
let output_dir = tempdir().map_err(|e| ZiskError::Execute(ExecuteError::Io(e)))?;
|
||||
let input_path = input_path(output_dir.path());
|
||||
|
||||
fs::File::create(&input_path)
|
||||
.and_then(|mut file| file.write_all(&input_bytes))
|
||||
.map_err(|e| ZiskError::Execute(ExecuteError::Io(e)))?;
|
||||
|
||||
let output = Command::new("ziskemu")
|
||||
.arg("-e")
|
||||
.arg(&self.elf_path)
|
||||
.arg("-i")
|
||||
.arg(&input_path)
|
||||
.arg("-x")
|
||||
.stderr(Stdio::inherit())
|
||||
.output()
|
||||
.map_err(|e| ZiskError::Execute(ExecuteError::Ziskemu { source: e }))?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(ZiskError::Execute(ExecuteError::ZiskemuFailed {
|
||||
status: output.status,
|
||||
})
|
||||
.into());
|
||||
}
|
||||
|
||||
let total_num_cycles = String::from_utf8_lossy(&output.stdout)
|
||||
.split_once("total steps = ")
|
||||
.and_then(|(_, stats)| {
|
||||
stats
|
||||
.split_whitespace()
|
||||
.next()
|
||||
.and_then(|steps| steps.parse::<u64>().ok())
|
||||
})
|
||||
.ok_or(ZiskError::Execute(ExecuteError::TotalStepsNotFound))?;
|
||||
|
||||
Ok(ProgramExecutionReport::new(total_num_cycles))
|
||||
}
|
||||
|
||||
fn prove(&self, input: &Input) -> Result<(Vec<u8>, ProgramProvingReport), zkVMError> {
|
||||
let input_bytes = input
|
||||
.iter()
|
||||
.try_fold(Vec::new(), |mut acc, item| {
|
||||
acc.extend(item.as_bytes().map_err(ProveError::SerializeInput)?);
|
||||
Ok(acc)
|
||||
})
|
||||
.map_err(ZiskError::Prove)?;
|
||||
|
||||
let output_dir = tempdir().map_err(|e| ZiskError::Prove(ProveError::Io(e)))?;
|
||||
let input_path = input_path(output_dir.path());
|
||||
let proof_path = proof_path(output_dir.path());
|
||||
let public_values_path = public_values_path(output_dir.path());
|
||||
|
||||
fs::File::create(&input_path)
|
||||
.and_then(|mut file| file.write_all(&input_bytes))
|
||||
.map_err(|e| ZiskError::Prove(ProveError::Io(e)))?;
|
||||
|
||||
let start = time::Instant::now();
|
||||
match self.resource {
|
||||
ProverResourceType::Cpu => {
|
||||
let status = Command::new("cargo-zisk")
|
||||
.arg("prove")
|
||||
.arg("-e")
|
||||
.arg(&self.elf_path)
|
||||
.arg("-i")
|
||||
.arg(&input_path)
|
||||
.arg("-o")
|
||||
.arg(output_dir.path())
|
||||
// FIXME: Not sure why if we don't set the flag `aggregation`
|
||||
// there will be no proof, but ideally we should
|
||||
// only generate the core proof as other zkVMs.
|
||||
.arg("-a")
|
||||
.status()
|
||||
.map_err(|e| ZiskError::Prove(ProveError::CargoZiskProve { source: e }))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(
|
||||
ZiskError::Prove(ProveError::CargoZiskProveFailed { status }).into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
ProverResourceType::Gpu => {
|
||||
// TODO: Need to install another version of `cargo-zisk` with
|
||||
// `features = gpu` and call it here.
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
let proving_time = start.elapsed();
|
||||
|
||||
let proof_with_public_values = ZiskProofWithPublicValues {
|
||||
proof: fs::read(proof_path).map_err(|e| ZiskError::Prove(ProveError::Io(e)))?,
|
||||
public_values: fs::read(public_values_path)
|
||||
.map_err(|e| ZiskError::Prove(ProveError::Io(e)))?,
|
||||
};
|
||||
let bytes = bincode::serialize(&proof_with_public_values)
|
||||
.map_err(|err| ZiskError::Prove(ProveError::Bincode(err)))?;
|
||||
|
||||
Ok((bytes, ProgramProvingReport::new(proving_time)))
|
||||
}
|
||||
|
||||
fn verify(&self, bytes: &[u8]) -> Result<(), zkVMError> {
|
||||
let proof_with_public_values: ZiskProofWithPublicValues = bincode::deserialize(bytes)
|
||||
.map_err(|err| ZiskError::Verify(VerifyError::Bincode(err)))?;
|
||||
|
||||
let output_dir = tempdir().map_err(|e| ZiskError::Verify(VerifyError::Io(e)))?;
|
||||
let proof_path = proof_path(output_dir.path());
|
||||
let public_values_path = public_values_path(output_dir.path());
|
||||
fs::create_dir_all(proof_dir(output_dir.path()))
|
||||
.map_err(|e| ZiskError::Verify(VerifyError::Io(e)))?;
|
||||
|
||||
fs::File::create(&proof_path)
|
||||
.and_then(|mut file| file.write_all(&proof_with_public_values.proof))
|
||||
.map_err(|e| ZiskError::Verify(VerifyError::Io(e)))?;
|
||||
fs::File::create(&public_values_path)
|
||||
.and_then(|mut file| file.write_all(&proof_with_public_values.public_values))
|
||||
.map_err(|e| ZiskError::Verify(VerifyError::Io(e)))?;
|
||||
|
||||
let output = Command::new("cargo-zisk")
|
||||
.arg("verify")
|
||||
.arg("-p")
|
||||
.arg(&proof_path)
|
||||
.arg("-u")
|
||||
.arg(&public_values_path)
|
||||
.output()
|
||||
.map_err(|e| ZiskError::Verify(VerifyError::CargoZiskVerify { source: e }))?;
|
||||
|
||||
if !output.status.success() {
|
||||
return Err(ZiskError::Verify(VerifyError::InvalidProof(
|
||||
String::from_utf8_lossy(&output.stderr).to_string(),
|
||||
))
|
||||
.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn input_path(dir: impl AsRef<Path>) -> PathBuf {
|
||||
dir.as_ref().join("input.bin")
|
||||
}
|
||||
|
||||
fn proof_dir(dir: impl AsRef<Path>) -> PathBuf {
|
||||
dir.as_ref().join("proofs")
|
||||
}
|
||||
|
||||
fn proof_path(dir: impl AsRef<Path>) -> PathBuf {
|
||||
proof_dir(dir).join("vadcop_final_proof.json")
|
||||
}
|
||||
|
||||
fn public_values_path(dir: impl AsRef<Path>) -> PathBuf {
|
||||
dir.as_ref().join("publics.json")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod execute_tests {
|
||||
use super::*;
|
||||
|
||||
fn get_compiled_test_zisk_elf() -> Result<PathBuf, ZiskError> {
|
||||
let test_guest_path = get_execute_test_guest_program_path();
|
||||
RV64_IMA_ZISK_ZKVM_ELF::compile(&test_guest_path)
|
||||
}
|
||||
|
||||
fn get_execute_test_guest_program_path() -> PathBuf {
|
||||
let workspace_dir = env!("CARGO_WORKSPACE_DIR");
|
||||
PathBuf::from(workspace_dir)
|
||||
.join("tests")
|
||||
.join("zisk")
|
||||
.join("execute")
|
||||
.join("basic")
|
||||
.canonicalize()
|
||||
.expect("Failed to find or canonicalize test guest program at <CARGO_WORKSPACE_DIR>/tests/execute/zisk")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_execute_zisk_dummy_input() {
|
||||
let elf_path = get_compiled_test_zisk_elf()
|
||||
.expect("Failed to compile test ZisK guest for execution test");
|
||||
|
||||
let mut input_builder = Input::new();
|
||||
let n: u32 = 42;
|
||||
let a: u16 = 42;
|
||||
input_builder.write(n);
|
||||
input_builder.write(a);
|
||||
|
||||
let zkvm = EreZisk::new(elf_path, ProverResourceType::Cpu);
|
||||
|
||||
let result = zkvm.execute(&input_builder);
|
||||
|
||||
if let Err(e) = &result {
|
||||
panic!("Execution error: {e:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_execute_zisk_no_input_for_guest_expecting_input() {
|
||||
let elf_path = get_compiled_test_zisk_elf()
|
||||
.expect("Failed to compile test ZisK guest for execution test");
|
||||
|
||||
let empty_input = Input::new();
|
||||
|
||||
let zkvm = EreZisk::new(elf_path, ProverResourceType::Cpu);
|
||||
assert!(zkvm.execute(&empty_input).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod prove_tests {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::*;
|
||||
use zkvm_interface::Input;
|
||||
|
||||
fn get_prove_test_guest_program_path() -> PathBuf {
|
||||
let workspace_dir = env!("CARGO_WORKSPACE_DIR");
|
||||
PathBuf::from(workspace_dir)
|
||||
.join("tests")
|
||||
.join("zisk")
|
||||
.join("prove")
|
||||
.join("basic")
|
||||
.canonicalize()
|
||||
.expect("Failed to find or canonicalize test guest program at <CARGO_WORKSPACE_DIR>/tests/execute/zisk")
|
||||
}
|
||||
|
||||
fn get_compiled_test_zisk_elf_for_prove() -> Result<PathBuf, ZiskError> {
|
||||
let test_guest_path = get_prove_test_guest_program_path();
|
||||
RV64_IMA_ZISK_ZKVM_ELF::compile(&test_guest_path)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prove_zisk_dummy_input() {
|
||||
let elf_path = get_compiled_test_zisk_elf_for_prove()
|
||||
.expect("Failed to compile test ZisK guest for proving test");
|
||||
|
||||
let mut input_builder = Input::new();
|
||||
let n: u32 = 42;
|
||||
let a: u16 = 42;
|
||||
input_builder.write(n);
|
||||
input_builder.write(a);
|
||||
|
||||
let zkvm = EreZisk::new(elf_path, ProverResourceType::Cpu);
|
||||
|
||||
let proof_bytes = match zkvm.prove(&input_builder) {
|
||||
Ok((prove_result, _)) => prove_result,
|
||||
Err(err) => {
|
||||
panic!("Proving error in test: {err:?}");
|
||||
}
|
||||
};
|
||||
|
||||
assert!(!proof_bytes.is_empty(), "Proof bytes should not be empty.");
|
||||
|
||||
assert!(zkvm.verify(&proof_bytes).is_ok());
|
||||
|
||||
let invalid_proof_bytes = {
|
||||
let mut invalid_proof: ZiskProofWithPublicValues =
|
||||
bincode::deserialize(&proof_bytes).unwrap();
|
||||
// alter the first digit of `evals[0][0]`
|
||||
invalid_proof.proof[40] = invalid_proof.proof[40].overflowing_add(1).0;
|
||||
bincode::serialize(&invalid_proof).unwrap()
|
||||
};
|
||||
assert!(zkvm.verify(&invalid_proof_bytes).is_err());
|
||||
|
||||
// TODO: Check public inputs
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_prove_zisk_fails_on_bad_input_causing_execution_failure() {
|
||||
let elf_path = get_compiled_test_zisk_elf_for_prove()
|
||||
.expect("Failed to compile test ZisK guest for proving test");
|
||||
|
||||
let empty_input = Input::new();
|
||||
|
||||
let zkvm = EreZisk::new(elf_path, ProverResourceType::Cpu);
|
||||
assert!(zkvm.prove(&empty_input).is_err());
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
use bincode::Options;
|
||||
use erased_serde::Serialize as ErasedSerialize;
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -69,12 +70,14 @@ impl InputItem {
|
||||
}
|
||||
|
||||
/// Get the item as bytes (serialize objects, return bytes directly)
|
||||
pub fn as_bytes(&self) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
pub fn as_bytes(&self) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
match self {
|
||||
InputItem::Object(obj) => {
|
||||
let mut buf = Vec::new();
|
||||
let mut serializer =
|
||||
bincode::Serializer::new(&mut buf, bincode::DefaultOptions::new());
|
||||
let mut serializer = bincode::Serializer::new(
|
||||
&mut buf,
|
||||
bincode::DefaultOptions::new().with_fixint_encoding(),
|
||||
);
|
||||
erased_serde::serialize(obj.as_ref(), &mut serializer)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user