mirror of
https://github.com/saymrwulf/pasta_curves-source.git
synced 2026-09-04 20:03:39 +00:00
Add MessageSchedule gates and assign fixed column cells
This commit is contained in:
parent
fc4f3576a0
commit
88379fa62f
5 changed files with 804 additions and 7 deletions
|
|
@ -7,10 +7,12 @@ use crate::{
|
|||
plonk::{Advice, Column, ConstraintSystem, Error, Permutation},
|
||||
};
|
||||
|
||||
mod gates;
|
||||
mod message_schedule;
|
||||
mod spread_table;
|
||||
mod util;
|
||||
|
||||
use gates::*;
|
||||
use message_schedule::*;
|
||||
use spread_table::*;
|
||||
|
||||
|
|
|
|||
118
src/gadget/sha256/table16/gates.rs
Normal file
118
src/gadget/sha256/table16/gates.rs
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
use crate::arithmetic::FieldExt;
|
||||
use crate::plonk::Expression;
|
||||
|
||||
pub struct Gate<F: FieldExt>(pub Expression<F>);
|
||||
|
||||
impl<F: FieldExt> Gate<F> {
|
||||
fn ones() -> Expression<F> {
|
||||
Expression::Constant(F::one())
|
||||
}
|
||||
|
||||
// Helper gates
|
||||
fn lagrange_interpolate(
|
||||
var: Expression<F>,
|
||||
points: Vec<u16>,
|
||||
evals: Vec<u32>,
|
||||
) -> (F, Expression<F>) {
|
||||
assert_eq!(points.len(), evals.len());
|
||||
let deg = points.len();
|
||||
|
||||
fn factorial(n: u64) -> u64 {
|
||||
if n < 2 {
|
||||
1
|
||||
} else {
|
||||
n * factorial(n - 1)
|
||||
}
|
||||
}
|
||||
|
||||
// Scale the whole expression by factor to avoid divisions
|
||||
let factor = factorial((deg - 1) as u64);
|
||||
|
||||
let numerator = |var: Expression<F>, eval: u32, idx: u64| {
|
||||
let mut expr = Self::ones();
|
||||
for i in 0..deg {
|
||||
let i = i as u64;
|
||||
if i != idx {
|
||||
expr = expr * (Self::ones() * (-F::one()) * F::from_u64(i) + var.clone());
|
||||
}
|
||||
}
|
||||
expr * F::from_u64(eval.into())
|
||||
};
|
||||
let denominator = |idx: i32| {
|
||||
let mut denom: i32 = 1;
|
||||
for i in 0..deg {
|
||||
let i = i as i32;
|
||||
if i != idx {
|
||||
denom *= idx - i
|
||||
}
|
||||
}
|
||||
if denom < 0 {
|
||||
-F::one() * F::from_u64(factor / (-denom as u64))
|
||||
} else {
|
||||
F::from_u64(factor / (denom as u64))
|
||||
}
|
||||
};
|
||||
|
||||
let mut expr = Self::ones() * F::zero();
|
||||
for ((idx, _), eval) in points.iter().enumerate().zip(evals.iter()) {
|
||||
expr = expr + numerator(var.clone(), *eval, idx as u64) * denominator(idx as i32)
|
||||
}
|
||||
|
||||
(F::from_u64(factor), expr)
|
||||
}
|
||||
|
||||
pub fn range_check(value: Expression<F>, lower_range: u64, upper_range: u64) -> Expression<F> {
|
||||
let mut expr = Self::ones();
|
||||
for i in lower_range..(upper_range + 1) {
|
||||
expr = expr * (Self::ones() * (-F::one()) * F::from_u64(i) + value.clone())
|
||||
}
|
||||
expr
|
||||
}
|
||||
|
||||
// 2-bit range check
|
||||
fn two_bit_range_check(value: Expression<F>) -> Expression<F> {
|
||||
Self::range_check(value, 0, (1 << 2) - 1)
|
||||
}
|
||||
|
||||
// 2-bit spread interpolation
|
||||
fn two_bit_spread(dense: Expression<F>, spread: Expression<F>) -> Expression<F> {
|
||||
let (factor, lagrange_poly) = Self::lagrange_interpolate(
|
||||
dense,
|
||||
vec![0b00, 0b01, 0b10, 0b11],
|
||||
vec![0b0000, 0b0001, 0b0100, 0b0101],
|
||||
);
|
||||
|
||||
lagrange_poly + (spread * factor * (-F::one()))
|
||||
}
|
||||
|
||||
// 3-bit range check
|
||||
fn three_bit_range_check(value: Expression<F>) -> Expression<F> {
|
||||
Self::range_check(value, 0, (1 << 3) - 1)
|
||||
}
|
||||
|
||||
// 3-bit spread
|
||||
fn three_bit_spread(dense: Expression<F>, spread: Expression<F>) -> Expression<F> {
|
||||
let (factor, lagrange_poly) = Self::lagrange_interpolate(
|
||||
dense,
|
||||
vec![0b000, 0b001, 0b010, 0b011, 0b100, 0b101, 0b110, 0b111],
|
||||
vec![
|
||||
0b000000, 0b000001, 0b000100, 0b000101, 0b010000, 0b010001, 0b010100, 0b010101,
|
||||
],
|
||||
);
|
||||
|
||||
lagrange_poly + (spread * factor * (-F::one()))
|
||||
}
|
||||
|
||||
/// Spread and range check on 2-bit word
|
||||
pub fn two_bit_spread_and_range(dense: Expression<F>, spread: Expression<F>) -> Expression<F> {
|
||||
Self::two_bit_range_check(dense.clone()) + Self::two_bit_spread(dense, spread)
|
||||
}
|
||||
|
||||
/// Spread and range check on 3-bit word
|
||||
pub fn three_bit_spread_and_range(
|
||||
dense: Expression<F>,
|
||||
spread: Expression<F>,
|
||||
) -> Expression<F> {
|
||||
Self::three_bit_range_check(dense.clone()) + Self::three_bit_spread(dense, spread)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,15 +7,17 @@ use crate::{
|
|||
arithmetic::FieldExt,
|
||||
circuit::{Cell, Layouter},
|
||||
plonk::{Advice, Column, ConstraintSystem, Error, Fixed, Permutation},
|
||||
poly::Rotation,
|
||||
};
|
||||
|
||||
// mod schedule_gates;
|
||||
mod schedule_gates;
|
||||
mod schedule_util;
|
||||
// mod subregion1;
|
||||
// mod subregion2;
|
||||
// mod subregion3;
|
||||
|
||||
// use schedule_gates::ScheduleGate;
|
||||
use schedule_gates::ScheduleGate;
|
||||
use schedule_util::*;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(super) struct MessageWord {
|
||||
|
|
@ -78,7 +80,208 @@ impl MessageSchedule {
|
|||
let s_lower_sigma_0_v2 = meta.fixed_column();
|
||||
let s_lower_sigma_1_v2 = meta.fixed_column();
|
||||
|
||||
// TODO: Create gates
|
||||
// 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];
|
||||
|
||||
// s_word for W_[16..64]
|
||||
meta.create_gate("s_word for W_[16..64]", |meta| {
|
||||
let s_word = meta.query_fixed(s_word, Rotation::cur());
|
||||
|
||||
let sigma_0_lo = meta.query_advice(a_6, Rotation::prev());
|
||||
let sigma_0_hi = meta.query_advice(a_6, Rotation::cur());
|
||||
|
||||
let sigma_1_lo = meta.query_advice(a_7, Rotation::prev());
|
||||
let sigma_1_hi = meta.query_advice(a_7, Rotation::cur());
|
||||
|
||||
let w_minus_9_lo = meta.query_advice(a_8, Rotation::prev());
|
||||
let w_minus_9_hi = meta.query_advice(a_8, Rotation::cur());
|
||||
|
||||
let w_minus_16_lo = meta.query_advice(a_3, Rotation::prev());
|
||||
let w_minus_16_hi = meta.query_advice(a_4, Rotation::prev());
|
||||
|
||||
let word = meta.query_advice(a_5, Rotation::cur());
|
||||
let carry = meta.query_advice(a_9, Rotation::cur());
|
||||
|
||||
ScheduleGate::s_word(
|
||||
s_word,
|
||||
sigma_0_lo,
|
||||
sigma_0_hi,
|
||||
sigma_1_lo,
|
||||
sigma_1_hi,
|
||||
w_minus_9_lo,
|
||||
w_minus_9_hi,
|
||||
w_minus_16_lo,
|
||||
w_minus_16_hi,
|
||||
word,
|
||||
carry,
|
||||
)
|
||||
.0
|
||||
});
|
||||
|
||||
// s_decompose_0 for all words
|
||||
meta.create_gate("s_decompose_0", |meta| {
|
||||
let s_decompose_0 = meta.query_fixed(s_decompose_0, Rotation::cur());
|
||||
let lo = meta.query_advice(a_3, Rotation::cur());
|
||||
let hi = meta.query_advice(a_4, Rotation::cur());
|
||||
let word = meta.query_advice(a_5, Rotation::cur());
|
||||
|
||||
ScheduleGate::s_decompose_0(s_decompose_0, lo, hi, word).0
|
||||
});
|
||||
|
||||
// s_decompose_1 for W_[1..14]
|
||||
// (3, 4, 11, 14)-bit chunks
|
||||
meta.create_gate("s_decompose_1", |meta| {
|
||||
let s_decompose_1 = meta.query_fixed(s_decompose_1, Rotation::cur());
|
||||
let a = meta.query_advice(a_3, Rotation::next()); // 3-bit chunk
|
||||
let b = meta.query_advice(a_4, Rotation::next()); // 4-bit chunk
|
||||
let c = meta.query_advice(a_1, Rotation::next()); // 11-bit chunk
|
||||
let tag_c = meta.query_advice(a_0, Rotation::next());
|
||||
let d = meta.query_advice(a_1, Rotation::cur()); // 14-bit chunk
|
||||
let tag_d = meta.query_advice(a_0, Rotation::cur());
|
||||
let word = meta.query_advice(a_5, Rotation::cur());
|
||||
|
||||
ScheduleGate::s_decompose_1(s_decompose_1, a, b, c, tag_c, d, tag_d, word).0
|
||||
});
|
||||
|
||||
// s_decompose_2 for W_[14..49]
|
||||
// (3, 4, 3, 7, 1, 1, 13)-bit chunks
|
||||
meta.create_gate("s_decompose_2", |meta| {
|
||||
let s_decompose_2 = meta.query_fixed(s_decompose_2, Rotation::cur());
|
||||
let a = meta.query_advice(a_3, Rotation::prev()); // 3-bit chunk
|
||||
let b = meta.query_advice(a_1, Rotation::next()); // 4-bit chunk
|
||||
let c = meta.query_advice(a_4, Rotation::prev()); // 3-bit chunk
|
||||
let d = meta.query_advice(a_1, Rotation::cur()); // 7-bit chunk
|
||||
let tag_d = meta.query_advice(a_0, Rotation::cur());
|
||||
let e = meta.query_advice(a_3, Rotation::next()); // 1-bit chunk
|
||||
let f = meta.query_advice(a_4, Rotation::next()); // 1-bit chunk
|
||||
let g = meta.query_advice(a_1, Rotation::prev()); // 13-bit chunk
|
||||
let tag_g = meta.query_advice(a_0, Rotation::prev());
|
||||
let word = meta.query_advice(a_5, Rotation::cur());
|
||||
|
||||
ScheduleGate::s_decompose_2(s_decompose_2, a, b, c, d, tag_d, e, f, g, tag_g, word).0
|
||||
});
|
||||
|
||||
// s_decompose_3 for W_49 to W_61
|
||||
// (10, 7, 2, 13)-bit chunks
|
||||
meta.create_gate("s_decompose_3", |meta| {
|
||||
let s_decompose_3 = meta.query_fixed(s_decompose_3, Rotation::cur());
|
||||
let a = meta.query_advice(a_1, Rotation::next()); // 10-bit chunk
|
||||
let tag_a = meta.query_advice(a_0, Rotation::next());
|
||||
let b = meta.query_advice(a_4, Rotation::next()); // 7-bit chunk
|
||||
let c = meta.query_advice(a_3, Rotation::next()); // 2-bit chunk
|
||||
let d = meta.query_advice(a_1, Rotation::cur()); // 13-bit chunk
|
||||
let tag_d = meta.query_advice(a_0, Rotation::cur());
|
||||
let word = meta.query_advice(a_5, Rotation::cur());
|
||||
|
||||
ScheduleGate::s_decompose_3(s_decompose_3, a, tag_a, b, c, d, tag_d, word).0
|
||||
});
|
||||
|
||||
// sigma_0 v1 on W_[1..14]
|
||||
// (3, 4, 11, 14)-bit chunks
|
||||
meta.create_gate("sigma_0 v1", |meta| {
|
||||
ScheduleGate::s_lower_sigma_0(
|
||||
meta.query_fixed(s_lower_sigma_0, Rotation::cur()), // s_lower_sigma_0
|
||||
meta.query_advice(a_2, Rotation::prev()), // spread_r0_even
|
||||
meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd
|
||||
meta.query_advice(a_2, Rotation::next()), // spread_r1_even
|
||||
meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd
|
||||
meta.query_advice(a_5, Rotation::next()), // a
|
||||
meta.query_advice(a_6, Rotation::next()), // spread_a
|
||||
meta.query_advice(a_6, Rotation::cur()), // b
|
||||
meta.query_advice(a_3, Rotation::prev()), // b_lo
|
||||
meta.query_advice(a_4, Rotation::prev()), // spread_b_lo
|
||||
meta.query_advice(a_5, Rotation::prev()), // b_hi
|
||||
meta.query_advice(a_6, Rotation::prev()), // spread_b_hi
|
||||
meta.query_advice(a_4, Rotation::cur()), // spread_c
|
||||
meta.query_advice(a_5, Rotation::cur()), // spread_d
|
||||
)
|
||||
.0
|
||||
});
|
||||
|
||||
// sigma_0 v2 on W_[14..49]
|
||||
// (3, 4, 3, 7, 1, 1, 13)-bit chunks
|
||||
meta.create_gate("sigma_0 v2", |meta| {
|
||||
ScheduleGate::s_lower_sigma_0_v2(
|
||||
meta.query_fixed(s_lower_sigma_0_v2, Rotation::cur()), // s_lower_sigma_0_v2
|
||||
meta.query_advice(a_2, Rotation::prev()), // spread_r0_even
|
||||
meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd
|
||||
meta.query_advice(a_2, Rotation::next()), // spread_r1_even
|
||||
meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd
|
||||
meta.query_advice(a_3, Rotation::next()), // a
|
||||
meta.query_advice(a_4, Rotation::next()), // spread_a
|
||||
meta.query_advice(a_6, Rotation::cur()), // b
|
||||
meta.query_advice(a_3, Rotation::prev()), // b_lo
|
||||
meta.query_advice(a_4, Rotation::prev()), // spread_b_lo
|
||||
meta.query_advice(a_5, Rotation::prev()), // b_hi
|
||||
meta.query_advice(a_6, Rotation::prev()), // spread_b_hi
|
||||
meta.query_advice(a_5, Rotation::next()), // c
|
||||
meta.query_advice(a_6, Rotation::next()), // spread_c
|
||||
meta.query_advice(a_4, Rotation::cur()), // spread_d
|
||||
meta.query_advice(a_7, Rotation::cur()), // spread_e
|
||||
meta.query_advice(a_7, Rotation::next()), // spread_f
|
||||
meta.query_advice(a_5, Rotation::cur()), // spread_g
|
||||
)
|
||||
.0
|
||||
});
|
||||
|
||||
// sigma_1 v2 on W_14 to W_48
|
||||
// (3, 4, 3, 7, 1, 1, 13)-bit chunks
|
||||
meta.create_gate("sigma_1 v2", |meta| {
|
||||
ScheduleGate::s_lower_sigma_1_v2(
|
||||
meta.query_fixed(s_lower_sigma_1_v2, Rotation::cur()), // s_lower_sigma_1_v2
|
||||
meta.query_advice(a_2, Rotation::prev()), // spread_r0_even
|
||||
meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd
|
||||
meta.query_advice(a_2, Rotation::next()), // spread_r1_even
|
||||
meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd
|
||||
meta.query_advice(a_3, Rotation::next()), // a
|
||||
meta.query_advice(a_4, Rotation::next()), // spread_a
|
||||
meta.query_advice(a_6, Rotation::cur()), // b
|
||||
meta.query_advice(a_3, Rotation::prev()), // b_lo
|
||||
meta.query_advice(a_4, Rotation::prev()), // spread_b_lo
|
||||
meta.query_advice(a_5, Rotation::prev()), // b_hi
|
||||
meta.query_advice(a_6, Rotation::prev()), // spread_b_hi
|
||||
meta.query_advice(a_5, Rotation::next()), // c
|
||||
meta.query_advice(a_6, Rotation::next()), // spread_c
|
||||
meta.query_advice(a_4, Rotation::cur()), // spread_d
|
||||
meta.query_advice(a_7, Rotation::cur()), // spread_e
|
||||
meta.query_advice(a_7, Rotation::next()), // spread_f
|
||||
meta.query_advice(a_5, Rotation::cur()), // spread_g
|
||||
)
|
||||
.0
|
||||
});
|
||||
|
||||
// sigma_1 v1 on W_49 to W_61
|
||||
// (10, 7, 2, 13)-bit chunks
|
||||
meta.create_gate("sigma_1 v1", |meta| {
|
||||
ScheduleGate::s_lower_sigma_1(
|
||||
meta.query_fixed(s_lower_sigma_1, Rotation::cur()), // s_lower_sigma_1
|
||||
meta.query_advice(a_2, Rotation::prev()), // spread_r0_even
|
||||
meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd
|
||||
meta.query_advice(a_2, Rotation::next()), // spread_r1_even
|
||||
meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd
|
||||
meta.query_advice(a_4, Rotation::cur()), // spread_a
|
||||
meta.query_advice(a_6, Rotation::cur()), // b
|
||||
meta.query_advice(a_3, Rotation::prev()), // b_lo
|
||||
meta.query_advice(a_4, Rotation::prev()), // spread_b_lo
|
||||
meta.query_advice(a_5, Rotation::prev()), // b_mid
|
||||
meta.query_advice(a_6, Rotation::prev()), // spread_b_mid
|
||||
meta.query_advice(a_5, Rotation::next()), // b_hi
|
||||
meta.query_advice(a_6, Rotation::next()), // spread_b_hi
|
||||
meta.query_advice(a_3, Rotation::next()), // c
|
||||
meta.query_advice(a_4, Rotation::next()), // spread_c
|
||||
meta.query_advice(a_5, Rotation::cur()), // spread_d
|
||||
)
|
||||
.0
|
||||
});
|
||||
|
||||
MessageSchedule {
|
||||
lookup,
|
||||
|
|
@ -107,10 +310,92 @@ impl MessageSchedule {
|
|||
|
||||
layouter.assign_region(
|
||||
|| "process message block",
|
||||
|region| {
|
||||
let region = std::cell::RefCell::new(region);
|
||||
|mut region| {
|
||||
w = Vec::<MessageWord>::with_capacity(ROUNDS);
|
||||
w_halves = Vec::<(CellValue16, CellValue16)>::with_capacity(ROUNDS);
|
||||
|
||||
// TODO: Assign cells
|
||||
// Assign all fixed columns
|
||||
for index in 1..14 {
|
||||
let row = get_word_row(index);
|
||||
region.assign_fixed(
|
||||
|| "s_decompose_1",
|
||||
self.s_decompose_1,
|
||||
row,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
region.assign_fixed(
|
||||
|| "s_lower_sigma_0",
|
||||
self.s_lower_sigma_0,
|
||||
row + 3,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
}
|
||||
|
||||
for index in 14..49 {
|
||||
let row = get_word_row(index);
|
||||
region.assign_fixed(
|
||||
|| "s_decompose_2",
|
||||
self.s_decompose_2,
|
||||
row,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
region.assign_fixed(
|
||||
|| "s_lower_sigma_0_v2",
|
||||
self.s_lower_sigma_0_v2,
|
||||
row + 3,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
region.assign_fixed(
|
||||
|| "s_lower_sigma_1_v2",
|
||||
self.s_lower_sigma_1_v2,
|
||||
row + SIGMA_0_V2_ROWS + 3,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
|
||||
let new_word_idx = index + 2;
|
||||
region.assign_fixed(
|
||||
|| "s_word",
|
||||
self.s_word,
|
||||
get_word_row(new_word_idx - 16) + 1,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
}
|
||||
|
||||
for index in 49..62 {
|
||||
let row = get_word_row(index);
|
||||
region.assign_fixed(
|
||||
|| "s_decompose_3",
|
||||
self.s_decompose_3,
|
||||
row,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
region.assign_fixed(
|
||||
|| "s_lower_sigma_1",
|
||||
self.s_lower_sigma_1,
|
||||
row + 3,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
|
||||
let new_word_idx = index + 2;
|
||||
region.assign_fixed(
|
||||
|| "s_word",
|
||||
self.s_word,
|
||||
get_word_row(new_word_idx - 16) + 1,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
}
|
||||
|
||||
for index in 0..64 {
|
||||
let row = get_word_row(index);
|
||||
region.assign_fixed(
|
||||
|| "s_decompose_0",
|
||||
self.s_decompose_0,
|
||||
row,
|
||||
|| Ok(F::one()),
|
||||
)?;
|
||||
}
|
||||
|
||||
// TODO: Assign advice columns
|
||||
|
||||
Ok(())
|
||||
},
|
||||
|
|
@ -118,4 +403,40 @@ impl MessageSchedule {
|
|||
|
||||
Ok((w.try_into().unwrap(), w_halves.try_into().unwrap()))
|
||||
}
|
||||
|
||||
/// Empty configuration without gates. Useful for fast testing
|
||||
pub(super) fn empty_configure<F: FieldExt>(
|
||||
meta: &mut ConstraintSystem<F>,
|
||||
lookup: SpreadInputs,
|
||||
message_schedule: Column<Advice>,
|
||||
extras: [Column<Advice>; 6],
|
||||
perm: Permutation,
|
||||
) -> Self {
|
||||
// Create fixed columns for the selectors we will require.
|
||||
let s_word = meta.fixed_column();
|
||||
let s_decompose_0 = meta.fixed_column();
|
||||
let s_decompose_1 = meta.fixed_column();
|
||||
let s_decompose_2 = meta.fixed_column();
|
||||
let s_decompose_3 = meta.fixed_column();
|
||||
let s_lower_sigma_0 = meta.fixed_column();
|
||||
let s_lower_sigma_1 = meta.fixed_column();
|
||||
let s_lower_sigma_0_v2 = meta.fixed_column();
|
||||
let s_lower_sigma_1_v2 = meta.fixed_column();
|
||||
|
||||
MessageSchedule {
|
||||
lookup,
|
||||
message_schedule,
|
||||
extras,
|
||||
s_word,
|
||||
s_decompose_0,
|
||||
s_decompose_1,
|
||||
s_decompose_2,
|
||||
s_decompose_3,
|
||||
s_lower_sigma_0,
|
||||
s_lower_sigma_1,
|
||||
s_lower_sigma_0_v2,
|
||||
s_lower_sigma_1_v2,
|
||||
perm,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
356
src/gadget/sha256/table16/message_schedule/schedule_gates.rs
Normal file
356
src/gadget/sha256/table16/message_schedule/schedule_gates.rs
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
use super::super::Gate;
|
||||
use crate::arithmetic::FieldExt;
|
||||
use crate::plonk::Expression;
|
||||
|
||||
pub struct ScheduleGate<F: FieldExt>(pub Expression<F>);
|
||||
|
||||
impl<F: FieldExt> ScheduleGate<F> {
|
||||
/// s_word for W_16 to W_63
|
||||
pub fn s_word(
|
||||
s_word: Expression<F>,
|
||||
sigma_0_lo: Expression<F>,
|
||||
sigma_0_hi: Expression<F>,
|
||||
sigma_1_lo: Expression<F>,
|
||||
sigma_1_hi: Expression<F>,
|
||||
w_minus_9_lo: Expression<F>,
|
||||
w_minus_9_hi: Expression<F>,
|
||||
w_minus_16_lo: Expression<F>,
|
||||
w_minus_16_hi: Expression<F>,
|
||||
word: Expression<F>,
|
||||
carry: Expression<F>,
|
||||
) -> Self {
|
||||
let lo = sigma_0_lo + sigma_1_lo + w_minus_9_lo + w_minus_16_lo;
|
||||
let hi = sigma_0_hi + sigma_1_hi + w_minus_9_hi + w_minus_16_hi;
|
||||
|
||||
let word_check = lo
|
||||
+ hi * F::from_u64(1 << 16)
|
||||
+ (carry.clone() * F::from_u64(1 << 32) * (-F::one()))
|
||||
+ (word * (-F::one()));
|
||||
let carry_check = Gate::range_check(carry, 0, 3);
|
||||
|
||||
ScheduleGate(s_word * (word_check + carry_check))
|
||||
}
|
||||
|
||||
/// s_decompose_0 for all words
|
||||
pub fn s_decompose_0(
|
||||
s_decompose_0: Expression<F>,
|
||||
lo: Expression<F>,
|
||||
hi: Expression<F>,
|
||||
word: Expression<F>,
|
||||
) -> Self {
|
||||
ScheduleGate(s_decompose_0 * (lo + hi * F::from_u64(1 << 16) + word * (-F::one())))
|
||||
}
|
||||
|
||||
/// s_decompose_1 for W_1 to W_13
|
||||
/// (3, 4, 11, 14)-bit chunks
|
||||
pub fn s_decompose_1(
|
||||
s_decompose_1: Expression<F>,
|
||||
a: Expression<F>,
|
||||
b: Expression<F>,
|
||||
c: Expression<F>,
|
||||
tag_c: Expression<F>,
|
||||
d: Expression<F>,
|
||||
tag_d: Expression<F>,
|
||||
word: Expression<F>,
|
||||
) -> Self {
|
||||
let decompose_check = a
|
||||
+ b * F::from_u64(1 << 3)
|
||||
+ c * F::from_u64(1 << 7)
|
||||
+ d * F::from_u64(1 << 18)
|
||||
+ word * (-F::one());
|
||||
let range_check_tag_c = Gate::range_check(tag_c, 0, 2);
|
||||
let range_check_tag_d = Gate::range_check(tag_d, 0, 4);
|
||||
ScheduleGate(s_decompose_1 * (decompose_check + range_check_tag_c + range_check_tag_d))
|
||||
}
|
||||
|
||||
/// s_decompose_2 for W_14 to W_48
|
||||
/// (3, 4, 3, 7, 1, 1, 13)-bit chunks
|
||||
pub fn s_decompose_2(
|
||||
s_decompose_2: Expression<F>,
|
||||
a: Expression<F>,
|
||||
b: Expression<F>,
|
||||
c: Expression<F>,
|
||||
d: Expression<F>,
|
||||
tag_d: Expression<F>,
|
||||
e: Expression<F>,
|
||||
f: Expression<F>,
|
||||
g: Expression<F>,
|
||||
tag_g: Expression<F>,
|
||||
word: Expression<F>,
|
||||
) -> Self {
|
||||
let decompose_check = a
|
||||
+ b * F::from_u64(1 << 3)
|
||||
+ c * F::from_u64(1 << 7)
|
||||
+ d * F::from_u64(1 << 10)
|
||||
+ e * F::from_u64(1 << 17)
|
||||
+ f * F::from_u64(1 << 18)
|
||||
+ g * F::from_u64(1 << 19)
|
||||
+ word * (-F::one());
|
||||
let range_check_tag_d = Gate::range_check(tag_d, 0, 0);
|
||||
let range_check_tag_g = Gate::range_check(tag_g, 0, 3);
|
||||
ScheduleGate(s_decompose_2 * (decompose_check + range_check_tag_g + range_check_tag_d))
|
||||
}
|
||||
|
||||
/// s_decompose_3 for W_49 to W_61
|
||||
/// (10, 7, 2, 13)-bit chunks
|
||||
pub fn s_decompose_3(
|
||||
s_decompose_3: Expression<F>,
|
||||
a: Expression<F>,
|
||||
tag_a: Expression<F>,
|
||||
b: Expression<F>,
|
||||
c: Expression<F>,
|
||||
d: Expression<F>,
|
||||
tag_d: Expression<F>,
|
||||
word: Expression<F>,
|
||||
) -> Self {
|
||||
let decompose_check = a
|
||||
+ b * F::from_u64(1 << 10)
|
||||
+ c * F::from_u64(1 << 17)
|
||||
+ d * F::from_u64(1 << 19)
|
||||
+ word * (-F::one());
|
||||
let range_check_tag_a = Gate::range_check(tag_a, 0, 1);
|
||||
let range_check_tag_d = Gate::range_check(tag_d, 0, 3);
|
||||
|
||||
ScheduleGate(s_decompose_3 * (decompose_check + range_check_tag_a + range_check_tag_d))
|
||||
}
|
||||
|
||||
/// b_lo + 2^2 * b_mid = b, on W_[1..49]
|
||||
fn check_b(b: Expression<F>, b_lo: Expression<F>, b_hi: Expression<F>) -> Expression<F> {
|
||||
let expected_b = b_lo + b_hi * F::from_u64(1 << 2);
|
||||
expected_b + (b * -F::one())
|
||||
}
|
||||
|
||||
/// b_lo + 2^2 * b_mid + 2^4 * b_hi = b, on W_[49..62]
|
||||
fn check_b1(
|
||||
b: Expression<F>,
|
||||
b_lo: Expression<F>,
|
||||
b_mid: Expression<F>,
|
||||
b_hi: Expression<F>,
|
||||
) -> Expression<F> {
|
||||
let expected_b = b_lo + b_mid * F::from_u64(1 << 2) + b_hi * F::from_u64(1 << 4);
|
||||
expected_b + (b * -F::one())
|
||||
}
|
||||
|
||||
/// sigma_0 v1 on W_1 to W_13
|
||||
/// (3, 4, 11, 14)-bit chunks
|
||||
pub fn s_lower_sigma_0(
|
||||
s_lower_sigma_0: Expression<F>,
|
||||
spread_r0_even: Expression<F>,
|
||||
spread_r0_odd: Expression<F>,
|
||||
spread_r1_even: Expression<F>,
|
||||
spread_r1_odd: Expression<F>,
|
||||
a: Expression<F>,
|
||||
spread_a: Expression<F>,
|
||||
b: Expression<F>,
|
||||
b_lo: Expression<F>,
|
||||
spread_b_lo: Expression<F>,
|
||||
b_hi: Expression<F>,
|
||||
spread_b_hi: Expression<F>,
|
||||
spread_c: Expression<F>,
|
||||
spread_d: Expression<F>,
|
||||
) -> Self {
|
||||
let check_spread_and_range =
|
||||
Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone())
|
||||
+ Gate::two_bit_spread_and_range(b_hi.clone(), spread_b_hi.clone())
|
||||
+ Gate::three_bit_spread_and_range(a, spread_a.clone());
|
||||
let check_b = Self::check_b(b, b_lo, b_hi);
|
||||
let spread_witness = spread_r0_even
|
||||
+ spread_r0_odd * F::from_u64(2)
|
||||
+ (spread_r1_even + spread_r1_odd * F::from_u64(2)) * F::from_u64(1 << 32);
|
||||
let xor_0 = spread_b_lo.clone()
|
||||
+ spread_b_hi.clone() * F::from_u64(1 << 4)
|
||||
+ spread_c.clone() * F::from_u64(1 << 8)
|
||||
+ spread_d.clone() * F::from_u64(1 << 30);
|
||||
let xor_1 = spread_c.clone()
|
||||
+ spread_d.clone() * F::from_u64(1 << 22)
|
||||
+ spread_a.clone() * F::from_u64(1 << 50)
|
||||
+ spread_b_lo.clone() * F::from_u64(1 << 56)
|
||||
+ spread_b_hi.clone() * F::from_u64(1 << 60);
|
||||
let xor_2 = spread_d
|
||||
+ spread_a * F::from_u64(1 << 28)
|
||||
+ spread_b_lo * F::from_u64(1 << 34)
|
||||
+ spread_b_hi * F::from_u64(1 << 38)
|
||||
+ spread_c * F::from_u64(1 << 42);
|
||||
let xor = xor_0 + xor_1 + xor_2;
|
||||
|
||||
ScheduleGate(
|
||||
s_lower_sigma_0
|
||||
* (check_spread_and_range + check_b + spread_witness + (xor * -F::one())),
|
||||
)
|
||||
}
|
||||
|
||||
/// sigma_1 v1 on W_49 to W_61
|
||||
/// (10, 7, 2, 13)-bit chunks
|
||||
pub fn s_lower_sigma_1(
|
||||
s_lower_sigma_1: Expression<F>,
|
||||
spread_r0_even: Expression<F>,
|
||||
spread_r0_odd: Expression<F>,
|
||||
spread_r1_even: Expression<F>,
|
||||
spread_r1_odd: Expression<F>,
|
||||
spread_a: Expression<F>,
|
||||
b: Expression<F>,
|
||||
b_lo: Expression<F>,
|
||||
spread_b_lo: Expression<F>,
|
||||
b_mid: Expression<F>,
|
||||
spread_b_mid: Expression<F>,
|
||||
b_hi: Expression<F>,
|
||||
spread_b_hi: Expression<F>,
|
||||
c: Expression<F>,
|
||||
spread_c: Expression<F>,
|
||||
spread_d: Expression<F>,
|
||||
) -> Self {
|
||||
let check_spread_and_range =
|
||||
Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone())
|
||||
+ Gate::two_bit_spread_and_range(b_mid.clone(), spread_b_mid.clone())
|
||||
+ Gate::two_bit_spread_and_range(c, spread_c.clone())
|
||||
+ Gate::three_bit_spread_and_range(b_hi.clone(), spread_b_hi.clone());
|
||||
let check_b1 = Self::check_b1(b, b_lo, b_mid, b_hi);
|
||||
let spread_witness = spread_r0_even
|
||||
+ spread_r0_odd * F::from_u64(2)
|
||||
+ (spread_r1_even + spread_r1_odd * F::from_u64(2)) * F::from_u64(1 << 32);
|
||||
let xor_0 = spread_b_lo.clone()
|
||||
+ spread_b_mid.clone() * F::from_u64(1 << 4)
|
||||
+ spread_b_hi.clone() * F::from_u64(1 << 8)
|
||||
+ spread_c.clone() * F::from_u64(1 << 14)
|
||||
+ spread_d.clone() * F::from_u64(1 << 18);
|
||||
let xor_1 = spread_c.clone()
|
||||
+ spread_d.clone() * F::from_u64(1 << 4)
|
||||
+ spread_a.clone() * F::from_u64(1 << 30)
|
||||
+ spread_b_lo.clone() * F::from_u64(1 << 50)
|
||||
+ spread_b_mid.clone() * F::from_u64(1 << 54)
|
||||
+ spread_b_hi.clone() * F::from_u64(1 << 58);
|
||||
let xor_2 = spread_d.clone()
|
||||
+ spread_a.clone() * F::from_u64(1 << 26)
|
||||
+ spread_b_lo.clone() * F::from_u64(1 << 46)
|
||||
+ spread_b_mid.clone() * F::from_u64(1 << 50)
|
||||
+ spread_b_hi.clone() * F::from_u64(1 << 54)
|
||||
+ spread_c.clone() * F::from_u64(1 << 60);
|
||||
let xor = xor_0 + xor_1 + xor_2;
|
||||
|
||||
ScheduleGate(
|
||||
s_lower_sigma_1
|
||||
* (check_spread_and_range + check_b1 + spread_witness + (xor * -F::one())),
|
||||
)
|
||||
}
|
||||
|
||||
/// sigma_0 v2 on W_14 to W_48
|
||||
/// (3, 4, 3, 7, 1, 1, 13)-bit chunks
|
||||
pub fn s_lower_sigma_0_v2(
|
||||
s_lower_sigma_0_v2: Expression<F>,
|
||||
spread_r0_even: Expression<F>,
|
||||
spread_r0_odd: Expression<F>,
|
||||
spread_r1_even: Expression<F>,
|
||||
spread_r1_odd: Expression<F>,
|
||||
a: Expression<F>,
|
||||
spread_a: Expression<F>,
|
||||
b: Expression<F>,
|
||||
b_lo: Expression<F>,
|
||||
spread_b_lo: Expression<F>,
|
||||
b_hi: Expression<F>,
|
||||
spread_b_hi: Expression<F>,
|
||||
c: Expression<F>,
|
||||
spread_c: Expression<F>,
|
||||
spread_d: Expression<F>,
|
||||
spread_e: Expression<F>,
|
||||
spread_f: Expression<F>,
|
||||
spread_g: Expression<F>,
|
||||
) -> Self {
|
||||
let check_spread_and_range =
|
||||
Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone())
|
||||
+ Gate::two_bit_spread_and_range(b_hi.clone(), spread_b_hi.clone())
|
||||
+ Gate::three_bit_spread_and_range(a, spread_a.clone())
|
||||
+ Gate::three_bit_spread_and_range(c, spread_c.clone());
|
||||
let check_b = Self::check_b(b, b_lo, b_hi);
|
||||
let spread_witness = spread_r0_even
|
||||
+ spread_r0_odd * F::from_u64(2)
|
||||
+ (spread_r1_even + spread_r1_odd * F::from_u64(2)) * F::from_u64(1 << 32);
|
||||
let xor_0 = spread_b_lo.clone()
|
||||
+ spread_b_hi.clone() * F::from_u64(1 << 4)
|
||||
+ spread_c.clone() * F::from_u64(1 << 8)
|
||||
+ spread_d.clone() * F::from_u64(1 << 14)
|
||||
+ spread_e.clone() * F::from_u64(1 << 28)
|
||||
+ spread_f.clone() * F::from_u64(1 << 30)
|
||||
+ spread_g.clone() * F::from_u64(1 << 32);
|
||||
let xor_1 = spread_c.clone()
|
||||
+ spread_d.clone() * F::from_u64(1 << 6)
|
||||
+ spread_e.clone() * F::from_u64(1 << 20)
|
||||
+ spread_f.clone() * F::from_u64(1 << 22)
|
||||
+ spread_g.clone() * F::from_u64(1 << 24)
|
||||
+ spread_a.clone() * F::from_u64(1 << 50)
|
||||
+ spread_b_lo.clone() * F::from_u64(1 << 56)
|
||||
+ spread_b_hi.clone() * F::from_u64(1 << 60);
|
||||
let xor_2 = spread_f
|
||||
+ spread_g * F::from_u64(1 << 2)
|
||||
+ spread_a * F::from_u64(1 << 28)
|
||||
+ spread_b_lo * F::from_u64(1 << 34)
|
||||
+ spread_b_hi * F::from_u64(1 << 38)
|
||||
+ spread_c * F::from_u64(1 << 42)
|
||||
+ spread_d * F::from_u64(1 << 48)
|
||||
+ spread_e * F::from_u64(1 << 62);
|
||||
let xor = xor_0 + xor_1 + xor_2;
|
||||
|
||||
ScheduleGate(
|
||||
s_lower_sigma_0_v2
|
||||
* (check_spread_and_range + check_b + spread_witness + (xor * -F::one())),
|
||||
)
|
||||
}
|
||||
|
||||
/// sigma_1 v2 on W_14 to W_48
|
||||
/// (3, 4, 3, 7, 1, 1, 13)-bit chunks
|
||||
pub fn s_lower_sigma_1_v2(
|
||||
s_lower_sigma_1_v2: Expression<F>,
|
||||
spread_r0_even: Expression<F>,
|
||||
spread_r0_odd: Expression<F>,
|
||||
spread_r1_even: Expression<F>,
|
||||
spread_r1_odd: Expression<F>,
|
||||
a: Expression<F>,
|
||||
spread_a: Expression<F>,
|
||||
b: Expression<F>,
|
||||
b_lo: Expression<F>,
|
||||
spread_b_lo: Expression<F>,
|
||||
b_hi: Expression<F>,
|
||||
spread_b_hi: Expression<F>,
|
||||
c: Expression<F>,
|
||||
spread_c: Expression<F>,
|
||||
spread_d: Expression<F>,
|
||||
spread_e: Expression<F>,
|
||||
spread_f: Expression<F>,
|
||||
spread_g: Expression<F>,
|
||||
) -> Self {
|
||||
let check_spread_and_range =
|
||||
Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone())
|
||||
+ Gate::two_bit_spread_and_range(b_hi.clone(), spread_b_hi.clone())
|
||||
+ Gate::three_bit_spread_and_range(a, spread_a.clone())
|
||||
+ Gate::three_bit_spread_and_range(c, spread_c.clone());
|
||||
let check_b = Self::check_b(b, b_lo, b_hi);
|
||||
let spread_witness = spread_r0_even
|
||||
+ spread_r0_odd * F::from_u64(2)
|
||||
+ (spread_r1_even + spread_r1_odd * F::from_u64(2)) * F::from_u64(1 << 32);
|
||||
let xor_0 = spread_d.clone()
|
||||
+ spread_e.clone() * F::from_u64(1 << 14)
|
||||
+ spread_f.clone() * F::from_u64(1 << 16)
|
||||
+ spread_g.clone() * F::from_u64(1 << 18);
|
||||
let xor_1 = spread_e.clone()
|
||||
+ spread_f.clone() * F::from_u64(1 << 2)
|
||||
+ spread_g.clone() * F::from_u64(1 << 4)
|
||||
+ spread_a.clone() * F::from_u64(1 << 30)
|
||||
+ spread_b_lo.clone() * F::from_u64(1 << 36)
|
||||
+ spread_b_hi.clone() * F::from_u64(1 << 40)
|
||||
+ spread_c.clone() * F::from_u64(1 << 44)
|
||||
+ spread_d.clone() * F::from_u64(1 << 50);
|
||||
let xor_2 = spread_g
|
||||
+ spread_a * F::from_u64(1 << 26)
|
||||
+ spread_b_lo * F::from_u64(1 << 32)
|
||||
+ spread_b_hi * F::from_u64(1 << 36)
|
||||
+ spread_c * F::from_u64(1 << 40)
|
||||
+ spread_d * F::from_u64(1 << 46)
|
||||
+ spread_e * F::from_u64(1 << 60)
|
||||
+ spread_f * F::from_u64(1 << 62);
|
||||
let xor = xor_0 + xor_1 + xor_2;
|
||||
|
||||
ScheduleGate(
|
||||
s_lower_sigma_1_v2
|
||||
* (check_spread_and_range + check_b + spread_witness + (xor * -F::one())),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -514,7 +514,7 @@ mod tests {
|
|||
],
|
||||
);
|
||||
|
||||
let message_schedule = MessageSchedule::configure(
|
||||
let message_schedule = MessageSchedule::empty_configure(
|
||||
meta,
|
||||
lookup_inputs.clone(),
|
||||
message_schedule,
|
||||
|
|
|
|||
Loading…
Reference in a new issue