diff --git a/src/gadget/sha256/table16.rs b/src/gadget/sha256/table16.rs index f5952a3..3542792 100644 --- a/src/gadget/sha256/table16.rs +++ b/src/gadget/sha256/table16.rs @@ -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::*; diff --git a/src/gadget/sha256/table16/gates.rs b/src/gadget/sha256/table16/gates.rs new file mode 100644 index 0000000..1bf070f --- /dev/null +++ b/src/gadget/sha256/table16/gates.rs @@ -0,0 +1,118 @@ +use crate::arithmetic::FieldExt; +use crate::plonk::Expression; + +pub struct Gate(pub Expression); + +impl Gate { + fn ones() -> Expression { + Expression::Constant(F::one()) + } + + // Helper gates + fn lagrange_interpolate( + var: Expression, + points: Vec, + evals: Vec, + ) -> (F, Expression) { + 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, 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, lower_range: u64, upper_range: u64) -> Expression { + 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) -> Expression { + Self::range_check(value, 0, (1 << 2) - 1) + } + + // 2-bit spread interpolation + fn two_bit_spread(dense: Expression, spread: Expression) -> Expression { + 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) -> Expression { + Self::range_check(value, 0, (1 << 3) - 1) + } + + // 3-bit spread + fn three_bit_spread(dense: Expression, spread: Expression) -> Expression { + 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, spread: Expression) -> Expression { + 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, + spread: Expression, + ) -> Expression { + Self::three_bit_range_check(dense.clone()) + Self::three_bit_spread(dense, spread) + } +} diff --git a/src/gadget/sha256/table16/message_schedule.rs b/src/gadget/sha256/table16/message_schedule.rs index 5d62832..ba602f9 100644 --- a/src/gadget/sha256/table16/message_schedule.rs +++ b/src/gadget/sha256/table16/message_schedule.rs @@ -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::::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( + meta: &mut ConstraintSystem, + lookup: SpreadInputs, + message_schedule: Column, + extras: [Column; 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, + } + } } diff --git a/src/gadget/sha256/table16/message_schedule/schedule_gates.rs b/src/gadget/sha256/table16/message_schedule/schedule_gates.rs new file mode 100644 index 0000000..de9cae4 --- /dev/null +++ b/src/gadget/sha256/table16/message_schedule/schedule_gates.rs @@ -0,0 +1,356 @@ +use super::super::Gate; +use crate::arithmetic::FieldExt; +use crate::plonk::Expression; + +pub struct ScheduleGate(pub Expression); + +impl ScheduleGate { + /// s_word for W_16 to W_63 + pub fn s_word( + s_word: Expression, + sigma_0_lo: Expression, + sigma_0_hi: Expression, + sigma_1_lo: Expression, + sigma_1_hi: Expression, + w_minus_9_lo: Expression, + w_minus_9_hi: Expression, + w_minus_16_lo: Expression, + w_minus_16_hi: Expression, + word: Expression, + carry: Expression, + ) -> 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, + lo: Expression, + hi: Expression, + word: Expression, + ) -> 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, + a: Expression, + b: Expression, + c: Expression, + tag_c: Expression, + d: Expression, + tag_d: Expression, + word: Expression, + ) -> 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, + a: Expression, + b: Expression, + c: Expression, + d: Expression, + tag_d: Expression, + e: Expression, + f: Expression, + g: Expression, + tag_g: Expression, + word: Expression, + ) -> 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, + a: Expression, + tag_a: Expression, + b: Expression, + c: Expression, + d: Expression, + tag_d: Expression, + word: Expression, + ) -> 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, b_lo: Expression, b_hi: Expression) -> Expression { + 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, + b_lo: Expression, + b_mid: Expression, + b_hi: Expression, + ) -> Expression { + 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, + spread_r0_even: Expression, + spread_r0_odd: Expression, + spread_r1_even: Expression, + spread_r1_odd: Expression, + a: Expression, + spread_a: Expression, + b: Expression, + b_lo: Expression, + spread_b_lo: Expression, + b_hi: Expression, + spread_b_hi: Expression, + spread_c: Expression, + spread_d: Expression, + ) -> 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, + spread_r0_even: Expression, + spread_r0_odd: Expression, + spread_r1_even: Expression, + spread_r1_odd: Expression, + spread_a: Expression, + b: Expression, + b_lo: Expression, + spread_b_lo: Expression, + b_mid: Expression, + spread_b_mid: Expression, + b_hi: Expression, + spread_b_hi: Expression, + c: Expression, + spread_c: Expression, + spread_d: Expression, + ) -> 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, + spread_r0_even: Expression, + spread_r0_odd: Expression, + spread_r1_even: Expression, + spread_r1_odd: Expression, + a: Expression, + spread_a: Expression, + b: Expression, + b_lo: Expression, + spread_b_lo: Expression, + b_hi: Expression, + spread_b_hi: Expression, + c: Expression, + spread_c: Expression, + spread_d: Expression, + spread_e: Expression, + spread_f: Expression, + spread_g: Expression, + ) -> 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, + spread_r0_even: Expression, + spread_r0_odd: Expression, + spread_r1_even: Expression, + spread_r1_odd: Expression, + a: Expression, + spread_a: Expression, + b: Expression, + b_lo: Expression, + spread_b_lo: Expression, + b_hi: Expression, + spread_b_hi: Expression, + c: Expression, + spread_c: Expression, + spread_d: Expression, + spread_e: Expression, + spread_f: Expression, + spread_g: Expression, + ) -> 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())), + ) + } +} diff --git a/src/gadget/sha256/table16/spread_table.rs b/src/gadget/sha256/table16/spread_table.rs index 8e0c866..cce299d 100644 --- a/src/gadget/sha256/table16/spread_table.rs +++ b/src/gadget/sha256/table16/spread_table.rs @@ -514,7 +514,7 @@ mod tests { ], ); - let message_schedule = MessageSchedule::configure( + let message_schedule = MessageSchedule::empty_configure( meta, lookup_inputs.clone(), message_schedule,