From 6efaeecc5c21201f19e9ffe7bd0e68e6a2f40e6a Mon Sep 17 00:00:00 2001 From: rebenkoy Date: Wed, 22 Nov 2023 01:35:52 +0300 Subject: [PATCH] consts moved into gate, static lookup for any table works --- src/circuit.rs | 29 +++++++-------- src/constraint_system.rs | 11 +++--- src/gadgets/arith.rs | 2 +- src/gadgets/bits.rs | 10 ++--- src/gadgets/ecmul.rs | 35 ++++++++++-------- src/gadgets/lc.rs | 10 ++--- src/gadgets/lookup.rs | 72 ++++++++++++++++++------------------ src/gadgets/nonzero_check.rs | 1 - src/gadgets/poseidon.rs | 11 +----- src/gadgets/range.rs | 12 +++--- src/gadgets/running_prod.rs | 2 +- src/gate.rs | 17 +++++---- src/gatelib.rs | 2 +- src/test.rs | 30 ++++++++------- src/utils/poly_utils.rs | 10 ++--- 15 files changed, 127 insertions(+), 127 deletions(-) diff --git a/src/circuit.rs b/src/circuit.rs index 52ac8f1..b6751b5 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -21,7 +21,7 @@ pub struct PolyOp<'closure, F: PrimeField>{ impl<'closure, F:PrimeField> PolyOp<'closure, F> { pub fn new(d: usize, i: usize, o: usize, f: impl Fn(&[F], &[F]) -> Vec + 'closure) -> Self { let f = Rc::new(f); - check_poly(d, i, o, f.clone()).unwrap(); + check_poly(d, i, o, f.clone(), &[]).unwrap(); Self { d, i, o, f } } @@ -41,7 +41,7 @@ impl<'closure, F: PrimeField> From> for Gatebb<'closure, F>{ results.iter().zip(outputs.iter()).map(|(res, out)|*res-*out).collect() }; - Gatebb::new(d, i, o, Rc::new(f)) + Gatebb::new(d, i, o, Rc::new(f), vec![]) } } @@ -249,7 +249,7 @@ where output } - fn apply_internal(&mut self, visibility: Visibility, round : usize, polyop: PolyOp<'circuit, F>, input: Vec, constants: &[F]) -> Vec { + fn apply_internal(&mut self, visibility: Visibility, round : usize, polyop: PolyOp<'circuit, F>, input: Vec) -> Vec { assert!(round < self.ops.len(), "The round is too large."); let op_index = self.ops[round].len(); @@ -270,40 +270,39 @@ where let mut gate_io = input; // do not move input into new buffer gate_io.extend(output.iter().cloned()); - self.constrain(&gate_io, &constants, polyop.into()); + self.constrain(&gate_io, polyop.into()); output } - pub fn apply(&mut self, round: usize, polyop: PolyOp<'circuit, F>, input: Vec, constants: &[F]) -> Vec { - self.apply_internal(Visibility::Private, round, polyop, input, constants) + pub fn apply(&mut self, round: usize, polyop: PolyOp<'circuit, F>, input: Vec) -> Vec { + self.apply_internal(Visibility::Private, round, polyop, input) } - pub fn apply_pub(&mut self, round : usize, polyop: PolyOp<'circuit, F>, input: Vec, constants: &[F]) -> Vec { - self.apply_internal(Visibility::Public, round, polyop, input, constants) + pub fn apply_pub(&mut self, round : usize, polyop: PolyOp<'circuit, F>, input: Vec) -> Vec { + self.apply_internal(Visibility::Public, round, polyop, input) } // TODO: pass input by value since we clone it down the stack either way - pub fn constrain(&mut self, input: &[Variable], constants: &[F], gate: G) { + pub fn constrain(&mut self, input: &[Variable], gate: G) { println!("Using legacy unnamed constrains"); - self._constrain(&input, &constants, gate) + self._constrain(&input, gate) } - fn _constrain(&mut self, input: &[Variable], constants: &[F], gate: G) { + fn _constrain(&mut self, input: &[Variable], gate: G) { assert!(gate.d() > 0, "Trying to constrain with gate of degree 0."); let kind = if gate.d() == 1 { CommitKind::Zero } else { CommitKind::Group }; - self.cs.constrain(kind, input, constants, gate); + self.cs.constrain(kind, input, gate); } pub fn constrain_with( &mut self, input: &[Variable], - constants: &[F], gate_fetcher: &dyn Fn(&FrozenMap>) -> G ) { let gate = gate_fetcher(&self.gate_registry); - self._constrain(&input, &constants, gate); + self._constrain(&input, gate); } pub fn load_pi(&'circuit mut self, round: usize, pi: ExternalValue) -> Variable { @@ -363,7 +362,7 @@ where pub fn valid_witness(&self) -> () { for constr in self.circuit.cs.iter_constraints() { let input_values: Vec<_> = constr.inputs.iter().map(|&x| self.cs.getvar(x)).collect(); - let result = constr.gate.exec(&input_values, &constr.constants); + let result = constr.gate.exec(&input_values); assert!(result.iter().all(|&output| output == F::ZERO), "Constraint {:?} is not satisfied", constr); } diff --git a/src/constraint_system.rs b/src/constraint_system.rs index 45c7c4c..07cc11c 100644 --- a/src/constraint_system.rs +++ b/src/constraint_system.rs @@ -35,7 +35,6 @@ pub struct Variable { #[derive(Debug, Clone)] pub struct Constraint<'c, F: PrimeField, G: Gate<'c, F>>{ pub inputs: Vec, - pub constants: Vec, pub gate: G, _marker: PhantomData<&'c F>, } @@ -63,12 +62,12 @@ impl<'c, F: PrimeField, G: Gate<'c, F>> ConstraintGroup<'c, F, G> { } } - pub fn constrain(&mut self, inputs: &[Variable], constants: &[F], gate: G) { + pub fn constrain(&mut self, inputs: &[Variable], gate: G) { assert!(gate.d() <= self.max_degree, "Constraint degree is too large for this group."); assert!(gate.i() == inputs.len(), "Invalid amount of arguments supplied."); self.num_rhs += gate.o(); - self.entries.push(Constraint{inputs : inputs.to_vec(), constants: constants.to_vec(), gate, _marker : PhantomData}); + self.entries.push(Constraint{inputs : inputs.to_vec(), gate, _marker : PhantomData}); } } @@ -114,7 +113,7 @@ pub trait CS<'c, F: PrimeField, G: Gate<'c, F>> { self.alloc_in_round(self.last_round(), visibility, size) } - fn constrain(&mut self, kind: CommitKind, inputs: &[Variable], constnts: &[F], gate: G); + fn constrain(&mut self, kind: CommitKind, inputs: &[Variable], gate: G); fn extval(&mut self, size: usize) -> Vec>; } @@ -192,8 +191,8 @@ impl<'c, F: PrimeField, G: Gate<'c, F>> CS<'c, F, G> for ConstraintSystem<'c, F, (prev..prev+size).into_iter().map(|index| Variable { visibility, round, index }).collect() } - fn constrain(&mut self, kind: CommitKind, inputs: &[Variable], constants: &[F], gate: G) { - self.constraint_group(kind).constrain(inputs, constants, gate); + fn constrain(&mut self, kind: CommitKind, inputs: &[Variable], gate: G) { + self.constraint_group(kind).constrain(inputs, gate); } fn extval(&mut self, size: usize) -> Vec> { diff --git a/src/gadgets/arith.rs b/src/gadgets/arith.rs index f25ee4c..97a5420 100644 --- a/src/gadgets/arith.rs +++ b/src/gadgets/arith.rs @@ -7,5 +7,5 @@ pub fn eq_gadget<'a, F: PrimeField+FieldUtils>( a: Variable, b: Variable, ) -> () { - circuit.constrain(&vec![a,b], &[], Gatebb::new(1, 2, 1, Rc::new(|args, _|vec![args[0]-args[1]]))); + circuit.constrain(&vec![a,b], Gatebb::new(1, 2, 1, Rc::new(|args, _|vec![args[0]-args[1]]), vec![])); } \ No newline at end of file diff --git a/src/gadgets/bits.rs b/src/gadgets/bits.rs index f30305e..f5beebe 100644 --- a/src/gadgets/bits.rs +++ b/src/gadgets/bits.rs @@ -46,16 +46,16 @@ pub fn bit_decomposition_gadget<'a, F: PrimeField+FieldUtils>(circuit: &mut Circ vec![] ); - let bitcheck_gate = Gatebb::new(2, 1, 1, Rc::new(|args, _| bitcheck::(args))); + let bitcheck_gate = Gatebb::new(2, 1, 1, Rc::new(|args, _| bitcheck::(args)), vec![]); for i in 0..num_bits-1 { - circuit.constrain(&vec![bits[i]], &[], bitcheck_gate.clone()) + circuit.constrain(&vec![bits[i]], bitcheck_gate.clone()) } - circuit.constrain(&vec![bits[num_bits-1]], &[], bitcheck_gate); + circuit.constrain(&vec![bits[num_bits-1]], bitcheck_gate); - let decompcheck_gate = Gatebb::new(1, num_bits+1, 1, Rc::new(|args, _| decompcheck::(args))); + let decompcheck_gate = Gatebb::new(1, num_bits+1, 1, Rc::new(|args, _| decompcheck::(args)), vec![]); let tmp : Vec<_> = repeat(input).take(1).chain(bits.iter().map(|x|*x)).collect(); - circuit.constrain(&tmp, &[], decompcheck_gate); + circuit.constrain(&tmp, decompcheck_gate); bits diff --git a/src/gadgets/ecmul.rs b/src/gadgets/ecmul.rs index e3dabd2..0fd059c 100644 --- a/src/gadgets/ecmul.rs +++ b/src/gadgets/ecmul.rs @@ -30,15 +30,19 @@ impl> EcAffinePoint { } pub fn new<'a>(circuit: &mut Circuit<'a, F, Gatebb<'a, F>>, x: Variable, y: Variable) -> Self{ - circuit.constrain(&[x,y], &[], Gatebb::new(3, 2, 1, Rc::new(|args, _|{ - let x = args[0]; - let y = args[1]; + circuit.constrain(&[x,y], Gatebb::new( + 3, 2, 1, + Rc::new(|args, _|{ + let x = args[0]; + let y = args[1]; - let a = C::a(); - let b = C::b(); + let a = C::a(); + let b = C::b(); - vec![x.cube() + a*x + b - y*y] - }))); + vec![x.cube() + a*x + b - y*y] + }), + vec![], + )); Self::new_unchecked(x,y) } @@ -93,7 +97,6 @@ pub fn eclin_gadget<'a, F: PrimeField+FieldUtils, C: CurveExt>( circuit.constrain( // Constrain that they are on the same line &pts, - &[], Gatebb::new( 2, 6, @@ -104,7 +107,8 @@ pub fn eclin_gadget<'a, F: PrimeField+FieldUtils, C: CurveExt>( let c = args[4]-args[0]; let d = -args[5]-args[1]; vec![a*d - b*c] - }) + }), + vec![], ) ); @@ -120,7 +124,6 @@ pub fn eclin_gadget<'a, F: PrimeField+FieldUtils, C: CurveExt>( } ), vec![pt1.x,pt2.x,pt3.x], - &[], )[0] ); } @@ -137,7 +140,6 @@ pub fn ectangent_gadget<'a, F: PrimeField+FieldUtils, C: CurveExt>( let pts = vec![pt1.x, pt1.y, pt2.x, pt2.y]; circuit.constrain( // Check that slope vector is collinear with vector from pt1 to [-pt2] &pts, - &[], Gatebb::new( 2, 4, @@ -148,7 +150,8 @@ pub fn ectangent_gadget<'a, F: PrimeField+FieldUtils, C: CurveExt>( let c = args[1].scale(2); let d = args[0].square().scale(3); vec![a*d - b*c] - }) + }), + vec![], ) ); nonzeros.push( @@ -163,7 +166,6 @@ pub fn ectangent_gadget<'a, F: PrimeField+FieldUtils, C: CurveExt>( } ), vec![pt1.x,pt2.x], - &[], )[0] ); } @@ -414,15 +416,16 @@ pub fn escalarmul_gadget_9<'a, F: PrimeField + FieldUtils, C: CurveExt>( let (x1,y1,z1) = double_proj::(a); let (x2,y2,z2) = add_proj::(b, (args[0], -args[1])); vec![x2 - x1*q, y2 - y1*q, z2 - z1*q] - }) + }), + vec![], ); for i in 0..num_limbs-1 { let input = vec![pt_acc[i].x, pt_acc[i].y, pt_x3[i].x, pt_x3[i].y, scale3[i]]; - circuit.constrain(&input, &[], triple_check.clone()); + circuit.constrain(&input, triple_check.clone()); nonzeros.push(scale3[i]); let input = vec![pt_x3[i].x, pt_x3[i].y, pt_x9[i].x, pt_x9[i].y, scale9[i]]; - circuit.constrain(&input, &[], triple_check.clone()); + circuit.constrain(&input, triple_check.clone()); nonzeros.push(scale9[i]); eclin_gadget(circuit, diff --git a/src/gadgets/lc.rs b/src/gadgets/lc.rs index 2b0c582..9071f36 100644 --- a/src/gadgets/lc.rs +++ b/src/gadgets/lc.rs @@ -26,8 +26,8 @@ pub fn sum_arr(args: &[F]) -> F { pub fn lc_constr<'a, F: PrimeField+FieldUtils>(circuit: &mut Circuit<'a, F, Gatebb<'a, F>>, coeffs:&'a [F], vars: &[Variable]) -> () { assert_eq!(coeffs.len(), vars.len()); let l = vars.len(); - let gate = Gatebb::new(1, l, 1, Rc::new(|args, _|{vec![inner_prod(coeffs, args)]})); // NO MOVE HERE!! - circuit.constrain(vars, &[], gate); + let gate = Gatebb::new(1, l, 1, Rc::new(|args, _|{vec![inner_prod(coeffs, args)]}), vec![]); // NO MOVE HERE!! + circuit.constrain(vars, gate); } pub fn qc<'a, F: PrimeField+FieldUtils>(circuit: &mut Circuit<'a, F, Gatebb<'a, F>>, a: &[Variable], b: &[Variable], round: usize) -> Variable { @@ -35,18 +35,18 @@ pub fn qc<'a, F: PrimeField+FieldUtils>(circuit: &mut Circuit<'a, F, Gatebb<'a, let l = a.len(); let poly = PolyOp::new(2, 2*l, 1, |args, _| split_and_ip::(args)); let args : Vec<_> = a.iter().chain(b.iter()).map(|x|*x).collect(); - circuit.apply(round, poly, args, &[])[0] + circuit.apply(round, poly, args)[0] } pub fn lc<'a, F: PrimeField+FieldUtils>(circuit: &mut Circuit<'a, F, Gatebb<'a, F>>, coeffs:&'a [F], vars: &[Variable], round: usize) -> Variable { assert_eq!(coeffs.len(), vars.len()); let l = vars.len(); let poly = PolyOp::new(1, l, 1, |args, _|{vec![inner_prod(coeffs, args)]}); // NO MOVE HERE!! - circuit.apply(round, poly, vars.to_vec(), &[])[0] + circuit.apply(round, poly, vars.to_vec())[0] } pub fn sum_gadget<'a, F: PrimeField+FieldUtils>(circuit: &mut Circuit<'a, F, Gatebb<'a, F>>, vars: &[Variable], round: usize) -> Variable { let l = vars.len(); let poly = PolyOp::new(1, l, 1, |arr, _|vec![sum_arr(arr)]); - circuit.apply(round, poly, vars.to_vec(), &[])[0] + circuit.apply(round, poly, vars.to_vec())[0] } \ No newline at end of file diff --git a/src/gadgets/lookup.rs b/src/gadgets/lookup.rs index c4b946d..5cdb18a 100644 --- a/src/gadgets/lookup.rs +++ b/src/gadgets/lookup.rs @@ -5,7 +5,7 @@ // 2. Table right now is implemented as priveleged subset of variables. Considering it is the same for all // step instances, it is not, actually, getting folded. This should be made a primitive. -use std::{iter::{once}, rc::Rc}; +use std::{iter::{once}, rc::Rc, collections::HashMap}; use ff::{PrimeField, BatchInvert}; use itertools::Itertools; @@ -46,7 +46,7 @@ pub fn montgomery(v: &[F]) -> (F, Vec) { /// Parses input as `a, c, vals[0], ... vals[k-1]` and returns F::ZERO if a == \sum 1/(vals[i]-c) or one of denominators is F::ZERO itself /// Assumes denominators are nonzero (which always happens provided c is a random challenge); unsound otherwise. -pub fn sum_of_fractions<'a, F:PrimeField+FieldUtils> (args: &[F], k: usize) -> F { +pub fn sum_of_fractions (args: &[F], k: usize) -> F { let (tmp, vals) = args.split_at(2); assert_eq!(vals.len(), k); let (res, c) = (tmp[0], tmp[1]); @@ -55,7 +55,7 @@ pub fn sum_of_fractions<'a, F:PrimeField+FieldUtils> (args: &[F], k: usize) -> F } /// Parses input as `a, c, vals[0], ... vals[k-1], nums[0], ... nums[k-1]` and returns F::ZERO if a == \sum nums[i]/(vals[i]-c) or one of denominators is F::ZERO itself -pub fn sum_of_fractions_with_nums<'a, F:PrimeField+FieldUtils> (args: &[F], dens: &[F], k: usize) -> F { +pub fn sum_of_fractions_with_nums (args: &[F], dens: &[F], k: usize) -> F { let (tmp1, nums) = args.split_at(2); assert!(nums.len() == k); let (res, c) = (tmp1[0], tmp1[1]); @@ -79,22 +79,22 @@ pub fn invsum_flat_constrain<'a, F: PrimeField+FieldUtils>( assert!(vals.len() > 0); let args = [res, challenge].iter().chain(vals.iter()).map(|x| *x).collect_vec(); let k = vals.len(); - let gate = Gatebb::new(vals.len() + 1, args.len(), 1, Rc::new(move |args, _|vec![sum_of_fractions(args, k)])); - circuit.constrain(&args, &[], gate); + let gate = Gatebb::new(vals.len() + 1, args.len(), 1, Rc::new(move |args, _|vec![sum_of_fractions(args, k)]), vec![]); + circuit.constrain(&args, gate); } -pub fn fracsum_flat_constrain<'a, F: PrimeField+FieldUtils>( - circuit: &mut Circuit<'a, F, Gatebb<'a, F>>, +pub fn fracsum_flat_constrain<'a, 'c, F: PrimeField+FieldUtils>( + circuit: &mut Circuit<'c, F, Gatebb<'c, F>>, nums: &[Variable], - dens: &'a[F], + dens: &'a [F], res: Variable, challenge: Variable, ) -> () { assert!(dens.len()==nums.len()); let args = [res, challenge].iter().chain(nums.iter()).map(|x|*x).collect_vec(); let k = dens.len(); - let gate = Gatebb::new(dens.len()+1, args.len(), 1, Rc::new(move |args, _|vec![sum_of_fractions_with_nums(args, &dens, k)])); - circuit.constrain(&args, &dens, gate); + let gate = Gatebb::new(dens.len()+1, args.len(), 1, Rc::new(move |args, dens|vec![sum_of_fractions_with_nums(args, &dens, k)]), dens.to_vec()); + circuit.constrain(&args, gate); } /// Gadget which returns the sum of inverses of an array, shifted by a challenge. @@ -145,8 +145,8 @@ pub fn invsum_gadget<'a, F: PrimeField+FieldUtils>( /// Assumes that array length is divisible by rate, pad otherwise. /// Unsound if one of the inverses is undefined. /// Rate - amount of values processed in a batch. Deg = rate+1 -pub fn fracsum_gadget<'a, F: PrimeField+FieldUtils>( - circuit: &mut Circuit<'a, F, Gatebb<'a, F>>, +pub fn fracsum_gadget<'a,'c, F: PrimeField+FieldUtils>( + circuit: &mut Circuit<'c, F, Gatebb<'c, F>>, nums: &[Variable], dens: &'a [F], challenge: Variable, @@ -159,12 +159,13 @@ pub fn fracsum_gadget<'a, F: PrimeField+FieldUtils>( assert!(l%rate == 0); let mut nums = nums; let mut dens = dens; + let captured_dens = dens.to_vec(); let mut num_chunk; let mut den_chunk; - let advice = Advice::new(l+1, 0, l/rate, move |args: &[F], _|{ + let advice = Advice::<'c, F>::new(l+1, 0, l/rate, move |args: &[F], _|{ let (nums, c) = args.split_at(l); let c = c[0]; - let mut inv = dens.iter().map(|x|*x-c).collect_vec(); + let mut inv = captured_dens.iter().map(|x|*x-c).collect_vec(); inv.batch_invert(); let mut ret = vec![]; let mut inv : &[F] = &inv; @@ -207,27 +208,27 @@ pub trait Lookup<'a, F: PrimeField+FieldUtils> { ) -> (); } -pub struct StaticLookup<'c, F: PrimeField+FieldUtils> { +pub struct StaticLookup { vars: Vec, round: usize, challenge: ExternalValue, - table: &'c [F], + table: Vec, } -impl<'c, F: PrimeField+FieldUtils> StaticLookup<'c, F> { - pub fn new(challenge_src: ExternalValue, table: &'c [F]) -> Self { +impl StaticLookup { + pub fn new<'c>(challenge_src: ExternalValue, table: &'c [F]) -> Self { Self{ vars: vec![], round: 0, challenge: challenge_src, - table, + table: table.to_vec(), } } } -impl<'a, 'c: 'a, F: PrimeField+FieldUtils> Lookup<'a, F> for StaticLookup<'c, F> { - fn check(&mut self, _circuit: &mut Circuit<'a, F, Gatebb<'a,F>>, var: Variable) -> () { +impl<'c, F: PrimeField+FieldUtils> Lookup<'c, F> for StaticLookup { + fn check(&mut self, _circuit: &mut Circuit<'c, F, Gatebb<'c,F>>, var: Variable) -> () { if self.round < var.round { self.round = var.round } @@ -235,7 +236,7 @@ impl<'a, 'c: 'a, F: PrimeField+FieldUtils> Lookup<'a, F> for StaticLookup<'c, F> } fn finalize( self, - circuit: &mut Circuit<'a, F, Gatebb<'a,F>>, + circuit: &mut Circuit<'c, F, Gatebb<'c,F>>, table_round: usize, access_round: usize, challenge_round: usize, @@ -246,19 +247,18 @@ impl<'a, 'c: 'a, F: PrimeField+FieldUtils> Lookup<'a, F> for StaticLookup<'c, F> assert!(table_round <= access_round); assert!(access_round >= round); assert!(challenge_round > access_round); - + let mut table_hash = HashMap::new(); + table.iter().enumerate().map(|(i, var)| table_hash.insert(BigUint::from_bytes_le(var.to_repr().as_ref()), i)).last(); // Access counts. let compute_accesses = Advice::new(vars.len(), 0, table.len(), move |vars: &[F], _|{ - let mut ret = vec![0; table.len()]; + let mut ret = vec![0; table_hash.len()]; for var in vars{ let var = BigUint::from_bytes_le(var.to_repr().as_ref()); - assert!(var < table.len().into(), "Error: lookup value out of range."); - let u64_digits = var.to_u64_digits(); - let mut i = 0 as usize; - if u64_digits.len() > 0 { - i = u64_digits[0] as usize; - } - ret[i]+=1; + let idx = match table_hash.get(&var) { + None => panic!("Error: lookup value {} out of range.", var), + Some(x) => *x, + }; + ret[idx] += 1; } ret.into_iter().map(|x|F::from(x)).collect() }); @@ -267,7 +267,7 @@ impl<'a, 'c: 'a, F: PrimeField+FieldUtils> Lookup<'a, F> for StaticLookup<'c, F> let challenge = input(circuit, challenge, challenge_round); let lhs = invsum_gadget(circuit, &vars, challenge, rate, challenge_round); - let rhs = fracsum_gadget(circuit, &access_counts, table, challenge, rate, challenge_round); + let rhs = fracsum_gadget(circuit, &access_counts, &table, challenge, rate, challenge_round); eq_gadget(circuit, lhs, rhs); } @@ -590,7 +590,7 @@ mod test { let indexes = 0..TEST_LEN; let range = 16; - let table = (0..range).map(|x| F::from(x as u64)).collect_vec(); + let table = (0..range).map(|_| F::random(OsRng)).collect_vec(); let mut circuit = Circuit::new(range + 1, TEST_LEN + 1); let challenge_value = circuit.ext_val(1)[0]; @@ -602,7 +602,7 @@ mod test { range_lookup.finalize(&mut circuit, 0, TEST_LEN - 1, TEST_LEN, 2); let mut circuit = circuit.finalize(); - test_values.into_iter().map(|val| circuit.set_ext(val, F::from(OsRng.next_u64() % range as u64))).last(); + test_values.into_iter().map(|val| circuit.set_ext(val, table[(OsRng.next_u64() % range as u64) as usize])).last(); for i in indexes { circuit.execute(i); } @@ -660,9 +660,9 @@ mod test { let range = 16; let rounds = 3; - let table = (0..range).map(|x| F::from(x as u64)).collect_vec(); let mut circuit = Circuit::new(range + 1, rounds); - + + let table = (0..range).map(|x| F::from(x as u64)).collect_vec(); let challenge_value: ExternalValue = circuit.ext_val(1)[0]; let test_value = circuit.ext_val(1)[0]; diff --git a/src/gadgets/nonzero_check.rs b/src/gadgets/nonzero_check.rs index be8a0e6..29d7a32 100644 --- a/src/gadgets/nonzero_check.rs +++ b/src/gadgets/nonzero_check.rs @@ -23,7 +23,6 @@ pub fn nonzero_gadget<'a, F: PrimeField + FieldUtils> (circuit: &mut Circuit<'a, circuit.constrain_with( &vec![prod, prod_inv], - &[], &nonzero_check(), ); } diff --git a/src/gadgets/poseidon.rs b/src/gadgets/poseidon.rs index 077cfdc..6cb06df 100644 --- a/src/gadgets/poseidon.rs +++ b/src/gadgets/poseidon.rs @@ -87,7 +87,8 @@ pub fn poseidon_partial_rounds_gate<'c>(n_rounds_p: usize, n_rounds_f: usize, t: let (adv_in, adv_out) = tmp.split_at(n_rounds_p); let (inp, out) = io.split_at(t); poseidon_partial_rounds_constraint(inp, out, adv_in, adv_out, &c, &m, n_rounds_f, n_rounds_p, t) - }) + }), + vec![] ) } @@ -144,7 +145,6 @@ pub fn poseidon_partial_rounds_gadget<'a>(circuit: &mut Circuit<'a, F, Gatebb<'a circuit.constrain_with( &to_constrain, - &[], &poseidon_partial_rounds_gate(n_rounds_p, n_rounds_f, t) ); @@ -181,7 +181,6 @@ pub fn poseidon_full_rounds_gadget<'a>(circuit: &mut Circuit<'a, F, Gatebb<'a, F } ), state, - &[], ); i+=k; } @@ -198,7 +197,6 @@ pub fn poseidon_full_rounds_gadget<'a>(circuit: &mut Circuit<'a, F, Gatebb<'a, F } ), state, - &[], ); i+=k } @@ -215,7 +213,6 @@ pub fn poseidon_full_rounds_gadget<'a>(circuit: &mut Circuit<'a, F, Gatebb<'a, F } ), state, - &[], ) } @@ -304,7 +301,6 @@ pub fn poseidon_mixed_strategy_full_rounds_gadget<'a>(circuit: &mut Circuit<'a, } ), state, - &[], ) } else { circuit.apply(round, @@ -317,7 +313,6 @@ pub fn poseidon_mixed_strategy_full_rounds_gadget<'a>(circuit: &mut Circuit<'a, } ), state, - &[], ) }; @@ -330,7 +325,6 @@ pub fn poseidon_mixed_strategy_full_rounds_gadget<'a>(circuit: &mut Circuit<'a, move |state, _| poseidon_mixed_strategy_mid(state, i + 1, cfg) ), state, - &[] ); circuit.apply( @@ -342,7 +336,6 @@ pub fn poseidon_mixed_strategy_full_rounds_gadget<'a>(circuit: &mut Circuit<'a, move |state, _| poseidon_mixed_strategy_end(state, i + 3, cfg) ), state, - &[] ) } diff --git a/src/gadgets/range.rs b/src/gadgets/range.rs index 6dc45a4..cb7d260 100644 --- a/src/gadgets/range.rs +++ b/src/gadgets/range.rs @@ -24,10 +24,11 @@ impl VarSmall { var: Variable, base: u32) -> Self { - circuit.constrain(&[var], &[], Gatebb::new(base as usize, 1, 1, + circuit.constrain(&[var], Gatebb::new(base as usize, 1, 1, Rc::new(move |args, _|{ vec![rangecheck(args[0], base as u64)] - }) + }), + vec![], )); Self::new_unchecked(var, base) @@ -206,7 +207,7 @@ pub fn limb_decompose_gadget<'a, F: PrimeField+FieldUtils>( limbs.push(input); - circuit.constrain(&limbs, &[], Gatebb::new(1, num_limbs+1, 1, + circuit.constrain(&limbs, Gatebb::new(1, num_limbs+1, 1, Rc::new(move |args, _| { let mut acc = F::ZERO; for i in 0..num_limbs { @@ -214,7 +215,8 @@ pub fn limb_decompose_gadget<'a, F: PrimeField+FieldUtils>( acc += args[num_limbs-i-1]; } vec![acc - args[num_limbs]] - }) + }), + vec![], ) ); @@ -258,5 +260,5 @@ pub fn choice_gadget<'a, F: PrimeField+FieldUtils> ( } ); - circuit.apply(round, choice_poly, v, &[]) + circuit.apply(round, choice_poly, v) } \ No newline at end of file diff --git a/src/gadgets/running_prod.rs b/src/gadgets/running_prod.rs index cecb16b..f3aedd4 100644 --- a/src/gadgets/running_prod.rs +++ b/src/gadgets/running_prod.rs @@ -11,7 +11,7 @@ pub fn prod_flat_gadget<'a, F: PrimeField + FieldUtils> (circuit: &mut Circuit<' 1 => *input.first().expect("should not be empty"), n => { let prod = PolyOp::new(n, n, 1, |args, _| vec![args.iter().product()]); - circuit.apply(round, prod, input, &[])[0] + circuit.apply(round, prod, input)[0] } } } diff --git a/src/gate.rs b/src/gate.rs index 0216a17..2efde7b 100644 --- a/src/gate.rs +++ b/src/gate.rs @@ -15,6 +15,7 @@ pub struct Gatebb<'a, F : PrimeField> { i : usize, o : usize, f : Rc Vec + 'a>, + consts: Vec, } impl<'a, F: PrimeField> Debug for Gatebb<'a, F> { @@ -24,12 +25,12 @@ impl<'a, F: PrimeField> Debug for Gatebb<'a, F> { } impl<'a, F: PrimeField> Gatebb<'a, F> { - pub fn new(d: usize, i: usize, o: usize, f: Rc Vec + 'a>) -> Self { - check_poly(d, i, o, f.clone()).unwrap(); - Gatebb::<'a>{d,i,o,f} + pub fn new(d: usize, i: usize, o: usize, f: Rc Vec + 'a>, consts: Vec) -> Self { + check_poly(d, i, o, f.clone(), &consts).unwrap(); + Gatebb::<'a>{d, i, o, f, consts} } - pub fn new_unchecked(d: usize, i: usize, o: usize, f: Rc Vec + 'a>) -> Self { - Gatebb::<'a>{d,i,o,f} + pub fn new_unchecked(d: usize, i: usize, o: usize, f: Rc Vec + 'a>, consts: Vec) -> Self { + Gatebb::<'a>{d, i, o, f, consts} } } @@ -41,7 +42,7 @@ pub trait Gate<'a, F : PrimeField> : Clone + Debug { /// Returns output size. fn o(&self) -> usize; /// Executes gate on a given input. - fn exec(& self, input : &[F], constants: &[F]) -> Vec; + fn exec(& self, input : &[F]) -> Vec; } impl<'a, F : PrimeField + FieldUtils> Gate<'a, F> for Gatebb<'a, F> { @@ -58,8 +59,8 @@ impl<'a, F : PrimeField + FieldUtils> Gate<'a, F> for Gatebb<'a, F> { self.o } /// Executes gate on a given input. - fn exec(&self, input : &[F], constants: &[F]) -> Vec{ - (self.f)(input, constants) + fn exec(&self, input : &[F]) -> Vec{ + (self.f)(input, &self.consts) } diff --git a/src/gatelib.rs b/src/gatelib.rs index 7a4a703..8e8c4c4 100644 --- a/src/gatelib.rs +++ b/src/gatelib.rs @@ -7,5 +7,5 @@ use gate_macro::make_gate; #[make_gate] fn nonzero_check<'c, F: PrimeField + FieldUtils>() -> Gatebb<'c, F> { - Gatebb::new(2, 2, 1, Rc::new(|args, _|vec![args[0]*args[1] - F::ONE])) + Gatebb::new(2, 2, 1, Rc::new(|args, _|vec![args[0]*args[1] - F::ONE]), vec![]) } \ No newline at end of file diff --git a/src/test.rs b/src/test.rs index 69bb41f..b1e22cb 100644 --- a/src/test.rs +++ b/src/test.rs @@ -61,8 +61,8 @@ mod tests { let sq = PolyOp::new(2, 1, 1, |x, _| vec!(x[0]*x[0])); let input = input(&mut circuit, public_input_source, 0); - let sq1 = circuit.apply(0, sq.clone(), vec![input], &[]); - let _ = circuit.apply_pub(0, sq.clone(), sq1, &[]); + let sq1 = circuit.apply(0, sq.clone(), vec![input]); + let _ = circuit.apply_pub(0, sq.clone(), sq1); let mut instance = circuit.finalize(); @@ -106,16 +106,20 @@ mod tests { ); } - let div_constr = Gatebb::::new(2, 4, 1, Rc::new(|args, _|{ - let one = args[0]; - let ch = args[1]; - let x = args[2]; - let res = args[3]; - vec![one*one - res * (x-ch)] - })); + let div_constr = Gatebb::::new( + 2, 4, 1, + Rc::new(|args, _|{ + let one = args[0]; + let ch = args[1]; + let x = args[2]; + let res = args[3]; + vec![one*one - res * (x-ch)] + }), + vec![], + ); for k in 0..5 { - circuit.constrain(&[one, challenge, pi[k], fractions[k]], &[], div_constr.clone()); + circuit.constrain(&[one, challenge, pi[k], fractions[k]], div_constr.clone()); } let mut circuit = circuit.finalize(); @@ -220,7 +224,7 @@ mod tests { fn test_check_poly() { let f = Rc::new(|x: &[F], _: &[F]|{vec![x[0].pow([5])]}); - check_poly(5, 1, 1, f).unwrap(); + check_poly(5, 1, 1, f, &[]).unwrap(); } @@ -301,7 +305,7 @@ mod tests { fn test_lagrange_choice() -> () { for n in 2..12 { for t in 0..n { - assert!(find_degree(32, 1, 1, Rc::new(move |v: &[F], _| vec![lagrange_choice(v[0],t,n)])).unwrap() == (n-1) as usize); + assert!(find_degree(32, 1, 1, Rc::new(move |v: &[F], _| vec![lagrange_choice(v[0],t,n)]), &[]).unwrap() == (n-1) as usize); for x in 0..n { if x == t { assert!(lagrange_choice(F::from(x), t, n) == F::ONE); @@ -318,7 +322,7 @@ mod tests { fn test_lagrange_batch() -> () { for n in 2..12 { - assert!(find_degree(32, 1, n, Rc::new(move |v: &[F], _| lagrange_choice_batched(v[0], n as u64))).unwrap() == (n-1)); + assert!(find_degree(32, 1, n, Rc::new(move |v: &[F], _| lagrange_choice_batched(v[0], n as u64)), &[]).unwrap() == (n-1)); for x in 0..n { let v = lagrange_choice_batched(F::from(x as u64), n as u64); for t in 0..n { diff --git a/src/utils/poly_utils.rs b/src/utils/poly_utils.rs index fbcb7e2..1c4fd0c 100644 --- a/src/utils/poly_utils.rs +++ b/src/utils/poly_utils.rs @@ -16,7 +16,7 @@ pub fn bits_le(n: usize) -> Vec { bits } -pub fn check_poly<'a, F: PrimeField>(d: usize, i: usize, o:usize, f: Rc Vec + 'a>) -> Result<(), &str>{ +pub fn check_poly<'c, F: PrimeField>(d: usize, i: usize, o:usize, f: Rc Vec + 'c>, consts: &[F]) -> Result<(), &'static str>{ let mut a = vec![]; for _ in 0..i {a.push(F::random(OsRng))} let mut b = vec![]; for _ in 0..i {b.push(F::random(OsRng))} @@ -26,7 +26,7 @@ pub fn check_poly<'a, F: PrimeField>(d: usize, i: usize, o:usize, f: Rc = a.iter().zip(b.iter()).map(|(a,b)|*a+F::from(j as u64)*b).collect(); - lcs.push((*f)(&tmp, &[])); + lcs.push((*f)(&tmp, consts)); } assert!(lcs[0].len() == o); @@ -58,11 +58,11 @@ pub fn check_poly<'a, F: PrimeField>(d: usize, i: usize, o:usize, f: Rc(max_degree: usize, i: usize, o:usize, f: Rc Vec + 'a>) -> Result{ +pub fn find_degree<'a, F: PrimeField>(max_degree: usize, i: usize, o:usize, f: Rc Vec + 'a>, consts: &[F]) -> Result{ let mut top = 1; loop { if top > max_degree {return Err("The degree of provided function is too large.")} - match check_poly(top, i, o, f.clone()) { + match check_poly(top, i, o, f.clone(), consts) { Err(_) => top*=2, Ok(()) => break, } @@ -71,7 +71,7 @@ pub fn find_degree<'a, F: PrimeField>(max_degree: usize, i: usize, o:usize, f: R if bot == 0 {return Ok(1)} while top-bot > 1 { let mid = (top+bot)/2; - match check_poly(mid, i, o, f.clone()) { + match check_poly(mid, i, o, f.clone(), consts) { Err(_) => bot = mid, Ok(()) => top = mid, }