Skip to content

Commit

Permalink
Merge pull request #13 from zkBob/feature/preparse_gates
Browse files Browse the repository at this point in the history
Adds optional warm boot for the prover
  • Loading branch information
r0wdy1 authored May 22, 2023
2 parents a893c53 + 2bc3e76 commit 9783ad0
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 76 deletions.
23 changes: 20 additions & 3 deletions fawkes-crypto/src/backend/bellman_groth16/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
circuit::{
cs::{RCS, WitnessCS, CS},
lc::{Index}
lc::{Index}, gates::{GateSource, Gate, GateIterator, evaluate_gates_memory_size}
},
core::signal::Signal,
ff_uint::{Num, PrimeField},
Expand Down Expand Up @@ -143,8 +143,12 @@ impl<E: Engine> Parameters<E> {
verifier::VK::from_bellman(&self.0.vk)
}

pub fn get_witness_rcs(&self)->RCS<WitnessCS<E::Fr>> {
WitnessCS::rc_new(self.1 as usize, &self.2, &self.3)
pub fn get_witness_rcs(&self) -> RCS<WitnessCS<E::Fr>> {
WitnessCS::rc_new(self.1 as usize, GateSource::Compressed(&self.2), &self.3)
}

pub fn get_witness_rcs_precomputed<'a>(&'a self, data: &'a PrecomputedData<E::Fr>) -> RCS<WitnessCS<E::Fr>> {
WitnessCS::rc_new(self.1 as usize, GateSource::Precomputed(&data.gates), &self.3)
}

pub fn write<W:std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
Expand Down Expand Up @@ -174,4 +178,17 @@ impl<E: Engine> Parameters<E> {
Ok(Self(e0, e1, e2, e3))
}

pub fn precompute(&self) -> PrecomputedData<E::Fr> {
PrecomputedData {
gates: GateIterator::new(&GateSource::Compressed(&self.2)).map(|g| g.gate()).collect()
}
}

pub fn precompute_memory_size(&self) -> std::io::Result<usize> {
evaluate_gates_memory_size::<E::Fr>(self.1 as usize, &self.2)
}
}

pub struct PrecomputedData<Fr: PrimeField> {
gates: Vec<Gate<Fr>>
}
25 changes: 24 additions & 1 deletion fawkes-crypto/src/backend/bellman_groth16/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,30 @@ pub fn prove<'a, E: Engine, Pub: Signal<WitnessCS<'a, E::Fr>>, Sec: Signal<Witne
input_sec: &Sec::Value,
circuit: C,
) -> (Vec<Num<E::Fr>>, Proof<E>) {
let ref rcs = params.get_witness_rcs();
let rcs = &params.get_witness_rcs();
prove_internal(params, input_pub, input_sec, circuit, rcs)
}

#[cfg(feature = "rand_support")]
pub fn prove_precomputed<'a, E: Engine, Pub: Signal<WitnessCS<'a, E::Fr>>, Sec: Signal<WitnessCS<'a, E::Fr>>, C: Fn(Pub, Sec)>(
params: &'a Parameters<E>,
input_pub: &Pub::Value,
input_sec: &Sec::Value,
circuit: C,
precomputed: &'a PrecomputedData<E::Fr>,
) -> (Vec<Num<E::Fr>>, Proof<E>) {
let rcs = &params.get_witness_rcs_precomputed(precomputed);
prove_internal(params, input_pub, input_sec, circuit, rcs)
}

#[cfg(feature = "rand_support")]
fn prove_internal<'a, E: Engine, Pub: Signal<WitnessCS<'a, E::Fr>>, Sec: Signal<WitnessCS<'a, E::Fr>>, C: Fn(Pub, Sec)>(
params: &'a Parameters<E>,
input_pub: &Pub::Value,
input_sec: &Sec::Value,
circuit: C,
rcs: &RCS<WitnessCS<'a, E::Fr>>
) -> (Vec<Num<E::Fr>>, Proof<E>) {
let signal_pub = Pub::alloc(rcs, Some(input_pub));
signal_pub.inputize();
let signal_sec = Sec::alloc(rcs, Some(input_sec));
Expand Down
86 changes: 17 additions & 69 deletions fawkes-crypto/src/circuit/r1cs/cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,22 @@ use crate::{

use std::{cell::RefCell, marker::PhantomData, rc::Rc};
use bit_vec::BitVec;
use byteorder::{ByteOrder, LittleEndian};

pub type RCS<C> = Rc<RefCell<C>>;

#[cfg(feature="borsh_support")]
use crate::borsh::{BorshSerialize, BorshDeserialize};
use super::gates::{Gate, self, GateSource, GateWrapper};


#[derive(Clone, Debug)]
#[cfg_attr(feature = "borsh_support", derive(BorshSerialize, BorshDeserialize))]
pub struct Gate<Fr:PrimeField>(
pub Vec<(Num<Fr>, Index)>,
pub Vec<(Num<Fr>, Index)>,
pub Vec<(Num<Fr>, Index)>,
);

pub trait CS: Clone {
type Fr: PrimeField;
type LC: AbstractLC<Self::Fr>;
type GateIterator: Iterator<Item=Gate<Self::Fr>>;
type GateIterator<'a>: Iterator<Item=GateWrapper<'a, Self::Fr>> where Self: 'a;

fn num_gates(&self) -> usize;
fn num_input(&self) -> usize;
fn num_aux(&self) -> usize;
fn get_value(&self, index:Index) -> Option<Num<Self::Fr>>;
fn get_gate_iterator(&self) -> Self::GateIterator;
fn get_gate_iterator(&self) -> Self::GateIterator<'_>;

// a*b === c
fn enforce(a: &CNum<Self>, b: &CNum<Self>, c: &CNum<Self>);
Expand Down Expand Up @@ -100,33 +90,33 @@ pub struct WitnessCS<'a, Fr: PrimeField> {
pub values_input: Vec<Num<Fr>>,
pub values_aux: Vec<Num<Fr>>,
pub num_gates: usize,
pub gates_data: &'a[u8],
pub gates: GateSource<'a, Fr>,
pub const_tracker: &'a BitVec,
pub const_tracker_index: usize
}

impl<'a, Fr: PrimeField> WitnessCS<'a, Fr> {
pub fn new(num_gates:usize, gates_data: &'a[u8], const_tracker: &'a BitVec) -> Self {
pub fn new(num_gates:usize, gates: GateSource<'a, Fr>, const_tracker: &'a BitVec) -> Self {
Self {
values_input: vec![Num::ONE],
values_aux: vec![],
num_gates,
gates_data,
gates,
const_tracker,
const_tracker_index: 0
}
}

pub fn rc_new(num_gates:usize, gates_data: &'a[u8], const_tracker: &'a BitVec) -> RCS<Self> {
Rc::new(RefCell::new(Self::new(num_gates, gates_data, const_tracker)))
pub fn rc_new(num_gates:usize, gates: GateSource<'a, Fr>, const_tracker: &'a BitVec) -> RCS<Self> {
Rc::new(RefCell::new(Self::new(num_gates, gates, const_tracker)))
}
}


impl<Fr: PrimeField> CS for DebugCS<Fr> {
type Fr = Fr;
type LC = LC<Fr>;
type GateIterator = core::iter::Empty<Gate<Self::Fr>>;
type GateIterator<'a> = core::iter::Empty<GateWrapper<'a, Self::Fr>> where Self: 'a;

fn num_gates(&self) -> usize {
self.num_gates
Expand All @@ -143,7 +133,7 @@ impl<Fr: PrimeField> CS for DebugCS<Fr> {
None
}

fn get_gate_iterator(&self) -> Self::GateIterator {
fn get_gate_iterator(&self) -> Self::GateIterator<'_> {
std::unimplemented!();
}

Expand Down Expand Up @@ -180,52 +170,10 @@ impl<Fr: PrimeField> CS for DebugCS<Fr> {

}


pub struct GateStreamedIterator<Fr:PrimeField, R:std::io::Read>(R,PhantomData<Fr>);

fn read_u32<R:std::io::Read>(r: &mut R) -> std::io::Result<u32> {
let mut b = [0; 4];
r.read_exact(&mut b)?;
Ok(LittleEndian::read_u32(&b))
}


fn read_gate_part<Fr:PrimeField, R:std::io::Read>(r: &mut R) -> std::io::Result<Vec<(Num<Fr>, Index)>> {
let sz = read_u32(r)? as usize;

let item_size = std::mem::size_of::<Fr>() + std::mem::size_of::<u8>() + std::mem::size_of::<u32>();
let mut buf = vec![0; sz*item_size];
r.read_exact(&mut buf)?;
let mut buf_ref = &buf[..];
let mut gate_part = Vec::with_capacity(sz);
for _ in 0..sz {
let a = Num::<Fr>::deserialize(&mut buf_ref)?;
let b1 = u8::deserialize(&mut buf_ref)?;
let b2 = u32::deserialize(&mut buf_ref)?;
let b = match b1 {
0 => Index::Input(b2),
1 => Index::Aux(b2),
_ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "enum elements overflow"))
};
gate_part.push((a,b));
}
Ok(gate_part)
}

impl<Fr:PrimeField, R:std::io::Read> Iterator for GateStreamedIterator<Fr, R> {
type Item = Gate<Fr>;
fn next(&mut self) -> Option<Self::Item> {
let a = read_gate_part(&mut self.0).ok()?;
let b = read_gate_part(&mut self.0).ok()?;
let c = read_gate_part(&mut self.0).ok()?;
Some(Gate(a,b,c))
}
}

impl<'a, Fr: PrimeField> CS for WitnessCS<'a, Fr> {
impl<'a, Fr: PrimeField + 'a> CS for WitnessCS<'a, Fr> {
type Fr = Fr;
type LC = ZeroLC;
type GateIterator = GateStreamedIterator<Fr, brotli::Decompressor<&'a [u8]>>;
type GateIterator<'b> = gates::GateIterator<'b, Fr> where Self: 'b;

fn num_gates(&self) -> usize {
self.num_gates
Expand All @@ -245,8 +193,8 @@ impl<'a, Fr: PrimeField> CS for WitnessCS<'a, Fr> {
}
}

fn get_gate_iterator(&self) -> Self::GateIterator {
GateStreamedIterator(brotli::Decompressor::new(self.gates_data, 4096), PhantomData)
fn get_gate_iterator(&self) -> Self::GateIterator<'_> {
gates::GateIterator::new(&self.gates)
}

fn enforce(_: &CNum<Self>, _: &CNum<Self>, _: &CNum<Self>) {
Expand Down Expand Up @@ -279,7 +227,7 @@ impl<'a, Fr: PrimeField> CS for WitnessCS<'a, Fr> {
impl<Fr: PrimeField> CS for BuildCS<Fr> {
type Fr = Fr;
type LC = LC<Fr>;
type GateIterator = std::vec::IntoIter<Gate<Self::Fr>>;
type GateIterator<'a> = gates::GateIterator<'a, Fr> where Self: 'a;

fn num_gates(&self) -> usize {
self.gates.len()
Expand All @@ -296,8 +244,8 @@ impl<Fr: PrimeField> CS for BuildCS<Fr> {
None
}

fn get_gate_iterator(&self) -> Self::GateIterator {
self.gates.clone().into_iter()
fn get_gate_iterator(&self) -> Self::GateIterator<'_> {
gates::GateIterator::new(&GateSource::Precomputed(&self.gates))
}

// a*b === c
Expand Down
142 changes: 142 additions & 0 deletions fawkes-crypto/src/circuit/r1cs/gates.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
use std::{marker::PhantomData, ops::Deref, io::Read};

#[cfg(feature="borsh_support")]
use borsh::{BorshSerialize, BorshDeserialize};

use byteorder::{LittleEndian, ByteOrder};
use ff_uint::{PrimeField, Num};

use super::lc::Index;


#[derive(Clone, Debug)]
#[cfg_attr(feature = "borsh_support", derive(BorshSerialize, BorshDeserialize))]
pub struct Gate<Fr: PrimeField>(
pub Vec<(Num<Fr>, Index)>,
pub Vec<(Num<Fr>, Index)>,
pub Vec<(Num<Fr>, Index)>,
);

#[derive(Clone, Debug)]
pub enum GateSource<'a, Fr: PrimeField> {
Compressed(&'a [u8]),
Precomputed(&'a Vec<Gate<Fr>>)
}

pub enum GateIterator<'a, Fr: PrimeField> {
Streamed(Box<GateStreamedIterator<Fr, brotli::Decompressor<&'a [u8]>>>),
Precomputed(std::slice::Iter<'a, Gate<Fr>>)
}

impl<'a, Fr: PrimeField> GateIterator<'a, Fr> {
pub fn new(source: &GateSource<'a, Fr>) -> Self {
match source {
GateSource::Compressed(bytes) => {
Self::Streamed(Box::new(GateStreamedIterator(brotli::Decompressor::new(bytes, 4096), PhantomData)))
},
GateSource::Precomputed(vec) => {
Self::Precomputed(vec.iter())
}
}
}
}

pub enum GateWrapper<'a, Fr: PrimeField> {
Value(Gate<Fr>),
Ref(&'a Gate<Fr>)
}

impl<'a, Fr: PrimeField> GateWrapper<'a, Fr> {
pub fn gate(self) -> Gate<Fr> {
match self {
Self::Value(v) => v,
Self::Ref(r) => r.clone()
}
}
}

impl<'a, Fr: PrimeField> Deref for GateWrapper<'a, Fr> {
type Target = Gate<Fr>;

fn deref(&self) -> &Self::Target {
match self {
Self::Value(val) => val,
Self::Ref(reference) => reference
}
}
}

impl<'a, Fr: PrimeField> Iterator for GateIterator<'a, Fr> {
type Item = GateWrapper<'a, Fr>;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Streamed(iter) => {
iter.next().map(|g| GateWrapper::Value(g))
}
Self::Precomputed(iter) => {
iter.next().map(|g| GateWrapper::Ref(g))
},
}
}
}

pub fn evaluate_gates_memory_size<Fr: PrimeField>(
num_gates: usize,
bytes: &[u8],
) -> std::io::Result<usize> {
let r = &mut brotli::Decompressor::new(bytes, 4096);
let mut memory_size = 0;
let item_size = std::mem::size_of::<Fr>() + std::mem::size_of::<u8>() + std::mem::size_of::<u32>();
let gate_size = std::mem::size_of::<Fr>() + std::mem::size_of::<Index>();
for _ in 0..num_gates {
for _ in 0..3 {
let count = read_u32(r)? as usize;
memory_size += count * gate_size;

let mut buf = vec![0; count * item_size];
r.read_exact(&mut buf)?;
}
}
Ok(memory_size)
}

pub struct GateStreamedIterator<Fr:PrimeField, R:std::io::Read>(R, PhantomData<Fr>);

fn read_u32<R:std::io::Read>(r: &mut R) -> std::io::Result<u32> {
let mut b = [0; 4];
r.read_exact(&mut b)?;
Ok(LittleEndian::read_u32(&b))
}


fn read_gate_part<Fr:PrimeField, R:std::io::Read>(r: &mut R) -> std::io::Result<Vec<(Num<Fr>, Index)>> {
let sz = read_u32(r)? as usize;

let item_size = std::mem::size_of::<Fr>() + std::mem::size_of::<u8>() + std::mem::size_of::<u32>();
let mut buf = vec![0; sz*item_size];
r.read_exact(&mut buf)?;
let mut buf_ref = &buf[..];
let mut gate_part = Vec::with_capacity(sz);
for _ in 0..sz {
let a = Num::<Fr>::deserialize(&mut buf_ref)?;
let b1 = u8::deserialize(&mut buf_ref)?;
let b2 = u32::deserialize(&mut buf_ref)?;
let b = match b1 {
0 => Index::Input(b2),
1 => Index::Aux(b2),
_ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "enum elements overflow"))
};
gate_part.push((a,b));
}
Ok(gate_part)
}

impl<Fr:PrimeField, R:std::io::Read> Iterator for GateStreamedIterator<Fr, R> {
type Item = Gate<Fr>;
fn next(&mut self) -> Option<Self::Item> {
let a = read_gate_part(&mut self.0).ok()?;
let b = read_gate_part(&mut self.0).ok()?;
let c = read_gate_part(&mut self.0).ok()?;
Some(Gate(a,b,c))
}
}
3 changes: 2 additions & 1 deletion fawkes-crypto/src/circuit/r1cs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod bool;
pub mod cs;
pub mod num;
pub mod lc;
pub mod lc;
pub mod gates;
Loading

0 comments on commit 9783ad0

Please sign in to comment.