diff --git a/Cargo.toml b/Cargo.toml index 2cc83dd..53eaf3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" # WASM operations wasmer = { version = "2.0" } fnv = { version = "1.0.3", default-features = false } +num = { version = "0.4.0" } num-traits = { version = "0.2.0", default-features = false } num-bigint = { version = "0.4", default-features = false, features = ["rand"] } diff --git a/src/witness/circom.rs b/src/witness/circom.rs index ae31b72..4b7a4e3 100644 --- a/src/witness/circom.rs +++ b/src/witness/circom.rs @@ -31,6 +31,10 @@ pub trait Circom2 { fn get_field_num_len32(&self) -> Result; fn get_raw_prime(&self) -> Result<()>; fn read_shared_rw_memory(&self, i: i32) -> Result; + fn write_shared_rw_memory(&self, i: i32, v: i32) -> Result<()>; + fn set_input_signal(&self, hmsb: i32, hlsb: i32, pos: i32) -> Result<()>; + fn get_witness(&self, i: i32) -> Result<()>; + fn get_witness_size(&self) -> Result; } #[cfg(not(feature = "circom-2"))] @@ -56,7 +60,7 @@ impl Circom2 for Wasm { fn get_raw_prime(&self) -> Result<()> { let func = self.func("getRawPrime"); - let _result = func.call(&[])?; + func.call(&[])?; Ok(()) } @@ -65,6 +69,30 @@ impl Circom2 for Wasm { let result = func.call(&[i.into()])?; Ok(result[0].unwrap_i32()) } + + fn write_shared_rw_memory(&self, i: i32, v: i32) -> Result<()> { + let func = self.func("writeSharedRWMemory"); + func.call(&[i.into(), v.into()])?; + Ok(()) + } + + fn set_input_signal(&self, hmsb: i32, hlsb: i32, pos: i32) -> Result<()> { + let func = self.func("setInputSignal"); + func.call(&[hmsb.into(), hlsb.into(), pos.into()])?; + Ok(()) + } + + fn get_witness(&self, i: i32) -> Result<()> { + let func = self.func("getWitness"); + func.call(&[i.into()])?; + Ok(()) + } + + fn get_witness_size(&self) -> Result { + let func = self.func("getWitnessSize"); + let result = func.call(&[])?; + Ok(result[0].unwrap_i32()) + } } impl CircomBase for Wasm { diff --git a/src/witness/witness_calculator.rs b/src/witness/witness_calculator.rs index 54904da..032ffb7 100644 --- a/src/witness/witness_calculator.rs +++ b/src/witness/witness_calculator.rs @@ -5,6 +5,9 @@ use num_traits::Zero; use std::cell::Cell; use wasmer::{imports, Function, Instance, Memory, MemoryType, Module, RuntimeError, Store}; +#[cfg(feature = "circom-2")] +use num::ToPrimitive; + #[cfg(feature = "circom-2")] use super::Circom2; @@ -34,6 +37,21 @@ fn from_array32(arr: Vec) -> BigInt { res } +#[cfg(feature = "circom-2")] +fn to_array32(s: &BigInt, size: usize) -> Vec { + let mut res = vec![0; size as usize]; + let mut rem = s.clone(); + let radix = BigInt::from(0x100000000u64); + let mut c = size - 1; + while !rem.is_zero() { + res[c] = (&rem % &radix).to_i32().unwrap(); + rem /= &radix; + c -= 1; + } + + res +} + impl WitnessCalculator { pub fn new(path: impl AsRef) -> Result { let store = Store::default(); @@ -59,29 +77,25 @@ impl WitnessCalculator { }; let instance = Wasm::new(Instance::new(&module, &import_object)?); - let n32; - let prime: BigInt; - let mut safe_memory: SafeMemory; - cfg_if::cfg_if! { if #[cfg(feature = "circom-2")] { //let version = instance.get_version()?; - n32 = instance.get_field_num_len32()?; - safe_memory = SafeMemory::new(memory, n32 as usize, BigInt::zero()); - let _res = instance.get_raw_prime()?; + let n32 = instance.get_field_num_len32()?; + let mut safe_memory = SafeMemory::new(memory, n32 as usize, BigInt::zero()); + instance.get_raw_prime()?; let mut arr = vec![0; n32 as usize]; for i in 0..n32 { let res = instance.read_shared_rw_memory(i)?; arr[(n32 as usize) - (i as usize) - 1] = res; } - prime = from_array32(arr); + let prime = from_array32(arr); } else { // Fallback to Circom 1 behavior //version = 1; - n32 = (instance.get_fr_len()? >> 2) - 2; - safe_memory = SafeMemory::new(memory, n32 as usize, BigInt::zero()); + let n32 = (instance.get_fr_len()? >> 2) - 2; + let mut safe_memory = SafeMemory::new(memory, n32 as usize, BigInt::zero()); let ptr = instance.get_ptr_raw_prime()?; - prime = safe_memory.read_big(ptr as usize, n32 as usize)?; + let prime = safe_memory.read_big(ptr as usize, n32 as usize)?; } } @@ -100,37 +114,71 @@ impl WitnessCalculator { inputs: I, sanity_check: bool, ) -> Result> { - let old_mem_free_pos = self.memory.free_pos(); - self.instance.init(sanity_check)?; - let p_sig_offset = self.memory.alloc_u32(); - let p_fr = self.memory.alloc_fr(); + cfg_if::cfg_if! { + if #[cfg(feature = "circom-2")] { + let n32 = self.instance.get_field_num_len32()?; + } else { + let old_mem_free_pos = self.memory.free_pos(); + let p_sig_offset = self.memory.alloc_u32(); + let p_fr = self.memory.alloc_fr(); + } + } // allocate the inputs for (name, values) in inputs.into_iter() { let (msb, lsb) = fnv(&name); - self.instance - .get_signal_offset32(p_sig_offset, 0, msb, lsb)?; - let sig_offset = self.memory.read_u32(p_sig_offset as usize) as usize; + cfg_if::cfg_if! { + if #[cfg(feature = "circom-2")] { + for (i, value) in values.into_iter().enumerate() { + let f_arr = to_array32(&value, n32 as usize); + for j in 0..n32 { + self.instance.write_shared_rw_memory(j as i32, f_arr[(n32 as usize) - 1 - (j as usize)])?; + } + self.instance.set_input_signal(msb as i32, lsb as i32, i as i32)?; + } + } else { + self.instance + .get_signal_offset32(p_sig_offset, 0, msb, lsb)?; - for (i, value) in values.into_iter().enumerate() { - self.memory.write_fr(p_fr as usize, &value)?; - self.instance - .set_signal(0, 0, (sig_offset + i) as i32, p_fr as i32)?; + let sig_offset = self.memory.read_u32(p_sig_offset as usize) as usize; + + for (i, value) in values.into_iter().enumerate() { + self.memory.write_fr(p_fr as usize, &value)?; + self.instance + .set_signal(0, 0, (sig_offset + i) as i32, p_fr as i32)?; + } + } } } let mut w = Vec::new(); - let n_vars = self.instance.get_n_vars()?; - for i in 0..n_vars { - let ptr = self.instance.get_ptr_witness(i)? as usize; - let el = self.memory.read_fr(ptr)?; - w.push(el); - } - self.memory.set_free_pos(old_mem_free_pos); + cfg_if::cfg_if! { + if #[cfg(feature = "circom-2")] { + let witness_size = self.instance.get_witness_size()?; + for i in 0..witness_size { + self.instance.get_witness(i)?; + let mut arr = vec![0; n32 as usize]; + for j in 0..n32 { + arr[(n32 as usize) - 1- (j as usize)] = self.instance.read_shared_rw_memory(j)?; + } + w.push(from_array32(arr)); + } + + } else { + let n_vars = self.instance.get_n_vars()?; + for i in 0..n_vars { + let ptr = self.instance.get_ptr_witness(i)? as usize; + let el = self.memory.read_fr(ptr)?; + w.push(el); + } + + self.memory.set_free_pos(old_mem_free_pos); + } + } Ok(w) } diff --git a/src/zkey.rs b/src/zkey.rs index e29a1f1..b5db8c1 100644 --- a/src/zkey.rs +++ b/src/zkey.rs @@ -43,6 +43,7 @@ use num_traits::Zero; #[derive(Clone, Debug)] struct Section { position: u64, + #[allow(dead_code)] size: usize, } @@ -58,7 +59,9 @@ pub fn read_zkey( #[derive(Debug)] struct BinFile<'a, R> { + #[allow(dead_code)] ftype: String, + #[allow(dead_code)] version: u32, sections: HashMap>, reader: &'a mut R, @@ -255,16 +258,20 @@ impl ZVerifyingKey { #[derive(Clone, Debug)] struct HeaderGroth { + #[allow(dead_code)] n8q: u32, + #[allow(dead_code)] q: BigInteger256, - + #[allow(dead_code)] n8r: u32, + #[allow(dead_code)] r: BigInteger256, n_vars: usize, n_public: usize, domain_size: u32, + #[allow(dead_code)] power: u32, verifying_key: ZVerifyingKey,