snarkvm_r1cs/
test_constraint_checker.rs1use crate::{errors::SynthesisError, ConstraintSystem, Index, LinearCombination, Variable};
16use snarkvm_fields::Field;
17
18pub struct TestConstraintChecker<F: Field> {
20 public_variables: Vec<F>,
22 private_variables: Vec<F>,
24 found_unsatisfactory_constraint: bool,
26 num_constraints: usize,
28 segments: Vec<String>,
30 first_unsatisfied_constraint: Option<String>,
32}
33
34impl<F: Field> Default for TestConstraintChecker<F> {
35 fn default() -> Self {
36 Self {
37 public_variables: vec![F::one()],
38 private_variables: vec![],
39 found_unsatisfactory_constraint: false,
40 num_constraints: 0,
41 segments: vec![],
42 first_unsatisfied_constraint: None,
43 }
44 }
45}
46
47impl<F: Field> TestConstraintChecker<F> {
48 pub fn new() -> Self {
49 Self::default()
50 }
51
52 pub fn which_is_unsatisfied(&self) -> Option<String> {
53 self.first_unsatisfied_constraint.clone()
54 }
55
56 #[inline]
57 pub fn is_satisfied(&self) -> bool {
58 !self.found_unsatisfactory_constraint
59 }
60
61 #[inline]
62 pub fn num_constraints(&self) -> usize {
63 self.num_constraints
64 }
65
66 #[inline]
67 pub fn public_inputs(&self) -> Vec<F> {
68 self.public_variables[1..].to_vec()
69 }
70}
71
72impl<F: Field> ConstraintSystem<F> for TestConstraintChecker<F> {
73 type Root = Self;
74
75 fn alloc<Fn, A, AR>(&mut self, _annotation: A, f: Fn) -> Result<Variable, SynthesisError>
76 where
77 Fn: FnOnce() -> Result<F, SynthesisError>,
78 A: FnOnce() -> AR,
79 AR: AsRef<str>,
80 {
81 let index = self.private_variables.len();
82 self.private_variables.push(f()?);
83 let var = Variable::new_unchecked(Index::Private(index));
84
85 Ok(var)
86 }
87
88 fn alloc_input<Fn, A, AR>(&mut self, _annotation: A, f: Fn) -> Result<Variable, SynthesisError>
89 where
90 Fn: FnOnce() -> Result<F, SynthesisError>,
91 A: FnOnce() -> AR,
92 AR: AsRef<str>,
93 {
94 let index = self.public_variables.len();
95 self.public_variables.push(f()?);
96 let var = Variable::new_unchecked(Index::Public(index));
97
98 Ok(var)
99 }
100
101 fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
102 where
103 A: FnOnce() -> AR,
104 AR: AsRef<str>,
105 LA: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
106 LB: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
107 LC: FnOnce(LinearCombination<F>) -> LinearCombination<F>,
108 {
109 self.num_constraints += 1;
110
111 let eval_lc = |lc: Vec<(Variable, F)>| -> F {
112 lc.into_iter()
113 .map(|(var, coeff)| {
114 let value = match var.get_unchecked() {
115 Index::Public(index) => self.public_variables[index],
116 Index::Private(index) => self.private_variables[index],
117 };
118 value * coeff
119 })
120 .sum::<F>()
121 };
122
123 let a = eval_lc(a(LinearCombination::zero()).0);
124 let b = eval_lc(b(LinearCombination::zero()).0);
125 let c = eval_lc(c(LinearCombination::zero()).0);
126
127 if a * b != c && self.first_unsatisfied_constraint.is_none() {
128 self.found_unsatisfactory_constraint = true;
129
130 let new = annotation().as_ref().to_string();
131 assert!(!new.contains('/'), "'/' is not allowed in names");
132
133 let mut path = self.segments.clone();
134 path.push(new);
135 self.first_unsatisfied_constraint = Some(path.join("/"));
136 }
137 }
138
139 fn push_namespace<NR: AsRef<str>, N: FnOnce() -> NR>(&mut self, name_fn: N) {
140 let new = name_fn().as_ref().to_string();
141 assert!(!new.contains('/'), "'/' is not allowed in names");
142
143 self.segments.push(new)
144 }
145
146 fn pop_namespace(&mut self) {
147 self.segments.pop();
148 }
149
150 #[inline]
151 fn get_root(&mut self) -> &mut Self::Root {
152 self
153 }
154
155 #[inline]
156 fn num_constraints(&self) -> usize {
157 self.num_constraints()
158 }
159
160 #[inline]
161 fn num_public_variables(&self) -> usize {
162 self.public_variables.len()
163 }
164
165 #[inline]
166 fn num_private_variables(&self) -> usize {
167 self.private_variables.len()
168 }
169
170 #[inline]
171 fn is_in_setup_mode(&self) -> bool {
172 false
173 }
174}