Fix SHA256 example

This commit is contained in:
therealyingtong 2021-04-20 19:26:32 +08:00
parent cae6f6af72
commit fe2ab0bc7b
14 changed files with 331 additions and 760 deletions

View File

@ -1,7 +1,6 @@
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
circuit::Chip, circuit::{layouter::SingleChipLayouter, Layouter},
circuit::{layouter, Layouter},
pasta::EqAffine, pasta::EqAffine,
plonk::{ plonk::{
create_proof, keygen_pk, keygen_vk, verify_proof, Assignment, Circuit, ConstraintSystem, 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<F: FieldExt> Circuit<F> for MyCircuit { impl<F: FieldExt> Circuit<F> for MyCircuit {
type Config = Table16Config; type Config = Table16Config;
fn configure(meta: &mut ConstraintSystem<F>) -> Table16Config { fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
Table16Chip::configure(meta) Table16Chip::configure(meta)
} }
fn synthesize( fn synthesize(
&self, &self,
cs: &mut impl Assignment<F>, cs: &mut impl Assignment<F>,
config: Table16Config, config: Self::Config,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::new(cs, config)?; let mut layouter = SingleChipLayouter::new(cs)?;
Table16Chip::load(&mut layouter)?; Table16Chip::<F>::load(config.clone(), &mut layouter)?;
let table16_chip = Table16Chip::<F>::construct(config);
// Test vector: "abc" // Test vector: "abc"
let test_input = [ let test_input = [
@ -65,7 +65,7 @@ fn bench(name: &str, k: u32, c: &mut Criterion) {
input.extend_from_slice(&test_input); input.extend_from_slice(&test_input);
} }
Sha256::digest(layouter.namespace(|| "test vector"), &input)?; Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 2"), &input)?;
Ok(()) Ok(())
} }

View File

@ -2,12 +2,12 @@
//! //!
//! [SHA-256]: https://tools.ietf.org/html/rfc6234 //! [SHA-256]: https://tools.ietf.org/html/rfc6234
/*
use std::cmp::min; use std::cmp::min;
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt; use std::fmt;
use halo2::{ use halo2::{
arithmetic::FieldExt,
circuit::{Chip, Layouter}, circuit::{Chip, Layouter},
plonk::Error, plonk::Error,
}; };
@ -23,7 +23,7 @@ pub const BLOCK_SIZE: usize = 16;
const DIGEST_SIZE: usize = 8; const DIGEST_SIZE: usize = 8;
/// The set of circuit instructions required to use the [`Sha256`] gadget. /// The set of circuit instructions required to use the [`Sha256`] gadget.
pub trait Sha256Instructions: Chip { pub trait Sha256Instructions<F: FieldExt>: Chip<F> {
/// Variable representing the SHA-256 internal state. /// Variable representing the SHA-256 internal state.
type State: Clone + fmt::Debug; type State: Clone + fmt::Debug;
/// Variable representing a 32-bit word of the input block to the SHA-256 compression /// 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; fn zero() -> Self::BlockWord;
/// Places the SHA-256 IV in the circuit, returning the initial state variable. /// Places the SHA-256 IV in the circuit, returning the initial state variable.
fn initialization_vector(layouter: &mut impl Layouter<Self>) -> Result<Self::State, Error>; fn initialization_vector(&self, layouter: &mut impl Layouter<F>) -> Result<Self::State, Error>;
/// Creates an initial state from the output state of a previous block /// Creates an initial state from the output state of a previous block
fn initialization( fn initialization(
layouter: &mut impl Layouter<Self>, &self,
layouter: &mut impl Layouter<F>,
init_state: &Self::State, init_state: &Self::State,
) -> Result<Self::State, Error>; ) -> Result<Self::State, Error>;
/// Starting from the given initialized state, processes a block of input and returns the /// Starting from the given initialized state, processes a block of input and returns the
/// final state. /// final state.
fn compress( fn compress(
layouter: &mut impl Layouter<Self>, &self,
layouter: &mut impl Layouter<F>,
initialized_state: &Self::State, initialized_state: &Self::State,
input: [Self::BlockWord; BLOCK_SIZE], input: [Self::BlockWord; BLOCK_SIZE],
) -> Result<Self::State, Error>; ) -> Result<Self::State, Error>;
/// Converts the given state into a message digest. /// Converts the given state into a message digest.
fn digest( fn digest(
layouter: &mut impl Layouter<Self>, &self,
layouter: &mut impl Layouter<F>,
state: &Self::State, state: &Self::State,
) -> Result<[Self::BlockWord; DIGEST_SIZE], Error>; ) -> Result<[Self::BlockWord; DIGEST_SIZE], Error>;
} }
@ -64,17 +67,20 @@ pub struct Sha256Digest<BlockWord>([BlockWord; DIGEST_SIZE]);
/// A gadget that constrains a SHA-256 invocation. It supports input at a granularity of /// A gadget that constrains a SHA-256 invocation. It supports input at a granularity of
/// 32 bits. /// 32 bits.
#[derive(Debug)] #[derive(Debug)]
pub struct Sha256<CS: Sha256Instructions> { pub struct Sha256<F: FieldExt, CS: Sha256Instructions<F>> {
chip: CS,
state: CS::State, state: CS::State,
cur_block: Vec<CS::BlockWord>, cur_block: Vec<CS::BlockWord>,
length: usize, length: usize,
} }
impl<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> { impl<F: FieldExt, Sha256Chip: Sha256Instructions<F>> Sha256<F, Sha256Chip> {
/// Create a new hasher instance. /// Create a new hasher instance.
pub fn new(mut layouter: impl Layouter<Sha256Chip>) -> Result<Self, Error> { pub fn new(chip: Sha256Chip, mut layouter: impl Layouter<F>) -> Result<Self, Error> {
let state = chip.initialization_vector(&mut layouter)?;
Ok(Sha256 { Ok(Sha256 {
state: Sha256Chip::initialization_vector(&mut layouter)?, chip,
state,
cur_block: Vec::with_capacity(BLOCK_SIZE), cur_block: Vec::with_capacity(BLOCK_SIZE),
length: 0, length: 0,
}) })
@ -83,7 +89,7 @@ impl<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
/// Digest data, updating the internal state. /// Digest data, updating the internal state.
pub fn update( pub fn update(
&mut self, &mut self,
mut layouter: impl Layouter<Sha256Chip>, mut layouter: impl Layouter<F>,
mut data: &[Sha256Chip::BlockWord], mut data: &[Sha256Chip::BlockWord],
) -> Result<(), Error> { ) -> Result<(), Error> {
self.length += data.len() * 32; self.length += data.len() * 32;
@ -100,7 +106,7 @@ impl<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
} }
// Process the now-full current block. // Process the now-full current block.
self.state = Sha256Chip::compress( self.state = self.chip.compress(
&mut layouter, &mut layouter,
&self.state, &self.state,
self.cur_block[..] self.cur_block[..]
@ -112,8 +118,8 @@ impl<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
// Process any additional full blocks. // Process any additional full blocks.
let mut chunks_iter = data.chunks_exact(BLOCK_SIZE); let mut chunks_iter = data.chunks_exact(BLOCK_SIZE);
for chunk in &mut chunks_iter { for chunk in &mut chunks_iter {
self.state = Sha256Chip::initialization(&mut layouter, &self.state)?; self.state = self.chip.initialization(&mut layouter, &self.state)?;
self.state = Sha256Chip::compress( self.state = self.chip.compress(
&mut layouter, &mut layouter,
&self.state, &self.state,
chunk.try_into().expect("chunk.len() == BLOCK_SIZE"), chunk.try_into().expect("chunk.len() == BLOCK_SIZE"),
@ -130,14 +136,14 @@ impl<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
/// Retrieve result and consume hasher instance. /// Retrieve result and consume hasher instance.
pub fn finalize( pub fn finalize(
mut self, mut self,
mut layouter: impl Layouter<Sha256Chip>, mut layouter: impl Layouter<F>,
) -> Result<Sha256Digest<Sha256Chip::BlockWord>, Error> { ) -> Result<Sha256Digest<Sha256Chip::BlockWord>, Error> {
// Pad the remaining block // Pad the remaining block
if !self.cur_block.is_empty() { if !self.cur_block.is_empty() {
let padding = vec![Sha256Chip::zero(); BLOCK_SIZE - self.cur_block.len()]; let padding = vec![Sha256Chip::zero(); BLOCK_SIZE - self.cur_block.len()];
self.cur_block.extend_from_slice(&padding); self.cur_block.extend_from_slice(&padding);
self.state = Sha256Chip::initialization(&mut layouter, &self.state)?; self.state = self.chip.initialization(&mut layouter, &self.state)?;
self.state = Sha256Chip::compress( self.state = self.chip.compress(
&mut layouter, &mut layouter,
&self.state, &self.state,
self.cur_block[..] self.cur_block[..]
@ -145,20 +151,22 @@ impl<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
.expect("cur_block.len() == BLOCK_SIZE"), .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, /// Convenience function to compute hash of the data. It will handle hasher creation,
/// data feeding and finalization. /// data feeding and finalization.
pub fn digest( pub fn digest(
mut layouter: impl Layouter<Sha256Chip>, chip: Sha256Chip,
mut layouter: impl Layouter<F>,
data: &[Sha256Chip::BlockWord], data: &[Sha256Chip::BlockWord],
) -> Result<Sha256Digest<Sha256Chip::BlockWord>, Error> { ) -> Result<Sha256Digest<Sha256Chip::BlockWord>, 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.update(layouter.namespace(|| "update"), data)?;
hasher.finalize(layouter.namespace(|| "finalize")) hasher.finalize(layouter.namespace(|| "finalize"))
} }
} }
*/
fn main() {} fn main() {}

View File

@ -100,26 +100,41 @@ impl Into<CellValue32> for CellValue16 {
/// Configuration for a [`Table16Chip`]. /// Configuration for a [`Table16Chip`].
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Table16Config { pub struct Table16Config {
lookup_table: SpreadTable, lookup: SpreadTableConfig,
message_schedule: MessageSchedule, message_schedule: MessageScheduleConfig,
compression: Compression, compression: CompressionConfig,
} }
/// A chip that implements SHA-256 with a maximum lookup table size of $2^16$. /// A chip that implements SHA-256 with a maximum lookup table size of $2^16$.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Table16Chip<F: FieldExt> { pub struct Table16Chip<F: FieldExt> {
config: Table16Config,
_marker: PhantomData<F>, _marker: PhantomData<F>,
} }
impl<F: FieldExt> Table16Chip<F> { impl<F: FieldExt> Chip<F> for Table16Chip<F> {
/// Configures this chip for use in a circuit. type Config = Table16Config;
pub fn configure(meta: &mut ConstraintSystem<F>) -> Table16Config { type Loaded = ();
// 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();
fn config(&self) -> &Self::Config {
&self.config
}
fn loaded(&self) -> &Self::Loaded {
&()
}
}
impl<F: FieldExt> Table16Chip<F> {
pub fn construct(config: <Self as Chip<F>>::Config) -> Self {
Self {
config,
_marker: PhantomData,
}
}
pub fn configure(meta: &mut ConstraintSystem<F>) -> <Self as Chip<F>>::Config {
// Columns required by this chip:
let message_schedule = meta.advice_column(); let message_schedule = meta.advice_column();
let extras = [ let extras = [
meta.advice_column(), meta.advice_column(),
@ -130,7 +145,13 @@ impl<F: FieldExt> Table16Chip<F> {
meta.advice_column(), 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. // Rename these here for ease of matching the gates to the specification.
let _a_0 = lookup_inputs.tag; let _a_0 = lookup_inputs.tag;
@ -158,7 +179,7 @@ impl<F: FieldExt> Table16Chip<F> {
], ],
); );
let compression = Compression::configure( let compression = CompressionConfig::configure(
meta, meta,
lookup_inputs.clone(), lookup_inputs.clone(),
message_schedule, message_schedule,
@ -166,29 +187,27 @@ impl<F: FieldExt> Table16Chip<F> {
perm.clone(), perm.clone(),
); );
let message_schedule = let message_schedule = MessageScheduleConfig::configure(
MessageSchedule::configure(meta, lookup_inputs, message_schedule, extras, perm); meta,
lookup_inputs.clone(),
message_schedule,
extras,
perm,
);
Table16Config { Table16Config {
lookup_table, lookup,
message_schedule, message_schedule,
compression, compression,
} }
} }
}
impl<F: FieldExt> Chip for Table16Chip<F> { pub fn load(config: Table16Config, layouter: &mut impl Layouter<F>) -> Result<(), Error> {
type Field = F; SpreadTableChip::load(config.lookup, layouter)
type Config = Table16Config;
type Loaded = ();
fn load(layouter: &mut impl Layouter<Self>) -> Result<(), Error> {
let table = layouter.config().lookup_table.clone();
table.load(layouter)
} }
} }
impl<F: FieldExt> Sha256Instructions for Table16Chip<F> { impl<F: FieldExt> Sha256Instructions<F> for Table16Chip<F> {
type State = State; type State = State;
type BlockWord = BlockWord; type BlockWord = BlockWord;
@ -196,17 +215,16 @@ impl<F: FieldExt> Sha256Instructions for Table16Chip<F> {
BlockWord::new(0) BlockWord::new(0)
} }
fn initialization_vector(layouter: &mut impl Layouter<Self>) -> Result<State, Error> { fn initialization_vector(&self, layouter: &mut impl Layouter<F>) -> Result<State, Error> {
let config = layouter.config().clone(); self.config().compression.initialize_with_iv(layouter, IV)
config.compression.initialize_with_iv(layouter, IV)
} }
fn initialization( fn initialization(
layouter: &mut impl Layouter<Table16Chip<F>>, &self,
layouter: &mut impl Layouter<F>,
init_state: &Self::State, init_state: &Self::State,
) -> Result<Self::State, Error> { ) -> Result<Self::State, Error> {
let config = layouter.config().clone(); self.config()
config
.compression .compression
.initialize_with_state(layouter, init_state.clone()) .initialize_with_state(layouter, init_state.clone())
} }
@ -214,26 +232,26 @@ impl<F: FieldExt> Sha256Instructions for Table16Chip<F> {
// Given an initialized state and an input message block, compress the // Given an initialized state and an input message block, compress the
// message block and return the final state. // message block and return the final state.
fn compress( fn compress(
layouter: &mut impl Layouter<Self>, &self,
layouter: &mut impl Layouter<F>,
initialized_state: &Self::State, initialized_state: &Self::State,
input: [Self::BlockWord; super::BLOCK_SIZE], input: [Self::BlockWord; super::BLOCK_SIZE],
) -> Result<Self::State, Error> { ) -> Result<Self::State, Error> {
let config = layouter.config().clone(); let config = self.config().clone();
let (_, w_halves) = config.message_schedule.process(layouter, input)?; let (_, w_halves) = config.message_schedule.process(layouter, input)?;
config config
.compression .compression
.compress(layouter, initialized_state.clone(), w_halves) .compress(layouter, initialized_state.clone(), w_halves)
} }
fn digest( fn digest(
layouter: &mut impl Layouter<Self>, &self,
layouter: &mut impl Layouter<F>,
state: &Self::State, state: &Self::State,
) -> Result<[Self::BlockWord; super::DIGEST_SIZE], Error> { ) -> Result<[Self::BlockWord; super::DIGEST_SIZE], Error> {
// Copy the dense forms of the state variable chunks down to this gate. // Copy the dense forms of the state variable chunks down to this gate.
// Reconstruct the 32-bit dense words. // Reconstruct the 32-bit dense words.
let config = layouter.config().clone(); self.config().compression.digest(layouter, state.clone())
config.compression.digest(layouter, state.clone())
} }
} }
@ -244,7 +262,7 @@ trait Table16Assignment<F: FieldExt> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn assign_spread_outputs( fn assign_spread_outputs(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
lookup: &SpreadInputs, lookup: &SpreadInputs,
a_3: Column<Advice>, a_3: Column<Advice>,
perm: &Permutation, perm: &Permutation,
@ -285,7 +303,7 @@ trait Table16Assignment<F: FieldExt> {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn assign_sigma_outputs( fn assign_sigma_outputs(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
lookup: &SpreadInputs, lookup: &SpreadInputs,
a_3: Column<Advice>, a_3: Column<Advice>,
perm: &Permutation, perm: &Permutation,
@ -305,7 +323,7 @@ trait Table16Assignment<F: FieldExt> {
// Assign a cell the same value as another cell and set up a copy constraint between them // Assign a cell the same value as another cell and set up a copy constraint between them
fn assign_and_constrain<A, AR>( fn assign_and_constrain<A, AR>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
annotation: A, annotation: A,
column: Column<Advice>, column: Column<Advice>,
row: usize, row: usize,
@ -326,12 +344,11 @@ trait Table16Assignment<F: FieldExt> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[cfg(feature = "dev-graph")] use super::super::{BlockWord, Sha256, BLOCK_SIZE};
use super::{Table16Chip, Table16Config};
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
circuit::Chip, circuit::{layouter::SingleChipLayouter, Layouter},
circuit::{layouter, Layouter},
gadget::sha256::{BlockWord, Sha256, Table16Chip, Table16Config, BLOCK_SIZE},
pasta::Fq, pasta::Fq,
plonk::{Assignment, Circuit, ConstraintSystem, Error}, plonk::{Assignment, Circuit, ConstraintSystem, Error},
}; };
@ -344,17 +361,18 @@ mod tests {
impl<F: FieldExt> Circuit<F> for MyCircuit { impl<F: FieldExt> Circuit<F> for MyCircuit {
type Config = Table16Config; type Config = Table16Config;
fn configure(meta: &mut ConstraintSystem<F>) -> Table16Config { fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
Table16Chip::configure(meta) Table16Chip::configure(meta)
} }
fn synthesize( fn synthesize(
&self, &self,
cs: &mut impl Assignment<F>, cs: &mut impl Assignment<F>,
config: Table16Config, config: Self::Config,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::new(cs, config)?; let mut layouter = SingleChipLayouter::new(cs)?;
Table16Chip::load(&mut layouter)?; let table16_chip = Table16Chip::<F>::construct(config.clone());
Table16Chip::<F>::load(config, &mut layouter)?;
// Test vector: "abc" // Test vector: "abc"
let test_input = [ let test_input = [
@ -381,14 +399,14 @@ mod tests {
input.extend_from_slice(&test_input); input.extend_from_slice(&test_input);
} }
Sha256::digest(layouter.namespace(|| "'abc' * 31"), &input)?; Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 31"), &input)?;
Ok(()) Ok(())
} }
} }
let circuit: MyCircuit = MyCircuit {}; let circuit: MyCircuit = MyCircuit {};
eprintln!("{}", crate::dev::circuit_dot_graph::<Fq, _>(&circuit)); eprintln!("{}", halo2::dev::circuit_dot_graph::<Fq, _>(&circuit));
} }
#[cfg(feature = "dev-graph")] #[cfg(feature = "dev-graph")]
@ -400,17 +418,18 @@ mod tests {
impl<F: FieldExt> Circuit<F> for MyCircuit { impl<F: FieldExt> Circuit<F> for MyCircuit {
type Config = Table16Config; type Config = Table16Config;
fn configure(meta: &mut ConstraintSystem<F>) -> Table16Config { fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
Table16Chip::configure(meta) Table16Chip::configure(meta)
} }
fn synthesize( fn synthesize(
&self, &self,
cs: &mut impl Assignment<F>, cs: &mut impl Assignment<F>,
config: Table16Config, config: Self::Config,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::new(cs, config)?; let mut layouter = SingleChipLayouter::new(cs)?;
Table16Chip::load(&mut layouter)?; let table16_chip = Table16Chip::<F>::construct(config.clone());
Table16Chip::<F>::load(config, &mut layouter)?;
// Test vector: "abc" // Test vector: "abc"
let test_input = [ let test_input = [
@ -437,7 +456,7 @@ mod tests {
input.extend_from_slice(&test_input); input.extend_from_slice(&test_input);
} }
Sha256::digest(layouter.namespace(|| "'abc' * 2"), &input)?; Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 2"), &input)?;
Ok(()) Ok(())
} }
@ -451,6 +470,6 @@ mod tests {
.unwrap(); .unwrap();
let circuit = MyCircuit {}; let circuit = MyCircuit {};
crate::dev::circuit_layout::<Fq, _, _>(&circuit, &root).unwrap(); halo2::dev::circuit_layout::<Fq, _, _>(&circuit, &root).unwrap();
} }
} }

View File

@ -1,6 +1,6 @@
use super::{ use super::{
super::DIGEST_SIZE, BlockWord, CellValue16, CellValue32, SpreadInputs, SpreadVar, super::DIGEST_SIZE, BlockWord, CellValue16, CellValue32, SpreadInputs, SpreadVar,
Table16Assignment, Table16Chip, ROUNDS, STATE, Table16Assignment, ROUNDS, STATE,
}; };
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
@ -231,7 +231,7 @@ pub enum StateWord {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(super) struct Compression { pub(super) struct CompressionConfig {
lookup: SpreadInputs, lookup: SpreadInputs,
message_schedule: Column<Advice>, message_schedule: Column<Advice>,
extras: [Column<Advice>; 6], extras: [Column<Advice>; 6],
@ -256,9 +256,9 @@ pub(super) struct Compression {
perm: Permutation, perm: Permutation,
} }
impl<F: FieldExt> Table16Assignment<F> for Compression {} impl<F: FieldExt> Table16Assignment<F> for CompressionConfig {}
impl Compression { impl CompressionConfig {
pub(super) fn configure<F: FieldExt>( pub(super) fn configure<F: FieldExt>(
meta: &mut ConstraintSystem<F>, meta: &mut ConstraintSystem<F>,
lookup: SpreadInputs, lookup: SpreadInputs,
@ -656,7 +656,7 @@ impl Compression {
.0 .0
}); });
Compression { CompressionConfig {
lookup, lookup,
message_schedule, message_schedule,
extras, extras,
@ -679,7 +679,7 @@ impl Compression {
/// Returns an initialized state. /// Returns an initialized state.
pub(super) fn initialize_with_iv<F: FieldExt>( pub(super) fn initialize_with_iv<F: FieldExt>(
&self, &self,
layouter: &mut impl Layouter<Table16Chip<F>>, layouter: &mut impl Layouter<F>,
init_state: [u32; STATE], init_state: [u32; STATE],
) -> Result<State, Error> { ) -> Result<State, Error> {
let mut new_state = State::empty_state(); let mut new_state = State::empty_state();
@ -697,7 +697,7 @@ impl Compression {
/// output from a previous compression round. /// output from a previous compression round.
pub(super) fn initialize_with_state<F: FieldExt>( pub(super) fn initialize_with_state<F: FieldExt>(
&self, &self,
layouter: &mut impl Layouter<Table16Chip<F>>, layouter: &mut impl Layouter<F>,
init_state: State, init_state: State,
) -> Result<State, Error> { ) -> Result<State, Error> {
let mut new_state = State::empty_state(); 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. /// Given an initialized state and a message schedule, perform 64 compression rounds.
pub(super) fn compress<F: FieldExt>( pub(super) fn compress<F: FieldExt>(
&self, &self,
layouter: &mut impl Layouter<Table16Chip<F>>, layouter: &mut impl Layouter<F>,
initialized_state: State, initialized_state: State,
w_halves: [(CellValue16, CellValue16); ROUNDS], w_halves: [(CellValue16, CellValue16); ROUNDS],
) -> Result<State, Error> { ) -> Result<State, Error> {
@ -736,7 +736,7 @@ impl Compression {
/// After the final round, convert the state into the final digest. /// After the final round, convert the state into the final digest.
pub(super) fn digest<F: FieldExt>( pub(super) fn digest<F: FieldExt>(
&self, &self,
layouter: &mut impl Layouter<Table16Chip<F>>, layouter: &mut impl Layouter<F>,
state: State, state: State,
) -> Result<[BlockWord; DIGEST_SIZE], Error> { ) -> Result<[BlockWord; DIGEST_SIZE], Error> {
let mut digest = [BlockWord::new(0); DIGEST_SIZE]; let mut digest = [BlockWord::new(0); DIGEST_SIZE];
@ -750,65 +750,19 @@ impl Compression {
)?; )?;
Ok(digest) Ok(digest)
} }
#[cfg(test)]
pub(super) fn empty_configure<F: FieldExt>(
meta: &mut ConstraintSystem<F>,
lookup: SpreadInputs,
message_schedule: Column<Advice>,
extras: [Column<Advice>; 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)] #[cfg(test)]
mod tests { mod tests {
use super::super::{ use super::super::{
super::BLOCK_SIZE, get_msg_schedule_test_input, BlockWord, MessageSchedule, SpreadTable, super::BLOCK_SIZE, get_msg_schedule_test_input, BlockWord, Table16Chip, Table16Config, IV,
Table16Chip, Table16Config, IV,
}; };
use super::Compression;
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
circuit::{layouter, Layouter}, circuit::layouter::SingleChipLayouter,
dev::MockProver, dev::MockProver,
pasta::Fp, pasta::Fp,
plonk::{Assignment, Circuit, ConstraintSystem, Error, Permutation}, plonk::{Assignment, Circuit, ConstraintSystem, Error},
}; };
#[test] #[test]
@ -819,69 +773,7 @@ mod tests {
type Config = Table16Config; type Config = Table16Config;
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config { fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
let a = meta.advice_column(); Table16Chip::configure(meta)
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,
}
} }
fn synthesize( fn synthesize(
@ -889,16 +781,12 @@ mod tests {
cs: &mut impl Assignment<F>, cs: &mut impl Assignment<F>,
config: Self::Config, config: Self::Config,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::new(cs, config)?; let mut layouter = SingleChipLayouter::new(cs)?;
Table16Chip::<F>::load(config.clone(), &mut layouter)?;
// Load table
let table = layouter.config().lookup_table.clone();
table.load(&mut layouter)?;
// Test vector: "abc" // Test vector: "abc"
let input: [BlockWord; BLOCK_SIZE] = get_msg_schedule_test_input(); 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 (_, w_halves) = config.message_schedule.process(&mut layouter, input)?;
let compression = config.compression.clone(); let compression = config.compression.clone();

View File

@ -1,9 +1,9 @@
use super::super::{ use super::super::{
util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, StateWord, Table16Assignment, util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, StateWord, Table16Assignment,
Table16Chip,
}; };
use super::{ use super::{
AbcdVar, Compression, EfghVar, RoundWordA, RoundWordDense, RoundWordE, RoundWordSpread, State, AbcdVar, CompressionConfig, EfghVar, RoundWordA, RoundWordDense, RoundWordE, RoundWordSpread,
State,
}; };
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
@ -144,10 +144,10 @@ pub fn get_digest_efgh_row() -> usize {
get_digest_abcd_row() + 2 get_digest_abcd_row() + 2
} }
impl Compression { impl CompressionConfig {
pub(super) fn decompose_abcd<F: FieldExt>( pub(super) fn decompose_abcd<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
row: usize, row: usize,
a_val: u32, a_val: u32,
) -> Result< ) -> Result<
@ -191,7 +191,7 @@ impl Compression {
pub(super) fn decompose_efgh<F: FieldExt>( pub(super) fn decompose_efgh<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
row: usize, row: usize,
val: u32, val: u32,
) -> Result< ) -> Result<
@ -234,7 +234,7 @@ impl Compression {
pub(super) fn decompose_a<F: FieldExt>( pub(super) fn decompose_a<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
a_val: u32, a_val: u32,
) -> Result<RoundWordA, Error> { ) -> Result<RoundWordA, Error> {
@ -257,7 +257,7 @@ impl Compression {
pub(super) fn decompose_e<F: FieldExt>( pub(super) fn decompose_e<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
e_val: u32, e_val: u32,
) -> Result<RoundWordE, Error> { ) -> Result<RoundWordE, Error> {
@ -280,7 +280,7 @@ impl Compression {
pub(super) fn assign_upper_sigma_0<F: FieldExt>( pub(super) fn assign_upper_sigma_0<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
word: AbcdVar, word: AbcdVar,
) -> Result<(CellValue16, CellValue16), Error> { ) -> Result<(CellValue16, CellValue16), Error> {
@ -385,7 +385,7 @@ impl Compression {
pub(super) fn assign_upper_sigma_1<F: FieldExt>( pub(super) fn assign_upper_sigma_1<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
word: EfghVar, word: EfghVar,
) -> Result<(CellValue16, CellValue16), Error> { ) -> Result<(CellValue16, CellValue16), Error> {
@ -490,7 +490,7 @@ impl Compression {
fn assign_ch_outputs<F: FieldExt>( fn assign_ch_outputs<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
row: usize, row: usize,
r_0_even: u16, r_0_even: u16,
r_0_odd: u16, r_0_odd: u16,
@ -516,7 +516,7 @@ impl Compression {
pub(super) fn assign_ch<F: FieldExt>( pub(super) fn assign_ch<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
spread_halves_e: (CellValue32, CellValue32), spread_halves_e: (CellValue32, CellValue32),
spread_halves_f: (CellValue32, CellValue32), spread_halves_f: (CellValue32, CellValue32),
@ -578,7 +578,7 @@ impl Compression {
pub(super) fn assign_ch_neg<F: FieldExt>( pub(super) fn assign_ch_neg<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
spread_halves_e: (CellValue32, CellValue32), spread_halves_e: (CellValue32, CellValue32),
spread_halves_g: (CellValue32, CellValue32), spread_halves_g: (CellValue32, CellValue32),
@ -661,7 +661,7 @@ impl Compression {
fn assign_maj_outputs<F: FieldExt>( fn assign_maj_outputs<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
row: usize, row: usize,
r_0_even: u16, r_0_even: u16,
r_0_odd: u16, r_0_odd: u16,
@ -686,7 +686,7 @@ impl Compression {
pub(super) fn assign_maj<F: FieldExt>( pub(super) fn assign_maj<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
spread_halves_a: (CellValue32, CellValue32), spread_halves_a: (CellValue32, CellValue32),
spread_halves_b: (CellValue32, CellValue32), spread_halves_b: (CellValue32, CellValue32),
@ -771,7 +771,7 @@ impl Compression {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub(super) fn assign_h_prime<F: FieldExt>( pub(super) fn assign_h_prime<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
h: (CellValue16, CellValue16), h: (CellValue16, CellValue16),
ch: (CellValue16, CellValue16), ch: (CellValue16, CellValue16),
@ -900,7 +900,7 @@ impl Compression {
// s_e_new to get E_new = H' + D // s_e_new to get E_new = H' + D
pub(super) fn assign_e_new<F: FieldExt>( pub(super) fn assign_e_new<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
d: (CellValue16, CellValue16), d: (CellValue16, CellValue16),
h_prime: (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) // s_a_new to get A_new = H' + Maj(A, B, C) + s_upper_sigma_0(A)
pub(super) fn assign_a_new<F: FieldExt>( pub(super) fn assign_a_new<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
maj: (CellValue16, CellValue16), maj: (CellValue16, CellValue16),
sigma_0: (CellValue16, CellValue16), sigma_0: (CellValue16, CellValue16),
@ -1026,7 +1026,7 @@ impl Compression {
pub fn assign_word_halves_dense<F: FieldExt>( pub fn assign_word_halves_dense<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
lo_row: usize, lo_row: usize,
lo_col: Column<Advice>, lo_col: Column<Advice>,
hi_row: usize, hi_row: usize,
@ -1056,7 +1056,7 @@ impl Compression {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn assign_word_halves<F: FieldExt>( pub fn assign_word_halves<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
row: usize, row: usize,
word: u32, word: u32,
) -> Result<((CellValue16, CellValue16), (CellValue32, CellValue32)), Error> { ) -> Result<((CellValue16, CellValue16), (CellValue32, CellValue32)), Error> {

View File

@ -1,16 +1,16 @@
use super::super::{super::DIGEST_SIZE, BlockWord, CellValue16, Table16Assignment, Table16Chip}; use super::super::{super::DIGEST_SIZE, BlockWord, CellValue16, Table16Assignment};
use super::{compression_util::*, Compression, State}; use super::{compression_util::*, CompressionConfig, State};
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
circuit::Region, circuit::Region,
plonk::{Advice, Column, Error}, plonk::{Advice, Column, Error},
}; };
impl Compression { impl CompressionConfig {
#[allow(clippy::many_single_char_names)] #[allow(clippy::many_single_char_names)]
pub fn assign_digest<F: FieldExt>( pub fn assign_digest<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
state: State, state: State,
) -> Result<[BlockWord; DIGEST_SIZE], Error> { ) -> Result<[BlockWord; DIGEST_SIZE], Error> {
let a_3 = self.extras[0]; let a_3 = self.extras[0];
@ -91,7 +91,7 @@ impl Compression {
fn assign_digest_word<F: FieldExt>( fn assign_digest_word<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
row: usize, row: usize,
lo_col: Column<Advice>, lo_col: Column<Advice>,
hi_col: Column<Advice>, hi_col: Column<Advice>,

View File

@ -1,12 +1,12 @@
use super::super::{RoundWordDense, RoundWordSpread, StateWord, Table16Chip, STATE}; use super::super::{RoundWordDense, RoundWordSpread, StateWord, STATE};
use super::{compression_util::*, Compression, State}; use super::{compression_util::*, CompressionConfig, State};
use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};
impl Compression { impl CompressionConfig {
#[allow(clippy::many_single_char_names)] #[allow(clippy::many_single_char_names)]
pub fn initialize_iv<F: FieldExt>( pub fn initialize_iv<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
iv: [u32; STATE], iv: [u32; STATE],
) -> Result<State, Error> { ) -> Result<State, Error> {
let a_7 = self.extras[3]; let a_7 = self.extras[3];
@ -52,7 +52,7 @@ impl Compression {
#[allow(clippy::many_single_char_names)] #[allow(clippy::many_single_char_names)]
pub fn initialize_state<F: FieldExt>( pub fn initialize_state<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
state: State, state: State,
) -> Result<State, Error> { ) -> Result<State, Error> {
let a_7 = self.extras[3]; let a_7 = self.extras[3];
@ -106,7 +106,7 @@ impl Compression {
fn decompose_b<F: FieldExt>( fn decompose_b<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
b_val: u32, b_val: u32,
) -> Result<RoundWordSpread, Error> { ) -> Result<RoundWordSpread, Error> {
@ -119,7 +119,7 @@ impl Compression {
fn decompose_c<F: FieldExt>( fn decompose_c<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
c_val: u32, c_val: u32,
) -> Result<RoundWordSpread, Error> { ) -> Result<RoundWordSpread, Error> {
@ -132,7 +132,7 @@ impl Compression {
fn decompose_f<F: FieldExt>( fn decompose_f<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
f_val: u32, f_val: u32,
) -> Result<RoundWordSpread, Error> { ) -> Result<RoundWordSpread, Error> {
@ -145,7 +145,7 @@ impl Compression {
fn decompose_g<F: FieldExt>( fn decompose_g<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
g_val: u32, g_val: u32,
) -> Result<RoundWordSpread, Error> { ) -> Result<RoundWordSpread, Error> {

View File

@ -1,14 +1,14 @@
use super::super::{ 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}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};
impl Compression { impl CompressionConfig {
#[allow(clippy::many_single_char_names)] #[allow(clippy::many_single_char_names)]
pub fn assign_round<F: FieldExt>( pub fn assign_round<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
idx: i32, idx: i32,
state: State, state: State,
schedule_word: (CellValue16, CellValue16), schedule_word: (CellValue16, CellValue16),

View File

@ -1,8 +1,6 @@
use std::convert::TryInto; use std::convert::TryInto;
use super::{ use super::{super::BLOCK_SIZE, BlockWord, CellValue16, SpreadInputs, Table16Assignment, ROUNDS};
super::BLOCK_SIZE, BlockWord, CellValue16, SpreadInputs, Table16Assignment, Table16Chip, ROUNDS,
};
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
circuit::{Cell, Layouter}, circuit::{Cell, Layouter},
@ -29,7 +27,7 @@ pub(super) struct MessageWord {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(super) struct MessageSchedule { pub(super) struct MessageScheduleConfig {
lookup: SpreadInputs, lookup: SpreadInputs,
message_schedule: Column<Advice>, message_schedule: Column<Advice>,
extras: [Column<Advice>; 6], extras: [Column<Advice>; 6],
@ -55,9 +53,9 @@ pub(super) struct MessageSchedule {
perm: Permutation, perm: Permutation,
} }
impl<F: FieldExt> Table16Assignment<F> for MessageSchedule {} impl<F: FieldExt> Table16Assignment<F> for MessageScheduleConfig {}
impl MessageSchedule { impl MessageScheduleConfig {
/// Configures the message schedule. /// Configures the message schedule.
/// ///
/// `message_schedule` is the column into which the message schedule will be placed. /// `message_schedule` is the column into which the message schedule will be placed.
@ -289,7 +287,7 @@ impl MessageSchedule {
.0 .0
}); });
MessageSchedule { MessageScheduleConfig {
lookup, lookup,
message_schedule, message_schedule,
extras, extras,
@ -309,7 +307,7 @@ impl MessageSchedule {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub(super) fn process<F: FieldExt>( pub(super) fn process<F: FieldExt>(
&self, &self,
layouter: &mut impl Layouter<Table16Chip<F>>, layouter: &mut impl Layouter<F>,
input: [BlockWord; BLOCK_SIZE], input: [BlockWord; BLOCK_SIZE],
) -> Result<([MessageWord; ROUNDS], [(CellValue16, CellValue16); ROUNDS]), Error> { ) -> Result<([MessageWord; ROUNDS], [(CellValue16, CellValue16); ROUNDS]), Error> {
let mut w = Vec::<MessageWord>::with_capacity(ROUNDS); let mut w = Vec::<MessageWord>::with_capacity(ROUNDS);
@ -439,57 +437,18 @@ impl MessageSchedule {
Ok((w.try_into().unwrap(), w_halves.try_into().unwrap())) 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<F: FieldExt>(
meta: &mut ConstraintSystem<F>,
lookup: SpreadInputs,
message_schedule: Column<Advice>,
extras: [Column<Advice>; 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)] #[cfg(test)]
mod tests { mod tests {
use super::super::{ use super::super::{super::BLOCK_SIZE, BlockWord, SpreadTableChip, Table16Chip, Table16Config};
super::BLOCK_SIZE, BlockWord, Compression, SpreadTable, Table16Chip, Table16Config, use super::schedule_util::*;
};
use super::{schedule_util::*, MessageSchedule};
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
circuit::{layouter, Layouter}, circuit::layouter::SingleChipLayouter,
dev::MockProver, dev::MockProver,
pasta::Fp, pasta::Fp,
plonk::{Assignment, Circuit, ConstraintSystem, Error, Permutation}, plonk::{Assignment, Circuit, ConstraintSystem, Error},
}; };
#[test] #[test]
@ -500,64 +459,7 @@ mod tests {
type Config = Table16Config; type Config = Table16Config;
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config { fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
let a = meta.advice_column(); Table16Chip::configure(meta)
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,
}
} }
fn synthesize( fn synthesize(
@ -565,19 +467,17 @@ mod tests {
cs: &mut impl Assignment<F>, cs: &mut impl Assignment<F>,
config: Self::Config, config: Self::Config,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::new(cs, config)?; let mut layouter = SingleChipLayouter::new(cs)?;
// Load table // Load lookup table
let table = layouter.config().lookup_table.clone(); SpreadTableChip::load(config.lookup.clone(), &mut layouter)?;
table.load(&mut layouter)?;
// Provide input // Provide input
// Test vector: "abc" // Test vector: "abc"
let inputs: [BlockWord; BLOCK_SIZE] = get_msg_schedule_test_input(); let inputs: [BlockWord; BLOCK_SIZE] = get_msg_schedule_test_input();
// Run message_scheduler to get W_[0..64] // Run message_scheduler to get W_[0..64]
let message_schedule = layouter.config().message_schedule.clone(); let (w, _) = config.message_schedule.process(&mut layouter, inputs)?;
let (w, _) = message_schedule.process(&mut layouter, inputs)?;
for (word, test_word) in w.iter().zip(MSG_SCHEDULE_TEST_OUTPUT.iter()) { for (word, test_word) in w.iter().zip(MSG_SCHEDULE_TEST_OUTPUT.iter()) {
let word = word.value.unwrap(); let word = word.value.unwrap();
assert_eq!(word, *test_word); assert_eq!(word, *test_word);

View File

@ -1,5 +1,5 @@
use super::super::{CellValue16, Table16Chip}; use super::super::CellValue16;
use super::MessageSchedule; use super::MessageScheduleConfig;
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
circuit::{Cell, Region}, circuit::{Cell, Region},
@ -148,11 +148,11 @@ pub const MSG_SCHEDULE_TEST_OUTPUT: [u32; ROUNDS] = [
0b00010010101100011110110111101011, 0b00010010101100011110110111101011,
]; ];
impl MessageSchedule { impl MessageScheduleConfig {
// Assign a word and its hi and lo halves // Assign a word and its hi and lo halves
pub fn assign_word_and_halves<F: FieldExt>( pub fn assign_word_and_halves<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
word: u32, word: u32,
word_idx: usize, word_idx: usize,
) -> Result<(Cell, (CellValue16, CellValue16)), Error> { ) -> Result<(Cell, (CellValue16, CellValue16)), Error> {

View File

@ -1,8 +1,7 @@
use super::super::{ use super::super::{
util::*, BlockWord, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment, 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}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};
// A word in subregion 1 // A word in subregion 1
@ -18,10 +17,10 @@ pub struct Subregion1Word {
spread_d: CellValue32, spread_d: CellValue32,
} }
impl MessageSchedule { impl MessageScheduleConfig {
pub fn assign_subregion1<F: FieldExt>( pub fn assign_subregion1<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
input: &[BlockWord], input: &[BlockWord],
) -> Result<Vec<(CellValue16, CellValue16)>, Error> { ) -> Result<Vec<(CellValue16, CellValue16)>, Error> {
assert_eq!(input.len(), SUBREGION_1_LEN); assert_eq!(input.len(), SUBREGION_1_LEN);
@ -42,7 +41,7 @@ impl MessageSchedule {
fn decompose_subregion1_word<F: FieldExt>( fn decompose_subregion1_word<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
word: u32, word: u32,
index: usize, index: usize,
) -> Result<Subregion1Word, Error> { ) -> Result<Subregion1Word, Error> {
@ -92,7 +91,7 @@ impl MessageSchedule {
// (3, 4, 11, 14)-bit chunks // (3, 4, 11, 14)-bit chunks
fn lower_sigma_0<F: FieldExt>( fn lower_sigma_0<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
word: Subregion1Word, word: Subregion1Word,
) -> Result<(CellValue16, CellValue16), Error> { ) -> Result<(CellValue16, CellValue16), Error> {
let a_3 = self.extras[0]; let a_3 = self.extras[0];

View File

@ -1,7 +1,5 @@
use super::super::{ use super::super::{util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment};
util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment, Table16Chip, use super::{schedule_util::*, MessageScheduleConfig, MessageWord};
};
use super::{schedule_util::*, MessageSchedule, MessageWord};
use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};
// A word in subregion 2 // A word in subregion 2
@ -20,11 +18,11 @@ pub struct Subregion2Word {
spread_g: CellValue32, spread_g: CellValue32,
} }
impl MessageSchedule { impl MessageScheduleConfig {
// W_[14..49] // W_[14..49]
pub fn assign_subregion2<F: FieldExt>( pub fn assign_subregion2<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
lower_sigma_0_output: Vec<(CellValue16, CellValue16)>, lower_sigma_0_output: Vec<(CellValue16, CellValue16)>,
w: &mut Vec<MessageWord>, w: &mut Vec<MessageWord>,
w_halves: &mut Vec<(CellValue16, CellValue16)>, w_halves: &mut Vec<(CellValue16, CellValue16)>,
@ -171,7 +169,7 @@ impl MessageSchedule {
fn decompose_subregion2_word<F: FieldExt>( fn decompose_subregion2_word<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
word: u32, word: u32,
index: usize, index: usize,
) -> Result<Subregion2Word, Error> { ) -> Result<Subregion2Word, Error> {
@ -224,7 +222,7 @@ impl MessageSchedule {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn assign_lower_sigma_v2_pieces<F: FieldExt>( fn assign_lower_sigma_v2_pieces<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
row: usize, row: usize,
subregion2_word: Subregion2Word, subregion2_word: Subregion2Word,
) -> Result<(u64, u64, u64, u64, u64, u64, u64, u64), Error> { ) -> Result<(u64, u64, u64, u64, u64, u64, u64, u64), Error> {
@ -323,7 +321,7 @@ impl MessageSchedule {
fn lower_sigma_0_v2<F: FieldExt>( fn lower_sigma_0_v2<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
subregion2_word: Subregion2Word, subregion2_word: Subregion2Word,
) -> Result<(CellValue16, CellValue16), Error> { ) -> Result<(CellValue16, CellValue16), Error> {
let a_3 = self.extras[0]; let a_3 = self.extras[0];
@ -378,7 +376,7 @@ impl MessageSchedule {
fn lower_sigma_1_v2<F: FieldExt>( fn lower_sigma_1_v2<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
subregion2_word: Subregion2Word, subregion2_word: Subregion2Word,
) -> Result<(CellValue16, CellValue16), Error> { ) -> Result<(CellValue16, CellValue16), Error> {
let a_3 = self.extras[0]; let a_3 = self.extras[0];

View File

@ -1,7 +1,5 @@
use super::super::{ use super::super::{util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment};
util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, Table16Assignment, Table16Chip, use super::{schedule_util::*, MessageScheduleConfig, MessageWord};
};
use super::{schedule_util::*, MessageSchedule, MessageWord};
use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error}; use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};
// A word in subregion 3 // A word in subregion 3
@ -18,11 +16,11 @@ pub struct Subregion3Word {
spread_d: CellValue32, spread_d: CellValue32,
} }
impl MessageSchedule { impl MessageScheduleConfig {
// W_[49..62] // W_[49..62]
pub fn assign_subregion3<F: FieldExt>( pub fn assign_subregion3<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
lower_sigma_0_v2_output: Vec<(CellValue16, CellValue16)>, lower_sigma_0_v2_output: Vec<(CellValue16, CellValue16)>,
w: &mut Vec<MessageWord>, w: &mut Vec<MessageWord>,
w_halves: &mut Vec<(CellValue16, CellValue16)>, w_halves: &mut Vec<(CellValue16, CellValue16)>,
@ -150,7 +148,7 @@ impl MessageSchedule {
fn decompose_subregion3_word<F: FieldExt>( fn decompose_subregion3_word<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
word: u32, word: u32,
index: usize, index: usize,
) -> Result<Subregion3Word, Error> { ) -> Result<Subregion3Word, Error> {
@ -189,7 +187,7 @@ impl MessageSchedule {
fn lower_sigma_1<F: FieldExt>( fn lower_sigma_1<F: FieldExt>(
&self, &self,
region: &mut Region<'_, Table16Chip<F>>, region: &mut Region<'_, F>,
word: Subregion3Word, word: Subregion3Word,
) -> Result<(CellValue16, CellValue16), Error> { ) -> Result<(CellValue16, CellValue16), Error> {
let a_3 = self.extras[0]; let a_3 = self.extras[0];

View File

@ -1,10 +1,11 @@
use super::{util::*, CellValue16, CellValue32, Table16Chip}; use super::{util::*, CellValue16, CellValue32};
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
circuit::{Chip, Layouter, Region}, circuit::{Chip, Layouter, Region},
plonk::{Advice, Column, ConstraintSystem, Error, Fixed}, plonk::{Advice, Column, ConstraintSystem, Error, Fixed},
poly::Rotation, poly::Rotation,
}; };
use std::marker::PhantomData;
/// An input word into a lookup, containing (tag, dense, spread) /// An input word into a lookup, containing (tag, dense, spread)
#[derive(Copy, Clone, Debug)] #[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)] #[derive(Copy, Clone, Debug)]
pub(super) struct SpreadVar { pub(super) struct SpreadVar {
pub tag: u8, pub tag: u8,
@ -33,8 +34,8 @@ pub(super) struct SpreadVar {
} }
impl SpreadVar { impl SpreadVar {
pub(super) fn with_lookup<'r, C: Chip>( pub(super) fn with_lookup<F: FieldExt>(
region: &mut Region<'r, C>, region: &mut Region<'_, F>,
cols: &SpreadInputs, cols: &SpreadInputs,
row: usize, row: usize,
word: SpreadWord, word: SpreadWord,
@ -42,19 +43,14 @@ impl SpreadVar {
let tag = word.tag; let tag = word.tag;
let dense_val = Some(word.dense); let dense_val = Some(word.dense);
let spread_val = Some(word.spread); let spread_val = Some(word.spread);
region.assign_advice( region.assign_advice(|| "tag", cols.tag, row, || Ok(F::from_u64(tag as u64)))?;
|| "tag",
cols.tag,
row,
|| Ok(C::Field::from_u64(tag as u64)),
)?;
let dense_var = region.assign_advice( let dense_var = region.assign_advice(
|| "dense", || "dense",
cols.dense, cols.dense,
row, row,
|| { || {
dense_val dense_val
.map(|v| C::Field::from_u64(v as u64)) .map(|v| F::from_u64(v as u64))
.ok_or(Error::SynthesisError) .ok_or(Error::SynthesisError)
}, },
)?; )?;
@ -64,7 +60,7 @@ impl SpreadVar {
row, row,
|| { || {
spread_val spread_val
.map(|v| C::Field::from_u64(v as u64)) .map(|v| F::from_u64(v as u64))
.ok_or(Error::SynthesisError) .ok_or(Error::SynthesisError)
}, },
)?; )?;
@ -76,8 +72,8 @@ impl SpreadVar {
}) })
} }
pub(super) fn without_lookup<C: Chip>( pub(super) fn without_lookup<F: FieldExt>(
region: &mut Region<'_, C>, region: &mut Region<'_, F>,
dense_col: Column<Advice>, dense_col: Column<Advice>,
dense_row: usize, dense_row: usize,
spread_col: Column<Advice>, spread_col: Column<Advice>,
@ -93,7 +89,7 @@ impl SpreadVar {
dense_row, dense_row,
|| { || {
dense_val dense_val
.map(|v| C::Field::from_u64(v as u64)) .map(|v| F::from_u64(v as u64))
.ok_or(Error::SynthesisError) .ok_or(Error::SynthesisError)
}, },
)?; )?;
@ -103,7 +99,7 @@ impl SpreadVar {
spread_row, spread_row,
|| { || {
spread_val spread_val
.map(|v| C::Field::from_u64(v as u64)) .map(|v| F::from_u64(v as u64))
.ok_or(Error::SynthesisError) .ok_or(Error::SynthesisError)
}, },
)?; )?;
@ -125,43 +121,116 @@ pub(super) struct SpreadInputs {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(super) struct SpreadTable { pub(super) struct SpreadTable {
table_tag: Column<Fixed>, pub(super) tag: Column<Fixed>,
table_dense: Column<Fixed>, pub(super) dense: Column<Fixed>,
table_spread: Column<Fixed>, pub(super) spread: Column<Fixed>,
} }
impl SpreadTable { #[derive(Clone, Debug)]
pub(super) fn configure<F: FieldExt>( pub(super) struct SpreadTableConfig {
pub input: SpreadInputs,
pub table: SpreadTable,
}
#[derive(Clone, Debug)]
pub(super) struct SpreadTableChip<F: FieldExt> {
config: SpreadTableConfig,
_marker: PhantomData<F>,
}
impl<F: FieldExt> Chip<F> for SpreadTableChip<F> {
type Config = SpreadTableConfig;
type Loaded = ();
fn config(&self) -> &Self::Config {
&self.config
}
fn loaded(&self) -> &Self::Loaded {
&()
}
}
impl<F: FieldExt> SpreadTableChip<F> {
pub fn configure(
meta: &mut ConstraintSystem<F>, meta: &mut ConstraintSystem<F>,
tag: Column<Advice>, input_tag: Column<Advice>,
dense: Column<Advice>, input_dense: Column<Advice>,
spread: Column<Advice>, input_spread: Column<Advice>,
) -> (SpreadInputs, Self) { ) -> <Self as Chip<F>>::Config {
let table_tag = meta.fixed_column(); let table_tag = meta.fixed_column();
let table_dense = meta.fixed_column(); let table_dense = meta.fixed_column();
let table_spread = meta.fixed_column(); let table_spread = meta.fixed_column();
let tag_ = meta.query_any(tag.into(), Rotation::cur()); let tag_cur = meta.query_advice(input_tag, Rotation::cur());
let dense_ = meta.query_any(dense.into(), Rotation::cur()); let dense_cur = meta.query_advice(input_dense, Rotation::cur());
let spread_ = meta.query_any(spread.into(), Rotation::cur()); let spread_cur = meta.query_advice(input_spread, Rotation::cur());
let table_tag_ = meta.query_any(table_tag.into(), Rotation::cur()); let table_tag_cur = meta.query_fixed(table_tag, Rotation::cur());
let table_dense_ = meta.query_any(table_dense.into(), Rotation::cur()); let table_dense_cur = meta.query_fixed(table_dense, Rotation::cur());
let table_spread_ = meta.query_any(table_spread.into(), Rotation::cur()); let table_spread_cur = meta.query_fixed(table_spread, Rotation::cur());
meta.lookup( meta.lookup(
&[tag_, dense_, spread_], &[tag_cur, dense_cur, spread_cur],
&[table_tag_, table_dense_, table_spread_], &[table_tag_cur, table_dense_cur, table_spread_cur],
); );
( SpreadTableConfig {
SpreadInputs { tag, dense, spread }, input: SpreadInputs {
SpreadTable { tag: input_tag,
table_tag, dense: input_dense,
table_dense, spread: input_spread,
table_spread, },
table: SpreadTable {
tag: table_tag,
dense: table_dense,
spread: table_spread,
},
}
}
pub fn load(
config: SpreadTableConfig,
layouter: &mut impl Layouter<F>,
) -> Result<<Self as Chip<F>>::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::<F>();
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<F: FieldExt>() -> impl Iterator<Item = (F, F, F)> { fn generate<F: FieldExt>() -> impl Iterator<Item = (F, F, F)> {
(1..=(1 << 16)).scan( (1..=(1 << 16)).scan(
(F::zero(), F::zero(), F::zero()), (F::zero(), F::zero(), F::zero()),
@ -192,70 +261,20 @@ impl SpreadTable {
}, },
) )
} }
pub(super) fn load<F: FieldExt>(
&self,
layouter: &mut impl Layouter<Table16Chip<F>>,
) -> 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::<F>();
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)] #[cfg(test)]
mod tests { mod tests {
use super::{SpreadTableChip, SpreadTableConfig};
use rand::Rng; use rand::Rng;
use std::cmp;
use std::collections::HashMap;
use std::fmt;
use std::marker::PhantomData;
use super::{ use crate::table16::util::{get_tag, interleave_u16_with_zeros};
super::{util::*, Compression, MessageSchedule, Table16Chip, Table16Config},
SpreadInputs, SpreadTable,
};
use halo2::{ use halo2::{
arithmetic::FieldExt, arithmetic::FieldExt,
circuit::{layouter, Cell, Layouter, Region, RegionIndex}, circuit::{layouter::SingleChipLayouter, Layouter},
dev::MockProver, dev::MockProver,
pasta::Fp, pasta::Fp,
plonk::{ plonk::{Advice, Assignment, Circuit, Column, ConstraintSystem, Error},
Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Error, Fixed, Permutation,
},
}; };
#[test] #[test]
@ -264,298 +283,40 @@ mod tests {
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct Variable(Column<Advice>, usize); pub struct Variable(Column<Advice>, usize);
#[derive(Clone, Debug)]
struct MyConfig {
lookup_inputs: SpreadInputs,
sha256: Table16Config,
}
struct MyCircuit {} struct MyCircuit {}
struct MyLayouter<'a, F: FieldExt, CS: Assignment<F> + 'a> {
cs: &'a mut CS,
config: MyConfig,
regions: Vec<usize>,
/// Stores the first empty row for each column.
columns: HashMap<Column<Any>, usize>,
_marker: PhantomData<F>,
}
impl<'a, F: FieldExt, CS: Assignment<F> + '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<FF>> MyLayouter<'a, FF, CS> {
fn new(cs: &'a mut CS, config: MyConfig) -> Result<Self, Error> {
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<F> + 'a> Layouter<Table16Chip<F>> for MyLayouter<'a, F, CS> {
type Root = Self;
fn config(&self) -> &Table16Config {
&self.config.sha256
}
fn loaded(&self) -> &() {
&()
}
fn assign_region<A, AR, N, NR>(
&mut self,
name: N,
mut assignment: A,
) -> Result<AR, Error>
where
A: FnMut(Region<'_, Table16Chip<F>>) -> Result<AR, Error>,
N: Fn() -> NR,
NR: Into<String>,
{
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<Table16Chip<F>> = &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<Table16Chip<F>> = &mut region;
assignment(region.into())
}?;
self.cs.exit_region();
Ok(result)
}
fn get_root(&mut self) -> &mut Self::Root {
self
}
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
self.cs.push_namespace(name_fn)
}
fn pop_namespace(&mut self, gadget_name: Option<String>) {
self.cs.pop_namespace(gadget_name)
}
}
struct MyRegion<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> {
layouter: &'r mut MyLayouter<'a, F, CS>,
region_index: RegionIndex,
_marker: PhantomData<F>,
}
impl<'r, 'a, F: FieldExt, CS: Assignment<F> + '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<F> + '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<F> + 'a> layouter::RegionLayouter<Table16Chip<F>>
for MyRegion<'r, 'a, F, CS>
{
fn assign_advice<'v>(
&'v mut self,
annotation: &'v (dyn Fn() -> String + 'v),
column: Column<Advice>,
offset: usize,
to: &'v mut (dyn FnMut() -> Result<F, Error> + 'v),
) -> Result<Cell, Error> {
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<Fixed>,
offset: usize,
to: &'v mut (dyn FnMut() -> Result<F, Error> + 'v),
) -> Result<Cell, Error> {
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<F: FieldExt> Circuit<F> for MyCircuit { impl<F: FieldExt> Circuit<F> for MyCircuit {
type Config = MyConfig; type Config = SpreadTableConfig;
fn configure(meta: &mut ConstraintSystem<F>) -> MyConfig { fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
let a = meta.advice_column(); let input_tag = meta.advice_column();
let b = meta.advice_column(); let input_dense = meta.advice_column();
let c = meta.advice_column(); let input_spread = meta.advice_column();
let (lookup_inputs, lookup_table) = SpreadTable::configure(meta, a, b, c); SpreadTableChip::configure(meta, input_tag, input_dense, input_spread)
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,
},
}
} }
fn synthesize( fn synthesize(
&self, &self,
cs: &mut impl Assignment<F>, cs: &mut impl Assignment<F>,
config: MyConfig, config: Self::Config,
) -> Result<(), Error> { ) -> Result<(), Error> {
let lookup = config.lookup_inputs.clone(); let mut layouter = SingleChipLayouter::new(cs)?;
let mut layouter = MyLayouter::new(cs, config)?; SpreadTableChip::load(config.clone(), &mut layouter)?;
layouter.assign_region( layouter.assign_region(
|| "spread_test", || "spread_test",
|mut gate| { |mut gate| {
let mut row = 0; let mut row = 0;
let mut add_row = |tag, dense, spread| { let mut add_row = |tag, dense, spread| {
gate.assign_advice(|| "tag", lookup.tag, row, || Ok(tag))?; gate.assign_advice(|| "tag", config.input.tag, row, || Ok(tag))?;
gate.assign_advice(|| "dense", lookup.dense, row, || Ok(dense))?; gate.assign_advice(|| "dense", config.input.dense, row, || Ok(dense))?;
gate.assign_advice(|| "spread", lookup.spread, row, || Ok(spread))?; gate.assign_advice(
|| "spread",
config.input.spread,
row,
|| Ok(spread),
)?;
row += 1; row += 1;
Ok(()) Ok(())
}; };