use ark_crypto_primitives::sponge::CryptographicSponge; use ark_ec::CurveGroup; use ark_poly::{univariate::DensePolynomial, EvaluationDomain, GeneralEvaluationDomain}; use ark_r1cs_std::{ alloc::AllocVar, fields::{fp::FpVar, FieldVar}, poly::polynomial::univariate::dense::DensePolynomialVar, }; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use super::{ folding::lagrange_polys, utils::{all_powers_var, betas_star_var, exponential_powers_var}, CommittedInstanceVar, }; use crate::{ folding::circuits::nonnative::affine::NonNativeAffineVar, transcript::TranscriptVar, utils::gadgets::VectorGadget, }; pub struct FoldingGadget {} impl FoldingGadget { pub fn fold_committed_instance( transcript: &mut impl TranscriptVar, // running instance instance: &CommittedInstanceVar, // incoming instances vec_instances: &[CommittedInstanceVar], // polys from P F_coeffs: Vec>, K_coeffs: Vec>, ) -> Result, SynthesisError> { let t = instance.betas.len(); let n = F_coeffs.len(); // absorb the committed instances transcript.absorb(instance)?; transcript.absorb(&vec_instances)?; let delta = transcript.get_challenge()?; let deltas = exponential_powers_var(delta, t); transcript.absorb(&F_coeffs)?; let alpha = transcript.get_challenge()?; let alphas = all_powers_var(alpha.clone(), n); // F(alpha) = e + \sum_t F_i * alpha^i let mut F_alpha = instance.e.clone(); for (i, F_i) in F_coeffs.iter().skip(1).enumerate() { F_alpha += F_i * &alphas[i + 1]; } let betas_star = betas_star_var(&instance.betas, &deltas, &alpha); let k = vec_instances.len(); let H = GeneralEvaluationDomain::new(k + 1).unwrap(); let L_X = lagrange_polys(H) .into_iter() .map(|poly| { DensePolynomialVar::from_coefficients_vec( poly.coeffs .into_iter() .map(FpVar::constant) .collect::>(), ) }) .collect::>(); let Z_X = DensePolynomialVar::from_coefficients_vec( DensePolynomial::from(H.vanishing_polynomial()) .coeffs .into_iter() .map(FpVar::constant) .collect::>(), ); let K_X = DensePolynomialVar { coeffs: K_coeffs }; transcript.absorb(&K_X.coeffs)?; let gamma = transcript.get_challenge()?; let L_X_evals = L_X .iter() .take(k + 1) .map(|L| L.evaluate(&gamma)) .collect::, _>>()?; let e_star = F_alpha * &L_X_evals[0] + Z_X.evaluate(&gamma)? * K_X.evaluate(&gamma)?; let mut u_star = &instance.u * &L_X_evals[0]; let mut x_star = instance.x.mul_scalar(&L_X_evals[0])?; for i in 0..k { u_star += &vec_instances[i].u * &L_X_evals[i + 1]; x_star = x_star.add(&vec_instances[i].x.mul_scalar(&L_X_evals[i + 1])?)?; } // return the folded instance Ok(CommittedInstanceVar { betas: betas_star, // phi will be computed in CycleFold phi: NonNativeAffineVar::new_constant(ConstraintSystemRef::None, C::zero())?, e: e_star, u: u_star, x: x_star, }) } } #[cfg(test)] mod tests { use ark_crypto_primitives::sponge::{ constraints::CryptographicSpongeVar, poseidon::{constraints::PoseidonSpongeVar, PoseidonSponge}, }; use ark_pallas::{Fr, Projective}; use ark_r1cs_std::R1CSVar; use ark_relations::r1cs::ConstraintSystem; use std::error::Error; use super::*; use crate::{ arith::r1cs::tests::get_test_r1cs, folding::protogalaxy::folding::{tests::prepare_inputs, Folding}, transcript::poseidon::poseidon_canonical_config, }; #[test] fn test_fold_gadget() -> Result<(), Box> { let k = 7; let (witness, instance, witnesses, instances) = prepare_inputs(k); let r1cs = get_test_r1cs::(); // init Prover & Verifier's transcript let poseidon_config = poseidon_canonical_config::(); let mut transcript_p = PoseidonSponge::new(&poseidon_config); let mut transcript_v = PoseidonSponge::new(&poseidon_config); let (_, _, F_coeffs, K_coeffs) = Folding::::prove( &mut transcript_p, &r1cs, &instance, &witness, &instances, &witnesses, )?; let folded_instance = Folding::::verify( &mut transcript_v, &r1cs, &instance, &instances, F_coeffs.clone(), K_coeffs.clone(), )?; let cs = ConstraintSystem::new_ref(); let mut transcript_var = PoseidonSpongeVar::new(cs.clone(), &poseidon_config); let instance_var = CommittedInstanceVar::new_witness(cs.clone(), || Ok(instance))?; let instances_var = Vec::new_witness(cs.clone(), || Ok(instances))?; let F_coeffs_var = Vec::new_witness(cs.clone(), || Ok(F_coeffs))?; let K_coeffs_var = Vec::new_witness(cs.clone(), || Ok(K_coeffs))?; let folded_instance_var = FoldingGadget::fold_committed_instance( &mut transcript_var, &instance_var, &instances_var, F_coeffs_var, K_coeffs_var, )?; assert_eq!(folded_instance.betas, folded_instance_var.betas.value()?); assert_eq!(folded_instance.e, folded_instance_var.e.value()?); assert_eq!(folded_instance.u, folded_instance_var.u.value()?); assert_eq!(folded_instance.x, folded_instance_var.x.value()?); assert!(cs.is_satisfied()?); Ok(()) } }