diff --git a/benches/bench_ecmul.rs b/benches/bench_ecmul.rs index 96dd71c..b7248a1 100644 --- a/benches/bench_ecmul.rs +++ b/benches/bench_ecmul.rs @@ -83,7 +83,8 @@ pub fn ecmul_pseudo_fold(c: &mut Criterion) { assemble_ecmul_circuit(&mut circuit, &pi, num_limbs); - let mut instance = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); let pi_a_ext = (pi[0], pi[1]); let pi_b_ext = (pi[2], pi[3]); // a*(1+9+...+9^{nl-1})+b=0 must be checked out of band @@ -141,7 +142,8 @@ pub fn ecmul_msm(c: &mut Criterion) { assemble_ecmul_circuit(&mut circuit, &pi, num_limbs); - let mut instance = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); let pi_a_ext = (pi[0], pi[1]); let pi_b_ext = (pi[2], pi[3]); // a*(1+9+...+9^{nl-1})+b=0 must be checked out of band diff --git a/benches/bench_poseidons.rs b/benches/bench_poseidons.rs index 922dc4c..6c7210e 100644 --- a/benches/bench_poseidons.rs +++ b/benches/bench_poseidons.rs @@ -64,7 +64,8 @@ pub fn poseidons_pseudo_fold(c: &mut Criterion) { assemble_poseidon_circuit(&mut circuit, &cfg, pi); - let mut instance = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); instance.set_ext(pi, F::random(OsRng)); instance.execute(0); @@ -99,7 +100,8 @@ pub fn poseidons_msm(c: &mut Criterion) { let pi = circuit.ext_val(1)[0]; assemble_poseidon_circuit(&mut circuit, &cfg, pi); - let mut instance = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); instance.set_ext(pi, F::random(OsRng)); instance.execute(0); diff --git a/src/circuit.rs b/src/circuit.rs index b6751b5..8e78556 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -1,8 +1,8 @@ -use std::{rc::Rc, marker::PhantomData, iter::repeat_with}; +use std::{rc::{Rc, Weak}, marker::PhantomData, iter::repeat_with, cell::RefCell}; use elsa::map::FrozenMap; use ff::PrimeField; -use crate::{witness::CSWtns, gate::{Gatebb, Gate}, constraint_system::{Variable, ConstraintSystem, CommitKind, Visibility, CS, Constraint}, utils::poly_utils::check_poly, circuit::circuit_operations::{AttachedAdvice, AttachedPolynomialAdvice, AttachedAdvicePub}}; +use crate::{witness::CSWtns, gate::{Gatebb, Gate}, constraint_system::{Variable, ConstraintSystem, CommitKind, Visibility, CS, Constraint}, utils::poly_utils::check_poly, circuit::circuit_operations::{AttachedAdvice, AttachedPolynomialAdvice, AttachedAdvicePub}, external_interface::{RunIndex, RunAllocator} }; use self::circuit_operations::CircuitOperation; @@ -74,11 +74,11 @@ impl InternalValue { pub ivar: usize, pub iext: usize, pub o: usize, - pub f: Rc Vec + 'closure>, + pub f: Rc Vec + 'closure>, } impl<'closure, F: PrimeField> Advice<'closure, F> { - pub fn new(ivar: usize, iext: usize, o: usize, f: impl Fn(&[F], &[F]) -> Vec + 'closure) -> Self { + pub fn new(ivar: usize, iext: usize, o: usize, f: impl Fn(&[F], &RunIndex) -> Vec + 'closure) -> Self { let f = Rc::new(f); Self { ivar, iext, o, f } @@ -104,10 +104,10 @@ pub mod circuit_operations { use std::rc::Rc; use ff::PrimeField; use crate::{constraint_system::Variable, gate::Gate, witness::CSWtns}; - use super::{ExternalValue, InternalValue}; + use super::{ExternalValue, RunIndex}; pub trait CircuitOperation<'a, F: PrimeField, G: Gate<'a, F>> { - fn execute(&self, witness: &mut CSWtns<'a, F, G>); + fn execute(&self, witness: &mut CSWtns<'a, F, G>, idx: &RunIndex); } pub struct AttachedAdvicePub<'advice, F: PrimeField> { @@ -123,7 +123,7 @@ pub mod circuit_operations { } impl<'advice, F: PrimeField, G: Gate<'advice, F>> CircuitOperation<'advice, F, G> for AttachedAdvicePub<'advice, F> { - fn execute(&self, witness: &mut CSWtns<'advice, F, G>) { + fn execute(&self, witness: &mut CSWtns<'advice, F, G>, idx: &RunIndex) { let aux: Vec<_> = self.aux.iter().map(|ev| witness.getext(*ev)).collect(); let output = (self.closure)(&aux); @@ -136,23 +136,21 @@ pub mod circuit_operations { pub struct AttachedAdvice<'advice, F: PrimeField> { input: Vec, - aux: Vec<&'advice InternalValue>, output: Vec, - closure: Rc Vec + 'advice>, + closure: Rc Vec + 'advice>, } impl<'advice, F: PrimeField> AttachedAdvice<'advice, F> { - pub fn new(input: Vec, aux: Vec<&'advice InternalValue>, output: Vec, closure: Rc Vec + 'advice>) -> Self { - Self { input, aux, output, closure } + pub fn new(input: Vec, output: Vec, closure: Rc Vec + 'advice>) -> Self { + Self { input, output, closure } } } impl<'advice, F: PrimeField, G: Gate<'advice, F>> CircuitOperation<'advice, F, G> for AttachedAdvice<'advice, F> { - fn execute(&self, witness: &mut CSWtns<'advice, F, G>) { + fn execute(&self, witness: &mut CSWtns<'advice, F, G>, idx: &RunIndex) { let input = witness.get_vars(&self.input); - let aux: Vec<_> = self.aux.iter().map(|ev| ev.get().expect("external values should be set before execution")).collect(); - let output = (self.closure)(&input, &aux); + let output = (self.closure)(&input, &idx); let value_set: Vec<_> = self.output.iter().cloned().zip(output).collect(); witness.set_vars(&value_set); @@ -172,7 +170,7 @@ pub mod circuit_operations { } impl<'closure, F: PrimeField, G: Gate<'closure, F>> CircuitOperation<'closure, F, G> for AttachedPolynomialAdvice<'closure, F> { - fn execute(&self, witness: &mut CSWtns<'closure, F, G>) { + fn execute(&self, witness: &mut CSWtns<'closure, F, G>, _: &RunIndex) { let input = witness.get_vars(&self.input); let output = (self.closure)(&input, &[]); @@ -216,7 +214,7 @@ where prep } - pub fn advice(&mut self, round: usize, advice: Advice<'circuit, F>, input: Vec, aux: Vec<&'circuit InternalValue>) -> Vec { + pub fn advice(&mut self, round: usize, advice: Advice<'circuit, F>, input: Vec) -> Vec { assert!(round < self.ops.len(), "The round is too large."); let op_index = self.ops[round].len(); @@ -226,10 +224,9 @@ where } assert!(input.len() == advice.ivar, "Incorrect amount of input vars at operation #{} (round {})", op_index, round); - assert!(aux.len() == advice.iext, "Incorrect amount of internal vals at operation #{} (round {})", op_index, round); let output = self.cs.alloc_in_round(round, Visibility::Private, advice.o); - let operation = Box::new(AttachedAdvice::new(input, aux, output.clone(), advice.f.clone())); + let operation = Box::new(AttachedAdvice::new(input, output.clone(), advice.f.clone())); self.ops[round].push(operation); output @@ -310,15 +307,10 @@ where self.advice_pub(round, adv, vec![pi])[0] } - pub fn finalize(self) -> SealedCircuit<'circuit, F, G> { - let cs = CSWtns::::new(&self.cs); - - let circuit = Rc::new(self); - - SealedCircuit { - cs, - circuit, - round_counter: 0, + pub fn finalize(self) -> ConstructedCircuit<'circuit, F, G> { + ConstructedCircuit { + circuit: self, + run_allocator: RefCell::new(RunAllocator::new()), } } @@ -331,13 +323,34 @@ where } } -pub struct SealedCircuit<'circuit, F: PrimeField, G: Gate<'circuit, F> + From>>{ - circuit: Rc >, +pub struct ConstructedCircuit<'circuit, F: PrimeField, G: Gate<'circuit, F> + From>> { + circuit: Circuit<'circuit, F, G>, + run_allocator: RefCell, +} + +impl<'circuit, F: PrimeField, G: Gate<'circuit, F> + From>> ConstructedCircuit<'circuit, F, G> { + pub fn spawn<'constructed>(&'constructed self) -> CircuitRun<'constructed, 'circuit, F, G> { + CircuitRun { + constructed: &self, + cs: CSWtns::::new(&self.circuit.cs), + round_counter: 0, + run_idx: self.run_allocator.borrow_mut().allocate(), + } + } + + fn deallocate<'constructed>(&'constructed self, idx: RunIndex) { + self.run_allocator.borrow_mut().deallocate(idx); + } +} + +pub struct CircuitRun<'constructed, 'circuit, F: PrimeField, G: Gate<'circuit, F> + From>>{ + constructed: &'constructed ConstructedCircuit<'circuit, F, G>, pub cs : CSWtns<'circuit, F, G>, round_counter : usize, + run_idx: RunIndex, } -impl<'circuit, F, G> SealedCircuit<'circuit, F, G> +impl<'constructed, 'circuit, F, G> CircuitRun<'constructed, 'circuit, F, G> where F: PrimeField, G: Gate<'circuit, F> + From>, @@ -347,8 +360,8 @@ where assert!(self.round_counter <= round, "Execution is already at round {}, tried to execute up to round {}", self.round_counter, round); while self.round_counter <= round { - for op in &self.circuit.ops[self.round_counter] { - op.execute(&mut self.cs); + for op in &self.constructed.circuit.ops[self.round_counter] { + op.execute(&mut self.cs, &self.run_idx); } self.round_counter += 1; } @@ -360,7 +373,7 @@ where pub fn valid_witness(&self) -> () { - for constr in self.circuit.cs.iter_constraints() { + for constr in self.constructed.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); @@ -369,6 +382,14 @@ where } pub fn iter_constraints(&self) -> impl Iterator> { - self.circuit.cs.iter_constraints() + self.constructed.circuit.cs.iter_constraints() } -} \ No newline at end of file + + pub fn finish(self) -> (CSWtns<'circuit, F, G>, &'constructed ConstraintSystem<'circuit, F, G>) { + let Self {constructed, cs, round_counter: _, run_idx} = self; + + constructed.deallocate(run_idx); + (cs, &constructed.circuit.cs) + } +} + diff --git a/src/external_interface.rs b/src/external_interface.rs new file mode 100644 index 0000000..0943865 --- /dev/null +++ b/src/external_interface.rs @@ -0,0 +1,105 @@ +use std::{cell::RefCell, rc::Rc}; + +pub struct RunAllocator { + free_slots: Vec, + total_spawned: usize, + active: usize, + allocated: usize, +} + +impl RunAllocator { + pub fn new() -> Self { + Self { free_slots: vec![], total_spawned: 0, active: 0, allocated: 0 } + } + + pub fn allocate(&mut self) -> RunIndex { + let slot = self.free_slots.pop().unwrap_or_else(|| { + self.allocated += 1; + self.allocated - 1 + }); + self.active += 1; + self.total_spawned += 1; + RunIndex { muid: self.total_spawned - 1, slot } + } + + pub fn deallocate(&mut self, idx: RunIndex) { + self.free_slots.push(idx.slot); + self.active -= 1; + } +} + +#[derive(Debug)] +pub struct RunIndex { + pub(crate) muid: usize, + pub(crate) slot: usize, +} + +struct CuratedSlot { + value: T, + muid: usize, +} + +#[derive(Clone)] +pub struct InnerValue { + data: Rc>>>> +} + +impl InnerValue { + pub fn new() -> Self { + Self { + data: Rc::new(RefCell::new(vec![])), + } + } + + pub fn get(&self, idx: &RunIndex) -> Option { + match self.data.borrow().get(idx.slot) { + Some(opt) => match opt { + Some(CuratedSlot{value, muid}) => match muid == &idx.muid { + true => Some(value.clone()), + false => match muid < &idx.muid { + true => None, + false => panic!("Accessing value with muid {} by idx: {:?}", muid, idx), + }, + }, + None => None, + }, + None => None, + } + + } + + pub fn set(&self, idx: &RunIndex, value: T) { + assert!(self.replace(idx, value).is_none(), "Attempting to set value by idx: {:?}, but is already set", idx) + } + + #[must_use = "if you intended to set a value, consider `set` method instead"] + pub fn replace(&self, idx: &RunIndex, value: T) -> Option { + let mut data = self.data.borrow_mut(); + if data.len() <= idx.slot { + data.resize_with(idx.slot + 1, || None); + } + match data[idx.slot] { + Some(CuratedSlot{muid, value: _}) => assert!(muid <= idx.muid, "Writing value with muid {} by idx: {:?}", muid, idx), + None => (), + } + data[idx.slot].replace(CuratedSlot { value: value.clone(), muid: idx.muid }).and_then(|CuratedSlot{value, muid}| if muid == idx.muid {Some(value)} else {None}) + } +} + + +#[test] +fn normal_usage() { + let x = InnerValue::new(); + + x.set(&RunIndex { muid: 0, slot: 0 }, 0); + x.set(&RunIndex { muid: 1, slot: 1 }, 1); + x.set(&RunIndex { muid: 2, slot: 2 }, 2); + assert_eq!(x.get(&RunIndex { muid: 0, slot: 0 }), Some(0)); + assert_eq!(x.get(&RunIndex { muid: 1, slot: 1 }), Some(1)); + assert_eq!(x.get(&RunIndex { muid: 2, slot: 2 }), Some(2)); + assert_eq!(x.get(&RunIndex { muid: 3, slot: 0 }), None); + x.set(&RunIndex { muid: 3, slot: 0 }, 3); + assert_eq!(x.get(&RunIndex { muid: 3, slot: 0 }), Some(3)); + assert_eq!(x.replace(&RunIndex { muid: 1, slot: 1 }, 5), Some(1)) +} + diff --git a/src/gadgets/bits.rs b/src/gadgets/bits.rs index f5beebe..8625898 100644 --- a/src/gadgets/bits.rs +++ b/src/gadgets/bits.rs @@ -43,7 +43,6 @@ pub fn bit_decomposition_gadget<'a, F: PrimeField+FieldUtils>(circuit: &mut Circ } ), vec![input], - vec![] ); let bitcheck_gate = Gatebb::new(2, 1, 1, Rc::new(|args, _| bitcheck::(args)), vec![]); diff --git a/src/gadgets/ecmul.rs b/src/gadgets/ecmul.rs index 0fd059c..0b7c8cf 100644 --- a/src/gadgets/ecmul.rs +++ b/src/gadgets/ecmul.rs @@ -193,7 +193,6 @@ pub fn ecadd_gadget<'a, F: PrimeField+FieldUtils, C: CurveExt>( } ), vec![pt1.x, pt1.y, pt2.x, pt2.y], - vec![] ); let pt3 = EcAffinePoint::::new(circuit, tmp[0], tmp[1]); @@ -223,7 +222,6 @@ pub fn ecdouble_gadget<'a, F: PrimeField+FieldUtils, C: CurveExt>( } ), vec![pt.x, pt.y], - vec![] ); let pt2 = EcAffinePoint::::new(circuit, tmp[0], tmp[1]); @@ -384,7 +382,6 @@ pub fn escalarmul_gadget_9<'a, F: PrimeField + FieldUtils, C: CurveExt>( round, adv, pts_limbs.clone(), - vec![] ); let (acc, rest) = advices.split_at(2*(num_limbs-1)); diff --git a/src/gadgets/lookup.rs b/src/gadgets/lookup.rs index 5cdb18a..7509786 100644 --- a/src/gadgets/lookup.rs +++ b/src/gadgets/lookup.rs @@ -131,7 +131,7 @@ pub fn invsum_gadget<'a, F: PrimeField+FieldUtils>( let mut args = vals.to_vec(); args.push(challenge); - let batches = circuit.advice(round, advice, args, vec![]); + let batches = circuit.advice(round, advice, args); for i in 0..l/rate { (chunk, vals) = vals.split_at(rate); invsum_flat_constrain(circuit, chunk, batches[i], challenge); @@ -182,7 +182,7 @@ pub fn fracsum_gadget<'a,'c, F: PrimeField+FieldUtils>( let args = nums.iter().map(|x|*x).chain(once(challenge)).collect(); - let batches = circuit.advice(round, advice, args, vec![]); + let batches = circuit.advice(round, advice, args); for i in 0..l/rate { (num_chunk, nums) = nums.split_at(rate); (den_chunk, dens) = dens.split_at(rate); @@ -262,7 +262,7 @@ impl<'c, F: PrimeField+FieldUtils> Lookup<'c, F> for StaticLookup { } ret.into_iter().map(|x|F::from(x)).collect() }); - let access_counts = circuit.advice(access_round, compute_accesses, vars.clone(), vec![]); + let access_counts = circuit.advice(access_round, compute_accesses, vars.clone()); // Allocate challenge. let challenge = input(circuit, challenge, challenge_round); @@ -469,7 +469,9 @@ mod test { let reslut_variable = input(&mut circuit, result_value, 0); invsum_flat_constrain(&mut circuit, &points_variables, reslut_variable, challenge_variable); - let mut instance = circuit.finalize(); + + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); instance.set_ext(challenge_value, challenge); points_values.into_iter().zip_eq(points).map(|(val, point)| instance.set_ext(val, point)).last(); @@ -505,7 +507,9 @@ mod test { let reslut_variable = input(&mut circuit, result_value, 0); fracsum_flat_constrain(&mut circuit, &numerator_variables, &points, reslut_variable, challenge_variable); - let mut instance = circuit.finalize(); + + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); instance.set_ext(challenge_value, challenge); numerators_values.into_iter().zip_eq(numerators).map(|(val, point)| instance.set_ext(val, point)).last(); @@ -535,15 +539,17 @@ mod test { let points_variables = points_values.clone().into_iter().map(|val| input(&mut circuit, val, 0)).collect_vec(); let result_variable = invsum_gadget(&mut circuit, &points_variables, challenge_variable, rate, 0); - let mut circuit = circuit.finalize(); + + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); - circuit.set_ext(challenge_value, challenge); - points_values.into_iter().zip_eq(points).map(|(val, point)| circuit.set_ext(val, point)).last(); + instance.set_ext(challenge_value, challenge); + points_values.into_iter().zip_eq(points).map(|(val, point)| instance.set_ext(val, point)).last(); - circuit.execute(0); - circuit.valid_witness(); + instance.execute(0); + instance.valid_witness(); - assert_eq!(result, circuit.cs.getvar(result_variable)); + assert_eq!(result, instance.cs.getvar(result_variable)); } } @@ -568,14 +574,16 @@ mod test { let numerator_variables = numerators_values.clone().into_iter().map(|val| input(&mut circuit, val, 0)).collect_vec(); let result_variable = fracsum_gadget(&mut circuit, &numerator_variables, &points, challenge_variable, 3, 0); - let mut circuit = circuit.finalize(); + + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); - circuit.set_ext(challenge_value, challenge); - numerators_values.into_iter().zip_eq(numerators).map(|(val, point)| circuit.set_ext(val, point)).last(); + instance.set_ext(challenge_value, challenge); + numerators_values.into_iter().zip_eq(numerators).map(|(val, point)| instance.set_ext(val, point)).last(); - circuit.execute(0); - circuit.valid_witness(); - assert_eq!(result, circuit.cs.getvar(result_variable)); + instance.execute(0); + instance.valid_witness(); + assert_eq!(result, instance.cs.getvar(result_variable)); } } @@ -600,16 +608,18 @@ mod test { let test_variables = test_values.clone().into_iter().enumerate().map(|(i, v)| input(&mut circuit, v, i)).collect_vec(); test_variables.into_iter().map(|variable| range_lookup.check(&mut circuit, variable)).last(); 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, table[(OsRng.next_u64() % range as u64) as usize])).last(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); + + test_values.into_iter().map(|val| instance.set_ext(val, table[(OsRng.next_u64() % range as u64) as usize])).last(); for i in indexes { - circuit.execute(i); + instance.execute(i); } let challenge = F::random(OsRng); - circuit.set_ext(challenge_value, challenge); - circuit.execute(TEST_LEN); - circuit.valid_witness(); + instance.set_ext(challenge_value, challenge); + instance.execute(TEST_LEN); + instance.valid_witness(); } mod invalid { diff --git a/src/gadgets/nonzero_check.rs b/src/gadgets/nonzero_check.rs index 29d7a32..c483d97 100644 --- a/src/gadgets/nonzero_check.rs +++ b/src/gadgets/nonzero_check.rs @@ -19,7 +19,7 @@ pub fn nonzero_gadget<'a, F: PrimeField + FieldUtils> (circuit: &mut Circuit<'a, let prod = prod_run_gadget(circuit, input.to_vec(), round, rate); let adv_invert = Advice::new(1, 0, 1, |arg: &[F], _| vec![arg[0].invert().unwrap()]); - let prod_inv = circuit.advice(round, adv_invert, vec![prod], vec![])[0]; + let prod_inv = circuit.advice(round, adv_invert, vec![prod])[0]; circuit.constrain_with( &vec![prod, prod_inv], diff --git a/src/gadgets/poseidon.rs b/src/gadgets/poseidon.rs index 6cb06df..536ac8e 100644 --- a/src/gadgets/poseidon.rs +++ b/src/gadgets/poseidon.rs @@ -132,10 +132,9 @@ pub fn poseidon_partial_rounds_gadget<'a>(circuit: &mut Circuit<'a, F, Gatebb<'a t, 0, n_rounds_p + t, - move |input_state: &[F], _: &[F]| poseidon_partial_rounds_advice(input_state, c, m, n_rounds_f, n_rounds_p, t) + move |input_state, _| poseidon_partial_rounds_advice(input_state, c, m, n_rounds_f, n_rounds_p, t) ), inp.clone(), - vec![], ); let (adv, out) = tmp.split_at(n_rounds_p); diff --git a/src/gadgets/range.rs b/src/gadgets/range.rs index cb7d260..ba73204 100644 --- a/src/gadgets/range.rs +++ b/src/gadgets/range.rs @@ -193,7 +193,7 @@ pub fn limb_decompose_gadget<'a, F: PrimeField+FieldUtils>( 1, 0, num_limbs, - move |args,_| { + move |args, _| { let x = args[0]; let limbs = limbs(x, base); assert!(limbs.len()<=num_limbs, "The value has too many limbs."); @@ -201,7 +201,6 @@ pub fn limb_decompose_gadget<'a, F: PrimeField+FieldUtils>( } ), vec![input], - vec![] ); diff --git a/src/lib.rs b/src/lib.rs index c45c7ae..9c646c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,4 +10,5 @@ pub mod gadgets; pub mod utils; pub mod folding; pub mod test; -pub mod gatelib; \ No newline at end of file +pub mod gatelib; +pub mod external_interface; \ No newline at end of file diff --git a/src/test.rs b/src/test.rs index b1e22cb..833a8e5 100644 --- a/src/test.rs +++ b/src/test.rs @@ -64,7 +64,8 @@ mod tests { let sq1 = circuit.apply(0, sq.clone(), vec![input]); let _ = circuit.apply_pub(0, sq.clone(), sq1); - let mut instance = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); instance.set_ext(public_input_source, F::from(2)); @@ -102,7 +103,7 @@ mod tests { let mut fractions = vec![]; for k in 0..5 { fractions.push( - circuit.advice(1, division_advice.clone(), vec![challenge, pi[k]], vec![])[0] + circuit.advice(1, division_advice.clone(), vec![challenge, pi[k]])[0] ); } @@ -122,22 +123,23 @@ mod tests { circuit.constrain(&[one, challenge, pi[k], fractions[k]], div_constr.clone()); } - let mut circuit = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); // construction phase ended - circuit.set_ext(pi_ext[0], F::from(2)); - circuit.set_ext(pi_ext[1], F::from(3)); - circuit.set_ext(pi_ext[2], F::from(4)); - circuit.set_ext(pi_ext[3], F::from(5)); - circuit.set_ext(pi_ext[4], F::from(6)); + instance.set_ext(pi_ext[0], F::from(2)); + instance.set_ext(pi_ext[1], F::from(3)); + instance.set_ext(pi_ext[2], F::from(4)); + instance.set_ext(pi_ext[3], F::from(5)); + instance.set_ext(pi_ext[4], F::from(6)); - circuit.execute(0); + instance.execute(0); - circuit.set_ext(challenge_ext, F::random(OsRng)); + instance.set_ext(challenge_ext, F::random(OsRng)); - circuit.execute(1); + instance.execute(1); - circuit.valid_witness(); // test that constraints are satisfied + instance.valid_witness(); // test that constraints are satisfied } #[test] @@ -148,14 +150,15 @@ mod tests { let pi = input(&mut circuit, pi_ext, 0); let ret = poseidon_gadget_internal(&mut circuit, &cfg, 1, 0, vec![pi]); - let mut circuit = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); - circuit.set_ext(pi_ext, F::ONE); + instance.set_ext(pi_ext, F::ONE); - circuit.execute(0); - circuit.valid_witness(); + instance.execute(0); + instance.valid_witness(); - assert_eq!(circuit.cs.getvar(ret), F::from_str_vartime("18586133768512220936620570745912940619677854269274689475585506675881198879027").unwrap()); + assert_eq!(instance.cs.getvar(ret), F::from_str_vartime("18586133768512220936620570745912940619677854269274689475585506675881198879027").unwrap()); } #[test] @@ -166,14 +169,15 @@ mod tests { let pi = input(&mut circuit, pi_ext, 0); let ret = poseidon_gadget_internal(&mut circuit, &cfg, 2, 0, vec![pi]); - let mut circuit = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); - circuit.set_ext(pi_ext, F::ONE); + instance.set_ext(pi_ext, F::ONE); - circuit.execute(0); - circuit.valid_witness(); + instance.execute(0); + instance.valid_witness(); - assert_eq!(circuit.cs.getvar(ret), F::from_str_vartime("18586133768512220936620570745912940619677854269274689475585506675881198879027").unwrap()); + assert_eq!(instance.cs.getvar(ret), F::from_str_vartime("18586133768512220936620570745912940619677854269274689475585506675881198879027").unwrap()); } #[test] @@ -184,18 +188,19 @@ mod tests { let pi = input(&mut circuit, pi_ext, 0); let ret = poseidon_gadget_mixstrat(&mut circuit, &cfg, 0, vec![pi]); - let mut circuit = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); - circuit.set_ext(pi_ext, F::ONE); + instance.set_ext(pi_ext, F::ONE); - circuit.execute(0); - circuit.valid_witness(); + instance.execute(0); + instance.valid_witness(); - assert!(circuit.cs.getvar(ret) == F::from_str_vartime("18586133768512220936620570745912940619677854269274689475585506675881198879027").unwrap()); + assert!(instance.cs.getvar(ret) == F::from_str_vartime("18586133768512220936620570745912940619677854269274689475585506675881198879027").unwrap()); assert!(cfg.hash(vec![F::ONE]) == F::from_str_vartime("18586133768512220936620570745912940619677854269274689475585506675881198879027").unwrap()); - println!("{:?}", circuit.cs.getvar(ret).to_repr()); + println!("{:?}", instance.cs.getvar(ret).to_repr()); } #[test] @@ -208,16 +213,18 @@ mod tests { let bits = bit_decomposition_gadget(&mut circuit, 0, 3, pi); - let mut circuit = circuit.finalize(); - circuit.set_ext(pi_ext, F::from(6)); - circuit.execute(0); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); + + instance.set_ext(pi_ext, F::from(6)); + instance.execute(0); - circuit.valid_witness(); + instance.valid_witness(); assert!(bits.len()==3); - assert!(circuit.cs.getvar(bits[0]) == F::ZERO); - assert!(circuit.cs.getvar(bits[1]) == F::ONE); - assert!(circuit.cs.getvar(bits[2]) == F::ONE); + assert!(instance.cs.getvar(bits[0]) == F::ZERO); + assert!(instance.cs.getvar(bits[1]) == F::ONE); + assert!(instance.cs.getvar(bits[2]) == F::ONE); } #[test] @@ -288,15 +295,17 @@ mod tests { let limbs = limb_decompose_gadget(&mut circuit, 9, 0, 2, pi); - let mut circuit = circuit.finalize(); - circuit.set_ext(pi_ext, F::from(25)); - circuit.execute(0); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); + + instance.set_ext(pi_ext, F::from(25)); + instance.execute(0); - circuit.valid_witness(); + instance.valid_witness(); assert!(limbs.len()==2); - assert!(circuit.cs.getvar(limbs[0].var) == F::from(7)); - assert!(circuit.cs.getvar(limbs[1].var) == F::from(2)); + assert!(instance.cs.getvar(limbs[0].var) == F::from(7)); + assert!(instance.cs.getvar(limbs[1].var) == F::from(2)); } @@ -356,21 +365,23 @@ mod tests { let pi : Vec<_> = pi.iter().map(|x|x.as_ref()).collect(); let chosen = choice_gadget(&mut circuit, &pi, VarSmall::new_unchecked(pi_id, 9), 0); - let mut circuit = circuit.finalize(); - circuit.set_ext(pi_id_ext, F::from(5)); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); + + instance.set_ext(pi_id_ext, F::from(5)); for i in 0..9 { for j in 0..3 { - circuit.set_ext(pi_ext[i][j], F::random(OsRng)); + instance.set_ext(pi_ext[i][j], F::random(OsRng)); } } - circuit.execute(0); + instance.execute(0); - circuit.valid_witness(); + instance.valid_witness(); assert!(chosen.len() == 3); for j in 0..3 { - assert!(circuit.cs.getvar(pi[5][j]) == circuit.cs.getvar(chosen[j])) + assert!(instance.cs.getvar(pi[5][j]) == instance.cs.getvar(chosen[j])) } } @@ -401,7 +412,8 @@ mod tests { let scmul = escalarmul_gadget_9(&mut circuit, sc, pt, num_limbs, 0, a, b, &mut nonzeros); nonzero_gadget(&mut circuit, &nonzeros, 9); - let mut instance = circuit.finalize(); + let constructed = circuit.finalize(); + let mut instance = constructed.spawn(); let pi_a = C::random(OsRng).to_affine(); instance.set_ext(pi_a_ext.0, pi_a.x);