ark-r1cs-std/r1cs-std/src/test_constraint_system.rs
r1cs-std/src/test_constraint_system.rsRaw
1use crate::{BTreeMap, String, Vec};
2use algebra::Field;
3use r1cs_core::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
4
5#[derive(Debug)]
6enum NamedObject {
7 Constraint(usize),
8 Var(Variable),
9 Namespace,
10}
11
12/// Constraint system for testing purposes.
13pub struct TestConstraintSystem<ConstraintF: Field> {
14 named_objects: BTreeMap<String, NamedObject>,
15 current_namespace: Vec<String>,
16 pub constraints: Vec<(
17 LinearCombination<ConstraintF>,
18 LinearCombination<ConstraintF>,
19 LinearCombination<ConstraintF>,
20 String,
21 )>,
22 inputs: Vec<(ConstraintF, String)>,
23 aux: Vec<(ConstraintF, String)>,
24}
25
26impl<ConstraintF: Field> TestConstraintSystem<ConstraintF> {
27 fn eval_lc(
28 terms: &[(Variable, ConstraintF)],
29 inputs: &[(ConstraintF, String)],
30 aux: &[(ConstraintF, String)],
31 ) -> ConstraintF {
32 let mut acc = ConstraintF::zero();
33
34 for &(var, ref coeff) in terms {
35 let mut tmp = match var.get_unchecked() {
36 Index::Input(index) => inputs[index].0,
37 Index::Aux(index) => aux[index].0,
38 };
39
40 tmp *= coeff;
41 acc += tmp;
42 }
43
44 acc
45 }
46}
47
48impl<ConstraintF: Field> TestConstraintSystem<ConstraintF> {
49 pub fn new() -> TestConstraintSystem<ConstraintF> {
50 let mut map = BTreeMap::new();
51 map.insert(
52 "ONE".into(),
53 NamedObject::Var(TestConstraintSystem::<ConstraintF>::one()),
54 );
55
56 TestConstraintSystem {
57 named_objects: map,
58 current_namespace: vec![],
59 constraints: vec![],
60 inputs: vec![(ConstraintF::one(), "ONE".into())],
61 aux: vec![],
62 }
63 }
64
65 #[allow(unused_variables)]
66 pub fn print_named_objects(&self) {
67 for &(_, _, _, ref name) in &self.constraints {
68 println!("{}", name);
69 }
70 }
71
72 pub fn which_is_unsatisfied(&self) -> Option<&str> {
73 for &(ref a, ref b, ref c, ref path) in &self.constraints {
74 let mut a = Self::eval_lc(a.as_ref(), &self.inputs, &self.aux);
75 let b = Self::eval_lc(b.as_ref(), &self.inputs, &self.aux);
76 let c = Self::eval_lc(c.as_ref(), &self.inputs, &self.aux);
77
78 a.mul_assign(&b);
79
80 if a != c {
81 return Some(&*path);
82 }
83 }
84
85 None
86 }
87
88 pub fn is_satisfied(&self) -> bool {
89 self.which_is_unsatisfied().is_none()
90 }
91
92 pub fn num_constraints(&self) -> usize {
93 self.constraints.len()
94 }
95
96 pub fn set(&mut self, path: &str, to: ConstraintF) {
97 match self.named_objects.get(path) {
98 Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
99 Index::Input(index) => self.inputs[index].0 = to,
100 Index::Aux(index) => self.aux[index].0 = to,
101 },
102 Some(e) => panic!(
103 "tried to set path `{}` to value, but `{:?}` already exists there.",
104 path, e
105 ),
106 _ => panic!("no variable exists at path: {}", path),
107 }
108 }
109
110 pub fn get(&mut self, path: &str) -> ConstraintF {
111 match self.named_objects.get(path) {
112 Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
113 Index::Input(index) => self.inputs[index].0,
114 Index::Aux(index) => self.aux[index].0,
115 },
116 Some(e) => panic!(
117 "tried to get value of path `{}`, but `{:?}` exists there (not a variable)",
118 path, e
119 ),
120 _ => panic!("no variable exists at path: {}", path),
121 }
122 }
123
124 fn set_named_obj(&mut self, path: String, to: NamedObject) {
125 if self.named_objects.get(&path).is_some() {
126 panic!("tried to create object at existing path: {}", path);
127 }
128
129 self.named_objects.insert(path, to);
130 }
131}
132
133fn compute_path(ns: &[String], this: String) -> String {
134 if this.chars().any(|a| a == '/') {
135 panic!(
136 "'/' is not allowed in namespaces. Error in namespace '{}'",
137 this
138 );
139 }
140
141 let mut name = String::new();
142
143 let mut needs_separation = false;
144 for ns in ns.iter().chain(Some(&this).into_iter()) {
145 if needs_separation {
146 name += "/";
147 }
148
149 name += ns;
150 needs_separation = true;
151 }
152
153 name
154}
155
156impl<ConstraintF: Field> ConstraintSystem<ConstraintF> for TestConstraintSystem<ConstraintF> {
157 type Root = Self;
158
159 fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
160 where
161 F: FnOnce() -> Result<ConstraintF, SynthesisError>,
162 A: FnOnce() -> AR,
163 AR: Into<String>,
164 {
165 let index = self.aux.len();
166 let path = compute_path(&self.current_namespace, annotation().into());
167 self.aux.push((f()?, path.clone()));
168 let var = Variable::new_unchecked(Index::Aux(index));
169 self.set_named_obj(path, NamedObject::Var(var));
170
171 Ok(var)
172 }
173
174 fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
175 where
176 F: FnOnce() -> Result<ConstraintF, SynthesisError>,
177 A: FnOnce() -> AR,
178 AR: Into<String>,
179 {
180 let index = self.inputs.len();
181 let path = compute_path(&self.current_namespace, annotation().into());
182 self.inputs.push((f()?, path.clone()));
183 let var = Variable::new_unchecked(Index::Input(index));
184 self.set_named_obj(path, NamedObject::Var(var));
185
186 Ok(var)
187 }
188
189 fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
190 where
191 A: FnOnce() -> AR,
192 AR: Into<String>,
193 LA: FnOnce(LinearCombination<ConstraintF>) -> LinearCombination<ConstraintF>,
194 LB: FnOnce(LinearCombination<ConstraintF>) -> LinearCombination<ConstraintF>,
195 LC: FnOnce(LinearCombination<ConstraintF>) -> LinearCombination<ConstraintF>,
196 {
197 let path = compute_path(&self.current_namespace, annotation().into());
198 let index = self.constraints.len();
199 self.set_named_obj(path.clone(), NamedObject::Constraint(index));
200
201 let mut a = a(LinearCombination::zero());
202 let mut b = b(LinearCombination::zero());
203 let mut c = c(LinearCombination::zero());
204 a.0.shrink_to_fit();
205 b.0.shrink_to_fit();
206 c.0.shrink_to_fit();
207
208 self.constraints.push((a, b, c, path));
209 }
210
211 fn push_namespace<NR, N>(&mut self, name_fn: N)
212 where
213 NR: Into<String>,
214 N: FnOnce() -> NR,
215 {
216 let name = name_fn().into();
217 let path = compute_path(&self.current_namespace, name.clone());
218 self.set_named_obj(path, NamedObject::Namespace);
219 self.current_namespace.push(name);
220 }
221
222 fn pop_namespace(&mut self) {
223 assert!(self.current_namespace.pop().is_some());
224 }
225
226 fn get_root(&mut self) -> &mut Self::Root {
227 self
228 }
229
230 fn num_constraints(&self) -> usize {
231 self.constraints.len()
232 }
233}