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::{
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<F: FieldExt> Circuit<F> for MyCircuit {
type Config = Table16Config;
fn configure(meta: &mut ConstraintSystem<F>) -> Table16Config {
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
Table16Chip::configure(meta)
}
fn synthesize(
&self,
cs: &mut impl Assignment<F>,
config: Table16Config,
config: Self::Config,
) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::new(cs, config)?;
Table16Chip::load(&mut layouter)?;
let mut layouter = SingleChipLayouter::new(cs)?;
Table16Chip::<F>::load(config.clone(), &mut layouter)?;
let table16_chip = Table16Chip::<F>::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(())
}

View File

@ -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<F: FieldExt>: Chip<F> {
/// 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<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
fn initialization(
layouter: &mut impl Layouter<Self>,
&self,
layouter: &mut impl Layouter<F>,
init_state: &Self::State,
) -> Result<Self::State, Error>;
/// Starting from the given initialized state, processes a block of input and returns the
/// final state.
fn compress(
layouter: &mut impl Layouter<Self>,
&self,
layouter: &mut impl Layouter<F>,
initialized_state: &Self::State,
input: [Self::BlockWord; BLOCK_SIZE],
) -> Result<Self::State, Error>;
/// Converts the given state into a message digest.
fn digest(
layouter: &mut impl Layouter<Self>,
&self,
layouter: &mut impl Layouter<F>,
state: &Self::State,
) -> 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
/// 32 bits.
#[derive(Debug)]
pub struct Sha256<CS: Sha256Instructions> {
pub struct Sha256<F: FieldExt, CS: Sha256Instructions<F>> {
chip: CS,
state: CS::State,
cur_block: Vec<CS::BlockWord>,
length: usize,
}
impl<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
impl<F: FieldExt, Sha256Chip: Sha256Instructions<F>> Sha256<F, Sha256Chip> {
/// 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 {
state: Sha256Chip::initialization_vector(&mut layouter)?,
chip,
state,
cur_block: Vec::with_capacity(BLOCK_SIZE),
length: 0,
})
@ -83,7 +89,7 @@ impl<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
/// Digest data, updating the internal state.
pub fn update(
&mut self,
mut layouter: impl Layouter<Sha256Chip>,
mut layouter: impl Layouter<F>,
mut data: &[Sha256Chip::BlockWord],
) -> Result<(), Error> {
self.length += data.len() * 32;
@ -100,7 +106,7 @@ impl<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
}
// 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<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
// 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<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
/// Retrieve result and consume hasher instance.
pub fn finalize(
mut self,
mut layouter: impl Layouter<Sha256Chip>,
mut layouter: impl Layouter<F>,
) -> Result<Sha256Digest<Sha256Chip::BlockWord>, 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<Sha256Chip: Sha256Instructions> Sha256<Sha256Chip> {
.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<Sha256Chip>,
chip: Sha256Chip,
mut layouter: impl Layouter<F>,
data: &[Sha256Chip::BlockWord],
) -> 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.finalize(layouter.namespace(|| "finalize"))
}
}
*/
fn main() {}

View File

@ -100,26 +100,41 @@ impl Into<CellValue32> 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<F: FieldExt> {
config: Table16Config,
_marker: PhantomData<F>,
}
impl<F: FieldExt> Table16Chip<F> {
/// Configures this chip for use in a circuit.
pub fn configure(meta: &mut ConstraintSystem<F>) -> 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<F: FieldExt> Chip<F> for Table16Chip<F> {
type Config = Table16Config;
type Loaded = ();
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 extras = [
meta.advice_column(),
@ -130,7 +145,13 @@ impl<F: FieldExt> Table16Chip<F> {
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<F: FieldExt> Table16Chip<F> {
],
);
let compression = Compression::configure(
let compression = CompressionConfig::configure(
meta,
lookup_inputs.clone(),
message_schedule,
@ -166,29 +187,27 @@ impl<F: FieldExt> Table16Chip<F> {
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<F: FieldExt> Chip for Table16Chip<F> {
type Field = F;
type Config = Table16Config;
type Loaded = ();
fn load(layouter: &mut impl Layouter<Self>) -> Result<(), Error> {
let table = layouter.config().lookup_table.clone();
table.load(layouter)
pub fn load(config: Table16Config, layouter: &mut impl Layouter<F>) -> Result<(), Error> {
SpreadTableChip::load(config.lookup, layouter)
}
}
impl<F: FieldExt> Sha256Instructions for Table16Chip<F> {
impl<F: FieldExt> Sha256Instructions<F> for Table16Chip<F> {
type State = State;
type BlockWord = BlockWord;
@ -196,17 +215,16 @@ impl<F: FieldExt> Sha256Instructions for Table16Chip<F> {
BlockWord::new(0)
}
fn initialization_vector(layouter: &mut impl Layouter<Self>) -> Result<State, Error> {
let config = layouter.config().clone();
config.compression.initialize_with_iv(layouter, IV)
fn initialization_vector(&self, layouter: &mut impl Layouter<F>) -> Result<State, Error> {
self.config().compression.initialize_with_iv(layouter, IV)
}
fn initialization(
layouter: &mut impl Layouter<Table16Chip<F>>,
&self,
layouter: &mut impl Layouter<F>,
init_state: &Self::State,
) -> Result<Self::State, Error> {
let config = layouter.config().clone();
config
self.config()
.compression
.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
// message block and return the final state.
fn compress(
layouter: &mut impl Layouter<Self>,
&self,
layouter: &mut impl Layouter<F>,
initialized_state: &Self::State,
input: [Self::BlockWord; super::BLOCK_SIZE],
) -> Result<Self::State, Error> {
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>,
&self,
layouter: &mut impl Layouter<F>,
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<F: FieldExt> {
#[allow(clippy::type_complexity)]
fn assign_spread_outputs(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
lookup: &SpreadInputs,
a_3: Column<Advice>,
perm: &Permutation,
@ -285,7 +303,7 @@ trait Table16Assignment<F: FieldExt> {
#[allow(clippy::too_many_arguments)]
fn assign_sigma_outputs(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
lookup: &SpreadInputs,
a_3: Column<Advice>,
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
fn assign_and_constrain<A, AR>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
annotation: A,
column: Column<Advice>,
row: usize,
@ -326,12 +344,11 @@ trait Table16Assignment<F: FieldExt> {
#[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<F: FieldExt> Circuit<F> for MyCircuit {
type Config = Table16Config;
fn configure(meta: &mut ConstraintSystem<F>) -> Table16Config {
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
Table16Chip::configure(meta)
}
fn synthesize(
&self,
cs: &mut impl Assignment<F>,
config: Table16Config,
config: Self::Config,
) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::new(cs, config)?;
Table16Chip::load(&mut layouter)?;
let mut layouter = SingleChipLayouter::new(cs)?;
let table16_chip = Table16Chip::<F>::construct(config.clone());
Table16Chip::<F>::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::<Fq, _>(&circuit));
eprintln!("{}", halo2::dev::circuit_dot_graph::<Fq, _>(&circuit));
}
#[cfg(feature = "dev-graph")]
@ -400,17 +418,18 @@ mod tests {
impl<F: FieldExt> Circuit<F> for MyCircuit {
type Config = Table16Config;
fn configure(meta: &mut ConstraintSystem<F>) -> Table16Config {
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config {
Table16Chip::configure(meta)
}
fn synthesize(
&self,
cs: &mut impl Assignment<F>,
config: Table16Config,
config: Self::Config,
) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::new(cs, config)?;
Table16Chip::load(&mut layouter)?;
let mut layouter = SingleChipLayouter::new(cs)?;
let table16_chip = Table16Chip::<F>::construct(config.clone());
Table16Chip::<F>::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::<Fq, _, _>(&circuit, &root).unwrap();
halo2::dev::circuit_layout::<Fq, _, _>(&circuit, &root).unwrap();
}
}

View File

@ -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<Advice>,
extras: [Column<Advice>; 6],
@ -256,9 +256,9 @@ pub(super) struct Compression {
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>(
meta: &mut ConstraintSystem<F>,
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<F: FieldExt>(
&self,
layouter: &mut impl Layouter<Table16Chip<F>>,
layouter: &mut impl Layouter<F>,
init_state: [u32; STATE],
) -> Result<State, Error> {
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<F: FieldExt>(
&self,
layouter: &mut impl Layouter<Table16Chip<F>>,
layouter: &mut impl Layouter<F>,
init_state: State,
) -> Result<State, Error> {
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<F: FieldExt>(
&self,
layouter: &mut impl Layouter<Table16Chip<F>>,
layouter: &mut impl Layouter<F>,
initialized_state: State,
w_halves: [(CellValue16, CellValue16); ROUNDS],
) -> Result<State, Error> {
@ -736,7 +736,7 @@ impl Compression {
/// After the final round, convert the state into the final digest.
pub(super) fn digest<F: FieldExt>(
&self,
layouter: &mut impl Layouter<Table16Chip<F>>,
layouter: &mut impl Layouter<F>,
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<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)]
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<F>) -> 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<F>,
config: Self::Config,
) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::new(cs, config)?;
// Load table
let table = layouter.config().lookup_table.clone();
table.load(&mut layouter)?;
let mut layouter = SingleChipLayouter::new(cs)?;
Table16Chip::<F>::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();

View File

@ -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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
row: usize,
a_val: u32,
) -> Result<
@ -191,7 +191,7 @@ impl Compression {
pub(super) fn decompose_efgh<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
row: usize,
val: u32,
) -> Result<
@ -234,7 +234,7 @@ impl Compression {
pub(super) fn decompose_a<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
idx: i32,
a_val: u32,
) -> Result<RoundWordA, Error> {
@ -257,7 +257,7 @@ impl Compression {
pub(super) fn decompose_e<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
idx: i32,
e_val: u32,
) -> Result<RoundWordE, Error> {
@ -280,7 +280,7 @@ impl Compression {
pub(super) fn assign_upper_sigma_0<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
idx: i32,
word: EfghVar,
) -> Result<(CellValue16, CellValue16), Error> {
@ -490,7 +490,7 @@ impl Compression {
fn assign_ch_outputs<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
lo_row: usize,
lo_col: Column<Advice>,
hi_row: usize,
@ -1056,7 +1056,7 @@ impl Compression {
#[allow(clippy::type_complexity)]
pub fn assign_word_halves<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
row: usize,
word: u32,
) -> Result<((CellValue16, CellValue16), (CellValue32, CellValue32)), Error> {

View File

@ -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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
row: usize,
lo_col: Column<Advice>,
hi_col: Column<Advice>,

View File

@ -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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
iv: [u32; STATE],
) -> Result<State, Error> {
let a_7 = self.extras[3];
@ -52,7 +52,7 @@ impl Compression {
#[allow(clippy::many_single_char_names)]
pub fn initialize_state<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
state: State,
) -> Result<State, Error> {
let a_7 = self.extras[3];
@ -106,7 +106,7 @@ impl Compression {
fn decompose_b<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
idx: i32,
b_val: u32,
) -> Result<RoundWordSpread, Error> {
@ -119,7 +119,7 @@ impl Compression {
fn decompose_c<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
idx: i32,
c_val: u32,
) -> Result<RoundWordSpread, Error> {
@ -132,7 +132,7 @@ impl Compression {
fn decompose_f<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
idx: i32,
f_val: u32,
) -> Result<RoundWordSpread, Error> {
@ -145,7 +145,7 @@ impl Compression {
fn decompose_g<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
idx: i32,
g_val: u32,
) -> Result<RoundWordSpread, Error> {

View File

@ -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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
idx: i32,
state: State,
schedule_word: (CellValue16, CellValue16),

View File

@ -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<Advice>,
extras: [Column<Advice>; 6],
@ -55,9 +53,9 @@ pub(super) struct MessageSchedule {
perm: Permutation,
}
impl<F: FieldExt> Table16Assignment<F> for MessageSchedule {}
impl<F: FieldExt> Table16Assignment<F> 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<F: FieldExt>(
&self,
layouter: &mut impl Layouter<Table16Chip<F>>,
layouter: &mut impl Layouter<F>,
input: [BlockWord; BLOCK_SIZE],
) -> Result<([MessageWord; ROUNDS], [(CellValue16, CellValue16); ROUNDS]), Error> {
let mut w = Vec::<MessageWord>::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<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)]
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<F>) -> 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<F>,
config: Self::Config,
) -> Result<(), Error> {
let mut layouter = layouter::SingleChip::<Table16Chip<F>, _>::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);

View File

@ -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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
word: u32,
word_idx: usize,
) -> Result<(Cell, (CellValue16, CellValue16)), Error> {

View File

@ -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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
input: &[BlockWord],
) -> Result<Vec<(CellValue16, CellValue16)>, Error> {
assert_eq!(input.len(), SUBREGION_1_LEN);
@ -42,7 +41,7 @@ impl MessageSchedule {
fn decompose_subregion1_word<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
word: u32,
index: usize,
) -> Result<Subregion1Word, Error> {
@ -92,7 +91,7 @@ impl MessageSchedule {
// (3, 4, 11, 14)-bit chunks
fn lower_sigma_0<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
word: Subregion1Word,
) -> Result<(CellValue16, CellValue16), Error> {
let a_3 = self.extras[0];

View File

@ -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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
lower_sigma_0_output: Vec<(CellValue16, CellValue16)>,
w: &mut Vec<MessageWord>,
w_halves: &mut Vec<(CellValue16, CellValue16)>,
@ -171,7 +169,7 @@ impl MessageSchedule {
fn decompose_subregion2_word<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
word: u32,
index: usize,
) -> Result<Subregion2Word, Error> {
@ -224,7 +222,7 @@ impl MessageSchedule {
#[allow(clippy::type_complexity)]
fn assign_lower_sigma_v2_pieces<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
subregion2_word: Subregion2Word,
) -> Result<(CellValue16, CellValue16), Error> {
let a_3 = self.extras[0];

View File

@ -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<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
lower_sigma_0_v2_output: Vec<(CellValue16, CellValue16)>,
w: &mut Vec<MessageWord>,
w_halves: &mut Vec<(CellValue16, CellValue16)>,
@ -150,7 +148,7 @@ impl MessageSchedule {
fn decompose_subregion3_word<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
word: u32,
index: usize,
) -> Result<Subregion3Word, Error> {
@ -189,7 +187,7 @@ impl MessageSchedule {
fn lower_sigma_1<F: FieldExt>(
&self,
region: &mut Region<'_, Table16Chip<F>>,
region: &mut Region<'_, F>,
word: Subregion3Word,
) -> Result<(CellValue16, CellValue16), Error> {
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::{
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<F: FieldExt>(
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<C: Chip>(
region: &mut Region<'_, C>,
pub(super) fn without_lookup<F: FieldExt>(
region: &mut Region<'_, F>,
dense_col: Column<Advice>,
dense_row: usize,
spread_col: Column<Advice>,
@ -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<Fixed>,
table_dense: Column<Fixed>,
table_spread: Column<Fixed>,
pub(super) tag: Column<Fixed>,
pub(super) dense: Column<Fixed>,
pub(super) spread: Column<Fixed>,
}
impl SpreadTable {
pub(super) fn configure<F: FieldExt>(
#[derive(Clone, Debug)]
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>,
tag: Column<Advice>,
dense: Column<Advice>,
spread: Column<Advice>,
) -> (SpreadInputs, Self) {
input_tag: Column<Advice>,
input_dense: Column<Advice>,
input_spread: Column<Advice>,
) -> <Self as Chip<F>>::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<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)> {
(1..=(1 << 16)).scan(
(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)]
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<Advice>, usize);
#[derive(Clone, Debug)]
struct MyConfig {
lookup_inputs: SpreadInputs,
sha256: Table16Config,
}
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 {
type Config = MyConfig;
type Config = SpreadTableConfig;
fn configure(meta: &mut ConstraintSystem<F>) -> MyConfig {
let a = meta.advice_column();
let b = meta.advice_column();
let c = meta.advice_column();
fn configure(meta: &mut ConstraintSystem<F>) -> 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<F>,
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(())
};