arnaucube
arnaucube/protogalaxy-pocPublic Self-hosted repository
add test folding k instances and n iterations. also some polishing
arnaucube root@arnaucube.com
Mon, 31 Jul 2023 20:13:45 +0200
commit

89b480f18501ed7f45881ea705695be7dae5cbe3

parent

59001400357d007352e806ae358484d7550e6de3

2 files changed, 97 insertions(+), 23 deletions(-)

jump to
M README.md → README.md

@@ -15,7 +15,7 @@

## Details Implementation of ProtoGalaxy's scheme described in section 4 of the paper. -Current version implements the folding on prover & verifier and it works, but it is not optimized. +Current version implements the folding on prover & verifier and it works for k-to-1 instances and with multiple iterations, but it is not optimized. Next steps in terms of implementation include: F(X) O(n) construction following Claim 4.4, compute K(X) in O(kd log(kd)M + ndkC) as described in Claim 4.5, add tests folding in multiple iterations and also in a tree approach, add the decider and integrate with some existing R1CS tooling for the R1CS & witness generation. ### Usage

@@ -45,7 +45,6 @@ phi: phi_i,

betas: betas.clone(), e: Fr::zero(), }; - witnesses.push(witness_i); instances.push(instance_i); }

@@ -76,5 +75,6 @@

// check that the folded instance satisfies the relation assert!(check_instance(&r2cs, folded_instance, folded_witness)); +// now, the folded instance & witness can be folded again with n other instances. ``` (see the actual code for more details)
M src/protogalaxy.rs → src/protogalaxy.rs

@@ -97,15 +97,13 @@ // sanity check: check that the new randomized instnace (the original instance but with

// 'refreshed' randomness) satisfies the relation. assert!(check_instance( r1cs, - CommittedInstance { + &CommittedInstance { phi: instance.phi.clone(), betas: betas_star.clone(), e: F_alpha, }, - w.clone(), + &w, )); - - let gamma = transcript.get_challenge(); let mut ws: Vec<Vec<C::ScalarField>> = Vec::new(); ws.push(w.w.clone());

@@ -116,6 +114,7 @@ }

let k = vec_instances.len(); let H = GeneralEvaluationDomain::<C::ScalarField>::new(k + 1).unwrap(); + // WIP review t/d let EH = GeneralEvaluationDomain::<C::ScalarField>::new(t * k + 1).unwrap(); let L_X: Vec<DensePolynomial<C::ScalarField>> = lagrange_polys(H);

@@ -165,6 +164,10 @@ // TODO move division by Z_X to the prev loop

let (K_X, remainder) = G_L0e.divide_by_vanishing_poly(H).unwrap(); assert!(remainder.is_zero()); + transcript.add_vec(&K_X.coeffs); + + let gamma = transcript.get_challenge(); + let e_star = F_alpha * L_X[0].evaluate(&gamma) + Z_X.evaluate(&gamma) * K_X.evaluate(&gamma);

@@ -178,6 +181,10 @@ w_star = vec_add(

&w_star, &vec_scalar_mul(&vec_w[i].w, &L_X[i + 1].evaluate(&gamma)), ); + } + let mut r_w_star: C::ScalarField = w.r_w * L_X[0].evaluate(&gamma); + for i in 0..k { + r_w_star += vec_w[i].r_w * L_X[i + 1].evaluate(&gamma); } (

@@ -219,8 +226,8 @@ let alphas = all_powers(alpha, n);

// F(alpha) = e + \sum_t F_i * alpha^i let mut F_alpha = instance.e; - for (i, F_i) in F_coeffs.iter().enumerate() { - F_alpha += *F_i * alphas[i]; + for (i, F_i) in F_coeffs.iter().skip(1).enumerate() { + F_alpha += *F_i * alphas[i + 1]; } let betas_star: Vec<C::ScalarField> = instance

@@ -235,14 +242,16 @@ )

.map(|(beta_i, delta_i_alpha)| *beta_i + delta_i_alpha) .collect(); - let gamma = transcript.get_challenge(); - let k = vec_instances.len(); let H = GeneralEvaluationDomain::<C::ScalarField>::new(k + 1).unwrap(); let L_X: Vec<DensePolynomial<C::ScalarField>> = lagrange_polys(H); let Z_X: DensePolynomial<C::ScalarField> = H.vanishing_polynomial().into(); let K_X: DensePolynomial<C::ScalarField> = DensePolynomial::<C::ScalarField>::from_coefficients_vec(K_coeffs); + + transcript.add_vec(&K_X.coeffs); + + let gamma = transcript.get_challenge(); let e_star = F_alpha * L_X[0].evaluate(&gamma) + Z_X.evaluate(&gamma) * K_X.evaluate(&gamma);

@@ -325,8 +334,8 @@ }

fn check_instance<C: CurveGroup>( r1cs: &R1CS<C::ScalarField>, - instance: CommittedInstance<C>, - w: Witness<C>, + instance: &CommittedInstance<C>, + w: &Witness<C>, ) -> bool { let n = 2_u64.pow(instance.betas.len() as u32) as usize;

@@ -473,25 +482,24 @@ let f_w = eval_f(&r1cs, &z);

assert!(!is_zero_vec(&f_w)); } - #[test] - fn test_fold_native_case() { + // k represents the number of instances to be fold, appart from the running instance + fn prepare_inputs( + k: usize, + ) -> ( + Witness<G1Projective>, + CommittedInstance<G1Projective>, + Vec<Witness<G1Projective>>, + Vec<CommittedInstance<G1Projective>>, + ) { let mut rng = ark_std::test_rng(); let pedersen_params = Pedersen::<G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec - let poseidon_config = poseidon_test_config::<Fr>(); - let k = 6; - - let r1cs = get_test_r1cs::<Fr>(); let z = get_test_z::<Fr>(3); let mut zs: Vec<Vec<Fr>> = Vec::new(); for i in 0..k { let z_i = get_test_z::<Fr>(i + 4); zs.push(z_i); } - - // init Prover & Verifier's transcript - let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config); - let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config); let n = z.len(); let t = log2(n) as usize;

@@ -528,6 +536,20 @@ witnesses.push(witness_i);

instances.push(instance_i); } + (witness, instance, witnesses, instances) + } + + #[test] + fn test_fold_native_case() { + let k = 6; + let (witness, instance, witnesses, instances) = prepare_inputs(k); + let r1cs = get_test_r1cs::<Fr>(); + + // init Prover & Verifier's transcript + let poseidon_config = poseidon_test_config::<Fr>(); + let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config); + let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config); + let (F_coeffs, K_coeffs, folded_instance, folded_witness) = Folding::<G1Projective>::prover( &mut transcript_p, &r1cs,

@@ -554,6 +576,58 @@ assert_eq!(folded_instance.e, folded_instance_v.e);

assert!(!folded_instance.e.is_zero()); // check that the folded instance satisfies the relation - assert!(check_instance(&r1cs, folded_instance, folded_witness)); + assert!(check_instance(&r1cs, &folded_instance, &folded_witness)); + } + + #[test] + fn test_fold_various_iterations() { + let r1cs = get_test_r1cs::<Fr>(); + + // init Prover & Verifier's transcript + let poseidon_config = poseidon_test_config::<Fr>(); + let mut transcript_p = Transcript::<Fr, G1Projective>::new(&poseidon_config); + let mut transcript_v = Transcript::<Fr, G1Projective>::new(&poseidon_config); + + let (mut running_witness, mut running_instance, _, _) = prepare_inputs(0); + + // fold k instances on each of num_iters iterations + let k = 6; + let num_iters = 10; + for _ in 0..num_iters { + // generate the instances to be fold + let (_, _, witnesses, instances) = prepare_inputs(k); + + let (F_coeffs, K_coeffs, folded_instance, folded_witness) = + Folding::<G1Projective>::prover( + &mut transcript_p, + &r1cs, + running_instance.clone(), + running_witness.clone(), + instances.clone(), + witnesses, + ); + + // veriier + let folded_instance_v = Folding::<G1Projective>::verifier( + &mut transcript_v, + &r1cs, + running_instance.clone(), + instances, + F_coeffs, + K_coeffs, + ); + + // check that prover & verifier folded instances are the same values + assert_eq!(folded_instance.phi.0, folded_instance_v.phi.0); + assert_eq!(folded_instance.betas, folded_instance_v.betas); + assert_eq!(folded_instance.e, folded_instance_v.e); + assert!(!folded_instance.e.is_zero()); + + // check that the folded instance satisfies the relation + assert!(check_instance(&r1cs, &folded_instance, &folded_witness)); + + running_witness = folded_witness; + running_instance = folded_instance; + } } }