Remove unwrap()s in synthesis.

This commit is contained in:
therealyingtong 2021-07-19 22:23:20 +08:00
parent 66268cf192
commit ee5bc8184a
15 changed files with 1069 additions and 731 deletions

View File

@ -47,21 +47,22 @@ fn bench(name: &str, k: u32, c: &mut Criterion) {
// Test vector: "abc"
let test_input = [
BlockWord::new(0b01100001011000100110001110000000),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord(Some(0b01100001011000100110001110000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000011000)),
];
// Create a message of length 31 blocks

View File

@ -28,10 +28,7 @@ pub trait Sha256Instructions<F: FieldExt>: Chip<F> {
type State: Clone + fmt::Debug;
/// Variable representing a 32-bit word of the input block to the SHA-256 compression
/// function.
type BlockWord: Copy + fmt::Debug;
/// The zero BlockWord
fn zero() -> Self::BlockWord;
type BlockWord: Copy + fmt::Debug + Default;
/// Places the SHA-256 IV in the circuit, returning the initial state variable.
fn initialization_vector(&self, layouter: &mut impl Layouter<F>) -> Result<Self::State, Error>;
@ -140,7 +137,7 @@ impl<F: FieldExt, Sha256Chip: Sha256Instructions<F>> Sha256<F, Sha256Chip> {
) -> Result<Sha256Digest<Sha256Chip::BlockWord>, Error> {
// Pad the remaining block
if !self.cur_block.is_empty() {
let padding = vec![Sha256Chip::zero(); BLOCK_SIZE - self.cur_block.len()];
let padding = vec![Sha256Chip::BlockWord::default(); BLOCK_SIZE - self.cur_block.len()];
self.cur_block.extend_from_slice(&padding);
self.state = self.chip.initialization(&mut layouter, &self.state)?;
self.state = self.chip.compress(

View File

@ -44,21 +44,13 @@ const IV: [u32; STATE] = [
0x5be0_cd19,
];
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Default)]
/// A word in a `Table16` message block.
pub struct BlockWord {
var: (),
value: Option<u32>,
}
pub struct BlockWord(pub(crate) Option<u32>);
impl BlockWord {
/// Create a new `BlockWord`.
pub fn new(value: u32) -> Self {
BlockWord {
var: (),
value: Some(value),
}
}
pub trait CellValue<T> {
fn var(&self) -> Cell;
fn value(&self) -> Option<T>;
}
#[derive(Clone, Copy, Debug)]
@ -67,12 +59,18 @@ pub struct CellValue16 {
value: Option<u16>,
}
impl<F: FieldExt> CellValue<F> for CellValue16 {
fn var(&self) -> Cell {
self.var
}
fn value(&self) -> Option<F> {
self.value.map(|value| F::from_u64(value as u64))
}
}
impl CellValue16 {
pub fn new(var: Cell, value: u16) -> Self {
CellValue16 {
var,
value: Some(value),
}
pub fn new(var: Cell, value: Option<u16>) -> Self {
CellValue16 { var, value }
}
}
@ -83,18 +81,24 @@ pub struct CellValue32 {
}
impl CellValue32 {
pub fn new(var: Cell, value: u32) -> Self {
CellValue32 {
var,
value: Some(value),
}
pub fn new(var: Cell, value: Option<u32>) -> Self {
CellValue32 { var, value }
}
}
impl<F: FieldExt> CellValue<F> for CellValue32 {
fn var(&self) -> Cell {
self.var
}
fn value(&self) -> Option<F> {
self.value.map(|value| F::from_u64(value as u64))
}
}
#[allow(clippy::from_over_into)]
impl Into<CellValue32> for CellValue16 {
fn into(self) -> CellValue32 {
CellValue32::new(self.var, self.value.unwrap() as u32)
CellValue32::new(self.var, self.value.map(|value| value as u32))
}
}
@ -193,10 +197,6 @@ impl<F: FieldExt> Sha256Instructions<F> for Table16Chip<F> {
type State = State;
type BlockWord = BlockWord;
fn zero() -> Self::BlockWord {
BlockWord::new(0)
}
fn initialization_vector(&self, layouter: &mut impl Layouter<F>) -> Result<State, Error> {
self.config().compression.initialize_with_iv(layouter, IV)
}
@ -248,34 +248,43 @@ trait Table16Assignment<F: FieldExt> {
lookup: &SpreadInputs,
a_3: Column<Advice>,
row: usize,
r_0_even: u16,
r_0_odd: u16,
r_1_even: u16,
r_1_odd: u16,
r_0_even: Option<u16>,
r_0_odd: Option<u16>,
r_1_even: Option<u16>,
r_1_odd: Option<u16>,
) -> Result<((CellValue16, CellValue16), (CellValue16, CellValue16)), Error> {
// Lookup R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd}
let r_0_even = SpreadVar::with_lookup(region, lookup, row - 1, SpreadWord::new(r_0_even))?;
let r_0_odd = SpreadVar::with_lookup(region, lookup, row, SpreadWord::new(r_0_odd))?;
let r_1_even = SpreadVar::with_lookup(region, lookup, row + 1, SpreadWord::new(r_1_even))?;
let r_1_odd = SpreadVar::with_lookup(region, lookup, row + 2, SpreadWord::new(r_1_odd))?;
let r_0_even =
SpreadVar::with_lookup(region, lookup, row - 1, SpreadWord::opt_new(r_0_even))?;
let r_0_odd = SpreadVar::with_lookup(region, lookup, row, SpreadWord::opt_new(r_0_odd))?;
let r_1_even =
SpreadVar::with_lookup(region, lookup, row + 1, SpreadWord::opt_new(r_1_even))?;
let r_1_odd =
SpreadVar::with_lookup(region, lookup, row + 2, SpreadWord::opt_new(r_1_odd))?;
// Assign and copy R_1^{odd}
let r_1_odd_spread = region.assign_advice(
|| "Assign and copy R_1^{odd}",
a_3,
row,
|| Ok(F::from_u64(r_1_odd.spread.value.unwrap().into())),
|| {
r_1_odd
.spread
.value
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.constrain_equal(r_1_odd.spread.var, r_1_odd_spread)?;
Ok((
(
CellValue16::new(r_0_even.dense.var, r_0_even.dense.value.unwrap()),
CellValue16::new(r_1_even.dense.var, r_1_even.dense.value.unwrap()),
CellValue16::new(r_0_even.dense.var, r_0_even.dense.value),
CellValue16::new(r_1_even.dense.var, r_1_even.dense.value),
),
(
CellValue16::new(r_0_odd.dense.var, r_0_odd.dense.value.unwrap()),
CellValue16::new(r_1_odd.dense.var, r_1_odd.dense.value.unwrap()),
CellValue16::new(r_0_odd.dense.var, r_0_odd.dense.value),
CellValue16::new(r_1_odd.dense.var, r_1_odd.dense.value),
),
))
}
@ -288,10 +297,10 @@ trait Table16Assignment<F: FieldExt> {
lookup: &SpreadInputs,
a_3: Column<Advice>,
row: usize,
r_0_even: u16,
r_0_odd: u16,
r_1_even: u16,
r_1_odd: u16,
r_0_even: Option<u16>,
r_0_odd: Option<u16>,
r_1_even: Option<u16>,
r_1_odd: Option<u16>,
) -> Result<(CellValue16, CellValue16), Error> {
let (even, _odd) = self.assign_spread_outputs(
region, lookup, a_3, row, r_0_even, r_0_odd, r_1_even, r_1_odd,
@ -307,16 +316,16 @@ trait Table16Assignment<F: FieldExt> {
annotation: A,
column: Column<Advice>,
row: usize,
copy: &CellValue32,
copy: impl CellValue<F>,
) -> Result<Cell, Error>
where
A: Fn() -> AR,
AR: Into<String>,
{
let cell = region.assign_advice(annotation, column, row, || {
Ok(F::from_u64(copy.value.unwrap() as u64))
copy.value().ok_or(Error::SynthesisError)
})?;
region.constrain_equal(cell, copy.var)?;
region.constrain_equal(cell, copy.var())?;
Ok(cell)
}
}
@ -324,7 +333,7 @@ trait Table16Assignment<F: FieldExt> {
#[cfg(test)]
mod tests {
use super::super::{BlockWord, Sha256, BLOCK_SIZE};
use super::{Table16Chip, Table16Config};
use super::{message_schedule::msg_schedule_test_input, Table16Chip, Table16Config};
use halo2::{
arithmetic::FieldExt,
circuit::{Layouter, SimpleFloorPlanner},
@ -358,23 +367,7 @@ mod tests {
Table16Chip::<F>::load(config, &mut layouter)?;
// Test vector: "abc"
let test_input = [
BlockWord::new(0b01100001011000100110001110000000),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
];
let test_input = msg_schedule_test_input();
// Create a message of length 31 blocks
let mut input = Vec::with_capacity(31 * BLOCK_SIZE);
@ -419,23 +412,7 @@ mod tests {
Table16Chip::<F>::load(config, &mut layouter)?;
// Test vector: "abc"
let test_input = [
BlockWord::new(0b01100001011000100110001110000000),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
BlockWord::new(0),
];
let test_input = msg_schedule_test_input();
// Create a message of length 2 blocks
let mut input = Vec::with_capacity(2 * BLOCK_SIZE);

View File

@ -30,7 +30,7 @@ use compression_gates::CompressionGate;
#[derive(Copy, Clone, Debug)]
pub struct AbcdVar {
idx: i32,
val: u32,
val: Option<u32>,
a: SpreadVar,
b: SpreadVar,
c_lo: SpreadVar,
@ -52,7 +52,7 @@ pub struct AbcdVar {
#[derive(Copy, Clone, Debug)]
pub struct EfghVar {
idx: i32,
val: u32,
val: Option<u32>,
a_lo: SpreadVar,
a_hi: SpreadVar,
b_lo: SpreadVar,
@ -727,7 +727,7 @@ impl CompressionConfig {
layouter: &mut impl Layouter<F>,
state: State,
) -> Result<[BlockWord; DIGEST_SIZE], Error> {
let mut digest = [BlockWord::new(0); DIGEST_SIZE];
let mut digest = [BlockWord(Some(0)); DIGEST_SIZE];
layouter.assign_region(
|| "digest",
|mut region| {
@ -743,7 +743,7 @@ impl CompressionConfig {
#[cfg(test)]
mod tests {
use super::super::{
super::BLOCK_SIZE, get_msg_schedule_test_input, BlockWord, Table16Chip, Table16Config, IV,
super::BLOCK_SIZE, msg_schedule_test_input, BlockWord, Table16Chip, Table16Config, IV,
};
use halo2::{
arithmetic::FieldExt,
@ -777,7 +777,7 @@ mod tests {
Table16Chip::<F>::load(config.clone(), &mut layouter)?;
// Test vector: "abc"
let input: [BlockWord; BLOCK_SIZE] = get_msg_schedule_test_input();
let input: [BlockWord; BLOCK_SIZE] = msg_schedule_test_input();
let (_, w_halves) = config.message_schedule.process(&mut layouter, input)?;
@ -792,7 +792,7 @@ mod tests {
let digest = config.compression.digest(&mut layouter, state)?;
for (idx, digest_word) in digest.iter().enumerate() {
assert_eq!(
(digest_word.value.unwrap() as u64 + IV[idx] as u64) as u32,
(digest_word.0.unwrap() as u64 + IV[idx] as u64) as u32,
super::compression_util::COMPRESSION_OUTPUT[idx]
);
}

View File

@ -1,10 +1,10 @@
use super::super::{
util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, StateWord, Table16Assignment,
};
use super::{
AbcdVar, CompressionConfig, EfghVar, RoundWordA, RoundWordDense, RoundWordE, RoundWordSpread,
State,
};
use crate::table16::{
util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, StateWord, Table16Assignment,
};
use halo2::{
arithmetic::FieldExt,
circuit::Region,
@ -149,7 +149,7 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
row: usize,
a_val: u32,
a_val: Option<u32>,
) -> Result<
(
SpreadVar,
@ -173,10 +173,13 @@ impl CompressionConfig {
let a_5 = self.message_schedule;
let a_6 = self.extras[2];
let a_spread_pieces = chop_u32(a_val, &[2, 11, 3, 3, 3, 10])
.iter()
.map(|piece| SpreadWord::new(*piece as u16))
.collect::<Vec<_>>();
let a_spread_pieces = a_val.map(|a_val| {
chop_u32(a_val, &[2, 11, 3, 3, 3, 10])
.iter()
.map(|piece| SpreadWord::new(*piece as u16))
.collect::<Vec<_>>()
});
let a_spread_pieces = transpose_option_vec(a_spread_pieces, 6);
let a = SpreadVar::without_lookup(region, a_3, row + 1, a_4, row + 1, a_spread_pieces[0])?;
let b = SpreadVar::with_lookup(region, &self.lookup, row, a_spread_pieces[1])?;
@ -193,7 +196,7 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
row: usize,
val: u32,
val: Option<u32>,
) -> Result<
(
SpreadVar,
@ -217,10 +220,13 @@ impl CompressionConfig {
let a_5 = self.message_schedule;
let a_6 = self.extras[2];
let spread_pieces = chop_u32(val, &[3, 3, 2, 3, 14, 7])
.iter()
.map(|piece| SpreadWord::new(*piece as u16))
.collect::<Vec<_>>();
let spread_pieces = val.map(|val| {
chop_u32(val, &[3, 3, 2, 3, 14, 7])
.iter()
.map(|piece| SpreadWord::new(*piece as u16))
.collect::<Vec<_>>()
});
let spread_pieces = transpose_option_vec(spread_pieces, 6);
let a_lo = SpreadVar::without_lookup(region, a_3, row + 1, a_4, row + 1, spread_pieces[0])?;
let a_hi = SpreadVar::without_lookup(region, a_5, row + 1, a_6, row + 1, spread_pieces[1])?;
@ -236,7 +242,7 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
idx: i32,
a_val: u32,
a_val: Option<u32>,
) -> Result<RoundWordA, Error> {
let row = get_decompose_a_row(idx);
@ -259,7 +265,7 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
idx: i32,
e_val: u32,
e_val: Option<u32>,
) -> Result<RoundWordE, Error> {
let row = get_decompose_e_row(idx);
@ -299,48 +305,54 @@ impl CompressionConfig {
)?;
// Assign `spread_a` and copy constraint
self.assign_and_constrain(region, || "spread_a", a_3, row + 1, &word.a.spread)?;
self.assign_and_constrain(region, || "spread_a", a_3, row + 1, word.a.spread)?;
// Assign `spread_b` and copy constraint
self.assign_and_constrain(region, || "spread_b", a_5, row, &word.b.spread)?;
self.assign_and_constrain(region, || "spread_b", a_5, row, word.b.spread)?;
// Assign `spread_c_lo` and copy constraint
self.assign_and_constrain(region, || "spread_c_lo", a_3, row - 1, &word.c_lo.spread)?;
self.assign_and_constrain(region, || "spread_c_lo", a_3, row - 1, word.c_lo.spread)?;
// Assign `spread_c_mid` and copy constraint
self.assign_and_constrain(region, || "spread_c_mid", a_4, row - 1, &word.c_mid.spread)?;
self.assign_and_constrain(region, || "spread_c_mid", a_4, row - 1, word.c_mid.spread)?;
// Assign `spread_c_hi` and copy constraint
self.assign_and_constrain(region, || "spread_c_hi", a_4, row + 1, &word.c_hi.spread)?;
self.assign_and_constrain(region, || "spread_c_hi", a_4, row + 1, word.c_hi.spread)?;
// Assign `spread_d` and copy constraint
self.assign_and_constrain(region, || "spread_d", a_4, row, &word.d.spread)?;
self.assign_and_constrain(region, || "spread_d", a_4, row, word.d.spread)?;
// Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd}
let spread_a = word.a.spread.value.unwrap() as u64;
let spread_b = word.b.spread.value.unwrap() as u64;
let spread_c_lo = word.c_lo.spread.value.unwrap() as u64;
let spread_c_mid = word.c_mid.spread.value.unwrap() as u64;
let spread_c_hi = word.c_hi.spread.value.unwrap() as u64;
let spread_d = word.d.spread.value.unwrap() as u64;
let (r_0_even, r_0_odd, r_1_even, r_1_odd) = if word.a.spread.value.is_some() {
let spread_a = word.a.spread.value.unwrap() as u64;
let spread_b = word.b.spread.value.unwrap() as u64;
let spread_c_lo = word.c_lo.spread.value.unwrap() as u64;
let spread_c_mid = word.c_mid.spread.value.unwrap() as u64;
let spread_c_hi = word.c_hi.spread.value.unwrap() as u64;
let spread_d = word.d.spread.value.unwrap() as u64;
let xor_0 = spread_b
+ (1 << 22) * spread_c_lo
+ (1 << 28) * spread_c_mid
+ (1 << 34) * spread_c_hi
+ (1 << 40) * spread_d
+ (1 << 60) * spread_a;
let xor_1 = spread_c_lo
+ (1 << 6) * spread_c_mid
+ (1 << 12) * spread_c_hi
+ (1 << 18) * spread_d
+ (1 << 38) * spread_a
+ (1 << 42) * spread_b;
let xor_2 = spread_d
+ (1 << 20) * spread_a
+ (1 << 24) * spread_b
+ (1 << 46) * spread_c_lo
+ (1 << 52) * spread_c_mid
+ (1 << 58) * spread_c_hi;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
let xor_0 = spread_b
+ (1 << 22) * spread_c_lo
+ (1 << 28) * spread_c_mid
+ (1 << 34) * spread_c_hi
+ (1 << 40) * spread_d
+ (1 << 60) * spread_a;
let xor_1 = spread_c_lo
+ (1 << 6) * spread_c_mid
+ (1 << 12) * spread_c_hi
+ (1 << 18) * spread_d
+ (1 << 38) * spread_a
+ (1 << 42) * spread_b;
let xor_2 = spread_d
+ (1 << 20) * spread_a
+ (1 << 24) * spread_b
+ (1 << 46) * spread_c_lo
+ (1 << 52) * spread_c_mid
+ (1 << 58) * spread_c_hi;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
(Some(r_0_even), Some(r_0_odd), Some(r_1_even), Some(r_1_odd))
} else {
(None, None, None, None)
};
self.assign_sigma_outputs(
region,
@ -375,48 +387,54 @@ impl CompressionConfig {
)?;
// Assign `spread_a_lo` and copy constraint
self.assign_and_constrain(region, || "spread_a_lo", a_3, row + 1, &word.a_lo.spread)?;
self.assign_and_constrain(region, || "spread_a_lo", a_3, row + 1, word.a_lo.spread)?;
// Assign `spread_a_hi` and copy constraint
self.assign_and_constrain(region, || "spread_a_hi", a_4, row + 1, &word.a_hi.spread)?;
self.assign_and_constrain(region, || "spread_a_hi", a_4, row + 1, word.a_hi.spread)?;
// Assign `spread_b_lo` and copy constraint
self.assign_and_constrain(region, || "spread_b_lo", a_3, row - 1, &word.b_lo.spread)?;
self.assign_and_constrain(region, || "spread_b_lo", a_3, row - 1, word.b_lo.spread)?;
// Assign `spread_b_hi` and copy constraint
self.assign_and_constrain(region, || "spread_b_hi", a_4, row - 1, &word.b_hi.spread)?;
self.assign_and_constrain(region, || "spread_b_hi", a_4, row - 1, word.b_hi.spread)?;
// Assign `spread_c` and copy constraint
self.assign_and_constrain(region, || "spread_c", a_5, row, &word.c.spread)?;
self.assign_and_constrain(region, || "spread_c", a_5, row, word.c.spread)?;
// Assign `spread_d` and copy constraint
self.assign_and_constrain(region, || "spread_d", a_4, row, &word.d.spread)?;
self.assign_and_constrain(region, || "spread_d", a_4, row, word.d.spread)?;
// Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd}
let spread_a_lo = word.a_lo.spread.value.unwrap() as u64;
let spread_a_hi = word.a_hi.spread.value.unwrap() as u64;
let spread_b_lo = word.b_lo.spread.value.unwrap() as u64;
let spread_b_hi = word.b_hi.spread.value.unwrap() as u64;
let spread_c = word.c.spread.value.unwrap() as u64;
let spread_d = word.d.spread.value.unwrap() as u64;
let (r_0_even, r_0_odd, r_1_even, r_1_odd) = if word.a_lo.spread.value.is_some() {
let spread_a_lo = word.a_lo.spread.value.unwrap() as u64;
let spread_a_hi = word.a_hi.spread.value.unwrap() as u64;
let spread_b_lo = word.b_lo.spread.value.unwrap() as u64;
let spread_b_hi = word.b_hi.spread.value.unwrap() as u64;
let spread_c = word.c.spread.value.unwrap() as u64;
let spread_d = word.d.spread.value.unwrap() as u64;
let xor_0 = spread_b_lo
+ (1 << 4) * spread_b_hi
+ (1 << 10) * spread_c
+ (1 << 38) * spread_d
+ (1 << 52) * spread_a_lo
+ (1 << 58) * spread_a_hi;
let xor_1 = spread_c
+ (1 << 28) * spread_d
+ (1 << 42) * spread_a_lo
+ (1 << 48) * spread_a_hi
+ (1 << 54) * spread_b_lo
+ (1 << 58) * spread_b_hi;
let xor_2 = spread_d
+ (1 << 14) * spread_a_lo
+ (1 << 20) * spread_a_hi
+ (1 << 26) * spread_b_lo
+ (1 << 30) * spread_b_hi
+ (1 << 36) * spread_c;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
let xor_0 = spread_b_lo
+ (1 << 4) * spread_b_hi
+ (1 << 10) * spread_c
+ (1 << 38) * spread_d
+ (1 << 52) * spread_a_lo
+ (1 << 58) * spread_a_hi;
let xor_1 = spread_c
+ (1 << 28) * spread_d
+ (1 << 42) * spread_a_lo
+ (1 << 48) * spread_a_hi
+ (1 << 54) * spread_b_lo
+ (1 << 58) * spread_b_hi;
let xor_2 = spread_d
+ (1 << 14) * spread_a_lo
+ (1 << 20) * spread_a_hi
+ (1 << 26) * spread_b_lo
+ (1 << 30) * spread_b_hi
+ (1 << 36) * spread_c;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
(Some(r_0_even), Some(r_0_odd), Some(r_1_even), Some(r_1_odd))
} else {
(None, None, None, None)
};
self.assign_sigma_outputs(
region,
@ -434,10 +452,10 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
row: usize,
r_0_even: u16,
r_0_odd: u16,
r_1_even: u16,
r_1_odd: u16,
r_0_even: Option<u16>,
r_0_odd: Option<u16>,
r_1_even: Option<u16>,
r_1_odd: Option<u16>,
) -> Result<(CellValue16, CellValue16), Error> {
let a_3 = self.extras[0];
@ -470,21 +488,27 @@ impl CompressionConfig {
region.assign_fixed(|| "s_ch", self.s_ch, row, || Ok(F::one()))?;
// Assign and copy spread_e_lo, spread_e_hi
self.assign_and_constrain(region, || "spread_e_lo", a_3, row - 1, &spread_halves_e.0)?;
self.assign_and_constrain(region, || "spread_e_hi", a_4, row - 1, &spread_halves_e.1)?;
self.assign_and_constrain(region, || "spread_e_lo", a_3, row - 1, spread_halves_e.0)?;
self.assign_and_constrain(region, || "spread_e_hi", a_4, row - 1, spread_halves_e.1)?;
// Assign and copy spread_f_lo, spread_f_hi
self.assign_and_constrain(region, || "spread_f_lo", a_3, row + 1, &spread_halves_f.0)?;
self.assign_and_constrain(region, || "spread_f_hi", a_4, row + 1, &spread_halves_f.1)?;
self.assign_and_constrain(region, || "spread_f_lo", a_3, row + 1, spread_halves_f.0)?;
self.assign_and_constrain(region, || "spread_f_hi", a_4, row + 1, spread_halves_f.1)?;
let p: u64 = spread_halves_e.0.value.unwrap() as u64
+ spread_halves_f.0.value.unwrap() as u64
+ (1 << 32) * (spread_halves_e.1.value.unwrap() as u64)
+ (1 << 32) * (spread_halves_f.1.value.unwrap() as u64);
let p_pieces = chop_u64(p, &[32, 32]); // p_0, p_1
let (p0_even, p0_odd, p1_even, p1_odd) = if spread_halves_e.0.value.is_some() {
let p: u64 = spread_halves_e.0.value.unwrap() as u64
+ spread_halves_f.0.value.unwrap() as u64
+ (1 << 32) * (spread_halves_e.1.value.unwrap() as u64)
+ (1 << 32) * (spread_halves_f.1.value.unwrap() as u64);
let p_pieces = chop_u64(p, &[32, 32]); // p_0, p_1
let (p0_even, p0_odd) = get_even_and_odd_bits_u32(p_pieces[0] as u32);
let (p1_even, p1_odd) = get_even_and_odd_bits_u32(p_pieces[1] as u32);
let (p0_even, p0_odd) = get_even_and_odd_bits_u32(p_pieces[0] as u32);
let (p1_even, p1_odd) = get_even_and_odd_bits_u32(p_pieces[1] as u32);
(Some(p0_even), Some(p0_odd), Some(p1_even), Some(p1_odd))
} else {
(None, None, None, None)
};
self.assign_ch_outputs(region, row, p0_even, p0_odd, p1_even, p1_odd)
}
@ -505,41 +529,59 @@ impl CompressionConfig {
let a_5 = self.message_schedule;
// Assign and copy spread_e_lo, spread_e_hi
self.assign_and_constrain(region, || "spread_e_lo", a_5, row - 1, &spread_halves_e.0)?;
self.assign_and_constrain(region, || "spread_e_hi", a_5, row, &spread_halves_e.1)?;
self.assign_and_constrain(region, || "spread_e_lo", a_5, row - 1, spread_halves_e.0)?;
self.assign_and_constrain(region, || "spread_e_hi", a_5, row, spread_halves_e.1)?;
// Assign and copy spread_g_lo, spread_g_hi
self.assign_and_constrain(region, || "spread_g_lo", a_3, row + 1, &spread_halves_g.0)?;
self.assign_and_constrain(region, || "spread_g_hi", a_4, row + 1, &spread_halves_g.1)?;
self.assign_and_constrain(region, || "spread_g_lo", a_3, row + 1, spread_halves_g.0)?;
self.assign_and_constrain(region, || "spread_g_hi", a_4, row + 1, spread_halves_g.1)?;
// Calculate neg_e_lo, neg_e_hi
let spread_e_lo = spread_halves_e.0.value.unwrap();
let spread_e_hi = spread_halves_e.1.value.unwrap();
let spread_neg_e_lo = (MASK_EVEN_32 - spread_e_lo) as u64;
let spread_neg_e_hi = (MASK_EVEN_32 - spread_e_hi) as u64;
let spread_neg_e_lo = spread_halves_e
.0
.value
.map(|spread_e_lo| (MASK_EVEN_32 - spread_e_lo) as u64);
let spread_neg_e_hi = spread_halves_e
.1
.value
.map(|spread_e_hi| (MASK_EVEN_32 - spread_e_hi) as u64);
// Assign spread_neg_e_lo, spread_neg_e_hi
region.assign_advice(
|| "spread_neg_e_lo",
a_3,
row - 1,
|| Ok(F::from_u64(spread_neg_e_lo)),
|| {
spread_neg_e_lo
.map(F::from_u64)
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| "spread_neg_e_hi",
a_4,
row - 1,
|| Ok(F::from_u64(spread_neg_e_hi)),
|| {
spread_neg_e_hi
.map(F::from_u64)
.ok_or(Error::SynthesisError)
},
)?;
let p: u64 = spread_neg_e_lo
+ spread_halves_g.0.value.unwrap() as u64
+ (1 << 32) * spread_neg_e_hi
+ (1 << 32) * (spread_halves_g.1.value.unwrap() as u64);
let p_pieces = chop_u64(p, &[32, 32]); // p_0, p_1
let (p0_even, p0_odd, p1_even, p1_odd) = if let Some(spread_neg_e_lo) = spread_neg_e_lo {
let p: u64 = spread_neg_e_lo as u64
+ spread_halves_g.0.value.unwrap() as u64
+ (1 << 32) * spread_neg_e_hi.unwrap() as u64
+ (1 << 32) * (spread_halves_g.1.value.unwrap() as u64);
let p_pieces = chop_u64(p, &[32, 32]); // p_0, p_1
let (p0_even, p0_odd) = get_even_and_odd_bits_u32(p_pieces[0] as u32);
let (p1_even, p1_odd) = get_even_and_odd_bits_u32(p_pieces[1] as u32);
let (p0_even, p0_odd) = get_even_and_odd_bits_u32(p_pieces[0] as u32);
let (p1_even, p1_odd) = get_even_and_odd_bits_u32(p_pieces[1] as u32);
(Some(p0_even), Some(p0_odd), Some(p1_even), Some(p1_odd))
} else {
(None, None, None, None)
};
self.assign_ch_outputs(region, row, p0_even, p0_odd, p1_even, p1_odd)
}
@ -548,10 +590,10 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
row: usize,
r_0_even: u16,
r_0_odd: u16,
r_1_even: u16,
r_1_odd: u16,
r_0_even: Option<u16>,
r_0_odd: Option<u16>,
r_1_even: Option<u16>,
r_1_odd: Option<u16>,
) -> Result<(CellValue16, CellValue16), Error> {
let a_3 = self.extras[0];
let (_even, odd) = self.assign_spread_outputs(
@ -584,27 +626,33 @@ impl CompressionConfig {
region.assign_fixed(|| "s_maj", self.s_maj, row, || Ok(F::one()))?;
// Assign and copy spread_a_lo, spread_a_hi
self.assign_and_constrain(region, || "spread_a_lo", a_4, row - 1, &spread_halves_a.0)?;
self.assign_and_constrain(region, || "spread_a_hi", a_5, row - 1, &spread_halves_a.1)?;
self.assign_and_constrain(region, || "spread_a_lo", a_4, row - 1, spread_halves_a.0)?;
self.assign_and_constrain(region, || "spread_a_hi", a_5, row - 1, spread_halves_a.1)?;
// Assign and copy spread_b_lo, spread_b_hi
self.assign_and_constrain(region, || "spread_b_lo", a_4, row, &spread_halves_b.0)?;
self.assign_and_constrain(region, || "spread_b_hi", a_5, row, &spread_halves_b.1)?;
self.assign_and_constrain(region, || "spread_b_lo", a_4, row, spread_halves_b.0)?;
self.assign_and_constrain(region, || "spread_b_hi", a_5, row, spread_halves_b.1)?;
// Assign and copy spread_c_lo, spread_c_hi
self.assign_and_constrain(region, || "spread_c_lo", a_4, row + 1, &spread_halves_c.0)?;
self.assign_and_constrain(region, || "spread_c_hi", a_5, row + 1, &spread_halves_c.1)?;
self.assign_and_constrain(region, || "spread_c_lo", a_4, row + 1, spread_halves_c.0)?;
self.assign_and_constrain(region, || "spread_c_hi", a_5, row + 1, spread_halves_c.1)?;
let m: u64 = spread_halves_a.0.value.unwrap() as u64
+ spread_halves_b.0.value.unwrap() as u64
+ spread_halves_c.0.value.unwrap() as u64
+ (1 << 32) * (spread_halves_a.1.value.unwrap() as u64)
+ (1 << 32) * (spread_halves_b.1.value.unwrap() as u64)
+ (1 << 32) * (spread_halves_c.1.value.unwrap() as u64);
let m_pieces = chop_u64(m, &[32, 32]); // m_0, m_1
let (m0_even, m0_odd, m1_even, m1_odd) = if spread_halves_a.0.value.is_some() {
let m: u64 = spread_halves_a.0.value.unwrap() as u64
+ spread_halves_b.0.value.unwrap() as u64
+ spread_halves_c.0.value.unwrap() as u64
+ (1 << 32) * (spread_halves_a.1.value.unwrap() as u64)
+ (1 << 32) * (spread_halves_b.1.value.unwrap() as u64)
+ (1 << 32) * (spread_halves_c.1.value.unwrap() as u64);
let m_pieces = chop_u64(m, &[32, 32]); // m_0, m_1
let (m0_even, m0_odd) = get_even_and_odd_bits_u32(m_pieces[0] as u32);
let (m1_even, m1_odd) = get_even_and_odd_bits_u32(m_pieces[1] as u32);
let (m0_even, m0_odd) = get_even_and_odd_bits_u32(m_pieces[0] as u32);
let (m1_even, m1_odd) = get_even_and_odd_bits_u32(m_pieces[1] as u32);
(Some(m0_even), Some(m0_odd), Some(m1_even), Some(m1_odd))
} else {
(None, None, None, None)
};
self.assign_maj_outputs(region, row, m0_even, m0_odd, m1_even, m1_odd)
}
@ -633,12 +681,12 @@ impl CompressionConfig {
let a_9 = self.extras[5];
// Assign and copy h
self.assign_and_constrain(region, || "h_lo", a_7, row - 1, &h.0.into())?;
self.assign_and_constrain(region, || "h_hi", a_7, row, &h.1.into())?;
self.assign_and_constrain(region, || "h_lo", a_7, row - 1, h.0)?;
self.assign_and_constrain(region, || "h_hi", a_7, row, h.1)?;
// Assign and copy sigma_1
self.assign_and_constrain(region, || "sigma_1_lo", a_4, row, &sigma_1.0.into())?;
self.assign_and_constrain(region, || "sigma_1_hi", a_5, row, &sigma_1.1.into())?;
self.assign_and_constrain(region, || "sigma_1_lo", a_4, row, sigma_1.0)?;
self.assign_and_constrain(region, || "sigma_1_hi", a_5, row, sigma_1.1)?;
// Assign k
let k_pieces = chop_u32(k, &[16, 16]);
@ -651,57 +699,70 @@ impl CompressionConfig {
region.assign_advice(|| "k_hi", a_6, row, || Ok(F::from_u64(k_pieces[1] as u64)))?;
// Assign and copy w
self.assign_and_constrain(region, || "w_lo", a_8, row - 1, &w.0.into())?;
self.assign_and_constrain(region, || "w_hi", a_8, row, &w.1.into())?;
self.assign_and_constrain(region, || "w_lo", a_8, row - 1, w.0)?;
self.assign_and_constrain(region, || "w_hi", a_8, row, w.1)?;
// Assign and copy ch
self.assign_and_constrain(region, || "ch_neg_hi", a_6, row + 1, &ch.1.into())?;
self.assign_and_constrain(region, || "ch_neg_hi", a_6, row + 1, ch.1)?;
// Assign and copy ch_neg
self.assign_and_constrain(region, || "ch_neg_lo", a_5, row - 1, &ch_neg.0.into())?;
self.assign_and_constrain(region, || "ch_neg_hi", a_5, row + 1, &ch_neg.1.into())?;
self.assign_and_constrain(region, || "ch_neg_lo", a_5, row - 1, ch_neg.0)?;
self.assign_and_constrain(region, || "ch_neg_hi", a_5, row + 1, ch_neg.1)?;
// Assign h_prime, h_prime_carry
let h_prime_lo = h.0.value.unwrap() as u32
+ ch.0.value.unwrap() as u32
+ ch_neg.0.value.unwrap() as u32
+ sigma_1.0.value.unwrap() as u32
+ k_pieces[0]
+ w.0.value.unwrap() as u32;
let h_prime_hi = h.1.value.unwrap() as u32
+ ch.1.value.unwrap() as u32
+ ch_neg.1.value.unwrap() as u32
+ sigma_1.1.value.unwrap() as u32
+ k_pieces[1]
+ w.1.value.unwrap() as u32;
// Assign h_prime_lo, h_prime_hi, h_prime_carry
let (h_prime, h_prime_carry) = sum_with_carry(vec![
(h.0.value, h.1.value),
(ch.0.value, ch.1.value),
(ch_neg.0.value, ch_neg.1.value),
(sigma_1.0.value, sigma_1.1.value),
(Some(k_pieces[0] as u16), Some(k_pieces[1] as u16)),
(w.0.value, w.1.value),
]);
let h_prime_halves = h_prime.map(|h_prime| chop_u32(h_prime as u32, &[16, 16]));
let (h_prime_lo, h_prime_hi) = (
h_prime_halves.clone().map(|halves| halves[0] as u16),
h_prime_halves.map(|halves| halves[1] as u16),
);
let h_prime: u64 = h_prime_lo as u64 + (1 << 16) * (h_prime_hi as u64);
let h_prime_carry = h_prime >> 32;
let h_prime_halves = chop_u32(h_prime as u32, &[16, 16]);
let h_prime_lo = {
let cell = region.assign_advice(
|| "h_prime_lo",
a_7,
row + 1,
|| {
h_prime_lo
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
CellValue16::new(cell, h_prime_lo)
};
let h_prime_hi = {
let cell = region.assign_advice(
|| "h_prime_hi",
a_8,
row + 1,
|| {
h_prime_hi
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
CellValue16::new(cell, h_prime_hi)
};
let h_prime_lo = region.assign_advice(
|| "h_prime_lo",
a_7,
row + 1,
|| Ok(F::from_u64(h_prime_halves[0] as u64)),
)?;
let h_prime_hi = region.assign_advice(
|| "h_prime_hi",
a_8,
row + 1,
|| Ok(F::from_u64(h_prime_halves[1] as u64)),
)?;
region.assign_advice(
|| "h_prime_carry",
a_9,
row + 1,
|| Ok(F::from_u64(h_prime_carry as u64)),
|| {
h_prime_carry
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
Ok((
CellValue16::new(h_prime_lo, h_prime_halves[0] as u16),
CellValue16::new(h_prime_hi, h_prime_halves[1] as u16),
))
Ok((h_prime_lo, h_prime_hi))
}
// s_e_new to get E_new = H' + D
@ -721,23 +782,21 @@ impl CompressionConfig {
let a_9 = self.extras[5];
// Assign and copy d_lo, d_hi
self.assign_and_constrain(region, || "d_lo", a_7, row, &d.0.into())?;
self.assign_and_constrain(region, || "d_hi", a_7, row + 1, &d.1.into())?;
self.assign_and_constrain(region, || "d_lo", a_7, row, d.0)?;
self.assign_and_constrain(region, || "d_hi", a_7, row + 1, d.1)?;
// Assign e_new, e_new_carry
let e_new_lo = h_prime.0.value.unwrap() as u32 + d.0.value.unwrap() as u32;
let e_new_hi = h_prime.1.value.unwrap() as u32 + d.1.value.unwrap() as u32;
let e_new: u64 = e_new_lo as u64 + (1 << 16) * (e_new_hi as u64);
let e_new_carry = e_new >> 32;
let e_new: u32 = e_new as u32;
let (e_new, e_new_carry) = sum_with_carry(vec![
(h_prime.0.value, h_prime.1.value),
(d.0.value, d.1.value),
]);
let e_new_dense = self.assign_word_halves_dense(region, row, a_8, row + 1, a_8, e_new)?;
region.assign_advice(
|| "e_new_carry",
a_9,
row + 1,
|| Ok(F::from_u64(e_new_carry as u64)),
|| e_new_carry.map(F::from_u64).ok_or(Error::SynthesisError),
)?;
Ok(e_new_dense)
@ -763,34 +822,29 @@ impl CompressionConfig {
let a_9 = self.extras[5];
// Assign and copy maj_1
self.assign_and_constrain(region, || "maj_1_hi", a_3, row - 1, &maj.1.into())?;
self.assign_and_constrain(region, || "maj_1_hi", a_3, row - 1, maj.1)?;
// Assign and copy sigma_0
self.assign_and_constrain(region, || "sigma_0_lo", a_6, row, &sigma_0.0.into())?;
self.assign_and_constrain(region, || "sigma_0_hi", a_6, row + 1, &sigma_0.1.into())?;
self.assign_and_constrain(region, || "sigma_0_lo", a_6, row, sigma_0.0)?;
self.assign_and_constrain(region, || "sigma_0_hi", a_6, row + 1, sigma_0.1)?;
// Assign and copy h_prime
self.assign_and_constrain(region, || "h_prime_lo", a_7, row - 1, &h_prime.0.into())?;
self.assign_and_constrain(region, || "h_prime_hi", a_8, row - 1, &h_prime.1.into())?;
self.assign_and_constrain(region, || "h_prime_lo", a_7, row - 1, h_prime.0)?;
self.assign_and_constrain(region, || "h_prime_hi", a_8, row - 1, h_prime.1)?;
// Assign a_new, a_new_carry
let a_new_lo = h_prime.0.value.unwrap() as u32
+ sigma_0.0.value.unwrap() as u32
+ maj.0.value.unwrap() as u32;
let a_new_hi = h_prime.1.value.unwrap() as u32
+ sigma_0.1.value.unwrap() as u32
+ maj.1.value.unwrap() as u32;
let a_new: u64 = a_new_lo as u64 + (1 << 16) * (a_new_hi as u64);
let a_new_carry = a_new >> 32;
let a_new: u32 = a_new as u32;
let (a_new, a_new_carry) = sum_with_carry(vec![
(h_prime.0.value, h_prime.1.value),
(sigma_0.0.value, sigma_0.1.value),
(maj.0.value, maj.1.value),
]);
let a_new_dense = self.assign_word_halves_dense(region, row, a_8, row + 1, a_8, a_new)?;
region.assign_advice(
|| "a_new_carry",
a_9,
row,
|| Ok(F::from_u64(a_new_carry as u64)),
|| a_new_carry.map(F::from_u64).ok_or(Error::SynthesisError),
)?;
Ok(a_new_dense)
@ -803,25 +857,40 @@ impl CompressionConfig {
lo_col: Column<Advice>,
hi_row: usize,
hi_col: Column<Advice>,
word: u32,
word: Option<u32>,
) -> Result<(CellValue16, CellValue16), Error> {
let halves = chop_u32(word, &[16, 16]);
let lo = region.assign_advice(
|| "lo",
lo_col,
lo_row,
|| Ok(F::from_u64(halves[0] as u64)),
)?;
let hi = region.assign_advice(
|| "hi",
hi_col,
hi_row,
|| Ok(F::from_u64(halves[1] as u64)),
)?;
let w_lo_cell = CellValue16::new(lo, halves[0] as u16);
let w_hi_cell = CellValue16::new(hi, halves[1] as u16);
let (lo, hi) = if let Some(word) = word {
let halves = chop_u32(word, &[16, 16]);
(Some(halves[0] as u16), Some(halves[1] as u16))
} else {
(None, None)
};
let lo = {
let cell = region.assign_advice(
|| "lo",
lo_col,
lo_row,
|| {
lo.map(|lo| F::from_u64(lo as u64))
.ok_or(Error::SynthesisError)
},
)?;
CellValue16::new(cell, lo)
};
let hi = {
let cell = region.assign_advice(
|| "hi",
hi_col,
hi_row,
|| {
hi.map(|hi| F::from_u64(hi as u64))
.ok_or(Error::SynthesisError)
},
)?;
CellValue16::new(cell, hi)
};
Ok((w_lo_cell, w_hi_cell))
Ok((lo, hi))
}
// Assign hi and lo halves for both dense and spread versions of a word
@ -830,30 +899,35 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
row: usize,
word: u32,
word: Option<u32>,
) -> Result<((CellValue16, CellValue16), (CellValue32, CellValue32)), Error> {
// Rename these here for ease of matching the gates to the specification.
let a_7 = self.extras[3];
let a_8 = self.extras[4];
let halves = chop_u32(word, &[16, 16]);
let w_lo = SpreadWord::new(halves[0] as u16);
let w_hi = SpreadWord::new(halves[1] as u16);
let halves = word.map(|word| chop_u32(word, &[16, 16]));
let halves = transpose_option_vec(halves, 2);
let w_lo = SpreadWord::opt_new(halves[0].map(|value| value as u16));
let w_hi = SpreadWord::opt_new(halves[1].map(|value| value as u16));
let w_lo = SpreadVar::without_lookup(region, a_7, row, a_8, row, w_lo)?;
let w_hi = SpreadVar::without_lookup(region, a_7, row + 1, a_8, row + 1, w_hi)?;
let w_lo_cell = CellValue16::new(w_lo.dense.var, w_lo.dense.value.unwrap());
let w_hi_cell = CellValue16::new(w_hi.dense.var, w_hi.dense.value.unwrap());
let spread_w_lo_cell = CellValue32::new(w_lo.spread.var, w_lo.spread.value.unwrap());
let spread_w_hi_cell = CellValue32::new(w_hi.spread.var, w_hi.spread.value.unwrap());
let w_lo_cell = CellValue16::new(w_lo.dense.var, w_lo.dense.value);
let w_hi_cell = CellValue16::new(w_hi.dense.var, w_hi.dense.value);
let spread_w_lo_cell = CellValue32::new(w_lo.spread.var, w_lo.spread.value);
let spread_w_hi_cell = CellValue32::new(w_hi.spread.var, w_hi.spread.value);
Ok(((w_lo_cell, w_hi_cell), (spread_w_lo_cell, spread_w_hi_cell)))
}
}
pub fn val_from_dense_halves(dense_halves: (CellValue16, CellValue16)) -> u32 {
dense_halves.0.value.unwrap() as u32 + (1 << 16) * dense_halves.1.value.unwrap() as u32
pub fn val_from_dense_halves(dense_halves: (CellValue16, CellValue16)) -> Option<u32> {
dense_halves
.0
.value
.zip(dense_halves.1.value)
.map(|(lo, hi)| lo as u32 + (1 << 16) * hi as u32)
}
#[allow(clippy::many_single_char_names)]

View File

@ -28,36 +28,50 @@ impl CompressionConfig {
region.assign_fixed(|| "s_digest", self.s_digest, efgh_row, || Ok(F::one()))?;
// Assign digest for A, B, C, D
self.assign_and_constrain(region, || "a_lo", a_3, abcd_row, &a.dense_halves.0.into())?;
self.assign_and_constrain(region, || "a_hi", a_4, abcd_row, &a.dense_halves.1.into())?;
let a = a.dense_halves.0.value.unwrap() as u32
+ (1 << 16) * (a.dense_halves.1.value.unwrap() as u32);
region.assign_advice(|| "a", a_5, abcd_row, || Ok(F::from_u64(a as u64)))?;
self.assign_and_constrain(region, || "a_lo", a_3, abcd_row, a.dense_halves.0)?;
self.assign_and_constrain(region, || "a_hi", a_4, abcd_row, a.dense_halves.1)?;
let a = val_from_dense_halves(a.dense_halves);
region.assign_advice(
|| "a",
a_5,
abcd_row,
|| {
a.map(|a| F::from_u64(a as u64))
.ok_or(Error::SynthesisError)
},
)?;
let b = self.assign_digest_word(region, abcd_row, a_6, a_7, a_8, b.dense_halves)?;
let c = self.assign_digest_word(region, abcd_row + 1, a_3, a_4, a_5, c.dense_halves)?;
let d = self.assign_digest_word(region, abcd_row + 1, a_6, a_7, a_8, d.dense_halves)?;
// Assign digest for E, F, G, H
self.assign_and_constrain(region, || "e_lo", a_3, efgh_row, &e.dense_halves.0.into())?;
self.assign_and_constrain(region, || "e_hi", a_4, efgh_row, &e.dense_halves.1.into())?;
let e = e.dense_halves.0.value.unwrap() as u32
+ (1 << 16) * (e.dense_halves.1.value.unwrap() as u32);
region.assign_advice(|| "e", a_5, efgh_row, || Ok(F::from_u64(e as u64)))?;
self.assign_and_constrain(region, || "e_lo", a_3, efgh_row, e.dense_halves.0)?;
self.assign_and_constrain(region, || "e_hi", a_4, efgh_row, e.dense_halves.1)?;
let e = val_from_dense_halves(e.dense_halves);
region.assign_advice(
|| "e",
a_5,
efgh_row,
|| {
e.map(|e| F::from_u64(e as u64))
.ok_or(Error::SynthesisError)
},
)?;
let f = self.assign_digest_word(region, efgh_row, a_6, a_7, a_8, f.dense_halves)?;
let g = self.assign_digest_word(region, efgh_row + 1, a_3, a_4, a_5, g.dense_halves)?;
let h = self.assign_digest_word(region, efgh_row + 1, a_6, a_7, a_8, h.dense_halves)?;
Ok([
BlockWord::new(a),
BlockWord::new(b),
BlockWord::new(c),
BlockWord::new(d),
BlockWord::new(e),
BlockWord::new(f),
BlockWord::new(g),
BlockWord::new(h),
BlockWord(a),
BlockWord(b),
BlockWord(c),
BlockWord(d),
BlockWord(e),
BlockWord(f),
BlockWord(g),
BlockWord(h),
])
}
@ -69,12 +83,20 @@ impl CompressionConfig {
hi_col: Column<Advice>,
word_col: Column<Advice>,
dense_halves: (CellValue16, CellValue16),
) -> Result<u32, Error> {
self.assign_and_constrain(region, || "lo", lo_col, row, &dense_halves.0.into())?;
self.assign_and_constrain(region, || "hi", hi_col, row, &dense_halves.1.into())?;
let val = dense_halves.0.value.unwrap() as u32
+ (1 << 16) * (dense_halves.1.value.unwrap() as u32);
region.assign_advice(|| "word", word_col, row, || Ok(F::from_u64(val as u64)))?;
) -> Result<Option<u32>, Error> {
self.assign_and_constrain(region, || "lo", lo_col, row, dense_halves.0)?;
self.assign_and_constrain(region, || "hi", hi_col, row, dense_halves.1)?;
let val = val_from_dense_halves(dense_halves);
region.assign_advice(
|| "word",
word_col,
row,
|| {
val.map(|val| F::from_u64(val as u64))
.ok_or(Error::SynthesisError)
},
)?;
Ok(val)
}

View File

@ -14,27 +14,29 @@ impl CompressionConfig {
let idx = -1;
// Decompose E into (6, 5, 14, 7)-bit chunks
let e = self.decompose_e(region, idx, iv[4])?;
let e = self.decompose_e(region, idx, Some(iv[4]))?;
// Decompose F, G
let f = self.decompose_f(region, idx, iv[5])?;
let g = self.decompose_g(region, idx, iv[6])?;
let f = self.decompose_f(region, idx, Some(iv[5]))?;
let g = self.decompose_g(region, idx, Some(iv[6]))?;
// Assign H
let h_row = get_h_row(idx);
let h_dense = self.assign_word_halves_dense(region, h_row, a_7, h_row + 1, a_7, iv[7])?;
let h_dense =
self.assign_word_halves_dense(region, h_row, a_7, h_row + 1, a_7, Some(iv[7]))?;
let h = RoundWordDense::new(h_dense);
// Decompose A into (2, 11, 9, 10)-bit chunks
let a = self.decompose_a(region, idx, iv[0])?;
let a = self.decompose_a(region, idx, Some(iv[0]))?;
// Decompose B, C
let b = self.decompose_b(region, idx, iv[1])?;
let c = self.decompose_c(region, idx, iv[2])?;
let b = self.decompose_b(region, idx, Some(iv[1]))?;
let c = self.decompose_c(region, idx, Some(iv[2]))?;
// Assign D
let d_row = get_d_row(idx);
let d_dense = self.assign_word_halves_dense(region, d_row, a_7, d_row + 1, a_7, iv[3])?;
let d_dense =
self.assign_word_halves_dense(region, d_row, a_7, d_row + 1, a_7, Some(iv[3]))?;
let d = RoundWordDense::new(d_dense);
Ok(State::new(
@ -108,7 +110,7 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
idx: i32,
b_val: u32,
b_val: Option<u32>,
) -> Result<RoundWordSpread, Error> {
let row = get_decompose_b_row(idx);
@ -121,7 +123,7 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
idx: i32,
c_val: u32,
c_val: Option<u32>,
) -> Result<RoundWordSpread, Error> {
let row = get_decompose_c_row(idx);
@ -134,7 +136,7 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
idx: i32,
f_val: u32,
f_val: Option<u32>,
) -> Result<RoundWordSpread, Error> {
let row = get_decompose_f_row(idx);
@ -147,7 +149,7 @@ impl CompressionConfig {
&self,
region: &mut Region<'_, F>,
idx: i32,
g_val: u32,
g_val: Option<u32>,
) -> Result<RoundWordSpread, Error> {
let row = get_decompose_g_row(idx);

View File

@ -61,37 +61,13 @@ impl CompressionConfig {
if idx < 63 {
// Assign and copy A_new
let a_new_row = get_decompose_a_row(idx + 1);
self.assign_and_constrain(
region,
|| "a_new_lo",
a_7,
a_new_row,
&a_new_dense.0.into(),
)?;
self.assign_and_constrain(
region,
|| "a_new_hi",
a_7,
a_new_row + 1,
&a_new_dense.1.into(),
)?;
self.assign_and_constrain(region, || "a_new_lo", a_7, a_new_row, a_new_dense.0)?;
self.assign_and_constrain(region, || "a_new_hi", a_7, a_new_row + 1, a_new_dense.1)?;
// Assign and copy E_new
let e_new_row = get_decompose_e_row(idx + 1);
self.assign_and_constrain(
region,
|| "e_new_lo",
a_7,
e_new_row,
&e_new_dense.0.into(),
)?;
self.assign_and_constrain(
region,
|| "e_new_hi",
a_7,
e_new_row + 1,
&e_new_dense.1.into(),
)?;
self.assign_and_constrain(region, || "e_new_lo", a_7, e_new_row, e_new_dense.0)?;
self.assign_and_constrain(region, || "e_new_hi", a_7, e_new_row + 1, e_new_dense.1)?;
// Decompose A into (2, 11, 9, 10)-bit chunks
let a_new = self.decompose_a(region, idx + 1, a_new_val)?;

View File

@ -18,7 +18,7 @@ use schedule_gates::ScheduleGate;
use schedule_util::*;
#[cfg(test)]
pub use schedule_util::get_msg_schedule_test_input;
pub use schedule_util::msg_schedule_test_input;
#[derive(Clone, Debug)]
pub(super) struct MessageWord {
@ -394,12 +394,8 @@ impl MessageScheduleConfig {
// Assign W[0..16]
for (i, word) in input.iter().enumerate() {
let (var, halves) =
self.assign_word_and_halves(&mut region, word.value.unwrap(), i)?;
w.push(MessageWord {
var,
value: word.value,
});
let (var, halves) = self.assign_word_and_halves(&mut region, word.0, i)?;
w.push(MessageWord { var, value: word.0 });
w_halves.push(halves);
}
@ -469,7 +465,7 @@ mod tests {
// Provide input
// Test vector: "abc"
let inputs: [BlockWord; BLOCK_SIZE] = get_msg_schedule_test_input();
let inputs: [BlockWord; BLOCK_SIZE] = msg_schedule_test_input();
// Run message_scheduler to get W_[0..64]
let (w, _) = config.message_schedule.process(&mut layouter, inputs)?;

View File

@ -59,24 +59,24 @@ pub fn get_word_row(word_idx: usize) -> usize {
/// Test vector: "abc"
#[cfg(test)]
pub fn get_msg_schedule_test_input() -> [BlockWord; BLOCK_SIZE] {
pub fn msg_schedule_test_input() -> [BlockWord; BLOCK_SIZE] {
[
BlockWord::new(0b01100001011000100110001110000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000000000),
BlockWord::new(0b00000000000000000000000000011000),
BlockWord(Some(0b01100001011000100110001110000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000000000)),
BlockWord(Some(0b00000000000000000000000000011000)),
]
}
@ -153,7 +153,7 @@ impl MessageScheduleConfig {
pub fn assign_word_and_halves<F: FieldExt>(
&self,
region: &mut Region<'_, F>,
word: u32,
word: Option<u32>,
word_idx: usize,
) -> Result<(Cell, (CellValue16, CellValue16)), Error> {
// Rename these here for ease of matching the gates to the specification.
@ -162,35 +162,45 @@ impl MessageScheduleConfig {
let row = get_word_row(word_idx);
let var = region.assign_advice(
|| format!("W_{}", word_idx),
self.message_schedule,
row,
|| Ok(F::from_u64(word as u64)),
)?;
let var = {
let word = word.map(|word| F::from_u64(word as u64));
region.assign_advice(
|| format!("W_{}", word_idx),
self.message_schedule,
row,
|| word.ok_or(Error::SynthesisError),
)?
};
let w_lo = word as u16;
let w_hi = (word >> 16) as u16;
let w_lo = {
let w_lo_val = word.map(|word| word as u16);
let w_lo_cell = region.assign_advice(
|| format!("W_{}_lo", word_idx),
a_3,
row,
|| {
w_lo_val
.map(|w_lo| F::from_u64(w_lo as u64))
.ok_or(Error::SynthesisError)
},
)?;
CellValue16::new(w_lo_cell, w_lo_val)
};
let w_hi = {
let w_hi_val = word.map(|word| (word >> 16) as u16);
let w_hi_cell = region.assign_advice(
|| format!("W_{}_hi", word_idx),
a_4,
row,
|| {
w_hi_val
.map(|w_hi| F::from_u64(w_hi as u64))
.ok_or(Error::SynthesisError)
},
)?;
CellValue16::new(w_hi_cell, w_hi_val)
};
let w_lo_cell = region.assign_advice(
|| format!("W_{}_lo", word_idx),
a_3,
row,
|| Ok(F::from_u64(w_lo as u64)),
)?;
let w_hi_cell = region.assign_advice(
|| format!("W_{}_hi", word_idx),
a_4,
row,
|| Ok(F::from_u64(w_hi as u64)),
)?;
Ok((
var,
(
CellValue16::new(w_lo_cell, w_lo),
CellValue16::new(w_hi_cell, w_hi),
),
))
Ok((var, (w_lo, w_hi)))
}
}

View File

@ -11,8 +11,8 @@ pub struct Subregion1Word {
index: usize,
a: CellValue32,
b: CellValue32,
c: CellValue32,
d: CellValue32,
c: CellValue16,
d: CellValue16,
spread_c: CellValue32,
spread_d: CellValue32,
}
@ -30,7 +30,7 @@ impl MessageScheduleConfig {
.map(|(idx, word)| {
// s_decompose_1 on W_[1..14]
let subregion1_word = self
.decompose_subregion1_word(region, word.value.unwrap(), idx + 1)
.decompose_subregion1_word(region, word.0, idx + 1)
.unwrap();
// lower_sigma_0 on W_[1..14]
@ -42,7 +42,7 @@ impl MessageScheduleConfig {
fn decompose_subregion1_word<F: FieldExt>(
&self,
region: &mut Region<'_, F>,
word: u32,
word: Option<u32>,
index: usize,
) -> Result<Subregion1Word, Error> {
let row = get_word_row(index);
@ -51,39 +51,48 @@ impl MessageScheduleConfig {
let a_3 = self.extras[0];
let a_4 = self.extras[1];
let pieces = chop_u32(word, &[3, 4, 11, 14]);
let pieces = word.map(|word| chop_u32(word, &[3, 4, 11, 14]));
let pieces = transpose_option_vec(pieces, 4);
// Assign `a` (3-bit piece)
let a = region.assign_advice(
|| "word_a",
a_3,
row + 1,
|| Ok(F::from_u64(pieces[0] as u64)),
|| {
pieces[0]
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `b` (4-bit piece)
let b = region.assign_advice(
|| "word_b",
a_4,
row + 1,
|| Ok(F::from_u64(pieces[1] as u64)),
|| {
pieces[1]
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `c` (11-bit piece) lookup
let spread_c = SpreadWord::new(pieces[2] as u16);
let spread_c = SpreadWord::opt_new(pieces[2].map(|value| value as u16));
let spread_c = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_c)?;
// Assign `d` (14-bit piece) lookup
let spread_d = SpreadWord::new(pieces[3] as u16);
let spread_d = SpreadWord::opt_new(pieces[3].map(|value| value as u16));
let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?;
Ok(Subregion1Word {
index,
a: CellValue32::new(a, pieces[0]),
b: CellValue32::new(b, pieces[1]),
c: CellValue32::new(spread_c.dense.var, spread_c.dense.value.unwrap().into()),
d: CellValue32::new(spread_d.dense.var, spread_d.dense.value.unwrap().into()),
spread_c: CellValue32::new(spread_c.spread.var, spread_c.spread.value.unwrap()),
spread_d: CellValue32::new(spread_d.spread.var, spread_d.spread.value.unwrap()),
c: CellValue16::new(spread_c.dense.var, spread_c.dense.value),
d: CellValue16::new(spread_d.dense.var, spread_d.dense.value),
spread_c: CellValue32::new(spread_c.spread.var, spread_c.spread.value),
spread_d: CellValue32::new(spread_d.spread.var, spread_d.spread.value),
})
}
@ -102,70 +111,107 @@ impl MessageScheduleConfig {
let row = get_word_row(word.index) + 3;
// Assign `a` and copy constraint
self.assign_and_constrain(region, || "a", a_5, row + 1, &word.a)?;
self.assign_and_constrain(region, || "a", a_5, row + 1, word.a)?;
// Witness `spread_a`
let spread_a = interleave_u16_with_zeros(word.a.value.unwrap() as u16);
let spread_a = word
.a
.value
.map(|value| interleave_u16_with_zeros(value as u16));
region.assign_advice(
|| "spread_a",
a_6,
row + 1,
|| Ok(F::from_u64(spread_a as u64)),
|| {
spread_a
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Split `b` (2-bit chunk) into `b_hi` and `b_lo`
let b = word.b.value.unwrap();
let (b_lo, b_hi) = bisect_four_bit(b);
let spread_b_lo = interleave_u16_with_zeros(b_lo as u16);
let spread_b_hi = interleave_u16_with_zeros(b_hi as u16);
let b = word.b.value.map(bisect_four_bit);
let spread_b_lo = b.map(|b| interleave_u16_with_zeros(b.0 as u16));
let spread_b_hi = b.map(|b| interleave_u16_with_zeros(b.1 as u16));
// Assign `b_hi`, `spread_b_hi`, `b_lo`, `spread_b_lo`
region.assign_advice(|| "b_lo", a_3, row - 1, || Ok(F::from_u64(b_lo as u64)))?;
region.assign_advice(
|| "b_lo",
a_3,
row - 1,
|| {
b.map(|(b_lo, _)| F::from_u64(b_lo as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| "spread_b_lo",
a_4,
row - 1,
|| Ok(F::from_u64(spread_b_lo as u64)),
|| {
spread_b_lo
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| "b_hi",
a_5,
row - 1,
|| {
b.map(|(_, b_hi)| F::from_u64(b_hi as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(|| "b_hi", a_5, row - 1, || Ok(F::from_u64(b_hi as u64)))?;
region.assign_advice(
|| "spread_b_hi",
a_6,
row - 1,
|| Ok(F::from_u64(spread_b_hi as u64)),
|| {
spread_b_hi
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `b` and copy constraint
self.assign_and_constrain(region, || "b", a_6, row, &word.b)?;
self.assign_and_constrain(region, || "b", a_6, row, word.b)?;
// Assign `spread_c` and copy constraint
self.assign_and_constrain(region, || "spread_c", a_4, row, &word.spread_c)?;
self.assign_and_constrain(region, || "spread_c", a_4, row, word.spread_c)?;
// Assign `spread_d` and copy constraint
self.assign_and_constrain(region, || "spread_d", a_5, row, &word.spread_d)?;
self.assign_and_constrain(region, || "spread_d", a_5, row, word.spread_d)?;
// Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd}
let spread_a = spread_a as u64;
let spread_b_lo = spread_b_lo as u64;
let spread_b_hi = spread_b_hi as u64;
let spread_c = word.spread_c.value.unwrap() as u64;
let spread_d = word.spread_d.value.unwrap() as u64;
let xor_0: u64 =
spread_b_lo + (1 << 4) * spread_b_hi + (1 << 8) * spread_c + (1 << 30) * spread_d;
let xor_1: u64 = spread_c
+ (1 << 22) * spread_d
+ (1 << 50) * spread_a
+ (1 << 56) * spread_b_lo
+ (1 << 60) * spread_b_hi;
let xor_2: u64 = spread_d
+ (1 << 28) * spread_a
+ (1 << 34) * spread_b_lo
+ (1 << 38) * spread_b_hi
+ (1 << 42) * spread_c;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
let (r_0_even, r_0_odd, r_1_even, r_1_odd) = if let Some(spread_a) = spread_a {
let spread_a = spread_a as u64;
let spread_b_lo = spread_b_lo.unwrap() as u64;
let spread_b_hi = spread_b_hi.unwrap() as u64;
let spread_c = word.spread_c.value.unwrap() as u64;
let spread_d = word.spread_d.value.unwrap() as u64;
let xor_0: u64 =
spread_b_lo + (1 << 4) * spread_b_hi + (1 << 8) * spread_c + (1 << 30) * spread_d;
let xor_1: u64 = spread_c
+ (1 << 22) * spread_d
+ (1 << 50) * spread_a
+ (1 << 56) * spread_b_lo
+ (1 << 60) * spread_b_hi;
let xor_2: u64 = spread_d
+ (1 << 28) * spread_a
+ (1 << 34) * spread_b_lo
+ (1 << 38) * spread_b_hi
+ (1 << 42) * spread_c;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
(Some(r_0_even), Some(r_0_odd), Some(r_1_even), Some(r_1_odd))
} else {
(None, None, None, None)
};
self.assign_sigma_outputs(
region,

View File

@ -8,12 +8,12 @@ use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};
pub struct Subregion2Word {
index: usize,
a: CellValue32,
b: CellValue32,
b: CellValue16,
c: CellValue32,
d: CellValue32,
d: CellValue16,
e: CellValue32,
f: CellValue32,
g: CellValue32,
g: CellValue16,
spread_d: CellValue32,
spread_g: CellValue32,
}
@ -50,8 +50,7 @@ impl MessageScheduleConfig {
sigma_0_output: (CellValue16, CellValue16)|
-> Result<Vec<(CellValue16, CellValue16)>, Error> {
// Decompose word into (3, 4, 3, 7, 1, 1, 13)-bit chunks
let subregion2_word =
self.decompose_subregion2_word(region, w[idx].value.unwrap(), idx)?;
let subregion2_word = self.decompose_subregion2_word(region, w[idx].value, idx)?;
// sigma_0 v2 and sigma_1 v2 on subregion2_word
lower_sigma_0_v2_results.push(self.lower_sigma_0_v2(region, subregion2_word.clone())?);
@ -65,14 +64,14 @@ impl MessageScheduleConfig {
|| format!("sigma_0(W_{})_lo", new_word_idx - 15),
a_6,
get_word_row(new_word_idx - 16),
&sigma_0_output.0.into(),
sigma_0_output.0,
)?;
self.assign_and_constrain(
region,
|| format!("sigma_0(W_{})_hi", new_word_idx - 15),
a_6,
get_word_row(new_word_idx - 16) + 1,
&sigma_0_output.1.into(),
sigma_0_output.1,
)?;
// Copy sigma_1(W_{i - 2})
@ -81,14 +80,14 @@ impl MessageScheduleConfig {
|| format!("sigma_1(W_{})_lo", new_word_idx - 2),
a_7,
get_word_row(new_word_idx - 16),
&lower_sigma_1_v2_results[new_word_idx - 16].0.into(),
lower_sigma_1_v2_results[new_word_idx - 16].0,
)?;
self.assign_and_constrain(
region,
|| format!("sigma_1(W_{})_hi", new_word_idx - 2),
a_7,
get_word_row(new_word_idx - 16) + 1,
&lower_sigma_1_v2_results[new_word_idx - 16].1.into(),
lower_sigma_1_v2_results[new_word_idx - 16].1,
)?;
// Copy W_{i - 7}
@ -97,48 +96,55 @@ impl MessageScheduleConfig {
|| format!("W_{}_lo", new_word_idx - 7),
a_8,
get_word_row(new_word_idx - 16),
&w_halves[new_word_idx - 7].0.into(),
w_halves[new_word_idx - 7].0,
)?;
self.assign_and_constrain(
region,
|| format!("W_{}_hi", new_word_idx - 7),
a_8,
get_word_row(new_word_idx - 16) + 1,
&w_halves[new_word_idx - 7].1.into(),
w_halves[new_word_idx - 7].1,
)?;
// Calculate W_i, carry_i
let word_lo: u32 = lower_sigma_1_v2_results[new_word_idx - 16].0.value.unwrap() as u32
+ w_halves[new_word_idx - 7].0.value.unwrap() as u32
+ sigma_0_output.0.value.unwrap() as u32
+ w_halves[new_word_idx - 16].0.value.unwrap() as u32;
let word_hi: u32 = lower_sigma_1_v2_results[new_word_idx - 16].1.value.unwrap() as u32
+ w_halves[new_word_idx - 7].1.value.unwrap() as u32
+ sigma_0_output.1.value.unwrap() as u32
+ w_halves[new_word_idx - 16].1.value.unwrap() as u32;
let word: u64 = word_lo as u64 + (1 << 16) * (word_hi as u64);
let carry = word >> 32;
let word = word as u32;
let (word, carry) = sum_with_carry(vec![
(
lower_sigma_1_v2_results[new_word_idx - 16].0.value,
lower_sigma_1_v2_results[new_word_idx - 16].1.value,
),
(
w_halves[new_word_idx - 7].0.value,
w_halves[new_word_idx - 7].1.value,
),
(sigma_0_output.0.value, sigma_0_output.1.value),
(
w_halves[new_word_idx - 16].0.value,
w_halves[new_word_idx - 16].1.value,
),
]);
// Assign W_i, carry_i
region.assign_advice(
|| format!("W_{}", new_word_idx),
a_5,
get_word_row(new_word_idx - 16) + 1,
|| Ok(F::from_u64(word as u64)),
|| {
word.map(|word| F::from_u64(word as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| format!("carry_{}", new_word_idx),
a_9,
get_word_row(new_word_idx - 16) + 1,
|| Ok(F::from_u64(carry as u64)),
|| {
carry
.map(|carry| F::from_u64(carry as u64))
.ok_or(Error::SynthesisError)
},
)?;
let (var, halves) = self.assign_word_and_halves(region, word, new_word_idx)?;
w.push(MessageWord {
var,
value: Some(word),
});
w.push(MessageWord { var, value: word });
w_halves.push(halves);
Ok(lower_sigma_0_v2_results.clone())
@ -164,7 +170,7 @@ impl MessageScheduleConfig {
fn decompose_subregion2_word<F: FieldExt>(
&self,
region: &mut Region<'_, F>,
word: u32,
word: Option<u32>,
index: usize,
) -> Result<Subregion2Word, Error> {
let row = get_word_row(index);
@ -173,43 +179,80 @@ impl MessageScheduleConfig {
let a_3 = self.extras[0];
let a_4 = self.extras[1];
let pieces = chop_u32(word, &[3, 4, 3, 7, 1, 1, 13]);
let pieces = word.map(|word| chop_u32(word, &[3, 4, 3, 7, 1, 1, 13]));
let pieces = transpose_option_vec(pieces, 7);
// Assign `a` (3-bit piece)
let a = region.assign_advice(|| "a", a_3, row - 1, || Ok(F::from_u64(pieces[0] as u64)))?;
let a = region.assign_advice(
|| "a",
a_3,
row - 1,
|| {
pieces[0]
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `b` (4-bit piece) lookup
let spread_b = SpreadWord::new(pieces[1] as u16);
let spread_b = SpreadWord::opt_new(pieces[1].map(|value| value as u16));
let spread_b = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_b)?;
// Assign `c` (3-bit piece)
let c = region.assign_advice(|| "c", a_4, row - 1, || Ok(F::from_u64(pieces[2] as u64)))?;
let c = region.assign_advice(
|| "c",
a_4,
row - 1,
|| {
pieces[2]
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `d` (7-bit piece) lookup
let spread_d = SpreadWord::new(pieces[3] as u16);
let spread_d = SpreadWord::opt_new(pieces[3].map(|value| value as u16));
let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?;
// Assign `e` (1-bit piece)
let e = region.assign_advice(|| "e", a_3, row + 1, || Ok(F::from_u64(pieces[4] as u64)))?;
let e = region.assign_advice(
|| "e",
a_3,
row + 1,
|| {
pieces[4]
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `f` (1-bit piece)
let f = region.assign_advice(|| "f", a_4, row + 1, || Ok(F::from_u64(pieces[5] as u64)))?;
let f = region.assign_advice(
|| "f",
a_4,
row + 1,
|| {
pieces[5]
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `g` (13-bit piece) lookup
let spread_g = SpreadWord::new(pieces[6] as u16);
let spread_g = SpreadWord::opt_new(pieces[6].map(|value| value as u16));
let spread_g = SpreadVar::with_lookup(region, &self.lookup, row - 1, spread_g)?;
Ok(Subregion2Word {
index,
a: CellValue32::new(a, pieces[0]),
b: CellValue32::new(spread_b.dense.var, spread_b.dense.value.unwrap().into()),
b: CellValue16::new(spread_b.dense.var, spread_b.dense.value),
c: CellValue32::new(c, pieces[2]),
d: CellValue32::new(spread_d.dense.var, spread_d.dense.value.unwrap().into()),
d: CellValue16::new(spread_d.dense.var, spread_d.dense.value),
e: CellValue32::new(e, pieces[4]),
f: CellValue32::new(f, pieces[5]),
g: CellValue32::new(spread_g.dense.var, spread_g.dense.value.unwrap().into()),
spread_d: CellValue32::new(spread_d.spread.var, spread_d.spread.value.unwrap()),
spread_g: CellValue32::new(spread_g.spread.var, spread_g.spread.value.unwrap()),
g: CellValue16::new(spread_g.dense.var, spread_g.dense.value),
spread_d: CellValue32::new(spread_d.spread.var, spread_d.spread.value),
spread_g: CellValue32::new(spread_g.spread.var, spread_g.spread.value),
})
}
@ -219,7 +262,7 @@ impl MessageScheduleConfig {
region: &mut Region<'_, F>,
row: usize,
subregion2_word: Subregion2Word,
) -> Result<(u64, u64, u64, u64, u64, u64, u64, u64), Error> {
) -> Result<[Option<u32>; 8], Error> {
let a_3 = self.extras[0];
let a_4 = self.extras[1];
let a_5 = self.message_schedule;
@ -227,76 +270,113 @@ impl MessageScheduleConfig {
let a_7 = self.extras[3];
// Assign `a` and copy constraint
self.assign_and_constrain(region, || "a", a_3, row + 1, &subregion2_word.a)?;
self.assign_and_constrain(region, || "a", a_3, row + 1, subregion2_word.a)?;
// Witness `spread_a`
let spread_a = interleave_u16_with_zeros(subregion2_word.a.value.unwrap() as u16);
let spread_a = subregion2_word
.a
.value
.map(|value| interleave_u16_with_zeros(value as u16));
region.assign_advice(
|| "spread_a",
a_4,
row + 1,
|| Ok(F::from_u64(spread_a as u64)),
|| {
spread_a
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Split `b` (2-bit chunk) into `b_hi` and `b_lo`
let b = subregion2_word.b.value.unwrap();
let (b_lo, b_hi) = bisect_four_bit(b);
let spread_b_lo = interleave_u16_with_zeros(b_lo as u16);
let spread_b_hi = interleave_u16_with_zeros(b_hi as u16);
let b = subregion2_word.b.value.map(bisect_four_bit);
let spread_b_lo = b.map(|b| interleave_u16_with_zeros(b.0 as u16));
let spread_b_hi = b.map(|b| interleave_u16_with_zeros(b.1 as u16));
// Assign `b_hi`, `spread_b_hi`, `b_lo`, `spread_b_lo`
region.assign_advice(|| "b_lo", a_3, row - 1, || Ok(F::from_u64(b_lo as u64)))?;
region.assign_advice(
|| "b_lo",
a_3,
row - 1,
|| {
b.map(|(b_lo, _)| F::from_u64(b_lo as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| "spread_b_lo",
a_4,
row - 1,
|| Ok(F::from_u64(spread_b_lo as u64)),
|| {
spread_b_lo
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| "b_hi",
a_5,
row - 1,
|| {
b.map(|(_, b_hi)| F::from_u64(b_hi as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(|| "b_hi", a_5, row - 1, || Ok(F::from_u64(b_hi as u64)))?;
region.assign_advice(
|| "spread_b_hi",
a_6,
row - 1,
|| Ok(F::from_u64(spread_b_hi as u64)),
|| {
spread_b_hi
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `b` and copy constraint
self.assign_and_constrain(region, || "b", a_6, row, &subregion2_word.b)?;
self.assign_and_constrain(region, || "b", a_6, row, subregion2_word.b)?;
// Assign `c` and copy constraint
self.assign_and_constrain(region, || "c", a_5, row + 1, &subregion2_word.c)?;
self.assign_and_constrain(region, || "c", a_5, row + 1, subregion2_word.c)?;
// Witness `spread_c`
let spread_c = interleave_u16_with_zeros(subregion2_word.c.value.unwrap() as u16);
let spread_c = subregion2_word.c.value.map(|value| {
let spread = interleave_u16_with_zeros(value as u16);
spread as u32
});
region.assign_advice(
|| "spread_c",
a_6,
row + 1,
|| Ok(F::from_u64(spread_c as u64)),
|| {
spread_c
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `spread_d` and copy constraint
self.assign_and_constrain(region, || "spread_d", a_4, row, &subregion2_word.spread_d)?;
self.assign_and_constrain(region, || "spread_d", a_4, row, subregion2_word.spread_d)?;
// Assign `e` and copy constraint
self.assign_and_constrain(region, || "e", a_7, row, &subregion2_word.e)?;
self.assign_and_constrain(region, || "e", a_7, row, subregion2_word.e)?;
// Assign `f` and copy constraint
self.assign_and_constrain(region, || "f", a_7, row + 1, &subregion2_word.f)?;
self.assign_and_constrain(region, || "f", a_7, row + 1, subregion2_word.f)?;
// Assign `spread_g` and copy constraint
self.assign_and_constrain(region, || "spread_g", a_5, row, &subregion2_word.spread_g)?;
self.assign_and_constrain(region, || "spread_g", a_5, row, subregion2_word.spread_g)?;
Ok((
spread_a as u64,
spread_b_lo as u64,
spread_b_hi as u64,
spread_c as u64,
subregion2_word.spread_d.value.unwrap() as u64,
subregion2_word.e.value.unwrap() as u64,
subregion2_word.f.value.unwrap() as u64,
subregion2_word.spread_g.value.unwrap() as u64,
))
Ok([
spread_a,
spread_b_lo,
spread_b_hi,
spread_c,
subregion2_word.spread_d.value,
subregion2_word.e.value,
subregion2_word.f.value,
subregion2_word.spread_g.value,
])
}
fn lower_sigma_0_v2<F: FieldExt>(
@ -308,38 +388,50 @@ impl MessageScheduleConfig {
let row = get_word_row(subregion2_word.index) + 3;
// Get spread pieces
let (spread_a, spread_b_lo, spread_b_hi, spread_c, spread_d, e, f, spread_g) =
self.assign_lower_sigma_v2_pieces(region, row, subregion2_word)?;
let pieces = self.assign_lower_sigma_v2_pieces(region, row, subregion2_word)?;
// Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd}
let xor_0 = spread_b_lo
+ (1 << 4) * spread_b_hi
+ (1 << 8) * spread_c
+ (1 << 14) * spread_d
+ (1 << 28) * e
+ (1 << 30) * f
+ (1 << 32) * spread_g;
let xor_1 = spread_c
+ (1 << 6) * spread_d
+ (1 << 20) * e
+ (1 << 22) * f
+ (1 << 24) * spread_g
+ (1 << 50) * spread_a
+ (1 << 56) * spread_b_lo
+ (1 << 60) * spread_b_hi;
let xor_2 = f
+ (1 << 2) * spread_g
+ (1 << 28) * spread_a
+ (1 << 34) * spread_b_lo
+ (1 << 38) * spread_b_hi
+ (1 << 42) * spread_c
+ (1 << 48) * spread_d
+ (1 << 62) * e;
let (r_0_even, r_0_odd, r_1_even, r_1_odd) = if pieces[0].is_some() {
let pieces = pieces
.iter()
.map(|piece| piece.unwrap() as u64)
.collect::<Vec<_>>();
let [spread_a, spread_b_lo, spread_b_hi, spread_c, spread_d, e, f, spread_g] = [
pieces[0], pieces[1], pieces[2], pieces[3], pieces[4], pieces[5], pieces[6],
pieces[7],
];
let xor_0 = spread_b_lo
+ (1 << 4) * spread_b_hi
+ (1 << 8) * spread_c
+ (1 << 14) * spread_d
+ (1 << 28) * e
+ (1 << 30) * f
+ (1 << 32) * spread_g;
let xor_1 = spread_c
+ (1 << 6) * spread_d
+ (1 << 20) * e
+ (1 << 22) * f
+ (1 << 24) * spread_g
+ (1 << 50) * spread_a
+ (1 << 56) * spread_b_lo
+ (1 << 60) * spread_b_hi;
let xor_2 = f
+ (1 << 2) * spread_g
+ (1 << 28) * spread_a
+ (1 << 34) * spread_b_lo
+ (1 << 38) * spread_b_hi
+ (1 << 42) * spread_c
+ (1 << 48) * spread_d
+ (1 << 62) * e;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
(Some(r_0_even), Some(r_0_odd), Some(r_1_even), Some(r_1_odd))
} else {
(None, None, None, None)
};
self.assign_sigma_outputs(
region,
@ -361,34 +453,46 @@ impl MessageScheduleConfig {
let a_3 = self.extras[0];
let row = get_word_row(subregion2_word.index) + SIGMA_0_V2_ROWS + 3;
let (spread_a, spread_b_lo, spread_b_hi, spread_c, spread_d, e, f, spread_g) =
self.assign_lower_sigma_v2_pieces(region, row, subregion2_word)?;
let pieces = self.assign_lower_sigma_v2_pieces(region, row, subregion2_word)?;
// (3, 4, 3, 7, 1, 1, 13)
// Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd}
let xor_0 = spread_d + (1 << 14) * e + (1 << 16) * f + (1 << 18) * spread_g;
let xor_1 = e
+ (1 << 2) * f
+ (1 << 4) * spread_g
+ (1 << 30) * spread_a
+ (1 << 36) * spread_b_lo
+ (1 << 40) * spread_b_hi
+ (1 << 44) * spread_c
+ (1 << 50) * spread_d;
let xor_2 = spread_g
+ (1 << 26) * spread_a
+ (1 << 32) * spread_b_lo
+ (1 << 36) * spread_b_hi
+ (1 << 40) * spread_c
+ (1 << 46) * spread_d
+ (1 << 60) * e
+ (1 << 62) * f;
let (r_0_even, r_0_odd, r_1_even, r_1_odd) = if pieces[0].is_some() {
let pieces = pieces
.iter()
.map(|piece| piece.unwrap() as u64)
.collect::<Vec<_>>();
let [spread_a, spread_b_lo, spread_b_hi, spread_c, spread_d, e, f, spread_g] = [
pieces[0], pieces[1], pieces[2], pieces[3], pieces[4], pieces[5], pieces[6],
pieces[7],
];
let xor_0 = spread_d + (1 << 14) * e + (1 << 16) * f + (1 << 18) * spread_g;
let xor_1 = e
+ (1 << 2) * f
+ (1 << 4) * spread_g
+ (1 << 30) * spread_a
+ (1 << 36) * spread_b_lo
+ (1 << 40) * spread_b_hi
+ (1 << 44) * spread_c
+ (1 << 50) * spread_d;
let xor_2 = spread_g
+ (1 << 26) * spread_a
+ (1 << 32) * spread_b_lo
+ (1 << 36) * spread_b_hi
+ (1 << 40) * spread_c
+ (1 << 46) * spread_d
+ (1 << 60) * e
+ (1 << 62) * f;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
(Some(r_0_even), Some(r_0_odd), Some(r_1_even), Some(r_1_odd))
} else {
(None, None, None, None)
};
self.assign_sigma_outputs(
region,

View File

@ -7,11 +7,11 @@ use halo2::{arithmetic::FieldExt, circuit::Region, plonk::Error};
pub struct Subregion3Word {
index: usize,
#[allow(dead_code)]
a: CellValue32,
b: CellValue32,
c: CellValue32,
a: CellValue16,
b: CellValue16,
c: CellValue16,
#[allow(dead_code)]
d: CellValue32,
d: CellValue16,
spread_a: CellValue32,
spread_d: CellValue32,
}
@ -40,8 +40,7 @@ impl MessageScheduleConfig {
// The lowest-index words involved will be W_[35..58]
let mut new_word = |idx: usize| -> Result<(), Error> {
// Decompose word into (10, 7, 2, 13)-bit chunks
let subregion3_word =
self.decompose_subregion3_word(region, w[idx].value.unwrap(), idx)?;
let subregion3_word = self.decompose_subregion3_word(region, w[idx].value, idx)?;
// sigma_1 on subregion3_word
let (r_0_even, r_1_even) = self.lower_sigma_1(region, subregion3_word)?;
@ -54,14 +53,14 @@ impl MessageScheduleConfig {
|| format!("sigma_0(W_{})_lo", new_word_idx - 15),
a_6,
get_word_row(new_word_idx - 16),
&lower_sigma_0_v2_output[idx - 49].0.into(),
lower_sigma_0_v2_output[idx - 49].0,
)?;
self.assign_and_constrain(
region,
|| format!("sigma_0(W_{})_hi", new_word_idx - 15),
a_6,
get_word_row(new_word_idx - 16) + 1,
&lower_sigma_0_v2_output[idx - 49].1.into(),
lower_sigma_0_v2_output[idx - 49].1,
)?;
// Copy sigma_1(W_{i - 2})
@ -70,14 +69,14 @@ impl MessageScheduleConfig {
|| format!("sigma_1(W_{})_lo", new_word_idx - 2),
a_7,
get_word_row(new_word_idx - 16),
&r_0_even.into(),
r_0_even,
)?;
self.assign_and_constrain(
region,
|| format!("sigma_1(W_{})_hi", new_word_idx - 2),
a_7,
get_word_row(new_word_idx - 16) + 1,
&r_1_even.into(),
r_1_even,
)?;
// Copy W_{i - 7}
@ -86,48 +85,55 @@ impl MessageScheduleConfig {
|| format!("W_{}_lo", new_word_idx - 7),
a_8,
get_word_row(new_word_idx - 16),
&w_halves[new_word_idx - 7].0.into(),
w_halves[new_word_idx - 7].0,
)?;
self.assign_and_constrain(
region,
|| format!("W_{}_hi", new_word_idx - 7),
a_8,
get_word_row(new_word_idx - 16) + 1,
&w_halves[new_word_idx - 7].1.into(),
w_halves[new_word_idx - 7].1,
)?;
// Calculate W_i, carry_i
let word_lo: u32 = r_0_even.value.unwrap() as u32
+ w_halves[new_word_idx - 7].0.value.unwrap() as u32
+ lower_sigma_0_v2_output[idx - 49].0.value.unwrap() as u32
+ w_halves[new_word_idx - 16].0.value.unwrap() as u32;
let word_hi: u32 = r_1_even.value.unwrap() as u32
+ w_halves[new_word_idx - 7].1.value.unwrap() as u32
+ lower_sigma_0_v2_output[idx - 49].1.value.unwrap() as u32
+ w_halves[new_word_idx - 16].1.value.unwrap() as u32;
let word: u64 = word_lo as u64 + (1 << 16) * (word_hi as u64);
let carry = word >> 32;
let word = word as u32;
let (word, carry) = sum_with_carry(vec![
(r_0_even.value, r_1_even.value),
(
w_halves[new_word_idx - 7].0.value,
w_halves[new_word_idx - 7].1.value,
),
(
lower_sigma_0_v2_output[idx - 49].0.value,
lower_sigma_0_v2_output[idx - 49].1.value,
),
(
w_halves[new_word_idx - 16].0.value,
w_halves[new_word_idx - 16].1.value,
),
]);
// Assign W_i, carry_i
region.assign_advice(
|| format!("W_{}", new_word_idx),
a_5,
get_word_row(new_word_idx - 16) + 1,
|| Ok(F::from_u64(word as u64)),
|| {
word.map(|word| F::from_u64(word as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| format!("carry_{}", new_word_idx),
a_9,
get_word_row(new_word_idx - 16) + 1,
|| Ok(F::from_u64(carry as u64)),
|| {
carry
.map(|carry| F::from_u64(carry as u64))
.ok_or(Error::SynthesisError)
},
)?;
let (var, halves) = self.assign_word_and_halves(region, word, new_word_idx)?;
w.push(MessageWord {
var,
value: Some(word),
});
w.push(MessageWord { var, value: word });
w_halves.push(halves);
Ok(())
@ -143,7 +149,7 @@ impl MessageScheduleConfig {
fn decompose_subregion3_word<F: FieldExt>(
&self,
region: &mut Region<'_, F>,
word: u32,
word: Option<u32>,
index: usize,
) -> Result<Subregion3Word, Error> {
let row = get_word_row(index);
@ -152,30 +158,56 @@ impl MessageScheduleConfig {
let a_3 = self.extras[0];
let a_4 = self.extras[1];
let pieces = chop_u32(word, &[10, 7, 2, 13]);
let pieces = transpose_option_vec(
word.map(|word| {
chop_u32(word, &[10, 7, 2, 13])
.into_iter()
.map(|piece| piece as u16)
.collect()
}),
4,
);
// Assign `a` (10-bit piece)
let spread_a = SpreadWord::new(pieces[0] as u16);
let spread_a = pieces[0].map(SpreadWord::new);
let spread_a = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_a)?;
// Assign `b` (7-bit piece)
let b = region.assign_advice(|| "b", a_4, row + 1, || Ok(F::from_u64(pieces[1] as u64)))?;
let b = region.assign_advice(
|| "b",
a_4,
row + 1,
|| {
pieces[1]
.map(|piece| F::from_u64(piece as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `c` (2-bit piece)
let c = region.assign_advice(|| "c", a_3, row + 1, || Ok(F::from_u64(pieces[2] as u64)))?;
let c = region.assign_advice(
|| "c",
a_3,
row + 1,
|| {
pieces[2]
.map(|piece| F::from_u64(piece as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `d` (13-bit piece) lookup
let spread_d = SpreadWord::new(pieces[3] as u16);
let spread_d = pieces[3].map(SpreadWord::new);
let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?;
Ok(Subregion3Word {
index,
a: CellValue32::new(spread_a.dense.var, spread_a.dense.value.unwrap().into()),
b: CellValue32::new(b, pieces[1]),
c: CellValue32::new(c, pieces[2]),
d: CellValue32::new(spread_d.dense.var, spread_d.dense.value.unwrap().into()),
spread_a: CellValue32::new(spread_a.spread.var, spread_a.spread.value.unwrap()),
spread_d: CellValue32::new(spread_d.spread.var, spread_d.spread.value.unwrap()),
a: CellValue16::new(spread_a.dense.var, spread_a.dense.value),
b: CellValue16::new(b, pieces[1]),
c: CellValue16::new(c, pieces[2]),
d: CellValue16::new(spread_d.dense.var, spread_d.dense.value),
spread_a: CellValue32::new(spread_a.spread.var, spread_a.spread.value),
spread_d: CellValue32::new(spread_d.spread.var, spread_d.spread.value),
})
}
@ -192,86 +224,144 @@ impl MessageScheduleConfig {
let row = get_word_row(word.index) + 3;
// Assign `spread_a` and copy constraint
self.assign_and_constrain(region, || "spread_a", a_4, row, &word.spread_a)?;
self.assign_and_constrain(region, || "spread_a", a_4, row, word.spread_a)?;
// Split `b` (7-bit chunk) into (2,2,3)-bit `b_lo`, `b_mid` and `b_hi`
let b = word.b.value.unwrap();
let b_hi = (b & 0b1110000) >> 4;
let (b_lo, b_mid) = bisect_four_bit(b & 0b1111);
let spread_b_lo = interleave_u16_with_zeros(b_lo as u16);
let spread_b_mid = interleave_u16_with_zeros(b_mid as u16);
let spread_b_hi = interleave_u16_with_zeros(b_hi as u16);
let (b_lo, b_mid, b_hi) = {
let b_hi = word.b.value.map(|b| (b & 0b1110000) >> 4);
let (b_lo, b_mid) = {
let b_lo_mid = word.b.value.map(|b| bisect_four_bit(b & 0b1111));
(b_lo_mid.map(|(lo, _)| lo), b_lo_mid.map(|(_, mid)| mid))
};
(b_lo, b_mid, b_hi)
};
let (spread_b_lo, spread_b_mid, spread_b_hi) = {
let spread_b_lo = b_lo.map(|b_lo| interleave_u16_with_zeros(b_lo as u16));
let spread_b_mid = b_mid.map(|b_mid| interleave_u16_with_zeros(b_mid as u16));
let spread_b_hi = b_hi.map(|b_hi| interleave_u16_with_zeros(b_hi as u16));
(spread_b_lo, spread_b_mid, spread_b_hi)
};
// Assign `b_lo`, `spread_b_lo`, `b_mid`, `spread_b_mid`, `b_hi`, `spread_b_hi`
region.assign_advice(|| "b_lo", a_3, row - 1, || Ok(F::from_u64(b_lo as u64)))?;
region.assign_advice(
|| "b_lo",
a_3,
row - 1,
|| {
b_lo.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| "spread_b_lo",
a_4,
row - 1,
|| Ok(F::from_u64(spread_b_lo as u64)),
|| {
spread_b_lo
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| "b_mid",
a_5,
row - 1,
|| {
b_mid
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(|| "b_mid", a_5, row - 1, || Ok(F::from_u64(b_mid as u64)))?;
region.assign_advice(
|| "spread_b_mid",
a_6,
row - 1,
|| Ok(F::from_u64(spread_b_mid as u64)),
|| {
spread_b_mid
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(
|| "b_hi",
a_5,
row + 1,
|| {
b_hi.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
region.assign_advice(|| "b_hi", a_5, row + 1, || Ok(F::from_u64(b_hi as u64)))?;
region.assign_advice(
|| "spread_b_hi",
a_6,
row + 1,
|| Ok(F::from_u64(spread_b_hi as u64)),
|| {
spread_b_hi
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `b` and copy constraint
self.assign_and_constrain(region, || "b", a_6, row, &word.b)?;
self.assign_and_constrain(region, || "b", a_6, row, word.b)?;
// Assign `c` and copy constraint
self.assign_and_constrain(region, || "c", a_3, row + 1, &word.c)?;
self.assign_and_constrain(region, || "c", a_3, row + 1, word.c)?;
// Witness `spread_c`
let spread_c = interleave_u16_with_zeros(word.c.value.unwrap() as u16);
let spread_c = word
.c
.value
.map(|value| interleave_u16_with_zeros(value as u16));
region.assign_advice(
|| "spread_c",
a_4,
row + 1,
|| Ok(F::from_u64(spread_c as u64)),
|| {
spread_c
.map(|value| F::from_u64(value as u64))
.ok_or(Error::SynthesisError)
},
)?;
// Assign `spread_d` and copy constraint
self.assign_and_constrain(region, || "spread_d", a_5, row, &word.spread_d)?;
self.assign_and_constrain(region, || "spread_d", a_5, row, word.spread_d)?;
// (10, 7, 2, 13)
// Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd}
let spread_a = word.spread_a.value.unwrap() as u64;
let spread_b_lo = spread_b_lo as u64;
let spread_b_mid = spread_b_mid as u64;
let spread_b_hi = spread_b_hi as u64;
let spread_c = spread_c as u64;
let spread_d = word.spread_d.value.unwrap() as u64;
let xor_0 = spread_b_lo
+ (1 << 4) * spread_b_mid
+ (1 << 8) * spread_b_hi
+ (1 << 14) * spread_c
+ (1 << 18) * spread_d;
let xor_1 = spread_c
+ (1 << 4) * spread_d
+ (1 << 30) * spread_a
+ (1 << 50) * spread_b_lo
+ (1 << 54) * spread_b_mid
+ (1 << 58) * spread_b_hi;
let xor_2 = spread_d
+ (1 << 26) * spread_a
+ (1 << 46) * spread_b_lo
+ (1 << 50) * spread_b_mid
+ (1 << 54) * spread_b_hi
+ (1 << 60) * spread_c;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
let (r_0_even, r_0_odd, r_1_even, r_1_odd) = if word.spread_a.value.is_some() {
let spread_a = word.spread_a.value.unwrap() as u64;
let spread_b_lo = spread_b_lo.unwrap() as u64;
let spread_b_mid = spread_b_mid.unwrap() as u64;
let spread_b_hi = spread_b_hi.unwrap() as u64;
let spread_c = spread_c.unwrap() as u64;
let spread_d = word.spread_d.value.unwrap() as u64;
let xor_0 = spread_b_lo
+ (1 << 4) * spread_b_mid
+ (1 << 8) * spread_b_hi
+ (1 << 14) * spread_c
+ (1 << 18) * spread_d;
let xor_1 = spread_c
+ (1 << 4) * spread_d
+ (1 << 30) * spread_a
+ (1 << 50) * spread_b_lo
+ (1 << 54) * spread_b_mid
+ (1 << 58) * spread_b_hi;
let xor_2 = spread_d
+ (1 << 26) * spread_a
+ (1 << 46) * spread_b_lo
+ (1 << 50) * spread_b_mid
+ (1 << 54) * spread_b_hi
+ (1 << 60) * spread_c;
let r = xor_0 + xor_1 + xor_2;
let r_pieces = chop_u64(r, &[32, 32]); // r_0, r_1
let (r_0_even, r_0_odd) = get_even_and_odd_bits_u32(r_pieces[0] as u32);
let (r_1_even, r_1_odd) = get_even_and_odd_bits_u32(r_pieces[1] as u32);
(Some(r_0_even), Some(r_0_odd), Some(r_1_even), Some(r_1_odd))
} else {
(None, None, None, None)
};
self.assign_sigma_outputs(
region,

View File

@ -23,12 +23,16 @@ impl SpreadWord {
spread: interleave_u16_with_zeros(word),
}
}
pub(super) fn opt_new(word: Option<u16>) -> Option<Self> {
word.map(SpreadWord::new)
}
}
/// A variable stored in advice columns corresponding to a row of [`SpreadTableConfig`].
#[derive(Copy, Clone, Debug)]
pub(super) struct SpreadVar {
pub tag: u8,
pub tag: Option<u8>,
pub dense: CellValue16,
pub spread: CellValue32,
}
@ -38,12 +42,22 @@ impl SpreadVar {
region: &mut Region<'_, F>,
cols: &SpreadInputs,
row: usize,
word: SpreadWord,
word: Option<SpreadWord>,
) -> Result<Self, Error> {
let tag = word.tag;
let dense_val = Some(word.dense);
let spread_val = Some(word.spread);
region.assign_advice(|| "tag", cols.tag, row, || Ok(F::from_u64(tag as u64)))?;
let tag = word.map(|word| word.tag);
let dense_val = word.map(|word| word.dense);
let spread_val = word.map(|word| word.spread);
region.assign_advice(
|| "tag",
cols.tag,
row,
|| {
tag.map(|tag| F::from_u64(tag as u64))
.ok_or(Error::SynthesisError)
},
)?;
let dense_var = region.assign_advice(
|| "dense",
cols.dense,
@ -67,8 +81,8 @@ impl SpreadVar {
Ok(SpreadVar {
tag,
dense: CellValue16::new(dense_var, dense_val.unwrap()),
spread: CellValue32::new(spread_var, spread_val.unwrap()),
dense: CellValue16::new(dense_var, dense_val),
spread: CellValue32::new(spread_var, spread_val),
})
}
@ -78,11 +92,11 @@ impl SpreadVar {
dense_row: usize,
spread_col: Column<Advice>,
spread_row: usize,
word: SpreadWord,
word: Option<SpreadWord>,
) -> Result<Self, Error> {
let tag = word.tag;
let dense_val = Some(word.dense);
let spread_val = Some(word.spread);
let tag = word.map(|word| word.tag);
let dense_val = word.map(|word| word.dense);
let spread_val = word.map(|word| word.spread);
let dense_var = region.assign_advice(
|| "dense",
dense_col,
@ -106,8 +120,8 @@ impl SpreadVar {
Ok(SpreadVar {
tag,
dense: CellValue16::new(dense_var, dense_val.unwrap()),
spread: CellValue32::new(spread_var, spread_val.unwrap()),
dense: CellValue16::new(dense_var, dense_val),
spread: CellValue32::new(spread_var, spread_val),
})
}
}

View File

@ -87,9 +87,38 @@ pub fn get_even_and_odd_bits_u32(word: u32) -> (u16, u16) {
}
// Split 4-bit value into 2-bit lo and hi halves
pub fn bisect_four_bit(word: u32) -> (u32, u32) {
assert!(word < 16); // 4-bit range-check
pub fn bisect_four_bit(word: impl Into<u32>) -> (u32, u32) {
let word: u32 = word.into();
assert!(word < (1 << 4)); // 4-bit range-check
let word_hi = (word & 0b1100) >> 2;
let word_lo = word & 0b0011;
(word_lo, word_hi)
}
/// Helper function to transpose an Option<Vec<F>> to a Vec<Option<F>>.
/// The length of the vector must be `len`.
pub fn transpose_option_vec<F: Copy>(vec: Option<Vec<F>>, len: usize) -> Vec<Option<F>> {
if let Some(vec) = vec {
vec.into_iter().map(Some).collect()
} else {
vec![None; len]
}
}
/// Given a vector of words as vec![(lo: u16, hi: u16)], returns their sum: u32, along
/// with a carry bit.
pub fn sum_with_carry(words: Vec<(Option<u16>, Option<u16>)>) -> (Option<u32>, Option<u64>) {
let words_lo: Option<Vec<u64>> = words.iter().map(|(lo, _)| lo.map(|lo| lo as u64)).collect();
let words_hi: Option<Vec<u64>> = words.iter().map(|(_, hi)| hi.map(|hi| hi as u64)).collect();
let sum: Option<u64> = {
let sum_lo: Option<u64> = words_lo.map(|vec| vec.iter().sum());
let sum_hi: Option<u64> = words_hi.map(|vec| vec.iter().sum());
sum_lo.zip(sum_hi).map(|(lo, hi)| lo + (1 << 16) * hi)
};
let carry = sum.map(|sum| (sum >> 32) as u64);
let sum = sum.map(|sum| sum as u32);
(sum, carry)
}