diff --git a/book/src/specs/kimchi.md b/book/src/specs/kimchi.md index 3fd8b4622c..dae3877e25 100644 --- a/book/src/specs/kimchi.md +++ b/book/src/specs/kimchi.md @@ -1647,8 +1647,8 @@ If lookup is used, the following values are added to the common index: To create the index, follow these steps: 1. If no lookup is used in the circuit, do not create a lookup index -2. Get the lookup selectors and lookup tables that are specified implicitly -3. Concatenate explicit runtime lookup tables with the ones (implicitly) used by gates. +2. Get the lookup selectors and lookup tables (TODO: how?) +3. Concatenate runtime lookup tables with the ones used by gates 4. Get the highest number of columns `max_table_width` that a lookup table can have. 5. Create the concatenated table of all the fixed lookup tables. diff --git a/kimchi/src/circuits/constraints.rs b/kimchi/src/circuits/constraints.rs index c158a023f0..83aeb30ffe 100644 --- a/kimchi/src/circuits/constraints.rs +++ b/kimchi/src/circuits/constraints.rs @@ -736,7 +736,18 @@ impl Builder { let lookup_domain_size = { // First we sum over the lookup table size - let mut lookup_domain_size: usize = lookup_tables.iter().map(|lt| lt.len()).sum(); + let mut lookup_domain_size: usize = lookup_tables + .iter() + .map( + |LookupTable { data, id: _ }| { + if data.is_empty() { + 0 + } else { + data[0].len() + } + }, + ) + .sum(); // After that on the runtime tables if let Some(runtime_tables) = runtime_tables.as_ref() { for runtime_table in runtime_tables.iter() { @@ -846,7 +857,7 @@ impl Builder { &domain, zk_rows as usize, ) - .map_err(SetupError::LookupCreation)?; + .map_err(|e| SetupError::ConstraintSystem(e.to_string()))?; let sid = shifts.map[0].clone(); diff --git a/kimchi/src/circuits/lookup/index.rs b/kimchi/src/circuits/lookup/index.rs index 41a9709737..ab3e4545ab 100644 --- a/kimchi/src/circuits/lookup/index.rs +++ b/kimchi/src/circuits/lookup/index.rs @@ -1,10 +1,10 @@ +use super::runtime_tables::{RuntimeTableCfg, RuntimeTableSpec}; use crate::circuits::{ domains::EvaluationDomains, gate::CircuitGate, lookup::{ constraints::LookupConfiguration, lookups::{LookupInfo, LookupPattern}, - runtime_tables::{RuntimeTableCfg, RuntimeTableSpec}, tables::LookupTable, }, }; @@ -21,15 +21,17 @@ use std::iter; use thiserror::Error; /// Represents an error found when computing the lookup constraint system -#[derive(Debug, Error, Clone)] +#[derive(Debug, Error)] pub enum LookupError { + #[error("One of the lookup tables has columns of different lengths")] + InconsistentTableLength, #[error("The combined lookup table is larger than allowed by the domain size. Observed: {length}, expected: {maximum_allowed}")] LookupTableTooLong { length: usize, maximum_allowed: usize, }, - #[error("Cannot create a combined table since ids for sub-tables are colliding. The collision type is: {collision_type}")] - LookupTableIdCollision { collision_type: String }, + #[error("The table with id 0 must have an entry of all zeros")] + TableIDZeroMustHaveZeroEntry, } /// Lookup selectors @@ -198,7 +200,7 @@ impl LookupConstraintSystem { /// Will give error if inputs validation do not match. pub fn create( gates: &[CircuitGate], - fixed_lookup_tables: Vec>, + lookup_tables: Vec>, runtime_tables: Option>>, domain: &EvaluationDomains, zk_rows: usize, @@ -215,64 +217,21 @@ impl LookupConstraintSystem { // product is 1, we cannot use those rows to store any values. let max_num_entries = d1_size - zk_rows - 1; - //~ 2. Get the lookup selectors and lookup tables that are specified implicitly - // by the lookup gates. + //~ 2. Get the lookup selectors and lookup tables (TODO: how?) let (lookup_selectors, gate_lookup_tables) = lookup_info.selector_polynomials_and_tables(domain, gates); - // Checks whether an iterator contains any duplicates, and if yes, raises - // a corresponding LookupTableIdCollision error. - fn check_id_duplicates<'a, I: Iterator>( - iter: I, - msg: &str, - ) -> Result<(), LookupError> { - use itertools::Itertools; - match iter.duplicates().collect::>() { - dups if !dups.is_empty() => Err(LookupError::LookupTableIdCollision { - collision_type: format!("{}: {:?}", msg, dups).to_string(), - }), - _ => Ok(()), - } - } - - // If there is a gate using a lookup table, this table must not be added - // explicitly to the constraint system. - let fixed_gate_joint_ids: Vec = fixed_lookup_tables - .iter() - .map(|lt| lt.id()) - .chain(gate_lookup_tables.iter().map(|lt| lt.id())) - .collect(); - check_id_duplicates( - fixed_gate_joint_ids.iter(), - "duplicates between fixed given and fixed from-gate tables", - )?; - - //~ 3. Concatenate explicit runtime lookup tables with the ones (implicitly) used by gates. - let mut lookup_tables: Vec> = fixed_lookup_tables + //~ 3. Concatenate runtime lookup tables with the ones used by gates + let mut lookup_tables: Vec<_> = gate_lookup_tables .into_iter() - .chain(gate_lookup_tables) + .chain(lookup_tables) .collect(); - let fixed_lookup_tables_ids: Vec = - lookup_tables.iter().map(|lt| lt.id()).collect(); - check_id_duplicates( - fixed_lookup_tables_ids.iter(), - "fixed lookup table duplicates", - )?; + let mut has_table_id_0 = false; // if we are using runtime tables let (runtime_table_offset, runtime_selector) = if let Some(runtime_tables) = &runtime_tables { - let runtime_tables_ids: Vec = - runtime_tables.iter().map(|rt| rt.id).collect(); - check_id_duplicates(runtime_tables_ids.iter(), "runtime table duplicates")?; - check_id_duplicates( - runtime_tables_ids - .iter() - .chain(fixed_lookup_tables_ids.iter()), - "duplicates between runtime and fixed tables", - )?; - // save the offset of the end of the table let mut runtime_table_offset = 0; for table in &lookup_tables { @@ -313,15 +272,18 @@ impl LookupConstraintSystem { let (id, first_column) = (runtime_table.id, runtime_table.first_column.clone()); + // record if table ID 0 is used in one of the runtime tables + // note: the check later will still force you to have a fixed table with ID 0 + if id == 0 { + has_table_id_0 = true; + } + // important: we still need a placeholder column to make sure that // if all other tables have a single column // we don't use the second table as table ID column. let placeholders = vec![F::zero(); first_column.len()]; let data = vec![first_column, placeholders]; - // TODO Check it does not fail actually. Maybe this should throw a different error. - let table = LookupTable::create(id, data) - .expect("Runtime table creation must succeed"); - + let table = LookupTable { id, data }; lookup_tables.push(table); } @@ -383,21 +345,31 @@ impl LookupConstraintSystem { let mut table_ids: Vec = Vec::with_capacity(d1_size); let mut non_zero_table_id = false; + let mut has_table_id_0_with_zero_entry = false; for table in &lookup_tables { let table_len = table.len(); - if table.id() != 0 { + if table.id == 0 { + has_table_id_0 = true; + if table.has_zero_entry() { + has_table_id_0_with_zero_entry = true; + } + } else { non_zero_table_id = true; } //~~ * Update the corresponding entries in a table id vector (of size the domain as well) //~ with the table ID of the table. - let table_id: F = i32_to_field(table.id()); + let table_id: F = i32_to_field(table.id); table_ids.extend(repeat_n(table_id, table_len)); //~~ * Copy the entries from the table to new rows in the corresponding columns of the concatenated table. - for (i, col) in table.data().iter().enumerate() { + for (i, col) in table.data.iter().enumerate() { + // See GH issue: https://github.com/MinaProtocol/mina/issues/14097 + if col.len() != table_len { + return Err(LookupError::InconsistentTableLength); + } lookup_table[i].extend(col); } @@ -407,6 +379,12 @@ impl LookupConstraintSystem { } } + // If a table has ID 0, then it must have a zero entry. + // This is for the dummy lookups to work. + if has_table_id_0 && !has_table_id_0_with_zero_entry { + return Err(LookupError::TableIDZeroMustHaveZeroEntry); + } + // Note: we use `>=` here to leave space for the dummy value. if lookup_table[0].len() >= max_num_entries { return Err(LookupError::LookupTableTooLong { @@ -433,8 +411,6 @@ impl LookupConstraintSystem { lookup_table8.push(eval); } - // @volhovm: Do we need to enforce that there is at least one table - // with id 0? //~ 9. pre-compute polynomial and evaluation form for the table IDs, //~ only if a table with an ID different from zero was used. let (table_ids, table_ids8) = if non_zero_table_id { @@ -467,105 +443,3 @@ impl LookupConstraintSystem { } } } - -#[cfg(test)] -mod tests { - - use super::{LookupError, LookupTable, RuntimeTableCfg}; - use crate::{ - circuits::constraints::ConstraintSystem, circuits::gate::CircuitGate, - circuits::lookup::tables::xor, circuits::polynomials::range_check, error::SetupError, - }; - use mina_curves::pasta::Fp; - - #[test] - fn colliding_table_ids() { - let (_, gates) = CircuitGate::::create_multi_range_check(0); - let collision_id: i32 = 5; - - let cs = ConstraintSystem::::create(gates.clone()) - .lookup(vec![range_check::gadget::lookup_table()]) - .build(); - - assert!( - matches!( - cs, - Err(SetupError::LookupCreation( - LookupError::LookupTableIdCollision { .. } - )) - ), - "LookupConstraintSystem::create(...) must fail due to range table passed twice" - ); - - let cs = ConstraintSystem::::create(gates.clone()) - .lookup(vec![xor::xor_table()]) - .build(); - - assert!( - cs.is_ok(), - "LookupConstraintSystem::create(...) must succeed, no duplicates exist" - ); - - let cs = ConstraintSystem::::create(gates.clone()) - .lookup(vec![ - LookupTable::create(collision_id, vec![vec![From::from(0); 16]]).unwrap(), - LookupTable::create(collision_id, vec![vec![From::from(1); 16]]).unwrap(), - ]) - .build(); - - assert!( - matches!( - cs, - Err(SetupError::LookupCreation( - LookupError::LookupTableIdCollision { .. } - )) - ), - "LookupConstraintSystem::create(...) must fail, collision in fixed ids" - ); - - let cs = ConstraintSystem::::create(gates.clone()) - .runtime(Some(vec![ - RuntimeTableCfg { - id: collision_id, - first_column: vec![From::from(0); 16], - }, - RuntimeTableCfg { - id: collision_id, - first_column: vec![From::from(1); 16], - }, - ])) - .build(); - - assert!( - matches!( - cs, - Err(SetupError::LookupCreation( - LookupError::LookupTableIdCollision { .. } - )) - ), - "LookupConstraintSystem::create(...) must fail, collision in runtime ids" - ); - - let cs = ConstraintSystem::::create(gates.clone()) - .lookup(vec![LookupTable::create( - collision_id, - vec![vec![From::from(0); 16]], - ) - .unwrap()]) - .runtime(Some(vec![RuntimeTableCfg { - id: collision_id, - first_column: vec![From::from(1); 16], - }])) - .build(); - - assert!( - matches!( - cs, - Err(SetupError::LookupCreation( - LookupError::LookupTableIdCollision { .. } - )) - ), - "LookupConstraintSystem::create(...) must fail, collision between runtime and lookup ids" - ); - } -} diff --git a/kimchi/src/circuits/lookup/lookups.rs b/kimchi/src/circuits/lookup/lookups.rs index 63266b3abf..002b040828 100644 --- a/kimchi/src/circuits/lookup/lookups.rs +++ b/kimchi/src/circuits/lookup/lookups.rs @@ -222,7 +222,7 @@ impl LookupInfo { }; // TODO: is take(n) useful here? I don't see why we need this - for (i, gate) in gates.iter().take(n).enumerate() { + for (i, gate) in gates.iter().enumerate().take(n) { let typ = gate.typ; if let Some(lookup_pattern) = LookupPattern::from_gate(typ, CurrOrNext::Curr) { diff --git a/kimchi/src/circuits/lookup/runtime_tables.rs b/kimchi/src/circuits/lookup/runtime_tables.rs index 3ed6afc9f7..ef2d9f7d15 100644 --- a/kimchi/src/circuits/lookup/runtime_tables.rs +++ b/kimchi/src/circuits/lookup/runtime_tables.rs @@ -18,8 +18,6 @@ pub struct RuntimeTableSpec { pub len: usize, } -/// A configuration of the runtime table as known at setup time. -/// /// Use this type at setup time, to list all the runtime tables. /// /// Note: care must be taken as table IDs can collide with IDs of other types of lookup tables. @@ -27,8 +25,7 @@ pub struct RuntimeTableSpec { pub struct RuntimeTableCfg { /// The table ID. pub id: i32, - /// The content of the first column of the runtime table, i.e. - /// keys when a table is viewed as a (k,v) array. + /// The content of the first column of the runtime table. pub first_column: Vec, } @@ -59,13 +56,12 @@ impl From> for RuntimeTableSpec { } /// A runtime table. Runtime tables must match the configuration -/// specified in [`RuntimeTableCfg`]. +/// that was specified in [`RuntimeTableCfg`]. #[derive(Debug, Clone)] pub struct RuntimeTable { /// The table id. pub id: i32, - /// A single column. Represents runtime table values, where - /// ['RuntimeTableCfg'] defines compile-time keys. + /// A single column. pub data: Vec, } diff --git a/kimchi/src/circuits/lookup/tables/mod.rs b/kimchi/src/circuits/lookup/tables/mod.rs index 5813d062b2..0c049f3e59 100644 --- a/kimchi/src/circuits/lookup/tables/mod.rs +++ b/kimchi/src/circuits/lookup/tables/mod.rs @@ -1,112 +1,10 @@ -use ark_ff::{Field, One, Zero}; +use ark_ff::{FftField, One, Zero}; use poly_commitment::PolyComm; use serde::{Deserialize, Serialize}; -use thiserror::Error; pub mod range_check; pub mod xor; -/// A table of values that can be used for a lookup, along with the ID for the table. -#[derive(Debug, Clone)] -pub struct LookupTable { - id: i32, - data: Vec>, -} - -/// Represents inconsistency errors during table construction and composition. -#[derive(Debug, Error)] -pub enum LookupTableError { - #[error("Table must be nonempty")] - InputTableDataEmpty, - #[error("One of the lookup tables has columns of different lengths")] - InconsistentTableLength, - #[error("The table with id 0 must have an entry of all zeros")] - TableIDZeroMustHaveZeroEntry, -} - -impl LookupTable -where - F: Field, -{ - pub fn create(id: i32, data: Vec>) -> Result { - let res = LookupTable { id, data }; - - // Empty tables are not allowed - if res.data.is_empty() { - return Err(LookupTableError::InputTableDataEmpty); - } - - // All columns in the table must have same length - let table_len = res.len(); - for col in res.data.iter() { - if col.len() != table_len { - return Err(LookupTableError::InconsistentTableLength); - } - } - - // If a table has ID 0, then it must have a zero entry. - // This is for the dummy lookups to work. - if id == 0 && !res.has_zero_entry() { - return Err(LookupTableError::TableIDZeroMustHaveZeroEntry); - } - - Ok(res) - } - - /// Return true if the table has an entry (row) containing all zeros. - fn has_zero_entry(&self) -> bool { - // reminder: a table is written as a list of columns, - // not as a list of row entries. - for row in 0..self.len() { - let mut row_zero = true; - for col in &self.data { - if !col[row].is_zero() { - row_zero = false; - break; - } - } - if row_zero { - return true; - } - } - - false - } - - /// Returns the number of columns, i.e. the width of the table. - /// It is less error prone to introduce this method than using the public - /// field data. - pub fn width(&self) -> usize { - self.data.len() - } - - /// Returns the length (height) of the table. - pub fn len(&self) -> usize { - if self.is_empty() { - panic!("LookupTable#len() is called on an empty table") - } - self.data[0].len() - } - - /// Returns `true` if the lookup table is empty, `false` otherwise. - pub fn is_empty(&self) -> bool { - self.data.is_empty() - } - - /// Returns table id. - pub fn id(&self) -> i32 { - self.id - } - - /// Returns table data. - pub fn data(&self) -> &Vec> { - &self.data - } -} - -// If you add new tables, update ../../../../../book/src/kimchi/lookup.md -// accordingly - //~ spec:startcode /// The table ID associated with the XOR lookup table. pub const XOR_TABLE_ID: i32 = 0; @@ -169,8 +67,53 @@ impl IntoIterator for GateLookupTables { } } +/// A table of values that can be used for a lookup, along with the ID for the table. +#[derive(Debug, Clone)] +pub struct LookupTable { + pub id: i32, + pub data: Vec>, +} + +impl LookupTable +where + F: FftField, +{ + /// Return true if the table has an entry containing all zeros. + pub fn has_zero_entry(&self) -> bool { + // reminder: a table is written as a list of columns, + // not as a list of row entries. + for row in 0..self.len() { + for col in &self.data { + if !col[row].is_zero() { + continue; + } + return true; + } + } + + false + } + + /// Returns the number of columns, i.e. the width of the table. + /// It is less error prone to introduce this method than using the public + /// field data. + pub fn width(&self) -> usize { + self.data.len() + } + + /// Returns the length of the table. + pub fn len(&self) -> usize { + self.data[0].len() + } + + /// Returns `true` if the lookup table is empty, `false` otherwise. + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } +} + /// Returns the lookup table associated to a [`GateLookupTable`]. -pub fn get_table(table_name: GateLookupTable) -> LookupTable { +pub fn get_table(table_name: GateLookupTable) -> LookupTable { match table_name { GateLookupTable::Xor => xor::xor_table(), GateLookupTable::RangeCheck => range_check::range_check_table(), @@ -212,7 +155,6 @@ where F: Zero + One + Clone, I: DoubleEndedIterator, { - // TODO: unnecessary cloning if binops between F and &F are supported v.rev() .fold(F::zero(), |acc, x| joint_combiner.clone() * acc + x.clone()) + table_id_combiner.clone() * table_id.clone() @@ -313,50 +255,3 @@ pub mod caml { } } } - -#[cfg(test)] -mod tests { - - use super::*; - use mina_curves::pasta::Fp; - - #[test] - fn test_zero_table_zero_row() { - let lookup_r: u64 = 32; - // Table column that /does not/ contain zeros - let lookup_table_values_1: Vec<_> = (1..lookup_r + 1).map(From::from).collect(); - // Another table column that /does/ contain zeros. - let lookup_table_values_2: Vec<_> = (0..lookup_r).map(From::from).collect(); - - // Jointly two columns /do not/ have a full zero now. - let table: Result, _> = - LookupTable::create(0, vec![lookup_table_values_1, lookup_table_values_2]); - - assert!( - matches!(table, Err(LookupTableError::TableIDZeroMustHaveZeroEntry)), - "LookupTable::create(...) must fail when zero table has no zero rows" - ); - } - - #[test] - fn test_invalid_data_inputs() { - let table: Result, _> = LookupTable::create(0, vec![]); - assert!( - matches!(table, Err(LookupTableError::InputTableDataEmpty)), - "LookupTable::create(...) must fail when empty table creation is attempted" - ); - - let lookup_r: u64 = 32; - // Two columns of different lengths - let lookup_table_values_1: Vec<_> = (0..2 * lookup_r).map(From::from).collect(); - let lookup_table_values_2: Vec<_> = (0..lookup_r).map(From::from).collect(); - - let table: Result, _> = - LookupTable::create(0, vec![lookup_table_values_1, lookup_table_values_2]); - - assert!( - matches!(table, Err(LookupTableError::InconsistentTableLength)), - "LookupTable::create(...) must fail when columns are not of the same length" - ); - } -} diff --git a/kimchi/src/circuits/lookup/tables/range_check.rs b/kimchi/src/circuits/lookup/tables/range_check.rs index 2bf00e64f7..001ffedd52 100644 --- a/kimchi/src/circuits/lookup/tables/range_check.rs +++ b/kimchi/src/circuits/lookup/tables/range_check.rs @@ -14,9 +14,11 @@ pub fn range_check_table() -> LookupTable where F: Field, { - let data = vec![(0..RANGE_CHECK_UPPERBOUND).map(F::from).collect()]; - LookupTable::create(RANGE_CHECK_TABLE_ID, data) - .expect("range_check_table creation must succeed") + let table = vec![(0..RANGE_CHECK_UPPERBOUND).map(F::from).collect()]; + LookupTable { + id: RANGE_CHECK_TABLE_ID, + data: table, + } } pub const TABLE_SIZE: usize = RANGE_CHECK_UPPERBOUND as usize; diff --git a/kimchi/src/circuits/lookup/tables/xor.rs b/kimchi/src/circuits/lookup/tables/xor.rs index 6f87377d96..d846942a31 100644 --- a/kimchi/src/circuits/lookup/tables/xor.rs +++ b/kimchi/src/circuits/lookup/tables/xor.rs @@ -37,8 +37,10 @@ pub fn xor_table() -> LookupTable { // Just to be safe. assert!(r[r.len() - 1].is_zero()); } - - LookupTable::create(XOR_TABLE_ID, data).expect("xor_table creation must succeed") + LookupTable { + id: XOR_TABLE_ID, + data, + } } pub const TABLE_SIZE: usize = 256; diff --git a/kimchi/src/error.rs b/kimchi/src/error.rs index 84bd430dfa..3c0b352eb7 100644 --- a/kimchi/src/error.rs +++ b/kimchi/src/error.rs @@ -1,6 +1,5 @@ //! This module implements the [`ProverError`] type. -use crate::circuits::lookup::index::LookupError; // not sure about hierarchy use poly_commitment::error::CommitmentError; use thiserror::Error; @@ -101,9 +100,6 @@ pub enum SetupError { #[error("the domain could not be constructed: {0}")] DomainCreation(DomainCreationError), - - #[error("the lookup constraint system cannot not be constructed: {0}")] - LookupCreation(LookupError), } /// Errors that can arise when creating a verifier index diff --git a/kimchi/src/precomputed_srs.rs b/kimchi/src/precomputed_srs.rs index 65041b698f..8c55d25377 100644 --- a/kimchi/src/precomputed_srs.rs +++ b/kimchi/src/precomputed_srs.rs @@ -33,9 +33,6 @@ where let file = File::open(srs_path.clone()).unwrap_or_else(|_| panic!("missing SRS file: {srs_path:?}")); let reader = BufReader::new(file); - // Note: In tests, this read takes significant amount of time (2 min) due - // to -O0 optimisation level. Compile tests with -O1 or --release flag. - // See: https://github.com/o1-labs/proof-systems/blob/develop/CONTRIBUTING.md#development rmp_serde::from_read(reader).unwrap() } diff --git a/kimchi/src/prover_index.rs b/kimchi/src/prover_index.rs index e01cf19e90..05db4f5b6b 100644 --- a/kimchi/src/prover_index.rs +++ b/kimchi/src/prover_index.rs @@ -211,7 +211,6 @@ pub mod testing { override_srs_size, |d1: D, size: usize| { let log2_size = size.ilog2(); - // Run test_srs_serialization test to generate test SRS & enable this let mut srs = if log2_size <= precomputed_srs::SERIALIZED_SRS_SIZE { // TODO: we should trim it if it's smaller precomputed_srs::get_srs() diff --git a/kimchi/src/tests/and.rs b/kimchi/src/tests/and.rs index 9c1a86fbcd..e344af6da4 100644 --- a/kimchi/src/tests/and.rs +++ b/kimchi/src/tests/and.rs @@ -255,7 +255,6 @@ fn verify_bad_and_decomposition( ); witness[col][and_row] += G::ScalarField::one(); } - if col == 2 { assert_eq!( cs.gates[0].verify_witness::(0, witness, &cs, &witness[0][0..cs.public]), diff --git a/kimchi/src/tests/foreign_field_add.rs b/kimchi/src/tests/foreign_field_add.rs index 760c7fa2d5..24c1d5a8c1 100644 --- a/kimchi/src/tests/foreign_field_add.rs +++ b/kimchi/src/tests/foreign_field_add.rs @@ -1490,6 +1490,7 @@ fn test_ffadd_finalization() { let index = { let cs = ConstraintSystem::create(gates.clone()) + .lookup(vec![range_check::gadget::lookup_table()]) .public(num_public_inputs) .build() .unwrap(); diff --git a/kimchi/src/tests/lookup.rs b/kimchi/src/tests/lookup.rs index 269235d35e..a674eba78f 100644 --- a/kimchi/src/tests/lookup.rs +++ b/kimchi/src/tests/lookup.rs @@ -22,12 +22,10 @@ type BaseSponge = DefaultFqSponge; type ScalarSponge = DefaultFrSponge; fn setup_lookup_proof(use_values_from_table: bool, num_lookups: usize, table_sizes: Vec) { - let mut lookup_table_values: Vec> = table_sizes + let lookup_table_values: Vec> = table_sizes .iter() .map(|size| (0..*size).map(|_| rand::random()).collect()) .collect(); - // Zero table must have a zero row - lookup_table_values[0][0] = From::from(0); let lookup_tables = lookup_table_values .iter() .enumerate() @@ -35,8 +33,10 @@ fn setup_lookup_proof(use_values_from_table: bool, num_lookups: usize, table_siz let index_column = (0..lookup_table_values.len() as u64) .map(Into::into) .collect(); - LookupTable::create(id as i32, vec![index_column, lookup_table_values.clone()]) - .expect("setup_lookup_proof: Table creation must succeed") + LookupTable { + id: id as i32, + data: vec![index_column, lookup_table_values.clone()], + } }) .collect(); @@ -200,7 +200,7 @@ fn test_runtime_table() { let len = first_column.len(); let mut runtime_tables_setup = vec![]; - for table_id in 1..num + 1 { + for table_id in 0..num { let cfg = RuntimeTableCfg { id: table_id, first_column: first_column.into_iter().map(Into::into).collect(), @@ -236,7 +236,7 @@ fn test_runtime_table() { for row in 0..20 { // the first register is the table id. We pick one random table. - lookup_cols[0][row] = (rng.gen_range(1..num + 1) as u32).into(); + lookup_cols[0][row] = (rng.gen_range(0..num) as u32).into(); // create queries into our runtime lookup table. // We will set [w1, w2], [w3, w4] and [w5, w6] to randon indexes and diff --git a/kimchi/src/tests/range_check.rs b/kimchi/src/tests/range_check.rs index 577e2aa4f7..27240db942 100644 --- a/kimchi/src/tests/range_check.rs +++ b/kimchi/src/tests/range_check.rs @@ -68,10 +68,7 @@ fn create_test_prover_index( gates, public_size, 0, - // specifying lookup table is not necessary, - // since it's already passed through patterns implicitly - //vec![range_check::gadget::lookup_table()], - vec![], + vec![range_check::gadget::lookup_table()], None, false, None, diff --git a/kimchi/src/tests/rot.rs b/kimchi/src/tests/rot.rs index 852747d196..c731884f7e 100644 --- a/kimchi/src/tests/rot.rs +++ b/kimchi/src/tests/rot.rs @@ -355,6 +355,7 @@ fn test_rot_finalization() { let index = { let cs = ConstraintSystem::create(gates.clone()) .public(num_public_inputs) + .lookup(vec![rot::lookup_table()]) .build() .unwrap(); let mut srs = SRS::::create(cs.domain.d1.size()); diff --git a/kimchi/src/tests/xor.rs b/kimchi/src/tests/xor.rs index 7ab28b4008..0344e0aea3 100644 --- a/kimchi/src/tests/xor.rs +++ b/kimchi/src/tests/xor.rs @@ -392,6 +392,7 @@ fn test_xor_finalization() { let index = { let cs = ConstraintSystem::create(gates.clone()) + .lookup(vec![xor::lookup_table()]) .public(num_inputs) .build() .unwrap();