From fe2ab0bc7bacdd2a55f88536c3c3eafba90d760b Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 20 Apr 2021 19:26:32 +0800 Subject: [PATCH] Fix SHA256 example --- examples/sha256/benches.rs | 14 +- examples/sha256/main.rs | 50 +- examples/sha256/table16.rs | 133 +++-- examples/sha256/table16/compression.rs | 142 +---- .../table16/compression/compression_util.rs | 38 +- .../table16/compression/subregion_digest.rs | 10 +- .../table16/compression/subregion_initial.rs | 18 +- .../table16/compression/subregion_main.rs | 8 +- examples/sha256/table16/message_schedule.rs | 130 +---- .../table16/message_schedule/schedule_util.rs | 8 +- .../table16/message_schedule/subregion1.rs | 11 +- .../table16/message_schedule/subregion2.rs | 18 +- .../table16/message_schedule/subregion3.rs | 14 +- examples/sha256/table16/spread_table.rs | 497 +++++------------- 14 files changed, 331 insertions(+), 760 deletions(-) diff --git a/examples/sha256/benches.rs b/examples/sha256/benches.rs index 0fb30bf8..f400d4c2 100644 --- a/examples/sha256/benches.rs +++ b/examples/sha256/benches.rs @@ -1,7 +1,6 @@ use halo2::{ arithmetic::FieldExt, - circuit::Chip, - circuit::{layouter, Layouter}, + circuit::{layouter::SingleChipLayouter, Layouter}, pasta::EqAffine, plonk::{ create_proof, keygen_pk, keygen_vk, verify_proof, Assignment, Circuit, ConstraintSystem, @@ -28,17 +27,18 @@ fn bench(name: &str, k: u32, c: &mut Criterion) { impl Circuit for MyCircuit { type Config = Table16Config; - fn configure(meta: &mut ConstraintSystem) -> Table16Config { + fn configure(meta: &mut ConstraintSystem) -> Self::Config { Table16Chip::configure(meta) } fn synthesize( &self, cs: &mut impl Assignment, - config: Table16Config, + config: Self::Config, ) -> Result<(), Error> { - let mut layouter = layouter::SingleChip::, _>::new(cs, config)?; - Table16Chip::load(&mut layouter)?; + let mut layouter = SingleChipLayouter::new(cs)?; + Table16Chip::::load(config.clone(), &mut layouter)?; + let table16_chip = Table16Chip::::construct(config); // Test vector: "abc" let test_input = [ @@ -65,7 +65,7 @@ fn bench(name: &str, k: u32, c: &mut Criterion) { input.extend_from_slice(&test_input); } - Sha256::digest(layouter.namespace(|| "test vector"), &input)?; + Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 2"), &input)?; Ok(()) } diff --git a/examples/sha256/main.rs b/examples/sha256/main.rs index 7e0b74b8..53e8a360 100644 --- a/examples/sha256/main.rs +++ b/examples/sha256/main.rs @@ -2,12 +2,12 @@ //! //! [SHA-256]: https://tools.ietf.org/html/rfc6234 -/* use std::cmp::min; use std::convert::TryInto; use std::fmt; use halo2::{ + arithmetic::FieldExt, circuit::{Chip, Layouter}, plonk::Error, }; @@ -23,7 +23,7 @@ pub const BLOCK_SIZE: usize = 16; const DIGEST_SIZE: usize = 8; /// The set of circuit instructions required to use the [`Sha256`] gadget. -pub trait Sha256Instructions: Chip { +pub trait Sha256Instructions: Chip { /// Variable representing the SHA-256 internal state. type State: Clone + fmt::Debug; /// Variable representing a 32-bit word of the input block to the SHA-256 compression @@ -34,25 +34,28 @@ pub trait Sha256Instructions: Chip { fn zero() -> Self::BlockWord; /// Places the SHA-256 IV in the circuit, returning the initial state variable. - fn initialization_vector(layouter: &mut impl Layouter) -> Result; + fn initialization_vector(&self, layouter: &mut impl Layouter) -> Result; /// Creates an initial state from the output state of a previous block fn initialization( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, init_state: &Self::State, ) -> Result; /// Starting from the given initialized state, processes a block of input and returns the /// final state. fn compress( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, initialized_state: &Self::State, input: [Self::BlockWord; BLOCK_SIZE], ) -> Result; /// Converts the given state into a message digest. fn digest( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, state: &Self::State, ) -> Result<[Self::BlockWord; DIGEST_SIZE], Error>; } @@ -64,17 +67,20 @@ pub struct Sha256Digest([BlockWord; DIGEST_SIZE]); /// A gadget that constrains a SHA-256 invocation. It supports input at a granularity of /// 32 bits. #[derive(Debug)] -pub struct Sha256 { +pub struct Sha256> { + chip: CS, state: CS::State, cur_block: Vec, length: usize, } -impl Sha256 { +impl> Sha256 { /// Create a new hasher instance. - pub fn new(mut layouter: impl Layouter) -> Result { + pub fn new(chip: Sha256Chip, mut layouter: impl Layouter) -> Result { + let state = chip.initialization_vector(&mut layouter)?; Ok(Sha256 { - state: Sha256Chip::initialization_vector(&mut layouter)?, + chip, + state, cur_block: Vec::with_capacity(BLOCK_SIZE), length: 0, }) @@ -83,7 +89,7 @@ impl Sha256 { /// Digest data, updating the internal state. pub fn update( &mut self, - mut layouter: impl Layouter, + mut layouter: impl Layouter, mut data: &[Sha256Chip::BlockWord], ) -> Result<(), Error> { self.length += data.len() * 32; @@ -100,7 +106,7 @@ impl Sha256 { } // Process the now-full current block. - self.state = Sha256Chip::compress( + self.state = self.chip.compress( &mut layouter, &self.state, self.cur_block[..] @@ -112,8 +118,8 @@ impl Sha256 { // Process any additional full blocks. let mut chunks_iter = data.chunks_exact(BLOCK_SIZE); for chunk in &mut chunks_iter { - self.state = Sha256Chip::initialization(&mut layouter, &self.state)?; - self.state = Sha256Chip::compress( + self.state = self.chip.initialization(&mut layouter, &self.state)?; + self.state = self.chip.compress( &mut layouter, &self.state, chunk.try_into().expect("chunk.len() == BLOCK_SIZE"), @@ -130,14 +136,14 @@ impl Sha256 { /// Retrieve result and consume hasher instance. pub fn finalize( mut self, - mut layouter: impl Layouter, + mut layouter: impl Layouter, ) -> Result, Error> { // Pad the remaining block if !self.cur_block.is_empty() { let padding = vec![Sha256Chip::zero(); BLOCK_SIZE - self.cur_block.len()]; self.cur_block.extend_from_slice(&padding); - self.state = Sha256Chip::initialization(&mut layouter, &self.state)?; - self.state = Sha256Chip::compress( + self.state = self.chip.initialization(&mut layouter, &self.state)?; + self.state = self.chip.compress( &mut layouter, &self.state, self.cur_block[..] @@ -145,20 +151,22 @@ impl Sha256 { .expect("cur_block.len() == BLOCK_SIZE"), )?; } - Sha256Chip::digest(&mut layouter, &self.state).map(Sha256Digest) + self.chip + .digest(&mut layouter, &self.state) + .map(Sha256Digest) } /// Convenience function to compute hash of the data. It will handle hasher creation, /// data feeding and finalization. pub fn digest( - mut layouter: impl Layouter, + chip: Sha256Chip, + mut layouter: impl Layouter, data: &[Sha256Chip::BlockWord], ) -> Result, Error> { - let mut hasher = Self::new(layouter.namespace(|| "init"))?; + let mut hasher = Self::new(chip, layouter.namespace(|| "init"))?; hasher.update(layouter.namespace(|| "update"), data)?; hasher.finalize(layouter.namespace(|| "finalize")) } } -*/ fn main() {} diff --git a/examples/sha256/table16.rs b/examples/sha256/table16.rs index 3d1c0781..0fdf96ba 100644 --- a/examples/sha256/table16.rs +++ b/examples/sha256/table16.rs @@ -100,26 +100,41 @@ impl Into for CellValue16 { /// Configuration for a [`Table16Chip`]. #[derive(Clone, Debug)] pub struct Table16Config { - lookup_table: SpreadTable, - message_schedule: MessageSchedule, - compression: Compression, + lookup: SpreadTableConfig, + message_schedule: MessageScheduleConfig, + compression: CompressionConfig, } /// A chip that implements SHA-256 with a maximum lookup table size of $2^16$. #[derive(Clone, Debug)] pub struct Table16Chip { + config: Table16Config, _marker: PhantomData, } -impl Table16Chip { - /// Configures this chip for use in a circuit. - pub fn configure(meta: &mut ConstraintSystem) -> Table16Config { - // Columns required by this chip: - // - Three advice columns to interact with the lookup table. - let tag = meta.advice_column(); - let dense = meta.advice_column(); - let spread = meta.advice_column(); +impl Chip for Table16Chip { + type Config = Table16Config; + type Loaded = (); + fn config(&self) -> &Self::Config { + &self.config + } + + fn loaded(&self) -> &Self::Loaded { + &() + } +} + +impl Table16Chip { + pub fn construct(config: >::Config) -> Self { + Self { + config, + _marker: PhantomData, + } + } + + pub fn configure(meta: &mut ConstraintSystem) -> >::Config { + // Columns required by this chip: let message_schedule = meta.advice_column(); let extras = [ meta.advice_column(), @@ -130,7 +145,13 @@ impl Table16Chip { meta.advice_column(), ]; - let (lookup_inputs, lookup_table) = SpreadTable::configure(meta, tag, dense, spread); + // - Three advice columns to interact with the lookup table. + let input_tag = meta.advice_column(); + let input_dense = meta.advice_column(); + let input_spread = meta.advice_column(); + + let lookup = SpreadTableChip::configure(meta, input_tag, input_dense, input_spread); + let lookup_inputs = lookup.input.clone(); // Rename these here for ease of matching the gates to the specification. let _a_0 = lookup_inputs.tag; @@ -158,7 +179,7 @@ impl Table16Chip { ], ); - let compression = Compression::configure( + let compression = CompressionConfig::configure( meta, lookup_inputs.clone(), message_schedule, @@ -166,29 +187,27 @@ impl Table16Chip { perm.clone(), ); - let message_schedule = - MessageSchedule::configure(meta, lookup_inputs, message_schedule, extras, perm); + let message_schedule = MessageScheduleConfig::configure( + meta, + lookup_inputs.clone(), + message_schedule, + extras, + perm, + ); Table16Config { - lookup_table, + lookup, message_schedule, compression, } } -} -impl Chip for Table16Chip { - type Field = F; - type Config = Table16Config; - type Loaded = (); - - fn load(layouter: &mut impl Layouter) -> Result<(), Error> { - let table = layouter.config().lookup_table.clone(); - table.load(layouter) + pub fn load(config: Table16Config, layouter: &mut impl Layouter) -> Result<(), Error> { + SpreadTableChip::load(config.lookup, layouter) } } -impl Sha256Instructions for Table16Chip { +impl Sha256Instructions for Table16Chip { type State = State; type BlockWord = BlockWord; @@ -196,17 +215,16 @@ impl Sha256Instructions for Table16Chip { BlockWord::new(0) } - fn initialization_vector(layouter: &mut impl Layouter) -> Result { - let config = layouter.config().clone(); - config.compression.initialize_with_iv(layouter, IV) + fn initialization_vector(&self, layouter: &mut impl Layouter) -> Result { + self.config().compression.initialize_with_iv(layouter, IV) } fn initialization( - layouter: &mut impl Layouter>, + &self, + layouter: &mut impl Layouter, init_state: &Self::State, ) -> Result { - let config = layouter.config().clone(); - config + self.config() .compression .initialize_with_state(layouter, init_state.clone()) } @@ -214,26 +232,26 @@ impl Sha256Instructions for Table16Chip { // Given an initialized state and an input message block, compress the // message block and return the final state. fn compress( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, initialized_state: &Self::State, input: [Self::BlockWord; super::BLOCK_SIZE], ) -> Result { - let config = layouter.config().clone(); + let config = self.config().clone(); let (_, w_halves) = config.message_schedule.process(layouter, input)?; - config .compression .compress(layouter, initialized_state.clone(), w_halves) } fn digest( - layouter: &mut impl Layouter, + &self, + layouter: &mut impl Layouter, state: &Self::State, ) -> Result<[Self::BlockWord; super::DIGEST_SIZE], Error> { // Copy the dense forms of the state variable chunks down to this gate. // Reconstruct the 32-bit dense words. - let config = layouter.config().clone(); - config.compression.digest(layouter, state.clone()) + self.config().compression.digest(layouter, state.clone()) } } @@ -244,7 +262,7 @@ trait Table16Assignment { #[allow(clippy::type_complexity)] fn assign_spread_outputs( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, lookup: &SpreadInputs, a_3: Column, perm: &Permutation, @@ -285,7 +303,7 @@ trait Table16Assignment { #[allow(clippy::too_many_arguments)] fn assign_sigma_outputs( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, lookup: &SpreadInputs, a_3: Column, perm: &Permutation, @@ -305,7 +323,7 @@ trait Table16Assignment { // Assign a cell the same value as another cell and set up a copy constraint between them fn assign_and_constrain( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, annotation: A, column: Column, row: usize, @@ -326,12 +344,11 @@ trait Table16Assignment { #[cfg(test)] mod tests { - #[cfg(feature = "dev-graph")] + use super::super::{BlockWord, Sha256, BLOCK_SIZE}; + use super::{Table16Chip, Table16Config}; use halo2::{ arithmetic::FieldExt, - circuit::Chip, - circuit::{layouter, Layouter}, - gadget::sha256::{BlockWord, Sha256, Table16Chip, Table16Config, BLOCK_SIZE}, + circuit::{layouter::SingleChipLayouter, Layouter}, pasta::Fq, plonk::{Assignment, Circuit, ConstraintSystem, Error}, }; @@ -344,17 +361,18 @@ mod tests { impl Circuit for MyCircuit { type Config = Table16Config; - fn configure(meta: &mut ConstraintSystem) -> Table16Config { + fn configure(meta: &mut ConstraintSystem) -> Self::Config { Table16Chip::configure(meta) } fn synthesize( &self, cs: &mut impl Assignment, - config: Table16Config, + config: Self::Config, ) -> Result<(), Error> { - let mut layouter = layouter::SingleChip::, _>::new(cs, config)?; - Table16Chip::load(&mut layouter)?; + let mut layouter = SingleChipLayouter::new(cs)?; + let table16_chip = Table16Chip::::construct(config.clone()); + Table16Chip::::load(config, &mut layouter)?; // Test vector: "abc" let test_input = [ @@ -381,14 +399,14 @@ mod tests { input.extend_from_slice(&test_input); } - Sha256::digest(layouter.namespace(|| "'abc' * 31"), &input)?; + Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 31"), &input)?; Ok(()) } } let circuit: MyCircuit = MyCircuit {}; - eprintln!("{}", crate::dev::circuit_dot_graph::(&circuit)); + eprintln!("{}", halo2::dev::circuit_dot_graph::(&circuit)); } #[cfg(feature = "dev-graph")] @@ -400,17 +418,18 @@ mod tests { impl Circuit for MyCircuit { type Config = Table16Config; - fn configure(meta: &mut ConstraintSystem) -> Table16Config { + fn configure(meta: &mut ConstraintSystem) -> Self::Config { Table16Chip::configure(meta) } fn synthesize( &self, cs: &mut impl Assignment, - config: Table16Config, + config: Self::Config, ) -> Result<(), Error> { - let mut layouter = layouter::SingleChip::, _>::new(cs, config)?; - Table16Chip::load(&mut layouter)?; + let mut layouter = SingleChipLayouter::new(cs)?; + let table16_chip = Table16Chip::::construct(config.clone()); + Table16Chip::::load(config, &mut layouter)?; // Test vector: "abc" let test_input = [ @@ -437,7 +456,7 @@ mod tests { input.extend_from_slice(&test_input); } - Sha256::digest(layouter.namespace(|| "'abc' * 2"), &input)?; + Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 2"), &input)?; Ok(()) } @@ -451,6 +470,6 @@ mod tests { .unwrap(); let circuit = MyCircuit {}; - crate::dev::circuit_layout::(&circuit, &root).unwrap(); + halo2::dev::circuit_layout::(&circuit, &root).unwrap(); } } diff --git a/examples/sha256/table16/compression.rs b/examples/sha256/table16/compression.rs index 7a70fe5a..e6ae0d4a 100644 --- a/examples/sha256/table16/compression.rs +++ b/examples/sha256/table16/compression.rs @@ -1,6 +1,6 @@ use super::{ super::DIGEST_SIZE, BlockWord, CellValue16, CellValue32, SpreadInputs, SpreadVar, - Table16Assignment, Table16Chip, ROUNDS, STATE, + Table16Assignment, ROUNDS, STATE, }; use halo2::{ arithmetic::FieldExt, @@ -231,7 +231,7 @@ pub enum StateWord { } #[derive(Clone, Debug)] -pub(super) struct Compression { +pub(super) struct CompressionConfig { lookup: SpreadInputs, message_schedule: Column, extras: [Column; 6], @@ -256,9 +256,9 @@ pub(super) struct Compression { perm: Permutation, } -impl Table16Assignment for Compression {} +impl Table16Assignment for CompressionConfig {} -impl Compression { +impl CompressionConfig { pub(super) fn configure( meta: &mut ConstraintSystem, lookup: SpreadInputs, @@ -656,7 +656,7 @@ impl Compression { .0 }); - Compression { + CompressionConfig { lookup, message_schedule, extras, @@ -679,7 +679,7 @@ impl Compression { /// Returns an initialized state. pub(super) fn initialize_with_iv( &self, - layouter: &mut impl Layouter>, + layouter: &mut impl Layouter, init_state: [u32; STATE], ) -> Result { let mut new_state = State::empty_state(); @@ -697,7 +697,7 @@ impl Compression { /// output from a previous compression round. pub(super) fn initialize_with_state( &self, - layouter: &mut impl Layouter>, + layouter: &mut impl Layouter, init_state: State, ) -> Result { let mut new_state = State::empty_state(); @@ -714,7 +714,7 @@ impl Compression { /// Given an initialized state and a message schedule, perform 64 compression rounds. pub(super) fn compress( &self, - layouter: &mut impl Layouter>, + layouter: &mut impl Layouter, initialized_state: State, w_halves: [(CellValue16, CellValue16); ROUNDS], ) -> Result { @@ -736,7 +736,7 @@ impl Compression { /// After the final round, convert the state into the final digest. pub(super) fn digest( &self, - layouter: &mut impl Layouter>, + layouter: &mut impl Layouter, state: State, ) -> Result<[BlockWord; DIGEST_SIZE], Error> { let mut digest = [BlockWord::new(0); DIGEST_SIZE]; @@ -750,65 +750,19 @@ impl Compression { )?; Ok(digest) } - - #[cfg(test)] - pub(super) fn empty_configure( - meta: &mut ConstraintSystem, - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - perm: Permutation, - ) -> Self { - let s_ch = meta.fixed_column(); - let s_ch_neg = meta.fixed_column(); - let s_maj = meta.fixed_column(); - let s_h_prime = meta.fixed_column(); - let s_a_new = meta.fixed_column(); - let s_e_new = meta.fixed_column(); - - let s_upper_sigma_0 = meta.fixed_column(); - let s_upper_sigma_1 = meta.fixed_column(); - - // Decomposition gate for AbcdVar - let s_decompose_abcd = meta.fixed_column(); - // Decomposition gate for EfghVar - let s_decompose_efgh = meta.fixed_column(); - - let s_digest = meta.fixed_column(); - - Compression { - lookup, - message_schedule, - extras, - s_ch, - s_ch_neg, - s_maj, - s_h_prime, - s_a_new, - s_e_new, - s_upper_sigma_0, - s_upper_sigma_1, - s_decompose_abcd, - s_decompose_efgh, - s_digest, - perm, - } - } } #[cfg(test)] mod tests { use super::super::{ - super::BLOCK_SIZE, get_msg_schedule_test_input, BlockWord, MessageSchedule, SpreadTable, - Table16Chip, Table16Config, IV, + super::BLOCK_SIZE, get_msg_schedule_test_input, BlockWord, Table16Chip, Table16Config, IV, }; - use super::Compression; use halo2::{ arithmetic::FieldExt, - circuit::{layouter, Layouter}, + circuit::layouter::SingleChipLayouter, dev::MockProver, pasta::Fp, - plonk::{Assignment, Circuit, ConstraintSystem, Error, Permutation}, + plonk::{Assignment, Circuit, ConstraintSystem, Error}, }; #[test] @@ -819,69 +773,7 @@ mod tests { type Config = Table16Config; fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let a = meta.advice_column(); - let b = meta.advice_column(); - let c = meta.advice_column(); - - let (lookup_inputs, lookup_table) = SpreadTable::configure(meta, a, b, c); - - let message_schedule = meta.advice_column(); - let extras = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // Rename these here for ease of matching the gates to the specification. - let _a_0 = lookup_inputs.tag; - let a_1 = lookup_inputs.dense; - let a_2 = lookup_inputs.spread; - let a_3 = extras[0]; - let a_4 = extras[1]; - let a_5 = message_schedule; - let a_6 = extras[2]; - let a_7 = extras[3]; - let a_8 = extras[4]; - let _a_9 = extras[5]; - - let perm = Permutation::new( - meta, - &[ - a_1.into(), - a_2.into(), - a_3.into(), - a_4.into(), - a_5.into(), - a_6.into(), - a_7.into(), - a_8.into(), - ], - ); - - let compression = Compression::configure( - meta, - lookup_inputs.clone(), - message_schedule, - extras, - perm.clone(), - ); - - let message_schedule = MessageSchedule::configure( - meta, - lookup_inputs.clone(), - message_schedule, - extras, - perm.clone(), - ); - - Table16Config { - lookup_table, - message_schedule, - compression, - } + Table16Chip::configure(meta) } fn synthesize( @@ -889,16 +781,12 @@ mod tests { cs: &mut impl Assignment, config: Self::Config, ) -> Result<(), Error> { - let mut layouter = layouter::SingleChip::, _>::new(cs, config)?; - - // Load table - let table = layouter.config().lookup_table.clone(); - table.load(&mut layouter)?; + let mut layouter = SingleChipLayouter::new(cs)?; + Table16Chip::::load(config.clone(), &mut layouter)?; // Test vector: "abc" let input: [BlockWord; BLOCK_SIZE] = get_msg_schedule_test_input(); - let config = layouter.config().clone(); let (_, w_halves) = config.message_schedule.process(&mut layouter, input)?; let compression = config.compression.clone(); diff --git a/examples/sha256/table16/compression/compression_util.rs b/examples/sha256/table16/compression/compression_util.rs index 31911152..2797f96c 100644 --- a/examples/sha256/table16/compression/compression_util.rs +++ b/examples/sha256/table16/compression/compression_util.rs @@ -1,9 +1,9 @@ use super::super::{ util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, StateWord, Table16Assignment, - Table16Chip, }; use super::{ - AbcdVar, Compression, EfghVar, RoundWordA, RoundWordDense, RoundWordE, RoundWordSpread, State, + AbcdVar, CompressionConfig, EfghVar, RoundWordA, RoundWordDense, RoundWordE, RoundWordSpread, + State, }; use halo2::{ arithmetic::FieldExt, @@ -144,10 +144,10 @@ pub fn get_digest_efgh_row() -> usize { get_digest_abcd_row() + 2 } -impl Compression { +impl CompressionConfig { pub(super) fn decompose_abcd( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, row: usize, a_val: u32, ) -> Result< @@ -191,7 +191,7 @@ impl Compression { pub(super) fn decompose_efgh( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, row: usize, val: u32, ) -> Result< @@ -234,7 +234,7 @@ impl Compression { pub(super) fn decompose_a( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, a_val: u32, ) -> Result { @@ -257,7 +257,7 @@ impl Compression { pub(super) fn decompose_e( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, e_val: u32, ) -> Result { @@ -280,7 +280,7 @@ impl Compression { pub(super) fn assign_upper_sigma_0( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, word: AbcdVar, ) -> Result<(CellValue16, CellValue16), Error> { @@ -385,7 +385,7 @@ impl Compression { pub(super) fn assign_upper_sigma_1( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, word: EfghVar, ) -> Result<(CellValue16, CellValue16), Error> { @@ -490,7 +490,7 @@ impl Compression { fn assign_ch_outputs( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, row: usize, r_0_even: u16, r_0_odd: u16, @@ -516,7 +516,7 @@ impl Compression { pub(super) fn assign_ch( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, spread_halves_e: (CellValue32, CellValue32), spread_halves_f: (CellValue32, CellValue32), @@ -578,7 +578,7 @@ impl Compression { pub(super) fn assign_ch_neg( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, spread_halves_e: (CellValue32, CellValue32), spread_halves_g: (CellValue32, CellValue32), @@ -661,7 +661,7 @@ impl Compression { fn assign_maj_outputs( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, row: usize, r_0_even: u16, r_0_odd: u16, @@ -686,7 +686,7 @@ impl Compression { pub(super) fn assign_maj( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, spread_halves_a: (CellValue32, CellValue32), spread_halves_b: (CellValue32, CellValue32), @@ -771,7 +771,7 @@ impl Compression { #[allow(clippy::too_many_arguments)] pub(super) fn assign_h_prime( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, h: (CellValue16, CellValue16), ch: (CellValue16, CellValue16), @@ -900,7 +900,7 @@ impl Compression { // s_e_new to get E_new = H' + D pub(super) fn assign_e_new( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, d: (CellValue16, CellValue16), h_prime: (CellValue16, CellValue16), @@ -939,7 +939,7 @@ impl Compression { // s_a_new to get A_new = H' + Maj(A, B, C) + s_upper_sigma_0(A) pub(super) fn assign_a_new( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, maj: (CellValue16, CellValue16), sigma_0: (CellValue16, CellValue16), @@ -1026,7 +1026,7 @@ impl Compression { pub fn assign_word_halves_dense( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, lo_row: usize, lo_col: Column, hi_row: usize, @@ -1056,7 +1056,7 @@ impl Compression { #[allow(clippy::type_complexity)] pub fn assign_word_halves( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, row: usize, word: u32, ) -> Result<((CellValue16, CellValue16), (CellValue32, CellValue32)), Error> { diff --git a/examples/sha256/table16/compression/subregion_digest.rs b/examples/sha256/table16/compression/subregion_digest.rs index dd077cfa..4acff7ed 100644 --- a/examples/sha256/table16/compression/subregion_digest.rs +++ b/examples/sha256/table16/compression/subregion_digest.rs @@ -1,16 +1,16 @@ -use super::super::{super::DIGEST_SIZE, BlockWord, CellValue16, Table16Assignment, Table16Chip}; -use super::{compression_util::*, Compression, State}; +use super::super::{super::DIGEST_SIZE, BlockWord, CellValue16, Table16Assignment}; +use super::{compression_util::*, CompressionConfig, State}; use halo2::{ arithmetic::FieldExt, circuit::Region, plonk::{Advice, Column, Error}, }; -impl Compression { +impl CompressionConfig { #[allow(clippy::many_single_char_names)] pub fn assign_digest( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, state: State, ) -> Result<[BlockWord; DIGEST_SIZE], Error> { let a_3 = self.extras[0]; @@ -91,7 +91,7 @@ impl Compression { fn assign_digest_word( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, row: usize, lo_col: Column, hi_col: Column, diff --git a/examples/sha256/table16/compression/subregion_initial.rs b/examples/sha256/table16/compression/subregion_initial.rs index ea1dd3c3..2e398c89 100644 --- a/examples/sha256/table16/compression/subregion_initial.rs +++ b/examples/sha256/table16/compression/subregion_initial.rs @@ -1,12 +1,12 @@ -use super::super::{RoundWordDense, RoundWordSpread, StateWord, Table16Chip, STATE}; -use super::{compression_util::*, Compression, State}; +use super::super::{RoundWordDense, RoundWordSpread, StateWord, STATE}; +use super::{compression_util::*, CompressionConfig, State}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; -impl Compression { +impl CompressionConfig { #[allow(clippy::many_single_char_names)] pub fn initialize_iv( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, iv: [u32; STATE], ) -> Result { let a_7 = self.extras[3]; @@ -52,7 +52,7 @@ impl Compression { #[allow(clippy::many_single_char_names)] pub fn initialize_state( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, state: State, ) -> Result { let a_7 = self.extras[3]; @@ -106,7 +106,7 @@ impl Compression { fn decompose_b( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, b_val: u32, ) -> Result { @@ -119,7 +119,7 @@ impl Compression { fn decompose_c( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, c_val: u32, ) -> Result { @@ -132,7 +132,7 @@ impl Compression { fn decompose_f( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, f_val: u32, ) -> Result { @@ -145,7 +145,7 @@ impl Compression { fn decompose_g( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, g_val: u32, ) -> Result { diff --git a/examples/sha256/table16/compression/subregion_main.rs b/examples/sha256/table16/compression/subregion_main.rs index f2a20450..07829cc7 100644 --- a/examples/sha256/table16/compression/subregion_main.rs +++ b/examples/sha256/table16/compression/subregion_main.rs @@ -1,14 +1,14 @@ use super::super::{ - CellValue16, RoundWordA, RoundWordE, StateWord, Table16Assignment, Table16Chip, ROUND_CONSTANTS, + CellValue16, RoundWordA, RoundWordE, StateWord, Table16Assignment, ROUND_CONSTANTS, }; -use super::{compression_util::*, Compression, State}; +use super::{compression_util::*, CompressionConfig, State}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; -impl Compression { +impl CompressionConfig { #[allow(clippy::many_single_char_names)] pub fn assign_round( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, idx: i32, state: State, schedule_word: (CellValue16, CellValue16), diff --git a/examples/sha256/table16/message_schedule.rs b/examples/sha256/table16/message_schedule.rs index a34b9a63..25879af3 100644 --- a/examples/sha256/table16/message_schedule.rs +++ b/examples/sha256/table16/message_schedule.rs @@ -1,8 +1,6 @@ use std::convert::TryInto; -use super::{ - super::BLOCK_SIZE, BlockWord, CellValue16, SpreadInputs, Table16Assignment, Table16Chip, ROUNDS, -}; +use super::{super::BLOCK_SIZE, BlockWord, CellValue16, SpreadInputs, Table16Assignment, ROUNDS}; use halo2::{ arithmetic::FieldExt, circuit::{Cell, Layouter}, @@ -29,7 +27,7 @@ pub(super) struct MessageWord { } #[derive(Clone, Debug)] -pub(super) struct MessageSchedule { +pub(super) struct MessageScheduleConfig { lookup: SpreadInputs, message_schedule: Column, extras: [Column; 6], @@ -55,9 +53,9 @@ pub(super) struct MessageSchedule { perm: Permutation, } -impl Table16Assignment for MessageSchedule {} +impl Table16Assignment for MessageScheduleConfig {} -impl MessageSchedule { +impl MessageScheduleConfig { /// Configures the message schedule. /// /// `message_schedule` is the column into which the message schedule will be placed. @@ -289,7 +287,7 @@ impl MessageSchedule { .0 }); - MessageSchedule { + MessageScheduleConfig { lookup, message_schedule, extras, @@ -309,7 +307,7 @@ impl MessageSchedule { #[allow(clippy::type_complexity)] pub(super) fn process( &self, - layouter: &mut impl Layouter>, + layouter: &mut impl Layouter, input: [BlockWord; BLOCK_SIZE], ) -> Result<([MessageWord; ROUNDS], [(CellValue16, CellValue16); ROUNDS]), Error> { let mut w = Vec::::with_capacity(ROUNDS); @@ -439,57 +437,18 @@ impl MessageSchedule { Ok((w.try_into().unwrap(), w_halves.try_into().unwrap())) } - - /// Empty configuration without gates. Useful for fast testing - #[cfg(test)] - pub(super) fn empty_configure( - meta: &mut ConstraintSystem, - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - perm: Permutation, - ) -> Self { - // Create fixed columns for the selectors we will require. - let s_word = meta.fixed_column(); - let s_decompose_0 = meta.fixed_column(); - let s_decompose_1 = meta.fixed_column(); - let s_decompose_2 = meta.fixed_column(); - let s_decompose_3 = meta.fixed_column(); - let s_lower_sigma_0 = meta.fixed_column(); - let s_lower_sigma_1 = meta.fixed_column(); - let s_lower_sigma_0_v2 = meta.fixed_column(); - let s_lower_sigma_1_v2 = meta.fixed_column(); - - MessageSchedule { - lookup, - message_schedule, - extras, - s_word, - s_decompose_0, - s_decompose_1, - s_decompose_2, - s_decompose_3, - s_lower_sigma_0, - s_lower_sigma_1, - s_lower_sigma_0_v2, - s_lower_sigma_1_v2, - perm, - } - } } #[cfg(test)] mod tests { - use super::super::{ - super::BLOCK_SIZE, BlockWord, Compression, SpreadTable, Table16Chip, Table16Config, - }; - use super::{schedule_util::*, MessageSchedule}; + use super::super::{super::BLOCK_SIZE, BlockWord, SpreadTableChip, Table16Chip, Table16Config}; + use super::schedule_util::*; use halo2::{ arithmetic::FieldExt, - circuit::{layouter, Layouter}, + circuit::layouter::SingleChipLayouter, dev::MockProver, pasta::Fp, - plonk::{Assignment, Circuit, ConstraintSystem, Error, Permutation}, + plonk::{Assignment, Circuit, ConstraintSystem, Error}, }; #[test] @@ -500,64 +459,7 @@ mod tests { type Config = Table16Config; fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let a = meta.advice_column(); - let b = meta.advice_column(); - let c = meta.advice_column(); - - let (lookup_inputs, lookup_table) = SpreadTable::configure(meta, a, b, c); - - let message_schedule = meta.advice_column(); - let extras = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // Rename these here for ease of matching the gates to the specification. - let _a_0 = lookup_inputs.tag; - let a_1 = lookup_inputs.dense; - let a_2 = lookup_inputs.spread; - let a_3 = extras[0]; - let a_4 = extras[1]; - let a_5 = message_schedule; - let a_6 = extras[2]; - let a_7 = extras[3]; - let a_8 = extras[4]; - let _a_9 = extras[5]; - - let perm = Permutation::new( - meta, - &[ - a_1.into(), - a_2.into(), - a_3.into(), - a_4.into(), - a_5.into(), - a_6.into(), - a_7.into(), - a_8.into(), - ], - ); - - let compression = Compression::empty_configure( - meta, - lookup_inputs.clone(), - message_schedule, - extras, - perm.clone(), - ); - - let message_schedule = - MessageSchedule::configure(meta, lookup_inputs, message_schedule, extras, perm); - - Table16Config { - lookup_table, - message_schedule, - compression, - } + Table16Chip::configure(meta) } fn synthesize( @@ -565,19 +467,17 @@ mod tests { cs: &mut impl Assignment, config: Self::Config, ) -> Result<(), Error> { - let mut layouter = layouter::SingleChip::, _>::new(cs, config)?; + let mut layouter = SingleChipLayouter::new(cs)?; - // Load table - let table = layouter.config().lookup_table.clone(); - table.load(&mut layouter)?; + // Load lookup table + SpreadTableChip::load(config.lookup.clone(), &mut layouter)?; // Provide input // Test vector: "abc" let inputs: [BlockWord; BLOCK_SIZE] = get_msg_schedule_test_input(); // Run message_scheduler to get W_[0..64] - let message_schedule = layouter.config().message_schedule.clone(); - let (w, _) = message_schedule.process(&mut layouter, inputs)?; + let (w, _) = config.message_schedule.process(&mut layouter, inputs)?; for (word, test_word) in w.iter().zip(MSG_SCHEDULE_TEST_OUTPUT.iter()) { let word = word.value.unwrap(); assert_eq!(word, *test_word); diff --git a/examples/sha256/table16/message_schedule/schedule_util.rs b/examples/sha256/table16/message_schedule/schedule_util.rs index daa4706b..cdd43f63 100644 --- a/examples/sha256/table16/message_schedule/schedule_util.rs +++ b/examples/sha256/table16/message_schedule/schedule_util.rs @@ -1,5 +1,5 @@ -use super::super::{CellValue16, Table16Chip}; -use super::MessageSchedule; +use super::super::CellValue16; +use super::MessageScheduleConfig; use halo2::{ arithmetic::FieldExt, circuit::{Cell, Region}, @@ -148,11 +148,11 @@ pub const MSG_SCHEDULE_TEST_OUTPUT: [u32; ROUNDS] = [ 0b00010010101100011110110111101011, ]; -impl MessageSchedule { +impl MessageScheduleConfig { // Assign a word and its hi and lo halves pub fn assign_word_and_halves( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, word: u32, word_idx: usize, ) -> Result<(Cell, (CellValue16, CellValue16)), Error> { diff --git a/examples/sha256/table16/message_schedule/subregion1.rs b/examples/sha256/table16/message_schedule/subregion1.rs index ab101a96..537bf00f 100644 --- a/examples/sha256/table16/message_schedule/subregion1.rs +++ b/examples/sha256/table16/message_schedule/subregion1.rs @@ -1,8 +1,7 @@ use super::super::{ util::*, BlockWord, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment, - Table16Chip, }; -use super::{schedule_util::*, MessageSchedule}; +use super::{schedule_util::*, MessageScheduleConfig}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; // A word in subregion 1 @@ -18,10 +17,10 @@ pub struct Subregion1Word { spread_d: CellValue32, } -impl MessageSchedule { +impl MessageScheduleConfig { pub fn assign_subregion1( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, input: &[BlockWord], ) -> Result, Error> { assert_eq!(input.len(), SUBREGION_1_LEN); @@ -42,7 +41,7 @@ impl MessageSchedule { fn decompose_subregion1_word( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, word: u32, index: usize, ) -> Result { @@ -92,7 +91,7 @@ impl MessageSchedule { // (3, 4, 11, 14)-bit chunks fn lower_sigma_0( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, word: Subregion1Word, ) -> Result<(CellValue16, CellValue16), Error> { let a_3 = self.extras[0]; diff --git a/examples/sha256/table16/message_schedule/subregion2.rs b/examples/sha256/table16/message_schedule/subregion2.rs index 3cec400c..cae59678 100644 --- a/examples/sha256/table16/message_schedule/subregion2.rs +++ b/examples/sha256/table16/message_schedule/subregion2.rs @@ -1,7 +1,5 @@ -use super::super::{ - util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment, Table16Chip, -}; -use super::{schedule_util::*, MessageSchedule, MessageWord}; +use super::super::{util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment}; +use super::{schedule_util::*, MessageScheduleConfig, MessageWord}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; // A word in subregion 2 @@ -20,11 +18,11 @@ pub struct Subregion2Word { spread_g: CellValue32, } -impl MessageSchedule { +impl MessageScheduleConfig { // W_[14..49] pub fn assign_subregion2( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, lower_sigma_0_output: Vec<(CellValue16, CellValue16)>, w: &mut Vec, w_halves: &mut Vec<(CellValue16, CellValue16)>, @@ -171,7 +169,7 @@ impl MessageSchedule { fn decompose_subregion2_word( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, word: u32, index: usize, ) -> Result { @@ -224,7 +222,7 @@ impl MessageSchedule { #[allow(clippy::type_complexity)] fn assign_lower_sigma_v2_pieces( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, row: usize, subregion2_word: Subregion2Word, ) -> Result<(u64, u64, u64, u64, u64, u64, u64, u64), Error> { @@ -323,7 +321,7 @@ impl MessageSchedule { fn lower_sigma_0_v2( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, subregion2_word: Subregion2Word, ) -> Result<(CellValue16, CellValue16), Error> { let a_3 = self.extras[0]; @@ -378,7 +376,7 @@ impl MessageSchedule { fn lower_sigma_1_v2( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, subregion2_word: Subregion2Word, ) -> Result<(CellValue16, CellValue16), Error> { let a_3 = self.extras[0]; diff --git a/examples/sha256/table16/message_schedule/subregion3.rs b/examples/sha256/table16/message_schedule/subregion3.rs index 8cf3035d..2851ddd0 100644 --- a/examples/sha256/table16/message_schedule/subregion3.rs +++ b/examples/sha256/table16/message_schedule/subregion3.rs @@ -1,7 +1,5 @@ -use super::super::{ - util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment, Table16Chip, -}; -use super::{schedule_util::*, MessageSchedule, MessageWord}; +use super::super::{util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment}; +use super::{schedule_util::*, MessageScheduleConfig, MessageWord}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; // A word in subregion 3 @@ -18,11 +16,11 @@ pub struct Subregion3Word { spread_d: CellValue32, } -impl MessageSchedule { +impl MessageScheduleConfig { // W_[49..62] pub fn assign_subregion3( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, lower_sigma_0_v2_output: Vec<(CellValue16, CellValue16)>, w: &mut Vec, w_halves: &mut Vec<(CellValue16, CellValue16)>, @@ -150,7 +148,7 @@ impl MessageSchedule { fn decompose_subregion3_word( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, word: u32, index: usize, ) -> Result { @@ -189,7 +187,7 @@ impl MessageSchedule { fn lower_sigma_1( &self, - region: &mut Region<'_, Table16Chip>, + region: &mut Region<'_, F>, word: Subregion3Word, ) -> Result<(CellValue16, CellValue16), Error> { let a_3 = self.extras[0]; diff --git a/examples/sha256/table16/spread_table.rs b/examples/sha256/table16/spread_table.rs index df0f8a79..90df3839 100644 --- a/examples/sha256/table16/spread_table.rs +++ b/examples/sha256/table16/spread_table.rs @@ -1,10 +1,11 @@ -use super::{util::*, CellValue16, CellValue32, Table16Chip}; +use super::{util::*, CellValue16, CellValue32}; use halo2::{ arithmetic::FieldExt, circuit::{Chip, Layouter, Region}, plonk::{Advice, Column, ConstraintSystem, Error, Fixed}, poly::Rotation, }; +use std::marker::PhantomData; /// An input word into a lookup, containing (tag, dense, spread) #[derive(Copy, Clone, Debug)] @@ -24,7 +25,7 @@ impl SpreadWord { } } -/// A variable stored in advice columns corresponding to a row of [`SpreadTable`]. +/// A variable stored in advice columns corresponding to a row of [`SpreadTableConfig`]. #[derive(Copy, Clone, Debug)] pub(super) struct SpreadVar { pub tag: u8, @@ -33,8 +34,8 @@ pub(super) struct SpreadVar { } impl SpreadVar { - pub(super) fn with_lookup<'r, C: Chip>( - region: &mut Region<'r, C>, + pub(super) fn with_lookup( + region: &mut Region<'_, F>, cols: &SpreadInputs, row: usize, word: SpreadWord, @@ -42,19 +43,14 @@ impl SpreadVar { let tag = word.tag; let dense_val = Some(word.dense); let spread_val = Some(word.spread); - region.assign_advice( - || "tag", - cols.tag, - row, - || Ok(C::Field::from_u64(tag as u64)), - )?; + region.assign_advice(|| "tag", cols.tag, row, || Ok(F::from_u64(tag as u64)))?; let dense_var = region.assign_advice( || "dense", cols.dense, row, || { dense_val - .map(|v| C::Field::from_u64(v as u64)) + .map(|v| F::from_u64(v as u64)) .ok_or(Error::SynthesisError) }, )?; @@ -64,7 +60,7 @@ impl SpreadVar { row, || { spread_val - .map(|v| C::Field::from_u64(v as u64)) + .map(|v| F::from_u64(v as u64)) .ok_or(Error::SynthesisError) }, )?; @@ -76,8 +72,8 @@ impl SpreadVar { }) } - pub(super) fn without_lookup( - region: &mut Region<'_, C>, + pub(super) fn without_lookup( + region: &mut Region<'_, F>, dense_col: Column, dense_row: usize, spread_col: Column, @@ -93,7 +89,7 @@ impl SpreadVar { dense_row, || { dense_val - .map(|v| C::Field::from_u64(v as u64)) + .map(|v| F::from_u64(v as u64)) .ok_or(Error::SynthesisError) }, )?; @@ -103,7 +99,7 @@ impl SpreadVar { spread_row, || { spread_val - .map(|v| C::Field::from_u64(v as u64)) + .map(|v| F::from_u64(v as u64)) .ok_or(Error::SynthesisError) }, )?; @@ -125,43 +121,116 @@ pub(super) struct SpreadInputs { #[derive(Clone, Debug)] pub(super) struct SpreadTable { - table_tag: Column, - table_dense: Column, - table_spread: Column, + pub(super) tag: Column, + pub(super) dense: Column, + pub(super) spread: Column, } -impl SpreadTable { - pub(super) fn configure( +#[derive(Clone, Debug)] +pub(super) struct SpreadTableConfig { + pub input: SpreadInputs, + pub table: SpreadTable, +} + +#[derive(Clone, Debug)] +pub(super) struct SpreadTableChip { + config: SpreadTableConfig, + _marker: PhantomData, +} + +impl Chip for SpreadTableChip { + type Config = SpreadTableConfig; + type Loaded = (); + + fn config(&self) -> &Self::Config { + &self.config + } + + fn loaded(&self) -> &Self::Loaded { + &() + } +} + +impl SpreadTableChip { + pub fn configure( meta: &mut ConstraintSystem, - tag: Column, - dense: Column, - spread: Column, - ) -> (SpreadInputs, Self) { + input_tag: Column, + input_dense: Column, + input_spread: Column, + ) -> >::Config { let table_tag = meta.fixed_column(); let table_dense = meta.fixed_column(); let table_spread = meta.fixed_column(); - let tag_ = meta.query_any(tag.into(), Rotation::cur()); - let dense_ = meta.query_any(dense.into(), Rotation::cur()); - let spread_ = meta.query_any(spread.into(), Rotation::cur()); - let table_tag_ = meta.query_any(table_tag.into(), Rotation::cur()); - let table_dense_ = meta.query_any(table_dense.into(), Rotation::cur()); - let table_spread_ = meta.query_any(table_spread.into(), Rotation::cur()); + let tag_cur = meta.query_advice(input_tag, Rotation::cur()); + let dense_cur = meta.query_advice(input_dense, Rotation::cur()); + let spread_cur = meta.query_advice(input_spread, Rotation::cur()); + let table_tag_cur = meta.query_fixed(table_tag, Rotation::cur()); + let table_dense_cur = meta.query_fixed(table_dense, Rotation::cur()); + let table_spread_cur = meta.query_fixed(table_spread, Rotation::cur()); meta.lookup( - &[tag_, dense_, spread_], - &[table_tag_, table_dense_, table_spread_], + &[tag_cur, dense_cur, spread_cur], + &[table_tag_cur, table_dense_cur, table_spread_cur], ); - ( - SpreadInputs { tag, dense, spread }, - SpreadTable { - table_tag, - table_dense, - table_spread, + SpreadTableConfig { + input: SpreadInputs { + tag: input_tag, + dense: input_dense, + spread: input_spread, + }, + table: SpreadTable { + tag: table_tag, + dense: table_dense, + spread: table_spread, + }, + } + } + + pub fn load( + config: SpreadTableConfig, + layouter: &mut impl Layouter, + ) -> Result<>::Loaded, Error> { + layouter.assign_region( + || "spread table", + |mut gate| { + // We generate the row values lazily (we only need them during keygen). + let mut rows = SpreadTableConfig::generate::(); + + for index in 0..(1 << 16) { + let mut row = None; + gate.assign_fixed( + || "tag", + config.table.tag, + index, + || { + row = rows.next(); + row.map(|(tag, _, _)| tag).ok_or(Error::SynthesisError) + }, + )?; + gate.assign_fixed( + || "dense", + config.table.dense, + index, + || row.map(|(_, dense, _)| dense).ok_or(Error::SynthesisError), + )?; + gate.assign_fixed( + || "spread", + config.table.spread, + index, + || { + row.map(|(_, _, spread)| spread) + .ok_or(Error::SynthesisError) + }, + )?; + } + Ok(()) }, ) } +} +impl SpreadTableConfig { fn generate() -> impl Iterator { (1..=(1 << 16)).scan( (F::zero(), F::zero(), F::zero()), @@ -192,70 +261,20 @@ impl SpreadTable { }, ) } - - pub(super) fn load( - &self, - layouter: &mut impl Layouter>, - ) -> Result<(), Error> { - layouter.assign_region( - || "spread table", - |mut gate| { - // We generate the row values lazily (we only need them during keygen). - let mut rows = Self::generate::(); - - for index in 0..(1 << 16) { - let mut row = None; - gate.assign_fixed( - || "tag", - self.table_tag, - index, - || { - row = rows.next(); - row.map(|(tag, _, _)| tag).ok_or(Error::SynthesisError) - }, - )?; - gate.assign_fixed( - || "dense", - self.table_dense, - index, - || row.map(|(_, dense, _)| dense).ok_or(Error::SynthesisError), - )?; - gate.assign_fixed( - || "spread", - self.table_spread, - index, - || { - row.map(|(_, _, spread)| spread) - .ok_or(Error::SynthesisError) - }, - )?; - } - Ok(()) - }, - ) - } } #[cfg(test)] mod tests { + use super::{SpreadTableChip, SpreadTableConfig}; use rand::Rng; - use std::cmp; - use std::collections::HashMap; - use std::fmt; - use std::marker::PhantomData; - use super::{ - super::{util::*, Compression, MessageSchedule, Table16Chip, Table16Config}, - SpreadInputs, SpreadTable, - }; + use crate::table16::util::{get_tag, interleave_u16_with_zeros}; use halo2::{ arithmetic::FieldExt, - circuit::{layouter, Cell, Layouter, Region, RegionIndex}, + circuit::{layouter::SingleChipLayouter, Layouter}, dev::MockProver, pasta::Fp, - plonk::{ - Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Error, Fixed, Permutation, - }, + plonk::{Advice, Assignment, Circuit, Column, ConstraintSystem, Error}, }; #[test] @@ -264,298 +283,40 @@ mod tests { #[derive(Copy, Clone, Debug)] pub struct Variable(Column, usize); - #[derive(Clone, Debug)] - struct MyConfig { - lookup_inputs: SpreadInputs, - sha256: Table16Config, - } - struct MyCircuit {} - struct MyLayouter<'a, F: FieldExt, CS: Assignment + 'a> { - cs: &'a mut CS, - config: MyConfig, - regions: Vec, - /// Stores the first empty row for each column. - columns: HashMap, usize>, - _marker: PhantomData, - } - - impl<'a, F: FieldExt, CS: Assignment + 'a> fmt::Debug for MyLayouter<'a, F, CS> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MyLayouter") - .field("config", &self.config) - .field("regions", &self.regions) - .field("columns", &self.columns) - .finish() - } - } - - impl<'a, FF: FieldExt, CS: Assignment> MyLayouter<'a, FF, CS> { - fn new(cs: &'a mut CS, config: MyConfig) -> Result { - let mut res = MyLayouter { - cs, - config, - regions: vec![], - columns: HashMap::default(), - _marker: PhantomData, - }; - - let table = res.config.sha256.lookup_table.clone(); - table.load(&mut res)?; - - Ok(res) - } - } - - impl<'a, F: FieldExt, CS: Assignment + 'a> Layouter> for MyLayouter<'a, F, CS> { - type Root = Self; - - fn config(&self) -> &Table16Config { - &self.config.sha256 - } - - fn loaded(&self) -> &() { - &() - } - - fn assign_region( - &mut self, - name: N, - mut assignment: A, - ) -> Result - where - A: FnMut(Region<'_, Table16Chip>) -> Result, - N: Fn() -> NR, - NR: Into, - { - let region_index = self.regions.len(); - - // Get shape of the region. - let mut shape = layouter::RegionShape::new(region_index.into()); - { - let region: &mut dyn layouter::RegionLayouter> = &mut shape; - assignment(region.into())?; - } - - // Lay out this region. We implement the simplest approach here: position the - // region starting at the earliest row for which none of the columns are in use. - let mut region_start = 0; - for column in shape.columns() { - region_start = - cmp::max(region_start, self.columns.get(column).cloned().unwrap_or(0)); - } - self.regions.push(region_start); - - // Update column usage information. - for column in shape.columns() { - self.columns - .insert(*column, region_start + shape.row_count()); - } - - self.cs.enter_region(name); - let mut region = MyRegion::new(self, region_index.into()); - let result = { - let region: &mut dyn layouter::RegionLayouter> = &mut region; - assignment(region.into()) - }?; - self.cs.exit_region(); - - Ok(result) - } - - fn get_root(&mut self) -> &mut Self::Root { - self - } - - fn push_namespace(&mut self, name_fn: N) - where - NR: Into, - N: FnOnce() -> NR, - { - self.cs.push_namespace(name_fn) - } - - fn pop_namespace(&mut self, gadget_name: Option) { - self.cs.pop_namespace(gadget_name) - } - } - - struct MyRegion<'r, 'a, F: FieldExt, CS: Assignment + 'a> { - layouter: &'r mut MyLayouter<'a, F, CS>, - region_index: RegionIndex, - _marker: PhantomData, - } - - impl<'r, 'a, F: FieldExt, CS: Assignment + 'a> fmt::Debug for MyRegion<'r, 'a, F, CS> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("MyRegion") - .field("layouter", &self.layouter) - .field("region_index", &self.region_index) - .finish() - } - } - - impl<'r, 'a, F: FieldExt, CS: Assignment + 'a> MyRegion<'r, 'a, F, CS> { - fn new(layouter: &'r mut MyLayouter<'a, F, CS>, region_index: RegionIndex) -> Self { - MyRegion { - layouter, - region_index, - _marker: PhantomData::default(), - } - } - } - - impl<'r, 'a, F: FieldExt, CS: Assignment + 'a> layouter::RegionLayouter> - for MyRegion<'r, 'a, F, CS> - { - fn assign_advice<'v>( - &'v mut self, - annotation: &'v (dyn Fn() -> String + 'v), - column: Column, - offset: usize, - to: &'v mut (dyn FnMut() -> Result + 'v), - ) -> Result { - self.layouter.cs.assign_advice( - annotation, - column, - self.layouter.regions[*self.region_index] + offset, - to, - )?; - - Ok(Cell { - region_index: self.region_index, - row_offset: offset, - column: column.into(), - }) - } - - fn assign_fixed<'v>( - &'v mut self, - annotation: &'v (dyn Fn() -> String + 'v), - column: Column, - offset: usize, - to: &'v mut (dyn FnMut() -> Result + 'v), - ) -> Result { - self.layouter.cs.assign_fixed( - annotation, - column, - self.layouter.regions[*self.region_index] + offset, - to, - )?; - Ok(Cell { - region_index: self.region_index, - row_offset: offset, - column: column.into(), - }) - } - - fn constrain_equal( - &mut self, - permutation: &Permutation, - left: Cell, - right: Cell, - ) -> Result<(), Error> { - self.layouter.cs.copy( - permutation, - left.column, - self.layouter.regions[*left.region_index] + left.row_offset, - right.column, - self.layouter.regions[*right.region_index] + right.row_offset, - )?; - - Ok(()) - } - } - impl Circuit for MyCircuit { - type Config = MyConfig; + type Config = SpreadTableConfig; - fn configure(meta: &mut ConstraintSystem) -> MyConfig { - let a = meta.advice_column(); - let b = meta.advice_column(); - let c = meta.advice_column(); + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let input_tag = meta.advice_column(); + let input_dense = meta.advice_column(); + let input_spread = meta.advice_column(); - let (lookup_inputs, lookup_table) = SpreadTable::configure(meta, a, b, c); - - let message_schedule = meta.advice_column(); - let extras = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // Rename these here for ease of matching the gates to the specification. - let _a_0 = lookup_inputs.tag; - let a_1 = lookup_inputs.dense; - let a_2 = lookup_inputs.spread; - let a_3 = extras[0]; - let a_4 = extras[1]; - let a_5 = message_schedule; - let a_6 = extras[2]; - let a_7 = extras[3]; - let a_8 = extras[4]; - let _a_9 = extras[5]; - - let perm = Permutation::new( - meta, - &[ - a_1.into(), - a_2.into(), - a_3.into(), - a_4.into(), - a_5.into(), - a_6.into(), - a_7.into(), - a_8.into(), - ], - ); - - let compression = Compression::empty_configure( - meta, - lookup_inputs.clone(), - message_schedule, - extras, - perm.clone(), - ); - - let message_schedule = MessageSchedule::empty_configure( - meta, - lookup_inputs.clone(), - message_schedule, - extras, - perm.clone(), - ); - - MyConfig { - lookup_inputs, - sha256: Table16Config { - lookup_table, - message_schedule, - compression, - }, - } + SpreadTableChip::configure(meta, input_tag, input_dense, input_spread) } fn synthesize( &self, cs: &mut impl Assignment, - config: MyConfig, + config: Self::Config, ) -> Result<(), Error> { - let lookup = config.lookup_inputs.clone(); - let mut layouter = MyLayouter::new(cs, config)?; + let mut layouter = SingleChipLayouter::new(cs)?; + SpreadTableChip::load(config.clone(), &mut layouter)?; layouter.assign_region( || "spread_test", |mut gate| { let mut row = 0; let mut add_row = |tag, dense, spread| { - gate.assign_advice(|| "tag", lookup.tag, row, || Ok(tag))?; - gate.assign_advice(|| "dense", lookup.dense, row, || Ok(dense))?; - gate.assign_advice(|| "spread", lookup.spread, row, || Ok(spread))?; + gate.assign_advice(|| "tag", config.input.tag, row, || Ok(tag))?; + gate.assign_advice(|| "dense", config.input.dense, row, || Ok(dense))?; + gate.assign_advice( + || "spread", + config.input.spread, + row, + || Ok(spread), + )?; row += 1; Ok(()) };