plonky2/starky2/src/cross_table_lookup.rs

173 lines
5.0 KiB
Rust
Raw Normal View History

2022-05-06 14:55:54 +02:00
use plonky2::field::extension_field::{Extendable, FieldExtension};
2022-05-05 22:21:09 +02:00
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;
2022-05-06 14:55:54 +02:00
use plonky2::util::reducing::ReducingFactor;
2022-05-05 22:21:09 +02:00
2022-05-06 17:35:25 +02:00
use crate::all_stark::Table;
2022-05-05 22:21:09 +02:00
use crate::config::StarkConfig;
2022-05-06 14:55:54 +02:00
use crate::constraint_consumer::ConstraintConsumer;
use crate::permutation::PermutationChallenge;
use crate::stark::Stark;
use crate::vars::StarkEvaluationVars;
2022-05-05 22:21:09 +02:00
2022-05-06 17:22:30 +02:00
pub struct CrossTableLookup {
pub looking_table: Table,
pub looking_columns: Vec<usize>,
2022-05-10 07:45:42 +02:00
pub looked_table: Table,
2022-05-06 17:22:30 +02:00
pub looked_columns: Vec<usize>,
}
impl CrossTableLookup {
pub fn new(
looking_table: Table,
looking_columns: Vec<usize>,
2022-05-10 07:45:42 +02:00
looked_table: Table,
2022-05-06 17:22:30 +02:00
looked_columns: Vec<usize>,
) -> Self {
assert_eq!(looking_columns.len(), looked_columns.len());
Self {
looking_table,
looking_columns,
looked_table,
looked_columns,
}
}
}
2022-05-05 22:21:09 +02:00
/// Lookup data for one table.
#[derive(Clone)]
pub struct LookupData<F: Field> {
2022-05-11 14:35:33 +02:00
pub beta: F,
pub gamma: F,
pub zs_columns: Vec<(PolynomialValues<F>, Vec<usize>)>,
2022-05-05 22:21:09 +02:00
}
2022-05-11 14:35:33 +02:00
impl<F: Field> LookupData<F> {
pub fn new(beta: F, gamma: F) -> Self {
2022-05-05 22:21:09 +02:00
Self {
2022-05-11 14:35:33 +02:00
beta,
gamma,
zs_columns: vec![],
2022-05-05 22:21:09 +02:00
}
}
2022-05-10 15:08:08 +02:00
pub fn len(&self) -> usize {
2022-05-11 14:35:33 +02:00
self.zs_columns.len()
2022-05-10 15:08:08 +02:00
}
2022-05-05 22:21:09 +02:00
pub fn is_empty(&self) -> bool {
2022-05-11 14:35:33 +02:00
self.zs_columns.is_empty()
2022-05-05 22:21:09 +02:00
}
pub fn z_polys(&self) -> Vec<PolynomialValues<F>> {
2022-05-11 14:35:33 +02:00
self.zs_columns.iter().map(|(p, _)| p.clone()).collect()
2022-05-05 22:21:09 +02:00
}
}
pub fn cross_table_lookup_zs<F: RichField, C: GenericConfig<D, F = F>, const D: usize>(
config: &StarkConfig,
trace_poly_values: &[Vec<PolynomialValues<F>>],
2022-05-06 17:22:30 +02:00
cross_table_lookups: &[CrossTableLookup],
2022-05-05 22:21:09 +02:00
challenger: &mut Challenger<F, C::Hasher>,
) -> Vec<LookupData<F>> {
2022-05-11 14:35:33 +02:00
let beta = challenger.get_challenge();
let gamma = challenger.get_challenge();
2022-05-05 22:21:09 +02:00
cross_table_lookups.iter().fold(
2022-05-11 14:35:33 +02:00
vec![LookupData::new(beta, gamma); trace_poly_values.len()],
2022-05-05 22:21:09 +02:00
|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 z_looking = partial_products(
&trace_poly_values[*looking_table as usize],
2022-05-06 16:59:25 +02:00
looking_columns,
2022-05-05 22:21:09 +02:00
beta,
gamma,
);
let z_looked = partial_products(
&trace_poly_values[*looked_table as usize],
2022-05-06 16:59:25 +02:00
looked_columns,
2022-05-05 22:21:09 +02:00
beta,
gamma,
);
2022-05-11 14:35:33 +02:00
acc[*looking_table as usize]
.zs_columns
.push((z_looking, looking_columns.clone()));
acc[*looked_table as usize]
.zs_columns
.push((z_looked, looked_columns.clone()));
2022-05-05 22:21:09 +02:00
}
acc
},
)
}
fn partial_products<F: Field>(
trace: &[PolynomialValues<F>],
columns: &[usize],
beta: F,
gamma: F,
) -> PolynomialValues<F> {
let mut partial_prod = F::ONE;
let mut res = Vec::new();
for i in 0..trace[0].len() {
partial_prod *=
2022-05-06 16:59:25 +02:00
gamma + reduce_with_powers(columns.iter().map(|&j| &trace[j].values[i]), beta);
2022-05-05 22:21:09 +02:00
res.push(partial_prod);
}
res.into()
}
pub struct CTLCheckVars<F, FE, P, const D2: usize>
where
F: Field,
FE: FieldExtension<D2, BaseField = F>,
P: PackedField<Scalar = FE>,
{
2022-05-06 14:55:54 +02:00
pub(crate) local_z: P,
pub(crate) next_z: P,
pub(crate) challenges: PermutationChallenge<F>,
pub(crate) columns: Vec<usize>,
2022-05-05 22:21:09 +02:00
}
2022-05-06 14:55:54 +02:00
pub(crate) fn eval_cross_table_lookup_checks<F, FE, P, C, S, const D: usize, const D2: usize>(
2022-05-05 22:21:09 +02:00
vars: StarkEvaluationVars<FE, P>,
2022-05-06 14:55:54 +02:00
lookup_data: &[CTLCheckVars<F, FE, P, D2>],
2022-05-05 22:21:09 +02:00
consumer: &mut ConstraintConsumer<P>,
) where
F: RichField + Extendable<D>,
FE: FieldExtension<D2, BaseField = F>,
P: PackedField<Scalar = FE>,
C: GenericConfig<D, F = F>,
S: Stark<F, D>,
{
2022-05-06 14:55:54 +02:00
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)
};
2022-05-05 22:21:09 +02:00
2022-05-06 14:55:54 +02:00
// 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));
2022-05-05 22:21:09 +02:00
}
}