diff --git a/.github/workflows/check_zisk_image.yml b/.github/workflows/check_zisk_image.yml index 0fea397..cc0d773 100644 --- a/.github/workflows/check_zisk_image.yml +++ b/.github/workflows/check_zisk_image.yml @@ -1,36 +1,36 @@ name: Check ZisK Docker Image -# on: -# push: -# branches: -# - master -# pull_request: -# branches: -# - master -# workflow_dispatch: +on: + push: + branches: + - master + pull_request: + branches: + - master + workflow_dispatch: -# jobs: -# build_zisk_image: -# name: Build ZisK Docker Image -# runs-on: ubuntu-latest +jobs: + build_zisk_image: + name: Build ZisK Docker Image + runs-on: ubuntu-latest -# steps: -# - name: Checkout repository -# uses: actions/checkout@v4 + steps: + - name: Checkout repository + uses: actions/checkout@v4 -# - name: Set up Docker Buildx -# uses: docker/setup-buildx-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 -# - name: Build dependent Docker base image -# run: | -# docker build \ -# --file docker/base/Dockerfile.base \ -# --tag ere-base:latest \ -# . + - name: Build dependent Docker base image + run: | + docker build \ + --file docker/base/Dockerfile.base \ + --tag ere-base:latest \ + . -# - name: Build ZisK Docker image -# run: | -# docker build \ -# --file docker/zisk/Dockerfile \ -# --tag ere-builder-zisk-check:latest \ -# . \ No newline at end of file + - name: Build ZisK Docker image + run: | + docker build \ + --file docker/zisk/Dockerfile \ + --tag ere-builder-zisk-check:latest \ + . \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index bf52b74..c28e3a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1193,7 +1193,7 @@ dependencies = [ "bitflags 2.9.0", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.11.0", "log", "prettyplease", "proc-macro2", @@ -2630,6 +2630,19 @@ dependencies = [ "zkvm-interface", ] +[[package]] +name = "ere-zisk" +version = "0.1.0" +dependencies = [ + "bincode", + "serde", + "tempfile", + "thiserror 2.0.12", + "toml", + "tracing", + "zkvm-interface", +] + [[package]] name = "errno" version = "0.3.11" @@ -2637,7 +2650,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -7142,7 +7155,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.101", @@ -7235,7 +7248,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b304e2d..f02f338 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "crates/ere-openvm", "crates/ere-pico", "crates/ere-jolt", + "crates/ere-zisk", ] resolver = "2" diff --git a/crates/ere-zisk/Cargo.toml b/crates/ere-zisk/Cargo.toml new file mode 100644 index 0000000..07ad51b --- /dev/null +++ b/crates/ere-zisk/Cargo.toml @@ -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" diff --git a/crates/ere-zisk/src/compile.rs b/crates/ere-zisk/src/compile.rs new file mode 100644 index 0000000..ea76188 --- /dev/null +++ b/crates/ere-zisk/src/compile.rs @@ -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 { + 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::() + .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 /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:?}"); + } + } + } +} diff --git a/crates/ere-zisk/src/error.rs b/crates/ere-zisk/src/error.rs new file mode 100644 index 0000000..83e529e --- /dev/null +++ b/crates/ere-zisk/src/error.rs @@ -0,0 +1,121 @@ +use std::{io, path::PathBuf, process::ExitStatus}; +use thiserror::Error; +use zkvm_interface::zkVMError; + +impl From 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), + #[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), + #[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), +} diff --git a/crates/ere-zisk/src/lib.rs b/crates/ere-zisk/src/lib.rs new file mode 100644 index 0000000..759e27f --- /dev/null +++ b/crates/ere-zisk/src/lib.rs @@ -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 { + 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, + /// The public values generated by the ZisK zkVM. + pub public_values: Vec, +} + +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 { + 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::().ok()) + }) + .ok_or(ZiskError::Execute(ExecuteError::TotalStepsNotFound))?; + + Ok(ProgramExecutionReport::new(total_num_cycles)) + } + + fn prove(&self, input: &Input) -> Result<(Vec, 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) -> PathBuf { + dir.as_ref().join("input.bin") +} + +fn proof_dir(dir: impl AsRef) -> PathBuf { + dir.as_ref().join("proofs") +} + +fn proof_path(dir: impl AsRef) -> PathBuf { + proof_dir(dir).join("vadcop_final_proof.json") +} + +fn public_values_path(dir: impl AsRef) -> PathBuf { + dir.as_ref().join("publics.json") +} + +#[cfg(test)] +mod execute_tests { + use super::*; + + fn get_compiled_test_zisk_elf() -> Result { + 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 /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 /tests/execute/zisk") + } + + fn get_compiled_test_zisk_elf_for_prove() -> Result { + 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()); + } +} diff --git a/crates/zkvm-interface/src/input.rs b/crates/zkvm-interface/src/input.rs index 3d22f8d..c098baa 100644 --- a/crates/zkvm-interface/src/input.rs +++ b/crates/zkvm-interface/src/input.rs @@ -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, Box> { + pub fn as_bytes(&self) -> Result, Box> { 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) } diff --git a/docker/zisk/Dockerfile b/docker/zisk/Dockerfile index cda85c9..762a5e3 100644 --- a/docker/zisk/Dockerfile +++ b/docker/zisk/Dockerfile @@ -40,13 +40,13 @@ RUN chmod +x /tmp/install_zisk_sdk.sh RUN /tmp/install_zisk_sdk.sh && rm /tmp/install_zisk_sdk.sh # Clean up the script # The 'zisk' Rust toolchain is now installed. -# cargo-zisk is installed in $HOME/.zisk/bin. -# The install_zisk_sdk.sh script adds $HOME/.zisk/bin to PATH for its session. -# For the image environment, we need to ensure $HOME/.zisk/bin is persistently in PATH. -ENV ZISK_TOOLS_BIN_DIR="${HOME}/.zisk/bin" -ENV PATH="${ZISK_TOOLS_BIN_DIR}:${PATH}" +# cargo-zisk is installed in /root/.zisk/bin. +# The ziskup script adds /root/.zisk/bin to PATH for its session. +# For the image environment, we need to ensure /root/.zisk/bin is persistently in PATH. +ENV ZISK_BIN_DIR="/root/.zisk/bin" +ENV PATH="${PATH}:${ZISK_BIN_DIR}" # Verify cargo-zisk is accessible -RUN echo "Verifying Zisk installation in Dockerfile ..." && cargo +zisk zisk --version +RUN echo "Verifying Zisk installation in Dockerfile ..." && cargo-zisk --version CMD ["/bin/bash"] \ No newline at end of file diff --git a/scripts/sdk_installers/install_zisk_sdk.sh b/scripts/sdk_installers/install_zisk_sdk.sh index e4db288..21ff362 100755 --- a/scripts/sdk_installers/install_zisk_sdk.sh +++ b/scripts/sdk_installers/install_zisk_sdk.sh @@ -31,32 +31,14 @@ ensure_tool_installed "rustup" "for managing Rust toolchains (ZisK installs its ensure_tool_installed "cargo" "as cargo-zisk is a cargo subcommand" # Step 1: Download and run the script that installs the ziskup binary itself. -ZISKUP_INSTALLER_DOWNLOAD_PATH="/tmp/ziskup_install.sh" -echo "Downloading the script that installs the 'ziskup' binary to ${ZISKUP_INSTALLER_DOWNLOAD_PATH}..." -curl -L https://raw.githubusercontent.com/0xPolygonHermez/zisk/main/ziskup/install.sh -o "${ZISKUP_INSTALLER_DOWNLOAD_PATH}" -chmod +x "${ZISKUP_INSTALLER_DOWNLOAD_PATH}" - -echo "Running the 'ziskup' binary installer script..." -"${ZISKUP_INSTALLER_DOWNLOAD_PATH}" # This script installs $HOME/.zisk/bin/ziskup -rm "${ZISKUP_INSTALLER_DOWNLOAD_PATH}" # Clean up the downloaded installer script - -# Step 2: Ensure the installed ziskup binary is in PATH for this script session. -ZISK_BIN_DIR="${HOME}/.zisk/bin" -if [ -d "${ZISK_BIN_DIR}" ] && [[ ":$PATH:" != *":${ZISK_BIN_DIR}:"* ]]; then - echo "Adding ${ZISK_BIN_DIR} to PATH for current script session." - export PATH="${ZISK_BIN_DIR}:$PATH" -fi - -# Ensure the ziskup binary itself is now installed and executable -ensure_tool_installed "ziskup" "ZisK SDK manager tool" - -# Step 3: Now run the installed ziskup binary with non-interactive flags. -echo "Running 'ziskup --provingkey' to install ZisK components..." # Export GH_RUNNER=true to ensure ziskup uses default non-interactive options. export GH_RUNNER=true -ziskup --provingkey # This is the actual ziskup tool that processes --provingkey +curl https://raw.githubusercontent.com/0xPolygonHermez/zisk/main/ziskup/install.sh | bash unset GH_RUNNER +# Step 2: Ensure the installed cargo-zisk binary is in PATH for this script session. +export PATH="${PATH}:${HOME}/.zisk/bin" + # Verify ZisK installation echo "Verifying ZisK installation..." @@ -76,16 +58,16 @@ else fi echo "Checking for cargo-zisk CLI tool (using +zisk toolchain)..." -# cargo-zisk should be callable via `cargo +zisk zisk ...` -if cargo +zisk zisk --version; then +# cargo-zisk should be callable via `cargo-zisk ...` +if cargo-zisk --version; then echo "cargo-zisk CLI tool verified successfully." else - echo "Error: 'cargo +zisk zisk --version' failed." >&2 + echo "Error: 'cargo-zisk --version' failed." >&2 echo " Attempting verification with cargo-zisk directly (if in PATH from ${ZISK_BIN_DIR})..." if command -v cargo-zisk &> /dev/null && cargo-zisk --version; then echo "cargo-zisk found directly in PATH and verified." else - echo "Error: cargo-zisk also not found directly or 'cargo +zisk zisk --version' failed." >&2 + echo "Error: cargo-zisk also not found directly or 'cargo-zisk --version' failed." >&2 echo " Ensure ${ZISK_BIN_DIR} is effectively in PATH for new shells and check ziskup output." >&2 exit 1 fi diff --git a/tests/zisk/compile/basic/Cargo.toml b/tests/zisk/compile/basic/Cargo.toml new file mode 100644 index 0000000..ee0a9f2 --- /dev/null +++ b/tests/zisk/compile/basic/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ere-test-zisk-guest" +version = "0.1.0" +edition = "2021" + +[workspace] + +[dependencies] +ziskos = { git = "https://github.com/0xPolygonHermez/zisk.git", rev = "f9a3655" } diff --git a/tests/zisk/compile/basic/src/main.rs b/tests/zisk/compile/basic/src/main.rs new file mode 100644 index 0000000..51730e7 --- /dev/null +++ b/tests/zisk/compile/basic/src/main.rs @@ -0,0 +1,14 @@ +#![no_main] + +ziskos::entrypoint!(main); + +fn main() { + // Read an input + let n = u32::from_le_bytes( + ziskos::read_input() + .try_into() + .expect("input to be 4 bytes"), + ); + // Write n*2 to output + ziskos::set_output(0, n * 2); +} diff --git a/tests/zisk/execute/basic/Cargo.toml b/tests/zisk/execute/basic/Cargo.toml new file mode 100644 index 0000000..ee0a9f2 --- /dev/null +++ b/tests/zisk/execute/basic/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ere-test-zisk-guest" +version = "0.1.0" +edition = "2021" + +[workspace] + +[dependencies] +ziskos = { git = "https://github.com/0xPolygonHermez/zisk.git", rev = "f9a3655" } diff --git a/tests/zisk/execute/basic/src/main.rs b/tests/zisk/execute/basic/src/main.rs new file mode 100644 index 0000000..e3dad2a --- /dev/null +++ b/tests/zisk/execute/basic/src/main.rs @@ -0,0 +1,16 @@ +#![no_main] + +ziskos::entrypoint!(main); + +fn main() { + let input = ziskos::read_input(); + if input.len() != 6 { + std::process::exit(1); + } + + // Read an input + let n = u32::from_le_bytes(input[..4].try_into().unwrap()); + let a = u16::from_le_bytes(input[4..6].try_into().unwrap()) as u32; + + ziskos::set_output(0, (n + a) * 2); +} diff --git a/tests/zisk/prove/basic/Cargo.toml b/tests/zisk/prove/basic/Cargo.toml new file mode 100644 index 0000000..ee0a9f2 --- /dev/null +++ b/tests/zisk/prove/basic/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ere-test-zisk-guest" +version = "0.1.0" +edition = "2021" + +[workspace] + +[dependencies] +ziskos = { git = "https://github.com/0xPolygonHermez/zisk.git", rev = "f9a3655" } diff --git a/tests/zisk/prove/basic/src/main.rs b/tests/zisk/prove/basic/src/main.rs new file mode 100644 index 0000000..e3dad2a --- /dev/null +++ b/tests/zisk/prove/basic/src/main.rs @@ -0,0 +1,16 @@ +#![no_main] + +ziskos::entrypoint!(main); + +fn main() { + let input = ziskos::read_input(); + if input.len() != 6 { + std::process::exit(1); + } + + // Read an input + let n = u32::from_le_bytes(input[..4].try_into().unwrap()); + let a = u16::from_le_bytes(input[4..6].try_into().unwrap()) as u32; + + ziskos::set_output(0, (n + a) * 2); +}