You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
6.9 KiB

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