|
@ -1,23 +1,17 @@ |
|
|
use super::{fnv, CircomBase, SafeMemory, Wasm};
|
|
|
|
|
|
|
|
|
use super::{fnv, SafeMemory, Wasm};
|
|
|
use color_eyre::Result;
|
|
|
use color_eyre::Result;
|
|
|
use num_bigint::BigInt;
|
|
|
use num_bigint::BigInt;
|
|
|
use num_traits::Zero;
|
|
|
use num_traits::Zero;
|
|
|
use wasmer::{imports, Function, Instance, Memory, MemoryType, Module, RuntimeError, Store};
|
|
|
use wasmer::{imports, Function, Instance, Memory, MemoryType, Module, RuntimeError, Store};
|
|
|
use wasmer_wasix::WasiEnv;
|
|
|
use wasmer_wasix::WasiEnv;
|
|
|
|
|
|
|
|
|
#[cfg(feature = "circom-2")]
|
|
|
|
|
|
use num::ToPrimitive;
|
|
|
use num::ToPrimitive;
|
|
|
|
|
|
|
|
|
use super::Circom1;
|
|
|
|
|
|
#[cfg(feature = "circom-2")]
|
|
|
|
|
|
use super::Circom2;
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
#[derive(Debug)]
|
|
|
pub struct WitnessCalculator {
|
|
|
pub struct WitnessCalculator {
|
|
|
pub instance: Wasm,
|
|
|
pub instance: Wasm,
|
|
|
pub memory: Option<SafeMemory>,
|
|
|
pub memory: Option<SafeMemory>,
|
|
|
pub n64: u32,
|
|
|
pub n64: u32,
|
|
|
pub circom_version: u32,
|
|
|
|
|
|
pub prime: BigInt,
|
|
|
pub prime: BigInt,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
@ -27,7 +21,6 @@ pub struct WitnessCalculator { |
|
|
#[error("{0}")]
|
|
|
#[error("{0}")]
|
|
|
struct ExitCode(u32);
|
|
|
struct ExitCode(u32);
|
|
|
|
|
|
|
|
|
#[cfg(feature = "circom-2")]
|
|
|
|
|
|
fn from_array32(arr: Vec<u32>) -> BigInt {
|
|
|
fn from_array32(arr: Vec<u32>) -> BigInt {
|
|
|
let mut res = BigInt::zero();
|
|
|
let mut res = BigInt::zero();
|
|
|
let radix = BigInt::from(0x100000000u64);
|
|
|
let radix = BigInt::from(0x100000000u64);
|
|
@ -37,7 +30,6 @@ fn from_array32(arr: Vec) -> BigInt { |
|
|
res
|
|
|
res
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
#[cfg(feature = "circom-2")]
|
|
|
|
|
|
fn to_array32(s: &BigInt, size: usize) -> Vec<u32> {
|
|
|
fn to_array32(s: &BigInt, size: usize) -> Vec<u32> {
|
|
|
let mut res = vec![0; size];
|
|
|
let mut res = vec![0; size];
|
|
|
let mut rem = s.clone();
|
|
|
let mut rem = s.clone();
|
|
@ -95,78 +87,24 @@ impl WitnessCalculator { |
|
|
Ok(wasm)
|
|
|
Ok(wasm)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
pub fn new_from_wasm(store: &mut Store, wasm: Wasm) -> Result<Self> {
|
|
|
|
|
|
let version = wasm.get_version(store).unwrap_or(1);
|
|
|
|
|
|
// Circom 2 feature flag with version 2
|
|
|
|
|
|
#[cfg(feature = "circom-2")]
|
|
|
|
|
|
fn new_circom2(
|
|
|
|
|
|
instance: Wasm,
|
|
|
|
|
|
store: &mut Store,
|
|
|
|
|
|
version: u32,
|
|
|
|
|
|
) -> Result<WitnessCalculator> {
|
|
|
|
|
|
let n32 = instance.get_field_num_len32(store)?;
|
|
|
|
|
|
instance.get_raw_prime(store)?;
|
|
|
|
|
|
let mut arr = vec![0; n32 as usize];
|
|
|
|
|
|
for i in 0..n32 {
|
|
|
|
|
|
let res = instance.read_shared_rw_memory(store, i)?;
|
|
|
|
|
|
arr[(n32 as usize) - (i as usize) - 1] = res;
|
|
|
|
|
|
}
|
|
|
|
|
|
let prime = from_array32(arr);
|
|
|
|
|
|
|
|
|
|
|
|
let n64 = ((prime.bits() - 1) / 64 + 1) as u32;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(WitnessCalculator {
|
|
|
|
|
|
instance,
|
|
|
|
|
|
memory: None,
|
|
|
|
|
|
n64,
|
|
|
|
|
|
circom_version: version,
|
|
|
|
|
|
prime,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
pub fn new_from_wasm(store: &mut Store, instance: Wasm) -> Result<Self> {
|
|
|
|
|
|
let n32 = instance.get_field_num_len32(store)?;
|
|
|
|
|
|
instance.get_raw_prime(store)?;
|
|
|
|
|
|
let mut arr = vec![0; n32 as usize];
|
|
|
|
|
|
for i in 0..n32 {
|
|
|
|
|
|
let res = instance.read_shared_rw_memory(store, i)?;
|
|
|
|
|
|
arr[(n32 as usize) - (i as usize) - 1] = res;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
let prime = from_array32(arr);
|
|
|
|
|
|
|
|
|
fn new_circom1(
|
|
|
|
|
|
instance: Wasm,
|
|
|
|
|
|
store: &mut Store,
|
|
|
|
|
|
version: u32,
|
|
|
|
|
|
) -> Result<WitnessCalculator> {
|
|
|
|
|
|
// Fallback to Circom 1 behavior
|
|
|
|
|
|
let n32 = (instance.get_fr_len(store)? >> 2) - 2;
|
|
|
|
|
|
let mut safe_memory =
|
|
|
|
|
|
SafeMemory::new(instance.memory.clone(), n32 as usize, BigInt::zero());
|
|
|
|
|
|
let ptr = instance.get_ptr_raw_prime(store)?;
|
|
|
|
|
|
let prime = safe_memory.read_big(store, ptr as usize, n32 as usize)?;
|
|
|
|
|
|
|
|
|
|
|
|
let n64 = ((prime.bits() - 1) / 64 + 1) as u32;
|
|
|
|
|
|
safe_memory.prime = prime.clone();
|
|
|
|
|
|
|
|
|
|
|
|
Ok(WitnessCalculator {
|
|
|
|
|
|
instance,
|
|
|
|
|
|
memory: Some(safe_memory),
|
|
|
|
|
|
n64,
|
|
|
|
|
|
circom_version: version,
|
|
|
|
|
|
prime,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Three possibilities:
|
|
|
|
|
|
// a) Circom 2 feature flag enabled, WASM runtime version 2
|
|
|
|
|
|
// b) Circom 2 feature flag enabled, WASM runtime version 1
|
|
|
|
|
|
// c) Circom 1 default behavior
|
|
|
|
|
|
//
|
|
|
|
|
|
// Once Circom 2 support is more stable, feature flag can be removed
|
|
|
|
|
|
|
|
|
let n64 = ((prime.bits() - 1) / 64 + 1) as u32;
|
|
|
|
|
|
|
|
|
cfg_if::cfg_if! {
|
|
|
|
|
|
if #[cfg(feature = "circom-2")] {
|
|
|
|
|
|
match version {
|
|
|
|
|
|
2 => new_circom2(wasm, store, version),
|
|
|
|
|
|
1 => new_circom1(wasm, store, version),
|
|
|
|
|
|
|
|
|
|
|
|
_ => panic!("Unknown Circom version")
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
new_circom1(instance, memory, version)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Ok(WitnessCalculator {
|
|
|
|
|
|
instance,
|
|
|
|
|
|
memory: None,
|
|
|
|
|
|
n64,
|
|
|
|
|
|
prime,
|
|
|
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
pub fn calculate_witness<I: IntoIterator<Item = (String, Vec<BigInt>)>>(
|
|
|
pub fn calculate_witness<I: IntoIterator<Item = (String, Vec<BigInt>)>>(
|
|
@ -177,72 +115,9 @@ impl WitnessCalculator { |
|
|
) -> Result<Vec<BigInt>> {
|
|
|
) -> Result<Vec<BigInt>> {
|
|
|
self.instance.init(store, sanity_check)?;
|
|
|
self.instance.init(store, sanity_check)?;
|
|
|
|
|
|
|
|
|
cfg_if::cfg_if! {
|
|
|
|
|
|
if #[cfg(feature = "circom-2")] {
|
|
|
|
|
|
match self.circom_version {
|
|
|
|
|
|
2 => self.calculate_witness_circom2(store, inputs),
|
|
|
|
|
|
1 => self.calculate_witness_circom1(store, inputs),
|
|
|
|
|
|
_ => panic!("Unknown Circom version")
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
self.calculate_witness_circom1(inputs, sanity_check)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
self.calculate_witness_circom2(store, inputs)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
// Circom 1 default behavior
|
|
|
|
|
|
fn calculate_witness_circom1<I: IntoIterator<Item = (String, Vec<BigInt>)>>(
|
|
|
|
|
|
&mut self,
|
|
|
|
|
|
store: &mut Store,
|
|
|
|
|
|
inputs: I,
|
|
|
|
|
|
) -> Result<Vec<BigInt>> {
|
|
|
|
|
|
let old_mem_free_pos = self.memory.as_ref().unwrap().free_pos(store)?;
|
|
|
|
|
|
let p_sig_offset = self.memory.as_mut().unwrap().alloc_u32(store)?;
|
|
|
|
|
|
let p_fr = self.memory.as_mut().unwrap().alloc_fr(store)?;
|
|
|
|
|
|
|
|
|
|
|
|
// allocate the inputs
|
|
|
|
|
|
for (name, values) in inputs.into_iter() {
|
|
|
|
|
|
let (msb, lsb) = fnv(&name);
|
|
|
|
|
|
|
|
|
|
|
|
self.instance
|
|
|
|
|
|
.get_signal_offset32(store, p_sig_offset, 0, msb, lsb)?;
|
|
|
|
|
|
|
|
|
|
|
|
let sig_offset = self
|
|
|
|
|
|
.memory
|
|
|
|
|
|
.as_ref()
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.read_u32(store, p_sig_offset as usize)
|
|
|
|
|
|
.unwrap() as usize;
|
|
|
|
|
|
|
|
|
|
|
|
for (i, value) in values.into_iter().enumerate() {
|
|
|
|
|
|
self.memory
|
|
|
|
|
|
.as_mut()
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.write_fr(store, p_fr as usize, &value)?;
|
|
|
|
|
|
self.instance
|
|
|
|
|
|
.set_signal(store, 0, 0, (sig_offset + i) as u32, p_fr)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let mut w = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
let n_vars = self.instance.get_n_vars(store)?;
|
|
|
|
|
|
for i in 0..n_vars {
|
|
|
|
|
|
let ptr = self.instance.get_ptr_witness(store, i)? as usize;
|
|
|
|
|
|
let el = self.memory.as_ref().unwrap().read_fr(store, ptr)?;
|
|
|
|
|
|
w.push(el);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.memory
|
|
|
|
|
|
.as_mut()
|
|
|
|
|
|
.unwrap()
|
|
|
|
|
|
.set_free_pos(store, old_mem_free_pos)?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(w)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Circom 2 feature flag with version 2
|
|
|
|
|
|
#[cfg(feature = "circom-2")]
|
|
|
|
|
|
fn calculate_witness_circom2<I: IntoIterator<Item = (String, Vec<BigInt>)>>(
|
|
|
fn calculate_witness_circom2<I: IntoIterator<Item = (String, Vec<BigInt>)>>(
|
|
|
&mut self,
|
|
|
&mut self,
|
|
|
store: &mut Store,
|
|
|
store: &mut Store,
|
|
@ -483,10 +358,6 @@ mod tests { |
|
|
wtns.prime.to_str_radix(16),
|
|
|
wtns.prime.to_str_radix(16),
|
|
|
"30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001".to_lowercase()
|
|
|
"30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001".to_lowercase()
|
|
|
);
|
|
|
);
|
|
|
assert_eq!(
|
|
|
|
|
|
{ wtns.instance.get_n_vars(&mut store).unwrap() },
|
|
|
|
|
|
case.n_vars
|
|
|
|
|
|
);
|
|
|
|
|
|
assert_eq!({ wtns.n64 }, case.n64);
|
|
|
assert_eq!({ wtns.n64 }, case.n64);
|
|
|
|
|
|
|
|
|
let inputs_str = std::fs::read_to_string(case.inputs_path).unwrap();
|
|
|
let inputs_str = std::fs::read_to_string(case.inputs_path).unwrap();
|
|
|