From df8dc945ee4968f6dd962625c97f2de48b3cf417 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Sat, 28 May 2022 23:07:17 +0200 Subject: [PATCH 01/18] add add config --- keccak256/src/permutation.rs | 1 + keccak256/src/permutation/add.rs | 156 +++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 keccak256/src/permutation/add.rs diff --git a/keccak256/src/permutation.rs b/keccak256/src/permutation.rs index 312658b48f..be874117db 100644 --- a/keccak256/src/permutation.rs +++ b/keccak256/src/permutation.rs @@ -1,6 +1,7 @@ #![allow(clippy::type_complexity)] #![allow(clippy::too_many_arguments)] pub(crate) mod absorb; +pub(crate) mod add; pub(crate) mod base_conversion; pub mod circuit; pub(crate) mod iota; diff --git a/keccak256/src/permutation/add.rs b/keccak256/src/permutation/add.rs new file mode 100644 index 0000000000..871a4e3c9d --- /dev/null +++ b/keccak256/src/permutation/add.rs @@ -0,0 +1,156 @@ +use eth_types::Field; +use halo2_proofs::circuit::AssignedCell; +use halo2_proofs::circuit::Layouter; +use halo2_proofs::{ + plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Selector}, + poly::Rotation, +}; +use std::marker::PhantomData; + +#[derive(Clone, Debug)] +pub struct AddConfig { + q_enable: Selector, + input: Column, + x: Column, + fixed: Column, + _marker: PhantomData, +} + +impl AddConfig { + pub fn configure( + meta: &mut ConstraintSystem, + input: Column, + x: Column, + fixed: Column, + ) -> Self { + let q_enable = meta.selector(); + meta.enable_equality(x); + meta.enable_equality(input); + + meta.create_gate("add", |meta| { + let q_enable = meta.query_selector(q_enable); + let x = meta.query_advice(x, Rotation::cur()); + let input_next = meta.query_advice(input, Rotation::next()); + let input = meta.query_advice(input, Rotation::cur()); + let fixed = meta.query_fixed(fixed, Rotation::cur()); + vec![q_enable * (input_next - input - x * fixed)] + }); + + Self { + q_enable, + input, + x, + fixed, + _marker: PhantomData, + } + } + + pub fn add_advice( + &self, + layouter: &mut impl Layouter, + input: AssignedCell, + x: AssignedCell, + ) -> Result, Error> { + layouter.assign_region( + || "add advice", + |mut region| { + let offset = 0; + self.q_enable.enable(&mut region, offset)?; + input.copy_advice(|| "input", &mut region, self.input, offset)?; + x.copy_advice(|| "x", &mut region, self.x, offset)?; + + // constrain fixed to 1 for a simple add. + region.assign_fixed(|| "1", self.fixed, offset, || Ok(F::one()))?; + + let offset = 1; + region.assign_advice( + || "input + x", + self.input, + offset, + || { + Ok(input.value().cloned().ok_or(Error::Synthesis)? + + x.value().cloned().ok_or(Error::Synthesis)?) + }, + ) + }, + ) + } + pub fn add_fixed( + &self, + layouter: &mut impl Layouter, + input: AssignedCell, + value: F, + ) -> Result, Error> { + layouter.assign_region( + || "add fixed", + |mut region| { + let offset = 0; + self.q_enable.enable(&mut region, offset)?; + input.copy_advice(|| "input", &mut region, self.input, offset)?; + + { + // constrain advice to 1 for a simple add. + let x = region.assign_advice(|| "x", self.x, offset, || Ok(F::one()))?; + region.constrain_constant(x.cell(), F::one())?; + } + region.assign_fixed(|| "fixed value", self.fixed, offset, || Ok(value))?; + + let offset = 1; + region.assign_advice( + || "input + x", + self.input, + offset, + || Ok(input.value().cloned().ok_or(Error::Synthesis)? + value), + ) + }, + ) + } + pub fn linear_combine( + &self, + layouter: &mut impl Layouter, + xs: [AssignedCell; N], + vs: [F; N], + ) -> Result, Error> { + layouter.assign_region( + || "linear combine", + |mut region| { + // | offset | input | x | fixed | + // | ------ | -----------: | -------: | ------: | + // | 0 | 0 | x0 | v0 | + // | 1 | x0v0 | x1 | v1 | + // | 2 | x0v0 + x1v1 | x2 | v2 | + // | ... | ... | ... | ... | + // | N - 1 | | x_(N-1) | v_(N-1) | + // | N | (sum) | | | + let mut acc = + region.assign_advice(|| "input 0", self.input, 0, || Ok(F::zero()))?; + region.constrain_constant(acc.cell(), F::zero())?; + let mut sum = F::zero(); + for offset in 0..N { + self.q_enable.enable(&mut region, offset)?; + let x = xs[offset].copy_advice(|| "x", &mut region, self.x, offset)?; + let v = region.assign_fixed(|| "v", self.fixed, offset, || Ok(vs[offset]))?; + acc = region.assign_advice( + || "accumulation", + self.input, + offset + 1, + || { + sum += x.value().cloned().ok_or(Error::Synthesis)? + * v.value().cloned().ok_or(Error::Synthesis)?; + Ok(sum) + }, + )?; + } + Ok(acc) + }, + ) + } + + pub fn running_sum( + &self, + layouter: &mut impl Layouter, + xs: [AssignedCell; N], + ) -> Result, Error> { + self.linear_combine(layouter, xs, [F::one(); N]) + } +} From eedf6f60e2ff3fad900fbcf917512d5f45ddad6e Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Sat, 28 May 2022 23:43:03 +0200 Subject: [PATCH 02/18] extract add_generic --- keccak256/src/permutation/add.rs | 80 ++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/keccak256/src/permutation/add.rs b/keccak256/src/permutation/add.rs index 871a4e3c9d..a063974912 100644 --- a/keccak256/src/permutation/add.rs +++ b/keccak256/src/permutation/add.rs @@ -45,11 +45,12 @@ impl AddConfig { } } - pub fn add_advice( + fn add_generic( &self, layouter: &mut impl Layouter, input: AssignedCell, - x: AssignedCell, + x: Option>, + value: Option, ) -> Result, Error> { layouter.assign_region( || "add advice", @@ -57,10 +58,28 @@ impl AddConfig { let offset = 0; self.q_enable.enable(&mut region, offset)?; input.copy_advice(|| "input", &mut region, self.input, offset)?; - x.copy_advice(|| "x", &mut region, self.x, offset)?; - - // constrain fixed to 1 for a simple add. - region.assign_fixed(|| "1", self.fixed, offset, || Ok(F::one()))?; + let x = match &x { + Some(x) => { + // copy x to use as a flag + (*x).copy_advice(|| "x", &mut region, self.x, offset)?; + x.clone() + } + None => { + // constrain advice to 1 for a simple add. + let x = region.assign_advice(|| "x", self.x, offset, || Ok(F::one()))?; + region.constrain_constant(x.cell(), F::one())?; + x + } + }; + let value = match value { + Some(value) => { + region.assign_fixed(|| "fixed value", self.fixed, offset, || Ok(value))? + } + None => { + // constrain fixed to 1 for a simple add. + region.assign_fixed(|| "1", self.fixed, offset, || Ok(F::one()))? + } + }; let offset = 1; region.assign_advice( @@ -69,41 +88,42 @@ impl AddConfig { offset, || { Ok(input.value().cloned().ok_or(Error::Synthesis)? - + x.value().cloned().ok_or(Error::Synthesis)?) + + x.value().cloned().ok_or(Error::Synthesis)? + * value.value().cloned().ok_or(Error::Synthesis)?) }, ) }, ) } + /// input += x + pub fn add_advice( + &self, + layouter: &mut impl Layouter, + input: AssignedCell, + x: AssignedCell, + ) -> Result, Error> { + self.add_generic(layouter, input, Some(x), None) + } + /// input += v pub fn add_fixed( &self, layouter: &mut impl Layouter, input: AssignedCell, value: F, ) -> Result, Error> { - layouter.assign_region( - || "add fixed", - |mut region| { - let offset = 0; - self.q_enable.enable(&mut region, offset)?; - input.copy_advice(|| "input", &mut region, self.input, offset)?; - - { - // constrain advice to 1 for a simple add. - let x = region.assign_advice(|| "x", self.x, offset, || Ok(F::one()))?; - region.constrain_constant(x.cell(), F::one())?; - } - region.assign_fixed(|| "fixed value", self.fixed, offset, || Ok(value))?; - - let offset = 1; - region.assign_advice( - || "input + x", - self.input, - offset, - || Ok(input.value().cloned().ok_or(Error::Synthesis)? + value), - ) - }, - ) + self.add_generic(layouter, input, None, Some(value)) + } + /// input += flag * v + /// No boolean check on the flag, we assume the flag is checked before + /// copied to here + pub fn conditional_add( + &self, + layouter: &mut impl Layouter, + input: AssignedCell, + flag: AssignedCell, + value: F, + ) -> Result, Error> { + self.add_generic(layouter, input, Some(flag), Some(value)) } pub fn linear_combine( &self, From 25a1e52f9bd82cf840cf9e1424796e4bfb599fc5 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Sun, 29 May 2022 00:00:08 +0200 Subject: [PATCH 03/18] refactor iota with add --- keccak256/src/permutation/circuit.rs | 16 ++-- keccak256/src/permutation/iota.rs | 128 +++------------------------ keccak256/src/permutation/mixing.rs | 5 +- 3 files changed, 27 insertions(+), 122 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 14fc29d38b..3cec87711c 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -3,9 +3,9 @@ use crate::{ common::{NEXT_INPUTS_LANES, PERMUTATION, ROUND_CONSTANTS}, keccak_arith::*, permutation::{ - base_conversion::BaseConversionConfig, iota::IotaConfig, mixing::MixingConfig, - pi::pi_gate_permutation, rho::RhoConfig, tables::FromBase9TableConfig, theta::ThetaConfig, - xi::XiConfig, + add::AddConfig, base_conversion::BaseConversionConfig, iota::IotaConfig, + mixing::MixingConfig, pi::pi_gate_permutation, rho::RhoConfig, + tables::FromBase9TableConfig, theta::ThetaConfig, xi::XiConfig, }, }; use eth_types::Field; @@ -44,20 +44,24 @@ impl KeccakFConfig { .try_into() .unwrap(); - let flag = meta.advice_column(); let fixed = [ meta.fixed_column(), meta.fixed_column(), meta.fixed_column(), + meta.fixed_column(), ]; + let input = meta.advice_column(); + let x = meta.advice_column(); + + let add_config = AddConfig::configure(meta, input, x, fixed[3]); // theta let theta_config = ThetaConfig::configure(meta.selector(), meta, state); // rho - let rho_config = RhoConfig::configure(meta, state, fixed); + let rho_config = RhoConfig::configure(meta, state, fixed[0..3].try_into().unwrap()); // xi let xi_config = XiConfig::configure(meta.selector(), meta, state); - let iota_config = IotaConfig::configure(meta, state[0], flag, fixed[0]); + let iota_config = IotaConfig::configure(add_config.clone()); // Allocate space for the activation flag of the base_conversion. let base_conv_activator = meta.advice_column(); diff --git a/keccak256/src/permutation/iota.rs b/keccak256/src/permutation/iota.rs index 76e7aa2122..66f6c629df 100644 --- a/keccak256/src/permutation/iota.rs +++ b/keccak256/src/permutation/iota.rs @@ -1,22 +1,17 @@ use crate::arith_helpers::{convert_b2_to_b13, convert_b2_to_b9, A4}; use crate::common::{PERMUTATION, ROUND_CONSTANTS}; use crate::gate_helpers::biguint_to_f; +use crate::permutation::add::AddConfig; use eth_types::Field; use halo2_proofs::circuit::AssignedCell; use halo2_proofs::circuit::Layouter; -use halo2_proofs::{ - plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Selector}, - poly::Rotation, -}; +use halo2_proofs::plonk::Error; use itertools::Itertools; use std::convert::TryInto; #[derive(Clone, Debug)] pub struct IotaConfig { - q_enable: Selector, - lane00: Column, - flag: Column, - round_constant: Column, + add: AddConfig, round_constant_b13: F, a4_times_round_constants_b9: [F; PERMUTATION], } @@ -39,25 +34,7 @@ impl IotaConfig { /// /// Otherwise, apply the round constant in base 13 to the state, which has /// been mixed with new input and converted form base 9 to base 13. - pub fn configure( - meta: &mut ConstraintSystem, - lane00: Column, - flag: Column, - round_constant: Column, - ) -> Self { - let q_enable = meta.selector(); - meta.enable_equality(lane00); - meta.enable_equality(flag); - - meta.create_gate("iota", |meta| { - let q_enable = meta.query_selector(q_enable); - let flag = meta.query_advice(flag, Rotation::cur()); - let lane00_next = meta.query_advice(lane00, Rotation::next()); - let lane00 = meta.query_advice(lane00, Rotation::cur()); - let round_constant = meta.query_fixed(round_constant, Rotation::cur()); - vec![q_enable * (lane00_next - lane00 - flag * round_constant)] - }); - + pub fn configure(add: AddConfig) -> Self { let round_constant_b13 = biguint_to_f::(&convert_b2_to_b13(ROUND_CONSTANTS[PERMUTATION - 1])); @@ -72,10 +49,7 @@ impl IotaConfig { .unwrap(); Self { - q_enable, - lane00, - flag, - round_constant, + add, round_constant_b13, a4_times_round_constants_b9, } @@ -91,33 +65,8 @@ impl IotaConfig { lane00: AssignedCell, round: usize, ) -> Result, Error> { - layouter.assign_region( - || "IotaB9", - |mut region| { - let offset = 0; - self.q_enable.enable(&mut region, offset)?; - lane00.copy_advice(|| "lane 00", &mut region, self.lane00, offset)?; - // In the normal round, we must add round constant. constrain flag to 1. - let flag = region.assign_advice(|| "flag", self.flag, offset, || Ok(F::one()))?; - region.constrain_constant(flag.cell(), F::one())?; - - let constant = self.a4_times_round_constants_b9[round]; - region.assign_fixed( - || "A4 * round_constant_b9", - self.round_constant, - offset, - || Ok(constant), - )?; - - let offset = 1; - region.assign_advice( - || "lane 00 + A4 * round_constant_b9", - self.lane00, - offset, - || Ok(lane00.value().cloned().unwrap_or_default() + constant), - ) - }, - ) + self.add + .add_fixed(layouter, lane00, self.a4_times_round_constants_b9[round]) } /// The 24-th round. Copy the flag `no_mixing` here. @@ -130,34 +79,11 @@ impl IotaConfig { lane00: AssignedCell, flag: AssignedCell, ) -> Result, Error> { - layouter.assign_region( - || "IotaB9", - |mut region| { - let offset = 0; - self.q_enable.enable(&mut region, offset)?; - lane00.copy_advice(|| "lane 00", &mut region, self.lane00, offset)?; - flag.copy_advice(|| "flag", &mut region, self.flag, offset)?; - - let constant = self.a4_times_round_constants_b9[PERMUTATION - 1]; - region.assign_fixed( - || "A4 * round_constant_b9", - self.round_constant, - offset, - || Ok(constant), - )?; - - let offset = 1; - region.assign_advice( - || "lane 00 + A4 * round_constant_b9", - self.lane00, - offset, - || { - let flag = flag.value().cloned().unwrap_or_default(); - let lane00 = lane00.value().cloned().unwrap_or_default(); - Ok(lane00 + flag * constant) - }, - ) - }, + self.add.conditional_add( + layouter, + lane00, + flag, + self.a4_times_round_constants_b9[PERMUTATION - 1], ) } @@ -171,33 +97,7 @@ impl IotaConfig { lane00: AssignedCell, flag: AssignedCell, ) -> Result, Error> { - layouter.assign_region( - || "IotaB9", - |mut region| { - let offset = 0; - self.q_enable.enable(&mut region, offset)?; - lane00.copy_advice(|| "lane 00", &mut region, self.lane00, offset)?; - flag.copy_advice(|| "flag", &mut region, self.flag, offset)?; - - region.assign_fixed( - || "round_constant_b13", - self.round_constant, - offset, - || Ok(self.round_constant_b13), - )?; - - let offset = 1; - region.assign_advice( - || "lane 00 + round_constant_b13", - self.lane00, - offset, - || { - let lane00 = lane00.value().cloned().unwrap_or_default(); - let flag = flag.value().cloned().unwrap_or_default(); - Ok(lane00 + flag * self.round_constant_b13) - }, - ) - }, - ) + self.add + .conditional_add(layouter, lane00, flag, self.round_constant_b13) } } diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index 84be22b959..bafd9d2a5c 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -285,7 +285,7 @@ impl MixingConfig { mod tests { use super::*; use crate::common::{State, ROUND_CONSTANTS}; - use crate::permutation::iota::IotaConfig; + use crate::permutation::{iota::IotaConfig, add::AddConfig}; use halo2_proofs::circuit::Layouter; use halo2_proofs::pairing::bn256::Fr as Fp; use halo2_proofs::plonk::{ConstraintSystem, Error}; @@ -332,7 +332,8 @@ mod tests { .try_into() .unwrap(); let fixed = meta.fixed_column(); - let iota_config = IotaConfig::configure(meta, state[0], state[1], fixed); + let add = AddConfig::configure(meta, state[0], state[1], fixed); + let iota_config = IotaConfig::configure(add.clone()); MyConfig { mixing_conf: MixingConfig::configure(meta, &table, iota_config, state), From e92e3e3fd217dbd8d6addb0797ad2487d84534aa Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Sun, 29 May 2022 22:43:25 +0200 Subject: [PATCH 04/18] refactor rho --- keccak256/src/permutation/add.rs | 28 ++- keccak256/src/permutation/circuit.rs | 6 +- keccak256/src/permutation/rho.rs | 19 +- keccak256/src/permutation/rho_checks.rs | 290 +++++++----------------- 4 files changed, 110 insertions(+), 233 deletions(-) diff --git a/keccak256/src/permutation/add.rs b/keccak256/src/permutation/add.rs index a063974912..8ba4089cda 100644 --- a/keccak256/src/permutation/add.rs +++ b/keccak256/src/permutation/add.rs @@ -5,6 +5,7 @@ use halo2_proofs::{ plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Selector}, poly::Rotation, }; +use itertools::Itertools; use std::marker::PhantomData; #[derive(Clone, Debug)] @@ -104,6 +105,15 @@ impl AddConfig { ) -> Result, Error> { self.add_generic(layouter, input, Some(x), None) } + /// input -= x + pub fn sub_advice( + &self, + layouter: &mut impl Layouter, + input: AssignedCell, + x: AssignedCell, + ) -> Result, Error> { + self.add_generic(layouter, input, Some(x), Some(-F::one())) + } /// input += v pub fn add_fixed( &self, @@ -125,12 +135,13 @@ impl AddConfig { ) -> Result, Error> { self.add_generic(layouter, input, Some(flag), Some(value)) } - pub fn linear_combine( + pub fn linear_combine( &self, layouter: &mut impl Layouter, - xs: [AssignedCell; N], - vs: [F; N], + xs: Vec>, + vs: Vec, ) -> Result, Error> { + debug_assert_eq!(xs.len(), vs.len()); layouter.assign_region( || "linear combine", |mut region| { @@ -146,9 +157,9 @@ impl AddConfig { region.assign_advice(|| "input 0", self.input, 0, || Ok(F::zero()))?; region.constrain_constant(acc.cell(), F::zero())?; let mut sum = F::zero(); - for offset in 0..N { + for (offset, x) in xs.iter().enumerate() { self.q_enable.enable(&mut region, offset)?; - let x = xs[offset].copy_advice(|| "x", &mut region, self.x, offset)?; + x.copy_advice(|| "x", &mut region, self.x, offset)?; let v = region.assign_fixed(|| "v", self.fixed, offset, || Ok(vs[offset]))?; acc = region.assign_advice( || "accumulation", @@ -166,11 +177,12 @@ impl AddConfig { ) } - pub fn running_sum( + pub fn running_sum( &self, layouter: &mut impl Layouter, - xs: [AssignedCell; N], + xs: Vec>, ) -> Result, Error> { - self.linear_combine(layouter, xs, [F::one(); N]) + let len = xs.len(); + self.linear_combine(layouter, xs, (0..len).map(|_| F::one()).collect_vec()) } } diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 3cec87711c..918cb7db03 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -53,15 +53,15 @@ impl KeccakFConfig { let input = meta.advice_column(); let x = meta.advice_column(); - let add_config = AddConfig::configure(meta, input, x, fixed[3]); + let add = AddConfig::configure(meta, input, x, fixed[3]); // theta let theta_config = ThetaConfig::configure(meta.selector(), meta, state); // rho - let rho_config = RhoConfig::configure(meta, state, fixed[0..3].try_into().unwrap()); + let rho_config = RhoConfig::configure(meta, state, fixed[0], add.clone()); // xi let xi_config = XiConfig::configure(meta.selector(), meta, state); - let iota_config = IotaConfig::configure(add_config.clone()); + let iota_config = IotaConfig::configure(add.clone()); // Allocate space for the activation flag of the base_conversion. let base_conv_activator = meta.advice_column(); diff --git a/keccak256/src/permutation/rho.rs b/keccak256/src/permutation/rho.rs index a347099e4c..294f3290ba 100644 --- a/keccak256/src/permutation/rho.rs +++ b/keccak256/src/permutation/rho.rs @@ -1,4 +1,5 @@ use crate::permutation::{ + add::AddConfig, rho_checks::{LaneRotateConversionConfig, OverflowCheckConfig}, rho_helpers::{STEP2_RANGE, STEP3_RANGE}, tables::{Base13toBase9TableConfig, RangeCheckConfig, SpecialChunkTableConfig}, @@ -25,7 +26,8 @@ impl RhoConfig { pub fn configure( meta: &mut ConstraintSystem, state: [Column; 25], - fixed: [Column; 3], + fixed: Column, + add: AddConfig, ) -> Self { state.iter().for_each(|col| meta.enable_equality(*col)); let base13_to_9_table = Base13toBase9TableConfig::configure(meta); @@ -37,15 +39,17 @@ impl RhoConfig { meta, &base13_to_9_table, &special_chunk_table, - state[0..5].try_into().unwrap(), + state[0..3].try_into().unwrap(), fixed, + add.clone(), ); let overflow_check_config = OverflowCheckConfig::configure( meta, &step2_range_table, &step3_range_table, - state[5..7].try_into().unwrap(), + add.clone(), + state[3], ); Self { lane_config, @@ -151,13 +155,10 @@ mod tests { .try_into() .unwrap(); - let fixed = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; + let fixed = meta.fixed_column(); + let add = AddConfig::configure(meta, state[0], state[1], fixed); - let rho_config = RhoConfig::configure(meta, state, fixed); + let rho_config = RhoConfig::configure(meta, state, fixed, add); 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 790ea7b0e1..bea2d0ded4 100644 --- a/keccak256/src/permutation/rho_checks.rs +++ b/keccak256/src/permutation/rho_checks.rs @@ -108,6 +108,7 @@ use crate::arith_helpers::*; use crate::common::ROTATION_CONSTANTS; use crate::gate_helpers::{biguint_to_f, f_to_biguint}; use crate::permutation::{ + add::AddConfig, rho_helpers::*, tables::{Base13toBase9TableConfig, RangeCheckConfig, SpecialChunkTableConfig}, }; @@ -117,20 +118,15 @@ use halo2_proofs::{ plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Selector}, poly::Rotation, }; -use std::marker::PhantomData; #[derive(Debug, Clone)] pub struct LaneRotateConversionConfig { q_normal: Selector, q_special: Selector, input_coef: Column, - input_pob: Column, - input_acc: Column, output_coef: Column, - output_pob: Column, - output_acc: Column, pub overflow_detector: Column, - _marker: PhantomData, + add: AddConfig, } impl LaneRotateConversionConfig { @@ -138,53 +134,17 @@ impl LaneRotateConversionConfig { meta: &mut ConstraintSystem, base13_to_9_table: &Base13toBase9TableConfig, special_chunk_table: &SpecialChunkTableConfig, - advices: [Column; 5], - fixed: [Column; 3], + advices: [Column; 3], + constant: Column, + add: AddConfig, ) -> Self { let q_normal = meta.complex_selector(); let q_special = meta.complex_selector(); - let [input_coef, input_acc, output_coef, output_acc, overflow_detector] = advices; - let [input_pob, output_pob, constant] = fixed; + let [input_coef, output_coef, overflow_detector] = advices; - meta.enable_equality(input_acc); - meta.enable_equality(output_acc); meta.enable_equality(overflow_detector); meta.enable_constant(constant); - // | coef | 13**x | acc | - // |------|-------|-----------| - // | a | b | c | - // | ... | ... | c - a * b | - meta.create_gate("Running down input", |meta| { - let q_normal = meta.query_selector(q_normal); - let coef = meta.query_advice(input_coef, Rotation::cur()); - let pob = meta.query_fixed(input_pob, Rotation::cur()); - let acc = meta.query_advice(input_acc, Rotation::cur()); - let acc_next = meta.query_advice(input_acc, Rotation::next()); - vec![( - "delta_acc === - coef * power_of_base", - q_normal * (acc_next - acc + coef * pob), - )] - }); - // | coef | 9**x | acc | - // |------|-------|--------| - // | a | b | 0 | - // | ... | ... | a * b | - meta.create_gate("Running up for output", |meta| { - let q_normal = meta.query_selector(q_normal); - let q_special = meta.query_selector(q_special); - let coef = meta.query_advice(output_coef, Rotation::cur()); - let pob = meta.query_fixed(output_pob, Rotation::cur()); - let acc = meta.query_advice(output_acc, Rotation::cur()); - let acc_next = meta.query_advice(output_acc, Rotation::next()); - // delta_acc === coef * power_of_base - let poly = acc_next - acc - coef * pob; - vec![ - ("check for q_normal", q_normal * poly.clone()), - ("check for q_special", q_special * poly), - ] - }); - meta.lookup("b13 -> b9 table", |meta| { let q_normal = meta.query_selector(q_normal); let base13_coef = meta.query_advice(input_coef, Rotation::cur()); @@ -200,12 +160,12 @@ impl LaneRotateConversionConfig { meta.lookup("special chunk", |meta| { let q_special = meta.query_selector(q_special); - let input_acc = meta.query_advice(input_acc, Rotation::cur()); + 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_acc, + q_special.clone() * input_coef, special_chunk_table.last_chunk, ), (q_special * output_coef, special_chunk_table.output_coef), @@ -215,13 +175,9 @@ impl LaneRotateConversionConfig { q_normal, q_special, input_coef, - input_pob, - input_acc, output_coef, - output_pob, - output_acc, overflow_detector, - _marker: PhantomData, + add, } } @@ -248,185 +204,95 @@ impl LaneRotateConversionConfig { rotation, ) .get_full_witness(); - layouter.assign_region( - || "lane rotate conversion", - |mut region| { - let slices = slice_lane(rotation); - let (step2_od, step3_od) = { + let slices = slice_lane(rotation); + + let (input_coefs, input_pobs, output_coefs, output_pobs, step2_od, step3_od) = layouter + .assign_region( + || "lane rotate conversion", + |mut region| { + let mut input_coefs: Vec> = vec![]; + let mut output_coefs: Vec> = vec![]; + let mut input_pobs: Vec = vec![]; + let mut output_pobs: Vec = vec![]; let mut step2_od: Vec> = vec![]; let mut step3_od: Vec> = vec![]; for (offset, (&(chunk_idx, step), conv)) in slices.iter().zip(conversions.iter()).enumerate() { self.q_normal.enable(&mut region, offset)?; - region.assign_advice( + let input_coef = region.assign_advice( || format!("Input Coef {}", chunk_idx), self.input_coef, offset, || Ok(biguint_to_f::(&conv.input.coef)), )?; - region.assign_fixed( - || "Input power of base", - self.input_pob, - offset, - || Ok(biguint_to_f::(&conv.input.power_of_base)), - )?; - { - let cell = region - .assign_advice( - || "Input accumulator", - self.input_acc, - offset, - || Ok(biguint_to_f::(&conv.input.pre_acc)), - )? - .cell(); - if offset == 0 { - region.constrain_equal(lane_base_13.cell(), cell)?; - } - } - region.assign_advice( + input_coefs.push(input_coef); + input_pobs.push(biguint_to_f::(&conv.input.power_of_base)); + let output_coef = region.assign_advice( || "Output Coef", self.output_coef, offset, || Ok(biguint_to_f::(&conv.output.coef)), )?; - region.assign_fixed( - || "Output power of base", - self.output_pob, + output_coefs.push(output_coef); + output_pobs.push(biguint_to_f::(&conv.output.power_of_base)); + + let od = region.assign_advice( + || "Overflow detector", + self.overflow_detector, offset, - || Ok(biguint_to_f::(&conv.output.power_of_base)), + || Ok(F::from(conv.overflow_detector.value as u64)), )?; - { - let cell = region - .assign_advice( - || "Output accumulator", - self.output_acc, - offset, - || Ok(biguint_to_f::(&conv.output.pre_acc)), - )? - .cell(); - if offset == 0 { - region.constrain_constant(cell, F::zero())?; - } - } - let od = { - let value = F::from(conv.overflow_detector.value as u64); - let od = region.assign_advice( - || "Overflow detector", - self.overflow_detector, - offset, - || Ok(value), - )?; - if step == 1 { - region.constrain_constant(od.cell(), F::zero())?; - } - od - }; match step { + 1 => region.constrain_constant(od.cell(), F::zero())?, 2 => step2_od.push(od), 3 => step3_od.push(od), - _ => {} + 4 => { // Do nothing + } + _ => unreachable!(), } } - (step2_od, step3_od) - }; - // special chunks - let output_lane = { - let offset = slices.len(); - self.q_special.enable(&mut region, offset)?; - region.assign_advice( - || "Special Input acc", - self.input_acc, - offset, - || Ok(biguint_to_f::(&special.input)), - )?; - region.assign_advice( - || "Special output coef", - self.output_coef, - offset, - || Ok(F::from(special.output_coef as u64)), - )?; - region.assign_fixed( - || "Special output power of base", - self.output_pob, - offset, - || Ok(F::from(B9 as u64).pow(&[rotation.into(), 0, 0, 0])), - )?; - region.assign_advice( - || "Special output acc pre", - self.output_acc, - offset, - || Ok(biguint_to_f::(&special.output_acc_pre)), - )?; - { - let value = biguint_to_f::(&special.output_acc_post); - region.assign_advice( - || "Special output acc post", - self.output_acc, - offset + 1, - || Ok(value), - )? - } - }; - Ok((output_lane, step2_od, step3_od)) - }, - ) - } -} -#[derive(Debug, Clone)] -pub struct SumConfig { - q_enable: Selector, - x: Column, - sum: Column, - _marker: PhantomData, -} -impl SumConfig { - // We assume the input columns are all copiable - pub fn configure(meta: &mut ConstraintSystem, advices: [Column; 2]) -> Self { - let q_enable = meta.selector(); - let [x, sum] = advices; - - meta.enable_equality(x); - meta.enable_equality(sum); + Ok(( + input_coefs, + input_pobs, + output_coefs, + output_pobs, + step2_od, + step3_od, + )) + }, + )?; + let input_from_chunks = self.add.linear_combine(layouter, input_coefs, input_pobs)?; + let diff = self + .add + .sub_advice(layouter, lane_base_13, input_from_chunks)?; - meta.create_gate("sum", |meta| { - let q_enable = meta.query_selector(q_enable); - let x = meta.query_advice(x, Rotation::cur()); - let sum_next = meta.query_advice(sum, Rotation::next()); - let sum = meta.query_advice(sum, Rotation::cur()); - vec![q_enable * (sum_next - sum - x)] - }); - Self { - q_enable, - x, - sum, - _marker: PhantomData, - } - } - pub fn assign_region( - &self, - layouter: &mut impl Layouter, - xs: Vec>, - ) -> Result, Error> { - debug_assert!(xs.len() > 1); - layouter.assign_region( - || "running sum", + let (final_output_coef, final_output_pob) = layouter.assign_region( + || "special chunks", |mut region| { - let mut sum = F::zero(); - let mut offset = 0; - for xs_item in xs.iter() { - self.q_enable.enable(&mut region, offset)?; - xs_item.copy_advice(|| "x", &mut region, self.x, offset)?; - region.assign_advice(|| "sum", self.sum, offset, || Ok(sum))?; - sum += xs_item.value().copied().unwrap_or_default(); - offset += 1; - } - let sum = region.assign_advice(|| "last sum", self.sum, offset, || Ok(sum))?; - - Ok(sum) + 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.clone(); + output_coefs.push(final_output_coef); + let mut output_pobs = output_pobs.clone(); + output_pobs.push(final_output_pob); + + let output_lane = self + .add + .linear_combine(layouter, output_coefs, output_pobs)?; + Ok((output_lane, step2_od, step3_od)) } } @@ -434,7 +300,7 @@ impl SumConfig { pub struct OverflowCheckConfig { q_step2: Selector, q_step3: Selector, - sum_config: SumConfig, + add: AddConfig, acc: Column, } impl OverflowCheckConfig { @@ -442,13 +308,11 @@ impl OverflowCheckConfig { meta: &mut ConstraintSystem, step2_range_table: &RangeCheckConfig, step3_range_table: &RangeCheckConfig, - advices: [Column; 2], + add: AddConfig, + acc: Column, ) -> Self { - let sum_config = SumConfig::configure(meta, advices); - let q_step2 = meta.complex_selector(); let q_step3 = meta.complex_selector(); - let acc = advices[0]; meta.enable_equality(acc); meta.lookup("Overflow check step2", |meta| { @@ -465,7 +329,7 @@ impl OverflowCheckConfig { Self { q_step2, q_step3, - sum_config, + add, acc, } } @@ -475,8 +339,8 @@ impl OverflowCheckConfig { step2_cells: Vec>, step3_cells: Vec>, ) -> Result<(), Error> { - let step2_sum = self.sum_config.assign_region(layouter, step2_cells)?; - let step3_sum = self.sum_config.assign_region(layouter, step3_cells)?; + let step2_sum = self.add.running_sum(layouter, step2_cells)?; + let step3_sum = self.add.running_sum(layouter, step3_cells)?; layouter.assign_region( || "Overflow range check", |mut region| { From 8ec8ac4d4da5090483fed5660e3027cdbc80b396 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Sun, 29 May 2022 23:23:21 +0200 Subject: [PATCH 05/18] refactored theta --- keccak256/src/permutation/circuit.rs | 12 +- keccak256/src/permutation/theta.rs | 170 ++++++++++++--------------- 2 files changed, 79 insertions(+), 103 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 918cb7db03..b26deee3f1 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -56,7 +56,7 @@ impl KeccakFConfig { let add = AddConfig::configure(meta, input, x, fixed[3]); // theta - let theta_config = ThetaConfig::configure(meta.selector(), meta, state); + let theta_config = ThetaConfig::configure(add.clone()); // rho let rho_config = RhoConfig::configure(meta, state, fixed[0], add.clone()); // xi @@ -132,15 +132,7 @@ impl KeccakFConfig { for round_idx in 0..PERMUTATION { // State in base-13 // theta - state = { - // Apply theta outside circuit - let out_state = - KeccakFArith::theta(&state_to_biguint(split_state_cells(state.clone()))); - let out_state = state_bigint_to_field(out_state); - // assignment - self.theta_config - .assign_state(layouter, &state, out_state)? - }; + state = self.theta_config.assign_state(layouter, &state)?; // rho state = self.rho_config.assign_rotation_checks(layouter, &state)?; diff --git a/keccak256/src/permutation/theta.rs b/keccak256/src/permutation/theta.rs index 38e54d4e33..c11cf722d9 100644 --- a/keccak256/src/permutation/theta.rs +++ b/keccak256/src/permutation/theta.rs @@ -1,98 +1,58 @@ use crate::arith_helpers::*; +use crate::permutation::add::AddConfig; use eth_types::Field; use halo2_proofs::{ circuit::{AssignedCell, Layouter}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector}, - poly::Rotation, + plonk::Error, }; use itertools::Itertools; use std::convert::TryInto; -use std::marker::PhantomData; #[derive(Clone, Debug)] pub struct ThetaConfig { - q_enable: Selector, - pub(crate) state: [Column; 25], - _marker: PhantomData, + add: AddConfig, } impl ThetaConfig { - pub fn configure( - q_enable: Selector, - meta: &mut ConstraintSystem, - state: [Column; 25], - ) -> ThetaConfig { - meta.create_gate("theta", |meta| { - let q_enable = meta.query_selector(q_enable); - let column_sum: Vec> = (0..5) - .map(|x| { - let state_x0 = meta.query_advice(state[5 * x], Rotation::cur()); - let state_x1 = meta.query_advice(state[5 * x + 1], Rotation::cur()); - let state_x2 = meta.query_advice(state[5 * x + 2], Rotation::cur()); - let state_x3 = meta.query_advice(state[5 * x + 3], Rotation::cur()); - let state_x4 = meta.query_advice(state[5 * x + 4], Rotation::cur()); - state_x0 + state_x1 + state_x2 + state_x3 + state_x4 - }) - .collect::>(); - - (0..5) - .cartesian_product(0..5) - .map(|(x, y)| { - let new_state = meta.query_advice(state[5 * x + y], Rotation::next()); - let old_state = meta.query_advice(state[5 * x + y], Rotation::cur()); - let right = old_state - + column_sum[(x + 4) % 5].clone() - + Expression::Constant(F::from(B13 as u64)) - * column_sum[(x + 1) % 5].clone(); - q_enable.clone() * (new_state - right) - }) - .collect::>() - }); - - ThetaConfig { - q_enable, - state, - _marker: PhantomData, - } + pub fn configure(add: AddConfig) -> Self { + Self { add } } pub fn assign_state( &self, layouter: &mut impl Layouter, state: &[AssignedCell; 25], - out_state: [F; 25], ) -> Result<[AssignedCell; 25], Error> { - layouter.assign_region( - || "Theta gate", - |mut region| { - let offset = 0; - self.q_enable.enable(&mut region, offset)?; - - for (idx, state) in state.iter().enumerate() { - state.copy_advice( - || format!("assign state {}", idx), - &mut region, - self.state[idx], - offset, - )?; - } - - let mut out_vec: Vec> = vec![]; - let out_state: [AssignedCell; 25] = { - for (idx, lane) in out_state.iter().enumerate() { - let out_cell = region.assign_advice( - || format!("assign out_state {}", idx), - self.state[idx], - offset + 1, - || Ok(*lane), - )?; - out_vec.push(out_cell); - } - out_vec.try_into().unwrap() - }; - Ok(out_state) - }, - ) + let theta_col_sums: Result>, Error> = (0..5) + .map(|x| { + let col_sum = self + .add + .running_sum(layouter, (0..5).map(|y| state[5 * x + y].clone()).collect())?; + Ok(col_sum) + }) + .into_iter() + .collect(); + let theta_col_sums = theta_col_sums?; + let theta_col_sums: [AssignedCell; 5] = theta_col_sums.try_into().unwrap(); + + let out_state: Result>, Error> = (0..5) + .cartesian_product(0..5) + .map(|(x, y)| { + let cells = vec![ + state[5 * x + y].clone(), + theta_col_sums[(x + 4) % 5].clone(), + theta_col_sums[(x + 1) % 5].clone(), + ]; + let vs = vec![F::one(), F::one(), F::from(B13 as u64)]; + let new_lane = self.add.linear_combine(layouter, cells, vs)?; + Ok(new_lane) + }) + .into_iter() + .collect(); + let out_state = out_state?; + let out_state: [AssignedCell; 25] = out_state.try_into().unwrap(); + + Ok(out_state) } } @@ -115,6 +75,31 @@ mod tests { #[test] fn test_theta_gates() { + #[derive(Clone, Debug)] + struct MyConfig { + lane: Column, + theta: ThetaConfig, + } + + impl MyConfig { + pub fn configure(meta: &mut ConstraintSystem) -> Self { + let advices: [Column; 3] = (0..3) + .map(|_| { + let column = meta.advice_column(); + meta.enable_equality(column); + column + }) + .collect::>() + .try_into() + .unwrap(); + let fixed = meta.fixed_column(); + + let lane = advices[0]; + let add = AddConfig::configure(meta, advices[1], advices[2], fixed); + let theta = ThetaConfig::configure(add); + Self { lane, theta } + } + } #[derive(Default)] struct MyCircuit { in_state: [F; 25], @@ -122,7 +107,7 @@ mod tests { _marker: PhantomData, } impl Circuit for MyCircuit { - type Config = ThetaConfig; + type Config = MyConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -130,19 +115,10 @@ mod tests { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let q_enable = meta.complex_selector(); - - let state: [Column; 25] = (0..25) - .map(|_| { - let column = meta.advice_column(); - meta.enable_equality(column); - column - }) - .collect::>() - .try_into() - .unwrap(); - - ThetaConfig::configure(q_enable, meta, state) + // this column is required by `constrain_constant` + let constant = meta.fixed_column(); + meta.enable_constant(constant); + Self::Config::configure(meta) } fn synthesize( @@ -150,17 +126,16 @@ mod tests { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - let offset = 0; let in_state = layouter.assign_region( || "Wittnes & assignation", |mut region| { // Witness `state` let in_state: [AssignedCell; 25] = { let mut state: Vec> = Vec::with_capacity(25); - for (idx, val) in self.in_state.iter().enumerate() { + for (offset, val) in self.in_state.iter().enumerate() { let cell = region.assign_advice( || "witness input state", - config.state[idx], + config.lane, offset, || Ok(*val), )?; @@ -172,8 +147,17 @@ mod tests { }, )?; - config.assign_state(&mut layouter, &in_state, self.out_state)?; + let out_state = config.theta.assign_state(&mut layouter, &in_state)?; + layouter.assign_region( + || "Check outstate", + |mut region| { + for (assigned, value) in out_state.iter().zip(self.out_state.iter()) { + region.constrain_constant(assigned.cell(), value)?; + } + Ok(()) + }, + )?; Ok(()) } } From dd533833434c2a9144dcd80929f1573a1b616c19 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Sun, 29 May 2022 23:39:08 +0200 Subject: [PATCH 06/18] refactor xi --- keccak256/src/permutation/circuit.rs | 11 +- keccak256/src/permutation/xi.rs | 163 +++++++++++---------------- 2 files changed, 69 insertions(+), 105 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index b26deee3f1..b29c3dd17c 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -60,7 +60,7 @@ impl KeccakFConfig { // rho let rho_config = RhoConfig::configure(meta, state, fixed[0], add.clone()); // xi - let xi_config = XiConfig::configure(meta.selector(), meta, state); + let xi_config = XiConfig::configure(add.clone()); let iota_config = IotaConfig::configure(add.clone()); // Allocate space for the activation flag of the base_conversion. @@ -142,14 +142,7 @@ impl KeccakFConfig { state = pi_gate_permutation(state.clone()); // xi - state = { - // Apply xi outside circuit - let out_state = - KeccakFArith::xi(&state_to_biguint(split_state_cells(state.clone()))); - let out_state = state_bigint_to_field(out_state); - // assignment - self.xi_config.assign_state(layouter, &state, out_state)? - }; + state = self.xi_config.assign_state(layouter, &state)?; // Last round before Mixing does not run IotaB9 nor BaseConversion if round_idx == PERMUTATION - 1 { diff --git a/keccak256/src/permutation/xi.rs b/keccak256/src/permutation/xi.rs index 5db50ac991..46a4978149 100644 --- a/keccak256/src/permutation/xi.rs +++ b/keccak256/src/permutation/xi.rs @@ -1,100 +1,46 @@ +use crate::arith_helpers::{A1, A2, A3}; +use crate::permutation::add::AddConfig; use eth_types::Field; use halo2_proofs::{ circuit::{AssignedCell, Layouter}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector}, - poly::Rotation, + plonk::Error, }; use itertools::Itertools; -use std::{convert::TryInto, marker::PhantomData}; +use std::convert::TryInto; #[derive(Clone, Debug)] pub struct XiConfig { - #[allow(dead_code)] - q_enable: Selector, - state: [Column; 25], - _marker: PhantomData, + add: AddConfig, } impl XiConfig { // We assume state is recieved in base-9. - pub fn configure( - q_enable: Selector, - meta: &mut ConstraintSystem, - state: [Column; 25], - ) -> XiConfig { - meta.create_gate("xi", |meta| { - // state in base 9, coefficient in 0~1 - // def xi(state: List[List[int]]): - // new_state = [[0 for x in range(5)] for y in range(5)] - // # Xi step - // for x in range(5): - // for y in range(5): - // # a, b, c, d are base9, coefficient in 0~1 - // a = state[x][y] - // b = state[(x + 1) % 5][y] - // c = state[(x + 2) % 5][y] - // # coefficient in 0~6 - // new_state[x][y] = 2*a + b + 3*c - // return new_state - (0..5) - .cartesian_product(0..5usize) - .map(|(x, y)| { - let a = meta.query_advice(state[5 * x + y], Rotation::cur()); - let b = meta.query_advice(state[5 * ((x + 1) % 5) + y], Rotation::cur()); - let c = meta.query_advice(state[5 * ((x + 2) % 5) + y], Rotation::cur()); - let next_lane = meta.query_advice(state[5 * x + y], Rotation::next()); - meta.query_selector(q_enable) - * ((Expression::Constant(F::from(2)) * a - + b - + Expression::Constant(F::from(3)) * c) - - next_lane) - }) - .collect::>() - }); - - XiConfig { - q_enable, - state, - _marker: PhantomData, - } + pub fn configure(add: AddConfig) -> Self { + Self { add } } pub fn assign_state( &self, layouter: &mut impl Layouter, state: &[AssignedCell; 25], - out_state: [F; 25], ) -> Result<[AssignedCell; 25], Error> { - layouter.assign_region( - || "Xi assignation", - |mut region| { - let offset = 0; - self.q_enable.enable(&mut region, offset)?; - for (idx, state_item) in state.iter().enumerate() { - state_item.copy_advice( - || format!("assign state {}", idx), - &mut region, - self.state[idx], - offset, - )?; - } - - let mut out_vec: Vec> = vec![]; - let out_state: [AssignedCell; 25] = { - for (idx, lane) in out_state.iter().enumerate() { - let out_cell = region.assign_advice( - || format!("assign out_state {}", idx), - self.state[idx], - offset + 1, - || Ok(*lane), - )?; - out_vec.push(out_cell); - } - out_vec.try_into().unwrap() - }; - Ok(out_state) - }, - ) + let out_state: Result>, Error> = (0..5) + .cartesian_product(0..5) + .map(|(x, y)| { + let cells = vec![ + state[5 * x + y].clone(), + state[5 * ((x + 1) % 5) + y].clone(), + state[5 * ((x + 2) % 5) + y].clone(), + ]; + let vs = vec![F::from(A1), F::from(A2), F::from(A3)]; + let new_lane = self.add.linear_combine(layouter, cells, vs)?; + Ok(new_lane) + }) + .into_iter() + .collect(); + let out_state = out_state?; + let out_state: [AssignedCell; 25] = out_state.try_into().unwrap(); + Ok(out_state) } } @@ -115,6 +61,31 @@ mod tests { #[test] fn test_xi_gate() { + #[derive(Clone, Debug)] + struct MyConfig { + lane: Column, + xi: XiConfig, + } + + impl MyConfig { + pub fn configure(meta: &mut ConstraintSystem) -> Self { + let advices: [Column; 3] = (0..3) + .map(|_| { + let column = meta.advice_column(); + meta.enable_equality(column); + column + }) + .collect::>() + .try_into() + .unwrap(); + let fixed = meta.fixed_column(); + + let lane = advices[0]; + let add = AddConfig::configure(meta, advices[1], advices[2], fixed); + let xi = XiConfig::configure(add); + Self { lane, xi } + } + } #[derive(Default)] struct MyCircuit { in_state: [F; 25], @@ -123,7 +94,7 @@ mod tests { } impl Circuit for MyCircuit { - type Config = XiConfig; + type Config = MyConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -131,19 +102,10 @@ mod tests { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let q_enable = meta.complex_selector(); - - let state: [Column; 25] = (0..25) - .map(|_| { - let column = meta.advice_column(); - meta.enable_equality(column); - column - }) - .collect::>() - .try_into() - .unwrap(); - - XiConfig::configure(q_enable, meta, state) + // this column is required by `constrain_constant` + let constant = meta.fixed_column(); + meta.enable_constant(constant); + Self::Config::configure(meta) } fn synthesize( @@ -151,17 +113,16 @@ mod tests { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - let offset = 0; let in_state = layouter.assign_region( || "Wittnes & assignation", |mut region| { // Witness `state` let in_state: [AssignedCell; 25] = { let mut state: Vec> = Vec::with_capacity(25); - for (idx, val) in self.in_state.iter().enumerate() { + for (offset, val) in self.in_state.iter().enumerate() { let cell = region.assign_advice( || "witness input state", - config.state[idx], + config.lane, offset, || Ok(*val), )?; @@ -173,7 +134,17 @@ mod tests { }, )?; - config.assign_state(&mut layouter, &in_state, self.out_state)?; + let out_state = config.xi.assign_state(&mut layouter, &in_state)?; + + layouter.assign_region( + || "Check outstate", + |mut region| { + for (assigned, value) in out_state.iter().zip(self.out_state.iter()) { + region.constrain_constant(assigned.cell(), value)?; + } + Ok(()) + }, + )?; Ok(()) } } From 622e636bf0c2ed239c9d93139f3581323a1ec2b7 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 1 Jun 2022 15:31:02 +0200 Subject: [PATCH 07/18] rm config for theta and xi --- keccak256/src/permutation/circuit.rs | 20 +++---- keccak256/src/permutation/pi.rs | 2 +- keccak256/src/permutation/theta.rs | 87 ++++++++++++---------------- keccak256/src/permutation/xi.rs | 63 ++++++++------------ 4 files changed, 70 insertions(+), 102 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index b29c3dd17c..537a2e1261 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -5,7 +5,7 @@ use crate::{ permutation::{ add::AddConfig, base_conversion::BaseConversionConfig, iota::IotaConfig, mixing::MixingConfig, pi::pi_gate_permutation, rho::RhoConfig, - tables::FromBase9TableConfig, theta::ThetaConfig, xi::XiConfig, + tables::FromBase9TableConfig, theta::assign_theta, xi::assign_xi, }, }; use eth_types::Field; @@ -19,9 +19,8 @@ use std::convert::TryInto; #[derive(Clone, Debug)] pub struct KeccakFConfig { - theta_config: ThetaConfig, + add: AddConfig, rho_config: RhoConfig, - xi_config: XiConfig, iota_config: IotaConfig, from_b9_table: FromBase9TableConfig, base_conversion_config: BaseConversionConfig, @@ -55,12 +54,8 @@ impl KeccakFConfig { let add = AddConfig::configure(meta, input, x, fixed[3]); - // theta - let theta_config = ThetaConfig::configure(add.clone()); // rho let rho_config = RhoConfig::configure(meta, state, fixed[0], add.clone()); - // xi - let xi_config = XiConfig::configure(add.clone()); let iota_config = IotaConfig::configure(add.clone()); // Allocate space for the activation flag of the base_conversion. @@ -99,10 +94,9 @@ impl KeccakFConfig { .collect_vec() }); - KeccakFConfig { - theta_config, + Self { + add, rho_config, - xi_config, iota_config, from_b9_table, base_conversion_config, @@ -132,17 +126,17 @@ impl KeccakFConfig { for round_idx in 0..PERMUTATION { // State in base-13 // theta - state = self.theta_config.assign_state(layouter, &state)?; + state = assign_theta(&self.add, layouter, &state)?; // rho state = self.rho_config.assign_rotation_checks(layouter, &state)?; // Outputs in base-9 which is what Pi requires // Apply Pi permutation - state = pi_gate_permutation(state.clone()); + state = pi_gate_permutation(&state); // xi - state = self.xi_config.assign_state(layouter, &state)?; + state = assign_xi(&self.add, layouter, &state)?; // Last round before Mixing does not run IotaB9 nor BaseConversion if round_idx == PERMUTATION - 1 { diff --git a/keccak256/src/permutation/pi.rs b/keccak256/src/permutation/pi.rs index 9bfc1d71c4..281d5c2207 100644 --- a/keccak256/src/permutation/pi.rs +++ b/keccak256/src/permutation/pi.rs @@ -8,7 +8,7 @@ use std::convert::TryInto; /// It has no gates. We just have to permute the previous state into the correct /// order. The copy constrain in the next gate can then enforce the Pi step /// permutation. -pub fn pi_gate_permutation(state: [AssignedCell; 25]) -> [AssignedCell; 25] { +pub fn pi_gate_permutation(state: &[AssignedCell; 25]) -> [AssignedCell; 25] { let state: [AssignedCell; 25] = (0..5) .cartesian_product(0..5) .map(|(x, y)| state[5 * ((x + 3 * y) % 5) + x].clone()) diff --git a/keccak256/src/permutation/theta.rs b/keccak256/src/permutation/theta.rs index c11cf722d9..de1c10dcbd 100644 --- a/keccak256/src/permutation/theta.rs +++ b/keccak256/src/permutation/theta.rs @@ -8,52 +8,40 @@ use halo2_proofs::{ use itertools::Itertools; use std::convert::TryInto; -#[derive(Clone, Debug)] -pub struct ThetaConfig { - add: AddConfig, -} - -impl ThetaConfig { - pub fn configure(add: AddConfig) -> Self { - Self { add } - } - - pub fn assign_state( - &self, - layouter: &mut impl Layouter, - state: &[AssignedCell; 25], - ) -> Result<[AssignedCell; 25], Error> { - let theta_col_sums: Result>, Error> = (0..5) - .map(|x| { - let col_sum = self - .add - .running_sum(layouter, (0..5).map(|y| state[5 * x + y].clone()).collect())?; - Ok(col_sum) - }) - .into_iter() - .collect(); - let theta_col_sums = theta_col_sums?; - let theta_col_sums: [AssignedCell; 5] = theta_col_sums.try_into().unwrap(); - - let out_state: Result>, Error> = (0..5) - .cartesian_product(0..5) - .map(|(x, y)| { - let cells = vec![ - state[5 * x + y].clone(), - theta_col_sums[(x + 4) % 5].clone(), - theta_col_sums[(x + 1) % 5].clone(), - ]; - let vs = vec![F::one(), F::one(), F::from(B13 as u64)]; - let new_lane = self.add.linear_combine(layouter, cells, vs)?; - Ok(new_lane) - }) - .into_iter() - .collect(); - let out_state = out_state?; - let out_state: [AssignedCell; 25] = out_state.try_into().unwrap(); - - Ok(out_state) - } +pub fn assign_theta( + add: &AddConfig, + layouter: &mut impl Layouter, + state: &[AssignedCell; 25], +) -> Result<[AssignedCell; 25], Error> { + let theta_col_sums: Result>, Error> = (0..5) + .map(|x| { + let col_sum = + add.running_sum(layouter, (0..5).map(|y| state[5 * x + y].clone()).collect())?; + Ok(col_sum) + }) + .into_iter() + .collect(); + let theta_col_sums = theta_col_sums?; + let theta_col_sums: [AssignedCell; 5] = theta_col_sums.try_into().unwrap(); + + let out_state: Result>, Error> = (0..5) + .cartesian_product(0..5) + .map(|(x, y)| { + let cells = vec![ + state[5 * x + y].clone(), + theta_col_sums[(x + 4) % 5].clone(), + theta_col_sums[(x + 1) % 5].clone(), + ]; + let vs = vec![F::one(), F::one(), F::from(B13 as u64)]; + let new_lane = add.linear_combine(layouter, cells, vs)?; + Ok(new_lane) + }) + .into_iter() + .collect(); + let out_state = out_state?; + let out_state: [AssignedCell; 25] = out_state.try_into().unwrap(); + + Ok(out_state) } #[cfg(test)] @@ -78,7 +66,7 @@ mod tests { #[derive(Clone, Debug)] struct MyConfig { lane: Column, - theta: ThetaConfig, + add: AddConfig, } impl MyConfig { @@ -96,8 +84,7 @@ mod tests { let lane = advices[0]; let add = AddConfig::configure(meta, advices[1], advices[2], fixed); - let theta = ThetaConfig::configure(add); - Self { lane, theta } + Self { lane, add } } } #[derive(Default)] @@ -147,7 +134,7 @@ mod tests { }, )?; - let out_state = config.theta.assign_state(&mut layouter, &in_state)?; + let out_state = assign_theta(&config.add, &mut layouter, &in_state)?; layouter.assign_region( || "Check outstate", diff --git a/keccak256/src/permutation/xi.rs b/keccak256/src/permutation/xi.rs index 46a4978149..2f1356a9c7 100644 --- a/keccak256/src/permutation/xi.rs +++ b/keccak256/src/permutation/xi.rs @@ -8,40 +8,28 @@ use halo2_proofs::{ use itertools::Itertools; use std::convert::TryInto; -#[derive(Clone, Debug)] -pub struct XiConfig { - add: AddConfig, -} - -impl XiConfig { - // We assume state is recieved in base-9. - pub fn configure(add: AddConfig) -> Self { - Self { add } - } - - pub fn assign_state( - &self, - layouter: &mut impl Layouter, - state: &[AssignedCell; 25], - ) -> Result<[AssignedCell; 25], Error> { - let out_state: Result>, Error> = (0..5) - .cartesian_product(0..5) - .map(|(x, y)| { - let cells = vec![ - state[5 * x + y].clone(), - state[5 * ((x + 1) % 5) + y].clone(), - state[5 * ((x + 2) % 5) + y].clone(), - ]; - let vs = vec![F::from(A1), F::from(A2), F::from(A3)]; - let new_lane = self.add.linear_combine(layouter, cells, vs)?; - Ok(new_lane) - }) - .into_iter() - .collect(); - let out_state = out_state?; - let out_state: [AssignedCell; 25] = out_state.try_into().unwrap(); - Ok(out_state) - } +pub fn assign_xi( + add: &AddConfig, + layouter: &mut impl Layouter, + state: &[AssignedCell; 25], +) -> Result<[AssignedCell; 25], Error> { + let out_state: Result>, Error> = (0..5) + .cartesian_product(0..5) + .map(|(x, y)| { + let cells = vec![ + state[5 * x + y].clone(), + state[5 * ((x + 1) % 5) + y].clone(), + state[5 * ((x + 2) % 5) + y].clone(), + ]; + let vs = vec![F::from(A1), F::from(A2), F::from(A3)]; + let new_lane = add.linear_combine(layouter, cells, vs)?; + Ok(new_lane) + }) + .into_iter() + .collect(); + let out_state = out_state?; + let out_state: [AssignedCell; 25] = out_state.try_into().unwrap(); + Ok(out_state) } #[cfg(test)] @@ -64,7 +52,7 @@ mod tests { #[derive(Clone, Debug)] struct MyConfig { lane: Column, - xi: XiConfig, + add: AddConfig, } impl MyConfig { @@ -82,8 +70,7 @@ mod tests { let lane = advices[0]; let add = AddConfig::configure(meta, advices[1], advices[2], fixed); - let xi = XiConfig::configure(add); - Self { lane, xi } + Self { lane, add } } } #[derive(Default)] @@ -134,7 +121,7 @@ mod tests { }, )?; - let out_state = config.xi.assign_state(&mut layouter, &in_state)?; + let out_state = assign_xi(&config.add, &mut layouter, &in_state)?; layouter.assign_region( || "Check outstate", From f5c1872fe9fe90924ea6e31144bc57490f42d858 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 1 Jun 2022 16:32:45 +0200 Subject: [PATCH 08/18] fix base conversion --- keccak256/src/permutation/add.rs | 7 +- keccak256/src/permutation/base_conversion.rs | 109 +++++-------------- keccak256/src/permutation/circuit.rs | 15 +-- keccak256/src/permutation/mixing.rs | 29 +++-- keccak256/src/permutation/rho_checks.rs | 8 +- keccak256/src/permutation/tables.rs | 15 +++ keccak256/src/permutation/theta.rs | 9 +- keccak256/src/permutation/xi.rs | 2 +- 8 files changed, 77 insertions(+), 117 deletions(-) diff --git a/keccak256/src/permutation/add.rs b/keccak256/src/permutation/add.rs index 8ba4089cda..425971bf30 100644 --- a/keccak256/src/permutation/add.rs +++ b/keccak256/src/permutation/add.rs @@ -140,6 +140,7 @@ impl AddConfig { layouter: &mut impl Layouter, xs: Vec>, vs: Vec, + outcome: Option>, ) -> Result, Error> { debug_assert_eq!(xs.len(), vs.len()); layouter.assign_region( @@ -172,6 +173,9 @@ impl AddConfig { }, )?; } + if let Some(outcome) = &outcome { + region.constrain_equal(outcome.cell(), acc.cell())?; + } Ok(acc) }, ) @@ -181,8 +185,9 @@ impl AddConfig { &self, layouter: &mut impl Layouter, xs: Vec>, + outcome: Option>, ) -> Result, Error> { let len = xs.len(); - self.linear_combine(layouter, xs, (0..len).map(|_| F::one()).collect_vec()) + self.linear_combine(layouter, xs, (0..len).map(|_| F::one()).collect_vec(), outcome) } } diff --git a/keccak256/src/permutation/base_conversion.rs b/keccak256/src/permutation/base_conversion.rs index 7e177ce23c..7a45c06bd6 100644 --- a/keccak256/src/permutation/base_conversion.rs +++ b/keccak256/src/permutation/base_conversion.rs @@ -4,22 +4,19 @@ use halo2_proofs::{ poly::Rotation, }; +use crate::permutation::add::AddConfig; + use super::tables::BaseInfo; use eth_types::Field; use std::convert::TryInto; #[derive(Clone, Debug)] pub(crate) struct BaseConversionConfig { - q_running_sum: Selector, q_lookup: Selector, base_info: BaseInfo, - // Flag is copied from the parent flag. Parent flag is assumed to be binary - // constrained. - flag: Column, input_coef: Column, - input_acc: Column, output_coef: Column, - output_acc: Column, + add: AddConfig, } impl BaseConversionConfig { @@ -27,63 +24,31 @@ impl BaseConversionConfig { pub(crate) fn configure( meta: &mut ConstraintSystem, base_info: BaseInfo, - input_lane: Column, - parent_flag: Column, - advices: [Column; 5], + advices: [Column; 2], + add: &AddConfig, ) -> Self { - let q_running_sum = meta.selector(); let q_lookup = meta.complex_selector(); - let [flag, input_coef, input_acc, output_coef, output_acc] = advices; + let [input_coef, output_coef] = advices; - meta.enable_equality(flag); meta.enable_equality(input_coef); - meta.enable_equality(input_acc); meta.enable_equality(output_coef); - meta.enable_equality(output_acc); - meta.enable_equality(input_lane); - meta.enable_equality(parent_flag); - - meta.create_gate("input running sum", |meta| { - let q_enable = meta.query_selector(q_running_sum); - let flag = meta.query_advice(flag, Rotation::cur()); - let coef = meta.query_advice(input_coef, Rotation::cur()); - let acc_prev = meta.query_advice(input_acc, Rotation::prev()); - let acc = meta.query_advice(input_acc, Rotation::cur()); - let power_of_base = base_info.input_pob(); - vec![q_enable * flag * (acc - acc_prev * power_of_base - coef)] - }); - meta.create_gate("output running sum", |meta| { - let q_enable = meta.query_selector(q_running_sum); - let flag = meta.query_advice(flag, Rotation::cur()); - let coef = meta.query_advice(output_coef, Rotation::cur()); - let acc_prev = meta.query_advice(output_acc, Rotation::prev()); - let acc = meta.query_advice(output_acc, Rotation::cur()); - let power_of_base = base_info.output_pob(); - vec![q_enable * flag * (acc - acc_prev * power_of_base - coef)] - }); + meta.lookup("Lookup i/o_coeff at Base conversion table", |meta| { let q_enable = meta.query_selector(q_lookup); - let flag = meta.query_advice(flag, Rotation::cur()); let input_slices = meta.query_advice(input_coef, Rotation::cur()); let output_slices = meta.query_advice(output_coef, Rotation::cur()); vec![ - ( - q_enable.clone() * flag.clone() * input_slices, - base_info.input_tc, - ), - (q_enable * flag * output_slices, base_info.output_tc), + (q_enable.clone() * input_slices, base_info.input_tc), + (q_enable * output_slices, base_info.output_tc), ] }); Self { - q_running_sum, q_lookup, base_info, - flag, input_coef, - input_acc, output_coef, - output_acc, + add: add.clone(), } } @@ -91,27 +56,22 @@ impl BaseConversionConfig { &self, layouter: &mut impl Layouter, input: AssignedCell, - flag: AssignedCell, ) -> Result, Error> { let (input_coefs, output_coefs, _) = self .base_info .compute_coefs(input.value().copied().unwrap_or_default())?; + let input_pobs = self.base_info.input_pobs(); + let output_pobs = self.base_info.output_pobs(); - layouter.assign_region( + let (input_coef_cells, output_coef_cells) = layouter.assign_region( || "Base conversion", |mut region| { - let mut input_acc = F::zero(); - let input_pob = self.base_info.input_pob(); - let mut output_acc = F::zero(); - let output_pob = self.base_info.output_pob(); + let mut input_coef_cells = vec![]; + let mut output_coef_cells = vec![]; for (offset, (&input_coef, &output_coef)) in input_coefs.iter().zip(output_coefs.iter()).enumerate() { self.q_lookup.enable(&mut region, offset)?; - if offset != 0 { - self.q_running_sum.enable(&mut region, offset)?; - } - flag.copy_advice(|| "Base conv flag", &mut region, self.flag, offset)?; let input_coef_cell = region.assign_advice( || "Input Coef", @@ -119,51 +79,36 @@ impl BaseConversionConfig { offset, || Ok(input_coef), )?; - input_acc = input_acc * input_pob + input_coef; - let input_acc_cell = region.assign_advice( - || "Input Acc", - self.input_acc, - offset, - || Ok(input_acc), - )?; + input_coef_cells.push(input_coef_cell); let output_coef_cell = region.assign_advice( || "Output Coef", self.output_coef, offset, || Ok(output_coef), )?; - output_acc = output_acc * output_pob + output_coef; - let output_acc_cell = region.assign_advice( - || "Output Acc", - self.output_acc, - offset, - || Ok(output_acc), - )?; - - if offset == 0 { - // bind first acc to first coef - region.constrain_equal(input_acc_cell.cell(), input_coef_cell.cell())?; - region.constrain_equal(output_acc_cell.cell(), output_coef_cell.cell())?; - } else if offset == input_coefs.len() - 1 { - //region.constrain_equal(input_acc_cell, input.0)?; - return Ok(output_acc_cell); - } + output_coef_cells.push(output_coef_cell); } - unreachable!(); + Ok((input_coef_cells, output_coef_cells)) }, - ) + )?; + self.add + .linear_combine(layouter, input_coef_cells, input_pobs, Some(input))?; + let output_lane = + self.add + .linear_combine(layouter, output_coef_cells, output_pobs, None)?; + + Ok(output_lane) } pub(crate) fn assign_state( &self, layouter: &mut impl Layouter, state: &[AssignedCell; 25], - flag: AssignedCell, ) -> Result<[AssignedCell; 25], Error> { let state: Result>, Error> = state .iter() .map(|lane| { - let output = self.assign_lane(layouter, lane.clone(), flag.clone())?; + let output = self.assign_lane(layouter, lane.clone())?; Ok(output) }) .into_iter() diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 537a2e1261..76b3a5195b 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -64,19 +64,13 @@ impl KeccakFConfig { // Base conversion config. let from_b9_table = FromBase9TableConfig::configure(meta); let base_info = from_b9_table.get_base_info(false); - let base_conv_lane = meta.advice_column(); - let base_conversion_config = BaseConversionConfig::configure( - meta, - base_info, - base_conv_lane, - base_conv_activator, - state[0..5].try_into().unwrap(), - ); + let base_conversion_config = + BaseConversionConfig::configure(meta, base_info, state[0..2].try_into().unwrap(), &add); // Mixing will make sure that the flag is binary constrained and that // the out state matches the expected result. let mixing_config = - MixingConfig::configure(meta, &from_b9_table, iota_config.clone(), state); + MixingConfig::configure(meta, &from_b9_table, iota_config.clone(), &add, state); // Allocate the `out state correctness` gate selector let q_out = meta.selector(); @@ -164,8 +158,7 @@ impl KeccakFConfig { }, )?; - self.base_conversion_config - .assign_state(layouter, &state, activation_flag)? + self.base_conversion_config.assign_state(layouter, &state)? } } diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index bafd9d2a5c..a5b1e44d6e 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -1,6 +1,8 @@ use super::super::arith_helpers::*; use super::tables::FromBase9TableConfig; -use super::{absorb::AbsorbConfig, base_conversion::BaseConversionConfig, iota::IotaConfig}; +use super::{ + absorb::AbsorbConfig, add::AddConfig, base_conversion::BaseConversionConfig, iota::IotaConfig, +}; use crate::common::*; use crate::keccak_arith::KeccakFArith; use eth_types::Field; @@ -18,6 +20,7 @@ pub struct MixingConfig { iota_config: IotaConfig, absorb_config: AbsorbConfig, base_conv_config: BaseConversionConfig, + add: AddConfig, state: [Column; 25], flag: Column, q_flag: Selector, @@ -29,8 +32,9 @@ impl MixingConfig { meta: &mut ConstraintSystem, table: &FromBase9TableConfig, iota_config: IotaConfig, + add: &AddConfig, state: [Column; 25], - ) -> MixingConfig { + ) -> Self { // Allocate space for the flag column from which we will copy to all of // the sub-configs. let flag = meta.advice_column(); @@ -71,14 +75,8 @@ impl MixingConfig { let absorb_config = AbsorbConfig::configure(meta, state); let base_info = table.get_base_info(false); - let base_conv_lane = meta.advice_column(); - let base_conv_config = BaseConversionConfig::configure( - meta, - base_info, - base_conv_lane, - flag, - state[0..5].try_into().unwrap(), - ); + let base_conv_config = + BaseConversionConfig::configure(meta, base_info, state[0..2].try_into().unwrap(), &add); let q_out_copy = meta.selector(); @@ -100,10 +98,11 @@ impl MixingConfig { [q_enable * ((left_side + right_side) - out_state)] }); - MixingConfig { + Self { iota_config, absorb_config, base_conv_config, + add: add.clone(), state, flag, q_flag, @@ -230,9 +229,9 @@ impl MixingConfig { )?; // Base conversion assign - let base_conv_cells = - self.base_conv_config - .assign_state(layouter, &out_state_absorb_cells, flag.clone())?; + let base_conv_cells = self + .base_conv_config + .assign_state(layouter, &out_state_absorb_cells)?; // IotaB13 let mix_res = { @@ -285,7 +284,7 @@ impl MixingConfig { mod tests { use super::*; use crate::common::{State, ROUND_CONSTANTS}; - use crate::permutation::{iota::IotaConfig, add::AddConfig}; + use crate::permutation::{add::AddConfig, iota::IotaConfig}; use halo2_proofs::circuit::Layouter; use halo2_proofs::pairing::bn256::Fr as Fp; use halo2_proofs::plonk::{ConstraintSystem, Error}; diff --git a/keccak256/src/permutation/rho_checks.rs b/keccak256/src/permutation/rho_checks.rs index bea2d0ded4..d874de9703 100644 --- a/keccak256/src/permutation/rho_checks.rs +++ b/keccak256/src/permutation/rho_checks.rs @@ -263,7 +263,7 @@ impl LaneRotateConversionConfig { )) }, )?; - let input_from_chunks = self.add.linear_combine(layouter, input_coefs, input_pobs)?; + let input_from_chunks = self.add.linear_combine(layouter, input_coefs, input_pobs, None)?; let diff = self .add .sub_advice(layouter, lane_base_13, input_from_chunks)?; @@ -291,7 +291,7 @@ impl LaneRotateConversionConfig { let output_lane = self .add - .linear_combine(layouter, output_coefs, output_pobs)?; + .linear_combine(layouter, output_coefs, output_pobs, None)?; Ok((output_lane, step2_od, step3_od)) } } @@ -339,8 +339,8 @@ impl OverflowCheckConfig { step2_cells: Vec>, step3_cells: Vec>, ) -> Result<(), Error> { - let step2_sum = self.add.running_sum(layouter, step2_cells)?; - let step3_sum = self.add.running_sum(layouter, step3_cells)?; + let step2_sum = self.add.running_sum(layouter, step2_cells, None)?; + let step3_sum = self.add.running_sum(layouter, step3_cells, None)?; layouter.assign_region( || "Overflow range check", |mut region| { diff --git a/keccak256/src/permutation/tables.rs b/keccak256/src/permutation/tables.rs index 49b825cd9f..91f83f634d 100644 --- a/keccak256/src/permutation/tables.rs +++ b/keccak256/src/permutation/tables.rs @@ -181,6 +181,21 @@ impl BaseInfo { pub fn output_pob(&self) -> F { F::from(self.output_base as u64).pow(&[self.num_chunks as u64, 0, 0, 0]) } + fn num_slices(&self) -> usize { + self.max_chunks / self.num_chunks + } + pub fn input_pobs(&self) -> Vec { + (0..self.num_slices()) + .map(|i| self.input_pob().pow(&[i as u64, 0, 0, 0])) + .rev() + .collect_vec() + } + pub fn output_pobs(&self) -> Vec { + (0..self.num_slices()) + .map(|i| self.input_pob().pow(&[i as u64, 0, 0, 0])) + .rev() + .collect_vec() + } pub fn compute_coefs(&self, input: F) -> Result<(Vec, Vec, F), Error> { // big-endian diff --git a/keccak256/src/permutation/theta.rs b/keccak256/src/permutation/theta.rs index de1c10dcbd..8861d86dfc 100644 --- a/keccak256/src/permutation/theta.rs +++ b/keccak256/src/permutation/theta.rs @@ -15,8 +15,11 @@ pub fn assign_theta( ) -> Result<[AssignedCell; 25], Error> { let theta_col_sums: Result>, Error> = (0..5) .map(|x| { - let col_sum = - add.running_sum(layouter, (0..5).map(|y| state[5 * x + y].clone()).collect())?; + let col_sum = add.running_sum( + layouter, + (0..5).map(|y| state[5 * x + y].clone()).collect(), + None, + )?; Ok(col_sum) }) .into_iter() @@ -33,7 +36,7 @@ pub fn assign_theta( theta_col_sums[(x + 1) % 5].clone(), ]; let vs = vec![F::one(), F::one(), F::from(B13 as u64)]; - let new_lane = add.linear_combine(layouter, cells, vs)?; + let new_lane = add.linear_combine(layouter, cells, vs, None)?; Ok(new_lane) }) .into_iter() diff --git a/keccak256/src/permutation/xi.rs b/keccak256/src/permutation/xi.rs index 2f1356a9c7..db5d5959c2 100644 --- a/keccak256/src/permutation/xi.rs +++ b/keccak256/src/permutation/xi.rs @@ -22,7 +22,7 @@ pub fn assign_xi( state[5 * ((x + 2) % 5) + y].clone(), ]; let vs = vec![F::from(A1), F::from(A2), F::from(A3)]; - let new_lane = add.linear_combine(layouter, cells, vs)?; + let new_lane = add.linear_combine(layouter, cells, vs, None)?; Ok(new_lane) }) .into_iter() From b08a641415bb42d1f6fe316a360c41a79d44f6c7 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 1 Jun 2022 16:44:04 +0200 Subject: [PATCH 09/18] fix mixing flag --- keccak256/src/permutation/circuit.rs | 2 +- keccak256/src/permutation/mixing.rs | 53 +++++++++++++++------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 76b3a5195b..050a39dd16 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -111,7 +111,7 @@ impl KeccakFConfig { layouter: &mut impl Layouter, in_state: [AssignedCell; 25], out_state: [F; 25], - flag: bool, + flag: Option, next_mixing: Option<[F; NEXT_INPUTS_LANES]>, ) -> Result<[AssignedCell; 25], Error> { let mut state = in_state; diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index a5b1e44d6e..06f6dbd40d 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -114,29 +114,35 @@ impl MixingConfig { pub fn enforce_flag_consistency( &self, layouter: &mut impl Layouter, - flag_bool: bool, + flag: Option, ) -> Result<(AssignedCell, AssignedCell), Error> { layouter.assign_region( || "Flag and Negated flag assignation", |mut region| { self.q_flag.enable(&mut region, 0)?; // Witness `is_mixing` flag - let flag = region.assign_advice( + let positive = region.assign_advice( || "witness is_mixing", self.flag, 0, - || Ok(F::from(flag_bool as u64)), + || { + flag.and_then(|flag| Some(F::from(flag as u64))) + .ok_or(Error::Synthesis) + }, )?; // Witness negated `is_mixing` flag - let negated_flag = region.assign_advice( + let negative = region.assign_advice( || "witness negated is_mixing", self.flag, 1, - || Ok(F::from(!flag_bool as u64)), + || { + flag.and_then(|flag| Some(F::from(!flag as u64))) + .ok_or(Error::Synthesis) + }, )?; - Ok((flag, negated_flag)) + Ok((positive, negative)) }, ) } @@ -145,7 +151,7 @@ impl MixingConfig { pub fn assign_out_mixing_states( &self, layouter: &mut impl Layouter, - flag_bool: bool, + flag: Option, negated_flag: AssignedCell, out_mixing_circ: &[AssignedCell; 25], out_non_mixing_circ: &[AssignedCell; 25], @@ -162,7 +168,10 @@ impl MixingConfig { || "witness is_mixing", self.flag, 0, - || Ok(F::from(flag_bool as u64)), + || { + flag.and_then(|flag| Some(F::from(flag as u64))) + .ok_or(Error::Synthesis) + }, )?; negated_flag.copy_advice(|| "witness is_mixing", &mut region, self.flag, 1)?; @@ -196,21 +205,19 @@ impl MixingConfig { layouter: &mut impl Layouter, in_state: &[AssignedCell; 25], out_state: [F; 25], - flag_bool: bool, + flag: Option, next_mixing: Option<[F; NEXT_INPUTS_LANES]>, ) -> Result<[AssignedCell; 25], Error> { // Enforce flag constraints and witness them. - let (flag, negated_flag) = self.enforce_flag_consistency(layouter, flag_bool)?; + let (f_pos, f_neg) = self.enforce_flag_consistency(layouter, flag)?; // If we don't mix: // IotaB9 let non_mix_res = { let mut state = in_state.clone(); - state[0] = self.iota_config.assign_b9_last_round( - layouter, - state[0].clone(), - negated_flag.clone(), - )?; + state[0] = + self.iota_config + .assign_b9_last_round(layouter, state[0].clone(), f_neg.clone())?; state }; @@ -225,7 +232,7 @@ impl MixingConfig { &state_to_state_bigint::(next_mixing.unwrap_or_default()), )), next_mixing.unwrap_or_default(), - flag.clone(), + f_pos.clone(), )?; // Base conversion assign @@ -239,24 +246,20 @@ impl MixingConfig { base_conv_cells[0] = self.iota_config - .assign_round_b13(layouter, base_conv_cells[0].clone(), flag)?; + .assign_round_b13(layouter, base_conv_cells[0].clone(), f_pos)?; base_conv_cells }; let mixing_res = self.assign_out_mixing_states( layouter, - flag_bool, - negated_flag, + flag, + f_neg.clone(), &mix_res, &non_mix_res, out_state, - ); + )?; - if !flag_bool { - Ok(non_mix_res) - } else { - mixing_res - } + Ok(mixing_res) } /// Copies the `[(Cell,F);25]` to the passed [Column; 25]. From 69fb6c4c7c785406ec0d091cf0f406bfddbb5f26 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 1 Jun 2022 17:38:02 +0200 Subject: [PATCH 10/18] fix base conv testing --- keccak256/src/permutation/base_conversion.rs | 110 +++++++++---------- keccak256/src/permutation/circuit.rs | 2 +- keccak256/src/permutation/mixing.rs | 4 +- keccak256/src/permutation/tables.rs | 4 +- 4 files changed, 56 insertions(+), 64 deletions(-) diff --git a/keccak256/src/permutation/base_conversion.rs b/keccak256/src/permutation/base_conversion.rs index 7a45c06bd6..835e7bb06c 100644 --- a/keccak256/src/permutation/base_conversion.rs +++ b/keccak256/src/permutation/base_conversion.rs @@ -124,7 +124,10 @@ mod tests { use super::*; use crate::arith_helpers::{convert_b2_to_b13, convert_b9_lane_to_b13}; use crate::gate_helpers::biguint_to_f; - use crate::permutation::tables::{FromBase9TableConfig, FromBinaryTableConfig}; + use crate::permutation::{ + add::AddConfig, + tables::{FromBase9TableConfig, FromBinaryTableConfig}, + }; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, dev::MockProver, @@ -141,7 +144,6 @@ mod tests { #[derive(Debug, Clone)] struct MyConfig { lane: Column, - flag: Column, table: FromBinaryTableConfig, conversion: BaseConversionConfig, } @@ -149,18 +151,23 @@ mod tests { pub fn configure(meta: &mut ConstraintSystem) -> Self { let table = FromBinaryTableConfig::configure(meta); let lane = meta.advice_column(); - let flag = meta.advice_column(); - let advices = (0..5) - .map(|_| meta.advice_column()) + meta.enable_equality(lane); + let advices: [Column; 2] = (0..2) + .map(|_| { + let col = meta.advice_column(); + meta.enable_equality(col); + col + }) .collect_vec() .try_into() .unwrap(); let base_info = table.get_base_info(false); - let conversion = - BaseConversionConfig::configure(meta, base_info, lane, flag, advices); + let fixed = meta.fixed_column(); + meta.enable_constant(fixed); + let add = AddConfig::configure(meta, advices[0], advices[1], fixed); + let conversion = BaseConversionConfig::configure(meta, base_info, advices, &add); Self { lane, - flag, table, conversion, } @@ -175,23 +182,11 @@ mod tests { layouter: &mut impl Layouter, input: F, ) -> Result, Error> { - // The main flag is enabled - let flag_value = F::one(); - let (lane, flag) = layouter.assign_region( + let lane = layouter.assign_region( || "Input lane", - |mut region| { - let lane = - region.assign_advice(|| "Input lane", self.lane, 0, || Ok(input))?; - let flag = region.assign_advice( - || "main flag", - self.flag, - 0, - || Ok(flag_value), - )?; - Ok((lane, flag)) - }, + |mut region| region.assign_advice(|| "Input lane", self.lane, 0, || Ok(input)), )?; - let output = self.conversion.assign_lane(layouter, lane, flag)?; + let output = self.conversion.assign_lane(layouter, lane)?; layouter.assign_region( || "Input lane", |mut region| output.copy_advice(|| "Output lane", &mut region, self.lane, 0), @@ -257,7 +252,6 @@ mod tests { #[derive(Debug, Clone)] struct MyConfig { lane: Column, - flag: Column, table: FromBase9TableConfig, conversion: BaseConversionConfig, } @@ -265,18 +259,23 @@ mod tests { pub fn configure(meta: &mut ConstraintSystem) -> Self { let table = FromBase9TableConfig::configure(meta); let lane = meta.advice_column(); - let flag = meta.advice_column(); - let advices = (0..5) - .map(|_| meta.advice_column()) + meta.enable_equality(lane); + let advices: [Column; 2] = (0..2) + .map(|_| { + let col = meta.advice_column(); + meta.enable_equality(col); + col + }) .collect_vec() .try_into() .unwrap(); let base_info = table.get_base_info(false); - let conversion = - BaseConversionConfig::configure(meta, base_info, lane, flag, advices); + let fixed = meta.fixed_column(); + meta.enable_constant(fixed); + let add = AddConfig::configure(meta, advices[0], advices[1], fixed); + let conversion = BaseConversionConfig::configure(meta, base_info, advices, &add); Self { lane, - flag, table, conversion, } @@ -291,24 +290,12 @@ mod tests { layouter: &mut impl Layouter, input: F, ) -> Result, Error> { - // The main flag is enabled - let flag_value = F::one(); - let (lane, flag) = layouter.assign_region( + let lane = layouter.assign_region( || "Input lane", - |mut region| { - let lane = - region.assign_advice(|| "Input lane", self.lane, 0, || Ok(input))?; - let flag = region.assign_advice( - || "main flag", - self.flag, - 0, - || Ok(flag_value), - )?; - Ok((lane, flag)) - }, + |mut region| region.assign_advice(|| "Input lane", self.lane, 0, || Ok(input)), )?; - let output = self.conversion.assign_lane(layouter, lane, flag)?; + let output = self.conversion.assign_lane(layouter, lane)?; layouter.assign_region( || "Input lane", |mut region| output.copy_advice(|| "Output lane", &mut region, self.lane, 0), @@ -364,7 +351,6 @@ mod tests { // We need to load the table #[derive(Debug, Clone)] struct MyConfig { - flag: Column, state: [Column; 25], table: FromBinaryTableConfig, conversion: BaseConversionConfig, @@ -373,21 +359,30 @@ mod tests { pub fn configure(meta: &mut ConstraintSystem) -> Self { let table = FromBinaryTableConfig::configure(meta); let state: [Column; 25] = (0..25) - .map(|_| meta.advice_column()) + .map(|_| { + let col = meta.advice_column(); + meta.enable_equality(col); + col + }) .collect::>() .try_into() .unwrap(); - let flag = meta.advice_column(); - let lane = meta.advice_column(); - let advices = (0..5) - .map(|_| meta.advice_column()) + let advices: [Column; 2] = (0..2) + .map(|_| { + let col = meta.advice_column(); + meta.enable_equality(col); + col + }) .collect_vec() .try_into() .unwrap(); let bi = table.get_base_info(false); - let conversion = BaseConversionConfig::configure(meta, bi, lane, flag, advices); + let fixed = meta.fixed_column(); + meta.enable_equality(fixed); + meta.enable_constant(fixed); + let add = AddConfig::configure(meta, advices[0], advices[1], fixed); + let conversion = BaseConversionConfig::configure(meta, bi, advices, &add); Self { - flag, state, table, conversion, @@ -403,8 +398,7 @@ mod tests { layouter: &mut impl Layouter, input: [F; 25], ) -> Result<[F; 25], Error> { - let flag_value = F::one(); - let (state, flag) = layouter.assign_region( + let state = layouter.assign_region( || "Input state", |mut region| { let state: [AssignedCell; 25] = input @@ -423,12 +417,10 @@ mod tests { .collect::>() .try_into() .unwrap(); - let flag = - region.assign_advice(|| "Flag", self.flag, 0, || Ok(flag_value))?; - Ok((state, flag)) + Ok(state) }, )?; - let output_state = self.conversion.assign_state(layouter, &state, flag)?; + let output_state = self.conversion.assign_state(layouter, &state)?; let output_state: [F; 25] = output_state .iter() .map(|cell| cell.value().copied().unwrap_or_default()) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 050a39dd16..9f62036c7c 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -310,7 +310,7 @@ mod tests { &mut layouter, in_state, self.out_state, - self.is_mixing, + Some(self.is_mixing), self.next_mixing, )?; Ok(()) diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index 06f6dbd40d..be9afceafd 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -338,7 +338,7 @@ mod tests { let iota_config = IotaConfig::configure(add.clone()); MyConfig { - mixing_conf: MixingConfig::configure(meta, &table, iota_config, state), + mixing_conf: MixingConfig::configure(meta, &table, iota_config, &add, state), table, } } @@ -378,7 +378,7 @@ mod tests { &mut layouter, &in_state, self.out_state, - self.is_mixing, + Some(self.is_mixing), self.next_mixing, )?; diff --git a/keccak256/src/permutation/tables.rs b/keccak256/src/permutation/tables.rs index 91f83f634d..17a455a1ce 100644 --- a/keccak256/src/permutation/tables.rs +++ b/keccak256/src/permutation/tables.rs @@ -182,7 +182,7 @@ impl BaseInfo { F::from(self.output_base as u64).pow(&[self.num_chunks as u64, 0, 0, 0]) } fn num_slices(&self) -> usize { - self.max_chunks / self.num_chunks + ((self.max_chunks as f32) / (self.num_chunks as f32)).ceil() as usize } pub fn input_pobs(&self) -> Vec { (0..self.num_slices()) @@ -192,7 +192,7 @@ impl BaseInfo { } pub fn output_pobs(&self) -> Vec { (0..self.num_slices()) - .map(|i| self.input_pob().pow(&[i as u64, 0, 0, 0])) + .map(|i| self.output_pob().pow(&[i as u64, 0, 0, 0])) .rev() .collect_vec() } From 3ddb7dbece66eb5c08cadec828fb192c6ed395a9 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Wed, 1 Jun 2022 17:39:55 +0200 Subject: [PATCH 11/18] fix mixing testing --- keccak256/src/permutation/add.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/keccak256/src/permutation/add.rs b/keccak256/src/permutation/add.rs index 425971bf30..5f4c47aef5 100644 --- a/keccak256/src/permutation/add.rs +++ b/keccak256/src/permutation/add.rs @@ -27,6 +27,7 @@ impl AddConfig { let q_enable = meta.selector(); meta.enable_equality(x); meta.enable_equality(input); + meta.enable_constant(fixed); meta.create_gate("add", |meta| { let q_enable = meta.query_selector(q_enable); @@ -188,6 +189,11 @@ impl AddConfig { outcome: Option>, ) -> Result, Error> { let len = xs.len(); - self.linear_combine(layouter, xs, (0..len).map(|_| F::one()).collect_vec(), outcome) + self.linear_combine( + layouter, + xs, + (0..len).map(|_| F::one()).collect_vec(), + outcome, + ) } } From ba10b63c521d40faf01cd5b21d2f931385e7fb52 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 2 Jun 2022 00:51:53 +0200 Subject: [PATCH 12/18] WIP absorb --- keccak256/src/permutation/absorb.rs | 375 +++------------------------ keccak256/src/permutation/add.rs | 7 +- keccak256/src/permutation/circuit.rs | 2 +- keccak256/src/permutation/mixing.rs | 24 +- 4 files changed, 49 insertions(+), 359 deletions(-) diff --git a/keccak256/src/permutation/absorb.rs b/keccak256/src/permutation/absorb.rs index 2da8fcae6b..c87cf7e8af 100644 --- a/keccak256/src/permutation/absorb.rs +++ b/keccak256/src/permutation/absorb.rs @@ -1,5 +1,7 @@ use crate::arith_helpers::*; use crate::common::*; +use crate::gate_helpers::*; +use crate::permutation::{add::AddConfig, base_conversion::BaseConversionConfig}; use eth_types::Field; use halo2_proofs::circuit::{AssignedCell, Layouter, Region}; use halo2_proofs::{ @@ -9,344 +11,45 @@ use halo2_proofs::{ use itertools::Itertools; use std::{convert::TryInto, marker::PhantomData}; -#[derive(Clone, Debug)] -pub struct AbsorbConfig { - q_mixing: Selector, - state: [Column; 25], - _marker: PhantomData, -} - -impl AbsorbConfig { - // We assume state is recieved in base-9. - // Rows are assigned as: - // 1) STATE (25 columns) (offset -1) - // 2) NEXT_INPUTS (17 columns) + is_mixing flag (1 column) (offset +0) - // (current rotation) - // 3) OUT_STATE (25 columns) (offset +1) - pub fn configure( - meta: &mut ConstraintSystem, - state: [Column; 25], - ) -> AbsorbConfig { - // def absorb(state: List[List[int], next_input: List[List[int]): - // for x in range(5): - // for y in range(5): - // # state[x][y] has 2*a + b + 3*c already, now add 2*d to - // make it 2*a + b + 3*c + 2*d # coefficient in 0~8 - // state[x][y] += 2 * next_input[x][y] - // return state - - // Declare the q_mixing. - let q_mixing = meta.selector(); - state - .iter() - .for_each(|column| meta.enable_equality(*column)); - - meta.create_gate("absorb", |meta| { - // We do a trick which consists on multiplying an internal selector - // which is always active by the actual `is_mixing` flag - // which will then enable or disable the gate. - let q_enable = { - // We query the flag value from the `state` `Advice` column at - // rotation curr and position = `NEXT_INPUTS_LANES + 1` - // and multiply to it the active selector so that we avoid the - // `PoisonedConstraints` and each gate equation - // can be satisfied while enforcing the correct gate logic. - // - // This is boolean-constrained outside of `AbsorbConfig` by `MixingConfig`. - let flag = meta.query_advice(state[NEXT_INPUTS_LANES], Rotation::cur()); - // Note also that we want to enable the gate when `is_mixing` is - // true. (flag = 1). See the flag computation above. - meta.query_selector(q_mixing) * flag - }; - - (0..NEXT_INPUTS_LANES) - .map(|idx| { - let val = meta.query_advice(state[idx], Rotation::prev()) - + (Expression::Constant(F::from(A4)) - * meta.query_advice(state[idx], Rotation::cur())); - - let next_lane = meta.query_advice(state[idx], Rotation::next()); - - q_enable.clone() * (val - next_lane) - }) - .collect::>() - }); - - AbsorbConfig { - q_mixing, - state, - _marker: PhantomData, - } - } - - fn assign_next_inp_and_flag( - &self, - region: &mut Region, - offset: usize, - flag: AssignedCell, - next_input: [F; NEXT_INPUTS_LANES], - ) -> Result, Error> { - // Generate next_input in base-9. - let mut next_mixing = state_to_biguint::(next_input); - for (x, y) in (0..5).cartesian_product(0..5) { - // Assign only first 17 values. - if x >= 3 && y >= 1 { - break; - } - next_mixing[(x, y)] = convert_b2_to_b9(next_mixing[(x, y)].clone().try_into().unwrap()) - } - let next_input = state_bigint_to_field::(next_mixing); - - // Assign next_mixing. - for (idx, lane) in next_input.iter().enumerate() { - region.assign_advice( - || format!("assign next_input {}", idx), - self.state[idx], - offset, - || Ok(*lane), - )?; - } - - // Assign flag at last column(17th). - let flag_assig_cell = flag.copy_advice( - || format!("assign next_input {}", NEXT_INPUTS_LANES), - region, - self.state[NEXT_INPUTS_LANES], - offset, - )?; - - Ok(flag_assig_cell) - } - - /// Doc this $ - pub fn copy_state_flag_next_inputs( - &self, - layouter: &mut impl Layouter, - in_state: &[AssignedCell; 25], - out_state: [F; 25], - // Passed in base-2 and converted internally after witnessing it. - next_input: [F; NEXT_INPUTS_LANES], - flag: AssignedCell, - ) -> Result<([AssignedCell; 25], AssignedCell), Error> { - layouter.assign_region( - || "Absorb state assignations", - |mut region| { - let mut offset = 0; - // State at offset + 0 - for (idx, in_state) in in_state.iter().enumerate() { - in_state.copy_advice( - || format!("assign state {}", idx), - &mut region, - self.state[idx], - offset, - )?; - } - - offset += 1; - // Enable `q_mixing` at `offset + 1` - self.q_mixing.enable(&mut region, offset)?; - - // Assign `next_inputs` and flag. - let flag = - self.assign_next_inp_and_flag(&mut region, offset, flag.clone(), next_input)?; - - offset += 1; - // Assign out_state at offset + 2 - let mut state: Vec> = Vec::with_capacity(25); - for (idx, lane) in out_state.iter().enumerate() { - let assig_cell = region.assign_advice( - || format!("assign state {}", idx), - self.state[idx], - offset, - || Ok(*lane), - )?; - state.push(assig_cell); - } - let out_state: [AssignedCell; 25] = state - .try_into() - .expect("Unexpected into_slice conversion err"); - - Ok((out_state, flag)) - }, - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::common::State; - use crate::keccak_arith::KeccakFArith; - use halo2_proofs::circuit::Layouter; - use halo2_proofs::pairing; - use halo2_proofs::plonk::{Advice, Column, ConstraintSystem, Error}; - use halo2_proofs::{circuit::SimpleFloorPlanner, dev::MockProver, plonk::Circuit}; - use itertools::Itertools; - use pairing::bn256::Fr as Fp; - use pairing::group::ff::PrimeField; - use pretty_assertions::assert_eq; - use std::convert::TryInto; - use std::marker::PhantomData; - - #[test] - fn test_absorb_gate() { - #[derive(Default)] - struct MyCircuit { - in_state: [F; 25], - out_state: [F; 25], - next_input: [F; NEXT_INPUTS_LANES], - is_mixing: bool, - _marker: PhantomData, - } - impl Circuit for MyCircuit - where - F: PrimeField, - { - type Config = AbsorbConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let state: [Column; 25] = (0..25) - .map(|_| { - let column = meta.advice_column(); - meta.enable_equality(column); - column - }) - .collect::>() - .try_into() - .unwrap(); - - AbsorbConfig::configure(meta, state) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let val: F = (self.is_mixing as u64).into(); - let flag: AssignedCell = layouter.assign_region( - || "witness_is_mixing_flag", - |mut region| { - let offset = 1; - region.assign_advice( - || "assign is_mixing", - config.state[NEXT_INPUTS_LANES + 1], - offset, - || Ok(val), - ) +// TODO: should do proper base conv here +pub(crate) fn apply_absorb( + add: &AddConfig, + layouter: &mut impl Layouter, + next_input_col: Column, + state: &[AssignedCell; 25], + next_input: &[Option; NEXT_INPUTS_LANES], +) -> Result<[AssignedCell; 25], Error> { + let next_input_b9 = layouter.assign_region( + || "next input words", + |mut region| { + let mut next_input_b9: Vec> = vec![]; + for (offset, input) in next_input.iter().enumerate() { + let cell = region.assign_advice( + || "next input words", + next_input_col, + offset, + || { + input + .map(|input| { + let input = f_to_biguint(input); + let input = + convert_b2_to_b9(*input.to_u64_digits().first().unwrap()); + biguint_to_f(&input) + }) + .ok_or(Error::Synthesis) }, )?; - - // Witness `in_state`. - let in_state: [AssignedCell; 25] = layouter.assign_region( - || "Witness input state", - |mut region| { - let mut state: Vec> = Vec::with_capacity(25); - for (idx, val) in self.in_state.iter().enumerate() { - let cell = region.assign_advice( - || "witness input state", - config.state[idx], - 0, - || Ok(*val), - )?; - state.push(cell) - } - - Ok(state.try_into().unwrap()) - }, - )?; - - config.copy_state_flag_next_inputs( - &mut layouter, - &in_state, - self.out_state, - self.next_input, - flag, - )?; - - Ok(()) + next_input_b9.push(cell); } - } - - let input1: State = [ - [1, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - ]; - - let input2: State = [ - [2, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - ]; - - // Convert the input to base9 as the gadget already expects it like this - // since it's always the output of IotaB9. - let mut in_state = StateBigInt::from(input1); - for (x, y) in (0..5).cartesian_product(0..5) { - in_state[(x, y)] = convert_b2_to_b9(input1[x][y]) - } - - let in_state = state_bigint_to_field(in_state); - let out_state = - state_bigint_to_field(KeccakFArith::absorb(&StateBigInt::from(input1), &input2)); - - let next_input = state_bigint_to_field(StateBigInt::from(input2)); - - // With flag set to true, the gate should trigger. - { - // With the correct input and output witnesses, the proof should - // pass. - let circuit = MyCircuit:: { - in_state, - out_state, - next_input, - is_mixing: true, - _marker: PhantomData, - }; - - let prover = MockProver::::run(9, &circuit, vec![]).unwrap(); - - assert_eq!(prover.verify(), Ok(())); - - // With wrong input and/or output witnesses, the proof should fail - // to be verified. - let circuit = MyCircuit:: { - in_state, - out_state: in_state, - next_input, - is_mixing: true, - _marker: PhantomData, - }; - - let prover = MockProver::::run(9, &circuit, vec![]).unwrap(); - - assert!(prover.verify().is_err()); - } - - // With flag set to `false`, the gate shouldn't trigger. - // And so we can pass any witness data and the proof should pass. - { - let circuit = MyCircuit:: { - in_state, - out_state: in_state, - next_input, - is_mixing: false, - _marker: PhantomData, - }; - - let prover = MockProver::::run(9, &circuit, vec![]).unwrap(); - - assert_eq!(prover.verify(), Ok(())); - } + Ok(next_input_b9) + }, + )?; + + let mut out_state: Vec> = vec![]; + for (i, input) in next_input_b9.iter().enumerate() { + let out_lane = + add.add_advice_mul_const(layouter, state[i].clone(), input.clone(), F::from(A4))?; + out_state.push(out_lane); } + Ok(out_state.try_into().unwrap()) } diff --git a/keccak256/src/permutation/add.rs b/keccak256/src/permutation/add.rs index 5f4c47aef5..2f6aa0e725 100644 --- a/keccak256/src/permutation/add.rs +++ b/keccak256/src/permutation/add.rs @@ -97,14 +97,15 @@ impl AddConfig { }, ) } - /// input += x - pub fn add_advice( + /// input += v * x + pub fn add_advice_mul_const( &self, layouter: &mut impl Layouter, input: AssignedCell, x: AssignedCell, + v: F, ) -> Result, Error> { - self.add_generic(layouter, input, Some(x), None) + self.add_generic(layouter, input, Some(x), Some(v)) } /// input -= x pub fn sub_advice( diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 9f62036c7c..e33b8bff07 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -112,7 +112,7 @@ impl KeccakFConfig { in_state: [AssignedCell; 25], out_state: [F; 25], flag: Option, - next_mixing: Option<[F; NEXT_INPUTS_LANES]>, + next_mixing: [Option; NEXT_INPUTS_LANES], ) -> Result<[AssignedCell; 25], Error> { let mut state = in_state; diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index be9afceafd..bbed17b79e 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -1,7 +1,7 @@ use super::super::arith_helpers::*; use super::tables::FromBase9TableConfig; use super::{ - absorb::AbsorbConfig, add::AddConfig, base_conversion::BaseConversionConfig, iota::IotaConfig, + absorb::apply_absorb, add::AddConfig, base_conversion::BaseConversionConfig, iota::IotaConfig, }; use crate::common::*; use crate::keccak_arith::KeccakFArith; @@ -18,7 +18,6 @@ use std::convert::TryInto; #[derive(Clone, Debug)] pub struct MixingConfig { iota_config: IotaConfig, - absorb_config: AbsorbConfig, base_conv_config: BaseConversionConfig, add: AddConfig, state: [Column; 25], @@ -71,9 +70,6 @@ impl MixingConfig { ] }); - // We mix -> Flag = true - let absorb_config = AbsorbConfig::configure(meta, state); - let base_info = table.get_base_info(false); let base_conv_config = BaseConversionConfig::configure(meta, base_info, state[0..2].try_into().unwrap(), &add); @@ -100,7 +96,6 @@ impl MixingConfig { Self { iota_config, - absorb_config, base_conv_config, add: add.clone(), state, @@ -169,7 +164,7 @@ impl MixingConfig { self.flag, 0, || { - flag.and_then(|flag| Some(F::from(flag as u64))) + flag.map(|flag| F::from(flag as u64)) .ok_or(Error::Synthesis) }, )?; @@ -206,7 +201,7 @@ impl MixingConfig { in_state: &[AssignedCell; 25], out_state: [F; 25], flag: Option, - next_mixing: Option<[F; NEXT_INPUTS_LANES]>, + next_mixing: [Option; NEXT_INPUTS_LANES], ) -> Result<[AssignedCell; 25], Error> { // Enforce flag constraints and witness them. let (f_pos, f_neg) = self.enforce_flag_consistency(layouter, flag)?; @@ -223,17 +218,8 @@ impl MixingConfig { // If we mix: // Absorb - let (out_state_absorb_cells, _) = self.absorb_config.copy_state_flag_next_inputs( - layouter, - in_state, - // Compute out_absorb state. - state_bigint_to_field(KeccakFArith::absorb( - &state_to_biguint(split_state_cells(in_state.clone())), - &state_to_state_bigint::(next_mixing.unwrap_or_default()), - )), - next_mixing.unwrap_or_default(), - f_pos.clone(), - )?; + let out_state_absorb_cells = + apply_absorb(&self.add, layouter, self.state[0], in_state, &next_mixing)?; // Base conversion assign let base_conv_cells = self From ed9e84fa2817536133a3e4085b95c41bb74b0ef4 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 2 Jun 2022 13:04:54 +0200 Subject: [PATCH 13/18] revamp add config and mix config --- keccak256/src/permutation/absorb.rs | 12 +- keccak256/src/permutation/add.rs | 177 ++++++++++++++----- keccak256/src/permutation/base_conversion.rs | 4 +- keccak256/src/permutation/circuit.rs | 115 ++---------- keccak256/src/permutation/iota.rs | 4 +- keccak256/src/permutation/mixing.rs | 122 +++---------- keccak256/src/permutation/rho_checks.rs | 4 +- keccak256/src/permutation/theta.rs | 2 +- keccak256/src/permutation/xi.rs | 2 +- 9 files changed, 173 insertions(+), 269 deletions(-) diff --git a/keccak256/src/permutation/absorb.rs b/keccak256/src/permutation/absorb.rs index c87cf7e8af..db36576b95 100644 --- a/keccak256/src/permutation/absorb.rs +++ b/keccak256/src/permutation/absorb.rs @@ -1,15 +1,11 @@ use crate::arith_helpers::*; use crate::common::*; use crate::gate_helpers::*; -use crate::permutation::{add::AddConfig, base_conversion::BaseConversionConfig}; +use crate::permutation::add::AddConfig; use eth_types::Field; -use halo2_proofs::circuit::{AssignedCell, Layouter, Region}; -use halo2_proofs::{ - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector}, - poly::Rotation, -}; -use itertools::Itertools; -use std::{convert::TryInto, marker::PhantomData}; +use halo2_proofs::circuit::{AssignedCell, Layouter}; +use halo2_proofs::plonk::{Advice, Column, Error}; +use std::convert::TryInto; // TODO: should do proper base conv here pub(crate) fn apply_absorb( diff --git a/keccak256/src/permutation/add.rs b/keccak256/src/permutation/add.rs index 2f6aa0e725..9699ae580b 100644 --- a/keccak256/src/permutation/add.rs +++ b/keccak256/src/permutation/add.rs @@ -11,38 +11,39 @@ use std::marker::PhantomData; #[derive(Clone, Debug)] pub struct AddConfig { q_enable: Selector, - input: Column, - x: Column, - fixed: Column, + io: Column, + left: Column, + right: Column, _marker: PhantomData, } impl AddConfig { pub fn configure( meta: &mut ConstraintSystem, - input: Column, - x: Column, + advices: [Column; 3], fixed: Column, ) -> Self { let q_enable = meta.selector(); - meta.enable_equality(x); - meta.enable_equality(input); + let [io, left, right] = advices; + meta.enable_equality(io); + meta.enable_equality(left); + meta.enable_equality(right); meta.enable_constant(fixed); meta.create_gate("add", |meta| { let q_enable = meta.query_selector(q_enable); - let x = meta.query_advice(x, Rotation::cur()); - let input_next = meta.query_advice(input, Rotation::next()); - let input = meta.query_advice(input, Rotation::cur()); - let fixed = meta.query_fixed(fixed, Rotation::cur()); - vec![q_enable * (input_next - input - x * fixed)] + let input = meta.query_advice(io, Rotation::cur()); + let output = meta.query_advice(io, Rotation::next()); + let left = meta.query_advice(left, Rotation::cur()); + let right = meta.query_advice(right, Rotation::cur()); + vec![q_enable * (output - input - left * right)] }); Self { q_enable, - input, - x, - fixed, + io, + left, + right, _marker: PhantomData, } } @@ -51,7 +52,8 @@ impl AddConfig { &self, layouter: &mut impl Layouter, input: AssignedCell, - x: Option>, + left: Option>, + right: Option>, value: Option, ) -> Result, Error> { layouter.assign_region( @@ -59,34 +61,51 @@ impl AddConfig { |mut region| { let offset = 0; self.q_enable.enable(&mut region, offset)?; - input.copy_advice(|| "input", &mut region, self.input, offset)?; - let x = match &x { + input.copy_advice(|| "input", &mut region, self.io, offset)?; + let x = match &left { Some(x) => { // copy x to use as a flag - (*x).copy_advice(|| "x", &mut region, self.x, offset)?; - x.clone() + (*x).copy_advice(|| "left adv", &mut region, self.left, offset)? } None => { // constrain advice to 1 for a simple add. - let x = region.assign_advice(|| "x", self.x, offset, || Ok(F::one()))?; - region.constrain_constant(x.cell(), F::one())?; - x + region.assign_advice_from_constant( + || "left const", + self.right, + offset, + F::one(), + )? } }; - let value = match value { - Some(value) => { - region.assign_fixed(|| "fixed value", self.fixed, offset, || Ok(value))? + if let Some(right) = &right { + if value.is_some() { + panic!("right and value can't be both some"); } + right.copy_advice(|| "right adv", &mut region, self.right, offset)?; + } + + let value = match value { + Some(value) => region.assign_advice_from_constant( + || "fixed value", + self.right, + offset, + value, + )?, None => { // constrain fixed to 1 for a simple add. - region.assign_fixed(|| "1", self.fixed, offset, || Ok(F::one()))? + region.assign_advice_from_constant( + || "fixed value", + self.right, + offset, + F::one(), + )? } }; let offset = 1; region.assign_advice( || "input + x", - self.input, + self.io, offset, || { Ok(input.value().cloned().ok_or(Error::Synthesis)? @@ -105,7 +124,7 @@ impl AddConfig { x: AssignedCell, v: F, ) -> Result, Error> { - self.add_generic(layouter, input, Some(x), Some(v)) + self.add_generic(layouter, input, Some(x), None, Some(v)) } /// input -= x pub fn sub_advice( @@ -114,7 +133,7 @@ impl AddConfig { input: AssignedCell, x: AssignedCell, ) -> Result, Error> { - self.add_generic(layouter, input, Some(x), Some(-F::one())) + self.add_generic(layouter, input, Some(x), None, Some(-F::one())) } /// input += v pub fn add_fixed( @@ -123,54 +142,96 @@ impl AddConfig { input: AssignedCell, value: F, ) -> Result, Error> { - self.add_generic(layouter, input, None, Some(value)) + self.add_generic(layouter, input, None, None, Some(value)) } /// input += flag * v /// No boolean check on the flag, we assume the flag is checked before /// copied to here - pub fn conditional_add( + pub fn conditional_add_const( &self, layouter: &mut impl Layouter, input: AssignedCell, flag: AssignedCell, value: F, ) -> Result, Error> { - self.add_generic(layouter, input, Some(flag), Some(value)) + self.add_generic(layouter, input, Some(flag), None, Some(value)) + } + /// input += flag * x + /// No boolean check on the flag, we assume the flag is checked before + /// copied to here + pub fn conditional_add_advice( + &self, + layouter: &mut impl Layouter, + input: AssignedCell, + flag: AssignedCell, + x: AssignedCell, + ) -> Result, Error> { + self.add_generic(layouter, input, Some(flag), Some(x), None) } - pub fn linear_combine( + fn linear_combine_generic( &self, layouter: &mut impl Layouter, xs: Vec>, - vs: Vec, + ys: Option>>, + vs: Option>, outcome: Option>, ) -> Result, Error> { - debug_assert_eq!(xs.len(), vs.len()); + debug_assert_eq!( + ys.is_some(), + vs.is_some(), + "They can't both some or both none" + ); + if let Some(ref vs) = vs { + debug_assert_eq!(xs.len(), vs.len()); + } + if let Some(ref ys) = ys { + debug_assert_eq!(xs.len(), ys.len()); + } layouter.assign_region( || "linear combine", |mut region| { - // | offset | input | x | fixed | + // | offset | input | x | y | // | ------ | -----------: | -------: | ------: | - // | 0 | 0 | x0 | v0 | - // | 1 | x0v0 | x1 | v1 | - // | 2 | x0v0 + x1v1 | x2 | v2 | + // | 0 | 0 | x0 | y0 | + // | 1 | x0y0 | x1 | y1 | + // | 2 | x0y0 + x1y1 | x2 | y2 | // | ... | ... | ... | ... | - // | N - 1 | | x_(N-1) | v_(N-1) | + // | N - 1 | | x_(N-1) | y_(N-1) | // | N | (sum) | | | - let mut acc = - region.assign_advice(|| "input 0", self.input, 0, || Ok(F::zero()))?; + let mut acc = region.assign_advice(|| "input 0", self.io, 0, || Ok(F::zero()))?; region.constrain_constant(acc.cell(), F::zero())?; let mut sum = F::zero(); for (offset, x) in xs.iter().enumerate() { self.q_enable.enable(&mut region, offset)?; - x.copy_advice(|| "x", &mut region, self.x, offset)?; - let v = region.assign_fixed(|| "v", self.fixed, offset, || Ok(vs[offset]))?; + x.copy_advice(|| "x", &mut region, self.left, offset)?; + let right = { + match &vs { + Some(vs) => region.assign_advice_from_constant( + || "v", + self.right, + offset, + vs[offset], + )?, + None => match &ys { + Some(ys) => ys[offset].copy_advice( + || "y", + &mut region, + self.right, + offset, + )?, + None => { + unreachable!() + } + }, + } + }; acc = region.assign_advice( || "accumulation", - self.input, + self.io, offset + 1, || { sum += x.value().cloned().ok_or(Error::Synthesis)? - * v.value().cloned().ok_or(Error::Synthesis)?; + * right.value().cloned().ok_or(Error::Synthesis)?; Ok(sum) }, )?; @@ -183,6 +244,26 @@ impl AddConfig { ) } + pub fn linear_combine_consts( + &self, + layouter: &mut impl Layouter, + xs: Vec>, + vs: Vec, + outcome: Option>, + ) -> Result, Error> { + self.linear_combine_generic(layouter, xs, None, Some(vs), outcome) + } + + pub fn linear_combine_advices( + &self, + layouter: &mut impl Layouter, + xs: Vec>, + ys: Vec>, + outcome: Option>, + ) -> Result, Error> { + self.linear_combine_generic(layouter, xs, Some(ys), None, outcome) + } + pub fn running_sum( &self, layouter: &mut impl Layouter, @@ -190,7 +271,7 @@ impl AddConfig { outcome: Option>, ) -> Result, Error> { let len = xs.len(); - self.linear_combine( + self.linear_combine_consts( layouter, xs, (0..len).map(|_| F::one()).collect_vec(), diff --git a/keccak256/src/permutation/base_conversion.rs b/keccak256/src/permutation/base_conversion.rs index 835e7bb06c..f648b08ddf 100644 --- a/keccak256/src/permutation/base_conversion.rs +++ b/keccak256/src/permutation/base_conversion.rs @@ -92,10 +92,10 @@ impl BaseConversionConfig { }, )?; self.add - .linear_combine(layouter, input_coef_cells, input_pobs, Some(input))?; + .linear_combine_consts(layouter, input_coef_cells, input_pobs, Some(input))?; let output_lane = self.add - .linear_combine(layouter, output_coef_cells, output_pobs, None)?; + .linear_combine_consts(layouter, output_coef_cells, output_pobs, None)?; Ok(output_lane) } diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index e33b8bff07..5fb7fc44f0 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -1,7 +1,5 @@ use crate::{ - arith_helpers::*, - common::{NEXT_INPUTS_LANES, PERMUTATION, ROUND_CONSTANTS}, - keccak_arith::*, + common::{NEXT_INPUTS_LANES, PERMUTATION}, permutation::{ add::AddConfig, base_conversion::BaseConversionConfig, iota::IotaConfig, mixing::MixingConfig, pi::pi_gate_permutation, rho::RhoConfig, @@ -10,8 +8,8 @@ use crate::{ }; use eth_types::Field; use halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region}, - plonk::{Advice, Column, ConstraintSystem, Error, Selector}, + circuit::{AssignedCell, Layouter}, + plonk::{Advice, Column, ConstraintSystem, Error}, poly::Rotation, }; use itertools::Itertools; @@ -26,14 +24,12 @@ pub struct KeccakFConfig { base_conversion_config: BaseConversionConfig, mixing_config: MixingConfig, pub state: [Column; 25], - q_out: Selector, - base_conv_activator: Column, } impl KeccakFConfig { // We assume state is received in base-9. pub fn configure(meta: &mut ConstraintSystem) -> Self { - let state = (0..25) + let state: [Column; 25] = (0..25) .map(|_| { let column = meta.advice_column(); meta.enable_equality(column); @@ -49,10 +45,8 @@ impl KeccakFConfig { meta.fixed_column(), meta.fixed_column(), ]; - let input = meta.advice_column(); - let x = meta.advice_column(); - let add = AddConfig::configure(meta, input, x, fixed[3]); + let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed[0]); // rho let rho_config = RhoConfig::configure(meta, state, fixed[0], add.clone()); @@ -96,8 +90,6 @@ impl KeccakFConfig { base_conversion_config, mixing_config, state, - q_out, - base_conv_activator, } } @@ -110,7 +102,6 @@ impl KeccakFConfig { &self, layouter: &mut impl Layouter, in_state: [AssignedCell; 25], - out_state: [F; 25], flag: Option, next_mixing: [Option; NEXT_INPUTS_LANES], ) -> Result<[AssignedCell; 25], Error> { @@ -145,96 +136,13 @@ impl KeccakFConfig { // The resulting state is in Base-9 now. We now convert it to // base_13 which is what Theta requires again at the // start of the loop. - state = { - let activation_flag = layouter.assign_region( - || "Base conversion enable", - |mut region| { - region.assign_advice( - || "Enable base conversion", - self.base_conv_activator, - 0, - || Ok(F::one()), - ) - }, - )?; - - self.base_conversion_config.assign_state(layouter, &state)? - } - } - - // Mixing step - let mix_res = KeccakFArith::mixing( - &state_to_biguint(split_state_cells(state.clone())), - next_mixing - .map(|state| state_to_state_bigint::(state)) - .as_ref(), - *ROUND_CONSTANTS.last().unwrap(), - ); - - let mix_res = self.mixing_config.assign_state( - layouter, - &state, - state_bigint_to_field(mix_res), - flag, - next_mixing, - )?; - - self.constrain_out_state(layouter, &mix_res, out_state) - } - - pub fn constrain_out_state( - &self, - layouter: &mut impl Layouter, - out_mixing: &[AssignedCell; 25], - out_state: [F; 25], - ) -> Result<[AssignedCell; 25], Error> { - layouter.assign_region( - || "Constraint out_state and out_mixing", - |mut region| { - // Enable selector at offset = 0 - self.q_out.enable(&mut region, 0)?; - - // Allocate out_mixing at offset = 0 in `state` column. - self.copy_state(&mut region, 0, self.state, out_mixing)?; - - // Witness out_state at offset = 1 in `state` column. - let out_state: [AssignedCell; 25] = { - let mut out_vec: Vec> = vec![]; - for (idx, lane) in out_state.iter().enumerate() { - let out_cell = region.assign_advice( - || format!("assign out_state [{}]", idx), - self.state[idx], - 1, - || Ok(*lane), - )?; - out_vec.push(out_cell); - } - out_vec.try_into().unwrap() - }; - - Ok(out_state) - }, - ) - } - - /// Copies the `state` cells to the passed [Column; 25]. - fn copy_state( - &self, - region: &mut Region<'_, F>, - offset: usize, - columns: [Column; 25], - state: &[AssignedCell; 25], - ) -> Result<(), Error> { - for (idx, cell) in state.iter().enumerate() { - cell.copy_advice( - || format!("Copy state {}", idx), - region, - columns[idx], - offset, - )?; + state = self.base_conversion_config.assign_state(layouter, &state)?; } - Ok(()) + let mix_res = self + .mixing_config + .assign_state(layouter, &state, flag, next_mixing)?; + Ok(mix_res) } } @@ -306,10 +214,9 @@ mod tests { }, )?; - config.assign_all( + let out_state = config.assign_all( &mut layouter, in_state, - self.out_state, Some(self.is_mixing), self.next_mixing, )?; diff --git a/keccak256/src/permutation/iota.rs b/keccak256/src/permutation/iota.rs index 66f6c629df..0ce4bb792f 100644 --- a/keccak256/src/permutation/iota.rs +++ b/keccak256/src/permutation/iota.rs @@ -79,7 +79,7 @@ impl IotaConfig { lane00: AssignedCell, flag: AssignedCell, ) -> Result, Error> { - self.add.conditional_add( + self.add.conditional_add_const( layouter, lane00, flag, @@ -98,6 +98,6 @@ impl IotaConfig { flag: AssignedCell, ) -> Result, Error> { self.add - .conditional_add(layouter, lane00, flag, self.round_constant_b13) + .conditional_add_const(layouter, lane00, flag, self.round_constant_b13) } } diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index bbed17b79e..851c0f57d9 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -1,18 +1,17 @@ -use super::super::arith_helpers::*; use super::tables::FromBase9TableConfig; use super::{ absorb::apply_absorb, add::AddConfig, base_conversion::BaseConversionConfig, iota::IotaConfig, }; use crate::common::*; -use crate::keccak_arith::KeccakFArith; use eth_types::Field; -use halo2_proofs::circuit::{AssignedCell, Region}; +use halo2_proofs::circuit::AssignedCell; use halo2_proofs::plonk::{Expression, Selector}; use halo2_proofs::poly::Rotation; use halo2_proofs::{ circuit::Layouter, plonk::{Advice, Column, ConstraintSystem, Error}, }; +use itertools::izip; use std::convert::TryInto; #[derive(Clone, Debug)] @@ -23,7 +22,6 @@ pub struct MixingConfig { state: [Column; 25], flag: Column, q_flag: Selector, - q_out_copy: Selector, } impl MixingConfig { @@ -101,7 +99,6 @@ impl MixingConfig { state, flag, q_flag, - q_out_copy, } } @@ -121,7 +118,7 @@ impl MixingConfig { self.flag, 0, || { - flag.and_then(|flag| Some(F::from(flag as u64))) + flag.map(|flag| F::from(flag as u64)) .ok_or(Error::Synthesis) }, )?; @@ -132,7 +129,7 @@ impl MixingConfig { self.flag, 1, || { - flag.and_then(|flag| Some(F::from(!flag as u64))) + flag.map(|flag| F::from(!flag as u64)) .ok_or(Error::Synthesis) }, )?; @@ -142,64 +139,10 @@ impl MixingConfig { ) } - /// Enforce flag constraints - pub fn assign_out_mixing_states( - &self, - layouter: &mut impl Layouter, - flag: Option, - negated_flag: AssignedCell, - out_mixing_circ: &[AssignedCell; 25], - out_non_mixing_circ: &[AssignedCell; 25], - out_state: [F; 25], - ) -> Result<[AssignedCell; 25], Error> { - layouter.assign_region( - || "Out Mixing states assignation", - |mut region| { - // Enable selector - self.q_out_copy.enable(&mut region, 0)?; - - // Copy constrain flags. - let _flag_cell = region.assign_advice( - || "witness is_mixing", - self.flag, - 0, - || { - flag.map(|flag| F::from(flag as u64)) - .ok_or(Error::Synthesis) - }, - )?; - - negated_flag.copy_advice(|| "witness is_mixing", &mut region, self.flag, 1)?; - - // Copy-constrain both out states. - self.copy_state(&mut region, 0, self.state, out_non_mixing_circ)?; - - self.copy_state(&mut region, 1, self.state, out_mixing_circ)?; - - let out_state: [AssignedCell; 25] = { - let mut out_vec: Vec> = vec![]; - for (idx, lane) in out_state.iter().enumerate() { - let out_cell = region.assign_advice( - || format!("assign out_state [{}]", idx), - self.state[idx], - 2, - || Ok(*lane), - )?; - out_vec.push(out_cell); - } - out_vec.try_into().unwrap() - }; - - Ok(out_state) - }, - ) - } - pub fn assign_state( &self, layouter: &mut impl Layouter, in_state: &[AssignedCell; 25], - out_state: [F; 25], flag: Option, next_mixing: [Option; NEXT_INPUTS_LANES], ) -> Result<[AssignedCell; 25], Error> { @@ -208,7 +151,7 @@ impl MixingConfig { // If we don't mix: // IotaB9 - let non_mix_res = { + let state_non_mix = { let mut state = in_state.clone(); state[0] = self.iota_config @@ -218,54 +161,31 @@ impl MixingConfig { // If we mix: // Absorb - let out_state_absorb_cells = - apply_absorb(&self.add, layouter, self.state[0], in_state, &next_mixing)?; + let state_mix = apply_absorb(&self.add, layouter, self.state[0], in_state, &next_mixing)?; // Base conversion assign - let base_conv_cells = self - .base_conv_config - .assign_state(layouter, &out_state_absorb_cells)?; + let state_mix = self.base_conv_config.assign_state(layouter, &state_mix)?; // IotaB13 - let mix_res = { - let mut base_conv_cells = base_conv_cells; + let state_mix = { + let mut state = state_mix; - base_conv_cells[0] = + state[0] = self.iota_config - .assign_round_b13(layouter, base_conv_cells[0].clone(), f_pos)?; - base_conv_cells + .assign_round_b13(layouter, state[0].clone(), f_pos.clone())?; + state }; - - let mixing_res = self.assign_out_mixing_states( - layouter, - flag, - f_neg.clone(), - &mix_res, - &non_mix_res, - out_state, - )?; - - Ok(mixing_res) - } - - /// Copies the `[(Cell,F);25]` to the passed [Column; 25]. - fn copy_state( - &self, - region: &mut Region<'_, F>, - offset: usize, - columns: [Column; 25], - state: &[AssignedCell; 25], - ) -> Result<(), Error> { - for (idx, state_cell) in state.iter().enumerate() { - state_cell.copy_advice( - || format!("Copy state {}", idx), - region, - columns[idx], - offset, + let mut out_state: Vec> = vec![]; + for (mix, non_mix) in izip!(state_mix, state_non_mix) { + let out_lane = self.add.linear_combine_advices( + layouter, + vec![mix, non_mix], + vec![f_pos.clone(), f_neg.clone()], + None, )?; + out_state.push(out_lane) } - - Ok(()) + Ok(out_state.try_into().unwrap()) } } diff --git a/keccak256/src/permutation/rho_checks.rs b/keccak256/src/permutation/rho_checks.rs index d874de9703..4a44e0cd19 100644 --- a/keccak256/src/permutation/rho_checks.rs +++ b/keccak256/src/permutation/rho_checks.rs @@ -263,7 +263,7 @@ impl LaneRotateConversionConfig { )) }, )?; - let input_from_chunks = self.add.linear_combine(layouter, input_coefs, input_pobs, None)?; + let input_from_chunks = self.add.linear_combine_consts(layouter, input_coefs, input_pobs, None)?; let diff = self .add .sub_advice(layouter, lane_base_13, input_from_chunks)?; @@ -291,7 +291,7 @@ impl LaneRotateConversionConfig { let output_lane = self .add - .linear_combine(layouter, output_coefs, output_pobs, None)?; + .linear_combine_consts(layouter, output_coefs, output_pobs, None)?; Ok((output_lane, step2_od, step3_od)) } } diff --git a/keccak256/src/permutation/theta.rs b/keccak256/src/permutation/theta.rs index 8861d86dfc..faab2c2ddf 100644 --- a/keccak256/src/permutation/theta.rs +++ b/keccak256/src/permutation/theta.rs @@ -36,7 +36,7 @@ pub fn assign_theta( theta_col_sums[(x + 1) % 5].clone(), ]; let vs = vec![F::one(), F::one(), F::from(B13 as u64)]; - let new_lane = add.linear_combine(layouter, cells, vs, None)?; + let new_lane = add.linear_combine_consts(layouter, cells, vs, None)?; Ok(new_lane) }) .into_iter() diff --git a/keccak256/src/permutation/xi.rs b/keccak256/src/permutation/xi.rs index db5d5959c2..aff5830b10 100644 --- a/keccak256/src/permutation/xi.rs +++ b/keccak256/src/permutation/xi.rs @@ -22,7 +22,7 @@ pub fn assign_xi( state[5 * ((x + 2) % 5) + y].clone(), ]; let vs = vec![F::from(A1), F::from(A2), F::from(A3)]; - let new_lane = add.linear_combine(layouter, cells, vs, None)?; + let new_lane = add.linear_combine_consts(layouter, cells, vs, None)?; Ok(new_lane) }) .into_iter() From 58b0a478bbb3acccc89ebc3eaaa19b2887f1ea03 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 2 Jun 2022 22:11:26 +0200 Subject: [PATCH 14/18] fix tests --- keccak256/src/permutation/absorb.rs | 12 +++-- keccak256/src/permutation/add.rs | 54 +++++++++++--------- keccak256/src/permutation/base_conversion.rs | 33 ++++++++---- keccak256/src/permutation/circuit.rs | 21 +++++--- keccak256/src/permutation/mixing.rs | 43 ++++++---------- keccak256/src/permutation/rho.rs | 2 +- keccak256/src/permutation/theta.rs | 2 +- keccak256/src/permutation/xi.rs | 2 +- 8 files changed, 95 insertions(+), 74 deletions(-) diff --git a/keccak256/src/permutation/absorb.rs b/keccak256/src/permutation/absorb.rs index db36576b95..c85b849bb9 100644 --- a/keccak256/src/permutation/absorb.rs +++ b/keccak256/src/permutation/absorb.rs @@ -25,14 +25,15 @@ pub(crate) fn apply_absorb( next_input_col, offset, || { - input + Ok(input .map(|input| { let input = f_to_biguint(input); - let input = - convert_b2_to_b9(*input.to_u64_digits().first().unwrap()); + let input = convert_b2_to_b9( + *input.to_u64_digits().first().unwrap_or(&0u64), + ); biguint_to_f(&input) }) - .ok_or(Error::Synthesis) + .unwrap_or(F::zero())) }, )?; next_input_b9.push(cell); @@ -47,5 +48,8 @@ pub(crate) fn apply_absorb( add.add_advice_mul_const(layouter, state[i].clone(), input.clone(), F::from(A4))?; out_state.push(out_lane); } + for i in NEXT_INPUTS_LANES..25 { + out_state.push(state[i].clone()); + } Ok(out_state.try_into().unwrap()) } diff --git a/keccak256/src/permutation/add.rs b/keccak256/src/permutation/add.rs index 9699ae580b..8fa2fb3daf 100644 --- a/keccak256/src/permutation/add.rs +++ b/keccak256/src/permutation/add.rs @@ -62,7 +62,7 @@ impl AddConfig { let offset = 0; self.q_enable.enable(&mut region, offset)?; input.copy_advice(|| "input", &mut region, self.io, offset)?; - let x = match &left { + let left = match &left { Some(x) => { // copy x to use as a flag (*x).copy_advice(|| "left adv", &mut region, self.left, offset)? @@ -71,34 +71,38 @@ impl AddConfig { // constrain advice to 1 for a simple add. region.assign_advice_from_constant( || "left const", - self.right, + self.left, offset, F::one(), )? } }; - if let Some(right) = &right { - if value.is_some() { - panic!("right and value can't be both some"); - } - right.copy_advice(|| "right adv", &mut region, self.right, offset)?; - } - let value = match value { - Some(value) => region.assign_advice_from_constant( - || "fixed value", - self.right, - offset, - value, - )?, + let right = match &right { + Some(right) => { + if value.is_some() { + panic!("right and value can't be both some"); + } + right.copy_advice(|| "right adv", &mut region, self.right, offset)? + } None => { - // constrain fixed to 1 for a simple add. - region.assign_advice_from_constant( - || "fixed value", - self.right, - offset, - F::one(), - )? + match value { + Some(value) => region.assign_advice_from_constant( + || "fixed value", + self.right, + offset, + value, + )?, + None => { + // constrain fixed to 1 for a simple add. + region.assign_advice_from_constant( + || "fixed value", + self.right, + offset, + F::one(), + )? + } + } } }; @@ -109,8 +113,8 @@ impl AddConfig { offset, || { Ok(input.value().cloned().ok_or(Error::Synthesis)? - + x.value().cloned().ok_or(Error::Synthesis)? - * value.value().cloned().ok_or(Error::Synthesis)?) + + left.value().cloned().ok_or(Error::Synthesis)? + * right.value().cloned().ok_or(Error::Synthesis)?) }, ) }, @@ -178,7 +182,7 @@ impl AddConfig { ) -> Result, Error> { debug_assert_eq!( ys.is_some(), - vs.is_some(), + vs.is_none(), "They can't both some or both none" ); if let Some(ref vs) = vs { diff --git a/keccak256/src/permutation/base_conversion.rs b/keccak256/src/permutation/base_conversion.rs index f648b08ddf..9c0319e832 100644 --- a/keccak256/src/permutation/base_conversion.rs +++ b/keccak256/src/permutation/base_conversion.rs @@ -152,7 +152,7 @@ mod tests { let table = FromBinaryTableConfig::configure(meta); let lane = meta.advice_column(); meta.enable_equality(lane); - let advices: [Column; 2] = (0..2) + let advices: [Column; 3] = (0..3) .map(|_| { let col = meta.advice_column(); meta.enable_equality(col); @@ -164,8 +164,13 @@ mod tests { let base_info = table.get_base_info(false); let fixed = meta.fixed_column(); meta.enable_constant(fixed); - let add = AddConfig::configure(meta, advices[0], advices[1], fixed); - let conversion = BaseConversionConfig::configure(meta, base_info, advices, &add); + let add = AddConfig::configure(meta, advices, fixed); + let conversion = BaseConversionConfig::configure( + meta, + base_info, + advices[0..2].try_into().unwrap(), + &add, + ); Self { lane, table, @@ -260,7 +265,7 @@ mod tests { let table = FromBase9TableConfig::configure(meta); let lane = meta.advice_column(); meta.enable_equality(lane); - let advices: [Column; 2] = (0..2) + let advices: [Column; 3] = (0..3) .map(|_| { let col = meta.advice_column(); meta.enable_equality(col); @@ -272,8 +277,13 @@ mod tests { let base_info = table.get_base_info(false); let fixed = meta.fixed_column(); meta.enable_constant(fixed); - let add = AddConfig::configure(meta, advices[0], advices[1], fixed); - let conversion = BaseConversionConfig::configure(meta, base_info, advices, &add); + let add = AddConfig::configure(meta, advices, fixed); + let conversion = BaseConversionConfig::configure( + meta, + base_info, + advices[0..2].try_into().unwrap(), + &add, + ); Self { lane, table, @@ -367,7 +377,7 @@ mod tests { .collect::>() .try_into() .unwrap(); - let advices: [Column; 2] = (0..2) + let advices: [Column; 3] = (0..3) .map(|_| { let col = meta.advice_column(); meta.enable_equality(col); @@ -380,8 +390,13 @@ mod tests { let fixed = meta.fixed_column(); meta.enable_equality(fixed); meta.enable_constant(fixed); - let add = AddConfig::configure(meta, advices[0], advices[1], fixed); - let conversion = BaseConversionConfig::configure(meta, bi, advices, &add); + let add = AddConfig::configure(meta, advices, fixed); + let conversion = BaseConversionConfig::configure( + meta, + bi, + advices[0..2].try_into().unwrap(), + &add, + ); Self { state, table, diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 5fb7fc44f0..f94073f042 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -149,8 +149,10 @@ impl KeccakFConfig { #[cfg(test)] mod tests { use super::*; + use crate::arith_helpers::*; use crate::common::{State, NEXT_INPUTS_LANES}; use crate::gate_helpers::biguint_to_f; + use crate::keccak_arith::*; use halo2_proofs::circuit::Layouter; use halo2_proofs::pairing::bn256::Fr as Fp; use halo2_proofs::plonk::{ConstraintSystem, Error}; @@ -166,7 +168,7 @@ mod tests { struct MyCircuit { in_state: [F; 25], out_state: [F; 25], - next_mixing: Option<[F; NEXT_INPUTS_LANES]>, + next_mixing: [Option; NEXT_INPUTS_LANES], // flag is_mixing: bool, } @@ -263,8 +265,13 @@ mod tests { // Generate next_input (tho one that is not None) in the form `[F;17]` // Generate next_input as `[Fp;NEXT_INPUTS_LANES]` - let next_input_fp: [Fp; NEXT_INPUTS_LANES] = - state_bigint_to_field(StateBigInt::from(next_input)); + let next_input_fp: [Option; NEXT_INPUTS_LANES] = + state_bigint_to_field::<_, NEXT_INPUTS_LANES>(StateBigInt::from(next_input)) + .iter() + .map(|&x| Some(x)) + .collect_vec() + .try_into() + .unwrap(); // When we pass no `mixing_inputs`, we perform the full keccak round // ending with Mixing executing IotaB9 @@ -274,7 +281,7 @@ mod tests { let circuit = MyCircuit:: { in_state: in_state_fp, out_state: out_state_non_mix, - next_mixing: None, + next_mixing: [None; NEXT_INPUTS_LANES], is_mixing: false, }; @@ -287,7 +294,7 @@ mod tests { let circuit = MyCircuit:: { in_state: out_state_non_mix, out_state: out_state_non_mix, - next_mixing: None, + next_mixing: [None; NEXT_INPUTS_LANES], is_mixing: true, }; let k = 17; @@ -314,7 +321,7 @@ mod tests { let circuit = MyCircuit:: { in_state: in_state_fp, out_state: out_state_mix, - next_mixing: Some(next_input_fp), + next_mixing: next_input_fp, is_mixing: true, }; @@ -327,7 +334,7 @@ mod tests { let circuit = MyCircuit:: { in_state: out_state_non_mix, out_state: out_state_non_mix, - next_mixing: Some(next_input_fp), + next_mixing: next_input_fp, is_mixing: true, }; diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index 851c0f57d9..cbc60426ea 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -72,26 +72,6 @@ impl MixingConfig { let base_conv_config = BaseConversionConfig::configure(meta, base_info, state[0..2].try_into().unwrap(), &add); - let q_out_copy = meta.selector(); - - meta.create_gate("Mixing result copies and constraints", |meta| { - let q_enable = meta.query_selector(q_out_copy); - // Add out mixing states together multiplied by the mixing_flag. - let negated_flag = meta.query_advice(flag, Rotation::next()); - let flag = meta.query_advice(flag, Rotation::cur()); - - // Multiply by flag and negated_flag the out mixing results. - let left_side = meta.query_advice(state[0], Rotation::cur()) * negated_flag; - let right_side = meta.query_advice(state[0], Rotation::next()) * flag; - let out_state = meta.query_advice(state[0], Rotation(2)); - - // We add the results of the mixing gate if/else branches multiplied - // by it's corresponding flags so that we always - // copy from the same place on the copy_constraints while enforcing - // the equality with the out_state of the permutation. - [q_enable * ((left_side + right_side) - out_state)] - }); - Self { iota_config, base_conv_config, @@ -192,7 +172,9 @@ impl MixingConfig { #[cfg(test)] mod tests { use super::*; + use crate::arith_helpers::*; use crate::common::{State, ROUND_CONSTANTS}; + use crate::keccak_arith::KeccakFArith; use crate::permutation::{add::AddConfig, iota::IotaConfig}; use halo2_proofs::circuit::Layouter; use halo2_proofs::pairing::bn256::Fr as Fp; @@ -204,7 +186,7 @@ mod tests { #[test] fn test_mixing_gate() { - #[derive(Default)] + #[derive(Default, Debug)] struct MyCircuit { in_state: [F; 25], out_state: [F; 25], @@ -240,7 +222,7 @@ mod tests { .try_into() .unwrap(); let fixed = meta.fixed_column(); - let add = AddConfig::configure(meta, state[0], state[1], fixed); + let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); let iota_config = IotaConfig::configure(add.clone()); MyConfig { @@ -280,14 +262,23 @@ mod tests { }, )?; - config.mixing_conf.assign_state( + let out_state = config.mixing_conf.assign_state( &mut layouter, &in_state, - self.out_state, Some(self.is_mixing), - self.next_mixing, + self.next_mixing.map_or([None; NEXT_INPUTS_LANES], |x| { + x.iter().map(|&x| Some(x)).collect_vec().try_into().unwrap() + }), + )?; + layouter.assign_region( + || "State check", + |mut region| { + for (lane, value) in out_state.iter().zip(self.out_state.iter()) { + region.constrain_constant(lane.cell(), value)?; + } + Ok(()) + }, )?; - Ok(()) } } diff --git a/keccak256/src/permutation/rho.rs b/keccak256/src/permutation/rho.rs index 294f3290ba..d9504de68f 100644 --- a/keccak256/src/permutation/rho.rs +++ b/keccak256/src/permutation/rho.rs @@ -156,7 +156,7 @@ mod tests { .unwrap(); let fixed = meta.fixed_column(); - let add = AddConfig::configure(meta, state[0], state[1], fixed); + let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); let rho_config = RhoConfig::configure(meta, state, fixed, add); diff --git a/keccak256/src/permutation/theta.rs b/keccak256/src/permutation/theta.rs index faab2c2ddf..ca078fbdbe 100644 --- a/keccak256/src/permutation/theta.rs +++ b/keccak256/src/permutation/theta.rs @@ -86,7 +86,7 @@ mod tests { let fixed = meta.fixed_column(); let lane = advices[0]; - let add = AddConfig::configure(meta, advices[1], advices[2], fixed); + let add = AddConfig::configure(meta, advices, fixed); Self { lane, add } } } diff --git a/keccak256/src/permutation/xi.rs b/keccak256/src/permutation/xi.rs index aff5830b10..18a6af4a7a 100644 --- a/keccak256/src/permutation/xi.rs +++ b/keccak256/src/permutation/xi.rs @@ -69,7 +69,7 @@ mod tests { let fixed = meta.fixed_column(); let lane = advices[0]; - let add = AddConfig::configure(meta, advices[1], advices[2], fixed); + let add = AddConfig::configure(meta, advices, fixed); Self { lane, add } } } From 7794a947ad698ecd8c904e754bf305e2aa2bb6a3 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 2 Jun 2022 22:19:02 +0200 Subject: [PATCH 15/18] fixed keccak_f test --- keccak256/src/permutation/circuit.rs | 40 +++++++++------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index f94073f042..8c4a9da748 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -10,7 +10,6 @@ use eth_types::Field; use halo2_proofs::{ circuit::{AssignedCell, Layouter}, plonk::{Advice, Column, ConstraintSystem, Error}, - poly::Rotation, }; use itertools::Itertools; use std::convert::TryInto; @@ -39,22 +38,14 @@ impl KeccakFConfig { .try_into() .unwrap(); - let fixed = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; + let fixed = meta.fixed_column(); - let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed[0]); + let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); // rho - let rho_config = RhoConfig::configure(meta, state, fixed[0], add.clone()); + let rho_config = RhoConfig::configure(meta, state, fixed, add.clone()); let iota_config = IotaConfig::configure(add.clone()); - // Allocate space for the activation flag of the base_conversion. - let base_conv_activator = meta.advice_column(); - meta.enable_equality(base_conv_activator); // Base conversion config. let from_b9_table = FromBase9TableConfig::configure(meta); let base_info = from_b9_table.get_base_info(false); @@ -66,22 +57,6 @@ impl KeccakFConfig { let mixing_config = MixingConfig::configure(meta, &from_b9_table, iota_config.clone(), &add, state); - // Allocate the `out state correctness` gate selector - let q_out = meta.selector(); - // Constraint the out of the mixing gate to be equal to the out state - // announced. - meta.create_gate("Constraint out_state correctness", |meta| { - (0..25usize) - .into_iter() - .map(|idx| { - let q_out = meta.query_selector(q_out); - let out_mixing = meta.query_advice(state[idx], Rotation::cur()); - let out_expected_state = meta.query_advice(state[idx], Rotation::next()); - q_out * (out_mixing - out_expected_state) - }) - .collect_vec() - }); - Self { add, rho_config, @@ -222,6 +197,15 @@ mod tests { Some(self.is_mixing), self.next_mixing, )?; + layouter.assign_region( + || "State check", + |mut region| { + for (lane, value) in out_state.iter().zip(self.out_state.iter()) { + region.constrain_constant(lane.cell(), value)?; + } + Ok(()) + }, + )?; Ok(()) } } From 2ec951bb3aded192e1c20a00b1da49172de2954c Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 2 Jun 2022 22:47:49 +0200 Subject: [PATCH 16/18] extract flag --- keccak256/src/permutation.rs | 1 + keccak256/src/permutation/circuit.rs | 5 +- keccak256/src/permutation/flag.rs | 80 ++++++++++++++++++++++ keccak256/src/permutation/mixing.rs | 99 +++++----------------------- 4 files changed, 99 insertions(+), 86 deletions(-) create mode 100644 keccak256/src/permutation/flag.rs diff --git a/keccak256/src/permutation.rs b/keccak256/src/permutation.rs index be874117db..c1b95177b2 100644 --- a/keccak256/src/permutation.rs +++ b/keccak256/src/permutation.rs @@ -4,6 +4,7 @@ pub(crate) mod absorb; pub(crate) mod add; pub(crate) mod base_conversion; pub mod circuit; +pub(crate) mod flag; pub(crate) mod iota; pub(crate) mod mixing; pub(crate) mod pi; diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 8c4a9da748..697155f04f 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -1,7 +1,7 @@ use crate::{ common::{NEXT_INPUTS_LANES, PERMUTATION}, permutation::{ - add::AddConfig, base_conversion::BaseConversionConfig, iota::IotaConfig, + add::AddConfig, base_conversion::BaseConversionConfig, flag::FlagConfig, iota::IotaConfig, mixing::MixingConfig, pi::pi_gate_permutation, rho::RhoConfig, tables::FromBase9TableConfig, theta::assign_theta, xi::assign_xi, }, @@ -41,6 +41,7 @@ impl KeccakFConfig { let fixed = meta.fixed_column(); let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); + let flag = FlagConfig::configure(meta, state[0]); // rho let rho_config = RhoConfig::configure(meta, state, fixed, add.clone()); @@ -55,7 +56,7 @@ impl KeccakFConfig { // Mixing will make sure that the flag is binary constrained and that // the out state matches the expected result. let mixing_config = - MixingConfig::configure(meta, &from_b9_table, iota_config.clone(), &add, state); + MixingConfig::configure(meta, &from_b9_table, iota_config.clone(), &add, state, flag); Self { add, diff --git a/keccak256/src/permutation/flag.rs b/keccak256/src/permutation/flag.rs new file mode 100644 index 0000000000..c391aaea47 --- /dev/null +++ b/keccak256/src/permutation/flag.rs @@ -0,0 +1,80 @@ +use eth_types::Field; +use halo2_proofs::{ + circuit::{AssignedCell, Layouter}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector}, + poly::Rotation, +}; +use std::marker::PhantomData; + +#[derive(Clone, Debug)] +pub struct FlagConfig { + flag: Column, + q_enable: Selector, + _marker: PhantomData, +} + +impl FlagConfig { + pub fn configure(meta: &mut ConstraintSystem, flag: Column) -> Self { + meta.enable_equality(flag); + + let q_enable = meta.selector(); + + meta.create_gate("Ensure flag consistency", |meta| { + let q_enable = meta.query_selector(q_enable); + + let f_positive = meta.query_advice(flag, Rotation::cur()); + let f_negative = meta.query_advice(flag, Rotation::next()); + let one = Expression::Constant(F::one()); + + [ + ( + "f_pos must be 1 or 0", + q_enable.clone() * (one.clone() - f_positive.clone()) * f_positive.clone(), + ), + ( + "f_neg must be 1 - f_pos", + q_enable * (f_positive + f_negative - one), + ), + ] + }); + + Self { + flag, + q_enable, + _marker: PhantomData, + } + } + + pub fn assign_flag( + &self, + layouter: &mut impl Layouter, + flag: Option, + ) -> Result<(AssignedCell, AssignedCell), Error> { + layouter.assign_region( + || "Flag and Negated flag assignation", + |mut region| { + self.q_enable.enable(&mut region, 0)?; + let positive = region.assign_advice( + || "flag positive", + self.flag, + 0, + || { + flag.map(|flag| F::from(flag as u64)) + .ok_or(Error::Synthesis) + }, + )?; + let negative = region.assign_advice( + || "flag negative", + self.flag, + 1, + || { + flag.map(|flag| F::from(!flag as u64)) + .ok_or(Error::Synthesis) + }, + )?; + + Ok((positive, negative)) + }, + ) + } +} diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index cbc60426ea..c97ef6346b 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -1,14 +1,12 @@ use super::tables::FromBase9TableConfig; use super::{ - absorb::apply_absorb, add::AddConfig, base_conversion::BaseConversionConfig, iota::IotaConfig, + absorb::apply_absorb, add::AddConfig, base_conversion::BaseConversionConfig, flag::FlagConfig, + iota::IotaConfig, }; use crate::common::*; use eth_types::Field; -use halo2_proofs::circuit::AssignedCell; -use halo2_proofs::plonk::{Expression, Selector}; -use halo2_proofs::poly::Rotation; use halo2_proofs::{ - circuit::Layouter, + circuit::{AssignedCell, Layouter}, plonk::{Advice, Column, ConstraintSystem, Error}, }; use itertools::izip; @@ -20,8 +18,7 @@ pub struct MixingConfig { base_conv_config: BaseConversionConfig, add: AddConfig, state: [Column; 25], - flag: Column, - q_flag: Selector, + flag: FlagConfig, } impl MixingConfig { @@ -31,43 +28,8 @@ impl MixingConfig { iota_config: IotaConfig, add: &AddConfig, state: [Column; 25], + flag: FlagConfig, ) -> Self { - // Allocate space for the flag column from which we will copy to all of - // the sub-configs. - let flag = meta.advice_column(); - meta.enable_equality(flag); - - let q_flag = meta.selector(); - - meta.create_gate("Ensure flag consistency", |meta| { - let q_flag = meta.query_selector(q_flag); - - let negated_flag = meta.query_advice(flag, Rotation::next()); - let flag = meta.query_advice(flag, Rotation::cur()); - // We do a trick which consists on multiplying an internal selector - // which is always active by the actual `negated_flag` - // which will then enable or disable the gate. - // - // Force that `flag + negated_flag = 1`. - // This ensures that flag = !negated_flag. - let flag_consistency = - (flag.clone() + negated_flag.clone()) - Expression::Constant(F::one()); - - // Define bool constraint for flags. - // Based on: `(1-flag) * flag = 0` only if `flag` is boolean. - let bool_constraint = |flag: Expression| -> Expression { - (Expression::Constant(F::one()) - flag.clone()) * flag - }; - - // Add a constraint that sums up the results of the two branches - // constraining it to be equal to `out_state`. - [ - q_flag.clone() * flag_consistency, - q_flag.clone() * bool_constraint(flag), - q_flag * bool_constraint(negated_flag), - ] - }); - let base_info = table.get_base_info(false); let base_conv_config = BaseConversionConfig::configure(meta, base_info, state[0..2].try_into().unwrap(), &add); @@ -78,47 +40,9 @@ impl MixingConfig { add: add.clone(), state, flag, - q_flag, } } - /// Enforce flag constraints - pub fn enforce_flag_consistency( - &self, - layouter: &mut impl Layouter, - flag: Option, - ) -> Result<(AssignedCell, AssignedCell), Error> { - layouter.assign_region( - || "Flag and Negated flag assignation", - |mut region| { - self.q_flag.enable(&mut region, 0)?; - // Witness `is_mixing` flag - let positive = region.assign_advice( - || "witness is_mixing", - self.flag, - 0, - || { - flag.map(|flag| F::from(flag as u64)) - .ok_or(Error::Synthesis) - }, - )?; - - // Witness negated `is_mixing` flag - let negative = region.assign_advice( - || "witness negated is_mixing", - self.flag, - 1, - || { - flag.map(|flag| F::from(!flag as u64)) - .ok_or(Error::Synthesis) - }, - )?; - - Ok((positive, negative)) - }, - ) - } - pub fn assign_state( &self, layouter: &mut impl Layouter, @@ -126,8 +50,7 @@ impl MixingConfig { flag: Option, next_mixing: [Option; NEXT_INPUTS_LANES], ) -> Result<[AssignedCell; 25], Error> { - // Enforce flag constraints and witness them. - let (f_pos, f_neg) = self.enforce_flag_consistency(layouter, flag)?; + let (f_pos, f_neg) = self.flag.assign_flag(layouter, flag)?; // If we don't mix: // IotaB9 @@ -224,9 +147,17 @@ mod tests { let fixed = meta.fixed_column(); let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); let iota_config = IotaConfig::configure(add.clone()); + let flag = FlagConfig::configure(meta, state[0]); MyConfig { - mixing_conf: MixingConfig::configure(meta, &table, iota_config, &add, state), + mixing_conf: MixingConfig::configure( + meta, + &table, + iota_config, + &add, + state, + flag, + ), table, } } From 90a53b22e3e9cd5a88fab0b3492fee6a76a40d75 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 2 Jun 2022 23:31:28 +0200 Subject: [PATCH 17/18] use less columns --- keccak256/src/permutation/circuit.rs | 33 ++++++++++------ keccak256/src/permutation/mixing.rs | 24 ++++++----- keccak256/src/permutation/rho.rs | 59 +++++++--------------------- 3 files changed, 45 insertions(+), 71 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index 697155f04f..c8db2c31d5 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -22,13 +22,12 @@ pub struct KeccakFConfig { from_b9_table: FromBase9TableConfig, base_conversion_config: BaseConversionConfig, mixing_config: MixingConfig, - pub state: [Column; 25], } impl KeccakFConfig { // We assume state is received in base-9. pub fn configure(meta: &mut ConstraintSystem) -> Self { - let state: [Column; 25] = (0..25) + let advices: [Column; 3] = (0..3) .map(|_| { let column = meta.advice_column(); meta.enable_equality(column); @@ -40,23 +39,33 @@ impl KeccakFConfig { let fixed = meta.fixed_column(); - let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); - let flag = FlagConfig::configure(meta, state[0]); + let add = AddConfig::configure(meta, advices, fixed); + let flag = FlagConfig::configure(meta, advices[0]); // rho - let rho_config = RhoConfig::configure(meta, state, fixed, add.clone()); + let rho_config = RhoConfig::configure(meta, advices, fixed, add.clone()); let iota_config = IotaConfig::configure(add.clone()); // Base conversion config. let from_b9_table = FromBase9TableConfig::configure(meta); let base_info = from_b9_table.get_base_info(false); - let base_conversion_config = - BaseConversionConfig::configure(meta, base_info, state[0..2].try_into().unwrap(), &add); + let base_conversion_config = BaseConversionConfig::configure( + meta, + base_info, + advices[0..2].try_into().unwrap(), + &add, + ); // Mixing will make sure that the flag is binary constrained and that // the out state matches the expected result. - let mixing_config = - MixingConfig::configure(meta, &from_b9_table, iota_config.clone(), &add, state, flag); + let mixing_config = MixingConfig::configure( + meta, + &from_b9_table, + iota_config.clone(), + &add, + advices[0..2].try_into().unwrap(), + flag, + ); Self { add, @@ -65,7 +74,6 @@ impl KeccakFConfig { from_b9_table, base_conversion_config, mixing_config, - state, } } @@ -168,7 +176,6 @@ mod tests { ) -> Result<(), Error> { // Load the table config.load(&mut layouter)?; - let offset: usize = 0; let in_state = layouter.assign_region( || "Keccak round Wittnes & flag assignation", @@ -176,10 +183,10 @@ mod tests { // Witness `state` let in_state: [AssignedCell; 25] = { let mut state: Vec> = Vec::with_capacity(25); - for (idx, val) in self.in_state.iter().enumerate() { + for (offset, val) in self.in_state.iter().enumerate() { let cell = region.assign_advice( || "witness input state", - config.state[idx], + config.advices[0], offset, || Ok(*val), )?; diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index c97ef6346b..7b9578402d 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -17,7 +17,7 @@ pub struct MixingConfig { iota_config: IotaConfig, base_conv_config: BaseConversionConfig, add: AddConfig, - state: [Column; 25], + advices: [Column; 2], flag: FlagConfig, } @@ -27,18 +27,17 @@ impl MixingConfig { table: &FromBase9TableConfig, iota_config: IotaConfig, add: &AddConfig, - state: [Column; 25], + advices: [Column; 2], flag: FlagConfig, ) -> Self { let base_info = table.get_base_info(false); - let base_conv_config = - BaseConversionConfig::configure(meta, base_info, state[0..2].try_into().unwrap(), &add); + let base_conv_config = BaseConversionConfig::configure(meta, base_info, advices, &add); Self { iota_config, base_conv_config, add: add.clone(), - state, + advices, flag, } } @@ -64,7 +63,7 @@ impl MixingConfig { // If we mix: // Absorb - let state_mix = apply_absorb(&self.add, layouter, self.state[0], in_state, &next_mixing)?; + let state_mix = apply_absorb(&self.add, layouter, self.advices[0], in_state, &next_mixing)?; // Base conversion assign let state_mix = self.base_conv_config.assign_state(layouter, &state_mix)?; @@ -135,7 +134,7 @@ mod tests { fn configure(meta: &mut ConstraintSystem) -> Self::Config { let table = FromBase9TableConfig::configure(meta); - let state: [Column; 25] = (0..25) + let advices: [Column; 3] = (0..3) .map(|_| { let col = meta.advice_column(); meta.enable_equality(col); @@ -145,9 +144,9 @@ mod tests { .try_into() .unwrap(); let fixed = meta.fixed_column(); - let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); + let add = AddConfig::configure(meta, advices, fixed); let iota_config = IotaConfig::configure(add.clone()); - let flag = FlagConfig::configure(meta, state[0]); + let flag = FlagConfig::configure(meta, advices[0]); MyConfig { mixing_conf: MixingConfig::configure( @@ -155,7 +154,7 @@ mod tests { &table, iota_config, &add, - state, + advices[0..2].try_into().unwrap(), flag, ), table, @@ -169,7 +168,6 @@ mod tests { ) -> Result<(), Error> { // Load the table config.table.load(&mut layouter)?; - let offset: usize = 0; let in_state = layouter.assign_region( || "Mixing Wittnes assignment", @@ -177,10 +175,10 @@ mod tests { // Witness `in_state` let in_state: [AssignedCell; 25] = { let mut state: Vec> = Vec::with_capacity(25); - for (idx, val) in self.in_state.iter().enumerate() { + for (offset, val) in self.in_state.iter().enumerate() { let cell = region.assign_advice( || "witness input state", - config.mixing_conf.state[idx], + config.mixing_conf.advices[0], offset, || Ok(*val), )?; diff --git a/keccak256/src/permutation/rho.rs b/keccak256/src/permutation/rho.rs index d9504de68f..cf3f554bdd 100644 --- a/keccak256/src/permutation/rho.rs +++ b/keccak256/src/permutation/rho.rs @@ -25,11 +25,10 @@ pub struct RhoConfig { impl RhoConfig { pub fn configure( meta: &mut ConstraintSystem, - state: [Column; 25], + advices: [Column; 3], fixed: Column, add: AddConfig, ) -> 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); @@ -39,7 +38,7 @@ impl RhoConfig { meta, &base13_to_9_table, &special_chunk_table, - state[0..3].try_into().unwrap(), + advices, fixed, add.clone(), ); @@ -49,7 +48,7 @@ impl RhoConfig { &step2_range_table, &step3_range_table, add.clone(), - state[3], + advices[0], ); Self { lane_config, @@ -121,7 +120,6 @@ mod tests { use halo2_proofs::pairing::bn256::Fr as Fp; use halo2_proofs::plonk::Selector; use halo2_proofs::plonk::{Advice, Column, ConstraintSystem, Error}; - use halo2_proofs::poly::Rotation; use halo2_proofs::{circuit::SimpleFloorPlanner, dev::MockProver, plonk::Circuit}; use itertools::Itertools; use std::convert::TryInto; @@ -138,7 +136,7 @@ mod tests { struct MyConfig { q_enable: Selector, rho_config: RhoConfig, - state: [Column; 25], + advices: [Column; 3], } impl Circuit for MyCircuit { type Config = MyConfig; @@ -149,34 +147,23 @@ mod tests { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let state: [Column; 25] = (0..25) + let advices: [Column; 3] = (0..3) .map(|_| meta.advice_column()) .collect::>() .try_into() .unwrap(); let fixed = meta.fixed_column(); - let add = AddConfig::configure(meta, state[0..3].try_into().unwrap(), fixed); + let add = AddConfig::configure(meta, advices, fixed); - let rho_config = RhoConfig::configure(meta, state, fixed, add); + let rho_config = RhoConfig::configure(meta, advices, fixed, add); let q_enable = meta.selector(); - meta.create_gate("Check states", |meta| { - let q_enable = meta.query_selector(q_enable); - state - .iter() - .map(|col| { - let final_state = meta.query_advice(*col, Rotation::cur()); - let expected_final_state = meta.query_advice(*col, Rotation::next()); - q_enable.clone() * (final_state - expected_final_state) - }) - .collect::>() - }); MyConfig { q_enable, rho_config, - state, + advices, } } @@ -189,16 +176,15 @@ mod tests { let state = layouter.assign_region( || "assign input state", |mut region| { - let offset = 0; let state: [AssignedCell; 25] = self .in_state .iter() .enumerate() - .map(|(idx, &value)| { + .map(|(offset, &value)| { region .assign_advice( - || format!("lane {}", idx), - config.state[idx], + || "lane", + config.advices[0], offset, || Ok(value), ) @@ -217,26 +203,9 @@ mod tests { || "check final states", |mut region| { config.q_enable.enable(&mut region, 0)?; - out_state.iter().enumerate().for_each(|(idx, cell)| { - cell.copy_advice( - || "out_state obtained", - &mut region, - config.state[idx], - 0, - ) - .unwrap(); - }); - - self.out_state.iter().enumerate().for_each(|(idx, &value)| { - region - .assign_advice( - || format!("lane {}", idx), - config.state[idx], - 1, - || Ok(value), - ) - .unwrap(); - }); + for (lane, value) in out_state.iter().zip(self.out_state.iter()) { + region.constrain_constant(lane.cell(), value)?; + } Ok(()) }, From 6a17916c262658695e7853bcd49fdc67eed36cd9 Mon Sep 17 00:00:00 2001 From: ChihChengLiang Date: Thu, 2 Jun 2022 23:49:18 +0200 Subject: [PATCH 18/18] rm duplicated from9 config --- keccak256/src/permutation/circuit.rs | 15 +++++----- keccak256/src/permutation/mixing.rs | 42 +++++++++++++++------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/keccak256/src/permutation/circuit.rs b/keccak256/src/permutation/circuit.rs index c8db2c31d5..50bba2060c 100644 --- a/keccak256/src/permutation/circuit.rs +++ b/keccak256/src/permutation/circuit.rs @@ -20,8 +20,9 @@ pub struct KeccakFConfig { rho_config: RhoConfig, iota_config: IotaConfig, from_b9_table: FromBase9TableConfig, - base_conversion_config: BaseConversionConfig, + from9_config: BaseConversionConfig, mixing_config: MixingConfig, + pub advices: [Column; 3], } impl KeccakFConfig { @@ -49,7 +50,7 @@ impl KeccakFConfig { // Base conversion config. let from_b9_table = FromBase9TableConfig::configure(meta); let base_info = from_b9_table.get_base_info(false); - let base_conversion_config = BaseConversionConfig::configure( + let from9_config = BaseConversionConfig::configure( meta, base_info, advices[0..2].try_into().unwrap(), @@ -59,12 +60,11 @@ impl KeccakFConfig { // Mixing will make sure that the flag is binary constrained and that // the out state matches the expected result. let mixing_config = MixingConfig::configure( - meta, - &from_b9_table, + from9_config.clone(), iota_config.clone(), &add, - advices[0..2].try_into().unwrap(), flag, + advices[0], ); Self { @@ -72,8 +72,9 @@ impl KeccakFConfig { rho_config, iota_config, from_b9_table, - base_conversion_config, + from9_config, mixing_config, + advices, } } @@ -120,7 +121,7 @@ impl KeccakFConfig { // The resulting state is in Base-9 now. We now convert it to // base_13 which is what Theta requires again at the // start of the loop. - state = self.base_conversion_config.assign_state(layouter, &state)?; + state = self.from9_config.assign_state(layouter, &state)?; } let mix_res = self diff --git a/keccak256/src/permutation/mixing.rs b/keccak256/src/permutation/mixing.rs index 7b9578402d..9dd016ebf0 100644 --- a/keccak256/src/permutation/mixing.rs +++ b/keccak256/src/permutation/mixing.rs @@ -1,4 +1,3 @@ -use super::tables::FromBase9TableConfig; use super::{ absorb::apply_absorb, add::AddConfig, base_conversion::BaseConversionConfig, flag::FlagConfig, iota::IotaConfig, @@ -7,38 +6,34 @@ use crate::common::*; use eth_types::Field; use halo2_proofs::{ circuit::{AssignedCell, Layouter}, - plonk::{Advice, Column, ConstraintSystem, Error}, + plonk::{Advice, Column, Error}, }; use itertools::izip; use std::convert::TryInto; #[derive(Clone, Debug)] -pub struct MixingConfig { +pub(crate) struct MixingConfig { iota_config: IotaConfig, - base_conv_config: BaseConversionConfig, + from9_config: BaseConversionConfig, add: AddConfig, - advices: [Column; 2], flag: FlagConfig, + advice: Column, } impl MixingConfig { pub fn configure( - meta: &mut ConstraintSystem, - table: &FromBase9TableConfig, + from9_config: BaseConversionConfig, iota_config: IotaConfig, add: &AddConfig, - advices: [Column; 2], flag: FlagConfig, + advice: Column, ) -> Self { - let base_info = table.get_base_info(false); - let base_conv_config = BaseConversionConfig::configure(meta, base_info, advices, &add); - Self { + from9_config, iota_config, - base_conv_config, add: add.clone(), - advices, flag, + advice, } } @@ -63,10 +58,10 @@ impl MixingConfig { // If we mix: // Absorb - let state_mix = apply_absorb(&self.add, layouter, self.advices[0], in_state, &next_mixing)?; + let state_mix = apply_absorb(&self.add, layouter, self.advice, in_state, &next_mixing)?; // Base conversion assign - let state_mix = self.base_conv_config.assign_state(layouter, &state_mix)?; + let state_mix = self.from9_config.assign_state(layouter, &state_mix)?; // IotaB13 let state_mix = { @@ -121,6 +116,7 @@ mod tests { struct MyConfig { mixing_conf: MixingConfig, table: FromBase9TableConfig, + advices: [Column; 3], } impl Circuit for MyCircuit { @@ -133,7 +129,7 @@ mod tests { fn configure(meta: &mut ConstraintSystem) -> Self::Config { let table = FromBase9TableConfig::configure(meta); - + let base_info = table.get_base_info(false); let advices: [Column; 3] = (0..3) .map(|_| { let col = meta.advice_column(); @@ -147,17 +143,23 @@ mod tests { let add = AddConfig::configure(meta, advices, fixed); let iota_config = IotaConfig::configure(add.clone()); let flag = FlagConfig::configure(meta, advices[0]); + let from9_config = BaseConversionConfig::configure( + meta, + base_info, + advices[0..2].try_into().unwrap(), + &add, + ); MyConfig { mixing_conf: MixingConfig::configure( - meta, - &table, + from9_config, iota_config, &add, - advices[0..2].try_into().unwrap(), flag, + advices[0], ), table, + advices, } } @@ -178,7 +180,7 @@ mod tests { for (offset, val) in self.in_state.iter().enumerate() { let cell = region.assign_advice( || "witness input state", - config.mixing_conf.advices[0], + config.advices[0], offset, || Ok(*val), )?;