diff --git a/ci_scripts/test-ubuntu.sh b/ci_scripts/test-ubuntu.sh index 78761df..2aeba86 100755 --- a/ci_scripts/test-ubuntu.sh +++ b/ci_scripts/test-ubuntu.sh @@ -4,7 +4,7 @@ curl -L https://risczero.com/install | bash /home/runner/.risc0/bin/rzup install source env.sh -RISC0_DEV_MODE=1 cargo test --release +RISC0_DEV_MODE=1 cargo test --release --features no_docker cd integration_tests export NSSA_WALLET_HOME_DIR=$(pwd)/configs/debug/wallet/ diff --git a/common/src/transaction.rs b/common/src/transaction.rs index fd38138..5332e5c 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -1,11 +1,8 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use generic_array::GenericArray; use k256::ecdsa::{Signature, SigningKey, VerifyingKey}; use log::info; use serde::{Deserialize, Serialize}; -use sha2::digest::typenum::{B0, B1}; -use sha2::digest::typenum::{UInt, UTerm}; use sha2::{Digest, digest::FixedOutput}; #[derive(Debug, Clone, PartialEq, Eq)] @@ -29,7 +26,6 @@ impl From for NSSATransaction { use crate::TreeHashType; pub type CipherText = Vec; -pub type Nonce = GenericArray, B1>, B0>, B0>>; pub type Tag = u8; #[derive( diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index db2dfeb..f7bd131 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -36,3 +36,4 @@ path = "../common" [dependencies.nssa] path = "../nssa" +features = ["no_docker"] diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index 93553a8..a86bd98 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -7,7 +7,7 @@ edition = "2024" thiserror = "2.0.12" risc0-zkvm = { version = "3.0.3", features = ['std'] } nssa-core = { path = "core", features = ["host"] } -program-methods = { path = "program_methods" } +program-methods = { path = "program_methods", optional = true } serde = "1.0.219" sha2 = "0.10.9" secp256k1 = "0.31.1" @@ -15,9 +15,14 @@ rand = "0.8" borsh = "1.5.7" hex = "0.4.3" +[build-dependencies] +risc0-build = "3.0.3" +risc0-binfmt = "3.0.2" + [dev-dependencies] test-program-methods = { path = "test_program_methods" } hex-literal = "1.0.0" [features] default = [] +no_docker = ["program-methods"] diff --git a/nssa/build.rs b/nssa/build.rs new file mode 100644 index 0000000..cc4608e --- /dev/null +++ b/nssa/build.rs @@ -0,0 +1,63 @@ +fn main() { + if cfg!(feature = "no_docker") { + println!("cargo:warning=NO_DOCKER feature enabled – deterministic build skipped"); + return; + } + + build_deterministic().expect("Deterministic build failed"); +} + +fn build_deterministic() -> Result<(), Box> { + use std::{env, fs, path::PathBuf, process::Command}; + + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?); + let out_dir = PathBuf::from(env::var("OUT_DIR")?); + let mod_dir = out_dir.join("program_methods"); + let mod_file = mod_dir.join("mod.rs"); + + println!("cargo:rerun-if-changed=program_methods/guest/src"); + println!("cargo:rerun-if-changed=program_methods/guest/Cargo.toml"); + + let guest_manifest = manifest_dir.join("program_methods/guest/Cargo.toml"); + + let status = Command::new("cargo") + .args(["risczero", "build", "--manifest-path"]) + .arg(&guest_manifest) + .status()?; + if !status.success() { + return Err("Risc0 deterministic build failed".into()); + } + + let target_dir = + manifest_dir.join("program_methods/guest/target/riscv32im-risc0-zkvm-elf/docker/"); + + let bins = fs::read_dir(&target_dir)? + .filter_map(Result::ok) + .filter(|e| e.path().extension().is_some_and(|ext| ext == "bin")) + .collect::>(); + + if bins.is_empty() { + return Err(format!("No .bin files found in {:?}", target_dir).into()); + } + + fs::create_dir_all(&mod_dir)?; + let mut src = String::new(); + for entry in bins { + let path = entry.path(); + let name = path.file_stem().unwrap().to_string_lossy(); + let bytecode = fs::read(&path)?; + let image_id: [u32; 8] = risc0_binfmt::compute_image_id(&bytecode)?.into(); + src.push_str(&format!( + "pub const {}_ELF: &[u8] = include_bytes!(r#\"{}\"#);\n\ + pub const {}_ID: [u32; 8] = {:?};\n", + name.to_uppercase(), + path.display(), + name.to_uppercase(), + image_id + )); + } + fs::write(&mod_file, src)?; + println!("cargo:warning=Generated module at {}", mod_file.display()); + + Ok(()) +} diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index 0dd4ff2..dc6bb15 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -1,3 +1,12 @@ +#[cfg(not(feature = "no_docker"))] +pub mod program_methods { + include!(concat!(env!("OUT_DIR"), "/program_methods/mod.rs")); +} + +#[cfg(feature = "no_docker")] +#[allow(clippy::single_component_path_imports)] +use program_methods; + pub mod encoding; pub mod error; mod merkle_tree; diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 3a98723..9ce0610 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -8,7 +8,7 @@ use risc0_zkvm::{ExecutorEnv, InnerReceipt, Receipt, default_prover}; use crate::{error::NssaError, program::Program}; -use program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID}; +use crate::program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID}; /// Proof of the privacy preserving execution circuit #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 5abc153..f6df8fe 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -1,11 +1,11 @@ +use crate::program_methods::{ + AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF, + TOKEN_ID, +}; use nssa_core::{ account::{Account, AccountWithMetadata}, program::{InstructionData, ProgramId, ProgramOutput}, }; -use program_methods::{ - AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF, - TOKEN_ID, -}; use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec}; use serde::Serialize;