Added unconstrained zk-SNARK implementation for SHA3

This commit is contained in:
Sean Bowe
2016-01-03 02:13:25 -07:00
parent bc77a837df
commit 7415d5ff3c
4 changed files with 481 additions and 91 deletions

142
src/variable.rs Normal file
View File

@@ -0,0 +1,142 @@
use tinysnark::FieldT;
use std::cell::Cell;
use std::rc::Rc;
use std::fmt;
use std::collections::BTreeMap;
pub type WitnessMap = BTreeMap<usize, Vec<(Vec<usize>, Vec<usize>, Rc<Fn(&[&FieldT], &mut [&mut FieldT]) + 'static>)>>;
use std::collections::Bound::Unbounded;
pub fn satisfy_field_elements(vars: &mut [FieldT], witness_map: &WitnessMap) {
for (n, group) in witness_map.range(Unbounded, Unbounded) {
for &(ref i, ref o, ref f) in group.iter() {
let i: Vec<&FieldT> = i.iter().map(|i| &vars[*i]).collect();
let o: Vec<&FieldT> = o.iter().map(|o| &vars[*o]).collect();
let mut o: Vec<&mut FieldT> = unsafe {
use std::mem::transmute;
transmute(o)
};
f(&i, &mut o);
}
}
}
#[derive(Clone)]
pub struct Constraint;
struct Gadget {
inputs: Vec<Var>,
aux: Vec<Var>,
witness: Rc<Fn(&[&FieldT], &mut [&mut FieldT]) + 'static>,
constraints: Vec<Constraint>,
group: usize,
visited: Cell<bool>
}
impl Gadget {
pub fn walk(&self, counter: &mut usize, constraints: &mut Vec<Constraint>, witness_map: &mut WitnessMap) {
if self.visited.get() {
return;
}
self.visited.set(true);
for a in &self.aux {
assert!(a.index.get() == 0);
a.index.set(*counter);
*counter += 1;
}
constraints.extend_from_slice(&self.constraints);
for i in &self.inputs {
i.walk(counter, constraints, witness_map);
}
let input_indexes = self.inputs.iter().map(|i| i.index.get()).collect();
let output_indexes = self.aux.iter().map(|i| i.index.get()).collect();
witness_map.entry(self.group)
.or_insert_with(|| Vec::new())
.push((input_indexes, output_indexes, self.witness.clone()));
}
}
#[derive(Clone)]
pub struct Var {
index: Rc<Cell<usize>>,
gadget: Option<Rc<Gadget>>
}
impl Var {
// todo: make this not public
pub fn new(i: usize) -> Var {
Var {
index: Rc::new(Cell::new(i)),
gadget: None
}
}
pub fn val(&self, map: &[FieldT]) -> FieldT {
let index = self.index.get();
assert!(index != 0);
map[index]
}
fn group(&self) -> usize {
match self.gadget {
None => 0,
Some(ref g) => g.group
}
}
pub fn walk(&self, counter: &mut usize, constraints: &mut Vec<Constraint>, witness_map: &mut WitnessMap) {
match self.gadget {
None => {},
Some(ref g) => g.walk(counter, constraints, witness_map)
}
}
}
pub fn gadget<W, C>(
inputs: &[&Var],
aux: usize,
witness: W,
constrain: C
) -> Vec<Var>
where C: for<'a> Fn(&[&'a Var], &[&'a Var], &mut Vec<Constraint>) -> Vec<&'a Var>,
W: Fn(&[&FieldT], &mut [&mut FieldT]) + 'static
{
let this_group = inputs.iter().map(|i| i.group()).max().map(|a| a+1).unwrap_or(0);
let aux: Vec<_> = (0..aux).map(|_| Var::new(0)).collect();
let aux: Vec<_> = aux.iter().collect();
let mut constraints = vec![];
let outputs = constrain(inputs, &*aux, &mut constraints);
let gadget = Rc::new(Gadget {
inputs: inputs.iter().map(|a| (*a).clone()).collect(),
aux: aux.iter().map(|a| (*a).clone()).collect(),
witness: Rc::new(witness),
constraints: constraints,
group: this_group,
visited: Cell::new(false)
});
outputs.into_iter().map(|a| {
let mut a = (*a).clone();
// TODO: we should augment the gadget instead
// of replacing it
debug_assert!(a.gadget.is_none());
a.gadget = Some(gadget.clone());
a
}).collect()
}