mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 16:23:12 +00:00
Implement multi-table CTLs
This commit is contained in:
parent
e8fc5b5752
commit
2e3a738bc5
@ -107,8 +107,8 @@ mod tests {
|
|||||||
keccak_trace[5].values[..].copy_from_slice(&vs1);
|
keccak_trace[5].values[..].copy_from_slice(&vs1);
|
||||||
|
|
||||||
let cross_table_lookups = vec![CrossTableLookup {
|
let cross_table_lookups = vec![CrossTableLookup {
|
||||||
looking_table: Table::Cpu,
|
looking_tables: vec![Table::Cpu],
|
||||||
looking_columns: vec![2, 4],
|
looking_columns: vec![vec![2, 4]],
|
||||||
looked_table: Table::Keccak,
|
looked_table: Table::Keccak,
|
||||||
looked_columns: vec![3, 5],
|
looked_columns: vec![3, 5],
|
||||||
default: vec![F::ONE; 2],
|
default: vec![F::ONE; 2],
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use anyhow::{ensure, Result};
|
use anyhow::{ensure, Result};
|
||||||
|
use itertools::izip;
|
||||||
use plonky2::field::extension_field::{Extendable, FieldExtension};
|
use plonky2::field::extension_field::{Extendable, FieldExtension};
|
||||||
use plonky2::field::field_types::Field;
|
use plonky2::field::field_types::Field;
|
||||||
use plonky2::field::packed_field::PackedField;
|
use plonky2::field::packed_field::PackedField;
|
||||||
@ -22,8 +23,8 @@ use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CrossTableLookup<F: Field> {
|
pub struct CrossTableLookup<F: Field> {
|
||||||
pub looking_table: Table,
|
pub looking_tables: Vec<Table>,
|
||||||
pub looking_columns: Vec<usize>,
|
pub looking_columns: Vec<Vec<usize>>,
|
||||||
pub looked_table: Table,
|
pub looked_table: Table,
|
||||||
pub looked_columns: Vec<usize>,
|
pub looked_columns: Vec<usize>,
|
||||||
pub default: Vec<F>,
|
pub default: Vec<F>,
|
||||||
@ -31,15 +32,18 @@ pub struct CrossTableLookup<F: Field> {
|
|||||||
|
|
||||||
impl<F: Field> CrossTableLookup<F> {
|
impl<F: Field> CrossTableLookup<F> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
looking_table: Table,
|
looking_tables: Vec<Table>,
|
||||||
looking_columns: Vec<usize>,
|
looking_columns: Vec<Vec<usize>>,
|
||||||
looked_table: Table,
|
looked_table: Table,
|
||||||
looked_columns: Vec<usize>,
|
looked_columns: Vec<usize>,
|
||||||
default: Vec<F>,
|
default: Vec<F>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
assert_eq!(looking_columns.len(), looked_columns.len());
|
assert_eq!(looking_tables.len(), looking_columns.len());
|
||||||
|
assert!(looking_columns
|
||||||
|
.iter()
|
||||||
|
.all(|cols| cols.len() == looked_columns.len()));
|
||||||
Self {
|
Self {
|
||||||
looking_table,
|
looking_tables,
|
||||||
looking_columns,
|
looking_columns,
|
||||||
looked_table,
|
looked_table,
|
||||||
looked_columns,
|
looked_columns,
|
||||||
@ -87,7 +91,7 @@ pub fn cross_table_lookup_data<F: RichField, C: GenericConfig<D, F = F>, const D
|
|||||||
let challenges = get_grand_product_challenge_set(challenger, config.num_challenges);
|
let challenges = get_grand_product_challenge_set(challenger, config.num_challenges);
|
||||||
let mut ctl_data_per_table = vec![CtlData::new(challenges.clone()); trace_poly_values.len()];
|
let mut ctl_data_per_table = vec![CtlData::new(challenges.clone()); trace_poly_values.len()];
|
||||||
for CrossTableLookup {
|
for CrossTableLookup {
|
||||||
looking_table,
|
looking_tables,
|
||||||
looking_columns,
|
looking_columns,
|
||||||
looked_table,
|
looked_table,
|
||||||
looked_columns,
|
looked_columns,
|
||||||
@ -95,11 +99,13 @@ pub fn cross_table_lookup_data<F: RichField, C: GenericConfig<D, F = F>, const D
|
|||||||
} in cross_table_lookups
|
} in cross_table_lookups
|
||||||
{
|
{
|
||||||
for &challenge in &challenges.challenges {
|
for &challenge in &challenges.challenges {
|
||||||
let z_looking = partial_products(
|
let zs_looking = looking_tables
|
||||||
&trace_poly_values[*looking_table as usize],
|
.iter()
|
||||||
looking_columns,
|
.zip(looking_columns)
|
||||||
challenge,
|
.map(|(table, columns)| {
|
||||||
);
|
partial_products(&trace_poly_values[*table as usize], columns, challenge)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let z_looked = partial_products(
|
let z_looked = partial_products(
|
||||||
&trace_poly_values[*looked_table as usize],
|
&trace_poly_values[*looked_table as usize],
|
||||||
looked_columns,
|
looked_columns,
|
||||||
@ -107,17 +113,25 @@ pub fn cross_table_lookup_data<F: RichField, C: GenericConfig<D, F = F>, const D
|
|||||||
);
|
);
|
||||||
|
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
*z_looking.values.last().unwrap(),
|
zs_looking
|
||||||
|
.iter()
|
||||||
|
.map(|z| *z.values.last().unwrap())
|
||||||
|
.product::<F>(),
|
||||||
*z_looked.values.last().unwrap()
|
*z_looked.values.last().unwrap()
|
||||||
* challenge.combine(default).exp_u64(
|
* challenge.combine(default).exp_u64(
|
||||||
trace_poly_values[*looking_table as usize][0].len() as u64
|
looking_tables
|
||||||
|
.iter()
|
||||||
|
.map(|table| trace_poly_values[*table as usize][0].len() as u64)
|
||||||
|
.sum::<u64>()
|
||||||
- trace_poly_values[*looked_table as usize][0].len() as u64
|
- trace_poly_values[*looked_table as usize][0].len() as u64
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
ctl_data_per_table[*looking_table as usize]
|
for (table, columns, z) in izip!(looking_tables, looking_columns, zs_looking) {
|
||||||
|
ctl_data_per_table[*table as usize]
|
||||||
.zs_columns
|
.zs_columns
|
||||||
.push((z_looking, looking_columns.clone()));
|
.push((z, columns.clone()));
|
||||||
|
}
|
||||||
ctl_data_per_table[*looked_table as usize]
|
ctl_data_per_table[*looked_table as usize]
|
||||||
.zs_columns
|
.zs_columns
|
||||||
.push((z_looked, looked_columns.clone()));
|
.push((z_looked, looked_columns.clone()));
|
||||||
@ -177,7 +191,7 @@ impl<'a, F: RichField + Extendable<D>, const D: usize>
|
|||||||
|
|
||||||
let mut ctl_vars_per_table = vec![vec![]; proofs.len()];
|
let mut ctl_vars_per_table = vec![vec![]; proofs.len()];
|
||||||
for CrossTableLookup {
|
for CrossTableLookup {
|
||||||
looking_table,
|
looking_tables,
|
||||||
looking_columns,
|
looking_columns,
|
||||||
looked_table,
|
looked_table,
|
||||||
looked_columns,
|
looked_columns,
|
||||||
@ -185,13 +199,15 @@ impl<'a, F: RichField + Extendable<D>, const D: usize>
|
|||||||
} in cross_table_lookups
|
} in cross_table_lookups
|
||||||
{
|
{
|
||||||
for &challenges in &ctl_challenges.challenges {
|
for &challenges in &ctl_challenges.challenges {
|
||||||
let (looking_z, looking_z_next) = ctl_zs[*looking_table as usize].next().unwrap();
|
for (table, columns) in looking_tables.iter().zip(looking_columns) {
|
||||||
ctl_vars_per_table[*looking_table as usize].push(Self {
|
let (looking_z, looking_z_next) = ctl_zs[*table as usize].next().unwrap();
|
||||||
|
ctl_vars_per_table[*table as usize].push(Self {
|
||||||
local_z: *looking_z,
|
local_z: *looking_z,
|
||||||
next_z: *looking_z_next,
|
next_z: *looking_z_next,
|
||||||
challenges,
|
challenges,
|
||||||
columns: looking_columns,
|
columns,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let (looked_z, looked_z_next) = ctl_zs[*looked_table as usize].next().unwrap();
|
let (looked_z, looked_z_next) = ctl_zs[*looked_table as usize].next().unwrap();
|
||||||
ctl_vars_per_table[*looked_table as usize].push(Self {
|
ctl_vars_per_table[*looked_table as usize].push(Self {
|
||||||
@ -262,7 +278,7 @@ impl<'a, const D: usize> CtlCheckVarsTarget<'a, D> {
|
|||||||
|
|
||||||
let mut ctl_vars_per_table = vec![vec![]; proofs.len()];
|
let mut ctl_vars_per_table = vec![vec![]; proofs.len()];
|
||||||
for CrossTableLookup {
|
for CrossTableLookup {
|
||||||
looking_table,
|
looking_tables,
|
||||||
looking_columns,
|
looking_columns,
|
||||||
looked_table,
|
looked_table,
|
||||||
looked_columns,
|
looked_columns,
|
||||||
@ -270,13 +286,15 @@ impl<'a, const D: usize> CtlCheckVarsTarget<'a, D> {
|
|||||||
} in cross_table_lookups
|
} in cross_table_lookups
|
||||||
{
|
{
|
||||||
for &challenges in &ctl_challenges.challenges {
|
for &challenges in &ctl_challenges.challenges {
|
||||||
let (looking_z, looking_z_next) = ctl_zs[*looking_table as usize].next().unwrap();
|
for (table, columns) in looking_tables.iter().zip(looking_columns) {
|
||||||
ctl_vars_per_table[*looking_table as usize].push(Self {
|
let (looking_z, looking_z_next) = ctl_zs[*table as usize].next().unwrap();
|
||||||
|
ctl_vars_per_table[*table as usize].push(Self {
|
||||||
local_z: *looking_z,
|
local_z: *looking_z,
|
||||||
next_z: *looking_z_next,
|
next_z: *looking_z_next,
|
||||||
challenges,
|
challenges,
|
||||||
columns: looking_columns,
|
columns,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let (looked_z, looked_z_next) = ctl_zs[*looked_table as usize].next().unwrap();
|
let (looked_z, looked_z_next) = ctl_zs[*looked_table as usize].next().unwrap();
|
||||||
ctl_vars_per_table[*looked_table as usize].push(Self {
|
ctl_vars_per_table[*looked_table as usize].push(Self {
|
||||||
@ -354,22 +372,29 @@ pub(crate) fn verify_cross_table_lookups<
|
|||||||
for (
|
for (
|
||||||
i,
|
i,
|
||||||
CrossTableLookup {
|
CrossTableLookup {
|
||||||
looking_table,
|
looking_tables,
|
||||||
looked_table,
|
looked_table,
|
||||||
default,
|
default,
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
) in cross_table_lookups.into_iter().enumerate()
|
) in cross_table_lookups.into_iter().enumerate()
|
||||||
{
|
{
|
||||||
let looking_degree = 1 << degrees_bits[looking_table as usize];
|
let looking_degrees_sum = looking_tables
|
||||||
|
.iter()
|
||||||
|
.map(|&table| 1 << degrees_bits[table as usize])
|
||||||
|
.sum::<u64>();
|
||||||
let looked_degree = 1 << degrees_bits[looked_table as usize];
|
let looked_degree = 1 << degrees_bits[looked_table as usize];
|
||||||
let looking_z = *ctl_zs_openings[looking_table as usize].next().unwrap();
|
let looking_zs_prod = looking_tables
|
||||||
|
.into_iter()
|
||||||
|
.map(|table| *ctl_zs_openings[table as usize].next().unwrap())
|
||||||
|
.product::<F>();
|
||||||
let looked_z = *ctl_zs_openings[looked_table as usize].next().unwrap();
|
let looked_z = *ctl_zs_openings[looked_table as usize].next().unwrap();
|
||||||
let challenge = challenges.challenges[i % config.num_challenges];
|
let challenge = challenges.challenges[i % config.num_challenges];
|
||||||
let combined_default = challenge.combine(default.iter());
|
let combined_default = challenge.combine(default.iter());
|
||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
looking_z == looked_z * combined_default.exp_u64(looking_degree - looked_degree),
|
looking_zs_prod
|
||||||
|
== looked_z * combined_default.exp_u64(looking_degrees_sum - looked_degree),
|
||||||
"Cross-table lookup verification failed."
|
"Cross-table lookup verification failed."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -399,16 +424,23 @@ pub(crate) fn verify_cross_table_lookups_circuit<
|
|||||||
for (
|
for (
|
||||||
i,
|
i,
|
||||||
CrossTableLookup {
|
CrossTableLookup {
|
||||||
looking_table,
|
looking_tables,
|
||||||
looked_table,
|
looked_table,
|
||||||
default,
|
default,
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
) in cross_table_lookups.into_iter().enumerate()
|
) in cross_table_lookups.into_iter().enumerate()
|
||||||
{
|
{
|
||||||
let looking_degree = 1 << degrees_bits[looking_table as usize];
|
let looking_degrees_sum = looking_tables
|
||||||
|
.iter()
|
||||||
|
.map(|&table| 1 << degrees_bits[table as usize])
|
||||||
|
.sum::<u64>();
|
||||||
let looked_degree = 1 << degrees_bits[looked_table as usize];
|
let looked_degree = 1 << degrees_bits[looked_table as usize];
|
||||||
let looking_z = *ctl_zs_openings[looking_table as usize].next().unwrap();
|
let looking_zs_prod = builder.mul_many(
|
||||||
|
looking_tables
|
||||||
|
.into_iter()
|
||||||
|
.map(|table| *ctl_zs_openings[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 as usize].next().unwrap();
|
||||||
let challenge = challenges.challenges[i % inner_config.num_challenges];
|
let challenge = challenges.challenges[i % inner_config.num_challenges];
|
||||||
let default = default
|
let default = default
|
||||||
@ -417,8 +449,8 @@ pub(crate) fn verify_cross_table_lookups_circuit<
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let combined_default = challenge.combine_base_circuit(builder, &default);
|
let combined_default = challenge.combine_base_circuit(builder, &default);
|
||||||
|
|
||||||
let pad = builder.exp_u64(combined_default, looking_degree - looked_degree);
|
let pad = builder.exp_u64(combined_default, looking_degrees_sum - looked_degree);
|
||||||
let padded_looked_z = builder.mul(looked_z, pad);
|
let padded_looked_z = builder.mul(looked_z, pad);
|
||||||
builder.connect(looking_z, padded_looked_z);
|
builder.connect(looking_zs_prod, padded_looked_z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
|
|
||||||
/// Computes `x^3`.
|
/// Computes `x^3`.
|
||||||
pub fn cube(&mut self, x: Target) -> Target {
|
pub fn cube(&mut self, x: Target) -> Target {
|
||||||
self.mul_many(&[x, x, x])
|
self.mul_many([x, x, x])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `const_0 * multiplicand_0 * multiplicand_1 + const_1 * addend`.
|
/// Computes `const_0 * multiplicand_0 * multiplicand_1 + const_1 * addend`.
|
||||||
@ -206,12 +206,16 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Multiply `n` `Target`s.
|
/// Multiply `n` `Target`s.
|
||||||
pub fn mul_many(&mut self, terms: &[Target]) -> Target {
|
pub fn mul_many<T>(&mut self, terms: impl IntoIterator<Item = T>) -> Target
|
||||||
terms
|
where
|
||||||
.iter()
|
T: Borrow<Target>,
|
||||||
.copied()
|
{
|
||||||
.reduce(|acc, t| self.mul(acc, t))
|
let mut iter = terms.into_iter();
|
||||||
.unwrap_or_else(|| self.one())
|
if let Some(first) = iter.next() {
|
||||||
|
iter.fold(*first.borrow(), |acc, t| self.mul(acc, *t.borrow()))
|
||||||
|
} else {
|
||||||
|
self.one()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exponentiate `base` to the power of `2^power_log`.
|
/// Exponentiate `base` to the power of `2^power_log`.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user