diff --git a/.gitignore b/.gitignore index 5f38836d9..08a51c08f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ /output crates/playground/wasm crates/playground/target +params/ +output/ diff --git a/crates/cli/src/app_builder.rs b/crates/cli/src/app_builder.rs index dfb7857bb..e958d86de 100644 --- a/crates/cli/src/app_builder.rs +++ b/crates/cli/src/app_builder.rs @@ -23,6 +23,7 @@ use crate::exec::exec_dry_run; use super::command::CommandBuilder; use super::exec::exec_create_proof; +use super::exec::exec_create_proof_from_trace; use super::exec::exec_image_checksum; use super::exec::exec_setup; use super::exec::exec_verify_proof; @@ -83,6 +84,7 @@ pub trait AppBuilder: CommandBuilder { let app = Self::append_setup_subcommand(app); let app = Self::append_dry_run_subcommand(app); let app = Self::append_create_single_proof_subcommand(app); + let app = Self::append_create_proof_from_trace_subcommand(app); let app = Self::append_verify_single_proof_subcommand(app); let app = Self::append_image_checksum_subcommand(app); @@ -265,6 +267,27 @@ pub trait AppBuilder: CommandBuilder { Ok(()) } + Some(("proof-from-trace", sub_matches)) => { + let tables_dir = sub_matches.get_one::("tables").unwrap(); + let proof_dir = sub_matches.get_one::("proof").unwrap(); + + let context_out_path: Option = + Self::parse_context_out_path_arg(&sub_matches); + + let context_out = Arc::new(Mutex::new(vec![])); + + exec_create_proof_from_trace( + Self::NAME, + zkwasm_k, + tables_dir, + &proof_dir, + ¶m_dir, + )?; + + write_context_output(&context_out.lock().unwrap(), context_out_path)?; + + Ok(()) + } Some(("single-verify", _)) => exec_verify_proof(Self::NAME, &output_dir, ¶m_dir), Some((_, _)) => todo!(), None => todo!(), diff --git a/crates/cli/src/args.rs b/crates/cli/src/args.rs index 39b7e1985..ad9efb30b 100644 --- a/crates/cli/src/args.rs +++ b/crates/cli/src/args.rs @@ -95,6 +95,13 @@ pub trait ArgBuilder { ).value_parser(value_parser!(PathBuf)) } + fn tables_path_arg<'a>() -> Arg<'a> { + arg!( + -t --tables [TABLES_PATH] "Path of the tables files.\nMust be provided." + ) + .value_parser(value_parser!(PathBuf)) + } + fn proof_path_arg<'a>() -> Arg<'a> { arg!( -p --proof "Path of proof." diff --git a/crates/cli/src/command.rs b/crates/cli/src/command.rs index 9f0d0c30a..02aba7321 100644 --- a/crates/cli/src/command.rs +++ b/crates/cli/src/command.rs @@ -36,6 +36,14 @@ pub trait CommandBuilder: ArgBuilder { app.subcommand(command) } + fn append_create_proof_from_trace_subcommand(app: App) -> App { + let command = Command::new("proof-from-trace") + .arg(Self::proof_path_arg()) + .arg(Self::tables_path_arg()); + + app.subcommand(command) + } + fn append_verify_single_proof_subcommand(app: App) -> App { let command = Command::new("single-verify"); app.subcommand(command) diff --git a/crates/cli/src/exec.rs b/crates/cli/src/exec.rs index 690a660da..ab984de55 100644 --- a/crates/cli/src/exec.rs +++ b/crates/cli/src/exec.rs @@ -5,6 +5,7 @@ use circuits_batcher::proof::ProofInfo; use circuits_batcher::proof::ProofLoadInfo; use circuits_batcher::proof::ProvingKeyCache; use delphinus_zkwasm::circuits::TestCircuit; +use delphinus_zkwasm::circuits::ZkWasmCircuitBuilder; use delphinus_zkwasm::loader::ZkWasmLoader; use delphinus_zkwasm::runtime::host::HostEnvBuilder; use halo2_proofs::pairing::bn256::Bn256; @@ -14,6 +15,7 @@ use halo2aggregator_s::circuits::utils::load_or_build_unsafe_params; use halo2aggregator_s::circuits::utils::TranscriptHash; use halo2aggregator_s::native_verifier; use log::info; +use specs::Tables; use std::io::Write; use std::path::PathBuf; @@ -181,6 +183,40 @@ pub fn exec_create_proof( Ok(()) } +pub fn exec_create_proof_from_trace( + prefix: &'static str, + zkwasm_k: u32, + tables_dir: &PathBuf, + proof_dir: &PathBuf, + param_dir: &PathBuf, +) -> Result<()> { + let (tables, public_inputs_and_outputs) = Tables::load_table(tables_dir.clone()); + let builder = ZkWasmCircuitBuilder { + tables, + public_inputs_and_outputs: public_inputs_and_outputs.clone(), + }; + let circuit = builder.build_circuit(); + + let instances = public_inputs_and_outputs + .iter() + .map(|v| (*v).into()) + .collect(); + + let circuit: CircuitInfo> = CircuitInfo::new( + circuit, + prefix.to_string(), + vec![instances], + zkwasm_k as usize, + circuits_batcher::args::HashType::Poseidon, + ); + circuit.proofloadinfo.save(proof_dir); + circuit.exec_create_proof(proof_dir, param_dir, 0); + + info!("Proof has been created."); + + Ok(()) +} + pub fn exec_verify_proof( prefix: &'static str, output_dir: &PathBuf, diff --git a/crates/cli/test_cli.sh b/crates/cli/test_cli.sh index 8df568320..566366aee 100755 --- a/crates/cli/test_cli.sh +++ b/crates/cli/test_cli.sh @@ -11,3 +11,5 @@ RUST_LOG=info cargo run --release --features cuda -- --host default -k 18 --func RUST_LOG=info cargo run --release --features cuda -- --host default -k 18 --function zkmain --param ./params --output ./output --wasm ../zkwasm/wasm/wasm_output.wasm single-prove --public 133:i64 --public 2:i64 RUST_LOG=info cargo run --release --features cuda -- --host default -k 18 --function zkmain --param ./params --output ./output --wasm ../zkwasm/wasm/wasm_output.wasm single-verify + +RUST_LOG=info cargo run --release --features cuda -- --host default -k 18 --function zkmain --param ./params --output ./output --wasm ../zkwasm/wasm/wasm_output.wasm proof-from-trace --tables ./ --proof ./output diff --git a/crates/specs/src/lib.rs b/crates/specs/src/lib.rs index 3add81166..5b010c680 100644 --- a/crates/specs/src/lib.rs +++ b/crates/specs/src/lib.rs @@ -3,6 +3,7 @@ #![deny(dead_code)] use std::env; +use std::io::BufReader; use std::io::Write; use std::path::PathBuf; @@ -14,6 +15,7 @@ use itable::InstructionTable; use jtable::JumpTable; use jtable::StaticFrameEntry; use mtable::MTable; +use serde::de::DeserializeOwned; use serde::Deserialize; use serde::Serialize; @@ -51,6 +53,11 @@ pub struct ExecutionTable { pub jtable: JumpTable, } +pub enum FileType { + JSON, + FLEXBUFFERS, +} + #[derive(Default, Clone)] pub struct Tables { pub compilation_tables: CompilationTable, @@ -58,8 +65,8 @@ pub struct Tables { } impl Tables { - pub fn write_json(&self, dir: Option) { - fn write_file(folder: &PathBuf, filename: &str, buf: &String) { + pub fn write_json(&self, dir: Option, public_inputs_and_outputs: &Vec) { + fn write_file(folder: &PathBuf, filename: &str, buf: String) { let mut folder = folder.clone(); folder.push(filename); let mut fd = std::fs::File::create(folder.as_path()).unwrap(); @@ -68,9 +75,26 @@ impl Tables { fd.write(buf.as_bytes()).unwrap(); } - let itable = serde_json::to_string_pretty(&self.compilation_tables.itable).unwrap(); - let imtable = serde_json::to_string_pretty(&self.compilation_tables.imtable).unwrap(); - let etable = serde_json::to_string_pretty(&self.execution_tables.etable).unwrap(); + let dir = dir.unwrap_or(env::current_dir().unwrap()); + + macro_rules! serialize { + ($t:ident, $name:ident) => { + let table = serde_json::to_string_pretty(&self.$t.$name).unwrap(); + write_file(&dir, &format!("{}.json", stringify!($name)), table); + }; + } + + serialize!(compilation_tables, itable); + serialize!(compilation_tables, imtable); + serialize!(compilation_tables, elem_table); + serialize!(compilation_tables, configure_table); + serialize!(compilation_tables, static_jtable); + serialize!(compilation_tables, fid_of_entry); + + serialize!(execution_tables, etable); + serialize!(execution_tables, mtable); + serialize!(execution_tables, jtable); + let external_host_call_table = serde_json::to_string_pretty( &self .execution_tables @@ -78,15 +102,49 @@ impl Tables { .filter_external_host_call_table(), ) .unwrap(); - let mtable = serde_json::to_string_pretty(&self.execution_tables.mtable).unwrap(); - let jtable = serde_json::to_string_pretty(&self.execution_tables.jtable).unwrap(); + let instances = serde_json::to_string_pretty(&public_inputs_and_outputs).unwrap(); - let dir = dir.unwrap_or(env::current_dir().unwrap()); - write_file(&dir, "itable.json", &itable); - write_file(&dir, "imtable.json", &imtable); - write_file(&dir, "etable.json", &etable); - write_file(&dir, "mtable.json", &mtable); - write_file(&dir, "jtable.json", &jtable); - write_file(&dir, "external_host_table.json", &external_host_call_table); + write_file(&dir, "instance.json", instances); + write_file(&dir, "external_host_table.json", external_host_call_table); + } + + pub fn load_table(dir: PathBuf) -> (Tables, Vec) { + fn load_file(folder: &PathBuf, filename: &str) -> T { + let mut folder = folder.clone(); + folder.push(filename); + let file = std::fs::File::open(folder.as_path()).unwrap(); + let reader = BufReader::new(file); + serde_json::from_reader(reader).unwrap() + } + let itable = load_file(&dir, "itable.json"); + let imtable = load_file(&dir, "imtable.json"); + let elem_table = load_file(&dir, "elem_table.json"); + let configure_table = load_file(&dir, "configure_table.json"); + let static_jtable = load_file(&dir, "static_jtable.json"); + let fid_of_entry = load_file(&dir, "fid_of_entry.json"); + + let etable = load_file(&dir, "etable.json"); + let mtable = load_file(&dir, "mtable.json"); + let jtable = load_file(&dir, "jtable.json"); + + let public_inputs_and_outputs: Vec = load_file(&dir, "instance.json"); + ( + Tables { + compilation_tables: CompilationTable { + itable, + imtable, + elem_table, + configure_table, + static_jtable, + fid_of_entry, + }, + execution_tables: ExecutionTable { + etable, + mtable, + jtable, + }, + }, + public_inputs_and_outputs, + ) } } diff --git a/crates/zkwasm/src/loader/mod.rs b/crates/zkwasm/src/loader/mod.rs index 953a9a089..509a46d49 100644 --- a/crates/zkwasm/src/loader/mod.rs +++ b/crates/zkwasm/src/loader/mod.rs @@ -190,7 +190,9 @@ impl> ZkWasmLoader( v }; - execution_result.tables.write_json(None); + execution_result + .tables + .write_json(None, &execution_result.public_inputs_and_outputs); let memory_writing_table: MemoryWritingTable = execution_result .tables .execution_tables