From 3aeee2bc06aea13374ee9a7e1b8ea318561fe302 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Fri, 10 Jan 2025 16:34:34 +0000 Subject: [PATCH 1/4] Add placeholders for lookup state --- o1vm/src/interpreters/mips/tests_helpers.rs | 2 ++ o1vm/src/interpreters/mips/witness.rs | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/o1vm/src/interpreters/mips/tests_helpers.rs b/o1vm/src/interpreters/mips/tests_helpers.rs index bd1a29d1de..3840975968 100644 --- a/o1vm/src/interpreters/mips/tests_helpers.rs +++ b/o1vm/src/interpreters/mips/tests_helpers.rs @@ -93,6 +93,8 @@ where scratch_state: [Fp::from(0); SCRATCH_SIZE], scratch_state_inverse: [Fp::from(0); SCRATCH_SIZE_INVERSE], lookup_multiplicities: LookupMultiplicities::new(), + lookup_state_idx: 0, + lookup_state: vec![], selector: crate::interpreters::mips::column::N_MIPS_SEL_COLS, halt: false, // Keccak related diff --git a/o1vm/src/interpreters/mips/witness.rs b/o1vm/src/interpreters/mips/witness.rs index 8fa26522ad..135b544a35 100644 --- a/o1vm/src/interpreters/mips/witness.rs +++ b/o1vm/src/interpreters/mips/witness.rs @@ -112,6 +112,8 @@ pub struct Env { pub scratch_state_idx_inverse: usize, pub scratch_state: [Fp; SCRATCH_SIZE], pub scratch_state_inverse: [Fp; SCRATCH_SIZE_INVERSE], + pub lookup_state_idx: usize, + pub lookup_state: Vec, pub halt: bool, pub syscall_env: SyscallEnv, pub selector: usize, @@ -935,6 +937,8 @@ impl Env { scratch_state_idx_inverse: 0, scratch_state: fresh_scratch_state(), scratch_state_inverse: fresh_scratch_state(), + lookup_state_idx: 0, + lookup_state: vec![], halt: state.exited, syscall_env, selector, @@ -959,6 +963,11 @@ impl Env { self.scratch_state_inverse = fresh_scratch_state(); } + pub fn reset_lookup_state(&mut self) { + self.lookup_state_idx = 0; + self.lookup_state = vec![]; + } + pub fn write_column(&mut self, column: Column, value: u64) { self.write_field_column(column, value.into()) } @@ -1202,6 +1211,7 @@ impl Env { ) -> Instruction { self.reset_scratch_state(); self.reset_scratch_state_inverse(); + self.reset_lookup_state(); let (opcode, _instruction) = self.decode_instruction(); self.pp_info(&config.info_at, metadata, start); From 619504c1b99cd731b7367397de778a0859b92cd1 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 11 Jan 2025 18:16:46 +0000 Subject: [PATCH 2/4] Add LookupState variant --- o1vm/src/pickles/column_env.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/o1vm/src/pickles/column_env.rs b/o1vm/src/pickles/column_env.rs index 4cb0661654..63feb2a061 100644 --- a/o1vm/src/pickles/column_env.rs +++ b/o1vm/src/pickles/column_env.rs @@ -18,6 +18,7 @@ type Evals = Evaluations>; pub enum RelationColumnType { Scratch(usize), ScratchInverse(usize), + LookupState(usize), InstructionCounter, Error, } @@ -67,6 +68,7 @@ impl WitnessColumns { Column::Relation(i) => match i { RelationColumnType::Scratch(i) => Some(&self.scratch[i]), RelationColumnType::ScratchInverse(i) => Some(&self.scratch_inverse[i]), + RelationColumnType::LookupState(_) => todo!(), RelationColumnType::InstructionCounter => Some(&self.instruction_counter), RelationColumnType::Error => Some(&self.error), }, From c37627930a0f22c8e6e9b098fe4de6a8503f4dfc Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 11 Jan 2025 18:24:18 +0000 Subject: [PATCH 3/4] Propagate lookup state through to prover --- o1vm/src/pickles/column_env.rs | 9 ++++++--- o1vm/src/pickles/main.rs | 25 ++++++++++++++++++++++++- o1vm/src/pickles/proof.rs | 2 ++ o1vm/src/pickles/prover.rs | 31 +++++++++++++++++++++++++++++++ o1vm/src/pickles/tests.rs | 1 + o1vm/src/pickles/verifier.rs | 13 ++++++++++++- 6 files changed, 76 insertions(+), 5 deletions(-) diff --git a/o1vm/src/pickles/column_env.rs b/o1vm/src/pickles/column_env.rs index 63feb2a061..f8eb37f5e0 100644 --- a/o1vm/src/pickles/column_env.rs +++ b/o1vm/src/pickles/column_env.rs @@ -44,9 +44,9 @@ pub struct ColumnEnvironment<'a, F: FftField> { pub domain: EvaluationDomains, } -pub fn get_all_columns() -> Vec> { +pub fn get_all_columns(num_lookup_columns: usize) -> Vec> { let mut cols = Vec::>::with_capacity( - SCRATCH_SIZE + SCRATCH_SIZE_INVERSE + 2 + N_MIPS_SEL_COLS, + SCRATCH_SIZE + SCRATCH_SIZE_INVERSE + num_lookup_columns + 2 + N_MIPS_SEL_COLS, ); for i in 0..SCRATCH_SIZE { cols.push(Column::Relation(RelationColumnType::Scratch(i))); @@ -54,6 +54,9 @@ pub fn get_all_columns() -> Vec> { for i in 0..SCRATCH_SIZE_INVERSE { cols.push(Column::Relation(RelationColumnType::ScratchInverse(i))); } + for i in 0..num_lookup_columns { + cols.push(Column::Relation(RelationColumnType::LookupState(i))); + } cols.push(Column::Relation(RelationColumnType::InstructionCounter)); cols.push(Column::Relation(RelationColumnType::Error)); for i in 0..N_MIPS_SEL_COLS { @@ -68,7 +71,7 @@ impl WitnessColumns { Column::Relation(i) => match i { RelationColumnType::Scratch(i) => Some(&self.scratch[i]), RelationColumnType::ScratchInverse(i) => Some(&self.scratch_inverse[i]), - RelationColumnType::LookupState(_) => todo!(), + RelationColumnType::LookupState(i) => Some(&self.lookup_state[i]), RelationColumnType::InstructionCounter => Some(&self.instruction_counter), RelationColumnType::Error => Some(&self.error), }, diff --git a/o1vm/src/pickles/main.rs b/o1vm/src/pickles/main.rs index da9c858bce..9765a5988a 100644 --- a/o1vm/src/pickles/main.rs +++ b/o1vm/src/pickles/main.rs @@ -1,4 +1,4 @@ -use ark_ff::UniformRand; +use ark_ff::{UniformRand, Zero}; use clap::Parser; use kimchi::circuits::domains::EvaluationDomains; use log::debug; @@ -95,6 +95,29 @@ pub fn cannon_main(args: cli::cannon::RunArgs) { { scratch_chunk.push(*scratch); } + // Lookup state + { + let lookup_state_size = std::cmp::max( + curr_proof_inputs.evaluations.lookup_state.len(), + mips_wit_env.lookup_state.len(), + ); + for idx in 0..lookup_state_size { + if idx < mips_wit_env.lookup_state.len() { + // We pad with 0s for dummy lookups. + curr_proof_inputs.evaluations.lookup_state[idx].push(Fp::zero()); + } else if idx < curr_proof_inputs.evaluations.lookup_state.len() { + // We create a new column filled with 0s. + let mut new_vec = + vec![Fp::zero(); curr_proof_inputs.evaluations.instruction_counter.len()]; + new_vec.push(Fp::from(mips_wit_env.lookup_state[idx])); + curr_proof_inputs.evaluations.lookup_state[idx] = new_vec; + } else { + // Push the value to the column. + curr_proof_inputs.evaluations.lookup_state[idx] + .push(Fp::from(mips_wit_env.lookup_state[idx])); + } + } + } curr_proof_inputs .evaluations .instruction_counter diff --git a/o1vm/src/pickles/proof.rs b/o1vm/src/pickles/proof.rs index 40529a3409..c1644903bc 100644 --- a/o1vm/src/pickles/proof.rs +++ b/o1vm/src/pickles/proof.rs @@ -6,6 +6,7 @@ use crate::interpreters::mips::column::{N_MIPS_SEL_COLS, SCRATCH_SIZE, SCRATCH_S pub struct WitnessColumns { pub scratch: [G; SCRATCH_SIZE], pub scratch_inverse: [G; SCRATCH_SIZE_INVERSE], + pub lookup_state: Vec, pub instruction_counter: G, pub error: G, pub selector: S, @@ -21,6 +22,7 @@ impl ProofInputs { evaluations: WitnessColumns { scratch: std::array::from_fn(|_| Vec::with_capacity(domain_size)), scratch_inverse: std::array::from_fn(|_| Vec::with_capacity(domain_size)), + lookup_state: vec![], instruction_counter: Vec::with_capacity(domain_size), error: Vec::with_capacity(domain_size), selector: Vec::with_capacity(domain_size), diff --git a/o1vm/src/pickles/prover.rs b/o1vm/src/pickles/prover.rs index d9aa9416cf..117f37e062 100644 --- a/o1vm/src/pickles/prover.rs +++ b/o1vm/src/pickles/prover.rs @@ -86,6 +86,7 @@ where let WitnessColumns { scratch, scratch_inverse, + lookup_state, instruction_counter, error, selector, @@ -119,10 +120,15 @@ where eval_col(evals) }) .collect::>(); + let lookup_state = lookup_state + .into_par_iter() + .map(eval_col) + .collect::>(); let selector = selector.into_par_iter().map(eval_col).collect::>(); WitnessColumns { scratch: scratch.try_into().unwrap(), scratch_inverse: scratch_inverse.try_into().unwrap(), + lookup_state, instruction_counter: eval_col(instruction_counter), error: eval_col(error.clone()), selector: selector.try_into().unwrap(), @@ -134,6 +140,7 @@ where let WitnessColumns { scratch, scratch_inverse, + lookup_state, instruction_counter, error, selector, @@ -151,10 +158,12 @@ where // Doing in parallel let scratch = scratch.par_iter().map(comm).collect::>(); let scratch_inverse = scratch_inverse.par_iter().map(comm).collect::>(); + let lookup_state = lookup_state.par_iter().map(comm).collect::>(); let selector = selector.par_iter().map(comm).collect::>(); WitnessColumns { scratch: scratch.try_into().unwrap(), scratch_inverse: scratch_inverse.try_into().unwrap(), + lookup_state, instruction_counter: comm(instruction_counter), error: comm(error), selector: selector.try_into().unwrap(), @@ -170,6 +179,7 @@ where let WitnessColumns { scratch, scratch_inverse, + lookup_state, instruction_counter, error, selector, @@ -182,10 +192,15 @@ where .into_par_iter() .map(eval_d8) .collect::>(); + let lookup_state = lookup_state + .into_par_iter() + .map(eval_d8) + .collect::>(); let selector = selector.into_par_iter().map(eval_d8).collect::>(); WitnessColumns { scratch: scratch.try_into().unwrap(), scratch_inverse: scratch_inverse.try_into().unwrap(), + lookup_state, instruction_counter: eval_d8(instruction_counter), error: eval_d8(error), selector: selector.try_into().unwrap(), @@ -200,6 +215,9 @@ where for comm in commitments.scratch_inverse.iter() { absorb_commitment(&mut fq_sponge, comm) } + for comm in commitments.lookup_state.iter() { + absorb_commitment(&mut fq_sponge, comm) + } absorb_commitment(&mut fq_sponge, &commitments.instruction_counter); absorb_commitment(&mut fq_sponge, &commitments.error); for comm in commitments.selector.iter() { @@ -314,6 +332,7 @@ where let WitnessColumns { scratch, scratch_inverse, + lookup_state, instruction_counter, error, selector, @@ -321,10 +340,12 @@ where let eval = |poly: &DensePolynomial| poly.evaluate(point); let scratch = scratch.par_iter().map(eval).collect::>(); let scratch_inverse = scratch_inverse.par_iter().map(eval).collect::>(); + let lookup_state = lookup_state.par_iter().map(eval).collect::>(); let selector = selector.par_iter().map(eval).collect::>(); WitnessColumns { scratch: scratch.try_into().unwrap(), scratch_inverse: scratch_inverse.try_into().unwrap(), + lookup_state, instruction_counter: eval(instruction_counter), error: eval(error), selector: selector.try_into().unwrap(), @@ -375,6 +396,15 @@ where fr_sponge.absorb(zeta_eval); fr_sponge.absorb(zeta_omega_eval); } + + for (zeta_eval, zeta_omega_eval) in zeta_evaluations + .lookup_state + .iter() + .zip(zeta_omega_evaluations.lookup_state.iter()) + { + fr_sponge.absorb(zeta_eval); + fr_sponge.absorb(zeta_omega_eval); + } fr_sponge.absorb(&zeta_evaluations.instruction_counter); fr_sponge.absorb(&zeta_omega_evaluations.instruction_counter); fr_sponge.absorb(&zeta_evaluations.error); @@ -401,6 +431,7 @@ where let mut polynomials: Vec<_> = polys.scratch.into_iter().collect(); polynomials.extend(polys.scratch_inverse); + polynomials.extend(polys.lookup_state); polynomials.push(polys.instruction_counter); polynomials.push(polys.error); polynomials.extend(polys.selector); diff --git a/o1vm/src/pickles/tests.rs b/o1vm/src/pickles/tests.rs index 97bfed9740..56afee502e 100644 --- a/o1vm/src/pickles/tests.rs +++ b/o1vm/src/pickles/tests.rs @@ -71,6 +71,7 @@ fn test_small_circuit() { evaluations: WitnessColumns { scratch: std::array::from_fn(|_| zero_to_n_minus_one(8)), scratch_inverse: std::array::from_fn(|_| (0..8).map(|_| Fq::zero()).collect()), + lookup_state: vec![], instruction_counter: zero_to_n_minus_one(8) .into_iter() .map(|x| x + Fq::one()) diff --git a/o1vm/src/pickles/verifier.rs b/o1vm/src/pickles/verifier.rs index 76ecd7e67b..87fe7b8719 100644 --- a/o1vm/src/pickles/verifier.rs +++ b/o1vm/src/pickles/verifier.rs @@ -99,6 +99,9 @@ where for comm in commitments.scratch_inverse.iter() { absorb_commitment(&mut fq_sponge, comm) } + for comm in commitments.lookup_state.iter() { + absorb_commitment(&mut fq_sponge, comm) + } absorb_commitment(&mut fq_sponge, &commitments.instruction_counter); absorb_commitment(&mut fq_sponge, &commitments.error); for comm in commitments.selector.iter() { @@ -148,6 +151,14 @@ where fr_sponge.absorb(zeta_eval); fr_sponge.absorb(zeta_omega_eval); } + for (zeta_eval, zeta_omega_eval) in zeta_evaluations + .lookup_state + .iter() + .zip(zeta_omega_evaluations.lookup_state.iter()) + { + fr_sponge.absorb(zeta_eval); + fr_sponge.absorb(zeta_omega_eval); + } fr_sponge.absorb(&zeta_evaluations.instruction_counter); fr_sponge.absorb(&zeta_omega_evaluations.instruction_counter); fr_sponge.absorb(&zeta_evaluations.error); @@ -204,7 +215,7 @@ where let u_chal = fr_sponge.challenge(); let u = u_chal.to_field(endo_r); - let mut evaluations: Vec<_> = get_all_columns() + let mut evaluations: Vec<_> = get_all_columns(column_eval.commitment.lookup_state.len()) .into_iter() .map(|column| { let commitment = column_eval From 3ebeaf4cea598ef62522707f10ff136117a08a10 Mon Sep 17 00:00:00 2001 From: mrmr1993 Date: Sat, 11 Jan 2025 18:43:02 +0000 Subject: [PATCH 4/4] Record lookup values in the lookup state as they are generated --- o1vm/src/interpreters/mips/witness.rs | 32 +++++++++++++++++++++++---- o1vm/src/pickles/main.rs | 17 +++++++------- 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/o1vm/src/interpreters/mips/witness.rs b/o1vm/src/interpreters/mips/witness.rs index 135b544a35..f65c0ffc56 100644 --- a/o1vm/src/interpreters/mips/witness.rs +++ b/o1vm/src/interpreters/mips/witness.rs @@ -22,6 +22,7 @@ use crate::{ }, lookups::{Lookup, LookupTableIDs}, preimage_oracle::PreImageOracleT, + ramlookup::LookupMode, utils::memory_size, }; use ark_ff::{Field, PrimeField}; @@ -113,7 +114,7 @@ pub struct Env { pub scratch_state: [Fp; SCRATCH_SIZE], pub scratch_state_inverse: [Fp; SCRATCH_SIZE_INVERSE], pub lookup_state_idx: usize, - pub lookup_state: Vec, + pub lookup_state: Vec, pub halt: bool, pub syscall_env: SyscallEnv, pub selector: usize, @@ -177,9 +178,32 @@ impl InterpreterEnv for Env) { - let values: Vec<_> = lookup.value.iter().map(|x| Fp::from(*x)).collect(); - if let Some(idx) = lookup.table_id.ix_by_value(values.as_slice()) { - match lookup.table_id { + let mut add_value = |x: Fp| { + self.lookup_state_idx += 1; + self.lookup_state.push(x); + }; + let Lookup { + table_id, + magnitude: numerator, + mode, + value: values, + } = lookup; + let values: Vec<_> = values.into_iter().map(|x| Fp::from(x)).collect(); + + // Add lookup numerator + match mode { + LookupMode::Write => add_value(Fp::from(numerator)), + LookupMode::Read => add_value(-Fp::from(numerator)), + }; + // Add lookup table ID + add_value(Fp::from(table_id.to_u32())); + // Add values + for value in values.iter() { + add_value(*value); + } + + if let Some(idx) = table_id.ix_by_value(values.as_slice()) { + match table_id { LookupTableIDs::PadLookup => self.lookup_multiplicities.pad_lookup[idx] += 1, LookupTableIDs::RoundConstantsLookup => { self.lookup_multiplicities.round_constants_lookup[idx] += 1 diff --git a/o1vm/src/pickles/main.rs b/o1vm/src/pickles/main.rs index 9765a5988a..5087cd27ff 100644 --- a/o1vm/src/pickles/main.rs +++ b/o1vm/src/pickles/main.rs @@ -97,20 +97,19 @@ pub fn cannon_main(args: cli::cannon::RunArgs) { } // Lookup state { - let lookup_state_size = std::cmp::max( - curr_proof_inputs.evaluations.lookup_state.len(), - mips_wit_env.lookup_state.len(), - ); + let proof_inputs_length = curr_proof_inputs.evaluations.lookup_state.len(); + let environment_length = mips_wit_env.lookup_state.len(); + let lookup_state_size = std::cmp::max(proof_inputs_length, environment_length); for idx in 0..lookup_state_size { - if idx < mips_wit_env.lookup_state.len() { - // We pad with 0s for dummy lookups. + if idx >= environment_length { + // We pad with 0s for dummy lookups missing from the environment. curr_proof_inputs.evaluations.lookup_state[idx].push(Fp::zero()); - } else if idx < curr_proof_inputs.evaluations.lookup_state.len() { - // We create a new column filled with 0s. + } else if idx >= proof_inputs_length { + // We create a new column filled with 0s in the proof inputs. let mut new_vec = vec![Fp::zero(); curr_proof_inputs.evaluations.instruction_counter.len()]; new_vec.push(Fp::from(mips_wit_env.lookup_state[idx])); - curr_proof_inputs.evaluations.lookup_state[idx] = new_vec; + curr_proof_inputs.evaluations.lookup_state.push(new_vec); } else { // Push the value to the column. curr_proof_inputs.evaluations.lookup_state[idx]