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.

492 lines
16 KiB

  1. use ark_ec::AffineRepr;
  2. use ark_ff::fields::PrimeField;
  3. use ark_std::{
  4. rand::{Rng, RngCore},
  5. UniformRand,
  6. };
  7. use ark_std::{One, Zero};
  8. use std::marker::PhantomData;
  9. use crate::pedersen::{Commitment, Params as PedersenParams, Pedersen, Proof as PedersenProof};
  10. use crate::transcript::Transcript;
  11. use crate::utils::*;
  12. pub struct R1CS<F: PrimeField> {
  13. pub A: Vec<Vec<F>>,
  14. pub B: Vec<Vec<F>>,
  15. pub C: Vec<Vec<F>>,
  16. }
  17. // Phi: φ in the paper (later 𝖴), a folded instance
  18. pub struct Phi<C: AffineRepr> {
  19. cmE: Commitment<C>,
  20. u: C::ScalarField,
  21. cmW: Commitment<C>,
  22. x: Vec<C::ScalarField>,
  23. }
  24. // FWit: Folded Witness
  25. pub struct FWit<C: AffineRepr> {
  26. E: Vec<C::ScalarField>,
  27. rE: C::ScalarField,
  28. W: Vec<C::ScalarField>,
  29. rW: C::ScalarField,
  30. }
  31. impl<C: AffineRepr> FWit<C> {
  32. pub fn new(z: Vec<C::ScalarField>, e_len: usize) -> Self {
  33. FWit::<C> {
  34. E: vec![C::ScalarField::zero(); e_len],
  35. rE: C::ScalarField::one(),
  36. W: z,
  37. rW: C::ScalarField::one(),
  38. }
  39. }
  40. pub fn commit(&self, params: &PedersenParams<C>) -> Phi<C> {
  41. let cmE = Pedersen::commit(&params, &self.E, &self.rE);
  42. let cmW = Pedersen::commit(&params, &self.W, &self.rW);
  43. Phi {
  44. cmE,
  45. u: C::ScalarField::one(),
  46. cmW,
  47. x: self.W.clone(),
  48. }
  49. }
  50. }
  51. pub struct NIFS<C: AffineRepr> {
  52. _phantom: PhantomData<C>,
  53. }
  54. impl<C: AffineRepr> NIFS<C> {
  55. // comp_T: compute cross-terms T
  56. pub fn comp_T(
  57. r1cs: &R1CS<C::ScalarField>,
  58. u1: C::ScalarField,
  59. u2: C::ScalarField,
  60. z1: &Vec<C::ScalarField>,
  61. z2: &Vec<C::ScalarField>,
  62. ) -> Vec<C::ScalarField> {
  63. let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
  64. // this is parallelizable (for the future)
  65. let Az1 = matrix_vector_product(&A, &z1);
  66. let Bz1 = matrix_vector_product(&B, &z1);
  67. let Cz1 = matrix_vector_product(&C, &z1);
  68. let Az2 = matrix_vector_product(&A, &z2);
  69. let Bz2 = matrix_vector_product(&B, &z2);
  70. let Cz2 = matrix_vector_product(&C, &z2);
  71. let Az1_Bz2 = hadamard_product(Az1, Bz2);
  72. let Az2_Bz1 = hadamard_product(Az2, Bz1);
  73. let u1Cz2 = vector_elem_product(&Cz2, &u1);
  74. let u2Cz1 = vector_elem_product(&Cz1, &u2);
  75. // let T = vec_sub(vec_sub(vec_add(Az1_Bz2, Az2_Bz1), u1Cz2), u2Cz1);
  76. let T = ((Ve(Az1_Bz2) + Ve(Az2_Bz1)) - Ve(u1Cz2)) - Ve(u2Cz1);
  77. T.0
  78. }
  79. pub fn fold_witness(
  80. r: C::ScalarField,
  81. fw1: &FWit<C>,
  82. fw2: &FWit<C>,
  83. T: &Vec<C::ScalarField>,
  84. rT: C::ScalarField,
  85. ) -> FWit<C> {
  86. let r2 = r * r;
  87. let E: Vec<C::ScalarField> = vec_add(
  88. // this syntax will be simplified with future operators impl (or at least a method
  89. // for r-lin)
  90. &vec_add(&fw1.E, &vector_elem_product(&T, &r)),
  91. &vector_elem_product(&fw2.E, &r2),
  92. );
  93. let rE = fw1.rE + r * rT + r2 * fw2.rE;
  94. let W = vec_add(&fw1.W, &vector_elem_product(&fw2.W, &r));
  95. let rW = fw1.rW + r * fw2.rW;
  96. FWit::<C> {
  97. E: E.into(),
  98. rE,
  99. W: W.into(),
  100. rW,
  101. }
  102. }
  103. pub fn fold_instance(
  104. r: C::ScalarField,
  105. phi1: &Phi<C>,
  106. phi2: &Phi<C>,
  107. cmT: &Commitment<C>,
  108. ) -> Phi<C> {
  109. let r2 = r * r;
  110. let cmE = phi1.cmE.0 + cmT.0.mul(r) + phi2.cmE.0.mul(r2);
  111. let u = phi1.u + r * phi2.u;
  112. let cmW = phi1.cmW.0 + phi2.cmW.0.mul(r);
  113. let x = vec_add(&phi1.x, &vector_elem_product(&phi2.x, &r));
  114. // let x = rlin(phi1.x, phi2.x, r);
  115. Phi::<C> {
  116. cmE: Commitment(cmE.into()),
  117. u,
  118. cmW: Commitment(cmW.into()),
  119. x,
  120. }
  121. }
  122. // NIFS.P
  123. pub fn P(
  124. tr: &mut Transcript<C::ScalarField>,
  125. pedersen_params: &PedersenParams<C>,
  126. r: C::ScalarField,
  127. r1cs: &R1CS<C::ScalarField>,
  128. fw1: FWit<C>,
  129. fw2: FWit<C>,
  130. ) -> (FWit<C>, Phi<C>, Phi<C>, Vec<C::ScalarField>, Commitment<C>) {
  131. // compute committed instances
  132. let phi1 = fw1.commit(&pedersen_params); // wip
  133. let phi2 = fw2.commit(&pedersen_params);
  134. // compute cross terms
  135. let T = Self::comp_T(&r1cs, phi1.u, phi2.u, &fw1.W, &fw2.W);
  136. let rT = tr.get_challenge(b"rT");
  137. let cmT = Pedersen::commit(&pedersen_params, &T, &rT);
  138. // fold witness
  139. let fw3 = NIFS::<C>::fold_witness(r, &fw1, &fw2, &T, rT);
  140. // fold committed instancs
  141. // let phi3 = NIFS::<C>::fold_instance(r, &phi1, &phi2, &cmT);
  142. return (fw3, phi1, phi2, T, cmT); // maybe return phi3
  143. }
  144. // NIFS.V
  145. pub fn V(r: C::ScalarField, phi1: &Phi<C>, phi2: &Phi<C>, cmT: &Commitment<C>) -> Phi<C> {
  146. NIFS::<C>::fold_instance(r, &phi1, &phi2, &cmT)
  147. }
  148. // verify commited folded instance (phi) relations
  149. pub fn verify(
  150. r: C::ScalarField,
  151. phi1: &Phi<C>,
  152. phi2: &Phi<C>,
  153. phi3: &Phi<C>,
  154. cmT: &Commitment<C>,
  155. ) -> bool {
  156. let r2 = r * r;
  157. if phi3.cmE.0 != (phi1.cmE.0 + cmT.0.mul(r) + phi2.cmE.0.mul(r2)).into() {
  158. return false;
  159. }
  160. if phi3.u != phi1.u + r * phi2.u {
  161. return false;
  162. }
  163. if phi3.cmW.0 != (phi1.cmW.0 + phi2.cmW.0.mul(r)).into() {
  164. return false;
  165. }
  166. if phi3.x != vec_add(&phi1.x, &vector_elem_product(&phi2.x, &r)) {
  167. return false;
  168. }
  169. true
  170. }
  171. pub fn open_commitments(
  172. tr: &mut Transcript<C::ScalarField>,
  173. pedersen_params: &PedersenParams<C>,
  174. fw: &FWit<C>,
  175. phi: &Phi<C>,
  176. T: Vec<C::ScalarField>,
  177. rT: C::ScalarField,
  178. cmT: &Commitment<C>,
  179. ) -> (PedersenProof<C>, PedersenProof<C>, PedersenProof<C>) {
  180. let cmE_proof = Pedersen::prove(&pedersen_params, tr, &phi.cmE, &fw.E, &fw.rE);
  181. let cmW_proof = Pedersen::prove(&pedersen_params, tr, &phi.cmW, &fw.W, &fw.rW);
  182. let cmT_proof = Pedersen::prove(&pedersen_params, tr, &cmT, &T, &rT);
  183. (cmE_proof, cmW_proof, cmT_proof)
  184. }
  185. pub fn verify_commitments(
  186. tr: &mut Transcript<C::ScalarField>,
  187. pedersen_params: &PedersenParams<C>,
  188. phi: Phi<C>,
  189. cmT: Commitment<C>,
  190. cmE_proof: PedersenProof<C>,
  191. cmW_proof: PedersenProof<C>,
  192. cmT_proof: PedersenProof<C>,
  193. ) -> bool {
  194. if !Pedersen::verify(&pedersen_params, tr, phi.cmE, cmE_proof) {
  195. return false;
  196. }
  197. if !Pedersen::verify(&pedersen_params, tr, phi.cmW, cmW_proof) {
  198. return false;
  199. }
  200. if !Pedersen::verify(&pedersen_params, tr, cmT, cmT_proof) {
  201. return false;
  202. }
  203. true
  204. }
  205. }
  206. #[cfg(test)]
  207. mod tests {
  208. use super::*;
  209. use crate::pedersen::Pedersen;
  210. use ark_bn254::{g1::G1Affine, Fr};
  211. use ark_ec::CurveGroup;
  212. use ark_std::{
  213. rand::{Rng, RngCore},
  214. UniformRand,
  215. };
  216. use ark_std::{One, Zero};
  217. use std::ops::Mul;
  218. fn gen_test_values<R: Rng>(
  219. rng: &mut R,
  220. ) -> (
  221. R1CS<Fr>,
  222. Vec<Fr>,
  223. Vec<Fr>,
  224. Vec<Fr>,
  225. Vec<Fr>,
  226. Vec<Fr>,
  227. Vec<Fr>,
  228. ) {
  229. // R1CS for: x^3 + x + 5 = y (example from article
  230. // https://www.vitalik.ca/general/2016/12/10/qap.html )
  231. let A = to_F_matrix::<Fr>(vec![
  232. vec![0, 1, 0, 0, 0, 0],
  233. vec![0, 0, 0, 1, 0, 0],
  234. vec![0, 1, 0, 0, 1, 0],
  235. vec![5, 0, 0, 0, 0, 1],
  236. ]);
  237. let B = to_F_matrix::<Fr>(vec![
  238. vec![0, 1, 0, 0, 0, 0],
  239. vec![0, 1, 0, 0, 0, 0],
  240. vec![1, 0, 0, 0, 0, 0],
  241. vec![1, 0, 0, 0, 0, 0],
  242. ]);
  243. let C = to_F_matrix::<Fr>(vec![
  244. vec![0, 0, 0, 1, 0, 0],
  245. vec![0, 0, 0, 0, 1, 0],
  246. vec![0, 0, 0, 0, 0, 1],
  247. vec![0, 0, 1, 0, 0, 0],
  248. ]);
  249. // TODO in the future update this method to generate witness, and generate n witnesses
  250. // instances, x: pub
  251. let w1 = to_F_vec::<Fr>(vec![1, 3, 35, 9, 27, 30]);
  252. let x1 = to_F_vec::<Fr>(vec![35]);
  253. let w2 = to_F_vec::<Fr>(vec![1, 4, 73, 16, 64, 68]);
  254. let x2 = to_F_vec::<Fr>(vec![73]);
  255. let w3 = to_F_vec::<Fr>(vec![1, 5, 135, 25, 125, 130]);
  256. let x3 = to_F_vec::<Fr>(vec![135]);
  257. let r1cs = R1CS::<Fr> {
  258. A: A.clone(),
  259. B: B.clone(),
  260. C: C.clone(),
  261. };
  262. (r1cs, w1, w2, w3, x1, x2, x3)
  263. }
  264. // fold 2 instances into one
  265. #[test]
  266. fn test_one_fold() {
  267. let mut rng = ark_std::test_rng();
  268. let pedersen_params = Pedersen::<G1Affine>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
  269. let (r1cs, w1, w2, _, x1, x2, _) = gen_test_values(&mut rng);
  270. let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
  271. let r = Fr::rand(&mut rng); // this would come from the transcript
  272. let fw1 = FWit::<G1Affine>::new(w1.clone(), A.len());
  273. let fw2 = FWit::<G1Affine>::new(w2.clone(), A.len());
  274. // get committed instances
  275. let phi1 = fw1.commit(&pedersen_params); // wip
  276. let phi2 = fw2.commit(&pedersen_params);
  277. let T = NIFS::<G1Affine>::comp_T(&r1cs, phi1.u, phi2.u, &w1, &w2);
  278. let rT: Fr = Fr::rand(&mut rng);
  279. let cmT = Pedersen::commit(&pedersen_params, &T, &rT);
  280. // fold witness
  281. let fw3 = NIFS::<G1Affine>::fold_witness(r, &fw1, &fw2, &T, rT);
  282. // fold instance
  283. let phi3 = NIFS::<G1Affine>::fold_instance(r, &phi1, &phi2, &cmT);
  284. // naive check that the folded witness satisfies the relaxed r1cs
  285. let Az = matrix_vector_product(&A, &fw3.W);
  286. let Bz = matrix_vector_product(&B, &fw3.W);
  287. let Cz = matrix_vector_product(&C, &fw3.W);
  288. assert_eq!(
  289. hadamard_product(Az, Bz),
  290. vec_add(&vector_elem_product(&Cz, &phi3.u), &fw3.E)
  291. );
  292. // check that folded commitments from folded instance (phi) are equal to folding the
  293. // use folded rE, rW to commit fw3
  294. let phi3_expected = fw3.commit(&pedersen_params);
  295. assert_eq!(phi3_expected.cmE.0, phi3.cmE.0);
  296. assert_eq!(phi3_expected.cmW.0, phi3.cmW.0);
  297. // NIFS.Verify:
  298. assert!(NIFS::<G1Affine>::verify(r, &phi1, &phi2, &phi3, &cmT));
  299. // init Prover's transcript
  300. let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
  301. // init Verifier's transcript
  302. let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
  303. // check openings of phi3.cmE, phi3.cmW and cmT
  304. let (cmE_proof, cmW_proof, cmT_proof) = NIFS::<G1Affine>::open_commitments(
  305. &mut transcript_p,
  306. &pedersen_params,
  307. &fw3,
  308. &phi3,
  309. T,
  310. rT,
  311. &cmT,
  312. );
  313. let v = NIFS::<G1Affine>::verify_commitments(
  314. &mut transcript_v,
  315. &pedersen_params,
  316. phi3,
  317. cmT,
  318. cmE_proof,
  319. cmW_proof,
  320. cmT_proof,
  321. );
  322. }
  323. // fold i_1, i_2 instances into i_12, and then i_12, i_3 into i_123
  324. #[test]
  325. fn test_two_fold() {
  326. let mut rng = ark_std::test_rng();
  327. let pedersen_params = Pedersen::<G1Affine>::new_params(&mut rng, 6);
  328. let (r1cs, w1, w2, w3, x1, x2, x3) = gen_test_values(&mut rng);
  329. let u1: Fr = Fr::one();
  330. let u2: Fr = Fr::one();
  331. let T_12 = NIFS::<G1Affine>::comp_T(&r1cs, u1, u2, &w1, &w2);
  332. let rT_12: Fr = Fr::rand(&mut rng);
  333. let cmT_12 = Pedersen::commit(&pedersen_params, &T_12, &rT_12);
  334. let r = Fr::rand(&mut rng); // this would come from the transcript
  335. let fw1 = FWit::<G1Affine>::new(w1, T_12.len());
  336. let fw2 = FWit::<G1Affine>::new(w2, T_12.len());
  337. // fold witness
  338. let fw_12 = NIFS::<G1Affine>::fold_witness(r, &fw1, &fw2, &T_12, rT_12);
  339. // get committed instances
  340. let phi1 = fw1.commit(&pedersen_params); // wip
  341. let phi2 = fw2.commit(&pedersen_params);
  342. // fold instance
  343. let phi_12 = NIFS::<G1Affine>::fold_instance(r, &phi1, &phi2, &cmT_12);
  344. // NIFS.Verify:
  345. assert!(NIFS::<G1Affine>::verify(r, &phi1, &phi2, &phi_12, &cmT_12));
  346. //----
  347. // 2nd fold
  348. let fw3 = FWit::<G1Affine>::new(w3, r1cs.A.len());
  349. // compute cross terms
  350. let T_123 = NIFS::<G1Affine>::comp_T(&r1cs, phi_12.u, Fr::one(), &fw_12.W, &fw3.W);
  351. let rT_123: Fr = Fr::rand(&mut rng);
  352. let cmT_123 = Pedersen::commit(&pedersen_params, &T_123, &rT_123);
  353. // V sets rand challenge r
  354. let r = Fr::rand(&mut rng); // this would come from the transcript
  355. // fold witness
  356. let fw_123 = NIFS::<G1Affine>::fold_witness(r, &fw_12, &fw3, &T_123, rT_123);
  357. // get committed instances
  358. // phi_12 is already known for Verifier from folding phi1, phi2
  359. // rm: let phi_12 = fw_12.commit(&pedersen_params); // wip
  360. let phi3 = fw3.commit(&pedersen_params);
  361. // fold instance
  362. let phi_123 = NIFS::<G1Affine>::fold_instance(r, &phi_12, &phi3, &cmT_123);
  363. // NIFS.Verify:
  364. assert!(NIFS::<G1Affine>::verify(
  365. r, &phi_12, &phi3, &phi_123, &cmT_123
  366. ));
  367. // naive check that the folded witness satisfies the relaxed r1cs
  368. let Az = matrix_vector_product(&r1cs.A, &fw_123.W);
  369. let Bz = matrix_vector_product(&r1cs.B, &fw_123.W);
  370. let Cz = matrix_vector_product(&r1cs.C, &fw_123.W);
  371. assert_eq!(
  372. hadamard_product(Az, Bz),
  373. vec_add(&vector_elem_product(&Cz, &phi_123.u), &fw_123.E)
  374. );
  375. // check that folded commitments from folded instance (phi) are equal to folding the
  376. // use folded rE, rW to commit fw3
  377. let phi_123_expected = fw_123.commit(&pedersen_params);
  378. assert_eq!(phi_123_expected.cmE.0, phi_123.cmE.0);
  379. assert_eq!(phi_123_expected.cmW.0, phi_123.cmW.0);
  380. // init Prover's transcript
  381. let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
  382. // init Verifier's transcript
  383. let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
  384. // check openings of phi_123.cmE, phi_123.cmW and cmT_123
  385. let (cmE_proof, cmW_proof, cmT_proof) = NIFS::<G1Affine>::open_commitments(
  386. &mut transcript_p,
  387. &pedersen_params,
  388. &fw_123,
  389. &phi_123,
  390. T_123,
  391. rT_123,
  392. &cmT_123,
  393. );
  394. let v = NIFS::<G1Affine>::verify_commitments(
  395. &mut transcript_v,
  396. &pedersen_params,
  397. phi_123,
  398. cmT_123,
  399. cmE_proof,
  400. cmW_proof,
  401. cmT_proof,
  402. );
  403. assert!(v);
  404. }
  405. #[test]
  406. fn test_nifs_interface() {
  407. let mut rng = ark_std::test_rng();
  408. let pedersen_params = Pedersen::<G1Affine>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
  409. let (r1cs, w1, w2, _, x1, x2, _) = gen_test_values(&mut rng);
  410. let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
  411. let r = Fr::rand(&mut rng); // this would come from the transcript
  412. let fw1 = FWit::<G1Affine>::new(w1.clone(), A.len());
  413. let fw2 = FWit::<G1Affine>::new(w2.clone(), A.len());
  414. // init Prover's transcript
  415. let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
  416. // NIFS.P
  417. let (fw3, phi1, phi2, T, cmT) =
  418. NIFS::<G1Affine>::P(&mut transcript_p, &pedersen_params, r, &r1cs, fw1, fw2);
  419. // init Verifier's transcript
  420. let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new();
  421. // NIFS.V
  422. let phi3 = NIFS::<G1Affine>::V(r, &phi1, &phi2, &cmT);
  423. assert!(NIFS::<G1Affine>::verify(r, &phi1, &phi2, &phi3, &cmT));
  424. }
  425. }