diff --git a/halo2-base/src/virtual_region/lookups.rs b/halo2-base/src/virtual_region/lookups.rs index bf82f211..e41875d4 100644 --- a/halo2-base/src/virtual_region/lookups.rs +++ b/halo2-base/src/virtual_region/lookups.rs @@ -14,6 +14,9 @@ use crate::{AssignedValue, ContextTag}; use super::copy_constraints::SharedCopyConstraintManager; use super::manager::VirtualRegionManager; +/// Basic dynamic lookup table gadget. +pub mod basic; + /// A manager that can be used for any lookup argument. This manager automates /// the process of copying cells to designed advice columns with lookup enabled. /// It also manages how many such advice columns are necessary. diff --git a/halo2-base/src/virtual_region/lookups/basic.rs b/halo2-base/src/virtual_region/lookups/basic.rs new file mode 100644 index 00000000..c3c60d86 --- /dev/null +++ b/halo2-base/src/virtual_region/lookups/basic.rs @@ -0,0 +1,140 @@ +use crate::{ + halo2_proofs::{ + circuit::{Layouter, Region, Value}, + halo2curves::ff::Field, + plonk::{Advice, Column, ConstraintSystem, Phase}, + poly::Rotation, + }, + utils::{ + halo2::{raw_assign_advice, Halo2AssignedCell}, + ScalarField, + }, + virtual_region::{ + copy_constraints::SharedCopyConstraintManager, lookups::LookupAnyManager, + manager::VirtualRegionManager, + }, + AssignedValue, +}; + +/// A simple dynamic lookup table for when you want to verify some length `KEY_COL` key +/// is in a provided (dynamic) table of the same format. +/// +/// Note that you can also use this to look up (key, out) pairs, where you consider the whole +/// pair as the new key. +/// +/// We can have multiple sets of dedicated columns to be looked up: these can be specified +/// when calling `new`, but typically we just need 1 set. +#[derive(Clone, Debug)] +pub struct BasicDynLookupConfig { + /// Columns for cells to be looked up. + pub to_lookup: Vec<[Column; KEY_COL]>, + /// Table to look up against. + pub table: [Column; KEY_COL], +} + +impl BasicDynLookupConfig { + /// Assumes all columns are in the same phase `P` to make life easier. + /// We enable equality on all columns because we envision both the columns to lookup + /// and the table will need to talk to halo2-lib. + pub fn new( + meta: &mut ConstraintSystem, + phase: impl Fn() -> P, + num_lu_sets: usize, + ) -> Self { + let mut make_columns = || { + [(); KEY_COL].map(|_| { + let advice = meta.advice_column_in(phase()); + meta.enable_equality(advice); + advice + }) + }; + let table = make_columns(); + let to_lookup: Vec<_> = (0..num_lu_sets).map(|_| make_columns()).collect(); + + for to_lookup in &to_lookup { + meta.lookup_any("dynamic lookup table", |meta| { + let table = table.map(|c| meta.query_advice(c, Rotation::cur())); + let to_lu = to_lookup.map(|c| meta.query_advice(c, Rotation::cur())); + to_lu.into_iter().zip(table).collect() + }); + } + + Self { table, to_lookup } + } + + /// Assign managed lookups + pub fn assign_managed_lookups( + &self, + mut layouter: impl Layouter, + lookup_manager: &LookupAnyManager, + ) { + layouter + .assign_region( + || "Managed lookup advice", + |mut region| { + lookup_manager.assign_raw(&self.to_lookup, &mut region); + Ok(()) + }, + ) + .unwrap(); + } + + /// Assign virtual table to raw + pub fn assign_virtual_table_to_raw( + &self, + mut layouter: impl Layouter, + rows: impl IntoIterator; KEY_COL]>, + copy_manager: Option<&SharedCopyConstraintManager>, + ) { + layouter + .assign_region( + || "Dynamic Lookup Table", + |mut region| { + self.assign_virtual_table_to_raw_from_offset( + &mut region, + rows, + 0, + copy_manager, + ); + Ok(()) + }, + ) + .unwrap(); + } + + /// `copy_manager` **must** be provided unless you are only doing witness generation + /// without constraints. + pub fn assign_virtual_table_to_raw_from_offset( + &self, + region: &mut Region, + rows: impl IntoIterator; KEY_COL]>, + offset: usize, + copy_manager: Option<&SharedCopyConstraintManager>, + ) { + for (i, row) in rows.into_iter().enumerate() { + for (col, virtual_cell) in self.table.into_iter().zip(row) { + assign_virtual_to_raw(region, col, offset + i, virtual_cell, copy_manager); + } + } + } +} + +/// Assign virtual cell to raw halo2 cell. +/// `copy_manager` **must** be provided unless you are only doing witness generation +/// without constraints. +pub fn assign_virtual_to_raw<'v, F: ScalarField>( + region: &mut Region, + column: Column, + offset: usize, + virtual_cell: AssignedValue, + copy_manager: Option<&SharedCopyConstraintManager>, +) -> Halo2AssignedCell<'v, F> { + let raw = raw_assign_advice(region, column, offset, Value::known(virtual_cell.value)); + if let Some(copy_manager) = copy_manager { + let mut copy_manager = copy_manager.lock().unwrap(); + let cell = virtual_cell.cell.unwrap(); + copy_manager.assigned_advices.insert(cell, raw.cell()); + drop(copy_manager); + } + raw +}