mirror of https://github.com/zcash/halo2.git
Fix SHA256 example
This commit is contained in:
parent
cae6f6af72
commit
fe2ab0bc7b
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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(())
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue