use plonky2::field::extension_field::{Extendable, FieldExtension}; use plonky2::field::field_types::Field; use plonky2::field::packed_field::PackedField; use plonky2::field::polynomial::PolynomialValues; use plonky2::hash::hash_types::RichField; use plonky2::iop::challenger::Challenger; use plonky2::plonk::config::GenericConfig; use plonky2::plonk::plonk_common::reduce_with_powers; use plonky2::util::reducing::ReducingFactor; use crate::all_stark::Table; use crate::config::StarkConfig; use crate::constraint_consumer::ConstraintConsumer; use crate::permutation::PermutationChallenge; use crate::stark::Stark; use crate::vars::StarkEvaluationVars; pub struct CrossTableLookup { pub looking_table: Table, pub looking_columns: Vec, pub looked_table: Table, pub looked_columns: Vec, } impl CrossTableLookup { pub fn new( looking_table: Table, looking_columns: Vec, looked_table: Table, looked_columns: Vec, ) -> Self { assert_eq!(looking_columns.len(), looked_columns.len()); Self { looking_table, looking_columns, looked_table, looked_columns, } } } /// Lookup data for one table. #[derive(Clone)] pub struct LookupData { pub zs_beta_gammas: Vec<(PolynomialValues, F, F, Vec)>, } impl Default for LookupData { fn default() -> Self { Self { zs_beta_gammas: Vec::new(), } } } impl LookupData { pub fn is_empty(&self) -> bool { self.zs_beta_gammas.is_empty() } pub fn z_polys(&self) -> Vec> { self.zs_beta_gammas .iter() .map(|(p, _, _, _)| p.clone()) .collect() } } pub fn cross_table_lookup_zs, const D: usize>( config: &StarkConfig, trace_poly_values: &[Vec>], cross_table_lookups: &[CrossTableLookup], challenger: &mut Challenger, ) -> Vec> { cross_table_lookups.iter().fold( vec![LookupData::default(); trace_poly_values.len()], |mut acc, cross_table_lookup| { let CrossTableLookup { looking_table, looking_columns, looked_table, looked_columns, .. } = cross_table_lookup; for _ in 0..config.num_challenges { let beta = challenger.get_challenge(); let gamma = challenger.get_challenge(); let z_looking = partial_products( &trace_poly_values[*looking_table as usize], looking_columns, beta, gamma, ); let z_looked = partial_products( &trace_poly_values[*looked_table as usize], looked_columns, beta, gamma, ); acc[*looking_table as usize].zs_beta_gammas.push(( z_looking, beta, gamma, looking_columns.clone(), )); acc[*looked_table as usize].zs_beta_gammas.push(( z_looked, beta, gamma, looked_columns.clone(), )); } acc }, ) } fn partial_products( trace: &[PolynomialValues], columns: &[usize], beta: F, gamma: F, ) -> PolynomialValues { let mut partial_prod = F::ONE; let mut res = Vec::new(); for i in 0..trace[0].len() { partial_prod *= gamma + reduce_with_powers(columns.iter().map(|&j| &trace[j].values[i]), beta); res.push(partial_prod); } res.into() } pub struct CTLCheckVars where F: Field, FE: FieldExtension, P: PackedField, { pub(crate) local_z: P, pub(crate) next_z: P, pub(crate) challenges: PermutationChallenge, pub(crate) columns: Vec, } pub(crate) fn eval_cross_table_lookup_checks( vars: StarkEvaluationVars, lookup_data: &[CTLCheckVars], consumer: &mut ConstraintConsumer

, ) where F: RichField + Extendable, FE: FieldExtension, P: PackedField, C: GenericConfig, S: Stark, { for lookup_datum in lookup_data { let CTLCheckVars { local_z, next_z, challenges, columns, } = lookup_datum; let mut factor = ReducingFactor::new(challenges.beta); let mut combine = |v: &[P]| -> P { factor.reduce_ext(columns.iter().map(|&i| v[i])) + FE::from_basefield(challenges.gamma) }; // Check value of `Z(1)` consumer.constraint_first_row(*local_z - combine(vars.local_values)); // Check `Z(gw) = combination * Z(w)` consumer.constraint_transition(*next_z - *local_z * combine(vars.next_values)); } }