Browse Source

circom2 proof generation (#14)

* circom2 proof generation

* fix fmt and test

* fix clippy and format dependency

* make clippy happy (circom2 changes)

* make clippy happy (#12)
pull/3/head
Philipp Sippl 2 years ago
committed by GitHub
parent
commit
1732e15d63
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 115 additions and 31 deletions
  1. +1
    -0
      Cargo.toml
  2. +29
    -1
      src/witness/circom.rs
  3. +77
    -29
      src/witness/witness_calculator.rs
  4. +8
    -1
      src/zkey.rs

+ 1
- 0
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"] }

+ 29
- 1
src/witness/circom.rs

@ -31,6 +31,10 @@ pub trait Circom2 {
fn get_field_num_len32(&self) -> Result<i32>;
fn get_raw_prime(&self) -> Result<()>;
fn read_shared_rw_memory(&self, i: i32) -> Result<i32>;
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<i32>;
}
#[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<i32> {
let func = self.func("getWitnessSize");
let result = func.call(&[])?;
Ok(result[0].unwrap_i32())
}
}
impl CircomBase for Wasm {

+ 77
- 29
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<i32> {
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<std::path::Path>) -> Result<Self> {
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<Vec<BigInt>> {
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)
}

+ 8
- 1
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<u32, Vec<Section>>,
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,

Loading…
Cancel
Save