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