Add MessageSchedule gates and assign fixed column cells

This commit is contained in:
therealyingtong 2021-01-06 13:32:07 +08:00 committed by Jack Grigg
parent fc4f3576a0
commit 88379fa62f
5 changed files with 804 additions and 7 deletions

View file

@ -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::*;

View 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)
}
}

View file

@ -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,
}
}
}

View 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())),
)
}
}

View file

@ -514,7 +514,7 @@ mod tests {
],
);
let message_schedule = MessageSchedule::configure(
let message_schedule = MessageSchedule::empty_configure(
meta,
lookup_inputs.clone(),
message_schedule,