From 4d7c7171079cf8173572359ed2e0fec035de4a9b Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 15 Jan 2021 13:05:42 +0800 Subject: [PATCH] Add utils for Compression assignments --- src/gadget/sha256/table16/compression.rs | 2 +- .../table16/compression/compression_util.rs | 1130 +++++++++++++++++ 2 files changed, 1131 insertions(+), 1 deletion(-) create mode 100644 src/gadget/sha256/table16/compression/compression_util.rs diff --git a/src/gadget/sha256/table16/compression.rs b/src/gadget/sha256/table16/compression.rs index b51d8b0f..3b1c4d3a 100644 --- a/src/gadget/sha256/table16/compression.rs +++ b/src/gadget/sha256/table16/compression.rs @@ -10,7 +10,7 @@ use crate::{ }; mod compression_gates; -// mod compression_util; +mod compression_util; // mod subregion_digest; // mod subregion_initial; // mod subregion_main; diff --git a/src/gadget/sha256/table16/compression/compression_util.rs b/src/gadget/sha256/table16/compression/compression_util.rs new file mode 100644 index 00000000..18fc1522 --- /dev/null +++ b/src/gadget/sha256/table16/compression/compression_util.rs @@ -0,0 +1,1130 @@ +use super::super::{ + util::*, CellValue16, CellValue32, SpreadVar, SpreadWord, StateWord, Table16Assignment, + Table16Chip, +}; +use super::{ + AbcdVar, Compression, EfghVar, RoundWordA, RoundWordDense, RoundWordE, RoundWordSpread, State, +}; +use crate::{ + arithmetic::FieldExt, + circuit::Region, + plonk::{Advice, Column, Error}, +}; + +// Test vector 'abc' +pub const COMPRESSION_OUTPUT: [u32; 8] = [ + 0b10111010011110000001011010111111, + 0b10001111000000011100111111101010, + 0b01000001010000010100000011011110, + 0b01011101101011100010001000100011, + 0b10110000000000110110000110100011, + 0b10010110000101110111101010011100, + 0b10110100000100001111111101100001, + 0b11110010000000000001010110101101, +]; + +// Rows needed for each gate +pub const SIGMA_0_ROWS: usize = 4; +pub const SIGMA_1_ROWS: usize = 4; +pub const CH_ROWS: usize = 8; +pub const MAJ_ROWS: usize = 4; +pub const DECOMPOSE_ABCD: usize = 2; +pub const DECOMPOSE_EFGH: usize = 2; + +// Rows needed for main subregion +pub const SUBREGION_MAIN_LEN: usize = 64; +pub const SUBREGION_MAIN_WORD: usize = + DECOMPOSE_ABCD + SIGMA_0_ROWS + DECOMPOSE_EFGH + SIGMA_1_ROWS + CH_ROWS + MAJ_ROWS; +pub const SUBREGION_MAIN_ROWS: usize = SUBREGION_MAIN_LEN * SUBREGION_MAIN_WORD; + +/// Returns starting row number of a compression round +pub fn get_round_row(round_idx: i32) -> usize { + assert!(round_idx >= -1); + assert!(round_idx < 64); + if round_idx == -1 { + // Init subregion + 0 + } else { + // Main subregion + (round_idx as usize) * SUBREGION_MAIN_WORD + } +} + +pub fn get_decompose_e_row(round_idx: i32) -> usize { + get_round_row(round_idx) +} + +pub fn get_decompose_f_row(round_idx: i32) -> usize { + assert_eq!(round_idx, -1); + get_decompose_e_row(round_idx) + DECOMPOSE_EFGH +} + +pub fn get_decompose_g_row(round_idx: i32) -> usize { + get_decompose_f_row(round_idx) + DECOMPOSE_EFGH +} + +pub fn get_upper_sigma_1_row(round_idx: i32) -> usize { + assert!(round_idx >= 0); + get_decompose_e_row(round_idx) + DECOMPOSE_EFGH + 1 +} + +pub fn get_ch_row(round_idx: i32) -> usize { + assert!(round_idx >= 0); + get_decompose_e_row(round_idx) + DECOMPOSE_EFGH + SIGMA_1_ROWS + 1 +} + +pub fn get_ch_neg_row(round_idx: i32) -> usize { + get_ch_row(round_idx) + CH_ROWS / 2 +} + +pub fn get_decompose_a_row(round_idx: i32) -> usize { + if round_idx == -1 { + get_h_row(round_idx) + DECOMPOSE_EFGH + } else { + get_ch_neg_row(round_idx) - 1 + CH_ROWS / 2 + } +} + +pub fn get_upper_sigma_0_row(round_idx: i32) -> usize { + assert!(round_idx >= 0); + get_decompose_a_row(round_idx) + DECOMPOSE_ABCD + 1 +} + +pub fn get_decompose_b_row(round_idx: i32) -> usize { + assert_eq!(round_idx, -1); + get_decompose_a_row(round_idx) + DECOMPOSE_ABCD +} + +pub fn get_decompose_c_row(round_idx: i32) -> usize { + get_decompose_b_row(round_idx) + DECOMPOSE_ABCD +} + +pub fn get_maj_row(round_idx: i32) -> usize { + assert!(round_idx >= 0); + get_upper_sigma_0_row(round_idx) + SIGMA_0_ROWS +} + +// Get state word rows +pub fn get_h_row(round_idx: i32) -> usize { + if round_idx == -1 { + get_decompose_g_row(round_idx) + DECOMPOSE_EFGH + } else { + get_ch_row(round_idx) - 1 + } +} + +pub fn get_h_prime_row(round_idx: i32) -> usize { + assert!(round_idx >= 0); + get_ch_row(round_idx) +} + +pub fn get_d_row(round_idx: i32) -> usize { + if round_idx == -1 { + get_decompose_c_row(round_idx) + DECOMPOSE_ABCD + } else { + get_ch_row(round_idx) + 2 + } +} + +pub fn get_e_new_row(round_idx: i32) -> usize { + assert!(round_idx >= 0); + get_d_row(round_idx) +} + +pub fn get_a_new_row(round_idx: i32) -> usize { + get_maj_row(round_idx) +} + +pub fn get_digest_abcd_row() -> usize { + SUBREGION_MAIN_ROWS +} + +pub fn get_digest_efgh_row() -> usize { + get_digest_abcd_row() + 2 +} + +impl Compression { + pub(super) fn decompose_abcd( + &self, + region: &mut Region<'_, Table16Chip>, + row: usize, + a_val: u32, + ) -> Result< + ( + SpreadVar, + SpreadVar, + SpreadVar, + SpreadVar, + SpreadVar, + SpreadVar, + ), + Error, + > { + region.assign_fixed( + || "s_decompose_abcd", + self.s_decompose_abcd, + row, + || Ok(F::one()), + )?; + + let a_3 = self.extras[0]; + let a_4 = self.extras[1]; + 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::>(); + + 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])?; + let c_lo = SpreadVar::without_lookup(region, a_3, row, a_4, row, a_spread_pieces[2])?; + let c_mid = SpreadVar::without_lookup(region, a_5, row, a_6, row, a_spread_pieces[3])?; + let c_hi = + SpreadVar::without_lookup(region, a_5, row + 1, a_6, row + 1, a_spread_pieces[4])?; + let d = SpreadVar::with_lookup(region, &self.lookup, row + 1, a_spread_pieces[5])?; + + Ok((a, b, c_lo, c_mid, c_hi, d)) + } + + pub(super) fn decompose_efgh( + &self, + region: &mut Region<'_, Table16Chip>, + row: usize, + val: u32, + ) -> Result< + ( + SpreadVar, + SpreadVar, + SpreadVar, + SpreadVar, + SpreadVar, + SpreadVar, + ), + Error, + > { + region.assign_fixed( + || "s_decompose_efgh", + self.s_decompose_efgh, + row, + || Ok(F::one()), + )?; + + let a_3 = self.extras[0]; + let a_4 = self.extras[1]; + 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::>(); + + 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])?; + let b_lo = SpreadVar::without_lookup(region, a_3, row, a_4, row, spread_pieces[2])?; + let b_hi = SpreadVar::without_lookup(region, a_5, row, a_6, row, spread_pieces[3])?; + let c = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_pieces[4])?; + let d = SpreadVar::with_lookup(region, &self.lookup, row, spread_pieces[5])?; + + Ok((a_lo, a_hi, b_lo, b_hi, c, d)) + } + + pub(super) fn decompose_a( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + a_val: u32, + ) -> Result { + let row = get_decompose_a_row(idx); + + let (dense_halves, spread_halves) = self.assign_word_halves(region, row, a_val)?; + let (a, b, c_lo, c_mid, c_hi, d) = self.decompose_abcd(region, row, a_val)?; + let a_pieces = AbcdVar { + idx, + val: a_val, + a, + b, + c_lo, + c_mid, + c_hi, + d, + }; + Ok(RoundWordA::new(a_pieces, dense_halves, spread_halves)) + } + + pub(super) fn decompose_e( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + e_val: u32, + ) -> Result { + let row = get_decompose_e_row(idx); + + let (dense_halves, spread_halves) = self.assign_word_halves(region, row, e_val)?; + let (a_lo, a_hi, b_lo, b_hi, c, d) = self.decompose_efgh(region, row, e_val)?; + let e_pieces = EfghVar { + idx, + val: e_val, + a_lo, + a_hi, + b_lo, + b_hi, + c, + d, + }; + Ok(RoundWordE::new(e_pieces, dense_halves, spread_halves)) + } + + pub(super) fn assign_upper_sigma_0( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + word: AbcdVar, + ) -> Result<(CellValue16, CellValue16), Error> { + // Rename these here for ease of matching the gates to the specification. + let a_3 = self.extras[0]; + let a_4 = self.extras[1]; + let a_5 = self.message_schedule; + + let row = get_upper_sigma_0_row(idx); + + region.assign_fixed( + || "s_upper_sigma_0", + self.s_upper_sigma_0, + row, + || Ok(F::one()), + )?; + + // Assign `spread_a` and copy constraint + self.assign_and_constrain( + region, + || "spread_a", + a_3, + row + 1, + &word.a.spread, + &self.perm, + )?; + // Assign `spread_b` and copy constraint + self.assign_and_constrain(region, || "spread_b", a_5, row, &word.b.spread, &self.perm)?; + // Assign `spread_c_lo` and copy constraint + self.assign_and_constrain( + region, + || "spread_c_lo", + a_3, + row - 1, + &word.c_lo.spread, + &self.perm, + )?; + // Assign `spread_c_mid` and copy constraint + self.assign_and_constrain( + region, + || "spread_c_mid", + a_4, + row - 1, + &word.c_mid.spread, + &self.perm, + )?; + // Assign `spread_c_hi` and copy constraint + self.assign_and_constrain( + region, + || "spread_c_hi", + a_4, + row + 1, + &word.c_hi.spread, + &self.perm, + )?; + // Assign `spread_d` and copy constraint + self.assign_and_constrain(region, || "spread_d", a_4, row, &word.d.spread, &self.perm)?; + + // 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 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); + + self.assign_sigma_outputs( + region, + &self.lookup, + a_3, + &self.perm, + row, + r_0_even, + r_0_odd, + r_1_even, + r_1_odd, + ) + } + + pub(super) fn assign_upper_sigma_1( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + word: EfghVar, + ) -> Result<(CellValue16, CellValue16), Error> { + // Rename these here for ease of matching the gates to the specification. + let a_3 = self.extras[0]; + let a_4 = self.extras[1]; + let a_5 = self.message_schedule; + + let row = get_upper_sigma_1_row(idx); + + region.assign_fixed( + || "s_upper_sigma_1", + self.s_upper_sigma_1, + row, + || Ok(F::one()), + )?; + + // Assign `spread_a_lo` and copy constraint + self.assign_and_constrain( + region, + || "spread_a_lo", + a_3, + row + 1, + &word.a_lo.spread, + &self.perm, + )?; + // Assign `spread_a_hi` and copy constraint + self.assign_and_constrain( + region, + || "spread_a_hi", + a_4, + row + 1, + &word.a_hi.spread, + &self.perm, + )?; + // Assign `spread_b_lo` and copy constraint + self.assign_and_constrain( + region, + || "spread_b_lo", + a_3, + row - 1, + &word.b_lo.spread, + &self.perm, + )?; + // Assign `spread_b_hi` and copy constraint + self.assign_and_constrain( + region, + || "spread_b_hi", + a_4, + row - 1, + &word.b_hi.spread, + &self.perm, + )?; + // Assign `spread_c` and copy constraint + self.assign_and_constrain(region, || "spread_c", a_5, row, &word.c.spread, &self.perm)?; + // Assign `spread_d` and copy constraint + self.assign_and_constrain(region, || "spread_d", a_4, row, &word.d.spread, &self.perm)?; + + // 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 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); + + self.assign_sigma_outputs( + region, + &self.lookup, + a_3, + &self.perm, + row, + r_0_even, + r_0_odd, + r_1_even, + r_1_odd, + ) + } + + fn assign_ch_outputs( + &self, + region: &mut Region<'_, Table16Chip>, + row: usize, + r_0_even: u16, + r_0_odd: u16, + r_1_even: u16, + r_1_odd: u16, + ) -> Result<(CellValue16, CellValue16), Error> { + let a_3 = self.extras[0]; + + let (_even, odd) = self.assign_spread_outputs( + region, + &self.lookup, + a_3, + &self.perm, + row, + r_0_even, + r_0_odd, + r_1_even, + r_1_odd, + )?; + + Ok(odd) + } + + pub(super) fn assign_ch( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + spread_halves_e: (CellValue32, CellValue32), + spread_halves_f: (CellValue32, CellValue32), + ) -> Result<(CellValue16, CellValue16), Error> { + let a_3 = self.extras[0]; + let a_4 = self.extras[1]; + + let row = get_ch_row(idx); + + 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.perm, + )?; + self.assign_and_constrain( + region, + || "spread_e_hi", + a_4, + row - 1, + &spread_halves_e.1, + &self.perm, + )?; + + // 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.perm, + )?; + self.assign_and_constrain( + region, + || "spread_f_hi", + a_4, + row + 1, + &spread_halves_f.1, + &self.perm, + )?; + + 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); + + self.assign_ch_outputs(region, row, p0_even, p0_odd, p1_even, p1_odd) + } + + pub(super) fn assign_ch_neg( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + spread_halves_e: (CellValue32, CellValue32), + spread_halves_g: (CellValue32, CellValue32), + ) -> Result<(CellValue16, CellValue16), Error> { + let row = get_ch_neg_row(idx); + + region.assign_fixed(|| "s_ch_neg", self.s_ch_neg, row, || Ok(F::one()))?; + + let a_3 = self.extras[0]; + let a_4 = self.extras[1]; + 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.perm, + )?; + self.assign_and_constrain( + region, + || "spread_e_hi", + a_5, + row, + &spread_halves_e.1, + &self.perm, + )?; + + // 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.perm, + )?; + self.assign_and_constrain( + region, + || "spread_g_hi", + a_4, + row + 1, + &spread_halves_g.1, + &self.perm, + )?; + + // 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; + + // 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)), + )?; + region.assign_advice( + || "spread_neg_e_hi", + a_4, + row - 1, + || Ok(F::from_u64(spread_neg_e_hi)), + )?; + + 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) = 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); + + self.assign_ch_outputs(region, row, p0_even, p0_odd, p1_even, p1_odd) + } + + fn assign_maj_outputs( + &self, + region: &mut Region<'_, Table16Chip>, + row: usize, + r_0_even: u16, + r_0_odd: u16, + r_1_even: u16, + r_1_odd: u16, + ) -> Result<(CellValue16, CellValue16), Error> { + let a_3 = self.extras[0]; + let (_even, odd) = self.assign_spread_outputs( + region, + &self.lookup, + a_3, + &self.perm, + row, + r_0_even, + r_0_odd, + r_1_even, + r_1_odd, + )?; + + Ok(odd) + } + + pub(super) fn assign_maj( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + spread_halves_a: (CellValue32, CellValue32), + spread_halves_b: (CellValue32, CellValue32), + spread_halves_c: (CellValue32, CellValue32), + ) -> Result<(CellValue16, CellValue16), Error> { + let a_4 = self.extras[1]; + let a_5 = self.message_schedule; + + let row = get_maj_row(idx); + + 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.perm, + )?; + self.assign_and_constrain( + region, + || "spread_a_hi", + a_5, + row - 1, + &spread_halves_a.1, + &self.perm, + )?; + + // 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.perm, + )?; + self.assign_and_constrain( + region, + || "spread_b_hi", + a_5, + row, + &spread_halves_b.1, + &self.perm, + )?; + + // 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.perm, + )?; + self.assign_and_constrain( + region, + || "spread_c_hi", + a_5, + row + 1, + &spread_halves_c.1, + &self.perm, + )?; + + 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); + + self.assign_maj_outputs(region, row, m0_even, m0_odd, m1_even, m1_odd) + } + + // s_h_prime to get H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W + pub(super) fn assign_h_prime( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + h: (CellValue16, CellValue16), + ch: (CellValue16, CellValue16), + ch_neg: (CellValue16, CellValue16), + sigma_1: (CellValue16, CellValue16), + k: u32, + w: (CellValue16, CellValue16), + ) -> Result<(CellValue16, CellValue16), Error> { + let row = get_h_prime_row(idx); + region.assign_fixed(|| "s_h_prime", self.s_h_prime, row, || Ok(F::one()))?; + + let a_4 = self.extras[1]; + let a_5 = self.message_schedule; + let a_6 = self.extras[2]; + let a_7 = self.extras[3]; + let a_8 = self.extras[4]; + 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.perm)?; + self.assign_and_constrain(region, || "h_hi", a_7, row, &h.1.into(), &self.perm)?; + + // Assign and copy sigma_1 + self.assign_and_constrain( + region, + || "sigma_1_lo", + a_4, + row, + &sigma_1.0.into(), + &self.perm, + )?; + self.assign_and_constrain( + region, + || "sigma_1_hi", + a_5, + row, + &sigma_1.1.into(), + &self.perm, + )?; + + // Assign k + let k_pieces = chop_u32(k, &[16, 16]); + region.assign_advice( + || "k_lo", + a_6, + row - 1, + || Ok(F::from_u64(k_pieces[0] as u64)), + )?; + 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.perm)?; + self.assign_and_constrain(region, || "w_hi", a_8, row, &w.1.into(), &self.perm)?; + + // Assign and copy ch + self.assign_and_constrain( + region, + || "ch_neg_hi", + a_6, + row + 1, + &ch.1.into(), + &self.perm, + )?; + + // Assign and copy ch_neg + self.assign_and_constrain( + region, + || "ch_neg_lo", + a_5, + row - 1, + &ch_neg.0.into(), + &self.perm, + )?; + self.assign_and_constrain( + region, + || "ch_neg_hi", + a_5, + row + 1, + &ch_neg.1.into(), + &self.perm, + )?; + + // 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; + + 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 = 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)), + )?; + + Ok(( + CellValue16::new(h_prime_lo, h_prime_halves[0] as u16), + CellValue16::new(h_prime_hi, h_prime_halves[1] as u16), + )) + } + + // s_e_new to get E_new = H' + D + pub(super) fn assign_e_new( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + d: (CellValue16, CellValue16), + h_prime: (CellValue16, CellValue16), + ) -> Result<(CellValue16, CellValue16), Error> { + let row = get_e_new_row(idx); + + region.assign_fixed(|| "s_e_new", self.s_e_new, row, || Ok(F::one()))?; + + let a_7 = self.extras[3]; + let a_8 = self.extras[4]; + 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.perm)?; + self.assign_and_constrain(region, || "d_hi", a_7, row + 1, &d.1.into(), &self.perm)?; + + // 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_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)), + )?; + + Ok(e_new_dense) + } + + // s_a_new to get A_new = H' + Maj(A, B, C) + s_upper_sigma_0(A) + pub(super) fn assign_a_new( + &self, + region: &mut Region<'_, Table16Chip>, + idx: i32, + maj: (CellValue16, CellValue16), + sigma_0: (CellValue16, CellValue16), + h_prime: (CellValue16, CellValue16), + ) -> Result<(CellValue16, CellValue16), Error> { + let row = get_a_new_row(idx); + + region.assign_fixed(|| "s_a_new", self.s_a_new, row, || Ok(F::one()))?; + + let a_3 = self.extras[0]; + let a_6 = self.extras[2]; + let a_7 = self.extras[3]; + let a_8 = self.extras[4]; + 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.perm, + )?; + + // Assign and copy sigma_0 + self.assign_and_constrain( + region, + || "sigma_0_lo", + a_6, + row, + &sigma_0.0.into(), + &self.perm, + )?; + self.assign_and_constrain( + region, + || "sigma_0_hi", + a_6, + row + 1, + &sigma_0.1.into(), + &self.perm, + )?; + + // Assign and copy h_prime + self.assign_and_constrain( + region, + || "h_prime_lo", + a_7, + row - 1, + &h_prime.0.into(), + &self.perm, + )?; + self.assign_and_constrain( + region, + || "h_prime_hi", + a_8, + row - 1, + &h_prime.1.into(), + &self.perm, + )?; + + // 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_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)), + )?; + + Ok(a_new_dense) + } + + pub fn assign_word_halves_dense( + &self, + region: &mut Region<'_, Table16Chip>, + lo_row: usize, + lo_col: Column, + hi_row: usize, + hi_col: Column, + word: 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); + + Ok((w_lo_cell, w_hi_cell)) + } + + // Assign hi and lo halves for both dense and spread versions of a word + pub fn assign_word_halves( + &self, + region: &mut Region<'_, Table16Chip>, + row: usize, + word: 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 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()); + + 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 match_state( + state: State, +) -> ( + RoundWordA, + RoundWordSpread, + RoundWordSpread, + RoundWordDense, + RoundWordE, + RoundWordSpread, + RoundWordSpread, + RoundWordDense, +) { + let a = match state.a { + Some(StateWord::A(a)) => a, + _ => unreachable!(), + }; + let b = match state.b { + Some(StateWord::B(b)) => b, + _ => unreachable!(), + }; + let c = match state.c { + Some(StateWord::C(c)) => c, + _ => unreachable!(), + }; + let d = match state.d { + Some(StateWord::D(d)) => d, + _ => unreachable!(), + }; + let e = match state.e { + Some(StateWord::E(e)) => e, + _ => unreachable!(), + }; + let f = match state.f { + Some(StateWord::F(f)) => f, + _ => unreachable!(), + }; + let g = match state.g { + Some(StateWord::G(g)) => g, + _ => unreachable!(), + }; + let h = match state.h { + Some(StateWord::H(h)) => h, + _ => unreachable!(), + }; + + (a, b, c, d, e, f, g, h) +}