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.

307 lines
8.1 KiB

Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
  1. use bellperson::{ConstraintSystem, SynthesisError};
  2. use bellperson_nonnative::{
  3. mp::bignat::BigNat,
  4. util::{convert::nat_to_f, num::Num},
  5. };
  6. use ff::PrimeField;
  7. use nova_snark::bellperson::{
  8. r1cs::{NovaShape, NovaWitness},
  9. shape_cs::ShapeCS,
  10. solver::SatisfyingAssignment,
  11. };
  12. use rug::Integer;
  13. fn synthesize_is_equal<Fr: PrimeField, CS: ConstraintSystem<Fr>>(
  14. cs: &mut CS,
  15. a_val: &Integer,
  16. limb_width: usize,
  17. n_limbs: usize,
  18. ) -> Result<(), SynthesisError> {
  19. let a1 = BigNat::alloc_from_nat(
  20. cs.namespace(|| "alloc a2"),
  21. || Ok(a_val.clone()),
  22. limb_width,
  23. n_limbs,
  24. )?;
  25. let _ = a1.inputize(cs.namespace(|| "make a input"));
  26. let a_num = Num::alloc(cs.namespace(|| "alloc a num"), || {
  27. Ok(nat_to_f(a_val).unwrap())
  28. })?;
  29. let a2 = BigNat::from_num(
  30. cs.namespace(|| "allocate a1_limbs"),
  31. a_num,
  32. limb_width,
  33. n_limbs,
  34. )?;
  35. let _ = a1.equal_when_carried(cs.namespace(|| "check equal"), &a2)?;
  36. Ok(())
  37. }
  38. #[allow(clippy::too_many_arguments)]
  39. fn synthesize_mult_mod<Fr: PrimeField, CS: ConstraintSystem<Fr>>(
  40. cs: &mut CS,
  41. a_val: &Integer,
  42. b_val: &Integer,
  43. m_val: &Integer,
  44. q_val: &Integer,
  45. r_val: &Integer,
  46. limb_width: usize,
  47. n_limbs: usize,
  48. ) -> Result<(), SynthesisError> {
  49. let a_num = Num::alloc(cs.namespace(|| "alloc a num"), || {
  50. Ok(nat_to_f(a_val).unwrap())
  51. })?;
  52. let m = BigNat::alloc_from_nat(
  53. cs.namespace(|| "m"),
  54. || Ok(m_val.clone()),
  55. limb_width,
  56. n_limbs,
  57. )?;
  58. let _ = m.inputize(cs.namespace(|| "modulus m"))?;
  59. let a = BigNat::from_num(
  60. cs.namespace(|| "allocate a_limbs"),
  61. a_num,
  62. limb_width,
  63. n_limbs,
  64. )?;
  65. let b = BigNat::alloc_from_nat(
  66. cs.namespace(|| "b"),
  67. || Ok(b_val.clone()),
  68. limb_width,
  69. n_limbs,
  70. )?;
  71. let q = BigNat::alloc_from_nat(
  72. cs.namespace(|| "q"),
  73. || Ok(q_val.clone()),
  74. limb_width,
  75. n_limbs,
  76. )?;
  77. let r = BigNat::alloc_from_nat(
  78. cs.namespace(|| "r"),
  79. || Ok(r_val.clone()),
  80. limb_width,
  81. n_limbs,
  82. )?;
  83. let (qa, ra) = a.mult_mod(cs.namespace(|| "prod"), &b, &m)?;
  84. qa.equal(cs.namespace(|| "qcheck"), &q)?;
  85. ra.equal(cs.namespace(|| "rcheck"), &r)?;
  86. Ok(())
  87. }
  88. fn synthesize_add<Fr: PrimeField, CS: ConstraintSystem<Fr>>(
  89. cs: &mut CS,
  90. a_val: &Integer,
  91. b_val: &Integer,
  92. c_val: &Integer,
  93. limb_width: usize,
  94. n_limbs: usize,
  95. ) -> Result<(), SynthesisError> {
  96. let a = BigNat::alloc_from_nat(
  97. cs.namespace(|| "a"),
  98. || Ok(a_val.clone()),
  99. limb_width,
  100. n_limbs,
  101. )?;
  102. let _ = a.inputize(cs.namespace(|| "input a"))?;
  103. let b = BigNat::alloc_from_nat(
  104. cs.namespace(|| "b"),
  105. || Ok(b_val.clone()),
  106. limb_width,
  107. n_limbs,
  108. )?;
  109. let _ = b.inputize(cs.namespace(|| "input b"))?;
  110. let c = BigNat::alloc_from_nat(
  111. cs.namespace(|| "c"),
  112. || Ok(c_val.clone()),
  113. limb_width,
  114. n_limbs,
  115. )?;
  116. let ca = a.add::<CS>(&b)?;
  117. ca.equal(cs.namespace(|| "ccheck"), &c)?;
  118. Ok(())
  119. }
  120. fn synthesize_add_mod<Fr: PrimeField, CS: ConstraintSystem<Fr>>(
  121. cs: &mut CS,
  122. a_val: &Integer,
  123. b_val: &Integer,
  124. c_val: &Integer,
  125. m_val: &Integer,
  126. limb_width: usize,
  127. n_limbs: usize,
  128. ) -> Result<(), SynthesisError> {
  129. let a = BigNat::alloc_from_nat(
  130. cs.namespace(|| "a"),
  131. || Ok(a_val.clone()),
  132. limb_width,
  133. n_limbs,
  134. )?;
  135. let _ = a.inputize(cs.namespace(|| "input a"))?;
  136. let b = BigNat::alloc_from_nat(
  137. cs.namespace(|| "b"),
  138. || Ok(b_val.clone()),
  139. limb_width,
  140. n_limbs,
  141. )?;
  142. let _ = b.inputize(cs.namespace(|| "input b"))?;
  143. let c = BigNat::alloc_from_nat(
  144. cs.namespace(|| "c"),
  145. || Ok(c_val.clone()),
  146. limb_width,
  147. n_limbs,
  148. )?;
  149. let m = BigNat::alloc_from_nat(
  150. cs.namespace(|| "m"),
  151. || Ok(m_val.clone()),
  152. limb_width,
  153. n_limbs,
  154. )?;
  155. let d = a.add::<CS>(&b)?;
  156. let ca = d.red_mod(cs.namespace(|| "reduce"), &m)?;
  157. ca.equal(cs.namespace(|| "ccheck"), &c)?;
  158. Ok(())
  159. }
  160. #[test]
  161. fn test_mult_mod() {
  162. type G = pasta_curves::pallas::Point;
  163. //Set the inputs
  164. let a_val = Integer::from_str_radix(
  165. "11572336752428856981970994795408771577024165681374400871001196932361466228192",
  166. 10,
  167. )
  168. .unwrap();
  169. let b_val = Integer::from_str_radix(
  170. "87673389408848523602668121701204553693362841135953267897017930941776218798802",
  171. 10,
  172. )
  173. .unwrap();
  174. let m_val = Integer::from_str_radix(
  175. "40000000000000000000000000000000224698fc094cf91b992d30ed00000001",
  176. 16,
  177. )
  178. .unwrap();
  179. let q_val = Integer::from_str_radix(
  180. "35048542371029440058224000662033175648615707461806414787901284501179083518342",
  181. 10,
  182. )
  183. .unwrap();
  184. let r_val = Integer::from_str_radix(
  185. "26362617993085418618858432307761590013874563896298265114483698919121453084730",
  186. 10,
  187. )
  188. .unwrap();
  189. //First create the shape
  190. let mut cs: ShapeCS<G> = ShapeCS::new();
  191. let _ = synthesize_mult_mod(&mut cs, &a_val, &b_val, &m_val, &q_val, &r_val, 32, 8);
  192. let shape = cs.r1cs_shape();
  193. let gens = cs.r1cs_gens();
  194. println!("Mult mod constraint no: {}", cs.num_constraints());
  195. //Now get the assignment
  196. let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
  197. let _ = synthesize_mult_mod(&mut cs, &a_val, &b_val, &m_val, &q_val, &r_val, 32, 8);
  198. let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
  199. //Make sure that this is satisfiable
  200. assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
  201. }
  202. #[test]
  203. fn test_add() {
  204. type G = pasta_curves::pallas::Point;
  205. //Set the inputs
  206. let a_val = Integer::from_str_radix(
  207. "11572336752428856981970994795408771577024165681374400871001196932361466228192",
  208. 10,
  209. )
  210. .unwrap();
  211. let b_val = Integer::from_str_radix("1", 10).unwrap();
  212. let c_val = Integer::from_str_radix(
  213. "11572336752428856981970994795408771577024165681374400871001196932361466228193",
  214. 10,
  215. )
  216. .unwrap();
  217. //First create the shape
  218. let mut cs: ShapeCS<G> = ShapeCS::new();
  219. let _ = synthesize_add(&mut cs, &a_val, &b_val, &c_val, 32, 8);
  220. let shape = cs.r1cs_shape();
  221. let gens = cs.r1cs_gens();
  222. println!("Add mod constraint no: {}", cs.num_constraints());
  223. //Now get the assignment
  224. let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
  225. let _ = synthesize_add(&mut cs, &a_val, &b_val, &c_val, 32, 8);
  226. let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
  227. //Make sure that this is satisfiable
  228. assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
  229. }
  230. #[test]
  231. fn test_add_mod() {
  232. type G = pasta_curves::pallas::Point;
  233. //Set the inputs
  234. let a_val = Integer::from_str_radix(
  235. "11572336752428856981970994795408771577024165681374400871001196932361466228192",
  236. 10,
  237. )
  238. .unwrap();
  239. let b_val = Integer::from_str_radix("1", 10).unwrap();
  240. let c_val = Integer::from_str_radix(
  241. "11572336752428856981970994795408771577024165681374400871001196932361466228193",
  242. 10,
  243. )
  244. .unwrap();
  245. let m_val = Integer::from_str_radix(
  246. "40000000000000000000000000000000224698fc094cf91b992d30ed00000001",
  247. 16,
  248. )
  249. .unwrap();
  250. //First create the shape
  251. let mut cs: ShapeCS<G> = ShapeCS::new();
  252. let _ = synthesize_add_mod(&mut cs, &a_val, &b_val, &c_val, &m_val, 32, 8);
  253. let shape = cs.r1cs_shape();
  254. let gens = cs.r1cs_gens();
  255. println!("Add mod constraint no: {}", cs.num_constraints());
  256. //Now get the assignment
  257. let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
  258. let _ = synthesize_add_mod(&mut cs, &a_val, &b_val, &c_val, &m_val, 32, 8);
  259. let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
  260. //Make sure that this is satisfiable
  261. assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
  262. }
  263. #[test]
  264. fn test_equal() {
  265. type G = pasta_curves::pallas::Point;
  266. //Set the inputs
  267. let a_val = Integer::from_str_radix("1157233675242885698197099479540877", 10).unwrap();
  268. //First create the shape
  269. let mut cs: ShapeCS<G> = ShapeCS::new();
  270. let _ = synthesize_is_equal(&mut cs, &a_val, 32, 8);
  271. let shape = cs.r1cs_shape();
  272. let gens = cs.r1cs_gens();
  273. println!("Equal constraint no: {}", cs.num_constraints());
  274. //Now get the assignment
  275. let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
  276. let _ = synthesize_is_equal(&mut cs, &a_val, 32, 8);
  277. let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
  278. //Make sure that this is satisfiable
  279. assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
  280. }