change C from AffineRepr to CurveGroup, use MNT4,6 for tests, other minor changes
@@ -15,7 +15,7 @@ ark-serialize = { version = "0.4.0", default-features = false, features = [ "derive" ] }
rand = { version = "0.8", features = [ "std", "std_rng" ] } merlin = { version = "3.0.0" } -ark-crypto-primitives = { version = "^0.4.0", default-features = true, features = [ "r1cs", "snark" ] } +ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = [ "r1cs", "snark"] } ark-r1cs-std = { version = "^0.4.0", default-features = false } ark-relations = { version = "^0.4.0", default-features = false } ark-snark = { version = "^0.4.0", default-features = false }@@ -24,4 +24,6 @@ tracing-subscriber = { version = "0.2" }
derivative = { version = "2.0", features = ["use_core"] } [dev-dependencies] -ark-bn254 = { version = "0.4.0", default-features = false, features=["curve"] } +ark-mnt4-298 = { version = "0.4.0", default-features = false, features=["curve", "r1cs"] } +ark-mnt6-298 = { version = "0.4.0", default-features = false, features=["r1cs"] } +ark-ed-on-mnt4-298 = { version = "0.4.0", default-features = false, features=["r1cs"] }
@@ -1,4 +1,5 @@
-use ark_ec::AffineRepr; +// use ark_ec::AffineRepr; +use ark_ec::CurveGroup; use ark_ff::fields::PrimeField; use ark_std::{ rand::{Rng, RngCore},@@ -18,22 +19,23 @@ pub C: Vec<Vec<F>>,
} // Phi: φ in the paper (later 𝖴), a folded instance -pub struct Phi<C: AffineRepr> { - cmE: Commitment<C>, - u: C::ScalarField, - cmW: Commitment<C>, - x: Vec<C::ScalarField>, +#[derive(Clone, Debug)] +pub struct Phi<C: CurveGroup> { + pub cmE: Commitment<C>, + pub u: C::ScalarField, + pub cmW: Commitment<C>, + pub x: C::ScalarField, } // FWit: Folded Witness -pub struct FWit<C: AffineRepr> { +pub struct FWit<C: CurveGroup> { E: Vec<C::ScalarField>, rE: C::ScalarField, W: Vec<C::ScalarField>, rW: C::ScalarField, } -impl<C: AffineRepr> FWit<C> { +impl<C: CurveGroup> FWit<C> { pub fn new(z: Vec<C::ScalarField>, e_len: usize) -> Self { FWit::<C> { E: vec![C::ScalarField::zero(); e_len],@@ -49,16 +51,16 @@ Phi {
cmE, u: C::ScalarField::one(), cmW, - x: self.W.clone(), + x: self.W[0].clone(), // TODO WIP review } } } -pub struct NIFS<C: AffineRepr> { +pub struct NIFS<C: CurveGroup> { _phantom: PhantomData<C>, } -impl<C: AffineRepr> NIFS<C> { +impl<C: CurveGroup> NIFS<C> { // comp_T: compute cross-terms T pub fn comp_T( r1cs: &R1CS<C::ScalarField>,@@ -123,13 +125,13 @@
let cmE = phi1.cmE.0 + cmT.0.mul(r) + phi2.cmE.0.mul(r2); let u = phi1.u + r * phi2.u; let cmW = phi1.cmW.0 + phi2.cmW.0.mul(r); - let x = vec_add(&phi1.x, &vector_elem_product(&phi2.x, &r)); - // let x = rlin(phi1.x, phi2.x, r); + // let x = vec_add(&phi1.x, &vector_elem_product(&phi2.x, &r)); + let x = phi1.x + r * phi2.x; Phi::<C> { - cmE: Commitment(cmE.into()), + cmE: Commitment(cmE), u, - cmW: Commitment(cmW.into()), + cmW: Commitment(cmW), x, } }@@ -174,16 +176,17 @@ phi3: &Phi<C>,
cmT: &Commitment<C>, ) -> bool { let r2 = r * r; - if phi3.cmE.0 != (phi1.cmE.0 + cmT.0.mul(r) + phi2.cmE.0.mul(r2)).into() { + if phi3.cmE.0 != (phi1.cmE.0 + cmT.0.mul(r) + phi2.cmE.0.mul(r2)) { return false; } if phi3.u != phi1.u + r * phi2.u { return false; } - if phi3.cmW.0 != (phi1.cmW.0 + phi2.cmW.0.mul(r)).into() { + if phi3.cmW.0 != (phi1.cmW.0 + phi2.cmW.0.mul(r)) { return false; } - if phi3.x != vec_add(&phi1.x, &vector_elem_product(&phi2.x, &r)) { + // if phi3.x != vec_add(&phi1.x, &vector_elem_product(&phi2.x, &r)) { + if phi3.x != phi1.x + r * phi2.x { return false; } true@@ -225,12 +228,53 @@ true
} } +// only for tests across different files +pub fn gen_test_values<R: Rng, F: PrimeField>( + rng: &mut R, +) -> (R1CS<F>, Vec<F>, Vec<F>, Vec<F>, Vec<F>, Vec<F>, Vec<F>) { + // R1CS for: x^3 + x + 5 = y (example from article + // https://www.vitalik.ca/general/2016/12/10/qap.html ) + let A = to_F_matrix::<F>(vec![ + vec![0, 1, 0, 0, 0, 0], + vec![0, 0, 0, 1, 0, 0], + vec![0, 1, 0, 0, 1, 0], + vec![5, 0, 0, 0, 0, 1], + ]); + let B = to_F_matrix::<F>(vec![ + vec![0, 1, 0, 0, 0, 0], + vec![0, 1, 0, 0, 0, 0], + vec![1, 0, 0, 0, 0, 0], + vec![1, 0, 0, 0, 0, 0], + ]); + let C = to_F_matrix::<F>(vec![ + vec![0, 0, 0, 1, 0, 0], + vec![0, 0, 0, 0, 1, 0], + vec![0, 0, 0, 0, 0, 1], + vec![0, 0, 1, 0, 0, 0], + ]); + // TODO in the future update this method to generate witness, and generate n witnesses + // instances, x: pub + let w1 = to_F_vec::<F>(vec![1, 3, 35, 9, 27, 30]); + let x1 = to_F_vec::<F>(vec![35]); + let w2 = to_F_vec::<F>(vec![1, 4, 73, 16, 64, 68]); + let x2 = to_F_vec::<F>(vec![73]); + let w3 = to_F_vec::<F>(vec![1, 5, 135, 25, 125, 130]); + let x3 = to_F_vec::<F>(vec![135]); + + let r1cs = R1CS::<F> { + A: A.clone(), + B: B.clone(), + C: C.clone(), + }; + (r1cs, w1, w2, w3, x1, x2, x3) +} + #[cfg(test)] mod tests { use super::*; use crate::pedersen::Pedersen; - use ark_bn254::{g1::G1Affine, Fr}; use ark_ec::CurveGroup; + use ark_mnt4_298::{Fr, G1Projective}; use ark_std::{ rand::{Rng, RngCore}, UniformRand,@@ -238,81 +282,33 @@ };
use ark_std::{One, Zero}; use std::ops::Mul; - fn gen_test_values<R: Rng>( - rng: &mut R, - ) -> ( - R1CS<Fr>, - Vec<Fr>, - Vec<Fr>, - Vec<Fr>, - Vec<Fr>, - Vec<Fr>, - Vec<Fr>, - ) { - // R1CS for: x^3 + x + 5 = y (example from article - // https://www.vitalik.ca/general/2016/12/10/qap.html ) - let A = to_F_matrix::<Fr>(vec![ - vec![0, 1, 0, 0, 0, 0], - vec![0, 0, 0, 1, 0, 0], - vec![0, 1, 0, 0, 1, 0], - vec![5, 0, 0, 0, 0, 1], - ]); - let B = to_F_matrix::<Fr>(vec![ - vec![0, 1, 0, 0, 0, 0], - vec![0, 1, 0, 0, 0, 0], - vec![1, 0, 0, 0, 0, 0], - vec![1, 0, 0, 0, 0, 0], - ]); - let C = to_F_matrix::<Fr>(vec![ - vec![0, 0, 0, 1, 0, 0], - vec![0, 0, 0, 0, 1, 0], - vec![0, 0, 0, 0, 0, 1], - vec![0, 0, 1, 0, 0, 0], - ]); - // TODO in the future update this method to generate witness, and generate n witnesses - // instances, x: pub - let w1 = to_F_vec::<Fr>(vec![1, 3, 35, 9, 27, 30]); - let x1 = to_F_vec::<Fr>(vec![35]); - let w2 = to_F_vec::<Fr>(vec![1, 4, 73, 16, 64, 68]); - let x2 = to_F_vec::<Fr>(vec![73]); - let w3 = to_F_vec::<Fr>(vec![1, 5, 135, 25, 125, 130]); - let x3 = to_F_vec::<Fr>(vec![135]); - - let r1cs = R1CS::<Fr> { - A: A.clone(), - B: B.clone(), - C: C.clone(), - }; - (r1cs, w1, w2, w3, x1, x2, x3) - } - // fold 2 instances into one #[test] fn test_one_fold() { let mut rng = ark_std::test_rng(); - let pedersen_params = Pedersen::<G1Affine>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec + let pedersen_params = Pedersen::<G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec let (r1cs, w1, w2, _, x1, x2, _) = gen_test_values(&mut rng); let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone()); let r = Fr::rand(&mut rng); // this would come from the transcript - let fw1 = FWit::<G1Affine>::new(w1.clone(), A.len()); - let fw2 = FWit::<G1Affine>::new(w2.clone(), A.len()); + let fw1 = FWit::<G1Projective>::new(w1.clone(), A.len()); + let fw2 = FWit::<G1Projective>::new(w2.clone(), A.len()); // get committed instances let phi1 = fw1.commit(&pedersen_params); // wip let phi2 = fw2.commit(&pedersen_params); - let T = NIFS::<G1Affine>::comp_T(&r1cs, phi1.u, phi2.u, &w1, &w2); + let T = NIFS::<G1Projective>::comp_T(&r1cs, phi1.u, phi2.u, &w1, &w2); let rT: Fr = Fr::rand(&mut rng); let cmT = Pedersen::commit(&pedersen_params, &T, &rT); // fold witness - let fw3 = NIFS::<G1Affine>::fold_witness(r, &fw1, &fw2, &T, rT); + let fw3 = NIFS::<G1Projective>::fold_witness(r, &fw1, &fw2, &T, rT); // fold instance - let phi3 = NIFS::<G1Affine>::fold_instance(r, &phi1, &phi2, &cmT); + let phi3 = NIFS::<G1Projective>::fold_instance(r, &phi1, &phi2, &cmT); // naive check that the folded witness satisfies the relaxed r1cs let Az = matrix_vector_product(&A, &fw3.W);@@ -330,7 +326,7 @@ assert_eq!(phi3_expected.cmE.0, phi3.cmE.0);
assert_eq!(phi3_expected.cmW.0, phi3.cmW.0); // NIFS.Verify: - assert!(NIFS::<G1Affine>::verify(r, &phi1, &phi2, &phi3, &cmT)); + assert!(NIFS::<G1Projective>::verify(r, &phi1, &phi2, &phi3, &cmT)); // init Prover's transcript let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();@@ -338,7 +334,7 @@ // init Verifier's transcript
let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new(); // check openings of phi3.cmE, phi3.cmW and cmT - let (cmE_proof, cmW_proof, cmT_proof) = NIFS::<G1Affine>::open_commitments( + let (cmE_proof, cmW_proof, cmT_proof) = NIFS::<G1Projective>::open_commitments( &mut transcript_p, &pedersen_params, &fw3,@@ -347,7 +343,7 @@ T,
rT, &cmT, ); - let v = NIFS::<G1Affine>::verify_commitments( + let v = NIFS::<G1Projective>::verify_commitments( &mut transcript_v, &pedersen_params, phi3,@@ -362,41 +358,43 @@ // fold i_1, i_2 instances into i_12, and then i_12, i_3 into i_123
#[test] fn test_two_fold() { let mut rng = ark_std::test_rng(); - let pedersen_params = Pedersen::<G1Affine>::new_params(&mut rng, 6); + let pedersen_params = Pedersen::<G1Projective>::new_params(&mut rng, 6); let (r1cs, w1, w2, w3, x1, x2, x3) = gen_test_values(&mut rng); let u1: Fr = Fr::one(); let u2: Fr = Fr::one(); - let T_12 = NIFS::<G1Affine>::comp_T(&r1cs, u1, u2, &w1, &w2); + let T_12 = NIFS::<G1Projective>::comp_T(&r1cs, u1, u2, &w1, &w2); let rT_12: Fr = Fr::rand(&mut rng); let cmT_12 = Pedersen::commit(&pedersen_params, &T_12, &rT_12); let r = Fr::rand(&mut rng); // this would come from the transcript - let fw1 = FWit::<G1Affine>::new(w1, T_12.len()); - let fw2 = FWit::<G1Affine>::new(w2, T_12.len()); + let fw1 = FWit::<G1Projective>::new(w1, T_12.len()); + let fw2 = FWit::<G1Projective>::new(w2, T_12.len()); // fold witness - let fw_12 = NIFS::<G1Affine>::fold_witness(r, &fw1, &fw2, &T_12, rT_12); + let fw_12 = NIFS::<G1Projective>::fold_witness(r, &fw1, &fw2, &T_12, rT_12); // get committed instances let phi1 = fw1.commit(&pedersen_params); // wip let phi2 = fw2.commit(&pedersen_params); // fold instance - let phi_12 = NIFS::<G1Affine>::fold_instance(r, &phi1, &phi2, &cmT_12); + let phi_12 = NIFS::<G1Projective>::fold_instance(r, &phi1, &phi2, &cmT_12); // NIFS.Verify: - assert!(NIFS::<G1Affine>::verify(r, &phi1, &phi2, &phi_12, &cmT_12)); + assert!(NIFS::<G1Projective>::verify( + r, &phi1, &phi2, &phi_12, &cmT_12 + )); //---- // 2nd fold - let fw3 = FWit::<G1Affine>::new(w3, r1cs.A.len()); + let fw3 = FWit::<G1Projective>::new(w3, r1cs.A.len()); // compute cross terms - let T_123 = NIFS::<G1Affine>::comp_T(&r1cs, phi_12.u, Fr::one(), &fw_12.W, &fw3.W); + let T_123 = NIFS::<G1Projective>::comp_T(&r1cs, phi_12.u, Fr::one(), &fw_12.W, &fw3.W); let rT_123: Fr = Fr::rand(&mut rng); let cmT_123 = Pedersen::commit(&pedersen_params, &T_123, &rT_123);@@ -404,7 +402,7 @@ // V sets rand challenge r
let r = Fr::rand(&mut rng); // this would come from the transcript // fold witness - let fw_123 = NIFS::<G1Affine>::fold_witness(r, &fw_12, &fw3, &T_123, rT_123); + let fw_123 = NIFS::<G1Projective>::fold_witness(r, &fw_12, &fw3, &T_123, rT_123); // get committed instances // phi_12 is already known for Verifier from folding phi1, phi2@@ -412,10 +410,10 @@ // rm: let phi_12 = fw_12.commit(&pedersen_params); // wip
let phi3 = fw3.commit(&pedersen_params); // fold instance - let phi_123 = NIFS::<G1Affine>::fold_instance(r, &phi_12, &phi3, &cmT_123); + let phi_123 = NIFS::<G1Projective>::fold_instance(r, &phi_12, &phi3, &cmT_123); // NIFS.Verify: - assert!(NIFS::<G1Affine>::verify( + assert!(NIFS::<G1Projective>::verify( r, &phi_12, &phi3, &phi_123, &cmT_123 ));@@ -440,7 +438,7 @@ // init Verifier's transcript
let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new(); // check openings of phi_123.cmE, phi_123.cmW and cmT_123 - let (cmE_proof, cmW_proof, cmT_proof) = NIFS::<G1Affine>::open_commitments( + let (cmE_proof, cmW_proof, cmT_proof) = NIFS::<G1Projective>::open_commitments( &mut transcript_p, &pedersen_params, &fw_123,@@ -449,7 +447,7 @@ T_123,
rT_123, &cmT_123, ); - let v = NIFS::<G1Affine>::verify_commitments( + let v = NIFS::<G1Projective>::verify_commitments( &mut transcript_v, &pedersen_params, phi_123,@@ -464,29 +462,29 @@
#[test] fn test_nifs_interface() { let mut rng = ark_std::test_rng(); - let pedersen_params = Pedersen::<G1Affine>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec + let pedersen_params = Pedersen::<G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec let (r1cs, w1, w2, _, x1, x2, _) = gen_test_values(&mut rng); let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone()); let r = Fr::rand(&mut rng); // this would come from the transcript - let fw1 = FWit::<G1Affine>::new(w1.clone(), A.len()); - let fw2 = FWit::<G1Affine>::new(w2.clone(), A.len()); + let fw1 = FWit::<G1Projective>::new(w1.clone(), A.len()); + let fw2 = FWit::<G1Projective>::new(w2.clone(), A.len()); // init Prover's transcript let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new(); // NIFS.P let (fw3, phi1, phi2, T, cmT) = - NIFS::<G1Affine>::P(&mut transcript_p, &pedersen_params, r, &r1cs, fw1, fw2); + NIFS::<G1Projective>::P(&mut transcript_p, &pedersen_params, r, &r1cs, fw1, fw2); // init Verifier's transcript let mut transcript_v: Transcript<Fr> = Transcript::<Fr>::new(); // NIFS.V - let phi3 = NIFS::<G1Affine>::V(r, &phi1, &phi2, &cmT); + let phi3 = NIFS::<G1Projective>::V(r, &phi1, &phi2, &cmT); - assert!(NIFS::<G1Affine>::verify(r, &phi1, &phi2, &phi3, &cmT)); + assert!(NIFS::<G1Projective>::verify(r, &phi1, &phi2, &phi3, &cmT)); } }
@@ -1,4 +1,5 @@
use ark_ec::AffineRepr; +use ark_ec::CurveGroup; use ark_std::{ rand::{Rng, RngCore}, UniformRand,@@ -8,35 +9,35 @@
use crate::transcript::Transcript; use crate::utils::{naive_msm, vec_add, vector_elem_product}; -pub struct Proof_elem<C: AffineRepr> { +pub struct Proof_elem<C: CurveGroup> { R: C, t1: C::ScalarField, t2: C::ScalarField, } -pub struct Proof<C: AffineRepr> { +pub struct Proof<C: CurveGroup> { R: C, u_: Vec<C::ScalarField>, ru_: C::ScalarField, } -pub struct Params<C: AffineRepr> { +pub struct Params<C: CurveGroup> { g: C, h: C, pub generators: Vec<C>, } -pub struct Pedersen<C: AffineRepr> { +pub struct Pedersen<C: CurveGroup> { _phantom: PhantomData<C>, } -impl<C: AffineRepr> Pedersen<C> { +impl<C: CurveGroup> Pedersen<C> { pub fn new_params<R: Rng>(rng: &mut R, max: usize) -> Params<C> { let h_scalar = C::ScalarField::rand(rng); let g: C = C::generator(); let generators: Vec<C> = vec![C::rand(rng); max]; let params: Params<C> = Params::<C> { g, - h: g.mul(h_scalar).into(), + h: g.mul(h_scalar), generators, }; params@@ -48,7 +49,7 @@ params: &Params<C>,
v: &C::ScalarField, ) -> CommitmentElem<C> { let r = C::ScalarField::rand(rng); - let cm: C = (params.g.mul(v) + params.h.mul(r)).into(); + let cm: C = (params.g.mul(v) + params.h.mul(r)); CommitmentElem::<C> { cm, r } } pub fn commit(@@ -57,7 +58,7 @@ v: &Vec<C::ScalarField>,
r: &C::ScalarField, // random value is provided, in order to be choosen by other parts of the protocol ) -> Commitment<C> { let cm = params.h.mul(r) + naive_msm(v, ¶ms.generators); - Commitment::<C>(cm.into()) + Commitment::<C>(cm) } pub fn prove_elem(@@ -70,7 +71,7 @@ ) -> Proof_elem<C> {
let r1 = transcript.get_challenge(b"r_1"); let r2 = transcript.get_challenge(b"r_2"); - let R: C = (params.g.mul(r1) + params.h.mul(r2)).into(); + let R: C = (params.g.mul(r1) + params.h.mul(r2)); transcript.add(b"cm", &cm); transcript.add(b"R", &R);@@ -91,7 +92,7 @@ ) -> Proof<C> {
let r1 = transcript.get_challenge(b"r_1"); let d = transcript.get_challenge_vec(b"d", v.len()); - let R: C = (params.h.mul(r1) + naive_msm(&d, ¶ms.generators)).into(); + let R: C = params.h.mul(r1) + naive_msm(&d, ¶ms.generators); transcript.add(b"cm", &cm.0); transcript.add(b"R", &R);@@ -145,13 +146,14 @@ true
} } -pub struct Commitment<C: AffineRepr>(pub C); +#[derive(Clone, Debug)] +pub struct Commitment<C: CurveGroup>(pub C); -pub struct CommitmentElem<C: AffineRepr> { +pub struct CommitmentElem<C: CurveGroup> { pub cm: C, pub r: C::ScalarField, } -impl<C: AffineRepr> CommitmentElem<C> { +impl<C: CurveGroup> CommitmentElem<C> { pub fn prove( &self, params: &Params<C>,@@ -165,8 +167,8 @@
#[cfg(test)] mod tests { use super::*; - use ark_bn254::{g1::G1Affine, Fr}; use ark_ec::CurveGroup; + use ark_mnt4_298::{Fr, G1Projective}; use std::ops::Mul; #[test]@@ -174,7 +176,7 @@ fn test_pedersen_single_element() {
let mut rng = ark_std::test_rng(); // setup params - let params = Pedersen::<G1Affine>::new_params( + let params = Pedersen::<G1Projective>::new_params( &mut rng, 0, /* 0, as here we don't use commit_vec */ );@@ -198,7 +200,7 @@ let mut rng = ark_std::test_rng();
const n: usize = 10; // setup params - let params = Pedersen::<G1Affine>::new_params(&mut rng, n); + let params = Pedersen::<G1Projective>::new_params(&mut rng, n); // init Prover's transcript let mut transcript_p: Transcript<Fr> = Transcript::<Fr>::new();
@@ -1,4 +1,5 @@
use ark_ec::AffineRepr; +use ark_ec::CurveGroup; use ark_ff::fields::PrimeField; use core::ops::{Add, Sub}; use std::fmt;@@ -36,14 +37,14 @@ // pub fn rlin<F: PrimeField>(a: Vec<F>, b: Vec<F>, r: F) -> Vec<F> {
// vec_add(a, vector_elem_product(&b, &r)) // WIP probably group loops // } -pub fn naive_msm<C: AffineRepr>(s: &Vec<C::ScalarField>, p: &Vec<C>) -> C { +pub fn naive_msm<C: CurveGroup>(s: &Vec<C::ScalarField>, p: &Vec<C>) -> C { // TODO check lengths, or at least check s.len()>= p.len() let mut r = p[0].mul(s[0]); for i in 1..s.len() { r = p[i].mul(s[i]); } - r.into() + r } pub fn vec_add<F: PrimeField>(a: &Vec<F>, b: &Vec<F>) -> Vec<F> {@@ -124,8 +125,8 @@
#[cfg(test)] mod tests { use super::*; - use ark_bn254::{g1::G1Affine, Fr}; use ark_ec::CurveGroup; + use ark_mnt4_298::{g1::G1Affine, Fr}; use ark_std::{One, Zero}; use std::ops::Mul;