arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/r1cs-std/src/test_constraint_counter.rs
r1cs-std/src/test_constraint_counter.rsRaw
  1use crate::String;
  2use algebra::Field;
  3use r1cs_core::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
  4
  5/// Constraint counter for testing purposes.
  6pub struct ConstraintCounter {
  7    pub num_inputs: usize,
  8    pub num_aux: usize,
  9    pub num_constraints: usize,
 10}
 11
 12impl ConstraintCounter {
 13    pub fn new() -> Self {
 14        Self {
 15            num_aux: 0,
 16            num_inputs: 0,
 17            num_constraints: 0,
 18        }
 19    }
 20
 21    pub fn num_constraints(&self) -> usize {
 22        self.num_constraints
 23    }
 24}
 25
 26impl<ConstraintF: Field> ConstraintSystem<ConstraintF> for ConstraintCounter {
 27    type Root = Self;
 28
 29    fn alloc<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
 30    where
 31        F: FnOnce() -> Result<ConstraintF, SynthesisError>,
 32        A: FnOnce() -> AR,
 33        AR: Into<String>,
 34    {
 35        let var = Variable::new_unchecked(Index::Aux(self.num_aux));
 36        self.num_aux += 1;
 37        Ok(var)
 38    }
 39
 40    fn alloc_input<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
 41    where
 42        F: FnOnce() -> Result<ConstraintF, SynthesisError>,
 43        A: FnOnce() -> AR,
 44        AR: Into<String>,
 45    {
 46        let var = Variable::new_unchecked(Index::Input(self.num_inputs));
 47        self.num_inputs += 1;
 48
 49        Ok(var)
 50    }
 51
 52    fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, _: LA, _: LB, _: LC)
 53    where
 54        A: FnOnce() -> AR,
 55        AR: Into<String>,
 56        LA: FnOnce(LinearCombination<ConstraintF>) -> LinearCombination<ConstraintF>,
 57        LB: FnOnce(LinearCombination<ConstraintF>) -> LinearCombination<ConstraintF>,
 58        LC: FnOnce(LinearCombination<ConstraintF>) -> LinearCombination<ConstraintF>,
 59    {
 60        self.num_constraints += 1;
 61    }
 62
 63    fn push_namespace<NR, N>(&mut self, _: N)
 64    where
 65        NR: Into<String>,
 66        N: FnOnce() -> NR,
 67    {
 68    }
 69
 70    fn pop_namespace(&mut self) {}
 71
 72    fn get_root(&mut self) -> &mut Self::Root {
 73        self
 74    }
 75
 76    fn num_constraints(&self) -> usize {
 77        self.num_constraints
 78    }
 79}
 80
 81#[cfg(test)]
 82mod tests {
 83    use super::*;
 84    use crate::test_constraint_system::TestConstraintSystem;
 85    use algebra::{bls12_381::Fq, Field};
 86    use r1cs_core::{ConstraintSynthesizer, SynthesisError};
 87
 88    // circuit proving knowledge of a square root
 89    #[derive(Clone, Debug)]
 90    struct TestCircuit<F>(Option<F>);
 91
 92    impl<F: Field> ConstraintSynthesizer<F> for TestCircuit<F> {
 93        fn generate_constraints<CS: ConstraintSystem<F>>(
 94            self,
 95            cs: &mut CS,
 96        ) -> Result<(), SynthesisError> {
 97            let x = cs.alloc(|| "x", || self.0.ok_or(SynthesisError::AssignmentMissing))?;
 98            // 1 input!
 99            let out = cs.alloc_input(
100                || "square",
101                || {
102                    self.0
103                        .map(|x| x.square())
104                        .ok_or(SynthesisError::AssignmentMissing)
105                },
106            )?;
107            cs.enforce(|| "x * x = x^2", |lc| lc + x, |lc| lc + x, |lc| lc + out);
108            Ok(())
109        }
110    }
111
112    #[test]
113    fn test_constraints_counter() {
114        let empty_circuit = TestCircuit::<Fq>(None);
115        let populated_circuit = TestCircuit(Some(Fq::from(10u32)));
116
117        let mut counter = ConstraintCounter::new();
118        let mut cs = TestConstraintSystem::new();
119
120        empty_circuit
121            .clone()
122            .generate_constraints(&mut counter)
123            .unwrap();
124        // an empty circuit cannot be used with TestConstraintSystem
125        empty_circuit.generate_constraints(&mut cs).unwrap_err();
126        populated_circuit.generate_constraints(&mut cs).unwrap();
127
128        assert_eq!(counter.num_constraints(), cs.num_constraints())
129    }
130}