From 5075916a57a9a21e1c8e5ca118f1fbcf92b825fd Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Sat, 11 Jun 2022 10:57:38 +0200 Subject: [PATCH 1/8] try merge range and special chunks table --- Cargo.lock | 2 + keccak256/Cargo.toml | 2 + keccak256/src/permutation/tables.rs | 127 +++++++++++++++++++++++++++- 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c23a86fc59..36299d8a0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2250,6 +2250,8 @@ dependencies = [ "plotters", "pretty_assertions", "rand", + "strum", + "strum_macros", ] [[package]] diff --git a/keccak256/Cargo.toml b/keccak256/Cargo.toml index 7c35517a70..6fc9344f1f 100644 --- a/keccak256/Cargo.toml +++ b/keccak256/Cargo.toml @@ -16,6 +16,8 @@ plotters = { version = "0.3.0", optional = true } eth-types = { path = "../eth-types" } lazy_static = "1.4" gadgets = { path = "../gadgets" } +strum = "0.24" +strum_macros = "0.24" [dev-dependencies] pretty_assertions = "1.0" diff --git a/keccak256/src/permutation/tables.rs b/keccak256/src/permutation/tables.rs index 49b825cd9f..57d94c4745 100644 --- a/keccak256/src/permutation/tables.rs +++ b/keccak256/src/permutation/tables.rs @@ -4,17 +4,140 @@ use crate::gate_helpers::f_to_biguint; use crate::permutation::rho_helpers::{get_overflow_detector, BASE_NUM_OF_CHUNKS}; use eth_types::Field; use halo2_proofs::{ - circuit::Layouter, - plonk::{ConstraintSystem, Error, TableColumn}, + circuit::{AssignedCell, Layouter}, + plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, + poly::Rotation, }; use itertools::Itertools; use std::convert::TryInto; use std::marker::PhantomData; +use strum_macros::{Display, EnumIter}; + +use super::rho_helpers::{STEP2_RANGE, STEP3_RANGE}; const MAX_CHUNKS: usize = 64; const NUM_OF_BINARY_CHUNKS: usize = 16; const NUM_OF_B9_CHUNKS: usize = 5; +#[derive(EnumIter, Display, Clone, Copy)] +enum TableTags { + Range12 = 0, + Range169, + SpecialChunk, +} + +#[derive(Debug, Clone)] +pub struct StackableTable { + tag: (Column, TableColumn), + col1: (Column, TableColumn), + col2: (Column, TableColumn), + _marker: PhantomData, +} + +impl StackableTable { + pub(crate) fn configure( + meta: &mut ConstraintSystem, + adv_cols: [Column; 3], + table_cols: [TableColumn; 3], + ) -> Self { + let tag = (adv_cols[0], table_cols[0]); + let col1 = (adv_cols[1], table_cols[1]); + let col2 = (adv_cols[2], table_cols[2]); + let q_enable = meta.complex_selector(); + meta.lookup("stackable lookup", |meta| { + let q_enable = meta.query_selector(q_enable); + vec![tag, col1, col2] + .iter() + .map(|&(adv_col, table_col)| { + ( + q_enable.clone() * meta.query_advice(adv_col, Rotation::cur()), + table_col, + ) + }) + .collect_vec() + }); + Self { + tag, + col1, + col2, + _marker: PhantomData, + } + } + pub(crate) fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + for &(tag, k) in [ + (TableTags::Range12, STEP2_RANGE), + (TableTags::Range169, STEP3_RANGE), + ] + .iter() + { + layouter.assign_table( + || format!("range {}", tag), + |mut table| { + for i in 0..=k { + table.assign_cell( + || format!("tag range{}", tag), + self.tag.1, + i as usize, + || Ok(F::from(tag as u64)), + )?; + table.assign_cell( + || format!("range{}", tag), + self.col1.1, + i as usize, + || Ok(F::from(i)), + )?; + table.assign_cell( + || format!("dummy col range{}", tag), + self.col2.1, + i as usize, + || Ok(F::zero()), + )?; + } + Ok(()) + }, + )?; + } + layouter.assign_table( + || "Special chunks", + |mut table| { + let mut offset = 0; + for i in 0..B13 { + for j in 0..(B13 - i) { + let (low, high) = (i, j); + let last_chunk = F::from(low as u64) + + F::from(high as u64) + * F::from(B13 as u64).pow(&[LANE_SIZE as u64, 0, 0, 0]); + let output_coef = F::from(convert_b13_coef(low + high) as u64); + table.assign_cell( + || "tag special chunks", + self.tag.1, + offset, + || Ok(F::from(TableTags::SpecialChunk as u64)), + )?; + table.assign_cell( + || "last chunk", + self.col1.1, + offset, + || Ok(last_chunk), + )?; + table.assign_cell( + || "output coef", + self.col2.1, + offset, + || Ok(output_coef), + )?; + offset += 1; + } + } + Ok(()) + }, + ) + } + pub(crate) fn lookup_range(value: AssignedCell) -> Result<(), Error> { + Ok(()) + } +} + #[derive(Debug, Clone)] pub struct RangeCheckConfig { pub range: TableColumn, From d4c7fe972f44358a1aa41c3ddade531b6f316b30 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Tue, 14 Jun 2022 13:56:41 +0200 Subject: [PATCH 2/8] stackable table done --- keccak256/src/permutation/tables.rs | 187 +++++++++++++++++----------- 1 file changed, 114 insertions(+), 73 deletions(-) diff --git a/keccak256/src/permutation/tables.rs b/keccak256/src/permutation/tables.rs index 57d94c4745..daea0ca501 100644 --- a/keccak256/src/permutation/tables.rs +++ b/keccak256/src/permutation/tables.rs @@ -4,7 +4,7 @@ use crate::gate_helpers::f_to_biguint; use crate::permutation::rho_helpers::{get_overflow_detector, BASE_NUM_OF_CHUNKS}; use eth_types::Field; use halo2_proofs::{ - circuit::{AssignedCell, Layouter}, + circuit::{AssignedCell, Layouter, Table}, plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, poly::Rotation, }; @@ -20,7 +20,7 @@ const NUM_OF_BINARY_CHUNKS: usize = 16; const NUM_OF_B9_CHUNKS: usize = 5; #[derive(EnumIter, Display, Clone, Copy)] -enum TableTags { +pub(crate) enum TableTags { Range12 = 0, Range169, SpecialChunk, @@ -46,15 +46,15 @@ impl StackableTable { let q_enable = meta.complex_selector(); meta.lookup("stackable lookup", |meta| { let q_enable = meta.query_selector(q_enable); - vec![tag, col1, col2] - .iter() - .map(|&(adv_col, table_col)| { - ( - q_enable.clone() * meta.query_advice(adv_col, Rotation::cur()), - table_col, - ) - }) - .collect_vec() + let tag_adv = meta.query_advice(tag.0, Rotation::cur()); + let col1_adv = meta.query_advice(col1.0, Rotation::cur()); + let col2_adv = meta.query_advice(col2.0, Rotation::cur()); + + vec![ + (q_enable.clone() * tag_adv, tag.1), + (q_enable.clone() * col1_adv, col1.1), + (q_enable * col2_adv, col2.1), + ] }); Self { tag, @@ -63,78 +63,119 @@ impl StackableTable { _marker: PhantomData, } } - pub(crate) fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - for &(tag, k) in [ - (TableTags::Range12, STEP2_RANGE), - (TableTags::Range169, STEP3_RANGE), - ] - .iter() - { - layouter.assign_table( - || format!("range {}", tag), - |mut table| { - for i in 0..=k { - table.assign_cell( - || format!("tag range{}", tag), - self.tag.1, - i as usize, - || Ok(F::from(tag as u64)), - )?; - table.assign_cell( - || format!("range{}", tag), - self.col1.1, - i as usize, - || Ok(F::from(i)), - )?; - table.assign_cell( - || format!("dummy col range{}", tag), - self.col2.1, - i as usize, - || Ok(F::zero()), - )?; - } - Ok(()) - }, + + fn load_range( + &self, + table: &mut Table, + offset: usize, + tag: TableTags, + k: u64, + ) -> Result { + let mut offset = offset; + for i in 0..=k { + table.assign_cell( + || format!("tag range{}", tag), + self.tag.1, + offset, + || Ok(F::from(tag as u64)), + )?; + table.assign_cell( + || format!("range{}", tag), + self.col1.1, + offset, + || Ok(F::from(i)), + )?; + table.assign_cell( + || format!("dummy col range{}", tag), + self.col2.1, + offset, + || Ok(F::zero()), )?; + offset += 1; } + Ok(offset) + } + fn load_special_chunks(&self, table: &mut Table, offset: usize) -> Result { + let mut offset = offset; + for i in 0..B13 { + for j in 0..(B13 - i) { + let (low, high) = (i, j); + let last_chunk = F::from(low as u64) + + F::from(high as u64) * F::from(B13 as u64).pow(&[LANE_SIZE as u64, 0, 0, 0]); + let output_coef = F::from(convert_b13_coef(low + high) as u64); + table.assign_cell( + || "tag special chunks", + self.tag.1, + offset, + || Ok(F::from(TableTags::SpecialChunk as u64)), + )?; + table.assign_cell(|| "last chunk", self.col1.1, offset, || Ok(last_chunk))?; + table.assign_cell(|| "output coef", self.col2.1, offset, || Ok(output_coef))?; + offset += 1; + } + } + Ok(offset) + } + pub(crate) fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { layouter.assign_table( - || "Special chunks", + || "stackable", |mut table| { let mut offset = 0; - for i in 0..B13 { - for j in 0..(B13 - i) { - let (low, high) = (i, j); - let last_chunk = F::from(low as u64) - + F::from(high as u64) - * F::from(B13 as u64).pow(&[LANE_SIZE as u64, 0, 0, 0]); - let output_coef = F::from(convert_b13_coef(low + high) as u64); - table.assign_cell( - || "tag special chunks", - self.tag.1, - offset, - || Ok(F::from(TableTags::SpecialChunk as u64)), - )?; - table.assign_cell( - || "last chunk", - self.col1.1, - offset, - || Ok(last_chunk), - )?; - table.assign_cell( - || "output coef", - self.col2.1, - offset, - || Ok(output_coef), - )?; - offset += 1; - } + for &(tag, k) in [ + (TableTags::Range12, STEP2_RANGE), + (TableTags::Range169, STEP3_RANGE), + ] + .iter() + { + offset = self.load_range(&mut table, offset, tag, k)?; } + self.load_special_chunks(&mut table, offset)?; Ok(()) }, ) } - pub(crate) fn lookup_range(value: AssignedCell) -> Result<(), Error> { - Ok(()) + + pub(crate) fn lookup_range( + &self, + layouter: &mut impl Layouter, + values: &[AssignedCell], + tag: TableTags, + ) -> Result<(), Error> { + layouter.assign_region( + || format!("lookup for {}", tag), + |mut region| { + let tag = F::from(tag as u64); + for (offset, v) in values.iter().enumerate() { + region.assign_advice_from_constant(|| "tag", self.tag.0, offset, tag)?; + v.copy_advice(|| "value", &mut region, self.col1.0, offset)?; + region.assign_advice_from_constant( + || "dummy", + self.col2.0, + offset, + F::zero(), + )?; + } + Ok(()) + }, + ) + } + pub(crate) fn lookup_special_chunks( + &self, + layouter: &mut impl Layouter, + values: &[(AssignedCell, AssignedCell)], + ) -> Result<(), Error> { + layouter.assign_region( + || "lookup for special chunks", + |mut region| { + let tag = F::from(TableTags::SpecialChunk as u64); + for (offset, (last_chunk, output_coef)) in values.iter().enumerate() { + region.assign_advice_from_constant(|| "tag", self.tag.0, offset, tag)?; + last_chunk.copy_advice(|| "last chunk", &mut region, self.col1.0, offset)?; + output_coef.copy_advice(|| "output coef", &mut region, self.col2.0, offset)?; + } + Ok(()) + }, + ) } } From 88185d1913e61c702ac1257673c8bb8e115126bf Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Tue, 14 Jun 2022 23:11:30 +0200 Subject: [PATCH 3/8] replace lookups with stackable --- keccak256/src/permutation/circuit.rs | 23 +++++-- keccak256/src/permutation/rho.rs | 58 ++++++++--------- keccak256/src/permutation/rho_checks.rs | 80 +----------------------- keccak256/src/permutation/tables.rs | 83 ++++++++----------------- 4 files changed, 69 insertions(+), 175 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index c1c649f139..2f90490210 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -3,15 +3,21 @@ use crate::{ common::{NEXT_INPUTS_LANES, PERMUTATION, ROUND_CONSTANTS}, keccak_arith::*, permutation::{ - base_conversion::BaseConversionConfig, generic::GenericConfig, iota::IotaConstants, - mixing::MixingConfig, pi::pi_gate_permutation, rho::RhoConfig, - tables::FromBase9TableConfig, theta::ThetaConfig, xi::XiConfig, + base_conversion::BaseConversionConfig, + generic::GenericConfig, + iota::IotaConstants, + mixing::MixingConfig, + pi::pi_gate_permutation, + rho::RhoConfig, + tables::{FromBase9TableConfig, StackableTable}, + theta::ThetaConfig, + xi::XiConfig, }, }; use eth_types::Field; use halo2_proofs::{ circuit::{AssignedCell, Layouter, Region}, - plonk::{Advice, Column, ConstraintSystem, Error, Selector}, + plonk::{Advice, Column, ConstraintSystem, Error, Selector, TableColumn}, poly::Rotation, }; use itertools::Itertools; @@ -45,11 +51,18 @@ impl KeccakFConfig { let fixed = meta.fixed_column(); let generic = GenericConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); + let table_cols: [TableColumn; 3] = (0..3) + .map(|_| meta.lookup_table_column()) + .collect_vec() + .try_into() + .unwrap(); + let stackable = + StackableTable::configure(meta, state[0..3].try_into().unwrap(), table_cols); // theta let theta_config = ThetaConfig::configure(meta.selector(), meta, state); // rho - let rho_config = RhoConfig::configure(meta, state, fixed, &generic); + let rho_config = RhoConfig::configure(meta, state, fixed, &generic, stackable); // xi let xi_config = XiConfig::configure(meta.selector(), meta, state); diff --git a/keccak256/src/permutation/rho.rs b/keccak256/src/permutation/rho.rs index 93718c8510..eb22a8f2ff 100644 --- a/keccak256/src/permutation/rho.rs +++ b/keccak256/src/permutation/rho.rs @@ -1,8 +1,7 @@ use crate::permutation::{ generic::GenericConfig, - rho_checks::{LaneRotateConversionConfig, OverflowCheckConfig}, - rho_helpers::{STEP2_RANGE, STEP3_RANGE}, - tables::{Base13toBase9TableConfig, RangeCheckConfig, SpecialChunkTableConfig}, + rho_checks::LaneRotateConversionConfig, + tables::{Base13toBase9TableConfig, StackableTable}, }; use eth_types::Field; @@ -15,11 +14,9 @@ use std::convert::TryInto; #[derive(Debug, Clone)] pub struct RhoConfig { lane_config: LaneRotateConversionConfig, - overflow_check_config: OverflowCheckConfig, base13_to_9_table: Base13toBase9TableConfig, - special_chunk_table: SpecialChunkTableConfig, - step2_range_table: RangeCheckConfig, - step3_range_table: RangeCheckConfig, + stackable: StackableTable, + sum: SumConfig, } impl RhoConfig { @@ -28,36 +25,24 @@ impl RhoConfig { state: [Column; 25], fixed: Column, generic: &GenericConfig, + stackable: StackableTable, ) -> Self { state.iter().for_each(|col| meta.enable_equality(*col)); let base13_to_9_table = Base13toBase9TableConfig::configure(meta); - let special_chunk_table = SpecialChunkTableConfig::configure(meta); - let step2_range_table = RangeCheckConfig::::configure(meta); - let step3_range_table = RangeCheckConfig::::configure(meta); let lane_config = LaneRotateConversionConfig::configure( meta, &base13_to_9_table, - &special_chunk_table, state[0..3].try_into().unwrap(), fixed, generic.clone(), ); - - let overflow_check_config = OverflowCheckConfig::configure( - meta, - &step2_range_table, - &step3_range_table, - state[3], - generic.clone(), - ); + let sum = SumConfig::configure(meta, [state[0], state[1]]); Self { lane_config, - overflow_check_config, base13_to_9_table, - special_chunk_table, - step2_range_table, - step3_range_table, + stackable, + sum, } } pub fn assign_rotation_checks( @@ -93,19 +78,15 @@ impl RhoConfig { .iter() .flat_map(|(_, _, step3_od)| step3_od.clone()) .collect::>(); - self.overflow_check_config.assign_region( - &mut layouter.namespace(|| "Final overflow check"), - step2_od_join, - step3_od_join, - )?; + let step2_sum = self.sum.assign_region(layouter, step2_od_join)?; + let step3_sum = self.sum.assign_region(layouter, step3_od_join)?; + self.stackable.lookup_range_12(layouter, &[step2_sum])?; + self.stackable.lookup_range_169(layouter, &[step3_sum])?; Ok(next_state) } pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { self.base13_to_9_table.load(layouter)?; - self.special_chunk_table.load(layouter)?; - self.step2_range_table.load(layouter)?; - self.step3_range_table.load(layouter)?; Ok(()) } } @@ -121,7 +102,7 @@ mod tests { circuit::{Layouter, SimpleFloorPlanner}, dev::MockProver, pairing::bn256::Fr as Fp, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Selector}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Selector, TableColumn}, poly::Rotation, }; use itertools::Itertools; @@ -139,6 +120,7 @@ mod tests { struct MyConfig { q_enable: Selector, rho_config: RhoConfig, + stackable: StackableTable, state: [Column; 25], } impl Circuit for MyCircuit { @@ -157,10 +139,18 @@ mod tests { .unwrap(); let fixed = meta.fixed_column(); + let table_cols: [TableColumn; 3] = (0..3) + .map(|_| meta.lookup_table_column()) + .collect_vec() + .try_into() + .unwrap(); + let stackable = + StackableTable::configure(meta, state[0..3].try_into().unwrap(), table_cols); let generic = GenericConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); - let rho_config = RhoConfig::configure(meta, state, fixed, &generic); + let rho_config = + RhoConfig::configure(meta, state, fixed, &generic, stackable.clone()); let q_enable = meta.selector(); meta.create_gate("Check states", |meta| { @@ -178,6 +168,7 @@ mod tests { MyConfig { q_enable, rho_config, + stackable, state, } } @@ -188,6 +179,7 @@ mod tests { mut layouter: impl Layouter, ) -> Result<(), Error> { config.rho_config.load(&mut layouter)?; + config.stackable.load(&mut layouter)?; let state = layouter.assign_region( || "assign input state", |mut region| { diff --git a/keccak256/src/permutation/rho_checks.rs b/keccak256/src/permutation/rho_checks.rs index e66fcda3d5..38dd5c3140 100644 --- a/keccak256/src/permutation/rho_checks.rs +++ b/keccak256/src/permutation/rho_checks.rs @@ -108,9 +108,7 @@ use crate::arith_helpers::*; use crate::common::ROTATION_CONSTANTS; use crate::gate_helpers::{biguint_to_f, f_to_biguint}; use crate::permutation::{ - generic::GenericConfig, - rho_helpers::*, - tables::{Base13toBase9TableConfig, RangeCheckConfig, SpecialChunkTableConfig}, + generic::GenericConfig, rho_helpers::*, tables::Base13toBase9TableConfig, }; use eth_types::Field; use halo2_proofs::{ @@ -133,7 +131,6 @@ impl LaneRotateConversionConfig { pub fn configure( meta: &mut ConstraintSystem, base13_to_9_table: &Base13toBase9TableConfig, - special_chunk_table: &SpecialChunkTableConfig, advices: [Column; 3], constant: Column, generic: GenericConfig, @@ -157,20 +154,6 @@ impl LaneRotateConversionConfig { (q_normal * od, base13_to_9_table.overflow_detector), ] }); - - meta.lookup("special chunk", |meta| { - let q_special = meta.query_selector(q_special); - let input_coef = meta.query_advice(input_coef, Rotation::cur()); - let output_coef = meta.query_advice(output_coef, Rotation::cur()); - - vec![ - ( - q_special.clone() * input_coef, - special_chunk_table.last_chunk, - ), - (q_special * output_coef, special_chunk_table.output_coef), - ] - }); Self { q_normal, q_special, @@ -297,64 +280,3 @@ impl LaneRotateConversionConfig { Ok((output_lane, step2_od, step3_od)) } } - -#[derive(Debug, Clone)] -pub struct OverflowCheckConfig { - q_step2: Selector, - q_step3: Selector, - generic: GenericConfig, - acc: Column, -} -impl OverflowCheckConfig { - pub fn configure( - meta: &mut ConstraintSystem, - step2_range_table: &RangeCheckConfig, - step3_range_table: &RangeCheckConfig, - acc: Column, - generic: GenericConfig, - ) -> Self { - let q_step2 = meta.complex_selector(); - let q_step3 = meta.complex_selector(); - meta.enable_equality(acc); - - meta.lookup("Overflow check step2", |meta| { - let q_step2 = meta.query_selector(q_step2); - let acc = meta.query_advice(acc, Rotation::cur()); - vec![(q_step2 * acc, step2_range_table.range)] - }); - meta.lookup("Overflow check step3", |meta| { - let q_step3 = meta.query_selector(q_step3); - let acc = meta.query_advice(acc, Rotation::cur()); - vec![(q_step3 * acc, step3_range_table.range)] - }); - - Self { - q_step2, - q_step3, - generic, - acc, - } - } - pub fn assign_region( - &self, - layouter: &mut impl Layouter, - step2_cells: Vec>, - step3_cells: Vec>, - ) -> Result<(), Error> { - let step2_sum = self.generic.running_sum(layouter, step2_cells, None)?; - let step3_sum = self.generic.running_sum(layouter, step3_cells, None)?; - layouter.assign_region( - || "Overflow range check", - |mut region| { - let offset = 0; - self.q_step2.enable(&mut region, offset)?; - step2_sum.copy_advice(|| "Step2 sum", &mut region, self.acc, offset)?; - let offset = 1; - self.q_step3.enable(&mut region, offset)?; - step3_sum.copy_advice(|| "Step3 sum", &mut region, self.acc, offset)?; - - Ok(()) - }, - ) - } -} diff --git a/keccak256/src/permutation/tables.rs b/keccak256/src/permutation/tables.rs index daea0ca501..e0798ecd36 100644 --- a/keccak256/src/permutation/tables.rs +++ b/keccak256/src/permutation/tables.rs @@ -5,7 +5,7 @@ use crate::permutation::rho_helpers::{get_overflow_detector, BASE_NUM_OF_CHUNKS} use eth_types::Field; use halo2_proofs::{ circuit::{AssignedCell, Layouter, Table}, - plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, + plonk::{Advice, Column, ConstraintSystem, Error, Selector, TableColumn}, poly::Rotation, }; use itertools::Itertools; @@ -20,7 +20,7 @@ const NUM_OF_BINARY_CHUNKS: usize = 16; const NUM_OF_B9_CHUNKS: usize = 5; #[derive(EnumIter, Display, Clone, Copy)] -pub(crate) enum TableTags { +enum TableTags { Range12 = 0, Range169, SpecialChunk, @@ -28,6 +28,7 @@ pub(crate) enum TableTags { #[derive(Debug, Clone)] pub struct StackableTable { + q_enable: Selector, tag: (Column, TableColumn), col1: (Column, TableColumn), col2: (Column, TableColumn), @@ -57,6 +58,7 @@ impl StackableTable { ] }); Self { + q_enable, tag, col1, col2, @@ -95,6 +97,9 @@ impl StackableTable { } Ok(offset) } + /// The table describes all possible combinations of these two variables: + /// - The last input accumulator: `high_value`*(13**64) + `low_value`, and + /// - The last output coef: `convert_b13_coef(high_value + low_value)` fn load_special_chunks(&self, table: &mut Table, offset: usize) -> Result { let mut offset = offset; for i in 0..B13 { @@ -135,7 +140,7 @@ impl StackableTable { ) } - pub(crate) fn lookup_range( + fn lookup_range( &self, layouter: &mut impl Layouter, values: &[AssignedCell], @@ -146,6 +151,7 @@ impl StackableTable { |mut region| { let tag = F::from(tag as u64); for (offset, v) in values.iter().enumerate() { + self.q_enable.enable(&mut region, offset)?; region.assign_advice_from_constant(|| "tag", self.tag.0, offset, tag)?; v.copy_advice(|| "value", &mut region, self.col1.0, offset)?; region.assign_advice_from_constant( @@ -159,6 +165,21 @@ impl StackableTable { }, ) } + pub(crate) fn lookup_range_12( + &self, + layouter: &mut impl Layouter, + values: &[AssignedCell], + ) -> Result<(), Error> { + self.lookup_range(layouter, values, TableTags::Range12) + } + pub(crate) fn lookup_range_169( + &self, + layouter: &mut impl Layouter, + values: &[AssignedCell], + ) -> Result<(), Error> { + self.lookup_range(layouter, values, TableTags::Range169) + } + pub(crate) fn lookup_special_chunks( &self, layouter: &mut impl Layouter, @@ -169,6 +190,7 @@ impl StackableTable { |mut region| { let tag = F::from(TableTags::SpecialChunk as u64); for (offset, (last_chunk, output_coef)) in values.iter().enumerate() { + self.q_enable.enable(&mut region, offset)?; region.assign_advice_from_constant(|| "tag", self.tag.0, offset, tag)?; last_chunk.copy_advice(|| "last chunk", &mut region, self.col1.0, offset)?; output_coef.copy_advice(|| "output coef", &mut region, self.col2.0, offset)?; @@ -197,7 +219,6 @@ impl RangeCheckConfig { }, ) } - pub(crate) fn configure(meta: &mut ConstraintSystem) -> Self { Self { range: meta.lookup_table_column(), @@ -271,60 +292,6 @@ impl Base13toBase9TableConfig { } } -/// The table describes all possible combinations of these two variables: -/// - The last input accumulator: `high_value`*(13**64) + `low_value`, and -/// - The last output coef: `convert_b13_coef(high_value + low_value)` -#[derive(Debug, Clone)] -pub struct SpecialChunkTableConfig { - pub last_chunk: TableColumn, - pub output_coef: TableColumn, - _marker: PhantomData, -} - -impl SpecialChunkTableConfig { - pub(crate) fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_table( - || "Special Chunks", - |mut table| { - // Iterate over all possible values less than 13 for both low - // and high - let mut offset = 0; - for i in 0..B13 { - for j in 0..(B13 - i) { - let (low, high) = (i, j); - let last_chunk = F::from(low as u64) - + F::from(high as u64) - * F::from(B13 as u64).pow(&[LANE_SIZE as u64, 0, 0, 0]); - let output_coef = F::from(convert_b13_coef(low + high) as u64); - table.assign_cell( - || "last chunk", - self.last_chunk, - offset, - || Ok(last_chunk), - )?; - table.assign_cell( - || "output coef", - self.output_coef, - offset, - || Ok(output_coef), - )?; - offset += 1; - } - } - Ok(()) - }, - ) - } - - pub(crate) fn configure(meta: &mut ConstraintSystem) -> Self { - Self { - last_chunk: meta.lookup_table_column(), - output_coef: meta.lookup_table_column(), - _marker: PhantomData, - } - } -} - #[derive(Clone, Debug)] pub(crate) struct BaseInfo { input_base: u8, From 57109dd8457ee64ee5a4bccda4babdf1e7096786 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 16 Jun 2022 01:41:10 +0200 Subject: [PATCH 4/8] lookup special chunk --- keccak256/src/permutation/circuit.rs | 6 +++- keccak256/src/permutation/rho.rs | 14 ++++----- keccak256/src/permutation/rho_checks.rs | 42 +++++++++++-------------- keccak256/src/permutation/tables.rs | 15 ++++----- 4 files changed, 38 insertions(+), 39 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 2f90490210..8b1a8a62d0 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -25,6 +25,7 @@ use std::convert::TryInto; #[derive(Clone, Debug)] pub struct KeccakFConfig { generic: GenericConfig, + stackable: StackableTable, theta_config: ThetaConfig, rho_config: RhoConfig, xi_config: XiConfig, @@ -62,7 +63,8 @@ impl KeccakFConfig { // theta let theta_config = ThetaConfig::configure(meta.selector(), meta, state); // rho - let rho_config = RhoConfig::configure(meta, state, fixed, &generic, stackable); + let rho_config = + RhoConfig::configure(meta, state, fixed, generic.clone(), stackable.clone()); // xi let xi_config = XiConfig::configure(meta.selector(), meta, state); @@ -103,6 +105,7 @@ impl KeccakFConfig { KeccakFConfig { generic, + stackable, theta_config, rho_config, xi_config, @@ -116,6 +119,7 @@ impl KeccakFConfig { } pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + self.stackable.load(layouter)?; self.rho_config.load(layouter)?; self.from_b9_table.load(layouter) } diff --git a/keccak256/src/permutation/rho.rs b/keccak256/src/permutation/rho.rs index eb22a8f2ff..6c54c5a941 100644 --- a/keccak256/src/permutation/rho.rs +++ b/keccak256/src/permutation/rho.rs @@ -16,7 +16,7 @@ pub struct RhoConfig { lane_config: LaneRotateConversionConfig, base13_to_9_table: Base13toBase9TableConfig, stackable: StackableTable, - sum: SumConfig, + generic: GenericConfig, } impl RhoConfig { @@ -24,7 +24,7 @@ impl RhoConfig { meta: &mut ConstraintSystem, state: [Column; 25], fixed: Column, - generic: &GenericConfig, + generic: GenericConfig, stackable: StackableTable, ) -> Self { state.iter().for_each(|col| meta.enable_equality(*col)); @@ -36,13 +36,13 @@ impl RhoConfig { state[0..3].try_into().unwrap(), fixed, generic.clone(), + stackable.clone(), ); - let sum = SumConfig::configure(meta, [state[0], state[1]]); Self { lane_config, base13_to_9_table, stackable, - sum, + generic, } } pub fn assign_rotation_checks( @@ -78,8 +78,8 @@ impl RhoConfig { .iter() .flat_map(|(_, _, step3_od)| step3_od.clone()) .collect::>(); - let step2_sum = self.sum.assign_region(layouter, step2_od_join)?; - let step3_sum = self.sum.assign_region(layouter, step3_od_join)?; + let step2_sum = self.generic.running_sum(layouter, step2_od_join, None)?; + let step3_sum = self.generic.running_sum(layouter, step3_od_join, None)?; self.stackable.lookup_range_12(layouter, &[step2_sum])?; self.stackable.lookup_range_169(layouter, &[step3_sum])?; Ok(next_state) @@ -150,7 +150,7 @@ mod tests { GenericConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); let rho_config = - RhoConfig::configure(meta, state, fixed, &generic, stackable.clone()); + RhoConfig::configure(meta, state, fixed, generic.clone(), stackable.clone()); let q_enable = meta.selector(); meta.create_gate("Check states", |meta| { diff --git a/keccak256/src/permutation/rho_checks.rs b/keccak256/src/permutation/rho_checks.rs index 38dd5c3140..d7b043a480 100644 --- a/keccak256/src/permutation/rho_checks.rs +++ b/keccak256/src/permutation/rho_checks.rs @@ -108,7 +108,9 @@ use crate::arith_helpers::*; use crate::common::ROTATION_CONSTANTS; use crate::gate_helpers::{biguint_to_f, f_to_biguint}; use crate::permutation::{ - generic::GenericConfig, rho_helpers::*, tables::Base13toBase9TableConfig, + generic::GenericConfig, + rho_helpers::*, + tables::{Base13toBase9TableConfig, StackableTable}, }; use eth_types::Field; use halo2_proofs::{ @@ -120,11 +122,11 @@ use halo2_proofs::{ #[derive(Debug, Clone)] pub struct LaneRotateConversionConfig { q_normal: Selector, - q_special: Selector, input_coef: Column, output_coef: Column, pub overflow_detector: Column, generic: GenericConfig, + stackable: StackableTable, } impl LaneRotateConversionConfig { @@ -134,9 +136,9 @@ impl LaneRotateConversionConfig { advices: [Column; 3], constant: Column, generic: GenericConfig, + stackable: StackableTable, ) -> Self { let q_normal = meta.complex_selector(); - let q_special = meta.complex_selector(); let [input_coef, output_coef, overflow_detector] = advices; meta.enable_equality(overflow_detector); @@ -156,11 +158,11 @@ impl LaneRotateConversionConfig { }); Self { q_normal, - q_special, input_coef, output_coef, overflow_detector, generic, + stackable, } } @@ -235,6 +237,16 @@ impl LaneRotateConversionConfig { _ => unreachable!(), } } + // Special chunk + let final_output_coef = region.assign_advice( + || "Special output coef", + self.output_coef, + slices.len(), + || Ok(F::from(special.output_coef as u64)), + )?; + let final_output_pob = F::from(B9 as u64).pow(&[rotation.into(), 0, 0, 0]); + output_coefs.push(final_output_coef); + output_pobs.push(final_output_pob); Ok(( input_coefs, @@ -253,26 +265,8 @@ impl LaneRotateConversionConfig { .generic .sub_advice(layouter, lane_base_13, input_from_chunks)?; - let (final_output_coef, final_output_pob) = layouter.assign_region( - || "special chunks", - |mut region| { - let offset = 0; - self.q_special.enable(&mut region, offset)?; - diff.copy_advice(|| "input lane diff", &mut region, self.input_coef, offset)?; - let output_coef = region.assign_advice( - || "Special output coef", - self.output_coef, - offset, - || Ok(F::from(special.output_coef as u64)), - )?; - let final_output_pob = F::from(B9 as u64).pow(&[rotation.into(), 0, 0, 0]); - Ok((output_coef, final_output_pob)) - }, - )?; - let mut output_coefs = output_coefs; - output_coefs.push(final_output_coef); - let mut output_pobs = output_pobs; - output_pobs.push(final_output_pob); + self.stackable + .lookup_special_chunks(layouter, &diff, output_coefs.last().unwrap())?; let output_lane = self.generic diff --git a/keccak256/src/permutation/tables.rs b/keccak256/src/permutation/tables.rs index e0798ecd36..f20820bed4 100644 --- a/keccak256/src/permutation/tables.rs +++ b/keccak256/src/permutation/tables.rs @@ -183,18 +183,18 @@ impl StackableTable { pub(crate) fn lookup_special_chunks( &self, layouter: &mut impl Layouter, - values: &[(AssignedCell, AssignedCell)], + last_chunk: &AssignedCell, + output_coef: &AssignedCell, ) -> Result<(), Error> { layouter.assign_region( || "lookup for special chunks", |mut region| { + let offset = 0; let tag = F::from(TableTags::SpecialChunk as u64); - for (offset, (last_chunk, output_coef)) in values.iter().enumerate() { - self.q_enable.enable(&mut region, offset)?; - region.assign_advice_from_constant(|| "tag", self.tag.0, offset, tag)?; - last_chunk.copy_advice(|| "last chunk", &mut region, self.col1.0, offset)?; - output_coef.copy_advice(|| "output coef", &mut region, self.col2.0, offset)?; - } + self.q_enable.enable(&mut region, offset)?; + region.assign_advice_from_constant(|| "tag", self.tag.0, offset, tag)?; + last_chunk.copy_advice(|| "last chunk", &mut region, self.col1.0, offset)?; + output_coef.copy_advice(|| "output coef", &mut region, self.col2.0, offset)?; Ok(()) }, ) @@ -219,6 +219,7 @@ impl RangeCheckConfig { }, ) } + #[allow(dead_code)] pub(crate) fn configure(meta: &mut ConstraintSystem) -> Self { Self { range: meta.lookup_table_column(), From 3dbb2bd7cea4ee5e870aa49d1c783c599095db11 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Mon, 20 Jun 2022 11:46:07 +0200 Subject: [PATCH 5/8] rm pub --- keccak256/src/permutation/rho_checks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keccak256/src/permutation/rho_checks.rs b/keccak256/src/permutation/rho_checks.rs index d7b043a480..e86f245e2b 100644 --- a/keccak256/src/permutation/rho_checks.rs +++ b/keccak256/src/permutation/rho_checks.rs @@ -124,7 +124,7 @@ pub struct LaneRotateConversionConfig { q_normal: Selector, input_coef: Column, output_coef: Column, - pub overflow_detector: Column, + overflow_detector: Column, generic: GenericConfig, stackable: StackableTable, } From 011a179a9b3b7d5ddd42bdbe096df222fb0fb046 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Tue, 21 Jun 2022 00:21:00 +0200 Subject: [PATCH 6/8] add dead code reason --- keccak256/src/permutation/tables.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/keccak256/src/permutation/tables.rs b/keccak256/src/permutation/tables.rs index f20820bed4..ff8d8fcc4a 100644 --- a/keccak256/src/permutation/tables.rs +++ b/keccak256/src/permutation/tables.rs @@ -219,6 +219,8 @@ impl RangeCheckConfig { }, ) } + // dead_code reason: WordBuilderConfig is using it. We defer the decision to + // remove this after WordBuilderConfig is complete #[allow(dead_code)] pub(crate) fn configure(meta: &mut ConstraintSystem) -> Self { Self { From c98293b8e2869e0e7ace58dc776c53fa1e0b2323 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Tue, 21 Jun 2022 00:39:10 +0200 Subject: [PATCH 7/8] clippy fix --- keccak256/src/permutation/rho.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keccak256/src/permutation/rho.rs b/keccak256/src/permutation/rho.rs index 6c54c5a941..33029dd6a4 100644 --- a/keccak256/src/permutation/rho.rs +++ b/keccak256/src/permutation/rho.rs @@ -150,7 +150,7 @@ mod tests { GenericConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); let rho_config = - RhoConfig::configure(meta, state, fixed, generic.clone(), stackable.clone()); + RhoConfig::configure(meta, state, fixed, generic, stackable.clone()); let q_enable = meta.selector(); meta.create_gate("Check states", |meta| { From 480facb280c35fc3e4337c8cc5cc94775bfb2884 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Tue, 21 Jun 2022 01:09:28 +0200 Subject: [PATCH 8/8] fix doc --- keccak256/src/permutation/rho_checks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keccak256/src/permutation/rho_checks.rs b/keccak256/src/permutation/rho_checks.rs index e86f245e2b..1198cea0b9 100644 --- a/keccak256/src/permutation/rho_checks.rs +++ b/keccak256/src/permutation/rho_checks.rs @@ -80,7 +80,7 @@ //! [`crate::permutation::tables::Base13toBase9TableConfig`] to lookup //! `overflow_detector`. We sum up all the overflow_detectors across 25 lanes, //! for each step 1, step 2, and step 3. At the end of the Rho step we perform -//! the final overflow detector range check in [`OverflowCheckConfig`]. +//! the final overflow detector range check for them. //! //! The `OVERFLOW_TRANSFORM` maps step 1 to 0, step 2 to 1, step 3 to 13, and //! step 4 to 170. It is defined that any possible overflow would result the