2021-01-08 00:10:55 -08:00
|
|
|
use super::{
|
|
|
|
super::DIGEST_SIZE, BlockWord, CellValue16, CellValue32, SpreadInputs, SpreadVar,
|
2021-04-20 04:26:32 -07:00
|
|
|
Table16Assignment, ROUNDS, STATE,
|
2021-01-08 00:10:55 -08:00
|
|
|
};
|
2021-02-25 11:50:50 -08:00
|
|
|
use halo2::{
|
2021-01-08 00:10:55 -08:00
|
|
|
circuit::Layouter,
|
2021-10-27 06:58:28 -07:00
|
|
|
pasta::pallas,
|
2021-10-27 05:00:43 -07:00
|
|
|
plonk::{Advice, Column, ConstraintSystem, Error, Selector},
|
2021-01-14 20:59:54 -08:00
|
|
|
poly::Rotation,
|
2021-01-08 00:10:55 -08:00
|
|
|
};
|
|
|
|
|
2021-01-14 20:59:54 -08:00
|
|
|
mod compression_gates;
|
2021-01-14 21:05:42 -08:00
|
|
|
mod compression_util;
|
2021-01-14 21:09:26 -08:00
|
|
|
mod subregion_digest;
|
2021-01-15 00:28:12 -08:00
|
|
|
mod subregion_initial;
|
2021-01-14 21:07:45 -08:00
|
|
|
mod subregion_main;
|
2021-01-08 00:10:55 -08:00
|
|
|
|
2021-01-14 20:59:54 -08:00
|
|
|
use compression_gates::CompressionGate;
|
2021-01-08 00:10:55 -08:00
|
|
|
|
|
|
|
/// A variable that represents the `[A,B,C,D]` words of the SHA-256 internal state.
|
|
|
|
///
|
|
|
|
/// The structure of this variable is influenced by the following factors:
|
|
|
|
/// - In `Σ_0(A)` we need `A` to be split into pieces `(a,b,c,d)` of lengths `(2,11,9,10)`
|
|
|
|
/// bits respectively (counting from the little end), as well as their spread forms.
|
|
|
|
/// - `Maj(A,B,C)` requires having the bits of each input in spread form. For `A` we can
|
|
|
|
/// reuse the pieces from `Σ_0(A)`. Since `B` and `C` are assigned from `A` and `B`
|
|
|
|
/// respectively in each round, we therefore also have the same pieces in earlier rows.
|
|
|
|
/// We align the columns to make it efficient to copy-constrain these forms where they
|
|
|
|
/// are needed.
|
2021-10-27 06:58:28 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2021-01-08 00:10:55 -08:00
|
|
|
pub struct AbcdVar {
|
|
|
|
idx: i32,
|
2021-07-19 07:23:20 -07:00
|
|
|
val: Option<u32>,
|
2021-01-08 00:10:55 -08:00
|
|
|
a: SpreadVar,
|
|
|
|
b: SpreadVar,
|
|
|
|
c_lo: SpreadVar,
|
|
|
|
c_mid: SpreadVar,
|
|
|
|
c_hi: SpreadVar,
|
|
|
|
d: SpreadVar,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A variable that represents the `[E,F,G,H]` words of the SHA-256 internal state.
|
|
|
|
///
|
|
|
|
/// The structure of this variable is influenced by the following factors:
|
|
|
|
/// - In `Σ_1(E)` we need `E` to be split into pieces `(a,b,c,d)` of lengths `(6,5,14,7)`
|
|
|
|
/// bits respectively (counting from the little end), as well as their spread forms.
|
|
|
|
/// - `Ch(E,F,G)` requires having the bits of each input in spread form. For `E` we can
|
|
|
|
/// reuse the pieces from `Σ_1(E)`. Since `F` and `G` are assigned from `E` and `F`
|
|
|
|
/// respectively in each round, we therefore also have the same pieces in earlier rows.
|
|
|
|
/// We align the columns to make it efficient to copy-constrain these forms where they
|
|
|
|
/// are needed.
|
2021-10-27 06:58:28 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2021-01-08 00:10:55 -08:00
|
|
|
pub struct EfghVar {
|
|
|
|
idx: i32,
|
2021-07-19 07:23:20 -07:00
|
|
|
val: Option<u32>,
|
2021-01-08 00:10:55 -08:00
|
|
|
a_lo: SpreadVar,
|
|
|
|
a_hi: SpreadVar,
|
|
|
|
b_lo: SpreadVar,
|
|
|
|
b_hi: SpreadVar,
|
|
|
|
c: SpreadVar,
|
|
|
|
d: SpreadVar,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct RoundWordDense {
|
|
|
|
dense_halves: (CellValue16, CellValue16),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RoundWordDense {
|
|
|
|
pub fn new(dense_halves: (CellValue16, CellValue16)) -> Self {
|
|
|
|
RoundWordDense { dense_halves }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct RoundWordSpread {
|
|
|
|
dense_halves: (CellValue16, CellValue16),
|
|
|
|
spread_halves: (CellValue32, CellValue32),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RoundWordSpread {
|
|
|
|
pub fn new(
|
|
|
|
dense_halves: (CellValue16, CellValue16),
|
|
|
|
spread_halves: (CellValue32, CellValue32),
|
|
|
|
) -> Self {
|
|
|
|
RoundWordSpread {
|
|
|
|
dense_halves,
|
|
|
|
spread_halves,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-16 08:33:22 -07:00
|
|
|
#[allow(clippy::from_over_into)]
|
2021-01-08 00:10:55 -08:00
|
|
|
impl Into<RoundWordDense> for RoundWordSpread {
|
|
|
|
fn into(self) -> RoundWordDense {
|
|
|
|
RoundWordDense::new(self.dense_halves)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct RoundWordA {
|
|
|
|
pieces: Option<AbcdVar>,
|
|
|
|
dense_halves: (CellValue16, CellValue16),
|
|
|
|
spread_halves: Option<(CellValue32, CellValue32)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RoundWordA {
|
|
|
|
pub fn new(
|
|
|
|
pieces: AbcdVar,
|
|
|
|
dense_halves: (CellValue16, CellValue16),
|
|
|
|
spread_halves: (CellValue32, CellValue32),
|
|
|
|
) -> Self {
|
|
|
|
RoundWordA {
|
|
|
|
pieces: Some(pieces),
|
|
|
|
dense_halves,
|
|
|
|
spread_halves: Some(spread_halves),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_dense(dense_halves: (CellValue16, CellValue16)) -> Self {
|
|
|
|
RoundWordA {
|
|
|
|
pieces: None,
|
|
|
|
dense_halves,
|
|
|
|
spread_halves: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-16 08:33:22 -07:00
|
|
|
#[allow(clippy::from_over_into)]
|
2021-01-08 00:10:55 -08:00
|
|
|
impl Into<RoundWordSpread> for RoundWordA {
|
|
|
|
fn into(self) -> RoundWordSpread {
|
|
|
|
RoundWordSpread::new(self.dense_halves, self.spread_halves.unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct RoundWordE {
|
|
|
|
pieces: Option<EfghVar>,
|
|
|
|
dense_halves: (CellValue16, CellValue16),
|
|
|
|
spread_halves: Option<(CellValue32, CellValue32)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RoundWordE {
|
|
|
|
pub fn new(
|
|
|
|
pieces: EfghVar,
|
|
|
|
dense_halves: (CellValue16, CellValue16),
|
|
|
|
spread_halves: (CellValue32, CellValue32),
|
|
|
|
) -> Self {
|
|
|
|
RoundWordE {
|
|
|
|
pieces: Some(pieces),
|
|
|
|
dense_halves,
|
|
|
|
spread_halves: Some(spread_halves),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_dense(dense_halves: (CellValue16, CellValue16)) -> Self {
|
|
|
|
RoundWordE {
|
|
|
|
pieces: None,
|
|
|
|
dense_halves,
|
|
|
|
spread_halves: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-16 08:33:22 -07:00
|
|
|
#[allow(clippy::from_over_into)]
|
2021-01-08 00:10:55 -08:00
|
|
|
impl Into<RoundWordSpread> for RoundWordE {
|
|
|
|
fn into(self) -> RoundWordSpread {
|
|
|
|
RoundWordSpread::new(self.dense_halves, self.spread_halves.unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The internal state for SHA-256.
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct State {
|
|
|
|
a: Option<StateWord>,
|
|
|
|
b: Option<StateWord>,
|
|
|
|
c: Option<StateWord>,
|
|
|
|
d: Option<StateWord>,
|
|
|
|
e: Option<StateWord>,
|
|
|
|
f: Option<StateWord>,
|
|
|
|
g: Option<StateWord>,
|
|
|
|
h: Option<StateWord>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl State {
|
2021-02-25 12:34:07 -08:00
|
|
|
#[allow(clippy::many_single_char_names)]
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-01-08 00:10:55 -08:00
|
|
|
pub fn new(
|
|
|
|
a: StateWord,
|
|
|
|
b: StateWord,
|
|
|
|
c: StateWord,
|
|
|
|
d: StateWord,
|
|
|
|
e: StateWord,
|
|
|
|
f: StateWord,
|
|
|
|
g: StateWord,
|
|
|
|
h: StateWord,
|
|
|
|
) -> Self {
|
|
|
|
State {
|
|
|
|
a: Some(a),
|
|
|
|
b: Some(b),
|
|
|
|
c: Some(c),
|
|
|
|
d: Some(d),
|
|
|
|
e: Some(e),
|
|
|
|
f: Some(f),
|
|
|
|
g: Some(g),
|
|
|
|
h: Some(h),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn empty_state() -> Self {
|
|
|
|
State {
|
|
|
|
a: None,
|
|
|
|
b: None,
|
|
|
|
c: None,
|
|
|
|
d: None,
|
|
|
|
e: None,
|
|
|
|
f: None,
|
|
|
|
g: None,
|
|
|
|
h: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub enum StateWord {
|
|
|
|
A(RoundWordA),
|
|
|
|
B(RoundWordSpread),
|
|
|
|
C(RoundWordSpread),
|
|
|
|
D(RoundWordDense),
|
|
|
|
E(RoundWordE),
|
|
|
|
F(RoundWordSpread),
|
|
|
|
G(RoundWordSpread),
|
|
|
|
H(RoundWordDense),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
2021-04-20 04:26:32 -07:00
|
|
|
pub(super) struct CompressionConfig {
|
2021-01-08 00:10:55 -08:00
|
|
|
lookup: SpreadInputs,
|
|
|
|
message_schedule: Column<Advice>,
|
|
|
|
extras: [Column<Advice>; 6],
|
|
|
|
|
2021-10-27 05:00:43 -07:00
|
|
|
s_ch: Selector,
|
|
|
|
s_ch_neg: Selector,
|
|
|
|
s_maj: Selector,
|
|
|
|
s_h_prime: Selector,
|
|
|
|
s_a_new: Selector,
|
|
|
|
s_e_new: Selector,
|
2021-01-08 00:10:55 -08:00
|
|
|
|
2021-10-27 05:00:43 -07:00
|
|
|
s_upper_sigma_0: Selector,
|
|
|
|
s_upper_sigma_1: Selector,
|
2021-01-08 00:10:55 -08:00
|
|
|
|
|
|
|
// Decomposition gate for AbcdVar
|
2021-10-27 05:00:43 -07:00
|
|
|
s_decompose_abcd: Selector,
|
2021-01-08 00:10:55 -08:00
|
|
|
// Decomposition gate for EfghVar
|
2021-10-27 05:00:43 -07:00
|
|
|
s_decompose_efgh: Selector,
|
2021-01-08 00:10:55 -08:00
|
|
|
|
2021-10-27 05:00:43 -07:00
|
|
|
s_digest: Selector,
|
2021-01-08 00:10:55 -08:00
|
|
|
}
|
|
|
|
|
2021-10-27 06:58:28 -07:00
|
|
|
impl Table16Assignment for CompressionConfig {}
|
2021-01-08 00:10:55 -08:00
|
|
|
|
2021-04-20 04:26:32 -07:00
|
|
|
impl CompressionConfig {
|
2021-10-27 06:58:28 -07:00
|
|
|
pub(super) fn configure(
|
|
|
|
meta: &mut ConstraintSystem<pallas::Base>,
|
2021-01-08 00:10:55 -08:00
|
|
|
lookup: SpreadInputs,
|
|
|
|
message_schedule: Column<Advice>,
|
|
|
|
extras: [Column<Advice>; 6],
|
|
|
|
) -> Self {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_ch = meta.selector();
|
|
|
|
let s_ch_neg = meta.selector();
|
|
|
|
let s_maj = meta.selector();
|
|
|
|
let s_h_prime = meta.selector();
|
|
|
|
let s_a_new = meta.selector();
|
|
|
|
let s_e_new = meta.selector();
|
2021-01-08 00:10:55 -08:00
|
|
|
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_upper_sigma_0 = meta.selector();
|
|
|
|
let s_upper_sigma_1 = meta.selector();
|
2021-01-08 00:10:55 -08:00
|
|
|
|
|
|
|
// Decomposition gate for AbcdVar
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_decompose_abcd = meta.selector();
|
2021-01-08 00:10:55 -08:00
|
|
|
// Decomposition gate for EfghVar
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_decompose_efgh = meta.selector();
|
2021-01-08 00:10:55 -08:00
|
|
|
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_digest = meta.selector();
|
2021-01-08 00:10:55 -08:00
|
|
|
|
|
|
|
// Rename these here for ease of matching the gates to the specification.
|
|
|
|
let a_0 = lookup.tag;
|
|
|
|
let a_1 = lookup.dense;
|
|
|
|
let a_2 = lookup.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];
|
|
|
|
|
2021-01-14 20:59:54 -08:00
|
|
|
// Decompose `A,B,C,D` words into (2, 11, 9, 10)-bit chunks.
|
|
|
|
// `c` is split into (3, 3, 3)-bit c_lo, c_mid, c_hi.
|
|
|
|
meta.create_gate("decompose ABCD", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_decompose_abcd = meta.query_selector(s_decompose_abcd);
|
2021-01-14 20:59:54 -08:00
|
|
|
let a = meta.query_advice(a_3, Rotation::next()); // 2-bit chunk
|
|
|
|
let spread_a = meta.query_advice(a_4, Rotation::next());
|
|
|
|
let b = meta.query_advice(a_1, Rotation::cur()); // 11-bit chunk
|
|
|
|
let spread_b = meta.query_advice(a_2, Rotation::cur());
|
|
|
|
let tag_b = meta.query_advice(a_0, Rotation::cur());
|
|
|
|
let c_lo = meta.query_advice(a_3, Rotation::cur()); // 3-bit chunk
|
|
|
|
let spread_c_lo = meta.query_advice(a_4, Rotation::cur());
|
|
|
|
let c_mid = meta.query_advice(a_5, Rotation::cur()); // 3-bit chunk
|
|
|
|
let spread_c_mid = meta.query_advice(a_6, Rotation::cur());
|
|
|
|
let c_hi = meta.query_advice(a_5, Rotation::next()); // 3-bit chunk
|
|
|
|
let spread_c_hi = meta.query_advice(a_6, Rotation::next());
|
|
|
|
let d = meta.query_advice(a_1, Rotation::next()); // 7-bit chunk
|
|
|
|
let spread_d = meta.query_advice(a_2, Rotation::next());
|
|
|
|
let tag_d = meta.query_advice(a_0, Rotation::next());
|
|
|
|
let word_lo = meta.query_advice(a_7, Rotation::cur());
|
|
|
|
let spread_word_lo = meta.query_advice(a_8, Rotation::cur());
|
|
|
|
let word_hi = meta.query_advice(a_7, Rotation::next());
|
|
|
|
let spread_word_hi = meta.query_advice(a_8, Rotation::next());
|
|
|
|
|
|
|
|
CompressionGate::s_decompose_abcd(
|
|
|
|
s_decompose_abcd,
|
|
|
|
a,
|
|
|
|
spread_a,
|
|
|
|
b,
|
|
|
|
spread_b,
|
|
|
|
tag_b,
|
|
|
|
c_lo,
|
|
|
|
spread_c_lo,
|
|
|
|
c_mid,
|
|
|
|
spread_c_mid,
|
|
|
|
c_hi,
|
|
|
|
spread_c_hi,
|
|
|
|
d,
|
|
|
|
spread_d,
|
|
|
|
tag_d,
|
|
|
|
word_lo,
|
|
|
|
spread_word_lo,
|
|
|
|
word_hi,
|
|
|
|
spread_word_hi,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// Decompose `E,F,G,H` words into (6, 5, 14, 7)-bit chunks.
|
|
|
|
// `a` is split into (3, 3)-bit a_lo, a_hi
|
|
|
|
// `b` is split into (2, 3)-bit b_lo, b_hi
|
|
|
|
meta.create_gate("Decompose EFGH", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_decompose_efgh = meta.query_selector(s_decompose_efgh);
|
2021-01-14 20:59:54 -08:00
|
|
|
let a_lo = meta.query_advice(a_3, Rotation::next()); // 3-bit chunk
|
|
|
|
let spread_a_lo = meta.query_advice(a_4, Rotation::next());
|
|
|
|
let a_hi = meta.query_advice(a_5, Rotation::next()); // 3-bit chunk
|
|
|
|
let spread_a_hi = meta.query_advice(a_6, Rotation::next());
|
|
|
|
let b_lo = meta.query_advice(a_3, Rotation::cur()); // 2-bit chunk
|
|
|
|
let spread_b_lo = meta.query_advice(a_4, Rotation::cur());
|
|
|
|
let b_hi = meta.query_advice(a_5, Rotation::cur()); // 3-bit chunk
|
|
|
|
let spread_b_hi = meta.query_advice(a_6, Rotation::cur());
|
|
|
|
let c = meta.query_advice(a_1, Rotation::next()); // 14-bit chunk
|
|
|
|
let spread_c = meta.query_advice(a_2, Rotation::next());
|
|
|
|
let tag_c = meta.query_advice(a_0, Rotation::next());
|
|
|
|
let d = meta.query_advice(a_1, Rotation::cur()); // 7-bit chunk
|
|
|
|
let spread_d = meta.query_advice(a_2, Rotation::cur());
|
|
|
|
let tag_d = meta.query_advice(a_0, Rotation::cur());
|
|
|
|
let word_lo = meta.query_advice(a_7, Rotation::cur());
|
|
|
|
let spread_word_lo = meta.query_advice(a_8, Rotation::cur());
|
|
|
|
let word_hi = meta.query_advice(a_7, Rotation::next());
|
|
|
|
let spread_word_hi = meta.query_advice(a_8, Rotation::next());
|
|
|
|
|
|
|
|
CompressionGate::s_decompose_efgh(
|
|
|
|
s_decompose_efgh,
|
|
|
|
a_lo,
|
|
|
|
spread_a_lo,
|
|
|
|
a_hi,
|
|
|
|
spread_a_hi,
|
|
|
|
b_lo,
|
|
|
|
spread_b_lo,
|
|
|
|
b_hi,
|
|
|
|
spread_b_hi,
|
|
|
|
c,
|
|
|
|
spread_c,
|
|
|
|
tag_c,
|
|
|
|
d,
|
|
|
|
spread_d,
|
|
|
|
tag_d,
|
|
|
|
word_lo,
|
|
|
|
spread_word_lo,
|
|
|
|
word_hi,
|
|
|
|
spread_word_hi,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// s_upper_sigma_0 on abcd words
|
|
|
|
// (2, 11, 9, 10)-bit chunks
|
|
|
|
meta.create_gate("s_upper_sigma_0", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_upper_sigma_0 = meta.query_selector(s_upper_sigma_0);
|
2021-01-14 20:59:54 -08:00
|
|
|
let spread_r0_even = meta.query_advice(a_2, Rotation::prev());
|
|
|
|
let spread_r0_odd = meta.query_advice(a_2, Rotation::cur());
|
|
|
|
let spread_r1_even = meta.query_advice(a_2, Rotation::next());
|
|
|
|
let spread_r1_odd = meta.query_advice(a_3, Rotation::cur());
|
|
|
|
|
|
|
|
let spread_a = meta.query_advice(a_3, Rotation::next());
|
|
|
|
let spread_b = meta.query_advice(a_5, Rotation::cur());
|
|
|
|
let spread_c_lo = meta.query_advice(a_3, Rotation::prev());
|
|
|
|
let spread_c_mid = meta.query_advice(a_4, Rotation::prev());
|
|
|
|
let spread_c_hi = meta.query_advice(a_4, Rotation::next());
|
|
|
|
let spread_d = meta.query_advice(a_4, Rotation::cur());
|
|
|
|
|
|
|
|
CompressionGate::s_upper_sigma_0(
|
|
|
|
s_upper_sigma_0,
|
|
|
|
spread_r0_even,
|
|
|
|
spread_r0_odd,
|
|
|
|
spread_r1_even,
|
|
|
|
spread_r1_odd,
|
|
|
|
spread_a,
|
|
|
|
spread_b,
|
|
|
|
spread_c_lo,
|
|
|
|
spread_c_mid,
|
|
|
|
spread_c_hi,
|
|
|
|
spread_d,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// s_upper_sigma_1 on efgh words
|
|
|
|
// (6, 5, 14, 7)-bit chunks
|
|
|
|
meta.create_gate("s_upper_sigma_1", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_upper_sigma_1 = meta.query_selector(s_upper_sigma_1);
|
2021-01-14 20:59:54 -08:00
|
|
|
let spread_r0_even = meta.query_advice(a_2, Rotation::prev());
|
|
|
|
let spread_r0_odd = meta.query_advice(a_2, Rotation::cur());
|
|
|
|
let spread_r1_even = meta.query_advice(a_2, Rotation::next());
|
|
|
|
let spread_r1_odd = meta.query_advice(a_3, Rotation::cur());
|
|
|
|
let spread_a_lo = meta.query_advice(a_3, Rotation::next());
|
|
|
|
let spread_a_hi = meta.query_advice(a_4, Rotation::next());
|
|
|
|
let spread_b_lo = meta.query_advice(a_3, Rotation::prev());
|
|
|
|
let spread_b_hi = meta.query_advice(a_4, Rotation::prev());
|
|
|
|
let spread_c = meta.query_advice(a_5, Rotation::cur());
|
|
|
|
let spread_d = meta.query_advice(a_4, Rotation::cur());
|
|
|
|
|
|
|
|
CompressionGate::s_upper_sigma_1(
|
|
|
|
s_upper_sigma_1,
|
|
|
|
spread_r0_even,
|
|
|
|
spread_r0_odd,
|
|
|
|
spread_r1_even,
|
|
|
|
spread_r1_odd,
|
|
|
|
spread_a_lo,
|
|
|
|
spread_a_hi,
|
|
|
|
spread_b_lo,
|
|
|
|
spread_b_hi,
|
|
|
|
spread_c,
|
|
|
|
spread_d,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// s_ch on efgh words
|
|
|
|
// First part of choice gate on (E, F, G), E ∧ F
|
|
|
|
meta.create_gate("s_ch", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_ch = meta.query_selector(s_ch);
|
2021-01-14 20:59:54 -08:00
|
|
|
let spread_p0_even = meta.query_advice(a_2, Rotation::prev());
|
|
|
|
let spread_p0_odd = meta.query_advice(a_2, Rotation::cur());
|
|
|
|
let spread_p1_even = meta.query_advice(a_2, Rotation::next());
|
|
|
|
let spread_p1_odd = meta.query_advice(a_3, Rotation::cur());
|
|
|
|
let spread_e_lo = meta.query_advice(a_3, Rotation::prev());
|
|
|
|
let spread_e_hi = meta.query_advice(a_4, Rotation::prev());
|
|
|
|
let spread_f_lo = meta.query_advice(a_3, Rotation::next());
|
|
|
|
let spread_f_hi = meta.query_advice(a_4, Rotation::next());
|
|
|
|
|
|
|
|
CompressionGate::s_ch(
|
|
|
|
s_ch,
|
|
|
|
spread_p0_even,
|
|
|
|
spread_p0_odd,
|
|
|
|
spread_p1_even,
|
|
|
|
spread_p1_odd,
|
|
|
|
spread_e_lo,
|
|
|
|
spread_e_hi,
|
|
|
|
spread_f_lo,
|
|
|
|
spread_f_hi,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// s_ch_neg on efgh words
|
|
|
|
// Second part of Choice gate on (E, F, G), ¬E ∧ G
|
|
|
|
meta.create_gate("s_ch_neg", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_ch_neg = meta.query_selector(s_ch_neg);
|
2021-01-14 20:59:54 -08:00
|
|
|
let spread_q0_even = meta.query_advice(a_2, Rotation::prev());
|
|
|
|
let spread_q0_odd = meta.query_advice(a_2, Rotation::cur());
|
|
|
|
let spread_q1_even = meta.query_advice(a_2, Rotation::next());
|
|
|
|
let spread_q1_odd = meta.query_advice(a_3, Rotation::cur());
|
|
|
|
let spread_e_lo = meta.query_advice(a_5, Rotation::prev());
|
|
|
|
let spread_e_hi = meta.query_advice(a_5, Rotation::cur());
|
|
|
|
let spread_e_neg_lo = meta.query_advice(a_3, Rotation::prev());
|
|
|
|
let spread_e_neg_hi = meta.query_advice(a_4, Rotation::prev());
|
|
|
|
let spread_g_lo = meta.query_advice(a_3, Rotation::next());
|
|
|
|
let spread_g_hi = meta.query_advice(a_4, Rotation::next());
|
|
|
|
|
|
|
|
CompressionGate::s_ch_neg(
|
|
|
|
s_ch_neg,
|
|
|
|
spread_q0_even,
|
|
|
|
spread_q0_odd,
|
|
|
|
spread_q1_even,
|
|
|
|
spread_q1_odd,
|
|
|
|
spread_e_lo,
|
|
|
|
spread_e_hi,
|
|
|
|
spread_e_neg_lo,
|
|
|
|
spread_e_neg_hi,
|
|
|
|
spread_g_lo,
|
|
|
|
spread_g_hi,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// s_maj on abcd words
|
|
|
|
meta.create_gate("s_maj", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_maj = meta.query_selector(s_maj);
|
2021-01-14 20:59:54 -08:00
|
|
|
let spread_m0_even = meta.query_advice(a_2, Rotation::prev());
|
|
|
|
let spread_m0_odd = meta.query_advice(a_2, Rotation::cur());
|
|
|
|
let spread_m1_even = meta.query_advice(a_2, Rotation::next());
|
|
|
|
let spread_m1_odd = meta.query_advice(a_3, Rotation::cur());
|
|
|
|
let spread_a_lo = meta.query_advice(a_4, Rotation::prev());
|
|
|
|
let spread_a_hi = meta.query_advice(a_5, Rotation::prev());
|
|
|
|
let spread_b_lo = meta.query_advice(a_4, Rotation::cur());
|
|
|
|
let spread_b_hi = meta.query_advice(a_5, Rotation::cur());
|
|
|
|
let spread_c_lo = meta.query_advice(a_4, Rotation::next());
|
|
|
|
let spread_c_hi = meta.query_advice(a_5, Rotation::next());
|
|
|
|
|
|
|
|
CompressionGate::s_maj(
|
|
|
|
s_maj,
|
|
|
|
spread_m0_even,
|
|
|
|
spread_m0_odd,
|
|
|
|
spread_m1_even,
|
|
|
|
spread_m1_odd,
|
|
|
|
spread_a_lo,
|
|
|
|
spread_a_hi,
|
|
|
|
spread_b_lo,
|
|
|
|
spread_b_hi,
|
|
|
|
spread_c_lo,
|
|
|
|
spread_c_hi,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// s_h_prime to compute H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W
|
|
|
|
meta.create_gate("s_h_prime", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_h_prime = meta.query_selector(s_h_prime);
|
2021-01-14 20:59:54 -08:00
|
|
|
let h_prime_lo = meta.query_advice(a_7, Rotation::next());
|
|
|
|
let h_prime_hi = meta.query_advice(a_8, Rotation::next());
|
|
|
|
let h_prime_carry = meta.query_advice(a_9, Rotation::next());
|
|
|
|
let sigma_e_lo = meta.query_advice(a_4, Rotation::cur());
|
|
|
|
let sigma_e_hi = meta.query_advice(a_5, Rotation::cur());
|
|
|
|
let ch_lo = meta.query_advice(a_1, Rotation::cur());
|
|
|
|
let ch_hi = meta.query_advice(a_6, Rotation::next());
|
|
|
|
let ch_neg_lo = meta.query_advice(a_5, Rotation::prev());
|
|
|
|
let ch_neg_hi = meta.query_advice(a_5, Rotation::next());
|
|
|
|
let h_lo = meta.query_advice(a_7, Rotation::prev());
|
|
|
|
let h_hi = meta.query_advice(a_7, Rotation::cur());
|
|
|
|
let k_lo = meta.query_advice(a_6, Rotation::prev());
|
|
|
|
let k_hi = meta.query_advice(a_6, Rotation::cur());
|
|
|
|
let w_lo = meta.query_advice(a_8, Rotation::prev());
|
|
|
|
let w_hi = meta.query_advice(a_8, Rotation::cur());
|
|
|
|
|
|
|
|
CompressionGate::s_h_prime(
|
|
|
|
s_h_prime,
|
|
|
|
h_prime_lo,
|
|
|
|
h_prime_hi,
|
|
|
|
h_prime_carry,
|
|
|
|
sigma_e_lo,
|
|
|
|
sigma_e_hi,
|
|
|
|
ch_lo,
|
|
|
|
ch_hi,
|
|
|
|
ch_neg_lo,
|
|
|
|
ch_neg_hi,
|
|
|
|
h_lo,
|
|
|
|
h_hi,
|
|
|
|
k_lo,
|
|
|
|
k_hi,
|
|
|
|
w_lo,
|
|
|
|
w_hi,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// s_a_new
|
|
|
|
meta.create_gate("s_a_new", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_a_new = meta.query_selector(s_a_new);
|
2021-01-14 20:59:54 -08:00
|
|
|
let a_new_lo = meta.query_advice(a_8, Rotation::cur());
|
|
|
|
let a_new_hi = meta.query_advice(a_8, Rotation::next());
|
|
|
|
let a_new_carry = meta.query_advice(a_9, Rotation::cur());
|
|
|
|
let sigma_a_lo = meta.query_advice(a_6, Rotation::cur());
|
|
|
|
let sigma_a_hi = meta.query_advice(a_6, Rotation::next());
|
|
|
|
let maj_abc_lo = meta.query_advice(a_1, Rotation::cur());
|
|
|
|
let maj_abc_hi = meta.query_advice(a_3, Rotation::prev());
|
|
|
|
let h_prime_lo = meta.query_advice(a_7, Rotation::prev());
|
|
|
|
let h_prime_hi = meta.query_advice(a_8, Rotation::prev());
|
|
|
|
|
|
|
|
CompressionGate::s_a_new(
|
|
|
|
s_a_new,
|
|
|
|
a_new_lo,
|
|
|
|
a_new_hi,
|
|
|
|
a_new_carry,
|
|
|
|
sigma_a_lo,
|
|
|
|
sigma_a_hi,
|
|
|
|
maj_abc_lo,
|
|
|
|
maj_abc_hi,
|
|
|
|
h_prime_lo,
|
|
|
|
h_prime_hi,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// s_e_new
|
|
|
|
meta.create_gate("s_e_new", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_e_new = meta.query_selector(s_e_new);
|
2021-01-14 20:59:54 -08:00
|
|
|
let e_new_lo = meta.query_advice(a_8, Rotation::cur());
|
|
|
|
let e_new_hi = meta.query_advice(a_8, Rotation::next());
|
|
|
|
let e_new_carry = meta.query_advice(a_9, Rotation::next());
|
|
|
|
let d_lo = meta.query_advice(a_7, Rotation::cur());
|
|
|
|
let d_hi = meta.query_advice(a_7, Rotation::next());
|
|
|
|
let h_prime_lo = meta.query_advice(a_7, Rotation::prev());
|
|
|
|
let h_prime_hi = meta.query_advice(a_8, Rotation::prev());
|
|
|
|
|
|
|
|
CompressionGate::s_e_new(
|
|
|
|
s_e_new,
|
|
|
|
e_new_lo,
|
|
|
|
e_new_hi,
|
|
|
|
e_new_carry,
|
|
|
|
d_lo,
|
|
|
|
d_hi,
|
|
|
|
h_prime_lo,
|
|
|
|
h_prime_hi,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
// s_digest for final round
|
|
|
|
meta.create_gate("s_digest", |meta| {
|
2021-10-27 05:00:43 -07:00
|
|
|
let s_digest = meta.query_selector(s_digest);
|
2021-01-14 20:59:54 -08:00
|
|
|
let lo_0 = meta.query_advice(a_3, Rotation::cur());
|
|
|
|
let hi_0 = meta.query_advice(a_4, Rotation::cur());
|
|
|
|
let word_0 = meta.query_advice(a_5, Rotation::cur());
|
|
|
|
let lo_1 = meta.query_advice(a_6, Rotation::cur());
|
|
|
|
let hi_1 = meta.query_advice(a_7, Rotation::cur());
|
|
|
|
let word_1 = meta.query_advice(a_8, Rotation::cur());
|
|
|
|
let lo_2 = meta.query_advice(a_3, Rotation::next());
|
|
|
|
let hi_2 = meta.query_advice(a_4, Rotation::next());
|
|
|
|
let word_2 = meta.query_advice(a_5, Rotation::next());
|
|
|
|
let lo_3 = meta.query_advice(a_6, Rotation::next());
|
|
|
|
let hi_3 = meta.query_advice(a_7, Rotation::next());
|
|
|
|
let word_3 = meta.query_advice(a_8, Rotation::next());
|
|
|
|
|
|
|
|
CompressionGate::s_digest(
|
|
|
|
s_digest, lo_0, hi_0, word_0, lo_1, hi_1, word_1, lo_2, hi_2, word_2, lo_3, hi_3,
|
|
|
|
word_3,
|
|
|
|
)
|
|
|
|
});
|
2021-01-08 00:10:55 -08:00
|
|
|
|
2021-04-20 04:26:32 -07:00
|
|
|
CompressionConfig {
|
2021-01-08 00:10:55 -08:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Initialize compression with a constant Initialization Vector of 32-byte words.
|
|
|
|
/// Returns an initialized state.
|
2021-10-27 06:58:28 -07:00
|
|
|
pub(super) fn initialize_with_iv(
|
2021-01-08 00:10:55 -08:00
|
|
|
&self,
|
2021-10-27 06:58:28 -07:00
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
2021-01-08 00:10:55 -08:00
|
|
|
init_state: [u32; STATE],
|
|
|
|
) -> Result<State, Error> {
|
|
|
|
let mut new_state = State::empty_state();
|
2021-01-15 00:28:12 -08:00
|
|
|
layouter.assign_region(
|
|
|
|
|| "initialize_with_iv",
|
|
|
|
|mut region| {
|
|
|
|
new_state = self.initialize_iv(&mut region, init_state)?;
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
)?;
|
|
|
|
Ok(new_state)
|
2021-01-08 00:10:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Initialize compression with some initialized state. This could be a state
|
|
|
|
/// output from a previous compression round.
|
2021-10-27 06:58:28 -07:00
|
|
|
pub(super) fn initialize_with_state(
|
2021-01-08 00:10:55 -08:00
|
|
|
&self,
|
2021-10-27 06:58:28 -07:00
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
2021-01-08 00:10:55 -08:00
|
|
|
init_state: State,
|
|
|
|
) -> Result<State, Error> {
|
|
|
|
let mut new_state = State::empty_state();
|
2021-01-15 00:28:12 -08:00
|
|
|
layouter.assign_region(
|
|
|
|
|| "initialize_with_state",
|
|
|
|
|mut region| {
|
|
|
|
new_state = self.initialize_state(&mut region, init_state.clone())?;
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
)?;
|
|
|
|
Ok(new_state)
|
2021-01-08 00:10:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Given an initialized state and a message schedule, perform 64 compression rounds.
|
2021-10-27 06:58:28 -07:00
|
|
|
pub(super) fn compress(
|
2021-01-08 00:10:55 -08:00
|
|
|
&self,
|
2021-10-27 06:58:28 -07:00
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
2021-01-08 00:10:55 -08:00
|
|
|
initialized_state: State,
|
|
|
|
w_halves: [(CellValue16, CellValue16); ROUNDS],
|
|
|
|
) -> Result<State, Error> {
|
|
|
|
let mut state = State::empty_state();
|
2021-01-14 21:07:45 -08:00
|
|
|
layouter.assign_region(
|
|
|
|
|| "compress",
|
|
|
|
|mut region| {
|
|
|
|
state = initialized_state.clone();
|
|
|
|
for idx in 0..64 {
|
2021-10-27 06:58:28 -07:00
|
|
|
state = self.assign_round(
|
|
|
|
&mut region,
|
|
|
|
idx,
|
|
|
|
state.clone(),
|
|
|
|
&w_halves[idx as usize],
|
|
|
|
)?;
|
2021-01-14 21:07:45 -08:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
)?;
|
|
|
|
Ok(state)
|
2021-01-08 00:10:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// After the final round, convert the state into the final digest.
|
2021-10-27 06:58:28 -07:00
|
|
|
pub(super) fn digest(
|
2021-01-08 00:10:55 -08:00
|
|
|
&self,
|
2021-10-27 06:58:28 -07:00
|
|
|
layouter: &mut impl Layouter<pallas::Base>,
|
2021-01-08 00:10:55 -08:00
|
|
|
state: State,
|
|
|
|
) -> Result<[BlockWord; DIGEST_SIZE], Error> {
|
2021-07-19 07:23:20 -07:00
|
|
|
let mut digest = [BlockWord(Some(0)); DIGEST_SIZE];
|
2021-01-14 21:09:26 -08:00
|
|
|
layouter.assign_region(
|
|
|
|
|| "digest",
|
|
|
|
|mut region| {
|
|
|
|
digest = self.assign_digest(&mut region, state.clone())?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
)?;
|
|
|
|
Ok(digest)
|
2021-01-08 00:10:55 -08:00
|
|
|
}
|
|
|
|
}
|
2021-01-14 19:56:29 -08:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::super::{
|
2021-07-19 07:23:20 -07:00
|
|
|
super::BLOCK_SIZE, msg_schedule_test_input, BlockWord, Table16Chip, Table16Config, IV,
|
2021-01-14 19:56:29 -08:00
|
|
|
};
|
2021-02-25 11:50:50 -08:00
|
|
|
use halo2::{
|
2021-07-16 08:33:22 -07:00
|
|
|
circuit::{Layouter, SimpleFloorPlanner},
|
2021-01-14 19:56:29 -08:00
|
|
|
dev::MockProver,
|
2021-10-27 06:58:28 -07:00
|
|
|
pasta::pallas,
|
2021-07-16 08:33:22 -07:00
|
|
|
plonk::{Circuit, ConstraintSystem, Error},
|
2021-01-14 19:56:29 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn compress() {
|
|
|
|
struct MyCircuit {}
|
|
|
|
|
2021-10-27 06:58:28 -07:00
|
|
|
impl Circuit<pallas::Base> for MyCircuit {
|
2021-01-14 19:56:29 -08:00
|
|
|
type Config = Table16Config;
|
2021-07-16 08:33:22 -07:00
|
|
|
type FloorPlanner = SimpleFloorPlanner;
|
|
|
|
|
|
|
|
fn without_witnesses(&self) -> Self {
|
|
|
|
MyCircuit {}
|
|
|
|
}
|
2021-01-14 19:56:29 -08:00
|
|
|
|
2021-10-27 06:58:28 -07:00
|
|
|
fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
|
2021-04-20 04:26:32 -07:00
|
|
|
Table16Chip::configure(meta)
|
2021-01-14 19:56:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn synthesize(
|
|
|
|
&self,
|
|
|
|
config: Self::Config,
|
2021-10-27 06:58:28 -07:00
|
|
|
mut layouter: impl Layouter<pallas::Base>,
|
2021-01-14 19:56:29 -08:00
|
|
|
) -> Result<(), Error> {
|
2021-10-27 06:58:28 -07:00
|
|
|
Table16Chip::load(config.clone(), &mut layouter)?;
|
2021-01-14 19:56:29 -08:00
|
|
|
|
|
|
|
// Test vector: "abc"
|
2021-07-19 07:23:20 -07:00
|
|
|
let input: [BlockWord; BLOCK_SIZE] = msg_schedule_test_input();
|
2021-01-14 19:56:29 -08:00
|
|
|
|
|
|
|
let (_, w_halves) = config.message_schedule.process(&mut layouter, input)?;
|
|
|
|
|
|
|
|
let compression = config.compression.clone();
|
|
|
|
let initial_state = compression.initialize_with_iv(&mut layouter, IV)?;
|
|
|
|
|
|
|
|
let state =
|
|
|
|
config
|
|
|
|
.compression
|
|
|
|
.compress(&mut layouter, initial_state.clone(), w_halves)?;
|
|
|
|
|
|
|
|
let digest = config.compression.digest(&mut layouter, state)?;
|
|
|
|
for (idx, digest_word) in digest.iter().enumerate() {
|
|
|
|
assert_eq!(
|
2021-07-19 07:23:20 -07:00
|
|
|
(digest_word.0.unwrap() as u64 + IV[idx] as u64) as u32,
|
2021-01-14 19:56:29 -08:00
|
|
|
super::compression_util::COMPRESSION_OUTPUT[idx]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let circuit: MyCircuit = MyCircuit {};
|
|
|
|
|
2021-10-27 06:58:28 -07:00
|
|
|
let prover = match MockProver::<pallas::Base>::run(17, &circuit, vec![]) {
|
2021-01-14 19:56:29 -08:00
|
|
|
Ok(prover) => prover,
|
|
|
|
Err(e) => panic!("{:?}", e),
|
|
|
|
};
|
|
|
|
assert_eq!(prover.verify(), Ok(()));
|
|
|
|
}
|
|
|
|
}
|