From 820456fc88a36a8bf7eaca309c2cd68a8644ef2b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 6 Jun 2022 20:51:14 +0200 Subject: [PATCH 1/9] Add TableWithColumns struct --- evm/src/all_stark.rs | 12 ++-- evm/src/cross_table_lookup.rs | 118 ++++++++++++++++++---------------- 2 files changed, 68 insertions(+), 62 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 4ef79314..d355bdae 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -61,7 +61,7 @@ mod tests { use crate::config::StarkConfig; use crate::cpu; use crate::cpu::cpu_stark::CpuStark; - use crate::cross_table_lookup::CrossTableLookup; + use crate::cross_table_lookup::{CrossTableLookup, TableWithColumns}; use crate::keccak::keccak_stark::KeccakStark; use crate::proof::AllProof; use crate::prover::prove; @@ -104,10 +104,12 @@ mod tests { let default = vec![F::ZERO; 2]; let cross_table_lookups = vec![CrossTableLookup { - looking_tables: vec![Table::Cpu], - looking_columns: vec![vec![cpu::columns::OPCODE]], - looked_table: Table::Keccak, - looked_columns: vec![keccak_looked_col], + looking_tables: vec![TableWithColumns::new( + Table::Cpu, + vec![cpu::columns::OPCODE], + None, + )], + looked_table: TableWithColumns::new(Table::Keccak, vec![keccak_looked_col], None), default, }]; diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index f4887b68..be4c0371 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -1,5 +1,4 @@ use anyhow::{ensure, Result}; -use itertools::izip; use plonky2::field::extension_field::{Extendable, FieldExtension}; use plonky2::field::field_types::Field; use plonky2::field::packed_field::PackedField; @@ -21,32 +20,42 @@ use crate::proof::{StarkProofWithPublicInputs, StarkProofWithPublicInputsTarget} use crate::stark::Stark; use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; +#[derive(Clone)] +pub struct TableWithColumns { + pub table: Table, + pub columns: Vec, + pub filter_column: Option, +} + +impl TableWithColumns { + pub fn new(table: Table, columns: Vec, filter_column: Option) -> Self { + Self { + table, + columns, + filter_column, + } + } +} + #[derive(Clone)] pub struct CrossTableLookup { - pub looking_tables: Vec, - pub looking_columns: Vec>, - pub looked_table: Table, - pub looked_columns: Vec, + pub looking_tables: Vec, + pub looked_table: TableWithColumns, pub default: Vec, } impl CrossTableLookup { pub fn new( - looking_tables: Vec
, - looking_columns: Vec>, - looked_table: Table, - looked_columns: Vec, + looking_tables: Vec, + looked_table: TableWithColumns, default: Vec, ) -> Self { - assert_eq!(looking_tables.len(), looking_columns.len()); - assert!(looking_columns + assert!(looking_tables .iter() - .all(|cols| cols.len() == looked_columns.len())); + .all(|twc| twc.columns.len() == looked_table.columns.len())); Self { looking_tables, - looking_columns, looked_table, - looked_columns, default, } } @@ -92,22 +101,21 @@ pub fn cross_table_lookup_data, const D let mut ctl_data_per_table = vec![CtlData::new(challenges.clone()); trace_poly_values.len()]; for CrossTableLookup { looking_tables, - looking_columns, looked_table, - looked_columns, default, } in cross_table_lookups { for &challenge in &challenges.challenges { - let zs_looking = looking_tables - .iter() - .zip(looking_columns) - .map(|(table, columns)| { - partial_products(&trace_poly_values[*table as usize], columns, challenge) - }); + let zs_looking = looking_tables.iter().map(|table| { + partial_products( + &trace_poly_values[table.table as usize], + &table.columns, + challenge, + ) + }); let z_looked = partial_products( - &trace_poly_values[*looked_table as usize], - looked_columns, + &trace_poly_values[looked_table.table as usize], + &looked_table.columns, challenge, ); @@ -120,20 +128,20 @@ pub fn cross_table_lookup_data, const D * challenge.combine(default).exp_u64( looking_tables .iter() - .map(|table| trace_poly_values[*table as usize][0].len() as u64) + .map(|table| trace_poly_values[table.table as usize][0].len() as u64) .sum::() - - trace_poly_values[*looked_table as usize][0].len() as u64 + - trace_poly_values[looked_table.table as usize][0].len() as u64 ) ); - for (table, columns, z) in izip!(looking_tables, looking_columns, zs_looking) { - ctl_data_per_table[*table as usize] + for (table, z) in looking_tables.iter().zip(zs_looking) { + ctl_data_per_table[table.table as usize] .zs_columns - .push((z, columns.clone())); + .push((z, table.columns.clone())); } - ctl_data_per_table[*looked_table as usize] + ctl_data_per_table[looked_table.table as usize] .zs_columns - .push((z_looked, looked_columns.clone())); + .push((z_looked, looked_table.columns.clone())); } } ctl_data_per_table @@ -191,29 +199,27 @@ impl<'a, F: RichField + Extendable, const D: usize> let mut ctl_vars_per_table = vec![vec![]; proofs.len()]; for CrossTableLookup { looking_tables, - looking_columns, looked_table, - looked_columns, .. } in cross_table_lookups { for &challenges in &ctl_challenges.challenges { - for (table, columns) in looking_tables.iter().zip(looking_columns) { - let (looking_z, looking_z_next) = ctl_zs[*table as usize].next().unwrap(); - ctl_vars_per_table[*table as usize].push(Self { + for table in looking_tables { + let (looking_z, looking_z_next) = ctl_zs[table.table as usize].next().unwrap(); + ctl_vars_per_table[table.table as usize].push(Self { local_z: *looking_z, next_z: *looking_z_next, challenges, - columns, + columns: &table.columns, }); } - let (looked_z, looked_z_next) = ctl_zs[*looked_table as usize].next().unwrap(); - ctl_vars_per_table[*looked_table as usize].push(Self { + let (looked_z, looked_z_next) = ctl_zs[looked_table.table as usize].next().unwrap(); + ctl_vars_per_table[looked_table.table as usize].push(Self { local_z: *looked_z, next_z: *looked_z_next, challenges, - columns: looked_columns, + columns: &looked_table.columns, }); } } @@ -278,29 +284,27 @@ impl<'a, const D: usize> CtlCheckVarsTarget<'a, D> { let mut ctl_vars_per_table = vec![vec![]; proofs.len()]; for CrossTableLookup { looking_tables, - looking_columns, looked_table, - looked_columns, .. } in cross_table_lookups { for &challenges in &ctl_challenges.challenges { - for (table, columns) in looking_tables.iter().zip(looking_columns) { - let (looking_z, looking_z_next) = ctl_zs[*table as usize].next().unwrap(); - ctl_vars_per_table[*table as usize].push(Self { + for table in looking_tables { + let (looking_z, looking_z_next) = ctl_zs[table.table as usize].next().unwrap(); + ctl_vars_per_table[table.table as usize].push(Self { local_z: *looking_z, next_z: *looking_z_next, challenges, - columns, + columns: &table.columns, }); } - let (looked_z, looked_z_next) = ctl_zs[*looked_table as usize].next().unwrap(); - ctl_vars_per_table[*looked_table as usize].push(Self { + let (looked_z, looked_z_next) = ctl_zs[looked_table.table as usize].next().unwrap(); + ctl_vars_per_table[looked_table.table as usize].push(Self { local_z: *looked_z, next_z: *looked_z_next, challenges, - columns: looked_columns, + columns: &looked_table.columns, }); } } @@ -380,14 +384,14 @@ pub(crate) fn verify_cross_table_lookups< { let looking_degrees_sum = looking_tables .iter() - .map(|&table| 1 << degrees_bits[table as usize]) + .map(|table| 1 << degrees_bits[table.table as usize]) .sum::(); - let looked_degree = 1 << degrees_bits[looked_table as usize]; + let looked_degree = 1 << degrees_bits[looked_table.table as usize]; let looking_zs_prod = looking_tables .into_iter() - .map(|table| *ctl_zs_openings[table as usize].next().unwrap()) + .map(|table| *ctl_zs_openings[table.table as usize].next().unwrap()) .product::(); - let looked_z = *ctl_zs_openings[looked_table as usize].next().unwrap(); + let looked_z = *ctl_zs_openings[looked_table.table as usize].next().unwrap(); let challenge = challenges.challenges[i % config.num_challenges]; let combined_default = challenge.combine(default.iter()); @@ -432,15 +436,15 @@ pub(crate) fn verify_cross_table_lookups_circuit< { let looking_degrees_sum = looking_tables .iter() - .map(|&table| 1 << degrees_bits[table as usize]) + .map(|table| 1 << degrees_bits[table.table as usize]) .sum::(); - let looked_degree = 1 << degrees_bits[looked_table as usize]; + let looked_degree = 1 << degrees_bits[looked_table.table as usize]; let looking_zs_prod = builder.mul_many( looking_tables .into_iter() - .map(|table| *ctl_zs_openings[table as usize].next().unwrap()), + .map(|table| *ctl_zs_openings[table.table as usize].next().unwrap()), ); - let looked_z = *ctl_zs_openings[looked_table as usize].next().unwrap(); + let looked_z = *ctl_zs_openings[looked_table.table as usize].next().unwrap(); let challenge = challenges.challenges[i % inner_config.num_challenges]; let default = default .into_iter() From dcb8c37f459f6daedfbdbd62dd5583e4e3243125 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 7 Jun 2022 17:23:46 +0200 Subject: [PATCH 2/9] Add linear combination of filter columns --- evm/src/all_stark.rs | 4 ++-- evm/src/cross_table_lookup.rs | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index d355bdae..4c36b5b6 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -107,9 +107,9 @@ mod tests { looking_tables: vec![TableWithColumns::new( Table::Cpu, vec![cpu::columns::OPCODE], - None, + vec![], )], - looked_table: TableWithColumns::new(Table::Keccak, vec![keccak_looked_col], None), + looked_table: TableWithColumns::new(Table::Keccak, vec![keccak_looked_col], vec![]), default, }]; diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index be4c0371..c5a0e20a 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use anyhow::{ensure, Result}; use plonky2::field::extension_field::{Extendable, FieldExtension}; use plonky2::field::field_types::Field; @@ -22,17 +24,24 @@ use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; #[derive(Clone)] pub struct TableWithColumns { - pub table: Table, - pub columns: Vec, - pub filter_column: Option, + table: Table, + columns: Vec, + /// Vector of columns `{c_1,...,c_k}` used as a filter using the sum `c_1 + ... + c_k`. + /// An empty vector corresponds to no filter. + filter_columns: Vec, } impl TableWithColumns { - pub fn new(table: Table, columns: Vec, filter_column: Option) -> Self { + pub fn new(table: Table, columns: Vec, filter_columns: Vec) -> Self { + debug_assert_eq!( + filter_columns.iter().collect::>().len(), + filter_columns.len(), + "Duplicate filter columns." + ); Self { table, columns, - filter_column, + filter_columns, } } } From 4deccb094fc7882462c04451d3a08a62149460c1 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 7 Jun 2022 18:08:12 +0200 Subject: [PATCH 3/9] Change partial product --- evm/src/cross_table_lookup.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index c5a0e20a..237c4a54 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -119,12 +119,14 @@ pub fn cross_table_lookup_data, const D partial_products( &trace_poly_values[table.table as usize], &table.columns, + &table.filter_columns, challenge, ) }); let z_looked = partial_products( &trace_poly_values[looked_table.table as usize], &looked_table.columns, + &looked_table.filter_columns, challenge, ); @@ -159,13 +161,23 @@ pub fn cross_table_lookup_data, const D fn partial_products( trace: &[PolynomialValues], columns: &[usize], + filter_columns: &[usize], 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 { - partial_prod *= challenge.combine(columns.iter().map(|&j| &trace[j].values[i])); + let filter = if filter_columns.is_empty() { + 1 + } else { + filter_columns.iter().sum() + }; + partial_prod *= match filter { + 0 => F::ONE, + 1 => challenge.combine(columns.iter().map(|&j| &trace[j].values[i])), + _ => panic!("Non-binary filter?"), + }; res.push(partial_prod); } res.into() From 47fc968b0a0698f4e8024bab03d86fad122ae737 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 7 Jun 2022 22:19:36 +0200 Subject: [PATCH 4/9] Set default to an Option --- evm/src/all_stark.rs | 2 +- evm/src/cross_table_lookup.rs | 51 ++++++++++++++++++++++------------- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 4c36b5b6..47e0420b 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -110,7 +110,7 @@ mod tests { vec![], )], looked_table: TableWithColumns::new(Table::Keccak, vec![keccak_looked_col], vec![]), - default, + default: Some(default), }]; let all_stark = AllStark { diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 237c4a54..d3e9e474 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -50,14 +50,15 @@ impl TableWithColumns { pub struct CrossTableLookup { pub looking_tables: Vec, pub looked_table: TableWithColumns, - pub default: Vec, + /// Default value if filters are not used. + pub default: Option>, } impl CrossTableLookup { pub fn new( looking_tables: Vec, looked_table: TableWithColumns, - default: Vec, + default: Option>, ) -> Self { assert!(looking_tables .iter() @@ -136,13 +137,21 @@ pub fn cross_table_lookup_data, const D .map(|z| *z.values.last().unwrap()) .product::(), *z_looked.values.last().unwrap() - * challenge.combine(default).exp_u64( - looking_tables - .iter() - .map(|table| trace_poly_values[table.table as usize][0].len() as u64) - .sum::() - - trace_poly_values[looked_table.table as usize][0].len() as u64 - ) + * default + .as_ref() + .map(|default| { + challenge.combine(default).exp_u64( + looking_tables + .iter() + .map(|table| { + trace_poly_values[table.table as usize][0].len() as u64 + }) + .sum::() + - trace_poly_values[looked_table.table as usize][0].len() + as u64, + ) + }) + .unwrap_or(F::ONE) ); for (table, z) in looking_tables.iter().zip(zs_looking) { @@ -414,7 +423,9 @@ pub(crate) fn verify_cross_table_lookups< .product::(); let looked_z = *ctl_zs_openings[looked_table.table as usize].next().unwrap(); let challenge = challenges.challenges[i % config.num_challenges]; - let combined_default = challenge.combine(default.iter()); + let combined_default = default + .map(|default| challenge.combine(default.iter())) + .unwrap_or(F::ONE); ensure!( looking_zs_prod @@ -467,14 +478,18 @@ pub(crate) fn verify_cross_table_lookups_circuit< ); let looked_z = *ctl_zs_openings[looked_table.table as usize].next().unwrap(); let challenge = challenges.challenges[i % inner_config.num_challenges]; - let default = default - .into_iter() - .map(|x| builder.constant(x)) - .collect::>(); - let combined_default = challenge.combine_base_circuit(builder, &default); + if let Some(default) = default { + let default = default + .into_iter() + .map(|x| builder.constant(x)) + .collect::>(); + let combined_default = challenge.combine_base_circuit(builder, &default); - let pad = builder.exp_u64(combined_default, looking_degrees_sum - looked_degree); - let padded_looked_z = builder.mul(looked_z, pad); - builder.connect(looking_zs_prod, padded_looked_z); + let pad = builder.exp_u64(combined_default, looking_degrees_sum - looked_degree); + let padded_looked_z = builder.mul(looked_z, pad); + builder.connect(looking_zs_prod, padded_looked_z); + } else { + builder.connect(looking_zs_prod, looked_z); + } } } From 05d2c69eb088f57fd160ed766ea9ad8712debac3 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 7 Jun 2022 23:09:09 +0200 Subject: [PATCH 5/9] Add constraints --- evm/src/all_stark.rs | 2 +- evm/src/cross_table_lookup.rs | 86 ++++++++++++++++++++++++++++------- evm/src/prover.rs | 38 +++++++++------- 3 files changed, 92 insertions(+), 34 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 47e0420b..5fa46c71 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -91,7 +91,7 @@ mod tests { let mut cpu_trace_rows = vec![]; for i in 0..cpu_rows { let mut cpu_trace_row = [F::ZERO; CpuStark::::COLUMNS]; - cpu_trace_row[cpu::columns::IS_CPU_CYCLE] = F::ONE; + cpu_trace_row[cpu::columns::IS_CPU_CYCLE] = F::ZERO; cpu_trace_row[cpu::columns::OPCODE] = F::from_canonical_usize(i); cpu_stark.generate(&mut cpu_trace_row); cpu_trace_rows.push(cpu_trace_row); diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index d3e9e474..83c0bc9f 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -76,8 +76,9 @@ impl CrossTableLookup { pub struct CtlData { /// Challenges used in the argument. pub(crate) challenges: GrandProductChallengeSet, - /// Vector of `(Z, columns)` where `Z` is a Z-polynomial for a lookup on columns `columns`. - pub zs_columns: Vec<(PolynomialValues, Vec)>, + /// Vector of `(Z, columns, filter_columns)` where `Z` is a Z-polynomial for a lookup + /// on columns `columns` with filter columns `filter_columns`. + pub zs_columns: Vec<(PolynomialValues, Vec, Vec)>, } impl CtlData { @@ -97,7 +98,7 @@ impl CtlData { } pub fn z_polys(&self) -> Vec> { - self.zs_columns.iter().map(|(p, _)| p.clone()).collect() + self.zs_columns.iter().map(|(p, _, _)| p.clone()).collect() } } @@ -155,13 +156,19 @@ pub fn cross_table_lookup_data, const D ); for (table, z) in looking_tables.iter().zip(zs_looking) { - ctl_data_per_table[table.table as usize] - .zs_columns - .push((z, table.columns.clone())); + ctl_data_per_table[table.table as usize].zs_columns.push(( + z, + table.columns.clone(), + table.filter_columns.clone(), + )); } ctl_data_per_table[looked_table.table as usize] .zs_columns - .push((z_looked, looked_table.columns.clone())); + .push(( + z_looked, + looked_table.columns.clone(), + looked_table.filter_columns.clone(), + )); } } ctl_data_per_table @@ -178,14 +185,16 @@ fn partial_products( let mut res = Vec::with_capacity(degree); for i in 0..degree { let filter = if filter_columns.is_empty() { - 1 + F::ONE } else { - filter_columns.iter().sum() + filter_columns.iter().map(|&j| trace[j].values[i]).sum() }; - partial_prod *= match filter { - 0 => F::ONE, - 1 => challenge.combine(columns.iter().map(|&j| &trace[j].values[i])), - _ => panic!("Non-binary filter?"), + partial_prod *= if filter.is_zero() { + F::ONE + } else if filter.is_one() { + challenge.combine(columns.iter().map(|&j| &trace[j].values[i])) + } else { + panic!("Non-binary filter?") }; res.push(partial_prod); } @@ -203,6 +212,7 @@ where pub(crate) next_z: P, pub(crate) challenges: GrandProductChallenge, pub(crate) columns: &'a [usize], + pub(crate) filter_columns: &'a [usize], } impl<'a, F: RichField + Extendable, const D: usize> @@ -241,6 +251,7 @@ impl<'a, F: RichField + Extendable, const D: usize> next_z: *looking_z_next, challenges, columns: &table.columns, + filter_columns: &table.filter_columns, }); } @@ -250,6 +261,7 @@ impl<'a, F: RichField + Extendable, const D: usize> next_z: *looked_z_next, challenges, columns: &looked_table.columns, + filter_columns: &looked_table.filter_columns, }); } } @@ -274,13 +286,26 @@ pub(crate) fn eval_cross_table_lookup_checks P { challenges.combine(columns.iter().map(|&i| &v[i])) }; + let filter = |v: &[P]| -> P { + if filter_columns.is_empty() { + P::ONES + } else { + filter_columns.iter().map(|&i| v[i]).sum() + } + }; + 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 - combine(vars.local_values)); + consumer.constraint_first_row(*local_z - select(local_filter, combine(vars.local_values))); // Check `Z(gw) = combination * Z(w)` - consumer.constraint_transition(*next_z - *local_z * combine(vars.next_values)); + consumer.constraint_transition( + *next_z - *local_z * select(next_filter, combine(vars.next_values)), + ); } } @@ -290,6 +315,7 @@ pub struct CtlCheckVarsTarget<'a, const D: usize> { pub(crate) next_z: ExtensionTarget, pub(crate) challenges: GrandProductChallenge, pub(crate) columns: &'a [usize], + pub(crate) filter_columns: &'a [usize], } impl<'a, const D: usize> CtlCheckVarsTarget<'a, D> { @@ -326,6 +352,7 @@ impl<'a, const D: usize> CtlCheckVarsTarget<'a, D> { next_z: *looking_z_next, challenges, columns: &table.columns, + filter_columns: &table.filter_columns, }); } @@ -335,6 +362,7 @@ impl<'a, const D: usize> CtlCheckVarsTarget<'a, D> { next_z: *looked_z_next, challenges, columns: &looked_table.columns, + filter_columns: &looked_table.filter_columns, }); } } @@ -358,8 +386,30 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< next_z, challenges, columns, + filter_columns, } = lookup_vars; + let one = builder.one_extension(); + let local_filter = if filter_columns.is_empty() { + one + } else { + builder.add_many_extension(filter_columns.iter().map(|&i| vars.local_values[i])) + }; + let next_filter = if filter_columns.is_empty() { + one + } else { + builder.add_many_extension(filter_columns.iter().map(|&i| vars.next_values[i])) + }; + fn select, const D: usize>( + builder: &mut CircuitBuilder, + filter: ExtensionTarget, + x: ExtensionTarget, + ) -> ExtensionTarget { + let one = builder.one_extension(); + let tmp = builder.sub_extension(one, filter); + builder.mul_add_extension(filter, x, tmp) // filter * x + 1 - filter + } + // Check value of `Z(1)` let combined_local = challenges.combine_circuit( builder, @@ -368,7 +418,8 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< .map(|&i| vars.local_values[i]) .collect::>(), ); - let first_row = builder.sub_extension(*local_z, combined_local); + 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 combined_next = challenges.combine_circuit( @@ -378,7 +429,8 @@ pub(crate) fn eval_cross_table_lookup_checks_circuit< .map(|&i| vars.next_values[i]) .collect::>(), ); - let mut transition = builder.mul_extension(*local_z, combined_next); + let selected_next = select(builder, next_filter, combined_next); + let mut transition = builder.mul_extension(*local_z, selected_next); transition = builder.sub_extension(*next_z, transition); consumer.constraint_transition(builder, transition); } diff --git a/evm/src/prover.rs b/evm/src/prover.rs index c0cc387a..cf0b9fae 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -391,14 +391,17 @@ where .zs_columns .iter() .enumerate() - .map(|(i, (_, columns))| CtlCheckVars:: { - local_z: permutation_ctl_zs_commitment.get_lde_values_packed(i_start, step) - [num_permutation_zs + i], - next_z: permutation_ctl_zs_commitment.get_lde_values_packed(i_next_start, step) - [num_permutation_zs + i], - challenges: ctl_data.challenges.challenges[i % config.num_challenges], - columns, - }) + .map( + |(i, (_, columns, filter_columns))| CtlCheckVars:: { + local_z: permutation_ctl_zs_commitment.get_lde_values_packed(i_start, step) + [num_permutation_zs + i], + next_z: permutation_ctl_zs_commitment + .get_lde_values_packed(i_next_start, step)[num_permutation_zs + i], + challenges: ctl_data.challenges.challenges[i % config.num_challenges], + columns, + filter_columns, + }, + ) .collect::>(); eval_vanishing_poly::( stark, @@ -506,14 +509,17 @@ fn check_constraints<'a, F, C, S, const D: usize>( .zs_columns .iter() .enumerate() - .map(|(iii, (_, columns))| CtlCheckVars:: { - local_z: get_comm_values(permutation_ctl_zs_commitment, i) - [num_permutation_zs + iii], - next_z: get_comm_values(permutation_ctl_zs_commitment, i_next) - [num_permutation_zs + iii], - challenges: ctl_data.challenges.challenges[iii % config.num_challenges], - columns, - }) + .map( + |(iii, (_, columns, filter_columns))| CtlCheckVars:: { + local_z: get_comm_values(permutation_ctl_zs_commitment, i) + [num_permutation_zs + iii], + next_z: get_comm_values(permutation_ctl_zs_commitment, i_next) + [num_permutation_zs + iii], + challenges: ctl_data.challenges.challenges[iii % config.num_challenges], + columns, + filter_columns, + }, + ) .collect::>(); eval_vanishing_poly::( stark, From f36c012e9c3cde792f4f643f11036abf6fa6b07f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 7 Jun 2022 23:37:35 +0200 Subject: [PATCH 6/9] Checks --- evm/src/cross_table_lookup.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 83c0bc9f..163ad363 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -26,7 +26,7 @@ use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; pub struct TableWithColumns { table: Table, columns: Vec, - /// Vector of columns `{c_1,...,c_k}` used as a filter using the sum `c_1 + ... + c_k`. + /// Vector of columns `[c_1,...,c_k]` used as a filter using the sum `c_1 + ... + c_k`. /// An empty vector corresponds to no filter. filter_columns: Vec, } @@ -63,6 +63,13 @@ impl CrossTableLookup { assert!(looking_tables .iter() .all(|twc| twc.columns.len() == looked_table.columns.len())); + assert!( + looking_tables + .iter() + .all(|twc| twc.filter_columns.is_empty()) + == default.is_some() + && default.is_some() == looked_table.filter_columns.is_empty() + ); Self { looking_tables, looked_table, From 4e848c77dbb7eb1cfde60c79f0fdd8dd95defd9c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 9 Jun 2022 18:13:41 +0200 Subject: [PATCH 7/9] Merge conflicts --- evm/src/all_stark.rs | 14 ++++++++------ evm/src/cross_table_lookup.rs | 7 +++++-- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index c3c9653c..b2306850 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -63,7 +63,7 @@ mod tests { use crate::config::StarkConfig; use crate::cpu; use crate::cpu::cpu_stark::CpuStark; - use crate::cross_table_lookup::CrossTableLookup; + use crate::cross_table_lookup::{CrossTableLookup, TableWithColumns}; use crate::keccak::keccak_stark::{KeccakStark, INPUT_LIMBS, NUM_ROUNDS}; use crate::proof::AllProof; use crate::prover::prove; @@ -116,11 +116,13 @@ mod tests { // TODO: temporary until cross-table-lookup filters are implemented let cross_table_lookups = vec![CrossTableLookup::new( - vec![Table::Cpu], - vec![vec![cpu::columns::OPCODE]], - Table::Keccak, - vec![keccak_looked_col], - default, + vec![TableWithColumns::new( + Table::Cpu, + vec![cpu::columns::OPCODE], + vec![], + )], + TableWithColumns::new(Table::Keccak, vec![keccak_looked_col], vec![]), + Some(default), )]; let all_stark = AllStark { diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 3cc38beb..50d5dbd1 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -68,9 +68,12 @@ impl CrossTableLookup { .iter() .all(|twc| twc.filter_columns.is_empty()) == default.is_some() - && default.is_some() == looked_table.filter_columns.is_empty() + && default.is_some() == looked_table.filter_columns.is_empty(), + "Default values should be provided iff there are no filter columns." ); - assert!(default.len() == looked_columns.len()); + if let Some(default) = &default { + assert_eq!(default.len(), looked_table.columns.len()); + } Self { looking_tables, looked_table, From fdd6a7cad894a40b1dbf973b35cc8352d8c30d4b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 10 Jun 2022 21:02:56 +0200 Subject: [PATCH 8/9] Wired CPU and Keccak --- evm/src/all_stark.rs | 71 +++++++++++++++------- evm/src/cpu/columns.rs | 114 +++++++++++++++++++++++++++++++++++- evm/src/keccak/registers.rs | 7 +-- 3 files changed, 167 insertions(+), 25 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 7387621b..83893cef 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -56,14 +56,12 @@ mod tests { use plonky2::plonk::circuit_data::CircuitConfig; use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2::util::timing::TimingTree; - use rand::{Rng, SeedableRng}; - use rand_chacha::ChaCha8Rng; + use rand::{thread_rng, Rng}; use crate::all_stark::{AllStark, Table}; use crate::config::StarkConfig; - use crate::cpu; use crate::cpu::cpu_stark::CpuStark; - use crate::cross_table_lookup::CrossTableLookup; + use crate::cross_table_lookup::{CrossTableLookup, TableWithColumns}; use crate::keccak::keccak_stark::{KeccakStark, NUM_INPUTS, NUM_ROUNDS}; use crate::proof::AllProof; use crate::prover::prove; @@ -73,6 +71,7 @@ mod tests { use crate::stark::Stark; use crate::util::trace_rows_to_poly_values; use crate::verifier::verify_proof; + use crate::{cpu, keccak}; const D: usize = 2; type C = PoseidonGoldilocksConfig; @@ -87,42 +86,74 @@ mod tests { let keccak_stark = KeccakStark:: { f: Default::default(), }; - let keccak_rows = (2 * NUM_ROUNDS + 1).next_power_of_two(); - let keccak_looked_col = 3; - let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25); + let mut rng = thread_rng(); let num_inputs = 2; let keccak_inputs = (0..num_inputs) .map(|_| [0u64; NUM_INPUTS].map(|_| rng.gen())) .collect_vec(); let keccak_trace = keccak_stark.generate_trace(keccak_inputs); - let column_to_copy: Vec<_> = keccak_trace[keccak_looked_col].values[..].into(); - - let default = vec![F::ONE; 1]; + let keccak_input_limbs: Vec<[F; 2 * NUM_INPUTS]> = (0..num_inputs) + .map(|i| { + (0..2 * NUM_INPUTS) + .map(|j| { + keccak_trace[keccak::registers::reg_input_limb(j)].values + [(i + 1) * NUM_ROUNDS - 1] + }) + .collect::>() + .try_into() + .unwrap() + }) + .collect(); + let keccak_output_limbs: Vec<[F; 2 * NUM_INPUTS]> = (0..num_inputs) + .map(|i| { + (0..2 * NUM_INPUTS) + .map(|j| { + keccak_trace[keccak::registers::reg_output_limb(j)].values + [(i + 1) * NUM_ROUNDS - 1] + }) + .collect::>() + .try_into() + .unwrap() + }) + .collect(); let mut cpu_trace_rows = vec![]; for i in 0..cpu_rows { let mut cpu_trace_row = [F::ZERO; CpuStark::::COLUMNS]; cpu_trace_row[cpu::columns::IS_CPU_CYCLE] = F::ONE; - if i < keccak_rows { - cpu_trace_row[cpu::columns::OPCODE] = column_to_copy[i]; - } else { - cpu_trace_row[cpu::columns::OPCODE] = default[0]; - } + cpu_trace_row[cpu::columns::OPCODE] = F::from_canonical_usize(i); cpu_stark.generate(&mut cpu_trace_row); cpu_trace_rows.push(cpu_trace_row); } + for i in 0..num_inputs { + cpu_trace_rows[i][cpu::columns::IS_KECCAK] = F::ONE; + for j in 0..2 * NUM_INPUTS { + cpu_trace_rows[i][cpu::columns::KECCAK_INPUT_LIMBS[j]] = keccak_input_limbs[i][j]; + cpu_trace_rows[i][cpu::columns::KECCAK_OUTPUT_LIMBS[j]] = keccak_output_limbs[i][j]; + } + } let cpu_trace = trace_rows_to_poly_values(cpu_trace_rows); - // TODO: temporary until cross-table-lookup filters are implemented + let mut cpu_keccak_input_output = cpu::columns::KECCAK_INPUT_LIMBS.to_vec(); + cpu_keccak_input_output.extend(cpu::columns::KECCAK_OUTPUT_LIMBS); + let mut keccak_keccak_input_output = (0..2 * NUM_INPUTS) + .map(keccak::registers::reg_input_limb) + .collect::>(); + keccak_keccak_input_output + .extend((0..2 * NUM_INPUTS).map(keccak::registers::reg_output_limb)); let cross_table_lookups = vec![CrossTableLookup::new( vec![TableWithColumns::new( Table::Cpu, - vec![cpu::columns::OPCODE], - vec![], + cpu_keccak_input_output, + vec![cpu::columns::IS_KECCAK], )], - TableWithColumns::new(Table::Keccak, vec![keccak_looked_col], vec![]), - Some(default), + TableWithColumns::new( + Table::Keccak, + keccak_keccak_input_output, + vec![keccak::registers::reg_step(NUM_ROUNDS - 1)], + ), + None, )]; let all_stark = AllStark { diff --git a/evm/src/cpu/columns.rs b/evm/src/cpu/columns.rs index d2b2e4bf..83623797 100644 --- a/evm/src/cpu/columns.rs +++ b/evm/src/cpu/columns.rs @@ -132,4 +132,116 @@ pub const OPCODE_BITS: [usize; 8] = [ END_INSTRUCTION_FLAGS + 7, ]; -pub const NUM_CPU_COLUMNS: usize = OPCODE_BITS[OPCODE_BITS.len() - 1] + 1; +/// Filter. 1 iff a Keccak permutation is computed on this row. +pub const IS_KECCAK: usize = OPCODE_BITS[OPCODE_BITS.len() - 1] + 1; + +pub const START_KECCAK_INPUT: usize = IS_KECCAK + 1; +#[allow(dead_code)] // TODO: Remove when used +pub const KECCAK_INPUT_LIMBS: [usize; 50] = [ + START_KECCAK_INPUT, + START_KECCAK_INPUT + 1, + START_KECCAK_INPUT + 2, + START_KECCAK_INPUT + 3, + START_KECCAK_INPUT + 4, + START_KECCAK_INPUT + 5, + START_KECCAK_INPUT + 6, + START_KECCAK_INPUT + 7, + START_KECCAK_INPUT + 8, + START_KECCAK_INPUT + 9, + START_KECCAK_INPUT + 10, + START_KECCAK_INPUT + 11, + START_KECCAK_INPUT + 12, + START_KECCAK_INPUT + 13, + START_KECCAK_INPUT + 14, + START_KECCAK_INPUT + 15, + START_KECCAK_INPUT + 16, + START_KECCAK_INPUT + 17, + START_KECCAK_INPUT + 18, + START_KECCAK_INPUT + 19, + START_KECCAK_INPUT + 20, + START_KECCAK_INPUT + 21, + START_KECCAK_INPUT + 22, + START_KECCAK_INPUT + 23, + START_KECCAK_INPUT + 24, + START_KECCAK_INPUT + 25, + START_KECCAK_INPUT + 26, + START_KECCAK_INPUT + 27, + START_KECCAK_INPUT + 28, + START_KECCAK_INPUT + 29, + START_KECCAK_INPUT + 30, + START_KECCAK_INPUT + 31, + START_KECCAK_INPUT + 32, + START_KECCAK_INPUT + 33, + START_KECCAK_INPUT + 34, + START_KECCAK_INPUT + 35, + START_KECCAK_INPUT + 36, + START_KECCAK_INPUT + 37, + START_KECCAK_INPUT + 38, + START_KECCAK_INPUT + 39, + START_KECCAK_INPUT + 40, + START_KECCAK_INPUT + 41, + START_KECCAK_INPUT + 42, + START_KECCAK_INPUT + 43, + START_KECCAK_INPUT + 44, + START_KECCAK_INPUT + 45, + START_KECCAK_INPUT + 46, + START_KECCAK_INPUT + 47, + START_KECCAK_INPUT + 48, + START_KECCAK_INPUT + 49, +]; + +pub const START_KECCAK_OUTPUT: usize = START_KECCAK_INPUT + 50; +pub const KECCAK_OUTPUT_LIMBS: [usize; 50] = [ + START_KECCAK_OUTPUT, + START_KECCAK_OUTPUT + 1, + START_KECCAK_OUTPUT + 2, + START_KECCAK_OUTPUT + 3, + START_KECCAK_OUTPUT + 4, + START_KECCAK_OUTPUT + 5, + START_KECCAK_OUTPUT + 6, + START_KECCAK_OUTPUT + 7, + START_KECCAK_OUTPUT + 8, + START_KECCAK_OUTPUT + 9, + START_KECCAK_OUTPUT + 10, + START_KECCAK_OUTPUT + 11, + START_KECCAK_OUTPUT + 12, + START_KECCAK_OUTPUT + 13, + START_KECCAK_OUTPUT + 14, + START_KECCAK_OUTPUT + 15, + START_KECCAK_OUTPUT + 16, + START_KECCAK_OUTPUT + 17, + START_KECCAK_OUTPUT + 18, + START_KECCAK_OUTPUT + 19, + START_KECCAK_OUTPUT + 20, + START_KECCAK_OUTPUT + 21, + START_KECCAK_OUTPUT + 22, + START_KECCAK_OUTPUT + 23, + START_KECCAK_OUTPUT + 24, + START_KECCAK_OUTPUT + 25, + START_KECCAK_OUTPUT + 26, + START_KECCAK_OUTPUT + 27, + START_KECCAK_OUTPUT + 28, + START_KECCAK_OUTPUT + 29, + START_KECCAK_OUTPUT + 30, + START_KECCAK_OUTPUT + 31, + START_KECCAK_OUTPUT + 32, + START_KECCAK_OUTPUT + 33, + START_KECCAK_OUTPUT + 34, + START_KECCAK_OUTPUT + 35, + START_KECCAK_OUTPUT + 36, + START_KECCAK_OUTPUT + 37, + START_KECCAK_OUTPUT + 38, + START_KECCAK_OUTPUT + 39, + START_KECCAK_OUTPUT + 40, + START_KECCAK_OUTPUT + 41, + START_KECCAK_OUTPUT + 42, + START_KECCAK_OUTPUT + 43, + START_KECCAK_OUTPUT + 44, + START_KECCAK_OUTPUT + 45, + START_KECCAK_OUTPUT + 46, + START_KECCAK_OUTPUT + 47, + START_KECCAK_OUTPUT + 48, + START_KECCAK_OUTPUT + 49, +]; + +pub const NUM_CPU_COLUMNS: usize = KECCAK_OUTPUT_LIMBS[KECCAK_OUTPUT_LIMBS.len() - 1] + 1; diff --git a/evm/src/keccak/registers.rs b/evm/src/keccak/registers.rs index 2dc019e3..04704d9c 100644 --- a/evm/src/keccak/registers.rs +++ b/evm/src/keccak/registers.rs @@ -1,7 +1,7 @@ use crate::keccak::keccak_stark::{NUM_INPUTS, NUM_ROUNDS}; /// A register which is set to 1 if we are in the `i`th round, otherwise 0. -pub(crate) const fn reg_step(i: usize) -> usize { +pub const fn reg_step(i: usize) -> usize { debug_assert!(i < NUM_ROUNDS); i } @@ -9,7 +9,7 @@ pub(crate) const fn reg_step(i: usize) -> usize { /// Registers to hold permutation inputs. /// `reg_input_limb(2*i) -> input[i] as u32` /// `reg_input_limb(2*i+1) -> input[i] >> 32` -pub(crate) const fn reg_input_limb(i: usize) -> usize { +pub const fn reg_input_limb(i: usize) -> usize { debug_assert!(i < 2 * NUM_INPUTS); NUM_ROUNDS + i } @@ -17,8 +17,7 @@ pub(crate) const fn reg_input_limb(i: usize) -> usize { /// Registers to hold permutation outputs. /// `reg_output_limb(2*i) -> output[i] as u32` /// `reg_output_limb(2*i+1) -> output[i] >> 32` -#[allow(dead_code)] // TODO: Remove once it is used. -pub(crate) const fn reg_output_limb(i: usize) -> usize { +pub const fn reg_output_limb(i: usize) -> usize { debug_assert!(i < 2 * NUM_INPUTS); let ii = i / 2; let x = ii / 5; From e969f10b203c550006aa50239fc7636006483e14 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 13 Jun 2022 18:54:12 +0200 Subject: [PATCH 9/9] PR feedback --- evm/src/all_stark.rs | 23 ++++--- evm/src/cpu/columns.rs | 112 ++-------------------------------- evm/src/cross_table_lookup.rs | 16 ++--- 3 files changed, 25 insertions(+), 126 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 83893cef..fd789bb1 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -49,7 +49,7 @@ impl Table { #[cfg(test)] mod tests { use anyhow::Result; - use itertools::Itertools; + use itertools::{izip, Itertools}; use plonky2::field::field_types::Field; use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; @@ -60,6 +60,7 @@ mod tests { use crate::all_stark::{AllStark, Table}; use crate::config::StarkConfig; + use crate::cpu::columns::{KECCAK_INPUT_LIMBS, KECCAK_OUTPUT_LIMBS}; use crate::cpu::cpu_stark::CpuStark; use crate::cross_table_lookup::{CrossTableLookup, TableWithColumns}; use crate::keccak::keccak_stark::{KeccakStark, NUM_INPUTS, NUM_ROUNDS}; @@ -88,12 +89,12 @@ mod tests { }; let mut rng = thread_rng(); - let num_inputs = 2; - let keccak_inputs = (0..num_inputs) + let num_keccak_perms = 2; + let keccak_inputs = (0..num_keccak_perms) .map(|_| [0u64; NUM_INPUTS].map(|_| rng.gen())) .collect_vec(); let keccak_trace = keccak_stark.generate_trace(keccak_inputs); - let keccak_input_limbs: Vec<[F; 2 * NUM_INPUTS]> = (0..num_inputs) + let keccak_input_limbs: Vec<[F; 2 * NUM_INPUTS]> = (0..num_keccak_perms) .map(|i| { (0..2 * NUM_INPUTS) .map(|j| { @@ -105,7 +106,7 @@ mod tests { .unwrap() }) .collect(); - let keccak_output_limbs: Vec<[F; 2 * NUM_INPUTS]> = (0..num_inputs) + let keccak_output_limbs: Vec<[F; 2 * NUM_INPUTS]> = (0..num_keccak_perms) .map(|i| { (0..2 * NUM_INPUTS) .map(|j| { @@ -126,16 +127,18 @@ mod tests { cpu_stark.generate(&mut cpu_trace_row); cpu_trace_rows.push(cpu_trace_row); } - for i in 0..num_inputs { + for i in 0..num_keccak_perms { cpu_trace_rows[i][cpu::columns::IS_KECCAK] = F::ONE; - for j in 0..2 * NUM_INPUTS { - cpu_trace_rows[i][cpu::columns::KECCAK_INPUT_LIMBS[j]] = keccak_input_limbs[i][j]; - cpu_trace_rows[i][cpu::columns::KECCAK_OUTPUT_LIMBS[j]] = keccak_output_limbs[i][j]; + for (j, input, output) in + izip!(0..2 * NUM_INPUTS, KECCAK_INPUT_LIMBS, KECCAK_OUTPUT_LIMBS) + { + cpu_trace_rows[i][input] = keccak_input_limbs[i][j]; + cpu_trace_rows[i][output] = keccak_output_limbs[i][j]; } } let cpu_trace = trace_rows_to_poly_values(cpu_trace_rows); - let mut cpu_keccak_input_output = cpu::columns::KECCAK_INPUT_LIMBS.to_vec(); + let mut cpu_keccak_input_output = cpu::columns::KECCAK_INPUT_LIMBS.collect::>(); cpu_keccak_input_output.extend(cpu::columns::KECCAK_OUTPUT_LIMBS); let mut keccak_keccak_input_output = (0..2 * NUM_INPUTS) .map(keccak::registers::reg_input_limb) diff --git a/evm/src/cpu/columns.rs b/evm/src/cpu/columns.rs index 83623797..66a87d9c 100644 --- a/evm/src/cpu/columns.rs +++ b/evm/src/cpu/columns.rs @@ -1,3 +1,5 @@ +use std::ops::Range; + // Filter. 1 if the row corresponds to a cycle of execution and 0 otherwise. // Lets us re-use decode columns in non-cycle rows. pub const IS_CPU_CYCLE: usize = 0; @@ -137,111 +139,9 @@ pub const IS_KECCAK: usize = OPCODE_BITS[OPCODE_BITS.len() - 1] + 1; pub const START_KECCAK_INPUT: usize = IS_KECCAK + 1; #[allow(dead_code)] // TODO: Remove when used -pub const KECCAK_INPUT_LIMBS: [usize; 50] = [ - START_KECCAK_INPUT, - START_KECCAK_INPUT + 1, - START_KECCAK_INPUT + 2, - START_KECCAK_INPUT + 3, - START_KECCAK_INPUT + 4, - START_KECCAK_INPUT + 5, - START_KECCAK_INPUT + 6, - START_KECCAK_INPUT + 7, - START_KECCAK_INPUT + 8, - START_KECCAK_INPUT + 9, - START_KECCAK_INPUT + 10, - START_KECCAK_INPUT + 11, - START_KECCAK_INPUT + 12, - START_KECCAK_INPUT + 13, - START_KECCAK_INPUT + 14, - START_KECCAK_INPUT + 15, - START_KECCAK_INPUT + 16, - START_KECCAK_INPUT + 17, - START_KECCAK_INPUT + 18, - START_KECCAK_INPUT + 19, - START_KECCAK_INPUT + 20, - START_KECCAK_INPUT + 21, - START_KECCAK_INPUT + 22, - START_KECCAK_INPUT + 23, - START_KECCAK_INPUT + 24, - START_KECCAK_INPUT + 25, - START_KECCAK_INPUT + 26, - START_KECCAK_INPUT + 27, - START_KECCAK_INPUT + 28, - START_KECCAK_INPUT + 29, - START_KECCAK_INPUT + 30, - START_KECCAK_INPUT + 31, - START_KECCAK_INPUT + 32, - START_KECCAK_INPUT + 33, - START_KECCAK_INPUT + 34, - START_KECCAK_INPUT + 35, - START_KECCAK_INPUT + 36, - START_KECCAK_INPUT + 37, - START_KECCAK_INPUT + 38, - START_KECCAK_INPUT + 39, - START_KECCAK_INPUT + 40, - START_KECCAK_INPUT + 41, - START_KECCAK_INPUT + 42, - START_KECCAK_INPUT + 43, - START_KECCAK_INPUT + 44, - START_KECCAK_INPUT + 45, - START_KECCAK_INPUT + 46, - START_KECCAK_INPUT + 47, - START_KECCAK_INPUT + 48, - START_KECCAK_INPUT + 49, -]; +pub const KECCAK_INPUT_LIMBS: Range = START_KECCAK_INPUT..START_KECCAK_INPUT + 50; -pub const START_KECCAK_OUTPUT: usize = START_KECCAK_INPUT + 50; -pub const KECCAK_OUTPUT_LIMBS: [usize; 50] = [ - START_KECCAK_OUTPUT, - START_KECCAK_OUTPUT + 1, - START_KECCAK_OUTPUT + 2, - START_KECCAK_OUTPUT + 3, - START_KECCAK_OUTPUT + 4, - START_KECCAK_OUTPUT + 5, - START_KECCAK_OUTPUT + 6, - START_KECCAK_OUTPUT + 7, - START_KECCAK_OUTPUT + 8, - START_KECCAK_OUTPUT + 9, - START_KECCAK_OUTPUT + 10, - START_KECCAK_OUTPUT + 11, - START_KECCAK_OUTPUT + 12, - START_KECCAK_OUTPUT + 13, - START_KECCAK_OUTPUT + 14, - START_KECCAK_OUTPUT + 15, - START_KECCAK_OUTPUT + 16, - START_KECCAK_OUTPUT + 17, - START_KECCAK_OUTPUT + 18, - START_KECCAK_OUTPUT + 19, - START_KECCAK_OUTPUT + 20, - START_KECCAK_OUTPUT + 21, - START_KECCAK_OUTPUT + 22, - START_KECCAK_OUTPUT + 23, - START_KECCAK_OUTPUT + 24, - START_KECCAK_OUTPUT + 25, - START_KECCAK_OUTPUT + 26, - START_KECCAK_OUTPUT + 27, - START_KECCAK_OUTPUT + 28, - START_KECCAK_OUTPUT + 29, - START_KECCAK_OUTPUT + 30, - START_KECCAK_OUTPUT + 31, - START_KECCAK_OUTPUT + 32, - START_KECCAK_OUTPUT + 33, - START_KECCAK_OUTPUT + 34, - START_KECCAK_OUTPUT + 35, - START_KECCAK_OUTPUT + 36, - START_KECCAK_OUTPUT + 37, - START_KECCAK_OUTPUT + 38, - START_KECCAK_OUTPUT + 39, - START_KECCAK_OUTPUT + 40, - START_KECCAK_OUTPUT + 41, - START_KECCAK_OUTPUT + 42, - START_KECCAK_OUTPUT + 43, - START_KECCAK_OUTPUT + 44, - START_KECCAK_OUTPUT + 45, - START_KECCAK_OUTPUT + 46, - START_KECCAK_OUTPUT + 47, - START_KECCAK_OUTPUT + 48, - START_KECCAK_OUTPUT + 49, -]; +pub const START_KECCAK_OUTPUT: usize = KECCAK_INPUT_LIMBS.end; +pub const KECCAK_OUTPUT_LIMBS: Range = START_KECCAK_OUTPUT..START_KECCAK_OUTPUT + 50; -pub const NUM_CPU_COLUMNS: usize = KECCAK_OUTPUT_LIMBS[KECCAK_OUTPUT_LIMBS.len() - 1] + 1; +pub const NUM_CPU_COLUMNS: usize = KECCAK_OUTPUT_LIMBS.end; diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 50d5dbd1..24d0878e 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -1,6 +1,5 @@ -use std::collections::HashSet; - use anyhow::{ensure, Result}; +use itertools::Itertools; use plonky2::field::extension_field::{Extendable, FieldExtension}; use plonky2::field::field_types::Field; use plonky2::field::packed_field::PackedField; @@ -34,7 +33,7 @@ pub struct TableWithColumns { impl TableWithColumns { pub fn new(table: Table, columns: Vec, filter_columns: Vec) -> Self { debug_assert_eq!( - filter_columns.iter().collect::>().len(), + filter_columns.iter().unique().count(), filter_columns.len(), "Duplicate filter columns." ); @@ -66,8 +65,7 @@ impl CrossTableLookup { assert!( looking_tables .iter() - .all(|twc| twc.filter_columns.is_empty()) - == default.is_some() + .all(|twc| twc.filter_columns.is_empty() == default.is_some()) && default.is_some() == looked_table.filter_columns.is_empty(), "Default values should be provided iff there are no filter columns." ); @@ -200,12 +198,10 @@ fn partial_products( } else { filter_columns.iter().map(|&j| trace[j].values[i]).sum() }; - partial_prod *= if filter.is_zero() { - F::ONE - } else if filter.is_one() { - challenge.combine(columns.iter().map(|&j| &trace[j].values[i])) + if filter.is_one() { + partial_prod *= challenge.combine(columns.iter().map(|&j| &trace[j].values[i])); } else { - panic!("Non-binary filter?") + assert_eq!(filter, F::ZERO, "Non-binary filter?") }; res.push(partial_prod); }