arnaucube
arnaucube/protogalaxy-pocPublic Self-hosted repository
add folding verifier impl, add last steps of folding prover (except G(X) & K(X))
arnaucube root@arnaucube.com
Fri, 28 Jul 2023 13:18:52 +0200
commit

2664dea6a76eb649a0a8345aa7fb2cb009be5bff

parent

097baa1aab0d0785fc2c58f946992abd66e7ee17

2 files changed, 199 insertions(+), 22 deletions(-)

jump to
M README.md → README.md

@@ -1,6 +1,6 @@

# protogalaxy-poc -Proof of concept implementation of ProtoGalaxy (https://eprint.iacr.org/2023/1106.pdf). +Proof of concept implementation of ProtoGalaxy (https://eprint.iacr.org/2023/1106.pdf) using [arkworks](https://github.com/arkworks-rs). > Do not use in production.
M src/protogalaxy.rs → src/protogalaxy.rs

@@ -2,11 +2,15 @@ use ark_crypto_primitives::sponge::Absorb;

use ark_ec::{CurveGroup, Group}; use ark_ff::fields::PrimeField; use ark_std::log2; -use ark_std::{One, Zero}; +use ark_std::{cfg_into_iter, One, Zero}; use std::marker::PhantomData; -use std::ops::Add; +use std::ops::{Add, Mul}; -use ark_poly::{univariate::SparsePolynomial, Polynomial}; +use ark_ff::{batch_inversion, FftField}; +use ark_poly::{ + univariate::{DensePolynomial, SparsePolynomial}, + DenseUVPolynomial, EvaluationDomain, Evaluations, GeneralEvaluationDomain, Polynomial, +}; use crate::pedersen::{Commitment, Params as PedersenParams, Pedersen, Proof as PedersenProof}; use crate::transcript::Transcript;

@@ -38,25 +42,28 @@ // WIP naming of functions

pub fn prover( tr: &mut Transcript<C::ScalarField, C>, pedersen_params: &PedersenParams<C>, - r1cs: R1CS<C::ScalarField>, + r1cs: &R1CS<C::ScalarField>, // running instance instance: CommittedInstance<C>, w: Witness<C>, // incomming instances vec_instances: Vec<CommittedInstance<C>>, vec_w: Vec<Witness<C>>, + ) -> ( + Vec<C::ScalarField>, + Vec<C::ScalarField>, + CommittedInstance<C>, + Witness<C>, ) { let t = instance.betas.len(); let n = r1cs.A[0].len(); + // TODO initialize transcript let delta = tr.get_challenge(); - let deltas = powers_of_beta(delta, t); let f_w = eval_f(&r1cs, &w.w); - dbg!(w.w.len()); - dbg!(f_w.len()); - dbg!(n); + // println!("is f(w) {:?}", f_w); // F(X) let mut F_X: SparsePolynomial<C::ScalarField> = SparsePolynomial::zero();

@@ -65,9 +72,12 @@ let lhs = pow_i_over_x::<C::ScalarField>(i, &instance.betas, &deltas);

let curr = &lhs * f_w[i]; F_X = F_X.add(curr); } - // TODO return F(X) + + let F_X_dense = DensePolynomial::from(F_X.clone()); + tr.add_vec(&F_X_dense.coeffs); let alpha = tr.get_challenge(); + // eval F(alpha) let F_alpha = F_X.evaluate(&alpha);

@@ -89,12 +99,122 @@ // 'refreshed' randomness) satisfies the relation.

assert!(check_instance( r1cs, CommittedInstance { - phi: instance.phi, - betas: betas_star, + phi: instance.phi.clone(), + betas: betas_star.clone(), e: F_alpha, }, w.clone(), )); + + let gamma = tr.get_challenge(); + + // TODO WIP compute G(X) & K(X) + let G_evals: Vec<C::ScalarField> = vec![C::ScalarField::zero(); n]; + let G_X: DensePolynomial<C::ScalarField> = + Evaluations::<C::ScalarField>::from_vec_and_domain(G_evals.clone(), H).interpolate(); + // dbg!(&G_X); + let (K_X, remainder) = G_X.divide_by_vanishing_poly(H).unwrap(); + // dbg!(&K_X); + assert!(remainder.is_zero()); + + let Z_X: DensePolynomial<C::ScalarField> = H.vanishing_polynomial().into(); + + let e_star = + F_alpha * L_X[0].evaluate(&gamma) + Z_X.evaluate(&gamma) * K_X.evaluate(&gamma); + + let mut phi_star: C = instance.phi.0 * L_X[0].evaluate(&gamma); + for i in 0..k { + phi_star += vec_instances[i].phi.0 * L_X[i].evaluate(&gamma); + } + let mut w_star: Vec<C::ScalarField> = vec_scalar_mul(&w.w, &L_X[0].evaluate(&gamma)); + for i in 0..k { + w_star = vec_add( + &w_star, + &vec_scalar_mul(&vec_w[i].w, &L_X[i].evaluate(&gamma)), + ); + } + + ( + F_X_dense.coeffs, + K_X.coeffs, + CommittedInstance { + betas: betas_star, + phi: Commitment(phi_star), + e: e_star, + }, + Witness { + w: w_star, + r_w: w.r_w, + }, + ) + } + + pub fn verifier( + tr: &mut Transcript<C::ScalarField, C>, + pedersen_params: &PedersenParams<C>, + r1cs: R1CS<C::ScalarField>, + // running instance + instance: CommittedInstance<C>, + // incomming instances + vec_instances: Vec<CommittedInstance<C>>, + // polys from P + F_coeffs: Vec<C::ScalarField>, + K_coeffs: Vec<C::ScalarField>, + ) -> CommittedInstance<C> { + let t = instance.betas.len(); + let n = r1cs.A[0].len(); + + let delta = tr.get_challenge(); + let deltas = powers_of_beta(delta, t); + + tr.add_vec(&F_coeffs); + + let alpha = tr.get_challenge(); + let alphas = all_powers(alpha, n); + + // dbg!(instance.e); + // dbg!(F_coeffs[0]); + + // 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]; + } + + let betas_star: Vec<C::ScalarField> = instance + .betas + .iter() + .zip( + deltas + .iter() + .map(|delta_i| alpha * delta_i) + .collect::<Vec<C::ScalarField>>(), + ) + .map(|(beta_i, delta_i_alpha)| *beta_i + delta_i_alpha) + .collect(); + + let gamma = tr.get_challenge(); + + let k = vec_instances.len(); + let domain_k = GeneralEvaluationDomain::<C::ScalarField>::new(k).unwrap(); + let L_X: Vec<DensePolynomial<C::ScalarField>> = lagrange_polys(domain_k); + let Z_X: DensePolynomial<C::ScalarField> = domain_k.vanishing_polynomial().into(); + let K_X: DensePolynomial<C::ScalarField> = + DensePolynomial::<C::ScalarField>::from_coefficients_vec(K_coeffs); + let e_star = + F_alpha * L_X[0].evaluate(&gamma) + Z_X.evaluate(&gamma) * K_X.evaluate(&gamma); + + let mut phi_star: C = instance.phi.0 * L_X[0].evaluate(&gamma); + for i in 0..k { + phi_star += vec_instances[i].phi.0 * L_X[i].evaluate(&gamma); + } + + // return the folded instance + CommittedInstance { + betas: betas_star, + phi: Commitment(phi_star), + e: e_star, + } } }

@@ -134,6 +254,19 @@ }

r } +// method from caulk: https://github.com/caulk-crypto/caulk/tree/8210b51fb8a9eef4335505d1695c44ddc7bf8170/src/multi/setup.rs#L300 +fn lagrange_polys<F: PrimeField>(domain_n: GeneralEvaluationDomain<F>) -> Vec<DensePolynomial<F>> { + let mut lagrange_polynomials: Vec<DensePolynomial<F>> = Vec::new(); + + for i in 0..domain_n.size() { + let evals: Vec<F> = cfg_into_iter!(0..domain_n.size()) + .map(|k| if k == i { F::one() } else { F::zero() }) + .collect(); + lagrange_polynomials.push(Evaluations::from_vec_and_domain(evals, domain_n).interpolate()); + } + lagrange_polynomials +} + #[derive(Clone, Debug)] pub struct R1CS<F: PrimeField> { pub A: Vec<Vec<F>>,

@@ -150,7 +283,7 @@ f_w

} fn check_instance<C: CurveGroup>( - r1cs: R1CS<C::ScalarField>, + r1cs: &R1CS<C::ScalarField>, instance: CommittedInstance<C>, w: Witness<C>, ) -> bool {

@@ -298,16 +431,24 @@ assert!(!is_zero_vec(&f_w));

} #[test] - fn test_fold_prover() { + fn test_fold() { 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 = 5; let r1cs = get_test_r1cs::<Fr>(); let mut 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's transcript + // 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;

@@ -318,24 +459,60 @@ let beta = Fr::rand(&mut rng);

let betas = powers_of_beta(beta, t); let witness = Witness::<G1Projective> { - w: z, // WIP + w: z.clone(), // WIP r_w: Fr::rand(&mut rng), }; let phi = Pedersen::<G1Projective>::commit(&pedersen_params, &witness.w, &witness.r_w); let instance = CommittedInstance::<G1Projective> { phi, - betas, + betas: betas.clone(), e: Fr::zero(), }; + // same for the other instances + let mut witnesses: Vec<Witness<G1Projective>> = Vec::new(); + let mut instances: Vec<CommittedInstance<G1Projective>> = Vec::new(); + for i in 0..k { + let witness_i = Witness::<G1Projective> { + w: zs[i].clone(), // WIP + r_w: Fr::rand(&mut rng), + }; + let phi_i = + Pedersen::<G1Projective>::commit(&pedersen_params, &witness_i.w, &witness_i.r_w); + let instance_i = CommittedInstance::<G1Projective> { + phi: phi_i, + betas: betas.clone(), + e: Fr::zero(), + }; + witnesses.push(witness_i); + instances.push(instance_i); + } - Folding::<G1Projective>::prover( + let (F_coeffs, K_coeffs, folded_instance, folded_witness) = Folding::<G1Projective>::prover( &mut transcript_p, &pedersen_params, - r1cs, + &r1cs, + instance.clone(), + witness, + instances.clone(), + witnesses, + ); + dbg!(&F_coeffs); + + // veriier + let folded_instance_v = Folding::<G1Projective>::verifier( + &mut transcript_v, + &pedersen_params, + r1cs.clone(), // TODO rm clone do borrow instance, - witness, - Vec::new(), - Vec::new(), + instances, + F_coeffs, + K_coeffs, ); + + 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!(check_instance(&r1cs, folded_instance, folded_witness)); } }