diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 24d4152..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "tinysnark/libsnark"] - path = tinysnark/libsnark - url = git://github.com/scipr-lab/libsnark.git diff --git a/.travis.yml b/.travis.yml index 359630d..8f0e50e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,7 @@ sudo: false language: rust rust: - - nightly - -install: -- export CXX="g++-4.8" CC="gcc-4.8" - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 - - gcc-4.8 - - libgmp-dev + - stable script: - - cd tinysnark && cargo test - - cd .. && cargo run --release - - cargo test \ No newline at end of file + - cargo test --release diff --git a/Cargo.toml b/Cargo.toml index 9088c1f..e3c9abf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,4 @@ repository = "https://github.com/ebfull/bellman" version = "0.0.1" [dependencies] -rand = "0.3.12" - -[dependencies.tinysnark] -path = "tinysnark" -version = "0.0.1" +rand = "0.3.15" diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index cdeba00..0000000 --- a/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM debian - -# Install Rust and Cargo -# TODO: make this architecture agnostic -RUN apt-get update && apt-get install -yy sudo wget -RUN wget https://static.rust-lang.org/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz -RUN tar xvf rust-nightly-x86_64-unknown-linux-gnu.tar.gz -RUN cd rust-nightly-x86_64-unknown-linux-gnu && ./install.sh - - -# Install libsnark dependencies -# g++ (for building libsnark) -# libgmp-dev (for bigint math) -RUN apt-get update && apt-get install -yy g++ libgmp-dev - -# Include this directory in the built image - -ADD . /bellman \ No newline at end of file diff --git a/src/bit.rs b/src/bit.rs deleted file mode 100644 index dfe19af..0000000 --- a/src/bit.rs +++ /dev/null @@ -1,560 +0,0 @@ -use tinysnark::FieldT; - -use std::rc::Rc; -use std::cell::RefCell; -use super::variable::*; -use self::Bit::*; -use self::Op::*; -use super::circuit::*; - -macro_rules! mirror { - ($a:pat, $b:pat) => (($a, $b) | ($b, $a)) -} - -macro_rules! mirror_match { - (@as_expr $e:expr) => {$e}; - - (@parse - $e:expr, ($($arms:tt)*); - $(,)* - ) => { - mirror_match!(@as_expr match $e { $($arms)* }) - }; - - (@parse - $e:expr, $arms:tt; - , $($tail:tt)* - ) => { - mirror_match!(@parse $e, $arms; $($tail)*) - }; - - (@parse - $e:expr, ($($arms:tt)*); - mirror!($a:pat, $b:pat) => $body:expr, - $($tail:tt)* - ) => { - mirror_match!( - @parse - $e, - ( - $($arms)* - ($a, $b) | ($b, $a) => $body, - ); - $($tail)* - ) - }; - - (@parse - $e:expr, ($($arms:tt)*); - $pat:pat => $body:expr, - $($tail:tt)* - ) => { - mirror_match!( - @parse - $e, - ( - $($arms)* - $pat => $body, - ); - $($tail)* - ) - }; - - (@parse - $e:expr, ($($arms:tt)*); - $pat:pat => $body:expr, - $($tail:tt)* - ) => { - mirror_match!( - @parse - $e, - ( - $($arms)* - $pat => $body, - ); - $($tail)* - ) - }; - - (($e:expr) { $($arms:tt)* }) => { - mirror_match!(@parse $e, (); $($arms)*) - }; -} - -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -enum Op { - And, - Nand, - - Xor, - Xnor, - - MaterialNonimplication, - MaterialImplication, - - Nor, - Or -} - -impl Op { - fn not(&self) -> Op { - match *self { - And => Nand, - Nand => And, - - Xor => Xnor, - Xnor => Xor, - - Nor => Or, - Or => Nor, - - MaterialNonimplication => MaterialImplication, - MaterialImplication => MaterialNonimplication - } - } - - fn val(&self, a: FieldT, b: FieldT) -> FieldT { - let a = a == FieldT::one(); - let b = b == FieldT::one(); - let res = match *self { - And => a && b, - Nand => !(a && b), - Xor => a != b, - Xnor => a == b, - Or => a || b, - Nor => !(a || b), - MaterialNonimplication => a && (!b), - MaterialImplication => !(a && (!b)) - }; - - if res { - FieldT::one() - } else { - FieldT::zero() - } - } -} - -#[derive(Clone)] -pub struct BinaryOp { - a: Var, - b: Var, - op: Op, - resolved: Rc>> -} - -impl BinaryOp { - fn new(a: Var, b: Var, op: Op) -> BinaryOp { - BinaryOp { - a: a, - b: b, - op: op, - resolved: Rc::new(RefCell::new(None)) - } - } - - fn walk(&self, counter: &mut usize, constraints: &mut Vec, witness_map: &mut WitnessMap) - { - self.a.walk(counter, constraints, witness_map); - self.b.walk(counter, constraints, witness_map); - } - - fn val(&self, map: &[FieldT], inverted: bool) -> FieldT { - let v = self.op.val(self.a.val(map), self.b.val(map)); - - if inverted { - if v == FieldT::one() { - FieldT::zero() - } else { - FieldT::one() - } - } else { - v - } - } - - fn resolve(&self, inverted: bool) -> Bit { - let res = { self.resolved.borrow_mut().clone() }; - - match res { - Some(v) => { - if inverted { - Not(v) - } else { - Is(v) - } - }, - None => { - let v = resolve(&self.a, &self.b, self.op); - - *self.resolved.borrow_mut() = Some(v.clone()); - - if inverted { - Not(v) - } else { - Is(v) - } - } - } - } -} - -#[derive(Clone)] -pub enum Bit { - Constant(bool), - Is(Var), - Not(Var), - Bin(BinaryOp, bool) -} - -struct BitEquality { - a: Bit, - b: Var -} - -impl Constrainable for BitEquality { - type Result = Var; - - fn synthesize(&self, enforce: &Bit) -> Var { - // TODO: currently only support unconditional enforcement - match enforce { - &Bit::Constant(true) => {}, - _ => unimplemented!() - } - - match self.a { - Bin(ref binop, inverted) => { - // TODO: figure this out later - assert!(binop.resolved.borrow().is_none()); - - let mut op = binop.op; - - if inverted { - op = op.not(); - } - - gadget(&[&binop.a, &binop.b, &self.b], 0, move |vals| { - let a = vals.get_input(0); - let b = vals.get_input(1); - - unsafe { vals.set_input(2, op.val(a, b)) }; - }, |i, o, cs| { - cs.push(binaryop_constraint(i[0], i[1], i[2], op)); - - vec![i[2]] - }).remove(0) - }, - _ => unimplemented!() - } - } -} - -impl Equals for Bit { - type Result = BitEquality; - - fn must_equal(&self, other: &Var) -> BitEquality { - BitEquality { - a: self.clone(), - b: other.clone() - } - } -} - -fn binaryop_constraint(a: &Var, b: &Var, c: &Var, op: Op) -> Constraint { - match op { - // a * b = c - And => Constraint(vec![(FieldT::one(), a.clone())], - vec![(FieldT::one(), b.clone())], - vec![(FieldT::one(), c.clone())] - ), - // a * b = 1 - c - Nand => Constraint(vec![(FieldT::one(), a.clone())], - vec![(FieldT::one(), b.clone())], - vec![(FieldT::one(), Var::one()), - (-FieldT::one(), c.clone()) - ] - ), - // 2a * b = a + b - c - Xor => Constraint(vec![(FieldT::from(2), a.clone())], - vec![(FieldT::one(), b.clone())], - vec![(FieldT::one(), a.clone()), - (FieldT::one(), b.clone()), - (-FieldT::one(), c.clone()) - ] - ), - // 2a * b = a + b + c - 1 - Xnor => Constraint(vec![(FieldT::from(2), a.clone())], - vec![(FieldT::one(), b.clone())], - vec![ - (FieldT::one(), a.clone()), - (FieldT::one(), b.clone()), - (FieldT::one(), c.clone()), - (-FieldT::one(), Var::one()) - ] - ), - // a * (1 - b) = c - MaterialNonimplication => Constraint(vec![(FieldT::one(), a.clone())], - vec![(FieldT::one(), Var::one()), - (-FieldT::one(), b.clone()) - ], - vec![(FieldT::one(), c.clone())] - ), - // a * b = a + c - 1 - MaterialImplication => Constraint(vec![(FieldT::one(), a.clone())], - vec![(FieldT::one(), b.clone())], - vec![(FieldT::one(), a.clone()), - (FieldT::one(), c.clone()), - (-FieldT::one(), Var::one()) - ] - ), - // (1 - a) * (1 - b) = c - Nor => Constraint(vec![(FieldT::one(), Var::one()), - (-FieldT::one(), a.clone()) - ], - vec![(FieldT::one(), Var::one()), - (-FieldT::one(), b.clone()) - ], - vec![(FieldT::one(), c.clone())] - ), - // a * b = a + b - c - Or => Constraint(vec![(FieldT::one(), a.clone())], - vec![(FieldT::one(), b.clone())], - vec![(FieldT::one(), a.clone()), - (FieldT::one(), b.clone()), - (-FieldT::one(), c.clone()) - ] - ) - } -} - -fn resolve(a: &Var, b: &Var, op: Op) -> Var { - gadget(&[a, b], 1, move |vals| { - let a = vals.get_input(0); - let b = vals.get_input(1); - - vals.set_output(0, op.val(a, b)); - }, |i, o, cs| { - cs.push(binaryop_constraint(i[0], i[1], o[0], op)); - - vec![o[0]] - }).remove(0) -} - -impl ConstraintWalker for Bit { - fn walk(&self, counter: &mut usize, constraints: &mut Vec, witness_map: &mut WitnessMap) - { - match *self { - Constant(_) => {}, - Not(ref v) => { - v.walk(counter, constraints, witness_map); - }, - Is(ref v) => { - v.walk(counter, constraints, witness_map); - }, - Bin(ref bin, _) => { - bin.walk(counter, constraints, witness_map); - } - } - } -} - -impl Bit { - pub fn val(&self, map: &[FieldT]) -> bool { - match *self { - Constant(c) => c, - Not(ref v) => v.val(map) == FieldT::zero(), - Is(ref v) => v.val(map) == FieldT::one(), - Bin(ref bin, inverted) => bin.val(map, inverted) == FieldT::one() - } - } - - // probably could remove this - pub fn resolve(&self) -> Bit { - match *self { - Bin(ref bin, inverted) => bin.resolve(inverted), - _ => self.clone() - } - } - - pub fn new(v: &Var) -> Bit { - Is(gadget(&[v], 0, |_| {}, |i, o, cs| { - // boolean constraint: - // (1 - a) * a = 0 - cs.push(Constraint(vec![(FieldT::one(), Var::one()), - (-FieldT::one(), i[0].clone())], - vec![(FieldT::one(), i[0].clone())], - vec![(FieldT::zero(), Var::one())] - )); - - vec![i[0]] - }).remove(0)) - } - - pub fn constant(num: bool) -> Bit { - Constant(num) - } - - // self xor other - pub fn xor(&self, other: &Bit) -> Bit { - mirror_match!(((self, other)) { - (&Constant(a), &Constant(b)) => { - Constant(a != b) - }, - mirror!(&Is(ref v), &Constant(a)) => { - if a { - // Anything XOR 1 is the NOT of that thing. - Not(v.clone()) - } else { - // Anything XOR 0 equals that thing. - Is(v.clone()) - } - }, - mirror!(&Not(ref v), &Constant(a)) => { - if a { - // Anything XOR 1 is the NOT of that thing. - Is(v.clone()) - } else { - Not(v.clone()) - } - }, - mirror!(&Bin(ref bin, inverted), &Constant(c)) => { - if c { - // Anything XOR 1 is the NOT of that thing. - Bin(bin.clone(), !inverted) - } else { - Bin(bin.clone(), inverted) - } - }, - mirror!(&Bin(ref bin, inverted), &Is(ref i)) => { - bin.resolve(inverted).xor(&Is(i.clone())) - }, - (&Bin(ref bin1, inverted1), &Bin(ref bin2, inverted2)) => { - bin1.resolve(inverted1).xor(&bin2.resolve(inverted2)) - }, - mirror!(&Bin(ref bin, inverted), &Not(ref n)) => { - bin.resolve(inverted).xor(&Not(n.clone())) - }, - (&Not(ref a), &Not(ref b)) => { - Bin(BinaryOp::new(a.clone(), b.clone(), Xor), false) - }, - mirror!(&Is(ref i), &Not(ref n)) => { - Bin(BinaryOp::new(i.clone(), n.clone(), Xnor), false) - }, - (&Is(ref a), &Is(ref b)) => { - Bin(BinaryOp::new(a.clone(), b.clone(), Xor), false) - }, - }) - } - - pub fn and(&self, other: &Bit) -> Bit { - mirror_match!(((self, other)) { - (&Constant(a), &Constant(b)) => { - Constant(a && b) - }, - mirror!(&Is(ref v), &Constant(a)) => { - if a { - // Anything AND 1 is the identity of that thing - Is(v.clone()) - } else { - // Anything AND 0 is false - Constant(false) - } - }, - mirror!(&Not(ref v), &Constant(a)) => { - if a { - // Anything AND 1 is the identity of that thing - Not(v.clone()) - } else { - // Anything AND 0 is false - Constant(false) - } - }, - mirror!(&Bin(ref bin, inverted), &Constant(c)) => { - if c { - // Anything AND 1 is the identity of that thing - Bin(bin.clone(), inverted) - } else { - // Anything AND 0 is false - Constant(false) - } - }, - mirror!(&Bin(ref bin, inverted), &Is(ref i)) => { - bin.resolve(inverted).and(&Is(i.clone())) - }, - (&Bin(ref bin1, inverted1), &Bin(ref bin2, inverted2)) => { - bin1.resolve(inverted1).and(&bin2.resolve(inverted2)) - }, - mirror!(&Bin(ref bin, inverted), &Not(ref n)) => { - bin.resolve(inverted).and(&Not(n.clone())) - }, - (&Not(ref a), &Not(ref b)) => { - Bin(BinaryOp::new(a.clone(), b.clone(), Nor), false) - }, - mirror!(&Is(ref i), &Not(ref n)) => { - Bin(BinaryOp::new(i.clone(), n.clone(), MaterialNonimplication), false) - }, - (&Is(ref a), &Is(ref b)) => { - Bin(BinaryOp::new(a.clone(), b.clone(), And), false) - }, - }) - } - - // (not self) and other - pub fn notand(&self, other: &Bit) -> Bit { - self.xor(&Constant(true)).and(other) - } -} - -#[cfg(test)] -fn test_binary_op Bit>(op: F, a_in: i64, b_in: i64, c_out: i64) -{ - let a = Var::new(1); - let b = Var::new(2); - let a = Bit::new(&a); - let b = Bit::new(&b); - let mut counter = 3; - let mut witness_map = WitnessMap::new(); - let mut constraints = vec![]; - - let c = op(&a, &b); - let c = c.resolve(); - c.walk(&mut counter, &mut constraints, &mut witness_map); - assert_eq!(counter, 4); - assert_eq!(constraints.len(), 3); - assert_eq!(witness_map.len(), 2); - assert_eq!(witness_map[&1].len(), 2); - assert_eq!(witness_map[&2].len(), 1); - - let mut f: Vec = (0..counter).map(|_| FieldT::zero()).collect(); - f[0] = FieldT::one(); - f[1] = FieldT::from(a_in); - f[2] = FieldT::from(b_in); - - witness_field_elements(&mut f, &witness_map); - - assert_eq!(f[3], FieldT::from(c_out)); -} - -#[test] -fn test_xor() { - use tinysnark; - - tinysnark::init(); - - test_binary_op(Bit::xor, 0, 0, 0); - test_binary_op(Bit::xor, 0, 1, 1); - test_binary_op(Bit::xor, 1, 0, 1); - test_binary_op(Bit::xor, 1, 1, 0); -} - -#[test] -fn test_and() { - use tinysnark; - - tinysnark::init(); - - test_binary_op(Bit::and, 0, 0, 0); - test_binary_op(Bit::and, 0, 1, 0); - test_binary_op(Bit::and, 1, 0, 0); - test_binary_op(Bit::and, 1, 1, 1); -} diff --git a/src/circuit.rs b/src/circuit.rs deleted file mode 100644 index c2f504e..0000000 --- a/src/circuit.rs +++ /dev/null @@ -1,148 +0,0 @@ -use tinysnark::{Proof, Keypair, FieldT, LinearTerm, ConstraintSystem}; -use super::variable::{Var,Constraint,WitnessMap,witness_field_elements}; -use super::bit::Bit; - -pub trait ConstraintWalker: 'static { - fn walk(&self, - counter: &mut usize, - constraints: &mut Vec, - witness_map: &mut WitnessMap); -} - -impl ConstraintWalker for Vec { - fn walk(&self, - counter: &mut usize, - constraints: &mut Vec, - witness_map: &mut WitnessMap) - { - for i in self { - i.walk(counter, constraints, witness_map); - } - } -} - -pub trait Constrainable { - type Result: ConstraintWalker; - - fn synthesize(&self, enforce: &Bit) -> Self::Result; -} - -impl Constrainable for Vec { - type Result = Vec; - - fn synthesize(&self, enforce: &Bit) -> Vec { - self.iter().map(|a| a.synthesize(enforce)).collect() - } -} - -pub trait Equals { - type Result: Constrainable; - - fn must_equal(&self, other: &Rhs) -> Self::Result; -} - -impl Equals<[Rhs]> for [Lhs] where Lhs: Equals { - type Result = Vec; - - fn must_equal(&self, other: &[Rhs]) -> Vec { - assert_eq!(self.len(), other.len()); - - self.iter().zip(other.iter()).map(|(a, b)| a.must_equal(b)).collect() - } -} - -pub struct Circuit { - public_inputs: usize, - private_inputs: usize, - aux_inputs: usize, - keypair: Keypair, - witness_map: WitnessMap -} - -impl Circuit { - pub fn verify(&self, proof: &Proof, public: &[FieldT]) -> bool - { - proof.verify(&self.keypair, public) - } - - pub fn prove(&self, public: &[FieldT], private: &[FieldT]) -> Result - { - assert_eq!(public.len(), self.public_inputs); - assert_eq!(private.len(), self.private_inputs); - - let mut vars = Vec::new(); - vars.push(FieldT::one()); - vars.extend_from_slice(public); - vars.extend_from_slice(private); - - for i in 0..self.aux_inputs { - vars.push(FieldT::zero()); - } - - witness_field_elements(&mut vars, &self.witness_map); - - let primary = &vars[1..public.len()+1]; - let aux = &vars[1+public.len()..]; - - if !self.keypair.is_satisfied(primary, aux) { - return Err(()) - } - - Ok(Proof::new(&self.keypair, primary, aux)) - } -} - -pub struct CircuitBuilder { - public_inputs: usize, - private_inputs: usize, - constraints: Vec> -} - -impl CircuitBuilder { - pub fn new(num_public: usize, num_private: usize) -> (Vec, Vec, CircuitBuilder) { - ( - (0..num_public).map(|x| Var::new(1+x)).collect(), - (0..num_private).map(|x| Var::new(1+num_public+x)).collect(), - CircuitBuilder { - public_inputs: num_public, - private_inputs: num_private, - constraints: Vec::new() - }, - ) - } - - pub fn constrain(&mut self, constraint: C) { - self.constraints.push(Box::new(constraint.synthesize(&Bit::constant(true)))); - } - - pub fn finalize(self) -> Circuit { - let mut counter = 1 + self.public_inputs + self.private_inputs; - let mut constraints = vec![]; - let mut witness_map = WitnessMap::new(); - - for c in self.constraints.into_iter() { - c.walk(&mut counter, &mut constraints, &mut witness_map); - } - - let mut cs = ConstraintSystem::new(self.public_inputs, (counter - 1) - self.public_inputs); - - for Constraint(a, b, c) in constraints { - let a: Vec<_> = a.into_iter().map(|x| LinearTerm { coeff: x.0, index: x.1.index() }).collect(); - let b: Vec<_> = b.into_iter().map(|x| LinearTerm { coeff: x.0, index: x.1.index() }).collect(); - let c: Vec<_> = c.into_iter().map(|x| LinearTerm { coeff: x.0, index: x.1.index() }).collect(); - - cs.add_constraint(&a, &b, &c); - } - - let kp = Keypair::new(&cs); - - Circuit { - public_inputs: self.public_inputs, - private_inputs: self.private_inputs, - aux_inputs: ((counter - 1) - self.public_inputs) - self.private_inputs, - keypair: kp, - witness_map: witness_map - } - } -} - diff --git a/src/keccak.rs b/src/keccak.rs deleted file mode 100644 index 87b2603..0000000 --- a/src/keccak.rs +++ /dev/null @@ -1,415 +0,0 @@ -use super::bit::Bit; -use std::slice::IterMut; - -const KECCAKF_RNDC: [u64; 24] = -[ - 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, - 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, - 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, - 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, - 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, - 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, - 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, - 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 -]; - -const KECCAKF_ROTC: [usize; 24] = -[ - 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, - 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 -]; - -const KECCAKF_PILN: [usize; 24] = -[ - 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, - 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 -]; - -fn keccakf(st: &mut [Byte], rounds: usize) -{ - use std::borrow::Borrow; - - struct State> { - bits: Vec - } - - impl<'a> State<&'a mut Bit> { - fn new(bytes: &'a mut [Byte]) -> State<&'a mut Bit> { - State { - bits: bytes.iter_mut() - .rev() // Endianness - .flat_map(|b| b.iter_mut()) - .collect() - } - } - - fn set(&mut self, to: State) { - for (a, b) in self.bits.iter_mut() - .zip(to.bits.into_iter()) { - **a = b; - } - } - } - - impl From for State { - fn from(num: u64) -> State { - fn bit_at(num: u64, i: usize) -> bool { - ((num << i) >> 63) == 1 - } - - State { - bits: (0..64).map(|i| Bit::constant(bit_at(num, i))).collect() - } - } - } - - impl> State { - fn duplicate(&self) -> State { - State { - bits: self.bits.iter().map(|a| a.borrow()) - .map(|a| (*a).clone()) - .collect() - } - } - - fn binary_map(&self, other: &State, f: F) -> State - where F: Fn(&Bit, &Bit) -> Bit, B: Borrow - { - State { - bits: self.bits.iter().map(|a| a.borrow()) - .zip(other.bits.iter().map(|a| a.borrow())) - .map(|(a, b)| f(a, b)) - .collect() - } - } - - fn xor>(&self, other: &State) -> State { - self.binary_map(other, Bit::xor) - } - - fn notand>(&self, other: &State) -> State { - self.binary_map(other, Bit::notand) - } - - fn rotl(&self, by: usize) -> State { - let by = by % 64; - - State { - bits: self.bits[by..].iter().map(|a| a.borrow()) - .chain(self.bits[0..by].iter().map(|a| a.borrow())) - .cloned() - .collect() - } - } - } - - let mut st: Vec<_> = st.chunks_mut(8).map(|c| State::new(c)).collect(); - - for round in 0..rounds { - /* - // Theta - for (i = 0; i < 5; i++) - bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; - */ - - let mut bc: Vec> = (0..5).map(|i| st[i] - .xor(&st[i+5]) - .xor(&st[i+10]) - .xor(&st[i+15]) - .xor(&st[i+20]) - ).collect(); - - /* - for (i = 0; i < 5; i++) { - t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); - for (j = 0; j < 25; j += 5) - st[j + i] ^= t; - } - */ - - for i in 0..5 { - let tmp = bc[(i + 4) % 5].xor(&bc[(i + 1) % 5].rotl(1)); - - for j in (0..25).filter(|a| a % 5 == 0) { - let new = tmp.xor(&st[j + i]); - st[j + i].set(new); - } - } - - { - /* - // Rho Pi - t = st[1]; - for (i = 0; i < 24; i++) { - j = keccakf_piln[i]; - bc[0] = st[j]; - st[j] = ROTL64(t, keccakf_rotc[i]); - t = bc[0]; - } - */ - let mut tmp = st[1].duplicate(); - - for i in 0..24 { - let j = KECCAKF_PILN[i]; - - bc[0] = st[j].duplicate(); - st[j].set(tmp.rotl(KECCAKF_ROTC[i])); - tmp = bc[0].duplicate(); - } - } - - { - /* - // Chi - for (j = 0; j < 25; j += 5) { - for (i = 0; i < 5; i++) - bc[i] = st[j + i]; - for (i = 0; i < 5; i++) - st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; - } - */ - - for j in (0..25).filter(|a| a % 5 == 0) { - for i in 0..5 { - bc[i] = st[j + i].duplicate(); - } - - for i in 0..5 { - let n = st[j + i].xor(&bc[(i + 1) % 5].notand(&bc[(i + 2) % 5])); - st[j + i].set(n); - } - } - } - - /* - // Iota - st[0] ^= keccakf_rndc[round]; - */ - - let n = st[0].xor(&KECCAKF_RNDC[round].into()); - st[0].set(n); - } -} - -pub fn sha3_256(message: &[Byte]) -> Vec { - // As defined by FIPS202 - keccak(1088, 512, message, 0x06, 32, 24) -} - -fn keccak(rate: usize, capacity: usize, mut input: &[Byte], delimited_suffix: u8, mut mdlen: usize, num_rounds: usize) - -> Vec -{ - use std::cmp::min; - - let mut st: Vec = Some(Byte::new(0)).into_iter().cycle().take(200).collect(); - - let rate_in_bytes = rate / 8; - let mut input_byte_len = input.len(); - let mut block_size = 0; - - if ((rate + capacity) != 1600) || ((rate % 8) != 0) { - panic!("invalid parameters"); - } - - while input_byte_len > 0 { - block_size = min(input_byte_len, rate_in_bytes); - - for i in 0..block_size { - st[i] = st[i].xor(&input[i]); - } - - input = &input[block_size..]; - input_byte_len -= block_size; - - if block_size == rate_in_bytes { - keccakf(&mut st, num_rounds); - block_size = 0; - } - } - - st[block_size] = st[block_size].xor(&Byte::new(delimited_suffix)); - - if ((delimited_suffix & 0x80) != 0) && (block_size == (rate_in_bytes-1)) { - keccakf(&mut st, num_rounds); - } - - st[rate_in_bytes-1] = st[rate_in_bytes-1].xor(&Byte::new(0x80)); - - keccakf(&mut st, num_rounds); - - let mut output = Vec::with_capacity(mdlen); - - while mdlen > 0 { - block_size = min(mdlen, rate_in_bytes); - output.extend_from_slice(&st[0..block_size]); - mdlen -= block_size; - - if mdlen > 0 { - keccakf(&mut st, num_rounds); - } - } - - output.into_iter().flat_map(|byte| byte.bits.into_iter()).collect() -} - -#[test] -fn test_sha3_256() { - use super::circuit::{CircuitBuilder,Equals}; - use super::variable::Var; - use tinysnark::{self,FieldT}; - - let test_vector: Vec<(Vec, [u8; 32])> = vec![ - (vec![0xff], - [0x44,0x4b,0x89,0xec,0xce,0x39,0x5a,0xec,0x5d,0xc9,0x8f,0x19,0xde,0xfd,0x3a,0x23,0xbc,0xa0,0x82,0x2f,0xc7,0x22,0x26,0xf5,0x8c,0xa4,0x6a,0x17,0xee,0xec,0xa4,0x42] - ), - (vec![0x00], - [0x5d,0x53,0x46,0x9f,0x20,0xfe,0xf4,0xf8,0xea,0xb5,0x2b,0x88,0x04,0x4e,0xde,0x69,0xc7,0x7a,0x6a,0x68,0xa6,0x07,0x28,0x60,0x9f,0xc4,0xa6,0x5f,0xf5,0x31,0xe7,0xd0] - ), - (vec![0x30, 0x31, 0x30, 0x31], - [0xe5,0xbf,0x4a,0xd7,0xda,0x2b,0x4d,0x64,0x0d,0x2b,0x8d,0xd3,0xae,0x9b,0x6e,0x71,0xb3,0x6e,0x0f,0x3d,0xb7,0x6a,0x1e,0xc0,0xad,0x6b,0x87,0x2f,0x3e,0xcc,0x2e,0xbc] - ), - (vec![0x30], - [0xf9,0xe2,0xea,0xaa,0x42,0xd9,0xfe,0x9e,0x55,0x8a,0x9b,0x8e,0xf1,0xbf,0x36,0x6f,0x19,0x0a,0xac,0xaa,0x83,0xba,0xd2,0x64,0x1e,0xe1,0x06,0xe9,0x04,0x10,0x96,0xe4] - ), - (vec![0x30,0x30], - [0x2e,0x16,0xaa,0xb4,0x83,0xcb,0x95,0x57,0x7c,0x50,0xd3,0x8c,0x8d,0x0d,0x70,0x40,0xf4,0x67,0x26,0x83,0x23,0x84,0x46,0xc9,0x90,0xba,0xbb,0xca,0x5a,0xe1,0x33,0xc8] - ), - ((0..64).map(|_| 0x30).collect::>(), - [0xc6,0xfd,0xd7,0xa7,0xf7,0x08,0x62,0xb3,0x6a,0x26,0xcc,0xd1,0x47,0x52,0x26,0x80,0x61,0xe9,0x81,0x03,0x29,0x9b,0x28,0xfe,0x77,0x63,0xbd,0x96,0x29,0x92,0x6f,0x4b] - ), - ((0..128).map(|_| 0x30).collect::>(), - [0x99,0x9d,0xb4,0xd4,0x28,0x7b,0x52,0x15,0x20,0x8d,0x11,0xe4,0x0a,0x27,0xca,0x54,0xac,0xa0,0x09,0xb2,0x5c,0x4f,0x7a,0xb9,0x1a,0xd8,0xaa,0x93,0x60,0xf0,0x63,0x71] - ), - ((0..256).map(|_| 0x30).collect::>(), - [0x11,0xea,0x74,0x37,0x7b,0x74,0xf1,0x53,0x9f,0x2e,0xd9,0x0a,0xb8,0xca,0x9e,0xb1,0xe0,0x70,0x8a,0x4b,0xfb,0xad,0x4e,0x81,0xcc,0x77,0xd9,0xa1,0x61,0x9a,0x10,0xdb] - ), - ((0..512).map(|_| 0x30).collect::>(), - [0x1c,0x80,0x1b,0x16,0x3a,0x2a,0xbe,0xd0,0xe8,0x07,0x1e,0x7f,0xf2,0x60,0x4e,0x98,0x11,0x22,0x80,0x54,0x14,0xf3,0xc8,0xfd,0x96,0x59,0x5d,0x7e,0xe1,0xd6,0x54,0xe2] - ), - ((0..64).map(|_| 0x00).collect::>(), - [0x07,0x0f,0xa1,0xab,0x6f,0xcc,0x55,0x7e,0xd1,0x4d,0x42,0x94,0x1f,0x19,0x67,0x69,0x30,0x48,0x55,0x1e,0xb9,0x04,0x2a,0x8d,0x0a,0x05,0x7a,0xfb,0xd7,0x5e,0x81,0xe0] - ), - ]; - - for (i, &(ref message, ref expected)) in test_vector.iter().enumerate() { - let message: Vec = message.iter().map(|a| Byte::new(*a)).collect(); - let result: Vec = sha3_256(&message) - .chunks(8) - .map(|a| Byte::from(a)) - .map(|a| a.unwrap_constant()) - .collect(); - - if &*result != expected { - print!("Got: "); - for i in result.iter() { - print!("0x{:02x},", i); - } - print!("\nExpected: "); - for i in expected.iter() { - print!("0x{:02x},", i); - } - println!(""); - panic!("Hash {} failed!", i+1); - } else { - println!("--- HASH {} SUCCESS ---", i+1); - } - } - - tinysnark::init(); - - for (i, &(ref message, ref expected)) in test_vector.iter().enumerate() { - fn into_bytes(a: &[Var]) -> Vec { - let a: Vec<_> = a.into_iter().map(|a| Bit::new(a)).collect(); - - a.chunks(8).map(|a| Byte::from(a)).collect() - } - - fn into_fieldt(a: &[u8], vars: &mut [FieldT]) { - let mut counter = 0; - - for byte in a { - for bit in (0..8).map(|i| byte & (1 << i) != 0).rev() { - if bit { vars[counter] = FieldT::one() } else { vars[counter] = FieldT::zero() } - counter += 1; - } - } - } - - let (public, private, mut circuit) = CircuitBuilder::new(expected.len() * 8, message.len() * 8); - - let private = into_bytes(&private); - - circuit.constrain(sha3_256(&private).must_equal(&public)); - - let circuit = circuit.finalize(); - - let mut input: Vec = (0..message.len() * 8).map(|_| FieldT::zero()).collect(); - let mut output: Vec = (0..expected.len() * 8).map(|_| FieldT::zero()).collect(); - - into_fieldt(message, &mut input); - into_fieldt(expected, &mut output); - - let proof = circuit.prove(&output, &input).unwrap(); - assert!(circuit.verify(&proof, &output)); - } -} - -#[derive(Clone)] -pub struct Byte { - bits: Vec -} - -impl<'a> From<&'a [Bit]> for Byte { - fn from(a: &'a [Bit]) -> Byte { - assert_eq!(8, a.len()); - - Byte { - bits: a.to_owned() - } - } -} - -impl Byte { - pub fn bits(&self) -> Vec { - self.bits.clone() - } - - pub fn new(byte: u8) -> Byte { - Byte { - bits: (0..8).map(|i| Bit::constant(byte & (1 << i) != 0)) - .rev() - .collect() - } - } - - pub fn iter_mut(&mut self) -> IterMut { - self.bits.iter_mut() - } - - pub fn unwrap_constant(&self) -> u8 { - let mut cur = 7; - let mut acc = 0; - - for bit in &self.bits { - match bit { - &Bit::Constant(true) => { - acc |= 1 << cur; - }, - &Bit::Constant(false) => {}, - _ => panic!("Tried to unwrap a constant from a non-constant") - } - cur -= 1; - } - - acc - } - - pub fn xor(&self, other: &Byte) -> Byte { - Byte { - bits: self.bits.iter() - .zip(other.bits.iter()) - .map(|(a, b)| a.xor(b)) - .collect() - } - } -} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 84773b6..0000000 --- a/src/main.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![feature(iter_arith, btree_range, collections_bound)] - -extern crate tinysnark; -extern crate rand; - -use tinysnark::{Proof, Keypair, FieldT, LinearTerm, ConstraintSystem}; -use variable::*; -use circuit::*; -use keccak::*; -use bit::*; - -mod variable; -mod keccak; -mod bit; -mod circuit; - -fn main() { - -} \ No newline at end of file diff --git a/src/variable.rs b/src/variable.rs deleted file mode 100644 index cdfeff4..0000000 --- a/src/variable.rs +++ /dev/null @@ -1,178 +0,0 @@ -use tinysnark::FieldT; -use std::cell::Cell; -use std::rc::Rc; -use std::collections::BTreeMap; -use super::circuit::ConstraintWalker; - -pub type WitnessMap = BTreeMap, Vec, Rc)>>; - -struct VariableView<'a> { - vars: &'a mut [FieldT], - inputs: &'a [usize], - outputs: &'a [usize] -} - -impl<'a> VariableView<'a> { - /// Sets an output variable at `index` to value `to`. - pub fn set_output(&mut self, index: usize, to: FieldT) { - self.vars[self.outputs[index]] = to; - } - - /// Gets the value of an input variable at `index`. - pub fn get_input(&self, index: usize) -> FieldT { - self.vars[self.inputs[index]] - } - - /// Sets the value of an input variable. This is unsafe - /// because theoretically this should not be necessary, - /// and could cause soundness problems, but I've temporarily - /// done this to make testing easier. - pub fn set_input(&mut self, index: usize, to: FieldT) { - self.vars[self.inputs[index]] = to; - } -} - -use std::collections::Bound::Unbounded; - -pub fn witness_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 mut vars = VariableView { - vars: vars, - inputs: &*i, - outputs: &*o - }; - - f(&mut vars); - } - } -} - -#[derive(Clone)] -pub struct Constraint(pub Vec<(FieldT, Var)>, pub Vec<(FieldT, Var)>, pub Vec<(FieldT, Var)>); - -struct Gadget { - inputs: Vec, - aux: Vec, - witness: Rc, - constraints: Vec, - group: usize, - visited: Cell -} - -impl Gadget { - pub fn walk(&self, counter: &mut usize, constraints: &mut Vec, 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>, - gadget: Option> -} - -impl Var { - // todo: make this not public - pub fn new(i: usize) -> Var { - Var { - index: Rc::new(Cell::new(i)), - gadget: None - } - } - - pub fn one() -> Var { - Var { - index: Rc::new(Cell::new(0)), - gadget: None - } - } - - pub fn index(&self) -> usize { - self.index.get() - } - - 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 - } - } -} - -impl ConstraintWalker for Var { - fn walk(&self, counter: &mut usize, constraints: &mut Vec, witness_map: &mut WitnessMap) { - match self.gadget { - None => {}, - Some(ref g) => g.walk(counter, constraints, witness_map) - } - } -} - -pub fn gadget( - inputs: &[&Var], - aux: usize, - witness: W, - constrain: C -) -> Vec - where C: for<'a> Fn(&[&'a Var], &[&'a Var], &mut Vec) -> Vec<&'a Var>, - W: Fn(&mut VariableView) + '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 - assert!(a.gadget.is_none()); - - a.gadget = Some(gadget.clone()); - a - }).collect() -} diff --git a/tinysnark/.gitignore b/tinysnark/.gitignore deleted file mode 100644 index a9d37c5..0000000 --- a/tinysnark/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -Cargo.lock diff --git a/tinysnark/Cargo.toml b/tinysnark/Cargo.toml deleted file mode 100644 index 57dc0d0..0000000 --- a/tinysnark/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -authors = ["Sean Bowe "] -build = "build.rs" -description = "Tiny libsnark bindings" -documentation = "https://github.com/ebfull/bellman" -homepage = "https://github.com/ebfull/bellman" -license = "MIT" -name = "tinysnark" -repository = "https://github.com/ebfull/bellman" -version = "0.0.1" - -[build-dependencies] -gcc = "0.3" - -[dependencies] -libc = "0.2.4" diff --git a/tinysnark/README.md b/tinysnark/README.md deleted file mode 100644 index 6e311a5..0000000 --- a/tinysnark/README.md +++ /dev/null @@ -1 +0,0 @@ -This is a tiny wrapper around libsnark's r1cs_ppzksnark on ALT_BN128. \ No newline at end of file diff --git a/tinysnark/build.rs b/tinysnark/build.rs deleted file mode 100644 index 5601419..0000000 --- a/tinysnark/build.rs +++ /dev/null @@ -1,40 +0,0 @@ -extern crate gcc; - -fn main() { - // we don't need ate-pairing for ALT_BN128, but - // i'll keep this in case i need it for some reason... - /* - let mut cfg = gcc::Config::new(); - - cfg.cpp(true) - .define("BN_SUPPORT_SNARK", None) - .include("ate-pairing/include") - .include("xbyak") - .file("ate-pairing/src/zm.cpp") - .file("ate-pairing/src/zm2.cpp") - .compile("libzm.a"); - */ - - println!("cargo:rustc-link-lib=gmp"); - println!("cargo:rustc-link-lib=gmpxx"); - - let mut cfg = gcc::Config::new(); - - cfg.cpp(true) - .define("NO_PROCPS", None) - .define("STATIC", None) - .define("CURVE_ALT_BN128", None) - .flag("-std=c++11") - .include("libsnark/src") - .file("tinysnark.cpp") - .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_g1.cpp") - .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_g2.cpp") - .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_init.cpp") - .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_pairing.cpp") - .file("libsnark/src/algebra/curves/alt_bn128/alt_bn128_pp.cpp") - .file("libsnark/src/common/utils.cpp") - .file("libsnark/src/common/profiling.cpp") - ; - - cfg.compile("libtinysnark.a"); -} \ No newline at end of file diff --git a/tinysnark/libsnark b/tinysnark/libsnark deleted file mode 160000 index 0b928a7..0000000 --- a/tinysnark/libsnark +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0b928a7b36717db6f67ff7e1e34dfa3bfaee1c97 diff --git a/tinysnark/src/arith.rs b/tinysnark/src/arith.rs deleted file mode 100644 index c4f52e1..0000000 --- a/tinysnark/src/arith.rs +++ /dev/null @@ -1,98 +0,0 @@ -use libc::{c_ulong, c_long}; -use std::ops::{Neg, Add, Mul}; - -extern "C" { - fn tinysnark_fieldt_zero() -> FieldT; - fn tinysnark_fieldt_one() -> FieldT; - fn tinysnark_fieldt_neg(val: FieldT) -> FieldT; - fn tinysnark_fieldt_inverse(val: FieldT) -> FieldT; - fn tinysnark_fieldt_from_long(val: c_long) -> FieldT; - fn tinysnark_long_from_fieldt(val: FieldT) -> c_ulong; - fn tinysnark_fieldt_mul(a: FieldT, b: FieldT) -> FieldT; - fn tinysnark_fieldt_add(a: FieldT, b: FieldT) -> FieldT; -} - -#[derive(Copy, Clone, Debug)] -#[repr(simd)] -struct EightBytes(u64); - -#[derive(Copy, Clone, Debug)] -#[repr(C)] -pub struct FieldT([u8; 32], [EightBytes; 0]); - -impl FieldT { - #[inline(always)] - pub fn one() -> FieldT { - unsafe { tinysnark_fieldt_one() } - } - - #[inline(always)] - pub fn zero() -> FieldT { - unsafe { tinysnark_fieldt_zero() } - } - - #[inline(always)] - pub fn inverse(self) -> FieldT { - unsafe { tinysnark_fieldt_inverse(self) } - } - - #[cfg(test)] - pub fn debug_equal(&self, is: [u8; 32]) -> bool { - &FieldT(is, []) == self - } -} - -impl From for FieldT { - #[inline(always)] - fn from(num: i64) -> FieldT { - unsafe { tinysnark_fieldt_from_long(num) } - } -} - -impl From for u64 { - #[inline(always)] - fn from(num: FieldT) -> u64 { - unsafe { tinysnark_long_from_fieldt(num) } - } -} - -impl Neg for FieldT { - type Output = FieldT; - - #[inline(always)] - fn neg(self) -> FieldT { - unsafe { tinysnark_fieldt_neg(self) } - } -} - -impl Add for FieldT { - type Output = FieldT; - - #[inline(always)] - fn add(self, other: FieldT) -> FieldT { - unsafe { tinysnark_fieldt_add(self, other) } - } -} - -impl Mul for FieldT { - type Output = FieldT; - - #[inline(always)] - fn mul(self, other: FieldT) -> FieldT { - unsafe { tinysnark_fieldt_mul(self, other) } - } -} - -impl PartialEq for FieldT { - fn eq(&self, other: &FieldT) -> bool { - for i in 0..32 { - if (self.0)[i] != (other.0)[i] { - return false; - } - } - - true - } -} - -impl Eq for FieldT { } diff --git a/tinysnark/src/lib.rs b/tinysnark/src/lib.rs deleted file mode 100644 index 7c90b9f..0000000 --- a/tinysnark/src/lib.rs +++ /dev/null @@ -1,156 +0,0 @@ -#![feature(box_syntax, repr_simd)] -#![allow(improper_ctypes)] -//#![cfg_attr(test, feature(test))] -extern crate libc; - -mod arith; -mod r1cs; - -pub use self::arith::*; -pub use self::r1cs::*; - -use std::sync::{Once, ONCE_INIT}; - -static START: Once = ONCE_INIT; -static mut INITIALIZED: bool = false; - -extern "C" { - fn tinysnark_init_public_params(); - pub fn tinysnark_test(); -} - -pub fn init() { - START.call_once(|| { - unsafe { tinysnark_init_public_params(); } - unsafe { INITIALIZED = true; } - }); -} - -pub fn is_initialized() -> bool { - unsafe { INITIALIZED } -} - -#[cfg(test)] -mod tests { - //extern crate test; - use super::{init, FieldT, Proof, Keypair, LinearTerm, ConstraintSystem}; - //use self::test::Bencher; - - #[test] - fn test_zk() { - fn test_cs_and_prove + Copy>(cs: &ConstraintSystem, primary: &[N], aux: &[N]) -> bool - { - let primary: Vec = primary.iter().map(|n| (*n).into()).collect(); - let aux: Vec = aux.iter().map(|n| (*n).into()).collect(); - - if !cs.test(&primary, &aux) { - return false; - } - - let kp = Keypair::new(cs); - let proof = Proof::new(&kp, &primary, &aux); - // If we construct a proof, it should be impossible - // that it doesn't verify. - assert!(proof.verify(&kp, &primary)); - - return true; - } - - init(); - { - let mut cs = ConstraintSystem::new(1, 2); - // zkpok { (a, b) c = a * b } - cs.add_constraint( - &[LinearTerm{coeff: FieldT::one(), index: 2}], - &[LinearTerm{coeff: FieldT::one(), index: 3}], - &[LinearTerm{coeff: FieldT::one(), index: 1}] - ); - - assert!(test_cs_and_prove(&cs, &[1], &[1, 1])); - assert!(test_cs_and_prove(&cs, &[0], &[0, 1])); - assert!(test_cs_and_prove(&cs, &[10], &[5, 2])); - assert!(!test_cs_and_prove(&cs, &[10], &[6, 2])); - } - { - let mut cs = ConstraintSystem::new(0, 1); - // simple boolean constraint - // (1-x) * x = 0 - cs.add_constraint( - &[LinearTerm{coeff: FieldT::one(), index: 0}, - LinearTerm{coeff: -FieldT::one(), index: 1}], - &[LinearTerm{coeff: FieldT::one(), index: 1}], - &[LinearTerm{coeff: FieldT::zero(), index: 0}] - ); - - assert!(test_cs_and_prove(&cs, &[], &[0])); - assert!(test_cs_and_prove(&cs, &[], &[1])); - assert!(!test_cs_and_prove(&cs, &[], &[2])); - } - { - let mut cs = ConstraintSystem::new(2, 1); - // boolean + xor - cs.add_constraint( - &[LinearTerm{coeff: FieldT::one(), index: 0}, - LinearTerm{coeff: -FieldT::one(), index: 3}], - &[LinearTerm{coeff: FieldT::one(), index: 3}], - &[LinearTerm{coeff: FieldT::zero(), index: 0}] - ); - cs.add_constraint( - &[LinearTerm{coeff: FieldT::from(2), index: 2}], - &[LinearTerm{coeff: FieldT::one(), index: 3}], - &[LinearTerm{coeff: FieldT::one(), index: 2}, - LinearTerm{coeff: FieldT::one(), index: 3}, - LinearTerm{coeff: -FieldT::one(), index: 1}] - ); - - assert!(test_cs_and_prove(&cs, &[0, 0], &[0])); - assert!(test_cs_and_prove(&cs, &[1, 1], &[0])); - assert!(test_cs_and_prove(&cs, &[1, 0], &[1])); - assert!(test_cs_and_prove(&cs, &[0, 1], &[1])); - assert!(!test_cs_and_prove(&cs, &[0, 1], &[100])); - } - } - - #[test] - fn test_one() { - init(); - let one = FieldT::one(); - let negone = -one; - let newone = -negone; - - assert!(one == newone); - assert!(one != negone); - assert!(newone != negone); - - assert_eq!(one, 1.into()); - assert_eq!(negone, (-1).into()); - - assert!(one.debug_equal([251, 255, 255, 79, 28, 52, 150, 172, 41, 205, 96, 159, 149, 118, 252, 54, 46, 70, 121, 120, 111, 163, 110, 102, 47, 223, 7, 154, 193, 119, 10, 14])); - assert!(negone.debug_equal([6, 0, 0, 160, 119, 193, 75, 151, 103, 163, 88, 218, 178, 113, 55, 241, 46, 18, 8, 9, 71, 162, 225, 81, 250, 192, 41, 71, 177, 214, 89, 34])); - } - - #[test] - fn test_math() { - init(); - - assert_eq!(FieldT::one() + 10.into(), 11.into()); - assert_eq!(FieldT::from(2) + 2.into(), FieldT::from(2) * 2.into()); - assert_eq!(FieldT::from(2), FieldT::from(-1) + FieldT::one() * 3.into()); - - assert_eq!(FieldT::one(), FieldT::from(100) * FieldT::from(100).inverse()); - } - - #[test] - fn test_conversions() { - init(); - - for i in 0..10000 { - let num: FieldT = i.into(); - let back: u64 = num.into(); - - assert_eq!(i, back as i64); - } - - assert_eq!(u64::from(FieldT::from(-1)), 4891460686036598784); - } -} \ No newline at end of file diff --git a/tinysnark/src/r1cs.rs b/tinysnark/src/r1cs.rs deleted file mode 100644 index 9916003..0000000 --- a/tinysnark/src/r1cs.rs +++ /dev/null @@ -1,158 +0,0 @@ -use libc::{size_t}; -use super::arith::FieldT; - -#[repr(C)] -struct R1ConstraintSystem; - -#[repr(C)] -pub struct LinearTerm { - pub coeff: FieldT, - pub index: size_t -} - -extern "C" { - fn tinysnark_new_r1cs(primary: size_t, aux: size_t) -> *mut R1ConstraintSystem; - fn tinysnark_drop_r1cs(cs: *mut R1ConstraintSystem); - fn tinysnark_satisfy_test(cs: *mut R1ConstraintSystem, primary: *const FieldT, aux: *const FieldT) -> bool; - fn tinysnark_add_constraint(cs: *mut R1ConstraintSystem, - a: *const LinearTerm, - a_len: size_t, - b: *const LinearTerm, - b_len: size_t, - c: *const LinearTerm, - c_len: size_t - ); -} - -pub struct ConstraintSystem { - cs: *mut R1ConstraintSystem, - primary_size: usize, - aux_size: usize -} - -impl Drop for ConstraintSystem { - fn drop(&mut self) { - unsafe { tinysnark_drop_r1cs(self.cs) } - } -} - -impl ConstraintSystem { - pub fn new(primary_size: usize, aux_size: usize) -> ConstraintSystem { - ConstraintSystem { - cs: unsafe { tinysnark_new_r1cs(primary_size, aux_size) }, - primary_size: primary_size, - aux_size: aux_size - } - } - - pub fn add_constraint(&mut self, a: &[LinearTerm], b: &[LinearTerm], c: &[LinearTerm]) - { - unsafe { - tinysnark_add_constraint( - self.cs, - a.get_unchecked(0), - a.len(), - b.get_unchecked(0), - b.len(), - c.get_unchecked(0), - c.len() - ); - } - } - - pub fn test(&self, primary: &[FieldT], aux: &[FieldT]) -> bool - { - assert_eq!(primary.len(), self.primary_size); - assert_eq!(aux.len(), self.aux_size); - - unsafe { - tinysnark_satisfy_test(self.cs, primary.get_unchecked(0), aux.get_unchecked(0)) - } - } -} - -#[repr(C)] -struct R1CSKeypair; - -pub struct Keypair { - kp: *mut R1CSKeypair, - primary_size: usize, - aux_size: usize -} - -impl Keypair { - pub fn new(constraint_system: &ConstraintSystem) -> Keypair { - Keypair { - kp: unsafe { tinysnark_gen_keypair(constraint_system.cs) }, - primary_size: constraint_system.primary_size, - aux_size: constraint_system.aux_size - } - } - - pub fn is_satisfied(&self, primary: &[FieldT], aux: &[FieldT]) -> bool { - assert_eq!(primary.len(), self.primary_size); - assert_eq!(aux.len(), self.aux_size); - - unsafe { - tinysnark_keypair_satisfies_test(self.kp, primary.get_unchecked(0), aux.get_unchecked(0)) - } - } -} - -impl Drop for Keypair { - fn drop(&mut self) { - unsafe { tinysnark_drop_keypair(self.kp) } - } -} - -extern "C" { - fn tinysnark_gen_keypair(cs: *mut R1ConstraintSystem) -> *mut R1CSKeypair; - fn tinysnark_drop_keypair(cs: *mut R1CSKeypair); - fn tinysnark_keypair_satisfies_test(kp: *mut R1CSKeypair, primary: *const FieldT, aux: *const FieldT) -> bool; -} - -#[repr(C)] -struct R1CSProof; - -pub struct Proof { - proof: *mut R1CSProof -} - -impl Proof { - pub fn new(keypair: &Keypair, primary: &[FieldT], aux: &[FieldT]) - -> Proof - { - assert_eq!(primary.len(), keypair.primary_size); - assert_eq!(aux.len(), keypair.aux_size); - - unsafe { - Proof { - proof: tinysnark_gen_proof(keypair.kp, primary.get_unchecked(0), aux.get_unchecked(0)) - } - } - } - - pub fn verify(&self, keypair: &Keypair, primary: &[FieldT]) -> bool { - assert_eq!(primary.len(), keypair.primary_size); - - unsafe { - tinysnark_verify_proof(self.proof, keypair.kp, primary.get_unchecked(0)) - } - } -} - -impl Drop for Proof { - fn drop(&mut self) { - unsafe { tinysnark_drop_proof(self.proof) } - } -} - -extern "C" { - fn tinysnark_gen_proof(keypair: *mut R1CSKeypair, - primary: *const FieldT, - aux: *const FieldT) -> *mut R1CSProof; - fn tinysnark_verify_proof(proof: *mut R1CSProof, - keypair: *mut R1CSKeypair, - primary: *const FieldT) -> bool; - fn tinysnark_drop_proof(proof: *mut R1CSProof); -} \ No newline at end of file diff --git a/tinysnark/tinysnark.cpp b/tinysnark/tinysnark.cpp deleted file mode 100644 index 0a01465..0000000 --- a/tinysnark/tinysnark.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* -This is a wrapper around libsnark which provides basic R1CS -zk-SNARK support using the ALT_BN128 curve. -*/ - -#include "gadgetlib1/gadgets/basic_gadgets.hpp" -#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" -#include "common/default_types/r1cs_ppzksnark_pp.hpp" -#include "common/utils.hpp" -#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" - -using namespace libsnark; -using namespace std; - -typedef Fr FieldT; - -struct tinysnark_linear_term { - FieldT coeff; - size_t index; -}; - -extern "C" void * tinysnark_gen_proof(void * kp, FieldT* primary, FieldT* aux) { - r1cs_ppzksnark_keypair* keypair = static_cast*>(kp); - - r1cs_primary_input primary_input(primary, primary+(keypair->pk.constraint_system.primary_input_size)); - r1cs_auxiliary_input aux_input(aux, aux+(keypair->pk.constraint_system.auxiliary_input_size)); - - auto proof = new r1cs_ppzksnark_proof( - r1cs_ppzksnark_prover(keypair->pk, primary_input, aux_input) - ); - - return static_cast(std::move(proof)); -} - -extern "C" bool tinysnark_verify_proof(void * iproof, void * kp, FieldT* primary) { - r1cs_ppzksnark_proof* proof = static_cast*>(iproof); - r1cs_ppzksnark_keypair* keypair = static_cast*>(kp); - - r1cs_primary_input primary_input(primary, primary+(keypair->pk.constraint_system.primary_input_size)); - - return r1cs_ppzksnark_verifier_strong_IC(keypair->vk, primary_input, *proof); -} - -extern "C" void * tinysnark_drop_proof(void * proof) { - r1cs_ppzksnark_proof* p = static_cast*>(proof); - - delete p; -} - -extern "C" void * tinysnark_gen_keypair(void * ics) { - r1cs_constraint_system* cs = static_cast*>(ics); - - auto keypair = new r1cs_ppzksnark_keypair( - r1cs_ppzksnark_generator(*cs) - ); - - return static_cast(std::move(keypair)); -} - -extern "C" void * tinysnark_drop_keypair(void * kp) { - r1cs_ppzksnark_keypair* k = static_cast*>(kp); - - delete k; -} - -extern "C" void * tinysnark_new_r1cs(size_t primary_size, size_t aux_size) { - auto cs = new r1cs_constraint_system(); - - cs->primary_input_size = primary_size; - cs->auxiliary_input_size = aux_size; - - return static_cast(std::move(cs)); -} - -extern "C" void tinysnark_drop_r1cs(void * ics) { - r1cs_constraint_system* cs = static_cast*>(ics); - - delete cs; -} - -extern "C" bool tinysnark_keypair_satisfies_test(void * kp, FieldT* primary, FieldT* aux) -{ - r1cs_ppzksnark_keypair* keypair = static_cast*>(kp); - - r1cs_constraint_system* cs = &keypair->pk.constraint_system; - - r1cs_primary_input primary_input(primary, primary+(cs->primary_input_size)); - r1cs_auxiliary_input aux_input(aux, aux+(cs->auxiliary_input_size)); - - return cs->is_valid() && cs->is_satisfied(primary_input, aux_input); -} - -extern "C" bool tinysnark_satisfy_test(void * ics, FieldT* primary, FieldT* aux) { - r1cs_constraint_system* cs = static_cast*>(ics); - - r1cs_primary_input primary_input(primary, primary+(cs->primary_input_size)); - r1cs_auxiliary_input aux_input(aux, aux+(cs->auxiliary_input_size)); - - return cs->is_valid() && cs->is_satisfied(primary_input, aux_input); -} - -extern "C" void * tinysnark_add_constraint( - void * ics, - tinysnark_linear_term * a_terms, - size_t a_terms_len, - tinysnark_linear_term * b_terms, - size_t b_terms_len, - tinysnark_linear_term * c_terms, - size_t c_terms_len -) { - r1cs_constraint_system* cs = static_cast*>(ics); - - std::vector> a; - std::vector> b; - std::vector> c; - - for (size_t i = 0; i < a_terms_len; i++) { - FieldT coeff = a_terms[i].coeff; - size_t index = a_terms[i].index; - - a.push_back(linear_term(variable(index), coeff)); - } - - for (size_t i = 0; i < b_terms_len; i++) { - FieldT coeff = b_terms[i].coeff; - size_t index = b_terms[i].index; - - b.push_back(linear_term(variable(index), coeff)); - } - - for (size_t i = 0; i < c_terms_len; i++) { - FieldT coeff = c_terms[i].coeff; - size_t index = c_terms[i].index; - - c.push_back(linear_term(variable(index), coeff)); - } - - linear_combination a_lc(a); - linear_combination b_lc(b); - linear_combination c_lc(c); - - r1cs_constraint constraint(a_lc, b_lc, c_lc); - - cs->add_constraint(constraint); -} - -extern "C" FieldT tinysnark_fieldt_mul(FieldT a, FieldT b) { - return a * b; -} - -extern "C" FieldT tinysnark_fieldt_add(FieldT a, FieldT b) { - return a + b; -} - -extern "C" unsigned long tinysnark_long_from_fieldt(FieldT num) { - return num.as_bigint().as_ulong(); -} - -extern "C" FieldT tinysnark_fieldt_from_long(long num) { - return FieldT(num); -} - -extern "C" FieldT tinysnark_fieldt_one() { - return FieldT::one(); -} - -extern "C" FieldT tinysnark_fieldt_zero() { - return FieldT::zero(); -} - -extern "C" FieldT tinysnark_fieldt_neg(FieldT val) { - return -val; -} - -extern "C" FieldT tinysnark_fieldt_inverse(FieldT val) { - return val.inverse(); -} - -extern "C" void tinysnark_init_public_params() { - default_r1cs_ppzksnark_pp::init_public_params(); - { - auto p = FieldT::one(); - assert(sizeof(p) == 32); - } -} - - - -extern "C" void tinysnark_test() { - typedef Fr FieldT; - - protoboard pb; - - auto input_bits = new digest_variable(pb, 512, "input_bits"); - auto output_bits = new digest_variable(pb, 256, "output_bits"); - auto input_block = new block_variable(pb, { - input_bits->bits - }, "input_block"); - auto IV = SHA256_default_IV(pb); - auto sha256 = new sha256_compression_function_gadget(pb, - IV, - input_block->bits, - *output_bits, - "sha256"); - - input_bits->generate_r1cs_constraints(); - output_bits->generate_r1cs_constraints(); - sha256->generate_r1cs_constraints(); - - const r1cs_constraint_system constraint_system = pb.get_constraint_system(); - - cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl; -} \ No newline at end of file