diff --git a/msm/src/logup.rs b/msm/src/logup.rs index 19ba65a191..c0dedb57e9 100644 --- a/msm/src/logup.rs +++ b/msm/src/logup.rs @@ -275,13 +275,13 @@ pub struct LogupWitness { #[derive(Debug, Clone)] pub struct LookupProof { /// The multiplicity polynomials - pub(crate) m: BTreeMap>, + pub m: BTreeMap>, /// The polynomial keeping the sum of each row - pub(crate) h: BTreeMap>, + pub h: BTreeMap>, /// The "running-sum" over the rows, coined `φ` - pub(crate) sum: T, + pub sum: T, /// All fixed lookup tables values, indexed by their ID - pub(crate) fixed_tables: BTreeMap, + pub fixed_tables: BTreeMap, } /// Iterator implementation to abstract the content of the structure. @@ -512,6 +512,7 @@ pub mod prover { } /// Represents the environment for the logup argument. + #[derive(Clone)] pub struct Env { /// The polynomial of the multiplicities, indexed by the table ID. pub lookup_counters_poly_d1: BTreeMap>>, diff --git a/o1vm/src/pickles/column_env.rs b/o1vm/src/pickles/column_env.rs index c66f68160f..b10b15b723 100644 --- a/o1vm/src/pickles/column_env.rs +++ b/o1vm/src/pickles/column_env.rs @@ -1,15 +1,19 @@ use ark_ff::FftField; use ark_poly::{Evaluations, Radix2EvaluationDomain}; -use kimchi_msm::columns::Column; +use kimchi_msm::{columns::Column, logup::prover::QuotientPolynomialEnvironment, LookupTableID}; +use poly_commitment::PolyComm; use crate::{ interpreters::mips::{column::N_MIPS_SEL_COLS, witness::SCRATCH_SIZE}, pickles::proof::WitnessColumns, }; -use kimchi::circuits::{ - berkeley_columns::{BerkeleyChallengeTerm, BerkeleyChallenges}, - domains::{Domain, EvaluationDomains}, - expr::{ColumnEnvironment as TColumnEnvironment, Constants}, +use kimchi::{ + circuits::{ + berkeley_columns::{BerkeleyChallengeTerm, BerkeleyChallenges}, + domains::{Domain, EvaluationDomains}, + expr::{ColumnEnvironment as TColumnEnvironment, Constants}, + }, + curve::KimchiCurve, }; type Evals = Evaluations>; @@ -18,10 +22,10 @@ type Evals = Evaluations>; /// required to evaluate an expression as a polynomial. /// /// All are evaluations. -pub struct ColumnEnvironment<'a, F: FftField> { +pub struct ColumnEnvironment<'a, F: FftField, G: KimchiCurve, ID: LookupTableID> { /// The witness column polynomials. Includes relation columns and dynamic /// selector columns. - pub witness: &'a WitnessColumns, [Evals; N_MIPS_SEL_COLS]>, + pub witness: &'a WitnessColumns, G, [Evals; N_MIPS_SEL_COLS], ID>, /// The value `prod_{j != 1} (1 - ω^j)`, used for efficiently /// computing the evaluations of the unnormalized Lagrange basis /// polynomials. @@ -33,6 +37,9 @@ pub struct ColumnEnvironment<'a, F: FftField> { pub challenges: BerkeleyChallenges, /// The domains used in the PLONK argument. pub domain: EvaluationDomains, + + /// Lookup specific polynomials + pub lookup: Option>, } pub fn get_all_columns() -> Vec { @@ -46,47 +53,142 @@ pub fn get_all_columns() -> Vec { cols } -impl WitnessColumns { - pub fn get_column(&self, col: &Column) -> Option<&G> { - match *col { - Column::Relation(i) => { - if i < SCRATCH_SIZE { - let res = &self.scratch[i]; - Some(res) - } else if i == SCRATCH_SIZE { - let res = &self.instruction_counter; - Some(res) - } else if i == SCRATCH_SIZE + 1 { - let res = &self.error; - Some(res) - } else { - panic!("We should not have that many relation columns"); - } +pub fn get_column_comm<'a, G: KimchiCurve, ID: LookupTableID>( + env: &'a WitnessColumns, G, [PolyComm; N_MIPS_SEL_COLS], ID>, + col: &Column, +) -> Option<&'a PolyComm> { + match *col { + Column::Relation(i) => { + if i < SCRATCH_SIZE { + let res = &env.scratch[i]; + Some(res) + } else if i == SCRATCH_SIZE { + let res = &env.instruction_counter; + Some(res) + } else if i == SCRATCH_SIZE + 1 { + let res = &env.error; + Some(res) + } else { + panic!("We should not have that many relation columns"); } - Column::DynamicSelector(i) => { - assert!( - i < N_MIPS_SEL_COLS, - "We do not have that many dynamic selector columns" - ); - let res = &self.selector[i]; + } + Column::DynamicSelector(i) => { + assert!( + i < N_MIPS_SEL_COLS, + "We do not have that many dynamic selector columns" + ); + let res = &env.selector[i]; + Some(res) + } + Column::LookupPartialSum((table_id, i)) => { + if let Some(ref lookup) = env.lookup_env { + let table_id = ID::from_u32(table_id); + Some(&lookup.lookup_terms_comms_d1[&table_id][i]) + } else { + panic!("No lookup provided") + } + } + Column::LookupAggregation => { + if let Some(ref lookup) = env.lookup_env { + Some(&lookup.lookup_aggregation_comm_d1) + } else { + panic!("No lookup provided") + } + } + Column::LookupMultiplicity((table_id, i)) => { + if let Some(ref lookup) = env.lookup_env { + Some(&lookup.lookup_counters_comm_d1[&ID::from_u32(table_id)][i]) + } else { + panic!("No lookup provided") + } + } + Column::LookupFixedTable(table_id) => { + if let Some(ref lookup) = env.lookup_env { + Some(&lookup.fixed_lookup_tables_comms_d1[&ID::from_u32(table_id)]) + } else { + panic!("No lookup provided") + } + } + _ => { + panic!("We should not have any other type of columns") + } + } +} + +pub fn get_column_eval<'a, G: KimchiCurve, ID: LookupTableID>( + env: &'a WitnessColumns, G, [Evals; N_MIPS_SEL_COLS], ID>, + col: &Column, +) -> Option<&'a Evals> { + match *col { + Column::Relation(i) => { + if i < SCRATCH_SIZE { + let res = &env.scratch[i]; + Some(res) + } else if i == SCRATCH_SIZE { + let res = &env.instruction_counter; Some(res) + } else if i == SCRATCH_SIZE + 1 { + let res = &env.error; + Some(res) + } else { + panic!("We should not have that many relation columns"); + } + } + Column::DynamicSelector(i) => { + assert!( + i < N_MIPS_SEL_COLS, + "We do not have that many dynamic selector columns" + ); + let res = &env.selector[i]; + Some(res) + } + Column::LookupPartialSum((table_id, i)) => { + if let Some(ref lookup) = env.lookup_env { + let table_id = ID::from_u32(table_id); + Some(&lookup.lookup_terms_evals_d8[&table_id][i]) + } else { + panic!("No lookup provided") + } + } + Column::LookupAggregation => { + if let Some(ref lookup) = env.lookup_env { + Some(&lookup.lookup_aggregation_evals_d8) + } else { + panic!("No lookup provided") } - _ => { - panic!("We should not have any other type of columns") + } + Column::LookupMultiplicity((table_id, i)) => { + if let Some(ref lookup) = env.lookup_env { + Some(&lookup.lookup_counters_evals_d8[&ID::from_u32(table_id)][i]) + } else { + panic!("No lookup provided") } } + Column::LookupFixedTable(table_id) => { + if let Some(ref lookup) = env.lookup_env { + Some(&lookup.fixed_lookup_tables_evals_d8[&ID::from_u32(table_id)]) + } else { + panic!("No lookup provided") + } + } + _ => { + panic!("We should not have any other type of columns") + } } } -impl<'a, F: FftField> TColumnEnvironment<'a, F, BerkeleyChallengeTerm, BerkeleyChallenges> - for ColumnEnvironment<'a, F> +impl<'a, F: FftField, G: KimchiCurve, ID: LookupTableID> + TColumnEnvironment<'a, F, BerkeleyChallengeTerm, BerkeleyChallenges> + for ColumnEnvironment<'a, F, G, ID> +where + G: KimchiCurve, { // FIXME: do we change to the MIPS column type? // We do not want to keep kimchi_msm/generic prover type Column = Column; fn get_column(&self, col: &Self::Column) -> Option<&'a Evals> { - self.witness.get_column(col) + get_column_eval(self.witness, col) } fn get_domain(&self, d: Domain) -> Radix2EvaluationDomain { diff --git a/o1vm/src/pickles/main.rs b/o1vm/src/pickles/main.rs index f60ae5948f..c83ef381f2 100644 --- a/o1vm/src/pickles/main.rs +++ b/o1vm/src/pickles/main.rs @@ -17,6 +17,7 @@ use o1vm::{ witness::{self as mips_witness}, Instruction, }, + lookups::LookupTableIDs, pickles::{proof::ProofInputs, prover, verifier}, preimage_oracle::PreImageOracle, }; @@ -28,6 +29,8 @@ use mina_curves::pasta::{Fp, Vesta}; pub const DOMAIN_SIZE: usize = 1 << 15; +type ID = LookupTableIDs; + pub fn main() -> ExitCode { let cli = cannon_cli::main_cli(); @@ -95,7 +98,7 @@ pub fn main() -> ExitCode { constraints }; - let mut curr_proof_inputs: ProofInputs = ProofInputs::new(DOMAIN_SIZE); + let mut curr_proof_inputs: ProofInputs = ProofInputs::new(DOMAIN_SIZE); while !mips_wit_env.halt { let _instr: Instruction = mips_wit_env.step(&configuration, &meta, &start); for (scratch, scratch_chunk) in mips_wit_env @@ -126,6 +129,7 @@ pub fn main() -> ExitCode { DefaultFqSponge, DefaultFrSponge, _, + ID, >(domain_fp, &srs, curr_proof_inputs, &constraints, &mut rng) .unwrap(); // FIXME: check that the proof is correct. This is for testing purposes. @@ -140,6 +144,7 @@ pub fn main() -> ExitCode { Vesta, DefaultFqSponge, DefaultFrSponge, + ID, >(domain_fp, &srs, &constraints, &proof); debug!( "Verification done in {elapsed} μs", diff --git a/o1vm/src/pickles/proof.rs b/o1vm/src/pickles/proof.rs index e3548cdbfe..a5699cacf6 100644 --- a/o1vm/src/pickles/proof.rs +++ b/o1vm/src/pickles/proof.rs @@ -1,20 +1,29 @@ +use std::collections::BTreeMap; + use kimchi::{curve::KimchiCurve, proof::PointEvaluations}; +use kimchi_msm::{ + logup::{prover::Env as LookupEnv, LookupProof}, + LogupWitness, LookupTableID, +}; use poly_commitment::{ipa::OpeningProof, PolyComm}; use crate::interpreters::mips::{column::N_MIPS_SEL_COLS, witness::SCRATCH_SIZE}; -pub struct WitnessColumns { - pub scratch: [G; SCRATCH_SIZE], - pub instruction_counter: G, - pub error: G, +#[derive(Clone)] +pub struct WitnessColumns { + pub scratch: [F; crate::interpreters::mips::witness::SCRATCH_SIZE], + pub instruction_counter: F, + pub error: F, pub selector: S, + pub lookup_env: Option>, } -pub struct ProofInputs { - pub evaluations: WitnessColumns, Vec>, +pub struct ProofInputs { + pub evaluations: WitnessColumns, G, Vec, ID>, + pub logups: BTreeMap>, } -impl ProofInputs { +impl ProofInputs { pub fn new(domain_size: usize) -> Self { ProofInputs { evaluations: WitnessColumns { @@ -22,18 +31,23 @@ impl ProofInputs { instruction_counter: Vec::with_capacity(domain_size), error: Vec::with_capacity(domain_size), selector: Vec::with_capacity(domain_size), + lookup_env: None, }, + logups: BTreeMap::new(), } } } // FIXME: should we blind the commitment? -pub struct Proof { - pub commitments: WitnessColumns, [PolyComm; N_MIPS_SEL_COLS]>, - pub zeta_evaluations: WitnessColumns, - pub zeta_omega_evaluations: WitnessColumns, +pub struct Proof { + pub commitments: WitnessColumns, G, [PolyComm; N_MIPS_SEL_COLS], ID>, + pub zeta_evaluations: WitnessColumns, + pub zeta_omega_evaluations: + WitnessColumns, pub quotient_commitment: PolyComm, pub quotient_evaluations: PointEvaluations>, + pub logup_commitments: Option, ID>>, + pub logup_evaluations: Option, ID>>, /// IPA opening proof pub opening_proof: OpeningProof, } diff --git a/o1vm/src/pickles/prover.rs b/o1vm/src/pickles/prover.rs index 2f40787546..4bcadcbf6b 100644 --- a/o1vm/src/pickles/prover.rs +++ b/o1vm/src/pickles/prover.rs @@ -13,6 +13,10 @@ use kimchi::{ plonk_sponge::FrSponge, proof::PointEvaluations, }; +use kimchi_msm::{ + logup::{prover::Env, LookupProof}, + LookupTableID, +}; use log::debug; use mina_poseidon::{sponge::ScalarChallenge, FqSponge}; use o1_utils::ExtendedDensePolynomial; @@ -56,13 +60,14 @@ pub fn prove< EFqSponge: FqSponge + Clone, EFrSponge: FrSponge, RNG, + ID: LookupTableID, >( domain: EvaluationDomains, srs: &SRS, - inputs: ProofInputs, + inputs: ProofInputs, constraints: &[E], rng: &mut RNG, -) -> Result, ProverError> +) -> Result, ProverError> where G::BaseField: PrimeField, RNG: RngCore + CryptoRng, @@ -77,16 +82,17 @@ where //////////////////////////////////////////////////////////////////////////// debug!("Prover: interpolating all columns, including the selectors"); - let ProofInputs { evaluations } = inputs; - let polys: WitnessColumns< - DensePolynomial, - [DensePolynomial; N_MIPS_SEL_COLS], - > = { + let ProofInputs { + evaluations, + logups, + } = inputs; + let polys: WitnessColumns, G, [DensePolynomial; N_MIPS_SEL_COLS], ID> = { let WitnessColumns { scratch, instruction_counter, error, selector, + ref lookup_env, } = evaluations; let domain_size = domain.d1.size as usize; @@ -116,16 +122,18 @@ where instruction_counter: eval_col(instruction_counter), error: eval_col(error.clone()), selector: selector.try_into().unwrap(), + lookup_env: lookup_env.clone(), } }; debug!("Prover: committing to all columns, including the selectors"); - let commitments: WitnessColumns, [PolyComm; N_MIPS_SEL_COLS]> = { + let commitments: WitnessColumns, G, [PolyComm; N_MIPS_SEL_COLS], ID> = { let WitnessColumns { scratch, instruction_counter, error, selector, + lookup_env, } = &polys; let comm = |poly: &DensePolynomial| { @@ -142,9 +150,10 @@ where let selector = selector.par_iter().map(comm).collect::>(); WitnessColumns { scratch: scratch.try_into().unwrap(), - instruction_counter: comm(instruction_counter), - error: comm(error), + instruction_counter: comm(&instruction_counter), + error: comm(&error), selector: selector.try_into().unwrap(), + lookup_env: lookup_env.clone(), } }; @@ -159,6 +168,7 @@ where instruction_counter, error, selector, + lookup_env, } = &polys; let eval_d8 = |poly: &DensePolynomial| poly.evaluate_over_domain_by_ref(domain.d8); @@ -170,6 +180,7 @@ where instruction_counter: eval_d8(instruction_counter), error: eval_d8(error), selector: selector.try_into().unwrap(), + lookup_env: lookup_env.clone(), } }; @@ -184,6 +195,26 @@ where absorb_commitment(&mut fq_sponge, comm) } + let lookup_env = if !logups.is_empty() { + Some(Env::create::, EFqSponge>( + logups, + domain, + &mut fq_sponge, + srs, + )) + } else { + None + }; + + // Don't need to be absorbed. Already absorbed in logup::prover::Env::create + // FIXME: remove clone + let logup_commitments = Option::map(lookup_env.as_ref(), |lookup_env| LookupProof { + m: lookup_env.lookup_counters_comm_d1.clone(), + h: lookup_env.lookup_terms_comms_d1.clone(), + sum: lookup_env.lookup_aggregation_comm_d1.clone(), + fixed_tables: lookup_env.fixed_lookup_tables_comms_d1.clone(), + }); + //////////////////////////////////////////////////////////////////////////// // Round 2: Creating and committing to the quotient polynomial //////////////////////////////////////////////////////////////////////////// @@ -194,7 +225,7 @@ where let alpha: G::ScalarField = fq_sponge.challenge(); let zk_rows = 0; - let column_env: ColumnEnvironment<'_, G::ScalarField> = { + let column_env: ColumnEnvironment<'_, G::ScalarField, G, ID> = { // FIXME: use a proper Challenge structure let challenges = BerkeleyChallenges { alpha, @@ -213,6 +244,14 @@ where challenges, witness: &evaluations_d8, l0_1: l0_1(domain.d1), + lookup: Option::map(lookup_env.as_ref(), |lookup_env| { + kimchi_msm::logup::prover::QuotientPolynomialEnvironment { + lookup_terms_evals_d8: &lookup_env.lookup_terms_evals_d8, + lookup_aggregation_evals_d8: &lookup_env.lookup_aggregation_evals_d8, + lookup_counters_evals_d8: &lookup_env.lookup_counters_evals_d8, + fixed_tables_evals_d8: &lookup_env.fixed_lookup_tables_evals_d8, + } + }), domain, } }; @@ -294,24 +333,30 @@ where instruction_counter, error, selector, + lookup_env, } = &polys; let eval = |poly: &DensePolynomial| poly.evaluate(point); let scratch = scratch.par_iter().map(eval).collect::>(); let selector = selector.par_iter().map(eval).collect::>(); WitnessColumns { scratch: scratch.try_into().unwrap(), - instruction_counter: eval(instruction_counter), - error: eval(error), + instruction_counter: eval(&instruction_counter), + error: eval(&error), selector: selector.try_into().unwrap(), + lookup_env: lookup_env.clone(), } }; // All evaluations at ζ - let zeta_evaluations: WitnessColumns = + let zeta_evaluations: WitnessColumns = evals(&zeta); // All evaluations at ζω - let zeta_omega_evaluations: WitnessColumns = - evals(&zeta_omega); + let zeta_omega_evaluations: WitnessColumns< + G::ScalarField, + G, + [G::ScalarField; N_MIPS_SEL_COLS], + ID, + > = evals(&zeta_omega); let chunked_quotient = quotient_poly .to_chunked_polynomial(DEGREE_QUOTIENT_POLYNOMIAL as usize, domain.d1.size as usize); @@ -328,6 +373,55 @@ where .collect(), }; + let logup_evaluations = lookup_env.as_ref().map(|lookup_env| LookupProof { + m: lookup_env + .lookup_counters_poly_d1 + .iter() + .map(|(id, polys)| { + ( + *id, + polys + .iter() + .map(|poly| { + let zeta = poly.evaluate(&zeta); + let zeta_omega = poly.evaluate(&zeta_omega); + PointEvaluations { zeta, zeta_omega } + }) + .collect(), + ) + }) + .collect(), + h: lookup_env + .lookup_terms_poly_d1 + .iter() + .map(|(id, polys)| { + let polys_evals: Vec<_> = polys + .iter() + .map(|poly| PointEvaluations { + zeta: poly.evaluate(&zeta), + zeta_omega: poly.evaluate(&zeta_omega), + }) + .collect(); + (*id, polys_evals) + }) + .collect(), + sum: PointEvaluations { + zeta: lookup_env.lookup_aggregation_poly_d1.evaluate(&zeta), + zeta_omega: lookup_env.lookup_aggregation_poly_d1.evaluate(&zeta_omega), + }, + fixed_tables: { + lookup_env + .fixed_lookup_tables_poly_d1 + .iter() + .map(|(id, poly)| { + let zeta = poly.evaluate(&zeta); + let zeta_omega = poly.evaluate(&zeta_omega); + (*id, PointEvaluations { zeta, zeta_omega }) + }) + .collect() + }, + }); + // Absorbing evaluations with a sponge for the other field // We initialize the state with the previous state of the fq_sponge let fq_sponge_before_evaluations = fq_sponge.clone(); @@ -362,6 +456,14 @@ where fr_sponge.absorb(quotient_zeta_eval); fr_sponge.absorb(quotient_zeta_omega_eval); } + + if lookup_env.is_some() { + for PointEvaluations { zeta, zeta_omega } in logup_evaluations.as_ref().unwrap().into_iter() + { + fr_sponge.absorb(zeta); + fr_sponge.absorb(zeta_omega); + } + } //////////////////////////////////////////////////////////////////////////// // Round 4: Opening proof w/o linearization polynomial //////////////////////////////////////////////////////////////////////////// @@ -389,6 +491,61 @@ where quotient_commitment.blinders, )); + if let Some(ref lookup_env) = lookup_env { + // -- first m(X) + polynomials.extend( + lookup_env + .lookup_counters_poly_d1 + .values() + .flat_map(|polys| { + polys + .iter() + .map(|poly| { + ( + DensePolynomialOrEvaluations::DensePolynomial(poly), + PolyComm::new(vec![G::ScalarField::one()]), + ) + }) + .collect::>() + }) + .collect::>(), + ); + // -- after that the partial sums + polynomials.extend({ + let polys = lookup_env.lookup_terms_poly_d1.values().map(|polys| { + polys + .iter() + .map(|poly| { + ( + DensePolynomialOrEvaluations::DensePolynomial(poly), + PolyComm::new(vec![G::ScalarField::one()]), + ) + }) + .collect::>() + }); + let polys: Vec<_> = polys.flatten().collect(); + polys + }); + // -- after that the running sum + polynomials.push(( + DensePolynomialOrEvaluations::DensePolynomial(&lookup_env.lookup_aggregation_poly_d1), + PolyComm::new(vec![G::ScalarField::one()]), + )); + // -- Adding fixed lookup tables + polynomials.extend( + lookup_env + .fixed_lookup_tables_poly_d1 + .values() + .map(|poly| { + ( + DensePolynomialOrEvaluations::DensePolynomial(poly), + PolyComm::new(vec![G::ScalarField::one()]), + ) + }) + .collect::>(), + ); + } + // poly scale let v_chal = fr_sponge.challenge(); let v = v_chal.to_field(endo_r); @@ -417,6 +574,8 @@ where zeta_omega_evaluations, quotient_commitment: quotient_commitment.commitment, quotient_evaluations, + logup_commitments, + logup_evaluations, opening_proof, }) } diff --git a/o1vm/src/pickles/tests.rs b/o1vm/src/pickles/tests.rs index 0260e06587..1780ce37dd 100644 --- a/o1vm/src/pickles/tests.rs +++ b/o1vm/src/pickles/tests.rs @@ -1,4 +1,4 @@ -use std::time::Instant; +use std::{collections::BTreeMap, time::Instant}; use super::{ super::interpreters::mips::witness::SCRATCH_SIZE, @@ -7,9 +7,8 @@ use super::{ }; use crate::{ interpreters::mips::{ - constraints as mips_constraints, interpreter, interpreter::InterpreterEnv, Instruction, - }, - pickles::{verifier::verify, MAXIMUM_DEGREE_CONSTRAINTS, TOTAL_NUMBER_OF_CONSTRAINTS}, + constraints as mips_constraints, interpreter::{self, InterpreterEnv}, Instruction, + }, lookups::LookupTableIDs, pickles::{verifier::verify, MAXIMUM_DEGREE_CONSTRAINTS, TOTAL_NUMBER_OF_CONSTRAINTS} }; use ark_ff::{One, Zero}; use interpreter::{ITypeInstruction, JTypeInstruction, RTypeInstruction}; @@ -81,7 +80,7 @@ fn zero_to_n_minus_one(n: usize) -> Vec { fn test_small_circuit() { let domain = EvaluationDomains::::create(8).unwrap(); let srs = SRS::create(8); - let proof_input = ProofInputs:: { + let proof_input = ProofInputs:: { evaluations: WitnessColumns { scratch: std::array::from_fn(|_| zero_to_n_minus_one(8)), instruction_counter: zero_to_n_minus_one(8) @@ -92,7 +91,9 @@ fn test_small_circuit() { .map(|i| -Fq::from((i * SCRATCH_SIZE + (i + 1)) as u64)) .collect(), selector: zero_to_n_minus_one(8), + lookup_env: None, }, + logups: BTreeMap::new(), }; let mut expr = Expr::zero(); for i in 0..SCRATCH_SIZE + 2 { @@ -103,7 +104,7 @@ fn test_small_circuit() { type BaseSponge = DefaultFqSponge; type ScalarSponge = DefaultFrSponge; - let proof = prove::( + let proof = prove::( domain, &srs, proof_input, @@ -113,7 +114,7 @@ fn test_small_circuit() { .unwrap(); let instant_before_verification = Instant::now(); - let verif = verify::(domain, &srs, &[expr.clone()], &proof); + let verif = verify::(domain, &srs, &[expr.clone()], &proof); let instant_after_verification = Instant::now(); debug!( "Verification took: {} ms", diff --git a/o1vm/src/pickles/verifier.rs b/o1vm/src/pickles/verifier.rs index 9057a89802..3acf49cc56 100644 --- a/o1vm/src/pickles/verifier.rs +++ b/o1vm/src/pickles/verifier.rs @@ -1,5 +1,6 @@ use ark_ec::AffineRepr; use ark_ff::{Field, One, PrimeField, Zero}; +use ark_poly::{Evaluations, Radix2EvaluationDomain}; use rand::thread_rng; use kimchi::{ @@ -22,24 +23,33 @@ use poly_commitment::{ ipa::OpeningProof, OpenProof, }; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use super::{ - column_env::get_all_columns, + column_env::{get_all_columns, get_column_comm, get_column_eval}, proof::{Proof, WitnessColumns}, }; use crate::{interpreters::mips::column::N_MIPS_SEL_COLS, E}; -use kimchi_msm::columns::Column; +use kimchi_msm::{columns::Column, LookupTableID}; -type CommitmentColumns = WitnessColumns, [PolyComm; N_MIPS_SEL_COLS]>; -type EvaluationColumns = WitnessColumns; +type Evals = Evaluations>; +type CommitmentColumns = WitnessColumns, G, [PolyComm; N_MIPS_SEL_COLS], ID>; +type EvaluationColumns = WitnessColumns< + Evals<::ScalarField>, + G, + [Evals<::ScalarField>; N_MIPS_SEL_COLS], + ID, +>; -struct ColumnEval<'a, G: AffineRepr> { - commitment: &'a CommitmentColumns, - zeta_eval: &'a EvaluationColumns, - zeta_omega_eval: &'a EvaluationColumns, +struct ColumnEval<'a, G: AffineRepr + KimchiCurve, ID: LookupTableID> { + commitment: &'a CommitmentColumns, + zeta_eval: &'a EvaluationColumns, + zeta_omega_eval: &'a EvaluationColumns, } -impl ColumnEvaluations for ColumnEval<'_, G> { +impl ColumnEvaluations + for ColumnEval<'_, G, ID> +{ type Column = Column; fn evaluate( &self, @@ -49,10 +59,15 @@ impl ColumnEvaluations for ColumnEval<'_, G> { commitment: _, zeta_eval, zeta_omega_eval, - } = self; - if let Some(&zeta) = zeta_eval.get_column(&col) { - if let Some(&zeta_omega) = zeta_omega_eval.get_column(&col) { - Ok(PointEvaluations { zeta, zeta_omega }) + } = *self; + if let Some(&ref zeta) = get_column_eval(zeta_eval, &col) { + if let Some(&ref zeta_omega) = get_column_eval(zeta_omega_eval, &col) { + assert!(zeta.evals.len() == 1); + assert!(zeta_omega.evals.len() == 1); + Ok(PointEvaluations { + zeta: zeta.evals[0], + zeta_omega: zeta_omega.evals[0], + }) } else { Err(ExprError::MissingEvaluation(col, CurrOrNext::Next)) } @@ -66,11 +81,12 @@ pub fn verify< G: KimchiCurve, EFqSponge: Clone + FqSponge, EFrSponge: FrSponge, + ID: LookupTableID, >( domain: EvaluationDomains, srs: & as OpenProof>::SRS, constraints: &[E], - proof: &Proof, + proof: &Proof, ) -> bool where ::BaseField: PrimeField, @@ -81,6 +97,8 @@ where zeta_omega_evaluations, quotient_commitment, quotient_evaluations, + logup_commitments: _, + logup_evaluations: _, opening_proof, } = proof; @@ -118,10 +136,35 @@ where let omega = domain.d1.group_gen; let zeta_omega = zeta * omega; + let to_eval_witness_columns = |witness_columns: WitnessColumns< + G::ScalarField, + G, + [G::ScalarField; N_MIPS_SEL_COLS], + ID, + >| { + let to_evals = |&x| Evaluations::from_vec_and_domain(vec![x], domain.d1.clone()); + let WitnessColumns { + scratch, + instruction_counter, + error, + selector, + lookup_env, + } = witness_columns; + let scratch = scratch.par_iter().map(to_evals).collect::>(); + let selector = selector.par_iter().map(to_evals).collect::>(); + WitnessColumns { + scratch: scratch.try_into().unwrap(), + instruction_counter: to_evals(&instruction_counter), + error: to_evals(&error.clone()), + selector: selector.try_into().unwrap(), + lookup_env, + } + }; + let column_eval = ColumnEval { commitment: commitments, - zeta_eval: zeta_evaluations, - zeta_omega_eval: zeta_omega_evaluations, + zeta_eval: &to_eval_witness_columns(zeta_evaluations.clone()), + zeta_omega_eval: &to_eval_witness_columns(zeta_omega_evaluations.clone()), }; // -- Absorb all commitments_and_evaluations @@ -196,9 +239,9 @@ where let mut evaluations: Vec<_> = get_all_columns() .into_iter() .map(|column| { - let commitment = column_eval - .commitment - .get_column(&column) + let commitment = get_column_comm(column_eval + .commitment, + &column) .unwrap_or_else(|| panic!("Could not get `commitment` for `Evaluation`")) .clone();