From 3c4f938f8568db81b72855fa6a811dba96f13bee Mon Sep 17 00:00:00 2001 From: Hamy Ratoanina Date: Mon, 11 Sep 2023 14:11:13 -0400 Subject: [PATCH 1/3] Make next row available to CTLs --- evm/src/all_stark.rs | 18 ++- evm/src/arithmetic/arithmetic_stark.rs | 1 + evm/src/cpu/cpu_stark.rs | 2 + evm/src/cross_table_lookup.rs | 161 +++++++++++++++---------- evm/src/fixed_recursive_verifier.rs | 2 +- evm/src/keccak/keccak_stark.rs | 3 +- evm/src/proof.rs | 37 +++--- evm/src/prover.rs | 9 +- evm/src/recursive_verifier.rs | 17 ++- evm/src/stark.rs | 15 +-- evm/src/verifier.rs | 13 +- 11 files changed, 162 insertions(+), 116 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index b0f3056cf6..9b1fc49b00 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -120,11 +120,13 @@ fn ctl_keccak() -> CrossTableLookup { let keccak_sponge_looking = TableWithColumns::new( Table::KeccakSponge, keccak_sponge_stark::ctl_looking_keccak(), + vec![], Some(keccak_sponge_stark::ctl_looking_keccak_filter()), ); let keccak_looked = TableWithColumns::new( Table::Keccak, keccak_stark::ctl_data(), + vec![], Some(keccak_stark::ctl_filter()), ); CrossTableLookup::new(vec![keccak_sponge_looking], keccak_looked) @@ -134,11 +136,13 @@ fn ctl_keccak_sponge() -> CrossTableLookup { let cpu_looking = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_keccak_sponge(), + vec![], Some(cpu_stark::ctl_filter_keccak_sponge()), ); let keccak_sponge_looked = TableWithColumns::new( Table::KeccakSponge, keccak_sponge_stark::ctl_looked_data(), + vec![], Some(keccak_sponge_stark::ctl_looked_filter()), ); CrossTableLookup::new(vec![cpu_looking], keccak_sponge_looked) @@ -148,6 +152,7 @@ fn ctl_logic() -> CrossTableLookup { let cpu_looking = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_logic(), + vec![], Some(cpu_stark::ctl_filter_logic()), ); let mut all_lookers = vec![cpu_looking]; @@ -155,12 +160,17 @@ fn ctl_logic() -> CrossTableLookup { let keccak_sponge_looking = TableWithColumns::new( Table::KeccakSponge, keccak_sponge_stark::ctl_looking_logic(i), + vec![], Some(keccak_sponge_stark::ctl_looking_logic_filter()), ); all_lookers.push(keccak_sponge_looking); } - let logic_looked = - TableWithColumns::new(Table::Logic, logic::ctl_data(), Some(logic::ctl_filter())); + let logic_looked = TableWithColumns::new( + Table::Logic, + logic::ctl_data(), + vec![], + Some(logic::ctl_filter()), + ); CrossTableLookup::new(all_lookers, logic_looked) } @@ -168,12 +178,14 @@ fn ctl_memory() -> CrossTableLookup { let cpu_memory_code_read = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_code_memory(), + vec![], Some(cpu_stark::ctl_filter_code_memory()), ); let cpu_memory_gp_ops = (0..NUM_GP_CHANNELS).map(|channel| { TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_gp_memory(channel), + vec![], Some(cpu_stark::ctl_filter_gp_memory(channel)), ) }); @@ -181,6 +193,7 @@ fn ctl_memory() -> CrossTableLookup { TableWithColumns::new( Table::KeccakSponge, keccak_sponge_stark::ctl_looking_memory(i), + vec![], Some(keccak_sponge_stark::ctl_looking_memory_filter(i)), ) }); @@ -191,6 +204,7 @@ fn ctl_memory() -> CrossTableLookup { let memory_looked = TableWithColumns::new( Table::Memory, memory_stark::ctl_data(), + vec![], Some(memory_stark::ctl_filter()), ); CrossTableLookup::new(all_lookers, memory_looked) diff --git a/evm/src/arithmetic/arithmetic_stark.rs b/evm/src/arithmetic/arithmetic_stark.rs index 4695798af5..accc914efe 100644 --- a/evm/src/arithmetic/arithmetic_stark.rs +++ b/evm/src/arithmetic/arithmetic_stark.rs @@ -81,6 +81,7 @@ pub fn ctl_arithmetic_rows() -> TableWithColumns { TableWithColumns::new( Table::Arithmetic, cpu_arith_data_link(&ARITH_OPS, ®ISTER_MAP), + vec![], Some(Column::sum(ARITH_OPS)), ) } diff --git a/evm/src/cpu/cpu_stark.rs b/evm/src/cpu/cpu_stark.rs index 7fd0c76fcc..f598f24d9f 100644 --- a/evm/src/cpu/cpu_stark.rs +++ b/evm/src/cpu/cpu_stark.rs @@ -118,6 +118,7 @@ pub fn ctl_arithmetic_base_rows() -> TableWithColumns { TableWithColumns::new( Table::Cpu, ctl_data_ternops(&OPS, false), + vec![], Some(Column::sum(OPS)), ) } @@ -149,6 +150,7 @@ pub fn ctl_arithmetic_shift_rows() -> TableWithColumns { TableWithColumns::new( Table::Cpu, ctl_data_ternops(&OPS, true), + vec![], Some(Column::sum([COL_MAP.op.shl, COL_MAP.op.shr])), ) } diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 8f481325c6..ac9630a065 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -141,15 +141,22 @@ impl Column { #[derive(Clone, Debug)] pub struct TableWithColumns { table: Table, - columns: Vec>, + local_columns: Vec>, + next_columns: Vec>, pub(crate) filter_column: Option>, } impl TableWithColumns { - pub fn new(table: Table, columns: Vec>, filter_column: Option>) -> Self { + pub fn new( + table: Table, + local_columns: Vec>, + next_columns: Vec>, + filter_column: Option>, + ) -> Self { Self { table, - columns, + local_columns, + next_columns, filter_column, } } @@ -168,7 +175,8 @@ impl CrossTableLookup { ) -> Self { assert!(looking_tables .iter() - .all(|twc| twc.columns.len() == looked_table.columns.len())); + .all(|twc| (twc.local_columns.len() + twc.next_columns.len()) + == (looked_table.local_columns.len() + looked_table.next_columns.len()))); Self { looking_tables, looked_table, @@ -196,7 +204,8 @@ pub struct CtlData { pub(crate) struct CtlZData { pub(crate) z: PolynomialValues, pub(crate) challenge: GrandProductChallenge, - pub(crate) columns: Vec>, + pub(crate) local_columns: Vec>, + pub(crate) next_columns: Vec>, pub(crate) filter_column: Option>, } @@ -233,14 +242,16 @@ pub(crate) fn cross_table_lookup_data( let zs_looking = looking_tables.iter().map(|table| { partial_products( &trace_poly_values[table.table as usize], - &table.columns, + &table.local_columns, + &table.next_columns, &table.filter_column, challenge, ) }); let z_looked = partial_products( &trace_poly_values[looked_table.table as usize], - &looked_table.columns, + &looked_table.local_columns, + &looked_table.next_columns, &looked_table.filter_column, challenge, ); @@ -250,7 +261,8 @@ pub(crate) fn cross_table_lookup_data( .push(CtlZData { z, challenge, - columns: table.columns.clone(), + local_columns: table.local_columns.clone(), + next_columns: table.next_columns.clone(), filter_column: table.filter_column.clone(), }); } @@ -259,7 +271,8 @@ pub(crate) fn cross_table_lookup_data( .push(CtlZData { z: z_looked, challenge, - columns: looked_table.columns.clone(), + local_columns: looked_table.local_columns.clone(), + next_columns: looked_table.next_columns.clone(), filter_column: looked_table.filter_column.clone(), }); } @@ -269,23 +282,31 @@ pub(crate) fn cross_table_lookup_data( fn partial_products( trace: &[PolynomialValues], - columns: &[Column], + local_columns: &[Column], + next_columns: &[Column], filter_column: &Option>, challenge: GrandProductChallenge, ) -> PolynomialValues { let mut partial_prod = F::ONE; let degree = trace[0].len(); let mut res = Vec::with_capacity(degree); - for i in 0..degree { + for i in (0..degree).rev() { let filter = if let Some(column) = filter_column { column.eval_table(trace, i) } else { F::ONE }; if filter.is_one() { - let evals = columns + let evals = local_columns .iter() .map(|c| c.eval_table(trace, i)) + .chain( + next_columns + .iter() + // The modulo is there to avoid out of bounds. For any CTL using next row + // values, we expect the filter to be 0 at the last row. + .map(|c| c.eval_table(trace, (i + 1) % degree)), + ) .collect::>(); partial_prod *= challenge.combine(evals.iter()); } else { @@ -293,6 +314,7 @@ fn partial_products( }; res.push(partial_prod); } + res.reverse(); res.into() } @@ -306,7 +328,8 @@ where pub(crate) local_z: P, pub(crate) next_z: P, pub(crate) challenges: GrandProductChallenge, - pub(crate) columns: &'a [Column], + pub(crate) local_columns: &'a [Column], + pub(crate) next_columns: &'a [Column], pub(crate) filter_column: &'a Option>, } @@ -343,7 +366,8 @@ impl<'a, F: RichField + Extendable, const D: usize> local_z: *looking_z, next_z: *looking_z_next, challenges, - columns: &table.columns, + local_columns: &table.local_columns, + next_columns: &table.next_columns, filter_column: &table.filter_column, }); } @@ -353,7 +377,8 @@ impl<'a, F: RichField + Extendable, const D: usize> local_z: *looked_z, next_z: *looked_z_next, challenges, - columns: &looked_table.columns, + local_columns: &looked_table.local_columns, + next_columns: &looked_table.next_columns, filter_column: &looked_table.filter_column, }); } @@ -362,6 +387,10 @@ impl<'a, F: RichField + Extendable, const D: usize> } } +/// CTL Z partial products are upside down: the complete product is on the first row, and +/// the first term is on the last row. This allows the transition constraint to be: +/// Z(w) = Z(gw) * combine(w) where combine is called on the local row +/// and not the next. This enables CTLs across two rows. pub(crate) fn eval_cross_table_lookup_checks( vars: StarkEvaluationVars, ctl_vars: &[CtlCheckVars], @@ -377,30 +406,28 @@ pub(crate) fn eval_cross_table_lookup_checks P { - let evals = columns.iter().map(|c| c.eval(v)).collect::>(); - challenges.combine(evals.iter()) - }; - let filter = |v: &[P]| -> P { - if let Some(column) = filter_column { - column.eval(v) - } else { - P::ONES - } + + let mut evals = local_columns + .iter() + .map(|c| c.eval(vars.local_values)) + .collect::>(); + evals.extend(next_columns.iter().map(|c| c.eval(vars.next_values))); + let combined = challenges.combine(evals.iter()); + let local_filter = if let Some(column) = filter_column { + column.eval(vars.local_values) + } else { + P::ONES }; - let local_filter = filter(vars.local_values); - let next_filter = filter(vars.next_values); - let select = |filter, x| filter * x + P::ONES - filter; - - // Check value of `Z(1)` - consumer.constraint_first_row(*local_z - select(local_filter, combine(vars.local_values))); - // Check `Z(gw) = combination * Z(w)` - consumer.constraint_transition( - *local_z * select(next_filter, combine(vars.next_values)) - *next_z, - ); + let select = local_filter * combined + P::ONES - local_filter; + + // Check value of `Z(g^(n-1))` + consumer.constraint_last_row(*local_z - select); + // Check `Z(w) = combination * Z(gw)` + consumer.constraint_transition(*next_z * select - *local_z); } } @@ -409,7 +436,8 @@ pub struct CtlCheckVarsTarget<'a, F: Field, const D: usize> { pub(crate) local_z: ExtensionTarget, pub(crate) next_z: ExtensionTarget, pub(crate) challenges: GrandProductChallenge, - pub(crate) columns: &'a [Column], + pub(crate) local_columns: &'a [Column], + pub(crate) next_columns: &'a [Column], pub(crate) filter_column: &'a Option>, } @@ -445,7 +473,8 @@ impl<'a, F: Field, const D: usize> CtlCheckVarsTarget<'a, F, D> { local_z: *looking_z, next_z: *looking_z_next, challenges, - columns: &looking_table.columns, + local_columns: &looking_table.local_columns, + next_columns: &looking_table.next_columns, filter_column: &looking_table.filter_column, }); } @@ -457,7 +486,8 @@ impl<'a, F: Field, const D: usize> CtlCheckVarsTarget<'a, F, D> { local_z: *looked_z, next_z: *looked_z_next, challenges, - columns: &looked_table.columns, + local_columns: &looked_table.local_columns, + next_columns: &looked_table.next_columns, filter_column: &looked_table.filter_column, }); } @@ -483,7 +513,8 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< local_z, next_z, challenges, - columns, + local_columns, + next_columns, filter_column, } = lookup_vars; @@ -493,11 +524,6 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< } else { one }; - let next_filter = if let Some(column) = filter_column { - column.eval_circuit(builder, vars.next_values) - } else { - one - }; fn select, const D: usize>( builder: &mut CircuitBuilder, filter: ExtensionTarget, @@ -508,34 +534,35 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< builder.mul_add_extension(filter, x, tmp) // filter * x + 1 - filter } - // Check value of `Z(1)` - let local_columns_eval = columns + let mut evals = local_columns .iter() .map(|c| c.eval_circuit(builder, vars.local_values)) .collect::>(); - let combined_local = challenges.combine_circuit(builder, &local_columns_eval); - let selected_local = select(builder, local_filter, combined_local); - let first_row = builder.sub_extension(*local_z, selected_local); - consumer.constraint_first_row(builder, first_row); - // Check `Z(gw) = combination * Z(w)` - let next_columns_eval = columns - .iter() - .map(|c| c.eval_circuit(builder, vars.next_values)) - .collect::>(); - let combined_next = challenges.combine_circuit(builder, &next_columns_eval); - let selected_next = select(builder, next_filter, combined_next); - let transition = builder.mul_sub_extension(*local_z, selected_next, *next_z); + evals.extend( + next_columns + .iter() + .map(|c| c.eval_circuit(builder, vars.next_values)), + ); + + let combined = challenges.combine_circuit(builder, &evals); + let select = select(builder, local_filter, combined); + + // Check value of `Z(g^(n-1))` + let last_row = builder.sub_extension(*local_z, select); + consumer.constraint_last_row(builder, last_row); + // Check `Z(w) = combination * Z(gw)` + let transition = builder.mul_sub_extension(*next_z, select, *local_z); consumer.constraint_transition(builder, transition); } } pub(crate) fn verify_cross_table_lookups, const D: usize>( cross_table_lookups: &[CrossTableLookup], - ctl_zs_lasts: [Vec; NUM_TABLES], + ctl_zs_first: [Vec; NUM_TABLES], ctl_extra_looking_products: Vec>, config: &StarkConfig, ) -> Result<()> { - let mut ctl_zs_openings = ctl_zs_lasts.iter().map(|v| v.iter()).collect::>(); + let mut ctl_zs_openings = ctl_zs_first.iter().map(|v| v.iter()).collect::>(); for CrossTableLookup { looking_tables, looked_table, @@ -564,11 +591,11 @@ pub(crate) fn verify_cross_table_lookups, const D: pub(crate) fn verify_cross_table_lookups_circuit, const D: usize>( builder: &mut CircuitBuilder, cross_table_lookups: Vec>, - ctl_zs_lasts: [Vec; NUM_TABLES], + ctl_zs_first: [Vec; NUM_TABLES], ctl_extra_looking_products: Vec>, inner_config: &StarkConfig, ) { - let mut ctl_zs_openings = ctl_zs_lasts.iter().map(|v| v.iter()).collect::>(); + let mut ctl_zs_openings = ctl_zs_first.iter().map(|v| v.iter()).collect::>(); for CrossTableLookup { looking_tables, looked_table, @@ -661,9 +688,15 @@ pub(crate) mod testutils { }; if filter.is_one() { let row = table - .columns + .local_columns .iter() .map(|c| c.eval_table(trace, i)) + .chain( + table + .next_columns + .iter() + .map(|c| c.eval_table(trace, (i + 1) % trace[0].len())), + ) .collect::>(); multiset.entry(row).or_default().push((table.table, i)); } else { diff --git a/evm/src/fixed_recursive_verifier.rs b/evm/src/fixed_recursive_verifier.rs index 72844db69c..ce1c6f5840 100644 --- a/evm/src/fixed_recursive_verifier.rs +++ b/evm/src/fixed_recursive_verifier.rs @@ -510,7 +510,7 @@ where verify_cross_table_lookups_circuit::( &mut builder, all_cross_table_lookups(), - pis.map(|p| p.ctl_zs_last), + pis.map(|p| p.ctl_zs_first), extra_looking_products, stark_config, ); diff --git a/evm/src/keccak/keccak_stark.rs b/evm/src/keccak/keccak_stark.rs index 74f92622fc..28e4e939cb 100644 --- a/evm/src/keccak/keccak_stark.rs +++ b/evm/src/keccak/keccak_stark.rs @@ -763,7 +763,8 @@ mod tests { beta: F::ZERO, gamma: F::ZERO, }, - columns: vec![], + local_columns: vec![], + next_columns: vec![], filter_column: None, }; let ctl_data = CtlData { diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 14f22b6791..76f3af32f0 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -623,7 +623,7 @@ impl, C: GenericConfig, const D: usize> S } pub fn num_ctl_zs(&self) -> usize { - self.openings.ctl_zs_last.len() + self.openings.ctl_zs_first.len() } } @@ -704,8 +704,8 @@ pub struct StarkOpeningSet, const D: usize> { pub permutation_ctl_zs: Vec, /// Openings of permutations and cross-table lookups `Z` polynomials at `g * zeta`. pub permutation_ctl_zs_next: Vec, - /// Openings of cross-table lookups `Z` polynomials at `g^-1`. - pub ctl_zs_last: Vec, + /// Openings of cross-table lookups `Z` polynomials at `1`. + pub ctl_zs_first: Vec, /// Openings of quotient polynomials at `zeta`. pub quotient_polys: Vec, } @@ -717,7 +717,6 @@ impl, const D: usize> StarkOpeningSet { trace_commitment: &PolynomialBatch, permutation_ctl_zs_commitment: &PolynomialBatch, quotient_commitment: &PolynomialBatch, - degree_bits: usize, num_permutation_zs: usize, ) -> Self { let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { @@ -738,10 +737,8 @@ impl, const D: usize> StarkOpeningSet { next_values: eval_commitment(zeta_next, trace_commitment), permutation_ctl_zs: eval_commitment(zeta, permutation_ctl_zs_commitment), permutation_ctl_zs_next: eval_commitment(zeta_next, permutation_ctl_zs_commitment), - ctl_zs_last: eval_commitment_base( - F::primitive_root_of_unity(degree_bits).inverse(), - permutation_ctl_zs_commitment, - )[num_permutation_zs..] + ctl_zs_first: eval_commitment_base(F::ONE, permutation_ctl_zs_commitment) + [num_permutation_zs..] .to_vec(), quotient_polys: eval_commitment(zeta, quotient_commitment), } @@ -765,10 +762,10 @@ impl, const D: usize> StarkOpeningSet { .copied() .collect_vec(), }; - debug_assert!(!self.ctl_zs_last.is_empty()); - let ctl_last_batch = FriOpeningBatch { + debug_assert!(!self.ctl_zs_first.is_empty()); + let ctl_first_batch = FriOpeningBatch { values: self - .ctl_zs_last + .ctl_zs_first .iter() .copied() .map(F::Extension::from_basefield) @@ -776,7 +773,7 @@ impl, const D: usize> StarkOpeningSet { }; FriOpenings { - batches: vec![zeta_batch, zeta_next_batch, ctl_last_batch], + batches: vec![zeta_batch, zeta_next_batch, ctl_first_batch], } } } @@ -787,7 +784,7 @@ pub struct StarkOpeningSetTarget { pub next_values: Vec>, pub permutation_ctl_zs: Vec>, pub permutation_ctl_zs_next: Vec>, - pub ctl_zs_last: Vec, + pub ctl_zs_first: Vec, pub quotient_polys: Vec>, } @@ -797,7 +794,7 @@ impl StarkOpeningSetTarget { buffer.write_target_ext_vec(&self.next_values)?; buffer.write_target_ext_vec(&self.permutation_ctl_zs)?; buffer.write_target_ext_vec(&self.permutation_ctl_zs_next)?; - buffer.write_target_vec(&self.ctl_zs_last)?; + buffer.write_target_vec(&self.ctl_zs_first)?; buffer.write_target_ext_vec(&self.quotient_polys)?; Ok(()) } @@ -807,7 +804,7 @@ impl StarkOpeningSetTarget { let next_values = buffer.read_target_ext_vec::()?; let permutation_ctl_zs = buffer.read_target_ext_vec::()?; let permutation_ctl_zs_next = buffer.read_target_ext_vec::()?; - let ctl_zs_last = buffer.read_target_vec()?; + let ctl_zs_first = buffer.read_target_vec()?; let quotient_polys = buffer.read_target_ext_vec::()?; Ok(Self { @@ -815,7 +812,7 @@ impl StarkOpeningSetTarget { next_values, permutation_ctl_zs, permutation_ctl_zs_next, - ctl_zs_last, + ctl_zs_first, quotient_polys, }) } @@ -838,10 +835,10 @@ impl StarkOpeningSetTarget { .copied() .collect_vec(), }; - debug_assert!(!self.ctl_zs_last.is_empty()); - let ctl_last_batch = FriOpeningBatchTarget { + debug_assert!(!self.ctl_zs_first.is_empty()); + let ctl_first_batch = FriOpeningBatchTarget { values: self - .ctl_zs_last + .ctl_zs_first .iter() .copied() .map(|t| t.to_ext_target(zero)) @@ -849,7 +846,7 @@ impl StarkOpeningSetTarget { }; FriOpeningsTarget { - batches: vec![zeta_batch, zeta_next_batch, ctl_last_batch], + batches: vec![zeta_batch, zeta_next_batch, ctl_first_batch], } } } diff --git a/evm/src/prover.rs b/evm/src/prover.rs index 31be89e701..989b1e22ad 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -433,7 +433,6 @@ where trace_commitment, &permutation_ctl_zs_commitment, "ient_commitment, - degree_bits, stark.num_permutation_batches(config), ); challenger.observe_openings(&openings.to_fri_openings()); @@ -448,7 +447,7 @@ where timing, "compute openings proof", PolynomialBatch::prove_openings( - &stark.fri_instance(zeta, g, degree_bits, ctl_data.len(), config), + &stark.fri_instance(zeta, g, ctl_data.len(), config), &initial_merkle_trees, challenger, &fri_params, @@ -570,7 +569,8 @@ where next_z: permutation_ctl_zs_commitment.get_lde_values_packed(i_next_start, step) [num_permutation_zs + i], challenges: zs_columns.challenge, - columns: &zs_columns.columns, + local_columns: &zs_columns.local_columns, + next_columns: &zs_columns.next_columns, filter_column: &zs_columns.filter_column, }) .collect::>(); @@ -688,7 +688,8 @@ fn check_constraints<'a, F, C, S, const D: usize>( local_z: permutation_ctl_zs_subgroup_evals[i][num_permutation_zs + iii], next_z: permutation_ctl_zs_subgroup_evals[i_next][num_permutation_zs + iii], challenges: zs_columns.challenge, - columns: &zs_columns.columns, + local_columns: &zs_columns.local_columns, + next_columns: &zs_columns.next_columns, filter_column: &zs_columns.filter_column, }) .collect::>(); diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index e669f4ab35..8a9661bf0d 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -59,7 +59,7 @@ pub struct RecursiveAllProof< pub(crate) struct PublicInputs> { pub(crate) trace_cap: Vec>, - pub(crate) ctl_zs_last: Vec, + pub(crate) ctl_zs_first: Vec, pub(crate) ctl_challenges: GrandProductChallengeSet, pub(crate) challenger_state_before: P, pub(crate) challenger_state_after: P, @@ -85,11 +85,11 @@ impl> Public }; let challenger_state_before = P::new(&mut iter); let challenger_state_after = P::new(&mut iter); - let ctl_zs_last: Vec<_> = iter.collect(); + let ctl_zs_first: Vec<_> = iter.collect(); Self { trace_cap, - ctl_zs_last, + ctl_zs_first, ctl_challenges, challenger_state_before, challenger_state_after, @@ -150,7 +150,7 @@ impl, C: GenericConfig, const D: usize> // Verify the CTL checks. verify_cross_table_lookups::( &cross_table_lookups, - pis.map(|p| p.ctl_zs_last), + pis.map(|p| p.ctl_zs_first), extra_looking_products, inner_config, )?; @@ -350,7 +350,7 @@ where let challenger_state = challenger.compact(&mut builder); builder.register_public_inputs(challenger_state.as_ref()); - builder.register_public_inputs(&proof_target.openings.ctl_zs_last); + builder.register_public_inputs(&proof_target.openings.ctl_zs_first); verify_stark_proof_with_challenges_circuit::( &mut builder, @@ -414,7 +414,7 @@ fn verify_stark_proof_with_challenges_circuit< next_values, permutation_ctl_zs, permutation_ctl_zs_next, - ctl_zs_last, + ctl_zs_first, quotient_polys, } = &proof.openings; let vars = StarkEvaluationTargets { @@ -484,8 +484,7 @@ fn verify_stark_proof_with_challenges_circuit< builder, challenges.stark_zeta, F::primitive_root_of_unity(degree_bits), - degree_bits, - ctl_zs_last.len(), + ctl_zs_first.len(), inner_config, ); builder.verify_fri_proof::( @@ -869,7 +868,7 @@ fn add_virtual_stark_opening_set, S: Stark, c .add_virtual_extension_targets(stark.num_permutation_batches(config) + num_ctl_zs), permutation_ctl_zs_next: builder .add_virtual_extension_targets(stark.num_permutation_batches(config) + num_ctl_zs), - ctl_zs_last: builder.add_virtual_targets(num_ctl_zs), + ctl_zs_first: builder.add_virtual_targets(num_ctl_zs), quotient_polys: builder .add_virtual_extension_targets(stark.quotient_degree_factor() * num_challenges), } diff --git a/evm/src/stark.rs b/evm/src/stark.rs index 72cee0ad60..73b51ada41 100644 --- a/evm/src/stark.rs +++ b/evm/src/stark.rs @@ -84,7 +84,6 @@ pub trait Stark, const D: usize>: Sync { &self, zeta: F::Extension, g: F, - degree_bits: usize, num_ctl_zs: usize, config: &StarkConfig, ) -> FriInstanceInfo { @@ -131,13 +130,13 @@ pub trait Stark, const D: usize>: Sync { point: zeta.scalar_mul(g), polynomials: [trace_info, permutation_ctl_zs_info].concat(), }; - let ctl_last_batch = FriBatchInfo { - point: F::Extension::primitive_root_of_unity(degree_bits).inverse(), + let ctl_first_batch = FriBatchInfo { + point: F::Extension::ONE, polynomials: ctl_zs_info, }; FriInstanceInfo { oracles: vec![trace_oracle, permutation_ctl_oracle, quotient_oracle], - batches: vec![zeta_batch, zeta_next_batch, ctl_last_batch], + batches: vec![zeta_batch, zeta_next_batch, ctl_first_batch], } } @@ -147,7 +146,6 @@ pub trait Stark, const D: usize>: Sync { builder: &mut CircuitBuilder, zeta: ExtensionTarget, g: F, - degree_bits: usize, num_ctl_zs: usize, inner_config: &StarkConfig, ) -> FriInstanceInfoTarget { @@ -195,14 +193,13 @@ pub trait Stark, const D: usize>: Sync { point: zeta_next, polynomials: [trace_info, permutation_ctl_zs_info].concat(), }; - let ctl_last_batch = FriBatchInfoTarget { - point: builder - .constant_extension(F::Extension::primitive_root_of_unity(degree_bits).inverse()), + let ctl_first_batch = FriBatchInfoTarget { + point: builder.one_extension(), polynomials: ctl_zs_info, }; FriInstanceInfoTarget { oracles: vec![trace_oracle, permutation_ctl_oracle, quotient_oracle], - batches: vec![zeta_batch, zeta_next_batch, ctl_last_batch], + batches: vec![zeta_batch, zeta_next_batch, ctl_first_batch], } } diff --git a/evm/src/verifier.rs b/evm/src/verifier.rs index 49225f1426..c54ceefcd9 100644 --- a/evm/src/verifier.rs +++ b/evm/src/verifier.rs @@ -128,7 +128,9 @@ where verify_cross_table_lookups::( cross_table_lookups, - all_proof.stark_proofs.map(|p| p.proof.openings.ctl_zs_last), + all_proof + .stark_proofs + .map(|p| p.proof.openings.ctl_zs_first), extra_looking_products, config, ) @@ -301,7 +303,7 @@ where next_values, permutation_ctl_zs, permutation_ctl_zs_next, - ctl_zs_last, + ctl_zs_first, quotient_polys, } = &proof.openings; let vars = StarkEvaluationVars { @@ -367,8 +369,7 @@ where &stark.fri_instance( challenges.stark_zeta, F::primitive_root_of_unity(degree_bits), - degree_bits, - ctl_zs_last.len(), + ctl_zs_first.len(), config, ), &proof.openings.to_fri_openings(), @@ -408,7 +409,7 @@ where next_values, permutation_ctl_zs, permutation_ctl_zs_next, - ctl_zs_last, + ctl_zs_first, quotient_polys, } = openings; @@ -425,7 +426,7 @@ where ensure!(next_values.len() == S::COLUMNS); ensure!(permutation_ctl_zs.len() == num_zs); ensure!(permutation_ctl_zs_next.len() == num_zs); - ensure!(ctl_zs_last.len() == num_ctl_zs); + ensure!(ctl_zs_first.len() == num_ctl_zs); ensure!(quotient_polys.len() == stark.num_quotient_polys(config)); Ok(()) From 61a1c246db47e41d7a5ded70ea6c4b9f7be16854 Mon Sep 17 00:00:00 2001 From: Hamy Ratoanina Date: Wed, 13 Sep 2023 10:55:27 -0400 Subject: [PATCH 2/3] Fix CTLs --- evm/src/all_stark.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 62788a5755..f374781a2b 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -128,16 +128,19 @@ fn ctl_byte_packing() -> CrossTableLookup { let cpu_packing_looking = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_byte_packing(), + vec![], Some(cpu_stark::ctl_filter_byte_packing()), ); let cpu_unpacking_looking = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_byte_unpacking(), + vec![], Some(cpu_stark::ctl_filter_byte_unpacking()), ); let byte_packing_looked = TableWithColumns::new( Table::BytePacking, byte_packing_stark::ctl_looked_data(), + vec![], Some(byte_packing_stark::ctl_looked_filter()), ); CrossTableLookup::new( @@ -231,6 +234,7 @@ fn ctl_memory() -> CrossTableLookup { TableWithColumns::new( Table::BytePacking, byte_packing_stark::ctl_looking_memory(i), + vec![], Some(byte_packing_stark::ctl_looking_memory_filter(i)), ) }); From 1a4caaa08f587ce1e92e01b5ffa66ca79861d01a Mon Sep 17 00:00:00 2001 From: Hamy Ratoanina Date: Fri, 15 Sep 2023 18:14:07 -0400 Subject: [PATCH 3/3] Move next row logic inside Column Co-authored-by: Nicholas Ward --- evm/src/all_stark.rs | 22 +-- evm/src/arithmetic/arithmetic_stark.rs | 1 - evm/src/cpu/cpu_stark.rs | 8 +- evm/src/cross_table_lookup.rs | 198 ++++++++++++++++--------- evm/src/keccak/keccak_stark.rs | 3 +- evm/src/prover.rs | 6 +- 6 files changed, 137 insertions(+), 101 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index f374781a2b..068b0bcbf9 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -128,19 +128,16 @@ fn ctl_byte_packing() -> CrossTableLookup { let cpu_packing_looking = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_byte_packing(), - vec![], Some(cpu_stark::ctl_filter_byte_packing()), ); let cpu_unpacking_looking = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_byte_unpacking(), - vec![], Some(cpu_stark::ctl_filter_byte_unpacking()), ); let byte_packing_looked = TableWithColumns::new( Table::BytePacking, byte_packing_stark::ctl_looked_data(), - vec![], Some(byte_packing_stark::ctl_looked_filter()), ); CrossTableLookup::new( @@ -153,13 +150,11 @@ fn ctl_keccak() -> CrossTableLookup { let keccak_sponge_looking = TableWithColumns::new( Table::KeccakSponge, keccak_sponge_stark::ctl_looking_keccak(), - vec![], Some(keccak_sponge_stark::ctl_looking_keccak_filter()), ); let keccak_looked = TableWithColumns::new( Table::Keccak, keccak_stark::ctl_data(), - vec![], Some(keccak_stark::ctl_filter()), ); CrossTableLookup::new(vec![keccak_sponge_looking], keccak_looked) @@ -169,13 +164,11 @@ fn ctl_keccak_sponge() -> CrossTableLookup { let cpu_looking = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_keccak_sponge(), - vec![], Some(cpu_stark::ctl_filter_keccak_sponge()), ); let keccak_sponge_looked = TableWithColumns::new( Table::KeccakSponge, keccak_sponge_stark::ctl_looked_data(), - vec![], Some(keccak_sponge_stark::ctl_looked_filter()), ); CrossTableLookup::new(vec![cpu_looking], keccak_sponge_looked) @@ -185,7 +178,6 @@ fn ctl_logic() -> CrossTableLookup { let cpu_looking = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_logic(), - vec![], Some(cpu_stark::ctl_filter_logic()), ); let mut all_lookers = vec![cpu_looking]; @@ -193,17 +185,12 @@ fn ctl_logic() -> CrossTableLookup { let keccak_sponge_looking = TableWithColumns::new( Table::KeccakSponge, keccak_sponge_stark::ctl_looking_logic(i), - vec![], Some(keccak_sponge_stark::ctl_looking_logic_filter()), ); all_lookers.push(keccak_sponge_looking); } - let logic_looked = TableWithColumns::new( - Table::Logic, - logic::ctl_data(), - vec![], - Some(logic::ctl_filter()), - ); + let logic_looked = + TableWithColumns::new(Table::Logic, logic::ctl_data(), Some(logic::ctl_filter())); CrossTableLookup::new(all_lookers, logic_looked) } @@ -211,14 +198,12 @@ fn ctl_memory() -> CrossTableLookup { let cpu_memory_code_read = TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_code_memory(), - vec![], Some(cpu_stark::ctl_filter_code_memory()), ); let cpu_memory_gp_ops = (0..NUM_GP_CHANNELS).map(|channel| { TableWithColumns::new( Table::Cpu, cpu_stark::ctl_data_gp_memory(channel), - vec![], Some(cpu_stark::ctl_filter_gp_memory(channel)), ) }); @@ -226,7 +211,6 @@ fn ctl_memory() -> CrossTableLookup { TableWithColumns::new( Table::KeccakSponge, keccak_sponge_stark::ctl_looking_memory(i), - vec![], Some(keccak_sponge_stark::ctl_looking_memory_filter(i)), ) }); @@ -234,7 +218,6 @@ fn ctl_memory() -> CrossTableLookup { TableWithColumns::new( Table::BytePacking, byte_packing_stark::ctl_looking_memory(i), - vec![], Some(byte_packing_stark::ctl_looking_memory_filter(i)), ) }); @@ -246,7 +229,6 @@ fn ctl_memory() -> CrossTableLookup { let memory_looked = TableWithColumns::new( Table::Memory, memory_stark::ctl_data(), - vec![], Some(memory_stark::ctl_filter()), ); CrossTableLookup::new(all_lookers, memory_looked) diff --git a/evm/src/arithmetic/arithmetic_stark.rs b/evm/src/arithmetic/arithmetic_stark.rs index 034620a403..5441cf2760 100644 --- a/evm/src/arithmetic/arithmetic_stark.rs +++ b/evm/src/arithmetic/arithmetic_stark.rs @@ -96,7 +96,6 @@ pub fn ctl_arithmetic_rows() -> TableWithColumns { TableWithColumns::new( Table::Arithmetic, cpu_arith_data_link(&COMBINED_OPS, ®ISTER_MAP), - vec![], filter_column, ) } diff --git a/evm/src/cpu/cpu_stark.rs b/evm/src/cpu/cpu_stark.rs index 6623b67e2a..1579b3a1c3 100644 --- a/evm/src/cpu/cpu_stark.rs +++ b/evm/src/cpu/cpu_stark.rs @@ -103,7 +103,6 @@ pub fn ctl_arithmetic_base_rows() -> TableWithColumns { TableWithColumns::new( Table::Cpu, columns, - vec![], Some(Column::sum([ COL_MAP.op.binary_op, COL_MAP.op.fp254_op, @@ -121,12 +120,7 @@ pub fn ctl_arithmetic_shift_rows() -> TableWithColumns { // (also `ops` is used as the operation filter). The list of // operations includes binary operations which will simply ignore // the third input. - TableWithColumns::new( - Table::Cpu, - columns, - vec![], - Some(Column::single(COL_MAP.op.shift)), - ) + TableWithColumns::new(Table::Cpu, columns, Some(Column::single(COL_MAP.op.shift))) } pub fn ctl_data_byte_packing() -> Vec> { diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index ecc6a34cd7..315bf42f7b 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -25,6 +25,7 @@ use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; #[derive(Clone, Debug)] pub struct Column { linear_combination: Vec<(usize, F)>, + next_row_linear_combination: Vec<(usize, F)>, constant: F, } @@ -32,6 +33,7 @@ impl Column { pub fn single(c: usize) -> Self { Self { linear_combination: vec![(c, F::ONE)], + next_row_linear_combination: vec![], constant: F::ZERO, } } @@ -42,9 +44,24 @@ impl Column { cs.into_iter().map(|c| Self::single(*c.borrow())) } + pub fn single_next_row(c: usize) -> Self { + Self { + linear_combination: vec![], + next_row_linear_combination: vec![(c, F::ONE)], + constant: F::ZERO, + } + } + + pub fn singles_next_row>>( + cs: I, + ) -> impl Iterator { + cs.into_iter().map(|c| Self::single_next_row(*c.borrow())) + } + pub fn constant(constant: F) -> Self { Self { linear_combination: vec![], + next_row_linear_combination: vec![], constant, } } @@ -70,6 +87,34 @@ impl Column { ); Self { linear_combination: v, + next_row_linear_combination: vec![], + constant, + } + } + + pub fn linear_combination_and_next_row_with_constant>( + iter: I, + next_row_iter: I, + constant: F, + ) -> Self { + let v = iter.into_iter().collect::>(); + let next_row_v = next_row_iter.into_iter().collect::>(); + + assert!(!v.is_empty() || !next_row_v.is_empty()); + debug_assert_eq!( + v.iter().map(|(c, _)| c).unique().count(), + v.len(), + "Duplicate columns." + ); + debug_assert_eq!( + next_row_v.iter().map(|(c, _)| c).unique().count(), + next_row_v.len(), + "Duplicate columns." + ); + + Self { + linear_combination: v, + next_row_linear_combination: next_row_v, constant, } } @@ -106,13 +151,43 @@ impl Column { + FE::from_basefield(self.constant) } + pub fn eval_with_next(&self, v: &[P], next_v: &[P]) -> P + where + FE: FieldExtension, + P: PackedField, + { + self.linear_combination + .iter() + .map(|&(c, f)| v[c] * FE::from_basefield(f)) + .sum::

() + + self + .next_row_linear_combination + .iter() + .map(|&(c, f)| next_v[c] * FE::from_basefield(f)) + .sum::

() + + FE::from_basefield(self.constant) + } + /// Evaluate on an row of a table given in column-major form. pub fn eval_table(&self, table: &[PolynomialValues], row: usize) -> F { - self.linear_combination + let mut res = self + .linear_combination .iter() .map(|&(c, f)| table[c].values[row] * f) .sum::() - + self.constant + + self.constant; + + // If we access the next row at the last row, for sanity, we consider the next row's values to be 0. + // If CTLs are correctly written, the filter should be 0 in that case anyway. + if !self.next_row_linear_combination.is_empty() && row < table.len() - 1 { + res += self + .next_row_linear_combination + .iter() + .map(|&(c, f)| table[c].values[row + 1] * f) + .sum::(); + } + + res } pub fn eval_circuit( @@ -136,27 +211,50 @@ impl Column { let constant = builder.constant_extension(F::Extension::from_basefield(self.constant)); builder.inner_product_extension(F::ONE, constant, pairs) } + + pub fn eval_with_next_circuit( + &self, + builder: &mut CircuitBuilder, + v: &[ExtensionTarget], + next_v: &[ExtensionTarget], + ) -> ExtensionTarget + where + F: RichField + Extendable, + { + let mut pairs = self + .linear_combination + .iter() + .map(|&(c, f)| { + ( + v[c], + builder.constant_extension(F::Extension::from_basefield(f)), + ) + }) + .collect::>(); + let next_row_pairs = self.next_row_linear_combination.iter().map(|&(c, f)| { + ( + next_v[c], + builder.constant_extension(F::Extension::from_basefield(f)), + ) + }); + pairs.extend(next_row_pairs); + let constant = builder.constant_extension(F::Extension::from_basefield(self.constant)); + builder.inner_product_extension(F::ONE, constant, pairs) + } } #[derive(Clone, Debug)] pub struct TableWithColumns { table: Table, - local_columns: Vec>, - next_columns: Vec>, + columns: Vec>, pub(crate) filter_column: Option>, } impl TableWithColumns { - pub fn new( - table: Table, - local_columns: Vec>, - next_columns: Vec>, - filter_column: Option>, - ) -> Self { + pub fn new(table: Table, columns: Vec>, filter_column: Option>) -> Self { Self { table, - local_columns, - next_columns, + columns, filter_column, } } @@ -175,8 +273,7 @@ impl CrossTableLookup { ) -> Self { assert!(looking_tables .iter() - .all(|twc| (twc.local_columns.len() + twc.next_columns.len()) - == (looked_table.local_columns.len() + looked_table.next_columns.len()))); + .all(|twc| twc.columns.len() == looked_table.columns.len())); Self { looking_tables, looked_table, @@ -204,8 +301,7 @@ pub struct CtlData { pub(crate) struct CtlZData { pub(crate) z: PolynomialValues, pub(crate) challenge: GrandProductChallenge, - pub(crate) local_columns: Vec>, - pub(crate) next_columns: Vec>, + pub(crate) columns: Vec>, pub(crate) filter_column: Option>, } @@ -242,16 +338,14 @@ pub(crate) fn cross_table_lookup_data( let zs_looking = looking_tables.iter().map(|table| { partial_products( &trace_poly_values[table.table as usize], - &table.local_columns, - &table.next_columns, + &table.columns, &table.filter_column, challenge, ) }); let z_looked = partial_products( &trace_poly_values[looked_table.table as usize], - &looked_table.local_columns, - &looked_table.next_columns, + &looked_table.columns, &looked_table.filter_column, challenge, ); @@ -261,8 +355,7 @@ pub(crate) fn cross_table_lookup_data( .push(CtlZData { z, challenge, - local_columns: table.local_columns.clone(), - next_columns: table.next_columns.clone(), + columns: table.columns.clone(), filter_column: table.filter_column.clone(), }); } @@ -271,8 +364,7 @@ pub(crate) fn cross_table_lookup_data( .push(CtlZData { z: z_looked, challenge, - local_columns: looked_table.local_columns.clone(), - next_columns: looked_table.next_columns.clone(), + columns: looked_table.columns.clone(), filter_column: looked_table.filter_column.clone(), }); } @@ -282,8 +374,7 @@ pub(crate) fn cross_table_lookup_data( fn partial_products( trace: &[PolynomialValues], - local_columns: &[Column], - next_columns: &[Column], + columns: &[Column], filter_column: &Option>, challenge: GrandProductChallenge, ) -> PolynomialValues { @@ -297,16 +388,9 @@ fn partial_products( F::ONE }; if filter.is_one() { - let evals = local_columns + let evals = columns .iter() .map(|c| c.eval_table(trace, i)) - .chain( - next_columns - .iter() - // The modulo is there to avoid out of bounds. For any CTL using next row - // values, we expect the filter to be 0 at the last row. - .map(|c| c.eval_table(trace, (i + 1) % degree)), - ) .collect::>(); partial_prod *= challenge.combine(evals.iter()); } else { @@ -328,8 +412,7 @@ where pub(crate) local_z: P, pub(crate) next_z: P, pub(crate) challenges: GrandProductChallenge, - pub(crate) local_columns: &'a [Column], - pub(crate) next_columns: &'a [Column], + pub(crate) columns: &'a [Column], pub(crate) filter_column: &'a Option>, } @@ -366,8 +449,7 @@ impl<'a, F: RichField + Extendable, const D: usize> local_z: *looking_z, next_z: *looking_z_next, challenges, - local_columns: &table.local_columns, - next_columns: &table.next_columns, + columns: &table.columns, filter_column: &table.filter_column, }); } @@ -377,8 +459,7 @@ impl<'a, F: RichField + Extendable, const D: usize> local_z: *looked_z, next_z: *looked_z_next, challenges, - local_columns: &looked_table.local_columns, - next_columns: &looked_table.next_columns, + columns: &looked_table.columns, filter_column: &looked_table.filter_column, }); } @@ -406,16 +487,14 @@ pub(crate) fn eval_cross_table_lookup_checks>(); - evals.extend(next_columns.iter().map(|c| c.eval(vars.next_values))); let combined = challenges.combine(evals.iter()); let local_filter = if let Some(column) = filter_column { column.eval(vars.local_values) @@ -436,8 +515,7 @@ pub struct CtlCheckVarsTarget<'a, F: Field, const D: usize> { pub(crate) local_z: ExtensionTarget, pub(crate) next_z: ExtensionTarget, pub(crate) challenges: GrandProductChallenge, - pub(crate) local_columns: &'a [Column], - pub(crate) next_columns: &'a [Column], + pub(crate) columns: &'a [Column], pub(crate) filter_column: &'a Option>, } @@ -473,8 +551,7 @@ impl<'a, F: Field, const D: usize> CtlCheckVarsTarget<'a, F, D> { local_z: *looking_z, next_z: *looking_z_next, challenges, - local_columns: &looking_table.local_columns, - next_columns: &looking_table.next_columns, + columns: &looking_table.columns, filter_column: &looking_table.filter_column, }); } @@ -486,8 +563,7 @@ impl<'a, F: Field, const D: usize> CtlCheckVarsTarget<'a, F, D> { local_z: *looked_z, next_z: *looked_z_next, challenges, - local_columns: &looked_table.local_columns, - next_columns: &looked_table.next_columns, + columns: &looked_table.columns, filter_column: &looked_table.filter_column, }); } @@ -513,8 +589,7 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< local_z, next_z, challenges, - local_columns, - next_columns, + columns, filter_column, } = lookup_vars; @@ -534,15 +609,10 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< builder.mul_add_extension(filter, x, tmp) // filter * x + 1 - filter } - let mut evals = local_columns + let evals = columns .iter() - .map(|c| c.eval_circuit(builder, vars.local_values)) + .map(|c| c.eval_with_next_circuit(builder, vars.local_values, vars.next_values)) .collect::>(); - evals.extend( - next_columns - .iter() - .map(|c| c.eval_circuit(builder, vars.next_values)), - ); let combined = challenges.combine_circuit(builder, &evals); let select = select(builder, local_filter, combined); @@ -692,15 +762,9 @@ pub(crate) mod testutils { }; if filter.is_one() { let row = table - .local_columns + .columns .iter() .map(|c| c.eval_table(trace, i)) - .chain( - table - .next_columns - .iter() - .map(|c| c.eval_table(trace, (i + 1) % trace[0].len())), - ) .collect::>(); multiset.entry(row).or_default().push((table.table, i)); } else { diff --git a/evm/src/keccak/keccak_stark.rs b/evm/src/keccak/keccak_stark.rs index 28e4e939cb..74f92622fc 100644 --- a/evm/src/keccak/keccak_stark.rs +++ b/evm/src/keccak/keccak_stark.rs @@ -763,8 +763,7 @@ mod tests { beta: F::ZERO, gamma: F::ZERO, }, - local_columns: vec![], - next_columns: vec![], + columns: vec![], filter_column: None, }; let ctl_data = CtlData { diff --git a/evm/src/prover.rs b/evm/src/prover.rs index 330dfcd1a8..0426da8ec5 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -589,8 +589,7 @@ where next_z: permutation_ctl_zs_commitment.get_lde_values_packed(i_next_start, step) [num_permutation_zs + i], challenges: zs_columns.challenge, - local_columns: &zs_columns.local_columns, - next_columns: &zs_columns.next_columns, + columns: &zs_columns.columns, filter_column: &zs_columns.filter_column, }) .collect::>(); @@ -708,8 +707,7 @@ fn check_constraints<'a, F, C, S, const D: usize>( local_z: permutation_ctl_zs_subgroup_evals[i][num_permutation_zs + iii], next_z: permutation_ctl_zs_subgroup_evals[i_next][num_permutation_zs + iii], challenges: zs_columns.challenge, - local_columns: &zs_columns.local_columns, - next_columns: &zs_columns.next_columns, + columns: &zs_columns.columns, filter_column: &zs_columns.filter_column, }) .collect::>();