From e73d1a2637268209ad6a3f098133fadc143f1779 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Thu, 15 Aug 2019 10:38:41 -0600 Subject: [PATCH] cargo fmt bellman --- src/domain.rs | 101 +-- src/gadgets.rs | 14 +- src/gadgets/blake2s.rs | 238 ++++-- src/gadgets/boolean.rs | 1203 ++++++++++++++++------------- src/gadgets/lookup.rs | 193 +++-- src/gadgets/multieq.rs | 76 +- src/gadgets/multipack.rs | 79 +- src/gadgets/num.rs | 289 +++---- src/gadgets/sha256.rs | 231 +++--- src/gadgets/test/mod.rs | 199 +++-- src/gadgets/uint32.rs | 383 +++++---- src/groth16/generator.rs | 211 ++--- src/groth16/mod.rs | 322 ++++---- src/groth16/prover.rs | 189 +++-- src/groth16/tests/dummy_engine.rs | 45 +- src/groth16/tests/mod.rs | 166 ++-- src/groth16/verifier.rs | 35 +- src/lib.rs | 180 ++--- src/multicore.rs | 47 +- src/multiexp.rs | 120 +-- tests/mimc.rs | 96 +-- 21 files changed, 2252 insertions(+), 2165 deletions(-) diff --git a/src/domain.rs b/src/domain.rs index 5d7d50009..808d2afd5 100644 --- a/src/domain.rs +++ b/src/domain.rs @@ -13,9 +13,7 @@ use ff::{Field, PrimeField, ScalarEngine}; use group::CurveProjective; -use super::{ - SynthesisError -}; +use super::SynthesisError; use super::multicore::Worker; @@ -25,7 +23,7 @@ pub struct EvaluationDomain> { omega: E::Fr, omegainv: E::Fr, geninv: E::Fr, - minv: E::Fr + minv: E::Fr, } impl> EvaluationDomain { @@ -41,8 +39,7 @@ impl> EvaluationDomain { self.coeffs } - pub fn from_coeffs(mut coeffs: Vec) -> Result, SynthesisError> - { + pub fn from_coeffs(mut coeffs: Vec) -> Result, SynthesisError> { // Compute the size of our evaluation domain let mut m = 1; let mut exp = 0; @@ -53,7 +50,7 @@ impl> EvaluationDomain { // The pairing-friendly curve may not be able to support // large enough (radix2) evaluation domains. if exp >= E::Fr::S { - return Err(SynthesisError::PolynomialDegreeTooLarge) + return Err(SynthesisError::PolynomialDegreeTooLarge); } } @@ -72,17 +69,18 @@ impl> EvaluationDomain { omega: omega, omegainv: omega.inverse().unwrap(), geninv: E::Fr::multiplicative_generator().inverse().unwrap(), - minv: E::Fr::from_str(&format!("{}", m)).unwrap().inverse().unwrap() + minv: E::Fr::from_str(&format!("{}", m)) + .unwrap() + .inverse() + .unwrap(), }) } - pub fn fft(&mut self, worker: &Worker) - { + pub fn fft(&mut self, worker: &Worker) { best_fft(&mut self.coeffs, worker, &self.omega, self.exp); } - pub fn ifft(&mut self, worker: &Worker) - { + pub fn ifft(&mut self, worker: &Worker) { best_fft(&mut self.coeffs, worker, &self.omegainv, self.exp); worker.scope(self.coeffs.len(), |scope, chunk| { @@ -98,8 +96,7 @@ impl> EvaluationDomain { }); } - pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) - { + pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) { worker.scope(self.coeffs.len(), |scope, chunk| { for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() { scope.spawn(move || { @@ -113,14 +110,12 @@ impl> EvaluationDomain { }); } - pub fn coset_fft(&mut self, worker: &Worker) - { + pub fn coset_fft(&mut self, worker: &Worker) { self.distribute_powers(worker, E::Fr::multiplicative_generator()); self.fft(worker); } - pub fn icoset_fft(&mut self, worker: &Worker) - { + pub fn icoset_fft(&mut self, worker: &Worker) { let geninv = self.geninv; self.ifft(worker); @@ -139,9 +134,11 @@ impl> EvaluationDomain { /// The target polynomial is the zero polynomial in our /// evaluation domain, so we must perform division over /// a coset. - pub fn divide_by_z_on_coset(&mut self, worker: &Worker) - { - let i = self.z(&E::Fr::multiplicative_generator()).inverse().unwrap(); + pub fn divide_by_z_on_coset(&mut self, worker: &Worker) { + let i = self + .z(&E::Fr::multiplicative_generator()) + .inverse() + .unwrap(); worker.scope(self.coeffs.len(), |scope, chunk| { for v in self.coeffs.chunks_mut(chunk) { @@ -159,7 +156,11 @@ impl> EvaluationDomain { assert_eq!(self.coeffs.len(), other.coeffs.len()); worker.scope(self.coeffs.len(), |scope, chunk| { - for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) { + for (a, b) in self + .coeffs + .chunks_mut(chunk) + .zip(other.coeffs.chunks(chunk)) + { scope.spawn(move || { for (a, b) in a.iter_mut().zip(b.iter()) { a.group_mul_assign(&b.0); @@ -174,7 +175,11 @@ impl> EvaluationDomain { assert_eq!(self.coeffs.len(), other.coeffs.len()); worker.scope(self.coeffs.len(), |scope, chunk| { - for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) { + for (a, b) in self + .coeffs + .chunks_mut(chunk) + .zip(other.coeffs.chunks(chunk)) + { scope.spawn(move || { for (a, b) in a.iter_mut().zip(b.iter()) { a.group_sub_assign(&b); @@ -200,7 +205,7 @@ impl PartialEq for Point { } } -impl Copy for Point { } +impl Copy for Point {} impl Clone for Point { fn clone(&self) -> Point { @@ -231,7 +236,7 @@ impl PartialEq for Scalar { } } -impl Copy for Scalar { } +impl Copy for Scalar {} impl Clone for Scalar { fn clone(&self) -> Scalar { @@ -254,8 +259,7 @@ impl Group for Scalar { } } -fn best_fft>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) -{ +fn best_fft>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) { let log_cpus = worker.log_num_cpus(); if log_n <= log_cpus { @@ -265,8 +269,7 @@ fn best_fft>(a: &mut [T], worker: &Worker, omega: & } } -fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u32) -{ +fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u32) { fn bitreverse(mut n: u32, l: u32) -> u32 { let mut r = 0; for _ in 0..l { @@ -288,22 +291,22 @@ fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u let mut m = 1; for _ in 0..log_n { - let w_m = omega.pow(&[(n / (2*m)) as u64]); + let w_m = omega.pow(&[(n / (2 * m)) as u64]); let mut k = 0; while k < n { let mut w = E::Fr::one(); for j in 0..m { - let mut t = a[(k+j+m) as usize]; + let mut t = a[(k + j + m) as usize]; t.group_mul_assign(&w); - let mut tmp = a[(k+j) as usize]; + let mut tmp = a[(k + j) as usize]; tmp.group_sub_assign(&t); - a[(k+j+m) as usize] = tmp; - a[(k+j) as usize].group_add_assign(&t); + a[(k + j + m) as usize] = tmp; + a[(k + j) as usize].group_add_assign(&t); w.mul_assign(&w_m); } - k += 2*m; + k += 2 * m; } m *= 2; @@ -315,9 +318,8 @@ fn parallel_fft>( worker: &Worker, omega: &E::Fr, log_n: u32, - log_cpus: u32 -) -{ + log_cpus: u32, +) { assert!(log_n >= log_cpus); let num_cpus = 1 << log_cpus; @@ -377,14 +379,17 @@ fn polynomial_arith() { use pairing::bls12_381::Bls12; use rand_core::RngCore; - fn test_mul(rng: &mut R) - { + fn test_mul(rng: &mut R) { let worker = Worker::new(); for coeffs_a in 0..70 { for coeffs_b in 0..70 { - let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::(E::Fr::random(rng))).collect(); - let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::(E::Fr::random(rng))).collect(); + let mut a: Vec<_> = (0..coeffs_a) + .map(|_| Scalar::(E::Fr::random(rng))) + .collect(); + let mut b: Vec<_> = (0..coeffs_b) + .map(|_| Scalar::(E::Fr::random(rng))) + .collect(); // naive evaluation let mut naive = vec![Scalar(E::Fr::zero()); coeffs_a + coeffs_b]; @@ -425,8 +430,7 @@ fn fft_composition() { use pairing::bls12_381::Bls12; use rand_core::RngCore; - fn test_comp(rng: &mut R) - { + fn test_comp(rng: &mut R) { let worker = Worker::new(); for coeffs in 0..10 { @@ -465,19 +469,20 @@ fn parallel_fft_consistency() { use rand_core::RngCore; use std::cmp::min; - fn test_consistency(rng: &mut R) - { + fn test_consistency(rng: &mut R) { let worker = Worker::new(); for _ in 0..5 { for log_d in 0..10 { let d = 1 << log_d; - let v1 = (0..d).map(|_| Scalar::(E::Fr::random(rng))).collect::>(); + let v1 = (0..d) + .map(|_| Scalar::(E::Fr::random(rng))) + .collect::>(); let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap(); let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).unwrap(); - for log_cpus in log_d..min(log_d+1, 3) { + for log_cpus in log_d..min(log_d + 1, 3) { parallel_fft(&mut v1.coeffs, &worker, &v1.omega, log_d, log_cpus); serial_fft(&mut v2.coeffs, &v2.omega, log_d); diff --git a/src/gadgets.rs b/src/gadgets.rs index 6c4b09cff..cf366df37 100644 --- a/src/gadgets.rs +++ b/src/gadgets.rs @@ -1,17 +1,15 @@ pub mod test; -pub mod boolean; -pub mod multieq; -pub mod uint32; pub mod blake2s; -pub mod num; +pub mod boolean; pub mod lookup; +pub mod multieq; pub mod multipack; +pub mod num; pub mod sha256; +pub mod uint32; -use crate::{ - SynthesisError -}; +use crate::SynthesisError; // TODO: This should probably be removed and we // should use existing helper methods on `Option` @@ -27,7 +25,7 @@ impl Assignment for Option { fn get(&self) -> Result<&T, SynthesisError> { match *self { Some(ref v) => Ok(v), - None => Err(SynthesisError::AssignmentMissing) + None => Err(SynthesisError::AssignmentMissing), } } } diff --git a/src/gadgets/blake2s.rs b/src/gadgets/blake2s.rs index cef50ebb1..c5cee23c9 100644 --- a/src/gadgets/blake2s.rs +++ b/src/gadgets/blake2s.rs @@ -1,19 +1,10 @@ -use pairing::{ - Engine, -}; +use pairing::Engine; -use crate::{ - SynthesisError, - ConstraintSystem -}; +use crate::{ConstraintSystem, SynthesisError}; -use super::boolean::{ - Boolean -}; +use super::boolean::Boolean; -use super::uint32::{ - UInt32 -}; +use super::uint32::UInt32; use super::multieq::MultiEq; @@ -65,7 +56,7 @@ const SIGMA: [[usize; 16]; 10] = [ [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], - [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0] + [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], ]; /* @@ -98,17 +89,30 @@ fn mixing_g, M>( c: usize, d: usize, x: &UInt32, - y: &UInt32 + y: &UInt32, ) -> Result<(), SynthesisError> - where M: ConstraintSystem> +where + M: ConstraintSystem>, { - v[a] = UInt32::addmany(cs.namespace(|| "mixing step 1"), &[v[a].clone(), v[b].clone(), x.clone()])?; + v[a] = UInt32::addmany( + cs.namespace(|| "mixing step 1"), + &[v[a].clone(), v[b].clone(), x.clone()], + )?; v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1); - v[c] = UInt32::addmany(cs.namespace(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?; + v[c] = UInt32::addmany( + cs.namespace(|| "mixing step 3"), + &[v[c].clone(), v[d].clone()], + )?; v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2); - v[a] = UInt32::addmany(cs.namespace(|| "mixing step 5"), &[v[a].clone(), v[b].clone(), y.clone()])?; + v[a] = UInt32::addmany( + cs.namespace(|| "mixing step 5"), + &[v[a].clone(), v[b].clone(), y.clone()], + )?; v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3); - v[c] = UInt32::addmany(cs.namespace(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?; + v[c] = UInt32::addmany( + cs.namespace(|| "mixing step 7"), + &[v[c].clone(), v[d].clone()], + )?; v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4); Ok(()) @@ -162,15 +166,13 @@ fn mixing_g, M>( END FUNCTION. */ - fn blake2s_compression>( mut cs: CS, h: &mut [UInt32], m: &[UInt32], t: u64, - f: bool -) -> Result<(), SynthesisError> -{ + f: bool, +) -> Result<(), SynthesisError> { assert_eq!(h.len(), 8); assert_eq!(m.len(), 16); @@ -196,10 +198,16 @@ fn blake2s_compression>( assert_eq!(v.len(), 16); v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?; - v[13] = v[13].xor(cs.namespace(|| "second xor"), &UInt32::constant((t >> 32) as u32))?; + v[13] = v[13].xor( + cs.namespace(|| "second xor"), + &UInt32::constant((t >> 32) as u32), + )?; if f { - v[14] = v[14].xor(cs.namespace(|| "third xor"), &UInt32::constant(u32::max_value()))?; + v[14] = v[14].xor( + cs.namespace(|| "third xor"), + &UInt32::constant(u32::max_value()), + )?; } { @@ -210,20 +218,92 @@ fn blake2s_compression>( let s = SIGMA[i % 10]; - mixing_g(cs.namespace(|| "mixing invocation 1"), &mut v, 0, 4, 8, 12, &m[s[ 0]], &m[s[ 1]])?; - mixing_g(cs.namespace(|| "mixing invocation 2"), &mut v, 1, 5, 9, 13, &m[s[ 2]], &m[s[ 3]])?; - mixing_g(cs.namespace(|| "mixing invocation 3"), &mut v, 2, 6, 10, 14, &m[s[ 4]], &m[s[ 5]])?; - mixing_g(cs.namespace(|| "mixing invocation 4"), &mut v, 3, 7, 11, 15, &m[s[ 6]], &m[s[ 7]])?; + mixing_g( + cs.namespace(|| "mixing invocation 1"), + &mut v, + 0, + 4, + 8, + 12, + &m[s[0]], + &m[s[1]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 2"), + &mut v, + 1, + 5, + 9, + 13, + &m[s[2]], + &m[s[3]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 3"), + &mut v, + 2, + 6, + 10, + 14, + &m[s[4]], + &m[s[5]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 4"), + &mut v, + 3, + 7, + 11, + 15, + &m[s[6]], + &m[s[7]], + )?; - mixing_g(cs.namespace(|| "mixing invocation 5"), &mut v, 0, 5, 10, 15, &m[s[ 8]], &m[s[ 9]])?; - mixing_g(cs.namespace(|| "mixing invocation 6"), &mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?; - mixing_g(cs.namespace(|| "mixing invocation 7"), &mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?; - mixing_g(cs.namespace(|| "mixing invocation 8"), &mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?; + mixing_g( + cs.namespace(|| "mixing invocation 5"), + &mut v, + 0, + 5, + 10, + 15, + &m[s[8]], + &m[s[9]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 6"), + &mut v, + 1, + 6, + 11, + 12, + &m[s[10]], + &m[s[11]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 7"), + &mut v, + 2, + 7, + 8, + 13, + &m[s[12]], + &m[s[13]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 8"), + &mut v, + 3, + 4, + 9, + 14, + &m[s[14]], + &m[s[15]], + )?; } } for i in 0..8 { - let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i=i)); + let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i = i)); h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?; h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?; @@ -262,9 +342,8 @@ fn blake2s_compression>( pub fn blake2s>( mut cs: CS, input: &[Boolean], - personalization: &[u8] -) -> Result, SynthesisError> -{ + personalization: &[u8], +) -> Result, SynthesisError> { use byteorder::{ByteOrder, LittleEndian}; assert_eq!(personalization.len(), 8); @@ -279,8 +358,12 @@ pub fn blake2s>( h.push(UInt32::constant(0x9B05688C)); // Personalization is stored here - h.push(UInt32::constant(0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]))); - h.push(UInt32::constant(0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]))); + h.push(UInt32::constant( + 0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]), + )); + h.push(UInt32::constant( + 0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]), + )); let mut blocks: Vec> = vec![]; @@ -312,7 +395,13 @@ pub fn blake2s>( { let cs = cs.namespace(|| "final block"); - blake2s_compression(cs, &mut h, &blocks[blocks.len() - 1], (input.len() / 8) as u64, true)?; + blake2s_compression( + cs, + &mut h, + &blocks[blocks.len() - 1], + (input.len() / 8) as u64, + true, + )?; } Ok(h.iter().flat_map(|b| b.into_bits()).collect()) @@ -321,14 +410,14 @@ pub fn blake2s>( #[cfg(test)] mod test { use blake2s_simd::Params as Blake2sParams; - use pairing::bls12_381::{Bls12}; + use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use crate::gadgets::boolean::{Boolean, AllocatedBit}; - use crate::gadgets::test::TestConstraintSystem; use super::blake2s; - use crate::{ConstraintSystem}; + use crate::gadgets::boolean::{AllocatedBit, Boolean}; + use crate::gadgets::test::TestConstraintSystem; + use crate::ConstraintSystem; #[test] fn test_blank_hash() { @@ -356,7 +445,13 @@ mod test { #[test] fn test_blake2s_constraints() { let mut cs = TestConstraintSystem::::new(); - let input_bits: Vec<_> = (0..512).map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()).collect(); + let input_bits: Vec<_> = (0..512) + .map(|i| { + AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)) + .unwrap() + .into() + }) + .collect(); blake2s(&mut cs, &input_bits, b"12345678").unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 21518); @@ -369,14 +464,17 @@ mod test { let mut cs = TestConstraintSystem::::new(); let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let input_bits: Vec<_> = (0..512) - .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) - .chain((0..512) - .map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into())) - .collect(); + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .chain((0..512).map(|i| { + AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)) + .unwrap() + .into() + })) + .collect(); blake2s(&mut cs, &input_bits, b"12345678").unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 21518); @@ -386,10 +484,12 @@ mod test { fn test_blake2s_constant_constraints() { let mut cs = TestConstraintSystem::::new(); let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); - let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect(); + let input_bits: Vec<_> = (0..512) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .collect(); blake2s(&mut cs, &input_bits, b"12345678").unwrap(); assert_eq!(cs.num_constraints(), 0); } @@ -397,13 +497,15 @@ mod test { #[test] fn test_blake2s() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); - for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) - { - let mut h = Blake2sParams::new().hash_length(32).personal(b"12345678").to_state(); + for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { + let mut h = Blake2sParams::new() + .hash_length(32) + .personal(b"12345678") + .to_state(); let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); @@ -419,7 +521,11 @@ mod test { for bit_i in 0..8 { let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); - input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into()); + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); } } @@ -427,17 +533,19 @@ mod test { assert!(cs.is_satisfied()); - let mut s = hash_result.as_ref().iter() - .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); + let mut s = hash_result + .as_ref() + .iter() + .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); for b in r { match b { Boolean::Is(b) => { assert!(s.next().unwrap() == b.get_value().unwrap()); - }, + } Boolean::Not(b) => { assert!(s.next().unwrap() != b.get_value().unwrap()); - }, + } Boolean::Constant(b) => { assert!(input_len == 0); assert!(s.next().unwrap() == b); diff --git a/src/gadgets/boolean.rs b/src/gadgets/boolean.rs index f6c11b69e..414b2909f 100644 --- a/src/gadgets/boolean.rs +++ b/src/gadgets/boolean.rs @@ -1,23 +1,16 @@ use ff::{BitIterator, Field, PrimeField}; use pairing::Engine; -use crate::{ - ConstraintSystem, - SynthesisError, - LinearCombination, - Variable -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; -use super::{ - Assignment -}; +use super::Assignment; /// Represents a variable in the constraint system which is guaranteed /// to be either zero or one. #[derive(Clone)] pub struct AllocatedBit { variable: Variable, - value: Option + value: Option, } impl AllocatedBit { @@ -35,18 +28,22 @@ impl AllocatedBit { pub fn alloc_conditionally( mut cs: CS, value: Option, - must_be_false: &AllocatedBit + must_be_false: &AllocatedBit, ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: Engine, + CS: ConstraintSystem, { - let var = cs.alloc(|| "boolean", || { - if *value.get()? { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - })?; + let var = cs.alloc( + || "boolean", + || { + if *value.get()? { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } + }, + )?; // Constrain: (1 - must_be_false - a) * a = 0 // if must_be_false is true, the equation @@ -58,31 +55,32 @@ impl AllocatedBit { || "boolean constraint", |lc| lc + CS::one() - must_be_false.variable - var, |lc| lc + var, - |lc| lc + |lc| lc, ); Ok(AllocatedBit { variable: var, - value: value + value: value, }) } /// Allocate a variable in the constraint system which can only be a /// boolean value. - pub fn alloc( - mut cs: CS, - value: Option, - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn alloc(mut cs: CS, value: Option) -> Result + where + E: Engine, + CS: ConstraintSystem, { - let var = cs.alloc(|| "boolean", || { - if *value.get()? { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - })?; + let var = cs.alloc( + || "boolean", + || { + if *value.get()? { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } + }, + )?; // Constrain: (1 - a) * a = 0 // This constrains a to be either 0 or 1. @@ -90,38 +88,38 @@ impl AllocatedBit { || "boolean constraint", |lc| lc + CS::one() - var, |lc| lc + var, - |lc| lc + |lc| lc, ); Ok(AllocatedBit { variable: var, - value: value + value: value, }) } /// Performs an XOR operation over the two operands, returning /// an `AllocatedBit`. - pub fn xor( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn xor(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "xor result", || { - if *a.value.get()? ^ *b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "xor result", + || { + if *a.value.get()? ^ *b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (a + a) * (b) = (a + b - c) // Given that a and b are boolean constrained, if they @@ -142,38 +140,38 @@ impl AllocatedBit { || "xor constraint", |lc| lc + a.variable + a.variable, |lc| lc + b.variable, - |lc| lc + a.variable + b.variable - result_var + |lc| lc + a.variable + b.variable - result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } /// Performs an AND operation over the two operands, returning /// an `AllocatedBit`. - pub fn and( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn and(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "and result", || { - if *a.value.get()? & *b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "and result", + || { + if *a.value.get()? & *b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (a) * (b) = (c), ensuring c is 1 iff // a AND b are both 1. @@ -181,37 +179,37 @@ impl AllocatedBit { || "and constraint", |lc| lc + a.variable, |lc| lc + b.variable, - |lc| lc + result_var + |lc| lc + result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } /// Calculates `a AND (NOT b)`. - pub fn and_not( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn and_not(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "and not result", || { - if *a.value.get()? & !*b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "and not result", + || { + if *a.value.get()? & !*b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (a) * (1 - b) = (c), ensuring c is 1 iff // a is true and b is false, and otherwise c is 0. @@ -219,37 +217,37 @@ impl AllocatedBit { || "and not constraint", |lc| lc + a.variable, |lc| lc + CS::one() - b.variable, - |lc| lc + result_var + |lc| lc + result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } /// Calculates `(NOT a) AND (NOT b)`. - pub fn nor( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn nor(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "nor result", || { - if !*a.value.get()? & !*b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "nor result", + || { + if !*a.value.get()? & !*b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (1 - a) * (1 - b) = (c), ensuring c is 1 iff // a and b are both false, and otherwise c is 0. @@ -257,21 +255,20 @@ impl AllocatedBit { || "nor constraint", |lc| lc + CS::one() - a.variable, |lc| lc + CS::one() - b.variable, - |lc| lc + result_var + |lc| lc + result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } } pub fn u64_into_boolean_vec_le>( mut cs: CS, - value: Option -) -> Result, SynthesisError> -{ + value: Option, +) -> Result, SynthesisError> { let values = match value { Some(ref value) => { let mut tmp = Vec::with_capacity(64); @@ -281,27 +278,28 @@ pub fn u64_into_boolean_vec_le>( } tmp - }, - None => { - vec![None; 64] } + None => vec![None; 64], }; - let bits = values.into_iter().enumerate().map(|(i, b)| { - Ok(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - b - )?)) - }).collect::, SynthesisError>>()?; + let bits = values + .into_iter() + .enumerate() + .map(|(i, b)| { + Ok(Boolean::from(AllocatedBit::alloc( + cs.namespace(|| format!("bit {}", i)), + b, + )?)) + }) + .collect::, SynthesisError>>()?; Ok(bits) } pub fn field_into_boolean_vec_le, F: PrimeField>( cs: CS, - value: Option -) -> Result, SynthesisError> -{ + value: Option, +) -> Result, SynthesisError> { let v = field_into_allocated_bits_le::(cs, value)?; Ok(v.into_iter().map(|e| Boolean::from(e)).collect()) @@ -309,9 +307,8 @@ pub fn field_into_boolean_vec_le, F: PrimeFie pub fn field_into_allocated_bits_le, F: PrimeField>( mut cs: CS, - value: Option -) -> Result, SynthesisError> -{ + value: Option, +) -> Result, SynthesisError> { // Deconstruct in big-endian bit order let values = match value { Some(ref value) => { @@ -333,19 +330,17 @@ pub fn field_into_allocated_bits_le, F: Prime assert_eq!(tmp.len(), F::NUM_BITS as usize); tmp - }, - None => { - vec![None; F::NUM_BITS as usize] } + None => vec![None; F::NUM_BITS as usize], }; // Allocate in little-endian order - let bits = values.into_iter().rev().enumerate().map(|(i, b)| { - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - b - ) - }).collect::, SynthesisError>>()?; + let bits = values + .into_iter() + .rev() + .enumerate() + .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), b)) + .collect::, SynthesisError>>()?; Ok(bits) } @@ -359,24 +354,21 @@ pub enum Boolean { /// Negated view of the boolean variable Not(AllocatedBit), /// Constant (not an allocated variable) - Constant(bool) + Constant(bool), } impl Boolean { pub fn is_constant(&self) -> bool { match *self { Boolean::Constant(_) => true, - _ => false + _ => false, } } - pub fn enforce_equal( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result<(), SynthesisError> - where E: Engine, - CS: ConstraintSystem + pub fn enforce_equal(mut cs: CS, a: &Self, b: &Self) -> Result<(), SynthesisError> + where + E: Engine, + CS: ConstraintSystem, { match (a, b) { (&Boolean::Constant(a), &Boolean::Constant(b)) => { @@ -385,33 +377,33 @@ impl Boolean { } else { Err(SynthesisError::Unsatisfiable) } - }, + } (&Boolean::Constant(true), a) | (a, &Boolean::Constant(true)) => { cs.enforce( || "enforce equal to one", |lc| lc, |lc| lc, - |lc| lc + CS::one() - &a.lc(CS::one(), E::Fr::one()) + |lc| lc + CS::one() - &a.lc(CS::one(), E::Fr::one()), ); Ok(()) - }, + } (&Boolean::Constant(false), a) | (a, &Boolean::Constant(false)) => { cs.enforce( || "enforce equal to zero", |lc| lc, |lc| lc, - |_| a.lc(CS::one(), E::Fr::one()) + |_| a.lc(CS::one(), E::Fr::one()), ); Ok(()) - }, + } (a, b) => { cs.enforce( || "enforce equal", |lc| lc, |lc| lc, - |_| a.lc(CS::one(), E::Fr::one()) - &b.lc(CS::one(), E::Fr::one()) + |_| a.lc(CS::one(), E::Fr::one()) - &b.lc(CS::one(), E::Fr::one()), ); Ok(()) @@ -423,16 +415,11 @@ impl Boolean { match self { &Boolean::Constant(c) => Some(c), &Boolean::Is(ref v) => v.get_value(), - &Boolean::Not(ref v) => v.get_value().map(|b| !b) + &Boolean::Not(ref v) => v.get_value().map(|b| !b), } } - pub fn lc( - &self, - one: Variable, - coeff: E::Fr - ) -> LinearCombination - { + pub fn lc(&self, one: Variable, coeff: E::Fr) -> LinearCombination { match self { &Boolean::Constant(c) => { if c { @@ -440,10 +427,8 @@ impl Boolean { } else { LinearCombination::::zero() } - }, - &Boolean::Is(ref v) => { - LinearCombination::::zero() + (coeff, v.get_variable()) - }, + } + &Boolean::Is(ref v) => LinearCombination::::zero() + (coeff, v.get_variable()), &Boolean::Not(ref v) => { LinearCombination::::zero() + (coeff, one) - (coeff, v.get_variable()) } @@ -460,59 +445,54 @@ impl Boolean { match self { &Boolean::Constant(c) => Boolean::Constant(!c), &Boolean::Is(ref v) => Boolean::Not(v.clone()), - &Boolean::Not(ref v) => Boolean::Is(v.clone()) + &Boolean::Not(ref v) => Boolean::Is(v.clone()), } } /// Perform XOR over two boolean operands - pub fn xor<'a, E, CS>( - cs: CS, - a: &'a Self, - b: &'a Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn xor<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { match (a, b) { (&Boolean::Constant(false), x) | (x, &Boolean::Constant(false)) => Ok(x.clone()), (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.not()), // a XOR (NOT b) = NOT(a XOR b) - (is @ &Boolean::Is(_), not @ &Boolean::Not(_)) | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => { - Ok(Boolean::xor( - cs, - is, - ¬.not() - )?.not()) - }, + (is @ &Boolean::Is(_), not @ &Boolean::Not(_)) + | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => { + Ok(Boolean::xor(cs, is, ¬.not())?.not()) + } // a XOR b = (NOT a) XOR (NOT b) - (&Boolean::Is(ref a), &Boolean::Is(ref b)) | (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { + (&Boolean::Is(ref a), &Boolean::Is(ref b)) + | (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { Ok(Boolean::Is(AllocatedBit::xor(cs, a, b)?)) } } } /// Perform AND over two boolean operands - pub fn and<'a, E, CS>( - cs: CS, - a: &'a Self, - b: &'a Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn and<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { match (a, b) { // false AND x is always false - (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => Ok(Boolean::Constant(false)), + (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => { + Ok(Boolean::Constant(false)) + } // true AND x is always x (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.clone()), // a AND (NOT b) - (&Boolean::Is(ref is), &Boolean::Not(ref not)) | (&Boolean::Not(ref not), &Boolean::Is(ref is)) => { + (&Boolean::Is(ref is), &Boolean::Not(ref not)) + | (&Boolean::Not(ref not), &Boolean::Is(ref is)) => { Ok(Boolean::Is(AllocatedBit::and_not(cs, is, not)?)) - }, + } // (NOT a) AND (NOT b) = a NOR b (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { Ok(Boolean::Is(AllocatedBit::nor(cs, a, b)?)) - }, + } // a AND b (&Boolean::Is(ref a), &Boolean::Is(ref b)) => { Ok(Boolean::Is(AllocatedBit::and(cs, a, b)?)) @@ -525,27 +505,26 @@ impl Boolean { mut cs: CS, a: &'a Self, b: &'a Self, - c: &'a Self + c: &'a Self, ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: Engine, + CS: ConstraintSystem, { let ch_value = match (a.get_value(), b.get_value(), c.get_value()) { (Some(a), Some(b), Some(c)) => { // (a and b) xor ((not a) and c) Some((a & b) ^ ((!a) & c)) - }, - _ => None + } + _ => None, }; match (a, b, c) { - (&Boolean::Constant(_), - &Boolean::Constant(_), - &Boolean::Constant(_)) => { + (&Boolean::Constant(_), &Boolean::Constant(_), &Boolean::Constant(_)) => { // They're all constants, so we can just compute the value. return Ok(Boolean::Constant(ch_value.expect("they're all constants"))); - }, + } (&Boolean::Constant(false), _, c) => { // If a is false // (a and b) xor ((not a) and c) @@ -554,29 +533,21 @@ impl Boolean { // equals // c return Ok(c.clone()); - }, + } (a, &Boolean::Constant(false), c) => { // If b is false // (a and b) xor ((not a) and c) // equals // ((not a) and c) - return Boolean::and( - cs, - &a.not(), - &c - ); - }, + return Boolean::and(cs, &a.not(), &c); + } (a, b, &Boolean::Constant(false)) => { // If c is false // (a and b) xor ((not a) and c) // equals // (a and b) - return Boolean::and( - cs, - &a, - &b - ); - }, + return Boolean::and(cs, &a, &b); + } (a, b, &Boolean::Constant(true)) => { // If c is true // (a and b) xor ((not a) and c) @@ -584,12 +555,8 @@ impl Boolean { // (a and b) xor (not a) // equals // not (a and (not b)) - return Ok(Boolean::and( - cs, - &a, - &b.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a, &b.not())?.not()); + } (a, &Boolean::Constant(true), c) => { // If b is true // (a and b) xor ((not a) and c) @@ -597,53 +564,47 @@ impl Boolean { // a xor ((not a) and c) // equals // not ((not a) and (not c)) - return Ok(Boolean::and( - cs, - &a.not(), - &c.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a.not(), &c.not())?.not()); + } (&Boolean::Constant(true), _, _) => { // If a is true // (a and b) xor ((not a) and c) // equals // b xor ((not a) and c) // So we just continue! - }, - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) - => {} + } + (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) => {} } - let ch = cs.alloc(|| "ch", || { - ch_value.get().map(|v| { - if *v { - E::Fr::one() - } else { - E::Fr::zero() - } - }) - })?; + let ch = cs.alloc( + || "ch", + || { + ch_value + .get() + .map(|v| if *v { E::Fr::one() } else { E::Fr::zero() }) + }, + )?; // a(b - c) = ch - c cs.enforce( || "ch computation", - |_| b.lc(CS::one(), E::Fr::one()) - - &c.lc(CS::one(), E::Fr::one()), + |_| b.lc(CS::one(), E::Fr::one()) - &c.lc(CS::one(), E::Fr::one()), |_| a.lc(CS::one(), E::Fr::one()), - |lc| lc + ch - &c.lc(CS::one(), E::Fr::one()) + |lc| lc + ch - &c.lc(CS::one(), E::Fr::one()), ); Ok(AllocatedBit { value: ch_value, - variable: ch - }.into()) + variable: ch, + } + .into()) } /// Computes (a and b) xor (a and c) xor (b and c) @@ -653,58 +614,45 @@ impl Boolean { b: &'a Self, c: &'a Self, ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: Engine, + CS: ConstraintSystem, { let maj_value = match (a.get_value(), b.get_value(), c.get_value()) { (Some(a), Some(b), Some(c)) => { // (a and b) xor (a and c) xor (b and c) Some((a & b) ^ (a & c) ^ (b & c)) - }, - _ => None + } + _ => None, }; match (a, b, c) { - (&Boolean::Constant(_), - &Boolean::Constant(_), - &Boolean::Constant(_)) => { + (&Boolean::Constant(_), &Boolean::Constant(_), &Boolean::Constant(_)) => { // They're all constants, so we can just compute the value. return Ok(Boolean::Constant(maj_value.expect("they're all constants"))); - }, + } (&Boolean::Constant(false), b, c) => { // If a is false, // (a and b) xor (a and c) xor (b and c) // equals // (b and c) - return Boolean::and( - cs, - b, - c - ); - }, + return Boolean::and(cs, b, c); + } (a, &Boolean::Constant(false), c) => { // If b is false, // (a and b) xor (a and c) xor (b and c) // equals // (a and c) - return Boolean::and( - cs, - a, - c - ); - }, + return Boolean::and(cs, a, c); + } (a, b, &Boolean::Constant(false)) => { // If c is false, // (a and b) xor (a and c) xor (b and c) // equals // (a and b) - return Boolean::and( - cs, - a, - b - ); - }, + return Boolean::and(cs, a, b); + } (a, b, &Boolean::Constant(true)) => { // If c is true, // (a and b) xor (a and c) xor (b and c) @@ -712,54 +660,40 @@ impl Boolean { // (a and b) xor (a) xor (b) // equals // not ((not a) and (not b)) - return Ok(Boolean::and( - cs, - &a.not(), - &b.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a.not(), &b.not())?.not()); + } (a, &Boolean::Constant(true), c) => { // If b is true, // (a and b) xor (a and c) xor (b and c) // equals // (a) xor (a and c) xor (c) - return Ok(Boolean::and( - cs, - &a.not(), - &c.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a.not(), &c.not())?.not()); + } (&Boolean::Constant(true), b, c) => { // If a is true, // (a and b) xor (a and c) xor (b and c) // equals // (b) xor (c) xor (b and c) - return Ok(Boolean::and( - cs, - &b.not(), - &c.not() - )?.not()); - }, - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) - => {} + return Ok(Boolean::and(cs, &b.not(), &c.not())?.not()); + } + (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) => {} } - let maj = cs.alloc(|| "maj", || { - maj_value.get().map(|v| { - if *v { - E::Fr::one() - } else { - E::Fr::zero() - } - }) - })?; + let maj = cs.alloc( + || "maj", + || { + maj_value + .get() + .map(|v| if *v { E::Fr::one() } else { E::Fr::zero() }) + }, + )?; // ¬(¬a ∧ ¬b) ∧ ¬(¬a ∧ ¬c) ∧ ¬(¬b ∧ ¬c) // (1 - ((1 - a) * (1 - b))) * (1 - ((1 - a) * (1 - c))) * (1 - ((1 - b) * (1 - c))) @@ -770,26 +704,24 @@ impl Boolean { // (b) * (c) = (bc) // (2bc - b - c) * (a) = bc - maj - let bc = Self::and( - cs.namespace(|| "b and c"), - b, - c - )?; + let bc = Self::and(cs.namespace(|| "b and c"), b, c)?; cs.enforce( || "maj computation", - |_| bc.lc(CS::one(), E::Fr::one()) - + &bc.lc(CS::one(), E::Fr::one()) - - &b.lc(CS::one(), E::Fr::one()) - - &c.lc(CS::one(), E::Fr::one()), + |_| { + bc.lc(CS::one(), E::Fr::one()) + &bc.lc(CS::one(), E::Fr::one()) + - &b.lc(CS::one(), E::Fr::one()) + - &c.lc(CS::one(), E::Fr::one()) + }, |_| a.lc(CS::one(), E::Fr::one()), - |_| bc.lc(CS::one(), E::Fr::one()) - maj + |_| bc.lc(CS::one(), E::Fr::one()) - maj, ); Ok(AllocatedBit { value: maj_value, - variable: maj - }.into()) + variable: maj, + } + .into()) } } @@ -801,16 +733,11 @@ impl From for Boolean { #[cfg(test)] mod test { - use crate::{ConstraintSystem}; + use super::{field_into_allocated_bits_le, u64_into_boolean_vec_le, AllocatedBit, Boolean}; + use crate::gadgets::test::*; + use crate::ConstraintSystem; use ff::{Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; - use crate::gadgets::test::*; - use super::{ - AllocatedBit, - Boolean, - field_into_allocated_bits_le, - u64_into_boolean_vec_le - }; #[test] fn test_allocated_bit() { @@ -839,10 +766,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("xor result") == if *a_val ^ *b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("xor result") + == if *a_val ^ *b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("xor result", if *a_val ^ *b_val { Field::zero() } else { Field::one() }); + cs.set( + "xor result", + if *a_val ^ *b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -861,10 +802,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("and result") == if *a_val & *b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("and result") + == if *a_val & *b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("and result", if *a_val & *b_val { Field::zero() } else { Field::one() }); + cs.set( + "and result", + if *a_val & *b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -883,10 +838,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("and not result") == if *a_val & !*b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("and not result") + == if *a_val & !*b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("and not result", if *a_val & !*b_val { Field::zero() } else { Field::one() }); + cs.set( + "and not result", + if *a_val & !*b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -905,10 +874,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("nor result") == if !*a_val & !*b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("nor result") + == if !*a_val & !*b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("nor result", if !*a_val & !*b_val { Field::zero() } else { Field::one() }); + cs.set( + "nor result", + if !*a_val & !*b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -923,8 +906,12 @@ mod test { { let mut cs = TestConstraintSystem::::new(); - let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap()); - let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap()); + let mut a = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(), + ); + let mut b = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap(), + ); if a_neg { a = a.not(); @@ -935,16 +922,15 @@ mod test { Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); + assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg)); } { let mut cs = TestConstraintSystem::::new(); let mut a = Boolean::Constant(a_bool); - let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap()); + let mut b = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap(), + ); if a_neg { a = a.not(); @@ -955,15 +941,14 @@ mod test { Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); + assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg)); } { let mut cs = TestConstraintSystem::::new(); - let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap()); + let mut a = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(), + ); let mut b = Boolean::Constant(b_bool); if a_neg { @@ -975,10 +960,7 @@ mod test { Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); + assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg)); } { let mut cs = TestConstraintSystem::::new(); @@ -1015,43 +997,43 @@ mod test { let mut b = Boolean::from(AllocatedBit::alloc(&mut cs, Some(true)).unwrap()); match b { - Boolean::Is(_) => {}, - _ => panic!("unexpected value") + Boolean::Is(_) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Not(_) => {}, - _ => panic!("unexpected value") + Boolean::Not(_) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Is(_) => {}, - _ => panic!("unexpected value") + Boolean::Is(_) => {} + _ => panic!("unexpected value"), } b = Boolean::constant(true); match b { - Boolean::Constant(true) => {}, - _ => panic!("unexpected value") + Boolean::Constant(true) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Constant(false) => {}, - _ => panic!("unexpected value") + Boolean::Constant(false) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Constant(true) => {}, - _ => panic!("unexpected value") + Boolean::Constant(true) => {} + _ => panic!("unexpected value"), } } @@ -1062,7 +1044,7 @@ mod test { AllocatedTrue, AllocatedFalse, NegatedAllocatedTrue, - NegatedAllocatedFalse + NegatedAllocatedFalse, } impl OperandType { @@ -1073,7 +1055,7 @@ mod test { OperandType::AllocatedTrue => false, OperandType::AllocatedFalse => false, OperandType::NegatedAllocatedTrue => false, - OperandType::NegatedAllocatedFalse => false + OperandType::NegatedAllocatedFalse => false, } } @@ -1084,12 +1066,11 @@ mod test { OperandType::AllocatedTrue => true, OperandType::AllocatedFalse => false, OperandType::NegatedAllocatedTrue => false, - OperandType::NegatedAllocatedFalse => true + OperandType::NegatedAllocatedFalse => true, } } } - #[test] fn test_boolean_xor() { let variants = [ @@ -1098,7 +1079,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1115,10 +1096,18 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not() + } } }; @@ -1131,97 +1120,161 @@ mod test { assert!(cs.is_satisfied()); match (first_operand, second_operand, c) { - (OperandType::True, OperandType::True, Boolean::Constant(false)) => {}, - (OperandType::True, OperandType::False, Boolean::Constant(true)) => {}, - (OperandType::True, OperandType::AllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::AllocatedFalse, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Is(_)) => {}, + (OperandType::True, OperandType::True, Boolean::Constant(false)) => {} + (OperandType::True, OperandType::False, Boolean::Constant(true)) => {} + (OperandType::True, OperandType::AllocatedTrue, Boolean::Not(_)) => {} + (OperandType::True, OperandType::AllocatedFalse, Boolean::Not(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Is(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Is(_)) => {} - (OperandType::False, OperandType::True, Boolean::Constant(true)) => {}, - (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {}, - (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}, + (OperandType::False, OperandType::True, Boolean::Constant(true)) => {} + (OperandType::False, OperandType::False, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {} + (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {} + (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {} + (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {} - (OperandType::AllocatedTrue, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {}, - (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedTrue, OperandType::True, Boolean::Not(_)) => {} + (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {} + ( + OperandType::AllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } - (OperandType::AllocatedFalse, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {}, - (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedFalse, OperandType::True, Boolean::Not(_)) => {} + (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {} + ( + OperandType::AllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Not(ref v)) => { + (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Is(_)) => {} + (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } - (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Not(ref v)) => { + (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Is(_)) => {} + (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - _ => panic!("this should never be encountered") + _ => panic!("this should never be encountered"), } } } @@ -1235,7 +1288,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1252,10 +1305,18 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not() + } } }; @@ -1268,98 +1329,183 @@ mod test { assert!(cs.is_satisfied()); match (first_operand, second_operand, c) { - (OperandType::True, OperandType::True, Boolean::Constant(true)) => {}, - (OperandType::True, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::True, OperandType::AllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::AllocatedFalse, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}, + (OperandType::True, OperandType::True, Boolean::Constant(true)) => {} + (OperandType::True, OperandType::False, Boolean::Constant(false)) => {} + (OperandType::True, OperandType::AllocatedTrue, Boolean::Is(_)) => {} + (OperandType::True, OperandType::AllocatedFalse, Boolean::Is(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {} - (OperandType::False, OperandType::True, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedTrue, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedFalse, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Constant(false)) => {}, + (OperandType::False, OperandType::True, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::False, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::AllocatedTrue, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::AllocatedFalse, Boolean::Constant(false)) => { + } + ( + OperandType::False, + OperandType::NegatedAllocatedTrue, + Boolean::Constant(false), + ) => {} + ( + OperandType::False, + OperandType::NegatedAllocatedFalse, + Boolean::Constant(false), + ) => {} - (OperandType::AllocatedTrue, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::AllocatedTrue, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedTrue, OperandType::True, Boolean::Is(_)) => {} + (OperandType::AllocatedTrue, OperandType::False, Boolean::Constant(false)) => {} + ( + OperandType::AllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } - (OperandType::AllocatedFalse, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::AllocatedFalse, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedFalse, OperandType::True, Boolean::Is(_)) => {} + (OperandType::AllocatedFalse, OperandType::False, Boolean::Constant(false)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedTrue, + OperandType::False, + Boolean::Constant(false), + ) => {} + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedFalse, + OperandType::False, + Boolean::Constant(false), + ) => {} + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } _ => { - panic!("unexpected behavior at {:?} AND {:?}", first_operand, second_operand); + panic!( + "unexpected behavior at {:?} AND {:?}", + first_operand, second_operand + ); } } } @@ -1391,7 +1537,10 @@ mod test { fn test_field_into_allocated_bits_le() { let mut cs = TestConstraintSystem::::new(); - let r = Fr::from_str("9147677615426976802526883532204139322118074541891858454835346926874644257775").unwrap(); + let r = Fr::from_str( + "9147677615426976802526883532204139322118074541891858454835346926874644257775", + ) + .unwrap(); let bits = field_into_allocated_bits_le(&mut cs, Some(r)).unwrap(); @@ -1417,7 +1566,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1430,8 +1579,8 @@ mod test { let c; // ch = (a and b) xor ((not a) and c) - let expected = (first_operand.val() & second_operand.val()) ^ - ((!first_operand.val()) & third_operand.val()); + let expected = (first_operand.val() & second_operand.val()) + ^ ((!first_operand.val()) & third_operand.val()); { let mut dyn_construct = |operand, name| { @@ -1440,10 +1589,20 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + .not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + .not() + } } }; @@ -1458,19 +1617,17 @@ mod test { assert_eq!(maj.get_value().unwrap(), expected); - if first_operand.is_constant() || - second_operand.is_constant() || - third_operand.is_constant() + if first_operand.is_constant() + || second_operand.is_constant() + || third_operand.is_constant() { - if first_operand.is_constant() && - second_operand.is_constant() && - third_operand.is_constant() + if first_operand.is_constant() + && second_operand.is_constant() + && third_operand.is_constant() { assert_eq!(cs.num_constraints(), 0); } - } - else - { + } else { assert_eq!(cs.get("ch"), { if expected { Fr::one() @@ -1500,7 +1657,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1513,9 +1670,9 @@ mod test { let c; // maj = (a and b) xor (a and c) xor (b and c) - let expected = (first_operand.val() & second_operand.val()) ^ - (first_operand.val() & third_operand.val()) ^ - (second_operand.val() & third_operand.val()); + let expected = (first_operand.val() & second_operand.val()) + ^ (first_operand.val() & third_operand.val()) + ^ (second_operand.val() & third_operand.val()); { let mut dyn_construct = |operand, name| { @@ -1524,10 +1681,20 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + .not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + .not() + } } }; @@ -1542,19 +1709,17 @@ mod test { assert_eq!(maj.get_value().unwrap(), expected); - if first_operand.is_constant() || - second_operand.is_constant() || - third_operand.is_constant() + if first_operand.is_constant() + || second_operand.is_constant() + || third_operand.is_constant() { - if first_operand.is_constant() && - second_operand.is_constant() && - third_operand.is_constant() + if first_operand.is_constant() + && second_operand.is_constant() + && third_operand.is_constant() { assert_eq!(cs.num_constraints(), 0); } - } - else - { + } else { assert_eq!(cs.get("maj"), { if expected { Fr::one() diff --git a/src/gadgets/lookup.rs b/src/gadgets/lookup.rs index 86ab10fff..bbb1da616 100644 --- a/src/gadgets/lookup.rs +++ b/src/gadgets/lookup.rs @@ -1,23 +1,15 @@ use ff::Field; use pairing::Engine; -use super::*; -use super::num::{ - AllocatedNum, - Num -}; use super::boolean::Boolean; -use crate::{ - ConstraintSystem -}; +use super::num::{AllocatedNum, Num}; +use super::*; +use crate::ConstraintSystem; // Synthesize the constants for each base pattern. -fn synth<'a, E: Engine, I>( - window_size: usize, - constants: I, - assignment: &mut [E::Fr] -) - where I: IntoIterator +fn synth<'a, E: Engine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr]) +where + I: IntoIterator, { assert_eq!(assignment.len(), 1 << window_size); @@ -39,16 +31,20 @@ fn synth<'a, E: Engine, I>( pub fn lookup3_xy( mut cs: CS, bits: &[Boolean], - coords: &[(E::Fr, E::Fr)] + coords: &[(E::Fr, E::Fr)], ) -> Result<(AllocatedNum, AllocatedNum), SynthesisError> - where CS: ConstraintSystem +where + CS: ConstraintSystem, { assert_eq!(bits.len(), 3); assert_eq!(coords.len(), 8); // Calculate the index into `coords` - let i = - match (bits[0].get_value(), bits[1].get_value(), bits[2].get_value()) { + let i = match ( + bits[0].get_value(), + bits[1].get_value(), + bits[2].get_value(), + ) { (Some(a_value), Some(b_value), Some(c_value)) => { let mut tmp = 0; if a_value { @@ -61,25 +57,15 @@ pub fn lookup3_xy( tmp += 4; } Some(tmp) - }, - _ => None + } + _ => None, }; // Allocate the x-coordinate resulting from the lookup - let res_x = AllocatedNum::alloc( - cs.namespace(|| "x"), - || { - Ok(coords[*i.get()?].0) - } - )?; + let res_x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(coords[*i.get()?].0))?; // Allocate the y-coordinate resulting from the lookup - let res_y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - Ok(coords[*i.get()?].1) - } - )?; + let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?; // Compute the coefficients for the lookup constraints let mut x_coeffs = [E::Fr::zero(); 8]; @@ -93,30 +79,38 @@ pub fn lookup3_xy( cs.enforce( || "x-coordinate lookup", - |lc| lc + (x_coeffs[0b001], one) + |lc| { + lc + (x_coeffs[0b001], one) + &bits[1].lc::(one, x_coeffs[0b011]) + &bits[2].lc::(one, x_coeffs[0b101]) - + &precomp.lc::(one, x_coeffs[0b111]), + + &precomp.lc::(one, x_coeffs[0b111]) + }, |lc| lc + &bits[0].lc::(one, E::Fr::one()), - |lc| lc + res_x.get_variable() + |lc| { + lc + res_x.get_variable() - (x_coeffs[0b000], one) - &bits[1].lc::(one, x_coeffs[0b010]) - &bits[2].lc::(one, x_coeffs[0b100]) - - &precomp.lc::(one, x_coeffs[0b110]), + - &precomp.lc::(one, x_coeffs[0b110]) + }, ); cs.enforce( || "y-coordinate lookup", - |lc| lc + (y_coeffs[0b001], one) + |lc| { + lc + (y_coeffs[0b001], one) + &bits[1].lc::(one, y_coeffs[0b011]) + &bits[2].lc::(one, y_coeffs[0b101]) - + &precomp.lc::(one, y_coeffs[0b111]), + + &precomp.lc::(one, y_coeffs[0b111]) + }, |lc| lc + &bits[0].lc::(one, E::Fr::one()), - |lc| lc + res_y.get_variable() + |lc| { + lc + res_y.get_variable() - (y_coeffs[0b000], one) - &bits[1].lc::(one, y_coeffs[0b010]) - &bits[2].lc::(one, y_coeffs[0b100]) - - &precomp.lc::(one, y_coeffs[0b110]), + - &precomp.lc::(one, y_coeffs[0b110]) + }, ); Ok((res_x, res_y)) @@ -127,16 +121,16 @@ pub fn lookup3_xy( pub fn lookup3_xy_with_conditional_negation( mut cs: CS, bits: &[Boolean], - coords: &[(E::Fr, E::Fr)] + coords: &[(E::Fr, E::Fr)], ) -> Result<(Num, Num), SynthesisError> - where CS: ConstraintSystem +where + CS: ConstraintSystem, { assert_eq!(bits.len(), 3); assert_eq!(coords.len(), 4); // Calculate the index into `coords` - let i = - match (bits[0].get_value(), bits[1].get_value()) { + let i = match (bits[0].get_value(), bits[1].get_value()) { (Some(a_value), Some(b_value)) => { let mut tmp = 0; if a_value { @@ -146,22 +140,19 @@ pub fn lookup3_xy_with_conditional_negation( tmp += 2; } Some(tmp) - }, - _ => None + } + _ => None, }; // Allocate the y-coordinate resulting from the lookup // and conditional negation - let y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - let mut tmp = coords[*i.get()?].1; - if *bits[2].get_value().get()? { - tmp.negate(); - } - Ok(tmp) + let y = AllocatedNum::alloc(cs.namespace(|| "y"), || { + let mut tmp = coords[*i.get()?].1; + if *bits[2].get_value().get()? { + tmp.negate(); } - )?; + Ok(tmp) + })?; let one = CS::one(); @@ -174,21 +165,21 @@ pub fn lookup3_xy_with_conditional_negation( let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?; let x = Num::zero() - .add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00]) - .add_bool_with_coeff(one, &bits[0], x_coeffs[0b01]) - .add_bool_with_coeff(one, &bits[1], x_coeffs[0b10]) - .add_bool_with_coeff(one, &precomp, x_coeffs[0b11]); + .add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00]) + .add_bool_with_coeff(one, &bits[0], x_coeffs[0b01]) + .add_bool_with_coeff(one, &bits[1], x_coeffs[0b10]) + .add_bool_with_coeff(one, &precomp, x_coeffs[0b11]); - let y_lc = precomp.lc::(one, y_coeffs[0b11]) + - &bits[1].lc::(one, y_coeffs[0b10]) + - &bits[0].lc::(one, y_coeffs[0b01]) + - (y_coeffs[0b00], one); + let y_lc = precomp.lc::(one, y_coeffs[0b11]) + + &bits[1].lc::(one, y_coeffs[0b10]) + + &bits[0].lc::(one, y_coeffs[0b01]) + + (y_coeffs[0b00], one); cs.enforce( || "y-coordinate lookup", |lc| lc + &y_lc + &y_lc, |lc| lc + &bits[2].lc::(one, E::Fr::one()), - |lc| lc + &y_lc - y.get_variable() + |lc| lc + &y_lc - y.get_variable(), ); Ok((x, y.into())) @@ -197,8 +188,8 @@ pub fn lookup3_xy_with_conditional_negation( #[cfg(test)] mod test { use super::*; + use crate::gadgets::boolean::{AllocatedBit, Boolean}; use crate::gadgets::test::*; - use crate::gadgets::boolean::{Boolean, AllocatedBit}; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; @@ -206,40 +197,42 @@ mod test { #[test] fn test_lookup3_xy() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); let a_val = rng.next_u32() % 2 != 0; - let a = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() - ); + let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()); let b_val = rng.next_u32() % 2 != 0; - let b = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() - ); + let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()); let c_val = rng.next_u32() % 2 != 0; - let c = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() - ); + let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()); let bits = vec![a, b, c]; - let points: Vec<(Fr, Fr)> = (0..8).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect(); + let points: Vec<(Fr, Fr)> = (0..8) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) + .collect(); let res = lookup3_xy(&mut cs, &bits, &points).unwrap(); assert!(cs.is_satisfied()); let mut index = 0; - if a_val { index += 1 } - if b_val { index += 2 } - if c_val { index += 4 } + if a_val { + index += 1 + } + if b_val { + index += 2 + } + if c_val { + index += 4 + } assert_eq!(res.0.get_value().unwrap(), points[index].0); assert_eq!(res.1.get_value().unwrap(), points[index].1); @@ -249,43 +242,45 @@ mod test { #[test] fn test_lookup3_xy_with_conditional_negation() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); let a_val = rng.next_u32() % 2 != 0; - let a = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() - ); + let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()); let b_val = rng.next_u32() % 2 != 0; - let b = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() - ); + let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()); let c_val = rng.next_u32() % 2 != 0; - let c = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() - ); + let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()); let bits = vec![a, b, c]; - let points: Vec<(Fr, Fr)> = (0..4).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect(); + let points: Vec<(Fr, Fr)> = (0..4) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) + .collect(); let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap(); assert!(cs.is_satisfied()); let mut index = 0; - if a_val { index += 1 } - if b_val { index += 2 } + if a_val { + index += 1 + } + if b_val { + index += 2 + } assert_eq!(res.0.get_value().unwrap(), points[index].0); let mut tmp = points[index].1; - if c_val { tmp.negate() } + if c_val { + tmp.negate() + } assert_eq!(res.1.get_value().unwrap(), tmp); } } @@ -293,14 +288,16 @@ mod test { #[test] fn test_synth() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let window_size = 4; let mut assignment = vec![Fr::zero(); 1 << window_size]; - let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::random(&mut rng)).collect(); + let constants: Vec<_> = (0..(1 << window_size)) + .map(|_| Fr::random(&mut rng)) + .collect(); synth::(window_size, &constants, &mut assignment); diff --git a/src/gadgets/multieq.rs b/src/gadgets/multieq.rs index b1dfd7c01..510802d4a 100644 --- a/src/gadgets/multieq.rs +++ b/src/gadgets/multieq.rs @@ -1,14 +1,9 @@ use ff::{Field, PrimeField}; use pairing::Engine; -use crate::{ - SynthesisError, - ConstraintSystem, - LinearCombination, - Variable -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; -pub struct MultiEq>{ +pub struct MultiEq> { cs: CS, ops: usize, bits_used: usize, @@ -23,12 +18,11 @@ impl> MultiEq { ops: 0, bits_used: 0, lhs: LinearCombination::zero(), - rhs: LinearCombination::zero() + rhs: LinearCombination::zero(), } } - fn accumulate(&mut self) - { + fn accumulate(&mut self) { let ops = self.ops; let lhs = self.lhs.clone(); let rhs = self.rhs.clone(); @@ -36,7 +30,7 @@ impl> MultiEq { || format!("multieq {}", ops), |_| lhs, |lc| lc + CS::one(), - |_| rhs + |_| rhs, ); self.lhs = LinearCombination::zero(); self.rhs = LinearCombination::zero(); @@ -48,9 +42,8 @@ impl> MultiEq { &mut self, num_bits: usize, lhs: &LinearCombination, - rhs: &LinearCombination - ) - { + rhs: &LinearCombination, + ) { // Check if we will exceed the capacity if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) { self.accumulate(); @@ -68,67 +61,60 @@ impl> MultiEq { impl> Drop for MultiEq { fn drop(&mut self) { if self.bits_used > 0 { - self.accumulate(); + self.accumulate(); } } } -impl> ConstraintSystem for MultiEq -{ +impl> ConstraintSystem for MultiEq { type Root = Self; fn one() -> Variable { CS::one() } - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.cs.alloc(annotation, f) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.cs.alloc_input(annotation, f) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { self.cs.enforce(annotation, a, b, c) } fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { self.cs.get_root().push_namespace(name_fn) } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { self.cs.get_root().pop_namespace() } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { self } } diff --git a/src/gadgets/multipack.rs b/src/gadgets/multipack.rs index b9b587778..34df7cd6d 100644 --- a/src/gadgets/multipack.rs +++ b/src/gadgets/multipack.rs @@ -1,20 +1,18 @@ -use ff::{Field, PrimeField}; -use pairing::Engine; -use crate::{ConstraintSystem, SynthesisError}; -use super::boolean::{Boolean}; +use super::boolean::Boolean; use super::num::Num; use super::Assignment; +use crate::{ConstraintSystem, SynthesisError}; +use ff::{Field, PrimeField}; +use pairing::Engine; /// Takes a sequence of booleans and exposes them as compact /// public inputs -pub fn pack_into_inputs( - mut cs: CS, - bits: &[Boolean] -) -> Result<(), SynthesisError> - where E: Engine, CS: ConstraintSystem +pub fn pack_into_inputs(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError> +where + E: Engine, + CS: ConstraintSystem, { - for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() - { + for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() { let mut num = Num::::zero(); let mut coeff = E::Fr::one(); for bit in bits { @@ -23,44 +21,38 @@ pub fn pack_into_inputs( coeff.double(); } - let input = cs.alloc_input(|| format!("input {}", i), || { - Ok(*num.get_value().get()?) - })?; + let input = cs.alloc_input(|| format!("input {}", i), || Ok(*num.get_value().get()?))?; // num * 1 = input cs.enforce( || format!("packing constraint {}", i), |_| num.lc(E::Fr::one()), |lc| lc + CS::one(), - |lc| lc + input + |lc| lc + input, ); } Ok(()) } -pub fn bytes_to_bits(bytes: &[u8]) -> Vec -{ - bytes.iter() - .flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1)) - .collect() +pub fn bytes_to_bits(bytes: &[u8]) -> Vec { + bytes + .iter() + .flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1)) + .collect() } -pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec -{ - bytes.iter() - .flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1)) - .collect() +pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec { + bytes + .iter() + .flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1)) + .collect() } -pub fn compute_multipacking( - bits: &[bool] -) -> Vec -{ +pub fn compute_multipacking(bits: &[bool]) -> Vec { let mut result = vec![]; - for bits in bits.chunks(E::Fr::CAPACITY as usize) - { + for bits in bits.chunks(E::Fr::CAPACITY as usize) { let mut cur = E::Fr::zero(); let mut coeff = E::Fr::one(); @@ -80,13 +72,13 @@ pub fn compute_multipacking( #[test] fn test_multipacking() { - use crate::{ConstraintSystem}; - use pairing::bls12_381::{Bls12}; + use crate::ConstraintSystem; + use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use crate::gadgets::test::*; use super::boolean::{AllocatedBit, Boolean}; + use crate::gadgets::test::*; let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -98,16 +90,15 @@ fn test_multipacking() { let bits: Vec = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect(); - let circuit_bits = bits.iter().enumerate() - .map(|(i, &b)| { - Boolean::from( - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - Some(b) - ).unwrap() - ) - }) - .collect::>(); + let circuit_bits = bits + .iter() + .enumerate() + .map(|(i, &b)| { + Boolean::from( + AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), Some(b)).unwrap(), + ) + }) + .collect::>(); let expected_inputs = compute_multipacking::(&bits); diff --git a/src/gadgets/num.rs b/src/gadgets/num.rs index 077301f87..84843c1b7 100644 --- a/src/gadgets/num.rs +++ b/src/gadgets/num.rs @@ -1,78 +1,61 @@ use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr}; use pairing::Engine; -use crate::{ - SynthesisError, - ConstraintSystem, - LinearCombination, - Variable -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; -use super::{ - Assignment -}; +use super::Assignment; -use super::boolean::{ - self, - Boolean, - AllocatedBit -}; +use super::boolean::{self, AllocatedBit, Boolean}; pub struct AllocatedNum { value: Option, - variable: Variable + variable: Variable, } impl Clone for AllocatedNum { fn clone(&self) -> Self { AllocatedNum { value: self.value, - variable: self.variable + variable: self.variable, } } } impl AllocatedNum { - pub fn alloc( - mut cs: CS, - value: F, - ) -> Result - where CS: ConstraintSystem, - F: FnOnce() -> Result + pub fn alloc(mut cs: CS, value: F) -> Result + where + CS: ConstraintSystem, + F: FnOnce() -> Result, { let mut new_value = None; - let var = cs.alloc(|| "num", || { - let tmp = value()?; + let var = cs.alloc( + || "num", + || { + let tmp = value()?; - new_value = Some(tmp); + new_value = Some(tmp); - Ok(tmp) - })?; + Ok(tmp) + }, + )?; Ok(AllocatedNum { value: new_value, - variable: var + variable: var, }) } - pub fn inputize( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem + pub fn inputize(&self, mut cs: CS) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, { - let input = cs.alloc_input( - || "input variable", - || { - Ok(*self.value.get()?) - } - )?; + let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?; cs.enforce( || "enforce input is correct", |lc| lc + input, |lc| lc + CS::one(), - |lc| lc + self.variable + |lc| lc + self.variable, ); Ok(()) @@ -83,18 +66,17 @@ impl AllocatedNum { /// order, requiring that the representation /// strictly exists "in the field" (i.e., a /// congruency is not allowed.) - pub fn into_bits_le_strict( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem + pub fn into_bits_le_strict(&self, mut cs: CS) -> Result, SynthesisError> + where + CS: ConstraintSystem, { pub fn kary_and( mut cs: CS, - v: &[AllocatedBit] + v: &[AllocatedBit], ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: Engine, + CS: ConstraintSystem, { assert!(v.len() > 0); @@ -109,7 +91,7 @@ impl AllocatedNum { cur = Some(AllocatedBit::and( cs.namespace(|| format!("and {}", i)), cur.as_ref().unwrap(), - v + v, )?); } } @@ -145,10 +127,7 @@ impl AllocatedNum { if b { // This is part of a run of ones. Let's just // allocate the boolean with the expected value. - let a_bit = AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - a_bit - )?; + let a_bit = AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), a_bit)?; // ... and add it to the current run of ones. current_run.push(a_bit.clone()); result.push(a_bit); @@ -162,7 +141,7 @@ impl AllocatedNum { } last_run = Some(kary_and( cs.namespace(|| format!("run ending at {}", i)), - ¤t_run + ¤t_run, )?); current_run.truncate(0); } @@ -175,7 +154,7 @@ impl AllocatedNum { let a_bit = AllocatedBit::alloc_conditionally( cs.namespace(|| format!("bit {}", i)), a_bit, - &last_run.as_ref().expect("char always starts with a one") + &last_run.as_ref().expect("char always starts with a one"), )?; result.push(a_bit); } @@ -201,12 +180,7 @@ impl AllocatedNum { lc = lc - self.variable; - cs.enforce( - || "unpacking constraint", - |lc| lc, - |lc| lc, - |_| lc - ); + cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc); // Convert into booleans, and reverse for little-endian bit order Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect()) @@ -215,16 +189,11 @@ impl AllocatedNum { /// Convert the allocated number into its little-endian representation. /// Note that this does not strongly enforce that the commitment is /// "in the field." - pub fn into_bits_le( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem + pub fn into_bits_le(&self, mut cs: CS) -> Result, SynthesisError> + where + CS: ConstraintSystem, { - let bits = boolean::field_into_allocated_bits_le( - &mut cs, - self.value - )?; + let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?; let mut lc = LinearCombination::zero(); let mut coeff = E::Fr::one(); @@ -237,94 +206,91 @@ impl AllocatedNum { lc = lc - self.variable; - cs.enforce( - || "unpacking constraint", - |lc| lc, - |lc| lc, - |_| lc - ); + cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc); Ok(bits.into_iter().map(|b| Boolean::from(b)).collect()) } - pub fn mul( - &self, - mut cs: CS, - other: &Self - ) -> Result - where CS: ConstraintSystem + pub fn mul(&self, mut cs: CS, other: &Self) -> Result + where + CS: ConstraintSystem, { let mut value = None; - let var = cs.alloc(|| "product num", || { - let mut tmp = *self.value.get()?; - tmp.mul_assign(other.value.get()?); + let var = cs.alloc( + || "product num", + || { + let mut tmp = *self.value.get()?; + tmp.mul_assign(other.value.get()?); - value = Some(tmp); + value = Some(tmp); - Ok(tmp) - })?; + Ok(tmp) + }, + )?; // Constrain: a * b = ab cs.enforce( || "multiplication constraint", |lc| lc + self.variable, |lc| lc + other.variable, - |lc| lc + var + |lc| lc + var, ); Ok(AllocatedNum { value: value, - variable: var + variable: var, }) } - pub fn square( - &self, - mut cs: CS - ) -> Result - where CS: ConstraintSystem + pub fn square(&self, mut cs: CS) -> Result + where + CS: ConstraintSystem, { let mut value = None; - let var = cs.alloc(|| "squared num", || { - let mut tmp = *self.value.get()?; - tmp.square(); + let var = cs.alloc( + || "squared num", + || { + let mut tmp = *self.value.get()?; + tmp.square(); - value = Some(tmp); + value = Some(tmp); - Ok(tmp) - })?; + Ok(tmp) + }, + )?; // Constrain: a * a = aa cs.enforce( || "squaring constraint", |lc| lc + self.variable, |lc| lc + self.variable, - |lc| lc + var + |lc| lc + var, ); Ok(AllocatedNum { value: value, - variable: var + variable: var, }) } - pub fn assert_nonzero( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem + pub fn assert_nonzero(&self, mut cs: CS) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, { - let inv = cs.alloc(|| "ephemeral inverse", || { - let tmp = *self.value.get()?; - - if tmp.is_zero() { - Err(SynthesisError::DivisionByZero) - } else { - Ok(tmp.inverse().unwrap()) - } - })?; + let inv = cs.alloc( + || "ephemeral inverse", + || { + let tmp = *self.value.get()?; + + if tmp.is_zero() { + Err(SynthesisError::DivisionByZero) + } else { + Ok(tmp.inverse().unwrap()) + } + }, + )?; // Constrain a * inv = 1, which is only valid // iff a has a multiplicative inverse, untrue @@ -333,7 +299,7 @@ impl AllocatedNum { || "nonzero assertion constraint", |lc| lc + self.variable, |lc| lc + inv, - |lc| lc + CS::one() + |lc| lc + CS::one(), ); Ok(()) @@ -346,44 +312,39 @@ impl AllocatedNum { mut cs: CS, a: &Self, b: &Self, - condition: &Boolean + condition: &Boolean, ) -> Result<(Self, Self), SynthesisError> - where CS: ConstraintSystem + where + CS: ConstraintSystem, { - let c = Self::alloc( - cs.namespace(|| "conditional reversal result 1"), - || { - if *condition.get_value().get()? { - Ok(*b.value.get()?) - } else { - Ok(*a.value.get()?) - } + let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || { + if *condition.get_value().get()? { + Ok(*b.value.get()?) + } else { + Ok(*a.value.get()?) } - )?; + })?; cs.enforce( || "first conditional reversal", |lc| lc + a.variable - b.variable, |_| condition.lc(CS::one(), E::Fr::one()), - |lc| lc + a.variable - c.variable + |lc| lc + a.variable - c.variable, ); - let d = Self::alloc( - cs.namespace(|| "conditional reversal result 2"), - || { - if *condition.get_value().get()? { - Ok(*a.value.get()?) - } else { - Ok(*b.value.get()?) - } + let d = Self::alloc(cs.namespace(|| "conditional reversal result 2"), || { + if *condition.get_value().get()? { + Ok(*a.value.get()?) + } else { + Ok(*b.value.get()?) } - )?; + })?; cs.enforce( || "second conditional reversal", |lc| lc + b.variable - a.variable, |_| condition.lc(CS::one(), E::Fr::one()), - |lc| lc + b.variable - d.variable + |lc| lc + b.variable - d.variable, ); Ok((c, d)) @@ -400,14 +361,14 @@ impl AllocatedNum { pub struct Num { value: Option, - lc: LinearCombination + lc: LinearCombination, } impl From> for Num { fn from(num: AllocatedNum) -> Num { Num { value: num.value, - lc: LinearCombination::::zero() + num.variable + lc: LinearCombination::::zero() + num.variable, } } } @@ -416,7 +377,7 @@ impl Num { pub fn zero() -> Self { Num { value: Some(E::Fr::zero()), - lc: LinearCombination::zero() + lc: LinearCombination::zero(), } } @@ -428,13 +389,7 @@ impl Num { LinearCombination::zero() + (coeff, &self.lc) } - pub fn add_bool_with_coeff( - self, - one: Variable, - bit: &Boolean, - coeff: E::Fr - ) -> Self - { + pub fn add_bool_with_coeff(self, one: Variable, bit: &Boolean, coeff: E::Fr) -> Self { let newval = match (self.value, bit.get_value()) { (Some(mut curval), Some(bval)) => { if bval { @@ -442,27 +397,27 @@ impl Num { } Some(curval) - }, - _ => None + } + _ => None, }; Num { value: newval, - lc: self.lc + &bit.lc(one, coeff) + lc: self.lc + &bit.lc(one, coeff), } } } #[cfg(test)] mod test { - use crate::{ConstraintSystem}; + use crate::ConstraintSystem; use ff::{BitIterator, Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; - use crate::gadgets::test::*; use super::{AllocatedNum, Boolean}; + use crate::gadgets::test::*; #[test] fn test_allocated_num() { @@ -491,8 +446,10 @@ mod test { fn test_num_multiplication() { let mut cs = TestConstraintSystem::::new(); - let n = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap(); - let n2 = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap(); + let n = + AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap(); + let n2 = + AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap(); let n3 = n.mul(&mut cs, &n2).unwrap(); assert!(cs.is_satisfied()); @@ -505,8 +462,8 @@ mod test { #[test] fn test_num_conditional_reversal() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); { let mut cs = TestConstraintSystem::::new(); @@ -573,14 +530,17 @@ mod test { cs.set("bit 254/boolean", Fr::one()); // this makes the conditional boolean constraint fail - assert_eq!(cs.which_is_unsatisfied().unwrap(), "bit 254/boolean constraint"); + assert_eq!( + cs.which_is_unsatisfied().unwrap(), + "bit 254/boolean constraint" + ); } #[test] fn test_into_bits() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for i in 0..200 { @@ -597,7 +557,10 @@ mod test { assert!(cs.is_satisfied()); - for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter().rev()) { + for (b, a) in BitIterator::new(r.into_repr()) + .skip(1) + .zip(bits.iter().rev()) + { if let &Boolean::Is(ref a) = a { assert_eq!(b, a.get_value().unwrap()); } else { diff --git a/src/gadgets/sha256.rs b/src/gadgets/sha256.rs index 2e4669e75..cb057f866 100644 --- a/src/gadgets/sha256.rs +++ b/src/gadgets/sha256.rs @@ -1,6 +1,6 @@ -use super::uint32::UInt32; -use super::multieq::MultiEq; use super::boolean::Boolean; +use super::multieq::MultiEq; +use super::uint32::UInt32; use crate::{ConstraintSystem, SynthesisError}; use pairing::Engine; @@ -12,37 +12,35 @@ const ROUND_CONSTANTS: [u32; 64] = [ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ]; const IV: [u32; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, ]; pub fn sha256_block_no_padding( mut cs: CS, - input: &[Boolean] + input: &[Boolean], ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: Engine, + CS: ConstraintSystem, { assert_eq!(input.len(), 512); - Ok(sha256_compression_function( - &mut cs, - &input, - &get_sha256_iv() - )? - .into_iter() - .flat_map(|e| e.into_bits_be()) - .collect()) + Ok( + sha256_compression_function(&mut cs, &input, &get_sha256_iv())? + .into_iter() + .flat_map(|e| e.into_bits_be()) + .collect(), + ) } -pub fn sha256( - mut cs: CS, - input: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +pub fn sha256(mut cs: CS, input: &[Boolean]) -> Result, SynthesisError> +where + E: Engine, + CS: ConstraintSystem, { assert!(input.len() % 8 == 0); @@ -62,16 +60,10 @@ pub fn sha256( let mut cur = get_sha256_iv(); for (i, block) in padded.chunks(512).enumerate() { - cur = sha256_compression_function( - cs.namespace(|| format!("block {}", i)), - block, - &cur - )?; + cur = sha256_compression_function(cs.namespace(|| format!("block {}", i)), block, &cur)?; } - Ok(cur.into_iter() - .flat_map(|e| e.into_bits_be()) - .collect()) + Ok(cur.into_iter().flat_map(|e| e.into_bits_be()).collect()) } fn get_sha256_iv() -> Vec { @@ -81,16 +73,19 @@ fn get_sha256_iv() -> Vec { fn sha256_compression_function( cs: CS, input: &[Boolean], - current_hash_value: &[UInt32] + current_hash_value: &[UInt32], ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: Engine, + CS: ConstraintSystem, { assert_eq!(input.len(), 512); assert_eq!(current_hash_value.len(), 8); - let mut w = input.chunks(32) - .map(|e| UInt32::from_bits_be(e)) - .collect::>(); + let mut w = input + .chunks(32) + .map(|e| UInt32::from_bits_be(e)) + .collect::>(); // We can save some constraints by combining some of // the constraints in different u32 additions @@ -100,30 +95,18 @@ fn sha256_compression_function( let cs = &mut cs.namespace(|| format!("w extension {}", i)); // s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3) - let mut s0 = w[i-15].rotr(7); - s0 = s0.xor( - cs.namespace(|| "first xor for s0"), - &w[i-15].rotr(18) - )?; - s0 = s0.xor( - cs.namespace(|| "second xor for s0"), - &w[i-15].shr(3) - )?; + let mut s0 = w[i - 15].rotr(7); + s0 = s0.xor(cs.namespace(|| "first xor for s0"), &w[i - 15].rotr(18))?; + s0 = s0.xor(cs.namespace(|| "second xor for s0"), &w[i - 15].shr(3))?; // s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10) - let mut s1 = w[i-2].rotr(17); - s1 = s1.xor( - cs.namespace(|| "first xor for s1"), - &w[i-2].rotr(19) - )?; - s1 = s1.xor( - cs.namespace(|| "second xor for s1"), - &w[i-2].shr(10) - )?; + let mut s1 = w[i - 2].rotr(17); + s1 = s1.xor(cs.namespace(|| "first xor for s1"), &w[i - 2].rotr(19))?; + s1 = s1.xor(cs.namespace(|| "second xor for s1"), &w[i - 2].shr(10))?; let tmp = UInt32::addmany( cs.namespace(|| "computation of w[i]"), - &[w[i-16].clone(), s0, w[i-7].clone(), s1] + &[w[i - 16].clone(), s0, w[i - 7].clone(), s1], )?; // w[i] := w[i-16] + s0 + w[i-7] + s1 @@ -134,29 +117,21 @@ fn sha256_compression_function( enum Maybe { Deferred(Vec), - Concrete(UInt32) + Concrete(UInt32), } impl Maybe { - fn compute( - self, - cs: M, - others: &[UInt32] - ) -> Result - where E: Engine, - CS: ConstraintSystem, - M: ConstraintSystem> + fn compute(self, cs: M, others: &[UInt32]) -> Result + where + E: Engine, + CS: ConstraintSystem, + M: ConstraintSystem>, { Ok(match self { - Maybe::Concrete(ref v) => { - return Ok(v.clone()) - }, + Maybe::Concrete(ref v) => return Ok(v.clone()), Maybe::Deferred(mut v) => { v.extend(others.into_iter().cloned()); - UInt32::addmany( - cs, - &v - )? + UInt32::addmany(cs, &v)? } }) } @@ -177,22 +152,11 @@ fn sha256_compression_function( // S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25) let new_e = e.compute(cs.namespace(|| "deferred e computation"), &[])?; let mut s1 = new_e.rotr(6); - s1 = s1.xor( - cs.namespace(|| "first xor for s1"), - &new_e.rotr(11) - )?; - s1 = s1.xor( - cs.namespace(|| "second xor for s1"), - &new_e.rotr(25) - )?; + s1 = s1.xor(cs.namespace(|| "first xor for s1"), &new_e.rotr(11))?; + s1 = s1.xor(cs.namespace(|| "second xor for s1"), &new_e.rotr(25))?; // ch := (e and f) xor ((not e) and g) - let ch = UInt32::sha256_ch( - cs.namespace(|| "ch"), - &new_e, - &f, - &g - )?; + let ch = UInt32::sha256_ch(cs.namespace(|| "ch"), &new_e, &f, &g)?; // temp1 := h + S1 + ch + k[i] + w[i] let temp1 = vec![ @@ -200,28 +164,17 @@ fn sha256_compression_function( s1, ch, UInt32::constant(ROUND_CONSTANTS[i]), - w[i].clone() + w[i].clone(), ]; // S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22) let new_a = a.compute(cs.namespace(|| "deferred a computation"), &[])?; let mut s0 = new_a.rotr(2); - s0 = s0.xor( - cs.namespace(|| "first xor for s0"), - &new_a.rotr(13) - )?; - s0 = s0.xor( - cs.namespace(|| "second xor for s0"), - &new_a.rotr(22) - )?; + s0 = s0.xor(cs.namespace(|| "first xor for s0"), &new_a.rotr(13))?; + s0 = s0.xor(cs.namespace(|| "second xor for s0"), &new_a.rotr(22))?; // maj := (a and b) xor (a and c) xor (b and c) - let maj = UInt32::sha256_maj( - cs.namespace(|| "maj"), - &new_a, - &b, - &c - )?; + let maj = UInt32::sha256_maj(cs.namespace(|| "maj"), &new_a, &b, &c)?; // temp2 := S0 + maj let temp2 = vec![s0, maj]; @@ -244,7 +197,13 @@ fn sha256_compression_function( d = c; c = b; b = new_a; - a = Maybe::Deferred(temp1.iter().cloned().chain(temp2.iter().cloned()).collect::>()); + a = Maybe::Deferred( + temp1 + .iter() + .cloned() + .chain(temp2.iter().cloned()) + .collect::>(), + ); } /* @@ -261,42 +220,42 @@ fn sha256_compression_function( let h0 = a.compute( cs.namespace(|| "deferred h0 computation"), - &[current_hash_value[0].clone()] + &[current_hash_value[0].clone()], )?; let h1 = UInt32::addmany( cs.namespace(|| "new h1"), - &[current_hash_value[1].clone(), b] + &[current_hash_value[1].clone(), b], )?; let h2 = UInt32::addmany( cs.namespace(|| "new h2"), - &[current_hash_value[2].clone(), c] + &[current_hash_value[2].clone(), c], )?; let h3 = UInt32::addmany( cs.namespace(|| "new h3"), - &[current_hash_value[3].clone(), d] + &[current_hash_value[3].clone(), d], )?; let h4 = e.compute( cs.namespace(|| "deferred h4 computation"), - &[current_hash_value[4].clone()] + &[current_hash_value[4].clone()], )?; let h5 = UInt32::addmany( cs.namespace(|| "new h5"), - &[current_hash_value[5].clone(), f] + &[current_hash_value[5].clone(), f], )?; let h6 = UInt32::addmany( cs.namespace(|| "new h6"), - &[current_hash_value[6].clone(), g] + &[current_hash_value[6].clone(), g], )?; let h7 = UInt32::addmany( cs.namespace(|| "new h7"), - &[current_hash_value[7].clone(), h] + &[current_hash_value[7].clone(), h], )?; Ok(vec![h0, h1, h2, h3, h4, h5, h6, h7]) @@ -306,8 +265,8 @@ fn sha256_compression_function( mod test { use super::*; use crate::gadgets::boolean::AllocatedBit; - use pairing::bls12_381::Bls12; use crate::gadgets::test::TestConstraintSystem; + use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; @@ -318,11 +277,7 @@ mod test { let mut cs = TestConstraintSystem::::new(); let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect(); input_bits[0] = Boolean::Constant(true); - let out = sha256_compression_function( - &mut cs, - &input_bits, - &iv - ).unwrap(); + let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap(); let out_bits: Vec<_> = out.into_iter().flat_map(|e| e.into_bits_be()).collect(); assert!(cs.is_satisfied()); @@ -343,27 +298,26 @@ mod test { #[test] fn test_full_block() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let iv = get_sha256_iv(); let mut cs = TestConstraintSystem::::new(); - let input_bits: Vec<_> = (0..512).map(|i| { - Boolean::from( - AllocatedBit::alloc( - cs.namespace(|| format!("input bit {}", i)), - Some(rng.next_u32() % 2 != 0) - ).unwrap() - ) - }).collect(); + let input_bits: Vec<_> = (0..512) + .map(|i| { + Boolean::from( + AllocatedBit::alloc( + cs.namespace(|| format!("input bit {}", i)), + Some(rng.next_u32() % 2 != 0), + ) + .unwrap(), + ) + }) + .collect(); - sha256_compression_function( - cs.namespace(|| "sha256"), - &input_bits, - &iv - ).unwrap(); + sha256_compression_function(cs.namespace(|| "sha256"), &input_bits, &iv).unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints() - 512, 25840); @@ -374,12 +328,11 @@ mod test { use sha2::{Digest, Sha256}; let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); - for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) - { + for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { let mut h = Sha256::new(); let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); h.input(&data); @@ -392,7 +345,11 @@ mod test { for bit_i in (0..8).rev() { let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); - input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into()); + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); } } @@ -400,17 +357,19 @@ mod test { assert!(cs.is_satisfied()); - let mut s = hash_result.as_ref().iter() - .flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8)); + let mut s = hash_result + .as_ref() + .iter() + .flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8)); for b in r { match b { Boolean::Is(b) => { assert!(s.next().unwrap() == b.get_value().unwrap()); - }, + } Boolean::Not(b) => { assert!(s.next().unwrap() != b.get_value().unwrap()); - }, + } Boolean::Constant(b) => { assert!(input_len == 0); assert!(s.next().unwrap() == b); diff --git a/src/gadgets/test/mod.rs b/src/gadgets/test/mod.rs index dc6adbfdc..58ba04062 100644 --- a/src/gadgets/test/mod.rs +++ b/src/gadgets/test/mod.rs @@ -1,13 +1,7 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; use pairing::Engine; -use crate::{ - LinearCombination, - SynthesisError, - ConstraintSystem, - Variable, - Index -}; +use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; use std::collections::HashMap; use std::fmt::Write; @@ -22,7 +16,7 @@ use blake2s_simd::{Params as Blake2sParams, State as Blake2sState}; enum NamedObject { Constraint(usize), Var(Variable), - Namespace + Namespace, } /// Constraint system for testing purposes. @@ -33,10 +27,10 @@ pub struct TestConstraintSystem { LinearCombination, LinearCombination, LinearCombination, - String + String, )>, inputs: Vec<(E::Fr, String)>, - aux: Vec<(E::Fr, String)> + aux: Vec<(E::Fr, String)>, } #[derive(Clone, Copy)] @@ -48,7 +42,7 @@ impl PartialEq for OrderedVariable { match (self.0.get_unchecked(), other.0.get_unchecked()) { (Index::Input(ref a), Index::Input(ref b)) => a == b, (Index::Aux(ref a), Index::Aux(ref b)) => a == b, - _ => false + _ => false, } } } @@ -63,20 +57,17 @@ impl Ord for OrderedVariable { (Index::Input(ref a), Index::Input(ref b)) => a.cmp(b), (Index::Aux(ref a), Index::Aux(ref b)) => a.cmp(b), (Index::Input(_), Index::Aux(_)) => Ordering::Less, - (Index::Aux(_), Index::Input(_)) => Ordering::Greater + (Index::Aux(_), Index::Input(_)) => Ordering::Greater, } } } -fn proc_lc( - terms: &[(Variable, E::Fr)], -) -> BTreeMap -{ +fn proc_lc(terms: &[(Variable, E::Fr)]) -> BTreeMap { let mut map = BTreeMap::new(); for &(var, coeff) in terms { map.entry(OrderedVariable(var)) - .or_insert(E::Fr::zero()) - .add_assign(&coeff); + .or_insert(E::Fr::zero()) + .add_assign(&coeff); } // Remove terms that have a zero coefficient to normalize @@ -94,11 +85,7 @@ fn proc_lc( map } -fn hash_lc( - terms: &[(Variable, E::Fr)], - h: &mut Blake2sState -) -{ +fn hash_lc(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) { let map = proc_lc::(terms); let mut buf = [0u8; 9 + 32]; @@ -110,13 +97,13 @@ fn hash_lc( Index::Input(i) => { buf[0] = b'I'; BigEndian::write_u64(&mut buf[1..9], i as u64); - }, + } Index::Aux(i) => { buf[0] = b'A'; BigEndian::write_u64(&mut buf[1..9], i as u64); } } - + coeff.into_repr().write_be(&mut buf[9..]).unwrap(); h.update(&buf); @@ -126,15 +113,14 @@ fn hash_lc( fn eval_lc( terms: &[(Variable, E::Fr)], inputs: &[(E::Fr, String)], - aux: &[(E::Fr, String)] -) -> E::Fr -{ + aux: &[(E::Fr, String)], +) -> E::Fr { let mut acc = E::Fr::zero(); for &(var, ref coeff) in terms { let mut tmp = match var.get_unchecked() { Index::Input(index) => inputs[index].0, - Index::Aux(index) => aux[index].0 + Index::Aux(index) => aux[index].0, }; tmp.mul_assign(&coeff); @@ -147,14 +133,17 @@ fn eval_lc( impl TestConstraintSystem { pub fn new() -> TestConstraintSystem { let mut map = HashMap::new(); - map.insert("ONE".into(), NamedObject::Var(TestConstraintSystem::::one())); + map.insert( + "ONE".into(), + NamedObject::Var(TestConstraintSystem::::one()), + ); TestConstraintSystem { named_objects: map, current_namespace: vec![], constraints: vec![], inputs: vec![(E::Fr::one(), "ONE".into())], - aux: vec![] + aux: vec![], } } @@ -167,9 +156,9 @@ impl TestConstraintSystem { tmp }; - let powers_of_two = (0..E::Fr::NUM_BITS).map(|i| { - E::Fr::from_str("2").unwrap().pow(&[i as u64]) - }).collect::>(); + let powers_of_two = (0..E::Fr::NUM_BITS) + .map(|i| E::Fr::from_str("2").unwrap().pow(&[i as u64])) + .collect::>(); let pp = |s: &mut String, lc: &LinearCombination| { write!(s, "(").unwrap(); @@ -196,7 +185,7 @@ impl TestConstraintSystem { match var.0.get_unchecked() { Index::Input(i) => { write!(s, "`{}`", &self.inputs[i].1).unwrap(); - }, + } Index::Aux(i) => { write!(s, "`{}`", &self.aux[i].1).unwrap(); } @@ -259,45 +248,41 @@ impl TestConstraintSystem { a.mul_assign(&b); if a != c { - return Some(&*path) + return Some(&*path); } } None } - pub fn is_satisfied(&self) -> bool - { + pub fn is_satisfied(&self) -> bool { self.which_is_unsatisfied().is_none() } - pub fn num_constraints(&self) -> usize - { + pub fn num_constraints(&self) -> usize { self.constraints.len() } - pub fn set(&mut self, path: &str, to: E::Fr) - { + pub fn set(&mut self, path: &str, to: E::Fr) { match self.named_objects.get(path) { - Some(&NamedObject::Var(ref v)) => { - match v.get_unchecked() { - Index::Input(index) => self.inputs[index].0 = to, - Index::Aux(index) => self.aux[index].0 = to - } - } - Some(e) => panic!("tried to set path `{}` to value, but `{:?}` already exists there.", path, e), - _ => panic!("no variable exists at path: {}", path) + Some(&NamedObject::Var(ref v)) => match v.get_unchecked() { + Index::Input(index) => self.inputs[index].0 = to, + Index::Aux(index) => self.aux[index].0 = to, + }, + Some(e) => panic!( + "tried to set path `{}` to value, but `{:?}` already exists there.", + path, e + ), + _ => panic!("no variable exists at path: {}", path), } } - pub fn verify(&self, expected: &[E::Fr]) -> bool - { + pub fn verify(&self, expected: &[E::Fr]) -> bool { assert_eq!(expected.len() + 1, self.inputs.len()); - for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) - { + for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) { if &a.0 != b { - return false + return false; } } @@ -308,8 +293,7 @@ impl TestConstraintSystem { self.inputs.len() } - pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr - { + pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr { let (assignment, name) = self.inputs[index].clone(); assert_eq!(path, name); @@ -317,17 +301,17 @@ impl TestConstraintSystem { assignment } - pub fn get(&mut self, path: &str) -> E::Fr - { + pub fn get(&mut self, path: &str) -> E::Fr { match self.named_objects.get(path) { - Some(&NamedObject::Var(ref v)) => { - match v.get_unchecked() { - Index::Input(index) => self.inputs[index].0, - Index::Aux(index) => self.aux[index].0 - } - } - Some(e) => panic!("tried to get value of path `{}`, but `{:?}` exists there (not a variable)", path, e), - _ => panic!("no variable exists at path: {}", path) + Some(&NamedObject::Var(ref v)) => match v.get_unchecked() { + Index::Input(index) => self.inputs[index].0, + Index::Aux(index) => self.aux[index].0, + }, + Some(e) => panic!( + "tried to get value of path `{}`, but `{:?}` exists there (not a variable)", + path, e + ), + _ => panic!("no variable exists at path: {}", path), } } @@ -348,8 +332,7 @@ fn compute_path(ns: &[String], this: String) -> String { let mut name = String::new(); let mut needs_separation = false; - for ns in ns.iter().chain(Some(&this).into_iter()) - { + for ns in ns.iter().chain(Some(&this).into_iter()) { if needs_separation { name += "/"; } @@ -364,12 +347,11 @@ fn compute_path(ns: &[String], this: String) -> String { impl ConstraintSystem for TestConstraintSystem { type Root = Self; - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { let index = self.aux.len(); let path = compute_path(&self.current_namespace, annotation().into()); @@ -380,12 +362,11 @@ impl ConstraintSystem for TestConstraintSystem { Ok(var) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { let index = self.inputs.len(); let path = compute_path(&self.current_namespace, annotation().into()); @@ -396,17 +377,13 @@ impl ConstraintSystem for TestConstraintSystem { Ok(var) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { let path = compute_path(&self.current_namespace, annotation().into()); let index = self.constraints.len(); @@ -420,7 +397,9 @@ impl ConstraintSystem for TestConstraintSystem { } fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { let name = name_fn().into(); let path = compute_path(&self.current_namespace, name.clone()); @@ -428,13 +407,11 @@ impl ConstraintSystem for TestConstraintSystem { self.current_namespace.push(name); } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { assert!(self.current_namespace.pop().is_some()); } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { self } } @@ -447,28 +424,26 @@ fn test_cs() { let mut cs = TestConstraintSystem::::new(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 0); - let a = cs.namespace(|| "a").alloc(|| "var", || Ok(Fr::from_str("10").unwrap())).unwrap(); - let b = cs.namespace(|| "b").alloc(|| "var", || Ok(Fr::from_str("4").unwrap())).unwrap(); - let c = cs.alloc(|| "product", || Ok(Fr::from_str("40").unwrap())).unwrap(); + let a = cs + .namespace(|| "a") + .alloc(|| "var", || Ok(Fr::from_str("10").unwrap())) + .unwrap(); + let b = cs + .namespace(|| "b") + .alloc(|| "var", || Ok(Fr::from_str("4").unwrap())) + .unwrap(); + let c = cs + .alloc(|| "product", || Ok(Fr::from_str("40").unwrap())) + .unwrap(); - cs.enforce( - || "mult", - |lc| lc + a, - |lc| lc + b, - |lc| lc + c - ); + cs.enforce(|| "mult", |lc| lc + a, |lc| lc + b, |lc| lc + c); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 1); cs.set("a/var", Fr::from_str("4").unwrap()); let one = TestConstraintSystem::::one(); - cs.enforce( - || "eq", - |lc| lc + a, - |lc| lc + one, - |lc| lc + b - ); + cs.enforce(|| "eq", |lc| lc + a, |lc| lc + one, |lc| lc + b); assert!(!cs.is_satisfied()); assert!(cs.which_is_unsatisfied() == Some("mult")); diff --git a/src/gadgets/uint32.rs b/src/gadgets/uint32.rs index 90f8d7e45..4c0d37601 100644 --- a/src/gadgets/uint32.rs +++ b/src/gadgets/uint32.rs @@ -1,16 +1,9 @@ use ff::{Field, PrimeField}; use pairing::Engine; -use crate::{ - SynthesisError, - ConstraintSystem, - LinearCombination -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError}; -use super::boolean::{ - Boolean, - AllocatedBit -}; +use super::boolean::{AllocatedBit, Boolean}; use super::multieq::MultiEq; @@ -20,13 +13,12 @@ use super::multieq::MultiEq; pub struct UInt32 { // Least significant bit first bits: Vec, - value: Option + value: Option, } impl UInt32 { /// Construct a constant `UInt32` from a `u32` - pub fn constant(value: u32) -> Self - { + pub fn constant(value: u32) -> Self { let mut bits = Vec::with_capacity(32); let mut tmp = value; @@ -42,17 +34,15 @@ impl UInt32 { UInt32 { bits: bits, - value: Some(value) + value: Some(value), } } /// Allocate a `UInt32` in the constraint system - pub fn alloc( - mut cs: CS, - value: Option - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn alloc(mut cs: CS, value: Option) -> Result + where + E: Engine, + CS: ConstraintSystem, { let values = match value { Some(mut val) => { @@ -64,23 +54,24 @@ impl UInt32 { } v - }, - None => vec![None; 32] + } + None => vec![None; 32], }; - let bits = values.into_iter() - .enumerate() - .map(|(i, v)| { - Ok(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("allocated bit {}", i)), - v - )?)) - }) - .collect::, SynthesisError>>()?; + let bits = values + .into_iter() + .enumerate() + .map(|(i, v)| { + Ok(Boolean::from(AllocatedBit::alloc( + cs.namespace(|| format!("allocated bit {}", i)), + v, + )?)) + }) + .collect::, SynthesisError>>()?; Ok(UInt32 { bits: bits, - value: value + value: value, }) } @@ -96,19 +87,22 @@ impl UInt32 { value.as_mut().map(|v| *v <<= 1); match b.get_value() { - Some(true) => { value.as_mut().map(|v| *v |= 1); }, - Some(false) => {}, - None => { value = None; } + Some(true) => { + value.as_mut().map(|v| *v |= 1); + } + Some(false) => {} + None => { + value = None; + } } } UInt32 { value: value, - bits: bits.iter().rev().cloned().collect() + bits: bits.iter().rev().cloned().collect(), } } - /// Turns this `UInt32` into its little-endian byte order representation. pub fn into_bits(&self) -> Vec { self.bits.clone() @@ -116,8 +110,7 @@ impl UInt32 { /// Converts a little-endian byte order representation of bits into a /// `UInt32`. - pub fn from_bits(bits: &[Boolean]) -> Self - { + pub fn from_bits(bits: &[Boolean]) -> Self { assert_eq!(bits.len(), 32); let new_bits = bits.to_vec(); @@ -131,43 +124,45 @@ impl UInt32 { if b { value.as_mut().map(|v| *v |= 1); } - }, - &Boolean::Is(ref b) => { - match b.get_value() { - Some(true) => { value.as_mut().map(|v| *v |= 1); }, - Some(false) => {}, - None => { value = None } - } - }, - &Boolean::Not(ref b) => { - match b.get_value() { - Some(false) => { value.as_mut().map(|v| *v |= 1); }, - Some(true) => {}, - None => { value = None } - } } + &Boolean::Is(ref b) => match b.get_value() { + Some(true) => { + value.as_mut().map(|v| *v |= 1); + } + Some(false) => {} + None => value = None, + }, + &Boolean::Not(ref b) => match b.get_value() { + Some(false) => { + value.as_mut().map(|v| *v |= 1); + } + Some(true) => {} + None => value = None, + }, } } UInt32 { value: value, - bits: new_bits + bits: new_bits, } } pub fn rotr(&self, by: usize) -> Self { let by = by % 32; - let new_bits = self.bits.iter() - .skip(by) - .chain(self.bits.iter()) - .take(32) - .cloned() - .collect(); + let new_bits = self + .bits + .iter() + .skip(by) + .chain(self.bits.iter()) + .take(32) + .cloned() + .collect(); UInt32 { bits: new_bits, - value: self.value.map(|v| v.rotate_right(by as u32)) + value: self.value.map(|v| v.rotate_right(by as u32)), } } @@ -176,17 +171,18 @@ impl UInt32 { let fill = Boolean::constant(false); - let new_bits = self.bits - .iter() // The bits are least significant first - .skip(by) // Skip the bits that will be lost during the shift - .chain(Some(&fill).into_iter().cycle()) // Rest will be zeros - .take(32) // Only 32 bits needed! - .cloned() - .collect(); + let new_bits = self + .bits + .iter() // The bits are least significant first + .skip(by) // Skip the bits that will be lost during the shift + .chain(Some(&fill).into_iter().cycle()) // Rest will be zeros + .take(32) // Only 32 bits needed! + .cloned() + .collect(); UInt32 { bits: new_bits, - value: self.value.map(|v| v >> by as u32) + value: self.value.map(|v| v >> by as u32), } } @@ -196,121 +192,99 @@ impl UInt32 { b: &Self, c: &Self, tri_fn: F, - circuit_fn: U + circuit_fn: U, ) -> Result - where E: Engine, - CS: ConstraintSystem, - F: Fn(u32, u32, u32) -> u32, - U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result + where + E: Engine, + CS: ConstraintSystem, + F: Fn(u32, u32, u32) -> u32, + U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result, { let new_value = match (a.value, b.value, c.value) { - (Some(a), Some(b), Some(c)) => { - Some(tri_fn(a, b, c)) - }, - _ => None + (Some(a), Some(b), Some(c)) => Some(tri_fn(a, b, c)), + _ => None, }; - let bits = a.bits.iter() - .zip(b.bits.iter()) - .zip(c.bits.iter()) - .enumerate() - .map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c)) - .collect::>()?; + let bits = a + .bits + .iter() + .zip(b.bits.iter()) + .zip(c.bits.iter()) + .enumerate() + .map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c)) + .collect::>()?; Ok(UInt32 { bits: bits, - value: new_value + value: new_value, }) } /// Compute the `maj` value (a and b) xor (a and c) xor (b and c) /// during SHA256. - pub fn sha256_maj( - cs: CS, - a: &Self, - b: &Self, - c: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn sha256_maj(cs: CS, a: &Self, b: &Self, c: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { - Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ (a & c) ^ (b & c), - |cs, i, a, b, c| { - Boolean::sha256_maj( - cs.namespace(|| format!("maj {}", i)), - a, - b, - c - ) - } + Self::triop( + cs, + a, + b, + c, + |a, b, c| (a & b) ^ (a & c) ^ (b & c), + |cs, i, a, b, c| Boolean::sha256_maj(cs.namespace(|| format!("maj {}", i)), a, b, c), ) } /// Compute the `ch` value `(a and b) xor ((not a) and c)` /// during SHA256. - pub fn sha256_ch( - cs: CS, - a: &Self, - b: &Self, - c: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn sha256_ch(cs: CS, a: &Self, b: &Self, c: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { - Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ ((!a) & c), - |cs, i, a, b, c| { - Boolean::sha256_ch( - cs.namespace(|| format!("ch {}", i)), - a, - b, - c - ) - } + Self::triop( + cs, + a, + b, + c, + |a, b, c| (a & b) ^ ((!a) & c), + |cs, i, a, b, c| Boolean::sha256_ch(cs.namespace(|| format!("ch {}", i)), a, b, c), ) } /// XOR this `UInt32` with another `UInt32` - pub fn xor( - &self, - mut cs: CS, - other: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn xor(&self, mut cs: CS, other: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let new_value = match (self.value, other.value) { - (Some(a), Some(b)) => { - Some(a ^ b) - }, - _ => None + (Some(a), Some(b)) => Some(a ^ b), + _ => None, }; - let bits = self.bits.iter() - .zip(other.bits.iter()) - .enumerate() - .map(|(i, (a, b))| { - Boolean::xor( - cs.namespace(|| format!("xor of bit {}", i)), - a, - b - ) - }) - .collect::>()?; + let bits = self + .bits + .iter() + .zip(other.bits.iter()) + .enumerate() + .map(|(i, (a, b))| Boolean::xor(cs.namespace(|| format!("xor of bit {}", i)), a, b)) + .collect::>()?; Ok(UInt32 { bits: bits, - value: new_value + value: new_value, }) } /// Perform modular addition of several `UInt32` objects. - pub fn addmany( - mut cs: M, - operands: &[Self] - ) -> Result - where E: Engine, - CS: ConstraintSystem, - M: ConstraintSystem> + pub fn addmany(mut cs: M, operands: &[Self]) -> Result + where + E: Engine, + CS: ConstraintSystem, + M: ConstraintSystem>, { // Make some arbitrary bounds for ourselves to avoid overflows // in the scalar field @@ -337,7 +311,7 @@ impl UInt32 { match op.value { Some(val) => { result_value.as_mut().map(|v| *v += val as u64); - }, + } None => { // If any of our operands have unknown value, we won't // know the value of the result @@ -381,7 +355,7 @@ impl UInt32 { // Allocate the bit let b = AllocatedBit::alloc( cs.namespace(|| format!("result bit {}", i)), - result_value.map(|v| (v >> i) & 1 == 1) + result_value.map(|v| (v >> i) & 1 == 1), )?; // Add this bit to the result combination @@ -402,32 +376,34 @@ impl UInt32 { Ok(UInt32 { bits: result_bits, - value: modular_value + value: modular_value, }) } } #[cfg(test)] mod test { - use crate::gadgets::boolean::{Boolean}; - use super::{UInt32}; - use ff::Field; - use pairing::bls12_381::{Bls12}; - use crate::gadgets::test::*; - use crate::{ConstraintSystem}; + use super::UInt32; + use crate::gadgets::boolean::Boolean; use crate::gadgets::multieq::MultiEq; + use crate::gadgets::test::*; + use crate::ConstraintSystem; + use ff::Field; + use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; #[test] fn test_uint32_from_bits_be() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::>(); + let mut v = (0..32) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .collect::>(); let b = UInt32::from_bits_be(&v); @@ -435,19 +411,18 @@ mod test { match bit { &Boolean::Constant(bit) => { assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); - }, - _ => unreachable!() + } + _ => unreachable!(), } } let expected_to_be_same = b.into_bits_be(); - for x in v.iter().zip(expected_to_be_same.iter()) - { + for x in v.iter().zip(expected_to_be_same.iter()) { match x { - (&Boolean::Constant(true), &Boolean::Constant(true)) => {}, - (&Boolean::Constant(false), &Boolean::Constant(false)) => {}, - _ => unreachable!() + (&Boolean::Constant(true), &Boolean::Constant(true)) => {} + (&Boolean::Constant(false), &Boolean::Constant(false)) => {} + _ => unreachable!(), } } } @@ -456,12 +431,14 @@ mod test { #[test] fn test_uint32_from_bits() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::>(); + let mut v = (0..32) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .collect::>(); let b = UInt32::from_bits(&v); @@ -469,19 +446,18 @@ mod test { match bit { &Boolean::Constant(bit) => { assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); - }, - _ => unreachable!() + } + _ => unreachable!(), } } let expected_to_be_same = b.into_bits(); - for x in v.iter().zip(expected_to_be_same.iter()) - { + for x in v.iter().zip(expected_to_be_same.iter()) { match x { - (&Boolean::Constant(true), &Boolean::Constant(true)) => {}, - (&Boolean::Constant(false), &Boolean::Constant(false)) => {}, - _ => unreachable!() + (&Boolean::Constant(true), &Boolean::Constant(true)) => {} + (&Boolean::Constant(false), &Boolean::Constant(false)) => {} + _ => unreachable!(), } } } @@ -490,8 +466,8 @@ mod test { #[test] fn test_uint32_xor() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -518,10 +494,10 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } @@ -535,8 +511,8 @@ mod test { #[test] fn test_uint32_addmany_constants() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -554,7 +530,8 @@ mod test { let r = { let mut cs = MultiEq::new(&mut cs); - let r = UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap(); + let r = + UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap(); r }; @@ -577,8 +554,8 @@ mod test { #[test] fn test_uint32_addmany() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -611,13 +588,11 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Constant(_) => { - unreachable!() } + &Boolean::Constant(_) => unreachable!(), } expected >>= 1; @@ -637,8 +612,8 @@ mod test { #[test] fn test_uint32_rotr() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let mut num = rng.next_u32(); @@ -656,8 +631,8 @@ mod test { match b { &Boolean::Constant(b) => { assert_eq!(b, tmp & 1 == 1); - }, - _ => unreachable!() + } + _ => unreachable!(), } tmp >>= 1; @@ -670,8 +645,8 @@ mod test { #[test] fn test_uint32_shr() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..50 { @@ -693,8 +668,8 @@ mod test { #[test] fn test_uint32_sha256_maj() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -720,10 +695,10 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } @@ -737,8 +712,8 @@ mod test { #[test] fn test_uint32_sha256_ch() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -764,10 +739,10 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } diff --git a/src/groth16/generator.rs b/src/groth16/generator.rs index 3e15b2bc1..596464f31 100644 --- a/src/groth16/generator.rs +++ b/src/groth16/generator.rs @@ -6,36 +6,24 @@ use ff::{Field, PrimeField}; use group::{CurveAffine, CurveProjective, Wnaf}; use pairing::Engine; -use super::{ - Parameters, - VerifyingKey -}; +use super::{Parameters, VerifyingKey}; -use ::{ - SynthesisError, - Circuit, - ConstraintSystem, - LinearCombination, - Variable, - Index -}; +use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; -use ::domain::{ - EvaluationDomain, - Scalar -}; +use domain::{EvaluationDomain, Scalar}; -use ::multicore::{ - Worker -}; +use multicore::Worker; /// Generates a random common reference string for /// a circuit. pub fn generate_random_parameters( circuit: C, - rng: &mut R + rng: &mut R, ) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: RngCore +where + E: Engine, + C: Circuit, + R: RngCore, { let g1 = E::G1::random(rng); let g2 = E::G2::random(rng); @@ -45,16 +33,7 @@ pub fn generate_random_parameters( let delta = E::Fr::random(rng); let tau = E::Fr::random(rng); - generate_parameters::( - circuit, - g1, - g2, - alpha, - beta, - gamma, - delta, - tau - ) + generate_parameters::(circuit, g1, g2, alpha, beta, gamma, delta, tau) } /// This is our assembly structure that we'll use to synthesize the @@ -68,18 +47,17 @@ struct KeypairAssembly { ct_inputs: Vec>, at_aux: Vec>, bt_aux: Vec>, - ct_aux: Vec> + ct_aux: Vec>, } impl ConstraintSystem for KeypairAssembly { type Root = Self; - fn alloc( - &mut self, - _: A, - _: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, _: A, _: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { // There is no assignment, so we don't even invoke the // function for obtaining one. @@ -94,12 +72,11 @@ impl ConstraintSystem for KeypairAssembly { Ok(Variable(Index::Aux(index))) } - fn alloc_input( - &mut self, - _: A, - _: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, _: A, _: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { // There is no assignment, so we don't even invoke the // function for obtaining one. @@ -114,48 +91,59 @@ impl ConstraintSystem for KeypairAssembly { Ok(Variable(Index::Input(index))) } - fn enforce( - &mut self, - _: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, _: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { fn eval( l: LinearCombination, inputs: &mut [Vec<(E::Fr, usize)>], aux: &mut [Vec<(E::Fr, usize)>], - this_constraint: usize - ) - { + this_constraint: usize, + ) { for (index, coeff) in l.0 { match index { Variable(Index::Input(id)) => inputs[id].push((coeff, this_constraint)), - Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint)) + Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint)), } } } - eval(a(LinearCombination::zero()), &mut self.at_inputs, &mut self.at_aux, self.num_constraints); - eval(b(LinearCombination::zero()), &mut self.bt_inputs, &mut self.bt_aux, self.num_constraints); - eval(c(LinearCombination::zero()), &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints); + eval( + a(LinearCombination::zero()), + &mut self.at_inputs, + &mut self.at_aux, + self.num_constraints, + ); + eval( + b(LinearCombination::zero()), + &mut self.bt_inputs, + &mut self.bt_aux, + self.num_constraints, + ); + eval( + c(LinearCombination::zero()), + &mut self.ct_inputs, + &mut self.ct_aux, + self.num_constraints, + ); self.num_constraints += 1; } fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { // Do nothing; we don't care about namespaces in this context. } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { // Do nothing; we don't care about namespaces in this context. } @@ -173,9 +161,11 @@ pub fn generate_parameters( beta: E::Fr, gamma: E::Fr, delta: E::Fr, - tau: E::Fr + tau: E::Fr, ) -> Result, SynthesisError> - where E: Engine, C: Circuit +where + E: Engine, + C: Circuit, { let mut assembly = KeypairAssembly { num_inputs: 0, @@ -186,7 +176,7 @@ pub fn generate_parameters( ct_inputs: vec![], at_aux: vec![], bt_aux: vec![], - ct_aux: vec![] + ct_aux: vec![], }; // Allocate the "one" input variable @@ -198,11 +188,7 @@ pub fn generate_parameters( // Input constraints to ensure full density of IC query // x * 0 = 0 for i in 0..assembly.num_inputs { - assembly.enforce(|| "", - |lc| lc + Variable(Index::Input(i)), - |lc| lc, - |lc| lc, - ); + assembly.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc); } // Create bases for blind evaluation of polynomials at tau @@ -240,10 +226,9 @@ pub fn generate_parameters( { let powers_of_tau = powers_of_tau.as_mut(); worker.scope(powers_of_tau.len(), |scope, chunk| { - for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() - { + for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() { scope.spawn(move || { - let mut current_tau_power = tau.pow(&[(i*chunk) as u64]); + let mut current_tau_power = tau.pow(&[(i * chunk) as u64]); for p in powers_of_tau { p.0 = current_tau_power; @@ -260,14 +245,15 @@ pub fn generate_parameters( // Compute the H query with multiple threads worker.scope(h.len(), |scope, chunk| { - for (h, p) in h.chunks_mut(chunk).zip(powers_of_tau.as_ref().chunks(chunk)) + for (h, p) in h + .chunks_mut(chunk) + .zip(powers_of_tau.as_ref().chunks(chunk)) { let mut g1_wnaf = g1_wnaf.shared(); scope.spawn(move || { // Set values of the H query to g1^{(tau^i * t(tau)) / delta} - for (h, p) in h.iter_mut().zip(p.iter()) - { + for (h, p) in h.iter_mut().zip(p.iter()) { // Compute final exponent let mut exp = p.0; exp.mul_assign(&coeff); @@ -320,9 +306,8 @@ pub fn generate_parameters( beta: &E::Fr, // Worker - worker: &Worker - ) - { + worker: &Worker, + ) { // Sanity check assert_eq!(a.len(), at.len()); assert_eq!(a.len(), bt.len()); @@ -333,31 +318,32 @@ pub fn generate_parameters( // Evaluate polynomials in multiple threads worker.scope(a.len(), |scope, chunk| { - for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.chunks_mut(chunk) - .zip(b_g1.chunks_mut(chunk)) - .zip(b_g2.chunks_mut(chunk)) - .zip(ext.chunks_mut(chunk)) - .zip(at.chunks(chunk)) - .zip(bt.chunks(chunk)) - .zip(ct.chunks(chunk)) + for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a + .chunks_mut(chunk) + .zip(b_g1.chunks_mut(chunk)) + .zip(b_g2.chunks_mut(chunk)) + .zip(ext.chunks_mut(chunk)) + .zip(at.chunks(chunk)) + .zip(bt.chunks(chunk)) + .zip(ct.chunks(chunk)) { let mut g1_wnaf = g1_wnaf.shared(); let mut g2_wnaf = g2_wnaf.shared(); scope.spawn(move || { - for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.iter_mut() - .zip(b_g1.iter_mut()) - .zip(b_g2.iter_mut()) - .zip(ext.iter_mut()) - .zip(at.iter()) - .zip(bt.iter()) - .zip(ct.iter()) + for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a + .iter_mut() + .zip(b_g1.iter_mut()) + .zip(b_g2.iter_mut()) + .zip(ext.iter_mut()) + .zip(at.iter()) + .zip(bt.iter()) + .zip(ct.iter()) { fn eval_at_tau( powers_of_tau: &[Scalar], - p: &[(E::Fr, usize)] - ) -> E::Fr - { + p: &[(E::Fr, usize)], + ) -> E::Fr { let mut acc = E::Fr::zero(); for &(ref coeff, index) in p { @@ -422,7 +408,7 @@ pub fn generate_parameters( &gamma_inverse, &alpha, &beta, - &worker + &worker, ); // Evaluate for auxiliary variables. @@ -440,7 +426,7 @@ pub fn generate_parameters( &delta_inverse, &alpha, &beta, - &worker + &worker, ); // Don't allow any elements be unconstrained, so that @@ -461,7 +447,7 @@ pub fn generate_parameters( gamma_g2: g2.mul(gamma).into_affine(), delta_g1: g1.mul(delta).into_affine(), delta_g2: g2.mul(delta).into_affine(), - ic: ic.into_iter().map(|e| e.into_affine()).collect() + ic: ic.into_iter().map(|e| e.into_affine()).collect(), }; Ok(Parameters { @@ -470,8 +456,23 @@ pub fn generate_parameters( l: Arc::new(l.into_iter().map(|e| e.into_affine()).collect()), // Filter points at infinity away from A/B queries - a: Arc::new(a.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()), - b_g1: Arc::new(b_g1.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()), - b_g2: Arc::new(b_g2.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()) + a: Arc::new( + a.into_iter() + .filter(|e| !e.is_zero()) + .map(|e| e.into_affine()) + .collect(), + ), + b_g1: Arc::new( + b_g1.into_iter() + .filter(|e| !e.is_zero()) + .map(|e| e.into_affine()) + .collect(), + ), + b_g2: Arc::new( + b_g2.into_iter() + .filter(|e| !e.is_zero()) + .map(|e| e.into_affine()) + .collect(), + ), }) } diff --git a/src/groth16/mod.rs b/src/groth16/mod.rs index 767150cba..85b7952bf 100644 --- a/src/groth16/mod.rs +++ b/src/groth16/mod.rs @@ -1,17 +1,12 @@ use group::{CurveAffine, EncodedPoint}; -use pairing::{ - Engine, - PairingCurveAffine, -}; +use pairing::{Engine, PairingCurveAffine}; -use ::{ - SynthesisError -}; +use SynthesisError; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use multiexp::SourceBuilder; use std::io::{self, Read, Write}; use std::sync::Arc; -use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; #[cfg(test)] mod tests; @@ -28,23 +23,17 @@ pub use self::verifier::*; pub struct Proof { pub a: E::G1Affine, pub b: E::G2Affine, - pub c: E::G1Affine + pub c: E::G1Affine, } impl PartialEq for Proof { fn eq(&self, other: &Self) -> bool { - self.a == other.a && - self.b == other.b && - self.c == other.c + self.a == other.a && self.b == other.b && self.c == other.c } } impl Proof { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { + pub fn write(&self, mut writer: W) -> io::Result<()> { writer.write_all(self.a.into_compressed().as_ref())?; writer.write_all(self.b.into_compressed().as_ref())?; writer.write_all(self.c.into_compressed().as_ref())?; @@ -52,48 +41,56 @@ impl Proof { Ok(()) } - pub fn read( - mut reader: R - ) -> io::Result - { + pub fn read(mut reader: R) -> io::Result { let mut g1_repr = ::Compressed::empty(); let mut g2_repr = ::Compressed::empty(); reader.read_exact(g1_repr.as_mut())?; let a = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) } else { Ok(e) - })?; + } + })?; reader.read_exact(g2_repr.as_mut())?; let b = g2_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) } else { Ok(e) - })?; + } + })?; reader.read_exact(g1_repr.as_mut())?; let c = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) } else { Ok(e) - })?; + } + })?; - Ok(Proof { - a: a, - b: b, - c: c - }) + Ok(Proof { a: a, b: b, c: c }) } } @@ -122,27 +119,23 @@ pub struct VerifyingKey { // for all public inputs. Because all public inputs have a dummy constraint, // this is the same size as the number of inputs, and never contains points // at infinity. - pub ic: Vec + pub ic: Vec, } impl PartialEq for VerifyingKey { fn eq(&self, other: &Self) -> bool { - self.alpha_g1 == other.alpha_g1 && - self.beta_g1 == other.beta_g1 && - self.beta_g2 == other.beta_g2 && - self.gamma_g2 == other.gamma_g2 && - self.delta_g1 == other.delta_g1 && - self.delta_g2 == other.delta_g2 && - self.ic == other.ic + self.alpha_g1 == other.alpha_g1 + && self.beta_g1 == other.beta_g1 + && self.beta_g2 == other.beta_g2 + && self.gamma_g2 == other.gamma_g2 + && self.delta_g1 == other.delta_g1 + && self.delta_g2 == other.delta_g2 + && self.ic == other.ic } } impl VerifyingKey { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { + pub fn write(&self, mut writer: W) -> io::Result<()> { writer.write_all(self.alpha_g1.into_uncompressed().as_ref())?; writer.write_all(self.beta_g1.into_uncompressed().as_ref())?; writer.write_all(self.beta_g2.into_uncompressed().as_ref())?; @@ -157,30 +150,39 @@ impl VerifyingKey { Ok(()) } - pub fn read( - mut reader: R - ) -> io::Result - { + pub fn read(mut reader: R) -> io::Result { let mut g1_repr = ::Uncompressed::empty(); let mut g2_repr = ::Uncompressed::empty(); reader.read_exact(g1_repr.as_mut())?; - let alpha_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let alpha_g1 = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g1_repr.as_mut())?; - let beta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let beta_g1 = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g2_repr.as_mut())?; - let beta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let beta_g2 = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g2_repr.as_mut())?; - let gamma_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let gamma_g2 = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g1_repr.as_mut())?; - let delta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let delta_g1 = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g2_repr.as_mut())?; - let delta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let delta_g2 = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; let ic_len = reader.read_u32::()? as usize; @@ -189,13 +191,18 @@ impl VerifyingKey { for _ in 0..ic_len { reader.read_exact(g1_repr.as_mut())?; let g1 = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - })?; + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } + })?; ic.push(g1); } @@ -207,7 +214,7 @@ impl VerifyingKey { gamma_g2: gamma_g2, delta_g1: delta_g1, delta_g2: delta_g2, - ic: ic + ic: ic, }) } } @@ -216,7 +223,7 @@ impl VerifyingKey { pub struct Parameters { pub vk: VerifyingKey, - // Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and + // Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and // m-2 inclusive. Never contains points at infinity. pub h: Arc>, @@ -234,26 +241,22 @@ pub struct Parameters { // G1 and G2 for C/B queries, respectively. Never contains points at // infinity for the same reason as the "A" polynomials. pub b_g1: Arc>, - pub b_g2: Arc> + pub b_g2: Arc>, } impl PartialEq for Parameters { fn eq(&self, other: &Self) -> bool { - self.vk == other.vk && - self.h == other.h && - self.l == other.l && - self.a == other.a && - self.b_g1 == other.b_g1 && - self.b_g2 == other.b_g2 + self.vk == other.vk + && self.h == other.h + && self.l == other.l + && self.a == other.a + && self.b_g1 == other.b_g1 + && self.b_g2 == other.b_g2 } } impl Parameters { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { + pub fn write(&self, mut writer: W) -> io::Result<()> { self.vk.write(&mut writer)?; writer.write_u32::(self.h.len() as u32)?; @@ -284,27 +287,26 @@ impl Parameters { Ok(()) } - pub fn read( - mut reader: R, - checked: bool - ) -> io::Result - { + pub fn read(mut reader: R, checked: bool) -> io::Result { let read_g1 = |reader: &mut R| -> io::Result { let mut repr = ::Uncompressed::empty(); reader.read_exact(repr.as_mut())?; if checked { - repr - .into_affine() + repr.into_affine() } else { - repr - .into_affine_unchecked() + repr.into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } }) }; @@ -313,17 +315,20 @@ impl Parameters { reader.read_exact(repr.as_mut())?; if checked { - repr - .into_affine() + repr.into_affine() } else { - repr - .into_affine_unchecked() + repr.into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } }) }; @@ -376,7 +381,7 @@ impl Parameters { l: Arc::new(l), a: Arc::new(a), b_g1: Arc::new(b_g1), - b_g2: Arc::new(b_g2) + b_g2: Arc::new(b_g2), }) } } @@ -389,39 +394,30 @@ pub struct PreparedVerifyingKey { /// -delta in G2 neg_delta_g2: ::Prepared, /// Copy of IC from `VerifiyingKey`. - ic: Vec + ic: Vec, } pub trait ParameterSource { type G1Builder: SourceBuilder; type G2Builder: SourceBuilder; - fn get_vk( - &mut self, - num_ic: usize - ) -> Result, SynthesisError>; - fn get_h( - &mut self, - num_h: usize - ) -> Result; - fn get_l( - &mut self, - num_l: usize - ) -> Result; + fn get_vk(&mut self, num_ic: usize) -> Result, SynthesisError>; + fn get_h(&mut self, num_h: usize) -> Result; + fn get_l(&mut self, num_l: usize) -> Result; fn get_a( &mut self, num_inputs: usize, - num_aux: usize + num_aux: usize, ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>; fn get_b_g1( &mut self, num_inputs: usize, - num_aux: usize + num_aux: usize, ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>; fn get_b_g2( &mut self, num_inputs: usize, - num_aux: usize + num_aux: usize, ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>; } @@ -429,54 +425,39 @@ impl<'a, E: Engine> ParameterSource for &'a Parameters { type G1Builder = (Arc>, usize); type G2Builder = (Arc>, usize); - fn get_vk( - &mut self, - _: usize - ) -> Result, SynthesisError> - { + fn get_vk(&mut self, _: usize) -> Result, SynthesisError> { Ok(self.vk.clone()) } - fn get_h( - &mut self, - _: usize - ) -> Result - { + fn get_h(&mut self, _: usize) -> Result { Ok((self.h.clone(), 0)) } - fn get_l( - &mut self, - _: usize - ) -> Result - { + fn get_l(&mut self, _: usize) -> Result { Ok((self.l.clone(), 0)) } fn get_a( &mut self, num_inputs: usize, - _: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> - { + _: usize, + ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> { Ok(((self.a.clone(), 0), (self.a.clone(), num_inputs))) } fn get_b_g1( &mut self, num_inputs: usize, - _: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> - { + _: usize, + ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> { Ok(((self.b_g1.clone(), 0), (self.b_g1.clone(), num_inputs))) } fn get_b_g2( &mut self, num_inputs: usize, - _: usize - ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> - { + _: usize, + ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> { Ok(((self.b_g2.clone(), 0), (self.b_g2.clone(), num_inputs))) } } @@ -484,41 +465,38 @@ impl<'a, E: Engine> ParameterSource for &'a Parameters { #[cfg(test)] mod test_with_bls12_381 { use super::*; - use {Circuit, SynthesisError, ConstraintSystem}; + use {Circuit, ConstraintSystem, SynthesisError}; use ff::Field; - use rand::{thread_rng}; use pairing::bls12_381::{Bls12, Fr}; + use rand::thread_rng; #[test] fn serialization() { struct MySillyCircuit { a: Option, - b: Option + b: Option, } impl Circuit for MySillyCircuit { fn synthesize>( self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { + cs: &mut CS, + ) -> Result<(), SynthesisError> { let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?; let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?; - let c = cs.alloc_input(|| "c", || { - let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; - let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; + let c = cs.alloc_input( + || "c", + || { + let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; + let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; - a.mul_assign(&b); - Ok(a) - })?; + a.mul_assign(&b); + Ok(a) + }, + )?; - cs.enforce( - || "a*b=c", - |lc| lc + a, - |lc| lc + b, - |lc| lc + c - ); + cs.enforce(|| "a*b=c", |lc| lc + a, |lc| lc + b, |lc| lc + c); Ok(()) } @@ -526,10 +504,9 @@ mod test_with_bls12_381 { let rng = &mut thread_rng(); - let params = generate_random_parameters::( - MySillyCircuit { a: None, b: None }, - rng - ).unwrap(); + let params = + generate_random_parameters::(MySillyCircuit { a: None, b: None }, rng) + .unwrap(); { let mut v = vec![]; @@ -555,11 +532,12 @@ mod test_with_bls12_381 { let proof = create_random_proof( MySillyCircuit { a: Some(a), - b: Some(b) + b: Some(b), }, ¶ms, - rng - ).unwrap(); + rng, + ) + .unwrap(); let mut v = vec![]; proof.write(&mut v).unwrap(); diff --git a/src/groth16/prover.rs b/src/groth16/prover.rs index ceb3dce7f..a502ac332 100644 --- a/src/groth16/prover.rs +++ b/src/groth16/prover.rs @@ -8,43 +8,23 @@ use ff::{Field, PrimeField}; use group::{CurveAffine, CurveProjective}; use pairing::Engine; -use super::{ - ParameterSource, - Proof -}; +use super::{ParameterSource, Proof}; -use ::{ - SynthesisError, - Circuit, - ConstraintSystem, - LinearCombination, - Variable, - Index -}; +use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; -use ::domain::{ - EvaluationDomain, - Scalar -}; +use domain::{EvaluationDomain, Scalar}; -use ::multiexp::{ - DensityTracker, - FullDensity, - multiexp -}; +use multiexp::{multiexp, DensityTracker, FullDensity}; -use ::multicore::{ - Worker -}; +use multicore::Worker; fn eval( lc: &LinearCombination, mut input_density: Option<&mut DensityTracker>, mut aux_density: Option<&mut DensityTracker>, input_assignment: &[E::Fr], - aux_assignment: &[E::Fr] -) -> E::Fr -{ + aux_assignment: &[E::Fr], +) -> E::Fr { let mut acc = E::Fr::zero(); for &(index, coeff) in lc.0.iter() { @@ -56,7 +36,7 @@ fn eval( if let Some(ref mut v) = input_density { v.inc(i); } - }, + } Variable(Index::Aux(i)) => { tmp = aux_assignment[i]; if let Some(ref mut v) = aux_density { @@ -66,10 +46,10 @@ fn eval( } if coeff == E::Fr::one() { - acc.add_assign(&tmp); + acc.add_assign(&tmp); } else { - tmp.mul_assign(&coeff); - acc.add_assign(&tmp); + tmp.mul_assign(&coeff); + acc.add_assign(&tmp); } } @@ -89,18 +69,17 @@ struct ProvingAssignment { // Assignments of variables input_assignment: Vec, - aux_assignment: Vec + aux_assignment: Vec, } impl ConstraintSystem for ProvingAssignment { type Root = Self; - fn alloc( - &mut self, - _: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, _: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.aux_assignment.push(f()?); self.a_aux_density.add_element(); @@ -109,12 +88,11 @@ impl ConstraintSystem for ProvingAssignment { Ok(Variable(Index::Aux(self.aux_assignment.len() - 1))) } - fn alloc_input( - &mut self, - _: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, _: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.input_assignment.push(f()?); self.b_input_density.add_element(); @@ -122,17 +100,13 @@ impl ConstraintSystem for ProvingAssignment { Ok(Variable(Index::Input(self.input_assignment.len() - 1))) } - fn enforce( - &mut self, - _: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, _: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { let a = a(LinearCombination::zero()); let b = b(LinearCombination::zero()); @@ -146,14 +120,14 @@ impl ConstraintSystem for ProvingAssignment { None, Some(&mut self.a_aux_density), &self.input_assignment, - &self.aux_assignment + &self.aux_assignment, ))); self.b.push(Scalar(eval( &b, Some(&mut self.b_input_density), Some(&mut self.b_aux_density), &self.input_assignment, - &self.aux_assignment + &self.aux_assignment, ))); self.c.push(Scalar(eval( &c, @@ -164,18 +138,19 @@ impl ConstraintSystem for ProvingAssignment { None, None, &self.input_assignment, - &self.aux_assignment + &self.aux_assignment, ))); } fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { // Do nothing; we don't care about namespaces in this context. } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { // Do nothing; we don't care about namespaces in this context. } @@ -187,9 +162,12 @@ impl ConstraintSystem for ProvingAssignment { pub fn create_random_proof>( circuit: C, params: P, - rng: &mut R + rng: &mut R, ) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: RngCore +where + E: Engine, + C: Circuit, + R: RngCore, { let r = E::Fr::random(rng); let s = E::Fr::random(rng); @@ -201,9 +179,11 @@ pub fn create_proof>( circuit: C, mut params: P, r: E::Fr, - s: E::Fr + s: E::Fr, ) -> Result, SynthesisError> - where E: Engine, C: Circuit +where + E: Engine, + C: Circuit, { let mut prover = ProvingAssignment { a_aux_density: DensityTracker::new(), @@ -213,7 +193,7 @@ pub fn create_proof>( b: vec![], c: vec![], input_assignment: vec![], - aux_assignment: vec![] + aux_assignment: vec![], }; prover.alloc_input(|| "", || Ok(E::Fr::one()))?; @@ -221,11 +201,7 @@ pub fn create_proof>( circuit.synthesize(&mut prover)?; for i in 0..prover.input_assignment.len() { - prover.enforce(|| "", - |lc| lc + Variable(Index::Input(i)), - |lc| lc, - |lc| lc, - ); + prover.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc); } let worker = Worker::new(); @@ -259,31 +235,76 @@ pub fn create_proof>( }; // TODO: parallelize if it's even helpful - let input_assignment = Arc::new(prover.input_assignment.into_iter().map(|s| s.into_repr()).collect::>()); - let aux_assignment = Arc::new(prover.aux_assignment.into_iter().map(|s| s.into_repr()).collect::>()); + let input_assignment = Arc::new( + prover + .input_assignment + .into_iter() + .map(|s| s.into_repr()) + .collect::>(), + ); + let aux_assignment = Arc::new( + prover + .aux_assignment + .into_iter() + .map(|s| s.into_repr()) + .collect::>(), + ); - let l = multiexp(&worker, params.get_l(aux_assignment.len())?, FullDensity, aux_assignment.clone()); + let l = multiexp( + &worker, + params.get_l(aux_assignment.len())?, + FullDensity, + aux_assignment.clone(), + ); let a_aux_density_total = prover.a_aux_density.get_total_density(); - let (a_inputs_source, a_aux_source) = params.get_a(input_assignment.len(), a_aux_density_total)?; + let (a_inputs_source, a_aux_source) = + params.get_a(input_assignment.len(), a_aux_density_total)?; - let a_inputs = multiexp(&worker, a_inputs_source, FullDensity, input_assignment.clone()); - let a_aux = multiexp(&worker, a_aux_source, Arc::new(prover.a_aux_density), aux_assignment.clone()); + let a_inputs = multiexp( + &worker, + a_inputs_source, + FullDensity, + input_assignment.clone(), + ); + let a_aux = multiexp( + &worker, + a_aux_source, + Arc::new(prover.a_aux_density), + aux_assignment.clone(), + ); let b_input_density = Arc::new(prover.b_input_density); let b_input_density_total = b_input_density.get_total_density(); let b_aux_density = Arc::new(prover.b_aux_density); let b_aux_density_total = b_aux_density.get_total_density(); - let (b_g1_inputs_source, b_g1_aux_source) = params.get_b_g1(b_input_density_total, b_aux_density_total)?; + let (b_g1_inputs_source, b_g1_aux_source) = + params.get_b_g1(b_input_density_total, b_aux_density_total)?; - let b_g1_inputs = multiexp(&worker, b_g1_inputs_source, b_input_density.clone(), input_assignment.clone()); - let b_g1_aux = multiexp(&worker, b_g1_aux_source, b_aux_density.clone(), aux_assignment.clone()); + let b_g1_inputs = multiexp( + &worker, + b_g1_inputs_source, + b_input_density.clone(), + input_assignment.clone(), + ); + let b_g1_aux = multiexp( + &worker, + b_g1_aux_source, + b_aux_density.clone(), + aux_assignment.clone(), + ); - let (b_g2_inputs_source, b_g2_aux_source) = params.get_b_g2(b_input_density_total, b_aux_density_total)?; - - let b_g2_inputs = multiexp(&worker, b_g2_inputs_source, b_input_density, input_assignment); + let (b_g2_inputs_source, b_g2_aux_source) = + params.get_b_g2(b_input_density_total, b_aux_density_total)?; + + let b_g2_inputs = multiexp( + &worker, + b_g2_inputs_source, + b_input_density, + input_assignment, + ); let b_g2_aux = multiexp(&worker, b_g2_aux_source, b_aux_density, aux_assignment); if vk.delta_g1.is_zero() || vk.delta_g2.is_zero() { @@ -325,6 +346,6 @@ pub fn create_proof>( Ok(Proof { a: g_a.into_affine(), b: g_b.into_affine(), - c: g_c.into_affine() + c: g_c.into_affine(), }) } diff --git a/src/groth16/tests/dummy_engine.rs b/src/groth16/tests/dummy_engine.rs index 654b8148a..4c5874d71 100644 --- a/src/groth16/tests/dummy_engine.rs +++ b/src/groth16/tests/dummy_engine.rs @@ -1,12 +1,13 @@ use ff::{ - Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, - PrimeFieldRepr, ScalarEngine, SqrtField}; + Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, + SqrtField, +}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use pairing::{Engine, PairingCurveAffine}; +use rand_core::RngCore; use std::cmp::Ordering; use std::fmt; -use rand_core::RngCore; use std::num::Wrapping; const MODULUS_R: Wrapping = Wrapping(64513); @@ -80,9 +81,13 @@ impl SqrtField for Fr { fn legendre(&self) -> LegendreSymbol { // s = self^((r - 1) // 2) let s = self.pow([32256]); - if s == ::zero() { LegendreSymbol::Zero } - else if s == ::one() { LegendreSymbol::QuadraticResidue } - else { LegendreSymbol::QuadraticNonResidue } + if s == ::zero() { + LegendreSymbol::Zero + } else if s == ::one() { + LegendreSymbol::QuadraticResidue + } else { + LegendreSymbol::QuadraticNonResidue + } } fn sqrt(&self) -> Option { @@ -100,7 +105,7 @@ impl SqrtField for Fr { let mut m = Fr::S; while t != ::one() { - let mut i = 1; + let mut i = 1; { let mut t2i = t; t2i.square(); @@ -258,15 +263,18 @@ impl Engine for DummyEngine { type G2Affine = Fr; type Fq = Fr; type Fqe = Fr; - + // TODO: This should be F_645131 or something. Doesn't matter for now. type Fqk = Fr; fn miller_loop<'a, I>(i: I) -> Self::Fqk - where I: IntoIterator::Prepared, - &'a ::Prepared - )> + where + I: IntoIterator< + Item = &'a ( + &'a ::Prepared, + &'a ::Prepared, + ), + >, { let mut acc = ::zero(); @@ -280,8 +288,7 @@ impl Engine for DummyEngine { } /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(this: &Self::Fqk) -> Option - { + fn final_exponentiation(this: &Self::Fqk) -> Option { Some(*this) } } @@ -308,9 +315,7 @@ impl CurveProjective for Fr { ::is_zero(self) } - fn batch_normalization(_: &mut [Self]) { - - } + fn batch_normalization(_: &mut [Self]) {} fn is_normalized(&self) -> bool { true @@ -332,8 +337,7 @@ impl CurveProjective for Fr { ::negate(self); } - fn mul_assign::Repr>>(&mut self, other: S) - { + fn mul_assign::Repr>>(&mut self, other: S) { let tmp = Fr::from_repr(other.into()).unwrap(); ::mul_assign(self, &tmp); @@ -415,8 +419,7 @@ impl CurveAffine for Fr { ::negate(self); } - fn mul::Repr>>(&self, other: S) -> Self::Projective - { + fn mul::Repr>>(&self, other: S) -> Self::Projective { let mut res = *self; let tmp = Fr::from_repr(other.into()).unwrap(); diff --git a/src/groth16/tests/mod.rs b/src/groth16/tests/mod.rs index 0e05c36ab..e6a36e4bc 100644 --- a/src/groth16/tests/mod.rs +++ b/src/groth16/tests/mod.rs @@ -6,86 +6,82 @@ use self::dummy_engine::*; use std::marker::PhantomData; -use ::{ - Circuit, - ConstraintSystem, - SynthesisError -}; +use {Circuit, ConstraintSystem, SynthesisError}; -use super::{ - generate_parameters, - prepare_verifying_key, - create_proof, - verify_proof -}; +use super::{create_proof, generate_parameters, prepare_verifying_key, verify_proof}; struct XORDemo { a: Option, b: Option, - _marker: PhantomData + _marker: PhantomData, } impl Circuit for XORDemo { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - let a_var = cs.alloc(|| "a", || { - if self.a.is_some() { - if self.a.unwrap() { - Ok(E::Fr::one()) + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { + let a_var = cs.alloc( + || "a", + || { + if self.a.is_some() { + if self.a.unwrap() { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } } else { - Ok(E::Fr::zero()) + Err(SynthesisError::AssignmentMissing) } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; + }, + )?; cs.enforce( || "a_boolean_constraint", |lc| lc + CS::one() - a_var, |lc| lc + a_var, - |lc| lc + |lc| lc, ); - let b_var = cs.alloc(|| "b", || { - if self.b.is_some() { - if self.b.unwrap() { - Ok(E::Fr::one()) + let b_var = cs.alloc( + || "b", + || { + if self.b.is_some() { + if self.b.unwrap() { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } } else { - Ok(E::Fr::zero()) + Err(SynthesisError::AssignmentMissing) } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; + }, + )?; cs.enforce( || "b_boolean_constraint", |lc| lc + CS::one() - b_var, |lc| lc + b_var, - |lc| lc + |lc| lc, ); - let c_var = cs.alloc_input(|| "c", || { - if self.a.is_some() && self.b.is_some() { - if self.a.unwrap() ^ self.b.unwrap() { - Ok(E::Fr::one()) + let c_var = cs.alloc_input( + || "c", + || { + if self.a.is_some() && self.b.is_some() { + if self.a.unwrap() ^ self.b.unwrap() { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } } else { - Ok(E::Fr::zero()) + Err(SynthesisError::AssignmentMissing) } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; + }, + )?; cs.enforce( || "c_xor_constraint", |lc| lc + a_var + a_var, |lc| lc + b_var, - |lc| lc + a_var + b_var - c_var + |lc| lc + a_var + b_var - c_var, ); Ok(()) @@ -106,19 +102,10 @@ fn test_xordemo() { let c = XORDemo:: { a: None, b: None, - _marker: PhantomData + _marker: PhantomData, }; - generate_parameters( - c, - g1, - g2, - alpha, - beta, - gamma, - delta, - tau - ).unwrap() + generate_parameters(c, g1, g2, alpha, beta, gamma, delta, tau).unwrap() }; // This will synthesize the constraint system: @@ -226,32 +213,35 @@ fn test_xordemo() { 59158 */ - let u_i = [59158, 48317, 21767, 10402].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); - let v_i = [0, 0, 60619, 30791].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); - let w_i = [0, 23320, 41193, 41193].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); + let u_i = [59158, 48317, 21767, 10402] + .iter() + .map(|e| Fr::from_str(&format!("{}", e)).unwrap()) + .collect::>(); + let v_i = [0, 0, 60619, 30791] + .iter() + .map(|e| Fr::from_str(&format!("{}", e)).unwrap()) + .collect::>(); + let w_i = [0, 23320, 41193, 41193] + .iter() + .map(|e| Fr::from_str(&format!("{}", e)).unwrap()) + .collect::>(); - for (u, a) in u_i.iter() - .zip(¶ms.a[..]) - { + for (u, a) in u_i.iter().zip(¶ms.a[..]) { assert_eq!(u, a); } - for (v, b) in v_i.iter() - .filter(|&&e| e != Fr::zero()) - .zip(¶ms.b_g1[..]) + for (v, b) in v_i + .iter() + .filter(|&&e| e != Fr::zero()) + .zip(¶ms.b_g1[..]) { assert_eq!(v, b); } - for (v, b) in v_i.iter() - .filter(|&&e| e != Fr::zero()) - .zip(¶ms.b_g2[..]) + for (v, b) in v_i + .iter() + .filter(|&&e| e != Fr::zero()) + .zip(¶ms.b_g2[..]) { assert_eq!(v, b); } @@ -296,15 +286,10 @@ fn test_xordemo() { let c = XORDemo { a: Some(true), b: Some(false), - _marker: PhantomData + _marker: PhantomData, }; - create_proof( - c, - ¶ms, - r, - s - ).unwrap() + create_proof(c, ¶ms, r, s).unwrap() }; // A(x) = @@ -320,7 +305,7 @@ fn test_xordemo() { expected_a.add_assign(&u_i[0]); // a_0 = 1 expected_a.add_assign(&u_i[1]); // a_1 = 1 expected_a.add_assign(&u_i[2]); // a_2 = 1 - // a_3 = 0 + // a_3 = 0 assert_eq!(proof.a, expected_a); } @@ -337,7 +322,7 @@ fn test_xordemo() { expected_b.add_assign(&v_i[0]); // a_0 = 1 expected_b.add_assign(&v_i[1]); // a_1 = 1 expected_b.add_assign(&v_i[2]); // a_2 = 1 - // a_3 = 0 + // a_3 = 0 assert_eq!(proof.b, expected_b); } @@ -378,7 +363,10 @@ fn test_xordemo() { expected_c.add_assign(¶ms.l[0]); // H query answer - for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739].iter().enumerate() { + for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739] + .iter() + .enumerate() + { let coeff = Fr::from_str(&format!("{}", coeff)).unwrap(); let mut tmp = params.h[i]; @@ -389,9 +377,5 @@ fn test_xordemo() { assert_eq!(expected_c, proof.c); } - assert!(verify_proof( - &pvk, - &proof, - &[Fr::one()] - ).unwrap()); + assert!(verify_proof(&pvk, &proof, &[Fr::one()]).unwrap()); } diff --git a/src/groth16/verifier.rs b/src/groth16/verifier.rs index 71c747837..926955a98 100644 --- a/src/groth16/verifier.rs +++ b/src/groth16/verifier.rs @@ -2,20 +2,11 @@ use ff::PrimeField; use group::{CurveAffine, CurveProjective}; use pairing::{Engine, PairingCurveAffine}; -use super::{ - Proof, - VerifyingKey, - PreparedVerifyingKey -}; +use super::{PreparedVerifyingKey, Proof, VerifyingKey}; -use ::{ - SynthesisError -}; +use SynthesisError; -pub fn prepare_verifying_key( - vk: &VerifyingKey -) -> PreparedVerifyingKey -{ +pub fn prepare_verifying_key(vk: &VerifyingKey) -> PreparedVerifyingKey { let mut gamma = vk.gamma_g2; gamma.negate(); let mut delta = vk.delta_g2; @@ -25,16 +16,15 @@ pub fn prepare_verifying_key( alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2), neg_gamma_g2: gamma.prepare(), neg_delta_g2: delta.prepare(), - ic: vk.ic.clone() + ic: vk.ic.clone(), } } pub fn verify_proof<'a, E: Engine>( pvk: &'a PreparedVerifyingKey, proof: &Proof, - public_inputs: &[E::Fr] -) -> Result -{ + public_inputs: &[E::Fr], +) -> Result { if (public_inputs.len() + 1) != pvk.ic.len() { return Err(SynthesisError::MalformedVerifyingKey); } @@ -53,11 +43,14 @@ pub fn verify_proof<'a, E: Engine>( // A * B + inputs * (-gamma) + C * (-delta) = alpha * beta // which allows us to do a single final exponentiation. - Ok(E::final_exponentiation( - &E::miller_loop([ + Ok(E::final_exponentiation(&E::miller_loop( + [ (&proof.a.prepare(), &proof.b.prepare()), (&acc.into_affine().prepare(), &pvk.neg_gamma_g2), - (&proof.c.prepare(), &pvk.neg_delta_g2) - ].into_iter()) - ).unwrap() == pvk.alpha_g1_beta_g2) + (&proof.c.prepare(), &pvk.neg_delta_g2), + ] + .into_iter(), + )) + .unwrap() + == pvk.alpha_g1_beta_g2) } diff --git a/src/lib.rs b/src/lib.rs index ee6bb8861..96400c9fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,10 +4,10 @@ extern crate group; extern crate pairing; extern crate rand_core; -extern crate futures; extern crate bit_vec; extern crate blake2s_simd; extern crate byteorder; +extern crate futures; #[cfg(feature = "multicore")] extern crate crossbeam; @@ -29,20 +29,20 @@ extern crate rand_xorshift; #[cfg(test)] extern crate sha2; -pub mod gadgets; -pub mod multicore; -mod multiexp; pub mod domain; +pub mod gadgets; #[cfg(feature = "groth16")] pub mod groth16; +pub mod multicore; +mod multiexp; use ff::{Field, ScalarEngine}; -use std::ops::{Add, Sub}; -use std::fmt; use std::error::Error; +use std::fmt; use std::io; use std::marker::PhantomData; +use std::ops::{Add, Sub}; /// Computations are expressed in terms of arithmetic circuits, in particular /// rank-1 quadratic constraint systems. The `Circuit` trait represents a @@ -50,10 +50,7 @@ use std::marker::PhantomData; /// CRS generation and during proving. pub trait Circuit { /// Synthesize the circuit into a rank-1 quadratic constraint system - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError>; + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError>; } /// Represents a variable in our constraint system. @@ -79,7 +76,7 @@ impl Variable { #[derive(Copy, Clone, PartialEq, Debug)] pub enum Index { Input(usize), - Aux(usize) + Aux(usize), } /// This represents a linear combination of some variables, with coefficients @@ -206,7 +203,7 @@ pub enum SynthesisError { /// During verification, our verifying key was malformed. MalformedVerifyingKey, /// During CRS generation, we observed an unconstrained auxiliary variable - UnconstrainedVariable + UnconstrainedVariable, } impl From for SynthesisError { @@ -218,14 +215,16 @@ impl From for SynthesisError { impl Error for SynthesisError { fn description(&self) -> &str { match *self { - SynthesisError::AssignmentMissing => "an assignment for a variable could not be computed", + SynthesisError::AssignmentMissing => { + "an assignment for a variable could not be computed" + } SynthesisError::DivisionByZero => "division by zero", SynthesisError::Unsatisfiable => "unsatisfiable constraint system", SynthesisError::PolynomialDegreeTooLarge => "polynomial degree is too large", SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS", SynthesisError::IoError(_) => "encountered an I/O error", SynthesisError::MalformedVerifyingKey => "malformed verifying key", - SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained" + SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained", } } } @@ -257,40 +256,36 @@ pub trait ConstraintSystem: Sized { /// determine the assignment of the variable. The given `annotation` function is invoked /// in testing contexts in order to derive a unique name for this variable in the current /// namespace. - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into; /// Allocate a public variable in the constraint system. The provided function is used to /// determine the assignment of the variable. - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into; /// Enforce that `A` * `B` = `C`. The `annotation` function is invoked in testing contexts /// in order to derive a unique name for the constraint in the current namespace. - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination; + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination; /// Create a new (sub)namespace and enter into it. Not intended /// for downstream use; use `namespace` instead. fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR; + where + NR: Into, + N: FnOnce() -> NR; /// Exit out of the existing namespace. Not intended for /// downstream use; use `namespace` instead. @@ -301,11 +296,10 @@ pub trait ConstraintSystem: Sized { fn get_root(&mut self) -> &mut Self::Root; /// Begin a namespace for this constraint system. - fn namespace<'a, NR, N>( - &'a mut self, - name_fn: N - ) -> Namespace<'a, E, Self::Root> - where NR: Into, N: FnOnce() -> NR + fn namespace<'a, NR, N>(&'a mut self, name_fn: N) -> Namespace<'a, E, Self::Root> + where + NR: Into, + N: FnOnce() -> NR, { self.get_root().push_namespace(name_fn); @@ -324,37 +318,31 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for Name CS::one() } - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.0.alloc(annotation, f) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.0.alloc_input(annotation, f) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { self.0.enforce(annotation, a, b, c) } @@ -364,18 +352,18 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for Name // never a root constraint system. fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { panic!("only the root's push_namespace should be called"); } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { panic!("only the root's pop_namespace should be called"); } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { self.0.get_root() } } @@ -395,54 +383,48 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for &'cs CS::one() } - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { (**self).alloc(annotation, f) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { (**self).alloc_input(annotation, f) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { (**self).enforce(annotation, a, b, c) } fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { (**self).push_namespace(name_fn) } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { (**self).pop_namespace() } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { (**self).get_root() } } diff --git a/src/multicore.rs b/src/multicore.rs index 8d0b00c51..e8b2dae1f 100644 --- a/src/multicore.rs +++ b/src/multicore.rs @@ -6,15 +6,15 @@ #[cfg(feature = "multicore")] mod implementation { - use num_cpus; - use futures::{Future, IntoFuture, Poll}; - use futures_cpupool::{CpuPool, CpuFuture}; use crossbeam::{self, Scope}; + use futures::{Future, IntoFuture, Poll}; + use futures_cpupool::{CpuFuture, CpuPool}; + use num_cpus; #[derive(Clone)] pub struct Worker { cpus: usize, - pool: CpuPool + pool: CpuPool, } impl Worker { @@ -24,7 +24,7 @@ mod implementation { pub(crate) fn new_with_cpus(cpus: usize) -> Worker { Worker { cpus: cpus, - pool: CpuPool::new(cpus) + pool: CpuPool::new(cpus), } } @@ -36,26 +36,22 @@ mod implementation { log2_floor(self.cpus) } - pub fn compute( - &self, f: F - ) -> WorkerFuture - where F: FnOnce() -> R + Send + 'static, - R: IntoFuture + 'static, - R::Future: Send + 'static, - R::Item: Send + 'static, - R::Error: Send + 'static + pub fn compute(&self, f: F) -> WorkerFuture + where + F: FnOnce() -> R + Send + 'static, + R: IntoFuture + 'static, + R::Future: Send + 'static, + R::Item: Send + 'static, + R::Error: Send + 'static, { WorkerFuture { - future: self.pool.spawn_fn(f) + future: self.pool.spawn_fn(f), } } - pub fn scope<'a, F, R>( - &self, - elements: usize, - f: F - ) -> R - where F: FnOnce(&Scope<'a>, usize) -> R + pub fn scope<'a, F, R>(&self, elements: usize, f: F) -> R + where + F: FnOnce(&Scope<'a>, usize) -> R, { let chunk_size = if elements < self.cpus { 1 @@ -63,22 +59,19 @@ mod implementation { elements / self.cpus }; - crossbeam::scope(|scope| { - f(scope, chunk_size) - }) + crossbeam::scope(|scope| f(scope, chunk_size)) } } pub struct WorkerFuture { - future: CpuFuture + future: CpuFuture, } impl Future for WorkerFuture { type Item = T; type Error = E; - fn poll(&mut self) -> Poll - { + fn poll(&mut self) -> Poll { self.future.poll() } } @@ -88,7 +81,7 @@ mod implementation { let mut pow = 0; - while (1 << (pow+1)) <= num { + while (1 << (pow + 1)) <= num { pow += 1; } diff --git a/src/multiexp.rs b/src/multiexp.rs index c6553971b..fabb97853 100644 --- a/src/multiexp.rs +++ b/src/multiexp.rs @@ -1,11 +1,11 @@ -use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; -use group::{CurveAffine, CurveProjective}; -use std::sync::Arc; -use std::io; -use bit_vec::{self, BitVec}; -use std::iter; -use futures::{Future}; use super::multicore::Worker; +use bit_vec::{self, BitVec}; +use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; +use futures::Future; +use group::{CurveAffine, CurveProjective}; +use std::io; +use std::iter; +use std::sync::Arc; use super::SynthesisError; @@ -19,7 +19,10 @@ pub trait SourceBuilder: Send + Sync + 'static + Clone { /// A source of bases, like an iterator. pub trait Source { /// Parses the element from the source. Fails if the point is at infinity. - fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError>; + fn add_assign_mixed( + &mut self, + to: &mut ::Projective, + ) -> Result<(), SynthesisError>; /// Skips `amt` elements from the source, avoiding deserialization. fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>; @@ -34,13 +37,20 @@ impl SourceBuilder for (Arc>, usize) { } impl Source for (Arc>, usize) { - fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError> { + fn add_assign_mixed( + &mut self, + to: &mut ::Projective, + ) -> Result<(), SynthesisError> { if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "expected more bases from source", + ) + .into()); } if self.0[self.1].is_zero() { - return Err(SynthesisError::UnexpectedIdentity) + return Err(SynthesisError::UnexpectedIdentity); } to.add_assign_mixed(&self.0[self.1]); @@ -52,7 +62,11 @@ impl Source for (Arc>, usize) { fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> { if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "expected more bases from source", + ) + .into()); } self.1 += amt; @@ -63,7 +77,7 @@ impl Source for (Arc>, usize) { pub trait QueryDensity { /// Returns whether the base exists. - type Iter: Iterator; + type Iter: Iterator; fn iter(self) -> Self::Iter; fn get_query_size(self) -> Option; @@ -92,7 +106,7 @@ impl<'a> QueryDensity for &'a FullDensity { pub struct DensityTracker { bv: BitVec, - total_density: usize + total_density: usize, } impl<'a> QueryDensity for &'a DensityTracker { @@ -111,7 +125,7 @@ impl DensityTracker { pub fn new() -> DensityTracker { DensityTracker { bv: BitVec::new(), - total_density: 0 + total_density: 0, } } @@ -138,12 +152,13 @@ fn multiexp_inner( exponents: Arc::Fr as PrimeField>::Repr>>, mut skip: u32, c: u32, - handle_trivial: bool -) -> Box::Projective, Error=SynthesisError>> - where for<'a> &'a Q: QueryDensity, - D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder + handle_trivial: bool, +) -> Box::Projective, Error = SynthesisError>> +where + for<'a> &'a Q: QueryDensity, + D: Send + Sync + 'static + Clone + AsRef, + G: CurveAffine, + S: SourceBuilder, { // Perform this region of the multiexp let this = { @@ -212,16 +227,24 @@ fn multiexp_inner( // There's another region more significant. Calculate and join it with // this region recursively. Box::new( - this.join(multiexp_inner(pool, bases, density_map, exponents, skip, c, false)) - .map(move |(this, mut higher)| { - for _ in 0..c { - higher.double(); - } + this.join(multiexp_inner( + pool, + bases, + density_map, + exponents, + skip, + c, + false, + )) + .map(move |(this, mut higher)| { + for _ in 0..c { + higher.double(); + } - higher.add_assign(&this); + higher.add_assign(&this); - higher - }) + higher + }), ) } } @@ -232,12 +255,13 @@ pub fn multiexp( pool: &Worker, bases: S, density_map: D, - exponents: Arc::Fr as PrimeField>::Repr>> -) -> Box::Projective, Error=SynthesisError>> - where for<'a> &'a Q: QueryDensity, - D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder + exponents: Arc::Fr as PrimeField>::Repr>>, +) -> Box::Projective, Error = SynthesisError>> +where + for<'a> &'a Q: QueryDensity, + D: Send + Sync + 'static + Clone + AsRef, + G: CurveAffine, + S: SourceBuilder, { let c = if exponents.len() < 32 { 3u32 @@ -260,9 +284,8 @@ pub fn multiexp( fn test_with_bls12() { fn naive_multiexp( bases: Arc>, - exponents: Arc::Repr>> - ) -> G::Projective - { + exponents: Arc::Repr>>, + ) -> G::Projective { assert_eq!(bases.len(), exponents.len()); let mut acc = G::Projective::zero(); @@ -274,25 +297,28 @@ fn test_with_bls12() { acc } - use rand; use pairing::{bls12_381::Bls12, Engine}; + use rand; const SAMPLES: usize = 1 << 14; let rng = &mut rand::thread_rng(); - let v = Arc::new((0..SAMPLES).map(|_| ::Fr::random(rng).into_repr()).collect::>()); - let g = Arc::new((0..SAMPLES).map(|_| ::G1::random(rng).into_affine()).collect::>()); + let v = Arc::new( + (0..SAMPLES) + .map(|_| ::Fr::random(rng).into_repr()) + .collect::>(), + ); + let g = Arc::new( + (0..SAMPLES) + .map(|_| ::G1::random(rng).into_affine()) + .collect::>(), + ); let naive = naive_multiexp(g.clone(), v.clone()); let pool = Worker::new(); - let fast = multiexp( - &pool, - (g, 0), - FullDensity, - v - ).wait().unwrap(); + let fast = multiexp(&pool, (g, 0), FullDensity, v).wait().unwrap(); assert_eq!(naive, fast); } diff --git a/tests/mimc.rs b/tests/mimc.rs index d08940f75..18aaece94 100644 --- a/tests/mimc.rs +++ b/tests/mimc.rs @@ -14,31 +14,21 @@ use ff::{Field, ScalarEngine}; use pairing::Engine; // We're going to use the BLS12-381 pairing-friendly elliptic curve. -use pairing::bls12_381::{ - Bls12 -}; +use pairing::bls12_381::Bls12; // We'll use these interfaces to construct our circuit. -use bellman::{ - Circuit, - ConstraintSystem, - SynthesisError -}; +use bellman::{Circuit, ConstraintSystem, SynthesisError}; // We're going to use the Groth16 proving system. use bellman::groth16::{ - Proof, - generate_random_parameters, - prepare_verifying_key, - create_random_proof, - verify_proof, + create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof, }; const MIMC_ROUNDS: usize = 322; /// This is an implementation of MiMC, specifically a /// variant named `LongsightF322p3` for BLS12-381. -/// See http://eprint.iacr.org/2016/492 for more +/// See http://eprint.iacr.org/2016/492 for more /// information about this construction. /// /// ``` @@ -49,12 +39,7 @@ const MIMC_ROUNDS: usize = 322; /// return xL /// } /// ``` -fn mimc( - mut xl: E::Fr, - mut xr: E::Fr, - constants: &[E::Fr] -) -> E::Fr -{ +fn mimc(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr { assert_eq!(constants.len(), MIMC_ROUNDS); for i in 0..MIMC_ROUNDS { @@ -76,31 +61,29 @@ fn mimc( struct MiMCDemo<'a, E: Engine> { xl: Option, xr: Option, - constants: &'a [E::Fr] + constants: &'a [E::Fr], } /// Our demo circuit implements this `Circuit` trait which /// is used during paramgen and proving in order to /// synthesize the constraint system. impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { assert_eq!(self.constants.len(), MIMC_ROUNDS); // Allocate the first component of the preimage. let mut xl_value = self.xl; - let mut xl = cs.alloc(|| "preimage xl", || { - xl_value.ok_or(SynthesisError::AssignmentMissing) - })?; + let mut xl = cs.alloc( + || "preimage xl", + || xl_value.ok_or(SynthesisError::AssignmentMissing), + )?; // Allocate the second component of the preimage. let mut xr_value = self.xr; - let mut xr = cs.alloc(|| "preimage xr", || { - xr_value.ok_or(SynthesisError::AssignmentMissing) - })?; + let mut xr = cs.alloc( + || "preimage xr", + || xr_value.ok_or(SynthesisError::AssignmentMissing), + )?; for i in 0..MIMC_ROUNDS { // xL, xR := xR + (xL + Ci)^3, xL @@ -112,15 +95,16 @@ impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { e.square(); e }); - let mut tmp = cs.alloc(|| "tmp", || { - tmp_value.ok_or(SynthesisError::AssignmentMissing) - })?; + let mut tmp = cs.alloc( + || "tmp", + || tmp_value.ok_or(SynthesisError::AssignmentMissing), + )?; cs.enforce( || "tmp = (xL + Ci)^2", |lc| lc + xl + (self.constants[i], CS::one()), |lc| lc + xl + (self.constants[i], CS::one()), - |lc| lc + tmp + |lc| lc + tmp, ); // new_xL = xR + (xL + Ci)^3 @@ -133,23 +117,25 @@ impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { e }); - let mut new_xl = if i == (MIMC_ROUNDS-1) { + let mut new_xl = if i == (MIMC_ROUNDS - 1) { // This is the last round, xL is our image and so // we allocate a public input. - cs.alloc_input(|| "image", || { - new_xl_value.ok_or(SynthesisError::AssignmentMissing) - })? + cs.alloc_input( + || "image", + || new_xl_value.ok_or(SynthesisError::AssignmentMissing), + )? } else { - cs.alloc(|| "new_xl", || { - new_xl_value.ok_or(SynthesisError::AssignmentMissing) - })? + cs.alloc( + || "new_xl", + || new_xl_value.ok_or(SynthesisError::AssignmentMissing), + )? }; cs.enforce( || "new_xL = xR + (xL + Ci)^3", |lc| lc + tmp, |lc| lc + xl + (self.constants[i], CS::one()), - |lc| lc + new_xl - xr + |lc| lc + new_xl - xr, ); // xR = xL @@ -172,7 +158,9 @@ fn test_mimc() { let rng = &mut thread_rng(); // Generate the MiMC round constants - let constants = (0..MIMC_ROUNDS).map(|_| ::Fr::random(rng)).collect::>(); + let constants = (0..MIMC_ROUNDS) + .map(|_| ::Fr::random(rng)) + .collect::>(); println!("Creating parameters..."); @@ -181,7 +169,7 @@ fn test_mimc() { let c = MiMCDemo:: { xl: None, xr: None, - constants: &constants + constants: &constants, }; generate_random_parameters(c, rng).unwrap() @@ -216,7 +204,7 @@ fn test_mimc() { let c = MiMCDemo { xl: Some(xl), xr: Some(xr), - constants: &constants + constants: &constants, }; // Create a groth16 proof with our parameters. @@ -230,20 +218,16 @@ fn test_mimc() { let start = Instant::now(); let proof = Proof::read(&proof_vec[..]).unwrap(); // Check the proof - assert!(verify_proof( - &pvk, - &proof, - &[image] - ).unwrap()); + assert!(verify_proof(&pvk, &proof, &[image]).unwrap()); total_verifying += start.elapsed(); } let proving_avg = total_proving / SAMPLES; - let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (proving_avg.as_secs() as f64); + let proving_avg = + proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (proving_avg.as_secs() as f64); let verifying_avg = total_verifying / SAMPLES; - let verifying_avg = verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (verifying_avg.as_secs() as f64); + let verifying_avg = + verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (verifying_avg.as_secs() as f64); println!("Average proving time: {:?} seconds", proving_avg); println!("Average verifying time: {:?} seconds", verifying_avg);