diff --git a/kimchi/src/circuits/expr.rs b/kimchi/src/circuits/expr.rs index bec4537289..a2c7c10239 100644 --- a/kimchi/src/circuits/expr.rs +++ b/kimchi/src/circuits/expr.rs @@ -1890,16 +1890,18 @@ impl /// respective values using `evaluate_constants` and will after evaluate the /// monomials with the corresponding column values using the method /// `evaluations`. - /// This function always evaluate on D8 - pub fn evaluations_d8< + /// This function evaluates on a user defined domain. + pub fn evaluations_with_domain< 'a, Challenge: Index, Environment: ColumnEnvironment<'a, F, ChallengeTerm, Challenge, Column = Column>, >( &self, env: &Environment, + domain: Domain, ) -> Evaluations> { - self.evaluate_constants(env).evaluations_d8(env) + self.evaluate_constants(env) + .evaluations_with_domain(env, domain) } } @@ -1967,7 +1969,7 @@ impl Expr { /// Helper function to compute the polynomial corresponding /// to this expression, in evaluation form. - /// Compute the smallest domain or uses D8 depending on compute_domain. + /// Compute the smallest domain or uses the given one depending on domain_opt. fn evaluations_conditional< 'a, ChallengeTerm, @@ -1976,13 +1978,12 @@ impl Expr { >( &self, env: &Environment, - compute_domain: bool, + domain_opt: Option, ) -> Evaluations> { let mut cache = HashMap::new(); - let d = if compute_domain { - self.get_domain(env) - } else { - Domain::D8 + let d = match domain_opt { + None => self.get_domain(env), + Some(d) => d, }; let evals = match self.evaluations_helper(&mut cache, d, env) { Either::Left(x) => x, @@ -2027,6 +2028,8 @@ impl Expr { let deg = self.degree(d1_size, env.get_constants().zk_rows); if deg <= d1_size { Domain::D1 + } else if deg <= 2 * d1_size { + Domain::D2 } else if deg <= 4 * d1_size { Domain::D4 } else if deg <= 8 * d1_size { @@ -2048,13 +2051,13 @@ impl Expr { &self, env: &Environment, ) -> Evaluations> { - self.evaluations_conditional(env, true) + self.evaluations_conditional(env, None) } /// Compute the polynomial corresponding /// to this expression, in evaluation form. - /// Uses D8, regardless of the degree of the expression. - pub fn evaluations_d8< + /// Uses user defined given domain, regardless of the degree of the expression. + pub fn evaluations_with_domain< 'a, ChallengeTerm, Challenge: Index, @@ -2062,8 +2065,9 @@ impl Expr { >( &self, env: &Environment, + domain: Domain, ) -> Evaluations> { - self.evaluations_conditional(env, false) + self.evaluations_conditional(env, Some(domain)) } fn evaluations_helper< diff --git a/kimchi/src/prover.rs b/kimchi/src/prover.rs index 711e2cacbf..ed0358af46 100644 --- a/kimchi/src/prover.rs +++ b/kimchi/src/prover.rs @@ -773,6 +773,11 @@ where (perm, bnd) }; + let mut t2 = Evaluations::from_vec_and_domain( + vec![G::ScalarField::zero(); index.cs.domain.d2.size.try_into().unwrap()], + index.cs.domain.d2, + ); + { use crate::circuits::argument::DynArgument; @@ -820,7 +825,9 @@ where { let constraint = gate.combined_constraints(&all_alphas, &mut cache); let eval = constraint.evaluations(&env); - if eval.domain().size == t4.domain().size { + if eval.domain().size == t2.domain().size { + t2 += &eval; + } else if eval.domain().size == t4.domain().size { t4 += &eval; } else if eval.domain().size == t8.domain().size { t8 += &eval; @@ -848,7 +855,9 @@ where let mut eval = constraint.evaluations(&env); eval.evals.par_iter_mut().for_each(|x| *x *= alpha_pow); - if eval.domain().size == t4.domain().size { + if eval.domain().size == t2.domain().size { + t2 += &eval; + } else if eval.domain().size == t4.domain().size { t4 += &eval; } else if eval.domain().size == t8.domain().size { t8 += &eval; @@ -864,7 +873,7 @@ where } // public polynomial - let mut f = t4.interpolate() + t8.interpolate(); + let mut f = t2.interpolate() + t4.interpolate() + t8.interpolate(); f += &public_poly; // divide contributions with vanishing polynomial diff --git a/o1vm/src/pickles/lookup_columns.rs b/o1vm/src/pickles/lookup_columns.rs index 8171c4d397..f601ab14da 100644 --- a/o1vm/src/pickles/lookup_columns.rs +++ b/o1vm/src/pickles/lookup_columns.rs @@ -139,6 +139,7 @@ pub enum LookupChallengeTerm { Alpha, } +#[derive(Clone)] pub struct LookupChallenges { pub beta: F, pub gamma: F, @@ -222,9 +223,9 @@ impl<'a, F: FftField> ColumnEnvironment<'a, F, LookupChallengeTerm, LookupChalle Domain::D8 => self.domain.d8, } } - // TODO verify this + fn column_domain(&self, _col: &Self::Column) -> Domain { - Domain::D8 + Domain::D4 } // We do not have constants here fn get_constants(&self) -> &Constants { diff --git a/o1vm/src/pickles/lookup_prover.rs b/o1vm/src/pickles/lookup_prover.rs index a39b6fb250..068cebfa6f 100644 --- a/o1vm/src/pickles/lookup_prover.rs +++ b/o1vm/src/pickles/lookup_prover.rs @@ -4,7 +4,7 @@ use ark_ff::{One, PrimeField, Zero}; use ark_poly::{univariate::DensePolynomial, Evaluations, Polynomial, Radix2EvaluationDomain}; use kimchi::{ circuits::{ - domains::EvaluationDomains, + domains::{Domain, EvaluationDomains}, expr::{l0_1, Constants}, }, curve::KimchiCurve, @@ -130,8 +130,6 @@ where RNG: RngCore + CryptoRng, { let LookupProverState { inverses, acc } = state; - // TODO check that - let num_chunk = 8; let LookupProofInput { wires, arity: _, @@ -146,6 +144,8 @@ where acc, dynamicselectors, }; + + ////// Commit and squeeze the constraint combiner alpha //interpolating let interpolate_col = |evals: Vec| { Evaluations::>::from_vec_and_domain( @@ -173,12 +173,6 @@ where .collect(), }; - // eval on d8 - // TODO: check the degree - // TODO: avoid cloning - let columns_eval_d8 = columns_poly - .clone() - .map(|poly| poly.evaluate_over_domain_by_ref(domain.d8)); // abosrbing commit // TODO don't absorb the wires which already have been // TODO avoid cloning @@ -190,14 +184,22 @@ where // Constraints combiner let alpha: G::ScalarField = fq_sponge.challenge(); + ////// Compute the quotient polynomial T + + // eval on d4 + // TODO: avoid cloning + let columns_eval_d4 = columns_poly + .clone() + .map(|poly| poly.evaluate_over_domain_by_ref(domain.d4)); let challenges = LookupChallenges { alpha, beta: beta_challenge, gamma: gamma_challenge, }; + let eval_env = LookupEvalEnvironment { challenges, - columns: &columns_eval_d8, + columns: &columns_eval_d4, domain: &domain, constants: Constants { endo_coefficient: G::ScalarField::zero(), @@ -207,16 +209,21 @@ where l0_1: l0_1(domain.d1), }; + let (t_numerator_evaluation, _) = constraints.iter().fold( ( Evaluations::from_vec_and_domain( - vec![G::ScalarField::zero(); domain.d8.size as usize], - domain.d8, + vec![G::ScalarField::zero(); domain.d4.size as usize], + domain.d4, ), G::ScalarField::one(), ), + // TODO use horner |(mut acc, alpha_pow), cst| { - acc.add_assign(&cst.evaluations_d8(&eval_env).mul(alpha_pow)); + acc.add_assign( + &cst.evaluations_with_domain(&eval_env, Domain::D4) + .mul(alpha_pow), + ); (acc, alpha_pow * alpha) }, ); @@ -225,11 +232,11 @@ where .divide_by_vanishing_poly(domain.d1) .unwrap(); assert!(rem.is_zero()); - let t_commitment = srs.commit_non_hiding( - // TODO: change the nb of chunks later - // For now we use this because the constraints null - &t, num_chunk, - ); + + //////// Squeeze the evaluation point zeta + // The constraint is of degree 3 + let num_chunk = 2; + let t_commitment = srs.commit_non_hiding(&t, num_chunk); // TODO avoid cloning let commitments = AllColumns { cols: columns_com, @@ -237,8 +244,6 @@ where }; // Absorb t absorb_commitment(&mut fq_sponge, &t_commitment); - // evaluate and prepare for IPA proof - // TODO check num_chunks and srs length let t_chunks = t.to_chunked_polynomial(num_chunk, srs.size()); // squeeze zeta // TODO: understand why we use the endo here and for IPA , @@ -247,6 +252,8 @@ where let zeta_chal = ScalarChallenge(fq_sponge.challenge()); let zeta: G::ScalarField = zeta_chal.to_field(endo_r); let zeta_omega = zeta * domain.d1.group_gen; + + /////// evaluate create the IPA proof let eval = |x, cols_poly: ColumnEnv>, diff --git a/o1vm/src/pickles/main.rs b/o1vm/src/pickles/main.rs index 8d8fc14df2..f3daab7dfb 100644 --- a/o1vm/src/pickles/main.rs +++ b/o1vm/src/pickles/main.rs @@ -188,7 +188,9 @@ pub fn cannon_main(args: cli::cannon::RunArgs) { instruction_set = HashSet::new(); } } - if curr_proof_inputs.evaluations.instruction_counter.len() < domain_size { + if curr_proof_inputs.evaluations.instruction_counter.len() < domain_size + && !curr_proof_inputs.evaluations.instruction_counter.is_empty() + { debug!("Padding witness for proof generation"); pad(&mips_wit_env, &mut curr_proof_inputs, &mut rng); prove_and_verify( diff --git a/o1vm/src/pickles/multiplicities_columns.rs b/o1vm/src/pickles/multiplicities_columns.rs index f453aed41f..d28bda91ae 100644 --- a/o1vm/src/pickles/multiplicities_columns.rs +++ b/o1vm/src/pickles/multiplicities_columns.rs @@ -227,9 +227,9 @@ impl<'a, F: FftField> Domain::D8 => self.domain.d8, } } - // TODO verify this + fn column_domain(&self, _col: &Self::Column) -> Domain { - Domain::D8 + Domain::D2 } // We do not have constants here fn get_constants(&self) -> &Constants { @@ -331,7 +331,7 @@ pub fn get_multiplicities_constraints( domain: &Radix2EvaluationDomain, acc_init: F, acc_final: F, -) -> Vec> { +) -> EMultiplicities { // Constraint the inverse wires let mut res = inverses_constraint(); @@ -378,5 +378,7 @@ pub fn get_multiplicities_constraints( res.push(acc_recursion); res.push(acc_init); res.push(acc_final); - res + + let alphas = 0..(res.len() as u32); + Expr::combine_constraints(alphas, res) } diff --git a/o1vm/src/pickles/multiplicities_prover.rs b/o1vm/src/pickles/multiplicities_prover.rs index 3c48fcc4e3..2bc0c524ba 100644 --- a/o1vm/src/pickles/multiplicities_prover.rs +++ b/o1vm/src/pickles/multiplicities_prover.rs @@ -1,5 +1,5 @@ use crate::{lookups::FixedLookup, pickles::multiplicities_columns::*}; -use ark_ff::{batch_inversion, One, PrimeField, Zero}; +use ark_ff::{batch_inversion, PrimeField, Zero}; use ark_poly::{univariate::DensePolynomial, Evaluations, Polynomial, Radix2EvaluationDomain}; use kimchi::{ circuits::{ @@ -13,7 +13,6 @@ use kimchi::{ use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; use o1_utils::ExtendedDensePolynomial; use poly_commitment::{commitment::absorb_commitment, ipa::SRS, OpenProof, SRS as _}; -use std::ops::{AddAssign, Mul}; use poly_commitment::{ipa::OpeningProof, utils::DensePolynomialOrEvaluations, PolyComm}; use rand::{CryptoRng, RngCore}; @@ -113,7 +112,7 @@ pub fn multiplicities_prove_snd_part< srs: &SRS, domain: EvaluationDomains, mut fq_sponge: EFqSponge, - constraints: &[EMultiplicities], + constraint: &EMultiplicities, rng: &mut RNG, state: MultiplicitiesProverState, ) -> Proof @@ -123,8 +122,6 @@ where { let MultiplicitiesProverState { inverses, acc } = state; - // TODO change that - let num_chunk = 8; let MultiplicitiesProofInput { fixedlookup, fixedlookup_transposed: _, @@ -141,6 +138,7 @@ where multiplicities, }; + ///// Commit to columns and squeeze the constraint combiner alpha // Interpolating let interpolate_col = |evals: Vec| { Evaluations::>::from_vec_and_domain( @@ -149,20 +147,12 @@ where .interpolate() }; let columns_poly = columns.map(interpolate_col); - // TODO avoid cloning // TODO don't commit to fixedlookup let columns_com = columns_poly.clone().map(|poly| { let PolyComm { chunks } = srs.commit_non_hiding(&poly, 1); chunks[0] }); - - // eval on d8 - // TODO: avoid cloning - // TODO don't eval fixedlookup - let columns_eval_d8 = columns_poly - .clone() - .map(|poly| poly.evaluate_over_domain_by_ref(domain.d8)); // absorbing commit // TODO don't absorb the wires which already have been // TODO avoid cloning @@ -170,10 +160,16 @@ where .clone() .into_iter() .for_each(|com| absorb_commitment(&mut fq_sponge, &PolyComm { chunks: vec![com] })); - // Constraints combiner let alpha: G::ScalarField = fq_sponge.challenge(); + ////// Compute the quotient polynomial T + // eval on d2 + // TODO: avoid cloning + // TODO don't eval fixedlookup + let columns_eval_d2 = columns_poly + .clone() + .map(|poly| poly.evaluate_over_domain_by_ref(domain.d2)); let challenges = MultiplicitiesChallenges { alpha, beta: beta_challenge, @@ -181,38 +177,25 @@ where }; let eval_env = MultiplicitiesEvalEnvironment { challenges, - columns: &columns_eval_d8, + columns: &columns_eval_d2, domain: &domain, constants: Constants { endo_coefficient: G::ScalarField::zero(), mds: &G::sponge_params().mds, zk_rows: 0, }, - l0_1: l0_1(domain.d1), }; - let (t_numerator_evaluation, _) = constraints.iter().fold( - ( - Evaluations::from_vec_and_domain( - vec![G::ScalarField::zero(); domain.d8.size as usize], - domain.d8, - ), - G::ScalarField::one(), - ), - |(mut acc, alpha_pow), cst| { - acc.add_assign(&cst.evaluations_d8(&eval_env).mul(alpha_pow)); - (acc, alpha_pow * alpha) - }, - ); + let t_numerator_evaluation = constraint.evaluations(&eval_env); let t_numerator_poly = t_numerator_evaluation.interpolate(); let (t, rem) = t_numerator_poly .divide_by_vanishing_poly(domain.d1) .unwrap(); assert!(rem.is_zero()); - let t_commitment = srs.commit_non_hiding( - // TODO: change the nb of chunks later - &t, num_chunk, - ); + + ///// Commit to T and squeeze the evaluation challenge zeta + let num_chunk = 1; + let t_commitment = srs.commit_non_hiding(&t, num_chunk); // TODO avoid cloning let commitments = AllColumns { cols: columns_com, @@ -221,7 +204,6 @@ where // Absorb t absorb_commitment(&mut fq_sponge, &t_commitment); // evaluate and prepare for IPA proof - // TODO check num_chunks and srs length let t_chunks = t.to_chunked_polynomial(num_chunk, srs.size()); // squeeze zeta // TODO: understand why we use the endo here and for IPA , @@ -230,6 +212,8 @@ where let zeta_chal = ScalarChallenge(fq_sponge.challenge()); let zeta: G::ScalarField = zeta_chal.to_field(endo_r); let zeta_omega = zeta * domain.d1.group_gen; + + ///// Evaluate and create the IPA proof let eval = |x, cols_poly: ColumnEnv>, diff --git a/o1vm/src/pickles/multiplicities_verifier.rs b/o1vm/src/pickles/multiplicities_verifier.rs index 500fa931af..c34ceb9001 100644 --- a/o1vm/src/pickles/multiplicities_verifier.rs +++ b/o1vm/src/pickles/multiplicities_verifier.rs @@ -3,7 +3,7 @@ use ark_ff::{Field, One, PrimeField, Zero}; use kimchi::{ circuits::{ domains::EvaluationDomains, - expr::{Constants, Expr, PolishToken}, + expr::{Constants, PolishToken}, }, curve::KimchiCurve, groupmap::GroupMap, @@ -25,7 +25,7 @@ pub fn multiplicities_verify< // input dependant of main proto beta_challenge: G::ScalarField, gamma_challenge: G::ScalarField, - constraints: Vec>, + constraint: EMultiplicities, mut fq_sponge: EFqSponge, // fixed input // TODO: we don't need the whole domain @@ -37,8 +37,6 @@ pub fn multiplicities_verify< where G::BaseField: PrimeField, { - let constraint = Expr::combine_constraints(0..(constraints.len() as u32), constraints.to_vec()); - let Proof { commitments, evaluations, diff --git a/o1vm/src/pickles/prover.rs b/o1vm/src/pickles/prover.rs index 1fedb1e4bf..8ee8511fe6 100644 --- a/o1vm/src/pickles/prover.rs +++ b/o1vm/src/pickles/prover.rs @@ -5,7 +5,7 @@ use ark_poly::{univariate::DensePolynomial, Evaluations, Polynomial, Radix2Evalu use kimchi::{ circuits::{ berkeley_columns::BerkeleyChallenges, - domains::EvaluationDomains, + domains::{Domain, EvaluationDomains}, expr::{l0_1, Constants}, }, curve::KimchiCurve, @@ -291,7 +291,10 @@ where G::ScalarField::one(), ), |(mut acc, alpha_pow), cst| { - acc.add_assign(&cst.evaluations_d8(&column_env).mul(alpha_pow)); + acc.add_assign( + &cst.evaluations_with_domain(&column_env, Domain::D8) + .mul(alpha_pow), + ); (acc, alpha_pow * alpha) }, );