use ff::{Field, PrimeField}; use pairing::Engine; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; pub struct MultiEq> { cs: CS, ops: usize, bits_used: usize, lhs: LinearCombination, rhs: LinearCombination, } impl> MultiEq { pub fn new(cs: CS) -> Self { MultiEq { cs: cs, ops: 0, bits_used: 0, lhs: LinearCombination::zero(), rhs: LinearCombination::zero(), } } fn accumulate(&mut self) { let ops = self.ops; let lhs = self.lhs.clone(); let rhs = self.rhs.clone(); self.cs.enforce( || format!("multieq {}", ops), |_| lhs, |lc| lc + CS::one(), |_| rhs, ); self.lhs = LinearCombination::zero(); self.rhs = LinearCombination::zero(); self.bits_used = 0; self.ops += 1; } pub fn enforce_equal( &mut self, num_bits: usize, lhs: &LinearCombination, rhs: &LinearCombination, ) { // Check if we will exceed the capacity if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) { self.accumulate(); } assert!((E::Fr::CAPACITY as usize) > (self.bits_used + num_bits)); let coeff = E::Fr::from_str("2").unwrap().pow(&[self.bits_used as u64]); self.lhs = self.lhs.clone() + (coeff, lhs); self.rhs = self.rhs.clone() + (coeff, rhs); self.bits_used += num_bits; } } impl> Drop for MultiEq { fn drop(&mut self) { if self.bits_used > 0 { self.accumulate(); } } } 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, { self.cs.alloc(annotation, f) } 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, { self.cs.enforce(annotation, a, b, c) } fn push_namespace(&mut self, name_fn: N) where NR: Into, N: FnOnce() -> NR, { self.cs.get_root().push_namespace(name_fn) } fn pop_namespace(&mut self) { self.cs.get_root().pop_namespace() } fn get_root(&mut self) -> &mut Self::Root { self } }