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}