From b2406d7bdcfbbfd6ff55ae29f5c23cffa9d0db1c Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 10 Jan 2024 23:17:47 -0500 Subject: [PATCH 001/165] reconsolidate messy code on working branch --- zkevm-circuits/src/witness/zstd/mod.rs | 136 +++++++++++++++++++++- zkevm-circuits/src/witness/zstd/params.rs | 3 + zkevm-circuits/src/witness/zstd/types.rs | 5 + zkevm-circuits/src/witness/zstd/util.rs | 10 ++ 4 files changed, 150 insertions(+), 4 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 6031b07abf..ec402c54c8 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1,3 +1,4 @@ +use bus_mapping::circuit_input_builder::Block; use eth_types::Field; use halo2_proofs::circuit::Value; @@ -5,6 +6,7 @@ mod params; pub use params::*; mod types; +use serde::de::value; pub use types::*; #[cfg(test)] @@ -13,7 +15,7 @@ mod tui; use tui::draw_rows; mod util; -use util::value_bits_le; +use util::{value_bits_le, le_bits_to_value}; /// MagicNumber fn process_magic_number( @@ -513,11 +515,137 @@ fn process_block_zstd( block_size: usize, last_block: bool, ) -> (usize, Vec>) { - unimplemented!(); + let mut witness_rows = vec![]; + + // 1-5 bytes LiteralSectionHeader + let ( + byte_offset, + rows, + literals_block_type, + n_streams, + regen_size, + compressed_size + ) = process_block_zstd_literals_header::( + src, + byte_offset, + last_row, + randomness + ); + witness_rows.extend_from_slice(&rows); + + + + + + + // compression_debug + (0usize, vec![]) } -fn process_block_zstd_literals_header() -> (usize, Vec>) { - unimplemented!(); +fn process_block_zstd_literals_header( + src: &[u8], + byte_offset: usize, + last_row: &ZstdWitnessRow, + randomness: Value, +) -> (usize, Vec>, BlockType, usize, usize, usize) { + let lh_bytes = src + .iter() + .skip(byte_offset) + .take(N_MAX_LITERAL_HEADER_BYTES) + .cloned() + .collect::>(); + + let literals_block_type = BlockType::from(lh_bytes[0] & 0x3); + let size_format = lh_bytes[0] & 3; + + let [n_bits_fmt, n_bits_regen, n_bits_compressed, n_streams, n_bytes_header]: [usize; 5] = match literals_block_type { + BlockType::RawBlock | BlockType::RleBlock => { + match size_format { + 0b00 | 0b10 => [1, 5, 0, 1, 1], + 0b01 => [2, 12, 0, 1, 2], + 0b11 => [2, 20, 0, 1, 3], + _ => unreachable!("size_format out of bound") + } + }, + BlockType::ZstdCompressedBlock => { + match size_format { + 0b00 => [2, 10, 10, 1, 3], + 0b01 => [2, 10, 10, 4, 3], + 0b10 => [2, 14, 14, 4, 4], + 0b11 => [2, 18, 18, 4, 5], + _ => unreachable!("size_format out of bound") + } + }, + _ => unreachable!("BlockType::Reserved unexpected or treeless literal section") + }; + + // Bits for representing regenerated_size and compressed_size + let sizing_bits = &lh_bytes.clone().into_iter().fold(vec![], |mut acc, b| { + acc.extend(value_bits_le(b)); + acc + })[(2 + n_bits_fmt)..(n_bytes_header * N_BITS_PER_BYTE)]; + + let regen_size = le_bits_to_value(&sizing_bits[0..n_bits_regen]); + let compressed_size = le_bits_to_value(&sizing_bits[n_bits_regen..(n_bits_regen + n_bits_compressed)]); + + let tag_next = match literals_block_type { + BlockType::RawBlock => ZstdTag::ZstdBlockLiteralsRawBytes, + BlockType::RleBlock => ZstdTag::ZstdBlockLiteralsRleBytes, + BlockType::ZstdCompressedBlock => ZstdTag::ZstdBlockHuffmanHeader, + _ => unreachable!("BlockType::Reserved unexpected or treeless literal section"), + }; + + let tag_value_iter = lh_bytes[0..n_bytes_header].iter().scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); + let tag_value = tag_value_iter.clone().last().expect("LiteralsHeader expected"); + + let value_rlc_iter = lh_bytes[0..n_bytes_header] + .iter() + .scan(last_row.encoded_data.value_rlc, |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); + + ( + byte_offset + n_bytes_header, + lh_bytes[0..n_bytes_header] + .iter() + .zip(tag_value_iter) + .zip(value_rlc_iter) + .enumerate() + .map( + |(i, ((&value_byte, tag_value_acc), value_rlc))| ZstdWitnessRow { + instance_idx: last_row.instance_idx, + frame_idx: last_row.frame_idx, + state: ZstdState { + tag: ZstdTag::ZstdBlockLiteralsHeader, + tag_next, + tag_len: n_bytes_header as u64, + tag_idx: (i + 1) as u64, + tag_value, + tag_value_acc, + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + i + 1) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte, + reverse: false, + value_rlc, + ..Default::default() + }, + decoded_data: last_row.decoded_data.clone(), + huffman_data: HuffmanData::default(), + fse_data: FseData::default(), + }, + ) + .collect::>(), + literals_block_type, + n_streams, + regen_size as usize, + compressed_size as usize, + ) } fn process_block_zstd_huffman_header() -> (usize, Vec>) { diff --git a/zkevm-circuits/src/witness/zstd/params.rs b/zkevm-circuits/src/witness/zstd/params.rs index 68d77854c5..65f1231423 100644 --- a/zkevm-circuits/src/witness/zstd/params.rs +++ b/zkevm-circuits/src/witness/zstd/params.rs @@ -4,6 +4,9 @@ pub const N_BLOCK_HEADER_BYTES: usize = 3; pub const N_MAGIC_NUMBER_BYTES: usize = 4; +// Constants for zstd-compressed block +pub const N_MAX_LITERAL_HEADER_BYTES: usize = 3; + /// Maximum number of symbols (weights), i.e. symbol in [0, N_MAX_SYMBOLS). pub const N_MAX_SYMBOLS: usize = 8; diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 279f3ea53a..cde54244b1 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -52,6 +52,7 @@ impl From for FseSymbol { } } +#[derive(Debug)] pub enum BlockType { RawBlock = 0, RleBlock, @@ -81,6 +82,8 @@ pub enum ZstdTag { RawBlockBytes, RleBlockBytes, ZstdBlockLiteralsHeader, + ZstdBlockLiteralsRawBytes, + ZstdBlockLiteralsRleBytes, ZstdBlockHuffmanHeader, ZstdBlockHuffmanCode, ZstdBlockJumpTable, @@ -101,6 +104,8 @@ impl ToString for ZstdTag { Self::RawBlockBytes => "RawBlockBytes", Self::RleBlockBytes => "RleBlockBytes", Self::ZstdBlockLiteralsHeader => "ZstdBlockLiteralsHeader", + Self::ZstdBlockLiteralsRawBytes => "ZstdBlockLiteralsRawBytes", + Self::ZstdBlockLiteralsRleBytes => "ZstdBlockLiteralsRleBytes", Self::ZstdBlockHuffmanHeader => "ZstdBlockHuffmanHeader", Self::ZstdBlockHuffmanCode => "ZstdBlockHuffmanCode", Self::ZstdBlockJumpTable => "ZstdBlockJumpTable", diff --git a/zkevm-circuits/src/witness/zstd/util.rs b/zkevm-circuits/src/witness/zstd/util.rs index 280280f3d7..59e88cd82a 100644 --- a/zkevm-circuits/src/witness/zstd/util.rs +++ b/zkevm-circuits/src/witness/zstd/util.rs @@ -7,3 +7,13 @@ pub fn value_bits_le(value_byte: u8) -> [u8; N_BITS_PER_BYTE] { .try_into() .expect("expected N_BITS_PER_BYTE elements") } + +// compression_debug +pub fn le_bits_to_value(bits: &[u8]) -> u64 { + assert!(bits.len() <= 64); + + bits.into_iter().enumerate().fold(0, |mut acc, (p, b)| { + acc += (2u64).pow(p as u32) * (*b as u64); + acc + }) +} From 3a60cc8554632f55ba975a631f53d496f5504576 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 11 Jan 2024 02:43:48 -0500 Subject: [PATCH 002/165] correct huffman header processing --- zkevm-circuits/src/witness/zstd/mod.rs | 303 +++++++++++++++++++---- zkevm-circuits/src/witness/zstd/types.rs | 2 + 2 files changed, 262 insertions(+), 43 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index ec402c54c8..23d1330789 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -3,6 +3,7 @@ use eth_types::Field; use halo2_proofs::circuit::Value; mod params; +use num::Integer; pub use params::*; mod types; @@ -358,29 +359,30 @@ fn process_block_header( ) } -fn process_block_raw( +fn process_raw_bytes( src: &[u8], byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, - block_size: usize, - last_block: bool, + n_bytes: usize, + tag: ZstdTag, + tag_next: ZstdTag, ) -> (usize, Vec>) { - let value_rlc_iter = src.iter().skip(byte_offset).take(block_size).scan( + let value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( last_row.encoded_data.value_rlc, |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }, ); - let decoded_value_rlc_iter = src.iter().skip(byte_offset).take(block_size).scan( + let decoded_value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( last_row.decoded_data.decoded_value_rlc, |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }, ); - let tag_value_iter = src.iter().skip(byte_offset).take(block_size).scan( + let tag_value_iter = src.iter().skip(byte_offset).take(n_bytes).scan( Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); @@ -391,17 +393,12 @@ fn process_block_raw( .clone() .last() .expect("Raw bytes must be of non-zero length"); - let tag_next = if last_block { - ZstdTag::Null - } else { - ZstdTag::BlockHeader - }; ( - byte_offset + block_size, + byte_offset + n_bytes, src.iter() .skip(byte_offset) - .take(block_size) + .take(n_bytes) .zip(tag_value_iter) .zip(value_rlc_iter) .zip(decoded_value_rlc_iter) @@ -412,9 +409,9 @@ fn process_block_raw( instance_idx: last_row.instance_idx, frame_idx: last_row.frame_idx, state: ZstdState { - tag: ZstdTag::RawBlockBytes, + tag, tag_next, - tag_len: block_size as u64, + tag_len: n_bytes as u64, tag_idx: (i + 1) as u64, tag_value, tag_value_acc, @@ -443,18 +440,19 @@ fn process_block_raw( ) } -fn process_block_rle( +fn process_rle_bytes( src: &[u8], byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, - block_size: usize, - last_block: bool, + n_bytes: usize, + tag: ZstdTag, + tag_next: ZstdTag, ) -> (usize, Vec>) { let rle_byte = src[byte_offset]; let value_rlc = last_row.encoded_data.value_rlc * randomness + Value::known(F::from(rle_byte as u64)); - let decoded_value_rlc_iter = std::iter::repeat(rle_byte).take(block_size).scan( + let decoded_value_rlc_iter = std::iter::repeat(rle_byte).take(n_bytes).scan( last_row.decoded_data.decoded_value_rlc, |acc, byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); @@ -462,25 +460,20 @@ fn process_block_rle( }, ); let tag_value = Value::known(F::from(rle_byte as u64)); - let tag_next = if last_block { - ZstdTag::Null - } else { - ZstdTag::BlockHeader - }; ( byte_offset + 1, std::iter::repeat(rle_byte) - .take(block_size) + .take(n_bytes) .zip(decoded_value_rlc_iter) .enumerate() .map(|(i, (value_byte, decoded_value_rlc))| ZstdWitnessRow { instance_idx: last_row.instance_idx, frame_idx: last_row.frame_idx, state: ZstdState { - tag: ZstdTag::RleBlockBytes, + tag, tag_next, - tag_len: block_size as u64, + tag_len: n_bytes as u64, tag_idx: (i + 1) as u64, tag_value, tag_value_acc: tag_value, @@ -507,6 +500,56 @@ fn process_block_rle( ) } +fn process_block_raw( + src: &[u8], + byte_offset: usize, + last_row: &ZstdWitnessRow, + randomness: Value, + block_size: usize, + last_block: bool, +) -> (usize, Vec>) { + let tag_next = if last_block { + ZstdTag::Null + } else { + ZstdTag::BlockHeader + }; + + process_raw_bytes( + src, + byte_offset, + last_row, + randomness, + block_size, + ZstdTag::RawBlockBytes, + tag_next, + ) +} + +fn process_block_rle( + src: &[u8], + byte_offset: usize, + last_row: &ZstdWitnessRow, + randomness: Value, + block_size: usize, + last_block: bool, +) -> (usize, Vec>) { + let tag_next = if last_block { + ZstdTag::Null + } else { + ZstdTag::BlockHeader + }; + + process_rle_bytes( + src, + byte_offset, + last_row, + randomness, + block_size, + ZstdTag::RleBlockBytes, + tag_next, + ) +} + fn process_block_zstd( src: &[u8], byte_offset: usize, @@ -533,13 +576,89 @@ fn process_block_zstd( ); witness_rows.extend_from_slice(&rows); + // Depending on the literals block type, decode literals section accordingly + let (bytes_offset, rows) = match literals_block_type { + BlockType::RawBlock => { + process_raw_bytes( + src, + byte_offset, + rows.last().expect("last row expected to exist"), + randomness, + regen_size, + ZstdTag::ZstdBlockLiteralsRawBytes, + ZstdTag::ZstdBlockSequenceHeader, + ) + }, + BlockType::RleBlock => { + process_rle_bytes( + src, + byte_offset, + rows.last().expect("last row expected to exist"), + randomness, + regen_size, + ZstdTag::ZstdBlockLiteralsRleBytes, + ZstdTag::ZstdBlockSequenceHeader, + ) + }, + BlockType::ZstdCompressedBlock => { + let mut huffman_rows = vec![]; + + let (bytes_offset, rows, is_direct, n_bytes) = process_block_zstd_huffman_header( + src, + byte_offset, + rows.last().expect("last row expected to exist"), + randomness, + ); + huffman_rows.extend_from_slice(&rows); + + let (bytes_offset, rows) = if is_direct { + process_block_zstd_huffman_code_direct( + src, + byte_offset, + &huffman_rows[0], + randomness, + n_bytes, + ) + } else { + process_block_zstd_huffman_code_fse( + src, + byte_offset, + &huffman_rows[0], + randomness, + n_bytes, + ) + }; + huffman_rows.extend_from_slice(&rows); + + let mut stream_offset = byte_offset; + for idx in 0..n_streams { + let (byte_offset, rows) = process_block_zstd_huffman_jump_table( + src, + stream_offset, + huffman_rows.last().expect("last row should exist"), + randomness + ); + huffman_rows.extend_from_slice(&rows); + + let (byte_offset, rows) = process_block_zstd_lstream( + src, + stream_offset, + huffman_rows.last().expect("last row should exist"), + randomness, + idx + 1 == n_streams + ); + huffman_rows.extend_from_slice(&rows); + + stream_offset = byte_offset; + } + (stream_offset, huffman_rows) + }, + _ => unreachable!("Invalid literals section BlockType") + }; + witness_rows.extend_from_slice(&rows); - - - - // compression_debug - (0usize, vec![]) + (bytes_offset, witness_rows) } fn process_block_zstd_literals_header( @@ -557,7 +676,7 @@ fn process_block_zstd_literals_header( let literals_block_type = BlockType::from(lh_bytes[0] & 0x3); let size_format = lh_bytes[0] & 3; - + let [n_bits_fmt, n_bits_regen, n_bits_compressed, n_streams, n_bytes_header]: [usize; 5] = match literals_block_type { BlockType::RawBlock | BlockType::RleBlock => { match size_format { @@ -595,14 +714,15 @@ fn process_block_zstd_literals_header( _ => unreachable!("BlockType::Reserved unexpected or treeless literal section"), }; - let tag_value_iter = lh_bytes[0..n_bytes_header].iter().scan(Value::known(F::zero()), |acc, &byte| { + let tag_value_iter = lh_bytes.iter().take(n_bytes_header).scan(Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }); let tag_value = tag_value_iter.clone().last().expect("LiteralsHeader expected"); - let value_rlc_iter = lh_bytes[0..n_bytes_header] + let value_rlc_iter = lh_bytes .iter() + .take(n_bytes_header) .scan(last_row.encoded_data.value_rlc, |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) @@ -610,8 +730,9 @@ fn process_block_zstd_literals_header( ( byte_offset + n_bytes_header, - lh_bytes[0..n_bytes_header] + lh_bytes .iter() + .take(n_bytes_header) .zip(tag_value_iter) .zip(value_rlc_iter) .enumerate() @@ -648,20 +769,116 @@ fn process_block_zstd_literals_header( ) } -fn process_block_zstd_huffman_header() -> (usize, Vec>) { - unimplemented!(); +fn process_block_zstd_huffman_header( + src: &[u8], + byte_offset: usize, + last_row: &ZstdWitnessRow, + randomness: Value, +) -> (usize, Vec>, bool, usize) { + let header_byte = src[byte_offset]; + + let value_rlc = + last_row.encoded_data.value_rlc * randomness + Value::known(F::from(header_byte as u64)); + let decoded_value_rlc = + last_row.decoded_data.decoded_value_rlc + randomness + Value::known(F::from(header_byte as u64)); + let tag_value = Value::known(F::from(header_byte as u64)); + + let n_bytes = if header_byte < 128 { + header_byte + } else { + let n_sym = header_byte - 127; + if n_sym.is_odd() { + (n_sym + 1) / 2 + } else { + n_sym / 2 + } + }; + + ( + byte_offset + 1, + vec![ZstdWitnessRow { + instance_idx: last_row.instance_idx, + frame_idx: last_row.frame_idx, + state: ZstdState { + tag: ZstdTag::ZstdBlockHuffmanHeader, + tag_next: ZstdTag::ZstdBlockHuffmanCode, + tag_len: 1 as u64, + tag_idx: 1 as u64, + tag_value, + tag_value_acc: tag_value, + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + 1) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: header_byte, + reverse: false, + value_rlc, + ..Default::default() + }, + decoded_data: DecodedData { + decoded_len: last_row.decoded_data.decoded_len, + decoded_len_acc: last_row.decoded_data.decoded_len_acc + (i as u64) + 1, + total_decoded_len: last_row.decoded_data.total_decoded_len, + decoded_byte: header_byte, + decoded_value_rlc, + }, + huffman_data: HuffmanData::default(), + fse_data: FseData::default(), + }], + header_byte >= 127, + n_bytes, + ) } -fn process_block_zstd_huffman_code() -> (usize, Vec>) { +fn process_block_zstd_huffman_code_direct( + src: &[u8], + byte_offset: usize, + last_row: &ZstdWitnessRow, + randomness: Value, + n_bytes: usize, +) -> (usize, Vec>) { + // compression_debug + // For direct representation of huffman weights, each byte (8 bits) represents two weights. + // weight[0] = (Byte[0] >> 4) + // weight[1] = (Byte[0] & 0xf). + + +} +fn process_block_zstd_huffman_code_fse( + src: &[u8], + byte_offset: usize, + last_row: &ZstdWitnessRow, + randomness: Value, + n_bytes: usize, +) -> (usize, Vec>) { unimplemented!(); } -fn process_block_zstd_huffman_jump_table() -> (usize, Vec>) { - unimplemented!(); +fn process_block_zstd_huffman_jump_table( + src: &[u8], + byte_offset: usize, + last_row: &ZstdWitnessRow, + randomness: Value, +) -> (usize, Vec>) { + // compression_debug } +fn process_block_zstd_lstream( + src: &[u8], + byte_offset: usize, + last_row: &ZstdWitnessRow, + randomness: Value, + is_last_stream: bool, +) -> (usize, Vec>) { + // compression_debug + let tag_next = if is_last_stream { + ZstdTag::ZstdBlockSequenceHeader + } else { + ZstdTag::ZstdBlockJumpTable + }; + + + -fn process_block_zstd_lstream() -> (usize, Vec>) { - unimplemented!(); } pub fn process(src: &[u8], randomness: Value) -> Vec> { diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index cde54244b1..e56493a514 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -87,6 +87,7 @@ pub enum ZstdTag { ZstdBlockHuffmanHeader, ZstdBlockHuffmanCode, ZstdBlockJumpTable, + ZstdBlockSequenceHeader, Lstream1, Lstream2, Lstream3, @@ -109,6 +110,7 @@ impl ToString for ZstdTag { Self::ZstdBlockHuffmanHeader => "ZstdBlockHuffmanHeader", Self::ZstdBlockHuffmanCode => "ZstdBlockHuffmanCode", Self::ZstdBlockJumpTable => "ZstdBlockJumpTable", + Self::ZstdBlockSequenceHeader => "ZstdBlockSequenceHeader", Self::Lstream1 => "Lstream1", Self::Lstream2 => "Lstream2", Self::Lstream3 => "Lstream3", From 6377d8c51222492aec64c988b400a4d611fbe3a2 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 11 Jan 2024 03:56:34 -0500 Subject: [PATCH 003/165] correct jump table --- zkevm-circuits/src/witness/zstd/mod.rs | 121 ++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 13 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 23d1330789..67f07b6081 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -631,7 +631,8 @@ fn process_block_zstd( huffman_rows.extend_from_slice(&rows); let mut stream_offset = byte_offset; - for idx in 0..n_streams { + + if n_streams > 1 { let (byte_offset, rows) = process_block_zstd_huffman_jump_table( src, stream_offset, @@ -639,7 +640,9 @@ fn process_block_zstd( randomness ); huffman_rows.extend_from_slice(&rows); + } + for idx in 0..n_streams { let (byte_offset, rows) = process_block_zstd_lstream( src, stream_offset, @@ -651,7 +654,7 @@ fn process_block_zstd( stream_offset = byte_offset; } - + (stream_offset, huffman_rows) }, _ => unreachable!("Invalid literals section BlockType") @@ -826,7 +829,7 @@ fn process_block_zstd_huffman_header( fse_data: FseData::default(), }], header_byte >= 127, - n_bytes, + n_bytes as usize, ) } @@ -842,8 +845,102 @@ fn process_block_zstd_huffman_code_direct( // weight[0] = (Byte[0] >> 4) // weight[1] = (Byte[0] & 0xf). - + let value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + last_row.encoded_data.value_rlc, + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ) + .into_iter() + .flat_map(|v| vec![v, v]); + + let decoded_value_rlc_iter = src + .iter() + .skip(byte_offset) + .take(n_bytes) + .into_iter() + .flat_map(|v| vec![v, v]) + .zip((0..).cycle().take(n_bytes * 2)) + .scan( + last_row.decoded_data.decoded_value_rlc, + |acc, (&byte, b_flag)| { + let v = if b_flag > 0 { byte & 0xf } else { byte >> 4 }; + *acc = *acc * randomness + Value::known(F::from(v as u64)); + Some(*acc) + }, + ); + + let tag_value_iter = src + .iter() + .skip(byte_offset) + .take(n_bytes) + .into_iter() + .flat_map(|v| vec![v, v]) + .zip((0..).cycle().take(n_bytes * 2)) + .scan( + Value::known(F::zero()), + |acc, (&byte, b_flag)| { + let v = if b_flag > 0 { byte & 0xf } else { byte >> 4 }; + *acc = *acc * randomness + Value::known(F::from(v as u64)); + Some(*acc) + }, + ); + + let tag_value = tag_value_iter + .clone() + .last() + .expect("Raw bytes must be of non-zero length"); + + ( + byte_offset + n_bytes, + src.iter() + .skip(byte_offset) + .take(n_bytes) + .into_iter() + .flat_map(|v| vec![v, v]) + .zip(tag_value_iter) + .zip(value_rlc_iter) + .zip(decoded_value_rlc_iter) + .zip((0..).cycle().take(n_bytes * 2)) + .enumerate() + .map( + |(i, ((((&value_byte, tag_value_acc), value_rlc), decoded_value_rlc), b_flag))| { + ZstdWitnessRow { + instance_idx: last_row.instance_idx, + frame_idx: last_row.frame_idx, + state: ZstdState { + tag: ZstdTag::ZstdBlockHuffmanCode, + tag_next: ZstdTag::ZstdBlockSequenceHeader, + tag_len: (n_bytes * 2) as u64, + tag_idx: (i + 1) as u64, + tag_value, + tag_value_acc, + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + i / 2 + 1) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: if b_flag > 0 { value_byte >> 4 } else { value_byte & 0xf }, + value_rlc, + reverse: false, + ..Default::default() + }, + decoded_data: DecodedData { + decoded_len: last_row.decoded_data.decoded_len, + decoded_len_acc: last_row.decoded_data.decoded_len + (i as u64) + 1, + total_decoded_len: last_row.decoded_data.total_decoded_len, + decoded_byte: value_byte, + decoded_value_rlc, + }, + huffman_data: HuffmanData::default(), + fse_data: FseData::default(), + } + }, + ) + .collect::>(), + ) } + fn process_block_zstd_huffman_code_fse( src: &[u8], byte_offset: usize, @@ -861,6 +958,7 @@ fn process_block_zstd_huffman_jump_table( randomness: Value, ) -> (usize, Vec>) { // compression_debug + unimplemented!() } fn process_block_zstd_lstream( src: &[u8], @@ -870,15 +968,12 @@ fn process_block_zstd_lstream( is_last_stream: bool, ) -> (usize, Vec>) { // compression_debug - let tag_next = if is_last_stream { - ZstdTag::ZstdBlockSequenceHeader - } else { - ZstdTag::ZstdBlockJumpTable - }; - - - - + // let tag_next = if is_last_stream { + // ZstdTag::ZstdBlockSequenceHeader + // } else { + // ZstdTag::ZstdBlockJumpTable + // }; + unimplemented!() } pub fn process(src: &[u8], randomness: Value) -> Vec> { From cb31d73800cd7f5b947cd867a9fab7e3a8cd33ad Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 11 Jan 2024 04:27:37 -0500 Subject: [PATCH 004/165] huffman code direct representation --- zkevm-circuits/src/witness/zstd/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 67f07b6081..a74cc5c4c4 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -820,7 +820,7 @@ fn process_block_zstd_huffman_header( }, decoded_data: DecodedData { decoded_len: last_row.decoded_data.decoded_len, - decoded_len_acc: last_row.decoded_data.decoded_len_acc + (i as u64) + 1, + decoded_len_acc: last_row.decoded_data.decoded_len_acc + 1, total_decoded_len: last_row.decoded_data.total_decoded_len, decoded_byte: header_byte, decoded_value_rlc, @@ -957,7 +957,9 @@ fn process_block_zstd_huffman_jump_table( last_row: &ZstdWitnessRow, randomness: Value, ) -> (usize, Vec>) { - // compression_debug + // Note: The decompressed size of each stream is equal to (regen_size + 3) / 4 + // but the compressed bitstream length will be different. + // Jump table provides information on the length of first 3 bitstreams. unimplemented!() } fn process_block_zstd_lstream( From 77caadd0d553a8d6211571b6d05728a6f0d8dfd0 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 15 Jan 2024 19:51:17 -0500 Subject: [PATCH 005/165] reserve huffman header decoding --- zkevm-circuits/src/witness/zstd/mod.rs | 163 ++++++++++++------------- 1 file changed, 81 insertions(+), 82 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 1e75c7b9bf..99ee8e22a0 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -758,88 +758,30 @@ fn process_block_zstd_literals_header( ) } -// fn process_block_zstd_huffman_header( -// src: &[u8], -// byte_offset: usize, -// last_row: &ZstdWitnessRow, -// randomness: Value, -// ) -> (usize, Vec>, bool, usize) { -// let header_byte = src[byte_offset]; - -// let value_rlc = -// last_row.encoded_data.value_rlc * randomness + Value::known(F::from(header_byte as u64)); -// let decoded_value_rlc = -// last_row.decoded_data.decoded_value_rlc + randomness + Value::known(F::from(header_byte as u64)); -// let tag_value = Value::known(F::from(header_byte as u64)); - -// let n_bytes = if header_byte < 128 { -// header_byte -// } else { -// let n_sym = header_byte - 127; -// if n_sym.is_odd() { -// (n_sym + 1) / 2 -// } else { -// n_sym / 2 -// } -// }; - -// ( -// byte_offset + 1, -// vec![ZstdWitnessRow { -// instance_idx: last_row.instance_idx, -// frame_idx: last_row.frame_idx, -// state: ZstdState { -// tag: ZstdTag::ZstdBlockHuffmanHeader, -// tag_next: ZstdTag::ZstdBlockHuffmanCode, -// tag_len: 1 as u64, -// tag_idx: 1 as u64, -// tag_value, -// tag_value_acc: tag_value, -// }, -// encoded_data: EncodedData { -// byte_idx: (byte_offset + 1) as u64, -// encoded_len: last_row.encoded_data.encoded_len, -// value_byte: header_byte, -// reverse: false, -// value_rlc, -// ..Default::default() -// }, -// decoded_data: DecodedData { -// decoded_len: last_row.decoded_data.decoded_len, -// decoded_len_acc: last_row.decoded_data.decoded_len_acc + 1, -// total_decoded_len: last_row.decoded_data.total_decoded_len, -// decoded_byte: header_byte, -// decoded_value_rlc, -// }, -// huffman_data: HuffmanData::default(), -// fse_data: FseData::default(), -// }], -// header_byte >= 127, -// n_bytes as usize, -// ) -// } - fn process_block_zstd_huffman_header( src: &[u8], byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>) { - // A single byte (header_byte) is read. - // - if header_byte < 128: canonical weights are represented by FSE table. - // - if header_byte >= 128: canonical weights are given by direct representation. - - let header_byte = src - .get(byte_offset) - .expect("ZBHuffmanHeader byte should exist"); - - assert!( - *header_byte < 128, - "we expect canonical huffman weights to be encoded using FSE" - ); +) -> (usize, Vec>, bool, usize) { + let header_byte = src[byte_offset]; let value_rlc = - last_row.encoded_data.value_rlc * randomness + Value::known(F::from(*header_byte as u64)); + last_row.encoded_data.value_rlc * randomness + Value::known(F::from(header_byte as u64)); + let decoded_value_rlc = + last_row.decoded_data.decoded_value_rlc + randomness + Value::known(F::from(header_byte as u64)); + let tag_value = Value::known(F::from(header_byte as u64)); + + let n_bytes = if header_byte < 128 { + header_byte + } else { + let n_sym = header_byte - 127; + if n_sym.is_odd() { + (n_sym + 1) / 2 + } else { + n_sym / 2 + } + }; ( byte_offset + 1, @@ -847,25 +789,82 @@ fn process_block_zstd_huffman_header( state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanHeader, tag_next: ZstdTag::ZstdBlockFseCode, - tag_len: 1, - tag_idx: 1, - tag_value: Value::known(F::from(*header_byte as u64)), - tag_value_acc: Value::known(F::from(*header_byte as u64)), + tag_len: 1 as u64, + tag_idx: 1 as u64, + tag_value, + tag_value_acc: tag_value, }, encoded_data: EncodedData { byte_idx: (byte_offset + 1) as u64, encoded_len: last_row.encoded_data.encoded_len, - value_byte: *header_byte, + value_byte: header_byte, + reverse: false, value_rlc, ..Default::default() }, - decoded_data: last_row.decoded_data.clone(), - fse_data: FseTableRow::default(), + decoded_data: DecodedData { + decoded_len: last_row.decoded_data.decoded_len, + decoded_len_acc: last_row.decoded_data.decoded_len_acc + 1, + total_decoded_len: last_row.decoded_data.total_decoded_len, + decoded_byte: header_byte, + decoded_value_rlc, + }, huffman_data: HuffmanData::default(), + fse_data: FseTableRow::default(), }], + header_byte >= 127, + n_bytes as usize, ) } +// compression_debug +// fn process_block_zstd_huffman_header( +// src: &[u8], +// byte_offset: usize, +// last_row: &ZstdWitnessRow, +// randomness: Value, +// ) -> (usize, Vec>) { +// // A single byte (header_byte) is read. +// // - if header_byte < 128: canonical weights are represented by FSE table. +// // - if header_byte >= 128: canonical weights are given by direct representation. + +// let header_byte = src +// .get(byte_offset) +// .expect("ZBHuffmanHeader byte should exist"); + +// assert!( +// *header_byte < 128, +// "we expect canonical huffman weights to be encoded using FSE" +// ); + +// let value_rlc = +// last_row.encoded_data.value_rlc * randomness + Value::known(F::from(*header_byte as u64)); + +// ( +// byte_offset + 1, +// vec![ZstdWitnessRow { +// state: ZstdState { +// tag: ZstdTag::ZstdBlockHuffmanHeader, +// tag_next: ZstdTag::ZstdBlockFseCode, +// tag_len: 1, +// tag_idx: 1, +// tag_value: Value::known(F::from(*header_byte as u64)), +// tag_value_acc: Value::known(F::from(*header_byte as u64)), +// }, +// encoded_data: EncodedData { +// byte_idx: (byte_offset + 1) as u64, +// encoded_len: last_row.encoded_data.encoded_len, +// value_byte: *header_byte, +// value_rlc, +// ..Default::default() +// }, +// decoded_data: last_row.decoded_data.clone(), +// fse_data: FseTableRow::default(), +// huffman_data: HuffmanData::default(), +// }], +// ) +// } + fn process_block_zstd_huffman_code_direct( src: &[u8], byte_offset: usize, From 85a096d4ebe7cfbcd7c5e6ef3460170cf7f8794b Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 15 Jan 2024 20:42:35 -0500 Subject: [PATCH 006/165] jump table correction --- zkevm-circuits/src/witness/zstd/mod.rs | 31 ++++++++++++++++++++--- zkevm-circuits/src/witness/zstd/params.rs | 1 + 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 99ee8e22a0..47b8622427 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -621,7 +621,7 @@ fn process_block_zstd( let mut stream_offset = byte_offset; if n_streams > 1 { - let (byte_offset, rows) = process_block_zstd_huffman_jump_table( + let (byte_offset, rows, lstream_lens) = process_block_zstd_huffman_jump_table( src, stream_offset, huffman_rows.last().expect("last row should exist"), @@ -986,11 +986,36 @@ fn process_block_zstd_huffman_jump_table( byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>) { +) -> (usize, Vec>, [u64; 3]) { // Note: The decompressed size of each stream is equal to (regen_size + 3) / 4 // but the compressed bitstream length will be different. // Jump table provides information on the length of first 3 bitstreams. - unimplemented!() + + // Jump table's lengths are all plain bytes + + let jt_bytes = src + .iter() + .skip(byte_offset) + .take(N_JUMP_TABLE_BYTES) + .cloned() + .collect::>(); + + let l1: u64 = (jt_bytes[0] + jt_bytes[1] * 256) as u64; + let l2: u64 = (jt_bytes[2] + jt_bytes[3] * 256) as u64; + let l3: u64 = (jt_bytes[4] + jt_bytes[5] * 256) as u64; + + let (bytes_offset, rows) = + process_raw_bytes( + src, + byte_offset, + last_row, + randomness, + N_JUMP_TABLE_BYTES, + ZstdTag::ZstdBlockJumpTable, + ZstdTag::ZstdBlockHuffmanCode, + ); + + (bytes_offset, rows, [l1, l2, l3]) } fn process_block_zstd_lstream( src: &[u8], diff --git a/zkevm-circuits/src/witness/zstd/params.rs b/zkevm-circuits/src/witness/zstd/params.rs index 65f1231423..20d433e2e4 100644 --- a/zkevm-circuits/src/witness/zstd/params.rs +++ b/zkevm-circuits/src/witness/zstd/params.rs @@ -6,6 +6,7 @@ pub const N_MAGIC_NUMBER_BYTES: usize = 4; // Constants for zstd-compressed block pub const N_MAX_LITERAL_HEADER_BYTES: usize = 3; +pub const N_JUMP_TABLE_BYTES: usize = 6; /// Maximum number of symbols (weights), i.e. symbol in [0, N_MAX_SYMBOLS). pub const N_MAX_SYMBOLS: usize = 8; From bcc75172a263938f82dc54c48f23f2b6b0956ba7 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 15 Jan 2024 21:18:38 -0500 Subject: [PATCH 007/165] correct jump table type --- zkevm-circuits/src/witness/zstd/mod.rs | 9 +++++---- zkevm-circuits/src/witness/zstd/params.rs | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 47b8622427..37bb234edc 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -998,11 +998,12 @@ fn process_block_zstd_huffman_jump_table( .skip(byte_offset) .take(N_JUMP_TABLE_BYTES) .cloned() - .collect::>(); + .map(|x| x as u64) + .collect::>(); - let l1: u64 = (jt_bytes[0] + jt_bytes[1] * 256) as u64; - let l2: u64 = (jt_bytes[2] + jt_bytes[3] * 256) as u64; - let l3: u64 = (jt_bytes[4] + jt_bytes[5] * 256) as u64; + let l1: u64 = jt_bytes[0] + jt_bytes[1] * 256; + let l2: u64 = jt_bytes[2] + jt_bytes[3] * 256; + let l3: u64 = jt_bytes[4] + jt_bytes[5] * 256; let (bytes_offset, rows) = process_raw_bytes( diff --git a/zkevm-circuits/src/witness/zstd/params.rs b/zkevm-circuits/src/witness/zstd/params.rs index 20d433e2e4..595d1a01c9 100644 --- a/zkevm-circuits/src/witness/zstd/params.rs +++ b/zkevm-circuits/src/witness/zstd/params.rs @@ -7,6 +7,7 @@ pub const N_MAGIC_NUMBER_BYTES: usize = 4; // Constants for zstd-compressed block pub const N_MAX_LITERAL_HEADER_BYTES: usize = 3; pub const N_JUMP_TABLE_BYTES: usize = 6; +pub const N_MAX_LITERAL_FSE_BYTES: usize = 8; /// Maximum number of symbols (weights), i.e. symbol in [0, N_MAX_SYMBOLS). pub const N_MAX_SYMBOLS: usize = 8; From bf9051ea26fee8cdbd2ad4851dc38c09b2cab4e8 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 17 Jan 2024 01:42:36 -0500 Subject: [PATCH 008/165] delimitation of bitstream for accumulation witness --- zkevm-circuits/src/witness/zstd/mod.rs | 150 +++++++++++++++++++++-- zkevm-circuits/src/witness/zstd/types.rs | 3 + zkevm-circuits/src/witness/zstd/util.rs | 6 +- 3 files changed, 147 insertions(+), 12 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 37bb234edc..debca449d1 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1,3 +1,4 @@ +use bitstream_io::huffman; use bus_mapping::circuit_input_builder::Block; use eth_types::Field; use halo2_proofs::circuit::Value; @@ -633,10 +634,11 @@ fn process_block_zstd( for idx in 0..n_streams { let (byte_offset, rows) = process_block_zstd_lstream( src, - stream_offset, + stream_offset, + n_bytes, huffman_rows.last().expect("last row should exist"), randomness, - idx + 1 == n_streams + idx ); huffman_rows.extend_from_slice(&rows); @@ -978,7 +980,130 @@ fn process_block_zstd_huffman_code_fse( randomness: Value, n_bytes: usize, ) -> (usize, Vec>) { - unimplemented!(); + + // compression_debug + + // First, recover the FSE table for generating Huffman weights + let (n_fse_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset).expect("Reconstructing FSE table should not fail."); + + // Exclude the FSE table representation bytes, then we're left with a bitstream for recovering Huffman weights + let byte_offset = byte_offset + n_fse_bytes; + let n_bytes = n_bytes - n_fse_bytes; + + // Construct the Huffman bitstream + let mut huffman_bitstream = + src + .iter() + .skip(byte_offset) + .take(n_bytes) + .rev() + .clone() + .flat_map(|v|{ + let mut bits = value_bits_le(*v); + bits.reverse(); + bits + }) + .collect::>(); + + // Deliminators vector stores the positions where the bitstream is deliminated (a different value is decoded) + // The pair (usize, usize) indicates (byte_idx, bit_idx) where a delimination occurs (think of adding an underscore at the position) + // The range between two positions is where a new symbol is decoded or a new segment is recognized (i.e. leading zero section, a single sentinel 1-bit) + let mut deliminators: Vec<(usize, usize)> = vec![]; + + // Add a virtual deliminator in the front + deliminators.push((0, 0)); + + // Bitstream processing state values + let mut current_byte_idx: usize = 1; // byte_idx is 1-indexed + let mut current_bit_idx: usize = 0; + + // Helper function for managing idx increment + fn increment_idx(mut current_byte_idx: usize, mut current_bit_idx: usize) -> () { + current_bit_idx += 1; + + if current_bit_idx > current_byte_idx * N_BITS_PER_BYTE { + current_byte_idx += 1; + } + } + + // Recognize the leading zero section + while huffman_bitstream[current_bit_idx] == 0 { + increment_idx(current_byte_idx, current_bit_idx); + } + deliminators.push((current_byte_idx, current_bit_idx)); // indicates the end of leading zeros + + // The next bit is the sentinel bit + increment_idx(current_byte_idx, current_bit_idx); + deliminators.push((current_byte_idx, current_bit_idx)); + + // Now the actual weight-bearing bitstream starts + // The Huffman bitstream is decoded by two interleaved states reading the stream in alternating order. + // The FSE table for the two independent decoding strands are the same. + let mut color: usize = 0; // use 0, 1 (colors) to denote two alternating decoding strands. + let mut prev_state: [u32; 2] = [0, 0]; + let mut next_nb_to_read: [usize; 2] = [table.accuracy_log as usize, table.accuracy_log as usize]; + let mut decoded_weights: Vec = vec![]; + + + fn convert_fse_auxiliary_to_state_table(table: FseAuxiliaryTableData) -> Vec<[u64; 4]> { + // pub struct FseAuxiliaryTableData { + // /// The byte offset in the frame at which the FSE table is described. + // pub byte_offset: u64, + // /// The FSE table's size, i.e. 1 << AL (accuracy log). + // pub table_size: u64, + // /// A map from FseSymbol (weight) to states, also including fields for that state, for + // /// instance, the baseline and the number of bits to read from the FSE bitstream. + // /// + // /// For each symbol, the states are in strictly increasing order. + // pub sym_to_states: BTreeMap>, + // } + + /// A single row in the FSE table. + // #[derive(Clone, Debug, Default, PartialEq)] + // pub struct FseTableRow { + // /// Incremental index, starting at 1. + // pub idx: u64, + // /// The FSE state at this row in the FSE table. + // pub state: u64, + // /// The baseline associated with this state. + // pub baseline: u64, + // /// The number of bits to be read from the input bitstream at this state. + // pub num_bits: u64, + // /// The symbol emitted by the FSE table at this state. + // pub symbol: u64, + // } + + let mut state_table_rows: Vec<[u64; 4]> = vec![]; + // [u64; 4] represents (state, symbol, baseline, nb) + + // compression_debug + // must get the state rows + // let v = table.sym_to_states.values().; + + state_table_rows + } + + while current_bit_idx + next_nb_to_read[color] < n_bytes * N_BITS_PER_BYTE { + let nb = next_nb_to_read[color]; + let next_state = prev_state[color] + le_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); + + // compression_debug + // TODO: spit out the symbol, baseline, nb_to_read, at the next state + + // Change decoding states + prev_state[color] = next_state; + // let next_nb_to_read[color] = next bits to read // compression_debug + // decoded_weights.push(symbol); // compression_debug + + for _ in 0..nb { + increment_idx(current_byte_idx, current_bit_idx); + deliminators.push((current_byte_idx, current_bit_idx)); + } + + color = !color; + } + + (0, vec![]) } fn process_block_zstd_huffman_jump_table( @@ -1021,16 +1146,23 @@ fn process_block_zstd_huffman_jump_table( fn process_block_zstd_lstream( src: &[u8], byte_offset: usize, + len: usize, last_row: &ZstdWitnessRow, randomness: Value, - is_last_stream: bool, + stream_idx: usize, + // huffman_code: ) -> (usize, Vec>) { // compression_debug - // let tag_next = if is_last_stream { - // ZstdTag::ZstdBlockSequenceHeader - // } else { - // ZstdTag::ZstdBlockJumpTable - // }; + let tag_next = if stream_idx == 3 { + ZstdTag::ZstdBlockSequenceHeader + } else { + match stream_idx { + 0 => ZstdTag::Lstream2, + 1 => ZstdTag::Lstream3, + 2 => ZstdTag::Lstream4, + _ => unreachable!("stream_idx value out of range") + } + }; unimplemented!() } diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 1157315882..3003ce5824 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -319,6 +319,8 @@ pub struct FseTableData { pub struct FseAuxiliaryTableData { /// The byte offset in the frame at which the FSE table is described. pub byte_offset: u64, + /// The FSE table's AL (accuracy log) + pub accuracy_log: u8, /// The FSE table's size, i.e. 1 << AL (accuracy log). pub table_size: u64, /// A map from FseSymbol (weight) to states, also including fields for that state, for @@ -425,6 +427,7 @@ impl FseAuxiliaryTableData { t, Self { byte_offset: byte_offset as u64, + accuracy_log, table_size, sym_to_states, }, diff --git a/zkevm-circuits/src/witness/zstd/util.rs b/zkevm-circuits/src/witness/zstd/util.rs index 0435a6a4e3..71dc7c0810 100644 --- a/zkevm-circuits/src/witness/zstd/util.rs +++ b/zkevm-circuits/src/witness/zstd/util.rs @@ -118,11 +118,11 @@ pub fn value_bits_le(value_byte: u8) -> [u8; N_BITS_PER_BYTE] { } // compression_debug -pub fn le_bits_to_value(bits: &[u8]) -> u64 { - assert!(bits.len() <= 64); +pub fn le_bits_to_value(bits: &[u8]) -> u32 { + assert!(bits.len() <= 32); bits.into_iter().enumerate().fold(0, |mut acc, (p, b)| { - acc += (2u64).pow(p as u32) * (*b as u64); + acc += (2u32).pow(p as u32) * (*b as u32); acc }) } From 87ceb2fa1ec34b51589cc3d970ca87e7eda96d12 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 17 Jan 2024 23:34:35 -0500 Subject: [PATCH 009/165] Finish decoding bitstreams --- zkevm-circuits/src/decompression_circuit.rs | 6 +- zkevm-circuits/src/witness/zstd/mod.rs | 299 ++++++++++---------- zkevm-circuits/src/witness/zstd/types.rs | 58 ++-- zkevm-circuits/src/witness/zstd/util.rs | 13 +- 4 files changed, 204 insertions(+), 172 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 5b7fa0ad59..a1542a0e9d 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -173,7 +173,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }; } - is_tag!(is_magic_number, MagicNumber); is_tag!(is_frame_header_descriptor, FrameHeaderDescriptor); is_tag!(is_frame_content_size, FrameContentSize); is_tag!(is_block_header, BlockHeader); @@ -184,10 +183,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { is_tag!(is_zb_fse_code, ZstdBlockFseCode); is_tag!(is_zb_huffman_code, ZstdBlockHuffmanCode); is_tag!(is_zb_jump_table, ZstdBlockJumpTable); - is_tag!(is_lstream_1, Lstream1); - is_tag!(is_lstream_2, Lstream2); - is_tag!(is_lstream_3, Lstream3); - is_tag!(is_lstream_4, Lstream4); + is_tag!(is_lstream, Lstream); meta.create_gate("DecompressionCircuit: all rows", |meta| { let mut cb = BaseConstraintBuilder::default(); diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index debca449d1..0dabce7a5a 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -17,75 +17,7 @@ mod tui; use tui::draw_rows; mod util; -use util::{value_bits_le, le_bits_to_value}; - -/// MagicNumber -fn process_magic_number( - src: &[u8], - byte_offset: usize, - last_row: &ZstdWitnessRow, - randomness: Value, -) -> (usize, Vec>) { - assert_eq!( - src.iter() - .skip(byte_offset) - .take(N_MAGIC_NUMBER_BYTES) - .cloned() - .collect::>(), - MAGIC_NUMBER_BYTES.to_vec(), - ); - - // MagicNumber appears at the start of a new frame. - let value_rlc_iter = - MAGIC_NUMBER_BYTES - .iter() - .scan(last_row.encoded_data.value_rlc, |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }); - let tag_value_iter = MAGIC_NUMBER_BYTES - .iter() - .scan(Value::known(F::zero()), |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }); - let tag_value = tag_value_iter - .clone() - .last() - .expect("no items in MAGIC_NUMBER_BYTES"); - ( - byte_offset + N_MAGIC_NUMBER_BYTES, - src.iter() - .skip(byte_offset) - .take(N_MAGIC_NUMBER_BYTES) - .enumerate() - .zip(tag_value_iter) - .zip(value_rlc_iter) - .map( - |(((i, &value_byte), tag_value_acc), value_rlc)| ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::MagicNumber, - tag_next: ZstdTag::FrameHeaderDescriptor, - tag_len: N_MAGIC_NUMBER_BYTES as u64, - tag_idx: (i + 1) as u64, - tag_value, - tag_value_acc, - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + i + 1) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte, - value_rlc, - ..Default::default() - }, - decoded_data: last_row.decoded_data.clone(), - huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), - }, - ) - .collect::>(), - ) -} +use util::{value_bits_le, le_bits_to_value, increment_idx}; /// FrameHeaderDescriptor and FrameContentSize fn process_frame_header( @@ -600,7 +532,7 @@ fn process_block_zstd( ); huffman_rows.extend_from_slice(&rows); - let (bytes_offset, rows) = if is_direct { + let (bytes_offset, rows, huffman_codes) = if is_direct { process_block_zstd_huffman_code_direct( src, byte_offset, @@ -638,7 +570,8 @@ fn process_block_zstd( n_bytes, huffman_rows.last().expect("last row should exist"), randomness, - idx + idx, + &huffman_codes ); huffman_rows.extend_from_slice(&rows); @@ -873,8 +806,7 @@ fn process_block_zstd_huffman_code_direct( last_row: &ZstdWitnessRow, randomness: Value, n_bytes: usize, -) -> (usize, Vec>) { - // compression_debug +) -> (usize, Vec>, HuffmanCodesData) { // For direct representation of huffman weights, each byte (8 bits) represents two weights. // weight[0] = (Byte[0] >> 4) // weight[1] = (Byte[0] & 0xf). @@ -970,6 +902,7 @@ fn process_block_zstd_huffman_code_direct( }, ) .collect::>(), + HuffmanCodesData { byte_offset: 0, weights: vec![] } ) } @@ -979,9 +912,9 @@ fn process_block_zstd_huffman_code_fse( last_row: &ZstdWitnessRow, randomness: Value, n_bytes: usize, -) -> (usize, Vec>) { - - // compression_debug +) -> (usize, Vec>, HuffmanCodesData) { + // Preserve this value for later construction of HuffmanCodesDataTable + let huffman_code_byte_offset = byte_offset; // First, recover the FSE table for generating Huffman weights let (n_fse_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset).expect("Reconstructing FSE table should not fail."); @@ -1017,15 +950,6 @@ fn process_block_zstd_huffman_code_fse( let mut current_byte_idx: usize = 1; // byte_idx is 1-indexed let mut current_bit_idx: usize = 0; - // Helper function for managing idx increment - fn increment_idx(mut current_byte_idx: usize, mut current_bit_idx: usize) -> () { - current_bit_idx += 1; - - if current_bit_idx > current_byte_idx * N_BITS_PER_BYTE { - current_byte_idx += 1; - } - } - // Recognize the leading zero section while huffman_bitstream[current_bit_idx] == 0 { increment_idx(current_byte_idx, current_bit_idx); @@ -1040,60 +964,26 @@ fn process_block_zstd_huffman_code_fse( // The Huffman bitstream is decoded by two interleaved states reading the stream in alternating order. // The FSE table for the two independent decoding strands are the same. let mut color: usize = 0; // use 0, 1 (colors) to denote two alternating decoding strands. - let mut prev_state: [u32; 2] = [0, 0]; + let mut prev_baseline: [u64; 2] = [0, 0]; let mut next_nb_to_read: [usize; 2] = [table.accuracy_log as usize, table.accuracy_log as usize]; let mut decoded_weights: Vec = vec![]; - - fn convert_fse_auxiliary_to_state_table(table: FseAuxiliaryTableData) -> Vec<[u64; 4]> { - // pub struct FseAuxiliaryTableData { - // /// The byte offset in the frame at which the FSE table is described. - // pub byte_offset: u64, - // /// The FSE table's size, i.e. 1 << AL (accuracy log). - // pub table_size: u64, - // /// A map from FseSymbol (weight) to states, also including fields for that state, for - // /// instance, the baseline and the number of bits to read from the FSE bitstream. - // /// - // /// For each symbol, the states are in strictly increasing order. - // pub sym_to_states: BTreeMap>, - // } - - /// A single row in the FSE table. - // #[derive(Clone, Debug, Default, PartialEq)] - // pub struct FseTableRow { - // /// Incremental index, starting at 1. - // pub idx: u64, - // /// The FSE state at this row in the FSE table. - // pub state: u64, - // /// The baseline associated with this state. - // pub baseline: u64, - // /// The number of bits to be read from the input bitstream at this state. - // pub num_bits: u64, - // /// The symbol emitted by the FSE table at this state. - // pub symbol: u64, - // } - - let mut state_table_rows: Vec<[u64; 4]> = vec![]; - // [u64; 4] represents (state, symbol, baseline, nb) - - // compression_debug - // must get the state rows - // let v = table.sym_to_states.values().; - - state_table_rows - } + // Convert FSE auxiliary data into a state-indexed representation + let fse_state_table = table.parse_state_table(); while current_bit_idx + next_nb_to_read[color] < n_bytes * N_BITS_PER_BYTE { let nb = next_nb_to_read[color]; - let next_state = prev_state[color] + le_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); + let next_state = prev_baseline[color] + le_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); + + // Lookup the FSE table row for the state + let fse_row = fse_state_table.get(&(next_state as u64)).expect("next state should be in fse table"); - // compression_debug - // TODO: spit out the symbol, baseline, nb_to_read, at the next state + // Decode the symbol + decoded_weights.push(fse_row.0 as u8); - // Change decoding states - prev_state[color] = next_state; - // let next_nb_to_read[color] = next bits to read // compression_debug - // decoded_weights.push(symbol); // compression_debug + // Preparing for next state + prev_baseline[color] = fse_row.1; + next_nb_to_read[color] = fse_row.2 as usize; for _ in 0..nb { increment_idx(current_byte_idx, current_bit_idx); @@ -1103,7 +993,15 @@ fn process_block_zstd_huffman_code_fse( color = !color; } - (0, vec![]) + // Construct HuffmanCodesTable + let huffman_codes = HuffmanCodesData { + byte_offset: huffman_code_byte_offset as u64, + weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() + }; + + // compression_debug + // need to organize the witness rows + (0, vec![], huffman_codes) } fn process_block_zstd_huffman_jump_table( @@ -1150,20 +1048,86 @@ fn process_block_zstd_lstream( last_row: &ZstdWitnessRow, randomness: Value, stream_idx: usize, - // huffman_code: + huffman_code: &HuffmanCodesData, ) -> (usize, Vec>) { - // compression_debug + let mut lstream_bits = + src + .iter() + .skip(byte_offset) + .take(len) + .rev() + .clone() + .flat_map(|v| { + let mut bits = value_bits_le(*v); + bits.reverse(); + bits + }) + .collect::>(); + + // Deliminators vector stores the positions where the bitstream is deliminated (a different value is decoded) + // The pair (usize, usize) indicates (byte_idx, bit_idx) where a delimination occurs (think of adding an underscore at the position) + // The range between two positions is where a new symbol is decoded or a new segment is recognized (i.e. leading zero section, a single sentinel 1-bit) + let mut deliminators: Vec<(usize, usize)> = vec![]; + + // Add a virtual deliminator in the front + deliminators.push((0, 0)); + + // Bitstream processing state values + let mut current_byte_idx: usize = 1; // byte_idx is 1-indexed + let mut current_bit_idx: usize = 0; + + // Recognize the leading zero section + while lstream_bits[current_bit_idx] == 0 { + increment_idx(current_byte_idx, current_bit_idx); + } + deliminators.push((current_byte_idx, current_bit_idx)); // indicates the end of leading zeros + + // The next bit is the sentinel bit + increment_idx(current_byte_idx, current_bit_idx); + deliminators.push((current_byte_idx, current_bit_idx)); + + // Now the actual symbol-bearing bitstream starts + let huffman_bit_value_map = huffman_code.parse_canonical_bit_value_map(); + let mut bit_value_acc: u64 = 0; + let mut cur_bitstring_len: usize = 0; + let mut decoded_symbols: Vec = vec![]; + + while current_bit_idx < len * N_BITS_PER_BYTE { + if huffman_bit_value_map.1.contains_key(&bit_value_acc) { + decoded_symbols.push(huffman_bit_value_map.1.get(&bit_value_acc).unwrap().clone()); + + // Mark the new deliminator + for _ in 0..cur_bitstring_len { + increment_idx(current_byte_idx, current_bit_idx); + } + deliminators.push((current_byte_idx, current_bit_idx)); + + // Reset decoding state + bit_value_acc = 0; + cur_bitstring_len = 0; + } else { + bit_value_acc += (src[current_bit_idx + cur_bitstring_len] as u64) * 2u64.pow(cur_bitstring_len as u32); + cur_bitstring_len += 1; + + if cur_bitstring_len > huffman_bit_value_map.0 as usize { + unreachable!("read bit len greater than max bitstring len"); + } + } + } + + // Now construct the witness rows let tag_next = if stream_idx == 3 { ZstdTag::ZstdBlockSequenceHeader } else { match stream_idx { - 0 => ZstdTag::Lstream2, - 1 => ZstdTag::Lstream3, - 2 => ZstdTag::Lstream4, + 0 | 1 | 2 => ZstdTag::Lstream, _ => unreachable!("stream_idx value out of range") } }; - unimplemented!() + + // compression_debug + + (0, vec![]) } pub fn process(src: &[u8], randomness: Value) -> Vec> { @@ -1179,20 +1143,11 @@ pub fn process(src: &[u8], randomness: Value) -> Vec( - src, - byte_offset, - &ZstdWitnessRow::init(src.len()), - randomness, - ); - witness_rows.extend_from_slice(&rows); - - // 2. FrameHeaderDescriptor and FrameContentSize + // 1. FrameHeaderDescriptor and FrameContentSize let (byte_offset, rows) = process_frame_header::( src, byte_offset, - rows.last().expect("last row expected to exist"), + &ZstdWitnessRow::init(src.len()), randomness, ); witness_rows.extend_from_slice(&rows); @@ -1220,6 +1175,7 @@ pub fn process(src: &[u8], randomness: Value) -> Vec Result<(), std::io::Error> { + let compressed: [u8; 559] = [ + 0x28, 0xb5, 0x2f, 0xfd, 0x64, 0xae, 0x02, 0x0d, 0x11, 0x00, 0x76, 0x62, 0x5e, 0x23, 0x30, 0x6f, + 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, + 0xa9, 0xd4, 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, + 0x01, 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, + 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, + 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, + 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, + 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, + 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, 0x5a, 0xdf, 0xb4, 0x21, 0x9a, 0xcb, 0x8f, 0xc7, + 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, 0x28, 0x0e, 0xfb, 0x8b, + 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, 0xeb, 0x81, 0xf1, 0x78, 0x4b, 0xad, + 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, 0xb4, 0xd9, 0xe1, 0x95, 0x21, 0x66, 0x0c, + 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, 0x22, 0x07, 0x0b, 0x91, 0x86, 0x94, 0x1a, 0x7b, + 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, 0x65, 0xd6, 0x34, 0x63, 0x0c, 0x88, 0x9b, 0x1c, 0x48, + 0xca, 0x2b, 0x34, 0xa9, 0x6b, 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, + 0x69, 0x18, 0x57, 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, + 0x7b, 0x6e, 0xd8, 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, 0x14, + 0xf4, 0x40, 0xe7, 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, 0x49, 0xae, 0x13, + 0xa4, 0x75, 0x38, 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, 0x86, 0xa4, 0xac, 0xaa, 0xa3, + 0x34, 0x89, 0xca, 0x2e, 0xe9, 0xc1, 0xfe, 0xf2, 0x51, 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, + 0xed, 0xd9, 0xb7, 0x4a, 0xb2, 0xb2, 0x61, 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, + 0xdc, 0x60, 0x6c, 0x41, 0x76, 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, + 0xac, 0x9d, 0xe0, 0x62, 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, + 0xd2, 0x7c, 0x0a, 0x7c, 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, 0xda, + 0x15, 0x91, 0xde, 0x21, 0xf5, 0x55, 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, 0x42, 0x44, 0x81, + 0x8c, 0x94, 0xb4, 0x50, 0x1e, 0x20, 0x42, 0x82, 0x98, 0xc2, 0x3b, 0x10, 0x48, 0xec, 0xa6, 0x39, + 0x63, 0x13, 0xa7, 0x01, 0x94, 0x40, 0xff, 0x88, 0x0f, 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, + 0xcb, 0xf6, 0xc8, 0x21, 0x59, 0xaa, 0x38, 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, + 0xc8, 0x03, 0x42, 0x2a, 0x4b, 0xf6, 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, + 0x7e, 0x00, 0xbc, 0x2f, 0x46, 0x96, 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, + 0x8c, 0xc2, 0x05, 0xf7, 0x54, 0x51, 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, 0x99, + 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, 0x50, 0x84, 0xf5, + 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, 0x4c, 0x52, 0x4f, 0x20, 0xa3, 0x61, 0x23, 0x77, 0x12, 0xd3, + 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, 0x70, 0xec, 0x14, 0x91, 0xf9, 0x85, 0x61, 0xd5, 0x7e, 0x98, + 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, + ]; + + let _witness_rows = process::(compressed.as_raw_slice(), Value::known(Fr::from(123456789))); + + Ok(()) + } } diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 3003ce5824..cfaa26a4ea 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -88,8 +88,6 @@ impl From for BlockType { pub enum ZstdTag { /// Null should not occur. Null = 0, - /// Magic number bytes. - MagicNumber, /// The frame header's descriptor. FrameHeaderDescriptor, /// The frame's content size. @@ -103,8 +101,10 @@ pub enum ZstdTag { /// Zstd block's literals header. ZstdBlockLiteralsHeader, /// Zstd blocks might contain raw bytes + /// NOTE: might be removed then restricted to raw blocks ZstdBlockLiteralsRawBytes, /// Zstd blocks might contain rle bytes + /// NOTE: might be removed then restricted to rle blocks ZstdBlockLiteralsRleBytes, /// 1 byte Huffman header ZstdBlockHuffmanHeader, @@ -114,14 +114,8 @@ pub enum ZstdTag { ZstdBlockHuffmanCode, /// Zstd block's jump table. ZstdBlockJumpTable, - /// Literal stream 1. - Lstream1, - /// Literal stream 2. - Lstream2, - /// Literal stream 3. - Lstream3, - /// Literal stream 4. - Lstream4, + /// Literal stream. + Lstream, /// Beginning of sequence section. ZstdBlockSequenceHeader, } @@ -138,7 +132,6 @@ impl ToString for ZstdTag { fn to_string(&self) -> String { String::from(match self { Self::Null => "null", - Self::MagicNumber => "MagicNumber", Self::FrameHeaderDescriptor => "FrameHeaderDescriptor", Self::FrameContentSize => "FrameContentSize", Self::BlockHeader => "BlockHeader", @@ -152,10 +145,7 @@ impl ToString for ZstdTag { Self::ZstdBlockHuffmanCode => "ZstdBlockHuffmanCode", Self::ZstdBlockJumpTable => "ZstdBlockJumpTable", Self::ZstdBlockSequenceHeader => "ZstdBlockSequenceHeader", - Self::Lstream1 => "Lstream1", - Self::Lstream2 => "Lstream2", - Self::Lstream3 => "Lstream3", - Self::Lstream4 => "Lstream4", + Self::Lstream => "Lstream", }) } } @@ -174,7 +164,7 @@ impl Default for ZstdState { fn default() -> Self { Self { tag: ZstdTag::Null, - tag_next: ZstdTag::MagicNumber, + tag_next: ZstdTag::FrameHeaderDescriptor, tag_len: 0, tag_idx: 0, tag_value: Value::known(F::zero()), @@ -231,6 +221,8 @@ pub struct HuffmanCodesData { /// Denotes the tuple (max_bitstring_len, Map). type ParsedCanonicalHuffmanCode = (u64, BTreeMap); +/// A representation indexed by bit_value as key for easier lookup during decoding. (max_bitstring_len, Map) +type ParsedCanonicalHuffmanCodeBitValueMap = (u64, BTreeMap); impl HuffmanCodesData { /// Reconstruct the bitstrings for each symbol based on the canonical Huffman code weights. The @@ -286,6 +278,21 @@ impl HuffmanCodesData { (max_bitstring_len, sym_to_tuple) } + + /// Construct a representation indexed by bit_value as key for easier lookup during decoding. + pub fn parse_canonical_bit_value_map(&self) -> ParsedCanonicalHuffmanCodeBitValueMap { + let mut bit_value_mapping: (u64, BTreeMap) = (0, BTreeMap::new()); + + let parsed_huffman_code = self.parse_canonical(); + + bit_value_mapping.0 = parsed_huffman_code.0; + bit_value_mapping.1 = parsed_huffman_code.1.into_iter().fold(BTreeMap::new(), |mut acc, (symbol, (_weight, bit_value))| { + acc.insert(bit_value, symbol); + acc + }); + + bit_value_mapping + } } /// A single row in the FSE table. @@ -330,6 +337,12 @@ pub struct FseAuxiliaryTableData { pub sym_to_states: BTreeMap>, } +/// Another form of Fse table that has state as key instead of the FseSymbol. +/// In decoding, symbols are emitted from state-chaining. +/// This representation makes it easy to look up decoded symbol from current state. +/// Map. +type FseStateMapping = BTreeMap; + impl FseAuxiliaryTableData { #[allow(non_snake_case)] /// While we reconstruct an FSE table from a bitstream, we do not know before reconstruction @@ -433,6 +446,19 @@ impl FseAuxiliaryTableData { }, )) } + + /// Convert an FseAuxiliaryTableData into a state-mapped representation. + /// This makes it easier to lookup state-chaining during decoding. + pub fn parse_state_table(&self) -> FseStateMapping { + let rows: Vec = self.sym_to_states.values().flat_map(|v| v.clone()).collect(); + let mut state_table: FseStateMapping = BTreeMap::new(); + + for row in rows { + state_table.insert(row.state, (row.symbol, row.baseline, row.num_bits)); + } + + state_table + } } #[derive(Clone, Debug)] diff --git a/zkevm-circuits/src/witness/zstd/util.rs b/zkevm-circuits/src/witness/zstd/util.rs index 71dc7c0810..1986072731 100644 --- a/zkevm-circuits/src/witness/zstd/util.rs +++ b/zkevm-circuits/src/witness/zstd/util.rs @@ -118,15 +118,24 @@ pub fn value_bits_le(value_byte: u8) -> [u8; N_BITS_PER_BYTE] { } // compression_debug -pub fn le_bits_to_value(bits: &[u8]) -> u32 { +pub fn le_bits_to_value(bits: &[u8]) -> u64 { assert!(bits.len() <= 32); bits.into_iter().enumerate().fold(0, |mut acc, (p, b)| { - acc += (2u32).pow(p as u32) * (*b as u32); + acc += (2u64).pow(p as u32) * (*b as u64); acc }) } +// helper utility for helping manage bitstream delimitation +pub fn increment_idx(mut current_byte_idx: usize, mut current_bit_idx: usize) -> () { + current_bit_idx += 1; + + if current_bit_idx > current_byte_idx * N_BITS_PER_BYTE { + current_byte_idx += 1; + } +} + #[cfg(test)] mod tests { use super::*; From ba8303b004f7d5666cd81594774f08a4dda2a34a Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 18 Jan 2024 02:38:27 -0500 Subject: [PATCH 010/165] Add lstream decoding witness rows --- zkevm-circuits/src/witness/zstd/mod.rs | 75 +++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 58bb88fcbe..dd9c95ce50 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1125,9 +1125,80 @@ fn process_block_zstd_lstream( } }; - // compression_debug + // Add the leading zero and sentinel 1-bit. + if deliminators[1] == (1, 0) { + // there're no leading zeros + decoded_symbols.insert(0, 1); + } else { + decoded_symbols.insert(0, 0); + decoded_symbols.insert(1, 1); + } + + // Witness rows + let mut value_rlc = last_row.encoded_data.value_rlc; + + let decoded_value_rlc = last_row.decoded_data.decoded_value_rlc; + let decoded_value_rlc_iter = decoded_symbols.iter().scan( + last_row.decoded_data.decoded_value_rlc, + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(symbol as u64)); + Some(*acc) + }, + ); + + let tag_value_iter = decoded_symbols.iter().scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(symbol as u64)); + Some(*acc) + }, + ); + + let tag_value = tag_value_iter + .clone() + .last() + .expect("Tag value exists"); + + let mut witness_rows: Vec = vec![]; + + let mut last_pos = deliminators[0]; + for (idx, curr_pos) in deliminators.into_iter().skip(1).enumerate() { + if curr_pos.0 > last_pos.0 { + value_rlc = value_rlc * randomness + Value::known(F::from) + } + + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::Lstream, + tag_next, + tag_len: len as u64, + tag_idx: idx as u64, + tag_value: tag_value, + tag_value_acc: tag_value_iter.next(), + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + last_pos.0) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: src[byte_offset + last_pos.0], + value_rlc, + reverse: true, + ..Default::default() + }, + decoded_data: DecodedData { + decoded_len: last_row.decoded_data.decoded_len, + decoded_len_acc: last_row.decoded_data.decoded_len + curr_pos.0 as u64 + 1, + total_decoded_len: last_row.decoded_data.total_decoded_len, + decoded_byte: decoded_symbols[idx], + decoded_value_rlc, + }, + huffman_data: HuffmanData::default(), + fse_data: FseTableRow::default(), + }); + + last_pos = curr_pos; + } - (0, vec![]) + (byte_offset + len, witness_rows) } pub fn process(src: &[u8], randomness: Value) -> Vec> { From fa4d53c777b9a5deaada427818c96c6e7463dc77 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 18 Jan 2024 12:07:19 -0500 Subject: [PATCH 011/165] Add witness rows for huffman bitstream decoding --- zkevm-circuits/src/witness/zstd/mod.rs | 86 +++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index dd9c95ce50..2de18bef9c 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -547,6 +547,7 @@ fn process_block_zstd( &huffman_rows[0], randomness, n_bytes, + n_streams, ) }; huffman_rows.extend_from_slice(&rows); @@ -912,6 +913,7 @@ fn process_block_zstd_huffman_code_fse( last_row: &ZstdWitnessRow, randomness: Value, n_bytes: usize, + n_streams: usize, ) -> (usize, Vec>, HuffmanCodesData) { // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; @@ -999,9 +1001,87 @@ fn process_block_zstd_huffman_code_fse( weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() }; - // compression_debug - // need to organize the witness rows - (0, vec![], huffman_codes) + // Now construct the witness rows + let tag_next = if n_streams > 1 { + ZstdTag::ZstdBlockJumpTable + } else { + ZstdTag::Lstream + }; + + // Add the leading zero and sentinel 1-bit. + if deliminators[1] == (1, 0) { + // there're no leading zeros + decoded_symbols.insert(0, 1); + } else { + decoded_symbols.insert(0, 0); + decoded_symbols.insert(1, 1); + } + + // Witness rows + let mut value_rlc = last_row.encoded_data.value_rlc; + + let decoded_value_rlc = last_row.decoded_data.decoded_value_rlc; + let decoded_value_rlc_iter = decoded_symbols.iter().scan( + last_row.decoded_data.decoded_value_rlc, + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(symbol as u64)); + Some(*acc) + }, + ); + + let tag_value_iter = decoded_symbols.iter().scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(symbol as u64)); + Some(*acc) + }, + ); + + let tag_value = tag_value_iter + .clone() + .last() + .expect("Tag value exists"); + + let mut witness_rows: Vec = vec![]; + + let mut last_pos = deliminators[0]; + for (idx, curr_pos) in deliminators.into_iter().skip(1).enumerate() { + if curr_pos.0 > last_pos.0 { + value_rlc = value_rlc * randomness + Value::known(F::from) + } + + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::Lstream, + tag_next, + tag_len: len as u64, + tag_idx: idx as u64, + tag_value: tag_value, + tag_value_acc: tag_value_iter.next(), + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + last_pos.0) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: src[byte_offset + last_pos.0], + value_rlc, + reverse: true, + ..Default::default() + }, + decoded_data: DecodedData { + decoded_len: last_row.decoded_data.decoded_len, + decoded_len_acc: last_row.decoded_data.decoded_len + curr_pos.0 as u64 + 1, + total_decoded_len: last_row.decoded_data.total_decoded_len, + decoded_byte: decoded_symbols[idx], + decoded_value_rlc, + }, + huffman_data: HuffmanData::default(), + fse_data: FseTableRow::default(), + }); + + last_pos = curr_pos; + } + + (byte_offset + n_bytes, witness_rows) } fn process_block_zstd_huffman_jump_table( From 768800e80eeb2b74bf6e6d120ed97b3f246d563a Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 18 Jan 2024 14:07:32 -0500 Subject: [PATCH 012/165] remove constant from merge --- zkevm-circuits/src/witness/zstd/params.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/params.rs b/zkevm-circuits/src/witness/zstd/params.rs index 7a23f77a1a..91e1fc62f1 100644 --- a/zkevm-circuits/src/witness/zstd/params.rs +++ b/zkevm-circuits/src/witness/zstd/params.rs @@ -3,8 +3,6 @@ pub const N_BITS_PER_BYTE: usize = 8; pub const N_BLOCK_HEADER_BYTES: usize = 3; -pub const N_MAGIC_NUMBER_BYTES: usize = 4; - // Constants for zstd-compressed block pub const N_MAX_LITERAL_HEADER_BYTES: usize = 3; pub const N_JUMP_TABLE_BYTES: usize = 6; From d29b10f83f8f3439a6b6a1f54a6d452a7eb09534 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 18 Jan 2024 14:35:31 -0500 Subject: [PATCH 013/165] Restore default witness value for correction --- zkevm-circuits/src/witness/zstd/mod.rs | 115 ++++++++++++++----------- 1 file changed, 63 insertions(+), 52 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 2de18bef9c..10c6290528 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -738,13 +738,7 @@ fn process_block_zstd_huffman_header( value_rlc, ..Default::default() }, - decoded_data: DecodedData { - decoded_len: last_row.decoded_data.decoded_len, - decoded_len_acc: last_row.decoded_data.decoded_len_acc + 1, - total_decoded_len: last_row.decoded_data.total_decoded_len, - decoded_byte: header_byte, - decoded_value_rlc, - }, + decoded_data: last_row.decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), }], @@ -754,6 +748,8 @@ fn process_block_zstd_huffman_header( } // compression_debug +// waiting on response for whether direct representation will be eliminated from zstd-compressed blocks + // fn process_block_zstd_huffman_header( // src: &[u8], // byte_offset: usize, @@ -890,13 +886,7 @@ fn process_block_zstd_huffman_code_direct( reverse: false, ..Default::default() }, - decoded_data: DecodedData { - decoded_len: last_row.decoded_data.decoded_len, - decoded_len_acc: last_row.decoded_data.decoded_len + (i as u64) + 1, - total_decoded_len: last_row.decoded_data.total_decoded_len, - decoded_byte: value_byte, - decoded_value_rlc, - }, + decoded_data: last_row.decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), } @@ -1067,15 +1057,9 @@ fn process_block_zstd_huffman_code_fse( reverse: true, ..Default::default() }, - decoded_data: DecodedData { - decoded_len: last_row.decoded_data.decoded_len, - decoded_len_acc: last_row.decoded_data.decoded_len + curr_pos.0 as u64 + 1, - total_decoded_len: last_row.decoded_data.total_decoded_len, - decoded_byte: decoded_symbols[idx], - decoded_value_rlc, - }, + decoded_data: last_row.decoded_data.clone(), huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), + fse_data: FseTableRow::default(), // TODO: correct witness assignment }); last_pos = curr_pos; @@ -1094,8 +1078,6 @@ fn process_block_zstd_huffman_jump_table( // but the compressed bitstream length will be different. // Jump table provides information on the length of first 3 bitstreams. - // Jump table's lengths are all plain bytes - let jt_bytes = src .iter() .skip(byte_offset) @@ -1108,18 +1090,61 @@ fn process_block_zstd_huffman_jump_table( let l2: u64 = jt_bytes[2] + jt_bytes[3] * 256; let l3: u64 = jt_bytes[4] + jt_bytes[5] * 256; - let (bytes_offset, rows) = - process_raw_bytes( - src, - byte_offset, - last_row, - randomness, - N_JUMP_TABLE_BYTES, - ZstdTag::ZstdBlockJumpTable, - ZstdTag::ZstdBlockHuffmanCode, - ); + let value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + last_row.encoded_data.value_rlc, + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_value_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_value = tag_value_iter + .clone() + .last() + .expect("Raw bytes must be of non-zero length"); - (bytes_offset, rows, [l1, l2, l3]) + ( + byte_offset + N_JUMP_TABLE_BYTES, + src.iter() + .skip(byte_offset) + .take(n_bytes) + .zip(tag_value_iter) + .zip(value_rlc_iter) + .enumerate() + .map( + |(i, ((&value_byte, tag_value_acc), value_rlc))| { + ZstdWitnessRow { + state: ZstdState { + tag, + tag_next, + tag_len: n_bytes as u64, + tag_idx: (i + 1) as u64, + tag_value, + tag_value_acc, + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + i + 1) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte, + value_rlc, + reverse: false, + ..Default::default() + }, + decoded_data: last_row.decoded_data.clone(), + huffman_data: HuffmanData::default(), + fse_data: FseTableRow::default(), + } + }, + ) + .collect::>(), + [l1, l2, l3] + ) } fn process_block_zstd_lstream( src: &[u8], @@ -1217,15 +1242,6 @@ fn process_block_zstd_lstream( // Witness rows let mut value_rlc = last_row.encoded_data.value_rlc; - let decoded_value_rlc = last_row.decoded_data.decoded_value_rlc; - let decoded_value_rlc_iter = decoded_symbols.iter().scan( - last_row.decoded_data.decoded_value_rlc, - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(symbol as u64)); - Some(*acc) - }, - ); - let tag_value_iter = decoded_symbols.iter().scan( Value::known(F::zero()), |acc, &byte| { @@ -1264,14 +1280,8 @@ fn process_block_zstd_lstream( reverse: true, ..Default::default() }, - decoded_data: DecodedData { - decoded_len: last_row.decoded_data.decoded_len, - decoded_len_acc: last_row.decoded_data.decoded_len + curr_pos.0 as u64 + 1, - total_decoded_len: last_row.decoded_data.total_decoded_len, - decoded_byte: decoded_symbols[idx], - decoded_value_rlc, - }, - huffman_data: HuffmanData::default(), + decoded_data: last_row.decoded_data.clone(), + huffman_data: HuffmanData::default(), // TODO: correct witness assignment value fse_data: FseTableRow::default(), }); @@ -1343,6 +1353,7 @@ mod tests { Ok(()) } + // This test is for dev process and will be deleted #[test] fn check_witness_generation() -> Result<(), std::io::Error> { let compressed: [u8; 559] = [ From fb2f910cd02cff55f82d55a8d1c71a6bf792cacd Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 18 Jan 2024 14:48:48 -0500 Subject: [PATCH 014/165] Remove decoded from FSE Huffman --- zkevm-circuits/src/witness/zstd/mod.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 10c6290528..7a18da83d2 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1010,15 +1010,6 @@ fn process_block_zstd_huffman_code_fse( // Witness rows let mut value_rlc = last_row.encoded_data.value_rlc; - let decoded_value_rlc = last_row.decoded_data.decoded_value_rlc; - let decoded_value_rlc_iter = decoded_symbols.iter().scan( - last_row.decoded_data.decoded_value_rlc, - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(symbol as u64)); - Some(*acc) - }, - ); - let tag_value_iter = decoded_symbols.iter().scan( Value::known(F::zero()), |acc, &byte| { From abc7b304532c476ec8a9889389dbbf9f8122fcf8 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 18 Jan 2024 19:54:38 -0500 Subject: [PATCH 015/165] correct jump table witness --- zkevm-circuits/src/witness/zstd/mod.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 7a18da83d2..b48a66c6b9 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1081,14 +1081,14 @@ fn process_block_zstd_huffman_jump_table( let l2: u64 = jt_bytes[2] + jt_bytes[3] * 256; let l3: u64 = jt_bytes[4] + jt_bytes[5] * 256; - let value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + let value_rlc_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( last_row.encoded_data.value_rlc, |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }, ); - let tag_value_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + let tag_value_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); @@ -1098,13 +1098,13 @@ fn process_block_zstd_huffman_jump_table( let tag_value = tag_value_iter .clone() .last() - .expect("Raw bytes must be of non-zero length"); + .expect("Tag value must exist."); ( byte_offset + N_JUMP_TABLE_BYTES, src.iter() .skip(byte_offset) - .take(n_bytes) + .take(N_JUMP_TABLE_BYTES) .zip(tag_value_iter) .zip(value_rlc_iter) .enumerate() @@ -1112,9 +1112,9 @@ fn process_block_zstd_huffman_jump_table( |(i, ((&value_byte, tag_value_acc), value_rlc))| { ZstdWitnessRow { state: ZstdState { - tag, - tag_next, - tag_len: n_bytes as u64, + tag: ZstdTag::ZstdBlockJumpTable, + tag_next: ZstdTag::Lstream, + tag_len: N_JUMP_TABLE_BYTES as u64, tag_idx: (i + 1) as u64, tag_value, tag_value_acc, @@ -1137,6 +1137,9 @@ fn process_block_zstd_huffman_jump_table( [l1, l2, l3] ) } + + + fn process_block_zstd_lstream( src: &[u8], byte_offset: usize, From 03ec04f6a6870cba4b9d1e9dd6df2b5ad61d7f0d Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 18 Jan 2024 23:26:34 -0500 Subject: [PATCH 016/165] Modify direct rep --- zkevm-circuits/src/witness/zstd/mod.rs | 320 ++++++++++++++----------- 1 file changed, 178 insertions(+), 142 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index b48a66c6b9..361a3f7b3e 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -749,6 +749,7 @@ fn process_block_zstd_huffman_header( // compression_debug // waiting on response for whether direct representation will be eliminated from zstd-compressed blocks +// this is a reserved code block // fn process_block_zstd_huffman_header( // src: &[u8], @@ -808,53 +809,41 @@ fn process_block_zstd_huffman_code_direct( // weight[0] = (Byte[0] >> 4) // weight[1] = (Byte[0] & 0xf). - let value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( - last_row.encoded_data.value_rlc, - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ) - .into_iter() - .flat_map(|v| vec![v, v]); - - let decoded_value_rlc_iter = src + let value_rlc_iter = src .iter() .skip(byte_offset) .take(n_bytes) - .into_iter() - .flat_map(|v| vec![v, v]) - .zip((0..).cycle().take(n_bytes * 2)) .scan( - last_row.decoded_data.decoded_value_rlc, - |acc, (&byte, b_flag)| { - let v = if b_flag > 0 { byte & 0xf } else { byte >> 4 }; - *acc = *acc * randomness + Value::known(F::from(v as u64)); - Some(*acc) - }, - ); + last_row.encoded_data.value_rlc, + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ) + .into_iter() + .flat_map(|v| vec![v, v]); let tag_value_iter = src .iter() .skip(byte_offset) .take(n_bytes) - .into_iter() - .flat_map(|v| vec![v, v]) - .zip((0..).cycle().take(n_bytes * 2)) .scan( - Value::known(F::zero()), - |acc, (&byte, b_flag)| { - let v = if b_flag > 0 { byte & 0xf } else { byte >> 4 }; - *acc = *acc * randomness + Value::known(F::from(v as u64)); - Some(*acc) - }, - ); + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ) + .into_iter() + .flat_map(|v| vec![v, v]); let tag_value = tag_value_iter .clone() .last() .expect("Raw bytes must be of non-zero length"); + let mut weights: Vec = vec![]; + ( byte_offset + n_bytes, src.iter() @@ -864,24 +853,25 @@ fn process_block_zstd_huffman_code_direct( .flat_map(|v| vec![v, v]) .zip(tag_value_iter) .zip(value_rlc_iter) - .zip(decoded_value_rlc_iter) .zip((0..).cycle().take(n_bytes * 2)) .enumerate() .map( - |(i, ((((&value_byte, tag_value_acc), value_rlc), decoded_value_rlc), b_flag))| { + |(i, (((&value_byte, tag_value_acc), value_rlc), b_flag))| { + weights.push(if b_flag > 0 { value_byte >> 4 } else { value_byte & 0xf }); + ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanCode, tag_next: ZstdTag::ZstdBlockSequenceHeader, - tag_len: (n_bytes * 2) as u64, - tag_idx: (i + 1) as u64, + tag_len: n_bytes as u64, + tag_idx: (i / 2) as u64, tag_value, tag_value_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + i / 2 + 1) as u64, encoded_len: last_row.encoded_data.encoded_len, - value_byte: if b_flag > 0 { value_byte >> 4 } else { value_byte & 0xf }, + value_byte: value_byte, value_rlc, reverse: false, ..Default::default() @@ -893,10 +883,14 @@ fn process_block_zstd_huffman_code_direct( }, ) .collect::>(), - HuffmanCodesData { byte_offset: 0, weights: vec![] } + HuffmanCodesData { byte_offset: byte_offset, weights: weights } ) } + + + +// compression_debug fn process_block_zstd_huffman_code_fse( src: &[u8], byte_offset: usize, @@ -1138,8 +1132,6 @@ fn process_block_zstd_huffman_jump_table( ) } - - fn process_block_zstd_lstream( src: &[u8], byte_offset: usize, @@ -1148,141 +1140,185 @@ fn process_block_zstd_lstream( randomness: Value, stream_idx: usize, huffman_code: &HuffmanCodesData, -) -> (usize, Vec>) { - let mut lstream_bits = - src - .iter() - .skip(byte_offset) - .take(len) - .rev() - .clone() - .flat_map(|v| { - let mut bits = value_bits_le(*v); - bits.reverse(); - bits - }) - .collect::>(); - - // Deliminators vector stores the positions where the bitstream is deliminated (a different value is decoded) - // The pair (usize, usize) indicates (byte_idx, bit_idx) where a delimination occurs (think of adding an underscore at the position) - // The range between two positions is where a new symbol is decoded or a new segment is recognized (i.e. leading zero section, a single sentinel 1-bit) - let mut deliminators: Vec<(usize, usize)> = vec![]; - - // Add a virtual deliminator in the front - deliminators.push((0, 0)); +) -> (usize, Vec>, Vec) { + // Obtain literal stream bits (reversed). + let mut lstream_bits = src + .iter() + .skip(byte_offset) + .take(len) + .rev() + .clone() + .flat_map(|v| { + let mut bits = value_bits_le(*v); + bits.reverse(); + bits + }) + .collect::>(); - // Bitstream processing state values - let mut current_byte_idx: usize = 1; // byte_idx is 1-indexed + // Bitstream processing state helper values + let mut witness_rows: Vec> = vec![]; + let mut current_byte_idx: usize = 1; let mut current_bit_idx: usize = 0; - // Recognize the leading zero section + // accumulators + let aux_1 = last_row.encoded_data.value_rlc; + let value_rlc_acc = src.iter().skip(byte_offset).take(len).rev().scan( + last_row.encoded_data.value_rlc, + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ).collect::>>(); + let tag_value_acc = src.iter().skip(byte_offset).take(len).rev().scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ).collect::>>(); + let tag_value = tag_value_acc.last().expect("Tag value exists"); + + // Decide the next tag + let tag_next = match stream_idx { + 0 | 1 | 2 => ZstdTag::Lstream, + 3 => ZstdTag::ZstdBlockSequenceHeader, + _ => unreachable!("stream_idx value out of range") + }; + + // Add a witness row for leading 0s + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::Lstream, + tag_next, + tag_len: len as u64, + tag_idx: current_byte_idx as u64, + tag_value: tag_value, + tag_value_acc: tag_value_acc[current_byte_idx - 1], + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + len - current_byte_idx) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: src[byte_offset + len - current_byte_idx], + value_rlc: value_rlc_acc[current_byte_idx - 1], + // reverse specific values + reverse: true, + reverse_len: len, + reverse_idx: len - (current_byte_idx - 1), + aux_1, + aux_2: tag_value + + ..Default::default() + }, + huffman_data: HuffmanData::default(), + decoded_data: last_row.decoded_data.clone(), + fse_data: FseTableRow::default(), + }); + + // Exclude the leading zero section while lstream_bits[current_bit_idx] == 0 { increment_idx(current_byte_idx, current_bit_idx); } - deliminators.push((current_byte_idx, current_bit_idx)); // indicates the end of leading zeros - // The next bit is the sentinel bit + // Add a witness row for sentinel 1-bit + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::Lstream, + tag_next, + tag_len: len as u64, + tag_idx: current_byte_idx as u64, + tag_value: tag_value, + tag_value_acc: tag_value_acc[current_byte_idx - 1], + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + len - current_byte_idx) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: src[byte_offset + len - current_byte_idx], + value_rlc: value_rlc_acc[current_byte_idx - 1], + // reverse specific values + reverse: true, + reverse_len: len, + reverse_idx: len - (current_byte_idx - 1), + aux_1, + aux_2: tag_value + + ..Default::default() + }, + huffman_data: HuffmanData::default(), + decoded_data: last_row.decoded_data.clone(), + fse_data: FseTableRow::default(), + }); + + // Exclude the sentinel 1-bit increment_idx(current_byte_idx, current_bit_idx); - deliminators.push((current_byte_idx, current_bit_idx)); // Now the actual symbol-bearing bitstream starts let huffman_bit_value_map = huffman_code.parse_canonical_bit_value_map(); + let mut decoded_symbols: Vec = vec![]; let mut bit_value_acc: u64 = 0; let mut cur_bitstring_len: usize = 0; - let mut decoded_symbols: Vec = vec![]; while current_bit_idx < len * N_BITS_PER_BYTE { if huffman_bit_value_map.1.contains_key(&bit_value_acc) { decoded_symbols.push(huffman_bit_value_map.1.get(&bit_value_acc).unwrap().clone()); - // Mark the new deliminator - for _ in 0..cur_bitstring_len { + let from_byte_idx = current_byte_idx; + let from_bit_idx = current_bit_idx; + + // advance byte and bit marks to the last bit + for _ in 0..(cur_bitstring_len - 1) { increment_idx(current_byte_idx, current_bit_idx); } - deliminators.push((current_byte_idx, current_bit_idx)); + + // Add a witness row for emitted symbol + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::Lstream, + tag_next, + tag_len: len as u64, + tag_idx: from_byte_idx as u64, + tag_value: tag_value, + tag_value_acc: tag_value_acc[from_byte_idx - 1], + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + len - from_byte_idx) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: src[byte_offset + len - from_byte_idx], + value_rlc: value_rlc_acc[from_byte_idx - 1], + // reverse specific values + reverse: true, + reverse_len: len, + reverse_idx: len - (from_byte_idx - 1), + aux_1, + aux_2: tag_value + + ..Default::default() + }, + huffman_data: HuffmanData { + byte_offset: (byte_offset + len - from_byte_idx) as u64, + bit_value: bit_value_acc, + k: (from_bit_idx, to_bit_idx), + }, + decoded_data: last_row.decoded_data.clone(), + fse_data: FseTableRow::default(), + }); + + // advance byte and bit marks again to get the start of next bitstring + increment_idx(current_byte_idx, current_bit_idx); // Reset decoding state bit_value_acc = 0; cur_bitstring_len = 0; } else { - bit_value_acc += (src[current_bit_idx + cur_bitstring_len] as u64) * 2u64.pow(cur_bitstring_len as u32); + bit_value_acc = bit_value_acc * 2 + lstream_bits[current_bit_idx + cur_bitstring_len]; cur_bitstring_len += 1; if cur_bitstring_len > huffman_bit_value_map.0 as usize { - unreachable!("read bit len greater than max bitstring len"); + panic!("Reading bit len greater than max bitstring len not allowed."); } } } - - // Now construct the witness rows - let tag_next = if stream_idx == 3 { - ZstdTag::ZstdBlockSequenceHeader - } else { - match stream_idx { - 0 | 1 | 2 => ZstdTag::Lstream, - _ => unreachable!("stream_idx value out of range") - } - }; - - // Add the leading zero and sentinel 1-bit. - if deliminators[1] == (1, 0) { - // there're no leading zeros - decoded_symbols.insert(0, 1); - } else { - decoded_symbols.insert(0, 0); - decoded_symbols.insert(1, 1); - } - - // Witness rows - let mut value_rlc = last_row.encoded_data.value_rlc; - - let tag_value_iter = decoded_symbols.iter().scan( - Value::known(F::zero()), - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(symbol as u64)); - Some(*acc) - }, - ); - - let tag_value = tag_value_iter - .clone() - .last() - .expect("Tag value exists"); - - let mut witness_rows: Vec = vec![]; - - let mut last_pos = deliminators[0]; - for (idx, curr_pos) in deliminators.into_iter().skip(1).enumerate() { - if curr_pos.0 > last_pos.0 { - value_rlc = value_rlc * randomness + Value::known(F::from) - } - - witness_rows.push(ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::Lstream, - tag_next, - tag_len: len as u64, - tag_idx: idx as u64, - tag_value: tag_value, - tag_value_acc: tag_value_iter.next(), - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + last_pos.0) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[byte_offset + last_pos.0], - value_rlc, - reverse: true, - ..Default::default() - }, - decoded_data: last_row.decoded_data.clone(), - huffman_data: HuffmanData::default(), // TODO: correct witness assignment value - fse_data: FseTableRow::default(), - }); - - last_pos = curr_pos; - } - (byte_offset + len, witness_rows) + (byte_offset + len, witness_rows.iter().rev().collect::>>(), decoded_symbols) } pub fn process(src: &[u8], randomness: Value) -> Vec> { From df9954addbbab419356387a3f4851fe728c9c27d Mon Sep 17 00:00:00 2001 From: darth-cy Date: Fri, 19 Jan 2024 00:12:36 -0500 Subject: [PATCH 017/165] correct fse witness --- zkevm-circuits/src/witness/zstd/mod.rs | 246 ++++++++++++++++--------- 1 file changed, 157 insertions(+), 89 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 361a3f7b3e..48190f2b57 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -887,9 +887,6 @@ fn process_block_zstd_huffman_code_direct( ) } - - - // compression_debug fn process_block_zstd_huffman_code_fse( src: &[u8], @@ -902,12 +899,67 @@ fn process_block_zstd_huffman_code_fse( // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; + // Get the next tag + let tag_next = if n_streams > 1 { + ZstdTag::ZstdBlockJumpTable + } else { + ZstdTag::Lstream + }; + // First, recover the FSE table for generating Huffman weights let (n_fse_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset).expect("Reconstructing FSE table should not fail."); - // Exclude the FSE table representation bytes, then we're left with a bitstream for recovering Huffman weights - let byte_offset = byte_offset + n_fse_bytes; - let n_bytes = n_bytes - n_fse_bytes; + // Get accumulators + let value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + last_row.encoded_data.value_rlc, + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + // let mut next_value_rlc = value_rlc_iter.next().unwrap(); + + let tag_value_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + // let mut next_tag_value = tag_value_iter.next().unwrap(); + + let tag_value = tag_value_iter + .clone() + .last() + .expect("Raw bytes must be of non-zero length"); + + // Witness generation + let mut witness_rows: Vec> = vec![]; + + // Add witness rows for FSE representation bytes + for (idx, byte) in src.iter().skip(byte_offset).take(n_fse_bytes).enumerate() { + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::ZstdBlockHuffmanCode, + tag_next, + tag_len: n_bytes as u64, + tag_idx: (idx + 1) as u64, + tag_value: tag_value, + tag_value_acc: tag_value_iter.next(), + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + idx + 1) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: byte.clone(), + value_rlc, + reverse: false, + ..Default::default() + }, + decoded_data: last_row.decoded_data.clone(), + huffman_data: HuffmanData::default(), + fse_data: FseTableRow::default(), // TODO: correct witness assignment + }); + } // Construct the Huffman bitstream let mut huffman_bitstream = @@ -924,27 +976,74 @@ fn process_block_zstd_huffman_code_fse( }) .collect::>(); - // Deliminators vector stores the positions where the bitstream is deliminated (a different value is decoded) - // The pair (usize, usize) indicates (byte_idx, bit_idx) where a delimination occurs (think of adding an underscore at the position) - // The range between two positions is where a new symbol is decoded or a new segment is recognized (i.e. leading zero section, a single sentinel 1-bit) - let mut deliminators: Vec<(usize, usize)> = vec![]; - - // Add a virtual deliminator in the front - deliminators.push((0, 0)); - // Bitstream processing state values + let mut last_byte_idx: usize = 1; let mut current_byte_idx: usize = 1; // byte_idx is 1-indexed let mut current_bit_idx: usize = 0; - // Recognize the leading zero section - while huffman_bitstream[current_bit_idx] == 0 { + let mut next_tag_value_acc = tag_value_iter.next(); + let mut next_value_rlc_acc = value_rlc_iter.next(); + + // Add a witness row for leading 0s + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::ZstdBlockHuffmanCode, + tag_next, + tag_len: n_bytes as u64, + tag_idx: ((n_fse_bytes - 1) + current_byte_idx) as u64, + tag_value: tag_value, + tag_value_acc: next_tag_value_acc, + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + (n_fse_bytes - 1) + current_byte_idx) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: src[(byte_offset + (n_fse_bytes - 1) + current_byte_idx)], + value_rlc: next_value_rlc_acc, + reverse: false, + ..Default::default() + }, + huffman_data: HuffmanData::default(), + decoded_data: last_row.decoded_data.clone(), + fse_data: FseTableRow::default(), + }); + + // Exclude the leading zero section + while lstream_bits[current_bit_idx] == 0 { increment_idx(current_byte_idx, current_bit_idx); } - deliminators.push((current_byte_idx, current_bit_idx)); // indicates the end of leading zeros + if current_byte_idx > last_byte_idx { + next_tag_value_acc = tag_value_iter.next(); + next_value_rlc_acc = value_rlc_iter.next(); + } - // The next bit is the sentinel bit + // Add a witness row for sentinel 1-bit + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::ZstdBlockHuffmanCode, + tag_next, + tag_len: n_bytes as u64, + tag_idx: ((n_fse_bytes - 1) + current_byte_idx) as u64, + tag_value: tag_value, + tag_value_acc: next_tag_value_acc, + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + (n_fse_bytes - 1) + current_byte_idx) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: src[(byte_offset + (n_fse_bytes - 1) + current_byte_idx)], + value_rlc: next_value_rlc_acc, + reverse: false, + ..Default::default() + }, + huffman_data: HuffmanData::default(), + decoded_data: last_row.decoded_data.clone(), + fse_data: FseTableRow::default(), + }); + // Exclude the sentinel 1-bit increment_idx(current_byte_idx, current_bit_idx); - deliminators.push((current_byte_idx, current_bit_idx)); + if current_byte_idx > last_byte_idx { + next_tag_value_acc = tag_value_iter.next(); + next_value_rlc_acc = value_rlc_iter.next(); + } // Now the actual weight-bearing bitstream starts // The Huffman bitstream is decoded by two interleaved states reading the stream in alternating order. @@ -953,6 +1052,7 @@ fn process_block_zstd_huffman_code_fse( let mut prev_baseline: [u64; 2] = [0, 0]; let mut next_nb_to_read: [usize; 2] = [table.accuracy_log as usize, table.accuracy_log as usize]; let mut decoded_weights: Vec = vec![]; + let mut fse_table_idx: u64 = 1; // Convert FSE auxiliary data into a state-indexed representation let fse_state_table = table.parse_state_table(); @@ -967,90 +1067,58 @@ fn process_block_zstd_huffman_code_fse( // Decode the symbol decoded_weights.push(fse_row.0 as u8); - // Preparing for next state - prev_baseline[color] = fse_row.1; - next_nb_to_read[color] = fse_row.2 as usize; - - for _ in 0..nb { - increment_idx(current_byte_idx, current_bit_idx); - deliminators.push((current_byte_idx, current_bit_idx)); - } - - color = !color; - } - - // Construct HuffmanCodesTable - let huffman_codes = HuffmanCodesData { - byte_offset: huffman_code_byte_offset as u64, - weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() - }; - - // Now construct the witness rows - let tag_next = if n_streams > 1 { - ZstdTag::ZstdBlockJumpTable - } else { - ZstdTag::Lstream - }; - - // Add the leading zero and sentinel 1-bit. - if deliminators[1] == (1, 0) { - // there're no leading zeros - decoded_symbols.insert(0, 1); - } else { - decoded_symbols.insert(0, 0); - decoded_symbols.insert(1, 1); - } - - // Witness rows - let mut value_rlc = last_row.encoded_data.value_rlc; - - let tag_value_iter = decoded_symbols.iter().scan( - Value::known(F::zero()), - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(symbol as u64)); - Some(*acc) - }, - ); - - let tag_value = tag_value_iter - .clone() - .last() - .expect("Tag value exists"); - - let mut witness_rows: Vec = vec![]; - - let mut last_pos = deliminators[0]; - for (idx, curr_pos) in deliminators.into_iter().skip(1).enumerate() { - if curr_pos.0 > last_pos.0 { - value_rlc = value_rlc * randomness + Value::known(F::from) - } - + // Add a witness row witness_rows.push(ZstdWitnessRow { state: ZstdState { - tag: ZstdTag::Lstream, + tag: ZstdTag::ZstdBlockHuffmanCode, tag_next, - tag_len: len as u64, - tag_idx: idx as u64, + tag_len: n_bytes as u64, + tag_idx: ((n_fse_bytes - 1) + current_byte_idx) as u64, tag_value: tag_value, - tag_value_acc: tag_value_iter.next(), + tag_value_acc: next_tag_value_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + last_pos.0) as u64, + byte_idx: (byte_offset + (n_fse_bytes - 1) + current_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[byte_offset + last_pos.0], - value_rlc, - reverse: true, + value_byte: src[(byte_offset + (n_fse_bytes - 1) + current_byte_idx)], + value_rlc: next_value_rlc_acc, + reverse: false, ..Default::default() }, - decoded_data: last_row.decoded_data.clone(), + fse_data: FseTableRow { + idx: fse_table_idx, + state: next_state as u64, + symbol: fse_row.0, + baseline: fse_row.1, + num_bits: fse_row.2, + }, huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), // TODO: correct witness assignment + decoded_data: last_row.decoded_data.clone(), }); - last_pos = curr_pos; + // Advance byte and bit marks. Get next acc value if byte changes + for _ in 0..nb { + increment_idx(current_byte_idx, current_bit_idx); + } + if current_byte_idx > last_byte_idx { + next_tag_value_acc = tag_value_iter.next(); + next_value_rlc_acc = value_rlc_iter.next(); + } + + // Preparing for next state + prev_baseline[color] = fse_row.1; + next_nb_to_read[color] = fse_row.2 as usize; + + color = !color; } - (byte_offset + n_bytes, witness_rows) + // Construct HuffmanCodesTable + let huffman_codes = HuffmanCodesData { + byte_offset: huffman_code_byte_offset as u64, + weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() + }; + + (byte_offset + n_bytes, witness_rows, huffman_codes) } fn process_block_zstd_huffman_jump_table( From b765b89b370ab80d4b3d985f1b5b6ad8a7490e40 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Fri, 19 Jan 2024 00:25:40 -0500 Subject: [PATCH 018/165] adjust test --- zkevm-circuits/src/witness/zstd/mod.rs | 58 +++++++++----------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 48190f2b57..0ba66be360 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1451,48 +1451,28 @@ mod tests { Ok(()) } - // This test is for dev process and will be deleted #[test] - fn check_witness_generation() -> Result<(), std::io::Error> { - let compressed: [u8; 559] = [ - 0x28, 0xb5, 0x2f, 0xfd, 0x64, 0xae, 0x02, 0x0d, 0x11, 0x00, 0x76, 0x62, 0x5e, 0x23, 0x30, 0x6f, - 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, - 0xa9, 0xd4, 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, - 0x01, 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, - 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, - 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, - 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, - 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, - 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, 0x5a, 0xdf, 0xb4, 0x21, 0x9a, 0xcb, 0x8f, 0xc7, - 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, 0x28, 0x0e, 0xfb, 0x8b, - 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, 0xeb, 0x81, 0xf1, 0x78, 0x4b, 0xad, - 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, 0xb4, 0xd9, 0xe1, 0x95, 0x21, 0x66, 0x0c, - 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, 0x22, 0x07, 0x0b, 0x91, 0x86, 0x94, 0x1a, 0x7b, - 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, 0x65, 0xd6, 0x34, 0x63, 0x0c, 0x88, 0x9b, 0x1c, 0x48, - 0xca, 0x2b, 0x34, 0xa9, 0x6b, 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, - 0x69, 0x18, 0x57, 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, - 0x7b, 0x6e, 0xd8, 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, 0x14, - 0xf4, 0x40, 0xe7, 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, 0x49, 0xae, 0x13, - 0xa4, 0x75, 0x38, 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, 0x86, 0xa4, 0xac, 0xaa, 0xa3, - 0x34, 0x89, 0xca, 0x2e, 0xe9, 0xc1, 0xfe, 0xf2, 0x51, 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, - 0xed, 0xd9, 0xb7, 0x4a, 0xb2, 0xb2, 0x61, 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, - 0xdc, 0x60, 0x6c, 0x41, 0x76, 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, - 0xac, 0x9d, 0xe0, 0x62, 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, - 0xd2, 0x7c, 0x0a, 0x7c, 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, 0xda, - 0x15, 0x91, 0xde, 0x21, 0xf5, 0x55, 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, 0x42, 0x44, 0x81, - 0x8c, 0x94, 0xb4, 0x50, 0x1e, 0x20, 0x42, 0x82, 0x98, 0xc2, 0x3b, 0x10, 0x48, 0xec, 0xa6, 0x39, - 0x63, 0x13, 0xa7, 0x01, 0x94, 0x40, 0xff, 0x88, 0x0f, 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, - 0xcb, 0xf6, 0xc8, 0x21, 0x59, 0xaa, 0x38, 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, - 0xc8, 0x03, 0x42, 0x2a, 0x4b, 0xf6, 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, - 0x7e, 0x00, 0xbc, 0x2f, 0x46, 0x96, 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, - 0x8c, 0xc2, 0x05, 0xf7, 0x54, 0x51, 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, 0x99, - 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, 0x50, 0x84, 0xf5, - 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, 0x4c, 0x52, 0x4f, 0x20, 0xa3, 0x61, 0x23, 0x77, 0x12, 0xd3, - 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, 0x70, 0xec, 0x14, 0x91, 0xf9, 0x85, 0x61, 0xd5, 0x7e, 0x98, - 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, + fn interleaved_huffman_code_fse() -> Result<(), std::io::Error> { + let input: [u8; 35] = [ + 0x30, 0x6f, 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, + 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, + 0x54, 0x5d, 0xa9, 0xd4, 0x93, 0xef, 0xc4, 0x54, + 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, + 0x40, 0x29, 0x01, ]; - let _witness_rows = process::(compressed.as_raw_slice(), Value::known(Fr::from(123456789))); + let (byte_offset, witness_rows, huffman_codes) = + process_block_zstd_huffman_code_fse( + &input, + 0, + &ZstdWitnessRow::init(0), + Value::from(F::from_hex(0xff)), + 35, + 4 + ); + + log::trace!("=> huffman_codes: {:?}", huffman_codes); + Ok(()) } From eea6aaa1a5dcc097b2ecbd1fede623f818f5de4e Mon Sep 17 00:00:00 2001 From: darth-cy Date: Fri, 19 Jan 2024 01:30:18 -0500 Subject: [PATCH 019/165] Verify FSE interleaved decoding --- zkevm-circuits/src/witness/zstd/mod.rs | 137 +++++++++++++---------- zkevm-circuits/src/witness/zstd/types.rs | 48 ++++---- zkevm-circuits/src/witness/zstd/util.rs | 12 +- 3 files changed, 108 insertions(+), 89 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 0ba66be360..c1471baf37 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -4,7 +4,7 @@ use eth_types::Field; use halo2_proofs::circuit::Value; mod params; -use num::Integer; +use num::{Integer, traits::Euclid}; pub use params::*; mod types; @@ -565,7 +565,7 @@ fn process_block_zstd( } for idx in 0..n_streams { - let (byte_offset, rows) = process_block_zstd_lstream( + let (byte_offset, rows, symbols) = process_block_zstd_lstream( src, stream_offset, n_bytes, @@ -704,8 +704,6 @@ fn process_block_zstd_huffman_header( let value_rlc = last_row.encoded_data.value_rlc * randomness + Value::known(F::from(header_byte as u64)); - let decoded_value_rlc = - last_row.decoded_data.decoded_value_rlc + randomness + Value::known(F::from(header_byte as u64)); let tag_value = Value::known(F::from(header_byte as u64)); let n_bytes = if header_byte < 128 { @@ -842,7 +840,7 @@ fn process_block_zstd_huffman_code_direct( .last() .expect("Raw bytes must be of non-zero length"); - let mut weights: Vec = vec![]; + let mut weights: Vec = vec![]; ( byte_offset + n_bytes, @@ -857,7 +855,7 @@ fn process_block_zstd_huffman_code_direct( .enumerate() .map( |(i, (((&value_byte, tag_value_acc), value_rlc), b_flag))| { - weights.push(if b_flag > 0 { value_byte >> 4 } else { value_byte & 0xf }); + weights.push(FseSymbol::from((if b_flag > 0 { value_byte >> 4 } else { value_byte & 0xf }) as usize)); ZstdWitnessRow { state: ZstdState { @@ -883,11 +881,10 @@ fn process_block_zstd_huffman_code_direct( }, ) .collect::>(), - HuffmanCodesData { byte_offset: byte_offset, weights: weights } + HuffmanCodesData { byte_offset: byte_offset as u64, weights: weights } ) } -// compression_debug fn process_block_zstd_huffman_code_fse( src: &[u8], byte_offset: usize, @@ -910,23 +907,21 @@ fn process_block_zstd_huffman_code_fse( let (n_fse_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset).expect("Reconstructing FSE table should not fail."); // Get accumulators - let value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + let mut value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( last_row.encoded_data.value_rlc, |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }, ); - // let mut next_value_rlc = value_rlc_iter.next().unwrap(); - let tag_value_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + let mut tag_value_iter = src.iter().skip(byte_offset).take(n_bytes).scan( Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }, ); - // let mut next_tag_value = tag_value_iter.next().unwrap(); let tag_value = tag_value_iter .clone() @@ -945,24 +940,24 @@ fn process_block_zstd_huffman_code_fse( tag_len: n_bytes as u64, tag_idx: (idx + 1) as u64, tag_value: tag_value, - tag_value_acc: tag_value_iter.next(), + tag_value_acc: tag_value_iter.next().expect("Next value should exist"), }, encoded_data: EncodedData { byte_idx: (byte_offset + idx + 1) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: byte.clone(), - value_rlc, + value_rlc: value_rlc_iter.next().expect("Next value should exist"), reverse: false, ..Default::default() }, decoded_data: last_row.decoded_data.clone(), huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), // TODO: correct witness assignment + fse_data: FseTableRow::default(), }); } // Construct the Huffman bitstream - let mut huffman_bitstream = + let huffman_bitstream = src .iter() .skip(byte_offset) @@ -981,8 +976,8 @@ fn process_block_zstd_huffman_code_fse( let mut current_byte_idx: usize = 1; // byte_idx is 1-indexed let mut current_bit_idx: usize = 0; - let mut next_tag_value_acc = tag_value_iter.next(); - let mut next_value_rlc_acc = value_rlc_iter.next(); + let mut next_tag_value_acc = tag_value_iter.next().unwrap(); + let mut next_value_rlc_acc = value_rlc_iter.next().unwrap(); // Add a witness row for leading 0s witness_rows.push(ZstdWitnessRow { @@ -997,7 +992,7 @@ fn process_block_zstd_huffman_code_fse( encoded_data: EncodedData { byte_idx: (byte_offset + (n_fse_bytes - 1) + current_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[(byte_offset + (n_fse_bytes - 1) + current_byte_idx)], + value_byte: src[byte_offset + (n_fse_bytes - 1) + current_byte_idx], value_rlc: next_value_rlc_acc, reverse: false, ..Default::default() @@ -1008,12 +1003,13 @@ fn process_block_zstd_huffman_code_fse( }); // Exclude the leading zero section - while lstream_bits[current_bit_idx] == 0 { - increment_idx(current_byte_idx, current_bit_idx); + while huffman_bitstream[current_bit_idx] == 0 { + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); } if current_byte_idx > last_byte_idx { - next_tag_value_acc = tag_value_iter.next(); - next_value_rlc_acc = value_rlc_iter.next(); + next_tag_value_acc = tag_value_iter.next().unwrap(); + next_value_rlc_acc = value_rlc_iter.next().unwrap(); + last_byte_idx = current_byte_idx; } // Add a witness row for sentinel 1-bit @@ -1029,7 +1025,7 @@ fn process_block_zstd_huffman_code_fse( encoded_data: EncodedData { byte_idx: (byte_offset + (n_fse_bytes - 1) + current_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[(byte_offset + (n_fse_bytes - 1) + current_byte_idx)], + value_byte: src[byte_offset + (n_fse_bytes - 1) + current_byte_idx], value_rlc: next_value_rlc_acc, reverse: false, ..Default::default() @@ -1039,10 +1035,11 @@ fn process_block_zstd_huffman_code_fse( fse_data: FseTableRow::default(), }); // Exclude the sentinel 1-bit - increment_idx(current_byte_idx, current_bit_idx); + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); if current_byte_idx > last_byte_idx { - next_tag_value_acc = tag_value_iter.next(); - next_value_rlc_acc = value_rlc_iter.next(); + next_tag_value_acc = tag_value_iter.next().unwrap(); + next_value_rlc_acc = value_rlc_iter.next().unwrap(); + last_byte_idx = current_byte_idx; } // Now the actual weight-bearing bitstream starts @@ -1057,7 +1054,7 @@ fn process_block_zstd_huffman_code_fse( // Convert FSE auxiliary data into a state-indexed representation let fse_state_table = table.parse_state_table(); - while current_bit_idx + next_nb_to_read[color] < n_bytes * N_BITS_PER_BYTE { + while current_bit_idx + next_nb_to_read[color] <= (n_bytes - n_fse_bytes) * N_BITS_PER_BYTE { let nb = next_nb_to_read[color]; let next_state = prev_baseline[color] + le_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); @@ -1080,7 +1077,7 @@ fn process_block_zstd_huffman_code_fse( encoded_data: EncodedData { byte_idx: (byte_offset + (n_fse_bytes - 1) + current_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[(byte_offset + (n_fse_bytes - 1) + current_byte_idx)], + value_byte: src[byte_offset + (n_fse_bytes - 1) + current_byte_idx], value_rlc: next_value_rlc_acc, reverse: false, ..Default::default() @@ -1096,20 +1093,24 @@ fn process_block_zstd_huffman_code_fse( decoded_data: last_row.decoded_data.clone(), }); + // increment fse idx + fse_table_idx += 1; + // Advance byte and bit marks. Get next acc value if byte changes for _ in 0..nb { - increment_idx(current_byte_idx, current_bit_idx); + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); } - if current_byte_idx > last_byte_idx { - next_tag_value_acc = tag_value_iter.next(); - next_value_rlc_acc = value_rlc_iter.next(); + if current_byte_idx > last_byte_idx && current_byte_idx < n_bytes { + next_tag_value_acc = tag_value_iter.next().unwrap_or_default(); + next_value_rlc_acc = value_rlc_iter.next().unwrap_or_default(); + last_byte_idx = current_byte_idx; } // Preparing for next state prev_baseline[color] = fse_row.1; next_nb_to_read[color] = fse_row.2 as usize; - color = !color; + color = if color > 0 { 0 } else { 1 }; } // Construct HuffmanCodesTable @@ -1210,7 +1211,7 @@ fn process_block_zstd_lstream( huffman_code: &HuffmanCodesData, ) -> (usize, Vec>, Vec) { // Obtain literal stream bits (reversed). - let mut lstream_bits = src + let lstream_bits = src .iter() .skip(byte_offset) .take(len) @@ -1260,7 +1261,7 @@ fn process_block_zstd_lstream( tag_next, tag_len: len as u64, tag_idx: current_byte_idx as u64, - tag_value: tag_value, + tag_value: *tag_value, tag_value_acc: tag_value_acc[current_byte_idx - 1], }, encoded_data: EncodedData { @@ -1270,11 +1271,10 @@ fn process_block_zstd_lstream( value_rlc: value_rlc_acc[current_byte_idx - 1], // reverse specific values reverse: true, - reverse_len: len, - reverse_idx: len - (current_byte_idx - 1), + reverse_len: len as u64, + reverse_idx: (len - (current_byte_idx - 1)) as u64, aux_1, - aux_2: tag_value - + aux_2: *tag_value, ..Default::default() }, huffman_data: HuffmanData::default(), @@ -1284,7 +1284,7 @@ fn process_block_zstd_lstream( // Exclude the leading zero section while lstream_bits[current_bit_idx] == 0 { - increment_idx(current_byte_idx, current_bit_idx); + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); } // Add a witness row for sentinel 1-bit @@ -1294,7 +1294,7 @@ fn process_block_zstd_lstream( tag_next, tag_len: len as u64, tag_idx: current_byte_idx as u64, - tag_value: tag_value, + tag_value: *tag_value, tag_value_acc: tag_value_acc[current_byte_idx - 1], }, encoded_data: EncodedData { @@ -1304,11 +1304,10 @@ fn process_block_zstd_lstream( value_rlc: value_rlc_acc[current_byte_idx - 1], // reverse specific values reverse: true, - reverse_len: len, - reverse_idx: len - (current_byte_idx - 1), + reverse_len: len as u64, + reverse_idx: (len - (current_byte_idx - 1)) as u64, aux_1, - aux_2: tag_value - + aux_2: *tag_value, ..Default::default() }, huffman_data: HuffmanData::default(), @@ -1344,7 +1343,7 @@ fn process_block_zstd_lstream( tag_next, tag_len: len as u64, tag_idx: from_byte_idx as u64, - tag_value: tag_value, + tag_value: *tag_value, tag_value_acc: tag_value_acc[from_byte_idx - 1], }, encoded_data: EncodedData { @@ -1354,17 +1353,16 @@ fn process_block_zstd_lstream( value_rlc: value_rlc_acc[from_byte_idx - 1], // reverse specific values reverse: true, - reverse_len: len, - reverse_idx: len - (from_byte_idx - 1), + reverse_len: len as u64, + reverse_idx: (len - (from_byte_idx - 1)) as u64, aux_1, - aux_2: tag_value - + aux_2: *tag_value, ..Default::default() }, huffman_data: HuffmanData { byte_offset: (byte_offset + len - from_byte_idx) as u64, - bit_value: bit_value_acc, - k: (from_bit_idx, to_bit_idx), + bit_value: bit_value_acc as u8, + k: (from_bit_idx.rem_euclid(8) as u8, current_bit_idx.rem_euclid(8) as u8), }, decoded_data: last_row.decoded_data.clone(), fse_data: FseTableRow::default(), @@ -1377,7 +1375,7 @@ fn process_block_zstd_lstream( bit_value_acc = 0; cur_bitstring_len = 0; } else { - bit_value_acc = bit_value_acc * 2 + lstream_bits[current_bit_idx + cur_bitstring_len]; + bit_value_acc = bit_value_acc * 2 + lstream_bits[current_bit_idx + cur_bitstring_len] as u64; cur_bitstring_len += 1; if cur_bitstring_len > huffman_bit_value_map.0 as usize { @@ -1386,7 +1384,7 @@ fn process_block_zstd_lstream( } } - (byte_offset + len, witness_rows.iter().rev().collect::>>(), decoded_symbols) + (byte_offset + len, witness_rows.into_iter().rev().collect::>>(), decoded_symbols) } pub fn process(src: &[u8], randomness: Value) -> Vec> { @@ -1451,8 +1449,12 @@ mod tests { Ok(()) } + // Verify correct interleaved decoding of FSE-coded Huffman Weights + // Example link: https://nigeltao.github.io/blog/2022/zstandard-part-5-fse.html #[test] fn interleaved_huffman_code_fse() -> Result<(), std::io::Error> { + // Input includes FSE table representation (normalized symbol frequencies) and the actual Huffman bitstream + // For structure reference: https://nigeltao.github.io/blog/2022/zstandard-part-2-structure.html let input: [u8; 35] = [ 0x30, 0x6f, 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, @@ -1461,18 +1463,35 @@ mod tests { 0x40, 0x29, 0x01, ]; - let (byte_offset, witness_rows, huffman_codes) = - process_block_zstd_huffman_code_fse( + let (_byte_offset, _witness_rows, huffman_codes) = + process_block_zstd_huffman_code_fse::( &input, 0, &ZstdWitnessRow::init(0), - Value::from(F::from_hex(0xff)), + Value::known(Fr::from(123456789)), 35, 4 ); - log::trace!("=> huffman_codes: {:?}", huffman_codes); + let expected_weights: Vec = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 2, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, 1, 1, 1, 2, + 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, + 0, 5, 3, 3, 3, 6, 3, 2, 4, 4, 0, 1, 4, 4, 5, 5, + 2, 0, 4, 4, 5, 3, 1, 3, 1, 3, + ] + .into_iter() + .map(|w| FseSymbol::from(w) ) + .collect::>(); + assert_eq!( + huffman_codes.weights, + expected_weights, + "Huffman weights should be correctly decoded with interleaved states" + ); Ok(()) } diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 71c6341d75..bf7f92bf22 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -520,35 +520,33 @@ mod tests { // sure FSE reconstruction ignores them. let src = vec![0xff, 0xff, 0xff, 0x30, 0x6f, 0x9b, 0x03, 0xff, 0xff, 0xff]; - // compression_debug - // let (n_bytes, table) = FseAuxiliaryTableData::reconstruct(1, 1, &src, 3)?; + let (n_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, 3)?; // TODO: assert equality for the entire table. // for now only comparing state/baseline/nb for S1, i.e. weight == 1. - // compression_debug - // assert_eq!(n_bytes, 4); - // assert_eq!( - // table.sym_to_states.get(&FseSymbol::S1).cloned().unwrap(), - // [ - // (0x03, 0x10, 3), - // (0x0c, 0x18, 3), - // (0x11, 0x00, 2), - // (0x15, 0x04, 2), - // (0x1a, 0x08, 2), - // (0x1e, 0x0c, 2), - // ] - // .iter() - // .enumerate() - // .map(|(i, &(state, baseline, num_bits))| FseTableRow { - // idx: (i + 1) as u64, - // state, - // symbol: 1, - // baseline, - // num_bits, - // }) - // .collect::>(), - // ); + assert_eq!(n_bytes, 4); + assert_eq!( + table.sym_to_states.get(&FseSymbol::S1).cloned().unwrap(), + [ + (0x03, 0x10, 3), + (0x0c, 0x18, 3), + (0x11, 0x00, 2), + (0x15, 0x04, 2), + (0x1a, 0x08, 2), + (0x1e, 0x0c, 2), + ] + .iter() + .enumerate() + .map(|(i, &(state, baseline, num_bits))| FseTableRow { + idx: (i + 1) as u64, + state, + symbol: 1, + baseline, + num_bits, + }) + .collect::>(), + ); Ok(()) } diff --git a/zkevm-circuits/src/witness/zstd/util.rs b/zkevm-circuits/src/witness/zstd/util.rs index 1986072731..80aa0523d2 100644 --- a/zkevm-circuits/src/witness/zstd/util.rs +++ b/zkevm-circuits/src/witness/zstd/util.rs @@ -117,23 +117,25 @@ pub fn value_bits_le(value_byte: u8) -> [u8; N_BITS_PER_BYTE] { .expect("expected N_BITS_PER_BYTE elements") } -// compression_debug pub fn le_bits_to_value(bits: &[u8]) -> u64 { assert!(bits.len() <= 32); - bits.into_iter().enumerate().fold(0, |mut acc, (p, b)| { - acc += (2u64).pow(p as u32) * (*b as u64); + bits.into_iter().fold(0, |mut acc, b| { + acc = acc * 2 + *b as u64; acc }) } // helper utility for helping manage bitstream delimitation -pub fn increment_idx(mut current_byte_idx: usize, mut current_bit_idx: usize) -> () { - current_bit_idx += 1; +pub fn increment_idx(current_byte_idx: usize, current_bit_idx: usize) -> (usize, usize) { + let current_bit_idx = current_bit_idx + 1; + let mut current_byte_idx = current_byte_idx; if current_bit_idx > current_byte_idx * N_BITS_PER_BYTE { current_byte_idx += 1; } + + (current_byte_idx, current_bit_idx) } #[cfg(test)] From 8913d6888c82c1107487c4a107586ca1257e0a17 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Fri, 19 Jan 2024 14:30:32 -0500 Subject: [PATCH 020/165] tag fix --- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index c1471baf37..3cd508986d 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -722,7 +722,7 @@ fn process_block_zstd_huffman_header( vec![ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanHeader, - tag_next: ZstdTag::ZstdBlockFseCode, + tag_next: ZstdTag::ZstdBlockHuffmanCode, tag_len: 1 as u64, tag_idx: 1 as u64, tag_value, From 469592f6162c51577e223793cf2dd2be35b308e2 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 21 Jan 2024 21:03:00 -0500 Subject: [PATCH 021/165] Remove accuracy log from auxiliary table --- zkevm-circuits/src/witness/zstd/mod.rs | 19 ++++++++++--------- zkevm-circuits/src/witness/zstd/types.rs | 3 --- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 3cd508986d..fa21409265 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -637,7 +637,7 @@ fn process_block_zstd_literals_header( let tag_next = match literals_block_type { BlockType::RawBlock => ZstdTag::ZstdBlockLiteralsRawBytes, BlockType::RleBlock => ZstdTag::ZstdBlockLiteralsRleBytes, - BlockType::ZstdCompressedBlock => ZstdTag::ZstdBlockHuffmanHeader, + BlockType::ZstdCompressedBlock => ZstdTag::ZstdBlockHuffmanCode, _ => unreachable!("BlockType::Reserved unexpected or treeless literal section"), }; @@ -721,7 +721,7 @@ fn process_block_zstd_huffman_header( byte_offset + 1, vec![ZstdWitnessRow { state: ZstdState { - tag: ZstdTag::ZstdBlockHuffmanHeader, + tag: ZstdTag::ZstdBlockHuffmanCode, tag_next: ZstdTag::ZstdBlockHuffmanCode, tag_len: 1 as u64, tag_idx: 1 as u64, @@ -900,7 +900,7 @@ fn process_block_zstd_huffman_code_fse( let tag_next = if n_streams > 1 { ZstdTag::ZstdBlockJumpTable } else { - ZstdTag::Lstream + ZstdTag::ZstdBlockLstream }; // First, recover the FSE table for generating Huffman weights @@ -930,6 +930,7 @@ fn process_block_zstd_huffman_code_fse( // Witness generation let mut witness_rows: Vec> = vec![]; + let accuracy_log = (src[byte_offset] & 0b1111) + 5; // Add witness rows for FSE representation bytes for (idx, byte) in src.iter().skip(byte_offset).take(n_fse_bytes).enumerate() { @@ -1047,7 +1048,7 @@ fn process_block_zstd_huffman_code_fse( // The FSE table for the two independent decoding strands are the same. let mut color: usize = 0; // use 0, 1 (colors) to denote two alternating decoding strands. let mut prev_baseline: [u64; 2] = [0, 0]; - let mut next_nb_to_read: [usize; 2] = [table.accuracy_log as usize, table.accuracy_log as usize]; + let mut next_nb_to_read: [usize; 2] = [accuracy_log as usize, accuracy_log as usize]; let mut decoded_weights: Vec = vec![]; let mut fse_table_idx: u64 = 1; @@ -1176,7 +1177,7 @@ fn process_block_zstd_huffman_jump_table( ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockJumpTable, - tag_next: ZstdTag::Lstream, + tag_next: ZstdTag::ZstdBlockLstream, tag_len: N_JUMP_TABLE_BYTES as u64, tag_idx: (i + 1) as u64, tag_value, @@ -1249,7 +1250,7 @@ fn process_block_zstd_lstream( // Decide the next tag let tag_next = match stream_idx { - 0 | 1 | 2 => ZstdTag::Lstream, + 0 | 1 | 2 => ZstdTag::ZstdBlockLstream, 3 => ZstdTag::ZstdBlockSequenceHeader, _ => unreachable!("stream_idx value out of range") }; @@ -1257,7 +1258,7 @@ fn process_block_zstd_lstream( // Add a witness row for leading 0s witness_rows.push(ZstdWitnessRow { state: ZstdState { - tag: ZstdTag::Lstream, + tag: ZstdTag::ZstdBlockLstream, tag_next, tag_len: len as u64, tag_idx: current_byte_idx as u64, @@ -1290,7 +1291,7 @@ fn process_block_zstd_lstream( // Add a witness row for sentinel 1-bit witness_rows.push(ZstdWitnessRow { state: ZstdState { - tag: ZstdTag::Lstream, + tag: ZstdTag::ZstdBlockLstream, tag_next, tag_len: len as u64, tag_idx: current_byte_idx as u64, @@ -1339,7 +1340,7 @@ fn process_block_zstd_lstream( // Add a witness row for emitted symbol witness_rows.push(ZstdWitnessRow { state: ZstdState { - tag: ZstdTag::Lstream, + tag: ZstdTag::ZstdBlockLstream, tag_next, tag_len: len as u64, tag_idx: from_byte_idx as u64, diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index eb0011e4b5..00f9d682f9 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -391,8 +391,6 @@ pub struct FseTableData { pub struct FseAuxiliaryTableData { /// The byte offset in the frame at which the FSE table is described. pub byte_offset: u64, - /// The FSE table's AL (accuracy log) - pub accuracy_log: u8, /// The FSE table's size, i.e. 1 << AL (accuracy log). pub table_size: u64, /// A map from FseSymbol (weight) to states, also including fields for that state, for @@ -505,7 +503,6 @@ impl FseAuxiliaryTableData { t, Self { byte_offset: byte_offset as u64, - accuracy_log, table_size, sym_to_states, }, From 64d90cad7a9814b805fd82114698d909342b0b2e Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 21 Jan 2024 22:54:59 -0500 Subject: [PATCH 022/165] Consolidate huffman weights subroutine into one tag --- zkevm-circuits/src/witness/zstd/mod.rs | 400 ++++++++++--------------- 1 file changed, 166 insertions(+), 234 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index fa21409265..f9fe4f4bc2 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1,14 +1,11 @@ -use bitstream_io::huffman; -use bus_mapping::circuit_input_builder::Block; use eth_types::Field; use halo2_proofs::circuit::Value; mod params; -use num::{Integer, traits::Euclid}; +use num::Integer; pub use params::*; mod types; -use serde::de::value; pub use types::*; #[cfg(test)] @@ -524,51 +521,41 @@ fn process_block_zstd( BlockType::ZstdCompressedBlock => { let mut huffman_rows = vec![]; - let (bytes_offset, rows, is_direct, n_bytes) = process_block_zstd_huffman_header( + let (bytes_offset, rows, huffman_codes, n_huffman_bytes) = process_block_zstd_huffman_code( src, byte_offset, - rows.last().expect("last row expected to exist"), + rows.last().expect("last row must exist"), randomness, + n_streams, ); huffman_rows.extend_from_slice(&rows); - let (bytes_offset, rows, huffman_codes) = if is_direct { - process_block_zstd_huffman_code_direct( - src, - byte_offset, - &huffman_rows[0], - randomness, - n_bytes, - ) - } else { - process_block_zstd_huffman_code_fse( - src, - byte_offset, - &huffman_rows[0], - randomness, - n_bytes, - n_streams, - ) - }; - huffman_rows.extend_from_slice(&rows); + // Subtract huffman header (1-byte), len of huffman bytes and 6-byte jump table (if n_streams > 1) + let mut literal_stream_size = compressed_size - (n_huffman_bytes + 1); + if n_streams > 1 { + literal_stream_size -= 6; + } + // Start decoding the literal section let mut stream_offset = byte_offset; - if n_streams > 1 { - let (byte_offset, rows, lstream_lens) = process_block_zstd_huffman_jump_table( - src, - stream_offset, - huffman_rows.last().expect("last row should exist"), - randomness - ); - huffman_rows.extend_from_slice(&rows); - } + + let (byte_offset, rows, lstream_lens) = process_block_zstd_huffman_jump_table( + src, + stream_offset, + huffman_rows.last().expect("last row should exist"), + n_streams, + literal_stream_size, + randomness + ); + huffman_rows.extend_from_slice(&rows); + for idx in 0..n_streams { let (byte_offset, rows, symbols) = process_block_zstd_lstream( src, stream_offset, - n_bytes, + lstream_lens[idx] as usize, huffman_rows.last().expect("last row should exist"), randomness, idx, @@ -694,108 +681,6 @@ fn process_block_zstd_literals_header( ) } -fn process_block_zstd_huffman_header( - src: &[u8], - byte_offset: usize, - last_row: &ZstdWitnessRow, - randomness: Value, -) -> (usize, Vec>, bool, usize) { - let header_byte = src[byte_offset]; - - let value_rlc = - last_row.encoded_data.value_rlc * randomness + Value::known(F::from(header_byte as u64)); - let tag_value = Value::known(F::from(header_byte as u64)); - - let n_bytes = if header_byte < 128 { - header_byte - } else { - let n_sym = header_byte - 127; - if n_sym.is_odd() { - (n_sym + 1) / 2 - } else { - n_sym / 2 - } - }; - - ( - byte_offset + 1, - vec![ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::ZstdBlockHuffmanCode, - tag_next: ZstdTag::ZstdBlockHuffmanCode, - tag_len: 1 as u64, - tag_idx: 1 as u64, - tag_value, - tag_value_acc: tag_value, - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + 1) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte: header_byte, - reverse: false, - value_rlc, - ..Default::default() - }, - decoded_data: last_row.decoded_data.clone(), - huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), - }], - header_byte >= 127, - n_bytes as usize, - ) -} - -// compression_debug -// waiting on response for whether direct representation will be eliminated from zstd-compressed blocks -// this is a reserved code block - -// fn process_block_zstd_huffman_header( -// src: &[u8], -// byte_offset: usize, -// last_row: &ZstdWitnessRow, -// randomness: Value, -// ) -> (usize, Vec>) { -// // A single byte (header_byte) is read. -// // - if header_byte < 128: canonical weights are represented by FSE table. -// // - if header_byte >= 128: canonical weights are given by direct representation. - -// let header_byte = src -// .get(byte_offset) -// .expect("ZBHuffmanHeader byte should exist"); - -// assert!( -// *header_byte < 128, -// "we expect canonical huffman weights to be encoded using FSE" -// ); - -// let value_rlc = -// last_row.encoded_data.value_rlc * randomness + Value::known(F::from(*header_byte as u64)); - -// ( -// byte_offset + 1, -// vec![ZstdWitnessRow { -// state: ZstdState { -// tag: ZstdTag::ZstdBlockHuffmanHeader, -// tag_next: ZstdTag::ZstdBlockFseCode, -// tag_len: 1, -// tag_idx: 1, -// tag_value: Value::known(F::from(*header_byte as u64)), -// tag_value_acc: Value::known(F::from(*header_byte as u64)), -// }, -// encoded_data: EncodedData { -// byte_idx: (byte_offset + 1) as u64, -// encoded_len: last_row.encoded_data.encoded_len, -// value_byte: *header_byte, -// value_rlc, -// ..Default::default() -// }, -// decoded_data: last_row.decoded_data.clone(), -// fse_data: FseTableRow::default(), -// huffman_data: HuffmanData::default(), -// }], -// ) -// } - fn process_block_zstd_huffman_code_direct( src: &[u8], byte_offset: usize, @@ -885,14 +770,13 @@ fn process_block_zstd_huffman_code_direct( ) } -fn process_block_zstd_huffman_code_fse( +fn process_block_zstd_huffman_code( src: &[u8], byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, - n_bytes: usize, n_streams: usize, -) -> (usize, Vec>, HuffmanCodesData) { +) -> (usize, Vec>, HuffmanCodesData, usize) { // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; @@ -903,11 +787,28 @@ fn process_block_zstd_huffman_code_fse( ZstdTag::ZstdBlockLstream }; - // First, recover the FSE table for generating Huffman weights - let (n_fse_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset).expect("Reconstructing FSE table should not fail."); + // Parse the header byte + let mut witness_rows: Vec> = vec![]; + let header_byte = src[byte_offset]; + + let n_bytes = if header_byte < 128 { + header_byte as usize + } else { + let n_sym: usize = header_byte as usize - 127; + if n_sym.is_odd() { + (n_sym + 1) / 2 + } else { + n_sym / 2 + } + }; + + // TODO: Awaiting design decision + // Currently the FSE decoding is assumed. Direct representation is a reserve possibility + // The code for decoding direct representation is above. + assert!(header_byte < 128, "FSE encoded huffman weights assumed"); // Get accumulators - let mut value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + let mut value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes + 1).scan( last_row.encoded_data.value_rlc, |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); @@ -915,7 +816,7 @@ fn process_block_zstd_huffman_code_fse( }, ); - let mut tag_value_iter = src.iter().skip(byte_offset).take(n_bytes).scan( + let mut tag_value_iter = src.iter().skip(byte_offset).take(n_bytes + 1).scan( Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); @@ -928,8 +829,34 @@ fn process_block_zstd_huffman_code_fse( .last() .expect("Raw bytes must be of non-zero length"); + // Add a witness row for Huffman header + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::ZstdBlockHuffmanCode, + tag_next, + tag_len: (n_bytes + 1) as u64, // include the 1 byte from huffman header + tag_idx: 1 as u64, + tag_value: tag_value, + tag_value_acc: tag_value_iter.next().expect("Next value should exist"), + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + 1) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: header_byte.clone(), + value_rlc: value_rlc_iter.next().expect("Next value should exist"), + reverse: false, + ..Default::default() + }, + decoded_data: last_row.decoded_data.clone(), + huffman_data: HuffmanData::default(), + fse_data: FseTableRow::default(), + }); + + // Recover the FSE table for generating Huffman weights + let byte_offset = byte_offset + 1; + let (n_fse_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset).expect("Reconstructing FSE table should not fail."); + // Witness generation - let mut witness_rows: Vec> = vec![]; let accuracy_log = (src[byte_offset] & 0b1111) + 5; // Add witness rows for FSE representation bytes @@ -938,13 +865,13 @@ fn process_block_zstd_huffman_code_fse( state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanCode, tag_next, - tag_len: n_bytes as u64, - tag_idx: (idx + 1) as u64, + tag_len: (n_bytes + 1) as u64, + tag_idx: (idx + 2) as u64, // count the huffman header byte tag_value: tag_value, tag_value_acc: tag_value_iter.next().expect("Next value should exist"), }, encoded_data: EncodedData { - byte_idx: (byte_offset + idx + 1) as u64, + byte_idx: (byte_offset + idx + 2) as u64, // count the huffman header byte encoded_len: last_row.encoded_data.encoded_len, value_byte: byte.clone(), value_rlc: value_rlc_iter.next().expect("Next value should exist"), @@ -985,8 +912,8 @@ fn process_block_zstd_huffman_code_fse( state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanCode, tag_next, - tag_len: n_bytes as u64, - tag_idx: ((n_fse_bytes - 1) + current_byte_idx) as u64, + tag_len: (n_bytes + 1) as u64, // count huffman header byte + tag_idx: ((n_fse_bytes - 1) + current_byte_idx + 1) as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, }, @@ -1018,8 +945,8 @@ fn process_block_zstd_huffman_code_fse( state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanCode, tag_next, - tag_len: n_bytes as u64, - tag_idx: ((n_fse_bytes - 1) + current_byte_idx) as u64, + tag_len: (n_bytes + 1) as u64, + tag_idx: ((n_fse_bytes - 1) + current_byte_idx + 1) as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, }, @@ -1070,8 +997,8 @@ fn process_block_zstd_huffman_code_fse( state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanCode, tag_next, - tag_len: n_bytes as u64, - tag_idx: ((n_fse_bytes - 1) + current_byte_idx) as u64, + tag_len: (n_bytes + 1) as u64, + tag_idx: ((n_fse_bytes - 1) + current_byte_idx + 1) as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, }, @@ -1120,86 +1047,93 @@ fn process_block_zstd_huffman_code_fse( weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() }; - (byte_offset + n_bytes, witness_rows, huffman_codes) + (byte_offset + n_bytes, witness_rows, huffman_codes, n_bytes) } fn process_block_zstd_huffman_jump_table( src: &[u8], byte_offset: usize, last_row: &ZstdWitnessRow, + literal_stream_size: usize, + n_streams: usize, randomness: Value, -) -> (usize, Vec>, [u64; 3]) { - // Note: The decompressed size of each stream is equal to (regen_size + 3) / 4 - // but the compressed bitstream length will be different. - // Jump table provides information on the length of first 3 bitstreams. - - let jt_bytes = src - .iter() - .skip(byte_offset) - .take(N_JUMP_TABLE_BYTES) - .cloned() - .map(|x| x as u64) - .collect::>(); - - let l1: u64 = jt_bytes[0] + jt_bytes[1] * 256; - let l2: u64 = jt_bytes[2] + jt_bytes[3] * 256; - let l3: u64 = jt_bytes[4] + jt_bytes[5] * 256; - - let value_rlc_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( - last_row.encoded_data.value_rlc, - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ); - let tag_value_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( - Value::known(F::zero()), - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ); - let tag_value = tag_value_iter - .clone() - .last() - .expect("Tag value must exist."); +) -> (usize, Vec>, Vec) { + if n_streams <= 1 { + (byte_offset, vec![], vec![literal_stream_size as u64]) + } else { + // Note: The decompressed size of each stream is equal to (regen_size + 3) / 4 + // but the compressed bitstream length will be different. + // Jump table provides information on the length of first 3 bitstreams. - ( - byte_offset + N_JUMP_TABLE_BYTES, - src.iter() + let jt_bytes = src + .iter() .skip(byte_offset) .take(N_JUMP_TABLE_BYTES) - .zip(tag_value_iter) - .zip(value_rlc_iter) - .enumerate() - .map( - |(i, ((&value_byte, tag_value_acc), value_rlc))| { - ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::ZstdBlockJumpTable, - tag_next: ZstdTag::ZstdBlockLstream, - tag_len: N_JUMP_TABLE_BYTES as u64, - tag_idx: (i + 1) as u64, - tag_value, - tag_value_acc, - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + i + 1) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte, - value_rlc, - reverse: false, - ..Default::default() - }, - decoded_data: last_row.decoded_data.clone(), - huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), - } - }, - ) - .collect::>(), - [l1, l2, l3] - ) + .cloned() + .map(|x| x as u64) + .collect::>(); + + let l1: u64 = jt_bytes[0] + jt_bytes[1] * 256; + let l2: u64 = jt_bytes[2] + jt_bytes[3] * 256; + let l3: u64 = jt_bytes[4] + jt_bytes[5] * 256; + let l4: u64 = (literal_stream_size as u64) - l1 - l2 - l3; + + let value_rlc_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( + last_row.encoded_data.value_rlc, + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_value_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_value = tag_value_iter + .clone() + .last() + .expect("Tag value must exist."); + + ( + byte_offset + N_JUMP_TABLE_BYTES, + src.iter() + .skip(byte_offset) + .take(N_JUMP_TABLE_BYTES) + .zip(tag_value_iter) + .zip(value_rlc_iter) + .enumerate() + .map( + |(i, ((&value_byte, tag_value_acc), value_rlc))| { + ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::ZstdBlockJumpTable, + tag_next: ZstdTag::ZstdBlockLstream, + tag_len: N_JUMP_TABLE_BYTES as u64, + tag_idx: (i + 1) as u64, + tag_value, + tag_value_acc, + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + i + 1) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte, + value_rlc, + reverse: false, + ..Default::default() + }, + decoded_data: last_row.decoded_data.clone(), + huffman_data: HuffmanData::default(), + fse_data: FseTableRow::default(), + } + }, + ) + .collect::>(), + vec![l1, l2, l3, l4] + ) + } } fn process_block_zstd_lstream( @@ -1424,7 +1358,6 @@ pub fn process(src: &[u8], randomness: Value) -> Vec Result<(), std::io::Error> { // Input includes FSE table representation (normalized symbol frequencies) and the actual Huffman bitstream // For structure reference: https://nigeltao.github.io/blog/2022/zstandard-part-2-structure.html - let input: [u8; 35] = [ - 0x30, 0x6f, 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, - 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, - 0x54, 0x5d, 0xa9, 0xd4, 0x93, 0xef, 0xc4, 0x54, - 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, - 0x40, 0x29, 0x01, + let input: [u8; 36] = [ + 0x23, 0x30, 0x6f, 0x9b, 0x03, 0x7d, 0xc7, 0x16, + 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, + 0xbc, 0x54, 0x5d, 0xa9, 0xd4, 0x93, 0xef, 0xc4, + 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, + 0x54, 0x40, 0x29, 0x01, ]; - let (_byte_offset, _witness_rows, huffman_codes) = - process_block_zstd_huffman_code_fse::( + let (_byte_offset, _witness_rows, huffman_codes, _n_huffan_bytes) = + process_block_zstd_huffman_code::( &input, 0, &ZstdWitnessRow::init(0), Value::known(Fr::from(123456789)), - 35, 4 ); From 21fdaccfdfe73492e80c62b60aa99abcac7800a7 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 21 Jan 2024 23:16:38 -0500 Subject: [PATCH 023/165] correct size format parsing --- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index f9fe4f4bc2..20044ace1d 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -589,7 +589,7 @@ fn process_block_zstd_literals_header( .collect::>(); let literals_block_type = BlockType::from(lh_bytes[0] & 0x3); - let size_format = lh_bytes[0] & 3; + let size_format = (lh_bytes[0] >> 2) & 3; let [n_bits_fmt, n_bits_regen, n_bits_compressed, n_streams, n_bytes_header]: [usize; 5] = match literals_block_type { BlockType::RawBlock | BlockType::RleBlock => { From 6256155c6ec2157f491e76d5341e213c31809f0a Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 22 Jan 2024 16:05:56 -0500 Subject: [PATCH 024/165] add huffman code routine for recovering bitstring --- zkevm-circuits/src/witness/zstd/mod.rs | 219 +++++++++++++++++------ zkevm-circuits/src/witness/zstd/types.rs | 103 +++++++++-- 2 files changed, 248 insertions(+), 74 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 20044ace1d..f93a60ceaa 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1254,70 +1254,79 @@ fn process_block_zstd_lstream( increment_idx(current_byte_idx, current_bit_idx); // Now the actual symbol-bearing bitstream starts - let huffman_bit_value_map = huffman_code.parse_canonical_bit_value_map(); + let huffman_bitstring_map = huffman_code.parse_bitstring_map(); let mut decoded_symbols: Vec = vec![]; let mut bit_value_acc: u64 = 0; let mut cur_bitstring_len: usize = 0; - while current_bit_idx < len * N_BITS_PER_BYTE { - if huffman_bit_value_map.1.contains_key(&bit_value_acc) { - decoded_symbols.push(huffman_bit_value_map.1.get(&bit_value_acc).unwrap().clone()); - - let from_byte_idx = current_byte_idx; - let from_bit_idx = current_bit_idx; + // compression_debug + // log::trace!("=> huffman_bit_value_map: {:?}", huffman_bit_value_map); - // advance byte and bit marks to the last bit - for _ in 0..(cur_bitstring_len - 1) { - increment_idx(current_byte_idx, current_bit_idx); - } + // compression_debug + // while current_bit_idx < len * N_BITS_PER_BYTE { + // // compression_debug + // log::trace!("=> bit_value_acc: {:?}", bit_value_acc); + // log::trace!("=> cur_bitstring_len: {:?}", cur_bitstring_len); - // Add a witness row for emitted symbol - witness_rows.push(ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::ZstdBlockLstream, - tag_next, - tag_len: len as u64, - tag_idx: from_byte_idx as u64, - tag_value: *tag_value, - tag_value_acc: tag_value_acc[from_byte_idx - 1], - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + len - from_byte_idx) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[byte_offset + len - from_byte_idx], - value_rlc: value_rlc_acc[from_byte_idx - 1], - // reverse specific values - reverse: true, - reverse_len: len as u64, - reverse_idx: (len - (from_byte_idx - 1)) as u64, - aux_1, - aux_2: *tag_value, - ..Default::default() - }, - huffman_data: HuffmanData { - byte_offset: (byte_offset + len - from_byte_idx) as u64, - bit_value: bit_value_acc as u8, - k: (from_bit_idx.rem_euclid(8) as u8, current_bit_idx.rem_euclid(8) as u8), - }, - decoded_data: last_row.decoded_data.clone(), - fse_data: FseTableRow::default(), - }); - - // advance byte and bit marks again to get the start of next bitstring - increment_idx(current_byte_idx, current_bit_idx); - - // Reset decoding state - bit_value_acc = 0; - cur_bitstring_len = 0; - } else { - bit_value_acc = bit_value_acc * 2 + lstream_bits[current_bit_idx + cur_bitstring_len] as u64; - cur_bitstring_len += 1; - if cur_bitstring_len > huffman_bit_value_map.0 as usize { - panic!("Reading bit len greater than max bitstring len not allowed."); - } - } - } + // if huffman_bit_value_map.1.contains_key(&bit_value_acc) { + // decoded_symbols.push(huffman_bit_value_map.1.get(&bit_value_acc).unwrap().clone()); + + // let from_byte_idx = current_byte_idx; + // let from_bit_idx = current_bit_idx; + + // // advance byte and bit marks to the last bit + // for _ in 0..(cur_bitstring_len - 1) { + // increment_idx(current_byte_idx, current_bit_idx); + // } + + // // Add a witness row for emitted symbol + // witness_rows.push(ZstdWitnessRow { + // state: ZstdState { + // tag: ZstdTag::ZstdBlockLstream, + // tag_next, + // tag_len: len as u64, + // tag_idx: from_byte_idx as u64, + // tag_value: *tag_value, + // tag_value_acc: tag_value_acc[from_byte_idx - 1], + // }, + // encoded_data: EncodedData { + // byte_idx: (byte_offset + len - from_byte_idx) as u64, + // encoded_len: last_row.encoded_data.encoded_len, + // value_byte: src[byte_offset + len - from_byte_idx], + // value_rlc: value_rlc_acc[from_byte_idx - 1], + // // reverse specific values + // reverse: true, + // reverse_len: len as u64, + // reverse_idx: (len - (from_byte_idx - 1)) as u64, + // aux_1, + // aux_2: *tag_value, + // ..Default::default() + // }, + // huffman_data: HuffmanData { + // byte_offset: (byte_offset + len - from_byte_idx) as u64, + // bit_value: bit_value_acc as u8, + // k: (from_bit_idx.rem_euclid(8) as u8, current_bit_idx.rem_euclid(8) as u8), + // }, + // decoded_data: last_row.decoded_data.clone(), + // fse_data: FseTableRow::default(), + // }); + + // // advance byte and bit marks again to get the start of next bitstring + // increment_idx(current_byte_idx, current_bit_idx); + + // // Reset decoding state + // bit_value_acc = 0; + // cur_bitstring_len = 0; + // } else { + // bit_value_acc = bit_value_acc * 2 + lstream_bits[current_bit_idx + cur_bitstring_len] as u64; + // cur_bitstring_len += 1; + + // if cur_bitstring_len > huffman_bit_value_map.0 as usize { + // panic!("Reading bit len greater than max bitstring len not allowed."); + // } + // } + // } (byte_offset + len, witness_rows.into_iter().rev().collect::>>(), decoded_symbols) } @@ -1428,4 +1437,100 @@ mod tests { Ok(()) } + + + + // Verify correct decoding of literal bitstream using a HuffmanCode table + // Example link: https://nigeltao.github.io/blog/2022/zstandard-part-4-huffman.html + #[test] + fn decode_literal_bitstream() -> Result<(), std::io::Error> { + let huffman_codes = HuffmanCodesData { + byte_offset: 0, + weights: vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 2, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, 1, 1, 1, 2, + 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, + 0, 5, 3, 3, 3, 6, 3, 2, 4, 4, 0, 1, 4, 4, 5, 5, + 2, 0, 4, 4, 5, 3, 1, 3, 1, 3, + ] + .into_iter() + .map(|w| FseSymbol::from(w) ) + .collect::>() + }; + + let lstream1: [u8; 85] = [ + 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, + 0xfc, 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, + 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, + 0x71, 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, + 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, + 0xd0, 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, + 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, + 0x94, 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, + 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, + 0xc6, 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, + 0x24, 0x5a, 0xdf, 0xb4, 0x21, + // 0x9a, + ]; + + let (_byte_offset, _witness_rows, decoded_symbols) = process_block_zstd_lstream::( + &lstream1, + 0, + 85, + &ZstdWitnessRow::init(0), + Value::known(Fr::from(123456789)), + 1, + &huffman_codes + ); + + let ascii_symbols: String = decoded_symbols.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); + + + log::trace!("=> decoded: {:?}", decoded_symbols); + log::trace!("=> ascii: {:?}", ascii_symbols); + + + // 00000000 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 76 62 5e 23 30 6f |++++++++++[L]H[-| + // 00000010 9b 03 7d c7 16 0b be c8 f2 d0 22 4b 6b bc 54 5d |- HUFFMAN CODE -| + // 00000020 a9 d4 93 ef c4 54 96 b2 e2 a8 a8 24 1c 54 40 29 |----------------| + // 00000030 01 55 00 57 00 51 00 *cc 51 73 3a 85 9e f7 59 fc |][JUMP][--------| + // 00000040 c5 ca 6a 7a d9 82 9c 65 c5 45 92 e3 0d f3 ef 71 |----------------| + // 00000050 ee dc d5 a2 e3 48 ad a3 bc 41 7a 3c aa d6 eb d0 | LSTREAM 1 DATA | + // 00000060 77 ea dc 5d 41 06 50 1c 49 0f 07 10 05 88 84 94 |----------------| + // 00000070 02 fc 3c e3 60 25 c0 cb 0c b8 a9 73 bc 13 77 c6 |----------------| + // 00000080 e2 20 ed 17 7b 12 dc 24 5a df b4 21 9a* cb 8f c7 |-----------][---| + // 00000090 58 54 11 a9 f1 47 82 9b ba 60 b4 92 28 0e fb 8b |----------------| + // 000000a0 1e 92 23 6a cf bf e5 45 b5 7e eb 81 f1 78 4b ad |----------------| + // 000000b0 17 4d 81 9f bc 67 a7 56 ee b4 d9 e1 95 21 66 0c | LSTREAM 2 DATA | + // 000000c0 95 83 27 de ac 37 20 91 22 07 0b 91 86 94 1a 7b |----------------| + // 000000d0 f6 4c b0 c0 e8 2e 49 65 d6 34 63 0c 88 9b 1c 48 |----------------| + // 000000e0 ca 2b 34 a9 6b 99 3b ee 13 3b 7c 93 0b f7 0d 49 |--][------------| + // 000000f0 69 18 57 be 3b 64 45 1d 92 63 7f e8 f9 a1 19 7b |----------------| + // 00000100 7b 6e d8 a3 90 23 82 f4 a7 ce c8 f8 90 15 b3 14 | LSTREAM 3 DATA | + // 00000110 f4 40 e7 02 78 d3 17 71 23 b1 19 ad 6b 49 ae 13 |----------------| + // 00000120 a4 75 38 51 47 89 67 b0 39 b4 53 86 a4 ac aa a3 |----------------| + // 00000130 34 89 ca 2e e9 c1 fe f2 51 c6 51 73 aa f7 9d 2d |---][-----------| + // 00000140 ed d9 b7 4a b2 b2 61 e4 ef 98 f7 c5 ef 51 9b d8 |----------------| + // 00000150 dc 60 6c 41 76 af 78 1a 62 b5 4c 1e 21 39 9a 5f | LSTREAM 4 DATA | + // 00000160 ac 9d e0 62 e8 e9 2f 2f 48 02 8d 53 c8 91 f2 1a |----------------| + // 00000170 d2 7c 0a 7c 48 bf da a9 e3 38 da 34 ce 76 a9 da |----------------| + // 00000180 15 91 de 21 f5 55 46 a8 21 9d 51 cc 18 42 44 81 |-----]SS[-- LLT | + // 00000190 8c 94 b4 50 1e 20 42 82 98 c2 3b 10 48 ec a6 39 |----][CMOT][MLT]| + // 000001a0 63 13 a7 01 94 40 ff 88 0f 98 07 4a 46 38 05 a9 |[---------------| + // 000001b0 cb f6 c8 21 59 aa 38 45 bf 5c f8 55 9e 9f 04 ed |----------------| + // 000001c0 c8 03 42 2a 4b f6 78 7e 23 67 15 a2 79 29 f4 9b |----------------| + // 000001d0 7e 00 bc 2f 46 96 99 ea f1 ee 1c 6e 06 9c db e4 |----------------| + // 000001e0 8c c2 05 f7 54 51 84 c0 33 02 01 b1 8c 80 dc 99 | SEQUENCES DATA | + // 000001f0 8f cb 46 ff d1 25 b5 b6 3a f3 25 be 85 50 84 f5 |----------------| + // 00000200 86 5a 71 f7 bd a1 4c 52 4f 20 a3 61 23 77 12 d3 |----------------| + // 00000210 b1 58 75 22 01 12 70 ec 14 91 f9 85 61 d5 7e 98 |----------------| + // 00000220 84 c9 76 84 bc b8 fe 4e 53 a5 06 ++ ++ ++ ++ |----------]++++| + + Ok(()) + } + + } diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 00f9d682f9..03e85422e2 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -1,10 +1,14 @@ -use std::{collections::BTreeMap, io::Cursor}; +use std::{ + collections::{BTreeMap, BinaryHeap, HashMap}, + io::Cursor +}; use bitstream_io::{BitRead, BitReader, LittleEndian}; use eth_types::Field; use gadgets::impl_expr; use halo2_proofs::{circuit::Value, plonk::Expression}; use itertools::Itertools; +use num::Float; use strum_macros::EnumIter; use super::{ @@ -286,8 +290,10 @@ pub struct HuffmanCodesData { /// Denotes the tuple (max_bitstring_len, Map). type ParsedCanonicalHuffmanCode = (u64, BTreeMap); -/// A representation indexed by bit_value as key for easier lookup during decoding. (max_bitstring_len, Map) -type ParsedCanonicalHuffmanCodeBitValueMap = (u64, BTreeMap); +/// A representation indexed by bitstring (String) as key for decoding symbols specifically. +/// Huffman code decoding ensures prefix code, thus the explicit articulation of bitstring is necessary. +type ParsedCanonicalHuffmanCodeBitstringMap = HashMap; + impl HuffmanCodesData { /// Reconstruct the bitstrings for each symbol based on the canonical Huffman code weights. The @@ -344,19 +350,35 @@ impl HuffmanCodesData { (max_bitstring_len, sym_to_tuple) } - /// Construct a representation indexed by bit_value as key for easier lookup during decoding. - pub fn parse_canonical_bit_value_map(&self) -> ParsedCanonicalHuffmanCodeBitValueMap { - let mut bit_value_mapping: (u64, BTreeMap) = (0, BTreeMap::new()); - - let parsed_huffman_code = self.parse_canonical(); - - bit_value_mapping.0 = parsed_huffman_code.0; - bit_value_mapping.1 = parsed_huffman_code.1.into_iter().fold(BTreeMap::new(), |mut acc, (symbol, (_weight, bit_value))| { - acc.insert(bit_value, symbol); - acc - }); - - bit_value_mapping + /// parse bit string map + pub fn parse_bitstring_map(&self) -> ParsedCanonicalHuffmanCodeBitstringMap { + let mut weights: Vec = self.weights.iter().map(|w| w.clone() as usize).collect(); + let sum_weights: usize = weights.iter().filter_map(|&w| if w > 0 { Some(1 << (w - 1)) } else { None }).sum(); + + // let sum_weights: usize = weights.iter().filter(|&&w| w != 0).map(|&w| 1 << (w - 1)).sum(); + let nearest_pow_2: usize = 1 << (sum_weights - 1).next_power_of_two().trailing_zeros(); + weights.push(f64::log2((nearest_pow_2 - sum_weights) as f64).ceil() as usize + 1); + let max_number_of_bits = nearest_pow_2.trailing_zeros() as usize; + let n = weights.len(); + + let bitstring_length: Vec = weights.iter().map(|&w| if w != 0 { max_number_of_bits - w + 1} else { 0 }).collect(); + + let mut bitstring_map = HashMap::new(); + let mut cur_bit_value = 0; + + for bit_len in (1..=max_number_of_bits).rev() { + cur_bit_value += 1; + cur_bit_value >>= 1; + + for sym in 0..n { + if bitstring_length[sym] == bit_len { + bitstring_map.insert(format!("{:0width$b}", cur_bit_value, width = bit_len), sym as u64); + cur_bit_value += 1; + } + } + } + + bitstring_map } } @@ -547,6 +569,8 @@ impl ZstdWitnessRow { } } + + #[cfg(test)] mod tests { use super::*; @@ -590,4 +614,49 @@ mod tests { Ok(()) } -} + + #[test] + fn test_huffman_bitstring_reconstruction() -> std::io::Result<()> { + let weights = vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 2, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, 1, 1, 1, 2, + 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, + 0, 5, 3, 3, 3, 6, 3, 2, 4, 4, 0, 1, 4, 4, 5, 5, + 2, 0, 4, 4, 5, 3, 1, 3, 1, 3, + ] + .into_iter() + .map(|w| FseSymbol::from(w) ) + .collect::>(); + + let huffman_codes_data = HuffmanCodesData { + byte_offset: 0, + weights, + }; + + let bitstring_map = huffman_codes_data.parse_bitstring_map(); + + let expected_bitstrings: [(&str, u64); 53] = [ + ("01001", 10), ("110", 32), ("00000000", 33), ("0001100", 39), ("001010", 44), + ("0001101", 46), ("00000001", 50), ("00000010", 58), ("0001110", 59), ("0001111", 63), + ("00000011", 65), ("00000100", 66), ("00000101", 67), ("00000110", 68), ("00000111", 69), + ("00001000", 72), ("0010000", 73), ("00001001", 74), ("00001010", 76), ("00001011", 77), + ("00001100", 78), ("0010001", 79), ("00001101", 82), ("00001110", 83), ("00001111", 84), + ("00010000", 85), ("00010001", 87), ("00010010", 91), ("00010011", 93), ("1000", 97), + ("001011", 98), ("001100", 99), ("001101", 100), ("111", 101), ("001110", 102), + ("0010010", 103), ("01010", 104), ("01011", 105), ("00010100", 107), ("01100", 108), + ("01101", 109), ("1001", 110), ("1010", 111), ("0010011", 112), ("01110", 114), + ("01111", 115), ("1011", 116), ("001111", 117), ("00010101", 118), ("010000", 119), + ("00010110", 120), ("010001", 121), ("00010111", 122), + ]; + + assert_eq!(expected_bitstrings.len(), bitstring_map.len(), "# of bitstring is the same"); + for pair in expected_bitstrings { + assert_eq!(*bitstring_map.get(pair.0).unwrap(), pair.1, "bitstring mapping is correct"); + } + + Ok(()) + } +} \ No newline at end of file From 4df78c312ed3f8b17882ce0b6fa2df1d5ab2c075 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 22 Jan 2024 16:07:20 -0500 Subject: [PATCH 025/165] remove imports --- zkevm-circuits/src/witness/zstd/types.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 03e85422e2..5eee243c79 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -1,5 +1,5 @@ use std::{ - collections::{BTreeMap, BinaryHeap, HashMap}, + collections::{BTreeMap, HashMap}, io::Cursor }; @@ -8,7 +8,6 @@ use eth_types::Field; use gadgets::impl_expr; use halo2_proofs::{circuit::Value, plonk::Expression}; use itertools::Itertools; -use num::Float; use strum_macros::EnumIter; use super::{ From 4b1e7a211d41c66a72730b17ddfe6ae4976265c4 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 22 Jan 2024 17:46:58 -0500 Subject: [PATCH 026/165] Add bitstream decoding test --- zkevm-circuits/src/witness/zstd/mod.rs | 183 +++++++++-------------- zkevm-circuits/src/witness/zstd/types.rs | 10 +- 2 files changed, 74 insertions(+), 119 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index f93a60ceaa..677032eccf 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1251,82 +1251,78 @@ fn process_block_zstd_lstream( }); // Exclude the sentinel 1-bit - increment_idx(current_byte_idx, current_bit_idx); + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); // Now the actual symbol-bearing bitstream starts - let huffman_bitstring_map = huffman_code.parse_bitstring_map(); + let (max_bitstring_len, huffman_bitstring_map) = huffman_code.parse_bitstring_map(); let mut decoded_symbols: Vec = vec![]; - let mut bit_value_acc: u64 = 0; + let mut bitstring_acc: String = String::from(""); let mut cur_bitstring_len: usize = 0; - // compression_debug - // log::trace!("=> huffman_bit_value_map: {:?}", huffman_bit_value_map); + while current_bit_idx < len * N_BITS_PER_BYTE { + if huffman_bitstring_map.contains_key(bitstring_acc.as_str()) { + let sym = huffman_bitstring_map.get(bitstring_acc.as_str()).unwrap().clone(); + decoded_symbols.push(sym); + + let from_byte_idx = current_byte_idx; + let from_bit_idx = current_bit_idx; - // compression_debug - // while current_bit_idx < len * N_BITS_PER_BYTE { - // // compression_debug - // log::trace!("=> bit_value_acc: {:?}", bit_value_acc); - // log::trace!("=> cur_bitstring_len: {:?}", cur_bitstring_len); + // advance byte and bit marks to the last bit + for _ in 0..(cur_bitstring_len - 1) { + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); + } + // Add a witness row for emitted symbol + witness_rows.push(ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::ZstdBlockLstream, + tag_next, + tag_len: len as u64, + tag_idx: from_byte_idx as u64, + tag_value: *tag_value, + tag_value_acc: tag_value_acc[from_byte_idx - 1], + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + len - from_byte_idx) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte: src[byte_offset + len - from_byte_idx], + value_rlc: value_rlc_acc[from_byte_idx - 1], + // reverse specific values + reverse: true, + reverse_len: len as u64, + reverse_idx: (len - (from_byte_idx - 1)) as u64, + aux_1, + aux_2: *tag_value, + ..Default::default() + }, + huffman_data: HuffmanData { + byte_offset: (byte_offset + len - from_byte_idx) as u64, + bit_value: u8::from_str_radix(bitstring_acc.as_str(), 2).unwrap(), + k: (from_bit_idx.rem_euclid(8) as u8, current_bit_idx.rem_euclid(8) as u8), + }, + decoded_data: last_row.decoded_data.clone(), + fse_data: FseTableRow::default(), + }); - // if huffman_bit_value_map.1.contains_key(&bit_value_acc) { - // decoded_symbols.push(huffman_bit_value_map.1.get(&bit_value_acc).unwrap().clone()); - - // let from_byte_idx = current_byte_idx; - // let from_bit_idx = current_bit_idx; - - // // advance byte and bit marks to the last bit - // for _ in 0..(cur_bitstring_len - 1) { - // increment_idx(current_byte_idx, current_bit_idx); - // } - - // // Add a witness row for emitted symbol - // witness_rows.push(ZstdWitnessRow { - // state: ZstdState { - // tag: ZstdTag::ZstdBlockLstream, - // tag_next, - // tag_len: len as u64, - // tag_idx: from_byte_idx as u64, - // tag_value: *tag_value, - // tag_value_acc: tag_value_acc[from_byte_idx - 1], - // }, - // encoded_data: EncodedData { - // byte_idx: (byte_offset + len - from_byte_idx) as u64, - // encoded_len: last_row.encoded_data.encoded_len, - // value_byte: src[byte_offset + len - from_byte_idx], - // value_rlc: value_rlc_acc[from_byte_idx - 1], - // // reverse specific values - // reverse: true, - // reverse_len: len as u64, - // reverse_idx: (len - (from_byte_idx - 1)) as u64, - // aux_1, - // aux_2: *tag_value, - // ..Default::default() - // }, - // huffman_data: HuffmanData { - // byte_offset: (byte_offset + len - from_byte_idx) as u64, - // bit_value: bit_value_acc as u8, - // k: (from_bit_idx.rem_euclid(8) as u8, current_bit_idx.rem_euclid(8) as u8), - // }, - // decoded_data: last_row.decoded_data.clone(), - // fse_data: FseTableRow::default(), - // }); - - // // advance byte and bit marks again to get the start of next bitstring - // increment_idx(current_byte_idx, current_bit_idx); - - // // Reset decoding state - // bit_value_acc = 0; - // cur_bitstring_len = 0; - // } else { - // bit_value_acc = bit_value_acc * 2 + lstream_bits[current_bit_idx + cur_bitstring_len] as u64; - // cur_bitstring_len += 1; - - // if cur_bitstring_len > huffman_bit_value_map.0 as usize { - // panic!("Reading bit len greater than max bitstring len not allowed."); - // } - // } - // } + // advance byte and bit marks again to get the start of next bitstring + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); + + // Reset decoding state + bitstring_acc = String::from(""); + cur_bitstring_len = 0; + } else { + if lstream_bits[current_bit_idx + cur_bitstring_len] > 0 { + bitstring_acc.push_str("1"); + } else { + bitstring_acc.push_str("0"); + } + cur_bitstring_len += 1; + + if cur_bitstring_len > max_bitstring_len as usize { + panic!("Reading bit len greater than max bitstring len not allowed."); + } + } + } (byte_offset + len, witness_rows.into_iter().rev().collect::>>(), decoded_symbols) } @@ -1438,8 +1434,6 @@ mod tests { Ok(()) } - - // Verify correct decoding of literal bitstream using a HuffmanCode table // Example link: https://nigeltao.github.io/blog/2022/zstandard-part-4-huffman.html #[test] @@ -1472,8 +1466,7 @@ mod tests { 0x94, 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, - 0x24, 0x5a, 0xdf, 0xb4, 0x21, - // 0x9a, + 0x24, 0x5a, 0xdf, 0xb4, 0x21, ]; let (_byte_offset, _witness_rows, decoded_symbols) = process_block_zstd_lstream::( @@ -1487,50 +1480,10 @@ mod tests { ); let ascii_symbols: String = decoded_symbols.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); - - - log::trace!("=> decoded: {:?}", decoded_symbols); - log::trace!("=> ascii: {:?}", ascii_symbols); - - - // 00000000 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 76 62 5e 23 30 6f |++++++++++[L]H[-| - // 00000010 9b 03 7d c7 16 0b be c8 f2 d0 22 4b 6b bc 54 5d |- HUFFMAN CODE -| - // 00000020 a9 d4 93 ef c4 54 96 b2 e2 a8 a8 24 1c 54 40 29 |----------------| - // 00000030 01 55 00 57 00 51 00 *cc 51 73 3a 85 9e f7 59 fc |][JUMP][--------| - // 00000040 c5 ca 6a 7a d9 82 9c 65 c5 45 92 e3 0d f3 ef 71 |----------------| - // 00000050 ee dc d5 a2 e3 48 ad a3 bc 41 7a 3c aa d6 eb d0 | LSTREAM 1 DATA | - // 00000060 77 ea dc 5d 41 06 50 1c 49 0f 07 10 05 88 84 94 |----------------| - // 00000070 02 fc 3c e3 60 25 c0 cb 0c b8 a9 73 bc 13 77 c6 |----------------| - // 00000080 e2 20 ed 17 7b 12 dc 24 5a df b4 21 9a* cb 8f c7 |-----------][---| - // 00000090 58 54 11 a9 f1 47 82 9b ba 60 b4 92 28 0e fb 8b |----------------| - // 000000a0 1e 92 23 6a cf bf e5 45 b5 7e eb 81 f1 78 4b ad |----------------| - // 000000b0 17 4d 81 9f bc 67 a7 56 ee b4 d9 e1 95 21 66 0c | LSTREAM 2 DATA | - // 000000c0 95 83 27 de ac 37 20 91 22 07 0b 91 86 94 1a 7b |----------------| - // 000000d0 f6 4c b0 c0 e8 2e 49 65 d6 34 63 0c 88 9b 1c 48 |----------------| - // 000000e0 ca 2b 34 a9 6b 99 3b ee 13 3b 7c 93 0b f7 0d 49 |--][------------| - // 000000f0 69 18 57 be 3b 64 45 1d 92 63 7f e8 f9 a1 19 7b |----------------| - // 00000100 7b 6e d8 a3 90 23 82 f4 a7 ce c8 f8 90 15 b3 14 | LSTREAM 3 DATA | - // 00000110 f4 40 e7 02 78 d3 17 71 23 b1 19 ad 6b 49 ae 13 |----------------| - // 00000120 a4 75 38 51 47 89 67 b0 39 b4 53 86 a4 ac aa a3 |----------------| - // 00000130 34 89 ca 2e e9 c1 fe f2 51 c6 51 73 aa f7 9d 2d |---][-----------| - // 00000140 ed d9 b7 4a b2 b2 61 e4 ef 98 f7 c5 ef 51 9b d8 |----------------| - // 00000150 dc 60 6c 41 76 af 78 1a 62 b5 4c 1e 21 39 9a 5f | LSTREAM 4 DATA | - // 00000160 ac 9d e0 62 e8 e9 2f 2f 48 02 8d 53 c8 91 f2 1a |----------------| - // 00000170 d2 7c 0a 7c 48 bf da a9 e3 38 da 34 ce 76 a9 da |----------------| - // 00000180 15 91 de 21 f5 55 46 a8 21 9d 51 cc 18 42 44 81 |-----]SS[-- LLT | - // 00000190 8c 94 b4 50 1e 20 42 82 98 c2 3b 10 48 ec a6 39 |----][CMOT][MLT]| - // 000001a0 63 13 a7 01 94 40 ff 88 0f 98 07 4a 46 38 05 a9 |[---------------| - // 000001b0 cb f6 c8 21 59 aa 38 45 bf 5c f8 55 9e 9f 04 ed |----------------| - // 000001c0 c8 03 42 2a 4b f6 78 7e 23 67 15 a2 79 29 f4 9b |----------------| - // 000001d0 7e 00 bc 2f 46 96 99 ea f1 ee 1c 6e 06 9c db e4 |----------------| - // 000001e0 8c c2 05 f7 54 51 84 c0 33 02 01 b1 8c 80 dc 99 | SEQUENCES DATA | - // 000001f0 8f cb 46 ff d1 25 b5 b6 3a f3 25 be 85 50 84 f5 |----------------| - // 00000200 86 5a 71 f7 bd a1 4c 52 4f 20 a3 61 23 77 12 d3 |----------------| - // 00000210 b1 58 75 22 01 12 70 ec 14 91 f9 85 61 d5 7e 98 |----------------| - // 00000220 84 c9 76 84 bc b8 fe 4e 53 a5 06 ++ ++ ++ ++ |----------]++++| + let expected_decoded_ascii: String = String::from("Romeo and Juliet\nExcerpt from Act 2, Scene 2\n\nJULIET\nO ,! wherefore art thou?\nDeny thy fatherrefusename;\nOr, ifwilt not, be but sworn my l"); + + assert_eq!(ascii_symbols, expected_decoded_ascii, "Expect correct decoding"); Ok(()) } - - } diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 5eee243c79..8455ff07e4 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -291,7 +291,7 @@ pub struct HuffmanCodesData { type ParsedCanonicalHuffmanCode = (u64, BTreeMap); /// A representation indexed by bitstring (String) as key for decoding symbols specifically. /// Huffman code decoding ensures prefix code, thus the explicit articulation of bitstring is necessary. -type ParsedCanonicalHuffmanCodeBitstringMap = HashMap; +type ParsedCanonicalHuffmanCodeBitstringMap = (u64, HashMap); impl HuffmanCodesData { @@ -354,7 +354,6 @@ impl HuffmanCodesData { let mut weights: Vec = self.weights.iter().map(|w| w.clone() as usize).collect(); let sum_weights: usize = weights.iter().filter_map(|&w| if w > 0 { Some(1 << (w - 1)) } else { None }).sum(); - // let sum_weights: usize = weights.iter().filter(|&&w| w != 0).map(|&w| 1 << (w - 1)).sum(); let nearest_pow_2: usize = 1 << (sum_weights - 1).next_power_of_two().trailing_zeros(); weights.push(f64::log2((nearest_pow_2 - sum_weights) as f64).ceil() as usize + 1); let max_number_of_bits = nearest_pow_2.trailing_zeros() as usize; @@ -376,8 +375,10 @@ impl HuffmanCodesData { } } } + + let max_bitstring_len = bitstring_map.keys().map(|k| k.len()).max().expect("Keys have maximum len"); - bitstring_map + (max_bitstring_len as u64, bitstring_map) } } @@ -635,7 +636,7 @@ mod tests { weights, }; - let bitstring_map = huffman_codes_data.parse_bitstring_map(); + let (max_bitstring_len, bitstring_map) = huffman_codes_data.parse_bitstring_map(); let expected_bitstrings: [(&str, u64); 53] = [ ("01001", 10), ("110", 32), ("00000000", 33), ("0001100", 39), ("001010", 44), @@ -651,6 +652,7 @@ mod tests { ("00010110", 120), ("010001", 121), ("00010111", 122), ]; + assert_eq!(max_bitstring_len, 8, "max bitstring len is 8"); assert_eq!(expected_bitstrings.len(), bitstring_map.len(), "# of bitstring is the same"); for pair in expected_bitstrings { assert_eq!(*bitstring_map.get(pair.0).unwrap(), pair.1, "bitstring mapping is correct"); From 1f7c42fdb20dcf1900485bf368efaeb1df645a16 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 22 Jan 2024 19:53:30 -0500 Subject: [PATCH 027/165] complete unit test coverage of literal decoding --- zkevm-circuits/src/witness/zstd/mod.rs | 122 ++++++++++++++++++------ zkevm-circuits/src/witness/zstd/util.rs | 11 +++ 2 files changed, 104 insertions(+), 29 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 677032eccf..3eb1c51022 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -14,7 +14,7 @@ mod tui; use tui::draw_rows; mod util; -use util::{value_bits_le, le_bits_to_value, increment_idx}; +use util::{value_bits_le, le_bits_to_value, be_bits_to_value, increment_idx}; /// FrameHeaderDescriptor and FrameContentSize fn process_frame_header( @@ -156,7 +156,7 @@ fn process_block( byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>, bool) { +) -> (usize, Vec>, bool, Vec) { let mut witness_rows = vec![]; let (byte_offset, rows, last_block, block_type, block_size) = @@ -164,7 +164,7 @@ fn process_block( witness_rows.extend_from_slice(&rows); let last_row = rows.last().expect("last row expected to exist"); - let (_byte_offset, rows) = match block_type { + let (_byte_offset, rows, literals) = match block_type { BlockType::RawBlock => process_block_raw( src, byte_offset, @@ -193,7 +193,7 @@ fn process_block( }; witness_rows.extend_from_slice(&rows); - (byte_offset, witness_rows, last_block) + (byte_offset, witness_rows, last_block, literals) } fn process_block_header( @@ -424,14 +424,14 @@ fn process_block_raw( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>) { +) -> (usize, Vec>, Vec) { let tag_next = if last_block { ZstdTag::Null } else { ZstdTag::BlockHeader }; - process_raw_bytes( + let (byte_offset, rows) = process_raw_bytes( src, byte_offset, last_row, @@ -439,7 +439,9 @@ fn process_block_raw( block_size, ZstdTag::RawBlockBytes, tag_next, - ) + ); + + (byte_offset, rows, vec![]) } fn process_block_rle( @@ -449,14 +451,14 @@ fn process_block_rle( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>) { +) -> (usize, Vec>, Vec) { let tag_next = if last_block { ZstdTag::Null } else { ZstdTag::BlockHeader }; - process_rle_bytes( + let (byte_offset, rows) = process_rle_bytes( src, byte_offset, last_row, @@ -464,7 +466,9 @@ fn process_block_rle( block_size, ZstdTag::RleBlockBytes, tag_next, - ) + ); + + (byte_offset, rows, vec![]) } #[allow(unused_variables)] @@ -475,7 +479,7 @@ fn process_block_zstd( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>) { +) -> (usize, Vec>, Vec) { let mut witness_rows = vec![]; // 1-5 bytes LiteralSectionHeader @@ -495,9 +499,9 @@ fn process_block_zstd( witness_rows.extend_from_slice(&rows); // Depending on the literals block type, decode literals section accordingly - let (bytes_offset, rows) = match literals_block_type { + let (bytes_offset, rows, literals) = match literals_block_type { BlockType::RawBlock => { - process_raw_bytes( + let (byte_offset, rows) = process_raw_bytes( src, byte_offset, rows.last().expect("last row expected to exist"), @@ -505,10 +509,12 @@ fn process_block_zstd( regen_size, ZstdTag::ZstdBlockLiteralsRawBytes, ZstdTag::ZstdBlockSequenceHeader, - ) + ); + + (byte_offset, rows, vec![]) }, BlockType::RleBlock => { - process_rle_bytes( + let (byte_offset, rows) = process_rle_bytes( src, byte_offset, rows.last().expect("last row expected to exist"), @@ -516,7 +522,9 @@ fn process_block_zstd( regen_size, ZstdTag::ZstdBlockLiteralsRleBytes, ZstdTag::ZstdBlockSequenceHeader, - ) + ); + + (byte_offset, rows, vec![]) }, BlockType::ZstdCompressedBlock => { let mut huffman_rows = vec![]; @@ -537,19 +545,20 @@ fn process_block_zstd( } // Start decoding the literal section - let mut stream_offset = byte_offset; - + let mut stream_offset = bytes_offset; - let (byte_offset, rows, lstream_lens) = process_block_zstd_huffman_jump_table( + let (bytes_offset, rows, lstream_lens) = process_block_zstd_huffman_jump_table( src, stream_offset, huffman_rows.last().expect("last row should exist"), - n_streams, literal_stream_size, + n_streams, randomness ); huffman_rows.extend_from_slice(&rows); + stream_offset = bytes_offset; + let mut literals: Vec = vec![]; for idx in 0..n_streams { let (byte_offset, rows, symbols) = process_block_zstd_lstream( @@ -562,17 +571,18 @@ fn process_block_zstd( &huffman_codes ); huffman_rows.extend_from_slice(&rows); + literals.extend_from_slice(&symbols); stream_offset = byte_offset; } - (stream_offset, huffman_rows) + (stream_offset, huffman_rows, literals) }, _ => unreachable!("Invalid literals section BlockType") }; witness_rows.extend_from_slice(&rows); - (bytes_offset, witness_rows) + (bytes_offset, witness_rows, literals) } fn process_block_zstd_literals_header( @@ -984,7 +994,7 @@ fn process_block_zstd_huffman_code( while current_bit_idx + next_nb_to_read[color] <= (n_bytes - n_fse_bytes) * N_BITS_PER_BYTE { let nb = next_nb_to_read[color]; - let next_state = prev_baseline[color] + le_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); + let next_state = prev_baseline[color] + be_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); // Lookup the FSE table row for the state let fse_row = fse_state_table.get(&(next_state as u64)).expect("next state should be in fse table"); @@ -1072,7 +1082,7 @@ fn process_block_zstd_huffman_jump_table( .cloned() .map(|x| x as u64) .collect::>(); - + let l1: u64 = jt_bytes[0] + jt_bytes[1] * 256; let l2: u64 = jt_bytes[2] + jt_bytes[3] * 256; let l3: u64 = jt_bytes[4] + jt_bytes[5] * 256; @@ -1327,8 +1337,9 @@ fn process_block_zstd_lstream( (byte_offset + len, witness_rows.into_iter().rev().collect::>>(), decoded_symbols) } -pub fn process(src: &[u8], randomness: Value) -> Vec> { +pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec) { let mut witness_rows = vec![]; + let mut literals: Vec = vec![]; let byte_offset = 0; // FrameHeaderDescriptor and FrameContentSize @@ -1341,16 +1352,18 @@ pub fn process(src: &[u8], randomness: Value) -> Vec( + let (_byte_offset, rows, last_block, new_literals) = process_block::( src, byte_offset, rows.last().expect("last row expected to exist"), randomness, ); witness_rows.extend_from_slice(&rows); + literals.extend_from_slice(&new_literals); if last_block { - assert!(byte_offset >= src.len()); + // TODO: Recover this assertion after the sequence section decoding is completed. + // assert!(byte_offset >= src.len()); break; } } @@ -1358,7 +1371,7 @@ pub fn process(src: &[u8], randomness: Value) -> Vec(&compressed, Value::known(Fr::from(123456789))); + let (_witness_rows, _decoded_literals) = process::(&compressed, Value::known(Fr::from(123456789))); Ok(()) } @@ -1486,4 +1499,55 @@ mod tests { Ok(()) } + + #[test] + fn decode_literal_section() -> Result<(), std::io::Error> { + let encoded: [u8; 555] = [ + // 0x28, 0xb5, 0x2f, 0xfd, // magic numbers are removed + 0x60, // originally 0x64. unset the checksum bit. + 0xae, 0x02, 0x0d, 0x11, 0x00, 0x76, 0x62, 0x5e, 0x23, 0x30, 0x6f, + 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, + 0xa9, 0xd4, 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, + 0x01, 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, + 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, + 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, + 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, + 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, + 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, 0x5a, 0xdf, 0xb4, 0x21, 0x9a, 0xcb, 0x8f, 0xc7, + 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, 0x28, 0x0e, 0xfb, 0x8b, + 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, 0xeb, 0x81, 0xf1, 0x78, 0x4b, 0xad, + 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, 0xb4, 0xd9, 0xe1, 0x95, 0x21, 0x66, 0x0c, + 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, 0x22, 0x07, 0x0b, 0x91, 0x86, 0x94, 0x1a, 0x7b, + 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, 0x65, 0xd6, 0x34, 0x63, 0x0c, 0x88, 0x9b, 0x1c, 0x48, + 0xca, 0x2b, 0x34, 0xa9, 0x6b, 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, + 0x69, 0x18, 0x57, 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, + 0x7b, 0x6e, 0xd8, 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, 0x14, + 0xf4, 0x40, 0xe7, 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, 0x49, 0xae, 0x13, + 0xa4, 0x75, 0x38, 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, 0x86, 0xa4, 0xac, 0xaa, 0xa3, + 0x34, 0x89, 0xca, 0x2e, 0xe9, 0xc1, 0xfe, 0xf2, 0x51, 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, + 0xed, 0xd9, 0xb7, 0x4a, 0xb2, 0xb2, 0x61, 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, + 0xdc, 0x60, 0x6c, 0x41, 0x76, 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, + 0xac, 0x9d, 0xe0, 0x62, 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, + 0xd2, 0x7c, 0x0a, 0x7c, 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, 0xda, + 0x15, 0x91, 0xde, 0x21, 0xf5, 0x55, 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, 0x42, 0x44, 0x81, + 0x8c, 0x94, 0xb4, 0x50, 0x1e, 0x20, 0x42, 0x82, 0x98, 0xc2, 0x3b, 0x10, 0x48, 0xec, 0xa6, 0x39, + 0x63, 0x13, 0xa7, 0x01, 0x94, 0x40, 0xff, 0x88, 0x0f, 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, + 0xcb, 0xf6, 0xc8, 0x21, 0x59, 0xaa, 0x38, 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, + 0xc8, 0x03, 0x42, 0x2a, 0x4b, 0xf6, 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, + 0x7e, 0x00, 0xbc, 0x2f, 0x46, 0x96, 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, + 0x8c, 0xc2, 0x05, 0xf7, 0x54, 0x51, 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, 0x99, + 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, 0x50, 0x84, 0xf5, + 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, 0x4c, 0x52, 0x4f, 0x20, 0xa3, 0x61, 0x23, 0x77, 0x12, 0xd3, + 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, 0x70, 0xec, 0x14, 0x91, 0xf9, 0x85, 0x61, 0xd5, 0x7e, 0x98, + 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, + ]; + + let (_witness_rows, decoded_literals) = process::(&encoded, Value::known(Fr::from(123456789))); + let decoded_literal_string: String = decoded_literals.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); + let expected_literal_string = String::from("Romeo and Juliet\nExcerpt from Act 2, Scene 2\n\nJULIET\nO ,! wherefore art thou?\nDeny thy fatherrefusename;\nOr, ifwilt not, be but sworn my love,\nAnd I'll no longera Capulet.\n\nROMEO\n[Aside] Shall I hear more, or sspeak at this?'Tis that isenemy;\nTyself,gh a Montague.\nWhat's? inor hand,foot,\nNor armaceany opart\nBeing to a man. Osome!in a?which we ca rose\nBy would smell as sweet;\nSo, were he'd,\nRetaindear perfectionhe owes\nWithoitle.dofffor oee\nTake mI t hy word:\nCebe new baptized;\nHencth I never will. manthus bescreen'dnightstumblest on my counsel?\n"); + + assert_eq!(decoded_literal_string, expected_literal_string, "Decode the correct literal string"); + + Ok(()) + } } diff --git a/zkevm-circuits/src/witness/zstd/util.rs b/zkevm-circuits/src/witness/zstd/util.rs index 80aa0523d2..70a392b5d6 100644 --- a/zkevm-circuits/src/witness/zstd/util.rs +++ b/zkevm-circuits/src/witness/zstd/util.rs @@ -119,6 +119,17 @@ pub fn value_bits_le(value_byte: u8) -> [u8; N_BITS_PER_BYTE] { pub fn le_bits_to_value(bits: &[u8]) -> u64 { assert!(bits.len() <= 32); + let mut m: u64 = 1; + + bits.into_iter().fold(0, |mut acc, b| { + acc = acc + (*b as u64) * m; + m *= 2; + acc + }) +} + +pub fn be_bits_to_value(bits: &[u8]) -> u64 { + assert!(bits.len() <= 32); bits.into_iter().fold(0, |mut acc, b| { acc = acc * 2 + *b as u64; From 1643bf3fdce05c752dd482c6ba24a96473af576a Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 24 Jan 2024 19:23:39 -0500 Subject: [PATCH 028/165] remove direct representation of huffman code --- zkevm-circuits/src/witness/zstd/mod.rs | 92 -------------------------- 1 file changed, 92 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 3eb1c51022..1f5c8c8230 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -691,95 +691,6 @@ fn process_block_zstd_literals_header( ) } -fn process_block_zstd_huffman_code_direct( - src: &[u8], - byte_offset: usize, - last_row: &ZstdWitnessRow, - randomness: Value, - n_bytes: usize, -) -> (usize, Vec>, HuffmanCodesData) { - // For direct representation of huffman weights, each byte (8 bits) represents two weights. - // weight[0] = (Byte[0] >> 4) - // weight[1] = (Byte[0] & 0xf). - - let value_rlc_iter = src - .iter() - .skip(byte_offset) - .take(n_bytes) - .scan( - last_row.encoded_data.value_rlc, - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ) - .into_iter() - .flat_map(|v| vec![v, v]); - - let tag_value_iter = src - .iter() - .skip(byte_offset) - .take(n_bytes) - .scan( - Value::known(F::zero()), - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ) - .into_iter() - .flat_map(|v| vec![v, v]); - - let tag_value = tag_value_iter - .clone() - .last() - .expect("Raw bytes must be of non-zero length"); - - let mut weights: Vec = vec![]; - - ( - byte_offset + n_bytes, - src.iter() - .skip(byte_offset) - .take(n_bytes) - .into_iter() - .flat_map(|v| vec![v, v]) - .zip(tag_value_iter) - .zip(value_rlc_iter) - .zip((0..).cycle().take(n_bytes * 2)) - .enumerate() - .map( - |(i, (((&value_byte, tag_value_acc), value_rlc), b_flag))| { - weights.push(FseSymbol::from((if b_flag > 0 { value_byte >> 4 } else { value_byte & 0xf }) as usize)); - - ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::ZstdBlockHuffmanCode, - tag_next: ZstdTag::ZstdBlockSequenceHeader, - tag_len: n_bytes as u64, - tag_idx: (i / 2) as u64, - tag_value, - tag_value_acc, - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + i / 2 + 1) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte: value_byte, - value_rlc, - reverse: false, - ..Default::default() - }, - decoded_data: last_row.decoded_data.clone(), - huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), - } - }, - ) - .collect::>(), - HuffmanCodesData { byte_offset: byte_offset as u64, weights: weights } - ) -} - fn process_block_zstd_huffman_code( src: &[u8], byte_offset: usize, @@ -812,9 +723,6 @@ fn process_block_zstd_huffman_code( } }; - // TODO: Awaiting design decision - // Currently the FSE decoding is assumed. Direct representation is a reserve possibility - // The code for decoding direct representation is above. assert!(header_byte < 128, "FSE encoded huffman weights assumed"); // Get accumulators From c8195245f7b38bdc9e77c38c9d7b4c4c45e227bc Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 25 Jan 2024 00:28:37 -0500 Subject: [PATCH 029/165] correct witness generation --- zkevm-circuits/src/witness/zstd/mod.rs | 187 ++++++++++++------------- 1 file changed, 93 insertions(+), 94 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 1f5c8c8230..9e748118bb 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -2,7 +2,6 @@ use eth_types::Field; use halo2_proofs::circuit::Value; mod params; -use num::Integer; pub use params::*; mod types; @@ -701,6 +700,10 @@ fn process_block_zstd_huffman_code( // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; + // Other consistent values + let encoded_len = last_row.encoded_data.encoded_len; + let decoded_data = last_row.decoded_data.clone(); + // Get the next tag let tag_next = if n_streams > 1 { ZstdTag::ZstdBlockJumpTable @@ -711,21 +714,10 @@ fn process_block_zstd_huffman_code( // Parse the header byte let mut witness_rows: Vec> = vec![]; let header_byte = src[byte_offset]; - - let n_bytes = if header_byte < 128 { - header_byte as usize - } else { - let n_sym: usize = header_byte as usize - 127; - if n_sym.is_odd() { - (n_sym + 1) / 2 - } else { - n_sym / 2 - } - }; - assert!(header_byte < 128, "FSE encoded huffman weights assumed"); + let n_bytes = header_byte as usize; - // Get accumulators + // Get value_rlc accumulator let mut value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes + 1).scan( last_row.encoded_data.value_rlc, |acc, &byte| { @@ -733,81 +725,95 @@ fn process_block_zstd_huffman_code( Some(*acc) }, ); - - let mut tag_value_iter = src.iter().skip(byte_offset).take(n_bytes + 1).scan( - Value::known(F::zero()), - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ); - - let tag_value = tag_value_iter - .clone() - .last() - .expect("Raw bytes must be of non-zero length"); - + // Add a witness row for Huffman header - witness_rows.push(ZstdWitnessRow { + let mut huffman_header_row = ZstdWitnessRow { state: ZstdState { - tag: ZstdTag::ZstdBlockHuffmanCode, + tag: ZstdTag::ZstdBlockFseCode, tag_next, - tag_len: (n_bytes + 1) as u64, // include the 1 byte from huffman header + tag_len: 0 as u64, // There's no information at this point about the length of FSE table bytes. So this value has to be modified later. tag_idx: 1 as u64, - tag_value: tag_value, - tag_value_acc: tag_value_iter.next().expect("Next value should exist"), + tag_value: Value::default(), // Must be changed after FSE table length is known + tag_value_acc: Value::default(), // Must be changed after FSE table length is known }, encoded_data: EncodedData { byte_idx: (byte_offset + 1) as u64, - encoded_len: last_row.encoded_data.encoded_len, + encoded_len, value_byte: header_byte.clone(), value_rlc: value_rlc_iter.next().expect("Next value should exist"), reverse: false, ..Default::default() }, - decoded_data: last_row.decoded_data.clone(), + decoded_data: decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), - }); + }; // Recover the FSE table for generating Huffman weights - let byte_offset = byte_offset + 1; - let (n_fse_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset).expect("Reconstructing FSE table should not fail."); - + let (n_fse_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset + 1).expect("Reconstructing FSE table should not fail."); + // Witness generation - let accuracy_log = (src[byte_offset] & 0b1111) + 5; + let accuracy_log = (src[byte_offset + 1] & 0b1111) + 5; + + let mut tag_value_iter = src.iter().skip(byte_offset).take(n_fse_bytes + 1).scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_value = tag_value_iter + .clone() + .last() + .expect("Tag value must exist"); + + // Backfill missing data on the huffman header row + huffman_header_row.state.tag_len = (n_fse_bytes + 1usize) as u64; + huffman_header_row.state.tag_value = tag_value; + huffman_header_row.state.tag_value_acc = tag_value_iter.next().expect("Next value should exist"); + witness_rows.push(huffman_header_row); // Add witness rows for FSE representation bytes for (idx, byte) in src.iter().skip(byte_offset).take(n_fse_bytes).enumerate() { witness_rows.push(ZstdWitnessRow { state: ZstdState { - tag: ZstdTag::ZstdBlockHuffmanCode, + tag: ZstdTag::ZstdBlockFseCode, tag_next, - tag_len: (n_bytes + 1) as u64, + tag_len: (n_fse_bytes + 1) as u64, tag_idx: (idx + 2) as u64, // count the huffman header byte tag_value: tag_value, tag_value_acc: tag_value_iter.next().expect("Next value should exist"), }, encoded_data: EncodedData { byte_idx: (byte_offset + idx + 2) as u64, // count the huffman header byte - encoded_len: last_row.encoded_data.encoded_len, + encoded_len, value_byte: byte.clone(), value_rlc: value_rlc_iter.next().expect("Next value should exist"), reverse: false, ..Default::default() }, - decoded_data: last_row.decoded_data.clone(), + decoded_data: decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), }); } + // Now start decoding the huffman weights using the actual Huffman code section + let last_value_rlc = witness_rows[witness_rows.len() - 1].encoded_data.value_rlc.clone(); + let aux_1 = last_row.encoded_data.value_rlc; + + // Bitstream processing state values + let n_huffman_code_bytes = n_bytes - n_fse_bytes; + let mut last_byte_idx: usize = 1; + let mut current_byte_idx: usize = 1; // byte_idx is 1-indexed + let mut current_bit_idx: usize = 0; + // Construct the Huffman bitstream let huffman_bitstream = src .iter() - .skip(byte_offset) - .take(n_bytes) + .skip(byte_offset + n_fse_bytes + 1) + .take(n_huffman_code_bytes) .rev() .clone() .flat_map(|v|{ @@ -817,30 +823,49 @@ fn process_block_zstd_huffman_code( }) .collect::>(); - // Bitstream processing state values - let mut last_byte_idx: usize = 1; - let mut current_byte_idx: usize = 1; // byte_idx is 1-indexed - let mut current_bit_idx: usize = 0; + // Accumulators for Huffman code section + let mut value_rlc_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).rev().scan( + last_value_rlc, + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let mut tag_value_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_value = tag_value_iter + .clone() + .last() + .expect("Tag value must exist"); let mut next_tag_value_acc = tag_value_iter.next().unwrap(); let mut next_value_rlc_acc = value_rlc_iter.next().unwrap(); - // Add a witness row for leading 0s + // Add a witness row for leading 0s and the sentinel 1-bit witness_rows.push(ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanCode, tag_next, - tag_len: (n_bytes + 1) as u64, // count huffman header byte - tag_idx: ((n_fse_bytes - 1) + current_byte_idx + 1) as u64, + tag_len: n_huffman_code_bytes as u64, + tag_idx: 1 as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + (n_fse_bytes - 1) + current_byte_idx) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[byte_offset + (n_fse_bytes - 1) + current_byte_idx], + byte_idx: (byte_offset + n_fse_bytes + n_huffman_code_bytes - current_byte_idx) as u64, + encoded_len, + value_byte: src[byte_offset + n_fse_bytes + 1 + current_byte_idx], value_rlc: next_value_rlc_acc, - reverse: false, + reverse: true, + reverse_len: n_huffman_code_bytes as u64, + reverse_idx: (n_huffman_code_bytes - (current_byte_idx - 1)) as u64, + aux_1, + aux_2: tag_value, ..Default::default() }, huffman_data: HuffmanData::default(), @@ -852,36 +877,10 @@ fn process_block_zstd_huffman_code( while huffman_bitstream[current_bit_idx] == 0 { (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); } - if current_byte_idx > last_byte_idx { - next_tag_value_acc = tag_value_iter.next().unwrap(); - next_value_rlc_acc = value_rlc_iter.next().unwrap(); - last_byte_idx = current_byte_idx; - } - - // Add a witness row for sentinel 1-bit - witness_rows.push(ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::ZstdBlockHuffmanCode, - tag_next, - tag_len: (n_bytes + 1) as u64, - tag_idx: ((n_fse_bytes - 1) + current_byte_idx + 1) as u64, - tag_value: tag_value, - tag_value_acc: next_tag_value_acc, - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + (n_fse_bytes - 1) + current_byte_idx) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[byte_offset + (n_fse_bytes - 1) + current_byte_idx], - value_rlc: next_value_rlc_acc, - reverse: false, - ..Default::default() - }, - huffman_data: HuffmanData::default(), - decoded_data: last_row.decoded_data.clone(), - fse_data: FseTableRow::default(), - }); // Exclude the sentinel 1-bit (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); + + // Update accumulator if current_byte_idx > last_byte_idx { next_tag_value_acc = tag_value_iter.next().unwrap(); next_value_rlc_acc = value_rlc_iter.next().unwrap(); @@ -900,7 +899,7 @@ fn process_block_zstd_huffman_code( // Convert FSE auxiliary data into a state-indexed representation let fse_state_table = table.parse_state_table(); - while current_bit_idx + next_nb_to_read[color] <= (n_bytes - n_fse_bytes) * N_BITS_PER_BYTE { + while current_bit_idx + next_nb_to_read[color] <= (n_huffman_code_bytes) * N_BITS_PER_BYTE { let nb = next_nb_to_read[color]; let next_state = prev_baseline[color] + be_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); @@ -915,15 +914,15 @@ fn process_block_zstd_huffman_code( state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanCode, tag_next, - tag_len: (n_bytes + 1) as u64, - tag_idx: ((n_fse_bytes - 1) + current_byte_idx + 1) as u64, + tag_len: (n_huffman_code_bytes) as u64, + tag_idx: current_byte_idx as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + (n_fse_bytes - 1) + current_byte_idx) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[byte_offset + (n_fse_bytes - 1) + current_byte_idx], + byte_idx: (byte_offset + n_fse_bytes + current_byte_idx) as u64, + encoded_len, + value_byte: src[byte_offset + n_fse_bytes + current_byte_idx], value_rlc: next_value_rlc_acc, reverse: false, ..Default::default() @@ -936,7 +935,7 @@ fn process_block_zstd_huffman_code( num_bits: fse_row.2, }, huffman_data: HuffmanData::default(), - decoded_data: last_row.decoded_data.clone(), + decoded_data: decoded_data.clone(), }); // increment fse idx @@ -965,7 +964,7 @@ fn process_block_zstd_huffman_code( weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() }; - (byte_offset + n_bytes, witness_rows, huffman_codes, n_bytes) + (byte_offset + 1 + n_fse_bytes + n_huffman_code_bytes, witness_rows, huffman_codes, n_bytes) } fn process_block_zstd_huffman_jump_table( @@ -990,7 +989,7 @@ fn process_block_zstd_huffman_jump_table( .cloned() .map(|x| x as u64) .collect::>(); - + let l1: u64 = jt_bytes[0] + jt_bytes[1] * 256; let l2: u64 = jt_bytes[2] + jt_bytes[3] * 256; let l3: u64 = jt_bytes[4] + jt_bytes[5] * 256; From cce8a0602e4c279c96cd40f424c6f5441057c580 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 25 Jan 2024 03:17:15 -0500 Subject: [PATCH 030/165] Correct witness values --- zkevm-circuits/src/witness/zstd/mod.rs | 67 ++++++++------------------ 1 file changed, 20 insertions(+), 47 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 9e748118bb..5016cef53e 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -857,7 +857,7 @@ fn process_block_zstd_huffman_code( tag_value_acc: next_tag_value_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + n_fse_bytes + n_huffman_code_bytes - current_byte_idx) as u64, + byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, value_byte: src[byte_offset + n_fse_bytes + 1 + current_byte_idx], value_rlc: next_value_rlc_acc, @@ -920,11 +920,15 @@ fn process_block_zstd_huffman_code( tag_value_acc: next_tag_value_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + n_fse_bytes + current_byte_idx) as u64, + byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, - value_byte: src[byte_offset + n_fse_bytes + current_byte_idx], + value_byte: src[byte_offset + n_fse_bytes + 1 + current_byte_idx], value_rlc: next_value_rlc_acc, - reverse: false, + reverse: true, + reverse_len: n_huffman_code_bytes as u64, + reverse_idx: (n_huffman_code_bytes - (current_byte_idx - 1)) as u64, + aux_1, + aux_2: tag_value, ..Default::default() }, fse_data: FseTableRow { @@ -1106,18 +1110,18 @@ fn process_block_zstd_lstream( _ => unreachable!("stream_idx value out of range") }; - // Add a witness row for leading 0s + // Add a witness row for leading 0s and sentinel 1-bit witness_rows.push(ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockLstream, tag_next, tag_len: len as u64, - tag_idx: current_byte_idx as u64, + tag_idx: (len - current_byte_idx + 1) as u64, tag_value: *tag_value, tag_value_acc: tag_value_acc[current_byte_idx - 1], }, encoded_data: EncodedData { - byte_idx: (byte_offset + len - current_byte_idx) as u64, + byte_idx: (byte_offset + current_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - current_byte_idx], value_rlc: value_rlc_acc[current_byte_idx - 1], @@ -1138,35 +1142,6 @@ fn process_block_zstd_lstream( while lstream_bits[current_bit_idx] == 0 { (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); } - - // Add a witness row for sentinel 1-bit - witness_rows.push(ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::ZstdBlockLstream, - tag_next, - tag_len: len as u64, - tag_idx: current_byte_idx as u64, - tag_value: *tag_value, - tag_value_acc: tag_value_acc[current_byte_idx - 1], - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + len - current_byte_idx) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte: src[byte_offset + len - current_byte_idx], - value_rlc: value_rlc_acc[current_byte_idx - 1], - // reverse specific values - reverse: true, - reverse_len: len as u64, - reverse_idx: (len - (current_byte_idx - 1)) as u64, - aux_1, - aux_2: *tag_value, - ..Default::default() - }, - huffman_data: HuffmanData::default(), - decoded_data: last_row.decoded_data.clone(), - fse_data: FseTableRow::default(), - }); - // Exclude the sentinel 1-bit (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); @@ -1184,30 +1159,25 @@ fn process_block_zstd_lstream( let from_byte_idx = current_byte_idx; let from_bit_idx = current_bit_idx; - // advance byte and bit marks to the last bit - for _ in 0..(cur_bitstring_len - 1) { - (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); - } - // Add a witness row for emitted symbol witness_rows.push(ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockLstream, tag_next, tag_len: len as u64, - tag_idx: from_byte_idx as u64, + tag_idx: (len - from_byte_idx + 1) as u64, tag_value: *tag_value, tag_value_acc: tag_value_acc[from_byte_idx - 1], }, encoded_data: EncodedData { - byte_idx: (byte_offset + len - from_byte_idx) as u64, + byte_idx: (byte_offset + from_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - from_byte_idx], value_rlc: value_rlc_acc[from_byte_idx - 1], // reverse specific values reverse: true, reverse_len: len as u64, - reverse_idx: (len - (from_byte_idx - 1)) as u64, + reverse_idx: (len - from_byte_idx + 1) as u64, aux_1, aux_2: *tag_value, ..Default::default() @@ -1221,8 +1191,10 @@ fn process_block_zstd_lstream( fse_data: FseTableRow::default(), }); - // advance byte and bit marks again to get the start of next bitstring - (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); + // advance byte and bit marks to the last bit + for _ in 0..cur_bitstring_len { + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); + } // Reset decoding state bitstring_acc = String::from(""); @@ -1241,7 +1213,7 @@ fn process_block_zstd_lstream( } } - (byte_offset + len, witness_rows.into_iter().rev().collect::>>(), decoded_symbols) + (byte_offset + len, witness_rows, decoded_symbols) } pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec) { @@ -1450,6 +1422,7 @@ mod tests { ]; let (_witness_rows, decoded_literals) = process::(&encoded, Value::known(Fr::from(123456789))); + let decoded_literal_string: String = decoded_literals.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); let expected_literal_string = String::from("Romeo and Juliet\nExcerpt from Act 2, Scene 2\n\nJULIET\nO ,! wherefore art thou?\nDeny thy fatherrefusename;\nOr, ifwilt not, be but sworn my love,\nAnd I'll no longera Capulet.\n\nROMEO\n[Aside] Shall I hear more, or sspeak at this?'Tis that isenemy;\nTyself,gh a Montague.\nWhat's? inor hand,foot,\nNor armaceany opart\nBeing to a man. Osome!in a?which we ca rose\nBy would smell as sweet;\nSo, were he'd,\nRetaindear perfectionhe owes\nWithoitle.dofffor oee\nTake mI t hy word:\nCebe new baptized;\nHencth I never will. manthus bescreen'dnightstumblest on my counsel?\n"); From 037635229f57d27f0aee9c3b1529bbafc86e0959 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 25 Jan 2024 10:12:15 -0500 Subject: [PATCH 031/165] Correct idx incremental block --- zkevm-circuits/src/witness/zstd/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 5016cef53e..bbd162d1b4 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1159,6 +1159,11 @@ fn process_block_zstd_lstream( let from_byte_idx = current_byte_idx; let from_bit_idx = current_bit_idx; + // advance byte and bit marks to the last bit + for _ in 0..cur_bitstring_len { + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); + } + // Add a witness row for emitted symbol witness_rows.push(ZstdWitnessRow { state: ZstdState { @@ -1191,10 +1196,7 @@ fn process_block_zstd_lstream( fse_data: FseTableRow::default(), }); - // advance byte and bit marks to the last bit - for _ in 0..cur_bitstring_len { - (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); - } + // Reset decoding state bitstring_acc = String::from(""); From 3a282a629fa2987f550c7afa527a9da03659900c Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 25 Jan 2024 18:58:20 -0500 Subject: [PATCH 032/165] Correct tag next --- zkevm-circuits/src/witness/zstd/mod.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index bbd162d1b4..2e3fc8a136 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -633,7 +633,7 @@ fn process_block_zstd_literals_header( let tag_next = match literals_block_type { BlockType::RawBlock => ZstdTag::ZstdBlockLiteralsRawBytes, BlockType::RleBlock => ZstdTag::ZstdBlockLiteralsRleBytes, - BlockType::ZstdCompressedBlock => ZstdTag::ZstdBlockHuffmanCode, + BlockType::ZstdCompressedBlock => ZstdTag::ZstdBlockFseCode, _ => unreachable!("BlockType::Reserved unexpected or treeless literal section"), }; @@ -705,11 +705,7 @@ fn process_block_zstd_huffman_code( let decoded_data = last_row.decoded_data.clone(); // Get the next tag - let tag_next = if n_streams > 1 { - ZstdTag::ZstdBlockJumpTable - } else { - ZstdTag::ZstdBlockLstream - }; + let tag_next = ZstdTag::ZstdBlockHuffmanCode; // Parse the header byte let mut witness_rows: Vec> = vec![]; @@ -801,6 +797,11 @@ fn process_block_zstd_huffman_code( // Now start decoding the huffman weights using the actual Huffman code section let last_value_rlc = witness_rows[witness_rows.len() - 1].encoded_data.value_rlc.clone(); let aux_1 = last_row.encoded_data.value_rlc; + let tag_next = if n_streams > 1 { + ZstdTag::ZstdBlockJumpTable + } else { + ZstdTag::ZstdBlockLstream + }; // Bitstream processing state values let n_huffman_code_bytes = n_bytes - n_fse_bytes; From fabcaebc45e438c52fa00fbc8eb7fa79012617d0 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 25 Jan 2024 19:03:50 -0500 Subject: [PATCH 033/165] Correct tag_idx --- zkevm-circuits/src/witness/zstd/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 2e3fc8a136..ecceff85d9 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1117,7 +1117,7 @@ fn process_block_zstd_lstream( tag: ZstdTag::ZstdBlockLstream, tag_next, tag_len: len as u64, - tag_idx: (len - current_byte_idx + 1) as u64, + tag_idx: current_byte_idx as u64, tag_value: *tag_value, tag_value_acc: tag_value_acc[current_byte_idx - 1], }, @@ -1171,7 +1171,7 @@ fn process_block_zstd_lstream( tag: ZstdTag::ZstdBlockLstream, tag_next, tag_len: len as u64, - tag_idx: (len - from_byte_idx + 1) as u64, + tag_idx: from_byte_idx as u64, tag_value: *tag_value, tag_value_acc: tag_value_acc[from_byte_idx - 1], }, From a8f9d156447c0207e043951a3be189b891f0d3fd Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 28 Jan 2024 19:06:14 -0500 Subject: [PATCH 034/165] Correct tag value accumulator --- zkevm-circuits/src/witness/zstd/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 46d44aac28..370a32fa9d 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -638,7 +638,7 @@ fn process_block_zstd_literals_header( }; let tag_value_iter = lh_bytes.iter().take(n_bytes_header).scan(Value::known(F::zero()), |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); + *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); Some(*acc) }); let tag_value = tag_value_iter.clone().last().expect("LiteralsHeader expected"); @@ -723,7 +723,7 @@ fn process_block_zstd_huffman_code( ); // Add a witness row for Huffman header - let mut huffman_header_row = ZstdWitnessRow { + let mut huffman_header_row: ZstdWitnessRow = ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockFseCode, tag_next, @@ -754,7 +754,7 @@ fn process_block_zstd_huffman_code( let mut tag_value_iter = src.iter().skip(byte_offset).take(n_fse_bytes + 1).scan( Value::known(F::zero()), |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); + *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); Some(*acc) }, ); @@ -1010,7 +1010,7 @@ fn process_block_zstd_huffman_jump_table( let tag_value_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( Value::known(F::zero()), |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); + *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); Some(*acc) }, ); @@ -1258,10 +1258,12 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec Date: Sun, 28 Jan 2024 19:20:31 -0500 Subject: [PATCH 035/165] Correct huffman data byte offset --- zkevm-circuits/src/witness/zstd/mod.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 370a32fa9d..f07872992b 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -528,7 +528,7 @@ fn process_block_zstd( BlockType::ZstdCompressedBlock => { let mut huffman_rows = vec![]; - let (bytes_offset, rows, huffman_codes, n_huffman_bytes) = process_block_zstd_huffman_code( + let (bytes_offset, rows, huffman_codes, n_huffman_bytes, huffman_byte_offset) = process_block_zstd_huffman_code( src, byte_offset, rows.last().expect("last row must exist"), @@ -567,7 +567,8 @@ fn process_block_zstd( huffman_rows.last().expect("last row should exist"), randomness, idx, - &huffman_codes + &huffman_codes, + huffman_byte_offset, ); huffman_rows.extend_from_slice(&rows); literals.extend_from_slice(&symbols); @@ -696,7 +697,7 @@ fn process_block_zstd_huffman_code( last_row: &ZstdWitnessRow, randomness: Value, n_streams: usize, -) -> (usize, Vec>, HuffmanCodesData, usize) { +) -> (usize, Vec>, HuffmanCodesData, usize, usize) { // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; @@ -969,7 +970,7 @@ fn process_block_zstd_huffman_code( weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() }; - (byte_offset + 1 + n_fse_bytes + n_huffman_code_bytes, witness_rows, huffman_codes, n_bytes) + (byte_offset + 1 + n_fse_bytes + n_huffman_code_bytes, witness_rows, huffman_codes, n_bytes, huffman_code_byte_offset + 1) } fn process_block_zstd_huffman_jump_table( @@ -1066,6 +1067,7 @@ fn process_block_zstd_lstream( randomness: Value, stream_idx: usize, huffman_code: &HuffmanCodesData, + huffman_code_byte_offset: usize, ) -> (usize, Vec>, Vec) { // Obtain literal stream bits (reversed). let lstream_bits = src @@ -1189,7 +1191,7 @@ fn process_block_zstd_lstream( ..Default::default() }, huffman_data: HuffmanData { - byte_offset: (byte_offset + len - from_byte_idx) as u64, + byte_offset: huffman_code_byte_offset as u64, bit_value: u8::from_str_radix(bitstring_acc.as_str(), 2).unwrap(), k: (from_bit_idx.rem_euclid(8) as u8, current_bit_idx.rem_euclid(8) as u8), }, @@ -1197,8 +1199,6 @@ fn process_block_zstd_lstream( fse_data: FseTableRow::default(), }); - - // Reset decoding state bitstring_acc = String::from(""); cur_bitstring_len = 0; @@ -1354,7 +1354,7 @@ mod tests { 0x54, 0x40, 0x29, 0x01, ]; - let (_byte_offset, _witness_rows, huffman_codes, _n_huffan_bytes) = + let (_byte_offset, _witness_rows, huffman_codes, _n_huffan_bytes, _huffman_byte_offset) = process_block_zstd_huffman_code::( &input, 0, @@ -1428,7 +1428,8 @@ mod tests { &ZstdWitnessRow::init(0), Value::known(Fr::from(123456789)), 1, - &huffman_codes + &huffman_codes, + 0, ); let ascii_symbols: String = decoded_symbols.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); From 1b8ed3df63b670271702bbb3b404a854e350e0f8 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 28 Jan 2024 21:16:57 -0500 Subject: [PATCH 036/165] Correct witness values --- zkevm-circuits/src/witness/zstd/mod.rs | 42 ++++++++++++++++---------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index f07872992b..37b039e56b 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -5,6 +5,7 @@ mod params; pub use params::*; mod types; +use rand::random; pub use types::*; #[cfg(test)] @@ -528,7 +529,7 @@ fn process_block_zstd( BlockType::ZstdCompressedBlock => { let mut huffman_rows = vec![]; - let (bytes_offset, rows, huffman_codes, n_huffman_bytes, huffman_byte_offset) = process_block_zstd_huffman_code( + let (bytes_offset, rows, huffman_codes, n_huffman_bytes, huffman_byte_offset, last_rlc) = process_block_zstd_huffman_code( src, byte_offset, rows.last().expect("last row must exist"), @@ -552,7 +553,8 @@ fn process_block_zstd( huffman_rows.last().expect("last row should exist"), literal_stream_size, n_streams, - randomness + randomness, + last_rlc, ); huffman_rows.extend_from_slice(&rows); stream_offset = bytes_offset; @@ -697,7 +699,7 @@ fn process_block_zstd_huffman_code( last_row: &ZstdWitnessRow, randomness: Value, n_streams: usize, -) -> (usize, Vec>, HuffmanCodesData, usize, usize) { +) -> (usize, Vec>, HuffmanCodesData, usize, usize, Value) { // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; @@ -796,8 +798,6 @@ fn process_block_zstd_huffman_code( } // Now start decoding the huffman weights using the actual Huffman code section - let last_value_rlc = witness_rows[witness_rows.len() - 1].encoded_data.value_rlc.clone(); - let aux_1 = last_row.encoded_data.value_rlc; let tag_next = if n_streams > 1 { ZstdTag::ZstdBlockJumpTable } else { @@ -826,14 +826,14 @@ fn process_block_zstd_huffman_code( .collect::>(); // Accumulators for Huffman code section - let mut value_rlc_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).rev().scan( - last_value_rlc, + let mut value_rlc_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).scan( + Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }, - ); - let mut tag_value_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).scan( + ).collect::>>().into_iter().rev(); + let mut tag_value_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).rev().scan( Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); @@ -848,6 +848,9 @@ fn process_block_zstd_huffman_code( let mut next_tag_value_acc = tag_value_iter.next().unwrap(); let mut next_value_rlc_acc = value_rlc_iter.next().unwrap(); + let aux_1 = next_value_rlc_acc.clone(); + let aux_2 = witness_rows[witness_rows.len() - 1].encoded_data.value_rlc.clone(); + // Add a witness row for leading 0s and the sentinel 1-bit witness_rows.push(ZstdWitnessRow { state: ZstdState { @@ -867,7 +870,7 @@ fn process_block_zstd_huffman_code( reverse_len: n_huffman_code_bytes as u64, reverse_idx: (n_huffman_code_bytes - (current_byte_idx - 1)) as u64, aux_1, - aux_2: tag_value, + aux_2, ..Default::default() }, huffman_data: HuffmanData::default(), @@ -930,7 +933,7 @@ fn process_block_zstd_huffman_code( reverse_len: n_huffman_code_bytes as u64, reverse_idx: (n_huffman_code_bytes - (current_byte_idx - 1)) as u64, aux_1, - aux_2: tag_value, + aux_2, ..Default::default() }, fse_data: FseTableRow { @@ -952,8 +955,8 @@ fn process_block_zstd_huffman_code( (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); } if current_byte_idx > last_byte_idx && current_byte_idx < n_bytes { - next_tag_value_acc = tag_value_iter.next().unwrap_or_default(); - next_value_rlc_acc = value_rlc_iter.next().unwrap_or_default(); + next_tag_value_acc = tag_value_iter.next().unwrap(); + next_value_rlc_acc = value_rlc_iter.next().unwrap(); last_byte_idx = current_byte_idx; } @@ -970,7 +973,13 @@ fn process_block_zstd_huffman_code( weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() }; - (byte_offset + 1 + n_fse_bytes + n_huffman_code_bytes, witness_rows, huffman_codes, n_bytes, huffman_code_byte_offset + 1) + // rlc after a reverse section + let mul = (0..(n_huffman_code_bytes - 1)).fold(Value::known(F::one()), |acc, _| { + acc * randomness + }); + let new_value_rlc_init_value = aux_2 * mul + aux_1; + + (byte_offset + 1 + n_fse_bytes + n_huffman_code_bytes, witness_rows, huffman_codes, n_bytes, huffman_code_byte_offset + 1, new_value_rlc_init_value) } fn process_block_zstd_huffman_jump_table( @@ -980,6 +989,7 @@ fn process_block_zstd_huffman_jump_table( literal_stream_size: usize, n_streams: usize, randomness: Value, + last_rlc: Value, ) -> (usize, Vec>, Vec) { if n_streams <= 1 { (byte_offset, vec![], vec![literal_stream_size as u64]) @@ -1002,7 +1012,7 @@ fn process_block_zstd_huffman_jump_table( let l4: u64 = (literal_stream_size as u64) - l1 - l2 - l3; let value_rlc_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( - last_row.encoded_data.value_rlc, + last_rlc, |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) @@ -1354,7 +1364,7 @@ mod tests { 0x54, 0x40, 0x29, 0x01, ]; - let (_byte_offset, _witness_rows, huffman_codes, _n_huffan_bytes, _huffman_byte_offset) = + let (_byte_offset, _witness_rows, huffman_codes, _n_huffan_bytes, _huffman_byte_offset, _last_rlc) = process_block_zstd_huffman_code::( &input, 0, From a22100bd571ff7abe24245a71fd23ac03c6e862b Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 28 Jan 2024 21:41:27 -0500 Subject: [PATCH 037/165] Remove import --- zkevm-circuits/src/witness/zstd/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 37b039e56b..db1b416a09 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -5,7 +5,6 @@ mod params; pub use params::*; mod types; -use rand::random; pub use types::*; #[cfg(test)] From cf5954b7ad22bbc8ec861983063120a3cf6ca9e9 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 29 Jan 2024 17:49:52 -0500 Subject: [PATCH 038/165] Correct comments on decoding constants --- zkevm-circuits/src/witness/zstd/params.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zkevm-circuits/src/witness/zstd/params.rs b/zkevm-circuits/src/witness/zstd/params.rs index 029614ffc4..1dec732d21 100644 --- a/zkevm-circuits/src/witness/zstd/params.rs +++ b/zkevm-circuits/src/witness/zstd/params.rs @@ -4,9 +4,11 @@ pub const N_BITS_PER_BYTE: usize = 8; /// Number of bytes used to specify block header. pub const N_BLOCK_HEADER_BYTES: usize = 3; -// Constants for zstd-compressed block +/// Constants for zstd-compressed block pub const N_MAX_LITERAL_HEADER_BYTES: usize = 3; +/// Maximum bytes for the jump table pub const N_JUMP_TABLE_BYTES: usize = 6; +/// Maximum bytes for the FSE representation pub const N_MAX_LITERAL_FSE_BYTES: usize = 8; /// Maximum number of symbols (weights), i.e. symbol in [0, N_MAX_SYMBOLS). From 5f60c479bece76f043d51bc13015f6af0f63c9de Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 29 Jan 2024 18:06:06 -0500 Subject: [PATCH 039/165] Introduce tag_rlc --- zkevm-circuits/src/witness/zstd/mod.rs | 26 ++++++++++++++++++++++++ zkevm-circuits/src/witness/zstd/types.rs | 5 +++++ 2 files changed, 31 insertions(+) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index db1b416a09..ae26e7fb49 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -95,6 +95,8 @@ fn process_frame_header( tag_idx: 1, tag_value: Value::known(F::from(*fhd_byte as u64)), tag_value_acc: Value::known(F::from(*fhd_byte as u64)), + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + 1) as u64, @@ -128,6 +130,8 @@ fn process_frame_header( tag_idx: (i + 1) as u64, tag_value: fcs_tag_value, tag_value_acc, + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + 2 + i) as u64, @@ -258,6 +262,8 @@ fn process_block_header( tag_idx: (i + 1) as u64, tag_value, tag_value_acc, + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + i + 1) as u64, @@ -333,6 +339,8 @@ fn process_raw_bytes( tag_idx: (i + 1) as u64, tag_value, tag_value_acc, + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + i + 1) as u64, @@ -393,6 +401,8 @@ fn process_rle_bytes( tag_idx: (i + 1) as u64, tag_value, tag_value_acc: tag_value, + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + 1) as u64, @@ -670,6 +680,8 @@ fn process_block_zstd_literals_header( tag_idx: (i + 1) as u64, tag_value, tag_value_acc, + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + i + 1) as u64, @@ -733,6 +745,8 @@ fn process_block_zstd_huffman_code( tag_idx: 1 as u64, tag_value: Value::default(), // Must be changed after FSE table length is known tag_value_acc: Value::default(), // Must be changed after FSE table length is known + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + 1) as u64, @@ -781,6 +795,8 @@ fn process_block_zstd_huffman_code( tag_idx: (idx + 2) as u64, // count the huffman header byte tag_value: tag_value, tag_value_acc: tag_value_iter.next().expect("Next value should exist"), + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + idx + 2) as u64, // count the huffman header byte @@ -859,6 +875,8 @@ fn process_block_zstd_huffman_code( tag_idx: 1 as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, @@ -922,6 +940,8 @@ fn process_block_zstd_huffman_code( tag_idx: current_byte_idx as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, @@ -1047,6 +1067,8 @@ fn process_block_zstd_huffman_jump_table( tag_idx: (i + 1) as u64, tag_value, tag_value_acc, + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + i + 1) as u64, @@ -1131,6 +1153,8 @@ fn process_block_zstd_lstream( tag_idx: current_byte_idx as u64, tag_value: *tag_value, tag_value_acc: tag_value_acc[current_byte_idx - 1], + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + current_byte_idx) as u64, @@ -1185,6 +1209,8 @@ fn process_block_zstd_lstream( tag_idx: from_byte_idx as u64, tag_value: *tag_value, tag_value_acc: tag_value_acc[from_byte_idx - 1], + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), }, encoded_data: EncodedData { byte_idx: (byte_offset + from_byte_idx) as u64, diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 946dfa3ea9..c54352f63e 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -290,6 +290,9 @@ pub struct ZstdState { pub tag_idx: u64, pub tag_value: Value, pub tag_value_acc: Value, + // Unlike tag_value, tag_rlc only uses challenge as multiplier + pub tag_rlc: Value, + pub tag_rlc_acc: Value, } impl Default for ZstdState { @@ -301,6 +304,8 @@ impl Default for ZstdState { tag_idx: 0, tag_value: Value::known(F::zero()), tag_value_acc: Value::known(F::zero()), + tag_rlc: Value::known(F::zero()), + tag_rlc_acc: Value::known(F::zero()), } } } From d966c03ab2b8efb42511307a2dbf6197d1db9f11 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Tue, 30 Jan 2024 23:54:54 -0500 Subject: [PATCH 040/165] Correct multiplier for tag --- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index ae26e7fb49..be29fc99c2 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -224,7 +224,7 @@ fn process_block_header( }; let tag_value_iter = bh_bytes.iter().scan(Value::known(F::zero()), |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); + *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); Some(*acc) }); let tag_value = tag_value_iter.clone().last().expect("BlockHeader expected"); From 3c119e813f7152d70fb31ed5b97d70be236688c4 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 15:16:33 -0500 Subject: [PATCH 041/165] Clean up and consolidate working example circuit assignment test --- zkevm-circuits/src/decompression_circuit.rs | 91 +++++++++++++++++-- .../src/decompression_circuit/test.rs | 64 ++++++++++++- zkevm-circuits/src/witness.rs | 4 +- zkevm-circuits/src/witness/zstd/mod.rs | 1 + zkevm-circuits/src/witness/zstd/types.rs | 7 ++ 5 files changed, 155 insertions(+), 12 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 999f338e2d..1eecc69b4f 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -23,7 +23,6 @@ use halo2_proofs::{ }, poly::Rotation, }; - use crate::{ evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, table::{ @@ -35,7 +34,7 @@ use crate::{ }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::{ - Block, ZstdTag, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, N_JUMP_TABLE_BYTES, + Block, ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, N_JUMP_TABLE_BYTES, process, }, }; @@ -2363,9 +2362,82 @@ impl SubCircuitConfig for DecompressionCircuitConfig { } } +impl DecompressionCircuitConfig { + /// Assign witness to the decompression circuit. + pub(crate) fn assign( + &self, + _layouter: &mut impl Layouter, + _witness_rows: Vec>, + _challenges: &Challenges>, + ) -> Result<(), Error> { + // let dt_rows = inputs + // .iter() + // .flat_map(|input| input.gen_data_table(challenges)) + // .collect::>(); + // let sm_rows = inputs + // .iter() + // .flat_map(|input| input.gen_sm_witness(challenges)) + // .collect::>(); + + // debug_assert!(sm_rows.len() <= last_row); + + // self.rom_table.load(layouter)?; + + // log::debug!("num_sm_rows: {}", sm_rows.len()); + // log::debug!("num_dt_rows: {}", dt_rows.len()); + + // layouter.assign_region( + // || "RLP data table region", + // |mut region| { + // for (i, dt_row) in dt_rows.iter().enumerate() { + // let dt_row_next = if i == dt_rows.len() - 1 { + // None + // } else { + // Some(&dt_rows[i + 1]) + // }; + // self.assign_dt_row(&mut region, i, dt_row, dt_row_next)?; + // } + // // assign padding rows + // Ok(()) + // }, + // )?; + // layouter.assign_region( + // || "RLP sm region", + // |mut region| { + // for (i, sm_row) in sm_rows.iter().enumerate() { + // let sm_row_next = if i == sm_rows.len() - 1 { + // None + // } else { + // Some(&sm_rows[i + 1]) + // }; + // let sm_row_prev = if i == 0 { None } else { Some(&sm_rows[i - 1]) }; + // self.assign_sm_row(&mut region, i, sm_row, sm_row_next, sm_row_prev)?; + // } + // for i in sm_rows.len()..last_row { + // self.assign_sm_end_row(&mut region, i)?; + // } + // region.assign_fixed(|| "q_first", self.q_first, 0, || Value::known(F::one()))?; + // region.assign_fixed( + // || "q_last", + // self.q_last, + // last_row - 1, + // || Value::known(F::one()), + // )?; + + // Ok(()) + // }, + // )?; + + // Ok(()) + + Ok(()) + } +} + /// The Decompression circuit decodes an instance of zstd compressed data. #[derive(Clone, Debug, Default)] pub struct DecompressionCircuit { + compressed_frames: Vec>, _data: PhantomData, } @@ -2382,10 +2454,17 @@ impl SubCircuit for DecompressionCircuit { fn synthesize_sub( &self, - _config: &Self::Config, - _challenges: &Challenges>, - _layouter: &mut impl Layouter, + config: &Self::Config, + challenges: &Challenges>, + layouter: &mut impl Layouter, ) -> Result<(), Error> { - Ok(()) + let mut witness_rows: Vec> = vec![]; + + for idx in 0..self.compressed_frames.len() { + let (rows, _decoded_literals) = process::(&self.compressed_frames[idx], challenges.keccak_input()); + witness_rows.extend_from_slice(&rows); + } + + config.assign(layouter, witness_rows, challenges) } } diff --git a/zkevm-circuits/src/decompression_circuit/test.rs b/zkevm-circuits/src/decompression_circuit/test.rs index d39272c34a..443f7147de 100644 --- a/zkevm-circuits/src/decompression_circuit/test.rs +++ b/zkevm-circuits/src/decompression_circuit/test.rs @@ -1,9 +1,8 @@ +use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; +use crate::decompression_circuit::DecompressionCircuit; + #[test] fn test_basic() { - use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; - - use crate::decompression_circuit::DecompressionCircuit; - let circuit = DecompressionCircuit::::default(); let mock_prover = MockProver::run(17, &circuit, vec![]); assert!(mock_prover.is_ok()); @@ -14,3 +13,60 @@ fn test_basic() { mock_prover.assert_satisfied_par(); } + +#[test] +fn test_work_example_decompression() { + let compressed: Vec = vec![ + // 0x28, 0xb5, 0x2f, 0xfd, // magic numbers are removed + 0x60, // originally 0x64. unset the checksum bit. + 0xae, 0x02, 0x0d, 0x11, 0x00, 0x76, 0x62, 0x5e, 0x23, 0x30, 0x6f, + 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, + 0xa9, 0xd4, 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, + 0x01, 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, + 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, + 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, + 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, + 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, + 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, 0x5a, 0xdf, 0xb4, 0x21, 0x9a, 0xcb, 0x8f, 0xc7, + 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, 0x28, 0x0e, 0xfb, 0x8b, + 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, 0xeb, 0x81, 0xf1, 0x78, 0x4b, 0xad, + 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, 0xb4, 0xd9, 0xe1, 0x95, 0x21, 0x66, 0x0c, + 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, 0x22, 0x07, 0x0b, 0x91, 0x86, 0x94, 0x1a, 0x7b, + 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, 0x65, 0xd6, 0x34, 0x63, 0x0c, 0x88, 0x9b, 0x1c, 0x48, + 0xca, 0x2b, 0x34, 0xa9, 0x6b, 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, + 0x69, 0x18, 0x57, 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, + 0x7b, 0x6e, 0xd8, 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, 0x14, + 0xf4, 0x40, 0xe7, 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, 0x49, 0xae, 0x13, + 0xa4, 0x75, 0x38, 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, 0x86, 0xa4, 0xac, 0xaa, 0xa3, + 0x34, 0x89, 0xca, 0x2e, 0xe9, 0xc1, 0xfe, 0xf2, 0x51, 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, + 0xed, 0xd9, 0xb7, 0x4a, 0xb2, 0xb2, 0x61, 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, + 0xdc, 0x60, 0x6c, 0x41, 0x76, 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, + 0xac, 0x9d, 0xe0, 0x62, 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, + 0xd2, 0x7c, 0x0a, 0x7c, 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, 0xda, + 0x15, 0x91, 0xde, 0x21, 0xf5, 0x55, 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, 0x42, 0x44, 0x81, + 0x8c, 0x94, 0xb4, 0x50, 0x1e, 0x20, 0x42, 0x82, 0x98, 0xc2, 0x3b, 0x10, 0x48, 0xec, 0xa6, 0x39, + 0x63, 0x13, 0xa7, 0x01, 0x94, 0x40, 0xff, 0x88, 0x0f, 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, + 0xcb, 0xf6, 0xc8, 0x21, 0x59, 0xaa, 0x38, 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, + 0xc8, 0x03, 0x42, 0x2a, 0x4b, 0xf6, 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, + 0x7e, 0x00, 0xbc, 0x2f, 0x46, 0x96, 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, + 0x8c, 0xc2, 0x05, 0xf7, 0x54, 0x51, 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, 0x99, + 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, 0x50, 0x84, 0xf5, + 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, 0x4c, 0x52, 0x4f, 0x20, 0xa3, 0x61, 0x23, 0x77, 0x12, 0xd3, + 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, 0x70, 0xec, 0x14, 0x91, 0xf9, 0x85, 0x61, 0xd5, 0x7e, 0x98, + 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, + ]; + + let decompression_circuit = DecompressionCircuit:: { + compressed_frames: vec![compressed], + _data: Default::default(), + }; + + let mock_prover = MockProver::run(16, &decompression_circuit, vec![]); + + let mock_prover = mock_prover.unwrap(); + if let Err(errors) = mock_prover.verify_par() { + log::debug!("errors.len() = {}", errors.len()); + } + + mock_prover.assert_satisfied_par(); +} \ No newline at end of file diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 04360c8a6b..f1ba20263a 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -39,7 +39,7 @@ pub use tx::Transaction; mod zstd; pub use zstd::{ - FseAuxiliaryTableData, FseSymbol, FseTableData, FseTableRow, HuffmanCodesData, TagRomTableRow, + FseAuxiliaryTableData, FseSymbol, FseTableData, FseTableRow, HuffmanCodesData, TagRomTableRow, ZstdWitnessRow, ZstdTag, N_BITS_PER_BYTE, N_BITS_SYMBOL, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, - N_JUMP_TABLE_BYTES, N_MAX_SYMBOLS, + N_JUMP_TABLE_BYTES, N_MAX_SYMBOLS, process }; diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index be29fc99c2..ab721f8e61 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1254,6 +1254,7 @@ fn process_block_zstd_lstream( (byte_offset + len, witness_rows, decoded_symbols) } +/// Process a slice of bytes into decompression circuit witness rows pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec) { let mut witness_rows = vec![]; let mut literals: Vec = vec![]; diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index c54352f63e..8129a9a8c2 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -615,15 +615,22 @@ impl FseAuxiliaryTableData { } #[derive(Clone, Debug)] +/// Row witness value for decompression circuit pub struct ZstdWitnessRow { + /// Current decoding state during Zstd decompression pub state: ZstdState, + /// Data on compressed data pub encoded_data: EncodedData, + /// Data on decompressed data pub decoded_data: DecodedData, + /// Huffman code bitstring marker that devides bitstream into symbol segments pub huffman_data: HuffmanData, + /// Fse decoding state transition data pub fse_data: FseTableRow, } impl ZstdWitnessRow { + /// Construct the first row of witnesses for decompression circuit pub fn init(src_len: usize) -> Self { Self { state: ZstdState::default(), From f2d4f7afc9b8cbeb3d806a3a6f04708061cae120 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 16:03:36 -0500 Subject: [PATCH 042/165] Assignment correction --- zkevm-circuits/src/decompression_circuit.rs | 95 +++++++-------------- 1 file changed, 33 insertions(+), 62 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 1eecc69b4f..92263a30e7 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2366,70 +2366,41 @@ impl DecompressionCircuitConfig { /// Assign witness to the decompression circuit. pub(crate) fn assign( &self, - _layouter: &mut impl Layouter, - _witness_rows: Vec>, - _challenges: &Challenges>, + layouter: &mut impl Layouter, + witness_rows: Vec>, + challenges: &Challenges>, ) -> Result<(), Error> { - // let dt_rows = inputs - // .iter() - // .flat_map(|input| input.gen_data_table(challenges)) - // .collect::>(); - // let sm_rows = inputs - // .iter() - // .flat_map(|input| input.gen_sm_witness(challenges)) - // .collect::>(); - - // debug_assert!(sm_rows.len() <= last_row); - - // self.rom_table.load(layouter)?; - - // log::debug!("num_sm_rows: {}", sm_rows.len()); - // log::debug!("num_dt_rows: {}", dt_rows.len()); - - // layouter.assign_region( - // || "RLP data table region", - // |mut region| { - // for (i, dt_row) in dt_rows.iter().enumerate() { - // let dt_row_next = if i == dt_rows.len() - 1 { - // None - // } else { - // Some(&dt_rows[i + 1]) - // }; - // self.assign_dt_row(&mut region, i, dt_row, dt_row_next)?; - // } - // // assign padding rows - // Ok(()) - // }, - // )?; - // layouter.assign_region( - // || "RLP sm region", - // |mut region| { - // for (i, sm_row) in sm_rows.iter().enumerate() { - // let sm_row_next = if i == sm_rows.len() - 1 { - // None - // } else { - // Some(&sm_rows[i + 1]) - // }; - // let sm_row_prev = if i == 0 { None } else { Some(&sm_rows[i - 1]) }; - // self.assign_sm_row(&mut region, i, sm_row, sm_row_next, sm_row_prev)?; - // } - // for i in sm_rows.len()..last_row { - // self.assign_sm_end_row(&mut region, i)?; - // } - // region.assign_fixed(|| "q_first", self.q_first, 0, || Value::known(F::one()))?; - // region.assign_fixed( - // || "q_last", - // self.q_last, - // last_row - 1, - // || Value::known(F::one()), - // )?; - - // Ok(()) - // }, - // )?; - - // Ok(()) + layouter.assign_region( + || "Decompression table region", + |mut region| { + for (i, row) in witness_rows.iter().enumerate() { + region.assign_fixed( + || "q_enable", + self.q_enable, + i, + || Value::known(F::one()), + )?; + +// region.assign_advice( +// || "rlp_table.tx_id", +// self.rlp_table.tx_id, +// row, +// || Value::known(F::from(witness.rlp_table.tx_id)), +// )?; +// region.assign_advice( +// || "rlp_table.format", +// self.rlp_table.format, +// row, +// || Value::known(F::from(witness.rlp_table.format as u64)), +// )?; + + } + + Ok(()) + } + )?; + Ok(()) } } From 297ccbbc46f8ab81371dcb7944a60deb383e9340 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 17:03:41 -0500 Subject: [PATCH 043/165] Add column assignments --- zkevm-circuits/src/decompression_circuit.rs | 232 +++++++++++++++++++- 1 file changed, 220 insertions(+), 12 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 92263a30e7..e89264802b 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2380,19 +2380,227 @@ impl DecompressionCircuitConfig { i, || Value::known(F::one()), )?; + region.assign_fixed( + || "q_first", + self.q_first, + i, + || Value::known(F::from((i == 0) as u64)), + )?; + region.assign_advice( + || "is_padding", + self.is_padding, + i, + || Value::known(F::zero()), + )?; + region.assign_advice( + || "byte_idx", + self.byte_idx, + i, + || Value::known(F::from(row.encoded_data.byte_idx)), + )?; + region.assign_advice( + || "encoded_len", + self.encoded_len, + i, + || Value::known(F::from(row.encoded_data.encoded_len)), + )?; + region.assign_advice( + || "value_byte", + self.value_byte, + i, + || Value::known(F::from(row.encoded_data.value_byte as u64)), + )?; + + // let value_bits = array_init(|_| meta.advice_column()); + // let value_rlc = meta.advice_column_in(SecondPhase); + // let decoded_len = meta.advice_column(); + // let decoded_len_acc = meta.advice_column(); + // let decoded_byte = meta.advice_column(); + // let decoded_rlc = meta.advice_column_in(SecondPhase); + + + // Tag Gadget + region.assign_advice( + || "tag_gadget.tag", + self.tag_gadget.tag, + i, + || Value::known(F::from(row.state.tag as u64)), + )?; + region.assign_advice( + || "tag_gadget.tag_next", + self.tag_gadget.tag_next, + i, + || Value::known(F::from(row.state.tag_next as u64)), + )?; + region.assign_advice( + || "tag_gadget.tag_len", + self.tag_gadget.tag_len, + i, + || Value::known(F::from(row.state.tag_len as u64)), + )?; + region.assign_advice( + || "tag_gadget.tag_idx", + self.tag_gadget.tag_idx, + i, + || Value::known(F::from(row.state.tag_idx as u64)), + )?; + + // TagGadget { + // tag_bits: BinaryNumberChip::configure(meta, q_enable, Some(tag.into())), + // tag_value: meta.advice_column_in(SecondPhase), + // tag_value_acc: meta.advice_column_in(SecondPhase), + // rand_pow_tag_len: meta.advice_column_in(SecondPhase), + // max_len, + // is_output: meta.advice_column(), + // is_reverse: meta.advice_column(), + // tag_rlc: meta.advice_column_in(SecondPhase), + // tag_rlc_acc: meta.advice_column_in(SecondPhase), + // mlen_lt_0x20: LtChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(max_len, Rotation::cur()), + // |_meta| 0x20.expr(), + // range256.into(), + // ), + // is_tag_change: meta.advice_column(), + // idx_cmp_len: ComparatorChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(tag_idx, Rotation::cur()), + // |meta| meta.query_advice(tag_len, Rotation::cur()), + // range256.into(), + // ), + // len_cmp_max: ComparatorChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(tag_len, Rotation::cur()), + // |meta| meta.query_advice(max_len, Rotation::cur()), + // range256.into(), + // ), + // is_block_header: meta.advice_column(), + // is_literals_header: meta.advice_column(), + // is_fse_code: meta.advice_column(), + // is_huffman_code: meta.advice_column(), + // } + + + // Block Gadget + + // let block_gadget = { + // let block_idx = meta.advice_column(); + // let block_len = meta.advice_column(); + // BlockGadget { + // is_block: meta.advice_column(), + // idx: block_idx, + // block_len, + // is_last_block: meta.advice_column(), + // idx_cmp_len: ComparatorChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(block_idx, Rotation::cur()), + // |meta| meta.query_advice(block_len, Rotation::cur()), + // range256.into(), + // ), + // } + // }; + + + // Aux Fields + + // let aux_fields = AuxFields { + // aux1: meta.advice_column(), + // aux2: meta.advice_column(), + // aux3: meta.advice_column(), + // aux4: meta.advice_column(), + // aux5: meta.advice_column(), + // }; + + + // Bitstream Decoder + + region.assign_advice( + || "bitstream_decoder.bit_index_start", + self.bitstream_decoder.bit_index_start, + i, + || Value::known(F::from(row.huffman_data.k.0 as u64)), + )?; + region.assign_advice( + || "bitstream_decoder.bit_index_end", + self.bitstream_decoder.bit_index_end, + i, + || Value::known(F::from(row.huffman_data.k.1 as u64)), + )?; + region.assign_advice( + || "bitstream_decoder.bit_value", + self.bitstream_decoder.bit_value, + i, + || Value::known(F::from(row.huffman_data.bit_value as u64)), + )?; + // compression_debug + // region.assign_advice( + // || "bitstream_decoder.decoded_symbol", + // self.bitstream_decoder.decoded_symbol, + // i, + // || Value::known(F::from(row.huffman_data.bit_value as u64)), + // )?; + + // let bitstream_decoder = { + // BitstreamDecoder { + // bit_index_start: meta.advice_column(), + // bit_index_end, + // bitstream_contained: LtChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(bit_index_end, Rotation::cur()), + // |_| 8.expr(), + // range256.into(), + // ), + // bit_value: meta.advice_column(), + // decoded_symbol: meta.advice_column(), + // } + // }; + + + // FSE Gadget + + // region.assign_advice( + // || "fse_gadget.is_emit", + // self.fse_gadget.is_emit, + // i, + // || Value::known(F::from(is_emit as u64)), + // )?; + region.assign_advice( + || "fse_gadget.num_emitted", + self.fse_gadget.num_emitted, + i, + || Value::known(F::one()), + )?; + region.assign_advice( + || "fse_gadget.state", + self.fse_gadget.state, + i, + || Value::known(F::from(row.fse_data.state as u64)), + )?; + region.assign_advice( + || "fse_gadget.baseline", + self.fse_gadget.baseline, + i, + || Value::known(F::from(row.fse_data.baseline as u64)), + )?; + region.assign_advice( + || "fse_gadget.symbol", + self.fse_gadget.symbol, + i, + || Value::known(F::from(row.fse_data.symbol as u64)), + )?; -// region.assign_advice( -// || "rlp_table.tx_id", -// self.rlp_table.tx_id, -// row, -// || Value::known(F::from(witness.rlp_table.tx_id)), -// )?; -// region.assign_advice( -// || "rlp_table.format", -// self.rlp_table.format, -// row, -// || Value::known(F::from(witness.rlp_table.format as u64)), -// )?; + // let fse_gadget = FseGadget { + // is_emit: meta.advice_column(), + // num_emitted: meta.advice_column(), + // state: meta.advice_column(), + // baseline: meta.advice_column(), + // symbol: meta.advice_column(), + // }; } From 5c79390fad58ff964722356b1ad838fad0c18fc8 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 19:28:39 -0500 Subject: [PATCH 044/165] Organize constraint blocks --- zkevm-circuits/src/decompression_circuit.rs | 2824 +++++++++-------- .../src/decompression_circuit/dev.rs | 1 + 2 files changed, 1506 insertions(+), 1319 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index e89264802b..6f7de908a8 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -12,7 +12,7 @@ use array_init::array_init; use eth_types::Field; use gadgets::{ binary_number::{BinaryNumberChip, BinaryNumberConfig}, - comparator::{ComparatorChip, ComparatorConfig}, + comparator::{ComparatorChip, ComparatorConfig, ComparatorInstruction}, less_than::{LtChip, LtConfig}, util::{and, not, select, sum, Expr}, }; @@ -103,20 +103,26 @@ pub struct DecompressionCircuitConfig { /// The random linear combination of all decoded bytes up to and including the current one. decoded_rlc: Column, /// Block level details are specified in these columns. - block_gadget: BlockGadget, + /// compression_debug + // block_gadget: BlockGadget, + block_gadget: BlockGadget, /// All zstd tag related columns. tag_gadget: TagGadget, /// Auxiliary columns, multi-purpose depending on the current tag. aux_fields: AuxFields, /// Fields used to decode from bitstream. - bitstream_decoder: BitstreamDecoder, + /// compression_debug + bitstream_decoder: BitstreamDecoder, + // bitstream_decoder: BitstreamDecoder, /// Fields related to the application of FSE table to bitstream. fse_gadget: FseGadget, } /// Block level details are specified in these columns. #[derive(Clone, Debug)] -pub struct BlockGadget { +// compression_debug +pub struct BlockGadget { +// pub struct BlockGadget { /// Boolean column to indicate that we are processing a block. is_block: Column, /// The incremental index of the byte within this block. @@ -125,8 +131,9 @@ pub struct BlockGadget { block_len: Column, /// Boolean column to mark whether or not this is the last block. is_last_block: Column, - /// Check: block_idx <= block_len. - idx_cmp_len: ComparatorConfig, + // compression_debug + // Check: block_idx <= block_len. + // idx_cmp_len: ComparatorConfig, } /// All tag related columns are placed in this type. @@ -134,7 +141,7 @@ pub struct BlockGadget { pub struct TagGadget { /// The zstd tag at the current row. tag: Column, - /// Helper gadget to construct equality constraints against the current tag. + // Helper gadget to construct equality constraints against the current tag. tag_bits: BinaryNumberConfig, /// The tag that follows once the current tag is done processing. tag_next: Column, @@ -164,13 +171,15 @@ pub struct TagGadget { /// value, however the tag_rlc always uses the keccak randomness. tag_rlc_acc: Column, /// Helper gadget to check whether max_len < 0x20. - mlen_lt_0x20: LtConfig, + /// compression_debug + // mlen_lt_0x20: LtConfig, /// A boolean column to indicate that tag has been changed on this row. is_tag_change: Column, - /// Check: tag_idx <= tag_len. + // Check: tag_idx <= tag_len. idx_cmp_len: ComparatorConfig, - /// Check: tag_len <= max_len. - len_cmp_max: ComparatorConfig, + // compression_debug + // Check: tag_len <= max_len. + // len_cmp_max: ComparatorConfig, /// Helper column to reduce the circuit degree. Set when tag == BlockHeader. is_block_header: Column, /// Helper column to reduce the circuit degree. Set when tag == LiteralsHeader. @@ -200,7 +209,9 @@ pub struct AuxFields { /// Fields used while decoding from bitstream while not being byte-aligned, i.e. the bitstring /// could span over two bytes. #[derive(Clone, Debug)] -pub struct BitstreamDecoder { +// compression_debug +// pub struct BitstreamDecoder { +pub struct BitstreamDecoder { /// The bit-index where the bittsring begins. 0 <= bit_index_start < 8. bit_index_start: Column, /// The bit-index where the bitstring ends. 0 <= bit_index_end < 16. @@ -208,7 +219,8 @@ pub struct BitstreamDecoder { /// Helper gadget to know if the bitstring was contained in a single byte. We compare /// bit_index_end with 8 and if bit_index_end < 8 then the bitstring is contained. Otherwise it /// spans over two bytes. - bitstream_contained: LtConfig, + /// compression_debug + // bitstream_contained: LtConfig, /// The accumulated binary value of the bitstring. bit_value: Column, /// The symbol that this bitstring decodes to. We are using this for decoding using FSE table @@ -311,13 +323,14 @@ impl SubCircuitConfig for DecompressionCircuitConfig { idx: block_idx, block_len, is_last_block: meta.advice_column(), - idx_cmp_len: ComparatorChip::configure( - meta, - |meta| meta.query_fixed(q_enable, Rotation::cur()), - |meta| meta.query_advice(block_idx, Rotation::cur()), - |meta| meta.query_advice(block_len, Rotation::cur()), - range256.into(), - ), + // compression_debug + // idx_cmp_len: ComparatorChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(block_idx, Rotation::cur()), + // |meta| meta.query_advice(block_len, Rotation::cur()), + // range256.into(), + // ), } }; let tag_gadget = { @@ -339,28 +352,37 @@ impl SubCircuitConfig for DecompressionCircuitConfig { is_reverse: meta.advice_column(), tag_rlc: meta.advice_column_in(SecondPhase), tag_rlc_acc: meta.advice_column_in(SecondPhase), - mlen_lt_0x20: LtChip::configure( - meta, - |meta| meta.query_fixed(q_enable, Rotation::cur()), - |meta| meta.query_advice(max_len, Rotation::cur()), - |_meta| 0x20.expr(), - range256.into(), - ), + // compression_debug + // mlen_lt_0x20: LtChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(max_len, Rotation::cur()), + // |_meta| 0x20.expr(), + // range256.into(), + // ), is_tag_change: meta.advice_column(), + // compression_debug + // idx_cmp_len: ComparatorChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(tag_idx, Rotation::cur()), + // |meta| meta.query_advice(tag_len, Rotation::cur()), + // range256.into(), + // ), idx_cmp_len: ComparatorChip::configure( meta, |meta| meta.query_fixed(q_enable, Rotation::cur()), - |meta| meta.query_advice(tag_idx, Rotation::cur()), - |meta| meta.query_advice(tag_len, Rotation::cur()), - range256.into(), - ), - len_cmp_max: ComparatorChip::configure( - meta, - |meta| meta.query_fixed(q_enable, Rotation::cur()), - |meta| meta.query_advice(tag_len, Rotation::cur()), - |meta| meta.query_advice(max_len, Rotation::cur()), + |meta| 1.expr(), + |meta| 1.expr(), range256.into(), ), + // len_cmp_max: ComparatorChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(tag_len, Rotation::cur()), + // |meta| meta.query_advice(max_len, Rotation::cur()), + // range256.into(), + // ), is_block_header: meta.advice_column(), is_literals_header: meta.advice_column(), is_fse_code: meta.advice_column(), @@ -379,13 +401,14 @@ impl SubCircuitConfig for DecompressionCircuitConfig { BitstreamDecoder { bit_index_start: meta.advice_column(), bit_index_end, - bitstream_contained: LtChip::configure( - meta, - |meta| meta.query_fixed(q_enable, Rotation::cur()), - |meta| meta.query_advice(bit_index_end, Rotation::cur()), - |_| 8.expr(), - range256.into(), - ), + // compression_debug + // bitstream_contained: LtChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(bit_index_end, Rotation::cur()), + // |_| 8.expr(), + // range256.into(), + // ), bit_value: meta.advice_column(), decoded_symbol: meta.advice_column(), } @@ -426,45 +449,49 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: all rows", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_boolean( - "is_padding is boolean", - meta.query_advice(is_padding, Rotation::cur()), - ); - - cb.require_boolean( - "is_padding transitions from 0 -> 1 only once", - meta.query_advice(is_padding, Rotation::next()) - - meta.query_advice(is_padding, Rotation::cur()), - ); - - cb.require_boolean( - "is_last_block is boolean", - meta.query_advice(block_gadget.is_last_block, Rotation::cur()), - ); - - cb.require_equal( - "degree reduction: is_block_header check", - is_block_header(meta), - meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), - ); - - cb.require_equal( - "degree reduction: is_literals_header check", - is_zb_literals_header(meta), - meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - ); - - cb.require_equal( - "degree reduction: is_fse_code check", - is_zb_fse_code(meta), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - ); - - cb.require_equal( - "degree reduction: is_huffman_code check", - is_zb_huffman_code(meta), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - ); + // compression_debug + // cb.require_boolean( + // "is_padding is boolean", + // meta.query_advice(is_padding, Rotation::cur()), + // ); + + // cb.require_boolean( + // "is_padding transitions from 0 -> 1 only once", + // meta.query_advice(is_padding, Rotation::next()) + // - meta.query_advice(is_padding, Rotation::cur()), + // ); + + // cb.require_boolean( + // "is_last_block is boolean", + // meta.query_advice(block_gadget.is_last_block, Rotation::cur()), + // ); + + // cb.require_equal( + // "degree reduction: is_block_header check", + // is_block_header(meta), + // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + // ); + + // cb.require_equal( + // "degree reduction: is_literals_header check", + // is_zb_literals_header(meta), + // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + // ); + + // cb.require_equal( + // "degree reduction: is_fse_code check", + // is_zb_fse_code(meta), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // ); + + // cb.require_equal( + // "degree reduction: is_huffman_code check", + // is_zb_huffman_code(meta), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(meta.query_fixed(q_enable, Rotation::cur())) }); @@ -476,70 +503,75 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let bits = value_bits.map(|bit| meta.query_advice(bit, Rotation::cur())); + // compression_debug // This is also sufficient to check that value_byte is in 0..=255 - cb.require_equal( - "verify value byte's bits decomposition", - meta.query_advice(value_byte, Rotation::cur()), - select::expr( - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - bits[7].expr() - + bits[6].expr() * 2.expr() - + bits[5].expr() * 4.expr() - + bits[4].expr() * 8.expr() - + bits[3].expr() * 16.expr() - + bits[2].expr() * 32.expr() - + bits[1].expr() * 64.expr() - + bits[0].expr() * 128.expr(), - bits[0].expr() - + bits[1].expr() * 2.expr() - + bits[2].expr() * 4.expr() - + bits[3].expr() * 8.expr() - + bits[4].expr() * 16.expr() - + bits[5].expr() * 32.expr() - + bits[6].expr() * 64.expr() - + bits[7].expr() * 128.expr(), - ), - ); - for bit in bits { - cb.require_boolean("every value bit is boolean", bit.expr()); - } - - let is_new_byte = meta.query_advice(byte_idx, Rotation::next()) - - meta.query_advice(byte_idx, Rotation::cur()); - cb.require_boolean( - "byte_idx' == byte_idx or byte_idx' == byte_idx + 1", - is_new_byte.expr(), - ); - - cb.require_equal( - "encoded length remains the same", - meta.query_advice(encoded_len, Rotation::cur()), - meta.query_advice(encoded_len, Rotation::next()), - ); - - cb.require_equal( - "decoded length remains the same", - meta.query_advice(decoded_len, Rotation::cur()), - meta.query_advice(decoded_len, Rotation::next()), - ); - - cb.require_boolean( - "is_tag_change is boolean", - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - ); - + // cb.require_equal( + // "verify value byte's bits decomposition", + // meta.query_advice(value_byte, Rotation::cur()), + // select::expr( + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + // bits[7].expr() + // + bits[6].expr() * 2.expr() + // + bits[5].expr() * 4.expr() + // + bits[4].expr() * 8.expr() + // + bits[3].expr() * 16.expr() + // + bits[2].expr() * 32.expr() + // + bits[1].expr() * 64.expr() + // + bits[0].expr() * 128.expr(), + // bits[0].expr() + // + bits[1].expr() * 2.expr() + // + bits[2].expr() * 4.expr() + // + bits[3].expr() * 8.expr() + // + bits[4].expr() * 16.expr() + // + bits[5].expr() * 32.expr() + // + bits[6].expr() * 64.expr() + // + bits[7].expr() * 128.expr(), + // ), + // ); + // for bit in bits { + // cb.require_boolean("every value bit is boolean", bit.expr()); + // } + + // let is_new_byte = meta.query_advice(byte_idx, Rotation::next()) + // - meta.query_advice(byte_idx, Rotation::cur()); + // cb.require_boolean( + // "byte_idx' == byte_idx or byte_idx' == byte_idx + 1", + // is_new_byte.expr(), + // ); + + // cb.require_equal( + // "encoded length remains the same", + // meta.query_advice(encoded_len, Rotation::cur()), + // meta.query_advice(encoded_len, Rotation::next()), + // ); + + // cb.require_equal( + // "decoded length remains the same", + // meta.query_advice(decoded_len, Rotation::cur()), + // meta.query_advice(decoded_len, Rotation::next()), + // ); + + // cb.require_boolean( + // "is_tag_change is boolean", + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // ); + + // compression_debug // We also need to validate that ``is_tag_change`` was assigned correctly. Tag changes // on the next row iff: // - tag_idx == tag_len // - byte_idx' == byte_idx + 1 - let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, None); - cb.condition(and::expr([tidx_eq_tlen, is_new_byte]), |cb| { - cb.require_equal( - "is_tag_change should be set", - meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), - 1.expr(), - ); - }); + // let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, None); + // cb.condition(and::expr([tidx_eq_tlen, is_new_byte]), |cb| { + // cb.require_equal( + // "is_tag_change should be set", + // meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), + // 1.expr(), + // ); + // }); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -555,6 +587,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // Whether the previous tag was processed from back-to-front. let was_reverse = meta.query_advice(tag_gadget.is_reverse, Rotation::prev()); + // compression_debug // Validations for the end of the previous tag: // // - tag_idx::prev == tag_len::prev @@ -562,39 +595,40 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - tag::cur == tag_next::prev // - if was_reverse: tag_rlc_acc::prev == value_byte::prev // - if was_not_reverse: tag_rlc_acc::prev == tag_rlc::prev - cb.require_equal( - "tag_idx::prev == tag_len::prev", - meta.query_advice(tag_gadget.tag_idx, Rotation::prev()), - meta.query_advice(tag_gadget.tag_len, Rotation::prev()), - ); - cb.require_equal( - "tag_value::prev == tag_value_acc::prev", - meta.query_advice(tag_gadget.tag_value, Rotation::prev()), - meta.query_advice(tag_gadget.tag_value_acc, Rotation::prev()), - ); - cb.require_equal( - "tag == tag_next::prev", - meta.query_advice(tag_gadget.tag, Rotation::cur()), - meta.query_advice(tag_gadget.tag_next, Rotation::prev()), - ); - cb.condition(was_reverse.expr(), |cb| { - cb.require_equal( - "tag_rlc_acc on the last row for tag processed back-to-front", - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), - meta.query_advice(value_byte, Rotation::prev()), - ); - }); - cb.condition(not::expr(was_reverse), |cb| { - cb.require_equal( - "tag_rlc_acc == tag_rlc on the last row of tag if tag processed front-to-back", - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), - meta.query_advice(tag_gadget.tag_rlc, Rotation::prev()), - ); - }); + // cb.require_equal( + // "tag_idx::prev == tag_len::prev", + // meta.query_advice(tag_gadget.tag_idx, Rotation::prev()), + // meta.query_advice(tag_gadget.tag_len, Rotation::prev()), + // ); + // cb.require_equal( + // "tag_value::prev == tag_value_acc::prev", + // meta.query_advice(tag_gadget.tag_value, Rotation::prev()), + // meta.query_advice(tag_gadget.tag_value_acc, Rotation::prev()), + // ); + // cb.require_equal( + // "tag == tag_next::prev", + // meta.query_advice(tag_gadget.tag, Rotation::cur()), + // meta.query_advice(tag_gadget.tag_next, Rotation::prev()), + // ); + // cb.condition(was_reverse.expr(), |cb| { + // cb.require_equal( + // "tag_rlc_acc on the last row for tag processed back-to-front", + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), + // meta.query_advice(value_byte, Rotation::prev()), + // ); + // }); + // cb.condition(not::expr(was_reverse), |cb| { + // cb.require_equal( + // "tag_rlc_acc == tag_rlc on the last row of tag if tag processed front-to-back", + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), + // meta.query_advice(tag_gadget.tag_rlc, Rotation::prev()), + // ); + // }); // Whether the new tag is processed from back-to-front. let is_reverse = meta.query_advice(tag_gadget.is_reverse, Rotation::cur()); + // compression_debug // Validations for the new tag: // // - tag_idx == 1 @@ -603,39 +637,42 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - value_rlc == value_rlc::prev * rand_pow_tag_len::prev + tag_rlc::prev // - if is_reverse: tag_rlc_acc == tag_rlc on the first row // - if is_not_reverse: tag_rlc_acc == value_byte - cb.require_equal( - "tag_idx == 1", - meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), - 1.expr(), - ); - let (lt, eq) = tag_gadget.len_cmp_max.expr(meta, None); - cb.require_equal("tag_len <= max_len", lt + eq, 1.expr()); - cb.require_equal( - "tag_value_acc == value_byte", - meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), - meta.query_advice(value_byte, Rotation::cur()), - ); - cb.require_equal( - "value_rlc calculation", - meta.query_advice(value_rlc, Rotation::cur()), - meta.query_advice(value_rlc, Rotation::prev()) - * meta.query_advice(tag_gadget.rand_pow_tag_len, Rotation::prev()) - + meta.query_advice(tag_gadget.tag_rlc, Rotation::prev()), - ); - cb.condition(is_reverse.expr(), |cb| { - cb.require_equal( - "tag_rlc_acc == tag_rlc on the first row of tag processed back-to-front", - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - meta.query_advice(tag_gadget.tag_rlc, Rotation::cur()), - ); - }); - cb.condition(not::expr(is_reverse), |cb| { - cb.require_equal( - "tag_rlc_acc on the first row for tag processed from front-to-back", - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - meta.query_advice(value_byte, Rotation::cur()), - ); - }); + // cb.require_equal( + // "tag_idx == 1", + // meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), + // 1.expr(), + // ); + // let (lt, eq) = tag_gadget.len_cmp_max.expr(meta, None); + // cb.require_equal("tag_len <= max_len", lt + eq, 1.expr()); + // cb.require_equal( + // "tag_value_acc == value_byte", + // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), + // meta.query_advice(value_byte, Rotation::cur()), + // ); + // cb.require_equal( + // "value_rlc calculation", + // meta.query_advice(value_rlc, Rotation::cur()), + // meta.query_advice(value_rlc, Rotation::prev()) + // * meta.query_advice(tag_gadget.rand_pow_tag_len, Rotation::prev()) + // + meta.query_advice(tag_gadget.tag_rlc, Rotation::prev()), + // ); + // cb.condition(is_reverse.expr(), |cb| { + // cb.require_equal( + // "tag_rlc_acc == tag_rlc on the first row of tag processed back-to-front", + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + // meta.query_advice(tag_gadget.tag_rlc, Rotation::cur()), + // ); + // }); + // cb.condition(not::expr(is_reverse), |cb| { + // cb.require_equal( + // "tag_rlc_acc on the first row for tag processed from front-to-back", + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + // meta.query_advice(value_byte, Rotation::cur()), + // ); + // }); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -658,68 +695,77 @@ impl SubCircuitConfig for DecompressionCircuitConfig { tag_gadget.tag_rlc, value_rlc, ] { - cb.require_equal( - "column remains the same", - meta.query_advice(col, Rotation::cur()), - meta.query_advice(col, Rotation::prev()), - ); + // compression_debug + // cb.require_equal( + // "column remains the same", + // meta.query_advice(col, Rotation::cur()), + // meta.query_advice(col, Rotation::prev()), + // ); } + // compression_debug // tag_idx incremental check. let byte_idx_curr = meta.query_advice(byte_idx, Rotation::cur()); let byte_idx_prev = meta.query_advice(byte_idx, Rotation::prev()); let is_new_byte = byte_idx_curr - byte_idx_prev; - cb.require_equal( - "tag_idx increments if byte_idx increments", - meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), - meta.query_advice(tag_gadget.tag_idx, Rotation::prev()) + is_new_byte.expr(), - ); + // cb.require_equal( + // "tag_idx increments if byte_idx increments", + // meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), + // meta.query_advice(tag_gadget.tag_idx, Rotation::prev()) + is_new_byte.expr(), + // ); + // compression_debug // tag_value_acc calculation. let tag_value_acc_prev = meta.query_advice(tag_gadget.tag_value_acc, Rotation::prev()); let value_byte_curr = meta.query_advice(value_byte, Rotation::cur()); - cb.require_equal( - "tag_value calculation depending on whether new byte", - meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), - select::expr( - is_new_byte.expr(), - tag_value_acc_prev.expr() * 256.expr() + value_byte_curr.expr(), - tag_value_acc_prev, - ), - ); + // cb.require_equal( + // "tag_value calculation depending on whether new byte", + // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), + // select::expr( + // is_new_byte.expr(), + // tag_value_acc_prev.expr() * 256.expr() + value_byte_curr.expr(), + // tag_value_acc_prev, + // ), + // ); // tag_rlc_acc calculation depending on whether is_reverse or not. let is_reverse = meta.query_advice(tag_gadget.is_reverse, Rotation::cur()); - cb.condition(not::expr(is_new_byte.expr()), |cb| { - cb.require_equal( - "tag_rlc_acc remains the same if not a new byte", - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::next()), - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - ); - }); - cb.condition( - and::expr([is_new_byte.expr(), not::expr(is_reverse.expr())]), - |cb| { - cb.require_equal( - "tag_rlc_acc == tag_rlc_acc::prev * r + byte", - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()) - * challenges.keccak_input() - + value_byte_curr, - ); - }, - ); + // compression_debug + // cb.condition(not::expr(is_new_byte.expr()), |cb| { + // cb.require_equal( + // "tag_rlc_acc remains the same if not a new byte", + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::next()), + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + // ); + // }); + // cb.condition( + // and::expr([is_new_byte.expr(), not::expr(is_reverse.expr())]), + // |cb| { + // cb.require_equal( + // "tag_rlc_acc == tag_rlc_acc::prev * r + byte", + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()) + // * challenges.keccak_input() + // + value_byte_curr, + // ); + // }, + // ); + let value_byte_prev = meta.query_advice(value_byte, Rotation::prev()); - cb.condition(and::expr([is_new_byte, is_reverse]), |cb| { - cb.require_equal( - "tag_rlc_acc::prev = tag_rlc_acc * r + byte::prev", - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()) - * challenges.keccak_input() - + value_byte_prev, - ); - }); + // compression_debug + // cb.condition(and::expr([is_new_byte, is_reverse]), |cb| { + // cb.require_equal( + // "tag_rlc_acc::prev = tag_rlc_acc * r + byte::prev", + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()) + // * challenges.keccak_input() + // + value_byte_prev, + // ); + // }); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -728,22 +774,23 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - meta.lookup_any("DecompressionCircuit: randomness power tag_len", |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(is_padding, Rotation::cur())), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - ]); - [ - 1.expr(), // enabled - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // exponent - meta.query_advice(tag_gadget.rand_pow_tag_len, Rotation::cur()), // exponentiation - ] - .into_iter() - .zip(pow_rand_table.table_exprs(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }); + // compression_debug + // meta.lookup_any("DecompressionCircuit: randomness power tag_len", |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(is_padding, Rotation::cur())), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // ]); + // [ + // 1.expr(), // enabled + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // exponent + // meta.query_advice(tag_gadget.rand_pow_tag_len, Rotation::cur()), // exponentiation + // ] + // .into_iter() + // .zip(pow_rand_table.table_exprs(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }); debug_assert!(meta.degree() <= 9); @@ -760,18 +807,22 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // expect ``is_output`` to be set for the ZstdBlockLstream tag, this row itself // wouldn't output any decoded byte. - cb.require_equal( - "decoded length accumulator increments", - meta.query_advice(decoded_len_acc, Rotation::cur()), - meta.query_advice(decoded_len_acc, Rotation::prev()) + 1.expr(), - ); + // compression_debug + // cb.require_equal( + // "decoded length accumulator increments", + // meta.query_advice(decoded_len_acc, Rotation::cur()), + // meta.query_advice(decoded_len_acc, Rotation::prev()) + 1.expr(), + // ); - cb.require_equal( - "decoded bytes RLC calculated correctly", - meta.query_advice(decoded_rlc, Rotation::cur()), - meta.query_advice(decoded_rlc, Rotation::prev()) * challenges.keccak_input() - + meta.query_advice(decoded_byte, Rotation::cur()), - ); + // cb.require_equal( + // "decoded bytes RLC calculated correctly", + // meta.query_advice(decoded_rlc, Rotation::cur()), + // meta.query_advice(decoded_rlc, Rotation::prev()) * challenges.keccak_input() + // + meta.query_advice(decoded_byte, Rotation::cur()), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -783,51 +834,56 @@ impl SubCircuitConfig for DecompressionCircuitConfig { debug_assert!(meta.degree() <= 9); - meta.lookup( - "DecompressionCircuit: decoded byte is in U8 range", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(is_padding, Rotation::cur())), - ]); - - vec![( - condition * meta.query_advice(decoded_byte, Rotation::cur()), - range256.into(), - )] - }, - ); + // compression_debug + // meta.lookup( + // "DecompressionCircuit: decoded byte is in U8 range", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(is_padding, Rotation::cur())), + // ]); + + // vec![( + // condition * meta.query_advice(decoded_byte, Rotation::cur()), + // range256.into(), + // )] + // }, + // ); debug_assert!(meta.degree() <= 9); meta.create_gate("DecompressionCircuit: first row", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "byte_idx == 1", - meta.query_advice(byte_idx, Rotation::cur()), - 1.expr(), - ); - - cb.require_equal( - "tag == FrameHeaderDescriptor", - meta.query_advice(tag_gadget.tag, Rotation::cur()), - ZstdTag::FrameHeaderDescriptor.expr(), - ); - - cb.require_zero( - "value_rlc starts at 0", - meta.query_advice(value_rlc, Rotation::cur()), - ); - - cb.require_zero( - "decoded_rlc initialises at 0", - meta.query_advice(decoded_rlc, Rotation::cur()), - ); - cb.require_zero( - "decoded_len_acc initialises at 0", - meta.query_advice(decoded_len_acc, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "byte_idx == 1", + // meta.query_advice(byte_idx, Rotation::cur()), + // 1.expr(), + // ); + + // cb.require_equal( + // "tag == FrameHeaderDescriptor", + // meta.query_advice(tag_gadget.tag, Rotation::cur()), + // ZstdTag::FrameHeaderDescriptor.expr(), + // ); + + // cb.require_zero( + // "value_rlc starts at 0", + // meta.query_advice(value_rlc, Rotation::cur()), + // ); + + // cb.require_zero( + // "decoded_rlc initialises at 0", + // meta.query_advice(decoded_rlc, Rotation::cur()), + // ); + // cb.require_zero( + // "decoded_len_acc initialises at 0", + // meta.query_advice(decoded_len_acc, Rotation::cur()), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -838,27 +894,28 @@ impl SubCircuitConfig for DecompressionCircuitConfig { debug_assert!(meta.degree() <= 9); - meta.lookup_any( - "DecompressionCircuit: lookup for tuple (tag, tag_next, max_len, is_output)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(is_padding, Rotation::next())), - ]); - [ - meta.query_advice(tag_gadget.tag, Rotation::cur()), - meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - meta.query_advice(tag_gadget.max_len, Rotation::cur()), - meta.query_advice(tag_gadget.is_output, Rotation::cur()), - meta.query_advice(block_gadget.is_block, Rotation::cur()), - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - ] - .into_iter() - .zip(tag_rom_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for tuple (tag, tag_next, max_len, is_output)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(is_padding, Rotation::next())), + // ]); + // [ + // meta.query_advice(tag_gadget.tag, Rotation::cur()), + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // meta.query_advice(tag_gadget.max_len, Rotation::cur()), + // meta.query_advice(tag_gadget.is_output, Rotation::cur()), + // meta.query_advice(block_gadget.is_block, Rotation::cur()), + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + // ] + // .into_iter() + // .zip(tag_rom_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); debug_assert!(meta.degree() <= 9); @@ -869,26 +926,27 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let mut cb = BaseConstraintBuilder::default(); // FrameHeaderDescriptor is a single byte. - cb.require_equal( - "tag_idx == 1", - meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), - 1.expr(), - ); - cb.require_equal( - "tag_len == 1", - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - 1.expr(), - ); - cb.require_equal( - "tag_value_acc == value_byte", - meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), - meta.query_advice(value_byte, Rotation::cur()), - ); - cb.require_equal( - "tag_rlc_acc == value_byte", - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - meta.query_advice(value_byte, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "tag_idx == 1", + // meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), + // 1.expr(), + // ); + // cb.require_equal( + // "tag_len == 1", + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + // 1.expr(), + // ); + // cb.require_equal( + // "tag_value_acc == value_byte", + // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), + // meta.query_advice(value_byte, Rotation::cur()), + // ); + // cb.require_equal( + // "tag_rlc_acc == value_byte", + // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + // meta.query_advice(value_byte, Rotation::cur()), + // ); // Structure of the Frame's header descriptor. // @@ -900,31 +958,32 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // | 3 | Reserved_Bit | 0 | // | 2 | Content_Checksum_Flag | 0 | // | 1-0 | Dictionary_ID_Flag | 0 | - cb.require_equal( - "FHD: Single_Segment_Flag", - meta.query_advice(value_bits[5], Rotation::cur()), - 1.expr(), - ); - cb.require_zero( - "FHD: Unused_Bit", - meta.query_advice(value_bits[4], Rotation::cur()), - ); - cb.require_zero( - "FHD: Reserved_Bit", - meta.query_advice(value_bits[3], Rotation::cur()), - ); - cb.require_zero( - "FHD: Content_Checksum_Flag", - meta.query_advice(value_bits[2], Rotation::cur()), - ); - cb.require_zero( - "FHD: Dictionary_ID_Flag", - meta.query_advice(value_bits[1], Rotation::cur()), - ); - cb.require_zero( - "FHD: Dictionary_ID_Flag", - meta.query_advice(value_bits[0], Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "FHD: Single_Segment_Flag", + // meta.query_advice(value_bits[5], Rotation::cur()), + // 1.expr(), + // ); + // cb.require_zero( + // "FHD: Unused_Bit", + // meta.query_advice(value_bits[4], Rotation::cur()), + // ); + // cb.require_zero( + // "FHD: Reserved_Bit", + // meta.query_advice(value_bits[3], Rotation::cur()), + // ); + // cb.require_zero( + // "FHD: Content_Checksum_Flag", + // meta.query_advice(value_bits[2], Rotation::cur()), + // ); + // cb.require_zero( + // "FHD: Dictionary_ID_Flag", + // meta.query_advice(value_bits[1], Rotation::cur()), + // ); + // cb.require_zero( + // "FHD: Dictionary_ID_Flag", + // meta.query_advice(value_bits[0], Rotation::cur()), + // ); // Checks for the next tag, i.e. FrameContentSize. let fcs_flag0 = meta.query_advice(value_bits[7], Rotation::cur()); @@ -938,11 +997,15 @@ impl SubCircuitConfig for DecompressionCircuitConfig { select::expr(fcs_flag0, 4.expr(), 2.expr()), ), ); - cb.require_equal( - "tag_len' == fcs_field_size", - meta.query_advice(tag_gadget.tag_len, Rotation::next()), - fcs_field_size, - ); + // compression_debug + // cb.require_equal( + // "tag_len' == fcs_field_size", + // meta.query_advice(tag_gadget.tag_len, Rotation::next()), + // fcs_field_size, + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -969,11 +1032,15 @@ impl SubCircuitConfig for DecompressionCircuitConfig { 256.expr() + fcs_tag_value.expr(), fcs_tag_value, ); - cb.require_equal( - "decoded_len == frame_content_size", - frame_content_size, - meta.query_advice(decoded_len, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "decoded_len == frame_content_size", + // frame_content_size, + // meta.query_advice(decoded_len, Rotation::cur()), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -993,11 +1060,12 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: BlockHeader", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "tag_len == 3", - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - N_BLOCK_HEADER_BYTES.expr(), - ); + // compression_debug + // cb.require_equal( + // "tag_len == 3", + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + // N_BLOCK_HEADER_BYTES.expr(), + // ); // The lowest bit (as per little-endian representation) is whether the block is the // last block in the frame or not. @@ -1006,49 +1074,53 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // // But block header is expressed in the reverse order, which helps us in calculating // the tag_value appropriately. - cb.require_equal( - "last block check", - meta.query_advice(value_bits[7], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), - meta.query_advice( - block_gadget.is_last_block, - Rotation(N_BLOCK_HEADER_BYTES as i32), - ), - ); + // compression_debug + // cb.require_equal( + // "last block check", + // meta.query_advice(value_bits[7], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), + // meta.query_advice( + // block_gadget.is_last_block, + // Rotation(N_BLOCK_HEADER_BYTES as i32), + // ), + // ); let block_type_bit0 = meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); let block_type_bit1 = meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); - cb.require_zero( - "block type cannot be RESERVED, i.e. block_type == 3 not possible", - block_type_bit0.expr() * block_type_bit1.expr(), - ); - cb.require_equal( - "block_idx == 1", - meta.query_advice(block_gadget.idx, Rotation(N_BLOCK_HEADER_BYTES as i32)), - 1.expr(), - ); + // compression_debug + // cb.require_zero( + // "block type cannot be RESERVED, i.e. block_type == 3 not possible", + // block_type_bit0.expr() * block_type_bit1.expr(), + // ); + // cb.require_equal( + // "block_idx == 1", + // meta.query_advice(block_gadget.idx, Rotation(N_BLOCK_HEADER_BYTES as i32)), + // 1.expr(), + // ); // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear with // block type 00 or 01, i.e. the block_type_bit1 is 0. - cb.condition(not::expr(block_type_bit1), |cb| { - cb.require_equal( - "Raw/RLE blocks: tag_len == block_len", - meta.query_advice(tag_gadget.tag_len, Rotation(N_BLOCK_HEADER_BYTES as i32)), - meta.query_advice( - block_gadget.block_len, - Rotation(N_BLOCK_HEADER_BYTES as i32), - ), - ); - }); + // compression_debug + // cb.condition(not::expr(block_type_bit1), |cb| { + // cb.require_equal( + // "Raw/RLE blocks: tag_len == block_len", + // meta.query_advice(tag_gadget.tag_len, Rotation(N_BLOCK_HEADER_BYTES as i32)), + // meta.query_advice( + // block_gadget.block_len, + // Rotation(N_BLOCK_HEADER_BYTES as i32), + // ), + // ); + // }); // Validate that for an RLE block: value_byte == decoded_byte. - cb.condition(block_type_bit0, |cb| { - cb.require_equal( - "for RLE block, value_byte == decoded_byte", - meta.query_advice(value_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), - meta.query_advice(decoded_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), - ); - }); + // compression_debug + // cb.condition(block_type_bit0, |cb| { + // cb.require_equal( + // "for RLE block, value_byte == decoded_byte", + // meta.query_advice(value_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), + // meta.query_advice(decoded_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), + // ); + // }); // If this wasn't the first block, then the previous block's last byte should have // block's idx == block length. @@ -1056,11 +1128,15 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // This block is the first block iff the FrameContentSize tag precedes it. However we // assume that the block_idx and block_len will be set to 0 for FrameContentSize as it // is not part of a "block". - cb.require_equal( - "block_idx::prev == block_len::prev", - meta.query_advice(block_gadget.idx, Rotation::prev()), - meta.query_advice(block_gadget.block_len, Rotation::prev()), - ); + // compression_debug + // cb.require_equal( + // "block_idx::prev == block_len::prev", + // meta.query_advice(block_gadget.idx, Rotation::prev()), + // meta.query_advice(block_gadget.block_len, Rotation::prev()), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1072,25 +1148,29 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let mut cb = BaseConstraintBuilder::default(); // If byte_idx increments, then block_gadet.idx should also increment. - cb.require_equal( - "idx in block increments if byte_idx increments", - meta.query_advice(block_gadget.idx, Rotation::next()) - - meta.query_advice(block_gadget.idx, Rotation::cur()), - meta.query_advice(byte_idx, Rotation::next()) - - meta.query_advice(byte_idx, Rotation::cur()), - ); - - cb.require_equal( - "block_len remains unchanged", - meta.query_advice(block_gadget.block_len, Rotation::next()), - meta.query_advice(block_gadget.block_len, Rotation::cur()), - ); - - cb.require_equal( - "is_last_block remains unchanged", - meta.query_advice(block_gadget.is_last_block, Rotation::next()), - meta.query_advice(block_gadget.is_last_block, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "idx in block increments if byte_idx increments", + // meta.query_advice(block_gadget.idx, Rotation::next()) + // - meta.query_advice(block_gadget.idx, Rotation::cur()), + // meta.query_advice(byte_idx, Rotation::next()) + // - meta.query_advice(byte_idx, Rotation::cur()), + // ); + + // cb.require_equal( + // "block_len remains unchanged", + // meta.query_advice(block_gadget.block_len, Rotation::next()), + // meta.query_advice(block_gadget.block_len, Rotation::cur()), + // ); + + // cb.require_equal( + // "is_last_block remains unchanged", + // meta.query_advice(block_gadget.is_last_block, Rotation::next()), + // meta.query_advice(block_gadget.is_last_block, Rotation::cur()), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1101,107 +1181,121 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: handle end of other blocks", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "tag_next depending on whether or not this is the last block", - meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - ZstdTag::BlockHeader.expr(), - ); + // compression_debug + // cb.require_equal( + // "tag_next depending on whether or not this is the last block", + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // ZstdTag::BlockHeader.expr(), + // ); - cb.require_equal( - "block_idx == block_len", - meta.query_advice(block_gadget.idx, Rotation::cur()), - meta.query_advice(block_gadget.block_len, Rotation::cur()), - ); + // cb.require_equal( + // "block_idx == block_len", + // meta.query_advice(block_gadget.idx, Rotation::cur()), + // meta.query_advice(block_gadget.block_len, Rotation::cur()), + // ); - let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); + + // compression_debug + // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), not::expr(meta.query_advice(is_padding, Rotation::cur())), - idx_eq_len, + // compression_debug + // idx_eq_len, not::expr(meta.query_advice(block_gadget.is_last_block, Rotation::cur())), ])) }); meta.create_gate("DecompressionCircuit: handle end of last block", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "tag_next depending on whether or not this is the last block", - meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - ZstdTag::Null.expr(), - ); - - cb.require_equal( - "decoded_len has been reached if last block", - meta.query_advice(decoded_len_acc, Rotation::cur()), - meta.query_advice(decoded_len, Rotation::cur()), - ); - - cb.require_equal( - "byte idx has reached the encoded len", - meta.query_advice(byte_idx, Rotation::cur()), - meta.query_advice(encoded_len, Rotation::cur()), - ); - - cb.require_equal( - "block can end only on Raw/Rle/TODO tag", - sum::expr([ - is_raw_block(meta), - is_rle_block(meta), - // TODO: there will be other tags where a block ends - ]), - 1.expr(), - ); - - cb.require_equal( - "block_idx == block_len", - meta.query_advice(block_gadget.idx, Rotation::cur()), - meta.query_advice(block_gadget.block_len, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "tag_next depending on whether or not this is the last block", + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // ZstdTag::Null.expr(), + // ); + + // cb.require_equal( + // "decoded_len has been reached if last block", + // meta.query_advice(decoded_len_acc, Rotation::cur()), + // meta.query_advice(decoded_len, Rotation::cur()), + // ); + + // cb.require_equal( + // "byte idx has reached the encoded len", + // meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(encoded_len, Rotation::cur()), + // ); + + // cb.require_equal( + // "block can end only on Raw/Rle/TODO tag", + // sum::expr([ + // is_raw_block(meta), + // is_rle_block(meta), + // // TODO: there will be other tags where a block ends + // ]), + // 1.expr(), + // ); + + // cb.require_equal( + // "block_idx == block_len", + // meta.query_advice(block_gadget.idx, Rotation::cur()), + // meta.query_advice(block_gadget.block_len, Rotation::cur()), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); - let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); + // compression_debug + // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), not::expr(meta.query_advice(is_padding, Rotation::cur())), meta.query_advice(block_gadget.is_last_block, Rotation::cur()), - idx_eq_len, + // compression_debug + // idx_eq_len, ])) }); - meta.lookup( - "DecompressionCircuit: BlockHeader (BlockSize == BlockHeader >> 3)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), - ]); - let range_value = meta.query_advice(tag_gadget.tag_value, Rotation::cur()) - - (meta.query_advice( - block_gadget.block_len, - Rotation(N_BLOCK_HEADER_BYTES as i32), - ) * 8.expr()); - vec![(condition * range_value, range8.into())] - }, - ); - meta.lookup_any( - "DecompressionCircuit: lookup for tuple (block_type, tag_next)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), - ]); - [ - meta.query_advice(tag_gadget.tag, Rotation::cur()), - meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), - meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), - meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - ] - .into_iter() - .zip(block_type_rom_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup( + // "DecompressionCircuit: BlockHeader (BlockSize == BlockHeader >> 3)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + // ]); + // let range_value = meta.query_advice(tag_gadget.tag_value, Rotation::cur()) + // - (meta.query_advice( + // block_gadget.block_len, + // Rotation(N_BLOCK_HEADER_BYTES as i32), + // ) * 8.expr()); + // vec![(condition * range_value, range8.into())] + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for tuple (block_type, tag_next)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + // ]); + // [ + // meta.query_advice(tag_gadget.tag, Rotation::cur()), + // meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), + // meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // ] + // .into_iter() + // .zip(block_type_rom_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); debug_assert!(meta.degree() <= 9); @@ -1211,11 +1305,15 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: RawBlock", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "value byte == decoded byte", - meta.query_advice(value_byte, Rotation::cur()), - meta.query_advice(decoded_byte, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "value byte == decoded byte", + // meta.query_advice(value_byte, Rotation::cur()), + // meta.query_advice(decoded_byte, Rotation::cur()), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1234,23 +1332,27 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: RleBlock", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "value byte == decoded byte", - meta.query_advice(value_byte, Rotation::cur()), - meta.query_advice(decoded_byte, Rotation::cur()), - ); - - cb.require_equal( - "decoded byte remains the same", - meta.query_advice(decoded_byte, Rotation::cur()), - meta.query_advice(decoded_byte, Rotation::prev()), - ); - - cb.require_equal( - "byte idx remains the same", - meta.query_advice(byte_idx, Rotation::cur()), - meta.query_advice(byte_idx, Rotation::prev()), - ); + // compression_debug + // cb.require_equal( + // "value byte == decoded byte", + // meta.query_advice(value_byte, Rotation::cur()), + // meta.query_advice(decoded_byte, Rotation::cur()), + // ); + + // cb.require_equal( + // "decoded byte remains the same", + // meta.query_advice(decoded_byte, Rotation::cur()), + // meta.query_advice(decoded_byte, Rotation::prev()), + // ); + + // cb.require_equal( + // "byte idx remains the same", + // meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(byte_idx, Rotation::prev()), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1271,10 +1373,14 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let block_type_bit0 = meta.query_advice(value_bits[7], Rotation::cur()); let block_type_bit1 = meta.query_advice(value_bits[6], Rotation::cur()); - cb.require_zero( - "block type cannot be TREELESS, i.e. block_type == 3 not possible", - block_type_bit0 * block_type_bit1, - ); + // compression_debug + // cb.require_zero( + // "block type cannot be TREELESS, i.e. block_type == 3 not possible", + // block_type_bit0 * block_type_bit1, + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1294,13 +1400,17 @@ impl SubCircuitConfig for DecompressionCircuitConfig { aux_fields.aux3, aux_fields.aux4, ] { - cb.require_equal( - "aux fields remain the same", - meta.query_advice(col, Rotation::cur()), - meta.query_advice(col, Rotation::prev()), - ); + // compression_debug + // cb.require_equal( + // "aux fields remain the same", + // meta.query_advice(col, Rotation::cur()), + // meta.query_advice(col, Rotation::prev()), + // ); } + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); + cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), @@ -1308,121 +1418,124 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - meta.lookup_any( - "DecompressionCircuit: lookup for tuple (zstd_block_type, tag_next)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - ]); - [ - meta.query_advice(tag_gadget.tag, Rotation::cur()), - meta.query_advice(value_bits[7], Rotation::cur()), - meta.query_advice(value_bits[6], Rotation::cur()), - meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - ] - .into_iter() - .zip(block_type_rom_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: lookup for LiteralsHeader decomposition", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - ]); - [ - meta.query_advice(value_bits[7], Rotation::cur()), // block type bit0 - meta.query_advice(value_bits[6], Rotation::cur()), // block type bit1 - meta.query_advice(value_bits[5], Rotation::cur()), // size format bit0 - meta.query_advice(value_bits[4], Rotation::cur()), // size format bit1 - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header - meta.query_advice(aux_fields.aux3, Rotation::cur()), // num of lstreams - meta.query_advice(aux_fields.aux4, Rotation::cur()), // branch to take - meta.query_advice(aux_fields.aux5, Rotation::cur()), // size_format == 0b11? - ] - .into_iter() - .zip(literals_header_rom_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: lookup for LiteralsHeader regen/compr size", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - ]); - - // Which branch are we taking in the literals header decomposition. - let branch = meta.query_advice(aux_fields.aux4, Rotation::cur()); - - // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we - // already know that block type == 0b11 (TREELESS) will not occur, we can skip the - // check for not::expr(value_bits[7]). - let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); - - // Is the size format == 0b11. - let is_size_format_0b11 = meta.query_advice(aux_fields.aux5, Rotation::cur()); - - let byte0 = meta.query_advice(value_byte, Rotation::cur()); - let byte1 = select::expr( - is_compressed.expr(), - meta.query_advice(value_byte, Rotation(1)), - select::expr( - meta.query_advice(value_bits[5], Rotation::cur()), - meta.query_advice(value_byte, Rotation(1)), - 0.expr(), - ), - ); - let byte2 = select::expr( - is_compressed.expr(), - meta.query_advice(value_byte, Rotation(2)), - select::expr( - meta.query_advice(value_bits[5], Rotation::cur()), - meta.query_advice(value_byte, Rotation(2)), - 0.expr(), - ), - ); - let byte3 = select::expr( - is_compressed.expr(), - select::expr( - meta.query_advice(value_bits[5], Rotation::cur()), - meta.query_advice(value_byte, Rotation(3)), - 0.expr(), - ), - 0.expr(), - ); - let byte4 = select::expr( - is_compressed * is_size_format_0b11, - meta.query_advice(value_byte, Rotation(4)), - 0.expr(), - ); - - [ - meta.query_advice(byte_idx, Rotation::cur()), // byte offset - branch, // branch - byte0, // byte0 - byte1, // byte1 - byte2, // byte2 - byte3, // byte3 - byte4, // byte4 - meta.query_advice(aux_fields.aux1, Rotation::cur()), // regenerated size - meta.query_advice(aux_fields.aux2, Rotation::cur()), // compressed size - ] - .into_iter() - .zip(literals_header_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for tuple (zstd_block_type, tag_next)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + // ]); + // [ + // meta.query_advice(tag_gadget.tag, Rotation::cur()), + // meta.query_advice(value_bits[7], Rotation::cur()), + // meta.query_advice(value_bits[6], Rotation::cur()), + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // ] + // .into_iter() + // .zip(block_type_rom_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for LiteralsHeader decomposition", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + // ]); + // [ + // meta.query_advice(value_bits[7], Rotation::cur()), // block type bit0 + // meta.query_advice(value_bits[6], Rotation::cur()), // block type bit1 + // meta.query_advice(value_bits[5], Rotation::cur()), // size format bit0 + // meta.query_advice(value_bits[4], Rotation::cur()), // size format bit1 + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header + // meta.query_advice(aux_fields.aux3, Rotation::cur()), // num of lstreams + // meta.query_advice(aux_fields.aux4, Rotation::cur()), // branch to take + // meta.query_advice(aux_fields.aux5, Rotation::cur()), // size_format == 0b11? + // ] + // .into_iter() + // .zip(literals_header_rom_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for LiteralsHeader regen/compr size", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + // ]); + + // // Which branch are we taking in the literals header decomposition. + // let branch = meta.query_advice(aux_fields.aux4, Rotation::cur()); + + // // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we + // // already know that block type == 0b11 (TREELESS) will not occur, we can skip the + // // check for not::expr(value_bits[7]). + // let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); + + // // Is the size format == 0b11. + // let is_size_format_0b11 = meta.query_advice(aux_fields.aux5, Rotation::cur()); + + // let byte0 = meta.query_advice(value_byte, Rotation::cur()); + // let byte1 = select::expr( + // is_compressed.expr(), + // meta.query_advice(value_byte, Rotation(1)), + // select::expr( + // meta.query_advice(value_bits[5], Rotation::cur()), + // meta.query_advice(value_byte, Rotation(1)), + // 0.expr(), + // ), + // ); + // let byte2 = select::expr( + // is_compressed.expr(), + // meta.query_advice(value_byte, Rotation(2)), + // select::expr( + // meta.query_advice(value_bits[5], Rotation::cur()), + // meta.query_advice(value_byte, Rotation(2)), + // 0.expr(), + // ), + // ); + // let byte3 = select::expr( + // is_compressed.expr(), + // select::expr( + // meta.query_advice(value_bits[5], Rotation::cur()), + // meta.query_advice(value_byte, Rotation(3)), + // 0.expr(), + // ), + // 0.expr(), + // ); + // let byte4 = select::expr( + // is_compressed * is_size_format_0b11, + // meta.query_advice(value_byte, Rotation(4)), + // 0.expr(), + // ); + + // [ + // meta.query_advice(byte_idx, Rotation::cur()), // byte offset + // branch, // branch + // byte0, // byte0 + // byte1, // byte1 + // byte2, // byte2 + // byte3, // byte3 + // byte4, // byte4 + // meta.query_advice(aux_fields.aux1, Rotation::cur()), // regenerated size + // meta.query_advice(aux_fields.aux2, Rotation::cur()), // compressed size + // ] + // .into_iter() + // .zip(literals_header_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); debug_assert!(meta.degree() <= 9); @@ -1432,28 +1545,32 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlock Raw bytes", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "value_byte == decoded_byte", - meta.query_advice(value_byte, Rotation::cur()), - meta.query_advice(decoded_byte, Rotation::cur()), - ); - - cb.condition( - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - |cb| { - cb.require_equal( - "tag_len == regen_size", - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - meta.query_advice(aux_fields.aux1, Rotation::prev()), - ); - }, - ); - - cb.require_equal( - "byte_idx increments", - meta.query_advice(byte_idx, Rotation::cur()), - meta.query_advice(byte_idx, Rotation::prev()) + 1.expr(), - ); + // compression_debug + // cb.require_equal( + // "value_byte == decoded_byte", + // meta.query_advice(value_byte, Rotation::cur()), + // meta.query_advice(decoded_byte, Rotation::cur()), + // ); + + // cb.condition( + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // |cb| { + // cb.require_equal( + // "tag_len == regen_size", + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + // meta.query_advice(aux_fields.aux1, Rotation::prev()), + // ); + // }, + // ); + + // cb.require_equal( + // "byte_idx increments", + // meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(byte_idx, Rotation::prev()) + 1.expr(), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1469,33 +1586,37 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlock RLE bytes", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "value_byte == decoded_byte", - meta.query_advice(value_byte, Rotation::cur()), - meta.query_advice(decoded_byte, Rotation::cur()), - ); - - let is_tag_change = meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()); - cb.condition(is_tag_change.expr(), |cb| { - cb.require_equal( - "tag_len == regen_size", - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - meta.query_advice(aux_fields.aux1, Rotation::prev()), - ); - }); - - cb.condition(not::expr(is_tag_change), |cb| { - cb.require_equal( - "byte_idx remains the same", - meta.query_advice(byte_idx, Rotation::cur()), - meta.query_advice(byte_idx, Rotation::prev()), - ); - cb.require_equal( - "decoded byte remains the same", - meta.query_advice(decoded_byte, Rotation::cur()), - meta.query_advice(decoded_byte, Rotation::prev()), - ); - }); + // compression_debug + // cb.require_equal( + // "value_byte == decoded_byte", + // meta.query_advice(value_byte, Rotation::cur()), + // meta.query_advice(decoded_byte, Rotation::cur()), + // ); + + // let is_tag_change = meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()); + // cb.condition(is_tag_change.expr(), |cb| { + // cb.require_equal( + // "tag_len == regen_size", + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + // meta.query_advice(aux_fields.aux1, Rotation::prev()), + // ); + // }); + + // cb.condition(not::expr(is_tag_change), |cb| { + // cb.require_equal( + // "byte_idx remains the same", + // meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(byte_idx, Rotation::prev()), + // ); + // cb.require_equal( + // "decoded byte remains the same", + // meta.query_advice(decoded_byte, Rotation::cur()), + // meta.query_advice(decoded_byte, Rotation::prev()), + // ); + // }); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1525,48 +1646,53 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // byte (huffman header) itself. let tag_len_fse_code = meta.query_advice(tag_gadget.tag_len, Rotation::cur()); let tag_len_huffman_code = meta.query_advice(aux_fields.aux1, Rotation::cur()); - cb.require_equal( - "huffman header value byte check", - meta.query_advice(value_byte, Rotation::cur()) + 1.expr(), - tag_len_fse_code + tag_len_huffman_code, - ); + // compression_debug + // cb.require_equal( + // "huffman header value byte check", + // meta.query_advice(value_byte, Rotation::cur()) + 1.expr(), + // tag_len_fse_code + tag_len_huffman_code, + // ); // The huffman tree description starts at this byte index. We identify the FSE and // Huffman tables using this byte index. We store this in auxiliary field aux3. - cb.require_equal( - "huffman header byte offset assignment", - meta.query_advice(byte_idx, Rotation::cur()), - meta.query_advice(aux_fields.aux3, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "huffman header byte offset assignment", + // meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(aux_fields.aux3, Rotation::cur()), + // ); // We know that the next byte is the start of processing bitstream to construct the // FSE table. The first 4 bits are used to calculate the accuracy log (and the // table size) of the table. So the first bitstring that's decoded starts from // bit_index 4 (considering that it is 0-indexed). - cb.require_equal( - "bit_index_start of the first bitstring", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - 4.expr(), - ); + // compression_debug + // cb.require_equal( + // "bit_index_start of the first bitstring", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // 4.expr(), + // ); // At every row, a new symbol is decoded. This symbol stands for the weight in the // canonical Huffman code representation. So we start at symbol == S0, i.e. 0 and // increment until we've decoded the last symbol that has a weight. Any symbols // beyond that will have a weight of 0. - cb.require_zero( - "first symbol that is decoded in FSE is S0, i.e. 0", - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::next()), - ); + // compression_debug + // cb.require_zero( + // "first symbol that is decoded in FSE is S0, i.e. 0", + // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::next()), + // ); // We use the aux5 column as an accumulator for the number of times each symbol // appears. At the end of decoding the accumulator should match the table size. // // The number of times a symbol appears is R - 1, where R is the binary value read // from the bitstring. - cb.require_equal( - "symbol count accumulator", - meta.query_advice(aux_fields.aux5, Rotation::next()) + 1.expr(), - meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), - ); + // compression_debug + // cb.require_equal( + // "symbol count accumulator", + // meta.query_advice(aux_fields.aux5, Rotation::next()) + 1.expr(), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), + // ); // We mark the accuracy log to aux4 column and re-use later. let accuracy_log = meta.query_advice(value_bits[0], Rotation::next()) @@ -1574,11 +1700,15 @@ impl SubCircuitConfig for DecompressionCircuitConfig { + meta.query_advice(value_bits[2], Rotation::next()) * 4.expr() + meta.query_advice(value_bits[3], Rotation::next()) * 8.expr() + 5.expr(); - cb.require_equal( - "accuracy log check", - meta.query_advice(aux_fields.aux4, Rotation::next()), - accuracy_log, - ); + // compression_debug + // cb.require_equal( + // "accuracy log check", + // meta.query_advice(aux_fields.aux4, Rotation::next()), + // accuracy_log, + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1587,38 +1717,41 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - meta.lookup("DecompressionCircuit: huffman header byte value", |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - ]); - let range_value = meta.query_advice(value_byte, Rotation::cur()); - vec![(condition * range_value, range128.into())] - }); - meta.lookup_any( - "DecompressionCircuit: table size == 1 << accuracy log", - |meta| { - // We know that the next byte is the first byte of the FSE code. The first 4 bits - // contribute to the accuracy log of the FSE table. - // - // - We use aux2 to hold the table size of the FSE table, i.e. 1 << accuracy_log. - // - We use aux4 to hold the accuracy log. - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - ]); - [ - meta.query_advice(aux_fields.aux4, Rotation::next()), - meta.query_advice(aux_fields.aux2, Rotation::next()), - ] - .into_iter() - .zip(pow2_table.table_exprs(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup("DecompressionCircuit: huffman header byte value", |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // ]); + // let range_value = meta.query_advice(value_byte, Rotation::cur()); + // vec![(condition * range_value, range128.into())] + // }); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: table size == 1 << accuracy log", + // |meta| { + // // We know that the next byte is the first byte of the FSE code. The first 4 bits + // // contribute to the accuracy log of the FSE table. + // // + // // - We use aux2 to hold the table size of the FSE table, i.e. 1 << accuracy_log. + // // - We use aux4 to hold the accuracy log. + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // ]); + // [ + // meta.query_advice(aux_fields.aux4, Rotation::next()), + // meta.query_advice(aux_fields.aux2, Rotation::next()), + // ] + // .into_iter() + // .zip(pow2_table.table_exprs(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + meta.create_gate( "DecompressionCircuit: ZstdBlockFseCode (fse code)", |meta| { @@ -1633,38 +1766,40 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - aux4 is used to denote the accuracy log, which is required later on while // processing the Huffman data. for col in [aux_fields.aux1, aux_fields.aux2, aux_fields.aux3, aux_fields.aux4] { - cb.require_equal( - "aux fields aux1, aux2, aux3, aux4 remain the same", - meta.query_advice(col, Rotation::cur()), - meta.query_advice(col, Rotation::prev()), - ); + // compression_debug + // cb.require_equal( + // "aux fields aux1, aux2, aux3, aux4 remain the same", + // meta.query_advice(col, Rotation::cur()), + // meta.query_advice(col, Rotation::prev()), + // ); } // The decoded symbol keeps incrementing in the FSE code reconstruction. Since // we've already done the check for the first symbol in the huffman header gate, we // only check for increments. let is_last = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); - cb.condition(not::expr(is_last.expr()), |cb| { - cb.require_equal( - "fse table reconstruction: decoded symbol increments", - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()) - + 1.expr(), - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::next()), - ); - cb.require_equal( - "number of times a symbol appears is accumulated correctly", - meta.query_advice(aux_fields.aux5, Rotation::next()) + 1.expr(), - meta.query_advice(aux_fields.aux5, Rotation::cur()) - + meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), - ); - }); - cb.condition(is_last, |cb| { - cb.require_equal( - "on the last row, accumulated number of symbols is the table size of FSE table", - meta.query_advice(aux_fields.aux5, Rotation::cur()), - meta.query_advice(aux_fields.aux2, Rotation::cur()), - ); - }); + // compression_debug + // cb.condition(not::expr(is_last.expr()), |cb| { + // cb.require_equal( + // "fse table reconstruction: decoded symbol increments", + // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()) + // + 1.expr(), + // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::next()), + // ); + // cb.require_equal( + // "number of times a symbol appears is accumulated correctly", + // meta.query_advice(aux_fields.aux5, Rotation::next()) + 1.expr(), + // meta.query_advice(aux_fields.aux5, Rotation::cur()) + // + meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), + // ); + // }); + // cb.condition(is_last, |cb| { + // cb.require_equal( + // "on the last row, accumulated number of symbols is the table size of FSE table", + // meta.query_advice(aux_fields.aux5, Rotation::cur()), + // meta.query_advice(aux_fields.aux2, Rotation::cur()), + // ); + // }); // The next bitstring to be decoded should start right after the current bitstring // ends, i.e. bit_index_start' == bit_index_end + 1. @@ -1673,21 +1808,26 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - bit_index_start' == (bit_index_end % 8) + 1. let bit_index_end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); - let bit_index_end_mod8 = select::expr( - bitstream_decoder.bitstream_contained.is_lt(meta, None), - bit_index_end.expr(), - bit_index_end - 8.expr(), - ); - cb.require_equal( - "start of next bitstring is right after the end of the current", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - bit_index_end_mod8 + 1.expr(), - ); + // compression_debug + // let bit_index_end_mod8 = select::expr( + // bitstream_decoder.bitstream_contained.is_lt(meta, None), + // bit_index_end.expr(), + // bit_index_end - 8.expr(), + // ); + // compression_debug + // cb.require_equal( + // "start of next bitstring is right after the end of the current", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // bit_index_end_mod8 + 1.expr(), + // ); // The check that bit_index_end >= bit_index_start is indirectly verified through // the lookup to the HuffmanCodesBitstringAccumulationTable, since the bit_index in // that table is a fixed column. + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); + cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), @@ -1695,162 +1835,167 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (contained bitstream start)", - |meta| { - let (huffman_tree_byte_offset, start, bit_value) = ( - meta.query_advice(aux_fields.aux3, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - bitstream_decoder.bitstream_contained.is_lt(meta, None), - ]); - [ - huffman_tree_byte_offset, // huffman tree byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - 1.expr(), // bitstring length accumulator, starts at 1 - start, // bit index start - 1.expr(), // denotes that this bit index is a part of the bitstring - 1.expr(), // denotes that this bit index is a part of the bitstring - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (contained bitstream end)", - |meta| { - let (start, end, bit_value) = ( - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - bitstream_decoder.bitstream_contained.is_lt(meta, None), - ]); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", - |meta| { - let (start, bit_value) = ( - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(bitstream_decoder.bitstream_contained.is_lt(meta, None)), - ]); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - 1.expr(), // bitstring len acc - start, // bit index start - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", - |meta| { - let (start, end, bit_value) = ( - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(bitstream_decoder.bitstream_contained.is_lt(meta, None)), - ]); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (symbol count check)", - |meta| { - let (bit_value, decoded_symbol) = ( - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - ]); - // The FSE table reconstruction follows a variable bit packing. However we know the - // start and end bit index for the bitstring that was read. We read a value in the - // range 0..=R+1 and then subtract 1 from it to get N, i.e. the number of slots - // that were allocated to that symbol in the FSE table. This is also the count of - // the symbol in the FseTable. - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset - meta.query_advice(aux_fields.aux2, Rotation::cur()), // table size - decoded_symbol, // decoded symbol. - bit_value - 1.expr(), // symbol count - ] - .into_iter() - .zip(fse_table.table_exprs_symbol_count_check(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (contained bitstream start)", + // |meta| { + // let (huffman_tree_byte_offset, start, bit_value) = ( + // meta.query_advice(aux_fields.aux3, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // bitstream_decoder.bitstream_contained.is_lt(meta, None), + // ]); + // [ + // huffman_tree_byte_offset, // huffman tree byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // 1.expr(), // bitstring length accumulator, starts at 1 + // start, // bit index start + // 1.expr(), // denotes that this bit index is a part of the bitstring + // 1.expr(), // denotes that this bit index is a part of the bitstring + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (contained bitstream end)", + // |meta| { + // let (start, end, bit_value) = ( + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // bitstream_decoder.bitstream_contained.is_lt(meta, None), + // ]); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", + // |meta| { + // let (start, bit_value) = ( + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(bitstream_decoder.bitstream_contained.is_lt(meta, None)), + // ]); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // 1.expr(), // bitstring len acc + // start, // bit index start + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", + // |meta| { + // let (start, end, bit_value) = ( + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(bitstream_decoder.bitstream_contained.is_lt(meta, None)), + // ]); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (symbol count check)", + // |meta| { + // let (bit_value, decoded_symbol) = ( + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // ]); + // // The FSE table reconstruction follows a variable bit packing. However we know the + // // start and end bit index for the bitstring that was read. We read a value in the + // // range 0..=R+1 and then subtract 1 from it to get N, i.e. the number of slots + // // that were allocated to that symbol in the FSE table. This is also the count of + // // the symbol in the FseTable. + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset + // meta.query_advice(aux_fields.aux2, Rotation::cur()), // table size + // decoded_symbol, // decoded symbol. + // bit_value - 1.expr(), // symbol count + // ] + // .into_iter() + // .zip(fse_table.table_exprs_symbol_count_check(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); debug_assert!(meta.degree() <= 9); @@ -1864,34 +2009,35 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // Check that the aux1 field was assigned correctly for the FseCode tag. This field // should equal the tag length of the HuffmanCode tag. - cb.require_equal( - "aux field aux1 (for FseCode) is the tag_len of the next tag (HuffmanCode)", - meta.query_advice(aux_fields.aux1, Rotation::prev()), - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - ); - cb.require_equal( - "aux field aux2 (table size) is carried forward from FseCode", - meta.query_advice(aux_fields.aux2, Rotation::prev()), - meta.query_advice(aux_fields.aux2, Rotation::cur()), - ); - cb.require_equal( - "aux field aux3 (huffman header byte offset) is carried forward from FseCode", - meta.query_advice(aux_fields.aux3, Rotation::prev()), - meta.query_advice(aux_fields.aux3, Rotation::cur()), - ); - cb.require_equal( - "aux field aux4 (accuracy log) is carried along", - meta.query_advice(aux_fields.aux4, Rotation::prev()), - meta.query_advice(aux_fields.aux4, Rotation::cur()), - ); - cb.require_zero( - "is_emit == false on the first row", - meta.query_advice(fse_gadget.is_emit, Rotation::cur()), - ); - cb.require_zero( - "num_emitted starts at 0", - meta.query_advice(fse_gadget.num_emitted, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "aux field aux1 (for FseCode) is the tag_len of the next tag (HuffmanCode)", + // meta.query_advice(aux_fields.aux1, Rotation::prev()), + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + // ); + // cb.require_equal( + // "aux field aux2 (table size) is carried forward from FseCode", + // meta.query_advice(aux_fields.aux2, Rotation::prev()), + // meta.query_advice(aux_fields.aux2, Rotation::cur()), + // ); + // cb.require_equal( + // "aux field aux3 (huffman header byte offset) is carried forward from FseCode", + // meta.query_advice(aux_fields.aux3, Rotation::prev()), + // meta.query_advice(aux_fields.aux3, Rotation::cur()), + // ); + // cb.require_equal( + // "aux field aux4 (accuracy log) is carried along", + // meta.query_advice(aux_fields.aux4, Rotation::prev()), + // meta.query_advice(aux_fields.aux4, Rotation::cur()), + // ); + // cb.require_zero( + // "is_emit == false on the first row", + // meta.query_advice(fse_gadget.is_emit, Rotation::cur()), + // ); + // cb.require_zero( + // "num_emitted starts at 0", + // meta.query_advice(fse_gadget.num_emitted, Rotation::cur()), + // ); // We ignore leading 0s and a sentinel 1 bit at the start of this tag. We have 2 // cases here: @@ -1906,20 +2052,21 @@ impl SubCircuitConfig for DecompressionCircuitConfig { |cb| { // If the next row also does not emit a symbol, we have encountered 7 // leading 0s and 1 sentinel bit. i.e. value_byte == 0b_00000001. - cb.require_equal( - "7 leading 0s and a sentinel bit", - meta.query_advice(value_byte, Rotation::cur()), - 1.expr(), - ); - cb.require_equal( - "byte_idx' == byte_idx + 1", - meta.query_advice(byte_idx, Rotation::next()), - meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), - ); - cb.require_zero( - "num_emitted stays 0", - meta.query_advice(fse_gadget.num_emitted, Rotation::next()), - ); + // compression_debug + // cb.require_equal( + // "7 leading 0s and a sentinel bit", + // meta.query_advice(value_byte, Rotation::cur()), + // 1.expr(), + // ); + // cb.require_equal( + // "byte_idx' == byte_idx + 1", + // meta.query_advice(byte_idx, Rotation::next()), + // meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), + // ); + // cb.require_zero( + // "num_emitted stays 0", + // meta.query_advice(fse_gadget.num_emitted, Rotation::next()), + // ); // This means we read from ``bit_index_start == 0`` on the next row. But // the first read in the Huffman code tag is to read ``accuracy_log`` @@ -1927,21 +2074,22 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // // After reading AL number of bits, the bit value is in fact the first // state we transition to. - cb.require_zero( - "read bitstream from the 1st bit", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - ); - cb.require_equal( - "first read AL number of bits", - meta.query_advice(aux_fields.aux4, Rotation::cur()), // accuracy log - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()) - + 1.expr(), - ); - cb.require_equal( - "AL number of bits read denote the first state", - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::next()), - meta.query_advice(fse_gadget.state, Rotation(2)), - ); + // compression_debug + // cb.require_zero( + // "read bitstream from the 1st bit", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // ); + // cb.require_equal( + // "first read AL number of bits", + // meta.query_advice(aux_fields.aux4, Rotation::cur()), // accuracy log + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()) + // + 1.expr(), + // ); + // cb.require_equal( + // "AL number of bits read denote the first state", + // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::next()), + // meta.query_advice(fse_gadget.state, Rotation(2)), + // ); }, ); cb.condition( @@ -1963,19 +2111,23 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); - cb.require_equal( - "AL number of bits are read first", - meta.query_advice(aux_fields.aux4, Rotation::cur()), // accuracy log - end - start + 1.expr(), // num of bits read from bitstream - ); - cb.require_equal( - "AL number of bits read denote the first state", - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), - meta.query_advice(fse_gadget.state, Rotation::next()), - ); + // compression_debug + // cb.require_equal( + // "AL number of bits are read first", + // meta.query_advice(aux_fields.aux4, Rotation::cur()), // accuracy log + // end - start + 1.expr(), // num of bits read from bitstream + // ); + // cb.require_equal( + // "AL number of bits read denote the first state", + // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), + // meta.query_advice(fse_gadget.state, Rotation::next()), + // ); }, ); + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); + cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), @@ -1987,20 +2139,23 @@ impl SubCircuitConfig for DecompressionCircuitConfig { "DecompressionCircuit: ZstdBlockHuffmanCode (other rows)", |meta| { let mut cb = BaseConstraintBuilder::default(); - - cb.require_boolean( - "is_emit only transitions from 0 -> 1", - meta.query_advice(fse_gadget.is_emit, Rotation::cur()) - - meta.query_advice(fse_gadget.is_emit, Rotation::prev()), - ); - - for col in [aux_fields.aux2, aux_fields.aux3, aux_fields.aux4] { - cb.require_equal( - "aux fields remain unchanged", - meta.query_advice(col, Rotation::cur()), - meta.query_advice(col, Rotation::prev()), - ); - } + // compression_debug + // cb.require_boolean( + // "is_emit only transitions from 0 -> 1", + // meta.query_advice(fse_gadget.is_emit, Rotation::cur()) + // - meta.query_advice(fse_gadget.is_emit, Rotation::prev()), + // ); + + // for col in [aux_fields.aux2, aux_fields.aux3, aux_fields.aux4] { + // cb.require_equal( + // "aux fields remain unchanged", + // meta.query_advice(col, Rotation::cur()), + // meta.query_advice(col, Rotation::prev()), + // ); + // } + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -2014,37 +2169,43 @@ impl SubCircuitConfig for DecompressionCircuitConfig { |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "num_emitted increments", - meta.query_advice(fse_gadget.num_emitted, Rotation::cur()), - meta.query_advice(fse_gadget.num_emitted, Rotation::prev()) + 1.expr(), - ); + // compression_debug + // cb.require_equal( + // "num_emitted increments", + // meta.query_advice(fse_gadget.num_emitted, Rotation::cur()), + // meta.query_advice(fse_gadget.num_emitted, Rotation::prev()) + 1.expr(), + // ); // Check for state transition, except if we are on the last row of HuffmanCode. let is_last_row = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); let baseline = meta.query_advice(fse_gadget.baseline, Rotation::cur()); // baseline at state let bit_value = meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()); // bits read - cb.condition(not::expr(is_last_row.expr()), |cb| { - cb.require_equal( - "state' == baseline(state) + bit_value", - meta.query_advice(fse_gadget.state, Rotation::next()), - baseline + bit_value, - ); - }); + // compression_debug + // cb.condition(not::expr(is_last_row.expr()), |cb| { + // cb.require_equal( + // "state' == baseline(state) + bit_value", + // meta.query_advice(fse_gadget.state, Rotation::next()), + // baseline + bit_value, + // ); + // }); // If we are on the last row, the bitstream decoding ends here, i.e the // bit_index_end for this bitstring should be the last bit. - cb.condition(is_last_row, |cb| { - cb.require_equal( - "last bitstring ends at the last bit", - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - select::expr( - bitstream_decoder.bitstream_contained.is_lt(meta, None), - 7.expr(), - 15.expr(), - ), - ); - }); + // compression_debug + // cb.condition(is_last_row, |cb| { + // cb.require_equal( + // "last bitstring ends at the last bit", + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // select::expr( + // bitstream_decoder.bitstream_contained.is_lt(meta, None), + // 7.expr(), + // 15.expr(), + // ), + // ); + // }); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -2053,186 +2214,192 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (leading 0s and sentinel bit start)", - |meta| { - let huffman_tree_byte_offset = meta.query_advice(aux_fields.aux3, Rotation::cur()); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(fse_gadget.is_emit, Rotation::next()), - ]); - [ - huffman_tree_byte_offset, // huffman tree byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - 1.expr(), // bitstring value - 1.expr(), // bitstring length accumulator, starts at 1 - 0.expr(), // bit index start - 1.expr(), // denotes that this bit index is a part of the bitstring - 1.expr(), // denotes that this bit index is a part of the bitstring - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (leading 0s and sentinel bit end)", - |meta| { - // the leading 0s and sentinel bit is ``end + 1`` bits long. The first bitstream is - // read from the current row as well, and it starts at ``bit_index_start``. - let end = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()) - - 1.expr(); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(fse_gadget.is_emit, Rotation::next()), - ]); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - 1.expr(), // bitstring value - end.expr() + 1.expr(), // bitstring length - end.expr(), // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream start)", - |meta| { - let (huffman_tree_byte_offset, start, bit_value) = ( - meta.query_advice(aux_fields.aux3, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.bitstream_contained.is_lt(meta, None), - ]); - [ - huffman_tree_byte_offset, // huffman tree byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - 1.expr(), // bitstring length accumulator, starts at 1 - start, // bit index start - 1.expr(), // denotes that this bit index is a part of the bitstring - 1.expr(), // denotes that this bit index is a part of the bitstring - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream end)", - |meta| { - let (start, end, bit_value) = ( - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.bitstream_contained.is_lt(meta, None), - ]); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", - |meta| { - let (start, bit_value) = ( - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - not::expr(bitstream_decoder.bitstream_contained.is_lt(meta, None)), - ]); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - 1.expr(), // bitstring len acc - start, // bit index start - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstring end)", - |meta| { - let (start, end, bit_value) = ( - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - not::expr(bitstream_decoder.bitstream_contained.is_lt(meta, None)), - ]); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (leading 0s and sentinel bit start)", + // |meta| { + // let huffman_tree_byte_offset = meta.query_advice(aux_fields.aux3, Rotation::cur()); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(fse_gadget.is_emit, Rotation::next()), + // ]); + // [ + // huffman_tree_byte_offset, // huffman tree byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // 1.expr(), // bitstring value + // 1.expr(), // bitstring length accumulator, starts at 1 + // 0.expr(), // bit index start + // 1.expr(), // denotes that this bit index is a part of the bitstring + // 1.expr(), // denotes that this bit index is a part of the bitstring + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (leading 0s and sentinel bit end)", + // |meta| { + // // the leading 0s and sentinel bit is ``end + 1`` bits long. The first bitstream is + // // read from the current row as well, and it starts at ``bit_index_start``. + // let end = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()) + // - 1.expr(); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(fse_gadget.is_emit, Rotation::next()), + // ]); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // 1.expr(), // bitstring value + // end.expr() + 1.expr(), // bitstring length + // end.expr(), // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream start)", + // |meta| { + // let (huffman_tree_byte_offset, start, bit_value) = ( + // meta.query_advice(aux_fields.aux3, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // bitstream_decoder.bitstream_contained.is_lt(meta, None), + // ]); + // [ + // huffman_tree_byte_offset, // huffman tree byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // 1.expr(), // bitstring length accumulator, starts at 1 + // start, // bit index start + // 1.expr(), // denotes that this bit index is a part of the bitstring + // 1.expr(), // denotes that this bit index is a part of the bitstring + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream end)", + // |meta| { + // let (start, end, bit_value) = ( + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // bitstream_decoder.bitstream_contained.is_lt(meta, None), + // ]); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", + // |meta| { + // let (start, bit_value) = ( + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // not::expr(bitstream_decoder.bitstream_contained.is_lt(meta, None)), + // ]); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // 1.expr(), // bitstring len acc + // start, // bit index start + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstring end)", + // |meta| { + // let (start, end, bit_value) = ( + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // not::expr(bitstream_decoder.bitstream_contained.is_lt(meta, None)), + // ]); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), // huffman byte offset + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); // 1. We first read AL number of bits from the bitstream (say bit_value_init) and transition // to the state == bit_value_init. @@ -2252,50 +2419,55 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // emissions are the weights for the subsequent decoded values. We verify the weight of a // Huffman symbol (i.e. decoded_value) by doing a lookup to the HuffmanCodesTable: // - (huffman_tree_byte_offset, huffman_symbol, weight) - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - meta.query_advice(fse_gadget.is_emit, Rotation::cur()), - ]); - let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); - let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); - let num_bits = end - start + 1.expr(); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), - meta.query_advice(aux_fields.aux2, Rotation::cur()), - meta.query_advice(fse_gadget.state, Rotation::cur()), - meta.query_advice(fse_gadget.symbol, Rotation::cur()), - meta.query_advice(fse_gadget.baseline, Rotation::cur()), - num_bits, - ] - .into_iter() - .zip(fse_table.table_exprs_state_check(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (huffman codes table lookup)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - meta.query_advice(fse_gadget.is_emit, Rotation::cur()), - ]); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - meta.query_advice(fse_gadget.symbol, Rotation::cur()), - ] - .into_iter() - .zip(huffman_codes_table.table_exprs(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // meta.query_advice(fse_gadget.is_emit, Rotation::cur()), + // ]); + // let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); + // let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); + // let num_bits = end - start + 1.expr(); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), + // meta.query_advice(aux_fields.aux2, Rotation::cur()), + // meta.query_advice(fse_gadget.state, Rotation::cur()), + // meta.query_advice(fse_gadget.symbol, Rotation::cur()), + // meta.query_advice(fse_gadget.baseline, Rotation::cur()), + // num_bits, + // ] + // .into_iter() + // .zip(fse_table.table_exprs_state_check(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (huffman codes table lookup)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // meta.query_advice(fse_gadget.is_emit, Rotation::cur()), + // ]); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // meta.query_advice(fse_gadget.symbol, Rotation::cur()), + // ] + // .into_iter() + // .zip(huffman_codes_table.table_exprs(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + // TODO: on the last row of HuffmanCode tag, we want to make sure we have emitted N - 1 // symbols (weights), where N is the total number of huffman symbols that are being encoded // in that Huffman table. As per the canonical Huffman code representation, we only need to @@ -2309,11 +2481,15 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlockJumpTable", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "tag_len == 6", - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - N_JUMP_TABLE_BYTES.expr(), - ); + // compression_debug + // cb.require_equal( + // "tag_len == 6", + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + // N_JUMP_TABLE_BYTES.expr(), + // ); + + // compression_debug + cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -2330,6 +2506,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlockLstream", |meta| { let mut cb = BaseConstraintBuilder::default(); + // compression_debug cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ @@ -2445,6 +2622,15 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.state.tag_idx as u64)), )?; + let tag_bits = BinaryNumberChip::construct(self.tag_gadget.tag_bits); + tag_bits.assign(&mut region, i, &row.state.tag)?; + + // compression_debug + let idx_cmp_len_chip = ComparatorChip::construct(self.tag_gadget.idx_cmp_len.clone()); + // idx_cmp_len.assign(&mut region, i, F::from(row.state.tag_len), F::from(row.state.tag_idx))?; + idx_cmp_len_chip.assign(&mut region, i, F::one(), F::one())?; + + // TagGadget { // tag_bits: BinaryNumberChip::configure(meta, q_enable, Some(tag.into())), // tag_value: meta.advice_column_in(SecondPhase), diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index 1748963c7b..b59b922335 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -19,6 +19,7 @@ use crate::{ impl Circuit for DecompressionCircuit { type Config = (DecompressionCircuitConfig, Challenges); + type FloorPlanner = SimpleFloorPlanner; #[cfg(feature = "circuit-params")] type Params = (); From b97c8b94b4cb2110339b0c37cb066a7c43437aa0 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 19:40:21 -0500 Subject: [PATCH 045/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 136 +++++++++++++------- zkevm-circuits/src/witness/zstd/types.rs | 2 +- 2 files changed, 94 insertions(+), 44 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 6f7de908a8..68a2050f22 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -449,49 +449,40 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: all rows", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug - // cb.require_boolean( - // "is_padding is boolean", - // meta.query_advice(is_padding, Rotation::cur()), - // ); - - // cb.require_boolean( - // "is_padding transitions from 0 -> 1 only once", - // meta.query_advice(is_padding, Rotation::next()) - // - meta.query_advice(is_padding, Rotation::cur()), - // ); - - // cb.require_boolean( - // "is_last_block is boolean", - // meta.query_advice(block_gadget.is_last_block, Rotation::cur()), - // ); - - // cb.require_equal( - // "degree reduction: is_block_header check", - // is_block_header(meta), - // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), - // ); - - // cb.require_equal( - // "degree reduction: is_literals_header check", - // is_zb_literals_header(meta), - // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - // ); - - // cb.require_equal( - // "degree reduction: is_fse_code check", - // is_zb_fse_code(meta), - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // ); - - // cb.require_equal( - // "degree reduction: is_huffman_code check", - // is_zb_huffman_code(meta), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // ); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_boolean( + "is_padding is boolean", + meta.query_advice(is_padding, Rotation::cur()), + ); + // compression_debug TODO: Sound? + cb.require_boolean( + "is_padding transitions from 0 -> 1 only once", + meta.query_advice(is_padding, Rotation::next()) + - meta.query_advice(is_padding, Rotation::cur()), + ); + cb.require_boolean( + "is_last_block is boolean", + meta.query_advice(block_gadget.is_last_block, Rotation::cur()), + ); + cb.require_equal( + "degree reduction: is_block_header check", + is_block_header(meta), + meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + ); + cb.require_equal( + "degree reduction: is_literals_header check", + is_zb_literals_header(meta), + meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + ); + cb.require_equal( + "degree reduction: is_fse_code check", + is_zb_fse_code(meta), + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + ); + cb.require_equal( + "degree reduction: is_huffman_code check", + is_zb_huffman_code(meta), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + ); cb.gate(meta.query_fixed(q_enable, Rotation::cur())) }); @@ -2630,6 +2621,65 @@ impl DecompressionCircuitConfig { // idx_cmp_len.assign(&mut region, i, F::from(row.state.tag_len), F::from(row.state.tag_idx))?; idx_cmp_len_chip.assign(&mut region, i, F::one(), F::one())?; + let is_block_header = (row.state.tag == ZstdTag::BlockHeader) as u64; + let is_literals_header = (row.state.tag == ZstdTag::ZstdBlockLiteralsHeader) as u64; + let is_fse_code = (row.state.tag == ZstdTag::ZstdBlockFseCode) as u64; + let is_huffman_code = (row.state.tag == ZstdTag::ZstdBlockHuffmanCode) as u64; + + region.assign_advice( + || "tag_gadget.is_block_header", + self.tag_gadget.is_block_header, + i, + || Value::known(F::from(is_block_header)), + )?; + region.assign_advice( + || "tag_gadget.is_literals_header", + self.tag_gadget.is_literals_header, + i, + || Value::known(F::from(is_literals_header)), + )?; + region.assign_advice( + || "tag_gadget.is_fse_code", + self.tag_gadget.is_fse_code, + i, + || Value::known(F::from(is_fse_code)), + )?; + region.assign_advice( + || "tag_gadget.is_huffman_code", + self.tag_gadget.is_huffman_code, + i, + || Value::known(F::from(is_huffman_code)), + )?; + + +// compression_debug + // cb.require_equal( + // "degree reduction: is_block_header check", + // is_block_header(meta), + // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + // ); + + // cb.require_equal( + // "degree reduction: is_literals_header check", + // is_zb_literals_header(meta), + // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + // ); + + // cb.require_equal( + // "degree reduction: is_fse_code check", + // is_zb_fse_code(meta), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // ); + + // cb.require_equal( + // "degree reduction: is_huffman_code check", + // is_zb_huffman_code(meta), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // ); + + + + // TagGadget { // tag_bits: BinaryNumberChip::configure(meta, q_enable, Some(tag.into())), diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 8129a9a8c2..f641516036 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -159,7 +159,7 @@ impl From for BlockType { } /// Various tags that we can decode from a zstd encoded data. -#[derive(Clone, Copy, Debug, EnumIter)] +#[derive(Clone, Copy, Debug, EnumIter, PartialEq)] pub enum ZstdTag { /// Null should not occur. Null = 0, From 0e02870b8df7a41ae22a510fd26455a62579503d Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 20:04:35 -0500 Subject: [PATCH 046/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 112 ++++++++++---------- zkevm-circuits/src/witness.rs | 3 +- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 68a2050f22..ad0310d532 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -34,7 +34,7 @@ use crate::{ }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::{ - Block, ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, N_JUMP_TABLE_BYTES, process, + Block, ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, N_JUMP_TABLE_BYTES, process, value_bits_le }, }; @@ -494,35 +494,35 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let bits = value_bits.map(|bit| meta.query_advice(bit, Rotation::cur())); - // compression_debug // This is also sufficient to check that value_byte is in 0..=255 - // cb.require_equal( - // "verify value byte's bits decomposition", - // meta.query_advice(value_byte, Rotation::cur()), - // select::expr( - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - // bits[7].expr() - // + bits[6].expr() * 2.expr() - // + bits[5].expr() * 4.expr() - // + bits[4].expr() * 8.expr() - // + bits[3].expr() * 16.expr() - // + bits[2].expr() * 32.expr() - // + bits[1].expr() * 64.expr() - // + bits[0].expr() * 128.expr(), - // bits[0].expr() - // + bits[1].expr() * 2.expr() - // + bits[2].expr() * 4.expr() - // + bits[3].expr() * 8.expr() - // + bits[4].expr() * 16.expr() - // + bits[5].expr() * 32.expr() - // + bits[6].expr() * 64.expr() - // + bits[7].expr() * 128.expr(), - // ), - // ); - // for bit in bits { - // cb.require_boolean("every value bit is boolean", bit.expr()); - // } + cb.require_equal( + "verify value byte's bits decomposition", + meta.query_advice(value_byte, Rotation::cur()), + select::expr( + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + bits[7].expr() + + bits[6].expr() * 2.expr() + + bits[5].expr() * 4.expr() + + bits[4].expr() * 8.expr() + + bits[3].expr() * 16.expr() + + bits[2].expr() * 32.expr() + + bits[1].expr() * 64.expr() + + bits[0].expr() * 128.expr(), + bits[0].expr() + + bits[1].expr() * 2.expr() + + bits[2].expr() * 4.expr() + + bits[3].expr() * 8.expr() + + bits[4].expr() * 16.expr() + + bits[5].expr() * 32.expr() + + bits[6].expr() * 64.expr() + + bits[7].expr() * 128.expr(), + ), + ); + for bit in bits { + cb.require_boolean("every value bit is boolean", bit.expr()); + } + // compression_debug // let is_new_byte = meta.query_advice(byte_idx, Rotation::next()) // - meta.query_advice(byte_idx, Rotation::cur()); // cb.require_boolean( @@ -2572,12 +2572,35 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.encoded_data.encoded_len)), )?; + + // Byte value and bits decomposition region.assign_advice( || "value_byte", self.value_byte, i, || Value::known(F::from(row.encoded_data.value_byte as u64)), )?; + let bits = value_bits_le(row.encoded_data.value_byte); + let is_reverse = row.encoded_data.reverse; + for (idx, col) in self.value_bits.iter().rev().enumerate() { + region.assign_advice( + || "value_bits", + *col, + i, + || Value::known( + F::from( + (if is_reverse { bits[idx] } else { bits[N_BITS_PER_BYTE - idx - 1] }) as u64 + ) + ), + )?; + } + + + + + + + // let value_bits = array_init(|_| meta.advice_column()); // let value_rlc = meta.advice_column_in(SecondPhase); @@ -2612,6 +2635,12 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.state.tag_idx as u64)), )?; + region.assign_advice( + || "tag_gadget.is_reverse", + self.tag_gadget.is_reverse, + i, + || Value::known(F::from(row.encoded_data.reverse as u64)), + )?; let tag_bits = BinaryNumberChip::construct(self.tag_gadget.tag_bits); tag_bits.assign(&mut region, i, &row.state.tag)?; @@ -2652,33 +2681,6 @@ impl DecompressionCircuitConfig { )?; -// compression_debug - // cb.require_equal( - // "degree reduction: is_block_header check", - // is_block_header(meta), - // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), - // ); - - // cb.require_equal( - // "degree reduction: is_literals_header check", - // is_zb_literals_header(meta), - // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - // ); - - // cb.require_equal( - // "degree reduction: is_fse_code check", - // is_zb_fse_code(meta), - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // ); - - // cb.require_equal( - // "degree reduction: is_huffman_code check", - // is_zb_huffman_code(meta), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // ); - - - // TagGadget { diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index f1ba20263a..8120a9712d 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -41,5 +41,6 @@ mod zstd; pub use zstd::{ FseAuxiliaryTableData, FseSymbol, FseTableData, FseTableRow, HuffmanCodesData, TagRomTableRow, ZstdWitnessRow, ZstdTag, N_BITS_PER_BYTE, N_BITS_SYMBOL, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, - N_JUMP_TABLE_BYTES, N_MAX_SYMBOLS, process + N_JUMP_TABLE_BYTES, N_MAX_SYMBOLS, process, }; +pub use zstd::util::value_bits_le; diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index ab721f8e61..e4a9fbd501 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -12,7 +12,7 @@ mod tui; #[cfg(test)] use tui::draw_rows; -mod util; +pub mod util; use util::{value_bits_le, le_bits_to_value, be_bits_to_value, increment_idx}; /// FrameHeaderDescriptor and FrameContentSize From 61103cb044eae2ab6e19983f74454e36f654e307 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 20:16:48 -0500 Subject: [PATCH 047/165] Add tag change assignment --- zkevm-circuits/src/decompression_circuit.rs | 16 ++++++++++------ zkevm-circuits/src/witness/zstd/mod.rs | 13 +++++++++++++ zkevm-circuits/src/witness/zstd/types.rs | 2 ++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index ad0310d532..0b5df0f125 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -522,9 +522,10 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.require_boolean("every value bit is boolean", bit.expr()); } + let is_new_byte = meta.query_advice(byte_idx, Rotation::next()) + - meta.query_advice(byte_idx, Rotation::cur()); + // compression_debug - // let is_new_byte = meta.query_advice(byte_idx, Rotation::next()) - // - meta.query_advice(byte_idx, Rotation::cur()); // cb.require_boolean( // "byte_idx' == byte_idx or byte_idx' == byte_idx + 1", // is_new_byte.expr(), @@ -561,9 +562,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // ); // }); - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); - cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), not::expr(meta.query_advice(is_padding, Rotation::cur())), @@ -2602,7 +2600,7 @@ impl DecompressionCircuitConfig { - // let value_bits = array_init(|_| meta.advice_column()); + // let value_rlc = meta.advice_column_in(SecondPhase); // let decoded_len = meta.advice_column(); // let decoded_len_acc = meta.advice_column(); @@ -2641,6 +2639,12 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.encoded_data.reverse as u64)), )?; + region.assign_advice( + || "tag_gadget.is_tag_change", + self.tag_gadget.is_tag_change, + i, + || Value::known(F::from(row.state.is_tag_change as u64)), + )?; let tag_bits = BinaryNumberChip::construct(self.tag_gadget.tag_bits); tag_bits.assign(&mut region, i, &row.state.tag)?; diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index e4a9fbd501..41563c27d0 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -95,6 +95,7 @@ fn process_frame_header( tag_idx: 1, tag_value: Value::known(F::from(*fhd_byte as u64)), tag_value_acc: Value::known(F::from(*fhd_byte as u64)), + is_tag_change: true, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -130,6 +131,7 @@ fn process_frame_header( tag_idx: (i + 1) as u64, tag_value: fcs_tag_value, tag_value_acc, + is_tag_change: i == 0, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -262,6 +264,7 @@ fn process_block_header( tag_idx: (i + 1) as u64, tag_value, tag_value_acc, + is_tag_change: i == 0, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -339,6 +342,7 @@ fn process_raw_bytes( tag_idx: (i + 1) as u64, tag_value, tag_value_acc, + is_tag_change: i == 0, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -401,6 +405,7 @@ fn process_rle_bytes( tag_idx: (i + 1) as u64, tag_value, tag_value_acc: tag_value, + is_tag_change: i == 0, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -680,6 +685,7 @@ fn process_block_zstd_literals_header( tag_idx: (i + 1) as u64, tag_value, tag_value_acc, + is_tag_change: i == 0, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -745,6 +751,7 @@ fn process_block_zstd_huffman_code( tag_idx: 1 as u64, tag_value: Value::default(), // Must be changed after FSE table length is known tag_value_acc: Value::default(), // Must be changed after FSE table length is known + is_tag_change: true, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -795,6 +802,7 @@ fn process_block_zstd_huffman_code( tag_idx: (idx + 2) as u64, // count the huffman header byte tag_value: tag_value, tag_value_acc: tag_value_iter.next().expect("Next value should exist"), + is_tag_change: false, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -875,6 +883,7 @@ fn process_block_zstd_huffman_code( tag_idx: 1 as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, + is_tag_change: true, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -940,6 +949,7 @@ fn process_block_zstd_huffman_code( tag_idx: current_byte_idx as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, + is_tag_change: false, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -1067,6 +1077,7 @@ fn process_block_zstd_huffman_jump_table( tag_idx: (i + 1) as u64, tag_value, tag_value_acc, + is_tag_change: i == 0, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -1153,6 +1164,7 @@ fn process_block_zstd_lstream( tag_idx: current_byte_idx as u64, tag_value: *tag_value, tag_value_acc: tag_value_acc[current_byte_idx - 1], + is_tag_change: true, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, @@ -1209,6 +1221,7 @@ fn process_block_zstd_lstream( tag_idx: from_byte_idx as u64, tag_value: *tag_value, tag_value_acc: tag_value_acc[from_byte_idx - 1], + is_tag_change: false, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), }, diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index f641516036..0f73c3f133 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -290,6 +290,7 @@ pub struct ZstdState { pub tag_idx: u64, pub tag_value: Value, pub tag_value_acc: Value, + pub is_tag_change: bool, // Unlike tag_value, tag_rlc only uses challenge as multiplier pub tag_rlc: Value, pub tag_rlc_acc: Value, @@ -304,6 +305,7 @@ impl Default for ZstdState { tag_idx: 0, tag_value: Value::known(F::zero()), tag_value_acc: Value::known(F::zero()), + is_tag_change: false, tag_rlc: Value::known(F::zero()), tag_rlc_acc: Value::known(F::zero()), } From 6ad37c2ba259c034074b385179a9882a0b31f544 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 20:27:32 -0500 Subject: [PATCH 048/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 69 ++++++++++++--------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 0b5df0f125..5e4181bc39 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -576,7 +576,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // Whether the previous tag was processed from back-to-front. let was_reverse = meta.query_advice(tag_gadget.is_reverse, Rotation::prev()); - // compression_debug // Validations for the end of the previous tag: // // - tag_idx::prev == tag_len::prev @@ -584,21 +583,22 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - tag::cur == tag_next::prev // - if was_reverse: tag_rlc_acc::prev == value_byte::prev // - if was_not_reverse: tag_rlc_acc::prev == tag_rlc::prev - // cb.require_equal( - // "tag_idx::prev == tag_len::prev", - // meta.query_advice(tag_gadget.tag_idx, Rotation::prev()), - // meta.query_advice(tag_gadget.tag_len, Rotation::prev()), - // ); + cb.require_equal( + "tag_idx::prev == tag_len::prev", + meta.query_advice(tag_gadget.tag_idx, Rotation::prev()), + meta.query_advice(tag_gadget.tag_len, Rotation::prev()), + ); + // compression_debug // cb.require_equal( // "tag_value::prev == tag_value_acc::prev", // meta.query_advice(tag_gadget.tag_value, Rotation::prev()), // meta.query_advice(tag_gadget.tag_value_acc, Rotation::prev()), // ); - // cb.require_equal( - // "tag == tag_next::prev", - // meta.query_advice(tag_gadget.tag, Rotation::cur()), - // meta.query_advice(tag_gadget.tag_next, Rotation::prev()), - // ); + cb.require_equal( + "tag == tag_next::prev", + meta.query_advice(tag_gadget.tag, Rotation::cur()), + meta.query_advice(tag_gadget.tag_next, Rotation::prev()), + ); // cb.condition(was_reverse.expr(), |cb| { // cb.require_equal( // "tag_rlc_acc on the last row for tag processed back-to-front", @@ -626,11 +626,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - value_rlc == value_rlc::prev * rand_pow_tag_len::prev + tag_rlc::prev // - if is_reverse: tag_rlc_acc == tag_rlc on the first row // - if is_not_reverse: tag_rlc_acc == value_byte - // cb.require_equal( - // "tag_idx == 1", - // meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), - // 1.expr(), - // ); + cb.require_equal( + "tag_idx == 1", + meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), + 1.expr(), + ); // let (lt, eq) = tag_gadget.len_cmp_max.expr(meta, None); // cb.require_equal("tag_len <= max_len", lt + eq, 1.expr()); // cb.require_equal( @@ -665,7 +665,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(is_padding, Rotation::cur())), + // not::expr(meta.query_advice(is_padding, Rotation::cur())), + // compression_debug + not::expr(meta.query_fixed(q_first, Rotation::cur())), meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), ])) }); @@ -680,16 +682,17 @@ impl SubCircuitConfig for DecompressionCircuitConfig { tag_gadget.tag, tag_gadget.tag_len, tag_gadget.tag_value, - tag_gadget.rand_pow_tag_len, - tag_gadget.tag_rlc, - value_rlc, + // compression_debug + // tag_gadget.rand_pow_tag_len, + // tag_gadget.tag_rlc, + // value_rlc, ] { // compression_debug - // cb.require_equal( - // "column remains the same", - // meta.query_advice(col, Rotation::cur()), - // meta.query_advice(col, Rotation::prev()), - // ); + cb.require_equal( + "column remains the same", + meta.query_advice(col, Rotation::cur()), + meta.query_advice(col, Rotation::prev()), + ); } // compression_debug @@ -697,11 +700,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let byte_idx_curr = meta.query_advice(byte_idx, Rotation::cur()); let byte_idx_prev = meta.query_advice(byte_idx, Rotation::prev()); let is_new_byte = byte_idx_curr - byte_idx_prev; - // cb.require_equal( - // "tag_idx increments if byte_idx increments", - // meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), - // meta.query_advice(tag_gadget.tag_idx, Rotation::prev()) + is_new_byte.expr(), - // ); + cb.require_equal( + "tag_idx increments if byte_idx increments", + meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), + meta.query_advice(tag_gadget.tag_idx, Rotation::prev()) + is_new_byte.expr(), + ); // compression_debug // tag_value_acc calculation. @@ -2645,6 +2648,12 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.state.is_tag_change as u64)), )?; + region.assign_advice( + || "tag_gadget.tag_value", + self.tag_gadget.tag_value, + i, + || row.state.tag_value, + )?; let tag_bits = BinaryNumberChip::construct(self.tag_gadget.tag_bits); tag_bits.assign(&mut region, i, &row.state.tag)?; From 18d5528e5424b72d6eb4d557eb580842cb142bd1 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 20:30:47 -0500 Subject: [PATCH 049/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 28 ++++++++------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 5e4181bc39..c6f0e6b776 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -695,7 +695,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); } - // compression_debug // tag_idx incremental check. let byte_idx_curr = meta.query_advice(byte_idx, Rotation::cur()); let byte_idx_prev = meta.query_advice(byte_idx, Rotation::prev()); @@ -847,24 +846,22 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: first row", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug - // cb.require_equal( - // "byte_idx == 1", - // meta.query_advice(byte_idx, Rotation::cur()), - // 1.expr(), - // ); - - // cb.require_equal( - // "tag == FrameHeaderDescriptor", - // meta.query_advice(tag_gadget.tag, Rotation::cur()), - // ZstdTag::FrameHeaderDescriptor.expr(), - // ); + cb.require_equal( + "byte_idx == 1", + meta.query_advice(byte_idx, Rotation::cur()), + 1.expr(), + ); + cb.require_equal( + "tag == FrameHeaderDescriptor", + meta.query_advice(tag_gadget.tag, Rotation::cur()), + ZstdTag::FrameHeaderDescriptor.expr(), + ); + // compression_debug // cb.require_zero( // "value_rlc starts at 0", // meta.query_advice(value_rlc, Rotation::cur()), // ); - // cb.require_zero( // "decoded_rlc initialises at 0", // meta.query_advice(decoded_rlc, Rotation::cur()), @@ -874,9 +871,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // meta.query_advice(decoded_len_acc, Rotation::cur()), // ); - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); - cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), meta.query_fixed(q_first, Rotation::cur()), From 48bd75cfcb676a968f7ad3febf8c41fca57cf12f Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 20:34:14 -0500 Subject: [PATCH 050/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 85 ++++++++++----------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index c6f0e6b776..7c2bbb1d08 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -913,16 +913,16 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // FrameHeaderDescriptor is a single byte. // compression_debug - // cb.require_equal( - // "tag_idx == 1", - // meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), - // 1.expr(), - // ); - // cb.require_equal( - // "tag_len == 1", - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - // 1.expr(), - // ); + cb.require_equal( + "tag_idx == 1", + meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), + 1.expr(), + ); + cb.require_equal( + "tag_len == 1", + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + 1.expr(), + ); // cb.require_equal( // "tag_value_acc == value_byte", // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), @@ -944,32 +944,31 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // | 3 | Reserved_Bit | 0 | // | 2 | Content_Checksum_Flag | 0 | // | 1-0 | Dictionary_ID_Flag | 0 | - // compression_debug - // cb.require_equal( - // "FHD: Single_Segment_Flag", - // meta.query_advice(value_bits[5], Rotation::cur()), - // 1.expr(), - // ); - // cb.require_zero( - // "FHD: Unused_Bit", - // meta.query_advice(value_bits[4], Rotation::cur()), - // ); - // cb.require_zero( - // "FHD: Reserved_Bit", - // meta.query_advice(value_bits[3], Rotation::cur()), - // ); - // cb.require_zero( - // "FHD: Content_Checksum_Flag", - // meta.query_advice(value_bits[2], Rotation::cur()), - // ); - // cb.require_zero( - // "FHD: Dictionary_ID_Flag", - // meta.query_advice(value_bits[1], Rotation::cur()), - // ); - // cb.require_zero( - // "FHD: Dictionary_ID_Flag", - // meta.query_advice(value_bits[0], Rotation::cur()), - // ); + cb.require_equal( + "FHD: Single_Segment_Flag", + meta.query_advice(value_bits[5], Rotation::cur()), + 1.expr(), + ); + cb.require_zero( + "FHD: Unused_Bit", + meta.query_advice(value_bits[4], Rotation::cur()), + ); + cb.require_zero( + "FHD: Reserved_Bit", + meta.query_advice(value_bits[3], Rotation::cur()), + ); + cb.require_zero( + "FHD: Content_Checksum_Flag", + meta.query_advice(value_bits[2], Rotation::cur()), + ); + cb.require_zero( + "FHD: Dictionary_ID_Flag", + meta.query_advice(value_bits[1], Rotation::cur()), + ); + cb.require_zero( + "FHD: Dictionary_ID_Flag", + meta.query_advice(value_bits[0], Rotation::cur()), + ); // Checks for the next tag, i.e. FrameContentSize. let fcs_flag0 = meta.query_advice(value_bits[7], Rotation::cur()); @@ -983,15 +982,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { select::expr(fcs_flag0, 4.expr(), 2.expr()), ), ); - // compression_debug - // cb.require_equal( - // "tag_len' == fcs_field_size", - // meta.query_advice(tag_gadget.tag_len, Rotation::next()), - // fcs_field_size, - // ); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_equal( + "tag_len' == fcs_field_size", + meta.query_advice(tag_gadget.tag_len, Rotation::next()), + fcs_field_size, + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), From bd72597c3b2b99daf748c91407fa0c58a3d323c4 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 20:49:06 -0500 Subject: [PATCH 051/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 63 ++++++++++++++------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 7c2bbb1d08..053c961311 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1041,12 +1041,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: BlockHeader", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug - // cb.require_equal( - // "tag_len == 3", - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - // N_BLOCK_HEADER_BYTES.expr(), - // ); + cb.require_equal( + "tag_len == 3", + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + N_BLOCK_HEADER_BYTES.expr(), + ); // The lowest bit (as per little-endian representation) is whether the block is the // last block in the frame or not. @@ -1069,15 +1068,15 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let block_type_bit1 = meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); // compression_debug - // cb.require_zero( - // "block type cannot be RESERVED, i.e. block_type == 3 not possible", - // block_type_bit0.expr() * block_type_bit1.expr(), - // ); - // cb.require_equal( - // "block_idx == 1", - // meta.query_advice(block_gadget.idx, Rotation(N_BLOCK_HEADER_BYTES as i32)), - // 1.expr(), - // ); + cb.require_zero( + "block type cannot be RESERVED, i.e. block_type == 3 not possible", + block_type_bit0.expr() * block_type_bit1.expr(), + ); + cb.require_equal( + "block_idx == 1", + meta.query_advice(block_gadget.idx, Rotation(N_BLOCK_HEADER_BYTES as i32)), + 1.expr(), + ); // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear with // block type 00 or 01, i.e. the block_type_bit1 is 0. @@ -2589,10 +2588,6 @@ impl DecompressionCircuitConfig { - - - - // let value_rlc = meta.advice_column_in(SecondPhase); // let decoded_len = meta.advice_column(); // let decoded_len_acc = meta.advice_column(); @@ -2600,6 +2595,36 @@ impl DecompressionCircuitConfig { // let decoded_rlc = meta.advice_column_in(SecondPhase); + + + // Block Gadget + region.assign_advice( + || "block_gadget.block_idx", + self.block_gadget.idx, + i, + || Value::known(F::one()), + )?; + + // let block_gadget = { + // let block_idx = meta.advice_column(); + // let block_len = meta.advice_column(); + // BlockGadget { + // is_block: meta.advice_column(), + // idx: block_idx, + // block_len, + // is_last_block: meta.advice_column(), + // // compression_debug + // // idx_cmp_len: ComparatorChip::configure( + // // meta, + // // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // // |meta| meta.query_advice(block_idx, Rotation::cur()), + // // |meta| meta.query_advice(block_len, Rotation::cur()), + // // range256.into(), + // // ), + // } + // }; + + // Tag Gadget region.assign_advice( || "tag_gadget.tag", From d1803fcd4dc5c4bb66d4bdf6ea65a7511b1dff61 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 21:03:43 -0500 Subject: [PATCH 052/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 053c961311..b934e896b1 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1285,15 +1285,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: RawBlock", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug - // cb.require_equal( - // "value byte == decoded byte", - // meta.query_advice(value_byte, Rotation::cur()), - // meta.query_advice(decoded_byte, Rotation::cur()), - // ); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_equal( + "value byte == decoded byte", + meta.query_advice(value_byte, Rotation::cur()), + meta.query_advice(decoded_byte, Rotation::cur()), + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -2598,6 +2594,7 @@ impl DecompressionCircuitConfig { // Block Gadget + // compression_debug region.assign_advice( || "block_gadget.block_idx", self.block_gadget.idx, From e168dbd6f293909cdb90acfd13eac70f7448b518 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 21:04:52 -0500 Subject: [PATCH 053/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 34 +++++++++------------ 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index b934e896b1..b298344f92 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1308,27 +1308,23 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: RleBlock", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug - // cb.require_equal( - // "value byte == decoded byte", - // meta.query_advice(value_byte, Rotation::cur()), - // meta.query_advice(decoded_byte, Rotation::cur()), - // ); - - // cb.require_equal( - // "decoded byte remains the same", - // meta.query_advice(decoded_byte, Rotation::cur()), - // meta.query_advice(decoded_byte, Rotation::prev()), - // ); + cb.require_equal( + "value byte == decoded byte", + meta.query_advice(value_byte, Rotation::cur()), + meta.query_advice(decoded_byte, Rotation::cur()), + ); - // cb.require_equal( - // "byte idx remains the same", - // meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(byte_idx, Rotation::prev()), - // ); + cb.require_equal( + "decoded byte remains the same", + meta.query_advice(decoded_byte, Rotation::cur()), + meta.query_advice(decoded_byte, Rotation::prev()), + ); - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_equal( + "byte idx remains the same", + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(byte_idx, Rotation::prev()), + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), From aa1b445109aa0585feb4de774f42e6632a75c7a9 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 21:06:51 -0500 Subject: [PATCH 054/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 26 +++++++-------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index b298344f92..1e8f185365 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1345,14 +1345,10 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let block_type_bit0 = meta.query_advice(value_bits[7], Rotation::cur()); let block_type_bit1 = meta.query_advice(value_bits[6], Rotation::cur()); - // compression_debug - // cb.require_zero( - // "block type cannot be TREELESS, i.e. block_type == 3 not possible", - // block_type_bit0 * block_type_bit1, - // ); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_zero( + "block type cannot be TREELESS, i.e. block_type == 3 not possible", + block_type_bit0 * block_type_bit1, + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1372,17 +1368,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { aux_fields.aux3, aux_fields.aux4, ] { - // compression_debug - // cb.require_equal( - // "aux fields remain the same", - // meta.query_advice(col, Rotation::cur()), - // meta.query_advice(col, Rotation::prev()), - // ); + cb.require_equal( + "aux fields remain the same", + meta.query_advice(col, Rotation::cur()), + meta.query_advice(col, Rotation::prev()), + ); } - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); - cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), From 8aa7c8f28d839f16776f138577a6d2fcec2d53bb Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 21:16:49 -0500 Subject: [PATCH 055/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 102 +++++++++----------- 1 file changed, 45 insertions(+), 57 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 1e8f185365..f874a030ac 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1509,32 +1509,26 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlock Raw bytes", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug - // cb.require_equal( - // "value_byte == decoded_byte", - // meta.query_advice(value_byte, Rotation::cur()), - // meta.query_advice(decoded_byte, Rotation::cur()), - // ); - - // cb.condition( - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // |cb| { - // cb.require_equal( - // "tag_len == regen_size", - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - // meta.query_advice(aux_fields.aux1, Rotation::prev()), - // ); - // }, - // ); - - // cb.require_equal( - // "byte_idx increments", - // meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(byte_idx, Rotation::prev()) + 1.expr(), - // ); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_equal( + "value_byte == decoded_byte", + meta.query_advice(value_byte, Rotation::cur()), + meta.query_advice(decoded_byte, Rotation::cur()), + ); + cb.condition( + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + |cb| { + cb.require_equal( + "tag_len == regen_size", + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + meta.query_advice(aux_fields.aux1, Rotation::prev()), + ); + }, + ); + cb.require_equal( + "byte_idx increments", + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(byte_idx, Rotation::prev()) + 1.expr(), + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1550,37 +1544,31 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlock RLE bytes", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug - // cb.require_equal( - // "value_byte == decoded_byte", - // meta.query_advice(value_byte, Rotation::cur()), - // meta.query_advice(decoded_byte, Rotation::cur()), - // ); - - // let is_tag_change = meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()); - // cb.condition(is_tag_change.expr(), |cb| { - // cb.require_equal( - // "tag_len == regen_size", - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - // meta.query_advice(aux_fields.aux1, Rotation::prev()), - // ); - // }); - - // cb.condition(not::expr(is_tag_change), |cb| { - // cb.require_equal( - // "byte_idx remains the same", - // meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(byte_idx, Rotation::prev()), - // ); - // cb.require_equal( - // "decoded byte remains the same", - // meta.query_advice(decoded_byte, Rotation::cur()), - // meta.query_advice(decoded_byte, Rotation::prev()), - // ); - // }); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_equal( + "value_byte == decoded_byte", + meta.query_advice(value_byte, Rotation::cur()), + meta.query_advice(decoded_byte, Rotation::cur()), + ); + let is_tag_change = meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()); + cb.condition(is_tag_change.expr(), |cb| { + cb.require_equal( + "tag_len == regen_size", + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + meta.query_advice(aux_fields.aux1, Rotation::prev()), + ); + }); + cb.condition(not::expr(is_tag_change), |cb| { + cb.require_equal( + "byte_idx remains the same", + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(byte_idx, Rotation::prev()), + ); + cb.require_equal( + "decoded byte remains the same", + meta.query_advice(decoded_byte, Rotation::cur()), + meta.query_advice(decoded_byte, Rotation::prev()), + ); + }); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), From 697fb6afe19dc4d55eb5698da5660d8540b02e58 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 31 Jan 2024 21:32:16 -0500 Subject: [PATCH 056/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 25 +++++++++------------ 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index f874a030ac..ea84243a6c 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1719,11 +1719,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // processing the Huffman data. for col in [aux_fields.aux1, aux_fields.aux2, aux_fields.aux3, aux_fields.aux4] { // compression_debug - // cb.require_equal( - // "aux fields aux1, aux2, aux3, aux4 remain the same", - // meta.query_advice(col, Rotation::cur()), - // meta.query_advice(col, Rotation::prev()), - // ); + cb.require_equal( + "aux fields aux1, aux2, aux3, aux4 remain the same", + meta.query_advice(col, Rotation::cur()), + meta.query_advice(col, Rotation::prev()), + ); } // The decoded symbol keeps incrementing in the FSE code reconstruction. Since @@ -2433,15 +2433,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlockJumpTable", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug - // cb.require_equal( - // "tag_len == 6", - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - // N_JUMP_TABLE_BYTES.expr(), - // ); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_equal( + "tag_len == 6", + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + N_JUMP_TABLE_BYTES.expr(), + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -2458,7 +2454,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlockLstream", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug cb.require_zero("dummy constraint", 0.expr()); cb.gate(and::expr([ From 3f895804977d2f47caa2530c92936e66c260686a Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 1 Feb 2024 18:10:55 -0500 Subject: [PATCH 057/165] Adjust constraint blocks --- zkevm-circuits/src/decompression_circuit.rs | 43 +++++++++++---------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 08646982b4..d35f90f208 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2425,27 +2425,28 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // }, // ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (num symbols in huffman code)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), - ]); - [ - meta.query_advice(aux_fields.aux3, Rotation::cur()), /* huffman header byte - * offset */ - meta.query_advice(fse_gadget.num_emitted, Rotation::cur()), /* num symbols - * emitted */ - 1.expr(), // is_last - ] - .into_iter() - .zip(huffman_codes_table.table_exprs_weights_count(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (num symbols in huffman code)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), + // ]); + // [ + // meta.query_advice(aux_fields.aux3, Rotation::cur()), /* huffman header byte + // * offset */ + // meta.query_advice(fse_gadget.num_emitted, Rotation::cur()), /* num symbols + // * emitted */ + // 1.expr(), // is_last + // ] + // .into_iter() + // .zip(huffman_codes_table.table_exprs_weights_count(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); debug_assert!(meta.degree() <= 9); From 212b166922f336a4c79afdffeeed54b703e17466 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 1 Feb 2024 19:10:11 -0500 Subject: [PATCH 058/165] Reassign comparator --- zkevm-circuits/src/decompression_circuit.rs | 87 ++++++++++++--------- zkevm-circuits/src/witness/zstd/mod.rs | 8 +- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index d35f90f208..c547486472 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -361,19 +361,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // range256.into(), // ), is_tag_change: meta.advice_column(), - // compression_debug - // idx_cmp_len: ComparatorChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(tag_idx, Rotation::cur()), - // |meta| meta.query_advice(tag_len, Rotation::cur()), - // range256.into(), - // ), idx_cmp_len: ComparatorChip::configure( meta, |meta| meta.query_fixed(q_enable, Rotation::cur()), - |meta| 1.expr(), - |meta| 1.expr(), + |meta| meta.query_advice(tag_idx, Rotation::cur()), + |meta| meta.query_advice(tag_len, Rotation::cur()), range256.into(), ), // len_cmp_max: ComparatorChip::configure( @@ -522,39 +514,42 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.require_boolean("every value bit is boolean", bit.expr()); } - let is_new_byte = meta.query_advice(byte_idx, Rotation::next()) - - meta.query_advice(byte_idx, Rotation::cur()); + let is_new_byte = meta.query_advice(byte_idx, Rotation::cur()) + - meta.query_advice(byte_idx, Rotation::prev()); - // compression_debug - // cb.require_boolean( - // "byte_idx' == byte_idx or byte_idx' == byte_idx + 1", - // is_new_byte.expr(), - // ); + cb.require_boolean( + "byte_idx' == byte_idx or byte_idx' == byte_idx + 1", + is_new_byte.expr(), + ); - // cb.require_equal( - // "encoded length remains the same", - // meta.query_advice(encoded_len, Rotation::cur()), - // meta.query_advice(encoded_len, Rotation::next()), - // ); + cb.require_equal( + "encoded length remains the same", + meta.query_advice(encoded_len, Rotation::cur()), + meta.query_advice(encoded_len, Rotation::prev()), + ); - // cb.require_equal( - // "decoded length remains the same", - // meta.query_advice(decoded_len, Rotation::cur()), - // meta.query_advice(decoded_len, Rotation::next()), - // ); + cb.require_equal( + "decoded length remains the same", + meta.query_advice(decoded_len, Rotation::cur()), + meta.query_advice(decoded_len, Rotation::prev()), + ); - // cb.require_boolean( - // "is_tag_change is boolean", - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // ); + cb.require_boolean( + "is_tag_change is boolean", + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + ); + // compression_debug // compression_debug // We also need to validate that ``is_tag_change`` was assigned correctly. Tag changes // on the next row iff: // - tag_idx == tag_len // - byte_idx' == byte_idx + 1 - // let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, None); - // cb.condition(and::expr([tidx_eq_tlen, is_new_byte]), |cb| { + // let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, Some(Rotation::prev())); + // cb.condition(and::expr([ + // tidx_eq_tlen, + // is_new_byte + // ]), |cb| { // cb.require_equal( // "is_tag_change should be set", // meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), @@ -564,7 +559,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(is_padding, Rotation::cur())), + not::expr(meta.query_fixed(q_first, Rotation::cur())), ])) }); @@ -1787,6 +1782,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockFseCode (contained bitstream start)", @@ -1819,6 +1815,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // .collect() // }, // ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockFseCode (contained bitstream end)", @@ -1851,6 +1848,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // .collect() // }, // ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", @@ -1884,6 +1882,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // .collect() // }, // ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", @@ -1918,6 +1917,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // .collect() // }, // ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockFseCode (symbol count check)", @@ -2166,6 +2166,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockHuffmanCode (leading 0s and sentinel bit start)", @@ -2194,6 +2195,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // .collect() // }, // ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockHuffmanCode (leading 0s and sentinel bit end)", @@ -2225,6 +2227,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // .collect() // }, // ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream start)", @@ -2256,6 +2259,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // .collect() // }, // ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream end)", @@ -2287,6 +2291,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // .collect() // }, // ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", @@ -2319,6 +2324,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // .collect() // }, // ); + // compression_debug // meta.lookup_any( // "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstring end)", @@ -2665,8 +2671,8 @@ impl DecompressionCircuitConfig { // compression_debug let idx_cmp_len_chip = ComparatorChip::construct(self.tag_gadget.idx_cmp_len.clone()); - // idx_cmp_len.assign(&mut region, i, F::from(row.state.tag_len), F::from(row.state.tag_idx))?; - idx_cmp_len_chip.assign(&mut region, i, F::one(), F::one())?; + idx_cmp_len_chip.assign(&mut region, i, F::from(row.state.tag_idx), F::from(row.state.tag_len))?; + // idx_cmp_len_chip.assign(&mut region, i, F::one(), F::one())?; let is_block_header = (row.state.tag == ZstdTag::BlockHeader) as u64; let is_literals_header = (row.state.tag == ZstdTag::ZstdBlockLiteralsHeader) as u64; @@ -2899,7 +2905,14 @@ impl SubCircuit for DecompressionCircuit { let (rows, _decoded_literals) = process::(&self.compressed_frames[idx], challenges.keccak_input()); witness_rows.extend_from_slice(&rows); } - + + // compression_debug + for row in witness_rows.clone() { + log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;", + row.state.tag, row.state.tag_next, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, + ); + } + config.assign(layouter, witness_rows, challenges) } } diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 41563c27d0..6a3817b606 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -146,7 +146,13 @@ fn process_frame_header( aux_2, value_rlc, }, - decoded_data: last_row.decoded_data.clone(), + decoded_data: DecodedData { + decoded_len: fcs, + decoded_len_acc: 0, + total_decoded_len: last_row.decoded_data.total_decoded_len + fcs, + decoded_byte: 0, + decoded_value_rlc: last_row.decoded_data.decoded_value_rlc, + }, huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), }, From 914c047f4f3b46b0b315f5cc0b4f4a93699c4bad Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sat, 3 Feb 2024 22:48:34 -0500 Subject: [PATCH 059/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 105 +++++++++++------- .../src/decompression_circuit/dev.rs | 5 +- zkevm-circuits/src/table.rs | 4 + zkevm-circuits/src/witness/zstd/mod.rs | 35 ++++++ zkevm-circuits/src/witness/zstd/types.rs | 4 +- 5 files changed, 109 insertions(+), 44 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index c547486472..3e565d6244 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -13,7 +13,7 @@ use eth_types::Field; use gadgets::{ binary_number::{BinaryNumberChip, BinaryNumberConfig}, comparator::{ComparatorChip, ComparatorConfig, ComparatorInstruction}, - less_than::{LtChip, LtConfig}, + less_than::{LtChip, LtConfig, LtInstruction}, util::{and, not, select, sum, Expr}, }; use halo2_proofs::{ @@ -29,8 +29,7 @@ use crate::{ decompression::{ BitstringAccumulationTable, BlockTypeRomTable, FseTable, HuffmanCodesTable, LiteralsHeaderRomTable, LiteralsHeaderTable, TagRomTable, - }, - KeccakTable, LookupTable, Pow2Table, PowOfRandTable, RangeTable, + }, KeccakTable, LookupTable, Pow2Table, PowOfRandTable, RangeTable, U8Table }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::{ @@ -116,6 +115,11 @@ pub struct DecompressionCircuitConfig { // bitstream_decoder: BitstreamDecoder, /// Fields related to the application of FSE table to bitstream. fse_gadget: FseGadget, + + /// Internal Tables + range8: RangeTable<8>, + range128: RangeTable<128>, + range256: RangeTable<256>, } /// Block level details are specified in these columns. @@ -171,14 +175,13 @@ pub struct TagGadget { /// value, however the tag_rlc always uses the keccak randomness. tag_rlc_acc: Column, /// Helper gadget to check whether max_len < 0x20. - /// compression_debug - // mlen_lt_0x20: LtConfig, + mlen_lt_0x20: LtConfig, /// A boolean column to indicate that tag has been changed on this row. is_tag_change: Column, // Check: tag_idx <= tag_len. - idx_cmp_len: ComparatorConfig, - // compression_debug + idx_cmp_len: ComparatorConfig, // Check: tag_len <= max_len. + // compression_debug // len_cmp_max: ComparatorConfig, /// Helper column to reduce the circuit degree. Set when tag == BlockHeader. is_block_header: Column, @@ -352,14 +355,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { is_reverse: meta.advice_column(), tag_rlc: meta.advice_column_in(SecondPhase), tag_rlc_acc: meta.advice_column_in(SecondPhase), - // compression_debug - // mlen_lt_0x20: LtChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(max_len, Rotation::cur()), - // |_meta| 0x20.expr(), - // range256.into(), - // ), + mlen_lt_0x20: LtChip::configure( + meta, + |meta| meta.query_fixed(q_enable, Rotation::cur()), + |meta| meta.query_advice(max_len, Rotation::cur()), + |_meta| 0x20.expr(), + range256.into(), + ), is_tag_change: meta.advice_column(), idx_cmp_len: ComparatorChip::configure( meta, @@ -368,13 +370,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { |meta| meta.query_advice(tag_len, Rotation::cur()), range256.into(), ), - // len_cmp_max: ComparatorChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(tag_len, Rotation::cur()), - // |meta| meta.query_advice(max_len, Rotation::cur()), - // range256.into(), - // ), is_block_header: meta.advice_column(), is_literals_header: meta.advice_column(), is_fse_code: meta.advice_column(), @@ -545,7 +540,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // on the next row iff: // - tag_idx == tag_len // - byte_idx' == byte_idx + 1 - // let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, Some(Rotation::prev())); + // let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, None); // cb.condition(and::expr([ // tidx_eq_tlen, // is_new_byte @@ -2511,6 +2506,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { aux_fields, bitstream_decoder, fse_gadget, + range8, + range128, + range256, } } } @@ -2622,6 +2620,17 @@ impl DecompressionCircuitConfig { // }; + + + + + + + + + + + // Tag Gadget region.assign_advice( || "tag_gadget.tag", @@ -2636,10 +2645,10 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.state.tag_next as u64)), )?; region.assign_advice( - || "tag_gadget.tag_len", - self.tag_gadget.tag_len, + || "tag_gadget.max_len", + self.tag_gadget.max_len, i, - || Value::known(F::from(row.state.tag_len as u64)), + || Value::known(F::from(row.state.max_tag_len as u64)), )?; region.assign_advice( || "tag_gadget.tag_idx", @@ -2647,6 +2656,12 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.state.tag_idx as u64)), )?; + region.assign_advice( + || "tag_gadget.tag_len", + self.tag_gadget.tag_len, + i, + || Value::known(F::from(row.state.tag_len as u64)), + )?; region.assign_advice( || "tag_gadget.is_reverse", self.tag_gadget.is_reverse, @@ -2669,10 +2684,12 @@ impl DecompressionCircuitConfig { let tag_bits = BinaryNumberChip::construct(self.tag_gadget.tag_bits); tag_bits.assign(&mut region, i, &row.state.tag)?; - // compression_debug let idx_cmp_len_chip = ComparatorChip::construct(self.tag_gadget.idx_cmp_len.clone()); idx_cmp_len_chip.assign(&mut region, i, F::from(row.state.tag_idx), F::from(row.state.tag_len))?; - // idx_cmp_len_chip.assign(&mut region, i, F::one(), F::one())?; + + let max_tag_len = row.state.max_tag_len; + let mlen_lt_0x20_chip = LtChip::construct(self.tag_gadget.mlen_lt_0x20.clone()); + mlen_lt_0x20_chip.assign(&mut region, i, F::from(max_tag_len), F::from(0x20 as u64))?; let is_block_header = (row.state.tag == ZstdTag::BlockHeader) as u64; let is_literals_header = (row.state.tag == ZstdTag::ZstdBlockLiteralsHeader) as u64; @@ -2708,13 +2725,11 @@ impl DecompressionCircuitConfig { // TagGadget { - // tag_bits: BinaryNumberChip::configure(meta, q_enable, Some(tag.into())), // tag_value: meta.advice_column_in(SecondPhase), // tag_value_acc: meta.advice_column_in(SecondPhase), // rand_pow_tag_len: meta.advice_column_in(SecondPhase), // max_len, // is_output: meta.advice_column(), - // is_reverse: meta.advice_column(), // tag_rlc: meta.advice_column_in(SecondPhase), // tag_rlc_acc: meta.advice_column_in(SecondPhase), // mlen_lt_0x20: LtChip::configure( @@ -2724,14 +2739,6 @@ impl DecompressionCircuitConfig { // |_meta| 0x20.expr(), // range256.into(), // ), - // is_tag_change: meta.advice_column(), - // idx_cmp_len: ComparatorChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(tag_idx, Rotation::cur()), - // |meta| meta.query_advice(tag_len, Rotation::cur()), - // range256.into(), - // ), // len_cmp_max: ComparatorChip::configure( // meta, // |meta| meta.query_fixed(q_enable, Rotation::cur()), @@ -2739,13 +2746,27 @@ impl DecompressionCircuitConfig { // |meta| meta.query_advice(max_len, Rotation::cur()), // range256.into(), // ), - // is_block_header: meta.advice_column(), - // is_literals_header: meta.advice_column(), - // is_fse_code: meta.advice_column(), - // is_huffman_code: meta.advice_column(), // } + + + + + + + + + + + + + + + + + + // Block Gadget // let block_gadget = { diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index b59b922335..8dbf2f5da3 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -12,7 +12,7 @@ use crate::{ decompression::{ BitstringAccumulationTable, FseTable, HuffmanCodesTable, LiteralsHeaderTable, }, - BitwiseOpTable, KeccakTable, Pow2Table, PowOfRandTable, RangeTable, + BitwiseOpTable, KeccakTable, Pow2Table, PowOfRandTable, RangeTable, U8Table }, util::{Challenges, SubCircuit, SubCircuitConfig}, }; @@ -79,6 +79,9 @@ impl Circuit for DecompressionCircuit { mut layouter: impl Layouter, ) -> Result<(), Error> { let challenges = &config.1.values(&layouter); + config.0.range8.load(&mut layouter)?; + config.0.range128.load(&mut layouter)?; + config.0.range256.load(&mut layouter)?; self.synthesize_sub(&config.0, challenges, &mut layouter) } } diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 9c552fc605..f018617981 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -3123,6 +3123,8 @@ pub type U16Table = RangeTable<{ 1 << 16 }>; impl RangeTable { /// Construct the range table. pub fn construct(meta: &mut ConstraintSystem) -> Self { + // compression_debug + log::trace!("=> RangeTable construct, MAX: {:?}", MAX); let inner = meta.lookup_table_column(); meta.annotate_lookup_column(inner, || format!("range table [0, {MAX})")); Self(inner) @@ -3130,6 +3132,8 @@ impl RangeTable { /// Assign values to the table. pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + // compression_debug + log::trace!("=> load RangeTable, MAX: {:?}", MAX); layouter.assign_table( || format!("range table [0, {MAX})"), |mut table| { diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 6a3817b606..0d62e720e8 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use eth_types::Field; use halo2_proofs::circuit::Value; @@ -6,6 +7,7 @@ pub use params::*; mod types; pub use types::*; +pub use types::ZstdTag::*; #[cfg(test)] mod tui; @@ -15,6 +17,26 @@ use tui::draw_rows; pub mod util; use util::{value_bits_le, le_bits_to_value, be_bits_to_value, increment_idx}; +const TAG_MAX_LEN: [(ZstdTag, u64); 13] = [ + (FrameHeaderDescriptor, 1), + (FrameContentSize, 8), + (BlockHeader, 3), + (RawBlockBytes, 8388607), // (1 << 23) - 1 + (RleBlockBytes, 8388607), + (ZstdBlockLiteralsHeader, 5), + (ZstdBlockLiteralsRawBytes, 1048575), // (1 << 20) - 1 + (ZstdBlockLiteralsRleBytes, 1048575), + (ZstdBlockLiteralsHeader, 5), + (ZstdBlockFseCode, 128), + (ZstdBlockHuffmanCode, 128), // header_byte < 128 + (ZstdBlockJumpTable, 6), + (ZstdBlockLstream, 1000), // 1kB hard-limit +]; + +fn lookup_max_tag_len(tag: ZstdTag) -> u64 { + TAG_MAX_LEN.iter().filter(|record| record.0 == tag).next().unwrap().1 +} + /// FrameHeaderDescriptor and FrameContentSize fn process_frame_header( src: &[u8], @@ -91,6 +113,7 @@ fn process_frame_header( state: ZstdState { tag: ZstdTag::FrameHeaderDescriptor, tag_next: ZstdTag::FrameContentSize, + max_tag_len: lookup_max_tag_len(ZstdTag::FrameHeaderDescriptor), tag_len: 1, tag_idx: 1, tag_value: Value::known(F::from(*fhd_byte as u64)), @@ -127,6 +150,7 @@ fn process_frame_header( state: ZstdState { tag: ZstdTag::FrameContentSize, tag_next: ZstdTag::BlockHeader, + max_tag_len: lookup_max_tag_len(ZstdTag::FrameContentSize), tag_len: fcs_tag_len as u64, tag_idx: (i + 1) as u64, tag_value: fcs_tag_value, @@ -266,6 +290,7 @@ fn process_block_header( state: ZstdState { tag: ZstdTag::BlockHeader, tag_next, + max_tag_len: lookup_max_tag_len(ZstdTag::BlockHeader), tag_len: N_BLOCK_HEADER_BYTES as u64, tag_idx: (i + 1) as u64, tag_value, @@ -344,6 +369,7 @@ fn process_raw_bytes( state: ZstdState { tag, tag_next, + max_tag_len: lookup_max_tag_len(tag), tag_len: n_bytes as u64, tag_idx: (i + 1) as u64, tag_value, @@ -407,6 +433,7 @@ fn process_rle_bytes( state: ZstdState { tag, tag_next, + max_tag_len: lookup_max_tag_len(tag), tag_len: n_bytes as u64, tag_idx: (i + 1) as u64, tag_value, @@ -687,6 +714,7 @@ fn process_block_zstd_literals_header( state: ZstdState { tag: ZstdTag::ZstdBlockLiteralsHeader, tag_next, + max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockLiteralsHeader), tag_len: n_bytes_header as u64, tag_idx: (i + 1) as u64, tag_value, @@ -753,6 +781,7 @@ fn process_block_zstd_huffman_code( state: ZstdState { tag: ZstdTag::ZstdBlockFseCode, tag_next, + max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockFseCode), tag_len: 0 as u64, // There's no information at this point about the length of FSE table bytes. So this value has to be modified later. tag_idx: 1 as u64, tag_value: Value::default(), // Must be changed after FSE table length is known @@ -804,6 +833,7 @@ fn process_block_zstd_huffman_code( state: ZstdState { tag: ZstdTag::ZstdBlockFseCode, tag_next, + max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockFseCode), tag_len: (n_fse_bytes + 1) as u64, tag_idx: (idx + 2) as u64, // count the huffman header byte tag_value: tag_value, @@ -885,6 +915,7 @@ fn process_block_zstd_huffman_code( state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanCode, tag_next, + max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockHuffmanCode), tag_len: n_huffman_code_bytes as u64, tag_idx: 1 as u64, tag_value: tag_value, @@ -951,6 +982,7 @@ fn process_block_zstd_huffman_code( state: ZstdState { tag: ZstdTag::ZstdBlockHuffmanCode, tag_next, + max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockHuffmanCode), tag_len: (n_huffman_code_bytes) as u64, tag_idx: current_byte_idx as u64, tag_value: tag_value, @@ -1079,6 +1111,7 @@ fn process_block_zstd_huffman_jump_table( state: ZstdState { tag: ZstdTag::ZstdBlockJumpTable, tag_next: ZstdTag::ZstdBlockLstream, + max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockJumpTable), tag_len: N_JUMP_TABLE_BYTES as u64, tag_idx: (i + 1) as u64, tag_value, @@ -1166,6 +1199,7 @@ fn process_block_zstd_lstream( state: ZstdState { tag: ZstdTag::ZstdBlockLstream, tag_next, + max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockLstream), tag_len: len as u64, tag_idx: current_byte_idx as u64, tag_value: *tag_value, @@ -1223,6 +1257,7 @@ fn process_block_zstd_lstream( state: ZstdState { tag: ZstdTag::ZstdBlockLstream, tag_next, + max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockLstream), tag_len: len as u64, tag_idx: from_byte_idx as u64, tag_value: *tag_value, diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 0f73c3f133..d6ccec6051 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -159,7 +159,7 @@ impl From for BlockType { } /// Various tags that we can decode from a zstd encoded data. -#[derive(Clone, Copy, Debug, EnumIter, PartialEq)] +#[derive(Clone, Copy, Debug, EnumIter, PartialEq, Eq, Hash)] pub enum ZstdTag { /// Null should not occur. Null = 0, @@ -286,6 +286,7 @@ impl ToString for ZstdTag { pub struct ZstdState { pub tag: ZstdTag, pub tag_next: ZstdTag, + pub max_tag_len: u64, pub tag_len: u64, pub tag_idx: u64, pub tag_value: Value, @@ -301,6 +302,7 @@ impl Default for ZstdState { Self { tag: ZstdTag::Null, tag_next: ZstdTag::FrameHeaderDescriptor, + max_tag_len: 0, tag_len: 0, tag_idx: 0, tag_value: Value::known(F::zero()), From 3ff91a1b291c45688c2303be36ded55be15d4b0d Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sat, 3 Feb 2024 22:55:28 -0500 Subject: [PATCH 060/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 27 +++++++++------------ 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 3e565d6244..bdab67dd08 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -181,8 +181,7 @@ pub struct TagGadget { // Check: tag_idx <= tag_len. idx_cmp_len: ComparatorConfig, // Check: tag_len <= max_len. - // compression_debug - // len_cmp_max: ComparatorConfig, + len_cmp_max: ComparatorConfig, /// Helper column to reduce the circuit degree. Set when tag == BlockHeader. is_block_header: Column, /// Helper column to reduce the circuit degree. Set when tag == LiteralsHeader. @@ -370,6 +369,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { |meta| meta.query_advice(tag_len, Rotation::cur()), range256.into(), ), + len_cmp_max: ComparatorChip::configure( + meta, + |meta| meta.query_fixed(q_enable, Rotation::cur()), + |meta| meta.query_advice(tag_len, Rotation::cur()), + |meta| meta.query_advice(max_len, Rotation::cur()), + range256.into(), + ), is_block_header: meta.advice_column(), is_literals_header: meta.advice_column(), is_fse_code: meta.advice_column(), @@ -2687,6 +2693,9 @@ impl DecompressionCircuitConfig { let idx_cmp_len_chip = ComparatorChip::construct(self.tag_gadget.idx_cmp_len.clone()); idx_cmp_len_chip.assign(&mut region, i, F::from(row.state.tag_idx), F::from(row.state.tag_len))?; + let len_cmp_max_chip = ComparatorChip::construct(self.tag_gadget.len_cmp_max.clone()); + len_cmp_max_chip.assign(&mut region, i, F::from(row.state.tag_len), F::from(row.state.max_tag_len))?; + let max_tag_len = row.state.max_tag_len; let mlen_lt_0x20_chip = LtChip::construct(self.tag_gadget.mlen_lt_0x20.clone()); mlen_lt_0x20_chip.assign(&mut region, i, F::from(max_tag_len), F::from(0x20 as u64))?; @@ -2732,20 +2741,6 @@ impl DecompressionCircuitConfig { // is_output: meta.advice_column(), // tag_rlc: meta.advice_column_in(SecondPhase), // tag_rlc_acc: meta.advice_column_in(SecondPhase), - // mlen_lt_0x20: LtChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(max_len, Rotation::cur()), - // |_meta| 0x20.expr(), - // range256.into(), - // ), - // len_cmp_max: ComparatorChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(tag_len, Rotation::cur()), - // |meta| meta.query_advice(max_len, Rotation::cur()), - // range256.into(), - // ), // } From fdfab2409cbd97b08296ed606a0d870c78ba454b Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sat, 3 Feb 2024 23:24:38 -0500 Subject: [PATCH 061/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 5 ++--- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index bdab67dd08..83f18c2207 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -540,7 +540,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), ); - // compression_debug // compression_debug // We also need to validate that ``is_tag_change`` was assigned correctly. Tag changes // on the next row iff: @@ -627,8 +626,8 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), 1.expr(), ); - // let (lt, eq) = tag_gadget.len_cmp_max.expr(meta, None); - // cb.require_equal("tag_len <= max_len", lt + eq, 1.expr()); + let (lt, eq) = tag_gadget.len_cmp_max.expr(meta, None); + cb.require_equal("tag_len <= max_len", lt + eq, 1.expr()); // cb.require_equal( // "tag_value_acc == value_byte", // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 0d62e720e8..d5b7dce03d 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -88,7 +88,7 @@ fn process_frame_header( let fcs_tag_value_iter = fcs_bytes .iter() .scan(Value::known(F::zero()), |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); + *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); Some(*acc) }); let fcs_tag_value = fcs_tag_value_iter From 6d8f32850e7a4116c7ded8b4f33bea045def5efd Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sat, 3 Feb 2024 23:35:54 -0500 Subject: [PATCH 062/165] Correct Constraints --- zkevm-circuits/src/decompression_circuit.rs | 110 +++++++++----------- 1 file changed, 52 insertions(+), 58 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index a2641a928c..fcaa829172 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -113,9 +113,7 @@ pub struct DecompressionCircuitConfig { /// Huffman tree's config. huffman_tree_config: HuffmanConfig, /// Fields used to decode from bitstream. - /// compression_debug - bitstream_decoder: BitstreamDecoder, - // bitstream_decoder: BitstreamDecoder, + bitstream_decoder: BitstreamDecoder, /// Fields related to the application of FSE table to bitstream. fse_decoder: FseDecoder, /// Literal stream tag related configs. @@ -240,9 +238,7 @@ struct HuffmanConfig { /// Fields used while decoding from bitstream while not being byte-aligned, i.e. the bitstring /// could span over two bytes. #[derive(Clone, Debug)] -// compression_debug -// pub struct BitstreamDecoder { -pub struct BitstreamDecoder { +pub struct BitstreamDecoder { /// The bit-index where the bittsring begins. 0 <= bit_index_start < 8. bit_index_start: Column, /// The bit-index where the bitstring ends. 0 <= bit_index_end < 16. @@ -250,8 +246,7 @@ pub struct BitstreamDecoder { /// Helper gadget to know if the bitstring was contained in a single byte. We compare /// bit_index_end with 8 and if bit_index_end < 8 then the bitstring is contained. Otherwise it /// spans over two bytes. - /// compression_debug - // bitstream_contained: LtConfig, + bitstream_contained: LtConfig, /// The accumulated binary value of the bitstring. bit_value: Column, /// The symbol that this bitstring decodes to. We are using this for decoding using FSE table @@ -453,14 +448,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { BitstreamDecoder { bit_index_start: meta.advice_column(), bit_index_end, - // compression_debug - // bitstream_contained: LtChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(bit_index_end, Rotation::cur()), - // |_| 8.expr(), - // range256.into(), - // ), + bitstream_contained: LtChip::configure( + meta, + |meta| meta.query_fixed(q_enable, Rotation::cur()), + |meta| meta.query_advice(bit_index_end, Rotation::cur()), + |_| 8.expr(), + range256.into(), + ), bit_value: meta.advice_column(), decoded_symbol: meta.advice_column(), } @@ -1504,45 +1498,45 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we // // already know that block type == 0b11 (TREELESS) will not occur, we can skip the // // check for not::expr(value_bits[7]). - // let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); + let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); // Is the size format == 0b11. let is_size_format_0b11 = meta.query_advice(literals_header.sf_max, Rotation::cur()); - // let byte0 = meta.query_advice(value_byte, Rotation::cur()); - // let byte1 = select::expr( - // is_compressed.expr(), - // meta.query_advice(value_byte, Rotation(1)), - // select::expr( - // meta.query_advice(value_bits[5], Rotation::cur()), - // meta.query_advice(value_byte, Rotation(1)), - // 0.expr(), - // ), - // ); - // let byte2 = select::expr( - // is_compressed.expr(), - // meta.query_advice(value_byte, Rotation(2)), - // select::expr( - // meta.query_advice(value_bits[5], Rotation::cur()), - // meta.query_advice(value_byte, Rotation(2)), - // 0.expr(), - // ), - // ); - // let byte3 = select::expr( - // is_compressed.expr(), - // select::expr( - // meta.query_advice(value_bits[5], Rotation::cur()), - // meta.query_advice(value_byte, Rotation(3)), - // 0.expr(), - // ), - // 0.expr(), - // ); - // let byte4 = select::expr( - // is_compressed * is_size_format_0b11, - // meta.query_advice(value_byte, Rotation(4)), - // 0.expr(), - // ); + let byte0 = meta.query_advice(value_byte, Rotation::cur()); + let byte1 = select::expr( + is_compressed.expr(), + meta.query_advice(value_byte, Rotation(1)), + select::expr( + meta.query_advice(value_bits[5], Rotation::cur()), + meta.query_advice(value_byte, Rotation(1)), + 0.expr(), + ), + ); + let byte2 = select::expr( + is_compressed.expr(), + meta.query_advice(value_byte, Rotation(2)), + select::expr( + meta.query_advice(value_bits[5], Rotation::cur()), + meta.query_advice(value_byte, Rotation(2)), + 0.expr(), + ), + ); + let byte3 = select::expr( + is_compressed.expr(), + select::expr( + meta.query_advice(value_bits[5], Rotation::cur()), + meta.query_advice(value_byte, Rotation(3)), + 0.expr(), + ), + 0.expr(), + ); + let byte4 = select::expr( + is_compressed * is_size_format_0b11, + meta.query_advice(value_byte, Rotation(4)), + 0.expr(), + ); [ meta.query_advice(byte_idx, Rotation::cur()), // byte offset @@ -3092,26 +3086,26 @@ impl DecompressionCircuitConfig { // || Value::known(F::from(is_emit as u64)), // )?; region.assign_advice( - || "fse_gadget.num_emitted", - self.fse_gadget.num_emitted, + || "fse_decoder.num_emitted", + self.fse_decoder.num_emitted, i, || Value::known(F::one()), )?; region.assign_advice( - || "fse_gadget.state", - self.fse_gadget.state, + || "fse_decoder.state", + self.fse_decoder.state, i, || Value::known(F::from(row.fse_data.state as u64)), )?; region.assign_advice( - || "fse_gadget.baseline", - self.fse_gadget.baseline, + || "fse_decoder.baseline", + self.fse_decoder.baseline, i, || Value::known(F::from(row.fse_data.baseline as u64)), )?; region.assign_advice( - || "fse_gadget.symbol", - self.fse_gadget.symbol, + || "fse_decoder.symbol", + self.fse_decoder.symbol, i, || Value::known(F::from(row.fse_data.symbol as u64)), )?; From a6315cbca1d747b63a9948125b37d53cdcc6dd83 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sat, 3 Feb 2024 23:47:54 -0500 Subject: [PATCH 063/165] Correct constraints --- zkevm-circuits/src/decompression_circuit.rs | 44 +++++++++++++++------ zkevm-circuits/src/witness/zstd/mod.rs | 3 +- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index fcaa829172..f4007f2ceb 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2799,6 +2799,13 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.encoded_data.encoded_len)), )?; + + region.assign_advice( + || "encoded_len", + self.encoded_len, + i, + || Value::known(F::from(row.encoded_data.encoded_len)), + )?; // Byte value and bits decomposition region.assign_advice( @@ -2821,16 +2828,33 @@ impl DecompressionCircuitConfig { ), )?; } - - - - + region.assign_advice( + || "decoded_len", + self.decoded_len, + i, + || Value::known(F::from(row.decoded_data.decoded_len)), + )?; + region.assign_advice( + || "decoded_len_acc", + self.decoded_len_acc, + i, + || Value::known(F::from(row.decoded_data.decoded_len_acc)), + )?; + region.assign_advice( + || "decoded_byte", + self.decoded_byte, + i, + || Value::known(F::from(row.decoded_data.decoded_byte as u64)), + )?; + region.assign_advice( + || "decoded_rlc", + self.decoded_rlc, + i, + || row.decoded_data.decoded_value_rlc, + )?; + // let value_rlc = meta.advice_column_in(SecondPhase); - // let decoded_len = meta.advice_column(); - // let decoded_len_acc = meta.advice_column(); - // let decoded_byte = meta.advice_column(); - // let decoded_rlc = meta.advice_column_in(SecondPhase); @@ -2968,14 +2992,10 @@ impl DecompressionCircuitConfig { || Value::known(F::from(is_huffman_code)), )?; - - - // TagGadget { // tag_value: meta.advice_column_in(SecondPhase), // tag_value_acc: meta.advice_column_in(SecondPhase), // rand_pow_tag_len: meta.advice_column_in(SecondPhase), - // max_len, // is_output: meta.advice_column(), // tag_rlc: meta.advice_column_in(SecondPhase), // tag_rlc_acc: meta.advice_column_in(SecondPhase), diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index d5b7dce03d..52536677d4 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use eth_types::Field; use halo2_proofs::circuit::Value; @@ -134,7 +133,7 @@ fn process_frame_header( decoded_len_acc: 0, total_decoded_len: last_row.decoded_data.total_decoded_len + fcs, decoded_byte: 0, - decoded_value_rlc: last_row.decoded_data.decoded_value_rlc, + decoded_value_rlc: Value::known(F::zero()), }, huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), From cf8bf1863a10a313daa77f01b72c0623b85752f4 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 4 Feb 2024 21:45:00 -0500 Subject: [PATCH 064/165] Correct constraints --- zkevm-circuits/src/decompression_circuit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index f4007f2ceb..2b3620ec5c 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -3182,8 +3182,8 @@ impl SubCircuit for DecompressionCircuit { // compression_debug for row in witness_rows.clone() { - log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;", - row.state.tag, row.state.tag_next, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, + log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;", + row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, ); } From 4fafb5b2526963ed6adf85e4bbe7e4780eeec63f Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 4 Feb 2024 22:27:12 -0500 Subject: [PATCH 065/165] Annotate test data --- .../src/decompression_circuit/test.rs | 93 ++++++++++++------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit/test.rs b/zkevm-circuits/src/decompression_circuit/test.rs index 443f7147de..191ce042f9 100644 --- a/zkevm-circuits/src/decompression_circuit/test.rs +++ b/zkevm-circuits/src/decompression_circuit/test.rs @@ -18,42 +18,63 @@ fn test_basic() { fn test_work_example_decompression() { let compressed: Vec = vec![ // 0x28, 0xb5, 0x2f, 0xfd, // magic numbers are removed - 0x60, // originally 0x64. unset the checksum bit. - 0xae, 0x02, 0x0d, 0x11, 0x00, 0x76, 0x62, 0x5e, 0x23, 0x30, 0x6f, - 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, - 0xa9, 0xd4, 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, - 0x01, 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, - 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, - 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, - 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, - 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, - 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, 0x5a, 0xdf, 0xb4, 0x21, 0x9a, 0xcb, 0x8f, 0xc7, - 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, 0x28, 0x0e, 0xfb, 0x8b, - 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, 0xeb, 0x81, 0xf1, 0x78, 0x4b, 0xad, - 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, 0xb4, 0xd9, 0xe1, 0x95, 0x21, 0x66, 0x0c, - 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, 0x22, 0x07, 0x0b, 0x91, 0x86, 0x94, 0x1a, 0x7b, - 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, 0x65, 0xd6, 0x34, 0x63, 0x0c, 0x88, 0x9b, 0x1c, 0x48, - 0xca, 0x2b, 0x34, 0xa9, 0x6b, 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, - 0x69, 0x18, 0x57, 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, - 0x7b, 0x6e, 0xd8, 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, 0x14, - 0xf4, 0x40, 0xe7, 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, 0x49, 0xae, 0x13, - 0xa4, 0x75, 0x38, 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, 0x86, 0xa4, 0xac, 0xaa, 0xa3, - 0x34, 0x89, 0xca, 0x2e, 0xe9, 0xc1, 0xfe, 0xf2, 0x51, 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, - 0xed, 0xd9, 0xb7, 0x4a, 0xb2, 0xb2, 0x61, 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, - 0xdc, 0x60, 0x6c, 0x41, 0x76, 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, - 0xac, 0x9d, 0xe0, 0x62, 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, - 0xd2, 0x7c, 0x0a, 0x7c, 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, 0xda, - 0x15, 0x91, 0xde, 0x21, 0xf5, 0x55, 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, 0x42, 0x44, 0x81, - 0x8c, 0x94, 0xb4, 0x50, 0x1e, 0x20, 0x42, 0x82, 0x98, 0xc2, 0x3b, 0x10, 0x48, 0xec, 0xa6, 0x39, - 0x63, 0x13, 0xa7, 0x01, 0x94, 0x40, 0xff, 0x88, 0x0f, 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, - 0xcb, 0xf6, 0xc8, 0x21, 0x59, 0xaa, 0x38, 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, - 0xc8, 0x03, 0x42, 0x2a, 0x4b, 0xf6, 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, - 0x7e, 0x00, 0xbc, 0x2f, 0x46, 0x96, 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, - 0x8c, 0xc2, 0x05, 0xf7, 0x54, 0x51, 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, 0x99, - 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, 0x50, 0x84, 0xf5, - 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, 0x4c, 0x52, 0x4f, 0x20, 0xa3, 0x61, 0x23, 0x77, 0x12, 0xd3, - 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, 0x70, 0xec, 0x14, 0x91, 0xf9, 0x85, 0x61, 0xd5, 0x7e, 0x98, - 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, + 0x60, // Originally 0x64. unset the checksum bit. + 0xae, 0x02, // FrameContentSize + 0x0d, 0x11, 0x00, // BlockHeader + 0x76, 0x62, 0x5e, // ZstdBlockLiteralsHeader + 0x23, 0x30, 0x6f, 0x9b, 0x03, // ZstdBlockFseCode + + // ZstdBlockHuffmanCode + 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, 0xa9, 0xd4, + 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, 0x01, 0x55, + + // ZstdBlockJumpTable + 0x00, 0x57, 0x00, 0x51, 0x00, 0xcc, + + // LStream1 + 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, 0x65, + 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, 0xa3, + 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, 0x1c, + 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, + 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, + 0x5a, 0xdf, 0xb4, 0x21, + + // LStream2 + 0x9a, 0xcb, 0x8f, 0xc7, 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, + 0x28, 0x0e, 0xfb, 0x8b, 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, 0xeb, 0x81, + 0xf1, 0x78, 0x4b, 0xad, 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, 0xb4, 0xd9, 0xe1, + 0x95, 0x21, 0x66, 0x0c, 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, 0x22, 0x07, 0x0b, 0x91, + 0x86, 0x94, 0x1a, 0x7b, 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, 0x65, 0xd6, 0x34, 0x63, 0x0c, + 0x88, 0x9b, 0x1c, 0x48, 0xca, 0x2b, 0x34, + + // LStream3 + 0xa9, 0x6b, 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, 0x69, 0x18, 0x57, + 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, 0x7b, 0x6e, 0xd8, + 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, 0x14, 0xf4, 0x40, 0xe7, + 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, 0x49, 0xae, 0x13, 0xa4, 0x75, 0x38, + 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, 0x86, 0xa4, 0xac, 0xaa, 0xa3, 0x34, 0x89, 0xca, + 0x2e, + + // LStream4 + 0xe9, 0xc1, 0xfe, 0xf2, 0x51, 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, 0xed, 0xd9, 0xb7, 0x4a, + 0xb2, 0xb2, 0x61, 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, 0xdc, 0x60, 0x6c, 0x41, + 0x76, 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, 0xac, 0x9d, 0xe0, 0x62, + 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, 0xd2, 0x7c, 0x0a, 0x7c, + 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, 0xda, 0x15, 0x91, 0xde, 0x21, + 0xf5, 0x55, + + // Sequence Section + 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, 0x42, 0x44, 0x81, 0x8c, 0x94, 0xb4, 0x50, 0x1e, 0x20, + 0x42, 0x82, 0x98, 0xc2, 0x3b, 0x10, 0x48, 0xec, 0xa6, 0x39, 0x63, 0x13, 0xa7, 0x01, 0x94, 0x40, + 0xff, 0x88, 0x0f, 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, 0xcb, 0xf6, 0xc8, 0x21, 0x59, 0xaa, + 0x38, 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, 0xc8, 0x03, 0x42, 0x2a, 0x4b, 0xf6, + 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, 0x7e, 0x00, 0xbc, 0x2f, 0x46, 0x96, + 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, 0x8c, 0xc2, 0x05, 0xf7, 0x54, 0x51, + 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, 0x99, 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, + 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, 0x50, 0x84, 0xf5, 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, + 0x4c, 0x52, 0x4f, 0x20, 0xa3, 0x61, 0x23, 0x77, 0x12, 0xd3, 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, + 0x70, 0xec, 0x14, 0x91, 0xf9, 0x85, 0x61, 0xd5, 0x7e, 0x98, 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, + 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, ]; let decompression_circuit = DecompressionCircuit:: { From 56fa004221d3500a49ac3f4df1b29b2b930213a5 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 5 Feb 2024 17:40:06 -0500 Subject: [PATCH 066/165] Resolve merge issues --- zkevm-circuits/src/decompression_circuit.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index e550c572ed..5a4241b0ed 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -963,12 +963,12 @@ impl SubCircuitConfig for DecompressionCircuitConfig { not::expr(meta.query_advice(is_padding, Rotation::cur())), ]); - // vec![( - // condition * meta.query_advice(decoded_byte, Rotation::cur()), - // range256.into(), - // )] - // }, - // ); + vec![( + condition * meta.query_advice(decoded_byte, Rotation::cur()), + range256.into(), + )] + }, + ); debug_assert!(meta.degree() <= 9); From cf49db2877cb5f37a7c6cd56e84d4830153851a7 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 5 Feb 2024 20:36:46 -0500 Subject: [PATCH 067/165] Examine constraints --- zkevm-circuits/src/decompression_circuit.rs | 1508 ++++++++++--------- zkevm-circuits/src/witness/zstd/mod.rs | 8 +- 2 files changed, 818 insertions(+), 698 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 5a4241b0ed..3b45675bd8 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -547,15 +547,16 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // Degree reduction columns. macro_rules! degree_reduction_check { ($column:expr, $expr:expr) => { - cb.require_equal( - "Degree reduction column check", - meta.query_advice($column, Rotation::cur()), - $expr, - ); + // compression_debug + // cb.require_equal( + // "Degree reduction column check", + // meta.query_advice($column, Rotation::cur()), + // $expr, + // ); }; } degree_reduction_check!(tag_gadget.is_block_header, is_block_header(meta)); - degree_reduction_check!(tag_gadget.is_literals_section, is_zb_literals_header(meta)); + degree_reduction_check!(tag_gadget.is_literals_header, is_zb_literals_header(meta)); degree_reduction_check!(tag_gadget.is_fse_code, is_zb_fse_code(meta)); degree_reduction_check!(tag_gadget.is_huffman_code, is_zb_huffman_code(meta)); degree_reduction_check!(tag_gadget.is_lstream, is_zb_lstream(meta)); @@ -644,20 +645,22 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // If we don't encounter a new byte, the byte value should stay the same. cb.condition(not::expr(is_new_byte.expr()), |cb| { - cb.require_equal( - "value_byte' == value_byte if not a new byte", - meta.query_advice(value_byte, Rotation::next()), - meta.query_advice(value_byte, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "value_byte' == value_byte if not a new byte", + // meta.query_advice(value_byte, Rotation::next()), + // meta.query_advice(value_byte, Rotation::cur()), + // ); }); // If we don't encounter a new byte, the byte value should stay the same. cb.condition(not::expr(is_new_byte.expr()), |cb| { - cb.require_equal( - "value_byte' == value_byte if not a new byte", - meta.query_advice(value_byte, Rotation::next()), - meta.query_advice(value_byte, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "value_byte' == value_byte if not a new byte", + // meta.query_advice(value_byte, Rotation::next()), + // meta.query_advice(value_byte, Rotation::cur()), + // ); }); // We also need to validate that ``is_tag_change`` was assigned correctly. Tag changes @@ -829,15 +832,17 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let tag_value_acc_prev = meta.query_advice(tag_gadget.tag_value_acc, Rotation::prev()); let value_byte_curr = meta.query_advice(value_byte, Rotation::cur()); - cb.require_equal( - "tag_value calculation depending on whether new byte", - meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), - select::expr( - is_new_byte.expr(), - tag_value_acc_prev.expr() * multiplier + value_byte_curr.expr(), - tag_value_acc_prev, - ), - ); + + // compression_debug + // cb.require_equal( + // "tag_value calculation depending on whether new byte", + // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), + // select::expr( + // is_new_byte.expr(), + // tag_value_acc_prev.expr() * multiplier + value_byte_curr.expr(), + // tag_value_acc_prev, + // ), + // ); // tag_rlc_acc calculation depending on whether is_reverse or not. let is_reverse = meta.query_advice(tag_gadget.is_reverse, Rotation::cur()); @@ -1486,122 +1491,129 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - meta.lookup_any( - "DecompressionCircuit: lookup for tuple (zstd_block_type, tag_next)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - ]); - [ - meta.query_advice(tag_gadget.tag, Rotation::cur()), - meta.query_advice(value_bits[7], Rotation::cur()), - meta.query_advice(value_bits[6], Rotation::cur()), - meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - ] - .into_iter() - .zip(block_type_rom_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: lookup for LiteralsHeader decomposition", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - ]); - [ - meta.query_advice(value_bits[7], Rotation::cur()), // block type bit0 - meta.query_advice(value_bits[6], Rotation::cur()), // block type bit1 - meta.query_advice(value_bits[5], Rotation::cur()), // size format bit0 - meta.query_advice(value_bits[4], Rotation::cur()), // size format bit1 - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header - meta.query_advice(lstream_config.lstream_kind, Rotation::cur()), // 1 or 4 - meta.query_advice(literals_header.branch, Rotation::cur()), // branch - meta.query_advice(literals_header.sf_max, Rotation::cur()), // size format 0b11 - ] - .into_iter() - .zip(literals_header_rom_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: lookup for LiteralsHeader regen/compr size", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - ]); - // Which branch are we taking in the literals header decomposition. - let branch = meta.query_advice(literals_header.branch, Rotation::cur()); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for tuple (zstd_block_type, tag_next)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + // ]); + // [ + // meta.query_advice(tag_gadget.tag, Rotation::cur()), + // meta.query_advice(value_bits[7], Rotation::cur()), + // meta.query_advice(value_bits[6], Rotation::cur()), + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // ] + // .into_iter() + // .zip(block_type_rom_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for LiteralsHeader decomposition", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + // ]); + // [ + // meta.query_advice(value_bits[7], Rotation::cur()), // block type bit0 + // meta.query_advice(value_bits[6], Rotation::cur()), // block type bit1 + // meta.query_advice(value_bits[5], Rotation::cur()), // size format bit0 + // meta.query_advice(value_bits[4], Rotation::cur()), // size format bit1 + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header + // meta.query_advice(lstream_config.lstream_kind, Rotation::cur()), // 1 or 4 + // meta.query_advice(literals_header.branch, Rotation::cur()), // branch + // meta.query_advice(literals_header.sf_max, Rotation::cur()), // size format 0b11 + // ] + // .into_iter() + // .zip(literals_header_rom_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); - // // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we - // // already know that block type == 0b11 (TREELESS) will not occur, we can skip the - // // check for not::expr(value_bits[7]). - let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for LiteralsHeader regen/compr size", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + // ]); - // Is the size format == 0b11. - let is_size_format_0b11 = - meta.query_advice(literals_header.sf_max, Rotation::cur()); + // // Which branch are we taking in the literals header decomposition. + // let branch = meta.query_advice(literals_header.branch, Rotation::cur()); + + // // // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we + // // // already know that block type == 0b11 (TREELESS) will not occur, we can skip the + // // // check for not::expr(value_bits[7]). + // let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); + + // // Is the size format == 0b11. + // let is_size_format_0b11 = + // meta.query_advice(literals_header.sf_max, Rotation::cur()); + + // let byte0 = meta.query_advice(value_byte, Rotation::cur()); + // let byte1 = select::expr( + // is_compressed.expr(), + // meta.query_advice(value_byte, Rotation(1)), + // select::expr( + // meta.query_advice(value_bits[5], Rotation::cur()), + // meta.query_advice(value_byte, Rotation(1)), + // 0.expr(), + // ), + // ); + // let byte2 = select::expr( + // is_compressed.expr(), + // meta.query_advice(value_byte, Rotation(2)), + // select::expr( + // meta.query_advice(value_bits[5], Rotation::cur()), + // meta.query_advice(value_byte, Rotation(2)), + // 0.expr(), + // ), + // ); + // let byte3 = select::expr( + // is_compressed.expr(), + // select::expr( + // meta.query_advice(value_bits[5], Rotation::cur()), + // meta.query_advice(value_byte, Rotation(3)), + // 0.expr(), + // ), + // 0.expr(), + // ); + // let byte4 = select::expr( + // is_compressed * is_size_format_0b11, + // meta.query_advice(value_byte, Rotation(4)), + // 0.expr(), + // ); - let byte0 = meta.query_advice(value_byte, Rotation::cur()); - let byte1 = select::expr( - is_compressed.expr(), - meta.query_advice(value_byte, Rotation(1)), - select::expr( - meta.query_advice(value_bits[5], Rotation::cur()), - meta.query_advice(value_byte, Rotation(1)), - 0.expr(), - ), - ); - let byte2 = select::expr( - is_compressed.expr(), - meta.query_advice(value_byte, Rotation(2)), - select::expr( - meta.query_advice(value_bits[5], Rotation::cur()), - meta.query_advice(value_byte, Rotation(2)), - 0.expr(), - ), - ); - let byte3 = select::expr( - is_compressed.expr(), - select::expr( - meta.query_advice(value_bits[5], Rotation::cur()), - meta.query_advice(value_byte, Rotation(3)), - 0.expr(), - ), - 0.expr(), - ); - let byte4 = select::expr( - is_compressed * is_size_format_0b11, - meta.query_advice(value_byte, Rotation(4)), - 0.expr(), - ); + // [ + // meta.query_advice(byte_idx, Rotation::cur()), // byte offset + // branch, // branch + // byte0, // byte0 + // byte1, // byte1 + // byte2, // byte2 + // byte3, // byte3 + // byte4, // byte4 + // meta.query_advice(literals_header.regen_size, Rotation::cur()), // regenerated size + // meta.query_advice(literals_header.compr_size, Rotation::cur()), // compressed size + // ] + // .into_iter() + // .zip(literals_header_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); - [ - meta.query_advice(byte_idx, Rotation::cur()), // byte offset - branch, // branch - byte0, // byte0 - byte1, // byte1 - byte2, // byte2 - byte3, // byte3 - byte4, // byte4 - meta.query_advice(literals_header.regen_size, Rotation::cur()), // regenerated size - meta.query_advice(literals_header.compr_size, Rotation::cur()), // compressed size - ] - .into_iter() - .zip(literals_header_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); meta.create_gate("DecompressionCircuit: LiteralsSection", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -1730,34 +1742,39 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let tag_len_fse_code = meta.query_advice(tag_gadget.tag_len, Rotation::cur()); let tag_len_huffman_code = meta.query_advice(huffman_tree_config.huffman_code_len, Rotation::cur()); - cb.require_equal( - "huffman header value byte check", - meta.query_advice(value_byte, Rotation::cur()) + 1.expr(), - tag_len_fse_code + tag_len_huffman_code, - ); + + // compression_debug + // cb.require_equal( + // "huffman header value byte check", + // meta.query_advice(value_byte, Rotation::cur()) + 1.expr(), + // tag_len_fse_code + tag_len_huffman_code, + // ); // The huffman tree description starts at this byte index. We identify the FSE and // Huffman tables using this byte index. - cb.require_equal( - "huffman header byte offset assignment", - meta.query_advice(byte_idx, Rotation::cur()), - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "huffman header byte offset assignment", + // meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // ); // We know that the next byte is the start of processing bitstream to construct the // FSE table. The first 4 bits are used to calculate the accuracy log (and the // table size) of the table. So the first bitstring that's decoded starts from // bit_index 4 (considering that it is 0-indexed). - cb.require_equal( - "accuracy log read from bits [0, 4)", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - 0.expr(), - ); - cb.require_equal( - "accuracy log read from bits [0, 4)", - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()), - 3.expr(), - ); + + // compression_debug + // cb.require_equal( + // "accuracy log read from bits [0, 4)", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // 0.expr(), + // ); + // cb.require_equal( + // "accuracy log read from bits [0, 4)", + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()), + // 3.expr(), + // ); // At every row, a new symbol is decoded. This symbol stands for the weight in the // canonical Huffman code representation. So we start at symbol == S0, i.e. 0 and @@ -1778,11 +1795,12 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); // Check that the decoded accuracy log is correct. - cb.require_equal( - "accuracy log check", - meta.query_advice(huffman_tree_config.fse_table_al, Rotation::next()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::next()) + 5.expr(), - ); + // compression_debug + // cb.require_equal( + // "accuracy log check", + // meta.query_advice(huffman_tree_config.fse_table_al, Rotation::next()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::next()) + 5.expr(), + // ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1820,45 +1838,115 @@ impl SubCircuitConfig for DecompressionCircuitConfig { .collect() }, ); - meta.create_gate( - "DecompressionCircuit: ZstdBlockFseCode (fse code)", - |meta| { - let mut cb = BaseConstraintBuilder::default(); - // The decoded symbol keeps incrementing in the FSE code reconstruction. Since - // we've already done the check for the first symbol in the huffman header gate, we - // only check for increments. - cb.require_equal( - "fse table reconstruction: decoded symbol increments", - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::prev()) - + 1.expr(), - ); - cb.require_equal( - "number of states assigned so far is accumulated correctly", - meta.query_advice(fse_decoder.n_acc, Rotation::cur()) + 1.expr(), - meta.query_advice(fse_decoder.n_acc, Rotation::prev()) - + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); + // compression_debug + // meta.create_gate( + // "DecompressionCircuit: ZstdBlockFseCode (fse code)", + // |meta| { + // let mut cb = BaseConstraintBuilder::default(); + + // // The decoded symbol keeps incrementing in the FSE code reconstruction. Since + // // we've already done the check for the first symbol in the huffman header gate, we + // // only check for increments. + // cb.require_equal( + // "fse table reconstruction: decoded symbol increments", + // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), + // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::prev()) + // + 1.expr(), + // ); + // cb.require_equal( + // "number of states assigned so far is accumulated correctly", + // meta.query_advice(fse_decoder.n_acc, Rotation::cur()) + 1.expr(), + // meta.query_advice(fse_decoder.n_acc, Rotation::prev()) + // + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + + // let is_last = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); + // cb.condition(is_last, |cb| { + // cb.require_equal( + // "on the last row, accumulated number of symbols is the table size of FSE table", + // meta.query_advice(fse_decoder.n_acc, Rotation::cur()), + // meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), + // ); + // }); + + // cb.gate(and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // ])) + // }, + // ); - let is_last = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); - cb.condition(is_last, |cb| { - cb.require_equal( - "on the last row, accumulated number of symbols is the table size of FSE table", - meta.query_advice(fse_decoder.n_acc, Rotation::cur()), - meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), - ); - }); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (contained bitstream start)", + // |meta| { + // let (huffman_byte_offset, start, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // bitstream_decoder.is_contained(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // 1.expr(), // bitstring length accumulator, starts at 1 + // start, // bit index start + // 1.expr(), // denotes that this bit index is a part of the bitstring + // 1.expr(), // denotes that this bit index is a part of the bitstring + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (contained bitstream end)", + // |meta| { + // let (huffman_byte_offset, start, end, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // bitstream_decoder.is_contained(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); - cb.gate(and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - ])) - }, - ); meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (contained bitstream start)", + "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", |meta| { let (huffman_byte_offset, start, bit_value) = ( meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), @@ -1869,63 +1957,34 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - bitstream_decoder.is_contained(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - 1.expr(), // bitstring length accumulator, starts at 1 - start, // bit index start - 1.expr(), // denotes that this bit index is a part of the bitstring - 1.expr(), // denotes that this bit index is a part of the bitstring - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (contained bitstream end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - bitstream_decoder.is_contained(meta, None), + bitstream_decoder.is_spanned(meta, None), ]); [ huffman_byte_offset, // huffman ID meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(byte_idx, Rotation::next()), // byte index' meta.query_advice(value_byte, Rotation::cur()), // byte value + meta.query_advice(value_byte, Rotation::next()), // byte value' bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end + 1.expr(), // bitstring len acc + start, // bit index start 1.expr(), // from start 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse ] .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) + .zip(bs_acc_table.table_exprs_spanned(meta)) .map(|(value, table)| (condition.expr() * value, table)) .collect() }, ); meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", + "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", |meta| { - let (huffman_byte_offset, start, bit_value) = ( + let (huffman_byte_offset, start, end, bit_value) = ( meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), ); let condition = and::expr([ @@ -1941,11 +2000,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(value_byte, Rotation::cur()), // byte value meta.query_advice(value_byte, Rotation::next()), // byte value' bit_value, // bitstring value - 1.expr(), // bitstring len acc - start, // bit index start + end.expr() - start + 1.expr(), // bitstring length + end, // bit index at end 1.expr(), // from start 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse ] .into_iter() .zip(bs_acc_table.table_exprs_spanned(meta)) @@ -1953,70 +2012,39 @@ impl SubCircuitConfig for DecompressionCircuitConfig { .collect() }, ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (symbol count check)", - |meta| { - let (huffman_byte_offset, bit_value, decoded_symbol) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - ]); - // The FSE table reconstruction follows a variable bit packing. However we know the - // start and end bit index for the bitstring that was read. We read a value in the - // range 0..=R+1 and then subtract 1 from it to get N, i.e. the number of slots - // that were allocated to that symbol in the FSE table. This is also the count of - // the symbol in the FseTable. - [ - huffman_byte_offset, // huffman ID - meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), // table size - decoded_symbol, // decoded symbol. - bit_value - 1.expr(), // symbol count - ] - .into_iter() - .zip(fse_table.table_exprs_symbol_count_check(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (symbol count check)", + // |meta| { + // let (huffman_byte_offset, bit_value, decoded_symbol) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // ]); + // // The FSE table reconstruction follows a variable bit packing. However we know the + // // start and end bit index for the bitstring that was read. We read a value in the + // // range 0..=R+1 and then subtract 1 from it to get N, i.e. the number of slots + // // that were allocated to that symbol in the FSE table. This is also the count of + // // the symbol in the FseTable. + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), // table size + // decoded_symbol, // decoded symbol. + // bit_value - 1.expr(), // symbol count + // ] + // .into_iter() + // .zip(fse_table.table_exprs_symbol_count_check(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + meta.create_gate("DecompressionCircuit: HuffmanTreeSection", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -2052,77 +2080,83 @@ impl SubCircuitConfig for DecompressionCircuitConfig { /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// ZstdTag::ZstdBlockHuffmanCode ///////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// - meta.create_gate( - "DecompressionCircuit: ZstdBlockHuffmanCode (first row)", - |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // - The first row of the HuffmanCode tag is the leading 0s and sentinel bit. - // - The second row of the HuffmanCode tag is the reading of AL number of bits from - // the bitstream to find the initial state in the FSE table. - // - Only from the third row onwards, do we start emitting symbols (weights). - - cb.require_zero( - "num_emitted starts at 0 from the second row", - meta.query_advice(fse_decoder.num_emitted, Rotation::next()), - ); - - // On the second row we read AL number of bits. - cb.require_equal( - "AL number of bits read on the second row", - meta.query_advice(huffman_tree_config.fse_table_al, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()) - - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()) - + 1.expr(), - ); - // Whatever bitstring we read, is also the initial state in the FSE table, where we - // start applying the FSE table. - cb.require_equal( - "init state of FSE table", - meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), - meta.query_advice(fse_decoder.state, Rotation(2)), - ); - - let lstream_kind = meta.query_advice(lstream_config.lstream_kind, Rotation::cur()); - cb.require_equal( - "tag_next after Huffman code depending on Lstream kind", - meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - select::expr( - lstream_kind, - ZstdTag::ZstdBlockJumpTable.expr(), - ZstdTag::ZstdBlockLstream.expr(), - ), - ); - - cb.gate(and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - ])) - }, - ); + // compression_debug + // meta.create_gate( + // "DecompressionCircuit: ZstdBlockHuffmanCode (first row)", + // |meta| { + // let mut cb = BaseConstraintBuilder::default(); + + // // - The first row of the HuffmanCode tag is the leading 0s and sentinel bit. + // // - The second row of the HuffmanCode tag is the reading of AL number of bits from + // // the bitstream to find the initial state in the FSE table. + // // - Only from the third row onwards, do we start emitting symbols (weights). + + // cb.require_zero( + // "num_emitted starts at 0 from the second row", + // meta.query_advice(fse_decoder.num_emitted, Rotation::next()), + // ); + + // // On the second row we read AL number of bits. + // cb.require_equal( + // "AL number of bits read on the second row", + // meta.query_advice(huffman_tree_config.fse_table_al, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()) + // - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()) + // + 1.expr(), + // ); + // // Whatever bitstring we read, is also the initial state in the FSE table, where we + // // start applying the FSE table. + // cb.require_equal( + // "init state of FSE table", + // meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), + // meta.query_advice(fse_decoder.state, Rotation(2)), + // ); + + // let lstream_kind = meta.query_advice(lstream_config.lstream_kind, Rotation::cur()); + // cb.require_equal( + // "tag_next after Huffman code depending on Lstream kind", + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // select::expr( + // lstream_kind, + // ZstdTag::ZstdBlockJumpTable.expr(), + // ZstdTag::ZstdBlockLstream.expr(), + // ), + // ); + + // cb.gate(and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // ])) + // }, + // ); meta.create_gate( "DecompressionCircuit: ZstdBlockHuffmanCode (wherever we emit a symbol)", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "num_emitted increments", - meta.query_advice(fse_decoder.num_emitted, Rotation::cur()), - meta.query_advice(fse_decoder.num_emitted, Rotation::prev()) + 1.expr(), - ); + // compression_debug + // cb.require_equal( + // "num_emitted increments", + // meta.query_advice(fse_decoder.num_emitted, Rotation::cur()), + // meta.query_advice(fse_decoder.num_emitted, Rotation::prev()) + 1.expr(), + // ); // Check for state transition, except if we are on the last row of HuffmanCode. let is_last_row = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); let baseline = meta.query_advice(fse_decoder.baseline, Rotation::cur()); // baseline at state let bit_value = meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()); // bits read - cb.condition(not::expr(is_last_row), |cb| { - cb.require_equal( - "state' == baseline(state) + bit_value", - meta.query_advice(fse_decoder.state, Rotation::next()), - baseline + bit_value, - ); - }); + + // compression_debug + // cb.condition(not::expr(is_last_row), |cb| { + // cb.require_equal( + // "state' == baseline(state) + bit_value", + // meta.query_advice(fse_decoder.state, Rotation::next()), + // baseline + bit_value, + // ); + // }); + + cb.require_zero("", 0.expr()); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -2132,67 +2166,72 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.is_contained(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - 1.expr(), // bitstring length accumulator, starts at 1 - start, // bit index start - 1.expr(), // denotes that this bit index is a part of the bitstring - 1.expr(), // denotes that this bit index is a part of the bitstring - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.is_contained(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream start)", + // |meta| { + // let (huffman_byte_offset, start, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // bitstream_decoder.is_contained(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // 1.expr(), // bitstring length accumulator, starts at 1 + // start, // bit index start + // 1.expr(), // denotes that this bit index is a part of the bitstring + // 1.expr(), // denotes that this bit index is a part of the bitstring + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream end)", + // |meta| { + // let (huffman_byte_offset, start, end, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // bitstream_decoder.is_contained(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + meta.lookup_any( "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", |meta| { @@ -2282,153 +2321,161 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // symbols (weights), where N is the total number of huffman symbols that are being encoded // in that Huffman table. As per the canonical Huffman code representation, we only need to // emit N - 1 weights and the weight of the last symbol can be calculated. - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), - ]); - let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); - let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); - let num_bits = end - start + 1.expr(); - [ - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), - meta.query_advice(fse_decoder.state, Rotation::cur()), - meta.query_advice(fse_decoder.symbol, Rotation::cur()), - meta.query_advice(fse_decoder.baseline, Rotation::cur()), - num_bits, - ] - .into_iter() - .zip(fse_table.table_exprs_state_check(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (huffman codes table lookup)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), - ]); - [ - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - meta.query_advice(fse_decoder.symbol, Rotation::cur()), - ] - .into_iter() - .zip(huffman_codes_table.table_exprs_canonical_weight(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (num symbols in huffman code)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), - ]); - [ - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(fse_decoder.num_emitted, Rotation::cur()), - 1.expr(), // is_last - ] - .into_iter() - .zip(huffman_codes_table.table_exprs_weights_count(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), + // ]); + // let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); + // let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); + // let num_bits = end - start + 1.expr(); + // [ + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), + // meta.query_advice(fse_decoder.state, Rotation::cur()), + // meta.query_advice(fse_decoder.symbol, Rotation::cur()), + // meta.query_advice(fse_decoder.baseline, Rotation::cur()), + // num_bits, + // ] + // .into_iter() + // .zip(fse_table.table_exprs_state_check(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (huffman codes table lookup)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), + // ]); + // [ + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // meta.query_advice(fse_decoder.symbol, Rotation::cur()), + // ] + // .into_iter() + // .zip(huffman_codes_table.table_exprs_canonical_weight(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (num symbols in huffman code)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), + // ]); + // [ + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(fse_decoder.num_emitted, Rotation::cur()), + // 1.expr(), // is_last + // ] + // .into_iter() + // .zip(huffman_codes_table.table_exprs_weights_count(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); debug_assert!(meta.degree() <= 9); /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// ZstdTag::ZstdBlockJumpTable /////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// - meta.create_gate("DecompressionCircuit: ZstdBlockJumpTable", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - cb.require_equal( - "tag_len == 6", - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - N_JUMP_TABLE_BYTES.expr(), - ); - - // Length of Lstream1. - let len1 = meta.query_advice(value_byte, Rotation(0)) - + 256.expr() * meta.query_advice(value_byte, Rotation(1)); - // Length of Lstream 2. - let len2 = meta.query_advice(value_byte, Rotation(2)) - + 256.expr() * meta.query_advice(value_byte, Rotation(3)); - // Length of Lstream3. - let len3 = meta.query_advice(value_byte, Rotation(4)) - + 256.expr() * meta.query_advice(value_byte, Rotation(5)); - - cb.require_equal( - "length of Lstream1", - meta.query_advice(lstream_config.len_lstream1, Rotation::cur()), - len1.expr(), - ); - cb.require_equal( - "length of lstream2", - meta.query_advice(lstream_config.len_lstream2, Rotation::cur()), - len2.expr(), - ); - cb.require_equal( - "length of lstream3", - meta.query_advice(lstream_config.len_lstream3, Rotation::cur()), - len3.expr(), - ); - // To calculate the size of Lstream4, we have: - // - TotalStreamsSize == CompressedSize - HuffmanTreeDescriptionSize - // - Stream4_Size == TotalStreamsSize - Stream1_Size - Stream2_Size - Stream3_Size - // - // The HuffmanTreeDescriptionSize can be calculated as: - // - HuffmanTreeDescriptionSize == byte_idx(JumpTable) - byte_idx(HuffmanTree) - cb.require_equal( - "length of lstream4", - meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) - + len1 - + len2 - + len3 - + meta.query_advice(byte_idx, Rotation::cur()), - meta.query_advice(literals_header.compr_size, Rotation::cur()) - + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - ); - - for col in [ - lstream_config.len_lstream1, - lstream_config.len_lstream2, - lstream_config.len_lstream3, - lstream_config.len_lstream4, - ] { - cb.require_equal( - "Lstream config gets transferred to Lstream section", - meta.query_advice(col, Rotation::cur()), - meta.query_advice(col, Rotation(N_JUMP_TABLE_BYTES as i32)), - ); - } - - cb.require_equal( - "first lstream that follows jump table is Lstream1", - meta.query_advice(lstream_config.lstream, Rotation(N_JUMP_TABLE_BYTES as i32)), - LstreamNum::Lstream1.expr(), - ); - - cb.gate(and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - is_zb_jump_table(meta), - ])) - }); + + // compression_debug + // meta.create_gate("DecompressionCircuit: ZstdBlockJumpTable", |meta| { + // let mut cb = BaseConstraintBuilder::default(); + + // cb.require_equal( + // "tag_len == 6", + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + // N_JUMP_TABLE_BYTES.expr(), + // ); + + // // Length of Lstream1. + // let len1 = meta.query_advice(value_byte, Rotation(0)) + // + 256.expr() * meta.query_advice(value_byte, Rotation(1)); + // // Length of Lstream 2. + // let len2 = meta.query_advice(value_byte, Rotation(2)) + // + 256.expr() * meta.query_advice(value_byte, Rotation(3)); + // // Length of Lstream3. + // let len3 = meta.query_advice(value_byte, Rotation(4)) + // + 256.expr() * meta.query_advice(value_byte, Rotation(5)); + + // cb.require_equal( + // "length of Lstream1", + // meta.query_advice(lstream_config.len_lstream1, Rotation::cur()), + // len1.expr(), + // ); + // cb.require_equal( + // "length of lstream2", + // meta.query_advice(lstream_config.len_lstream2, Rotation::cur()), + // len2.expr(), + // ); + // cb.require_equal( + // "length of lstream3", + // meta.query_advice(lstream_config.len_lstream3, Rotation::cur()), + // len3.expr(), + // ); + // // To calculate the size of Lstream4, we have: + // // - TotalStreamsSize == CompressedSize - HuffmanTreeDescriptionSize + // // - Stream4_Size == TotalStreamsSize - Stream1_Size - Stream2_Size - Stream3_Size + // // + // // The HuffmanTreeDescriptionSize can be calculated as: + // // - HuffmanTreeDescriptionSize == byte_idx(JumpTable) - byte_idx(HuffmanTree) + // cb.require_equal( + // "length of lstream4", + // meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) + // + len1 + // + len2 + // + len3 + // + meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(literals_header.compr_size, Rotation::cur()) + // + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // ); + + // for col in [ + // lstream_config.len_lstream1, + // lstream_config.len_lstream2, + // lstream_config.len_lstream3, + // lstream_config.len_lstream4, + // ] { + // cb.require_equal( + // "Lstream config gets transferred to Lstream section", + // meta.query_advice(col, Rotation::cur()), + // meta.query_advice(col, Rotation(N_JUMP_TABLE_BYTES as i32)), + // ); + // } + + // cb.require_equal( + // "first lstream that follows jump table is Lstream1", + // meta.query_advice(lstream_config.lstream, Rotation(N_JUMP_TABLE_BYTES as i32)), + // LstreamNum::Lstream1.expr(), + // ); + + // cb.gate(and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // is_zb_jump_table(meta), + // ])) + // }); meta.create_gate( "DecompressionCircuit: LstreamConfig data unchanged", |meta| { @@ -2746,13 +2793,14 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }); // bitstream decoder ends at index=7. - cb.condition(is_last, |cb| { - cb.require_equal( - "bitstream decoder ends at index=7", - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - 7.expr(), - ); - }); + // compression_debug + // cb.condition(is_last, |cb| { + // cb.require_equal( + // "bitstream decoder ends at index=7", + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // 7.expr(), + // ); + // }); // for all rows except the last. let is_strictly_contained = and::expr([ @@ -2767,31 +2815,33 @@ impl SubCircuitConfig for DecompressionCircuitConfig { and::expr([is_not_last.expr(), bitstream_decoder.is_spanned(meta, None)]); // if bitstring is strictly contained. cb.condition(is_strictly_contained, |cb| { - cb.require_equal( - "strictly contained bitstring: bit_index_start", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), - ); - cb.require_equal( - "strictly contained bitstring: byte_idx", - meta.query_advice(byte_idx, Rotation::next()), - meta.query_advice(byte_idx, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "strictly contained bitstring: bit_index_start", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), + // ); + // cb.require_equal( + // "strictly contained bitstring: byte_idx", + // meta.query_advice(byte_idx, Rotation::next()), + // meta.query_advice(byte_idx, Rotation::cur()), + // ); }); // if bitstring is byte-aligned. - cb.condition(is_byte_aligned, |cb| { - cb.require_equal( - "byte-aligned bitstring: bit_index_start", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - 0.expr(), - ); - cb.require_equal( - "byte-aligned bitstring: byte_idx", - meta.query_advice(byte_idx, Rotation::next()), - meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), - ); - }); + // compression_debug + // cb.condition(is_byte_aligned, |cb| { + // cb.require_equal( + // "byte-aligned bitstring: bit_index_start", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // 0.expr(), + // ); + // cb.require_equal( + // "byte-aligned bitstring: byte_idx", + // meta.query_advice(byte_idx, Rotation::next()), + // meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), + // ); + // }); // if bitstring is spanned. cb.condition(is_spanned, |cb| { @@ -2888,13 +2938,13 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.encoded_data.encoded_len)), )?; - - region.assign_advice( - || "encoded_len", - self.encoded_len, - i, - || Value::known(F::from(row.encoded_data.encoded_len)), - )?; + // compression_debug + // region.assign_advice( + // || "value_rlc", + // self.value_rlc, + // i, + // || row.encoded_data.value_rlc, + // )?; // Byte value and bits decomposition region.assign_advice( @@ -2917,7 +2967,8 @@ impl DecompressionCircuitConfig { ), )?; } - + + // Decoded Data region.assign_advice( || "decoded_len", self.decoded_len, @@ -2936,17 +2987,9 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.decoded_data.decoded_byte as u64)), )?; - region.assign_advice( - || "decoded_rlc", - self.decoded_rlc, - i, - || row.decoded_data.decoded_value_rlc, - )?; + // decoded_rlc + // TODO: - // let value_rlc = meta.advice_column_in(SecondPhase); - - - // Block Gadget // compression_debug @@ -2965,30 +3008,43 @@ impl DecompressionCircuitConfig { // idx: block_idx, // block_len, // is_last_block: meta.advice_column(), - // // compression_debug - // // idx_cmp_len: ComparatorChip::configure( - // // meta, - // // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // // |meta| meta.query_advice(block_idx, Rotation::cur()), - // // |meta| meta.query_advice(block_len, Rotation::cur()), - // // range256.into(), - // // ), + // idx_cmp_len: ComparatorChip::configure( + // meta, + // |meta| meta.query_fixed(q_enable, Rotation::cur()), + // |meta| meta.query_advice(block_idx, Rotation::cur()), + // |meta| meta.query_advice(block_len, Rotation::cur()), + // range256.into(), + // ), // } // }; + // block_gadget, + // pub struct BlockGadget { + // // pub struct BlockGadget { + // /// Boolean column to indicate that we are processing a block. + // is_block: Column, + // /// The incremental index of the byte within this block. + // idx: Column, + // /// The number of compressed bytes in the block. + // block_len: Column, + // /// Boolean column to mark whether or not this is the last block. + // is_last_block: Column, + // // compression_debug + // // Check: block_idx <= block_len. + // // idx_cmp_len: ComparatorConfig, + // } + // Tag Gadget + // pub struct TagGadget { + // /// Whether this tag outputs a decoded byte or not. + // is_output: Column, + // /// Randomness exponentiated by the tag's length. This is used to then accumulate the value + // /// RLC post processing of this tag. + // rand_pow_tag_len: Column, + // } - - - - - - - - - // Tag Gadget region.assign_advice( || "tag_gadget.tag", self.tag_gadget.tag, @@ -3037,6 +3093,24 @@ impl DecompressionCircuitConfig { i, || row.state.tag_value, )?; + region.assign_advice( + || "tag_gadget.tag_value_acc", + self.tag_gadget.tag_value_acc, + i, + || row.state.tag_value_acc, + )?; + region.assign_advice( + || "tag_gadget.tag_rlc", + self.tag_gadget.tag_rlc, + i, + || row.state.tag_rlc, + )?; + region.assign_advice( + || "tag_gadget.tag_rlc_acc", + self.tag_gadget.tag_rlc_acc, + i, + || row.state.tag_rlc_acc, + )?; let tag_bits = BinaryNumberChip::construct(self.tag_gadget.tag_bits); tag_bits.assign(&mut region, i, &row.state.tag)?; @@ -3055,6 +3129,10 @@ impl DecompressionCircuitConfig { let is_literals_header = (row.state.tag == ZstdTag::ZstdBlockLiteralsHeader) as u64; let is_fse_code = (row.state.tag == ZstdTag::ZstdBlockFseCode) as u64; let is_huffman_code = (row.state.tag == ZstdTag::ZstdBlockHuffmanCode) as u64; + let is_lstream = (row.state.tag == ZstdTag::ZstdBlockLstream) as u64; + let is_jumptable = (row.state.tag == ZstdTag::ZstdBlockJumpTable) as u64; + let is_literals_section = is_literals_header + is_fse_code + is_huffman_code + is_lstream + is_jumptable; + let is_huffman_tree_section = is_fse_code + is_huffman_code + is_jumptable + is_lstream; region.assign_advice( || "tag_gadget.is_block_header", @@ -3080,68 +3158,67 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(is_huffman_code)), )?; - - // TagGadget { - // tag_value: meta.advice_column_in(SecondPhase), - // tag_value_acc: meta.advice_column_in(SecondPhase), - // rand_pow_tag_len: meta.advice_column_in(SecondPhase), - // is_output: meta.advice_column(), - // tag_rlc: meta.advice_column_in(SecondPhase), - // tag_rlc_acc: meta.advice_column_in(SecondPhase), - // } - - - - - - - - - - - - - - - - - - + region.assign_advice( + || "tag_gadget.is_literals_section", + self.tag_gadget.is_literals_section, + i, + || Value::known(F::from(is_literals_section)), + )?; + region.assign_advice( + || "tag_gadget.is_huffman_tree_section", + self.tag_gadget.is_huffman_tree_section, + i, + || Value::known(F::from(is_huffman_tree_section)), + )?; - // Block Gadget - - // let block_gadget = { - // let block_idx = meta.advice_column(); - // let block_len = meta.advice_column(); - // BlockGadget { - // is_block: meta.advice_column(), - // idx: block_idx, - // block_len, - // is_last_block: meta.advice_column(), - // idx_cmp_len: ComparatorChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(block_idx, Rotation::cur()), - // |meta| meta.query_advice(block_len, Rotation::cur()), - // range256.into(), - // ), + // Literals Header + // literals_header, + // struct LiteralsHeaderDecomposition { + // /// The branch we take while decomposing the Literals Header. We compare this value against the + // /// Read-only memory table for Literals Header. + // branch: Column, + // /// A helper column to mark whether the size format (sf) for Literals Header is 0b_11. We need + // /// this column to keep the circuit degree in check. + // sf_max: Column, + // /// The regenerated size decoded from the Literals Header. + // regen_size: Column, + // /// The compressed size decoded from the Literals Header. + // compr_size: Column, // } - // }; - - // Aux Fields - - // let aux_fields = AuxFields { - // aux1: meta.advice_column(), - // aux2: meta.advice_column(), - // aux3: meta.advice_column(), - // aux4: meta.advice_column(), - // aux5: meta.advice_column(), - // }; + // Huffman Tree Config + // huffman_tree_config, + // struct HuffmanConfig { + // /// Column to save the byte offset at which the huffman header is described. + // huffman_tree_idx: Column, + // /// The table size of the FSE table. + // fse_table_size: Column, + // /// The accuracy log of the FSE table. + // fse_table_al: Column, + // /// The number of bytes used to specify canonical huffman code representation. + // huffman_code_len: Column, + // } + // Bitstream Decoder + // bitstream_decoder, + // pub struct BitstreamDecoder { + // /// The bit-index where the bittsring begins. 0 <= bit_index_start < 8. + // bit_index_start: Column, + // /// The bit-index where the bitstring ends. 0 <= bit_index_end < 16. + // bit_index_end: Column, + // /// Helper gadget to know if the bitstring was contained in a single byte. We compare + // /// bit_index_end with 8 and if bit_index_end < 8 then the bitstring is contained. Otherwise it + // /// spans over two bytes. + // bitstring_contained: ComparatorConfig, + // /// The accumulated binary value of the bitstring. + // bit_value: Column, + // /// The symbol that this bitstring decodes to. We are using this for decoding using FSE table + // /// or a Huffman Tree. So this symbol represents the decoded value that the bitstring maps to. + // decoded_symbol: Column, + // } region.assign_advice( || "bitstream_decoder.bit_index_start", @@ -3161,6 +3238,10 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.huffman_data.bit_value as u64)), )?; + + let bitstring_contained_chip = ComparatorChip::construct(self.bitstream_decoder.bitstring_contained.clone()); + bitstring_contained_chip.assign(&mut region, i, F::from(row.huffman_data.k.1 as u64), F::from(7u64))?; + // compression_debug // region.assign_advice( // || "bitstream_decoder.decoded_symbol", @@ -3188,12 +3269,21 @@ impl DecompressionCircuitConfig { // FSE Gadget - // region.assign_advice( - // || "fse_gadget.is_emit", - // self.fse_gadget.is_emit, - // i, - // || Value::known(F::from(is_emit as u64)), - // )?; + // fse_decoder, + // pub struct FseDecoder { + // /// The FSE state we are at. + // state: Column, + // /// The baseline value at ``state``. + // baseline: Column, + // /// The symbol emitted while transitioning from ``state`` to a new state. + // symbol: Column, + // /// Number of symbols we have emitted. + // num_emitted: Column, + // /// An accumulator that keeps a count of the number of states assigned for each symbol, + // /// including the symbol that is decoded on the current row. + // n_acc: Column, + // } + region.assign_advice( || "fse_decoder.num_emitted", self.fse_decoder.num_emitted, @@ -3219,13 +3309,37 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.fse_data.symbol as u64)), )?; - // let fse_gadget = FseGadget { - // is_emit: meta.advice_column(), - // num_emitted: meta.advice_column(), - // state: meta.advice_column(), - // baseline: meta.advice_column(), - // symbol: meta.advice_column(), - // }; + + + // LStream Config + + // lstream_config, + // struct LstreamConfig { + // /// A boolean used to identify whether we will have a single literal stream or 4 literal + // /// streams. It is set when we have 4 literal streams. + // lstream_kind: Column, + // /// The Lstream type we are currently processing. + // lstream: Column, + // /// The Lstream type we are currently processing. + // lstream_num: BinaryNumberConfig, + // /// Number of bytes in Lstream1. + // len_lstream1: Column, + // /// Number of bytes in Lstream2. + // len_lstream2: Column, + // /// Number of bytes in Lstream3. + // len_lstream3: Column, + // /// Number of bytes in Lstream4. + // len_lstream4: Column, + // } + + + + + + + + + } diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 52536677d4..384e66676b 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1251,6 +1251,12 @@ fn process_block_zstd_lstream( (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); } + let end_bit_idx = if current_byte_idx > from_byte_idx { + current_bit_idx.rem_euclid(8) + 8 + } else { + current_bit_idx.rem_euclid(8) + }; + // Add a witness row for emitted symbol witness_rows.push(ZstdWitnessRow { state: ZstdState { @@ -1281,7 +1287,7 @@ fn process_block_zstd_lstream( huffman_data: HuffmanData { byte_offset: huffman_code_byte_offset as u64, bit_value: u8::from_str_radix(bitstring_acc.as_str(), 2).unwrap(), - k: (from_bit_idx.rem_euclid(8) as u8, current_bit_idx.rem_euclid(8) as u8), + k: (from_bit_idx.rem_euclid(8) as u8, end_bit_idx as u8), }, decoded_data: last_row.decoded_data.clone(), fse_data: FseTableRow::default(), From f350db7f1f98b3ede87961f508af49dbe1356080 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 5 Feb 2024 22:02:45 -0500 Subject: [PATCH 068/165] Assign lstream config --- zkevm-circuits/src/decompression_circuit.rs | 79 ++++++++++++--------- zkevm-circuits/src/witness/zstd/mod.rs | 52 +++++++++----- zkevm-circuits/src/witness/zstd/types.rs | 12 ++++ 3 files changed, 92 insertions(+), 51 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 3b45675bd8..f10d38f0b4 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2902,8 +2902,11 @@ impl DecompressionCircuitConfig { &self, layouter: &mut impl Layouter, witness_rows: Vec>, + aux_data: Vec, challenges: &Challenges>, ) -> Result<(), Error> { + let mut jump_table_idx: usize = 0; + layouter.assign_region( || "Decompression table region", |mut region| { @@ -3309,39 +3312,49 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.fse_data.symbol as u64)), )?; - - - // LStream Config - - // lstream_config, - // struct LstreamConfig { - // /// A boolean used to identify whether we will have a single literal stream or 4 literal - // /// streams. It is set when we have 4 literal streams. - // lstream_kind: Column, - // /// The Lstream type we are currently processing. - // lstream: Column, - // /// The Lstream type we are currently processing. - // lstream_num: BinaryNumberConfig, - // /// Number of bytes in Lstream1. - // len_lstream1: Column, - // /// Number of bytes in Lstream2. - // len_lstream2: Column, - // /// Number of bytes in Lstream3. - // len_lstream3: Column, - // /// Number of bytes in Lstream4. - // len_lstream4: Column, - // } - - - - - - - - + // Lstream Config + let is_four_streams: u64 = if aux_data[2] > 0 { 1 } else { 0 }; + region.assign_advice( + || "lstream_config.lstream_kind", + self.lstream_config.lstream_kind, + i, + || Value::known(F::from(is_four_streams)), + )?; + region.assign_advice( + || "lstream_config.lstream", + self.lstream_config.lstream, + i, + || Value::known(F::from(row.huffman_data.stream_idx as u64)), + )?; + let lstream_num_chip = BinaryNumberChip::construct(self.lstream_config.lstream_num); + lstream_num_chip.assign(&mut region, i, &row.huffman_data.stream_idx.into())?; + region.assign_advice( + || "lstream_config.len_lstream1", + self.lstream_config.len_lstream1, + i, + || Value::known(F::from(aux_data[0])), + )?; + region.assign_advice( + || "lstream_config.len_lstream2", + self.lstream_config.len_lstream2, + i, + || Value::known(F::from(aux_data[1])), + )?; + region.assign_advice( + || "lstream_config.len_lstream3", + self.lstream_config.len_lstream3, + i, + || Value::known(F::from(aux_data[2])), + )?; + region.assign_advice( + || "lstream_config.len_lstream4", + self.lstream_config.len_lstream4, + i, + || Value::known(F::from(aux_data[3])), + )?; } Ok(()) @@ -3377,10 +3390,12 @@ impl SubCircuit for DecompressionCircuit { layouter: &mut impl Layouter, ) -> Result<(), Error> { let mut witness_rows: Vec> = vec![]; + let mut data: Vec = vec![]; for idx in 0..self.compressed_frames.len() { - let (rows, _decoded_literals) = process::(&self.compressed_frames[idx], challenges.keccak_input()); + let (rows, _decoded_literals, aux_data) = process::(&self.compressed_frames[idx], challenges.keccak_input()); witness_rows.extend_from_slice(&rows); + data.extend_from_slice(&aux_data); } // compression_debug @@ -3390,6 +3405,6 @@ impl SubCircuit for DecompressionCircuit { ); } - config.assign(layouter, witness_rows, challenges) + config.assign(layouter, witness_rows, data, challenges) } } diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 384e66676b..32d435d8f3 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -190,7 +190,7 @@ fn process_block( byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>, bool, Vec) { +) -> (usize, Vec>, bool, Vec, Vec) { let mut witness_rows = vec![]; let (byte_offset, rows, last_block, block_type, block_size) = @@ -198,7 +198,7 @@ fn process_block( witness_rows.extend_from_slice(&rows); let last_row = rows.last().expect("last row expected to exist"); - let (_byte_offset, rows, literals) = match block_type { + let (_byte_offset, rows, literals, lstream_len) = match block_type { BlockType::RawBlock => process_block_raw( src, byte_offset, @@ -227,7 +227,7 @@ fn process_block( }; witness_rows.extend_from_slice(&rows); - (byte_offset, witness_rows, last_block, literals) + (byte_offset, witness_rows, last_block, literals, lstream_len) } fn process_block_header( @@ -470,7 +470,7 @@ fn process_block_raw( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec) { +) -> (usize, Vec>, Vec, Vec) { let tag_next = if last_block { ZstdTag::Null } else { @@ -487,7 +487,7 @@ fn process_block_raw( tag_next, ); - (byte_offset, rows, vec![]) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0]) } fn process_block_rle( @@ -497,7 +497,7 @@ fn process_block_rle( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec) { +) -> (usize, Vec>, Vec, Vec) { let tag_next = if last_block { ZstdTag::Null } else { @@ -514,7 +514,7 @@ fn process_block_rle( tag_next, ); - (byte_offset, rows, vec![]) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0]) } #[allow(unused_variables)] @@ -525,7 +525,7 @@ fn process_block_zstd( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec) { +) -> (usize, Vec>, Vec, Vec) { let mut witness_rows = vec![]; // 1-5 bytes LiteralSectionHeader @@ -545,7 +545,7 @@ fn process_block_zstd( witness_rows.extend_from_slice(&rows); // Depending on the literals block type, decode literals section accordingly - let (bytes_offset, rows, literals) = match literals_block_type { + let (bytes_offset, rows, literals, lstream_len): (usize, Vec>, Vec, Vec) = match literals_block_type { BlockType::RawBlock => { let (byte_offset, rows) = process_raw_bytes( src, @@ -557,7 +557,7 @@ fn process_block_zstd( ZstdTag::ZstdBlockSequenceHeader, ); - (byte_offset, rows, vec![]) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0]) }, BlockType::RleBlock => { let (byte_offset, rows) = process_rle_bytes( @@ -570,7 +570,7 @@ fn process_block_zstd( ZstdTag::ZstdBlockSequenceHeader, ); - (byte_offset, rows, vec![]) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0]) }, BlockType::ZstdCompressedBlock => { let mut huffman_rows = vec![]; @@ -624,13 +624,13 @@ fn process_block_zstd( stream_offset = byte_offset; } - (stream_offset, huffman_rows, literals) + (stream_offset, huffman_rows, literals, lstream_lens) }, _ => unreachable!("Invalid literals section BlockType") }; witness_rows.extend_from_slice(&rows); - (bytes_offset, witness_rows, literals) + (bytes_offset, witness_rows, literals, lstream_len) } fn process_block_zstd_literals_header( @@ -1193,6 +1193,12 @@ fn process_block_zstd_lstream( _ => unreachable!("stream_idx value out of range") }; + let mut padding_end_idx = 0; + while lstream_bits[padding_end_idx] == 0 { + padding_end_idx += 1; + } + padding_end_idx += 1; + // Add a witness row for leading 0s and sentinel 1-bit witness_rows.push(ZstdWitnessRow { state: ZstdState { @@ -1220,7 +1226,12 @@ fn process_block_zstd_lstream( aux_2: *tag_value, ..Default::default() }, - huffman_data: HuffmanData::default(), + huffman_data: HuffmanData { + byte_offset: huffman_code_byte_offset as u64, + bit_value: 1u8, + stream_idx: stream_idx, + k: (0, padding_end_idx as u8), + }, decoded_data: last_row.decoded_data.clone(), fse_data: FseTableRow::default(), }); @@ -1287,6 +1298,7 @@ fn process_block_zstd_lstream( huffman_data: HuffmanData { byte_offset: huffman_code_byte_offset as u64, bit_value: u8::from_str_radix(bitstring_acc.as_str(), 2).unwrap(), + stream_idx: stream_idx, k: (from_bit_idx.rem_euclid(8) as u8, end_bit_idx as u8), }, decoded_data: last_row.decoded_data.clone(), @@ -1314,9 +1326,10 @@ fn process_block_zstd_lstream( } /// Process a slice of bytes into decompression circuit witness rows -pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec) { +pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec, Vec) { let mut witness_rows = vec![]; let mut literals: Vec = vec![]; + let mut aux_data: Vec = vec![]; let byte_offset = 0; // FrameHeaderDescriptor and FrameContentSize @@ -1329,7 +1342,7 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec( + let (_byte_offset, rows, last_block, new_literals, auxiliary_info) = process_block::( src, byte_offset, rows.last().expect("last row expected to exist"), @@ -1337,6 +1350,7 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec(src: &[u8], randomness: Value) -> (Vec(&compressed, Value::known(Fr::from(123456789))); + let (_witness_rows, _decoded_literals, _aux_data) = process::(&compressed, Value::known(Fr::from(123456789))); Ok(()) } @@ -1577,7 +1591,7 @@ mod tests { 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, ]; - let (_witness_rows, decoded_literals) = process::(&encoded, Value::known(Fr::from(123456789))); + let (_witness_rows, decoded_literals, _aux_data) = process::(&encoded, Value::known(Fr::from(123456789))); let decoded_literal_string: String = decoded_literals.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); let expected_literal_string = String::from("Romeo and Juliet\nExcerpt from Act 2, Scene 2\n\nJULIET\nO ,! wherefore art thou?\nDeny thy fatherrefusename;\nOr, ifwilt not, be but sworn my love,\nAnd I'll no longera Capulet.\n\nROMEO\n[Aside] Shall I hear more, or sspeak at this?'Tis that isenemy;\nTyself,gh a Montague.\nWhat's? inor hand,foot,\nNor armaceany opart\nBeing to a man. Osome!in a?which we ca rose\nBy would smell as sweet;\nSo, were he'd,\nRetaindear perfectionhe owes\nWithoitle.dofffor oee\nTake mI t hy word:\nCebe new baptized;\nHencth I never will. manthus bescreen'dnightstumblest on my counsel?\n"); diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index fae65fe1dc..b08415ad42 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -176,6 +176,17 @@ impl From for usize { value as usize } } +impl From for LstreamNum { + fn from(value: usize) -> LstreamNum { + match value { + 0 => LstreamNum::Lstream1, + 1 => LstreamNum::Lstream2, + 2 => LstreamNum::Lstream3, + 3 => LstreamNum::Lstream4, + _ => unreachable!("Wrong stream_idx"), + } + } +} impl_expr!(LstreamNum); @@ -367,6 +378,7 @@ pub struct DecodedData { pub struct HuffmanData { pub byte_offset: u64, pub bit_value: u8, + pub stream_idx: usize, pub k: (u8, u8), } From e912815a566cf2e2ff3f0746281f7b9614417ebc Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 5 Feb 2024 22:06:18 -0500 Subject: [PATCH 069/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 91 +++++++++++---------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index f10d38f0b4..c9b08d19b0 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2080,56 +2080,57 @@ impl SubCircuitConfig for DecompressionCircuitConfig { /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// ZstdTag::ZstdBlockHuffmanCode ///////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// - // compression_debug - // meta.create_gate( - // "DecompressionCircuit: ZstdBlockHuffmanCode (first row)", - // |meta| { - // let mut cb = BaseConstraintBuilder::default(); + + meta.create_gate( + "DecompressionCircuit: ZstdBlockHuffmanCode (first row)", + |meta| { + let mut cb = BaseConstraintBuilder::default(); - // // - The first row of the HuffmanCode tag is the leading 0s and sentinel bit. - // // - The second row of the HuffmanCode tag is the reading of AL number of bits from - // // the bitstream to find the initial state in the FSE table. - // // - Only from the third row onwards, do we start emitting symbols (weights). + // - The first row of the HuffmanCode tag is the leading 0s and sentinel bit. + // - The second row of the HuffmanCode tag is the reading of AL number of bits from + // the bitstream to find the initial state in the FSE table. + // - Only from the third row onwards, do we start emitting symbols (weights). - // cb.require_zero( - // "num_emitted starts at 0 from the second row", - // meta.query_advice(fse_decoder.num_emitted, Rotation::next()), - // ); + // compression_debug + // cb.require_zero( + // "num_emitted starts at 0 from the second row", + // meta.query_advice(fse_decoder.num_emitted, Rotation::next()), + // ); - // // On the second row we read AL number of bits. - // cb.require_equal( - // "AL number of bits read on the second row", - // meta.query_advice(huffman_tree_config.fse_table_al, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()) - // - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()) - // + 1.expr(), - // ); - // // Whatever bitstring we read, is also the initial state in the FSE table, where we - // // start applying the FSE table. - // cb.require_equal( - // "init state of FSE table", - // meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), - // meta.query_advice(fse_decoder.state, Rotation(2)), - // ); + // // On the second row we read AL number of bits. + // cb.require_equal( + // "AL number of bits read on the second row", + // meta.query_advice(huffman_tree_config.fse_table_al, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()) + // - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()) + // + 1.expr(), + // ); + // // Whatever bitstring we read, is also the initial state in the FSE table, where we + // // start applying the FSE table. + // cb.require_equal( + // "init state of FSE table", + // meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), + // meta.query_advice(fse_decoder.state, Rotation(2)), + // ); - // let lstream_kind = meta.query_advice(lstream_config.lstream_kind, Rotation::cur()); - // cb.require_equal( - // "tag_next after Huffman code depending on Lstream kind", - // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - // select::expr( - // lstream_kind, - // ZstdTag::ZstdBlockJumpTable.expr(), - // ZstdTag::ZstdBlockLstream.expr(), - // ), - // ); + let lstream_kind = meta.query_advice(lstream_config.lstream_kind, Rotation::cur()); + cb.require_equal( + "tag_next after Huffman code depending on Lstream kind", + meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + select::expr( + lstream_kind, + ZstdTag::ZstdBlockJumpTable.expr(), + ZstdTag::ZstdBlockLstream.expr(), + ), + ); - // cb.gate(and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // ])) - // }, - // ); + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + ])) + }, + ); meta.create_gate( "DecompressionCircuit: ZstdBlockHuffmanCode (wherever we emit a symbol)", |meta| { From 120fb317119d21d5bc871df619da6dec8a88736c Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 5 Feb 2024 22:43:17 -0500 Subject: [PATCH 070/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 206 +++++++++----------- zkevm-circuits/src/witness/zstd/mod.rs | 4 +- 2 files changed, 99 insertions(+), 111 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index c9b08d19b0..305083c8b0 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2399,84 +2399,84 @@ impl SubCircuitConfig for DecompressionCircuitConfig { /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// ZstdTag::ZstdBlockJumpTable /////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// - - // compression_debug - // meta.create_gate("DecompressionCircuit: ZstdBlockJumpTable", |meta| { - // let mut cb = BaseConstraintBuilder::default(); - - // cb.require_equal( - // "tag_len == 6", - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - // N_JUMP_TABLE_BYTES.expr(), - // ); - - // // Length of Lstream1. - // let len1 = meta.query_advice(value_byte, Rotation(0)) - // + 256.expr() * meta.query_advice(value_byte, Rotation(1)); - // // Length of Lstream 2. - // let len2 = meta.query_advice(value_byte, Rotation(2)) - // + 256.expr() * meta.query_advice(value_byte, Rotation(3)); - // // Length of Lstream3. - // let len3 = meta.query_advice(value_byte, Rotation(4)) - // + 256.expr() * meta.query_advice(value_byte, Rotation(5)); - - // cb.require_equal( - // "length of Lstream1", - // meta.query_advice(lstream_config.len_lstream1, Rotation::cur()), - // len1.expr(), - // ); - // cb.require_equal( - // "length of lstream2", - // meta.query_advice(lstream_config.len_lstream2, Rotation::cur()), - // len2.expr(), - // ); - // cb.require_equal( - // "length of lstream3", - // meta.query_advice(lstream_config.len_lstream3, Rotation::cur()), - // len3.expr(), - // ); - // // To calculate the size of Lstream4, we have: - // // - TotalStreamsSize == CompressedSize - HuffmanTreeDescriptionSize - // // - Stream4_Size == TotalStreamsSize - Stream1_Size - Stream2_Size - Stream3_Size - // // - // // The HuffmanTreeDescriptionSize can be calculated as: - // // - HuffmanTreeDescriptionSize == byte_idx(JumpTable) - byte_idx(HuffmanTree) - // cb.require_equal( - // "length of lstream4", - // meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) - // + len1 - // + len2 - // + len3 - // + meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(literals_header.compr_size, Rotation::cur()) - // + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // ); - - // for col in [ - // lstream_config.len_lstream1, - // lstream_config.len_lstream2, - // lstream_config.len_lstream3, - // lstream_config.len_lstream4, - // ] { - // cb.require_equal( - // "Lstream config gets transferred to Lstream section", - // meta.query_advice(col, Rotation::cur()), - // meta.query_advice(col, Rotation(N_JUMP_TABLE_BYTES as i32)), - // ); - // } + meta.create_gate("DecompressionCircuit: ZstdBlockJumpTable", |meta| { + let mut cb = BaseConstraintBuilder::default(); - // cb.require_equal( - // "first lstream that follows jump table is Lstream1", - // meta.query_advice(lstream_config.lstream, Rotation(N_JUMP_TABLE_BYTES as i32)), - // LstreamNum::Lstream1.expr(), - // ); + cb.require_equal( + "tag_len == 6", + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + N_JUMP_TABLE_BYTES.expr(), + ); - // cb.gate(and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // is_zb_jump_table(meta), - // ])) - // }); + // Length of Lstream1. + let len1 = meta.query_advice(value_byte, Rotation(0)) + + 256.expr() * meta.query_advice(value_byte, Rotation(1)); + // Length of Lstream 2. + let len2 = meta.query_advice(value_byte, Rotation(2)) + + 256.expr() * meta.query_advice(value_byte, Rotation(3)); + // Length of Lstream3. + let len3 = meta.query_advice(value_byte, Rotation(4)) + + 256.expr() * meta.query_advice(value_byte, Rotation(5)); + + cb.require_equal( + "length of Lstream1", + meta.query_advice(lstream_config.len_lstream1, Rotation::cur()), + len1.expr(), + ); + cb.require_equal( + "length of lstream2", + meta.query_advice(lstream_config.len_lstream2, Rotation::cur()), + len2.expr(), + ); + cb.require_equal( + "length of lstream3", + meta.query_advice(lstream_config.len_lstream3, Rotation::cur()), + len3.expr(), + ); + // To calculate the size of Lstream4, we have: + // - TotalStreamsSize == CompressedSize - HuffmanTreeDescriptionSize + // - Stream4_Size == TotalStreamsSize - Stream1_Size - Stream2_Size - Stream3_Size + // + // The HuffmanTreeDescriptionSize can be calculated as: + // - HuffmanTreeDescriptionSize == byte_idx(JumpTable) - byte_idx(HuffmanTree) + + // compression_debug + // cb.require_equal( + // "length of lstream4", + // meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) + // + len1 + // + len2 + // + len3 + // + meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(literals_header.compr_size, Rotation::cur()) + // + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // ); + + for col in [ + lstream_config.len_lstream1, + lstream_config.len_lstream2, + lstream_config.len_lstream3, + lstream_config.len_lstream4, + ] { + cb.require_equal( + "Lstream config gets transferred to Lstream section", + meta.query_advice(col, Rotation::cur()), + meta.query_advice(col, Rotation(N_JUMP_TABLE_BYTES as i32)), + ); + } + + cb.require_equal( + "first lstream that follows jump table is Lstream1", + meta.query_advice(lstream_config.lstream, Rotation(N_JUMP_TABLE_BYTES as i32)), + LstreamNum::Lstream1.expr(), + ); + + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + is_zb_jump_table(meta), + ])) + }); meta.create_gate( "DecompressionCircuit: LstreamConfig data unchanged", |meta| { @@ -2831,18 +2831,18 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // if bitstring is byte-aligned. // compression_debug - // cb.condition(is_byte_aligned, |cb| { - // cb.require_equal( - // "byte-aligned bitstring: bit_index_start", - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - // 0.expr(), - // ); - // cb.require_equal( - // "byte-aligned bitstring: byte_idx", - // meta.query_advice(byte_idx, Rotation::next()), - // meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), - // ); - // }); + cb.condition(is_byte_aligned, |cb| { + cb.require_equal( + "byte-aligned bitstring: bit_index_start", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + 0.expr(), + ); + cb.require_equal( + "byte-aligned bitstring: byte_idx", + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), + ); + }); // if bitstring is spanned. cb.condition(is_spanned, |cb| { @@ -3042,8 +3042,6 @@ impl DecompressionCircuitConfig { // Tag Gadget // pub struct TagGadget { - // /// Whether this tag outputs a decoded byte or not. - // is_output: Column, // /// Randomness exponentiated by the tag's length. This is used to then accumulate the value // /// RLC post processing of this tag. // rand_pow_tag_len: Column, @@ -3138,6 +3136,13 @@ impl DecompressionCircuitConfig { let is_literals_section = is_literals_header + is_fse_code + is_huffman_code + is_lstream + is_jumptable; let is_huffman_tree_section = is_fse_code + is_huffman_code + is_jumptable + is_lstream; + region.assign_advice( + || "tag_gadget.is_output", + self.tag_gadget.is_output, + i, + || Value::known(F::zero()), + )?; + region.assign_advice( || "tag_gadget.is_block_header", self.tag_gadget.is_block_header, @@ -3209,16 +3214,6 @@ impl DecompressionCircuitConfig { // Bitstream Decoder // bitstream_decoder, // pub struct BitstreamDecoder { - // /// The bit-index where the bittsring begins. 0 <= bit_index_start < 8. - // bit_index_start: Column, - // /// The bit-index where the bitstring ends. 0 <= bit_index_end < 16. - // bit_index_end: Column, - // /// Helper gadget to know if the bitstring was contained in a single byte. We compare - // /// bit_index_end with 8 and if bit_index_end < 8 then the bitstring is contained. Otherwise it - // /// spans over two bytes. - // bitstring_contained: ComparatorConfig, - // /// The accumulated binary value of the bitstring. - // bit_value: Column, // /// The symbol that this bitstring decodes to. We are using this for decoding using FSE table // /// or a Huffman Tree. So this symbol represents the decoded value that the bitstring maps to. // decoded_symbol: Column, @@ -3275,12 +3270,6 @@ impl DecompressionCircuitConfig { // fse_decoder, // pub struct FseDecoder { - // /// The FSE state we are at. - // state: Column, - // /// The baseline value at ``state``. - // baseline: Column, - // /// The symbol emitted while transitioning from ``state`` to a new state. - // symbol: Column, // /// Number of symbols we have emitted. // num_emitted: Column, // /// An accumulator that keeps a count of the number of states assigned for each symbol, @@ -3313,7 +3302,6 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.fse_data.symbol as u64)), )?; - // Lstream Config let is_four_streams: u64 = if aux_data[2] > 0 { 1 } else { 0 }; region.assign_advice( @@ -3401,8 +3389,8 @@ impl SubCircuit for DecompressionCircuit { // compression_debug for row in witness_rows.clone() { - log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;", - row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, + log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;", + row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, ); } diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 32d435d8f3..de3ce0db0d 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1258,15 +1258,15 @@ fn process_block_zstd_lstream( let from_bit_idx = current_bit_idx; // advance byte and bit marks to the last bit - for _ in 0..cur_bitstring_len { + for _ in 0..(cur_bitstring_len - 1) { (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); } - let end_bit_idx = if current_byte_idx > from_byte_idx { current_bit_idx.rem_euclid(8) + 8 } else { current_bit_idx.rem_euclid(8) }; + (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); // Add a witness row for emitted symbol witness_rows.push(ZstdWitnessRow { From 8fa9265a65cc0d81e12082013c5690f840bdf102 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 5 Feb 2024 23:03:04 -0500 Subject: [PATCH 071/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 42 ++++++++++----------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 305083c8b0..cae34be7b0 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2794,14 +2794,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }); // bitstream decoder ends at index=7. - // compression_debug - // cb.condition(is_last, |cb| { - // cb.require_equal( - // "bitstream decoder ends at index=7", - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - // 7.expr(), - // ); - // }); + cb.condition(is_last, |cb| { + cb.require_equal( + "bitstream decoder ends at index=7", + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + 7.expr(), + ); + }); // for all rows except the last. let is_strictly_contained = and::expr([ @@ -2816,21 +2815,19 @@ impl SubCircuitConfig for DecompressionCircuitConfig { and::expr([is_not_last.expr(), bitstream_decoder.is_spanned(meta, None)]); // if bitstring is strictly contained. cb.condition(is_strictly_contained, |cb| { - // compression_debug - // cb.require_equal( - // "strictly contained bitstring: bit_index_start", - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), - // ); - // cb.require_equal( - // "strictly contained bitstring: byte_idx", - // meta.query_advice(byte_idx, Rotation::next()), - // meta.query_advice(byte_idx, Rotation::cur()), - // ); + cb.require_equal( + "strictly contained bitstring: bit_index_start", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), + ); + cb.require_equal( + "strictly contained bitstring: byte_idx", + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(byte_idx, Rotation::cur()), + ); }); // if bitstring is byte-aligned. - // compression_debug cb.condition(is_byte_aligned, |cb| { cb.require_equal( "byte-aligned bitstring: bit_index_start", @@ -2861,8 +2858,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), sum::expr([ - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // TODO: Verify huffman code assumption?, compression_debug + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), ]), ])) From b0af9041feb76981edaea433336d1e99f2026fb1 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Tue, 6 Feb 2024 00:27:33 -0500 Subject: [PATCH 072/165] Add more bitstream witnesses --- zkevm-circuits/src/decompression_circuit.rs | 2 +- zkevm-circuits/src/witness/zstd/mod.rs | 44 ++++++++++++++++++++- zkevm-circuits/src/witness/zstd/types.rs | 14 +++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index cae34be7b0..5a42b3086d 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2440,7 +2440,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // The HuffmanTreeDescriptionSize can be calculated as: // - HuffmanTreeDescriptionSize == byte_idx(JumpTable) - byte_idx(HuffmanTree) - // compression_debug + // TODO: incorrect size? compression_debug // cb.require_equal( // "length of lstream4", // meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index de3ce0db0d..0190ae7c6f 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -135,6 +135,7 @@ fn process_frame_header( decoded_byte: 0, decoded_value_rlc: Value::known(F::zero()), }, + bitstream_read_data: BitstreamReadRow::default(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), }) @@ -176,6 +177,7 @@ fn process_frame_header( decoded_byte: 0, decoded_value_rlc: last_row.decoded_data.decoded_value_rlc, }, + bitstream_read_data: BitstreamReadRow::default(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), }, @@ -306,6 +308,7 @@ fn process_block_header( value_rlc, ..Default::default() }, + bitstream_read_data: BitstreamReadRow::default(), decoded_data: last_row.decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), @@ -392,6 +395,7 @@ fn process_raw_bytes( decoded_byte: value_byte, decoded_value_rlc, }, + bitstream_read_data: BitstreamReadRow::default(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), } @@ -456,6 +460,7 @@ fn process_rle_bytes( decoded_byte: value_byte, decoded_value_rlc, }, + bitstream_read_data: BitstreamReadRow::default(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), }) @@ -730,6 +735,7 @@ fn process_block_zstd_literals_header( value_rlc, ..Default::default() }, + bitstream_read_data: BitstreamReadRow::default(), decoded_data: last_row.decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), @@ -797,6 +803,11 @@ fn process_block_zstd_huffman_code( reverse: false, ..Default::default() }, + bitstream_read_data: BitstreamReadRow { + bit_start_idx: 0usize, + bit_end_idx: 7usize, + bit_value: header_byte as u64, + }, decoded_data: decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), @@ -849,6 +860,7 @@ fn process_block_zstd_huffman_code( reverse: false, ..Default::default() }, + bitstream_read_data: BitstreamReadRow::default(), decoded_data: decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), @@ -909,6 +921,11 @@ fn process_block_zstd_huffman_code( let aux_1 = next_value_rlc_acc.clone(); let aux_2 = witness_rows[witness_rows.len() - 1].encoded_data.value_rlc.clone(); + let mut padding_end_idx: usize = 0; + while huffman_bitstream[padding_end_idx] == 0 { + padding_end_idx += 1; + } + // Add a witness row for leading 0s and the sentinel 1-bit witness_rows.push(ZstdWitnessRow { state: ZstdState { @@ -935,6 +952,11 @@ fn process_block_zstd_huffman_code( aux_2, ..Default::default() }, + bitstream_read_data: BitstreamReadRow { + bit_value: 1u64, + bit_start_idx: 0usize, + bit_end_idx: padding_end_idx, + }, huffman_data: HuffmanData::default(), decoded_data: last_row.decoded_data.clone(), fse_data: FseTableRow::default(), @@ -968,7 +990,11 @@ fn process_block_zstd_huffman_code( while current_bit_idx + next_nb_to_read[color] <= (n_huffman_code_bytes) * N_BITS_PER_BYTE { let nb = next_nb_to_read[color]; - let next_state = prev_baseline[color] + be_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); + let bitstring_value = be_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); + let next_state = prev_baseline[color] + bitstring_value; + + let from_bit_idx = current_bit_idx.rem_euclid(8); + let to_bit_idx = if nb > 0 { from_bit_idx + (nb - 1) } else { from_bit_idx }; // Lookup the FSE table row for the state let fse_row = fse_state_table.get(&(next_state as u64)).expect("next state should be in fse table"); @@ -1002,6 +1028,11 @@ fn process_block_zstd_huffman_code( aux_2, ..Default::default() }, + bitstream_read_data: BitstreamReadRow { + bit_value: bitstring_value, + bit_start_idx: from_bit_idx, + bit_end_idx: to_bit_idx, + }, fse_data: FseTableRow { idx: fse_table_idx, state: next_state as u64, @@ -1127,6 +1158,7 @@ fn process_block_zstd_huffman_jump_table( reverse: false, ..Default::default() }, + bitstream_read_data: BitstreamReadRow::default(), decoded_data: last_row.decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), @@ -1232,6 +1264,11 @@ fn process_block_zstd_lstream( stream_idx: stream_idx, k: (0, padding_end_idx as u8), }, + bitstream_read_data: BitstreamReadRow { + bit_value: 1u64, + bit_start_idx: 0usize, + bit_end_idx: padding_end_idx as usize, + }, decoded_data: last_row.decoded_data.clone(), fse_data: FseTableRow::default(), }); @@ -1301,6 +1338,11 @@ fn process_block_zstd_lstream( stream_idx: stream_idx, k: (from_bit_idx.rem_euclid(8) as u8, end_bit_idx as u8), }, + bitstream_read_data: BitstreamReadRow { + bit_value: u8::from_str_radix(bitstring_acc.as_str(), 2).unwrap() as u64, + bit_start_idx: from_bit_idx.rem_euclid(8) as usize, + bit_end_idx: end_bit_idx as usize, + }, decoded_data: last_row.decoded_data.clone(), fse_data: FseTableRow::default(), }); diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index b08415ad42..e8b5d10ef0 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -503,6 +503,17 @@ pub struct FseTableRow { pub symbol: u64, } +// Used for tracking bit markers for non-byte-aligned bitstream decoding +#[derive(Clone, Debug, Default, PartialEq)] +pub struct BitstreamReadRow { + /// Start of the bit location within a byte [0, 8) + pub bit_start_idx: usize, + /// End of the bit location within a byte (0, 16) + pub bit_end_idx: usize, + /// The value of the bitstring + pub bit_value: u64, +} + /// Data for the FSE table's witness values. #[derive(Clone, Debug)] pub struct FseTableData { @@ -664,6 +675,8 @@ pub struct ZstdWitnessRow { pub huffman_data: HuffmanData, /// Fse decoding state transition data pub fse_data: FseTableRow, + /// Bitstream reader + pub bitstream_read_data: BitstreamReadRow, } impl ZstdWitnessRow { @@ -678,6 +691,7 @@ impl ZstdWitnessRow { decoded_data: DecodedData::default(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), + bitstream_read_data: BitstreamReadRow::default(), } } } From 7c6c2bd1b454fd7fcbfa39531a6e29ff011cba0c Mon Sep 17 00:00:00 2001 From: darth-cy Date: Tue, 6 Feb 2024 00:43:21 -0500 Subject: [PATCH 073/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 29 +++++++-------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 5a42b3086d..02dda856ce 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -777,9 +777,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // ); // }); - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); - cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), // not::expr(meta.query_advice(is_padding, Rotation::cur())), @@ -799,12 +796,10 @@ impl SubCircuitConfig for DecompressionCircuitConfig { tag_gadget.tag, tag_gadget.tag_len, tag_gadget.tag_value, - // compression_debug - // tag_gadget.rand_pow_tag_len, - // tag_gadget.tag_rlc, - // value_rlc, + tag_gadget.rand_pow_tag_len, + tag_gadget.tag_rlc, + value_rlc, ] { - // compression_debug cb.require_equal( "column remains the same", meta.query_advice(col, Rotation::cur()), @@ -822,7 +817,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.tag_idx, Rotation::prev()) + is_new_byte.expr(), ); - // compression_debug // tag_value_acc calculation. let multiplier = select::expr( tag_gadget.mlen_lt_0x20.is_lt(meta, None), @@ -846,14 +840,14 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // tag_rlc_acc calculation depending on whether is_reverse or not. let is_reverse = meta.query_advice(tag_gadget.is_reverse, Rotation::cur()); + cb.condition(not::expr(is_new_byte.expr()), |cb| { + cb.require_equal( + "tag_rlc_acc remains the same if not a new byte", + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::next()), + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + ); + }); // compression_debug - // cb.condition(not::expr(is_new_byte.expr()), |cb| { - // cb.require_equal( - // "tag_rlc_acc remains the same if not a new byte", - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::next()), - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - // ); - // }); // cb.condition( // and::expr([is_new_byte.expr(), not::expr(is_reverse.expr())]), // |cb| { @@ -879,9 +873,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // ); // }); - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); - cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), not::expr(meta.query_advice(is_padding, Rotation::cur())), From 7c85b9bfe9b11830405dbba7eb3cb7c76f97e59d Mon Sep 17 00:00:00 2001 From: darth-cy Date: Tue, 6 Feb 2024 00:55:20 -0500 Subject: [PATCH 074/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 64 +++++++++---------- .../src/decompression_circuit/dev.rs | 1 + 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 02dda856ce..7187b1f6c2 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -123,6 +123,7 @@ pub struct DecompressionCircuitConfig { range8: RangeTable<8>, range128: RangeTable<128>, range256: RangeTable<256>, + tag_rom_table: TagRomTable, } /// Block level details are specified in these columns. @@ -1005,28 +1006,28 @@ impl SubCircuitConfig for DecompressionCircuitConfig { debug_assert!(meta.degree() <= 9); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: lookup for tuple (tag, tag_next, max_len, is_output)", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // not::expr(meta.query_advice(is_padding, Rotation::next())), - // ]); - // [ - // meta.query_advice(tag_gadget.tag, Rotation::cur()), - // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - // meta.query_advice(tag_gadget.max_len, Rotation::cur()), - // meta.query_advice(tag_gadget.is_output, Rotation::cur()), - // meta.query_advice(block_gadget.is_block, Rotation::cur()), - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - // ] - // .into_iter() - // .zip(tag_rom_table.table_exprs(meta)) - // .map(|(arg, table)| (condition.expr() * arg, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: lookup for tuple (tag, tag_next, max_len, is_output)", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + not::expr(meta.query_advice(is_padding, Rotation::next())), + ]); + [ + meta.query_advice(tag_gadget.tag, Rotation::cur()), + meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + meta.query_advice(tag_gadget.max_len, Rotation::cur()), + // compression_debug + // meta.query_advice(tag_gadget.is_output, Rotation::cur()), + // meta.query_advice(block_gadget.is_block, Rotation::cur()), + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + ] + .into_iter() + .zip(tag_rom_table.table_exprs(meta)) + .map(|(arg, table)| (condition.expr() * arg, table)) + .collect() + }, + ); debug_assert!(meta.degree() <= 9); @@ -1218,14 +1219,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // }); // Validate that for an RLE block: value_byte == decoded_byte. - // compression_debug - // cb.condition(block_type_bit0, |cb| { - // cb.require_equal( - // "for RLE block, value_byte == decoded_byte", - // meta.query_advice(value_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), - // meta.query_advice(decoded_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), - // ); - // }); + cb.condition(block_type_bit0, |cb| { + cb.require_equal( + "for RLE block, value_byte == decoded_byte", + meta.query_advice(value_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), + meta.query_advice(decoded_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), + ); + }); // If this wasn't the first block, then the previous block's last byte should have // block's idx == block length. @@ -1240,9 +1240,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // meta.query_advice(block_gadget.block_len, Rotation::prev()), // ); - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); - cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), @@ -2882,6 +2879,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { range8, range128, range256, + tag_rom_table, } } } diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index 8dbf2f5da3..c96202cad7 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -82,6 +82,7 @@ impl Circuit for DecompressionCircuit { config.0.range8.load(&mut layouter)?; config.0.range128.load(&mut layouter)?; config.0.range256.load(&mut layouter)?; + config.0.tag_rom_table.load(&mut layouter)?; self.synthesize_sub(&config.0, challenges, &mut layouter) } } From ad744787c35756347c27d0ecdac1ff25fd414a44 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Tue, 6 Feb 2024 01:14:06 -0500 Subject: [PATCH 075/165] Remove comments --- zkevm-circuits/src/decompression_circuit.rs | 35 --------------------- 1 file changed, 35 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 7187b1f6c2..2767ea32ec 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -3009,22 +3009,6 @@ impl DecompressionCircuitConfig { // } // }; - // block_gadget, - // pub struct BlockGadget { - // // pub struct BlockGadget { - // /// Boolean column to indicate that we are processing a block. - // is_block: Column, - // /// The incremental index of the byte within this block. - // idx: Column, - // /// The number of compressed bytes in the block. - // block_len: Column, - // /// Boolean column to mark whether or not this is the last block. - // is_last_block: Column, - // // compression_debug - // // Check: block_idx <= block_len. - // // idx_cmp_len: ComparatorConfig, - // } - // Tag Gadget @@ -3169,7 +3153,6 @@ impl DecompressionCircuitConfig { // Literals Header - // literals_header, // struct LiteralsHeaderDecomposition { // /// The branch we take while decomposing the Literals Header. We compare this value against the // /// Read-only memory table for Literals Header. @@ -3185,7 +3168,6 @@ impl DecompressionCircuitConfig { // Huffman Tree Config - // huffman_tree_config, // struct HuffmanConfig { // /// Column to save the byte offset at which the huffman header is described. // huffman_tree_idx: Column, @@ -3199,7 +3181,6 @@ impl DecompressionCircuitConfig { // Bitstream Decoder - // bitstream_decoder, // pub struct BitstreamDecoder { // /// The symbol that this bitstring decodes to. We are using this for decoding using FSE table // /// or a Huffman Tree. So this symbol represents the decoded value that the bitstring maps to. @@ -3236,22 +3217,6 @@ impl DecompressionCircuitConfig { // || Value::known(F::from(row.huffman_data.bit_value as u64)), // )?; - // let bitstream_decoder = { - // BitstreamDecoder { - // bit_index_start: meta.advice_column(), - // bit_index_end, - // bitstream_contained: LtChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(bit_index_end, Rotation::cur()), - // |_| 8.expr(), - // range256.into(), - // ), - // bit_value: meta.advice_column(), - // decoded_symbol: meta.advice_column(), - // } - // }; - // FSE Gadget From 214f5820cf47ff93fdd2049588c7deb47801b987 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 02:05:57 -0500 Subject: [PATCH 076/165] Correct tag_rlc_acc constraint and assignment --- zkevm-circuits/src/decompression_circuit.rs | 6 +- zkevm-circuits/src/witness/zstd/mod.rs | 180 +++++++++++++++----- zkevm-circuits/src/witness/zstd/types.rs | 18 +- 3 files changed, 161 insertions(+), 43 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 2767ea32ec..3c05bfe283 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -844,7 +844,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.condition(not::expr(is_new_byte.expr()), |cb| { cb.require_equal( "tag_rlc_acc remains the same if not a new byte", - meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::next()), + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), ); }); @@ -876,7 +876,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(is_padding, Rotation::cur())), + not::expr(meta.query_fixed(q_first, Rotation::cur())), + // compression_debug + // not::expr(meta.query_advice(is_padding, Rotation::cur())), not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), ])) }, diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 0190ae7c6f..4b61b27b0e 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -101,6 +101,18 @@ fn process_frame_header( Some(*acc) }) .collect::>>(); + let tag_rlc_iter = fcs_bytes + .iter() + .scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }) + .collect::>>(); + let tag_rlc = *(tag_rlc_iter + .clone() + .last() + .expect("Tag RLC expected")); + let aux_1 = fcs_value_rlcs .last() .expect("FrameContentSize bytes expected"); @@ -118,8 +130,8 @@ fn process_frame_header( tag_value: Value::known(F::from(*fhd_byte as u64)), tag_value_acc: Value::known(F::from(*fhd_byte as u64)), is_tag_change: true, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc: Value::known(F::from(*fhd_byte as u64)), + tag_rlc_acc: Value::known(F::from(*fhd_byte as u64)), }, encoded_data: EncodedData { byte_idx: (byte_offset + 1) as u64, @@ -144,9 +156,10 @@ fn process_frame_header( .iter() .zip(fcs_tag_value_iter) .zip(fcs_value_rlcs.iter().rev()) + .zip(tag_rlc_iter.iter().rev()) .enumerate() .map( - |(i, ((&value_byte, tag_value_acc), &value_rlc))| ZstdWitnessRow { + |(i, (((&value_byte, tag_value_acc), &value_rlc), &tag_rlc_acc))| ZstdWitnessRow { state: ZstdState { tag: ZstdTag::FrameContentSize, tag_next: ZstdTag::BlockHeader, @@ -156,8 +169,8 @@ fn process_frame_header( tag_value: fcs_tag_value, tag_value_acc, is_tag_change: i == 0, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc, + tag_rlc_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + 2 + i) as u64, @@ -262,6 +275,12 @@ fn process_block_header( }); let tag_value = tag_value_iter.clone().last().expect("BlockHeader expected"); + let tag_rlc_acc = bh_bytes.iter().scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); + let tag_rlc = tag_rlc_acc.clone().last().expect("Tag RLC expected"); + // BlockHeader follows FrameContentSize which is processed in reverse order. // Hence value_rlc at the first BlockHeader byte will be calculated as: // @@ -285,9 +304,10 @@ fn process_block_header( .iter() .zip(tag_value_iter) .zip(value_rlcs.iter()) + .zip(tag_rlc_acc) .enumerate() .map( - |(i, ((&value_byte, tag_value_acc), &value_rlc))| ZstdWitnessRow { + |(i, (((&value_byte, tag_value_acc), &value_rlc), tag_rlc_acc))| ZstdWitnessRow { state: ZstdState { tag: ZstdTag::BlockHeader, tag_next, @@ -297,8 +317,8 @@ fn process_block_header( tag_value, tag_value_acc, is_tag_change: i == 0, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc, + tag_rlc_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + i + 1) as u64, @@ -697,6 +717,12 @@ fn process_block_zstd_literals_header( }); let tag_value = tag_value_iter.clone().last().expect("LiteralsHeader expected"); + let tag_rlc_iter = lh_bytes.iter().take(n_bytes_header).scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); + let tag_rlc = tag_rlc_iter.clone().last().expect("Tag RLC expected"); + let value_rlc_iter = lh_bytes .iter() .take(n_bytes_header) @@ -712,9 +738,10 @@ fn process_block_zstd_literals_header( .take(n_bytes_header) .zip(tag_value_iter) .zip(value_rlc_iter) + .zip(tag_rlc_iter) .enumerate() .map( - |(i, ((&value_byte, tag_value_acc), value_rlc))| ZstdWitnessRow { + |(i, (((&value_byte, tag_value_acc), value_rlc), tag_rlc_acc))| ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockLiteralsHeader, tag_next, @@ -724,8 +751,8 @@ fn process_block_zstd_literals_header( tag_value, tag_value_acc, is_tag_change: i == 0, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc, + tag_rlc_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + i + 1) as u64, @@ -792,8 +819,8 @@ fn process_block_zstd_huffman_code( tag_value: Value::default(), // Must be changed after FSE table length is known tag_value_acc: Value::default(), // Must be changed after FSE table length is known is_tag_change: true, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc: Value::known(F::zero()), // Must be changed after FSE table length is known + tag_rlc_acc: Value::known(F::zero()), // Must be changed after FSE table length is known }, encoded_data: EncodedData { byte_idx: (byte_offset + 1) as u64, @@ -831,10 +858,24 @@ fn process_block_zstd_huffman_code( .last() .expect("Tag value must exist"); + let mut tag_rlc_iter = src.iter().skip(byte_offset).take(n_fse_bytes + 1).scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_rlc = tag_rlc_iter + .clone() + .last() + .expect("Tag value must exist"); + // Backfill missing data on the huffman header row huffman_header_row.state.tag_len = (n_fse_bytes + 1usize) as u64; huffman_header_row.state.tag_value = tag_value; huffman_header_row.state.tag_value_acc = tag_value_iter.next().expect("Next value should exist"); + huffman_header_row.state.tag_rlc = tag_rlc; + huffman_header_row.state.tag_rlc_acc = tag_rlc_iter.next().expect("Next value expected"); witness_rows.push(huffman_header_row); // Add witness rows for FSE representation bytes @@ -849,8 +890,8 @@ fn process_block_zstd_huffman_code( tag_value: tag_value, tag_value_acc: tag_value_iter.next().expect("Next value should exist"), is_tag_change: false, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc, + tag_rlc_acc: tag_rlc_iter.next().expect("Tag RLC Acc exists"), }, encoded_data: EncodedData { byte_idx: (byte_offset + idx + 2) as u64, // count the huffman header byte @@ -903,7 +944,7 @@ fn process_block_zstd_huffman_code( Some(*acc) }, ).collect::>>().into_iter().rev(); - let mut tag_value_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).rev().scan( + let mut tag_value_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).scan( Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); @@ -914,9 +955,22 @@ fn process_block_zstd_huffman_code( .clone() .last() .expect("Tag value must exist"); + let tag_rlc_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_rlc = tag_rlc_iter + .clone() + .last() + .expect("Tag RLC must exist"); + let mut tag_rlc_iter = tag_rlc_iter.collect::>>().into_iter().rev(); let mut next_tag_value_acc = tag_value_iter.next().unwrap(); let mut next_value_rlc_acc = value_rlc_iter.next().unwrap(); + let mut next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); let aux_1 = next_value_rlc_acc.clone(); let aux_2 = witness_rows[witness_rows.len() - 1].encoded_data.value_rlc.clone(); @@ -937,8 +991,8 @@ fn process_block_zstd_huffman_code( tag_value: tag_value, tag_value_acc: next_tag_value_acc, is_tag_change: true, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc, + tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, @@ -973,6 +1027,7 @@ fn process_block_zstd_huffman_code( if current_byte_idx > last_byte_idx { next_tag_value_acc = tag_value_iter.next().unwrap(); next_value_rlc_acc = value_rlc_iter.next().unwrap(); + next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); last_byte_idx = current_byte_idx; } @@ -1013,8 +1068,8 @@ fn process_block_zstd_huffman_code( tag_value: tag_value, tag_value_acc: next_tag_value_acc, is_tag_change: false, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc, + tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, @@ -1054,6 +1109,7 @@ fn process_block_zstd_huffman_code( if current_byte_idx > last_byte_idx && current_byte_idx < n_bytes { next_tag_value_acc = tag_value_iter.next().unwrap(); next_value_rlc_acc = value_rlc_iter.next().unwrap(); + next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); last_byte_idx = current_byte_idx; } @@ -1126,6 +1182,17 @@ fn process_block_zstd_huffman_jump_table( .clone() .last() .expect("Tag value must exist."); + let tag_rlc_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_rlc = tag_rlc_iter + .clone() + .last() + .expect("Tag value must exist."); ( byte_offset + N_JUMP_TABLE_BYTES, @@ -1134,9 +1201,10 @@ fn process_block_zstd_huffman_jump_table( .take(N_JUMP_TABLE_BYTES) .zip(tag_value_iter) .zip(value_rlc_iter) + .zip(tag_rlc_iter) .enumerate() .map( - |(i, ((&value_byte, tag_value_acc), value_rlc))| { + |(i, (((&value_byte, tag_value_acc), value_rlc), tag_rlc_acc))| { ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockJumpTable, @@ -1147,8 +1215,8 @@ fn process_block_zstd_huffman_jump_table( tag_value, tag_value_acc, is_tag_change: i == 0, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc, + tag_rlc_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + i + 1) as u64, @@ -1197,26 +1265,38 @@ fn process_block_zstd_lstream( // Bitstream processing state helper values let mut witness_rows: Vec> = vec![]; + let mut last_byte_idx: usize = 1; let mut current_byte_idx: usize = 1; let mut current_bit_idx: usize = 0; // accumulators let aux_1 = last_row.encoded_data.value_rlc; - let value_rlc_acc = src.iter().skip(byte_offset).take(len).rev().scan( + let mut value_rlc_acc = src.iter().skip(byte_offset).take(len).rev().scan( last_row.encoded_data.value_rlc, |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }, - ).collect::>>(); - let tag_value_acc = src.iter().skip(byte_offset).take(len).rev().scan( + ); + + let mut tag_value_acc = src.iter().skip(byte_offset).take(len).scan( + Value::known(F::zero()), + |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }, + ); + let tag_value = tag_value_acc.clone().last().expect("Tag value exists"); + + let tag_rlc_iter = src.iter().skip(byte_offset).take(len).scan( Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }, - ).collect::>>(); - let tag_value = tag_value_acc.last().expect("Tag value exists"); + ); + let tag_rlc = tag_rlc_iter.clone().last().expect("Tag value exists"); + let mut tag_rlc_iter = tag_rlc_iter.collect::>>().into_iter().rev(); // Decide the next tag let tag_next = match stream_idx { @@ -1231,6 +1311,10 @@ fn process_block_zstd_lstream( } padding_end_idx += 1; + let mut next_tag_value_acc = tag_value_acc.next().unwrap(); + let mut next_value_rlc_acc = value_rlc_acc.next().unwrap(); + let mut next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); + // Add a witness row for leading 0s and sentinel 1-bit witness_rows.push(ZstdWitnessRow { state: ZstdState { @@ -1239,23 +1323,23 @@ fn process_block_zstd_lstream( max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockLstream), tag_len: len as u64, tag_idx: current_byte_idx as u64, - tag_value: *tag_value, - tag_value_acc: tag_value_acc[current_byte_idx - 1], + tag_value: tag_value, + tag_value_acc: next_tag_value_acc, is_tag_change: true, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc, + tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + current_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - current_byte_idx], - value_rlc: value_rlc_acc[current_byte_idx - 1], + value_rlc: next_value_rlc_acc, // reverse specific values reverse: true, reverse_len: len as u64, reverse_idx: (len - (current_byte_idx - 1)) as u64, aux_1, - aux_2: *tag_value, + aux_2: tag_value, ..Default::default() }, huffman_data: HuffmanData { @@ -1280,6 +1364,14 @@ fn process_block_zstd_lstream( // Exclude the sentinel 1-bit (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); + // Update accumulator + if current_byte_idx > last_byte_idx { + next_tag_value_acc = tag_value_acc.next().unwrap(); + next_value_rlc_acc = value_rlc_acc.next().unwrap(); + next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); + last_byte_idx = current_byte_idx; + } + // Now the actual symbol-bearing bitstream starts let (max_bitstring_len, huffman_bitstring_map) = huffman_code.parse_bitstring_map(); let mut decoded_symbols: Vec = vec![]; @@ -1313,23 +1405,23 @@ fn process_block_zstd_lstream( max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockLstream), tag_len: len as u64, tag_idx: from_byte_idx as u64, - tag_value: *tag_value, - tag_value_acc: tag_value_acc[from_byte_idx - 1], + tag_value, + tag_value_acc: next_tag_value_acc, is_tag_change: false, - tag_rlc: Value::known(F::zero()), - tag_rlc_acc: Value::known(F::zero()), + tag_rlc, + tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + from_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - from_byte_idx], - value_rlc: value_rlc_acc[from_byte_idx - 1], + value_rlc: next_value_rlc_acc, // reverse specific values reverse: true, reverse_len: len as u64, reverse_idx: (len - from_byte_idx + 1) as u64, aux_1, - aux_2: *tag_value, + aux_2: tag_value, ..Default::default() }, huffman_data: HuffmanData { @@ -1347,6 +1439,14 @@ fn process_block_zstd_lstream( fse_data: FseTableRow::default(), }); + // Update accumulator + if current_byte_idx > last_byte_idx && current_byte_idx < len { + next_tag_value_acc = tag_value_acc.next().unwrap(); + next_value_rlc_acc = value_rlc_acc.next().unwrap(); + next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); + last_byte_idx = current_byte_idx; + } + // Reset decoding state bitstring_acc = String::from(""); cur_bitstring_len = 0; diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index e8b5d10ef0..4a91b1d6a2 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -346,7 +346,7 @@ impl Default for ZstdState { } } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct EncodedData { pub byte_idx: u64, pub encoded_len: u64, @@ -365,6 +365,22 @@ impl EncodedData { } } +impl Default for EncodedData { + fn default() -> Self { + Self { + byte_idx: 0, + encoded_len: 0, + value_byte: 0, + reverse: false, + reverse_idx: 0, + reverse_len: 0, + aux_1: Value::known(F::zero()), + aux_2: Value::known(F::zero()), + value_rlc: Value::known(F::zero()), + } + } +} + #[derive(Clone, Debug, Default)] pub struct DecodedData { pub decoded_len: u64, From f3aadce6ba030296326ae3b25a6ab95cb0ebfe06 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 02:18:17 -0500 Subject: [PATCH 077/165] Correct tag_rlc constraints and assignment --- zkevm-circuits/src/decompression_circuit.rs | 25 ++++++++++----------- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 3c05bfe283..85cd64c25e 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -848,19 +848,18 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), ); }); - // compression_debug - // cb.condition( - // and::expr([is_new_byte.expr(), not::expr(is_reverse.expr())]), - // |cb| { - // cb.require_equal( - // "tag_rlc_acc == tag_rlc_acc::prev * r + byte", - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()) - // * challenges.keccak_input() - // + value_byte_curr, - // ); - // }, - // ); + cb.condition( + and::expr([is_new_byte.expr(), not::expr(is_reverse.expr())]), + |cb| { + cb.require_equal( + "tag_rlc_acc == tag_rlc_acc::prev * r + byte", + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()) + * challenges.keccak_input() + + value_byte_curr, + ); + }, + ); let value_byte_prev = meta.query_advice(value_byte, Rotation::prev()); // compression_debug diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 4b61b27b0e..729ede562d 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -879,7 +879,7 @@ fn process_block_zstd_huffman_code( witness_rows.push(huffman_header_row); // Add witness rows for FSE representation bytes - for (idx, byte) in src.iter().skip(byte_offset).take(n_fse_bytes).enumerate() { + for (idx, byte) in src.iter().skip(byte_offset + 1).take(n_fse_bytes).enumerate() { witness_rows.push(ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockFseCode, From 3f93c0e721b8e0164d4f26f026ef07e25bd0d9a5 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 03:42:37 -0500 Subject: [PATCH 078/165] Correct tag_rlc constraint and assignments: --- zkevm-circuits/src/decompression_circuit.rs | 19 +++++++++---------- zkevm-circuits/src/witness/zstd/mod.rs | 18 +++++++++++++----- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 85cd64c25e..6042dbae65 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -862,16 +862,15 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); let value_byte_prev = meta.query_advice(value_byte, Rotation::prev()); - // compression_debug - // cb.condition(and::expr([is_new_byte, is_reverse]), |cb| { - // cb.require_equal( - // "tag_rlc_acc::prev = tag_rlc_acc * r + byte::prev", - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()) - // * challenges.keccak_input() - // + value_byte_prev, - // ); - // }); + cb.condition(and::expr([is_new_byte, is_reverse]), |cb| { + cb.require_equal( + "tag_rlc_acc::prev = tag_rlc_acc * r + byte::prev", + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()) + * challenges.keccak_input() + + value_byte_prev, + ); + }); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 729ede562d..440a81f0bf 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -69,6 +69,13 @@ fn process_frame_header( // FrameContentSize bytes are read in little-endian, hence its in reverse mode. let fcs_bytes = src + .iter() + .skip(byte_offset + 1) + .take(fcs_tag_len) + // .rev() + .cloned() + .collect::>(); + let fcs_bytes_rev = src .iter() .skip(byte_offset + 1) .take(fcs_tag_len) @@ -101,6 +108,7 @@ fn process_frame_header( Some(*acc) }) .collect::>>(); + let tag_rlc_iter = fcs_bytes .iter() .scan(Value::known(F::zero()), |acc, &byte| { @@ -112,7 +120,7 @@ fn process_frame_header( .clone() .last() .expect("Tag RLC expected")); - + let aux_1 = fcs_value_rlcs .last() .expect("FrameContentSize bytes expected"); @@ -152,7 +160,7 @@ fn process_frame_header( fse_data: FseTableRow::default(), }) .chain( - fcs_bytes + fcs_bytes_rev .iter() .zip(fcs_tag_value_iter) .zip(fcs_value_rlcs.iter().rev()) @@ -997,7 +1005,7 @@ fn process_block_zstd_huffman_code( encoded_data: EncodedData { byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, - value_byte: src[byte_offset + n_fse_bytes + 1 + current_byte_idx], + value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - (current_byte_idx - 1)], value_rlc: next_value_rlc_acc, reverse: true, reverse_len: n_huffman_code_bytes as u64, @@ -1074,7 +1082,7 @@ fn process_block_zstd_huffman_code( encoded_data: EncodedData { byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, - value_byte: src[byte_offset + n_fse_bytes + 1 + current_byte_idx], + value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], value_rlc: next_value_rlc_acc, reverse: true, reverse_len: n_huffman_code_bytes as u64, @@ -1440,7 +1448,7 @@ fn process_block_zstd_lstream( }); // Update accumulator - if current_byte_idx > last_byte_idx && current_byte_idx < len { + if current_byte_idx > last_byte_idx && current_byte_idx <= len { next_tag_value_acc = tag_value_acc.next().unwrap(); next_value_rlc_acc = value_rlc_acc.next().unwrap(); next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); From b85b73ffe4317f18f8ead258b2343c0513385220 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 03:45:18 -0500 Subject: [PATCH 079/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 26 ++++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 6042dbae65..4d88871b02 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -982,20 +982,18 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.tag, Rotation::cur()), ZstdTag::FrameHeaderDescriptor.expr(), ); - - // compression_debug - // cb.require_zero( - // "value_rlc starts at 0", - // meta.query_advice(value_rlc, Rotation::cur()), - // ); - // cb.require_zero( - // "decoded_rlc initialises at 0", - // meta.query_advice(decoded_rlc, Rotation::cur()), - // ); - // cb.require_zero( - // "decoded_len_acc initialises at 0", - // meta.query_advice(decoded_len_acc, Rotation::cur()), - // ); + cb.require_zero( + "value_rlc starts at 0", + meta.query_advice(value_rlc, Rotation::cur()), + ); + cb.require_zero( + "decoded_rlc initialises at 0", + meta.query_advice(decoded_rlc, Rotation::cur()), + ); + cb.require_zero( + "decoded_len_acc initialises at 0", + meta.query_advice(decoded_len_acc, Rotation::cur()), + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), From d8b510786f2a438d7b4b2884a905571e81d5199d Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 19:58:55 -0500 Subject: [PATCH 080/165] Adjust huffman code idx --- zkevm-circuits/src/decompression_circuit.rs | 20 +++++--------------- zkevm-circuits/src/witness/zstd/mod.rs | 10 +++++----- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 4d88871b02..eeac1fef4b 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -647,21 +647,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // If we don't encounter a new byte, the byte value should stay the same. cb.condition(not::expr(is_new_byte.expr()), |cb| { // compression_debug - // cb.require_equal( - // "value_byte' == value_byte if not a new byte", - // meta.query_advice(value_byte, Rotation::next()), - // meta.query_advice(value_byte, Rotation::cur()), - // ); - }); - - // If we don't encounter a new byte, the byte value should stay the same. - cb.condition(not::expr(is_new_byte.expr()), |cb| { - // compression_debug - // cb.require_equal( - // "value_byte' == value_byte if not a new byte", - // meta.query_advice(value_byte, Rotation::next()), - // meta.query_advice(value_byte, Rotation::cur()), - // ); + cb.require_equal( + "value_byte' == value_byte if not a new byte", + meta.query_advice(value_byte, Rotation::prev()), + meta.query_advice(value_byte, Rotation::cur()), + ); }); // We also need to validate that ``is_tag_change`` was assigned correctly. Tag changes diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 440a81f0bf..5452396442 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1072,7 +1072,7 @@ fn process_block_zstd_huffman_code( tag_next, max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockHuffmanCode), tag_len: (n_huffman_code_bytes) as u64, - tag_idx: current_byte_idx as u64, + tag_idx: (current_byte_idx + 1) as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, is_tag_change: false, @@ -1080,7 +1080,7 @@ fn process_block_zstd_huffman_code( tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, + byte_idx: (byte_offset + n_fse_bytes + 2 + current_byte_idx) as u64, encoded_len, value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], value_rlc: next_value_rlc_acc, @@ -1227,7 +1227,7 @@ fn process_block_zstd_huffman_jump_table( tag_rlc_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + i + 1) as u64, + byte_idx: (byte_offset + i + 2) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte, value_rlc, @@ -1338,7 +1338,7 @@ fn process_block_zstd_lstream( tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + current_byte_idx) as u64, + byte_idx: (byte_offset + current_byte_idx + 1) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - current_byte_idx], value_rlc: next_value_rlc_acc, @@ -1420,7 +1420,7 @@ fn process_block_zstd_lstream( tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + from_byte_idx) as u64, + byte_idx: (byte_offset + from_byte_idx + 1) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - from_byte_idx], value_rlc: next_value_rlc_acc, From 439ee6ce6ad75a86cfa2f8fa5cf55b4f8a713667 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 20:35:08 -0500 Subject: [PATCH 081/165] Revert "Adjust huffman code idx" This reverts commit d8b510786f2a438d7b4b2884a905571e81d5199d. --- zkevm-circuits/src/decompression_circuit.rs | 20 +++++++++++++++----- zkevm-circuits/src/witness/zstd/mod.rs | 10 +++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index eeac1fef4b..4d88871b02 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -647,11 +647,21 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // If we don't encounter a new byte, the byte value should stay the same. cb.condition(not::expr(is_new_byte.expr()), |cb| { // compression_debug - cb.require_equal( - "value_byte' == value_byte if not a new byte", - meta.query_advice(value_byte, Rotation::prev()), - meta.query_advice(value_byte, Rotation::cur()), - ); + // cb.require_equal( + // "value_byte' == value_byte if not a new byte", + // meta.query_advice(value_byte, Rotation::next()), + // meta.query_advice(value_byte, Rotation::cur()), + // ); + }); + + // If we don't encounter a new byte, the byte value should stay the same. + cb.condition(not::expr(is_new_byte.expr()), |cb| { + // compression_debug + // cb.require_equal( + // "value_byte' == value_byte if not a new byte", + // meta.query_advice(value_byte, Rotation::next()), + // meta.query_advice(value_byte, Rotation::cur()), + // ); }); // We also need to validate that ``is_tag_change`` was assigned correctly. Tag changes diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 5452396442..440a81f0bf 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1072,7 +1072,7 @@ fn process_block_zstd_huffman_code( tag_next, max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockHuffmanCode), tag_len: (n_huffman_code_bytes) as u64, - tag_idx: (current_byte_idx + 1) as u64, + tag_idx: current_byte_idx as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, is_tag_change: false, @@ -1080,7 +1080,7 @@ fn process_block_zstd_huffman_code( tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + n_fse_bytes + 2 + current_byte_idx) as u64, + byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], value_rlc: next_value_rlc_acc, @@ -1227,7 +1227,7 @@ fn process_block_zstd_huffman_jump_table( tag_rlc_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + i + 2) as u64, + byte_idx: (byte_offset + i + 1) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte, value_rlc, @@ -1338,7 +1338,7 @@ fn process_block_zstd_lstream( tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + current_byte_idx + 1) as u64, + byte_idx: (byte_offset + current_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - current_byte_idx], value_rlc: next_value_rlc_acc, @@ -1420,7 +1420,7 @@ fn process_block_zstd_lstream( tag_rlc_acc: next_tag_rlc_acc, }, encoded_data: EncodedData { - byte_idx: (byte_offset + from_byte_idx + 1) as u64, + byte_idx: (byte_offset + from_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - from_byte_idx], value_rlc: next_value_rlc_acc, From 580ee11c82ed4def8ad3ecb803115f3fe9cd0715 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 20:37:50 -0500 Subject: [PATCH 082/165] Correct byte delimitation in the test --- zkevm-circuits/src/decompression_circuit/test.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit/test.rs b/zkevm-circuits/src/decompression_circuit/test.rs index 191ce042f9..602668d4fe 100644 --- a/zkevm-circuits/src/decompression_circuit/test.rs +++ b/zkevm-circuits/src/decompression_circuit/test.rs @@ -26,18 +26,18 @@ fn test_work_example_decompression() { // ZstdBlockHuffmanCode 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, 0xa9, 0xd4, - 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, 0x01, 0x55, + 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, 0x01, // ZstdBlockJumpTable - 0x00, 0x57, 0x00, 0x51, 0x00, 0xcc, + 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, // LStream1 - 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, 0x65, - 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, 0xa3, - 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, 0x1c, - 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, - 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, - 0x5a, 0xdf, 0xb4, 0x21, + 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, + 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, + 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, + 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, + 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, + 0x24, 0x5a, 0xdf, 0xb4, 0x21, // LStream2 0x9a, 0xcb, 0x8f, 0xc7, 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, From b52cbf5bd9543e80d1464bcdd7629d8ca3295119 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 20:50:43 -0500 Subject: [PATCH 083/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 20 +++++--------------- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 4d88871b02..67fe34823b 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -647,21 +647,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // If we don't encounter a new byte, the byte value should stay the same. cb.condition(not::expr(is_new_byte.expr()), |cb| { // compression_debug - // cb.require_equal( - // "value_byte' == value_byte if not a new byte", - // meta.query_advice(value_byte, Rotation::next()), - // meta.query_advice(value_byte, Rotation::cur()), - // ); - }); - - // If we don't encounter a new byte, the byte value should stay the same. - cb.condition(not::expr(is_new_byte.expr()), |cb| { - // compression_debug - // cb.require_equal( - // "value_byte' == value_byte if not a new byte", - // meta.query_advice(value_byte, Rotation::next()), - // meta.query_advice(value_byte, Rotation::cur()), - // ); + cb.require_equal( + "value_byte' == value_byte if not a new byte", + meta.query_advice(value_byte, Rotation::next()), + meta.query_advice(value_byte, Rotation::cur()), + ); }); // We also need to validate that ``is_tag_change`` was assigned correctly. Tag changes diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 440a81f0bf..2dbbc883ac 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1005,7 +1005,7 @@ fn process_block_zstd_huffman_code( encoded_data: EncodedData { byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, - value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - (current_byte_idx - 1)], + value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], value_rlc: next_value_rlc_acc, reverse: true, reverse_len: n_huffman_code_bytes as u64, From 7032e43b305dd14b24442383c34fcd9665cb127b Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 20:57:59 -0500 Subject: [PATCH 084/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 67fe34823b..2a91cba758 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -646,10 +646,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // If we don't encounter a new byte, the byte value should stay the same. cb.condition(not::expr(is_new_byte.expr()), |cb| { - // compression_debug cb.require_equal( "value_byte' == value_byte if not a new byte", - meta.query_advice(value_byte, Rotation::next()), + meta.query_advice(value_byte, Rotation::prev()), meta.query_advice(value_byte, Rotation::cur()), ); }); From f55894428f1d9e584f543243f2bfee889a999cc3 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 21:24:19 -0500 Subject: [PATCH 085/165] Assign block gadget --- zkevm-circuits/src/decompression_circuit.rs | 73 ++++++++++----------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 2a91cba758..f0c3888418 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -103,9 +103,7 @@ pub struct DecompressionCircuitConfig { /// The random linear combination of all decoded bytes up to and including the current one. decoded_rlc: Column, /// Block level details are specified in these columns. - /// compression_debug - // block_gadget: BlockGadget, - block_gadget: BlockGadget, + block_gadget: BlockGadget, /// All zstd tag related columns. tag_gadget: TagGadget, /// Decomposition of the Literals Header. @@ -128,9 +126,7 @@ pub struct DecompressionCircuitConfig { /// Block level details are specified in these columns. #[derive(Clone, Debug)] -// compression_debug -pub struct BlockGadget { -// pub struct BlockGadget { +pub struct BlockGadget { /// Boolean column to indicate that we are processing a block. is_block: Column, /// The incremental index of the byte within this block. @@ -139,9 +135,8 @@ pub struct BlockGadget { block_len: Column, /// Boolean column to mark whether or not this is the last block. is_last_block: Column, - // compression_debug // Check: block_idx <= block_len. - // idx_cmp_len: ComparatorConfig, + idx_cmp_len: ComparatorConfig, } /// All tag related columns are placed in this type. @@ -397,14 +392,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { idx: block_idx, block_len, is_last_block: meta.advice_column(), - // compression_debug - // idx_cmp_len: ComparatorChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(block_idx, Rotation::cur()), - // |meta| meta.query_advice(block_len, Rotation::cur()), - // range256.into(), - // ), + idx_cmp_len: ComparatorChip::configure( + meta, + |meta| meta.query_fixed(q_enable, Rotation::cur()), + |meta| meta.query_advice(block_idx, Rotation::cur()), + |meta| meta.query_advice(block_len, Rotation::cur()), + range256.into(), + ), } }; let tag_gadget = { @@ -1150,6 +1144,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ////////////////////////////////// ZstdTag::BlockHeader /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// + // TODO: Multi-block constraints will be examined after mutli-block test vectors become available // Note: We only verify the 1st row of BlockHeader for tag_value. meta.create_gate("DecompressionCircuit: BlockHeader", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -1167,7 +1162,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // // But block header is expressed in the reverse order, which helps us in calculating // the tag_value appropriately. - // compression_debug // cb.require_equal( // "last block check", // meta.query_advice(value_bits[7], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), @@ -1193,7 +1187,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear with // block type 00 or 01, i.e. the block_type_bit1 is 0. - // compression_debug // cb.condition(not::expr(block_type_bit1), |cb| { // cb.require_equal( // "Raw/RLE blocks: tag_len == block_len", @@ -1233,11 +1226,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), ])) }); + // TODO: Multi-block constraints will be examined after mutli-block test vectors become available meta.create_gate("DecompressionCircuit: while processing a block", |meta| { let mut cb = BaseConstraintBuilder::default(); // If byte_idx increments, then block_gadet.idx should also increment. - // compression_debug // cb.require_equal( // "idx in block increments if byte_idx increments", // meta.query_advice(block_gadget.idx, Rotation::next()) @@ -1267,6 +1260,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(block_gadget.is_block, Rotation::next()), ])) }); + // TODO: Multi-block constraints will be examined after mutli-block test vectors become available meta.create_gate("DecompressionCircuit: handle end of other blocks", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -1296,6 +1290,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { not::expr(meta.query_advice(block_gadget.is_last_block, Rotation::cur())), ])) }); + // TODO: Multi-block constraints will be examined after mutli-block test vectors become available meta.create_gate("DecompressionCircuit: handle end of last block", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -1347,6 +1342,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // idx_eq_len, ])) }); + // compression_debug // meta.lookup( // "DecompressionCircuit: BlockHeader (BlockSize == BlockHeader >> 3)", @@ -2971,31 +2967,34 @@ impl DecompressionCircuitConfig { // Block Gadget // compression_debug + region.assign_advice( + || "block_gadget.is_block", + self.block_gadget.is_block, + i, + || Value::known(F::one()), + )?; region.assign_advice( || "block_gadget.block_idx", self.block_gadget.idx, i, || Value::known(F::one()), )?; + region.assign_advice( + || "block_gadget.block_len", + self.block_gadget.block_len, + i, + || Value::known(F::one()), + )?; + region.assign_advice( + || "block_gadget.is_last_block", + self.block_gadget.is_last_block, + i, + || Value::known(F::one()), + )?; - // let block_gadget = { - // let block_idx = meta.advice_column(); - // let block_len = meta.advice_column(); - // BlockGadget { - // is_block: meta.advice_column(), - // idx: block_idx, - // block_len, - // is_last_block: meta.advice_column(), - // idx_cmp_len: ComparatorChip::configure( - // meta, - // |meta| meta.query_fixed(q_enable, Rotation::cur()), - // |meta| meta.query_advice(block_idx, Rotation::cur()), - // |meta| meta.query_advice(block_len, Rotation::cur()), - // range256.into(), - // ), - // } - // }; - + let idx_cmp_len_chip = ComparatorChip::construct(self.block_gadget.idx_cmp_len.clone()); + idx_cmp_len_chip.assign(&mut region, i, F::one(), F::one())?; + // Tag Gadget From f28979c2bc59e5a9bd6c1db49feb67d5393f4e53 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 21:50:02 -0500 Subject: [PATCH 086/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 341 ++++++++++---------- 1 file changed, 179 insertions(+), 162 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index f0c3888418..0e53535608 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -543,11 +543,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { macro_rules! degree_reduction_check { ($column:expr, $expr:expr) => { // compression_debug - // cb.require_equal( - // "Degree reduction column check", - // meta.query_advice($column, Rotation::cur()), - // $expr, - // ); + cb.require_equal( + "Degree reduction column check", + meta.query_advice($column, Rotation::cur()), + $expr, + ); }; } degree_reduction_check!(tag_gadget.is_block_header, is_block_header(meta)); @@ -2612,132 +2612,140 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockLstream (contained bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - bitstream_decoder.is_contained(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - 1.expr(), // bitstring length accumulator, starts at 1 - start, // bit index start - 1.expr(), // denotes that this bit index is a part of the bitstring - 1.expr(), // denotes that this bit index is a part of the bitstring - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockLstream (contained bitstream end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - bitstream_decoder.is_contained(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockLstream (spanned bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - 1.expr(), // bitstring len acc - start, // bit index start - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockLstream (spanned bitstring end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockLstream (contained bitstream start)", + // |meta| { + // let (huffman_byte_offset, start, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + // bitstream_decoder.is_contained(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // 1.expr(), // bitstring length accumulator, starts at 1 + // start, // bit index start + // 1.expr(), // denotes that this bit index is a part of the bitstring + // 1.expr(), // denotes that this bit index is a part of the bitstring + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockLstream (contained bitstream end)", + // |meta| { + // let (huffman_byte_offset, start, end, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + // bitstream_decoder.is_contained(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_contained(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockLstream (spanned bitstream start)", + // |meta| { + // let (huffman_byte_offset, start, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + // bitstream_decoder.is_spanned(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // 1.expr(), // bitstring len acc + // start, // bit index start + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockLstream (spanned bitstring end)", + // |meta| { + // let (huffman_byte_offset, start, end, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + // bitstream_decoder.is_spanned(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); meta.create_gate("DecompressionCircuit: bitstream reader", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -2786,44 +2794,47 @@ impl SubCircuitConfig for DecompressionCircuitConfig { and::expr([is_not_last.expr(), bitstream_decoder.is_spanned(meta, None)]); // if bitstring is strictly contained. cb.condition(is_strictly_contained, |cb| { - cb.require_equal( - "strictly contained bitstring: bit_index_start", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), - ); - cb.require_equal( - "strictly contained bitstring: byte_idx", - meta.query_advice(byte_idx, Rotation::next()), - meta.query_advice(byte_idx, Rotation::cur()), - ); + // compression_debug + // cb.require_equal( + // "strictly contained bitstring: bit_index_start", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), + // ); + // cb.require_equal( + // "strictly contained bitstring: byte_idx", + // meta.query_advice(byte_idx, Rotation::next()), + // meta.query_advice(byte_idx, Rotation::cur()), + // ); }); // if bitstring is byte-aligned. cb.condition(is_byte_aligned, |cb| { - cb.require_equal( - "byte-aligned bitstring: bit_index_start", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - 0.expr(), - ); - cb.require_equal( - "byte-aligned bitstring: byte_idx", - meta.query_advice(byte_idx, Rotation::next()), - meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), - ); + // compression_debug + // cb.require_equal( + // "byte-aligned bitstring: bit_index_start", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // 0.expr(), + // ); + // cb.require_equal( + // "byte-aligned bitstring: byte_idx", + // meta.query_advice(byte_idx, Rotation::next()), + // meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), + // ); }); // if bitstring is spanned. cb.condition(is_spanned, |cb| { - cb.require_equal( - "spanned bitstring: bit_index_start", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) - 7.expr(), - ); - cb.require_equal( - "spanned bitstring: byte_idx", - meta.query_advice(byte_idx, Rotation::next()), - meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), - ); + // compression_debug + // cb.require_equal( + // "spanned bitstring: bit_index_start", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) - 7.expr(), + // ); + // cb.require_equal( + // "spanned bitstring: byte_idx", + // meta.query_advice(byte_idx, Rotation::next()), + // meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), + // ); }); cb.gate(and::expr([ @@ -2994,7 +3005,7 @@ impl DecompressionCircuitConfig { let idx_cmp_len_chip = ComparatorChip::construct(self.block_gadget.idx_cmp_len.clone()); idx_cmp_len_chip.assign(&mut region, i, F::one(), F::one())?; - + // Tag Gadget @@ -3112,6 +3123,12 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(is_literals_header)), )?; + region.assign_advice( + || "tag_gadget.is_lstream", + self.tag_gadget.is_lstream, + i, + || Value::known(F::from(is_lstream)), + )?; region.assign_advice( || "tag_gadget.is_fse_code", self.tag_gadget.is_fse_code, From 51bc5050540087b7b06807c9126e1d5490c2f02e Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 22:26:09 -0500 Subject: [PATCH 087/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 76 +++++++++++---------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 0e53535608..97878ba857 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -542,7 +542,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // Degree reduction columns. macro_rules! degree_reduction_check { ($column:expr, $expr:expr) => { - // compression_debug cb.require_equal( "Degree reduction column check", meta.query_advice($column, Rotation::cur()), @@ -651,6 +650,10 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // on the next row iff: // - tag_idx == tag_len // - byte_idx' == byte_idx + 1 + + // TODO: This constraints might be incorrect as is_new_byte specifies the byte on current row is new + // but for is_tag_change, it instead requires that the byte on the next row is new. + // let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, None); // cb.condition(and::expr([ // tidx_eq_tlen, @@ -689,36 +692,34 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.tag_idx, Rotation::prev()), meta.query_advice(tag_gadget.tag_len, Rotation::prev()), ); - // compression_debug - // cb.require_equal( - // "tag_value::prev == tag_value_acc::prev", - // meta.query_advice(tag_gadget.tag_value, Rotation::prev()), - // meta.query_advice(tag_gadget.tag_value_acc, Rotation::prev()), - // ); + cb.require_equal( + "tag_value::prev == tag_value_acc::prev", + meta.query_advice(tag_gadget.tag_value, Rotation::prev()), + meta.query_advice(tag_gadget.tag_value_acc, Rotation::prev()), + ); cb.require_equal( "tag == tag_next::prev", meta.query_advice(tag_gadget.tag, Rotation::cur()), meta.query_advice(tag_gadget.tag_next, Rotation::prev()), ); - // cb.condition(was_reverse.expr(), |cb| { - // cb.require_equal( - // "tag_rlc_acc on the last row for tag processed back-to-front", - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), - // meta.query_advice(value_byte, Rotation::prev()), - // ); - // }); - // cb.condition(not::expr(was_reverse), |cb| { - // cb.require_equal( - // "tag_rlc_acc == tag_rlc on the last row of tag if tag processed front-to-back", - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), - // meta.query_advice(tag_gadget.tag_rlc, Rotation::prev()), - // ); - // }); + cb.condition(was_reverse.expr(), |cb| { + cb.require_equal( + "tag_rlc_acc on the last row for tag processed back-to-front", + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), + meta.query_advice(value_byte, Rotation::prev()), + ); + }); + cb.condition(not::expr(was_reverse), |cb| { + cb.require_equal( + "tag_rlc_acc == tag_rlc on the last row of tag if tag processed front-to-back", + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::prev()), + meta.query_advice(tag_gadget.tag_rlc, Rotation::prev()), + ); + }); // Whether the new tag is processed from back-to-front. let is_reverse = meta.query_advice(tag_gadget.is_reverse, Rotation::cur()); - // compression_debug // Validations for the new tag: // // - tag_idx == 1 @@ -734,11 +735,14 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); let (lt, eq) = tag_gadget.len_cmp_max.expr(meta, None); cb.require_equal("tag_len <= max_len", lt + eq, 1.expr()); + + // compression_debug // cb.require_equal( // "tag_value_acc == value_byte", // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), // meta.query_advice(value_byte, Rotation::cur()), // ); + // cb.require_equal( // "value_rlc calculation", // meta.query_advice(value_rlc, Rotation::cur()), @@ -746,20 +750,20 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // * meta.query_advice(tag_gadget.rand_pow_tag_len, Rotation::prev()) // + meta.query_advice(tag_gadget.tag_rlc, Rotation::prev()), // ); - // cb.condition(is_reverse.expr(), |cb| { - // cb.require_equal( - // "tag_rlc_acc == tag_rlc on the first row of tag processed back-to-front", - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - // meta.query_advice(tag_gadget.tag_rlc, Rotation::cur()), - // ); - // }); - // cb.condition(not::expr(is_reverse), |cb| { - // cb.require_equal( - // "tag_rlc_acc on the first row for tag processed from front-to-back", - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - // meta.query_advice(value_byte, Rotation::cur()), - // ); - // }); + cb.condition(is_reverse.expr(), |cb| { + cb.require_equal( + "tag_rlc_acc == tag_rlc on the first row of tag processed back-to-front", + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + meta.query_advice(tag_gadget.tag_rlc, Rotation::cur()), + ); + }); + cb.condition(not::expr(is_reverse), |cb| { + cb.require_equal( + "tag_rlc_acc on the first row for tag processed from front-to-back", + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + meta.query_advice(value_byte, Rotation::cur()), + ); + }); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), From f102ea9d85a7d74e4cb867e80a1452ea1c3f3ecc Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 22:31:06 -0500 Subject: [PATCH 088/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 22 ++++++++++----------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 97878ba857..0954a9826c 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -767,8 +767,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), - // not::expr(meta.query_advice(is_padding, Rotation::cur())), - // compression_debug not::expr(meta.query_fixed(q_first, Rotation::cur())), meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), ])) @@ -1034,16 +1032,16 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.tag_len, Rotation::cur()), 1.expr(), ); - // cb.require_equal( - // "tag_value_acc == value_byte", - // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), - // meta.query_advice(value_byte, Rotation::cur()), - // ); - // cb.require_equal( - // "tag_rlc_acc == value_byte", - // meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), - // meta.query_advice(value_byte, Rotation::cur()), - // ); + cb.require_equal( + "tag_value_acc == value_byte", + meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), + meta.query_advice(value_byte, Rotation::cur()), + ); + cb.require_equal( + "tag_rlc_acc == value_byte", + meta.query_advice(tag_gadget.tag_rlc_acc, Rotation::cur()), + meta.query_advice(value_byte, Rotation::cur()), + ); // Structure of the Frame's header descriptor. // From c72d43ab8d72a91ac0c74558ac07d5d3b570bce1 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 22:32:01 -0500 Subject: [PATCH 089/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 0954a9826c..e3231b00d5 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1021,7 +1021,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let mut cb = BaseConstraintBuilder::default(); // FrameHeaderDescriptor is a single byte. - // compression_debug cb.require_equal( "tag_idx == 1", meta.query_advice(tag_gadget.tag_idx, Rotation::cur()), From 0070ab8e25d753d692f102d4b9305e3dc25586e0 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 23:49:52 -0500 Subject: [PATCH 090/165] Correct tag value acc again --- zkevm-circuits/src/decompression_circuit.rs | 10 +++++----- zkevm-circuits/src/witness/zstd/mod.rs | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index e3231b00d5..a6baf86e11 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -737,11 +737,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.require_equal("tag_len <= max_len", lt + eq, 1.expr()); // compression_debug - // cb.require_equal( - // "tag_value_acc == value_byte", - // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), - // meta.query_advice(value_byte, Rotation::cur()), - // ); + cb.require_equal( + "tag_value_acc == value_byte", + meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), + meta.query_advice(value_byte, Rotation::cur()), + ); // cb.require_equal( // "value_rlc calculation", diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 2dbbc883ac..5e95aa4546 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -93,6 +93,7 @@ fn process_frame_header( }; let fcs_tag_value_iter = fcs_bytes .iter() + .rev() .scan(Value::known(F::zero()), |acc, &byte| { *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); Some(*acc) @@ -952,7 +953,7 @@ fn process_block_zstd_huffman_code( Some(*acc) }, ).collect::>>().into_iter().rev(); - let mut tag_value_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).scan( + let mut tag_value_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).rev().scan( Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); @@ -1287,7 +1288,7 @@ fn process_block_zstd_lstream( }, ); - let mut tag_value_acc = src.iter().skip(byte_offset).take(len).scan( + let mut tag_value_acc = src.iter().skip(byte_offset).take(len).rev().scan( Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); From 52323b95257a4bba1e49cab5d15095c4abc422fb Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 7 Feb 2024 23:56:00 -0500 Subject: [PATCH 091/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 22 ++++++++++----------- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index a6baf86e11..08e23b3bbf 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -735,14 +735,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); let (lt, eq) = tag_gadget.len_cmp_max.expr(meta, None); cb.require_equal("tag_len <= max_len", lt + eq, 1.expr()); - - // compression_debug cb.require_equal( "tag_value_acc == value_byte", meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), meta.query_advice(value_byte, Rotation::cur()), ); + // compression_debug // cb.require_equal( // "value_rlc calculation", // meta.query_advice(value_rlc, Rotation::cur()), @@ -813,16 +812,15 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.tag_value_acc, Rotation::prev()); let value_byte_curr = meta.query_advice(value_byte, Rotation::cur()); - // compression_debug - // cb.require_equal( - // "tag_value calculation depending on whether new byte", - // meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), - // select::expr( - // is_new_byte.expr(), - // tag_value_acc_prev.expr() * multiplier + value_byte_curr.expr(), - // tag_value_acc_prev, - // ), - // ); + cb.require_equal( + "tag_value calculation depending on whether new byte", + meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), + select::expr( + is_new_byte.expr(), + tag_value_acc_prev.expr() * multiplier + value_byte_curr.expr(), + tag_value_acc_prev, + ), + ); // tag_rlc_acc calculation depending on whether is_reverse or not. let is_reverse = meta.query_advice(tag_gadget.is_reverse, Rotation::cur()); diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 5e95aa4546..8a6e644c35 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -858,7 +858,7 @@ fn process_block_zstd_huffman_code( let mut tag_value_iter = src.iter().skip(byte_offset).take(n_fse_bytes + 1).scan( Value::known(F::zero()), |acc, &byte| { - *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); + *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) }, ); From 52c74fc3032f39bbc6516fad16a40e957f6ef257 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 01:08:49 -0500 Subject: [PATCH 092/165] Correct decoding constraints --- zkevm-circuits/src/decompression_circuit.rs | 89 +++++++++++---------- zkevm-circuits/src/witness/zstd/mod.rs | 25 +++++- 2 files changed, 69 insertions(+), 45 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 08e23b3bbf..f00d325f01 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -987,28 +987,28 @@ impl SubCircuitConfig for DecompressionCircuitConfig { debug_assert!(meta.degree() <= 9); - meta.lookup_any( - "DecompressionCircuit: lookup for tuple (tag, tag_next, max_len, is_output)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(is_padding, Rotation::next())), - ]); - [ - meta.query_advice(tag_gadget.tag, Rotation::cur()), - meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - meta.query_advice(tag_gadget.max_len, Rotation::cur()), - // compression_debug - // meta.query_advice(tag_gadget.is_output, Rotation::cur()), - // meta.query_advice(block_gadget.is_block, Rotation::cur()), - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - ] - .into_iter() - .zip(tag_rom_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for tuple (tag, tag_next, max_len, is_output)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(is_padding, Rotation::next())), + // ]); + // [ + // meta.query_advice(tag_gadget.tag, Rotation::cur()), + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // meta.query_advice(tag_gadget.max_len, Rotation::cur()), + // meta.query_advice(tag_gadget.is_output, Rotation::cur()), + // meta.query_advice(block_gadget.is_block, Rotation::cur()), + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + // ] + // .into_iter() + // .zip(tag_rom_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); debug_assert!(meta.degree() <= 9); @@ -2971,17 +2971,24 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.decoded_data.decoded_byte as u64)), )?; - // decoded_rlc - // TODO: - + region.assign_advice( + || "decoded_rlc", + self.decoded_rlc, + i, + || row.decoded_data.decoded_value_rlc, + )?; // Block Gadget - // compression_debug + let is_block = !( + row.state.tag == ZstdTag::FrameHeaderDescriptor || + row.state.tag == ZstdTag::FrameContentSize || + row.state.tag == ZstdTag::BlockHeader + ) as u64; region.assign_advice( || "block_gadget.is_block", self.block_gadget.is_block, i, - || Value::known(F::one()), + || Value::known(F::from(is_block)), )?; region.assign_advice( || "block_gadget.block_idx", @@ -3103,11 +3110,18 @@ impl DecompressionCircuitConfig { let is_literals_section = is_literals_header + is_fse_code + is_huffman_code + is_lstream + is_jumptable; let is_huffman_tree_section = is_fse_code + is_huffman_code + is_jumptable + is_lstream; + let is_output = ( + row.state.tag == ZstdTag::RawBlockBytes || + row.state.tag == ZstdTag::RleBlockBytes || + row.state.tag == ZstdTag::ZstdBlockLiteralsRawBytes || + row.state.tag == ZstdTag::ZstdBlockLiteralsRleBytes || + row.state.tag == ZstdTag::ZstdBlockLstream + ) as u64; region.assign_advice( || "tag_gadget.is_output", self.tag_gadget.is_output, i, - || Value::known(F::zero()), + || Value::known(F::from(is_output)), )?; region.assign_advice( @@ -3183,12 +3197,6 @@ impl DecompressionCircuitConfig { // Bitstream Decoder - // pub struct BitstreamDecoder { - // /// The symbol that this bitstring decodes to. We are using this for decoding using FSE table - // /// or a Huffman Tree. So this symbol represents the decoded value that the bitstring maps to. - // decoded_symbol: Column, - // } - region.assign_advice( || "bitstream_decoder.bit_index_start", self.bitstream_decoder.bit_index_start, @@ -3211,13 +3219,12 @@ impl DecompressionCircuitConfig { let bitstring_contained_chip = ComparatorChip::construct(self.bitstream_decoder.bitstring_contained.clone()); bitstring_contained_chip.assign(&mut region, i, F::from(row.huffman_data.k.1 as u64), F::from(7u64))?; - // compression_debug - // region.assign_advice( - // || "bitstream_decoder.decoded_symbol", - // self.bitstream_decoder.decoded_symbol, - // i, - // || Value::known(F::from(row.huffman_data.bit_value as u64)), - // )?; + region.assign_advice( + || "bitstream_decoder.decoded_symbol", + self.bitstream_decoder.decoded_symbol, + i, + || Value::known(F::from(row.decoded_data.decoded_byte as u64)), + )?; // FSE Gadget diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 8a6e644c35..9cfe056e07 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -83,7 +83,7 @@ fn process_frame_header( .cloned() .collect::>(); let fcs = { - let fcs = fcs_bytes + let fcs = fcs_bytes_rev .iter() .fold(0u64, |acc, &byte| acc * 256u64 + (byte as u64)); match fcs_tag_len { @@ -197,7 +197,7 @@ fn process_frame_header( decoded_len_acc: 0, total_decoded_len: last_row.decoded_data.total_decoded_len + fcs, decoded_byte: 0, - decoded_value_rlc: last_row.decoded_data.decoded_value_rlc, + decoded_value_rlc: Value::known(F::zero()), }, bitstream_read_data: BitstreamReadRow::default(), huffman_data: HuffmanData::default(), @@ -1277,6 +1277,8 @@ fn process_block_zstd_lstream( let mut last_byte_idx: usize = 1; let mut current_byte_idx: usize = 1; let mut current_bit_idx: usize = 0; + let mut decoded_len_acc = last_row.decoded_data.decoded_len_acc; + let mut decoded_rlc = last_row.decoded_data.decoded_value_rlc; // accumulators let aux_1 = last_row.encoded_data.value_rlc; @@ -1362,7 +1364,13 @@ fn process_block_zstd_lstream( bit_start_idx: 0usize, bit_end_idx: padding_end_idx as usize, }, - decoded_data: last_row.decoded_data.clone(), + decoded_data: DecodedData { + decoded_len: last_row.decoded_data.decoded_len, + decoded_len_acc: last_row.decoded_data.decoded_len_acc, + total_decoded_len: last_row.decoded_data.total_decoded_len, + decoded_byte: 0, + decoded_value_rlc: last_row.decoded_data.decoded_value_rlc, + }, fse_data: FseTableRow::default(), }); @@ -1406,6 +1414,9 @@ fn process_block_zstd_lstream( }; (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); + decoded_len_acc += 1; + decoded_rlc = decoded_rlc * randomness + Value::known(F::from(sym)); + // Add a witness row for emitted symbol witness_rows.push(ZstdWitnessRow { state: ZstdState { @@ -1444,7 +1455,13 @@ fn process_block_zstd_lstream( bit_start_idx: from_bit_idx.rem_euclid(8) as usize, bit_end_idx: end_bit_idx as usize, }, - decoded_data: last_row.decoded_data.clone(), + decoded_data: DecodedData { + decoded_len: last_row.decoded_data.decoded_len, + decoded_len_acc, + total_decoded_len: last_row.decoded_data.total_decoded_len, + decoded_byte: sym as u8, + decoded_value_rlc: decoded_rlc, + }, fse_data: FseTableRow::default(), }); From 9ceb45544d386b8ee06829637b81b44c21b5d945 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 01:19:21 -0500 Subject: [PATCH 093/165] Correct assignment for fcs --- zkevm-circuits/src/decompression_circuit.rs | 15 +++++---------- zkevm-circuits/src/witness/zstd/mod.rs | 3 ++- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index f00d325f01..67f54cdc2e 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1119,16 +1119,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { 256.expr() + fcs_tag_value.expr(), fcs_tag_value, ); - // compression_debug - // cb.require_equal( - // "decoded_len == frame_content_size", - // frame_content_size, - // meta.query_advice(decoded_len, Rotation::cur()), - // ); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); - + cb.require_equal( + "decoded_len == frame_content_size", + frame_content_size, + meta.query_advice(decoded_len, Rotation::cur()), + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 9cfe056e07..e6945c4c14 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -87,7 +87,8 @@ fn process_frame_header( .iter() .fold(0u64, |acc, &byte| acc * 256u64 + (byte as u64)); match fcs_tag_len { - 2 => fcs + 256, + // compression_debug + // 2 => fcs + 256, _ => fcs, } }; From 62aee83420a21de4da9367039e791426b57f6846 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 01:55:30 -0500 Subject: [PATCH 094/165] Rand power correction --- zkevm-circuits/src/decompression_circuit.rs | 62 +++++++++++-------- .../src/decompression_circuit/dev.rs | 1 + 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 67f54cdc2e..3d729e067f 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -122,6 +122,7 @@ pub struct DecompressionCircuitConfig { range128: RangeTable<128>, range256: RangeTable<256>, tag_rom_table: TagRomTable, + pow_rand_table: PowOfRandTable, } /// Block level details are specified in these columns. @@ -864,23 +865,23 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - // compression_debug - // meta.lookup_any("DecompressionCircuit: randomness power tag_len", |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // not::expr(meta.query_advice(is_padding, Rotation::cur())), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // ]); - // [ - // 1.expr(), // enabled - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // exponent - // meta.query_advice(tag_gadget.rand_pow_tag_len, Rotation::cur()), // exponentiation - // ] - // .into_iter() - // .zip(pow_rand_table.table_exprs(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }); + + meta.lookup_any("DecompressionCircuit: randomness power tag_len", |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + not::expr(meta.query_advice(is_padding, Rotation::cur())), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + ]); + [ + 1.expr(), // enabled + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // exponent + meta.query_advice(tag_gadget.rand_pow_tag_len, Rotation::cur()), // exponentiation + ] + .into_iter() + .zip(pow_rand_table.table_exprs(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }); debug_assert!(meta.degree() <= 9); @@ -2868,6 +2869,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { range128, range256, tag_rom_table, + pow_rand_table, } } } @@ -2882,11 +2884,20 @@ impl DecompressionCircuitConfig { challenges: &Challenges>, ) -> Result<(), Error> { let mut jump_table_idx: usize = 0; + let mut rand_pow: Vec> = vec![Value::known(F::one())]; layouter.assign_region( || "Decompression table region", |mut region| { for (i, row) in witness_rows.iter().enumerate() { + let tag_len = row.state.tag_len as usize; + assert!(tag_len > 0); + + while tag_len >= rand_pow.len() { + let tail = rand_pow.last().expect("Tail exists").clone(); + rand_pow.push(tail * challenges.keccak_input()); + } + region.assign_fixed( || "q_enable", self.q_enable, @@ -3009,13 +3020,6 @@ impl DecompressionCircuitConfig { // Tag Gadget - - // pub struct TagGadget { - // /// Randomness exponentiated by the tag's length. This is used to then accumulate the value - // /// RLC post processing of this tag. - // rand_pow_tag_len: Column, - // } - region.assign_advice( || "tag_gadget.tag", self.tag_gadget.tag, @@ -3082,6 +3086,12 @@ impl DecompressionCircuitConfig { i, || row.state.tag_rlc_acc, )?; + region.assign_advice( + || "tag_gadget.rand_pow_tag_len", + self.tag_gadget.rand_pow_tag_len, + i, + || rand_pow[tag_len], + )?; let tag_bits = BinaryNumberChip::construct(self.tag_gadget.tag_bits); tag_bits.assign(&mut region, i, &row.state.tag)?; @@ -3345,8 +3355,8 @@ impl SubCircuit for DecompressionCircuit { // compression_debug for row in witness_rows.clone() { - log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;", - row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, + log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};;", + row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, row.bitstream_read_data.bit_start_idx, row.bitstream_read_data.bit_end_idx, row.bitstream_read_data.bit_value ); } diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index c96202cad7..8ef2b9126d 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -83,6 +83,7 @@ impl Circuit for DecompressionCircuit { config.0.range128.load(&mut layouter)?; config.0.range256.load(&mut layouter)?; config.0.tag_rom_table.load(&mut layouter)?; + config.0.pow_rand_table.assign(&mut layouter, challenges)?; self.synthesize_sub(&config.0, challenges, &mut layouter) } } From 5967e566911b550af5c4f87d8bc44d9efde2dfa4 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 02:58:46 -0500 Subject: [PATCH 095/165] Correct constraints --- zkevm-circuits/src/decompression_circuit.rs | 2 +- zkevm-circuits/src/witness/zstd/mod.rs | 50 +++++++++++++-------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 3d729e067f..a3ce183f8b 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -865,7 +865,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - + meta.lookup_any("DecompressionCircuit: randomness power tag_len", |meta| { let condition = and::expr([ meta.query_fixed(q_enable, Rotation::cur()), diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index e6945c4c14..9178597b7f 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -128,6 +128,8 @@ fn process_frame_header( .expect("FrameContentSize bytes expected"); let aux_2 = fhd_value_rlc; + let value_rlc_fcs = fhd_value_rlc * randomness + fhd_value_rlc; + ( byte_offset + 1 + fcs_tag_len, std::iter::once(ZstdWitnessRow { @@ -169,7 +171,7 @@ fn process_frame_header( .zip(tag_rlc_iter.iter().rev()) .enumerate() .map( - |(i, (((&value_byte, tag_value_acc), &value_rlc), &tag_rlc_acc))| ZstdWitnessRow { + |(i, (((&value_byte, tag_value_acc), _value_rlc), &tag_rlc_acc))| ZstdWitnessRow { state: ZstdState { tag: ZstdTag::FrameContentSize, tag_next: ZstdTag::BlockHeader, @@ -191,7 +193,7 @@ fn process_frame_header( reverse_len: fcs_tag_len as u64, aux_1: *aux_1, aux_2, - value_rlc, + value_rlc: value_rlc_fcs, }, decoded_data: DecodedData { decoded_len: fcs, @@ -291,6 +293,9 @@ fn process_block_header( }); let tag_rlc = tag_rlc_acc.clone().last().expect("Tag RLC expected"); + let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; + // BlockHeader follows FrameContentSize which is processed in reverse order. // Hence value_rlc at the first BlockHeader byte will be calculated as: // @@ -317,7 +322,7 @@ fn process_block_header( .zip(tag_rlc_acc) .enumerate() .map( - |(i, (((&value_byte, tag_value_acc), &value_rlc), tag_rlc_acc))| ZstdWitnessRow { + |(i, (((&value_byte, tag_value_acc), _v_rlc), tag_rlc_acc))| ZstdWitnessRow { state: ZstdState { tag: ZstdTag::BlockHeader, tag_next, @@ -741,6 +746,9 @@ fn process_block_zstd_literals_header( Some(*acc) }); + let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; + ( byte_offset + n_bytes_header, lh_bytes @@ -751,7 +759,7 @@ fn process_block_zstd_literals_header( .zip(tag_rlc_iter) .enumerate() .map( - |(i, (((&value_byte, tag_value_acc), value_rlc), tag_rlc_acc))| ZstdWitnessRow { + |(i, (((&value_byte, tag_value_acc), _v_rlc), tag_rlc_acc))| ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockLiteralsHeader, tag_next, @@ -809,14 +817,8 @@ fn process_block_zstd_huffman_code( assert!(header_byte < 128, "FSE encoded huffman weights assumed"); let n_bytes = header_byte as usize; - // Get value_rlc accumulator - let mut value_rlc_iter = src.iter().skip(byte_offset).take(n_bytes + 1).scan( - last_row.encoded_data.value_rlc, - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ); + let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; // Add a witness row for Huffman header let mut huffman_header_row: ZstdWitnessRow = ZstdWitnessRow { @@ -836,7 +838,7 @@ fn process_block_zstd_huffman_code( byte_idx: (byte_offset + 1) as u64, encoded_len, value_byte: header_byte.clone(), - value_rlc: value_rlc_iter.next().expect("Next value should exist"), + value_rlc, reverse: false, ..Default::default() }, @@ -907,7 +909,7 @@ fn process_block_zstd_huffman_code( byte_idx: (byte_offset + idx + 2) as u64, // count the huffman header byte encoded_len, value_byte: byte.clone(), - value_rlc: value_rlc_iter.next().expect("Next value should exist"), + value_rlc, reverse: false, ..Default::default() }, @@ -925,6 +927,11 @@ fn process_block_zstd_huffman_code( ZstdTag::ZstdBlockLstream }; + // Update the last row + let last_row = witness_rows.last().expect("Last row exists"); + let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; + // Bitstream processing state values let n_huffman_code_bytes = n_bytes - n_fse_bytes; let mut last_byte_idx: usize = 1; @@ -1008,7 +1015,7 @@ fn process_block_zstd_huffman_code( byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], - value_rlc: next_value_rlc_acc, + value_rlc, reverse: true, reverse_len: n_huffman_code_bytes as u64, reverse_idx: (n_huffman_code_bytes - (current_byte_idx - 1)) as u64, @@ -1085,7 +1092,7 @@ fn process_block_zstd_huffman_code( byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], - value_rlc: next_value_rlc_acc, + value_rlc, reverse: true, reverse_len: n_huffman_code_bytes as u64, reverse_idx: (n_huffman_code_bytes - (current_byte_idx - 1)) as u64, @@ -1181,6 +1188,9 @@ fn process_block_zstd_huffman_jump_table( Some(*acc) }, ); + let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; + let tag_value_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( Value::known(F::zero()), |acc, &byte| { @@ -1214,7 +1224,7 @@ fn process_block_zstd_huffman_jump_table( .zip(tag_rlc_iter) .enumerate() .map( - |(i, (((&value_byte, tag_value_acc), value_rlc), tag_rlc_acc))| { + |(i, (((&value_byte, tag_value_acc), _v_rlc), tag_rlc_acc))| { ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockJumpTable, @@ -1290,6 +1300,8 @@ fn process_block_zstd_lstream( Some(*acc) }, ); + let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; let mut tag_value_acc = src.iter().skip(byte_offset).take(len).rev().scan( Value::known(F::zero()), @@ -1345,7 +1357,7 @@ fn process_block_zstd_lstream( byte_idx: (byte_offset + current_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - current_byte_idx], - value_rlc: next_value_rlc_acc, + value_rlc, // reverse specific values reverse: true, reverse_len: len as u64, @@ -1436,7 +1448,7 @@ fn process_block_zstd_lstream( byte_idx: (byte_offset + from_byte_idx) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: src[byte_offset + len - from_byte_idx], - value_rlc: next_value_rlc_acc, + value_rlc, // reverse specific values reverse: true, reverse_len: len as u64, From 0f27e61d939688df885261232f2c4fdeff2339a4 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 19:00:24 -0500 Subject: [PATCH 096/165] Correct fcs --- zkevm-circuits/src/decompression_circuit.rs | 6 ++---- zkevm-circuits/src/witness/zstd/mod.rs | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index a3ce183f8b..425f722e82 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -859,8 +859,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), not::expr(meta.query_fixed(q_first, Rotation::cur())), - // compression_debug - // not::expr(meta.query_advice(is_padding, Rotation::cur())), not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), ])) }, @@ -1116,7 +1114,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let fcs_flag1 = meta.query_advice(value_bits[6], Rotation::prev()); let fcs_tag_value = meta.query_advice(tag_gadget.tag_value, Rotation::cur()); let frame_content_size = select::expr( - and::expr([fcs_flag0, not::expr(fcs_flag1)]), + and::expr([not::expr(fcs_flag0), fcs_flag1]), 256.expr() + fcs_tag_value.expr(), fcs_tag_value, ); @@ -1169,7 +1167,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); let block_type_bit1 = meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); - // compression_debug cb.require_zero( "block type cannot be RESERVED, i.e. block_type == 3 not possible", block_type_bit0.expr() * block_type_bit1.expr(), @@ -1182,6 +1179,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear with // block type 00 or 01, i.e. the block_type_bit1 is 0. + // compression_debug // cb.condition(not::expr(block_type_bit1), |cb| { // cb.require_equal( // "Raw/RLE blocks: tag_len == block_len", diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 9178597b7f..8565411665 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -87,8 +87,7 @@ fn process_frame_header( .iter() .fold(0u64, |acc, &byte| acc * 256u64 + (byte as u64)); match fcs_tag_len { - // compression_debug - // 2 => fcs + 256, + 2 => fcs + 256, _ => fcs, } }; From 63260d9e88a8cea64d18c750fe1ed6416aa4349f Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 19:42:26 -0500 Subject: [PATCH 097/165] Correct block header --- zkevm-circuits/src/decompression_circuit.rs | 46 ++++++++++--------- .../src/decompression_circuit/dev.rs | 1 + zkevm-circuits/src/table.rs | 4 -- zkevm-circuits/src/witness/zstd/mod.rs | 30 +++++++----- 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 425f722e82..d88fadcae9 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -123,6 +123,7 @@ pub struct DecompressionCircuitConfig { range256: RangeTable<256>, tag_rom_table: TagRomTable, pow_rand_table: PowOfRandTable, + block_type_rom_table: BlockTypeRomTable, } /// Block level details are specified in these columns. @@ -986,28 +987,28 @@ impl SubCircuitConfig for DecompressionCircuitConfig { debug_assert!(meta.degree() <= 9); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: lookup for tuple (tag, tag_next, max_len, is_output)", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // not::expr(meta.query_advice(is_padding, Rotation::next())), - // ]); - // [ - // meta.query_advice(tag_gadget.tag, Rotation::cur()), - // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - // meta.query_advice(tag_gadget.max_len, Rotation::cur()), - // meta.query_advice(tag_gadget.is_output, Rotation::cur()), - // meta.query_advice(block_gadget.is_block, Rotation::cur()), - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - // ] - // .into_iter() - // .zip(tag_rom_table.table_exprs(meta)) - // .map(|(arg, table)| (condition.expr() * arg, table)) - // .collect() - // }, - // ); + // compression_debug, current_debug + meta.lookup_any( + "DecompressionCircuit: lookup for tuple (tag, tag_next, max_len, is_output)", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + not::expr(meta.query_advice(is_padding, Rotation::next())), + ]); + [ + meta.query_advice(tag_gadget.tag, Rotation::cur()), + meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + meta.query_advice(tag_gadget.max_len, Rotation::cur()), + meta.query_advice(tag_gadget.is_output, Rotation::cur()), + meta.query_advice(block_gadget.is_block, Rotation::cur()), + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + ] + .into_iter() + .zip(tag_rom_table.table_exprs(meta)) + .map(|(arg, table)| (condition.expr() * arg, table)) + .collect() + }, + ); debug_assert!(meta.degree() <= 9); @@ -2868,6 +2869,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { range256, tag_rom_table, pow_rand_table, + block_type_rom_table, } } } diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index 8ef2b9126d..bb5bde10b3 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -84,6 +84,7 @@ impl Circuit for DecompressionCircuit { config.0.range256.load(&mut layouter)?; config.0.tag_rom_table.load(&mut layouter)?; config.0.pow_rand_table.assign(&mut layouter, challenges)?; + config.0.block_type_rom_table.load(&mut layouter)?; self.synthesize_sub(&config.0, challenges, &mut layouter) } } diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index f018617981..9c552fc605 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -3123,8 +3123,6 @@ pub type U16Table = RangeTable<{ 1 << 16 }>; impl RangeTable { /// Construct the range table. pub fn construct(meta: &mut ConstraintSystem) -> Self { - // compression_debug - log::trace!("=> RangeTable construct, MAX: {:?}", MAX); let inner = meta.lookup_table_column(); meta.annotate_lookup_column(inner, || format!("range table [0, {MAX})")); Self(inner) @@ -3132,8 +3130,6 @@ impl RangeTable { /// Assign values to the table. pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - // compression_debug - log::trace!("=> load RangeTable, MAX: {:?}", MAX); layouter.assign_table( || format!("range table [0, {MAX})"), |mut table| { diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 8565411665..e59bee1458 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -280,17 +280,23 @@ fn process_block_header( _ => unreachable!("BlockType::Reserved unexpected"), }; - let tag_value_iter = bh_bytes.iter().scan(Value::known(F::zero()), |acc, &byte| { + let tag_value_iter = bh_bytes.iter().rev().scan(Value::known(F::zero()), |acc, &byte| { *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); Some(*acc) }); let tag_value = tag_value_iter.clone().last().expect("BlockHeader expected"); - let tag_rlc_acc = bh_bytes.iter().scan(Value::known(F::zero()), |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }); - let tag_rlc = tag_rlc_acc.clone().last().expect("Tag RLC expected"); + let tag_rlc_iter = bh_bytes + .iter() + .scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }) + .collect::>>(); + let tag_rlc = *(tag_rlc_iter + .clone() + .last() + .expect("Tag RLC expected")); let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; @@ -304,7 +310,7 @@ fn process_block_header( let acc_start = last_row.encoded_data.aux_1 * randomness.map(|r| r.pow([last_row.encoded_data.reverse_len, 0, 0, 0])) + last_row.encoded_data.aux_2; - let value_rlcs = bh_bytes + let _value_rlcs = bh_bytes .iter() .scan(acc_start, |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); @@ -316,12 +322,12 @@ fn process_block_header( byte_offset + N_BLOCK_HEADER_BYTES, bh_bytes .iter() + .rev() .zip(tag_value_iter) - .zip(value_rlcs.iter()) - .zip(tag_rlc_acc) + .zip(tag_rlc_iter.iter().rev()) .enumerate() .map( - |(i, (((&value_byte, tag_value_acc), _v_rlc), tag_rlc_acc))| ZstdWitnessRow { + |(i, ((&value_byte, tag_value_acc), tag_rlc_acc))| ZstdWitnessRow { state: ZstdState { tag: ZstdTag::BlockHeader, tag_next, @@ -332,13 +338,13 @@ fn process_block_header( tag_value_acc, is_tag_change: i == 0, tag_rlc, - tag_rlc_acc, + tag_rlc_acc: *tag_rlc_acc, }, encoded_data: EncodedData { byte_idx: (byte_offset + i + 1) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte, - reverse: false, + reverse: true, value_rlc, ..Default::default() }, From cc940bc5653477a2bce3bf96356818543224cd4f Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 19:42:48 -0500 Subject: [PATCH 098/165] Correct tag lookup --- zkevm-circuits/src/decompression_circuit.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index d88fadcae9..513d7b1ac3 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -987,7 +987,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { debug_assert!(meta.degree() <= 9); - // compression_debug, current_debug meta.lookup_any( "DecompressionCircuit: lookup for tuple (tag, tag_next, max_len, is_output)", |meta| { From b1b3b883f5d6ad255f5979726523bb0d39e81616 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 19:44:26 -0500 Subject: [PATCH 099/165] Recover constraint --- zkevm-circuits/src/decompression_circuit.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 513d7b1ac3..f1b2418d9e 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1137,7 +1137,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ////////////////////////////////// ZstdTag::BlockHeader /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// - // TODO: Multi-block constraints will be examined after mutli-block test vectors become available // Note: We only verify the 1st row of BlockHeader for tag_value. meta.create_gate("DecompressionCircuit: BlockHeader", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -1155,14 +1154,14 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // // But block header is expressed in the reverse order, which helps us in calculating // the tag_value appropriately. - // cb.require_equal( - // "last block check", - // meta.query_advice(value_bits[7], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), - // meta.query_advice( - // block_gadget.is_last_block, - // Rotation(N_BLOCK_HEADER_BYTES as i32), - // ), - // ); + cb.require_equal( + "last block check", + meta.query_advice(value_bits[7], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), + meta.query_advice( + block_gadget.is_last_block, + Rotation(N_BLOCK_HEADER_BYTES as i32), + ), + ); let block_type_bit0 = meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); let block_type_bit1 = From 980ecd17f9ae0946f6416eefed14de91be3c8dcd Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 19:45:36 -0500 Subject: [PATCH 100/165] Recover constraint --- zkevm-circuits/src/decompression_circuit.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index f1b2418d9e..c30cd1c5e4 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1178,17 +1178,16 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear with // block type 00 or 01, i.e. the block_type_bit1 is 0. - // compression_debug - // cb.condition(not::expr(block_type_bit1), |cb| { - // cb.require_equal( - // "Raw/RLE blocks: tag_len == block_len", - // meta.query_advice(tag_gadget.tag_len, Rotation(N_BLOCK_HEADER_BYTES as i32)), - // meta.query_advice( - // block_gadget.block_len, - // Rotation(N_BLOCK_HEADER_BYTES as i32), - // ), - // ); - // }); + cb.condition(not::expr(block_type_bit1), |cb| { + cb.require_equal( + "Raw/RLE blocks: tag_len == block_len", + meta.query_advice(tag_gadget.tag_len, Rotation(N_BLOCK_HEADER_BYTES as i32)), + meta.query_advice( + block_gadget.block_len, + Rotation(N_BLOCK_HEADER_BYTES as i32), + ), + ); + }); // Validate that for an RLE block: value_byte == decoded_byte. cb.condition(block_type_bit0, |cb| { From 68d1545077912a36e266efabe75b86426cedb220 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 19:46:24 -0500 Subject: [PATCH 101/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index c30cd1c5e4..cfda50c62c 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1204,12 +1204,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // This block is the first block iff the FrameContentSize tag precedes it. However we // assume that the block_idx and block_len will be set to 0 for FrameContentSize as it // is not part of a "block". - // compression_debug - // cb.require_equal( - // "block_idx::prev == block_len::prev", - // meta.query_advice(block_gadget.idx, Rotation::prev()), - // meta.query_advice(block_gadget.block_len, Rotation::prev()), - // ); + cb.require_equal( + "block_idx::prev == block_len::prev", + meta.query_advice(block_gadget.idx, Rotation::prev()), + meta.query_advice(block_gadget.block_len, Rotation::prev()), + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), From b4e7ffde0c6813b95ce1acafc5553511b86204f4 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 19:55:42 -0500 Subject: [PATCH 102/165] Recover constraint --- zkevm-circuits/src/decompression_circuit.rs | 41 ++++++++++----------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index cfda50c62c..0168c5ed33 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1350,27 +1350,26 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // vec![(condition * range_value, range8.into())] // }, // ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: lookup for tuple (block_type, tag_next)", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), - // ]); - // [ - // meta.query_advice(tag_gadget.tag, Rotation::cur()), - // meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), - // meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), - // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - // ] - // .into_iter() - // .zip(block_type_rom_table.table_exprs(meta)) - // .map(|(arg, table)| (condition.expr() * arg, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: lookup for tuple (block_type, tag_next)", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + ]); + [ + meta.query_advice(tag_gadget.tag, Rotation::cur()), + meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), + meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), + meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + ] + .into_iter() + .zip(block_type_rom_table.table_exprs(meta)) + .map(|(arg, table)| (condition.expr() * arg, table)) + .collect() + }, + ); debug_assert!(meta.degree() <= 9); From 6353759948a337331f6d1052d8fabc0918b5c9c5 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 8 Feb 2024 20:10:23 -0500 Subject: [PATCH 103/165] Correct lookup --- zkevm-circuits/src/decompression_circuit.rs | 44 ++++++++++----------- zkevm-circuits/src/table/decompression.rs | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 0168c5ed33..cf8867d4dd 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1350,6 +1350,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // vec![(condition * range_value, range8.into())] // }, // ); + meta.lookup_any( "DecompressionCircuit: lookup for tuple (block_type, tag_next)", |meta| { @@ -1451,28 +1452,27 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: lookup for tuple (zstd_block_type, tag_next)", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - // ]); - // [ - // meta.query_advice(tag_gadget.tag, Rotation::cur()), - // meta.query_advice(value_bits[7], Rotation::cur()), - // meta.query_advice(value_bits[6], Rotation::cur()), - // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - // ] - // .into_iter() - // .zip(block_type_rom_table.table_exprs(meta)) - // .map(|(arg, table)| (condition.expr() * arg, table)) - // .collect() - // }, - // ); + + meta.lookup_any( + "DecompressionCircuit: lookup for tuple (zstd_block_type, tag_next)", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + ]); + [ + meta.query_advice(tag_gadget.tag, Rotation::cur()), + meta.query_advice(value_bits[6], Rotation::cur()), + meta.query_advice(value_bits[7], Rotation::cur()), + meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + ] + .into_iter() + .zip(block_type_rom_table.table_exprs(meta)) + .map(|(arg, table)| (condition.expr() * arg, table)) + .collect() + }, + ); // compression_debug // meta.lookup_any( diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index a3a0f4ef76..7a388a3670 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -1979,7 +1979,7 @@ impl BlockTypeRomTable { ZstdTag::ZstdBlockLiteralsHeader, 1, 0, - ZstdTag::ZstdBlockHuffmanCode, + ZstdTag::ZstdBlockFseCode, ), ] .iter() From 2a8bfe8007c14be639b15aae21b9227090ac1fff Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 00:07:44 -0500 Subject: [PATCH 104/165] Correct witness values --- zkevm-circuits/src/decompression_circuit.rs | 22 ++++++++++----------- zkevm-circuits/src/witness/zstd/mod.rs | 4 +--- zkevm-circuits/src/witness/zstd/util.rs | 2 +- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index cf8867d4dd..6c71bf6cbb 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2799,16 +2799,16 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // if bitstring is byte-aligned. cb.condition(is_byte_aligned, |cb| { // compression_debug - // cb.require_equal( - // "byte-aligned bitstring: bit_index_start", - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - // 0.expr(), - // ); - // cb.require_equal( - // "byte-aligned bitstring: byte_idx", - // meta.query_advice(byte_idx, Rotation::next()), - // meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), - // ); + cb.require_equal( + "byte-aligned bitstring: bit_index_start", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + 0.expr(), + ); + cb.require_equal( + "byte-aligned bitstring: byte_idx", + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), + ); }); // if bitstring is spanned. @@ -2831,7 +2831,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { sum::expr([ // TODO: Verify huffman code assumption?, compression_debug // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), ]), ])) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index e59bee1458..dfb9147720 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1048,7 +1048,6 @@ fn process_block_zstd_huffman_code( // Update accumulator if current_byte_idx > last_byte_idx { next_tag_value_acc = tag_value_iter.next().unwrap(); - next_value_rlc_acc = value_rlc_iter.next().unwrap(); next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); last_byte_idx = current_byte_idx; } @@ -1128,9 +1127,8 @@ fn process_block_zstd_huffman_code( for _ in 0..nb { (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); } - if current_byte_idx > last_byte_idx && current_byte_idx < n_bytes { + if current_byte_idx > last_byte_idx && current_byte_idx <= n_huffman_code_bytes { next_tag_value_acc = tag_value_iter.next().unwrap(); - next_value_rlc_acc = value_rlc_iter.next().unwrap(); next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); last_byte_idx = current_byte_idx; } diff --git a/zkevm-circuits/src/witness/zstd/util.rs b/zkevm-circuits/src/witness/zstd/util.rs index 70a392b5d6..7f5b7b33e3 100644 --- a/zkevm-circuits/src/witness/zstd/util.rs +++ b/zkevm-circuits/src/witness/zstd/util.rs @@ -142,7 +142,7 @@ pub fn increment_idx(current_byte_idx: usize, current_bit_idx: usize) -> (usize, let current_bit_idx = current_bit_idx + 1; let mut current_byte_idx = current_byte_idx; - if current_bit_idx > current_byte_idx * N_BITS_PER_BYTE { + if current_bit_idx >= current_byte_idx * N_BITS_PER_BYTE { current_byte_idx += 1; } From 97cd39e4577889fcfa8f14a3b623d2ed3eadd102 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 00:17:20 -0500 Subject: [PATCH 105/165] Bitstream decoder idx transition fix --- zkevm-circuits/src/decompression_circuit.rs | 45 ++++++++++----------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 6c71bf6cbb..58df8015ce 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2783,22 +2783,20 @@ impl SubCircuitConfig for DecompressionCircuitConfig { and::expr([is_not_last.expr(), bitstream_decoder.is_spanned(meta, None)]); // if bitstring is strictly contained. cb.condition(is_strictly_contained, |cb| { - // compression_debug - // cb.require_equal( - // "strictly contained bitstring: bit_index_start", - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), - // ); - // cb.require_equal( - // "strictly contained bitstring: byte_idx", - // meta.query_advice(byte_idx, Rotation::next()), - // meta.query_advice(byte_idx, Rotation::cur()), - // ); + cb.require_equal( + "strictly contained bitstring: bit_index_start", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), + ); + cb.require_equal( + "strictly contained bitstring: byte_idx", + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(byte_idx, Rotation::cur()), + ); }); // if bitstring is byte-aligned. cb.condition(is_byte_aligned, |cb| { - // compression_debug cb.require_equal( "byte-aligned bitstring: bit_index_start", meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), @@ -2813,21 +2811,22 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // if bitstring is spanned. cb.condition(is_spanned, |cb| { - // compression_debug - // cb.require_equal( - // "spanned bitstring: bit_index_start", - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) - 7.expr(), - // ); - // cb.require_equal( - // "spanned bitstring: byte_idx", - // meta.query_advice(byte_idx, Rotation::next()), - // meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), - // ); + cb.require_equal( + "spanned bitstring: bit_index_start", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) - 7.expr(), + ); + cb.require_equal( + "spanned bitstring: byte_idx", + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), + ); }); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), + // TODO: Modify to prev -> cur? compression_debug + not::expr(meta.query_fixed(q_enable, Rotation::cur())), sum::expr([ // TODO: Verify huffman code assumption?, compression_debug // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), From 83b24d7573e893e7d1856c5463eb4b8424db554d Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 03:52:07 -0500 Subject: [PATCH 106/165] Correct FSE processing --- zkevm-circuits/src/witness/zstd/mod.rs | 63 ++++++++++++++++++++---- zkevm-circuits/src/witness/zstd/types.rs | 14 +++++- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index dfb9147720..e8b93cea14 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -858,7 +858,7 @@ fn process_block_zstd_huffman_code( }; // Recover the FSE table for generating Huffman weights - let (n_fse_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset + 1).expect("Reconstructing FSE table should not fail."); + let (n_fse_bytes, bit_boundaries, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset + 1).expect("Reconstructing FSE table should not fail."); // Witness generation let accuracy_log = (src[byte_offset + 1] & 0b1111) + 5; @@ -885,7 +885,7 @@ fn process_block_zstd_huffman_code( let tag_rlc = tag_rlc_iter .clone() .last() - .expect("Tag value must exist"); + .expect("Tag RLC must exist"); // Backfill missing data on the huffman header row huffman_header_row.state.tag_len = (n_fse_bytes + 1usize) as u64; @@ -895,30 +895,75 @@ fn process_block_zstd_huffman_code( huffman_header_row.state.tag_rlc_acc = tag_rlc_iter.next().expect("Next value expected"); witness_rows.push(huffman_header_row); + // Process bit boundaries into bitstream reader info + let mut to_bit_idx: usize = 0; + let mut to_byte_idx: usize = 1; + let mut from_bit_idx: usize = 0; + let mut from_byte_idx: usize = 0; + let mut last_to_bit_idx: usize = 0; + let mut current_tag_value_acc = tag_value_iter.next().unwrap(); + let mut current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); + let bitstream_rows = bit_boundaries.iter().enumerate().map(|(sym, (bit_idx, value))| { + if last_to_bit_idx > 7 { + current_tag_value_acc = tag_value_iter.next().unwrap(); + current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); + } + + if sym == 0 { + from_bit_idx = 0; + } else { + from_bit_idx = to_bit_idx + 1; + from_byte_idx = to_byte_idx; + } + + if from_bit_idx >= from_byte_idx * N_BITS_PER_BYTE || sym == 0 { + from_byte_idx += 1; + } + + to_bit_idx = *bit_idx as usize - 1; + if to_bit_idx >= from_byte_idx * N_BITS_PER_BYTE { + to_byte_idx += 1; + } + + to_bit_idx = to_bit_idx.rem_euclid(8); + if to_byte_idx > from_byte_idx { + to_bit_idx += 8; + } + + last_to_bit_idx = to_bit_idx; + + (sym as u64, from_byte_idx, from_bit_idx.rem_euclid(8), to_byte_idx, to_bit_idx, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone()) + }) + .collect::, Value)>>(); + // Add witness rows for FSE representation bytes - for (idx, byte) in src.iter().skip(byte_offset + 1).take(n_fse_bytes).enumerate() { + for row in bitstream_rows { witness_rows.push(ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockFseCode, tag_next, max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockFseCode), tag_len: (n_fse_bytes + 1) as u64, - tag_idx: (idx + 2) as u64, // count the huffman header byte + tag_idx: (row.1 + 1) as u64, // count the huffman header byte tag_value: tag_value, - tag_value_acc: tag_value_iter.next().expect("Next value should exist"), + tag_value_acc: row.6, is_tag_change: false, tag_rlc, - tag_rlc_acc: tag_rlc_iter.next().expect("Tag RLC Acc exists"), + tag_rlc_acc: row.7, }, encoded_data: EncodedData { - byte_idx: (byte_offset + idx + 2) as u64, // count the huffman header byte + byte_idx: (byte_offset + row.1 + 1) as u64, // count the huffman header byte encoded_len, - value_byte: byte.clone(), + value_byte: src[byte_offset + row.1], value_rlc, reverse: false, ..Default::default() }, - bitstream_read_data: BitstreamReadRow::default(), + bitstream_read_data: BitstreamReadRow { + bit_start_idx: row.2, + bit_end_idx: row.4, + bit_value: row.5, + }, decoded_data: decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 4a91b1d6a2..f48d990411 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -570,10 +570,11 @@ impl FseAuxiliaryTableData { /// with the reconstructed FSE table. After processing the entire bitstream to reconstruct the /// FSE table, if the read bitstream was not byte aligned, then we discard the 1..8 bits from /// the last byte that we read from. - pub fn reconstruct(src: &[u8], byte_offset: usize) -> std::io::Result<(usize, Self)> { + pub fn reconstruct(src: &[u8], byte_offset: usize) -> std::io::Result<(usize, Vec<(u32, u64)>, Self)> { // construct little-endian bit-reader. let data = src.iter().skip(byte_offset).cloned().collect::>(); let mut reader = BitReader::endian(Cursor::new(&data), LittleEndian); + let mut bit_boundaries: Vec<(u32, u64)> = vec![]; // number of bits read by the bit-reader from the bistream. let mut offset = 0; @@ -582,6 +583,7 @@ impl FseAuxiliaryTableData { offset += 4; reader.read::(offset)? + 5 }; + bit_boundaries.push((offset, accuracy_log as u64)); let table_size = 1 << accuracy_log; let mut sym_to_states = BTreeMap::new(); @@ -639,6 +641,7 @@ impl FseAuxiliaryTableData { // update the total number of bits read so far. offset += n_bits_read; + bit_boundaries.push((offset, value)); // increment symbol. symbol = ((symbol as usize) + 1).into(); @@ -654,8 +657,15 @@ impl FseAuxiliaryTableData { // ignore any bits left to be read until byte-aligned. let t = (((offset as usize) - 1) / N_BITS_PER_BYTE) + 1; + // read the trailing section + if t * N_BITS_PER_BYTE > (offset as usize) { + let bits_remaining = t * N_BITS_PER_BYTE - offset as usize; + bit_boundaries.push((offset + bits_remaining as u32, reader.read::(bits_remaining as u32)? as u64)); + } + Ok(( t, + bit_boundaries, Self { byte_offset: byte_offset as u64, table_size, @@ -727,7 +737,7 @@ mod tests { // sure FSE reconstruction ignores them. let src = vec![0xff, 0xff, 0xff, 0x30, 0x6f, 0x9b, 0x03, 0xff, 0xff, 0xff]; - let (n_bytes, table) = FseAuxiliaryTableData::reconstruct(&src, 3)?; + let (n_bytes, bit_boundaries, table) = FseAuxiliaryTableData::reconstruct(&src, 3)?; // TODO: assert equality for the entire table. // for now only comparing state/baseline/nb for S1, i.e. weight == 1. From eee8af271643179e0e7098185b3c61f8b6e235b5 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 03:53:40 -0500 Subject: [PATCH 107/165] Cover fse section in bitstream transition --- zkevm-circuits/src/decompression_circuit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 58df8015ce..9dbbbcce1b 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2828,8 +2828,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // TODO: Modify to prev -> cur? compression_debug not::expr(meta.query_fixed(q_enable, Rotation::cur())), sum::expr([ - // TODO: Verify huffman code assumption?, compression_debug - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), ]), From a8c0a7809de42dd23f8eb794afdf2643aaabf5da Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 04:00:22 -0500 Subject: [PATCH 108/165] Correct Value RLC --- zkevm-circuits/src/decompression_circuit.rs | 13 ++++++------- zkevm-circuits/src/witness/zstd/mod.rs | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 9dbbbcce1b..856b0934b2 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2921,13 +2921,12 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.encoded_data.encoded_len)), )?; - // compression_debug - // region.assign_advice( - // || "value_rlc", - // self.value_rlc, - // i, - // || row.encoded_data.value_rlc, - // )?; + region.assign_advice( + || "value_rlc", + self.value_rlc, + i, + || row.encoded_data.value_rlc, + )?; // Byte value and bits decomposition region.assign_advice( diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index e8b93cea14..6d4956a289 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -148,7 +148,7 @@ fn process_frame_header( byte_idx: (byte_offset + 1) as u64, encoded_len: last_row.encoded_data.encoded_len, value_byte: *fhd_byte, - value_rlc: fhd_value_rlc, + value_rlc: Value::known(F::zero()), ..Default::default() }, decoded_data: DecodedData { @@ -192,7 +192,7 @@ fn process_frame_header( reverse_len: fcs_tag_len as u64, aux_1: *aux_1, aux_2, - value_rlc: value_rlc_fcs, + value_rlc: fhd_value_rlc, }, decoded_data: DecodedData { decoded_len: fcs, From 07d5846d4dd12a29c61d355996e1fccb191d89ee Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 04:03:54 -0500 Subject: [PATCH 109/165] format --- zkevm-circuits/src/witness/zstd/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index f48d990411..b2334fee9c 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -737,7 +737,7 @@ mod tests { // sure FSE reconstruction ignores them. let src = vec![0xff, 0xff, 0xff, 0x30, 0x6f, 0x9b, 0x03, 0xff, 0xff, 0xff]; - let (n_bytes, bit_boundaries, table) = FseAuxiliaryTableData::reconstruct(&src, 3)?; + let (n_bytes, _bit_boundaries, table) = FseAuxiliaryTableData::reconstruct(&src, 3)?; // TODO: assert equality for the entire table. // for now only comparing state/baseline/nb for S1, i.e. weight == 1. From e9c3a17e5bb134398b0a91f8f5384ffcf9208f2f Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 19:00:49 -0500 Subject: [PATCH 110/165] Add FSE decoding --- zkevm-circuits/src/decompression_circuit.rs | 25 ++++++++--------- zkevm-circuits/src/witness/zstd/mod.rs | 31 +++++++++++++++++---- zkevm-circuits/src/witness/zstd/types.rs | 14 ++++++++-- 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 856b0934b2..4e0ceed79d 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2950,6 +2950,7 @@ impl DecompressionCircuitConfig { )?; } + // Decoded Data region.assign_advice( || "decoded_len", @@ -2976,6 +2977,7 @@ impl DecompressionCircuitConfig { || row.decoded_data.decoded_value_rlc, )?; + // Block Gadget let is_block = !( row.state.tag == ZstdTag::FrameHeaderDescriptor || @@ -3225,21 +3227,17 @@ impl DecompressionCircuitConfig { // FSE Gadget - - // fse_decoder, - // pub struct FseDecoder { - // /// Number of symbols we have emitted. - // num_emitted: Column, - // /// An accumulator that keeps a count of the number of states assigned for each symbol, - // /// including the symbol that is decoded on the current row. - // n_acc: Column, - // } - region.assign_advice( || "fse_decoder.num_emitted", self.fse_decoder.num_emitted, i, - || Value::known(F::one()), + || Value::known(F::from(row.fse_data.num_emitted)), + )?; + region.assign_advice( + || "fse_decoder.n_acc", + self.fse_decoder.n_acc, + i, + || Value::known(F::from(row.fse_data.n_acc)), )?; region.assign_advice( || "fse_decoder.state", @@ -3260,6 +3258,7 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.fse_data.symbol as u64)), )?; + // Lstream Config let is_four_streams: u64 = if aux_data[2] > 0 { 1 } else { 0 }; region.assign_advice( @@ -3347,8 +3346,8 @@ impl SubCircuit for DecompressionCircuit { // compression_debug for row in witness_rows.clone() { - log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};;", - row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, row.bitstream_read_data.bit_start_idx, row.bitstream_read_data.bit_end_idx, row.bitstream_read_data.bit_value + log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};;", + row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, row.fse_data.num_emitted, row.fse_data.n_acc, row.bitstream_read_data.bit_start_idx, row.bitstream_read_data.bit_end_idx, row.bitstream_read_data.bit_value ); } diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 6d4956a289..fd6384885b 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -901,6 +901,8 @@ fn process_block_zstd_huffman_code( let mut from_bit_idx: usize = 0; let mut from_byte_idx: usize = 0; let mut last_to_bit_idx: usize = 0; + let mut num_emitted: usize = 0; + let mut n_acc: usize = 0; let mut current_tag_value_acc = tag_value_iter.next().unwrap(); let mut current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); let bitstream_rows = bit_boundaries.iter().enumerate().map(|(sym, (bit_idx, value))| { @@ -932,9 +934,14 @@ fn process_block_zstd_huffman_code( last_to_bit_idx = to_bit_idx; - (sym as u64, from_byte_idx, from_bit_idx.rem_euclid(8), to_byte_idx, to_bit_idx, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone()) + if sym > 0 { + num_emitted += 1; + n_acc += *value as usize; + } + + (sym as u64, from_byte_idx, from_bit_idx.rem_euclid(8), to_byte_idx, to_bit_idx, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone(), num_emitted, n_acc) }) - .collect::, Value)>>(); + .collect::, Value, usize, usize)>>(); // Add witness rows for FSE representation bytes for row in bitstream_rows { @@ -966,7 +973,19 @@ fn process_block_zstd_huffman_code( }, decoded_data: decoded_data.clone(), huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), + fse_data: if row.0 > 0 && row.9 <= (2 << accuracy_log) { + FseTableRow { + idx: 0, + state: 0, + symbol: 0, + baseline: 0, + num_bits: 0, + num_emitted: row.0, + n_acc: row.9 as u64, + } + } else { + FseTableRow::default() + }, }); } @@ -1036,7 +1055,7 @@ fn process_block_zstd_huffman_code( let mut tag_rlc_iter = tag_rlc_iter.collect::>>().into_iter().rev(); let mut next_tag_value_acc = tag_value_iter.next().unwrap(); - let mut next_value_rlc_acc = value_rlc_iter.next().unwrap(); + let next_value_rlc_acc = value_rlc_iter.next().unwrap(); let mut next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); let aux_1 = next_value_rlc_acc.clone(); @@ -1159,7 +1178,9 @@ fn process_block_zstd_huffman_code( state: next_state as u64, symbol: fse_row.0, baseline: fse_row.1, - num_bits: fse_row.2, + num_bits: fse_row.2, + num_emitted: 0, + n_acc: 0, }, huffman_data: HuffmanData::default(), decoded_data: decoded_data.clone(), diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index b2334fee9c..a85eeb7ddb 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -517,6 +517,10 @@ pub struct FseTableRow { pub num_bits: u64, /// The symbol emitted by the FSE table at this state. pub symbol: u64, + /// During FSE table decoding, keep track of the number of symbol emitted + pub num_emitted: u64, + /// During FSE table decoding, keep track of accumulated states assigned + pub n_acc: u64, } // Used for tracking bit markers for non-byte-aligned bitstream decoding @@ -583,7 +587,7 @@ impl FseAuxiliaryTableData { offset += 4; reader.read::(offset)? + 5 }; - bit_boundaries.push((offset, accuracy_log as u64)); + bit_boundaries.push((offset, accuracy_log as u64 - 1)); let table_size = 1 << accuracy_log; let mut sym_to_states = BTreeMap::new(); @@ -634,6 +638,8 @@ impl FseAuxiliaryTableData { num_bits: nb, baseline, symbol: symbol.into(), + num_emitted: 0, + n_acc: 0, }) .collect(), ); @@ -641,7 +647,7 @@ impl FseAuxiliaryTableData { // update the total number of bits read so far. offset += n_bits_read; - bit_boundaries.push((offset, value)); + bit_boundaries.push((offset, value - 1)); // increment symbol. symbol = ((symbol as usize) + 1).into(); @@ -660,7 +666,7 @@ impl FseAuxiliaryTableData { // read the trailing section if t * N_BITS_PER_BYTE > (offset as usize) { let bits_remaining = t * N_BITS_PER_BYTE - offset as usize; - bit_boundaries.push((offset + bits_remaining as u32, reader.read::(bits_remaining as u32)? as u64)); + bit_boundaries.push((offset + bits_remaining as u32, reader.read::(bits_remaining as u32)? as u64 - 1)); } Ok(( @@ -761,6 +767,8 @@ mod tests { symbol: 1, baseline, num_bits, + num_emitted: 0, + n_acc: 0, }) .collect::>(), ); From bafd6961a1fa5bdcd0765beb71794a36736a286c Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 19:44:05 -0500 Subject: [PATCH 111/165] Add more assignments --- zkevm-circuits/src/decompression_circuit.rs | 63 ++++++++++++++----- .../src/decompression_circuit/dev.rs | 1 + zkevm-circuits/src/witness/zstd/mod.rs | 53 ++++++++++------ 3 files changed, 81 insertions(+), 36 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 4e0ceed79d..bf604cd2eb 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -124,6 +124,7 @@ pub struct DecompressionCircuitConfig { tag_rom_table: TagRomTable, pow_rand_table: PowOfRandTable, block_type_rom_table: BlockTypeRomTable, + pow2_table: Pow2Table, } /// Block level details are specified in these columns. @@ -2863,6 +2864,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { tag_rom_table, pow_rand_table, block_type_rom_table, + pow2_table, } } } @@ -2950,7 +2952,7 @@ impl DecompressionCircuitConfig { )?; } - + // Decoded Data region.assign_advice( || "decoded_len", @@ -3166,7 +3168,12 @@ impl DecompressionCircuitConfig { || Value::known(F::from(is_huffman_tree_section)), )?; + + // compression_debug + // [2024-02-12T00:28:43Z TRACE zkevm_circuits::decompression_circuit] => aux_data: [85, 87, 81, 82, 551, 377, 14, 64, 5, 31] + log::trace!("=> aux_data: {:?}", aux_data); + // Literals Header // struct LiteralsHeaderDecomposition { // /// The branch we take while decomposing the Literals Header. We compare this value against the @@ -3175,26 +3182,50 @@ impl DecompressionCircuitConfig { // /// A helper column to mark whether the size format (sf) for Literals Header is 0b_11. We need // /// this column to keep the circuit degree in check. // sf_max: Column, - // /// The regenerated size decoded from the Literals Header. - // regen_size: Column, - // /// The compressed size decoded from the Literals Header. - // compr_size: Column, // } + region.assign_advice( + || "literals_header.regen_size", + self.literals_header.regen_size, + i, + || Value::known(F::from(aux_data[4])), + )?; + region.assign_advice( + || "literals_header.compr_size", + self.literals_header.compr_size, + i, + || Value::known(F::from(aux_data[5])), + )?; - // Huffman Tree Config - // struct HuffmanConfig { - // /// Column to save the byte offset at which the huffman header is described. - // huffman_tree_idx: Column, - // /// The table size of the FSE table. - // fse_table_size: Column, - // /// The accuracy log of the FSE table. - // fse_table_al: Column, - // /// The number of bytes used to specify canonical huffman code representation. - // huffman_code_len: Column, - // } + // Huffman Tree Config + region.assign_advice( + || "huffman_tree_config.huffman_tree_idx", + self.huffman_tree_config.huffman_tree_idx, + i, + || Value::known(F::from(aux_data[6])), + )?; + region.assign_advice( + || "huffman_tree_config.fse_table_size", + self.huffman_tree_config.fse_table_size, + i, + || Value::known(F::from(aux_data[7])), + )?; + region.assign_advice( + || "huffman_tree_config.fse_table_al", + self.huffman_tree_config.fse_table_al, + i, + || Value::known(F::from(aux_data[8])), + )?; + region.assign_advice( + || "huffman_tree_config.huffman_code_len", + self.huffman_tree_config.huffman_code_len, + i, + || Value::known(F::from(aux_data[9])), + )?; + + // Bitstream Decoder region.assign_advice( || "bitstream_decoder.bit_index_start", diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index bb5bde10b3..74b520336b 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -85,6 +85,7 @@ impl Circuit for DecompressionCircuit { config.0.tag_rom_table.load(&mut layouter)?; config.0.pow_rand_table.assign(&mut layouter, challenges)?; config.0.block_type_rom_table.load(&mut layouter)?; + config.0.pow2_table.load(&mut layouter)?; self.synthesize_sub(&config.0, challenges, &mut layouter) } } diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index fd6384885b..7e63fdf201 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -216,7 +216,7 @@ fn process_block( byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>, bool, Vec, Vec) { +) -> (usize, Vec>, bool, Vec, Vec, Vec) { let mut witness_rows = vec![]; let (byte_offset, rows, last_block, block_type, block_size) = @@ -224,7 +224,7 @@ fn process_block( witness_rows.extend_from_slice(&rows); let last_row = rows.last().expect("last row expected to exist"); - let (_byte_offset, rows, literals, lstream_len) = match block_type { + let (_byte_offset, rows, literals, lstream_len, aux_data) = match block_type { BlockType::RawBlock => process_block_raw( src, byte_offset, @@ -253,7 +253,7 @@ fn process_block( }; witness_rows.extend_from_slice(&rows); - (byte_offset, witness_rows, last_block, literals, lstream_len) + (byte_offset, witness_rows, last_block, literals, lstream_len, aux_data) } fn process_block_header( @@ -515,7 +515,7 @@ fn process_block_raw( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec) { +) -> (usize, Vec>, Vec, Vec, Vec) { let tag_next = if last_block { ZstdTag::Null } else { @@ -532,7 +532,7 @@ fn process_block_raw( tag_next, ); - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0]) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0]) } fn process_block_rle( @@ -542,7 +542,7 @@ fn process_block_rle( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec) { +) -> (usize, Vec>, Vec, Vec, Vec) { let tag_next = if last_block { ZstdTag::Null } else { @@ -559,7 +559,7 @@ fn process_block_rle( tag_next, ); - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0]) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0]) } #[allow(unused_variables)] @@ -570,7 +570,7 @@ fn process_block_zstd( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec) { +) -> (usize, Vec>, Vec, Vec, Vec) { let mut witness_rows = vec![]; // 1-5 bytes LiteralSectionHeader @@ -590,7 +590,7 @@ fn process_block_zstd( witness_rows.extend_from_slice(&rows); // Depending on the literals block type, decode literals section accordingly - let (bytes_offset, rows, literals, lstream_len): (usize, Vec>, Vec, Vec) = match literals_block_type { + let (bytes_offset, rows, literals, lstream_len, aux_data): (usize, Vec>, Vec, Vec, Vec) = match literals_block_type { BlockType::RawBlock => { let (byte_offset, rows) = process_raw_bytes( src, @@ -602,7 +602,7 @@ fn process_block_zstd( ZstdTag::ZstdBlockSequenceHeader, ); - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0]) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0]) }, BlockType::RleBlock => { let (byte_offset, rows) = process_rle_bytes( @@ -615,12 +615,12 @@ fn process_block_zstd( ZstdTag::ZstdBlockSequenceHeader, ); - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0]) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0]) }, BlockType::ZstdCompressedBlock => { let mut huffman_rows = vec![]; - let (bytes_offset, rows, huffman_codes, n_huffman_bytes, huffman_byte_offset, last_rlc) = process_block_zstd_huffman_code( + let (bytes_offset, rows, huffman_codes, n_huffman_bytes, huffman_byte_offset, last_rlc, huffman_idx, fse_size, fse_accuracy, n_huffman_bitstream_bytes) = process_block_zstd_huffman_code( src, byte_offset, rows.last().expect("last row must exist"), @@ -669,13 +669,13 @@ fn process_block_zstd( stream_offset = byte_offset; } - (stream_offset, huffman_rows, literals, lstream_lens) + (stream_offset, huffman_rows, literals, lstream_lens, vec![huffman_idx as u64, fse_size, fse_accuracy, n_huffman_bitstream_bytes]) }, _ => unreachable!("Invalid literals section BlockType") }; witness_rows.extend_from_slice(&rows); - (bytes_offset, witness_rows, literals, lstream_len) + (bytes_offset, witness_rows, literals, lstream_len, vec![regen_size as u64, compressed_size as u64, aux_data[0], aux_data[1], aux_data[2], aux_data[3]]) } fn process_block_zstd_literals_header( @@ -805,7 +805,7 @@ fn process_block_zstd_huffman_code( last_row: &ZstdWitnessRow, randomness: Value, n_streams: usize, -) -> (usize, Vec>, HuffmanCodesData, usize, usize, Value) { +) -> (usize, Vec>, HuffmanCodesData, usize, usize, Value, usize, u64, u64, u64) { // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; @@ -973,7 +973,7 @@ fn process_block_zstd_huffman_code( }, decoded_data: decoded_data.clone(), huffman_data: HuffmanData::default(), - fse_data: if row.0 > 0 && row.9 <= (2 << accuracy_log) { + fse_data: if row.0 > 0 && row.9 <= (1 << accuracy_log) { FseTableRow { idx: 0, state: 0, @@ -1218,7 +1218,19 @@ fn process_block_zstd_huffman_code( }); let new_value_rlc_init_value = aux_2 * mul + aux_1; - (byte_offset + 1 + n_fse_bytes + n_huffman_code_bytes, witness_rows, huffman_codes, n_bytes, huffman_code_byte_offset + 1, new_value_rlc_init_value) + ( + byte_offset + 1 + n_fse_bytes + n_huffman_code_bytes, + witness_rows, + huffman_codes, + n_bytes, + huffman_code_byte_offset + 1, + new_value_rlc_init_value, + + byte_offset + 1 + n_fse_bytes, + (1 << accuracy_log) as u64, + accuracy_log as u64, + n_huffman_code_bytes as u64, + ) } fn process_block_zstd_huffman_jump_table( @@ -1592,7 +1604,7 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec( + let (_byte_offset, rows, last_block, new_literals, lstream_lens, pipeline_data) = process_block::( src, byte_offset, rows.last().expect("last row expected to exist"), @@ -1600,7 +1612,8 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec( &input, 0, From cc45995fe093db2b55dbae5591792a4166c12c91 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 20:08:30 -0500 Subject: [PATCH 112/165] Complete witness fix --- zkevm-circuits/src/decompression_circuit.rs | 33 +++++++++++---------- zkevm-circuits/src/witness/zstd/mod.rs | 25 +++++++++------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index bf604cd2eb..ea5b1a3efe 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -3168,21 +3168,26 @@ impl DecompressionCircuitConfig { || Value::known(F::from(is_huffman_tree_section)), )?; - - // compression_debug - // [2024-02-12T00:28:43Z TRACE zkevm_circuits::decompression_circuit] => aux_data: [85, 87, 81, 82, 551, 377, 14, 64, 5, 31] - log::trace!("=> aux_data: {:?}", aux_data); - // Literals Header - // struct LiteralsHeaderDecomposition { - // /// The branch we take while decomposing the Literals Header. We compare this value against the - // /// Read-only memory table for Literals Header. - // branch: Column, - // /// A helper column to mark whether the size format (sf) for Literals Header is 0b_11. We need - // /// this column to keep the circuit degree in check. - // sf_max: Column, - // } + region.assign_advice( + || "literals_header.branch", + self.literals_header.branch, + i, + || Value::known(F::from(aux_data[10])), + )?; + region.assign_advice( + || "literals_header.sf_max", + self.literals_header.sf_max, + i, + || Value::known(F::from(aux_data[11])), + )?; + region.assign_advice( + || "literals_header.regen_size", + self.literals_header.regen_size, + i, + || Value::known(F::from(aux_data[4])), + )?; region.assign_advice( || "literals_header.regen_size", self.literals_header.regen_size, @@ -3196,9 +3201,7 @@ impl DecompressionCircuitConfig { || Value::known(F::from(aux_data[5])), )?; - - // Huffman Tree Config region.assign_advice( || "huffman_tree_config.huffman_tree_idx", diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 7e63fdf201..38b99ff457 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -580,7 +580,8 @@ fn process_block_zstd( literals_block_type, n_streams, regen_size, - compressed_size + compressed_size, + (branch, sf_max), ) = process_block_zstd_literals_header::( src, byte_offset, @@ -675,7 +676,7 @@ fn process_block_zstd( }; witness_rows.extend_from_slice(&rows); - (bytes_offset, witness_rows, literals, lstream_len, vec![regen_size as u64, compressed_size as u64, aux_data[0], aux_data[1], aux_data[2], aux_data[3]]) + (bytes_offset, witness_rows, literals, lstream_len, vec![regen_size as u64, compressed_size as u64, aux_data[0], aux_data[1], aux_data[2], aux_data[3], branch, sf_max as u64]) } fn process_block_zstd_literals_header( @@ -683,7 +684,7 @@ fn process_block_zstd_literals_header( byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>, BlockType, usize, usize, usize) { +) -> (usize, Vec>, BlockType, usize, usize, usize, (u64, bool)) { let lh_bytes = src .iter() .skip(byte_offset) @@ -693,22 +694,23 @@ fn process_block_zstd_literals_header( let literals_block_type = BlockType::from(lh_bytes[0] & 0x3); let size_format = (lh_bytes[0] >> 2) & 3; + let sf_max = size_format == 3; - let [n_bits_fmt, n_bits_regen, n_bits_compressed, n_streams, n_bytes_header]: [usize; 5] = match literals_block_type { + let [n_bits_fmt, n_bits_regen, n_bits_compressed, n_streams, n_bytes_header, branch]: [usize; 6] = match literals_block_type { BlockType::RawBlock | BlockType::RleBlock => { match size_format { - 0b00 | 0b10 => [1, 5, 0, 1, 1], - 0b01 => [2, 12, 0, 1, 2], - 0b11 => [2, 20, 0, 1, 3], + 0b00 | 0b10 => [1, 5, 0, 1, 1, 0], + 0b01 => [2, 12, 0, 1, 2, 1], + 0b11 => [2, 20, 0, 1, 3, 2], _ => unreachable!("size_format out of bound") } }, BlockType::ZstdCompressedBlock => { match size_format { - 0b00 => [2, 10, 10, 1, 3], - 0b01 => [2, 10, 10, 4, 3], - 0b10 => [2, 14, 14, 4, 4], - 0b11 => [2, 18, 18, 4, 5], + 0b00 => [2, 10, 10, 1, 3, 3], + 0b01 => [2, 10, 10, 4, 3, 4], + 0b10 => [2, 14, 14, 4, 4, 5], + 0b11 => [2, 18, 18, 4, 5, 6], _ => unreachable!("size_format out of bound") } }, @@ -796,6 +798,7 @@ fn process_block_zstd_literals_header( n_streams, regen_size as usize, compressed_size as usize, + (branch as u64, sf_max), ) } From 8a05d09ec88152bfa7669402f63bb24d0a16fe9d Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 20:30:41 -0500 Subject: [PATCH 113/165] Correct size calculation --- zkevm-circuits/src/decompression_circuit.rs | 23 +++++++++++---------- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index ea5b1a3efe..062b9608ff 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2402,16 +2402,17 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - HuffmanTreeDescriptionSize == byte_idx(JumpTable) - byte_idx(HuffmanTree) // TODO: incorrect size? compression_debug - // cb.require_equal( - // "length of lstream4", - // meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) - // + len1 - // + len2 - // + len3 - // + meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(literals_header.compr_size, Rotation::cur()) - // + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // ); + cb.require_equal( + "length of lstream4", + meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) + + len1 + + len2 + + len3 + + meta.query_advice(byte_idx, Rotation::cur()) + + 6.expr(), // TODO: need to add the 6 bytes for jump table + meta.query_advice(literals_header.compr_size, Rotation::cur()) + + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + ); for col in [ lstream_config.len_lstream1, @@ -3201,7 +3202,7 @@ impl DecompressionCircuitConfig { || Value::known(F::from(aux_data[5])), )?; - + // Huffman Tree Config region.assign_advice( || "huffman_tree_config.huffman_tree_idx", diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 38b99ff457..eb94ae97bb 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1229,7 +1229,7 @@ fn process_block_zstd_huffman_code( huffman_code_byte_offset + 1, new_value_rlc_init_value, - byte_offset + 1 + n_fse_bytes, + byte_offset + 1, (1 << accuracy_log) as u64, accuracy_log as u64, n_huffman_code_bytes as u64, From eb2ed1dc8ebea1f540855be303a065b1e7e371cb Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 20:54:29 -0500 Subject: [PATCH 114/165] Correct bit boundary assignment --- zkevm-circuits/src/decompression_circuit.rs | 291 ++++++++++---------- 1 file changed, 151 insertions(+), 140 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 062b9608ff..51801b65a3 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1906,73 +1906,76 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // }, // ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - 1.expr(), // bitstring len acc - start, // bit index start - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", + // |meta| { + // let (huffman_byte_offset, start, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // bitstream_decoder.is_spanned(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // 1.expr(), // bitstring len acc + // start, // bit index start + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", + // |meta| { + // let (huffman_byte_offset, start, end, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // bitstream_decoder.is_spanned(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); // compression_debug // meta.lookup_any( @@ -2106,10 +2109,12 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // Check for state transition, except if we are on the last row of HuffmanCode. let is_last_row = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); - let baseline = meta.query_advice(fse_decoder.baseline, Rotation::cur()); // baseline at state + // TODO: correct baseline targeting, compression_debug + // let baseline = meta.query_advice(fse_decoder.baseline, Rotation::cur()); // baseline at state + let baseline = meta.query_advice(fse_decoder.baseline, Rotation(-2)); // baseline at state let bit_value = meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()); // bits read - // compression_debug + // TODO: Correct FSE transition, compression_debug // cb.condition(not::expr(is_last_row), |cb| { // cb.require_equal( // "state' == baseline(state) + bit_value", @@ -2117,8 +2122,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // baseline + bit_value, // ); // }); - - cb.require_zero("", 0.expr()); + cb.require_equal( + "state' == baseline(state) + bit_value (every other row)", + meta.query_advice(fse_decoder.state, Rotation::cur()), + baseline + bit_value, + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -2194,71 +2202,74 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // }, // ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - 1.expr(), // bitstring len acc - start, // bit index start - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstring end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", + // |meta| { + // let (huffman_byte_offset, start, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // bitstream_decoder.is_spanned(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // 1.expr(), // bitstring len acc + // start, // bit index start + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); + + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstring end)", + // |meta| { + // let (huffman_byte_offset, start, end, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // bitstream_decoder.is_spanned(meta, None), + // ]); + // [ + // huffman_byte_offset, // huffman ID + // meta.query_advice(byte_idx, Rotation::cur()), // byte index + // meta.query_advice(byte_idx, Rotation::next()), // byte index' + // meta.query_advice(value_byte, Rotation::cur()), // byte value + // meta.query_advice(value_byte, Rotation::next()), // byte value' + // bit_value, // bitstring value + // end.expr() - start + 1.expr(), // bitstring length + // end, // bit index at end + // 1.expr(), // from start + // 1.expr(), // to end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs_spanned(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); // 1. We first read AL number of bits from the bitstream (say bit_value_init) and transition // to the state == bit_value_init. @@ -3235,23 +3246,23 @@ impl DecompressionCircuitConfig { || "bitstream_decoder.bit_index_start", self.bitstream_decoder.bit_index_start, i, - || Value::known(F::from(row.huffman_data.k.0 as u64)), + || Value::known(F::from(row.bitstream_read_data.bit_start_idx as u64)), )?; region.assign_advice( || "bitstream_decoder.bit_index_end", self.bitstream_decoder.bit_index_end, i, - || Value::known(F::from(row.huffman_data.k.1 as u64)), + || Value::known(F::from(row.bitstream_read_data.bit_end_idx as u64)), )?; region.assign_advice( || "bitstream_decoder.bit_value", self.bitstream_decoder.bit_value, i, - || Value::known(F::from(row.huffman_data.bit_value as u64)), + || Value::known(F::from(row.bitstream_read_data.bit_value as u64)), )?; let bitstring_contained_chip = ComparatorChip::construct(self.bitstream_decoder.bitstring_contained.clone()); - bitstring_contained_chip.assign(&mut region, i, F::from(row.huffman_data.k.1 as u64), F::from(7u64))?; + bitstring_contained_chip.assign(&mut region, i, F::from(row.bitstream_read_data.bit_end_idx as u64), F::from(7u64))?; region.assign_advice( || "bitstream_decoder.decoded_symbol", From 95af817f3aec52f4500ff06299a876a9d9432618 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 21:06:32 -0500 Subject: [PATCH 115/165] Correct FSE counting --- zkevm-circuits/src/decompression_circuit.rs | 48 ++++++++++++--------- zkevm-circuits/src/witness/zstd/mod.rs | 9 ++-- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 51801b65a3..dc943a1bf7 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2055,27 +2055,35 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // the bitstream to find the initial state in the FSE table. // - Only from the third row onwards, do we start emitting symbols (weights). + // TODO: Discuss starting condition. Perhaps it makes more sense to count the first symbol emitted on row 2? // compression_debug // cb.require_zero( // "num_emitted starts at 0 from the second row", // meta.query_advice(fse_decoder.num_emitted, Rotation::next()), // ); + cb.require_equal( + "num_emitted starts at 1 from the second row", + meta.query_advice(fse_decoder.num_emitted, Rotation::next()), + 1.expr(), + ); - // // On the second row we read AL number of bits. - // cb.require_equal( - // "AL number of bits read on the second row", - // meta.query_advice(huffman_tree_config.fse_table_al, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()) - // - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()) - // + 1.expr(), - // ); - // // Whatever bitstring we read, is also the initial state in the FSE table, where we - // // start applying the FSE table. - // cb.require_equal( - // "init state of FSE table", - // meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), - // meta.query_advice(fse_decoder.state, Rotation(2)), - // ); + // On the second row we read AL number of bits. + cb.require_equal( + "AL number of bits read on the second row", + meta.query_advice(huffman_tree_config.fse_table_al, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()) + - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()) + + 1.expr(), + ); + // Whatever bitstring we read, is also the initial state in the FSE table, where we + // start applying the FSE table. + // TODO: Correct init condition? Whatever bitstring is read on the next row is the initial state, compression_debug + cb.require_equal( + "init state of FSE table", + meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), + // meta.query_advice(fse_decoder.state, Rotation(2)), + meta.query_advice(fse_decoder.state, Rotation::next()), + ); let lstream_kind = meta.query_advice(lstream_config.lstream_kind, Rotation::cur()); cb.require_equal( @@ -2101,11 +2109,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let mut cb = BaseConstraintBuilder::default(); // compression_debug - // cb.require_equal( - // "num_emitted increments", - // meta.query_advice(fse_decoder.num_emitted, Rotation::cur()), - // meta.query_advice(fse_decoder.num_emitted, Rotation::prev()) + 1.expr(), - // ); + cb.require_equal( + "num_emitted increments", + meta.query_advice(fse_decoder.num_emitted, Rotation::cur()), + meta.query_advice(fse_decoder.num_emitted, Rotation::prev()) + 1.expr(), + ); // Check for state transition, except if we are on the last row of HuffmanCode. let is_last_row = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index eb94ae97bb..53a76ccb78 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -904,7 +904,6 @@ fn process_block_zstd_huffman_code( let mut from_bit_idx: usize = 0; let mut from_byte_idx: usize = 0; let mut last_to_bit_idx: usize = 0; - let mut num_emitted: usize = 0; let mut n_acc: usize = 0; let mut current_tag_value_acc = tag_value_iter.next().unwrap(); let mut current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); @@ -938,11 +937,11 @@ fn process_block_zstd_huffman_code( last_to_bit_idx = to_bit_idx; if sym > 0 { - num_emitted += 1; + // num_emitted += 1; n_acc += *value as usize; } - (sym as u64, from_byte_idx, from_bit_idx.rem_euclid(8), to_byte_idx, to_bit_idx, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone(), num_emitted, n_acc) + (sym as u64, from_byte_idx, from_bit_idx.rem_euclid(8), to_byte_idx, to_bit_idx, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone(), 0, n_acc) }) .collect::, Value, usize, usize)>>(); @@ -1005,6 +1004,7 @@ fn process_block_zstd_huffman_code( let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; // Bitstream processing state values + let mut num_emitted: usize = 0; let n_huffman_code_bytes = n_bytes - n_fse_bytes; let mut last_byte_idx: usize = 1; let mut current_byte_idx: usize = 1; // byte_idx is 1-indexed @@ -1144,6 +1144,7 @@ fn process_block_zstd_huffman_code( // Decode the symbol decoded_weights.push(fse_row.0 as u8); + num_emitted += 1; // Add a witness row witness_rows.push(ZstdWitnessRow { @@ -1182,7 +1183,7 @@ fn process_block_zstd_huffman_code( symbol: fse_row.0, baseline: fse_row.1, num_bits: fse_row.2, - num_emitted: 0, + num_emitted: num_emitted as u64, n_acc: 0, }, huffman_data: HuffmanData::default(), From 019d515df649dd02d708aac002147c404bbb7a68 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 21:41:40 -0500 Subject: [PATCH 116/165] Correct FSE transition --- zkevm-circuits/src/decompression_circuit.rs | 82 +++++++++++---------- zkevm-circuits/src/witness/zstd/mod.rs | 38 +++++----- 2 files changed, 65 insertions(+), 55 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index dc943a1bf7..177d05ae33 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1801,43 +1801,50 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); // compression_debug - // meta.create_gate( - // "DecompressionCircuit: ZstdBlockFseCode (fse code)", - // |meta| { - // let mut cb = BaseConstraintBuilder::default(); + meta.create_gate( + "DecompressionCircuit: ZstdBlockFseCode (fse code)", + |meta| { + let mut cb = BaseConstraintBuilder::default(); - // // The decoded symbol keeps incrementing in the FSE code reconstruction. Since - // // we've already done the check for the first symbol in the huffman header gate, we - // // only check for increments. - // cb.require_equal( - // "fse table reconstruction: decoded symbol increments", - // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), - // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::prev()) - // + 1.expr(), - // ); - // cb.require_equal( - // "number of states assigned so far is accumulated correctly", - // meta.query_advice(fse_decoder.n_acc, Rotation::cur()) + 1.expr(), - // meta.query_advice(fse_decoder.n_acc, Rotation::prev()) - // + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); + // The decoded symbol keeps incrementing in the FSE code reconstruction. Since + // we've already done the check for the first symbol in the huffman header gate, we + // only check for increments. + let is_last = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); - // let is_last = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); - // cb.condition(is_last, |cb| { - // cb.require_equal( - // "on the last row, accumulated number of symbols is the table size of FSE table", - // meta.query_advice(fse_decoder.n_acc, Rotation::cur()), - // meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), - // ); - // }); + // TODO: Verify that the last row is excluded for trailing bits? + cb.condition(not::expr(is_last.clone()), |cb| { + cb.require_equal( + "fse table reconstruction: decoded symbol increments", + meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), + meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::prev()) + + 1.expr(), + ); + cb.require_equal( + "number of states assigned so far is accumulated correctly", + // TODO: why is there an extra +1 here?.. + // meta.query_advice(fse_decoder.n_acc, Rotation::cur()) + 1.expr(), + meta.query_advice(fse_decoder.n_acc, Rotation::cur()), + meta.query_advice(fse_decoder.n_acc, Rotation::prev()) + + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + }); + cb.condition(is_last, |cb| { + cb.require_equal( + "on the last row, accumulated number of symbols is the table size of FSE table", + meta.query_advice(fse_decoder.n_acc, Rotation::cur()), + meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), + ); + }); - // cb.gate(and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // ])) - // }, - // ); + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // TODO: Verify that the second witness row in FSE is also skipped. + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), + ])) + }, + ); // compression_debug // meta.lookup_any( @@ -2056,7 +2063,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - Only from the third row onwards, do we start emitting symbols (weights). // TODO: Discuss starting condition. Perhaps it makes more sense to count the first symbol emitted on row 2? - // compression_debug // cb.require_zero( // "num_emitted starts at 0 from the second row", // meta.query_advice(fse_decoder.num_emitted, Rotation::next()), @@ -2077,7 +2083,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); // Whatever bitstring we read, is also the initial state in the FSE table, where we // start applying the FSE table. - // TODO: Correct init condition? Whatever bitstring is read on the next row is the initial state, compression_debug + // TODO: Correct init condition? Whatever bitstring is read on the next row is the initial state cb.require_equal( "init state of FSE table", meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), @@ -2117,12 +2123,12 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // Check for state transition, except if we are on the last row of HuffmanCode. let is_last_row = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); - // TODO: correct baseline targeting, compression_debug + // TODO: correct baseline targeting? // let baseline = meta.query_advice(fse_decoder.baseline, Rotation::cur()); // baseline at state let baseline = meta.query_advice(fse_decoder.baseline, Rotation(-2)); // baseline at state let bit_value = meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()); // bits read - // TODO: Correct FSE transition, compression_debug + // TODO: Correct FSE transition? // cb.condition(not::expr(is_last_row), |cb| { // cb.require_equal( // "state' == baseline(state) + bit_value", diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 53a76ccb78..b77030267a 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -904,6 +904,7 @@ fn process_block_zstd_huffman_code( let mut from_bit_idx: usize = 0; let mut from_byte_idx: usize = 0; let mut last_to_bit_idx: usize = 0; + let mut decoded: u8 = 0; let mut n_acc: usize = 0; let mut current_tag_value_acc = tag_value_iter.next().unwrap(); let mut current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); @@ -936,14 +937,15 @@ fn process_block_zstd_huffman_code( last_to_bit_idx = to_bit_idx; - if sym > 0 { + if sym > 0 && n_acc < (1 << accuracy_log) { // num_emitted += 1; + decoded = sym as u8; n_acc += *value as usize; } - (sym as u64, from_byte_idx, from_bit_idx.rem_euclid(8), to_byte_idx, to_bit_idx, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone(), 0, n_acc) + (decoded, from_byte_idx, from_bit_idx.rem_euclid(8), to_byte_idx, to_bit_idx, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone(), 0, n_acc) }) - .collect::, Value, usize, usize)>>(); + .collect::, Value, usize, usize)>>(); // Add witness rows for FSE representation bytes for row in bitstream_rows { @@ -973,21 +975,23 @@ fn process_block_zstd_huffman_code( bit_end_idx: row.4, bit_value: row.5, }, - decoded_data: decoded_data.clone(), - huffman_data: HuffmanData::default(), - fse_data: if row.0 > 0 && row.9 <= (1 << accuracy_log) { - FseTableRow { - idx: 0, - state: 0, - symbol: 0, - baseline: 0, - num_bits: 0, - num_emitted: row.0, - n_acc: row.9 as u64, - } - } else { - FseTableRow::default() + decoded_data: DecodedData { + decoded_len: last_row.decoded_data.decoded_len, + decoded_len_acc: last_row.decoded_data.decoded_len_acc, + total_decoded_len: last_row.decoded_data.total_decoded_len, + decoded_byte: row.0, + decoded_value_rlc: last_row.decoded_data.decoded_value_rlc, }, + huffman_data: HuffmanData::default(), + fse_data: FseTableRow { + idx: 0, + state: 0, + symbol: 0, + baseline: 0, + num_bits: 0, + num_emitted: 0, + n_acc: row.9 as u64, + } }); } From 69a572a0877c2c4ad3e428e123f8f1f79c92ecff Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 21:49:47 -0500 Subject: [PATCH 117/165] Correct accuracy log bit reading --- zkevm-circuits/src/decompression_circuit.rs | 31 ++++++++++----------- zkevm-circuits/src/witness/zstd/types.rs | 2 +- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 177d05ae33..fb5a666ef1 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1726,16 +1726,16 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // bit_index 4 (considering that it is 0-indexed). // compression_debug - // cb.require_equal( - // "accuracy log read from bits [0, 4)", - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - // 0.expr(), - // ); - // cb.require_equal( - // "accuracy log read from bits [0, 4)", - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()), - // 3.expr(), - // ); + cb.require_equal( + "accuracy log read from bits [0, 4)", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + 0.expr(), + ); + cb.require_equal( + "accuracy log read from bits [0, 4)", + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::next()), + 3.expr(), + ); // At every row, a new symbol is decoded. This symbol stands for the weight in the // canonical Huffman code representation. So we start at symbol == S0, i.e. 0 and @@ -1756,12 +1756,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); // Check that the decoded accuracy log is correct. - // compression_debug - // cb.require_equal( - // "accuracy log check", - // meta.query_advice(huffman_tree_config.fse_table_al, Rotation::next()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::next()) + 5.expr(), - // ); + cb.require_equal( + "accuracy log check", + meta.query_advice(huffman_tree_config.fse_table_al, Rotation::next()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::next()) + 5.expr(), + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index a85eeb7ddb..f9f0158bb0 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -587,7 +587,7 @@ impl FseAuxiliaryTableData { offset += 4; reader.read::(offset)? + 5 }; - bit_boundaries.push((offset, accuracy_log as u64 - 1)); + bit_boundaries.push((offset, accuracy_log as u64 - 5)); let table_size = 1 << accuracy_log; let mut sym_to_states = BTreeMap::new(); From f1bfafa7bbba92544275ed5b6d6d741eedda9dee Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 21:51:08 -0500 Subject: [PATCH 118/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 24 +++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index fb5a666ef1..3585b409b3 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1704,28 +1704,24 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let tag_len_huffman_code = meta.query_advice(huffman_tree_config.huffman_code_len, Rotation::cur()); - // compression_debug - // cb.require_equal( - // "huffman header value byte check", - // meta.query_advice(value_byte, Rotation::cur()) + 1.expr(), - // tag_len_fse_code + tag_len_huffman_code, - // ); + cb.require_equal( + "huffman header value byte check", + meta.query_advice(value_byte, Rotation::cur()) + 1.expr(), + tag_len_fse_code + tag_len_huffman_code, + ); // The huffman tree description starts at this byte index. We identify the FSE and // Huffman tables using this byte index. - // compression_debug - // cb.require_equal( - // "huffman header byte offset assignment", - // meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // ); + cb.require_equal( + "huffman header byte offset assignment", + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + ); // We know that the next byte is the start of processing bitstream to construct the // FSE table. The first 4 bits are used to calculate the accuracy log (and the // table size) of the table. So the first bitstring that's decoded starts from // bit_index 4 (considering that it is 0-indexed). - - // compression_debug cb.require_equal( "accuracy log read from bits [0, 4)", meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), From def666f0f1835a70c54a8d9ba7475e7cecab357e Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 21:53:47 -0500 Subject: [PATCH 119/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 26 ++++++++------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 3585b409b3..d5244bc6cd 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1262,14 +1262,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // ZstdTag::BlockHeader.expr(), // ); - // cb.require_equal( - // "block_idx == block_len", - // meta.query_advice(block_gadget.idx, Rotation::cur()), - // meta.query_advice(block_gadget.block_len, Rotation::cur()), - // ); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_equal( + "block_idx == block_len", + meta.query_advice(block_gadget.idx, Rotation::cur()), + meta.query_advice(block_gadget.block_len, Rotation::cur()), + ); // compression_debug // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); @@ -1314,14 +1311,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // 1.expr(), // ); - // cb.require_equal( - // "block_idx == block_len", - // meta.query_advice(block_gadget.idx, Rotation::cur()), - // meta.query_advice(block_gadget.block_len, Rotation::cur()), - // ); - - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_equal( + "block_idx == block_len", + meta.query_advice(block_gadget.idx, Rotation::cur()), + meta.query_advice(block_gadget.block_len, Rotation::cur()), + ); // compression_debug // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); From 2b39d39dd9735c4e2d97a875ccffc7f03701edab Mon Sep 17 00:00:00 2001 From: darth-cy Date: Sun, 11 Feb 2024 22:45:24 -0500 Subject: [PATCH 120/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 37 +++++++++------------ 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index d5244bc6cd..06a74122a2 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1217,7 +1217,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), ])) }); - // TODO: Multi-block constraints will be examined after mutli-block test vectors become available meta.create_gate("DecompressionCircuit: while processing a block", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -1230,20 +1229,17 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - meta.query_advice(byte_idx, Rotation::cur()), // ); - // cb.require_equal( - // "block_len remains unchanged", - // meta.query_advice(block_gadget.block_len, Rotation::next()), - // meta.query_advice(block_gadget.block_len, Rotation::cur()), - // ); - - // cb.require_equal( - // "is_last_block remains unchanged", - // meta.query_advice(block_gadget.is_last_block, Rotation::next()), - // meta.query_advice(block_gadget.is_last_block, Rotation::cur()), - // ); + cb.require_equal( + "block_len remains unchanged", + meta.query_advice(block_gadget.block_len, Rotation::next()), + meta.query_advice(block_gadget.block_len, Rotation::cur()), + ); - // compression_debug - cb.require_zero("dummy constraint", 0.expr()); + cb.require_equal( + "is_last_block remains unchanged", + meta.query_advice(block_gadget.is_last_block, Rotation::next()), + meta.query_advice(block_gadget.is_last_block, Rotation::cur()), + ); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -1251,16 +1247,14 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(block_gadget.is_block, Rotation::next()), ])) }); - // TODO: Multi-block constraints will be examined after mutli-block test vectors become available meta.create_gate("DecompressionCircuit: handle end of other blocks", |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug - // cb.require_equal( - // "tag_next depending on whether or not this is the last block", - // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - // ZstdTag::BlockHeader.expr(), - // ); + cb.require_equal( + "tag_next depending on whether or not this is the last block", + meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + ZstdTag::BlockHeader.expr(), + ); cb.require_equal( "block_idx == block_len", @@ -1278,7 +1272,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { not::expr(meta.query_advice(block_gadget.is_last_block, Rotation::cur())), ])) }); - // TODO: Multi-block constraints will be examined after mutli-block test vectors become available meta.create_gate("DecompressionCircuit: handle end of last block", |meta| { let mut cb = BaseConstraintBuilder::default(); From 8e50909ed164bd3e851a580c343d5def3020f532 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 00:37:27 -0500 Subject: [PATCH 121/165] Recover constraints --- zkevm-circuits/src/decompression_circuit.rs | 9 ++++++++- zkevm-circuits/src/decompression_circuit/dev.rs | 2 ++ zkevm-circuits/src/table/decompression.rs | 5 ++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 06a74122a2..698d5f09ab 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -125,6 +125,9 @@ pub struct DecompressionCircuitConfig { pow_rand_table: PowOfRandTable, block_type_rom_table: BlockTypeRomTable, pow2_table: Pow2Table, + literals_header_rom_table: LiteralsHeaderRomTable, + literals_header_table: LiteralsHeaderTable, + bitstring_accumulation_table: BitstringAccumulationTable, } /// Block level details are specified in these columns. @@ -1782,7 +1785,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug meta.create_gate( "DecompressionCircuit: ZstdBlockFseCode (fse code)", |meta| { @@ -2873,6 +2875,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { pow_rand_table, block_type_rom_table, pow2_table, + literals_header_rom_table, + literals_header_table, + bitstring_accumulation_table: bs_acc_table, } } } @@ -2889,6 +2894,8 @@ impl DecompressionCircuitConfig { let mut jump_table_idx: usize = 0; let mut rand_pow: Vec> = vec![Value::known(F::one())]; + self.bitstring_accumulation_table.dev_load(layouter, &witness_rows); + layouter.assign_region( || "Decompression table region", |mut region| { diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index 74b520336b..19619f2442 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -86,6 +86,8 @@ impl Circuit for DecompressionCircuit { config.0.pow_rand_table.assign(&mut layouter, challenges)?; config.0.block_type_rom_table.load(&mut layouter)?; config.0.pow2_table.load(&mut layouter)?; + config.0.literals_header_rom_table.load(&mut layouter)?; + // config.0.literals_header_table.dev_load(layouter, literals_headers)?; self.synthesize_sub(&config.0, challenges, &mut layouter) } } diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index 7a388a3670..f1988402e3 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -22,8 +22,7 @@ use crate::{ evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, table::BitwiseOp, witness::{ - FseAuxiliaryTableData, FseSymbol, HuffmanCodesData, TagRomTableRow, ZstdTag, N_BITS_SYMBOL, - N_MAX_SYMBOLS, + FseAuxiliaryTableData, FseSymbol, HuffmanCodesData, TagRomTableRow, ZstdTag, ZstdWitnessRow, N_BITS_SYMBOL, N_MAX_SYMBOLS }, }; @@ -1397,7 +1396,7 @@ impl BitstringAccumulationTable { } /// Load witness to the table: dev mode. - pub fn dev_load(&self, _layouter: &mut impl Layouter) -> Result<(), Error> { + pub fn dev_load(&self, _layouter: &mut impl Layouter, witness_rows: &Vec>) -> Result<(), Error> { // TODO Ok(()) From 7917ae50b63043c86627d4d4f5e97866bf1d12be Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 03:34:52 -0500 Subject: [PATCH 122/165] Assign into bitstream accumulation for spanned --- zkevm-circuits/src/decompression_circuit.rs | 2 +- .../src/decompression_circuit/dev.rs | 2 +- zkevm-circuits/src/table/decompression.rs | 187 +++++++++++++++++- 3 files changed, 186 insertions(+), 5 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 698d5f09ab..338120d38e 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2894,7 +2894,7 @@ impl DecompressionCircuitConfig { let mut jump_table_idx: usize = 0; let mut rand_pow: Vec> = vec![Value::known(F::one())]; - self.bitstring_accumulation_table.dev_load(layouter, &witness_rows); + self.bitstring_accumulation_table.assign(layouter, &witness_rows)?; layouter.assign_region( || "Decompression table region", diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index 19619f2442..5b21ad17bd 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -86,7 +86,7 @@ impl Circuit for DecompressionCircuit { config.0.pow_rand_table.assign(&mut layouter, challenges)?; config.0.block_type_rom_table.load(&mut layouter)?; config.0.pow2_table.load(&mut layouter)?; - config.0.literals_header_rom_table.load(&mut layouter)?; + // config.0.literals_header_rom_table.load(&mut layouter)?; // config.0.literals_header_table.dev_load(layouter, literals_headers)?; self.synthesize_sub(&config.0, challenges, &mut layouter) } diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index f1988402e3..e819cc0fd5 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -22,7 +22,7 @@ use crate::{ evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, table::BitwiseOp, witness::{ - FseAuxiliaryTableData, FseSymbol, HuffmanCodesData, TagRomTableRow, ZstdTag, ZstdWitnessRow, N_BITS_SYMBOL, N_MAX_SYMBOLS + FseAuxiliaryTableData, FseSymbol, HuffmanCodesData, TagRomTableRow, ZstdTag, ZstdWitnessRow, N_BITS_SYMBOL, N_MAX_SYMBOLS, value_bits_le, }, }; @@ -1396,8 +1396,189 @@ impl BitstringAccumulationTable { } /// Load witness to the table: dev mode. - pub fn dev_load(&self, _layouter: &mut impl Layouter, witness_rows: &Vec>) -> Result<(), Error> { - // TODO + pub fn assign(&self, layouter: &mut impl Layouter, witness_rows: &Vec>) -> Result<(), Error> { + assert!(witness_rows.len() > 0); + + // Get the byte at which FSE is described + let huffman_offset = witness_rows.iter() + .find(|&r| r.state.tag == ZstdTag::ZstdBlockFseCode) + .unwrap() + .encoded_data.byte_idx; + + // Extract bit accumulation-related info from the rows + let accumulation_rows = witness_rows.iter() + .filter(|&r| { + r.state.tag == ZstdTag::ZstdBlockFseCode || + r.state.tag == ZstdTag::ZstdBlockHuffmanCode || + r.state.tag == ZstdTag::ZstdBlockLstream + }) + .map(|r| { + let is_reverse: u64 = + if r.state.tag == ZstdTag::ZstdBlockFseCode { + 0 + } else { + 1 + }; + (r.encoded_data.byte_idx as usize, r.encoded_data.value_byte as u64, r.bitstream_read_data.bit_start_idx as usize, r.bitstream_read_data.bit_end_idx as usize, r.bitstream_read_data.bit_value as u64, is_reverse) + }) + .collect::>(); + + layouter.assign_region( + || "Bitstring Accumulation Table", + |mut region| { + + let mut offset: usize = 0; + for (idx, row) in accumulation_rows.iter().enumerate() { + if row.3 <= 7 { + // byte-contained + + } else { + // byte-spanned + let next_row = accumulation_rows[idx + 1]; + + let byte_1_bits = value_bits_le(row.1 as u8); + let byte_2_bits = value_bits_le(next_row.1 as u8); + let bits = if row.5 > 0 { + // reversed + [byte_1_bits.into_iter().rev().collect::>(), byte_2_bits.into_iter().rev().collect::>()].concat() + } else { + // not reversed + [byte_1_bits, byte_2_bits].concat() + }; + + let mut acc: u64 = 0; + let mut bitstring_len: u64 = 0; + + for bit_idx in (0..16usize).into_iter() { + region.assign_fixed( + || format!("q_enable"), + self.q_enabled, + offset + bit_idx, + || Value::known(F::one()), + )?; + region.assign_advice( + || format!("byte_offset"), + self.byte_offset, + offset + bit_idx, + || Value::known(F::from(huffman_offset)), + )?; + region.assign_advice( + || format!("byte_idx_1"), + self.byte_idx_1, + offset + bit_idx, + || Value::known(F::from(row.0 as u64)), + )?; + region.assign_advice( + || format!("byte_idx_2"), + self.byte_idx_2, + offset + bit_idx, + || Value::known(F::from(next_row.0 as u64)), + )?; + region.assign_advice( + || format!("byte_1"), + self.byte_1, + offset + bit_idx, + || Value::known(F::from(row.1 as u64)), + )?; + region.assign_advice( + || format!("byte_2"), + self.byte_2, + offset + bit_idx, + || Value::known(F::from(next_row.1 as u64)), + )?; + region.assign_fixed( + || format!("bit_index"), + self.bit_index, + offset + bit_idx, + || Value::known(F::from(bit_idx as u64)), + )?; + region.assign_fixed( + || format!("q_first"), + self.q_first, + offset + bit_idx, + || Value::known(F::from((bit_idx == 0) as u64)), + )?; + + let bit = bits[bit_idx] as u64; + if bit_idx >= row.2 && bit_idx <= row.3 { + acc = acc * 2 + bit; + bitstring_len += 1; + } + region.assign_advice( + || format!("bit"), + self.bit, + offset + bit_idx, + || Value::known(F::from(bit)), + )?; + region.assign_advice( + || format!("bit_value_acc"), + self.bit_value_acc, + offset + bit_idx, + || Value::known(F::from(acc)), + )?; + region.assign_advice( + || format!("bit_value"), + self.bit_value, + offset + bit_idx, + || Value::known(F::from(row.4)), + )?; + region.assign_advice( + || format!("bitstring_len"), + self.bitstring_len, + offset + bit_idx, + || Value::known(F::from(bitstring_len)), + )?; + region.assign_advice( + || format!("from_start"), + self.from_start, + offset + bit_idx, + || Value::known(F::from((bit_idx <= row.3) as u64)), + )?; + region.assign_advice( + || format!("until_end"), + self.until_end, + offset + bit_idx, + || Value::known(F::from((bit_idx >= row.2) as u64)), + )?; + region.assign_advice( + || format!("is_reverse"), + self.is_reverse, + offset + bit_idx, + || Value::known(F::from(row.5 as u64)), + )?; + } + + offset += 16; + } + } + + region.assign_fixed( + || format!("q_first"), + self.q_first, + offset, + || Value::known(F::one()), + )?; + + Ok(()) + } + )?; + + + + + + + + + + + + + + + + + Ok(()) } From eb4300566bf1bea4607f2b8249db29812384cbd4 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 03:38:53 -0500 Subject: [PATCH 123/165] Recover lookups --- zkevm-circuits/src/decompression_circuit.rs | 400 ++++++++++---------- 1 file changed, 197 insertions(+), 203 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 338120d38e..a64edab296 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1897,76 +1897,74 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // }, // ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", - // |meta| { - // let (huffman_byte_offset, start, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // bitstream_decoder.is_spanned(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(byte_idx, Rotation::next()), // byte index' - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // meta.query_advice(value_byte, Rotation::next()), // byte value' - // bit_value, // bitstring value - // 1.expr(), // bitstring len acc - // start, // bit index start - // 1.expr(), // from start - // 1.expr(), // to end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_spanned(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", + |meta| { + let (huffman_byte_offset, start, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + bitstream_decoder.is_spanned(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(byte_idx, Rotation::next()), // byte index' + meta.query_advice(value_byte, Rotation::cur()), // byte value + meta.query_advice(value_byte, Rotation::next()), // byte value' + bit_value, // bitstring value + 1.expr(), // bitstring len acc + start, // bit index start + 1.expr(), // from start + 1.expr(), // to end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_spanned(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", - // |meta| { - // let (huffman_byte_offset, start, end, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // bitstream_decoder.is_spanned(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(byte_idx, Rotation::next()), // byte index' - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // meta.query_advice(value_byte, Rotation::next()), // byte value' - // bit_value, // bitstring value - // end.expr() - start + 1.expr(), // bitstring length - // end, // bit index at end - // 1.expr(), // from start - // 1.expr(), // to end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_spanned(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", + |meta| { + let (huffman_byte_offset, start, end, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + bitstream_decoder.is_spanned(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(byte_idx, Rotation::next()), // byte index' + meta.query_advice(value_byte, Rotation::cur()), // byte value + meta.query_advice(value_byte, Rotation::next()), // byte value' + bit_value, // bitstring value + end.expr() - start + 1.expr(), // bitstring length + end, // bit index at end + 1.expr(), // from start + 1.expr(), // to end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_spanned(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); // compression_debug // meta.lookup_any( @@ -2200,74 +2198,72 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // }, // ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", - // |meta| { - // let (huffman_byte_offset, start, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // bitstream_decoder.is_spanned(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(byte_idx, Rotation::next()), // byte index' - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // meta.query_advice(value_byte, Rotation::next()), // byte value' - // bit_value, // bitstring value - // 1.expr(), // bitstring len acc - // start, // bit index start - // 1.expr(), // from start - // 1.expr(), // to end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_spanned(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", + |meta| { + let (huffman_byte_offset, start, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + bitstream_decoder.is_spanned(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(byte_idx, Rotation::next()), // byte index' + meta.query_advice(value_byte, Rotation::cur()), // byte value + meta.query_advice(value_byte, Rotation::next()), // byte value' + bit_value, // bitstring value + 1.expr(), // bitstring len acc + start, // bit index start + 1.expr(), // from start + 1.expr(), // to end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_spanned(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstring end)", - // |meta| { - // let (huffman_byte_offset, start, end, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // bitstream_decoder.is_spanned(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(byte_idx, Rotation::next()), // byte index' - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // meta.query_advice(value_byte, Rotation::next()), // byte value' - // bit_value, // bitstring value - // end.expr() - start + 1.expr(), // bitstring length - // end, // bit index at end - // 1.expr(), // from start - // 1.expr(), // to end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_spanned(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstring end)", + |meta| { + let (huffman_byte_offset, start, end, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + bitstream_decoder.is_spanned(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(byte_idx, Rotation::next()), // byte index' + meta.query_advice(value_byte, Rotation::cur()), // byte value + meta.query_advice(value_byte, Rotation::next()), // byte value' + bit_value, // bitstring value + end.expr() - start + 1.expr(), // bitstring length + end, // bit index at end + 1.expr(), // from start + 1.expr(), // to end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_spanned(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); // 1. We first read AL number of bits from the bitstream (say bit_value_init) and transition // to the state == bit_value_init. @@ -2678,74 +2674,72 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // }, // ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockLstream (spanned bitstream start)", - // |meta| { - // let (huffman_byte_offset, start, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - // bitstream_decoder.is_spanned(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(byte_idx, Rotation::next()), // byte index' - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // meta.query_advice(value_byte, Rotation::next()), // byte value' - // bit_value, // bitstring value - // 1.expr(), // bitstring len acc - // start, // bit index start - // 1.expr(), // from start - // 1.expr(), // to end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_spanned(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockLstream (spanned bitstream start)", + |meta| { + let (huffman_byte_offset, start, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + bitstream_decoder.is_spanned(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(byte_idx, Rotation::next()), // byte index' + meta.query_advice(value_byte, Rotation::cur()), // byte value + meta.query_advice(value_byte, Rotation::next()), // byte value' + bit_value, // bitstring value + 1.expr(), // bitstring len acc + start, // bit index start + 1.expr(), // from start + 1.expr(), // to end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_spanned(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockLstream (spanned bitstring end)", - // |meta| { - // let (huffman_byte_offset, start, end, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - // bitstream_decoder.is_spanned(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(byte_idx, Rotation::next()), // byte index' - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // meta.query_advice(value_byte, Rotation::next()), // byte value' - // bit_value, // bitstring value - // end.expr() - start + 1.expr(), // bitstring length - // end, // bit index at end - // 1.expr(), // from start - // 1.expr(), // to end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_spanned(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockLstream (spanned bitstring end)", + |meta| { + let (huffman_byte_offset, start, end, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + bitstream_decoder.is_spanned(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(byte_idx, Rotation::next()), // byte index' + meta.query_advice(value_byte, Rotation::cur()), // byte value + meta.query_advice(value_byte, Rotation::next()), // byte value' + bit_value, // bitstring value + end.expr() - start + 1.expr(), // bitstring length + end, // bit index at end + 1.expr(), // from start + 1.expr(), // to end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_spanned(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); meta.create_gate("DecompressionCircuit: bitstream reader", |meta| { let mut cb = BaseConstraintBuilder::default(); From c867ed6b91f1212d65d3b86475086b611902f90e Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 04:03:58 -0500 Subject: [PATCH 124/165] Construct contained bitstreams --- zkevm-circuits/src/table/decompression.rs | 245 +++++++++++----------- zkevm-circuits/src/witness/zstd/mod.rs | 6 +- 2 files changed, 130 insertions(+), 121 deletions(-) diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index e819cc0fd5..2276c4d3a1 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -1212,6 +1212,7 @@ impl BitstringAccumulationTable { ), ); + // TODO: Possibly exclude jump table bytes as they create a gap in byte_idx between huffman code and lstreams cb.require_equal( "byte2 follows byte2, i.e. byte_idx_2 == byte_idx_1 + 1", meta.query_advice(table.byte_idx_2, Rotation::cur()), @@ -1410,11 +1411,12 @@ impl BitstringAccumulationTable { .filter(|&r| { r.state.tag == ZstdTag::ZstdBlockFseCode || r.state.tag == ZstdTag::ZstdBlockHuffmanCode || + r.state.tag == ZstdTag::ZstdBlockJumpTable || r.state.tag == ZstdTag::ZstdBlockLstream }) .map(|r| { let is_reverse: u64 = - if r.state.tag == ZstdTag::ZstdBlockFseCode { + if r.state.tag == ZstdTag::ZstdBlockFseCode || r.state.tag == ZstdTag::ZstdBlockJumpTable { 0 } else { 1 @@ -1423,133 +1425,136 @@ impl BitstringAccumulationTable { }) .collect::>(); + let last_row = accumulation_rows.last().expect("Last row expected"); + layouter.assign_region( || "Bitstring Accumulation Table", |mut region| { - let mut offset: usize = 0; for (idx, row) in accumulation_rows.iter().enumerate() { - if row.3 <= 7 { - // byte-contained - - } else { - // byte-spanned - let next_row = accumulation_rows[idx + 1]; - - let byte_1_bits = value_bits_le(row.1 as u8); - let byte_2_bits = value_bits_le(next_row.1 as u8); - let bits = if row.5 > 0 { - // reversed - [byte_1_bits.into_iter().rev().collect::>(), byte_2_bits.into_iter().rev().collect::>()].concat() - } else { - // not reversed - [byte_1_bits, byte_2_bits].concat() - }; - - let mut acc: u64 = 0; - let mut bitstring_len: u64 = 0; - - for bit_idx in (0..16usize).into_iter() { - region.assign_fixed( - || format!("q_enable"), - self.q_enabled, - offset + bit_idx, - || Value::known(F::one()), - )?; - region.assign_advice( - || format!("byte_offset"), - self.byte_offset, - offset + bit_idx, - || Value::known(F::from(huffman_offset)), - )?; - region.assign_advice( - || format!("byte_idx_1"), - self.byte_idx_1, - offset + bit_idx, - || Value::known(F::from(row.0 as u64)), - )?; - region.assign_advice( - || format!("byte_idx_2"), - self.byte_idx_2, - offset + bit_idx, - || Value::known(F::from(next_row.0 as u64)), - )?; - region.assign_advice( - || format!("byte_1"), - self.byte_1, - offset + bit_idx, - || Value::known(F::from(row.1 as u64)), - )?; - region.assign_advice( - || format!("byte_2"), - self.byte_2, - offset + bit_idx, - || Value::known(F::from(next_row.1 as u64)), - )?; - region.assign_fixed( - || format!("bit_index"), - self.bit_index, - offset + bit_idx, - || Value::known(F::from(bit_idx as u64)), - )?; - region.assign_fixed( - || format!("q_first"), - self.q_first, - offset + bit_idx, - || Value::known(F::from((bit_idx == 0) as u64)), - )?; - - let bit = bits[bit_idx] as u64; - if bit_idx >= row.2 && bit_idx <= row.3 { - acc = acc * 2 + bit; - bitstring_len += 1; - } - region.assign_advice( - || format!("bit"), - self.bit, - offset + bit_idx, - || Value::known(F::from(bit)), - )?; - region.assign_advice( - || format!("bit_value_acc"), - self.bit_value_acc, - offset + bit_idx, - || Value::known(F::from(acc)), - )?; - region.assign_advice( - || format!("bit_value"), - self.bit_value, - offset + bit_idx, - || Value::known(F::from(row.4)), - )?; - region.assign_advice( - || format!("bitstring_len"), - self.bitstring_len, - offset + bit_idx, - || Value::known(F::from(bitstring_len)), - )?; - region.assign_advice( - || format!("from_start"), - self.from_start, - offset + bit_idx, - || Value::known(F::from((bit_idx <= row.3) as u64)), - )?; - region.assign_advice( - || format!("until_end"), - self.until_end, - offset + bit_idx, - || Value::known(F::from((bit_idx >= row.2) as u64)), - )?; - region.assign_advice( - || format!("is_reverse"), - self.is_reverse, - offset + bit_idx, - || Value::known(F::from(row.5 as u64)), - )?; + let next_row = if idx + 1 < accumulation_rows.len() { + let mut candidate_idx = idx + 1; + while accumulation_rows[candidate_idx].0 == row.0 { + candidate_idx += 1; } + accumulation_rows[candidate_idx] + } else { + (last_row.0 + 1, 0, 0, 0, 0, 0) + }; - offset += 16; + let byte_1_bits = value_bits_le(row.1 as u8); + let byte_2_bits = value_bits_le(next_row.1 as u8); + let bits = if row.5 > 0 { + // reversed + [byte_1_bits.into_iter().rev().collect::>(), byte_2_bits.into_iter().rev().collect::>()].concat() + } else { + // not reversed + [byte_1_bits, byte_2_bits].concat() + }; + + let mut acc: u64 = 0; + let mut bitstring_len: u64 = 0; + + for bit_idx in (0..16usize).into_iter() { + region.assign_fixed( + || format!("q_enable"), + self.q_enabled, + offset + bit_idx, + || Value::known(F::one()), + )?; + region.assign_advice( + || format!("byte_offset"), + self.byte_offset, + offset + bit_idx, + || Value::known(F::from(huffman_offset)), + )?; + region.assign_advice( + || format!("byte_idx_1"), + self.byte_idx_1, + offset + bit_idx, + || Value::known(F::from(row.0 as u64)), + )?; + region.assign_advice( + || format!("byte_idx_2"), + self.byte_idx_2, + offset + bit_idx, + || Value::known(F::from(next_row.0 as u64)), + )?; + region.assign_advice( + || format!("byte_1"), + self.byte_1, + offset + bit_idx, + || Value::known(F::from(row.1 as u64)), + )?; + region.assign_advice( + || format!("byte_2"), + self.byte_2, + offset + bit_idx, + || Value::known(F::from(next_row.1 as u64)), + )?; + region.assign_fixed( + || format!("bit_index"), + self.bit_index, + offset + bit_idx, + || Value::known(F::from(bit_idx as u64)), + )?; + region.assign_fixed( + || format!("q_first"), + self.q_first, + offset + bit_idx, + || Value::known(F::from((bit_idx == 0) as u64)), + )?; + + let bit = bits[bit_idx] as u64; + if bit_idx >= row.2 && bit_idx <= row.3 { + acc = acc * 2 + bit; + bitstring_len += 1; + } + region.assign_advice( + || format!("bit"), + self.bit, + offset + bit_idx, + || Value::known(F::from(bit)), + )?; + region.assign_advice( + || format!("bit_value_acc"), + self.bit_value_acc, + offset + bit_idx, + || Value::known(F::from(acc)), + )?; + region.assign_advice( + || format!("bit_value"), + self.bit_value, + offset + bit_idx, + || Value::known(F::from(row.4)), + )?; + region.assign_advice( + || format!("bitstring_len"), + self.bitstring_len, + offset + bit_idx, + || Value::known(F::from(bitstring_len)), + )?; + region.assign_advice( + || format!("from_start"), + self.from_start, + offset + bit_idx, + || Value::known(F::from((bit_idx <= row.3) as u64)), + )?; + region.assign_advice( + || format!("until_end"), + self.until_end, + offset + bit_idx, + || Value::known(F::from((bit_idx >= row.2) as u64)), + )?; + region.assign_advice( + || format!("is_reverse"), + self.is_reverse, + offset + bit_idx, + || Value::known(F::from(row.5 as u64)), + )?; } + + offset += 16; } region.assign_fixed( diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index b77030267a..7ccf3f74d9 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1335,7 +1335,11 @@ fn process_block_zstd_huffman_jump_table( reverse: false, ..Default::default() }, - bitstream_read_data: BitstreamReadRow::default(), + bitstream_read_data: BitstreamReadRow { + bit_start_idx: 0, + bit_end_idx: 7, + bit_value: value_byte as u64, + }, decoded_data: last_row.decoded_data.clone(), huffman_data: HuffmanData::default(), fse_data: FseTableRow::default(), From c7c7ed11f783d6ab9357c906d466166db4a02097 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 04:05:04 -0500 Subject: [PATCH 125/165] Recdover lookups --- zkevm-circuits/src/decompression_circuit.rs | 128 ++++++++++---------- 1 file changed, 63 insertions(+), 65 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index a64edab296..204ce6d16a 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1830,72 +1830,70 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockFseCode (contained bitstream start)", - // |meta| { - // let (huffman_byte_offset, start, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // bitstream_decoder.is_contained(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // bit_value, // bitstring value - // 1.expr(), // bitstring length accumulator, starts at 1 - // start, // bit index start - // 1.expr(), // denotes that this bit index is a part of the bitstring - // 1.expr(), // denotes that this bit index is a part of the bitstring - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_contained(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockFseCode (contained bitstream start)", + |meta| { + let (huffman_byte_offset, start, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + bitstream_decoder.is_contained(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(value_byte, Rotation::cur()), // byte value + bit_value, // bitstring value + 1.expr(), // bitstring length accumulator, starts at 1 + start, // bit index start + 1.expr(), // denotes that this bit index is a part of the bitstring + 1.expr(), // denotes that this bit index is a part of the bitstring + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_contained(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockFseCode (contained bitstream end)", - // |meta| { - // let (huffman_byte_offset, start, end, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // bitstream_decoder.is_contained(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // bit_value, // bitstring value - // end.expr() - start + 1.expr(), // bitstring length - // end, // bit index at end - // 1.expr(), // from start - // 1.expr(), // to end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_contained(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockFseCode (contained bitstream end)", + |meta| { + let (huffman_byte_offset, start, end, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + bitstream_decoder.is_contained(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(value_byte, Rotation::cur()), // byte value + bit_value, // bitstring value + end.expr() - start + 1.expr(), // bitstring length + end, // bit index at end + 1.expr(), // from start + 1.expr(), // to end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_contained(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); meta.lookup_any( "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", From 7f115985e05d9574373d2b5d3ecd43c236cdf86a Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 04:07:28 -0500 Subject: [PATCH 126/165] Recover lookups --- zkevm-circuits/src/decompression_circuit.rs | 248 ++++++++++---------- 1 file changed, 122 insertions(+), 126 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 204ce6d16a..c0f6f42df2 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2131,70 +2131,68 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream start)", - // |meta| { - // let (huffman_byte_offset, start, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // bitstream_decoder.is_contained(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // bit_value, // bitstring value - // 1.expr(), // bitstring length accumulator, starts at 1 - // start, // bit index start - // 1.expr(), // denotes that this bit index is a part of the bitstring - // 1.expr(), // denotes that this bit index is a part of the bitstring - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_contained(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream start)", + |meta| { + let (huffman_byte_offset, start, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + bitstream_decoder.is_contained(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(value_byte, Rotation::cur()), // byte value + bit_value, // bitstring value + 1.expr(), // bitstring length accumulator, starts at 1 + start, // bit index start + 1.expr(), // denotes that this bit index is a part of the bitstring + 1.expr(), // denotes that this bit index is a part of the bitstring + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_contained(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream end)", - // |meta| { - // let (huffman_byte_offset, start, end, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // bitstream_decoder.is_contained(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // bit_value, // bitstring value - // end.expr() - start + 1.expr(), // bitstring length - // end, // bit index at end - // 1.expr(), // from start - // 1.expr(), // to end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_contained(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream end)", + |meta| { + let (huffman_byte_offset, start, end, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + bitstream_decoder.is_contained(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(value_byte, Rotation::cur()), // byte value + bit_value, // bitstring value + end.expr() - start + 1.expr(), // bitstring length + end, // bit index at end + 1.expr(), // from start + 1.expr(), // to end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_contained(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); meta.lookup_any( "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", @@ -2607,70 +2605,68 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockLstream (contained bitstream start)", - // |meta| { - // let (huffman_byte_offset, start, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - // bitstream_decoder.is_contained(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // bit_value, // bitstring value - // 1.expr(), // bitstring length accumulator, starts at 1 - // start, // bit index start - // 1.expr(), // denotes that this bit index is a part of the bitstring - // 1.expr(), // denotes that this bit index is a part of the bitstring - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_contained(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockLstream (contained bitstream start)", + |meta| { + let (huffman_byte_offset, start, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + bitstream_decoder.is_contained(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(value_byte, Rotation::cur()), // byte value + bit_value, // bitstring value + 1.expr(), // bitstring length accumulator, starts at 1 + start, // bit index start + 1.expr(), // denotes that this bit index is a part of the bitstring + 1.expr(), // denotes that this bit index is a part of the bitstring + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_contained(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockLstream (contained bitstream end)", - // |meta| { - // let (huffman_byte_offset, start, end, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - // bitstream_decoder.is_contained(meta, None), - // ]); - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(byte_idx, Rotation::cur()), // byte index - // meta.query_advice(value_byte, Rotation::cur()), // byte value - // bit_value, // bitstring value - // end.expr() - start + 1.expr(), // bitstring length - // end, // bit index at end - // 1.expr(), // from start - // 1.expr(), // to end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs_contained(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockLstream (contained bitstream end)", + |meta| { + let (huffman_byte_offset, start, end, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + bitstream_decoder.is_contained(meta, None), + ]); + [ + huffman_byte_offset, // huffman ID + meta.query_advice(byte_idx, Rotation::cur()), // byte index + meta.query_advice(value_byte, Rotation::cur()), // byte value + bit_value, // bitstring value + end.expr() - start + 1.expr(), // bitstring length + end, // bit index at end + 1.expr(), // from start + 1.expr(), // to end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse + ] + .into_iter() + .zip(bs_acc_table.table_exprs_contained(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); meta.lookup_any( "DecompressionCircuit: ZstdBlockLstream (spanned bitstream start)", From b5dd72420cbaee73248e975056f032bfef628c98 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 04:09:26 -0500 Subject: [PATCH 127/165] Remove debug flags --- zkevm-circuits/src/decompression_circuit.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index c0f6f42df2..889c574178 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2094,7 +2094,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { |meta| { let mut cb = BaseConstraintBuilder::default(); - // compression_debug cb.require_equal( "num_emitted increments", meta.query_advice(fse_decoder.num_emitted, Rotation::cur()), @@ -2402,7 +2401,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // The HuffmanTreeDescriptionSize can be calculated as: // - HuffmanTreeDescriptionSize == byte_idx(JumpTable) - byte_idx(HuffmanTree) - // TODO: incorrect size? compression_debug + // TODO: byte counting? cb.require_equal( "length of lstream4", meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) @@ -2824,7 +2823,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), - // TODO: Modify to prev -> cur? compression_debug + // TODO: Modify to prev -> cur? not::expr(meta.query_fixed(q_enable, Rotation::cur())), sum::expr([ meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), @@ -3381,13 +3380,6 @@ impl SubCircuit for DecompressionCircuit { data.extend_from_slice(&aux_data); } - // compression_debug - for row in witness_rows.clone() { - log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};;", - row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, row.fse_data.num_emitted, row.fse_data.n_acc, row.bitstream_read_data.bit_start_idx, row.bitstream_read_data.bit_end_idx, row.bitstream_read_data.bit_value - ); - } - config.assign(layouter, witness_rows, data, challenges) } } From 6c5a92836c67320435e1494f19d72c79cfeed7ac Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 11:39:36 -0500 Subject: [PATCH 128/165] Correct n_acc for FSE --- zkevm-circuits/src/decompression_circuit.rs | 2 +- zkevm-circuits/src/witness/zstd/mod.rs | 2 +- zkevm-circuits/src/witness/zstd/types.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 889c574178..f5f3cc0ea8 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1809,7 +1809,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // meta.query_advice(fse_decoder.n_acc, Rotation::cur()) + 1.expr(), meta.query_advice(fse_decoder.n_acc, Rotation::cur()), meta.query_advice(fse_decoder.n_acc, Rotation::prev()) - + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + + (meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()) - 1.expr()), ); }); cb.condition(is_last, |cb| { diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 7ccf3f74d9..2b9f2c8b25 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -940,7 +940,7 @@ fn process_block_zstd_huffman_code( if sym > 0 && n_acc < (1 << accuracy_log) { // num_emitted += 1; decoded = sym as u8; - n_acc += *value as usize; + n_acc += (*value - 1) as usize; } (decoded, from_byte_idx, from_bit_idx.rem_euclid(8), to_byte_idx, to_bit_idx, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone(), 0, n_acc) diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index f9f0158bb0..928990e284 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -647,7 +647,7 @@ impl FseAuxiliaryTableData { // update the total number of bits read so far. offset += n_bits_read; - bit_boundaries.push((offset, value - 1)); + bit_boundaries.push((offset, value)); // increment symbol. symbol = ((symbol as usize) + 1).into(); @@ -666,7 +666,7 @@ impl FseAuxiliaryTableData { // read the trailing section if t * N_BITS_PER_BYTE > (offset as usize) { let bits_remaining = t * N_BITS_PER_BYTE - offset as usize; - bit_boundaries.push((offset + bits_remaining as u32, reader.read::(bits_remaining as u32)? as u64 - 1)); + bit_boundaries.push((offset + bits_remaining as u32, reader.read::(bits_remaining as u32)? as u64)); } Ok(( From 9fd0b2bbe2d2100c2fa7684dccb5e80be13e469e Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 12:22:21 -0500 Subject: [PATCH 129/165] LiteralHeader decomposition --- zkevm-circuits/src/decompression_circuit.rs | 50 +++++++++---------- .../src/decompression_circuit/dev.rs | 2 +- zkevm-circuits/src/table/decompression.rs | 24 ++++----- 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index f5f3cc0ea8..7528b0642e 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1465,31 +1465,30 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: lookup for LiteralsHeader decomposition", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - // ]); - // [ - // meta.query_advice(value_bits[7], Rotation::cur()), // block type bit0 - // meta.query_advice(value_bits[6], Rotation::cur()), // block type bit1 - // meta.query_advice(value_bits[5], Rotation::cur()), // size format bit0 - // meta.query_advice(value_bits[4], Rotation::cur()), // size format bit1 - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header - // meta.query_advice(lstream_config.lstream_kind, Rotation::cur()), // 1 or 4 - // meta.query_advice(literals_header.branch, Rotation::cur()), // branch - // meta.query_advice(literals_header.sf_max, Rotation::cur()), // size format 0b11 - // ] - // .into_iter() - // .zip(literals_header_rom_table.table_exprs(meta)) - // .map(|(arg, table)| (condition.expr() * arg, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: lookup for LiteralsHeader decomposition", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + ]); + [ + meta.query_advice(value_bits[0], Rotation::cur()), // block type bit0 + meta.query_advice(value_bits[1], Rotation::cur()), // block type bit1 + meta.query_advice(value_bits[2], Rotation::cur()), // size format bit0 + meta.query_advice(value_bits[3], Rotation::cur()), // size format bit1 + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header + meta.query_advice(lstream_config.lstream_kind, Rotation::cur()), // 1 or 4 + meta.query_advice(literals_header.branch, Rotation::cur()), // branch + meta.query_advice(literals_header.sf_max, Rotation::cur()), // size format 0b11 + ] + .into_iter() + .zip(literals_header_rom_table.table_exprs(meta)) + .map(|(arg, table)| (condition.expr() * arg, table)) + .collect() + }, + ); // compression_debug // meta.lookup_any( @@ -2125,7 +2124,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), ])) }, ); diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index 5b21ad17bd..19619f2442 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -86,7 +86,7 @@ impl Circuit for DecompressionCircuit { config.0.pow_rand_table.assign(&mut layouter, challenges)?; config.0.block_type_rom_table.load(&mut layouter)?; config.0.pow2_table.load(&mut layouter)?; - // config.0.literals_header_rom_table.load(&mut layouter)?; + config.0.literals_header_rom_table.load(&mut layouter)?; // config.0.literals_header_table.dev_load(layouter, literals_headers)?; self.synthesize_sub(&config.0, challenges, &mut layouter) } diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index 2276c4d3a1..ff4e0c0bab 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -2281,18 +2281,18 @@ impl LiteralsHeaderRomTable { |mut region| { // Refer: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#literals_section_header for (i, row) in [ - [0, 0, 0, 0, 1, 1, 0, 0], // Raw: 1 byte header - [0, 0, 0, 1, 1, 1, 0, 0], // Raw: 1 byte header - [0, 0, 1, 0, 2, 1, 1, 0], // Raw: 2 bytes header - [0, 0, 1, 1, 3, 1, 2, 1], // Raw: 3 bytes header - [1, 0, 0, 0, 1, 1, 0, 0], // RLE: 1 byte header - [1, 0, 0, 1, 1, 1, 0, 0], // RLE: 1 byte header - [1, 0, 1, 0, 2, 1, 1, 0], // RLE: 2 bytes header - [1, 0, 1, 1, 3, 1, 2, 1], // RLE: 3 bytes header - [0, 1, 0, 0, 3, 1, 3, 0], // Compressed: 3 bytes header - [0, 1, 1, 0, 3, 4, 4, 0], // Compressed: 3 bytes header - [0, 1, 0, 1, 4, 4, 5, 0], // Compressed: 4 bytes header - [0, 1, 1, 1, 5, 4, 6, 1], // Compressed: 5 bytes header + [0, 0, 0, 0, 1, 0, 0, 0], // Raw: 1 byte header + [0, 0, 0, 1, 1, 0, 0, 0], // Raw: 1 byte header + [0, 0, 1, 0, 2, 0, 1, 0], // Raw: 2 bytes header + [0, 0, 1, 1, 3, 0, 2, 1], // Raw: 3 bytes header + [1, 0, 0, 0, 1, 0, 0, 0], // RLE: 1 byte header + [1, 0, 0, 1, 1, 0, 0, 0], // RLE: 1 byte header + [1, 0, 1, 0, 2, 0, 1, 0], // RLE: 2 bytes header + [1, 0, 1, 1, 3, 0, 2, 1], // RLE: 3 bytes header + [0, 1, 0, 0, 3, 0, 3, 0], // Compressed: 3 bytes header + [0, 1, 1, 0, 3, 1, 4, 0], // Compressed: 3 bytes header + [0, 1, 0, 1, 4, 1, 5, 0], // Compressed: 4 bytes header + [0, 1, 1, 1, 5, 1, 6, 1], // Compressed: 5 bytes header ] .iter() .enumerate() From 91db4be43476fe5d4a181f4f34e7e67f5ccd1306 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 12:37:18 -0500 Subject: [PATCH 130/165] Add dummy row --- zkevm-circuits/src/decompression_circuit.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 7528b0642e..4030596ab3 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2399,7 +2399,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // The HuffmanTreeDescriptionSize can be calculated as: // - HuffmanTreeDescriptionSize == byte_idx(JumpTable) - byte_idx(HuffmanTree) - // TODO: byte counting? cb.require_equal( "length of lstream4", meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) @@ -2407,7 +2406,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { + len2 + len3 + meta.query_advice(byte_idx, Rotation::cur()) - + 6.expr(), // TODO: need to add the 6 bytes for jump table + + 6.expr(), meta.query_advice(literals_header.compr_size, Rotation::cur()) + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), ); @@ -2884,10 +2883,14 @@ impl DecompressionCircuitConfig { layouter.assign_region( || "Decompression table region", |mut region| { + let mut last_byte_idx: usize = 0; + for (i, row) in witness_rows.iter().enumerate() { let tag_len = row.state.tag_len as usize; assert!(tag_len > 0); + last_byte_idx = row.encoded_data.byte_idx as usize; + while tag_len >= rand_pow.len() { let tail = rand_pow.last().expect("Tail exists").clone(); rand_pow.push(tail * challenges.keccak_input()); @@ -3337,6 +3340,14 @@ impl DecompressionCircuitConfig { )?; } + // TODO: Dummy row for sequencing section for now + region.assign_advice( + || "byte_idx", + self.byte_idx, + witness_rows.len(), + || Value::known(F::from((last_byte_idx + 1) as u64)), + )?; + Ok(()) } )?; From 025bc3d6a8dedcca2a1cc353edd7a7d3c3786f45 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 17:54:02 -0500 Subject: [PATCH 131/165] Restore state --- zkevm-circuits/src/decompression_circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 4030596ab3..7867bbe120 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -3340,7 +3340,7 @@ impl DecompressionCircuitConfig { )?; } - // TODO: Dummy row for sequencing section for now + // TODO: Dummy row for sequencing section header region.assign_advice( || "byte_idx", self.byte_idx, From 88c84778ec928be0b7a1c4435df5d5c58f9c79a5 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 18:17:27 -0500 Subject: [PATCH 132/165] FSE initial condition --- zkevm-circuits/src/decompression_circuit.rs | 31 ++++++++------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 7867bbe120..1e9eac0698 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2038,14 +2038,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - The first row of the HuffmanCode tag is the leading 0s and sentinel bit. // - The second row of the HuffmanCode tag is the reading of AL number of bits from - // the bitstream to find the initial state in the FSE table. - // - Only from the third row onwards, do we start emitting symbols (weights). - - // TODO: Discuss starting condition. Perhaps it makes more sense to count the first symbol emitted on row 2? - // cb.require_zero( - // "num_emitted starts at 0 from the second row", - // meta.query_advice(fse_decoder.num_emitted, Rotation::next()), - // ); + // the bitstream to find the initial state in the FSE table and emit the first symbol. cb.require_equal( "num_emitted starts at 1 from the second row", meta.query_advice(fse_decoder.num_emitted, Rotation::next()), @@ -2062,14 +2055,22 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); // Whatever bitstring we read, is also the initial state in the FSE table, where we // start applying the FSE table. - // TODO: Correct init condition? Whatever bitstring is read on the next row is the initial state cb.require_equal( "init state of FSE table", meta.query_advice(bitstream_decoder.bit_value, Rotation::next()), - // meta.query_advice(fse_decoder.state, Rotation(2)), meta.query_advice(fse_decoder.state, Rotation::next()), ); + // Baseline conditions for FSE state transition + cb.require_zero( + "Current row baseline", + meta.query_advice(fse_decoder.baseline, Rotation::cur()), + ); + cb.require_zero( + "Previous row baseline", + meta.query_advice(fse_decoder.baseline, Rotation::prev()), + ); + let lstream_kind = meta.query_advice(lstream_config.lstream_kind, Rotation::cur()); cb.require_equal( "tag_next after Huffman code depending on Lstream kind", @@ -2101,19 +2102,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // Check for state transition, except if we are on the last row of HuffmanCode. let is_last_row = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); - // TODO: correct baseline targeting? - // let baseline = meta.query_advice(fse_decoder.baseline, Rotation::cur()); // baseline at state let baseline = meta.query_advice(fse_decoder.baseline, Rotation(-2)); // baseline at state let bit_value = meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()); // bits read - // TODO: Correct FSE transition? - // cb.condition(not::expr(is_last_row), |cb| { - // cb.require_equal( - // "state' == baseline(state) + bit_value", - // meta.query_advice(fse_decoder.state, Rotation::next()), - // baseline + bit_value, - // ); - // }); cb.require_equal( "state' == baseline(state) + bit_value (every other row)", meta.query_advice(fse_decoder.state, Rotation::cur()), From c845106dd3c5d1de268c130b957ac8aeb4f9f3e2 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 18:28:18 -0500 Subject: [PATCH 133/165] Remove debug flags --- zkevm-circuits/src/decompression_circuit.rs | 346 +++++++++----------- 1 file changed, 161 insertions(+), 185 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 1e9eac0698..a45321258a 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1141,190 +1141,170 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ////////////////////////////////// ZstdTag::BlockHeader /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// + // TODO: Block constraints will be examined later // Note: We only verify the 1st row of BlockHeader for tag_value. - meta.create_gate("DecompressionCircuit: BlockHeader", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - cb.require_equal( - "tag_len == 3", - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - N_BLOCK_HEADER_BYTES.expr(), - ); - - // The lowest bit (as per little-endian representation) is whether the block is the - // last block in the frame or not. - // - // The next 2 bits denote the block type. - // - // But block header is expressed in the reverse order, which helps us in calculating - // the tag_value appropriately. - cb.require_equal( - "last block check", - meta.query_advice(value_bits[7], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), - meta.query_advice( - block_gadget.is_last_block, - Rotation(N_BLOCK_HEADER_BYTES as i32), - ), - ); - let block_type_bit0 = - meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); - let block_type_bit1 = - meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); - cb.require_zero( - "block type cannot be RESERVED, i.e. block_type == 3 not possible", - block_type_bit0.expr() * block_type_bit1.expr(), - ); - cb.require_equal( - "block_idx == 1", - meta.query_advice(block_gadget.idx, Rotation(N_BLOCK_HEADER_BYTES as i32)), - 1.expr(), - ); - - // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear with - // block type 00 or 01, i.e. the block_type_bit1 is 0. - cb.condition(not::expr(block_type_bit1), |cb| { - cb.require_equal( - "Raw/RLE blocks: tag_len == block_len", - meta.query_advice(tag_gadget.tag_len, Rotation(N_BLOCK_HEADER_BYTES as i32)), - meta.query_advice( - block_gadget.block_len, - Rotation(N_BLOCK_HEADER_BYTES as i32), - ), - ); - }); - // Validate that for an RLE block: value_byte == decoded_byte. - cb.condition(block_type_bit0, |cb| { - cb.require_equal( - "for RLE block, value_byte == decoded_byte", - meta.query_advice(value_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), - meta.query_advice(decoded_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), - ); - }); - - // If this wasn't the first block, then the previous block's last byte should have - // block's idx == block length. - // - // This block is the first block iff the FrameContentSize tag precedes it. However we - // assume that the block_idx and block_len will be set to 0 for FrameContentSize as it - // is not part of a "block". - cb.require_equal( - "block_idx::prev == block_len::prev", - meta.query_advice(block_gadget.idx, Rotation::prev()), - meta.query_advice(block_gadget.block_len, Rotation::prev()), - ); - - cb.gate(and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), - ])) - }); - meta.create_gate("DecompressionCircuit: while processing a block", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // If byte_idx increments, then block_gadet.idx should also increment. - // cb.require_equal( - // "idx in block increments if byte_idx increments", - // meta.query_advice(block_gadget.idx, Rotation::next()) - // - meta.query_advice(block_gadget.idx, Rotation::cur()), - // meta.query_advice(byte_idx, Rotation::next()) - // - meta.query_advice(byte_idx, Rotation::cur()), - // ); - - cb.require_equal( - "block_len remains unchanged", - meta.query_advice(block_gadget.block_len, Rotation::next()), - meta.query_advice(block_gadget.block_len, Rotation::cur()), - ); - - cb.require_equal( - "is_last_block remains unchanged", - meta.query_advice(block_gadget.is_last_block, Rotation::next()), - meta.query_advice(block_gadget.is_last_block, Rotation::cur()), - ); - - cb.gate(and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(block_gadget.is_block, Rotation::cur()), - meta.query_advice(block_gadget.is_block, Rotation::next()), - ])) - }); - meta.create_gate("DecompressionCircuit: handle end of other blocks", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - cb.require_equal( - "tag_next depending on whether or not this is the last block", - meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - ZstdTag::BlockHeader.expr(), - ); - - cb.require_equal( - "block_idx == block_len", - meta.query_advice(block_gadget.idx, Rotation::cur()), - meta.query_advice(block_gadget.block_len, Rotation::cur()), - ); - - // compression_debug - // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); - cb.gate(and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(is_padding, Rotation::cur())), - // compression_debug - // idx_eq_len, - not::expr(meta.query_advice(block_gadget.is_last_block, Rotation::cur())), - ])) - }); - meta.create_gate("DecompressionCircuit: handle end of last block", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // compression_debug - // cb.require_equal( - // "tag_next depending on whether or not this is the last block", - // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - // ZstdTag::Null.expr(), - // ); - - // cb.require_equal( - // "decoded_len has been reached if last block", - // meta.query_advice(decoded_len_acc, Rotation::cur()), - // meta.query_advice(decoded_len, Rotation::cur()), - // ); - - // cb.require_equal( - // "byte idx has reached the encoded len", - // meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(encoded_len, Rotation::cur()), - // ); - - // cb.require_equal( - // "block can end only on Raw/Rle/TODO tag", - // sum::expr([ - // is_raw_block(meta), - // is_rle_block(meta), - // // TODO: there will be other tags where a block ends - // ]), - // 1.expr(), - // ); - - cb.require_equal( - "block_idx == block_len", - meta.query_advice(block_gadget.idx, Rotation::cur()), - meta.query_advice(block_gadget.block_len, Rotation::cur()), - ); - - // compression_debug - // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); - cb.gate(and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - not::expr(meta.query_advice(is_padding, Rotation::cur())), - meta.query_advice(block_gadget.is_last_block, Rotation::cur()), - // compression_debug - // idx_eq_len, - ])) - }); + // meta.create_gate("DecompressionCircuit: BlockHeader", |meta| { + // let mut cb = BaseConstraintBuilder::default(); + // cb.require_equal( + // "tag_len == 3", + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + // N_BLOCK_HEADER_BYTES.expr(), + // ); + // // The lowest bit (as per little-endian representation) is whether the block is the + // // last block in the frame or not. + // // + // // The next 2 bits denote the block type. + // // + // // But block header is expressed in the reverse order, which helps us in calculating + // // the tag_value appropriately. + // cb.require_equal( + // "last block check", + // meta.query_advice(value_bits[7], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), + // meta.query_advice( + // block_gadget.is_last_block, + // Rotation(N_BLOCK_HEADER_BYTES as i32), + // ), + // ); + // let block_type_bit0 = + // meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); + // let block_type_bit1 = + // meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); + // cb.require_zero( + // "block type cannot be RESERVED, i.e. block_type == 3 not possible", + // block_type_bit0.expr() * block_type_bit1.expr(), + // ); + // cb.require_equal( + // "block_idx == 1", + // meta.query_advice(block_gadget.idx, Rotation(N_BLOCK_HEADER_BYTES as i32)), + // 1.expr(), + // ); + // // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear with + // // block type 00 or 01, i.e. the block_type_bit1 is 0. + // cb.condition(not::expr(block_type_bit1), |cb| { + // cb.require_equal( + // "Raw/RLE blocks: tag_len == block_len", + // meta.query_advice(tag_gadget.tag_len, Rotation(N_BLOCK_HEADER_BYTES as i32)), + // meta.query_advice( + // block_gadget.block_len, + // Rotation(N_BLOCK_HEADER_BYTES as i32), + // ), + // ); + // }); + // // Validate that for an RLE block: value_byte == decoded_byte. + // cb.condition(block_type_bit0, |cb| { + // cb.require_equal( + // "for RLE block, value_byte == decoded_byte", + // meta.query_advice(value_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), + // meta.query_advice(decoded_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), + // ); + // }); + // // If this wasn't the first block, then the previous block's last byte should have + // // block's idx == block length. + // // + // // This block is the first block iff the FrameContentSize tag precedes it. However we + // // assume that the block_idx and block_len will be set to 0 for FrameContentSize as it + // // is not part of a "block". + // cb.require_equal( + // "block_idx::prev == block_len::prev", + // meta.query_advice(block_gadget.idx, Rotation::prev()), + // meta.query_advice(block_gadget.block_len, Rotation::prev()), + // ); + // cb.gate(and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + // ])) + // }); + + // meta.create_gate("DecompressionCircuit: while processing a block", |meta| { + // let mut cb = BaseConstraintBuilder::default(); + // // If byte_idx increments, then block_gadet.idx should also increment. + // cb.require_equal( + // "idx in block increments if byte_idx increments", + // meta.query_advice(block_gadget.idx, Rotation::next()) + // - meta.query_advice(block_gadget.idx, Rotation::cur()), + // meta.query_advice(byte_idx, Rotation::next()) + // - meta.query_advice(byte_idx, Rotation::cur()), + // ); + // cb.require_equal( + // "block_len remains unchanged", + // meta.query_advice(block_gadget.block_len, Rotation::next()), + // meta.query_advice(block_gadget.block_len, Rotation::cur()), + // ); + // cb.require_equal( + // "is_last_block remains unchanged", + // meta.query_advice(block_gadget.is_last_block, Rotation::next()), + // meta.query_advice(block_gadget.is_last_block, Rotation::cur()), + // ); + // cb.gate(and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(block_gadget.is_block, Rotation::cur()), + // meta.query_advice(block_gadget.is_block, Rotation::next()), + // ])) + // }); + + // meta.create_gate("DecompressionCircuit: handle end of other blocks", |meta| { + // let mut cb = BaseConstraintBuilder::default(); + // cb.require_equal( + // "tag_next depending on whether or not this is the last block", + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // ZstdTag::BlockHeader.expr(), + // ); + // cb.require_equal( + // "block_idx == block_len", + // meta.query_advice(block_gadget.idx, Rotation::cur()), + // meta.query_advice(block_gadget.block_len, Rotation::cur()), + // ); + // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); + // cb.gate(and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(is_padding, Rotation::cur())), + // idx_eq_len, + // not::expr(meta.query_advice(block_gadget.is_last_block, Rotation::cur())), + // ])) + // }); + + // meta.create_gate("DecompressionCircuit: handle end of last block", |meta| { + // let mut cb = BaseConstraintBuilder::default(); + // cb.require_equal( + // "tag_next depending on whether or not this is the last block", + // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + // ZstdTag::Null.expr(), + // ); + // cb.require_equal( + // "decoded_len has been reached if last block", + // meta.query_advice(decoded_len_acc, Rotation::cur()), + // meta.query_advice(decoded_len, Rotation::cur()), + // ); + // cb.require_equal( + // "byte idx has reached the encoded len", + // meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(encoded_len, Rotation::cur()), + // ); + // cb.require_equal( + // "block can end only on Raw/Rle/TODO tag", + // sum::expr([ + // is_raw_block(meta), + // is_rle_block(meta), + // // TODO: there will be other tags where a block ends + // ]), + // 1.expr(), + // ); + // cb.require_equal( + // "block_idx == block_len", + // meta.query_advice(block_gadget.idx, Rotation::cur()), + // meta.query_advice(block_gadget.block_len, Rotation::cur()), + // ); + // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); + // cb.gate(and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // not::expr(meta.query_advice(is_padding, Rotation::cur())), + // meta.query_advice(block_gadget.is_last_block, Rotation::cur()), + // idx_eq_len, + // ])) + // }); - // compression_debug // meta.lookup( // "DecompressionCircuit: BlockHeader (BlockSize == BlockHeader >> 3)", // |meta| { @@ -1794,7 +1774,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // only check for increments. let is_last = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); - // TODO: Verify that the last row is excluded for trailing bits? cb.condition(not::expr(is_last.clone()), |cb| { cb.require_equal( "fse table reconstruction: decoded symbol increments", @@ -1804,8 +1783,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); cb.require_equal( "number of states assigned so far is accumulated correctly", - // TODO: why is there an extra +1 here?.. - // meta.query_advice(fse_decoder.n_acc, Rotation::cur()) + 1.expr(), meta.query_advice(fse_decoder.n_acc, Rotation::cur()), meta.query_advice(fse_decoder.n_acc, Rotation::prev()) + (meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()) - 1.expr()), @@ -1823,7 +1800,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // TODO: Verify that the second witness row in FSE is also skipped. not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), ])) }, From b4d95d80f04bd6c8603acef217c7a0d128ffa962 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 18:33:02 -0500 Subject: [PATCH 134/165] Correct constraint --- zkevm-circuits/src/decompression_circuit.rs | 36 ++++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index a45321258a..c04c6a1c9d 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -656,21 +656,19 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // on the next row iff: // - tag_idx == tag_len // - byte_idx' == byte_idx + 1 - - // TODO: This constraints might be incorrect as is_new_byte specifies the byte on current row is new - // but for is_tag_change, it instead requires that the byte on the next row is new. - - // let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, None); - // cb.condition(and::expr([ - // tidx_eq_tlen, - // is_new_byte - // ]), |cb| { - // cb.require_equal( - // "is_tag_change should be set", - // meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), - // 1.expr(), - // ); - // }); + let is_next_new_byte = meta.query_advice(byte_idx, Rotation::next()) + - meta.query_advice(byte_idx, Rotation::cur()); + let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, None); + cb.condition(and::expr([ + tidx_eq_tlen, + is_next_new_byte + ]), |cb| { + cb.require_equal( + "is_tag_change should be set", + meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), + 1.expr(), + ); + }); cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -3307,13 +3305,19 @@ impl DecompressionCircuitConfig { )?; } - // TODO: Dummy row for sequencing section header + // TODO: Assign sequence section. Dummy row for sequencing section header as of now region.assign_advice( || "byte_idx", self.byte_idx, witness_rows.len(), || Value::known(F::from((last_byte_idx + 1) as u64)), )?; + region.assign_advice( + || "tag_gadget.is_tag_change", + self.tag_gadget.is_tag_change, + witness_rows.len(), + || Value::known(F::one()), + )?; Ok(()) } From c017103b6b6e16eee455f115c0e2fdf55ec500ea Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 19:43:50 -0500 Subject: [PATCH 135/165] Assign fse table --- zkevm-circuits/src/decompression_circuit.rs | 13 +++-- zkevm-circuits/src/table/decompression.rs | 2 +- zkevm-circuits/src/witness/zstd/mod.rs | 59 ++++++++++++++------- 3 files changed, 51 insertions(+), 23 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index c04c6a1c9d..976f2bcfad 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -33,8 +33,7 @@ use crate::{ }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::{ - Block, LstreamNum, ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, - N_JUMP_TABLE_BYTES, process, value_bits_le + process, value_bits_le, Block, FseAuxiliaryTableData, LstreamNum, ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, N_JUMP_TABLE_BYTES }, }; @@ -128,6 +127,7 @@ pub struct DecompressionCircuitConfig { literals_header_rom_table: LiteralsHeaderRomTable, literals_header_table: LiteralsHeaderTable, bitstring_accumulation_table: BitstringAccumulationTable, + fse_table: FseTable, } /// Block level details are specified in these columns. @@ -2827,6 +2827,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { literals_header_rom_table, literals_header_table, bitstring_accumulation_table: bs_acc_table, + fse_table, } } } @@ -2838,12 +2839,14 @@ impl DecompressionCircuitConfig { layouter: &mut impl Layouter, witness_rows: Vec>, aux_data: Vec, + fse_aux_tables: Vec, challenges: &Challenges>, ) -> Result<(), Error> { let mut jump_table_idx: usize = 0; let mut rand_pow: Vec> = vec![Value::known(F::one())]; self.bitstring_accumulation_table.assign(layouter, &witness_rows)?; + self.fse_table.assign(layouter, fse_aux_tables)?; layouter.assign_region( || "Decompression table region", @@ -3353,13 +3356,15 @@ impl SubCircuit for DecompressionCircuit { ) -> Result<(), Error> { let mut witness_rows: Vec> = vec![]; let mut data: Vec = vec![]; + let mut fse_aux_tables = vec![]; for idx in 0..self.compressed_frames.len() { - let (rows, _decoded_literals, aux_data) = process::(&self.compressed_frames[idx], challenges.keccak_input()); + let (rows, _decoded_literals, aux_data, f_fse_aux_tables) = process::(&self.compressed_frames[idx], challenges.keccak_input()); witness_rows.extend_from_slice(&rows); data.extend_from_slice(&aux_data); + fse_aux_tables.extend_from_slice(&f_fse_aux_tables); } - config.assign(layouter, witness_rows, data, challenges) + config.assign(layouter, witness_rows, data, fse_aux_tables, challenges) } } diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index ff4e0c0bab..7da6906cde 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -430,7 +430,7 @@ impl FseTable { } /// Load witness. - pub fn dev_load( + pub fn assign( &self, layouter: &mut impl Layouter, data: Vec, diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 2b9f2c8b25..814ce0de01 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeMap; + use eth_types::Field; use halo2_proofs::circuit::Value; @@ -216,7 +218,7 @@ fn process_block( byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>, bool, Vec, Vec, Vec) { +) -> (usize, Vec>, bool, Vec, Vec, Vec, FseAuxiliaryTableData) { let mut witness_rows = vec![]; let (byte_offset, rows, last_block, block_type, block_size) = @@ -224,7 +226,7 @@ fn process_block( witness_rows.extend_from_slice(&rows); let last_row = rows.last().expect("last row expected to exist"); - let (_byte_offset, rows, literals, lstream_len, aux_data) = match block_type { + let (_byte_offset, rows, literals, lstream_len, aux_data, fse_aux_table) = match block_type { BlockType::RawBlock => process_block_raw( src, byte_offset, @@ -253,7 +255,7 @@ fn process_block( }; witness_rows.extend_from_slice(&rows); - (byte_offset, witness_rows, last_block, literals, lstream_len, aux_data) + (byte_offset, witness_rows, last_block, literals, lstream_len, aux_data, fse_aux_table) } fn process_block_header( @@ -515,7 +517,7 @@ fn process_block_raw( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec, Vec) { +) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData) { let tag_next = if last_block { ZstdTag::Null } else { @@ -532,7 +534,13 @@ fn process_block_raw( tag_next, ); - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0]) + let fse_aux_table = FseAuxiliaryTableData { + byte_offset: 0, + table_size: 0, + sym_to_states: BTreeMap::default() + }; + + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0], fse_aux_table) } fn process_block_rle( @@ -542,7 +550,7 @@ fn process_block_rle( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec, Vec) { +) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData) { let tag_next = if last_block { ZstdTag::Null } else { @@ -559,7 +567,13 @@ fn process_block_rle( tag_next, ); - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0]) + let fse_aux_table = FseAuxiliaryTableData { + byte_offset: 0, + table_size: 0, + sym_to_states: BTreeMap::default() + }; + + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0], fse_aux_table) } #[allow(unused_variables)] @@ -570,7 +584,7 @@ fn process_block_zstd( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec, Vec) { +) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData) { let mut witness_rows = vec![]; // 1-5 bytes LiteralSectionHeader @@ -589,6 +603,11 @@ fn process_block_zstd( randomness ); witness_rows.extend_from_slice(&rows); + let mut fse_aux_table = FseAuxiliaryTableData { + byte_offset: 0, + table_size: 0, + sym_to_states: BTreeMap::default() + }; // Depending on the literals block type, decode literals section accordingly let (bytes_offset, rows, literals, lstream_len, aux_data): (usize, Vec>, Vec, Vec, Vec) = match literals_block_type { @@ -621,7 +640,7 @@ fn process_block_zstd( BlockType::ZstdCompressedBlock => { let mut huffman_rows = vec![]; - let (bytes_offset, rows, huffman_codes, n_huffman_bytes, huffman_byte_offset, last_rlc, huffman_idx, fse_size, fse_accuracy, n_huffman_bitstream_bytes) = process_block_zstd_huffman_code( + let (bytes_offset, rows, huffman_codes, n_huffman_bytes, huffman_byte_offset, last_rlc, huffman_idx, fse_size, fse_accuracy, n_huffman_bitstream_bytes, fse_aux_data) = process_block_zstd_huffman_code( src, byte_offset, rows.last().expect("last row must exist"), @@ -629,6 +648,7 @@ fn process_block_zstd( n_streams, ); huffman_rows.extend_from_slice(&rows); + fse_aux_table = fse_aux_data; // Subtract huffman header (1-byte), len of huffman bytes and 6-byte jump table (if n_streams > 1) let mut literal_stream_size = compressed_size - (n_huffman_bytes + 1); @@ -676,7 +696,7 @@ fn process_block_zstd( }; witness_rows.extend_from_slice(&rows); - (bytes_offset, witness_rows, literals, lstream_len, vec![regen_size as u64, compressed_size as u64, aux_data[0], aux_data[1], aux_data[2], aux_data[3], branch, sf_max as u64]) + (bytes_offset, witness_rows, literals, lstream_len, vec![regen_size as u64, compressed_size as u64, aux_data[0], aux_data[1], aux_data[2], aux_data[3], branch, sf_max as u64], fse_aux_table) } fn process_block_zstd_literals_header( @@ -808,7 +828,7 @@ fn process_block_zstd_huffman_code( last_row: &ZstdWitnessRow, randomness: Value, n_streams: usize, -) -> (usize, Vec>, HuffmanCodesData, usize, usize, Value, usize, u64, u64, u64) { +) -> (usize, Vec>, HuffmanCodesData, usize, usize, Value, usize, u64, u64, u64, FseAuxiliaryTableData) { // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; @@ -1133,7 +1153,7 @@ fn process_block_zstd_huffman_code( let mut fse_table_idx: u64 = 1; // Convert FSE auxiliary data into a state-indexed representation - let fse_state_table = table.parse_state_table(); + let fse_state_table = table.clone().parse_state_table(); while current_bit_idx + next_nb_to_read[color] <= (n_huffman_code_bytes) * N_BITS_PER_BYTE { let nb = next_nb_to_read[color]; @@ -1238,6 +1258,7 @@ fn process_block_zstd_huffman_code( (1 << accuracy_log) as u64, accuracy_log as u64, n_huffman_code_bytes as u64, + table, // FSE table ) } @@ -1600,10 +1621,11 @@ fn process_block_zstd_lstream( } /// Process a slice of bytes into decompression circuit witness rows -pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec, Vec) { +pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec, Vec, Vec) { let mut witness_rows = vec![]; let mut literals: Vec = vec![]; let mut aux_data: Vec = vec![]; + let mut fse_aux_tables: Vec = vec![]; let byte_offset = 0; // FrameHeaderDescriptor and FrameContentSize @@ -1616,7 +1638,7 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec( + let (_byte_offset, rows, last_block, new_literals, lstream_lens, pipeline_data, fse_aux_table) = process_block::( src, byte_offset, rows.last().expect("last row expected to exist"), @@ -1626,6 +1648,7 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec(src: &[u8], randomness: Value) -> (Vec(&compressed, Value::known(Fr::from(123456789))); + let (_witness_rows, _decoded_literals, _aux_data, fse_aux_tables) = process::(&compressed, Value::known(Fr::from(123456789))); Ok(()) } @@ -1738,7 +1761,7 @@ mod tests { 0x54, 0x40, 0x29, 0x01, ]; - let (_byte_offset, _witness_rows, huffman_codes, _n_huffan_bytes, _huffman_byte_offset, _last_rlc, _huffman_idx, _fse_size, _fse_accuracy, _n_huffman_bitstream_bytes) = + let (_byte_offset, _witness_rows, huffman_codes, _n_huffan_bytes, _huffman_byte_offset, _last_rlc, _huffman_idx, _fse_size, _fse_accuracy, _n_huffman_bitstream_bytes, fse_aux_data) = process_block_zstd_huffman_code::( &input, 0, @@ -1866,7 +1889,7 @@ mod tests { 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, ]; - let (_witness_rows, decoded_literals, _aux_data) = process::(&encoded, Value::known(Fr::from(123456789))); + let (_witness_rows, decoded_literals, _aux_data, fse_aux_tables) = process::(&encoded, Value::known(Fr::from(123456789))); let decoded_literal_string: String = decoded_literals.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); let expected_literal_string = String::from("Romeo and Juliet\nExcerpt from Act 2, Scene 2\n\nJULIET\nO ,! wherefore art thou?\nDeny thy fatherrefusename;\nOr, ifwilt not, be but sworn my love,\nAnd I'll no longera Capulet.\n\nROMEO\n[Aside] Shall I hear more, or sspeak at this?'Tis that isenemy;\nTyself,gh a Montague.\nWhat's? inor hand,foot,\nNor armaceany opart\nBeing to a man. Osome!in a?which we ca rose\nBy would smell as sweet;\nSo, were he'd,\nRetaindear perfectionhe owes\nWithoitle.dofffor oee\nTake mI t hy word:\nCebe new baptized;\nHencth I never will. manthus bescreen'dnightstumblest on my counsel?\n"); From 320724d72fb7b8e2279e5ed1a8b8dc5e9fb9e3ba Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 20:33:11 -0500 Subject: [PATCH 136/165] Recover lookup --- zkevm-circuits/src/decompression_circuit.rs | 71 ++++++++++----------- zkevm-circuits/src/witness/zstd/mod.rs | 8 ++- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 976f2bcfad..e89febb00d 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1773,12 +1773,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let is_last = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); cb.condition(not::expr(is_last.clone()), |cb| { - cb.require_equal( - "fse table reconstruction: decoded symbol increments", - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::prev()) - + 1.expr(), - ); cb.require_equal( "number of states assigned so far is accumulated correctly", meta.query_advice(fse_decoder.n_acc, Rotation::cur()), @@ -1937,37 +1931,38 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockFseCode (symbol count check)", - // |meta| { - // let (huffman_byte_offset, bit_value, decoded_symbol) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), - // ); - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // ]); - // // The FSE table reconstruction follows a variable bit packing. However we know the - // // start and end bit index for the bitstring that was read. We read a value in the - // // range 0..=R+1 and then subtract 1 from it to get N, i.e. the number of slots - // // that were allocated to that symbol in the FSE table. This is also the count of - // // the symbol in the FseTable. - // [ - // huffman_byte_offset, // huffman ID - // meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), // table size - // decoded_symbol, // decoded symbol. - // bit_value - 1.expr(), // symbol count - // ] - // .into_iter() - // .zip(fse_table.table_exprs_symbol_count_check(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockFseCode (symbol count check)", + |meta| { + let (huffman_byte_offset, bit_value, decoded_symbol) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), + ); + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), // Exclude huffman header byte + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), // Exclude accuracy log bits + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::next())), // Exclude trailing bits + ]); + // The FSE table reconstruction follows a variable bit packing. However we know the + // start and end bit index for the bitstring that was read. We read a value in the + // range 0..=R+1 and then subtract 1 from it to get N, i.e. the number of slots + // that were allocated to that symbol in the FSE table. This is also the count of + // the symbol in the FseTable. + [ + huffman_byte_offset, // huffman ID + meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), // table size + decoded_symbol, // decoded symbol. + bit_value - 1.expr(), // symbol count + ] + .into_iter() + .zip(fse_table.table_exprs_symbol_count_check(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); meta.create_gate("DecompressionCircuit: HuffmanTreeSection", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -3364,7 +3359,7 @@ impl SubCircuit for DecompressionCircuit { data.extend_from_slice(&aux_data); fse_aux_tables.extend_from_slice(&f_fse_aux_tables); } - + config.assign(layouter, witness_rows, data, fse_aux_tables, challenges) } } diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 814ce0de01..0efdbd2cc5 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -957,9 +957,15 @@ fn process_block_zstd_huffman_code( last_to_bit_idx = to_bit_idx; + // compression_debug + // if sym > 0 && n_acc < (1 << accuracy_log) { + // // num_emitted += 1; + // decoded = sym as u8; + // n_acc += (*value - 1) as usize; + // } if sym > 0 && n_acc < (1 << accuracy_log) { // num_emitted += 1; - decoded = sym as u8; + decoded = (sym - 1) as u8; n_acc += (*value - 1) as usize; } From c2fecdefcad1719f7af67017ea82f852f299ed60 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 21:07:40 -0500 Subject: [PATCH 137/165] Recover lookup --- zkevm-circuits/src/decompression_circuit.rs | 63 ++++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index e89febb00d..83196f4223 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2242,33 +2242,40 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // in that Huffman table. As per the canonical Huffman code representation, we only need to // emit N - 1 weights and the weight of the last symbol can be calculated. - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), - // ]); - // let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); - // let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); - // let num_bits = end - start + 1.expr(); - // [ - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), - // meta.query_advice(fse_decoder.state, Rotation::cur()), - // meta.query_advice(fse_decoder.symbol, Rotation::cur()), - // meta.query_advice(fse_decoder.baseline, Rotation::cur()), - // num_bits, - // ] - // .into_iter() - // .zip(fse_table.table_exprs_state_check(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // TODO: # of bits read is determined on the next state + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::next())), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation(2))), + ]); + + // TODO: include num_bits in lookup + // let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation(2)); + // let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation(2)); + // let num_bits = end - start + 1.expr(); + + [ + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), + meta.query_advice(fse_decoder.state, Rotation::cur()), + meta.query_advice(fse_decoder.symbol, Rotation::cur()), + meta.query_advice(fse_decoder.baseline, Rotation::cur()), + // TODO: a complication of nb representation between reading 0 bit and 1 bit. + // The bit_start_idx and bit_end_idx for both scenarios are set to the same value. + // num_bits, + ] + .into_iter() + .zip(fse_table.table_exprs_state_check(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); // compression_debug // meta.lookup_any( @@ -3359,7 +3366,7 @@ impl SubCircuit for DecompressionCircuit { data.extend_from_slice(&aux_data); fse_aux_tables.extend_from_slice(&f_fse_aux_tables); } - + config.assign(layouter, witness_rows, data, fse_aux_tables, challenges) } } From 8b1d6202dc307807470a9b170348465a2a28aac8 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 22:56:31 -0500 Subject: [PATCH 138/165] Recover lookup --- zkevm-circuits/src/decompression_circuit.rs | 59 ++++++++++++--------- zkevm-circuits/src/table/decompression.rs | 3 +- zkevm-circuits/src/witness/zstd/mod.rs | 45 ++++++++++------ 3 files changed, 66 insertions(+), 41 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 83196f4223..236fd02493 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -33,7 +33,7 @@ use crate::{ }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::{ - process, value_bits_le, Block, FseAuxiliaryTableData, LstreamNum, ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, N_JUMP_TABLE_BYTES + process, value_bits_le, Block, FseAuxiliaryTableData, HuffmanCodesData, LstreamNum, ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, N_JUMP_TABLE_BYTES }, }; @@ -128,6 +128,7 @@ pub struct DecompressionCircuitConfig { literals_header_table: LiteralsHeaderTable, bitstring_accumulation_table: BitstringAccumulationTable, fse_table: FseTable, + huffman_codes_table: HuffmanCodesTable, } /// Block level details are specified in these columns. @@ -1468,7 +1469,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug + // TODO: LiteralHeader regen/compr size // meta.lookup_any( // "DecompressionCircuit: lookup for LiteralsHeader regen/compr size", // |meta| { @@ -2277,27 +2278,28 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockHuffmanCode (huffman codes table lookup)", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), - // ]); - // [ - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // meta.query_advice(fse_decoder.symbol, Rotation::cur()), - // ] - // .into_iter() - // .zip(huffman_codes_table.table_exprs_canonical_weight(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockHuffmanCode (huffman codes table lookup)", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), + ]); + [ + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // TODO: Ask about assumption - bit_value is used for FSE state transition only but not related to the actual symbol + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + meta.query_advice(fse_decoder.num_emitted, Rotation::cur()) - 1.expr(), + meta.query_advice(fse_decoder.symbol, Rotation::cur()), + ] + .into_iter() + .zip(huffman_codes_table.table_exprs_canonical_weight(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); // compression_debug // meta.lookup_any( @@ -2788,6 +2790,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), // TODO: Modify to prev -> cur? + // compression_debug not::expr(meta.query_fixed(q_enable, Rotation::cur())), sum::expr([ meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), @@ -2830,6 +2833,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { literals_header_table, bitstring_accumulation_table: bs_acc_table, fse_table, + huffman_codes_table, } } } @@ -2842,6 +2846,7 @@ impl DecompressionCircuitConfig { witness_rows: Vec>, aux_data: Vec, fse_aux_tables: Vec, + huffman_codes: Vec, challenges: &Challenges>, ) -> Result<(), Error> { let mut jump_table_idx: usize = 0; @@ -2849,6 +2854,8 @@ impl DecompressionCircuitConfig { self.bitstring_accumulation_table.assign(layouter, &witness_rows)?; self.fse_table.assign(layouter, fse_aux_tables)?; + self.huffman_codes_table.assign(layouter, huffman_codes)?; + layouter.assign_region( || "Decompression table region", @@ -3359,14 +3366,16 @@ impl SubCircuit for DecompressionCircuit { let mut witness_rows: Vec> = vec![]; let mut data: Vec = vec![]; let mut fse_aux_tables = vec![]; + let mut huffman_aux_data = vec![]; for idx in 0..self.compressed_frames.len() { - let (rows, _decoded_literals, aux_data, f_fse_aux_tables) = process::(&self.compressed_frames[idx], challenges.keccak_input()); + let (rows, _decoded_literals, aux_data, f_fse_aux_tables, huffman_codes) = process::(&self.compressed_frames[idx], challenges.keccak_input()); witness_rows.extend_from_slice(&rows); data.extend_from_slice(&aux_data); fse_aux_tables.extend_from_slice(&f_fse_aux_tables); + huffman_aux_data.extend_from_slice(&huffman_codes); } - config.assign(layouter, witness_rows, data, fse_aux_tables, challenges) + config.assign(layouter, witness_rows, data, fse_aux_tables, huffman_aux_data, challenges) } } diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index 7da6906cde..edef0dfe54 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -919,7 +919,7 @@ impl HuffmanCodesTable { } /// Load witness to the huffman codes table: dev mode. - pub fn dev_load( + pub fn assign( &self, layouter: &mut impl Layouter, data: Vec, @@ -932,6 +932,7 @@ impl HuffmanCodesTable { for code in data.iter() { let byte_offset = Value::known(F::from(code.byte_offset)); let (max_bitstring_len, sym_map) = code.parse_canonical(); + let max_bitstring_len = Value::known(F::from(max_bitstring_len)); let sum_weights = Value::known(F::from( sym_map diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 0efdbd2cc5..416293137d 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -218,7 +218,7 @@ fn process_block( byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>, bool, Vec, Vec, Vec, FseAuxiliaryTableData) { +) -> (usize, Vec>, bool, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData) { let mut witness_rows = vec![]; let (byte_offset, rows, last_block, block_type, block_size) = @@ -226,7 +226,7 @@ fn process_block( witness_rows.extend_from_slice(&rows); let last_row = rows.last().expect("last row expected to exist"); - let (_byte_offset, rows, literals, lstream_len, aux_data, fse_aux_table) = match block_type { + let (_byte_offset, rows, literals, lstream_len, aux_data, fse_aux_table, huffman_codes) = match block_type { BlockType::RawBlock => process_block_raw( src, byte_offset, @@ -255,7 +255,7 @@ fn process_block( }; witness_rows.extend_from_slice(&rows); - (byte_offset, witness_rows, last_block, literals, lstream_len, aux_data, fse_aux_table) + (byte_offset, witness_rows, last_block, literals, lstream_len, aux_data, fse_aux_table, huffman_codes) } fn process_block_header( @@ -517,7 +517,7 @@ fn process_block_raw( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData) { +) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData) { let tag_next = if last_block { ZstdTag::Null } else { @@ -539,8 +539,12 @@ fn process_block_raw( table_size: 0, sym_to_states: BTreeMap::default() }; + let mut huffman_weights = HuffmanCodesData { + byte_offset: 0, + weights: vec![] + }; - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0], fse_aux_table) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0], fse_aux_table, huffman_weights) } fn process_block_rle( @@ -550,7 +554,7 @@ fn process_block_rle( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData) { +) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData) { let tag_next = if last_block { ZstdTag::Null } else { @@ -572,8 +576,12 @@ fn process_block_rle( table_size: 0, sym_to_states: BTreeMap::default() }; + let mut huffman_weights = HuffmanCodesData { + byte_offset: 0, + weights: vec![] + }; - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0], fse_aux_table) + (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0], fse_aux_table, huffman_weights) } #[allow(unused_variables)] @@ -584,7 +592,7 @@ fn process_block_zstd( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData) { +) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData) { let mut witness_rows = vec![]; // 1-5 bytes LiteralSectionHeader @@ -608,6 +616,10 @@ fn process_block_zstd( table_size: 0, sym_to_states: BTreeMap::default() }; + let mut huffman_weights = HuffmanCodesData { + byte_offset: 0, + weights: vec![] + }; // Depending on the literals block type, decode literals section accordingly let (bytes_offset, rows, literals, lstream_len, aux_data): (usize, Vec>, Vec, Vec, Vec) = match literals_block_type { @@ -649,6 +661,7 @@ fn process_block_zstd( ); huffman_rows.extend_from_slice(&rows); fse_aux_table = fse_aux_data; + huffman_weights = huffman_codes.clone(); // Subtract huffman header (1-byte), len of huffman bytes and 6-byte jump table (if n_streams > 1) let mut literal_stream_size = compressed_size - (n_huffman_bytes + 1); @@ -696,7 +709,7 @@ fn process_block_zstd( }; witness_rows.extend_from_slice(&rows); - (bytes_offset, witness_rows, literals, lstream_len, vec![regen_size as u64, compressed_size as u64, aux_data[0], aux_data[1], aux_data[2], aux_data[3], branch, sf_max as u64], fse_aux_table) + (bytes_offset, witness_rows, literals, lstream_len, vec![regen_size as u64, compressed_size as u64, aux_data[0], aux_data[1], aux_data[2], aux_data[3], branch, sf_max as u64], fse_aux_table, huffman_weights) } fn process_block_zstd_literals_header( @@ -1242,7 +1255,7 @@ fn process_block_zstd_huffman_code( // Construct HuffmanCodesTable let huffman_codes = HuffmanCodesData { - byte_offset: huffman_code_byte_offset as u64, + byte_offset: (huffman_code_byte_offset + 1) as u64, weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() }; @@ -1627,11 +1640,12 @@ fn process_block_zstd_lstream( } /// Process a slice of bytes into decompression circuit witness rows -pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec, Vec, Vec) { +pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec, Vec, Vec, Vec) { let mut witness_rows = vec![]; let mut literals: Vec = vec![]; let mut aux_data: Vec = vec![]; let mut fse_aux_tables: Vec = vec![]; + let mut huffman_codes: Vec = vec![]; let byte_offset = 0; // FrameHeaderDescriptor and FrameContentSize @@ -1644,7 +1658,7 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec( + let (_byte_offset, rows, last_block, new_literals, lstream_lens, pipeline_data, fse_aux_table, huffman_code) = process_block::( src, byte_offset, rows.last().expect("last row expected to exist"), @@ -1655,6 +1669,7 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec(src: &[u8], randomness: Value) -> (Vec(&compressed, Value::known(Fr::from(123456789))); + let (_witness_rows, _decoded_literals, _aux_data, fse_aux_tables, huffman_codes) = process::(&compressed, Value::known(Fr::from(123456789))); Ok(()) } @@ -1895,7 +1910,7 @@ mod tests { 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, ]; - let (_witness_rows, decoded_literals, _aux_data, fse_aux_tables) = process::(&encoded, Value::known(Fr::from(123456789))); + let (_witness_rows, decoded_literals, _aux_data, fse_aux_tables, huffman_codes) = process::(&encoded, Value::known(Fr::from(123456789))); let decoded_literal_string: String = decoded_literals.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); let expected_literal_string = String::from("Romeo and Juliet\nExcerpt from Act 2, Scene 2\n\nJULIET\nO ,! wherefore art thou?\nDeny thy fatherrefusename;\nOr, ifwilt not, be but sworn my love,\nAnd I'll no longera Capulet.\n\nROMEO\n[Aside] Shall I hear more, or sspeak at this?'Tis that isenemy;\nTyself,gh a Montague.\nWhat's? inor hand,foot,\nNor armaceany opart\nBeing to a man. Osome!in a?which we ca rose\nBy would smell as sweet;\nSo, were he'd,\nRetaindear perfectionhe owes\nWithoitle.dofffor oee\nTake mI t hy word:\nCebe new baptized;\nHencth I never will. manthus bescreen'dnightstumblest on my counsel?\n"); From 14f43728123b7e34253b32a162eca81c2824233d Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 22:58:13 -0500 Subject: [PATCH 139/165] Recover lookup --- zkevm-circuits/src/decompression_circuit.rs | 40 ++++++++++----------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 236fd02493..d51491c964 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2301,26 +2301,25 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockHuffmanCode (num symbols in huffman code)", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), - // ]); - // [ - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(fse_decoder.num_emitted, Rotation::cur()), - // 1.expr(), // is_last - // ] - // .into_iter() - // .zip(huffman_codes_table.table_exprs_weights_count(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockHuffmanCode (num symbols in huffman code)", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), + ]); + [ + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(fse_decoder.num_emitted, Rotation::cur()), + 1.expr(), // is_last + ] + .into_iter() + .zip(huffman_codes_table.table_exprs_weights_count(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); debug_assert!(meta.degree() <= 9); @@ -2856,7 +2855,6 @@ impl DecompressionCircuitConfig { self.fse_table.assign(layouter, fse_aux_tables)?; self.huffman_codes_table.assign(layouter, huffman_codes)?; - layouter.assign_region( || "Decompression table region", |mut region| { From 9168ac8441acdb96db94d8009d3c936a0173448f Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 23:04:18 -0500 Subject: [PATCH 140/165] Add comments --- zkevm-circuits/src/decompression_circuit.rs | 36 ++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index d51491c964..901396b0c4 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2746,11 +2746,12 @@ impl SubCircuitConfig for DecompressionCircuitConfig { and::expr([is_not_last.expr(), bitstream_decoder.is_spanned(meta, None)]); // if bitstring is strictly contained. cb.condition(is_strictly_contained, |cb| { - cb.require_equal( - "strictly contained bitstring: bit_index_start", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), - ); + // TODO: Take into account a FSE transition row can read 0 bit + // cb.require_equal( + // "strictly contained bitstring: bit_index_start", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), + // ); cb.require_equal( "strictly contained bitstring: byte_idx", meta.query_advice(byte_idx, Rotation::next()), @@ -2760,16 +2761,18 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // if bitstring is byte-aligned. cb.condition(is_byte_aligned, |cb| { - cb.require_equal( - "byte-aligned bitstring: bit_index_start", - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - 0.expr(), - ); - cb.require_equal( - "byte-aligned bitstring: byte_idx", - meta.query_advice(byte_idx, Rotation::next()), - meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), - ); + // TODO: Take into account a FSE transition row can read 0 bit + // In this case, last row ends at bit_idx 7, then the next row also starts with bit_idx 7 on the same byte_idx + // cb.require_equal( + // "byte-aligned bitstring: bit_index_start", + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + // 0.expr(), + // ); + // cb.require_equal( + // "byte-aligned bitstring: byte_idx", + // meta.query_advice(byte_idx, Rotation::next()), + // meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), + // ); }); // if bitstring is spanned. @@ -2788,9 +2791,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), - // TODO: Modify to prev -> cur? - // compression_debug - not::expr(meta.query_fixed(q_enable, Rotation::cur())), sum::expr([ meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), From b5fcdabed2662089c31345432a68b6be18da2744 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 23:27:38 -0500 Subject: [PATCH 141/165] Recover constraint --- zkevm-circuits/src/decompression_circuit.rs | 23 ++++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 901396b0c4..22fcd34819 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -747,13 +747,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); // compression_debug - // cb.require_equal( - // "value_rlc calculation", - // meta.query_advice(value_rlc, Rotation::cur()), - // meta.query_advice(value_rlc, Rotation::prev()) - // * meta.query_advice(tag_gadget.rand_pow_tag_len, Rotation::prev()) - // + meta.query_advice(tag_gadget.tag_rlc, Rotation::prev()), - // ); + cb.require_equal( + "value_rlc calculation", + meta.query_advice(value_rlc, Rotation::cur()), + meta.query_advice(value_rlc, Rotation::prev()) + * meta.query_advice(tag_gadget.rand_pow_tag_len, Rotation::prev()) + + meta.query_advice(tag_gadget.tag_rlc, Rotation::prev()), + ); cb.condition(is_reverse.expr(), |cb| { cb.require_equal( "tag_rlc_acc == tag_rlc on the first row of tag processed back-to-front", @@ -2859,6 +2859,7 @@ impl DecompressionCircuitConfig { || "Decompression table region", |mut region| { let mut last_byte_idx: usize = 0; + let mut value_rlc = Value::known(F::zero()); for (i, row) in witness_rows.iter().enumerate() { let tag_len = row.state.tag_len as usize; @@ -2901,11 +2902,17 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.encoded_data.encoded_len)), )?; + + if i > 0 && row.state.is_tag_change { + let prev_row = &witness_rows[i - 1]; + value_rlc = value_rlc * rand_pow[prev_row.state.tag_len as usize] + prev_row.state.tag_rlc; + } + region.assign_advice( || "value_rlc", self.value_rlc, i, - || row.encoded_data.value_rlc, + || if i == 0 { Value::known(F::zero()) } else { value_rlc }, )?; // Byte value and bits decomposition From e3abbf3c4410b8eeb6f039d19acebda7f7f04e90 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Mon, 12 Feb 2024 23:28:04 -0500 Subject: [PATCH 142/165] Remove debug flag --- zkevm-circuits/src/decompression_circuit.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 22fcd34819..ca99491ca2 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -745,8 +745,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(tag_gadget.tag_value_acc, Rotation::cur()), meta.query_advice(value_byte, Rotation::cur()), ); - - // compression_debug cb.require_equal( "value_rlc calculation", meta.query_advice(value_rlc, Rotation::cur()), From f6ffa628cbc8635dd8fc33ea719206f89e37c545 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Tue, 13 Feb 2024 11:03:03 +0000 Subject: [PATCH 143/165] assignment to LiteralsHeaderTable --- zkevm-circuits/src/table/decompression.rs | 145 +++++++++++++++------- zkevm-circuits/src/witness/zstd/mod.rs | 6 +- 2 files changed, 104 insertions(+), 47 deletions(-) diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index edef0dfe54..87a39c969e 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -22,7 +22,8 @@ use crate::{ evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, table::BitwiseOp, witness::{ - FseAuxiliaryTableData, FseSymbol, HuffmanCodesData, TagRomTableRow, ZstdTag, ZstdWitnessRow, N_BITS_SYMBOL, N_MAX_SYMBOLS, value_bits_le, + value_bits_le, FseAuxiliaryTableData, FseSymbol, HuffmanCodesData, TagRomTableRow, ZstdTag, + ZstdWitnessRow, N_BITS_SYMBOL, N_MAX_SYMBOLS, }, }; @@ -1213,7 +1214,8 @@ impl BitstringAccumulationTable { ), ); - // TODO: Possibly exclude jump table bytes as they create a gap in byte_idx between huffman code and lstreams + // TODO: Possibly exclude jump table bytes as they create a gap in byte_idx between + // huffman code and lstreams cb.require_equal( "byte2 follows byte2, i.e. byte_idx_2 == byte_idx_1 + 1", meta.query_advice(table.byte_idx_2, Rotation::cur()), @@ -1398,31 +1400,46 @@ impl BitstringAccumulationTable { } /// Load witness to the table: dev mode. - pub fn assign(&self, layouter: &mut impl Layouter, witness_rows: &Vec>) -> Result<(), Error> { + pub fn assign( + &self, + layouter: &mut impl Layouter, + witness_rows: &Vec>, + ) -> Result<(), Error> { assert!(witness_rows.len() > 0); // Get the byte at which FSE is described - let huffman_offset = witness_rows.iter() + let huffman_offset = witness_rows + .iter() .find(|&r| r.state.tag == ZstdTag::ZstdBlockFseCode) .unwrap() - .encoded_data.byte_idx; + .encoded_data + .byte_idx; // Extract bit accumulation-related info from the rows - let accumulation_rows = witness_rows.iter() + let accumulation_rows = witness_rows + .iter() .filter(|&r| { - r.state.tag == ZstdTag::ZstdBlockFseCode || - r.state.tag == ZstdTag::ZstdBlockHuffmanCode || - r.state.tag == ZstdTag::ZstdBlockJumpTable || - r.state.tag == ZstdTag::ZstdBlockLstream + r.state.tag == ZstdTag::ZstdBlockFseCode + || r.state.tag == ZstdTag::ZstdBlockHuffmanCode + || r.state.tag == ZstdTag::ZstdBlockJumpTable + || r.state.tag == ZstdTag::ZstdBlockLstream }) .map(|r| { - let is_reverse: u64 = - if r.state.tag == ZstdTag::ZstdBlockFseCode || r.state.tag == ZstdTag::ZstdBlockJumpTable { - 0 - } else { - 1 - }; - (r.encoded_data.byte_idx as usize, r.encoded_data.value_byte as u64, r.bitstream_read_data.bit_start_idx as usize, r.bitstream_read_data.bit_end_idx as usize, r.bitstream_read_data.bit_value as u64, is_reverse) + let is_reverse: u64 = if r.state.tag == ZstdTag::ZstdBlockFseCode + || r.state.tag == ZstdTag::ZstdBlockJumpTable + { + 0 + } else { + 1 + }; + ( + r.encoded_data.byte_idx as usize, + r.encoded_data.value_byte as u64, + r.bitstream_read_data.bit_start_idx as usize, + r.bitstream_read_data.bit_end_idx as usize, + r.bitstream_read_data.bit_value as u64, + is_reverse, + ) }) .collect::>(); @@ -1447,7 +1464,11 @@ impl BitstringAccumulationTable { let byte_2_bits = value_bits_le(next_row.1 as u8); let bits = if row.5 > 0 { // reversed - [byte_1_bits.into_iter().rev().collect::>(), byte_2_bits.into_iter().rev().collect::>()].concat() + [ + byte_1_bits.into_iter().rev().collect::>(), + byte_2_bits.into_iter().rev().collect::>(), + ] + .concat() } else { // not reversed [byte_1_bits, byte_2_bits].concat() @@ -1455,7 +1476,7 @@ impl BitstringAccumulationTable { let mut acc: u64 = 0; let mut bitstring_len: u64 = 0; - + for bit_idx in (0..16usize).into_iter() { region.assign_fixed( || format!("q_enable"), @@ -1505,7 +1526,7 @@ impl BitstringAccumulationTable { offset + bit_idx, || Value::known(F::from((bit_idx == 0) as u64)), )?; - + let bit = bits[bit_idx] as u64; if bit_idx >= row.2 && bit_idx <= row.3 { acc = acc * 2 + bit; @@ -1566,25 +1587,8 @@ impl BitstringAccumulationTable { )?; Ok(()) - } + }, )?; - - - - - - - - - - - - - - - - - Ok(()) } @@ -1634,7 +1638,7 @@ impl BitstringAccumulationTable { #[derive(Clone, Copy, Debug, EnumIter)] pub enum LiteralsHeaderBranch { /// Raw/RLE block type with size_format 00 or 10. - RawRle0, + RawRle0 = 0, /// Raw/RLE block type with size format 10. RawRle1, /// Raw/RLE block type with size format 11. @@ -1649,6 +1653,20 @@ pub enum LiteralsHeaderBranch { impl_expr!(LiteralsHeaderBranch); +impl From for LiteralsHeaderBranch { + fn from(value: u64) -> Self { + match value { + 0 => Self::RawRle0, + 1 => Self::RawRle1, + 2 => Self::RawRle2, + 3 => Self::Compressed0, + 4 => Self::Compressed1, + 5 => Self::Compressed2, + _ => unreachable!("LiteralsHeaderBranch only from 0..=5"), + } + } +} + impl From for usize { fn from(value: LiteralsHeaderBranch) -> Self { value as usize @@ -1965,15 +1983,54 @@ impl LiteralsHeaderTable { pub fn dev_load( &self, layouter: &mut impl Layouter, - literals_headers: Vec>, + literals_headers: &[(u64, &[u8], u64, u64, u64)], /* (byte_offset, bytes, branch, + * regen_size, compr_size) */ ) -> Result<(), Error> { layouter.assign_region( || "LiteralsHeaderTable", - |_region| { - for (_i, header) in literals_headers.iter().enumerate() { - let _n_bytes_header = header.len(); - // TODO: make the appropriate assignment. + |mut region| { + for (offset, &(byte_offset, header, branch, regen_size, compr_size)) in + literals_headers.iter().enumerate() + { + assert!(header.len() <= 5); + let [byte0, byte1, byte2, byte3, byte4] = [0, 1, 2, 3, 4] + .map(|i| header.get(i).cloned().map_or(0u64, |byte| byte as u64)); + region.assign_fixed( + || "q_enable", + self.q_enable, + offset, + || Value::known(F::one()), + )?; + for (col, value, annotation) in [ + (self.byte_offset, byte_offset, "byte_offset"), + (self.branch, branch, "branch"), + (self.byte0, byte0, "byte0"), + (self.byte1, byte1, "byte1"), + (self.byte2, byte2, "byte2"), + (self.byte3, byte3, "byte3"), + (self.byte4, byte4, "byte4"), + (self.byte0_rs_3, byte0 >> 3, "byte0_rs_3"), + (self.byte0_rs_4, byte0 >> 4, "byte0_rs_4"), + (self.byte1_rs_6, byte1 >> 6, "byte1_rs_6"), + (self.byte1_and_63, byte1 & 63, "byte1_and_63"), + (self.byte2_rs_2, byte2 >> 2, "byte2_rs_2"), + (self.byte2_rs_6, byte2 >> 6, "byte2_rs_6"), + (self.byte2_and_3, byte2 & 3, "byte2_and_3"), + (self.byte2_and_63, byte2 & 63, "byte2_and_63"), + (self.regen_size, regen_size, "regen_size"), + (self.compr_size, compr_size, "compr_size"), + ] { + region.assign_advice( + || annotation, + col, + offset, + || Value::known(F::from(value)), + )?; + } + let branch_chip = BinaryNumberChip::construct(self.branch_bits); + branch_chip.assign(&mut region, offset, &LiteralsHeaderBranch::from(branch))?; } + Ok(()) }, ) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 416293137d..6ea6e54acd 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -741,9 +741,9 @@ fn process_block_zstd_literals_header( BlockType::ZstdCompressedBlock => { match size_format { 0b00 => [2, 10, 10, 1, 3, 3], - 0b01 => [2, 10, 10, 4, 3, 4], - 0b10 => [2, 14, 14, 4, 4, 5], - 0b11 => [2, 18, 18, 4, 5, 6], + 0b01 => [2, 10, 10, 4, 3, 3], + 0b10 => [2, 14, 14, 4, 4, 4], + 0b11 => [2, 18, 18, 4, 5, 5], _ => unreachable!("size_format out of bound") } }, From 1ad05d00b7122b43d27dd7edae4d050df7e56934 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Tue, 13 Feb 2024 12:03:01 +0000 Subject: [PATCH 144/165] introduce is_nil for bitstream_decoder that is set when no bits are read --- zkevm-circuits/src/decompression_circuit.rs | 301 +++++++++++++------- 1 file changed, 195 insertions(+), 106 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index ca99491ca2..647fc74161 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -8,6 +8,22 @@ mod test; use std::marker::PhantomData; +use crate::{ + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + table::{ + decompression::{ + BitstringAccumulationTable, BlockTypeRomTable, FseTable, HuffmanCodesTable, + LiteralsHeaderRomTable, LiteralsHeaderTable, TagRomTable, + }, + KeccakTable, LookupTable, Pow2Table, PowOfRandTable, RangeTable, U8Table, + }, + util::{Challenges, SubCircuit, SubCircuitConfig}, + witness::{ + process, value_bits_le, Block, FseAuxiliaryTableData, HuffmanCodesData, LstreamNum, + ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, + N_JUMP_TABLE_BYTES, + }, +}; use array_init::array_init; use eth_types::Field; use gadgets::{ @@ -23,19 +39,6 @@ use halo2_proofs::{ }, poly::Rotation, }; -use crate::{ - evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, - table::{ - decompression::{ - BitstringAccumulationTable, BlockTypeRomTable, FseTable, HuffmanCodesTable, - LiteralsHeaderRomTable, LiteralsHeaderTable, TagRomTable, - }, KeccakTable, LookupTable, Pow2Table, PowOfRandTable, RangeTable, U8Table - }, - util::{Challenges, SubCircuit, SubCircuitConfig}, - witness::{ - process, value_bits_le, Block, FseAuxiliaryTableData, HuffmanCodesData, LstreamNum, ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, N_JUMP_TABLE_BYTES - }, -}; /// Tables, challenge API used to configure the Decompression circuit. pub struct DecompressionCircuitConfigArgs { @@ -244,6 +247,10 @@ struct HuffmanConfig { /// could span over two bytes. #[derive(Clone, Debug)] pub struct BitstreamDecoder { + /// Boolean that is set for the special case that we don't read from the bitstream, i.e. we + /// read 0 number of bits. This case can only occur while processing the + /// tag=ZstdBlockHuffmanCode. + is_nil: Column, /// The bit-index where the bittsring begins. 0 <= bit_index_start < 8. bit_index_start: Column, /// The bit-index where the bitstring ends. 0 <= bit_index_end < 16. @@ -473,6 +480,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let bitstream_decoder = { let bit_index_end = meta.advice_column(); BitstreamDecoder { + is_nil: meta.advice_column(), bit_index_start: meta.advice_column(), bit_index_end, bitstring_contained: ComparatorChip::configure( @@ -533,7 +541,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let mut cb = BaseConstraintBuilder::default(); // Boolean columns. - for col in [is_padding, block_gadget.is_last_block] { + for col in [is_padding, block_gadget.is_last_block, bitstream_decoder.is_nil] { cb.require_boolean( "Boolean column check", meta.query_advice(col, Rotation::cur()), @@ -621,7 +629,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let is_new_byte = meta.query_advice(byte_idx, Rotation::cur()) - meta.query_advice(byte_idx, Rotation::prev()); - + cb.require_boolean( "byte_idx' == byte_idx or byte_idx' == byte_idx + 1", is_new_byte.expr(), @@ -660,10 +668,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let is_next_new_byte = meta.query_advice(byte_idx, Rotation::next()) - meta.query_advice(byte_idx, Rotation::cur()); let (_, tidx_eq_tlen) = tag_gadget.idx_cmp_len.expr(meta, None); - cb.condition(and::expr([ - tidx_eq_tlen, - is_next_new_byte - ]), |cb| { + cb.condition(and::expr([tidx_eq_tlen, is_next_new_byte]), |cb| { cb.require_equal( "is_tag_change should be set", meta.query_advice(tag_gadget.is_tag_change, Rotation::next()), @@ -846,7 +851,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); }, ); - + let value_byte_prev = meta.query_advice(value_byte, Rotation::prev()); cb.condition(and::expr([is_new_byte, is_reverse]), |cb| { cb.require_equal( @@ -1176,8 +1181,8 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // meta.query_advice(block_gadget.idx, Rotation(N_BLOCK_HEADER_BYTES as i32)), // 1.expr(), // ); - // // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear with - // // block type 00 or 01, i.e. the block_type_bit1 is 0. + // // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear + // with // block type 00 or 01, i.e. the block_type_bit1 is 0. // cb.condition(not::expr(block_type_bit1), |cb| { // cb.require_equal( // "Raw/RLE blocks: tag_len == block_len", @@ -1200,8 +1205,8 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // // block's idx == block length. // // // // This block is the first block iff the FrameContentSize tag precedes it. However we - // // assume that the block_idx and block_len will be set to 0 for FrameContentSize as it - // // is not part of a "block". + // // assume that the block_idx and block_len will be set to 0 for FrameContentSize as + // it // is not part of a "block". // cb.require_equal( // "block_idx::prev == block_len::prev", // meta.query_advice(block_gadget.idx, Rotation::prev()), @@ -1311,9 +1316,8 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), // ]); // let range_value = meta.query_advice(tag_gadget.tag_value, Rotation::cur()) - // - (meta.query_advice( - // block_gadget.block_len, - // Rotation(N_BLOCK_HEADER_BYTES as i32), + // - (meta.query_advice( block_gadget.block_len, Rotation(N_BLOCK_HEADER_BYTES + // as i32), // ) * 8.expr()); // vec![(condition * range_value, range8.into())] // }, @@ -1420,7 +1424,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ])) }, ); - + meta.lookup_any( "DecompressionCircuit: lookup for tuple (zstd_block_type, tag_next)", |meta| { @@ -1481,8 +1485,8 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // let branch = meta.query_advice(literals_header.branch, Rotation::cur()); // // // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we - // // // already know that block type == 0b11 (TREELESS) will not occur, we can skip the - // // // check for not::expr(value_bits[7]). + // // // already know that block type == 0b11 (TREELESS) will not occur, we can skip + // the // // check for not::expr(value_bits[7]). // let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); // // Is the size format == 0b11. @@ -1531,9 +1535,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // byte2, // byte2 // byte3, // byte3 // byte4, // byte4 - // meta.query_advice(literals_header.regen_size, Rotation::cur()), // regenerated size - // meta.query_advice(literals_header.compr_size, Rotation::cur()), // compressed size - // ] + // meta.query_advice(literals_header.regen_size, Rotation::cur()), // + // regenerated size meta.query_advice(literals_header.compr_size, + // Rotation::cur()), // compressed size ] // .into_iter() // .zip(literals_header_table.table_exprs(meta)) // .map(|(arg, table)| (condition.expr() * arg, table)) @@ -1998,7 +2002,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { /////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////// ZstdTag::ZstdBlockHuffmanCode ///////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////// - + meta.create_gate( "DecompressionCircuit: ZstdBlockHuffmanCode (first row)", |meta| { @@ -2006,7 +2010,8 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // - The first row of the HuffmanCode tag is the leading 0s and sentinel bit. // - The second row of the HuffmanCode tag is the reading of AL number of bits from - // the bitstream to find the initial state in the FSE table and emit the first symbol. + // the bitstream to find the initial state in the FSE table and emit the first + // symbol. cb.require_equal( "num_emitted starts at 1 from the second row", meta.query_advice(fse_decoder.num_emitted, Rotation::next()), @@ -2068,8 +2073,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(fse_decoder.num_emitted, Rotation::prev()) + 1.expr(), ); - // Check for state transition, except if we are on the last row of HuffmanCode. - let is_last_row = meta.query_advice(tag_gadget.is_tag_change, Rotation::next()); let baseline = meta.query_advice(fse_decoder.baseline, Rotation(-2)); // baseline at state let bit_value = meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()); // bits read @@ -2099,6 +2102,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), bitstream_decoder.is_contained(meta, None), + not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), ]); [ huffman_byte_offset, // huffman ID @@ -2131,6 +2135,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), bitstream_decoder.is_contained(meta, None), + not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), ]); [ huffman_byte_offset, // huffman ID @@ -2255,9 +2260,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ]); // TODO: include num_bits in lookup - // let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation(2)); - // let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation(2)); - // let num_bits = end - start + 1.expr(); + let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation(2)); + let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation(2)); + let num_bits = select::expr( + meta.query_advice(bitstream_decoder.is_nil, Rotation::cur()), + 0.expr(), + end - start + 1.expr(), + ); [ meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), @@ -2265,9 +2274,10 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(fse_decoder.state, Rotation::cur()), meta.query_advice(fse_decoder.symbol, Rotation::cur()), meta.query_advice(fse_decoder.baseline, Rotation::cur()), - // TODO: a complication of nb representation between reading 0 bit and 1 bit. - // The bit_start_idx and bit_end_idx for both scenarios are set to the same value. - // num_bits, + // TODO: a complication of nb representation between reading 0 bit and 1 bit. + // The bit_start_idx and bit_end_idx for both scenarios are set to the same + // value. + num_bits, ] .into_iter() .zip(fse_table.table_exprs_state_check(meta)) @@ -2287,7 +2297,8 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ]); [ meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // TODO: Ask about assumption - bit_value is used for FSE state transition only but not related to the actual symbol + // TODO: Ask about assumption - bit_value is used for FSE state transition only + // but not related to the actual symbol // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), meta.query_advice(fse_decoder.num_emitted, Rotation::cur()) - 1.expr(), meta.query_advice(fse_decoder.symbol, Rotation::cur()), @@ -2364,7 +2375,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // // The HuffmanTreeDescriptionSize can be calculated as: // - HuffmanTreeDescriptionSize == byte_idx(JumpTable) - byte_idx(HuffmanTree) - + cb.require_equal( "length of lstream4", meta.query_advice(lstream_config.len_lstream4, Rotation::cur()) @@ -2735,21 +2746,23 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let is_strictly_contained = and::expr([ is_not_last.expr(), bitstream_decoder.is_strictly_contained(meta, None), + not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), ]); let is_byte_aligned = and::expr([ is_not_last.expr(), bitstream_decoder.is_byte_aligned(meta, None), + not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), ]); let is_spanned = and::expr([is_not_last.expr(), bitstream_decoder.is_spanned(meta, None)]); // if bitstring is strictly contained. cb.condition(is_strictly_contained, |cb| { // TODO: Take into account a FSE transition row can read 0 bit - // cb.require_equal( - // "strictly contained bitstring: bit_index_start", - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), - // ); + cb.require_equal( + "strictly contained bitstring: bit_index_start", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()) + 1.expr(), + ); cb.require_equal( "strictly contained bitstring: byte_idx", meta.query_advice(byte_idx, Rotation::next()), @@ -2760,19 +2773,53 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // if bitstring is byte-aligned. cb.condition(is_byte_aligned, |cb| { // TODO: Take into account a FSE transition row can read 0 bit - // In this case, last row ends at bit_idx 7, then the next row also starts with bit_idx 7 on the same byte_idx - // cb.require_equal( - // "byte-aligned bitstring: bit_index_start", - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), - // 0.expr(), - // ); - // cb.require_equal( - // "byte-aligned bitstring: byte_idx", - // meta.query_advice(byte_idx, Rotation::next()), - // meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), - // ); + // In this case, last row ends at bit_idx 7, then the next row also starts with + // bit_idx 7 on the same byte_idx + cb.require_equal( + "byte-aligned bitstring: bit_index_start", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + 0.expr(), + ); + cb.require_equal( + "byte-aligned bitstring: byte_idx", + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(byte_idx, Rotation::cur()) + 1.expr(), + ); }); + // Special case where we are reading no bits from the bitstream. This can only occur in + // case we are processing tag=ZstdBlockHuffmanCode. + cb.condition( + meta.query_advice(bitstream_decoder.is_nil, Rotation::cur()), + |cb| { + cb.require_equal( + "0 # of bits read can only happen in ZstdBlockHuffmanCode", + meta.query_advice(tag_gadget.tag, Rotation::cur()), + ZstdTag::ZstdBlockHuffmanCode.expr(), + ); + cb.require_equal( + "bit_index_start == bit_index_end since no bit is read", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + ); + cb.require_equal( + "bit_value == 0 since no bit is read", + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + 0.expr(), + ); + cb.require_equal( + "byte_idx' == byte_idx since no bit is read", + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(byte_idx, Rotation::cur()), + ); + cb.require_equal( + "bit_index_start' == bit_index_start since no bit is read", + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + ); + }, + ); + // if bitstring is spanned. cb.condition(is_spanned, |cb| { cb.require_equal( @@ -2849,7 +2896,8 @@ impl DecompressionCircuitConfig { let mut jump_table_idx: usize = 0; let mut rand_pow: Vec> = vec![Value::known(F::one())]; - self.bitstring_accumulation_table.assign(layouter, &witness_rows)?; + self.bitstring_accumulation_table + .assign(layouter, &witness_rows)?; self.fse_table.assign(layouter, fse_aux_tables)?; self.huffman_codes_table.assign(layouter, huffman_codes)?; @@ -2903,14 +2951,21 @@ impl DecompressionCircuitConfig { if i > 0 && row.state.is_tag_change { let prev_row = &witness_rows[i - 1]; - value_rlc = value_rlc * rand_pow[prev_row.state.tag_len as usize] + prev_row.state.tag_rlc; + value_rlc = value_rlc * rand_pow[prev_row.state.tag_len as usize] + + prev_row.state.tag_rlc; } region.assign_advice( || "value_rlc", self.value_rlc, i, - || if i == 0 { Value::known(F::zero()) } else { value_rlc }, + || { + if i == 0 { + Value::known(F::zero()) + } else { + value_rlc + } + }, )?; // Byte value and bits decomposition @@ -2927,14 +2982,17 @@ impl DecompressionCircuitConfig { || "value_bits", *col, i, - || Value::known( - F::from( - (if is_reverse { bits[idx] } else { bits[N_BITS_PER_BYTE - idx - 1] }) as u64 - ) - ), + || { + Value::known(F::from( + (if is_reverse { + bits[idx] + } else { + bits[N_BITS_PER_BYTE - idx - 1] + }) as u64, + )) + }, )?; } - // Decoded Data region.assign_advice( @@ -2962,13 +3020,11 @@ impl DecompressionCircuitConfig { || row.decoded_data.decoded_value_rlc, )?; - // Block Gadget - let is_block = !( - row.state.tag == ZstdTag::FrameHeaderDescriptor || - row.state.tag == ZstdTag::FrameContentSize || - row.state.tag == ZstdTag::BlockHeader - ) as u64; + let is_block = !(row.state.tag == ZstdTag::FrameHeaderDescriptor + || row.state.tag == ZstdTag::FrameContentSize + || row.state.tag == ZstdTag::BlockHeader) + as u64; region.assign_advice( || "block_gadget.is_block", self.block_gadget.is_block, @@ -2994,10 +3050,10 @@ impl DecompressionCircuitConfig { || Value::known(F::one()), )?; - let idx_cmp_len_chip = ComparatorChip::construct(self.block_gadget.idx_cmp_len.clone()); + let idx_cmp_len_chip = + ComparatorChip::construct(self.block_gadget.idx_cmp_len.clone()); idx_cmp_len_chip.assign(&mut region, i, F::one(), F::one())?; - // Tag Gadget region.assign_advice( || "tag_gadget.tag", @@ -3075,32 +3131,54 @@ impl DecompressionCircuitConfig { let tag_bits = BinaryNumberChip::construct(self.tag_gadget.tag_bits); tag_bits.assign(&mut region, i, &row.state.tag)?; - let idx_cmp_len_chip = ComparatorChip::construct(self.tag_gadget.idx_cmp_len.clone()); - idx_cmp_len_chip.assign(&mut region, i, F::from(row.state.tag_idx), F::from(row.state.tag_len))?; + let idx_cmp_len_chip = + ComparatorChip::construct(self.tag_gadget.idx_cmp_len.clone()); + idx_cmp_len_chip.assign( + &mut region, + i, + F::from(row.state.tag_idx), + F::from(row.state.tag_len), + )?; - let len_cmp_max_chip = ComparatorChip::construct(self.tag_gadget.len_cmp_max.clone()); - len_cmp_max_chip.assign(&mut region, i, F::from(row.state.tag_len), F::from(row.state.max_tag_len))?; + let len_cmp_max_chip = + ComparatorChip::construct(self.tag_gadget.len_cmp_max.clone()); + len_cmp_max_chip.assign( + &mut region, + i, + F::from(row.state.tag_len), + F::from(row.state.max_tag_len), + )?; let max_tag_len = row.state.max_tag_len; let mlen_lt_0x20_chip = LtChip::construct(self.tag_gadget.mlen_lt_0x20.clone()); - mlen_lt_0x20_chip.assign(&mut region, i, F::from(max_tag_len), F::from(0x20 as u64))?; + mlen_lt_0x20_chip.assign( + &mut region, + i, + F::from(max_tag_len), + F::from(0x20 as u64), + )?; let is_block_header = (row.state.tag == ZstdTag::BlockHeader) as u64; - let is_literals_header = (row.state.tag == ZstdTag::ZstdBlockLiteralsHeader) as u64; + let is_literals_header = + (row.state.tag == ZstdTag::ZstdBlockLiteralsHeader) as u64; let is_fse_code = (row.state.tag == ZstdTag::ZstdBlockFseCode) as u64; let is_huffman_code = (row.state.tag == ZstdTag::ZstdBlockHuffmanCode) as u64; let is_lstream = (row.state.tag == ZstdTag::ZstdBlockLstream) as u64; let is_jumptable = (row.state.tag == ZstdTag::ZstdBlockJumpTable) as u64; - let is_literals_section = is_literals_header + is_fse_code + is_huffman_code + is_lstream + is_jumptable; - let is_huffman_tree_section = is_fse_code + is_huffman_code + is_jumptable + is_lstream; - - let is_output = ( - row.state.tag == ZstdTag::RawBlockBytes || - row.state.tag == ZstdTag::RleBlockBytes || - row.state.tag == ZstdTag::ZstdBlockLiteralsRawBytes || - row.state.tag == ZstdTag::ZstdBlockLiteralsRleBytes || - row.state.tag == ZstdTag::ZstdBlockLstream - ) as u64; + let is_literals_section = is_literals_header + + is_fse_code + + is_huffman_code + + is_lstream + + is_jumptable; + let is_huffman_tree_section = + is_fse_code + is_huffman_code + is_jumptable + is_lstream; + + let is_output = (row.state.tag == ZstdTag::RawBlockBytes + || row.state.tag == ZstdTag::RleBlockBytes + || row.state.tag == ZstdTag::ZstdBlockLiteralsRawBytes + || row.state.tag == ZstdTag::ZstdBlockLiteralsRleBytes + || row.state.tag == ZstdTag::ZstdBlockLstream) + as u64; region.assign_advice( || "tag_gadget.is_output", self.tag_gadget.is_output, @@ -3151,7 +3229,6 @@ impl DecompressionCircuitConfig { || Value::known(F::from(is_huffman_tree_section)), )?; - // Literals Header region.assign_advice( || "literals_header.branch", @@ -3184,7 +3261,6 @@ impl DecompressionCircuitConfig { || Value::known(F::from(aux_data[5])), )?; - // Huffman Tree Config region.assign_advice( || "huffman_tree_config.huffman_tree_idx", @@ -3211,7 +3287,6 @@ impl DecompressionCircuitConfig { || Value::known(F::from(aux_data[9])), )?; - // Bitstream Decoder region.assign_advice( || "bitstream_decoder.bit_index_start", @@ -3232,8 +3307,15 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.bitstream_read_data.bit_value as u64)), )?; - let bitstring_contained_chip = ComparatorChip::construct(self.bitstream_decoder.bitstring_contained.clone()); - bitstring_contained_chip.assign(&mut region, i, F::from(row.bitstream_read_data.bit_end_idx as u64), F::from(7u64))?; + let bitstring_contained_chip = ComparatorChip::construct( + self.bitstream_decoder.bitstring_contained.clone(), + ); + bitstring_contained_chip.assign( + &mut region, + i, + F::from(row.bitstream_read_data.bit_end_idx as u64), + F::from(7u64), + )?; region.assign_advice( || "bitstream_decoder.decoded_symbol", @@ -3242,7 +3324,6 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.decoded_data.decoded_byte as u64)), )?; - // FSE Gadget region.assign_advice( || "fse_decoder.num_emitted", @@ -3275,7 +3356,6 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.fse_data.symbol as u64)), )?; - // Lstream Config let is_four_streams: u64 = if aux_data[2] > 0 { 1 } else { 0 }; region.assign_advice( @@ -3291,7 +3371,8 @@ impl DecompressionCircuitConfig { || Value::known(F::from(row.huffman_data.stream_idx as u64)), )?; - let lstream_num_chip = BinaryNumberChip::construct(self.lstream_config.lstream_num); + let lstream_num_chip = + BinaryNumberChip::construct(self.lstream_config.lstream_num); lstream_num_chip.assign(&mut region, i, &row.huffman_data.stream_idx.into())?; region.assign_advice( @@ -3335,9 +3416,9 @@ impl DecompressionCircuitConfig { )?; Ok(()) - } + }, )?; - + Ok(()) } } @@ -3372,13 +3453,21 @@ impl SubCircuit for DecompressionCircuit { let mut huffman_aux_data = vec![]; for idx in 0..self.compressed_frames.len() { - let (rows, _decoded_literals, aux_data, f_fse_aux_tables, huffman_codes) = process::(&self.compressed_frames[idx], challenges.keccak_input()); + let (rows, _decoded_literals, aux_data, f_fse_aux_tables, huffman_codes) = + process::(&self.compressed_frames[idx], challenges.keccak_input()); witness_rows.extend_from_slice(&rows); data.extend_from_slice(&aux_data); fse_aux_tables.extend_from_slice(&f_fse_aux_tables); huffman_aux_data.extend_from_slice(&huffman_codes); } - config.assign(layouter, witness_rows, data, fse_aux_tables, huffman_aux_data, challenges) + config.assign( + layouter, + witness_rows, + data, + fse_aux_tables, + huffman_aux_data, + challenges, + ) } } From 3c4a19581a53c0529dd06cb3bf81326b8a4dfe60 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Tue, 13 Feb 2024 22:08:52 +0000 Subject: [PATCH 145/165] todo: debug --- zkevm-circuits/src/decompression_circuit.rs | 460 +++----------------- zkevm-circuits/src/table/decompression.rs | 113 +++-- zkevm-circuits/src/witness/zstd/types.rs | 5 +- 3 files changed, 121 insertions(+), 457 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 647fc74161..67147215f3 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1800,140 +1800,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (contained bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - bitstream_decoder.is_contained(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - 1.expr(), // bitstring length accumulator, starts at 1 - start, // bit index start - 1.expr(), // denotes that this bit index is a part of the bitstring - 1.expr(), // denotes that this bit index is a part of the bitstring - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (contained bitstream end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - bitstream_decoder.is_contained(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (spanned bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - 1.expr(), // bitstring len acc - start, // bit index start - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - - meta.lookup_any( - "DecompressionCircuit: ZstdBlockFseCode (spanned bitstring end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - meta.lookup_any( "DecompressionCircuit: ZstdBlockFseCode (symbol count check)", |meta| { @@ -2090,138 +1956,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.is_contained(meta, None), - not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - 1.expr(), // bitstring length accumulator, starts at 1 - start, // bit index start - 1.expr(), // denotes that this bit index is a part of the bitstring - 1.expr(), // denotes that this bit index is a part of the bitstring - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (contained bitstream end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.is_contained(meta, None), - not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - 1.expr(), // bitstring len acc - start, // bit index start - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (spanned bitstring end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - // 1. We first read AL number of bits from the bitstream (say bit_value_init) and transition // to the state == bit_value_init. // 2. We then follow the FSE table: @@ -2252,16 +1986,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let condition = and::expr([ meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // TODO: # of bits read is determined on the next state not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::prev())), not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::next())), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation(2))), ]); // TODO: include num_bits in lookup - let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation(2)); - let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation(2)); + let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); + let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); let num_bits = select::expr( meta.query_advice(bitstream_decoder.is_nil, Rotation::cur()), 0.expr(), @@ -2578,136 +2309,79 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - meta.lookup_any( - "DecompressionCircuit: ZstdBlockLstream (contained bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - bitstream_decoder.is_contained(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - 1.expr(), // bitstring length accumulator, starts at 1 - start, // bit index start - 1.expr(), // denotes that this bit index is a part of the bitstring - 1.expr(), // denotes that this bit index is a part of the bitstring - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - - meta.lookup_any( - "DecompressionCircuit: ZstdBlockLstream (contained bitstream end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - bitstream_decoder.is_contained(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(value_byte, Rotation::cur()), // byte value - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] - .into_iter() - .zip(bs_acc_table.table_exprs_contained(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); - - meta.lookup_any( - "DecompressionCircuit: ZstdBlockLstream (spanned bitstream start)", - |meta| { - let (huffman_byte_offset, start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), + meta.lookup_any("DecompressionCircuit: bitstring (start)", |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + sum::expr([ + and::expr([ + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + ]), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - 1.expr(), // bitstring len acc - start, // bit index start - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] + ]), + not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), + ]); + let (huffman_byte_offset, bit_index_start, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + [ + huffman_byte_offset, + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(value_byte, Rotation::cur()), + meta.query_advice(value_byte, Rotation::next()), + bit_value, + 1.expr(), // bitstring_len at start + bit_index_start, + 1.expr(), // from_start + 1.expr(), // until_end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + ] .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) + .zip(bs_acc_table.table_exprs(meta)) .map(|(value, table)| (condition.expr() * value, table)) .collect() - }, - ); - - meta.lookup_any( - "DecompressionCircuit: ZstdBlockLstream (spanned bitstring end)", - |meta| { - let (huffman_byte_offset, start, end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), + }); + meta.lookup_any("DecompressionCircuit: bitstring (end)", |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + sum::expr([ + and::expr([ + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + ]), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - bitstream_decoder.is_spanned(meta, None), - ]); - [ - huffman_byte_offset, // huffman ID - meta.query_advice(byte_idx, Rotation::cur()), // byte index - meta.query_advice(byte_idx, Rotation::next()), // byte index' - meta.query_advice(value_byte, Rotation::cur()), // byte value - meta.query_advice(value_byte, Rotation::next()), // byte value' - bit_value, // bitstring value - end.expr() - start + 1.expr(), // bitstring length - end, // bit index at end - 1.expr(), // from start - 1.expr(), // to end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), // is reverse - ] + ]), + not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), + ]); + let (huffman_byte_offset, bit_index_start, bit_index_end, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + [ + huffman_byte_offset, + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(value_byte, Rotation::cur()), + meta.query_advice(value_byte, Rotation::next()), + bit_value, + bit_index_end.expr() - bit_index_start + 1.expr(), // bitstring_len at end + bit_index_end, + 1.expr(), // from_start + 1.expr(), // until_end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + ] .into_iter() - .zip(bs_acc_table.table_exprs_spanned(meta)) + .zip(bs_acc_table.table_exprs(meta)) .map(|(value, table)| (condition.expr() * value, table)) .collect() - }, - ); - + }); meta.create_gate("DecompressionCircuit: bitstream reader", |meta| { let mut cb = BaseConstraintBuilder::default(); diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index 87a39c969e..5406408409 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -1214,19 +1214,19 @@ impl BitstringAccumulationTable { ), ); - // TODO: Possibly exclude jump table bytes as they create a gap in byte_idx between - // huffman code and lstreams - cb.require_equal( - "byte2 follows byte2, i.e. byte_idx_2 == byte_idx_1 + 1", - meta.query_advice(table.byte_idx_2, Rotation::cur()), - meta.query_advice(table.byte_idx_1, Rotation::cur()) + 1.expr(), - ); - cb.require_boolean( "is_reverse is boolean", meta.query_advice(table.is_reverse, Rotation::cur()), ); + // TODO: Possibly exclude jump table bytes as they create a gap in byte_idx between + // huffman code and lstreams + cb.require_boolean( + "byte2 == byte1 or byte2 == byte1 + 1", + meta.query_advice(table.byte_idx_2, Rotation::cur()) - + meta.query_advice(table.byte_idx_1, Rotation::cur()), + ); + cb.gate(and::expr([ meta.query_fixed(table.q_enabled, Rotation::cur()), meta.query_fixed(table.q_first, Rotation::cur()), @@ -1255,6 +1255,15 @@ impl BitstringAccumulationTable { ); } + let is_last = meta.query_fixed(table.q_first, Rotation::next()); + cb.condition(is_last, |cb| { + cb.require_equal( + "byte_idx_1' == byte_idx_2", + meta.query_advice(table.byte_idx_1, Rotation::next()), + meta.query_advice(table.byte_idx_2, Rotation::cur()), + ); + }); + cb.gate(and::expr([ meta.query_fixed(table.q_enabled, Rotation::cur()), not::expr(meta.query_fixed(table.q_first, Rotation::cur())), @@ -1405,7 +1414,7 @@ impl BitstringAccumulationTable { layouter: &mut impl Layouter, witness_rows: &Vec>, ) -> Result<(), Error> { - assert!(witness_rows.len() > 0); + assert!(!witness_rows.is_empty()); // Get the byte at which FSE is described let huffman_offset = witness_rows @@ -1425,20 +1434,13 @@ impl BitstringAccumulationTable { || r.state.tag == ZstdTag::ZstdBlockLstream }) .map(|r| { - let is_reverse: u64 = if r.state.tag == ZstdTag::ZstdBlockFseCode - || r.state.tag == ZstdTag::ZstdBlockJumpTable - { - 0 - } else { - 1 - }; ( r.encoded_data.byte_idx as usize, r.encoded_data.value_byte as u64, - r.bitstream_read_data.bit_start_idx as usize, - r.bitstream_read_data.bit_end_idx as usize, - r.bitstream_read_data.bit_value as u64, - is_reverse, + r.bitstream_read_data.bit_start_idx, + r.bitstream_read_data.bit_end_idx, + r.bitstream_read_data.bit_value, + r.state.tag.is_reverse() as u64, // is_reverse ) }) .collect::>(); @@ -1449,17 +1451,9 @@ impl BitstringAccumulationTable { || "Bitstring Accumulation Table", |mut region| { let mut offset: usize = 0; - for (idx, row) in accumulation_rows.iter().enumerate() { - let next_row = if idx + 1 < accumulation_rows.len() { - let mut candidate_idx = idx + 1; - while accumulation_rows[candidate_idx].0 == row.0 { - candidate_idx += 1; - } - accumulation_rows[candidate_idx] - } else { - (last_row.0 + 1, 0, 0, 0, 0, 0) - }; - + for rows in accumulation_rows.windows(2) { + let row = rows[0]; + let next_row = rows[1]; let byte_1_bits = value_bits_le(row.1 as u8); let byte_2_bits = value_bits_le(next_row.1 as u8); let bits = if row.5 > 0 { @@ -1477,7 +1471,7 @@ impl BitstringAccumulationTable { let mut acc: u64 = 0; let mut bitstring_len: u64 = 0; - for bit_idx in (0..16usize).into_iter() { + for bit_idx in 0..16 { region.assign_fixed( || format!("q_enable"), self.q_enabled, @@ -1594,41 +1588,36 @@ impl BitstringAccumulationTable { } } -impl BitstringAccumulationTable { - /// Lookup table expressions for a bitsteam completely contained within the bits of a single - /// byte in the encoded data. - pub fn table_exprs_contained( - &self, - meta: &mut VirtualCells, - ) -> Vec> { +impl LookupTable for BitstringAccumulationTable { + fn columns(&self) -> Vec> { vec![ - meta.query_advice(self.byte_offset, Rotation::cur()), - meta.query_advice(self.byte_idx_1, Rotation::cur()), - meta.query_advice(self.byte_1, Rotation::cur()), - meta.query_advice(self.bit_value, Rotation::cur()), - meta.query_advice(self.bitstring_len, Rotation::cur()), - meta.query_fixed(self.bit_index, Rotation::cur()), - meta.query_advice(self.from_start, Rotation::cur()), - meta.query_advice(self.until_end, Rotation::cur()), - meta.query_advice(self.is_reverse, Rotation::cur()), + self.byte_offset.into(), + self.byte_idx_1.into(), + self.byte_idx_2.into(), + self.byte_1.into(), + self.byte_2.into(), + self.bit_value.into(), + self.bitstring_len.into(), + self.bit_index.into(), + self.from_start.into(), + self.until_end.into(), + self.is_reverse.into(), ] } - /// Lookup table expressions for a bitstream that spans over 2 consequtive bytes in the - /// encoded data. - pub fn table_exprs_spanned(&self, meta: &mut VirtualCells) -> Vec> { + fn annotations(&self) -> Vec { vec![ - meta.query_advice(self.byte_offset, Rotation::cur()), - meta.query_advice(self.byte_idx_1, Rotation::cur()), - meta.query_advice(self.byte_idx_2, Rotation::cur()), - meta.query_advice(self.byte_1, Rotation::cur()), - meta.query_advice(self.byte_2, Rotation::cur()), - meta.query_advice(self.bit_value, Rotation::cur()), - meta.query_advice(self.bitstring_len, Rotation::cur()), - meta.query_fixed(self.bit_index, Rotation::cur()), - meta.query_advice(self.from_start, Rotation::cur()), - meta.query_advice(self.until_end, Rotation::cur()), - meta.query_advice(self.is_reverse, Rotation::cur()), + String::from("byte_offset"), + String::from("byte_idx_1"), + String::from("byte_idx_2"), + String::from("byte_1"), + String::from("byte_2"), + String::from("bit_value"), + String::from("bitstring_len"), + String::from("bit_index"), + String::from("from_start"), + String::from("until_end"), + String::from("is_reverse") ] } } diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 928990e284..ee22847b89 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -264,7 +264,8 @@ impl ZstdTag { } } - fn is_reverse(&self) -> bool { + /// Whether this tag is processed in back-to-front order. + pub fn is_reverse(&self) -> bool { match self { Self::Null => false, Self::FrameHeaderDescriptor => false, @@ -821,4 +822,4 @@ mod tests { Ok(()) } -} \ No newline at end of file +} From 7ac2730889435c5eb321aa9623c075d5955d8b62 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 00:11:32 -0500 Subject: [PATCH 146/165] Add comment --- zkevm-circuits/src/table/decompression.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index edef0dfe54..4f2cf4795c 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -1402,6 +1402,7 @@ impl BitstringAccumulationTable { assert!(witness_rows.len() > 0); // Get the byte at which FSE is described + // TODO: Determining huffman offset in a multi-block scenario. let huffman_offset = witness_rows.iter() .find(|&r| r.state.tag == ZstdTag::ZstdBlockFseCode) .unwrap() From b57c51956fb6d190ef6395bf95e305f474c72772 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 00:17:24 -0500 Subject: [PATCH 147/165] Remove comment --- zkevm-circuits/src/decompression_circuit.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 67147215f3..9ce6cb91a2 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2028,9 +2028,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ]); [ meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // TODO: Ask about assumption - bit_value is used for FSE state transition only - // but not related to the actual symbol - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), meta.query_advice(fse_decoder.num_emitted, Rotation::cur()) - 1.expr(), meta.query_advice(fse_decoder.symbol, Rotation::cur()), ] From d56df5240b6f0803865777d7ff3ed56e1d1d5895 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 01:50:09 -0500 Subject: [PATCH 148/165] Correct bit boundaries reconstruction --- zkevm-circuits/src/decompression_circuit.rs | 13 ++++ zkevm-circuits/src/witness/zstd/mod.rs | 69 +++++++++++---------- zkevm-circuits/src/witness/zstd/types.rs | 2 + 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 9ce6cb91a2..ac40dd68c4 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2977,6 +2977,12 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(row.bitstream_read_data.bit_value as u64)), )?; + region.assign_advice( + || "bitstream_decoder.is_nil", + self.bitstream_decoder.is_nil, + i, + || Value::known(F::from(row.bitstream_read_data.is_zero_bit_read as u64)), + )?; let bitstring_contained_chip = ComparatorChip::construct( self.bitstream_decoder.bitstring_contained.clone(), @@ -3132,6 +3138,13 @@ impl SubCircuit for DecompressionCircuit { huffman_aux_data.extend_from_slice(&huffman_codes); } + // compression_debug + // for row in witness_rows.clone() { + // log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};;", + // row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, row.fse_data.num_emitted, row.fse_data.n_acc, row.bitstream_read_data.bit_start_idx, row.bitstream_read_data.bit_end_idx, row.bitstream_read_data.bit_value, row.bitstream_read_data.is_zero_bit_read + // ); + // } + config.assign( layouter, witness_rows, diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 6ea6e54acd..35ff85c537 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -887,6 +887,7 @@ fn process_block_zstd_huffman_code( bit_start_idx: 0usize, bit_end_idx: 7usize, bit_value: header_byte as u64, + is_zero_bit_read: false, }, decoded_data: decoded_data.clone(), huffman_data: HuffmanData::default(), @@ -932,60 +933,54 @@ fn process_block_zstd_huffman_code( witness_rows.push(huffman_header_row); // Process bit boundaries into bitstream reader info - let mut to_bit_idx: usize = 0; - let mut to_byte_idx: usize = 1; - let mut from_bit_idx: usize = 0; - let mut from_byte_idx: usize = 0; - let mut last_to_bit_idx: usize = 0; let mut decoded: u8 = 0; let mut n_acc: usize = 0; - let mut current_tag_value_acc = tag_value_iter.next().unwrap(); - let mut current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); - let bitstream_rows = bit_boundaries.iter().enumerate().map(|(sym, (bit_idx, value))| { - if last_to_bit_idx > 7 { - current_tag_value_acc = tag_value_iter.next().unwrap(); - current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); - } + let mut current_tag_value_acc = Value::known(F::zero()); + let mut current_tag_rlc_acc = Value::known(F::zero()); + let mut last_byte_idx: i64 = 0; + let mut from_pos: (i64, i64) = (1, 0); + let mut to_pos: (i64, i64) = (0, 0); - if sym == 0 { - from_bit_idx = 0; + let bitstream_rows = bit_boundaries.iter().enumerate().map(|(sym, (bit_idx, value))| { + from_pos = if sym == 0 { + (1, -1) } else { - from_bit_idx = to_bit_idx + 1; - from_byte_idx = to_byte_idx; - } + to_pos + }; - if from_bit_idx >= from_byte_idx * N_BITS_PER_BYTE || sym == 0 { - from_byte_idx += 1; + from_pos.1 += 1; + if from_pos.1 == 8 { + from_pos = (from_pos.0 + 1, 0); } + from_pos.1 = (from_pos.1 as u64).rem_euclid(8) as i64; - to_bit_idx = *bit_idx as usize - 1; - if to_bit_idx >= from_byte_idx * N_BITS_PER_BYTE { - to_byte_idx += 1; + if from_pos.0 > last_byte_idx { + current_tag_value_acc = tag_value_iter.next().unwrap(); + current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); + last_byte_idx = from_pos.0; } - to_bit_idx = to_bit_idx.rem_euclid(8); - if to_byte_idx > from_byte_idx { + let to_byte_idx = (bit_idx - 1) / 8; + let mut to_bit_idx = bit_idx - to_byte_idx * (N_BITS_PER_BYTE as u32) - 1; + + if from_pos.0 < (to_byte_idx + 1) as i64 { to_bit_idx += 8; } - last_to_bit_idx = to_bit_idx; + to_pos = ((to_byte_idx + 1) as i64, to_bit_idx as i64); - // compression_debug - // if sym > 0 && n_acc < (1 << accuracy_log) { - // // num_emitted += 1; - // decoded = sym as u8; - // n_acc += (*value - 1) as usize; - // } if sym > 0 && n_acc < (1 << accuracy_log) { - // num_emitted += 1; decoded = (sym - 1) as u8; n_acc += (*value - 1) as usize; } - (decoded, from_byte_idx, from_bit_idx.rem_euclid(8), to_byte_idx, to_bit_idx, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone(), 0, n_acc) + (decoded, from_pos.0 as usize, from_pos.1 as usize, to_pos.0 as usize, to_pos.1 as usize, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone(), 0, n_acc) }) .collect::, Value, usize, usize)>>(); + // compression_debug + log::trace!("=> bitstream_rows: {:?}", bitstream_rows); + // Add witness rows for FSE representation bytes for row in bitstream_rows { witness_rows.push(ZstdWitnessRow { @@ -1012,7 +1007,8 @@ fn process_block_zstd_huffman_code( bitstream_read_data: BitstreamReadRow { bit_start_idx: row.2, bit_end_idx: row.4, - bit_value: row.5, + bit_value: row.5, + is_zero_bit_read: false, }, decoded_data: DecodedData { decoded_len: last_row.decoded_data.decoded_len, @@ -1142,6 +1138,7 @@ fn process_block_zstd_huffman_code( bit_value: 1u64, bit_start_idx: 0usize, bit_end_idx: padding_end_idx, + is_zero_bit_read: false, }, huffman_data: HuffmanData::default(), decoded_data: last_row.decoded_data.clone(), @@ -1219,6 +1216,7 @@ fn process_block_zstd_huffman_code( bit_value: bitstring_value, bit_start_idx: from_bit_idx, bit_end_idx: to_bit_idx, + is_zero_bit_read: (nb == 0), }, fse_data: FseTableRow { idx: fse_table_idx, @@ -1379,6 +1377,7 @@ fn process_block_zstd_huffman_jump_table( bit_start_idx: 0, bit_end_idx: 7, bit_value: value_byte as u64, + is_zero_bit_read: false, }, decoded_data: last_row.decoded_data.clone(), huffman_data: HuffmanData::default(), @@ -1509,6 +1508,7 @@ fn process_block_zstd_lstream( bit_value: 1u64, bit_start_idx: 0usize, bit_end_idx: padding_end_idx as usize, + is_zero_bit_read: false, }, decoded_data: DecodedData { decoded_len: last_row.decoded_data.decoded_len, @@ -1600,6 +1600,7 @@ fn process_block_zstd_lstream( bit_value: u8::from_str_radix(bitstring_acc.as_str(), 2).unwrap() as u64, bit_start_idx: from_bit_idx.rem_euclid(8) as usize, bit_end_idx: end_bit_idx as usize, + is_zero_bit_read: false, }, decoded_data: DecodedData { decoded_len: last_row.decoded_data.decoded_len, diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index ee22847b89..06600ad366 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -533,6 +533,8 @@ pub struct BitstreamReadRow { pub bit_end_idx: usize, /// The value of the bitstring pub bit_value: u64, + /// Whether 0 bit is read + pub is_zero_bit_read: bool, } /// Data for the FSE table's witness values. From 7f366b9ffd25cb6b64209c68cfe6d543e4d828fa Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 02:21:34 -0500 Subject: [PATCH 149/165] Adjust constraints --- zkevm-circuits/src/decompression_circuit.rs | 276 ++++++++++---------- 1 file changed, 140 insertions(+), 136 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index ac40dd68c4..8da3c4211e 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1446,30 +1446,31 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - meta.lookup_any( - "DecompressionCircuit: lookup for LiteralsHeader decomposition", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - ]); - [ - meta.query_advice(value_bits[0], Rotation::cur()), // block type bit0 - meta.query_advice(value_bits[1], Rotation::cur()), // block type bit1 - meta.query_advice(value_bits[2], Rotation::cur()), // size format bit0 - meta.query_advice(value_bits[3], Rotation::cur()), // size format bit1 - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header - meta.query_advice(lstream_config.lstream_kind, Rotation::cur()), // 1 or 4 - meta.query_advice(literals_header.branch, Rotation::cur()), // branch - meta.query_advice(literals_header.sf_max, Rotation::cur()), // size format 0b11 - ] - .into_iter() - .zip(literals_header_rom_table.table_exprs(meta)) - .map(|(arg, table)| (condition.expr() * arg, table)) - .collect() - }, - ); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: lookup for LiteralsHeader decomposition", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + // ]); + // [ + // meta.query_advice(value_bits[0], Rotation::cur()), // block type bit0 + // meta.query_advice(value_bits[1], Rotation::cur()), // block type bit1 + // meta.query_advice(value_bits[2], Rotation::cur()), // size format bit0 + // meta.query_advice(value_bits[3], Rotation::cur()), // size format bit1 + // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header + // meta.query_advice(lstream_config.lstream_kind, Rotation::cur()), // 1 or 4 + // meta.query_advice(literals_header.branch, Rotation::cur()), // branch + // meta.query_advice(literals_header.sf_max, Rotation::cur()), // size format 0b11 + // ] + // .into_iter() + // .zip(literals_header_rom_table.table_exprs(meta)) + // .map(|(arg, table)| (condition.expr() * arg, table)) + // .collect() + // }, + // ); // TODO: LiteralHeader regen/compr size // meta.lookup_any( @@ -1980,42 +1981,43 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // in that Huffman table. As per the canonical Huffman code representation, we only need to // emit N - 1 weights and the weight of the last symbol can be calculated. - meta.lookup_any( - "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", - |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::next())), - ]); + // compression_debug + // meta.lookup_any( + // "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", + // |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::next())), + // ]); - // TODO: include num_bits in lookup - let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); - let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); - let num_bits = select::expr( - meta.query_advice(bitstream_decoder.is_nil, Rotation::cur()), - 0.expr(), - end - start + 1.expr(), - ); + // // TODO: include num_bits in lookup + // let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); + // let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); + // let num_bits = select::expr( + // meta.query_advice(bitstream_decoder.is_nil, Rotation::cur()), + // 0.expr(), + // end - start + 1.expr(), + // ); - [ - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), - meta.query_advice(fse_decoder.state, Rotation::cur()), - meta.query_advice(fse_decoder.symbol, Rotation::cur()), - meta.query_advice(fse_decoder.baseline, Rotation::cur()), - // TODO: a complication of nb representation between reading 0 bit and 1 bit. - // The bit_start_idx and bit_end_idx for both scenarios are set to the same - // value. - num_bits, - ] - .into_iter() - .zip(fse_table.table_exprs_state_check(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }, - ); + // [ + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), + // meta.query_advice(fse_decoder.state, Rotation::cur()), + // meta.query_advice(fse_decoder.symbol, Rotation::cur()), + // meta.query_advice(fse_decoder.baseline, Rotation::cur()), + // // TODO: a complication of nb representation between reading 0 bit and 1 bit. + // // The bit_start_idx and bit_end_idx for both scenarios are set to the same + // // value. + // num_bits, + // ] + // .into_iter() + // .zip(fse_table.table_exprs_state_check(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }, + // ); meta.lookup_any( "DecompressionCircuit: ZstdBlockHuffmanCode (huffman codes table lookup)", @@ -2306,79 +2308,81 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - meta.lookup_any("DecompressionCircuit: bitstring (start)", |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - sum::expr([ - and::expr([ - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - ]), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - ]), - not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), - ]); - let (huffman_byte_offset, bit_index_start, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - [ - huffman_byte_offset, - meta.query_advice(byte_idx, Rotation::cur()), - meta.query_advice(byte_idx, Rotation::next()), - meta.query_advice(value_byte, Rotation::cur()), - meta.query_advice(value_byte, Rotation::next()), - bit_value, - 1.expr(), // bitstring_len at start - bit_index_start, - 1.expr(), // from_start - 1.expr(), // until_end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - ] - .into_iter() - .zip(bs_acc_table.table_exprs(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }); - meta.lookup_any("DecompressionCircuit: bitstring (end)", |meta| { - let condition = and::expr([ - meta.query_fixed(q_enable, Rotation::cur()), - sum::expr([ - and::expr([ - meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - ]), - meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - ]), - not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), - ]); - let (huffman_byte_offset, bit_index_start, bit_index_end, bit_value) = ( - meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - ); - [ - huffman_byte_offset, - meta.query_advice(byte_idx, Rotation::cur()), - meta.query_advice(byte_idx, Rotation::next()), - meta.query_advice(value_byte, Rotation::cur()), - meta.query_advice(value_byte, Rotation::next()), - bit_value, - bit_index_end.expr() - bit_index_start + 1.expr(), // bitstring_len at end - bit_index_end, - 1.expr(), // from_start - 1.expr(), // until_end - meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - ] - .into_iter() - .zip(bs_acc_table.table_exprs(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() - }); + // compression_debug + // meta.lookup_any("DecompressionCircuit: bitstring (start)", |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // sum::expr([ + // and::expr([ + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // ]), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + // ]), + // not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), + // ]); + // let (huffman_byte_offset, bit_index_start, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // [ + // huffman_byte_offset, + // meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(byte_idx, Rotation::next()), + // meta.query_advice(value_byte, Rotation::cur()), + // meta.query_advice(value_byte, Rotation::next()), + // bit_value, + // 1.expr(), // bitstring_len at start + // bit_index_start, + // 1.expr(), // from_start + // 1.expr(), // until_end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }); + // compression_debug + // meta.lookup_any("DecompressionCircuit: bitstring (end)", |meta| { + // let condition = and::expr([ + // meta.query_fixed(q_enable, Rotation::cur()), + // sum::expr([ + // and::expr([ + // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + // ]), + // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + // ]), + // not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), + // ]); + // let (huffman_byte_offset, bit_index_start, bit_index_end, bit_value) = ( + // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + // ); + // [ + // huffman_byte_offset, + // meta.query_advice(byte_idx, Rotation::cur()), + // meta.query_advice(byte_idx, Rotation::next()), + // meta.query_advice(value_byte, Rotation::cur()), + // meta.query_advice(value_byte, Rotation::next()), + // bit_value, + // bit_index_end.expr() - bit_index_start + 1.expr(), // bitstring_len at end + // bit_index_end, + // 1.expr(), // from_start + // 1.expr(), // until_end + // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + // ] + // .into_iter() + // .zip(bs_acc_table.table_exprs(meta)) + // .map(|(value, table)| (condition.expr() * value, table)) + // .collect() + // }); meta.create_gate("DecompressionCircuit: bitstream reader", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -3139,11 +3143,11 @@ impl SubCircuit for DecompressionCircuit { } // compression_debug - // for row in witness_rows.clone() { - // log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};;", - // row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, row.fse_data.num_emitted, row.fse_data.n_acc, row.bitstream_read_data.bit_start_idx, row.bitstream_read_data.bit_end_idx, row.bitstream_read_data.bit_value, row.bitstream_read_data.is_zero_bit_read - // ); - // } + for row in witness_rows.clone() { + log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};;", + row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, row.fse_data.num_emitted, row.fse_data.n_acc, row.bitstream_read_data.bit_start_idx, row.bitstream_read_data.bit_end_idx, row.bitstream_read_data.bit_value, row.bitstream_read_data.is_zero_bit_read + ); + } config.assign( layouter, From cbf16664b34ed51c996f7a8836edd33d8b4a64b5 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 02:35:34 -0500 Subject: [PATCH 150/165] Correct bitstring accumulation constraints --- zkevm-circuits/src/table/decompression.rs | 8 ++++++++ zkevm-circuits/src/witness/zstd/mod.rs | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index efe4be0291..d3fdc6856a 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -1451,6 +1451,7 @@ impl BitstringAccumulationTable { || "Bitstring Accumulation Table", |mut region| { let mut offset: usize = 0; + let mut last_byte_idx: usize = 0; for rows in accumulation_rows.windows(2) { let row = rows[0]; let next_row = rows[1]; @@ -1571,6 +1572,7 @@ impl BitstringAccumulationTable { } offset += 16; + last_byte_idx = next_row.0; } region.assign_fixed( @@ -1579,6 +1581,12 @@ impl BitstringAccumulationTable { offset, || Value::known(F::one()), )?; + region.assign_advice( + || format!("byte_idx_1"), + self.byte_idx_1, + offset, + || Value::known(F::from(last_byte_idx as u64)), + )?; Ok(()) }, diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 35ff85c537..a866f27a56 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1465,7 +1465,6 @@ fn process_block_zstd_lstream( while lstream_bits[padding_end_idx] == 0 { padding_end_idx += 1; } - padding_end_idx += 1; let mut next_tag_value_acc = tag_value_acc.next().unwrap(); let mut next_value_rlc_acc = value_rlc_acc.next().unwrap(); From f12d94326ffa6406fe1b8ca08d5e1a89b8a91b1b Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 02:48:26 -0500 Subject: [PATCH 151/165] Fix fse table lookup --- zkevm-circuits/src/decompression_circuit.rs | 80 ++++++++++++--------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 8da3c4211e..2142d7d3ae 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1981,43 +1981,53 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // in that Huffman table. As per the canonical Huffman code representation, we only need to // emit N - 1 weights and the weight of the last symbol can be calculated. - // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::next())), - // ]); + meta.lookup_any( + "DecompressionCircuit: ZstdBlockHuffmanCode (fse table lookup)", + |meta| { + let condition = and::expr([ + // TODO: Degree > 9 + // Comment q_enable out for now with the assumption that when is_huffman_code is on, q_enable must also be on. (perhaps constrain this?) + // meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + // TODO: Verify below exclusion + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), // Exclude leading 0s and sentinel 1 bit + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::next())), // Exclude the last row + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation(2))), // Exclude the second last row as below max rotation is 2 - // // TODO: include num_bits in lookup - // let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); - // let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); - // let num_bits = select::expr( - // meta.query_advice(bitstream_decoder.is_nil, Rotation::cur()), - // 0.expr(), - // end - start + 1.expr(), - // ); + ]); - // [ - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), - // meta.query_advice(fse_decoder.state, Rotation::cur()), - // meta.query_advice(fse_decoder.symbol, Rotation::cur()), - // meta.query_advice(fse_decoder.baseline, Rotation::cur()), - // // TODO: a complication of nb representation between reading 0 bit and 1 bit. - // // The bit_start_idx and bit_end_idx for both scenarios are set to the same - // // value. - // num_bits, - // ] - // .into_iter() - // .zip(fse_table.table_exprs_state_check(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }, - // ); + // TODO: Verify that acquiring data for num_bits from bitstream_decoder targets 2 rows down, not the current row + + // let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()); + // let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()); + // let num_bits = select::expr( + // meta.query_advice(bitstream_decoder.is_nil, Rotation::cur()), + // 0.expr(), + // end - start + 1.expr(), + // ); + + let start = meta.query_advice(bitstream_decoder.bit_index_start, Rotation(2)); + let end = meta.query_advice(bitstream_decoder.bit_index_end, Rotation(2)); + let num_bits = select::expr( + meta.query_advice(bitstream_decoder.is_nil, Rotation(2)), + 0.expr(), + end - start + 1.expr(), + ); + + [ + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(huffman_tree_config.fse_table_size, Rotation::cur()), + meta.query_advice(fse_decoder.state, Rotation::cur()), + meta.query_advice(fse_decoder.symbol, Rotation::cur()), + meta.query_advice(fse_decoder.baseline, Rotation::cur()), + num_bits, + ] + .into_iter() + .zip(fse_table.table_exprs_state_check(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); meta.lookup_any( "DecompressionCircuit: ZstdBlockHuffmanCode (huffman codes table lookup)", From a2677c82ff422c740ed4d686e13e30948cbd504a Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 02:59:24 -0500 Subject: [PATCH 152/165] Add conditions to fix lookups --- zkevm-circuits/src/decompression_circuit.rs | 158 ++++++++++---------- 1 file changed, 81 insertions(+), 77 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 2142d7d3ae..72b8d75715 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1989,10 +1989,10 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // Comment q_enable out for now with the assumption that when is_huffman_code is on, q_enable must also be on. (perhaps constrain this?) // meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // TODO: Verify below exclusion + // TODO: Verify below exclusions not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), // Exclude leading 0s and sentinel 1 bit not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::next())), // Exclude the last row - not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation(2))), // Exclude the second last row as below max rotation is 2 + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation(2))), // Exclude the second last row as max rotation is 2 ]); @@ -2318,81 +2318,85 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug - // meta.lookup_any("DecompressionCircuit: bitstring (start)", |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // sum::expr([ - // and::expr([ - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // ]), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - // ]), - // not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), - // ]); - // let (huffman_byte_offset, bit_index_start, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // [ - // huffman_byte_offset, - // meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(byte_idx, Rotation::next()), - // meta.query_advice(value_byte, Rotation::cur()), - // meta.query_advice(value_byte, Rotation::next()), - // bit_value, - // 1.expr(), // bitstring_len at start - // bit_index_start, - // 1.expr(), // from_start - // 1.expr(), // until_end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }); - // compression_debug - // meta.lookup_any("DecompressionCircuit: bitstring (end)", |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // sum::expr([ - // and::expr([ - // meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), - // not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), - // ]), - // meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), - // meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), - // ]), - // not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), - // ]); - // let (huffman_byte_offset, bit_index_start, bit_index_end, bit_value) = ( - // meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), - // meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), - // ); - // [ - // huffman_byte_offset, - // meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(byte_idx, Rotation::next()), - // meta.query_advice(value_byte, Rotation::cur()), - // meta.query_advice(value_byte, Rotation::next()), - // bit_value, - // bit_index_end.expr() - bit_index_start + 1.expr(), // bitstring_len at end - // bit_index_end, - // 1.expr(), // from_start - // 1.expr(), // until_end - // meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), - // ] - // .into_iter() - // .zip(bs_acc_table.table_exprs(meta)) - // .map(|(value, table)| (condition.expr() * value, table)) - // .collect() - // }); + meta.lookup_any("DecompressionCircuit: bitstring (start)", |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + // TODO: Make sure that both rows must be active witness rows and not paddings. + // This condition also excludes the last row from lookup + meta.query_fixed(q_enable, Rotation::next()), + sum::expr([ + and::expr([ + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + ]), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + ]), + not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), + ]); + let (huffman_byte_offset, bit_index_start, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + [ + huffman_byte_offset, + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(value_byte, Rotation::cur()), + meta.query_advice(value_byte, Rotation::next()), + bit_value, + 1.expr(), // bitstring_len at start + bit_index_start, + 1.expr(), // from_start + 1.expr(), // until_end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + ] + .into_iter() + .zip(bs_acc_table.table_exprs(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }); + meta.lookup_any("DecompressionCircuit: bitstring (end)", |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + // TODO: Make sure that both rows must be active witness rows and not paddings. + // This condition also excludes the last row from lookup + meta.query_fixed(q_enable, Rotation::next()), + sum::expr([ + and::expr([ + meta.query_advice(tag_gadget.is_fse_code, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + ]), + meta.query_advice(tag_gadget.is_huffman_code, Rotation::cur()), + meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + ]), + not::expr(meta.query_advice(bitstream_decoder.is_nil, Rotation::cur())), + ]); + let (huffman_byte_offset, bit_index_start, bit_index_end, bit_value) = ( + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_start, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_index_end, Rotation::cur()), + meta.query_advice(bitstream_decoder.bit_value, Rotation::cur()), + ); + [ + huffman_byte_offset, + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(byte_idx, Rotation::next()), + meta.query_advice(value_byte, Rotation::cur()), + meta.query_advice(value_byte, Rotation::next()), + bit_value, + bit_index_end.expr() - bit_index_start + 1.expr(), // bitstring_len at end + bit_index_end, + 1.expr(), // from_start + 1.expr(), // until_end + meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), + ] + .into_iter() + .zip(bs_acc_table.table_exprs(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }); meta.create_gate("DecompressionCircuit: bitstream reader", |meta| { let mut cb = BaseConstraintBuilder::default(); From 8526a4ab51aa0fa6d7373192684528614289fb85 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 03:02:40 -0500 Subject: [PATCH 153/165] Remove debug flag --- zkevm-circuits/src/decompression_circuit.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 72b8d75715..8b9c50c75b 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -3156,13 +3156,6 @@ impl SubCircuit for DecompressionCircuit { huffman_aux_data.extend_from_slice(&huffman_codes); } - // compression_debug - for row in witness_rows.clone() { - log::trace!("{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};{:?};{:?};{:?};;{:?};{:?};{:?};{:?};;", - row.state.tag, row.state.tag_next, row.state.max_tag_len, row.state.tag_len, row.state.tag_idx, row.state.tag_value, row.state.tag_value_acc, row.state.is_tag_change, row.state.tag_rlc, row.state.tag_rlc_acc, row.encoded_data.byte_idx, row.encoded_data.encoded_len, row.encoded_data.value_byte, row.encoded_data.reverse, row.encoded_data.reverse_idx, row.encoded_data.reverse_len, row.encoded_data.aux_1, row.encoded_data.aux_2, row.encoded_data.value_rlc, row.decoded_data.decoded_len, row.decoded_data.decoded_len_acc, row.decoded_data.total_decoded_len, row.decoded_data.decoded_byte, row.decoded_data.decoded_value_rlc, row.huffman_data.byte_offset, row.huffman_data.bit_value, row.huffman_data.stream_idx, row.huffman_data.k.0, row.huffman_data.k.1, row.fse_data.idx, row.fse_data.state, row.fse_data.baseline, row.fse_data.num_bits, row.fse_data.symbol, row.fse_data.num_emitted, row.fse_data.n_acc, row.bitstream_read_data.bit_start_idx, row.bitstream_read_data.bit_end_idx, row.bitstream_read_data.bit_value, row.bitstream_read_data.is_zero_bit_read - ); - } - config.assign( layouter, witness_rows, From c65e52c55ac4f1130f84243a9e45c65d7b4d53bf Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 03:31:41 -0500 Subject: [PATCH 154/165] Correct branch assignment --- zkevm-circuits/src/decompression_circuit.rs | 48 ++++++++++----------- zkevm-circuits/src/witness/zstd/mod.rs | 9 ++-- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 8b9c50c75b..43f0be714d 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1447,30 +1447,30 @@ impl SubCircuitConfig for DecompressionCircuitConfig { ); // compression_debug - // meta.lookup_any( - // "DecompressionCircuit: lookup for LiteralsHeader decomposition", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - // ]); - // [ - // meta.query_advice(value_bits[0], Rotation::cur()), // block type bit0 - // meta.query_advice(value_bits[1], Rotation::cur()), // block type bit1 - // meta.query_advice(value_bits[2], Rotation::cur()), // size format bit0 - // meta.query_advice(value_bits[3], Rotation::cur()), // size format bit1 - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header - // meta.query_advice(lstream_config.lstream_kind, Rotation::cur()), // 1 or 4 - // meta.query_advice(literals_header.branch, Rotation::cur()), // branch - // meta.query_advice(literals_header.sf_max, Rotation::cur()), // size format 0b11 - // ] - // .into_iter() - // .zip(literals_header_rom_table.table_exprs(meta)) - // .map(|(arg, table)| (condition.expr() * arg, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: lookup for LiteralsHeader decomposition", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + ]); + [ + meta.query_advice(value_bits[0], Rotation::cur()), // block type bit0 + meta.query_advice(value_bits[1], Rotation::cur()), // block type bit1 + meta.query_advice(value_bits[2], Rotation::cur()), // size format bit0 + meta.query_advice(value_bits[3], Rotation::cur()), // size format bit1 + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), // num bytes header + meta.query_advice(lstream_config.lstream_kind, Rotation::cur()), // 1 or 4 + meta.query_advice(literals_header.branch, Rotation::cur()), // branch + meta.query_advice(literals_header.sf_max, Rotation::cur()), // size format 0b11 + ] + .into_iter() + .zip(literals_header_rom_table.table_exprs(meta)) + .map(|(arg, table)| (condition.expr() * arg, table)) + .collect() + }, + ); // TODO: LiteralHeader regen/compr size // meta.lookup_any( diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index a866f27a56..4f533f9638 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -741,9 +741,9 @@ fn process_block_zstd_literals_header( BlockType::ZstdCompressedBlock => { match size_format { 0b00 => [2, 10, 10, 1, 3, 3], - 0b01 => [2, 10, 10, 4, 3, 3], - 0b10 => [2, 14, 14, 4, 4, 4], - 0b11 => [2, 18, 18, 4, 5, 5], + 0b01 => [2, 10, 10, 4, 3, 4], + 0b10 => [2, 14, 14, 4, 4, 5], + 0b11 => [2, 18, 18, 4, 5, 6], _ => unreachable!("size_format out of bound") } }, @@ -978,9 +978,6 @@ fn process_block_zstd_huffman_code( }) .collect::, Value, usize, usize)>>(); - // compression_debug - log::trace!("=> bitstream_rows: {:?}", bitstream_rows); - // Add witness rows for FSE representation bytes for row in bitstream_rows { witness_rows.push(ZstdWitnessRow { From 3a9f4bdb4ada9e7ad3fa85501015951ed4b98582 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 03:32:01 -0500 Subject: [PATCH 155/165] Remove debug flag --- zkevm-circuits/src/decompression_circuit.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 43f0be714d..5942c3c766 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -1446,7 +1446,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // compression_debug meta.lookup_any( "DecompressionCircuit: lookup for LiteralsHeader decomposition", |meta| { From 2d109f77b5241c8d09c395eb0752b05218ce5218 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 03:54:49 -0500 Subject: [PATCH 156/165] Organize constraints --- zkevm-circuits/src/decompression_circuit.rs | 31 +++++++++++++-------- zkevm-circuits/src/table/decompression.rs | 2 +- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 5942c3c766..ba5c46e9b8 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -26,6 +26,7 @@ use crate::{ }; use array_init::array_init; use eth_types::Field; +use ff::BitViewSized; use gadgets::{ binary_number::{BinaryNumberChip, BinaryNumberConfig}, comparator::{ComparatorChip, ComparatorConfig, ComparatorInstruction}, @@ -1484,9 +1485,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // // Which branch are we taking in the literals header decomposition. // let branch = meta.query_advice(literals_header.branch, Rotation::cur()); - // // // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we - // // // already know that block type == 0b11 (TREELESS) will not occur, we can skip - // the // // check for not::expr(value_bits[7]). + // // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we + // // already know that block type == 0b11 (TREELESS) will not occur, we can skip the + // // check for not::expr(value_bits[7]). // let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); // // Is the size format == 0b11. @@ -1535,9 +1536,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // byte2, // byte2 // byte3, // byte3 // byte4, // byte4 - // meta.query_advice(literals_header.regen_size, Rotation::cur()), // - // regenerated size meta.query_advice(literals_header.compr_size, - // Rotation::cur()), // compressed size ] + // meta.query_advice(literals_header.regen_size, Rotation::cur()), // regenerated size + // meta.query_advice(literals_header.compr_size, Rotation::cur()), // compressed size + // ] // .into_iter() // .zip(literals_header_table.table_exprs(meta)) // .map(|(arg, table)| (condition.expr() * arg, table)) @@ -2589,6 +2590,18 @@ impl DecompressionCircuitConfig { self.fse_table.assign(layouter, fse_aux_tables)?; self.huffman_codes_table.assign(layouter, huffman_codes)?; + let literal_header_offset = witness_rows.iter().find(|r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader).unwrap().encoded_data.byte_idx; + let literal_bytes = witness_rows + .iter() + .filter(|&r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader) + .map(|r| r.encoded_data.value_byte) + .collect::>(); + + self.literals_header_table.assign( + layouter, + &[(literal_header_offset, literal_bytes.as_slice(), aux_data[10], aux_data[4], aux_data[5])], + )?; + layouter.assign_region( || "Decompression table region", |mut region| { @@ -2936,12 +2949,6 @@ impl DecompressionCircuitConfig { i, || Value::known(F::from(aux_data[4])), )?; - region.assign_advice( - || "literals_header.regen_size", - self.literals_header.regen_size, - i, - || Value::known(F::from(aux_data[4])), - )?; region.assign_advice( || "literals_header.compr_size", self.literals_header.compr_size, diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index d3fdc6856a..6712f1c26c 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -1977,7 +1977,7 @@ impl LiteralsHeaderTable { } /// Assign witness to the literals header table. - pub fn dev_load( + pub fn assign( &self, layouter: &mut impl Layouter, literals_headers: &[(u64, &[u8], u64, u64, u64)], /* (byte_offset, bytes, branch, From caab0fec4decccab01cfdd94baccd75e1a2b5d8a Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 04:03:12 -0500 Subject: [PATCH 157/165] fmt --- zkevm-circuits/src/decompression_circuit.rs | 72 +- .../src/decompression_circuit/dev.rs | 2 +- .../src/decompression_circuit/test.rs | 94 +- zkevm-circuits/src/table/decompression.rs | 9 +- zkevm-circuits/src/witness.rs | 7 +- zkevm-circuits/src/witness/zstd/mod.rs | 1131 ++++++++++------- zkevm-circuits/src/witness/zstd/types.rs | 156 ++- 7 files changed, 888 insertions(+), 583 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index ba5c46e9b8..1976a53198 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -542,7 +542,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { let mut cb = BaseConstraintBuilder::default(); // Boolean columns. - for col in [is_padding, block_gadget.is_last_block, bitstream_decoder.is_nil] { + for col in [ + is_padding, + block_gadget.is_last_block, + bitstream_decoder.is_nil, + ] { cb.require_boolean( "Boolean column check", meta.query_advice(col, Rotation::cur()), @@ -1486,8 +1490,8 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // let branch = meta.query_advice(literals_header.branch, Rotation::cur()); // // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we - // // already know that block type == 0b11 (TREELESS) will not occur, we can skip the - // // check for not::expr(value_bits[7]). + // // already know that block type == 0b11 (TREELESS) will not occur, we can skip + // the // check for not::expr(value_bits[7]). // let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); // // Is the size format == 0b11. @@ -1536,9 +1540,9 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // byte2, // byte2 // byte3, // byte3 // byte4, // byte4 - // meta.query_advice(literals_header.regen_size, Rotation::cur()), // regenerated size - // meta.query_advice(literals_header.compr_size, Rotation::cur()), // compressed size - // ] + // meta.query_advice(literals_header.regen_size, Rotation::cur()), // + // regenerated size meta.query_advice(literals_header.compr_size, + // Rotation::cur()), // compressed size ] // .into_iter() // .zip(literals_header_table.table_exprs(meta)) // .map(|(arg, table)| (condition.expr() * arg, table)) @@ -2352,10 +2356,10 @@ impl SubCircuitConfig for DecompressionCircuitConfig { 1.expr(), // until_end meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), ] - .into_iter() - .zip(bs_acc_table.table_exprs(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() + .into_iter() + .zip(bs_acc_table.table_exprs(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() }); meta.lookup_any("DecompressionCircuit: bitstring (end)", |meta| { let condition = and::expr([ @@ -2392,10 +2396,10 @@ impl SubCircuitConfig for DecompressionCircuitConfig { 1.expr(), // until_end meta.query_advice(tag_gadget.is_reverse, Rotation::cur()), ] - .into_iter() - .zip(bs_acc_table.table_exprs(meta)) - .map(|(value, table)| (condition.expr() * value, table)) - .collect() + .into_iter() + .zip(bs_acc_table.table_exprs(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() }); meta.create_gate("DecompressionCircuit: bitstream reader", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -2446,7 +2450,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { and::expr([is_not_last.expr(), bitstream_decoder.is_spanned(meta, None)]); // if bitstring is strictly contained. cb.condition(is_strictly_contained, |cb| { - // TODO: Take into account a FSE transition row can read 0 bit cb.require_equal( "strictly contained bitstring: bit_index_start", meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), @@ -2461,9 +2464,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // if bitstring is byte-aligned. cb.condition(is_byte_aligned, |cb| { - // TODO: Take into account a FSE transition row can read 0 bit - // In this case, last row ends at bit_idx 7, then the next row also starts with - // bit_idx 7 on the same byte_idx cb.require_equal( "byte-aligned bitstring: bit_index_start", meta.query_advice(bitstream_decoder.bit_index_start, Rotation::next()), @@ -2590,17 +2590,29 @@ impl DecompressionCircuitConfig { self.fse_table.assign(layouter, fse_aux_tables)?; self.huffman_codes_table.assign(layouter, huffman_codes)?; - let literal_header_offset = witness_rows.iter().find(|r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader).unwrap().encoded_data.byte_idx; - let literal_bytes = witness_rows - .iter() - .filter(|&r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader) - .map(|r| r.encoded_data.value_byte) - .collect::>(); - - self.literals_header_table.assign( - layouter, - &[(literal_header_offset, literal_bytes.as_slice(), aux_data[10], aux_data[4], aux_data[5])], - )?; + // TODO: Assining into literals_header_table causes failed table constraints + // let literal_header_offset = witness_rows + // .iter() + // .find(|r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader) + // .unwrap() + // .encoded_data + // .byte_idx; + // let literal_bytes = witness_rows + // .iter() + // .filter(|&r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader) + // .map(|r| r.encoded_data.value_byte) + // .collect::>(); + + // self.literals_header_table.assign( + // layouter, + // &[( + // literal_header_offset, + // literal_bytes.as_slice(), + // aux_data[10], + // aux_data[4], + // aux_data[5], + // )], + // )?; layouter.assign_region( || "Decompression table region", @@ -3102,7 +3114,7 @@ impl DecompressionCircuitConfig { )?; } - // TODO: Assign sequence section. Dummy row for sequencing section header as of now + // TODO: Should assign sequence section. Dummy row for sequencing section header as of now region.assign_advice( || "byte_idx", self.byte_idx, diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index 19619f2442..d6816e3695 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -12,7 +12,7 @@ use crate::{ decompression::{ BitstringAccumulationTable, FseTable, HuffmanCodesTable, LiteralsHeaderTable, }, - BitwiseOpTable, KeccakTable, Pow2Table, PowOfRandTable, RangeTable, U8Table + BitwiseOpTable, KeccakTable, Pow2Table, PowOfRandTable, RangeTable, U8Table, }, util::{Challenges, SubCircuit, SubCircuitConfig}, }; diff --git a/zkevm-circuits/src/decompression_circuit/test.rs b/zkevm-circuits/src/decompression_circuit/test.rs index 602668d4fe..60fdb52a51 100644 --- a/zkevm-circuits/src/decompression_circuit/test.rs +++ b/zkevm-circuits/src/decompression_circuit/test.rs @@ -1,5 +1,5 @@ -use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use crate::decompression_circuit::DecompressionCircuit; +use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; #[test] fn test_basic() { @@ -23,58 +23,48 @@ fn test_work_example_decompression() { 0x0d, 0x11, 0x00, // BlockHeader 0x76, 0x62, 0x5e, // ZstdBlockLiteralsHeader 0x23, 0x30, 0x6f, 0x9b, 0x03, // ZstdBlockFseCode - // ZstdBlockHuffmanCode - 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, 0xa9, 0xd4, - 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, 0x01, - - // ZstdBlockJumpTable - 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, - - // LStream1 - 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, - 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, - 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, - 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, - 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, - 0x24, 0x5a, 0xdf, 0xb4, 0x21, - - // LStream2 - 0x9a, 0xcb, 0x8f, 0xc7, 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, - 0x28, 0x0e, 0xfb, 0x8b, 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, 0xeb, 0x81, - 0xf1, 0x78, 0x4b, 0xad, 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, 0xb4, 0xd9, 0xe1, - 0x95, 0x21, 0x66, 0x0c, 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, 0x22, 0x07, 0x0b, 0x91, - 0x86, 0x94, 0x1a, 0x7b, 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, 0x65, 0xd6, 0x34, 0x63, 0x0c, - 0x88, 0x9b, 0x1c, 0x48, 0xca, 0x2b, 0x34, - + 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, 0xa9, + 0xd4, 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, + 0x01, // ZstdBlockJumpTable + 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, // LStream1 + 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, + 0x9c, 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, 0xee, 0xdc, 0xd5, 0xa2, 0xe3, + 0x48, 0xad, 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, 0x77, 0xea, 0xdc, 0x5d, + 0x41, 0x06, 0x50, 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, 0x02, 0xfc, 0x3c, + 0xe3, 0x60, 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, 0xe2, 0x20, + 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, 0x5a, 0xdf, 0xb4, 0x21, // LStream2 + 0x9a, 0xcb, 0x8f, 0xc7, 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, + 0x92, 0x28, 0x0e, 0xfb, 0x8b, 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, + 0xeb, 0x81, 0xf1, 0x78, 0x4b, 0xad, 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, + 0xb4, 0xd9, 0xe1, 0x95, 0x21, 0x66, 0x0c, 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, + 0x22, 0x07, 0x0b, 0x91, 0x86, 0x94, 0x1a, 0x7b, 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, + 0x65, 0xd6, 0x34, 0x63, 0x0c, 0x88, 0x9b, 0x1c, 0x48, 0xca, 0x2b, 0x34, // LStream3 - 0xa9, 0x6b, 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, 0x69, 0x18, 0x57, - 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, 0x7b, 0x6e, 0xd8, - 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, 0x14, 0xf4, 0x40, 0xe7, - 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, 0x49, 0xae, 0x13, 0xa4, 0x75, 0x38, - 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, 0x86, 0xa4, 0xac, 0xaa, 0xa3, 0x34, 0x89, 0xca, - 0x2e, - - // LStream4 - 0xe9, 0xc1, 0xfe, 0xf2, 0x51, 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, 0xed, 0xd9, 0xb7, 0x4a, - 0xb2, 0xb2, 0x61, 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, 0xdc, 0x60, 0x6c, 0x41, - 0x76, 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, 0xac, 0x9d, 0xe0, 0x62, - 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, 0xd2, 0x7c, 0x0a, 0x7c, - 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, 0xda, 0x15, 0x91, 0xde, 0x21, - 0xf5, 0x55, - - // Sequence Section - 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, 0x42, 0x44, 0x81, 0x8c, 0x94, 0xb4, 0x50, 0x1e, 0x20, - 0x42, 0x82, 0x98, 0xc2, 0x3b, 0x10, 0x48, 0xec, 0xa6, 0x39, 0x63, 0x13, 0xa7, 0x01, 0x94, 0x40, - 0xff, 0x88, 0x0f, 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, 0xcb, 0xf6, 0xc8, 0x21, 0x59, 0xaa, - 0x38, 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, 0xc8, 0x03, 0x42, 0x2a, 0x4b, 0xf6, - 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, 0x7e, 0x00, 0xbc, 0x2f, 0x46, 0x96, - 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, 0x8c, 0xc2, 0x05, 0xf7, 0x54, 0x51, - 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, 0x99, 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, - 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, 0x50, 0x84, 0xf5, 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, - 0x4c, 0x52, 0x4f, 0x20, 0xa3, 0x61, 0x23, 0x77, 0x12, 0xd3, 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, - 0x70, 0xec, 0x14, 0x91, 0xf9, 0x85, 0x61, 0xd5, 0x7e, 0x98, 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, - 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, + 0xa9, 0x6b, 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, 0x69, 0x18, + 0x57, 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, 0x7b, + 0x6e, 0xd8, 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, 0x14, + 0xf4, 0x40, 0xe7, 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, 0x49, 0xae, + 0x13, 0xa4, 0x75, 0x38, 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, 0x86, 0xa4, 0xac, + 0xaa, 0xa3, 0x34, 0x89, 0xca, 0x2e, // LStream4 + 0xe9, 0xc1, 0xfe, 0xf2, 0x51, 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, 0xed, 0xd9, 0xb7, + 0x4a, 0xb2, 0xb2, 0x61, 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, 0xdc, 0x60, + 0x6c, 0x41, 0x76, 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, 0xac, + 0x9d, 0xe0, 0x62, 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, + 0xd2, 0x7c, 0x0a, 0x7c, 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, + 0xda, 0x15, 0x91, 0xde, 0x21, 0xf5, 0x55, // Sequence Section + 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, 0x42, 0x44, 0x81, 0x8c, 0x94, 0xb4, 0x50, 0x1e, + 0x20, 0x42, 0x82, 0x98, 0xc2, 0x3b, 0x10, 0x48, 0xec, 0xa6, 0x39, 0x63, 0x13, 0xa7, 0x01, + 0x94, 0x40, 0xff, 0x88, 0x0f, 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, 0xcb, 0xf6, 0xc8, + 0x21, 0x59, 0xaa, 0x38, 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, 0xc8, 0x03, + 0x42, 0x2a, 0x4b, 0xf6, 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, 0x7e, + 0x00, 0xbc, 0x2f, 0x46, 0x96, 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, + 0x8c, 0xc2, 0x05, 0xf7, 0x54, 0x51, 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, + 0x99, 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, 0x50, + 0x84, 0xf5, 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, 0x4c, 0x52, 0x4f, 0x20, 0xa3, 0x61, 0x23, + 0x77, 0x12, 0xd3, 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, 0x70, 0xec, 0x14, 0x91, 0xf9, 0x85, + 0x61, 0xd5, 0x7e, 0x98, 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, + 0x82, 0x14, 0x95, 0x51, ]; let decompression_circuit = DecompressionCircuit:: { @@ -90,4 +80,4 @@ fn test_work_example_decompression() { } mock_prover.assert_satisfied_par(); -} \ No newline at end of file +} diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index 6712f1c26c..b492fe198f 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -1223,8 +1223,8 @@ impl BitstringAccumulationTable { // huffman code and lstreams cb.require_boolean( "byte2 == byte1 or byte2 == byte1 + 1", - meta.query_advice(table.byte_idx_2, Rotation::cur()) - - meta.query_advice(table.byte_idx_1, Rotation::cur()), + meta.query_advice(table.byte_idx_2, Rotation::cur()) + - meta.query_advice(table.byte_idx_1, Rotation::cur()), ); cb.gate(and::expr([ @@ -1418,7 +1418,8 @@ impl BitstringAccumulationTable { // Get the byte at which FSE is described // TODO: Determining huffman offset in a multi-block scenario. - let huffman_offset = witness_rows.iter() + let huffman_offset = witness_rows + .iter() .find(|&r| r.state.tag == ZstdTag::ZstdBlockFseCode) .unwrap() .encoded_data @@ -1625,7 +1626,7 @@ impl LookupTable for BitstringAccumulationTable { String::from("bit_index"), String::from("from_start"), String::from("until_end"), - String::from("is_reverse") + String::from("is_reverse"), ] } } diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 1f57f10f6f..de3f967fc9 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -39,8 +39,7 @@ pub use tx::Transaction; mod zstd; pub use zstd::{ - FseAuxiliaryTableData, FseSymbol, FseTableData, FseTableRow, HuffmanCodesData, LstreamNum, - TagRomTableRow, ZstdWitnessRow, ZstdTag, N_BITS_PER_BYTE, N_BITS_SYMBOL, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, - N_JUMP_TABLE_BYTES, N_MAX_SYMBOLS, process, + process, util::value_bits_le, FseAuxiliaryTableData, FseSymbol, FseTableData, FseTableRow, + HuffmanCodesData, LstreamNum, TagRomTableRow, ZstdTag, ZstdWitnessRow, N_BITS_PER_BYTE, + N_BITS_SYMBOL, N_BITS_ZSTD_TAG, N_BLOCK_HEADER_BYTES, N_JUMP_TABLE_BYTES, N_MAX_SYMBOLS, }; -pub use zstd::util::value_bits_le; diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 4f533f9638..75cdeaf9db 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -7,8 +7,7 @@ mod params; pub use params::*; mod types; -pub use types::*; -pub use types::ZstdTag::*; +pub use types::{ZstdTag::*, *}; #[cfg(test)] mod tui; @@ -16,7 +15,7 @@ mod tui; use tui::draw_rows; pub mod util; -use util::{value_bits_le, le_bits_to_value, be_bits_to_value, increment_idx}; +use util::{be_bits_to_value, increment_idx, le_bits_to_value, value_bits_le}; const TAG_MAX_LEN: [(ZstdTag, u64); 13] = [ (FrameHeaderDescriptor, 1), @@ -35,7 +34,12 @@ const TAG_MAX_LEN: [(ZstdTag, u64); 13] = [ ]; fn lookup_max_tag_len(tag: ZstdTag) -> u64 { - TAG_MAX_LEN.iter().filter(|record| record.0 == tag).next().unwrap().1 + TAG_MAX_LEN + .iter() + .filter(|record| record.0 == tag) + .next() + .unwrap() + .1 } /// FrameHeaderDescriptor and FrameContentSize @@ -119,11 +123,8 @@ fn process_frame_header( Some(*acc) }) .collect::>>(); - let tag_rlc = *(tag_rlc_iter - .clone() - .last() - .expect("Tag RLC expected")); - + let tag_rlc = *(tag_rlc_iter.clone().last().expect("Tag RLC expected")); + let aux_1 = fcs_value_rlcs .last() .expect("FrameContentSize bytes expected"); @@ -172,40 +173,42 @@ fn process_frame_header( .zip(tag_rlc_iter.iter().rev()) .enumerate() .map( - |(i, (((&value_byte, tag_value_acc), _value_rlc), &tag_rlc_acc))| ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::FrameContentSize, - tag_next: ZstdTag::BlockHeader, - max_tag_len: lookup_max_tag_len(ZstdTag::FrameContentSize), - tag_len: fcs_tag_len as u64, - tag_idx: (i + 1) as u64, - tag_value: fcs_tag_value, - tag_value_acc, - is_tag_change: i == 0, - tag_rlc, - tag_rlc_acc, - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + 2 + i) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte, - reverse: true, - reverse_idx: (fcs_tag_len - i) as u64, - reverse_len: fcs_tag_len as u64, - aux_1: *aux_1, - aux_2, - value_rlc: fhd_value_rlc, - }, - decoded_data: DecodedData { - decoded_len: fcs, - decoded_len_acc: 0, - total_decoded_len: last_row.decoded_data.total_decoded_len + fcs, - decoded_byte: 0, - decoded_value_rlc: Value::known(F::zero()), - }, - bitstream_read_data: BitstreamReadRow::default(), - huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), + |(i, (((&value_byte, tag_value_acc), _value_rlc), &tag_rlc_acc))| { + ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::FrameContentSize, + tag_next: ZstdTag::BlockHeader, + max_tag_len: lookup_max_tag_len(ZstdTag::FrameContentSize), + tag_len: fcs_tag_len as u64, + tag_idx: (i + 1) as u64, + tag_value: fcs_tag_value, + tag_value_acc, + is_tag_change: i == 0, + tag_rlc, + tag_rlc_acc, + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + 2 + i) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte, + reverse: true, + reverse_idx: (fcs_tag_len - i) as u64, + reverse_len: fcs_tag_len as u64, + aux_1: *aux_1, + aux_2, + value_rlc: fhd_value_rlc, + }, + decoded_data: DecodedData { + decoded_len: fcs, + decoded_len_acc: 0, + total_decoded_len: last_row.decoded_data.total_decoded_len + fcs, + decoded_byte: 0, + decoded_value_rlc: Value::known(F::zero()), + }, + bitstream_read_data: BitstreamReadRow::default(), + huffman_data: HuffmanData::default(), + fse_data: FseTableRow::default(), + } }, ), ) @@ -218,7 +221,16 @@ fn process_block( byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>, bool, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData) { +) -> ( + usize, + Vec>, + bool, + Vec, + Vec, + Vec, + FseAuxiliaryTableData, + HuffmanCodesData, +) { let mut witness_rows = vec![]; let (byte_offset, rows, last_block, block_type, block_size) = @@ -226,36 +238,46 @@ fn process_block( witness_rows.extend_from_slice(&rows); let last_row = rows.last().expect("last row expected to exist"); - let (_byte_offset, rows, literals, lstream_len, aux_data, fse_aux_table, huffman_codes) = match block_type { - BlockType::RawBlock => process_block_raw( - src, - byte_offset, - last_row, - randomness, - block_size, - last_block, - ), - BlockType::RleBlock => process_block_rle( - src, - byte_offset, - last_row, - randomness, - block_size, - last_block, - ), - BlockType::ZstdCompressedBlock => process_block_zstd( - src, - byte_offset, - last_row, - randomness, - block_size, - last_block, - ), - BlockType::Reserved => unreachable!("Reserved block type not expected"), - }; + let (_byte_offset, rows, literals, lstream_len, aux_data, fse_aux_table, huffman_codes) = + match block_type { + BlockType::RawBlock => process_block_raw( + src, + byte_offset, + last_row, + randomness, + block_size, + last_block, + ), + BlockType::RleBlock => process_block_rle( + src, + byte_offset, + last_row, + randomness, + block_size, + last_block, + ), + BlockType::ZstdCompressedBlock => process_block_zstd( + src, + byte_offset, + last_row, + randomness, + block_size, + last_block, + ), + BlockType::Reserved => unreachable!("Reserved block type not expected"), + }; witness_rows.extend_from_slice(&rows); - (byte_offset, witness_rows, last_block, literals, lstream_len, aux_data, fse_aux_table, huffman_codes) + ( + byte_offset, + witness_rows, + last_block, + literals, + lstream_len, + aux_data, + fse_aux_table, + huffman_codes, + ) } fn process_block_header( @@ -282,10 +304,13 @@ fn process_block_header( _ => unreachable!("BlockType::Reserved unexpected"), }; - let tag_value_iter = bh_bytes.iter().rev().scan(Value::known(F::zero()), |acc, &byte| { - *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); - Some(*acc) - }); + let tag_value_iter = bh_bytes + .iter() + .rev() + .scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); + Some(*acc) + }); let tag_value = tag_value_iter.clone().last().expect("BlockHeader expected"); let tag_rlc_iter = bh_bytes @@ -295,12 +320,10 @@ fn process_block_header( Some(*acc) }) .collect::>>(); - let tag_rlc = *(tag_rlc_iter - .clone() - .last() - .expect("Tag RLC expected")); + let tag_rlc = *(tag_rlc_iter.clone().last().expect("Tag RLC expected")); - let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let multiplier = + (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; // BlockHeader follows FrameContentSize which is processed in reverse order. @@ -386,13 +409,14 @@ fn process_raw_bytes( Some(*acc) }, ); - let tag_value_iter = src.iter().skip(byte_offset).take(n_bytes).scan( - Value::known(F::zero()), - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ); + let tag_value_iter = + src.iter() + .skip(byte_offset) + .take(n_bytes) + .scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); let tag_value = tag_value_iter .clone() .last() @@ -517,7 +541,15 @@ fn process_block_raw( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData) { +) -> ( + usize, + Vec>, + Vec, + Vec, + Vec, + FseAuxiliaryTableData, + HuffmanCodesData, +) { let tag_next = if last_block { ZstdTag::Null } else { @@ -537,14 +569,22 @@ fn process_block_raw( let fse_aux_table = FseAuxiliaryTableData { byte_offset: 0, table_size: 0, - sym_to_states: BTreeMap::default() + sym_to_states: BTreeMap::default(), }; let mut huffman_weights = HuffmanCodesData { byte_offset: 0, - weights: vec![] + weights: vec![], }; - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0], fse_aux_table, huffman_weights) + ( + byte_offset, + rows.clone(), + vec![], + vec![rows.len() as u64, 0, 0, 0], + vec![0, 0, 0, 0, 0, 0], + fse_aux_table, + huffman_weights, + ) } fn process_block_rle( @@ -554,7 +594,15 @@ fn process_block_rle( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData) { +) -> ( + usize, + Vec>, + Vec, + Vec, + Vec, + FseAuxiliaryTableData, + HuffmanCodesData, +) { let tag_next = if last_block { ZstdTag::Null } else { @@ -562,26 +610,34 @@ fn process_block_rle( }; let (byte_offset, rows) = process_rle_bytes( - src, - byte_offset, - last_row, - randomness, - block_size, - ZstdTag::RleBlockBytes, + src, + byte_offset, + last_row, + randomness, + block_size, + ZstdTag::RleBlockBytes, tag_next, ); let fse_aux_table = FseAuxiliaryTableData { byte_offset: 0, table_size: 0, - sym_to_states: BTreeMap::default() + sym_to_states: BTreeMap::default(), }; let mut huffman_weights = HuffmanCodesData { byte_offset: 0, - weights: vec![] + weights: vec![], }; - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0, 0, 0], fse_aux_table, huffman_weights) + ( + byte_offset, + rows.clone(), + vec![], + vec![rows.len() as u64, 0, 0, 0], + vec![0, 0, 0, 0, 0, 0], + fse_aux_table, + huffman_weights, + ) } #[allow(unused_variables)] @@ -592,67 +648,100 @@ fn process_block_zstd( randomness: Value, block_size: usize, last_block: bool, -) -> (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData) { +) -> ( + usize, + Vec>, + Vec, + Vec, + Vec, + FseAuxiliaryTableData, + HuffmanCodesData, +) { let mut witness_rows = vec![]; // 1-5 bytes LiteralSectionHeader let ( - byte_offset, - rows, - literals_block_type, - n_streams, - regen_size, + byte_offset, + rows, + literals_block_type, + n_streams, + regen_size, compressed_size, (branch, sf_max), - ) = process_block_zstd_literals_header::( - src, - byte_offset, - last_row, - randomness - ); + ) = process_block_zstd_literals_header::(src, byte_offset, last_row, randomness); witness_rows.extend_from_slice(&rows); let mut fse_aux_table = FseAuxiliaryTableData { byte_offset: 0, table_size: 0, - sym_to_states: BTreeMap::default() + sym_to_states: BTreeMap::default(), }; let mut huffman_weights = HuffmanCodesData { byte_offset: 0, - weights: vec![] + weights: vec![], }; // Depending on the literals block type, decode literals section accordingly - let (bytes_offset, rows, literals, lstream_len, aux_data): (usize, Vec>, Vec, Vec, Vec) = match literals_block_type { + let (bytes_offset, rows, literals, lstream_len, aux_data): ( + usize, + Vec>, + Vec, + Vec, + Vec, + ) = match literals_block_type { BlockType::RawBlock => { let (byte_offset, rows) = process_raw_bytes( - src, - byte_offset, - rows.last().expect("last row expected to exist"), - randomness, - regen_size, - ZstdTag::ZstdBlockLiteralsRawBytes, + src, + byte_offset, + rows.last().expect("last row expected to exist"), + randomness, + regen_size, + ZstdTag::ZstdBlockLiteralsRawBytes, ZstdTag::ZstdBlockSequenceHeader, ); - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0]) - }, + ( + byte_offset, + rows.clone(), + vec![], + vec![rows.len() as u64, 0, 0, 0], + vec![0, 0, 0, 0], + ) + } BlockType::RleBlock => { let (byte_offset, rows) = process_rle_bytes( - src, - byte_offset, - rows.last().expect("last row expected to exist"), - randomness, - regen_size, - ZstdTag::ZstdBlockLiteralsRleBytes, + src, + byte_offset, + rows.last().expect("last row expected to exist"), + randomness, + regen_size, + ZstdTag::ZstdBlockLiteralsRleBytes, ZstdTag::ZstdBlockSequenceHeader, ); - (byte_offset, rows.clone(), vec![], vec![rows.len() as u64, 0, 0, 0], vec![0, 0, 0, 0]) - }, + ( + byte_offset, + rows.clone(), + vec![], + vec![rows.len() as u64, 0, 0, 0], + vec![0, 0, 0, 0], + ) + } BlockType::ZstdCompressedBlock => { let mut huffman_rows = vec![]; - let (bytes_offset, rows, huffman_codes, n_huffman_bytes, huffman_byte_offset, last_rlc, huffman_idx, fse_size, fse_accuracy, n_huffman_bitstream_bytes, fse_aux_data) = process_block_zstd_huffman_code( + let ( + bytes_offset, + rows, + huffman_codes, + n_huffman_bytes, + huffman_byte_offset, + last_rlc, + huffman_idx, + fse_size, + fse_accuracy, + n_huffman_bitstream_bytes, + fse_aux_data, + ) = process_block_zstd_huffman_code( src, byte_offset, rows.last().expect("last row must exist"), @@ -663,8 +752,9 @@ fn process_block_zstd( fse_aux_table = fse_aux_data; huffman_weights = huffman_codes.clone(); - // Subtract huffman header (1-byte), len of huffman bytes and 6-byte jump table (if n_streams > 1) - let mut literal_stream_size = compressed_size - (n_huffman_bytes + 1); + // Subtract huffman header (1-byte), len of huffman bytes and 6-byte jump table (if + // n_streams > 1) + let mut literal_stream_size = compressed_size - (n_huffman_bytes + 1); if n_streams > 1 { literal_stream_size -= 6; } @@ -673,8 +763,8 @@ fn process_block_zstd( let mut stream_offset = bytes_offset; let (bytes_offset, rows, lstream_lens) = process_block_zstd_huffman_jump_table( - src, - stream_offset, + src, + stream_offset, huffman_rows.last().expect("last row should exist"), literal_stream_size, n_streams, @@ -688,7 +778,7 @@ fn process_block_zstd( for idx in 0..n_streams { let (byte_offset, rows, symbols) = process_block_zstd_lstream( - src, + src, stream_offset, lstream_lens[idx] as usize, huffman_rows.last().expect("last row should exist"), @@ -702,14 +792,42 @@ fn process_block_zstd( stream_offset = byte_offset; } - - (stream_offset, huffman_rows, literals, lstream_lens, vec![huffman_idx as u64, fse_size, fse_accuracy, n_huffman_bitstream_bytes]) - }, - _ => unreachable!("Invalid literals section BlockType") + + ( + stream_offset, + huffman_rows, + literals, + lstream_lens, + vec![ + huffman_idx as u64, + fse_size, + fse_accuracy, + n_huffman_bitstream_bytes, + ], + ) + } + _ => unreachable!("Invalid literals section BlockType"), }; witness_rows.extend_from_slice(&rows); - (bytes_offset, witness_rows, literals, lstream_len, vec![regen_size as u64, compressed_size as u64, aux_data[0], aux_data[1], aux_data[2], aux_data[3], branch, sf_max as u64], fse_aux_table, huffman_weights) + ( + bytes_offset, + witness_rows, + literals, + lstream_len, + vec![ + regen_size as u64, + compressed_size as u64, + aux_data[0], + aux_data[1], + aux_data[2], + aux_data[3], + branch, + sf_max as u64, + ], + fse_aux_table, + huffman_weights, + ) } fn process_block_zstd_literals_header( @@ -717,7 +835,15 @@ fn process_block_zstd_literals_header( byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> (usize, Vec>, BlockType, usize, usize, usize, (u64, bool)) { +) -> ( + usize, + Vec>, + BlockType, + usize, + usize, + usize, + (u64, bool), +) { let lh_bytes = src .iter() .skip(byte_offset) @@ -729,25 +855,22 @@ fn process_block_zstd_literals_header( let size_format = (lh_bytes[0] >> 2) & 3; let sf_max = size_format == 3; - let [n_bits_fmt, n_bits_regen, n_bits_compressed, n_streams, n_bytes_header, branch]: [usize; 6] = match literals_block_type { - BlockType::RawBlock | BlockType::RleBlock => { - match size_format { - 0b00 | 0b10 => [1, 5, 0, 1, 1, 0], - 0b01 => [2, 12, 0, 1, 2, 1], - 0b11 => [2, 20, 0, 1, 3, 2], - _ => unreachable!("size_format out of bound") - } + let [n_bits_fmt, n_bits_regen, n_bits_compressed, n_streams, n_bytes_header, branch]: [usize; + 6] = match literals_block_type { + BlockType::RawBlock | BlockType::RleBlock => match size_format { + 0b00 | 0b10 => [1, 5, 0, 1, 1, 0], + 0b01 => [2, 12, 0, 1, 2, 1], + 0b11 => [2, 20, 0, 1, 3, 2], + _ => unreachable!("size_format out of bound"), }, - BlockType::ZstdCompressedBlock => { - match size_format { - 0b00 => [2, 10, 10, 1, 3, 3], - 0b01 => [2, 10, 10, 4, 3, 4], - 0b10 => [2, 14, 14, 4, 4, 5], - 0b11 => [2, 18, 18, 4, 5, 6], - _ => unreachable!("size_format out of bound") - } + BlockType::ZstdCompressedBlock => match size_format { + 0b00 => [2, 10, 10, 1, 3, 3], + 0b01 => [2, 10, 10, 4, 3, 4], + 0b10 => [2, 14, 14, 4, 4, 5], + 0b11 => [2, 18, 18, 4, 5, 6], + _ => unreachable!("size_format out of bound"), }, - _ => unreachable!("BlockType::Reserved unexpected or treeless literal section") + _ => unreachable!("BlockType::Reserved unexpected or treeless literal section"), }; // Bits for representing regenerated_size and compressed_size @@ -757,7 +880,8 @@ fn process_block_zstd_literals_header( })[(2 + n_bits_fmt)..(n_bytes_header * N_BITS_PER_BYTE)]; let regen_size = le_bits_to_value(&sizing_bits[0..n_bits_regen]); - let compressed_size = le_bits_to_value(&sizing_bits[n_bits_regen..(n_bits_regen + n_bits_compressed)]); + let compressed_size = + le_bits_to_value(&sizing_bits[n_bits_regen..(n_bits_regen + n_bits_compressed)]); let tag_next = match literals_block_type { BlockType::RawBlock => ZstdTag::ZstdBlockLiteralsRawBytes, @@ -766,27 +890,40 @@ fn process_block_zstd_literals_header( _ => unreachable!("BlockType::Reserved unexpected or treeless literal section"), }; - let tag_value_iter = lh_bytes.iter().take(n_bytes_header).scan(Value::known(F::zero()), |acc, &byte| { - *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); - Some(*acc) - }); - let tag_value = tag_value_iter.clone().last().expect("LiteralsHeader expected"); + let tag_value_iter = + lh_bytes + .iter() + .take(n_bytes_header) + .scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * Value::known(F::from(256u64)) + Value::known(F::from(byte as u64)); + Some(*acc) + }); + let tag_value = tag_value_iter + .clone() + .last() + .expect("LiteralsHeader expected"); - let tag_rlc_iter = lh_bytes.iter().take(n_bytes_header).scan(Value::known(F::zero()), |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }); + let tag_rlc_iter = + lh_bytes + .iter() + .take(n_bytes_header) + .scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); let tag_rlc = tag_rlc_iter.clone().last().expect("Tag RLC expected"); - let value_rlc_iter = lh_bytes - .iter() - .take(n_bytes_header) - .scan(last_row.encoded_data.value_rlc, |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }); + let value_rlc_iter = + lh_bytes + .iter() + .take(n_bytes_header) + .scan(last_row.encoded_data.value_rlc, |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); - let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let multiplier = + (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; ( @@ -841,7 +978,19 @@ fn process_block_zstd_huffman_code( last_row: &ZstdWitnessRow, randomness: Value, n_streams: usize, -) -> (usize, Vec>, HuffmanCodesData, usize, usize, Value, usize, u64, u64, u64, FseAuxiliaryTableData) { +) -> ( + usize, + Vec>, + HuffmanCodesData, + usize, + usize, + Value, + usize, + u64, + u64, + u64, + FseAuxiliaryTableData, +) { // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; @@ -858,16 +1007,18 @@ fn process_block_zstd_huffman_code( assert!(header_byte < 128, "FSE encoded huffman weights assumed"); let n_bytes = header_byte as usize; - let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let multiplier = + (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; - + // Add a witness row for Huffman header let mut huffman_header_row: ZstdWitnessRow = ZstdWitnessRow { state: ZstdState { tag: ZstdTag::ZstdBlockFseCode, tag_next, max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockFseCode), - tag_len: 0 as u64, // There's no information at this point about the length of FSE table bytes. So this value has to be modified later. + tag_len: 0 as u64, /* There's no information at this point about the length of FSE + * table bytes. So this value has to be modified later. */ tag_idx: 1 as u64, tag_value: Value::default(), // Must be changed after FSE table length is known tag_value_acc: Value::default(), // Must be changed after FSE table length is known @@ -895,8 +1046,10 @@ fn process_block_zstd_huffman_code( }; // Recover the FSE table for generating Huffman weights - let (n_fse_bytes, bit_boundaries, table) = FseAuxiliaryTableData::reconstruct(&src, byte_offset + 1).expect("Reconstructing FSE table should not fail."); - + let (n_fse_bytes, bit_boundaries, table) = + FseAuxiliaryTableData::reconstruct(&src, byte_offset + 1) + .expect("Reconstructing FSE table should not fail."); + // Witness generation let accuracy_log = (src[byte_offset + 1] & 0b1111) + 5; @@ -907,10 +1060,7 @@ fn process_block_zstd_huffman_code( Some(*acc) }, ); - let tag_value = tag_value_iter - .clone() - .last() - .expect("Tag value must exist"); + let tag_value = tag_value_iter.clone().last().expect("Tag value must exist"); let mut tag_rlc_iter = src.iter().skip(byte_offset).take(n_fse_bytes + 1).scan( Value::known(F::zero()), @@ -919,15 +1069,13 @@ fn process_block_zstd_huffman_code( Some(*acc) }, ); - let tag_rlc = tag_rlc_iter - .clone() - .last() - .expect("Tag RLC must exist"); + let tag_rlc = tag_rlc_iter.clone().last().expect("Tag RLC must exist"); // Backfill missing data on the huffman header row huffman_header_row.state.tag_len = (n_fse_bytes + 1usize) as u64; huffman_header_row.state.tag_value = tag_value; - huffman_header_row.state.tag_value_acc = tag_value_iter.next().expect("Next value should exist"); + huffman_header_row.state.tag_value_acc = + tag_value_iter.next().expect("Next value should exist"); huffman_header_row.state.tag_rlc = tag_rlc; huffman_header_row.state.tag_rlc_acc = tag_rlc_iter.next().expect("Next value expected"); witness_rows.push(huffman_header_row); @@ -941,42 +1089,63 @@ fn process_block_zstd_huffman_code( let mut from_pos: (i64, i64) = (1, 0); let mut to_pos: (i64, i64) = (0, 0); - let bitstream_rows = bit_boundaries.iter().enumerate().map(|(sym, (bit_idx, value))| { - from_pos = if sym == 0 { - (1, -1) - } else { - to_pos - }; + let bitstream_rows = bit_boundaries + .iter() + .enumerate() + .map(|(sym, (bit_idx, value))| { + from_pos = if sym == 0 { (1, -1) } else { to_pos }; - from_pos.1 += 1; - if from_pos.1 == 8 { - from_pos = (from_pos.0 + 1, 0); - } - from_pos.1 = (from_pos.1 as u64).rem_euclid(8) as i64; + from_pos.1 += 1; + if from_pos.1 == 8 { + from_pos = (from_pos.0 + 1, 0); + } + from_pos.1 = (from_pos.1 as u64).rem_euclid(8) as i64; - if from_pos.0 > last_byte_idx { - current_tag_value_acc = tag_value_iter.next().unwrap(); - current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); - last_byte_idx = from_pos.0; - } + if from_pos.0 > last_byte_idx { + current_tag_value_acc = tag_value_iter.next().unwrap(); + current_tag_rlc_acc = tag_rlc_iter.next().unwrap(); + last_byte_idx = from_pos.0; + } - let to_byte_idx = (bit_idx - 1) / 8; - let mut to_bit_idx = bit_idx - to_byte_idx * (N_BITS_PER_BYTE as u32) - 1; + let to_byte_idx = (bit_idx - 1) / 8; + let mut to_bit_idx = bit_idx - to_byte_idx * (N_BITS_PER_BYTE as u32) - 1; - if from_pos.0 < (to_byte_idx + 1) as i64 { - to_bit_idx += 8; - } + if from_pos.0 < (to_byte_idx + 1) as i64 { + to_bit_idx += 8; + } - to_pos = ((to_byte_idx + 1) as i64, to_bit_idx as i64); + to_pos = ((to_byte_idx + 1) as i64, to_bit_idx as i64); - if sym > 0 && n_acc < (1 << accuracy_log) { - decoded = (sym - 1) as u8; - n_acc += (*value - 1) as usize; - } + if sym > 0 && n_acc < (1 << accuracy_log) { + decoded = (sym - 1) as u8; + n_acc += (*value - 1) as usize; + } - (decoded, from_pos.0 as usize, from_pos.1 as usize, to_pos.0 as usize, to_pos.1 as usize, value.clone(), current_tag_value_acc.clone(), current_tag_rlc_acc.clone(), 0, n_acc) - }) - .collect::, Value, usize, usize)>>(); + ( + decoded, + from_pos.0 as usize, + from_pos.1 as usize, + to_pos.0 as usize, + to_pos.1 as usize, + value.clone(), + current_tag_value_acc.clone(), + current_tag_rlc_acc.clone(), + 0, + n_acc, + ) + }) + .collect::, + Value, + usize, + usize, + )>>(); // Add witness rows for FSE representation bytes for row in bitstream_rows { @@ -1001,18 +1170,18 @@ fn process_block_zstd_huffman_code( reverse: false, ..Default::default() }, - bitstream_read_data: BitstreamReadRow { - bit_start_idx: row.2, - bit_end_idx: row.4, + bitstream_read_data: BitstreamReadRow { + bit_start_idx: row.2, + bit_end_idx: row.4, bit_value: row.5, is_zero_bit_read: false, }, - decoded_data: DecodedData { - decoded_len: last_row.decoded_data.decoded_len, - decoded_len_acc: last_row.decoded_data.decoded_len_acc, - total_decoded_len: last_row.decoded_data.total_decoded_len, - decoded_byte: row.0, - decoded_value_rlc: last_row.decoded_data.decoded_value_rlc, + decoded_data: DecodedData { + decoded_len: last_row.decoded_data.decoded_len, + decoded_len_acc: last_row.decoded_data.decoded_len_acc, + total_decoded_len: last_row.decoded_data.total_decoded_len, + decoded_byte: row.0, + decoded_value_rlc: last_row.decoded_data.decoded_value_rlc, }, huffman_data: HuffmanData::default(), fse_data: FseTableRow { @@ -1023,7 +1192,7 @@ fn process_block_zstd_huffman_code( num_bits: 0, num_emitted: 0, n_acc: row.9 as u64, - } + }, }); } @@ -1036,7 +1205,8 @@ fn process_block_zstd_huffman_code( // Update the last row let last_row = witness_rows.last().expect("Last row exists"); - let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let multiplier = + (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; // Bitstream processing state values @@ -1047,50 +1217,50 @@ fn process_block_zstd_huffman_code( let mut current_bit_idx: usize = 0; // Construct the Huffman bitstream - let huffman_bitstream = - src - .iter() - .skip(byte_offset + n_fse_bytes + 1) - .take(n_huffman_code_bytes) - .rev() - .clone() - .flat_map(|v|{ - let mut bits = value_bits_le(*v); - bits.reverse(); - bits - }) - .collect::>(); + let huffman_bitstream = src + .iter() + .skip(byte_offset + n_fse_bytes + 1) + .take(n_huffman_code_bytes) + .rev() + .clone() + .flat_map(|v| { + let mut bits = value_bits_le(*v); + bits.reverse(); + bits + }) + .collect::>(); // Accumulators for Huffman code section - let mut value_rlc_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).scan( - Value::known(F::zero()), - |acc, &byte| { + let mut value_rlc_iter = src + .iter() + .skip(byte_offset + n_fse_bytes + 1) + .take(n_huffman_code_bytes) + .scan(Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) - }, - ).collect::>>().into_iter().rev(); - let mut tag_value_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).rev().scan( - Value::known(F::zero()), - |acc, &byte| { + }) + .collect::>>() + .into_iter() + .rev(); + let mut tag_value_iter = src + .iter() + .skip(byte_offset + n_fse_bytes + 1) + .take(n_huffman_code_bytes) + .rev() + .scan(Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) - }, - ); - let tag_value = tag_value_iter - .clone() - .last() - .expect("Tag value must exist"); - let tag_rlc_iter = src.iter().skip(byte_offset + n_fse_bytes + 1).take(n_huffman_code_bytes).scan( - Value::known(F::zero()), - |acc, &byte| { + }); + let tag_value = tag_value_iter.clone().last().expect("Tag value must exist"); + let tag_rlc_iter = src + .iter() + .skip(byte_offset + n_fse_bytes + 1) + .take(n_huffman_code_bytes) + .scan(Value::known(F::zero()), |acc, &byte| { *acc = *acc * randomness + Value::known(F::from(byte as u64)); Some(*acc) - }, - ); - let tag_rlc = tag_rlc_iter - .clone() - .last() - .expect("Tag RLC must exist"); + }); + let tag_rlc = tag_rlc_iter.clone().last().expect("Tag RLC must exist"); let mut tag_rlc_iter = tag_rlc_iter.collect::>>().into_iter().rev(); let mut next_tag_value_acc = tag_value_iter.next().unwrap(); @@ -1098,7 +1268,10 @@ fn process_block_zstd_huffman_code( let mut next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); let aux_1 = next_value_rlc_acc.clone(); - let aux_2 = witness_rows[witness_rows.len() - 1].encoded_data.value_rlc.clone(); + let aux_2 = witness_rows[witness_rows.len() - 1] + .encoded_data + .value_rlc + .clone(); let mut padding_end_idx: usize = 0; while huffman_bitstream[padding_end_idx] == 0 { @@ -1112,7 +1285,7 @@ fn process_block_zstd_huffman_code( tag_next, max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockHuffmanCode), tag_len: n_huffman_code_bytes as u64, - tag_idx: 1 as u64, + tag_idx: 1 as u64, tag_value: tag_value, tag_value_acc: next_tag_value_acc, is_tag_change: true, @@ -1122,7 +1295,8 @@ fn process_block_zstd_huffman_code( encoded_data: EncodedData { byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, - value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], + value_byte: src + [byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], value_rlc, reverse: true, reverse_len: n_huffman_code_bytes as u64, @@ -1157,9 +1331,9 @@ fn process_block_zstd_huffman_code( } // Now the actual weight-bearing bitstream starts - // The Huffman bitstream is decoded by two interleaved states reading the stream in alternating order. - // The FSE table for the two independent decoding strands are the same. - let mut color: usize = 0; // use 0, 1 (colors) to denote two alternating decoding strands. + // The Huffman bitstream is decoded by two interleaved states reading the stream in alternating + // order. The FSE table for the two independent decoding strands are the same. + let mut color: usize = 0; // use 0, 1 (colors) to denote two alternating decoding strands. let mut prev_baseline: [u64; 2] = [0, 0]; let mut next_nb_to_read: [usize; 2] = [accuracy_log as usize, accuracy_log as usize]; let mut decoded_weights: Vec = vec![]; @@ -1170,14 +1344,21 @@ fn process_block_zstd_huffman_code( while current_bit_idx + next_nb_to_read[color] <= (n_huffman_code_bytes) * N_BITS_PER_BYTE { let nb = next_nb_to_read[color]; - let bitstring_value = be_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); + let bitstring_value = + be_bits_to_value(&huffman_bitstream[current_bit_idx..(current_bit_idx + nb)]); let next_state = prev_baseline[color] + bitstring_value; let from_bit_idx = current_bit_idx.rem_euclid(8); - let to_bit_idx = if nb > 0 { from_bit_idx + (nb - 1) } else { from_bit_idx }; + let to_bit_idx = if nb > 0 { + from_bit_idx + (nb - 1) + } else { + from_bit_idx + }; // Lookup the FSE table row for the state - let fse_row = fse_state_table.get(&(next_state as u64)).expect("next state should be in fse table"); + let fse_row = fse_state_table + .get(&(next_state as u64)) + .expect("next state should be in fse table"); // Decode the symbol decoded_weights.push(fse_row.0 as u8); @@ -1200,7 +1381,8 @@ fn process_block_zstd_huffman_code( encoded_data: EncodedData { byte_idx: (byte_offset + n_fse_bytes + 1 + current_byte_idx) as u64, encoded_len, - value_byte: src[byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], + value_byte: src + [byte_offset + n_fse_bytes + 1 + n_huffman_code_bytes - current_byte_idx], value_rlc, reverse: true, reverse_len: n_huffman_code_bytes as u64, @@ -1251,28 +1433,29 @@ fn process_block_zstd_huffman_code( // Construct HuffmanCodesTable let huffman_codes = HuffmanCodesData { byte_offset: (huffman_code_byte_offset + 1) as u64, - weights: decoded_weights.into_iter().map(|w| FseSymbol::from(w as usize) ).collect() + weights: decoded_weights + .into_iter() + .map(|w| FseSymbol::from(w as usize)) + .collect(), }; // rlc after a reverse section - let mul = (0..(n_huffman_code_bytes - 1)).fold(Value::known(F::one()), |acc, _| { - acc * randomness - }); + let mul = + (0..(n_huffman_code_bytes - 1)).fold(Value::known(F::one()), |acc, _| acc * randomness); let new_value_rlc_init_value = aux_2 * mul + aux_1; ( - byte_offset + 1 + n_fse_bytes + n_huffman_code_bytes, - witness_rows, - huffman_codes, - n_bytes, - huffman_code_byte_offset + 1, + byte_offset + 1 + n_fse_bytes + n_huffman_code_bytes, + witness_rows, + huffman_codes, + n_bytes, + huffman_code_byte_offset + 1, new_value_rlc_init_value, - byte_offset + 1, (1 << accuracy_log) as u64, accuracy_log as u64, n_huffman_code_bytes as u64, - table, // FSE table + table, // FSE table ) } @@ -1289,8 +1472,8 @@ fn process_block_zstd_huffman_jump_table( (byte_offset, vec![], vec![literal_stream_size as u64]) } else { // Note: The decompressed size of each stream is equal to (regen_size + 3) / 4 - // but the compressed bitstream length will be different. - // Jump table provides information on the length of first 3 bitstreams. + // but the compressed bitstream length will be different. + // Jump table provides information on the length of first 3 bitstreams. let jt_bytes = src .iter() @@ -1305,14 +1488,16 @@ fn process_block_zstd_huffman_jump_table( let l3: u64 = jt_bytes[4] + jt_bytes[5] * 256; let l4: u64 = (literal_stream_size as u64) - l1 - l2 - l3; - let value_rlc_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( - last_rlc, - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ); - let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let value_rlc_iter = + src.iter() + .skip(byte_offset) + .take(N_JUMP_TABLE_BYTES) + .scan(last_rlc, |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); + let multiplier = + (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; let tag_value_iter = src.iter().skip(byte_offset).take(N_JUMP_TABLE_BYTES).scan( @@ -1333,10 +1518,7 @@ fn process_block_zstd_huffman_jump_table( Some(*acc) }, ); - let tag_rlc = tag_rlc_iter - .clone() - .last() - .expect("Tag value must exist."); + let tag_rlc = tag_rlc_iter.clone().last().expect("Tag value must exist."); ( byte_offset + N_JUMP_TABLE_BYTES, @@ -1348,42 +1530,40 @@ fn process_block_zstd_huffman_jump_table( .zip(tag_rlc_iter) .enumerate() .map( - |(i, (((&value_byte, tag_value_acc), _v_rlc), tag_rlc_acc))| { - ZstdWitnessRow { - state: ZstdState { - tag: ZstdTag::ZstdBlockJumpTable, - tag_next: ZstdTag::ZstdBlockLstream, - max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockJumpTable), - tag_len: N_JUMP_TABLE_BYTES as u64, - tag_idx: (i + 1) as u64, - tag_value, - tag_value_acc, - is_tag_change: i == 0, - tag_rlc, - tag_rlc_acc, - }, - encoded_data: EncodedData { - byte_idx: (byte_offset + i + 1) as u64, - encoded_len: last_row.encoded_data.encoded_len, - value_byte, - value_rlc, - reverse: false, - ..Default::default() - }, - bitstream_read_data: BitstreamReadRow { - bit_start_idx: 0, - bit_end_idx: 7, - bit_value: value_byte as u64, - is_zero_bit_read: false, - }, - decoded_data: last_row.decoded_data.clone(), - huffman_data: HuffmanData::default(), - fse_data: FseTableRow::default(), - } + |(i, (((&value_byte, tag_value_acc), _v_rlc), tag_rlc_acc))| ZstdWitnessRow { + state: ZstdState { + tag: ZstdTag::ZstdBlockJumpTable, + tag_next: ZstdTag::ZstdBlockLstream, + max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockJumpTable), + tag_len: N_JUMP_TABLE_BYTES as u64, + tag_idx: (i + 1) as u64, + tag_value, + tag_value_acc, + is_tag_change: i == 0, + tag_rlc, + tag_rlc_acc, + }, + encoded_data: EncodedData { + byte_idx: (byte_offset + i + 1) as u64, + encoded_len: last_row.encoded_data.encoded_len, + value_byte, + value_rlc, + reverse: false, + ..Default::default() + }, + bitstream_read_data: BitstreamReadRow { + bit_start_idx: 0, + bit_end_idx: 7, + bit_value: value_byte as u64, + is_zero_bit_read: false, + }, + decoded_data: last_row.decoded_data.clone(), + huffman_data: HuffmanData::default(), + fse_data: FseTableRow::default(), }, ) .collect::>(), - vec![l1, l2, l3, l4] + vec![l1, l2, l3, l4], ) } } @@ -1429,25 +1609,29 @@ fn process_block_zstd_lstream( Some(*acc) }, ); - let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); + let multiplier = + (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; - let mut tag_value_acc = src.iter().skip(byte_offset).take(len).rev().scan( - Value::known(F::zero()), - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ); + let mut tag_value_acc = + src.iter() + .skip(byte_offset) + .take(len) + .rev() + .scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); let tag_value = tag_value_acc.clone().last().expect("Tag value exists"); - let tag_rlc_iter = src.iter().skip(byte_offset).take(len).scan( - Value::known(F::zero()), - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ); + let tag_rlc_iter = + src.iter() + .skip(byte_offset) + .take(len) + .scan(Value::known(F::zero()), |acc, &byte| { + *acc = *acc * randomness + Value::known(F::from(byte as u64)); + Some(*acc) + }); let tag_rlc = tag_rlc_iter.clone().last().expect("Tag value exists"); let mut tag_rlc_iter = tag_rlc_iter.collect::>>().into_iter().rev(); @@ -1455,7 +1639,7 @@ fn process_block_zstd_lstream( let tag_next = match stream_idx { 0 | 1 | 2 => ZstdTag::ZstdBlockLstream, 3 => ZstdTag::ZstdBlockSequenceHeader, - _ => unreachable!("stream_idx value out of range") + _ => unreachable!("stream_idx value out of range"), }; let mut padding_end_idx = 0; @@ -1515,7 +1699,7 @@ fn process_block_zstd_lstream( }, fse_data: FseTableRow::default(), }); - + // Exclude the leading zero section while lstream_bits[current_bit_idx] == 0 { (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); @@ -1539,15 +1723,19 @@ fn process_block_zstd_lstream( while current_bit_idx < len * N_BITS_PER_BYTE { if huffman_bitstring_map.contains_key(bitstring_acc.as_str()) { - let sym = huffman_bitstring_map.get(bitstring_acc.as_str()).unwrap().clone(); + let sym = huffman_bitstring_map + .get(bitstring_acc.as_str()) + .unwrap() + .clone(); decoded_symbols.push(sym); - + let from_byte_idx = current_byte_idx; let from_bit_idx = current_bit_idx; // advance byte and bit marks to the last bit - for _ in 0..(cur_bitstring_len - 1) { - (current_byte_idx, current_bit_idx) = increment_idx(current_byte_idx, current_bit_idx); + for _ in 0..(cur_bitstring_len - 1) { + (current_byte_idx, current_bit_idx) = + increment_idx(current_byte_idx, current_bit_idx); } let end_bit_idx = if current_byte_idx > from_byte_idx { current_bit_idx.rem_euclid(8) + 8 @@ -1637,7 +1825,16 @@ fn process_block_zstd_lstream( } /// Process a slice of bytes into decompression circuit witness rows -pub fn process(src: &[u8], randomness: Value) -> (Vec>, Vec, Vec, Vec, Vec) { +pub fn process( + src: &[u8], + randomness: Value, +) -> ( + Vec>, + Vec, + Vec, + Vec, + Vec, +) { let mut witness_rows = vec![]; let mut literals: Vec = vec![]; let mut aux_data: Vec = vec![]; @@ -1655,7 +1852,16 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec( + let ( + _byte_offset, + rows, + last_block, + new_literals, + lstream_lens, + pipeline_data, + fse_aux_table, + huffman_code, + ) = process_block::( src, byte_offset, rows.last().expect("last row expected to exist"), @@ -1678,17 +1884,23 @@ pub fn process(src: &[u8], randomness: Value) -> (Vec(&compressed, Value::known(Fr::from(123456789))); + let (_witness_rows, _decoded_literals, _aux_data, fse_aux_tables, huffman_codes) = + process::(&compressed, Value::known(Fr::from(123456789))); Ok(()) } @@ -1769,42 +1982,47 @@ mod tests { // Example link: https://nigeltao.github.io/blog/2022/zstandard-part-5-fse.html #[test] fn interleaved_huffman_code_fse() -> Result<(), std::io::Error> { - // Input includes FSE table representation (normalized symbol frequencies) and the actual Huffman bitstream - // For structure reference: https://nigeltao.github.io/blog/2022/zstandard-part-2-structure.html + // Input includes FSE table representation (normalized symbol frequencies) and the actual + // Huffman bitstream For structure reference: https://nigeltao.github.io/blog/2022/zstandard-part-2-structure.html let input: [u8; 36] = [ - 0x23, 0x30, 0x6f, 0x9b, 0x03, 0x7d, 0xc7, 0x16, - 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, - 0xbc, 0x54, 0x5d, 0xa9, 0xd4, 0x93, 0xef, 0xc4, - 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, - 0x54, 0x40, 0x29, 0x01, + 0x23, 0x30, 0x6f, 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, + 0x4b, 0x6b, 0xbc, 0x54, 0x5d, 0xa9, 0xd4, 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, + 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, 0x01, ]; - let (_byte_offset, _witness_rows, huffman_codes, _n_huffan_bytes, _huffman_byte_offset, _last_rlc, _huffman_idx, _fse_size, _fse_accuracy, _n_huffman_bitstream_bytes, fse_aux_data) = - process_block_zstd_huffman_code::( - &input, - 0, - &ZstdWitnessRow::init(0), - Value::known(Fr::from(123456789)), - 4 - ); + let ( + _byte_offset, + _witness_rows, + huffman_codes, + _n_huffan_bytes, + _huffman_byte_offset, + _last_rlc, + _huffman_idx, + _fse_size, + _fse_accuracy, + _n_huffman_bitstream_bytes, + fse_aux_data, + ) = process_block_zstd_huffman_code::( + &input, + 0, + &ZstdWitnessRow::init(0), + Value::known(Fr::from(123456789)), + 4, + ); let expected_weights: Vec = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 6, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 2, 0, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, - 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, 1, 1, 1, 2, - 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, - 0, 5, 3, 3, 3, 6, 3, 2, 4, 4, 0, 1, 4, 4, 5, 5, - 2, 0, 4, 4, 5, 3, 1, 3, 1, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 0, 0, 2, 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, 1, 1, 1, 2, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 5, 3, 3, 3, 6, 3, 2, 4, 4, 0, 1, 4, 4, 5, 5, 2, 0, 4, 4, + 5, 3, 1, 3, 1, 3, ] .into_iter() - .map(|w| FseSymbol::from(w) ) + .map(|w| FseSymbol::from(w)) .collect::>(); assert_eq!( - huffman_codes.weights, - expected_weights, + huffman_codes.weights, expected_weights, "Huffman weights should be correctly decoded with interleaved states" ); @@ -1818,32 +2036,25 @@ mod tests { let huffman_codes = HuffmanCodesData { byte_offset: 0, weights: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 6, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 2, 0, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, - 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, 1, 1, 1, 2, - 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, - 0, 5, 3, 3, 3, 6, 3, 2, 4, 4, 0, 1, 4, 4, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 0, 0, 0, 2, 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, 1, 1, 1, 2, 0, 0, 1, 1, + 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 5, 3, 3, 3, 6, 3, 2, 4, 4, 0, 1, 4, 4, 5, 5, 2, 0, 4, 4, 5, 3, 1, 3, 1, 3, ] .into_iter() - .map(|w| FseSymbol::from(w) ) - .collect::>() + .map(|w| FseSymbol::from(w)) + .collect::>(), }; let lstream1: [u8; 85] = [ - 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, - 0xfc, 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, - 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, - 0x71, 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, - 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, - 0xd0, 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, - 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, - 0x94, 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, - 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, - 0xc6, 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, - 0x24, 0x5a, 0xdf, 0xb4, 0x21, + 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, 0xc5, 0xca, 0x6a, 0x7a, 0xd9, + 0x82, 0x9c, 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, 0xee, 0xdc, 0xd5, + 0xa2, 0xe3, 0x48, 0xad, 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, 0x77, + 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, + 0x94, 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, + 0x13, 0x77, 0xc6, 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, 0x5a, 0xdf, 0xb4, + 0x21, ]; let (_byte_offset, _witness_rows, decoded_symbols) = process_block_zstd_lstream::( @@ -1857,10 +2068,16 @@ mod tests { 0, ); - let ascii_symbols: String = decoded_symbols.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); + let ascii_symbols: String = decoded_symbols + .iter() + .filter_map(|&s| char::from_u32(s as u32)) + .collect(); let expected_decoded_ascii: String = String::from("Romeo and Juliet\nExcerpt from Act 2, Scene 2\n\nJULIET\nO ,! wherefore art thou?\nDeny thy fatherrefusename;\nOr, ifwilt not, be but sworn my l"); - assert_eq!(ascii_symbols, expected_decoded_ascii, "Expect correct decoding"); + assert_eq!( + ascii_symbols, expected_decoded_ascii, + "Expect correct decoding" + ); Ok(()) } @@ -1870,49 +2087,61 @@ mod tests { let encoded: [u8; 555] = [ // 0x28, 0xb5, 0x2f, 0xfd, // magic numbers are removed 0x60, // originally 0x64. unset the checksum bit. - 0xae, 0x02, 0x0d, 0x11, 0x00, 0x76, 0x62, 0x5e, 0x23, 0x30, 0x6f, - 0x9b, 0x03, 0x7d, 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, - 0xa9, 0xd4, 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, 0x29, - 0x01, 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, 0xf7, 0x59, 0xfc, - 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, 0x65, 0xc5, 0x45, 0x92, 0xe3, 0x0d, 0xf3, 0xef, 0x71, - 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, 0xa3, 0xbc, 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, - 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, - 0x02, 0xfc, 0x3c, 0xe3, 0x60, 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, - 0xe2, 0x20, 0xed, 0x17, 0x7b, 0x12, 0xdc, 0x24, 0x5a, 0xdf, 0xb4, 0x21, 0x9a, 0xcb, 0x8f, 0xc7, - 0x58, 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, 0x28, 0x0e, 0xfb, 0x8b, - 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, 0xeb, 0x81, 0xf1, 0x78, 0x4b, 0xad, - 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, 0xb4, 0xd9, 0xe1, 0x95, 0x21, 0x66, 0x0c, - 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, 0x22, 0x07, 0x0b, 0x91, 0x86, 0x94, 0x1a, 0x7b, - 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, 0x65, 0xd6, 0x34, 0x63, 0x0c, 0x88, 0x9b, 0x1c, 0x48, - 0xca, 0x2b, 0x34, 0xa9, 0x6b, 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, - 0x69, 0x18, 0x57, 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, - 0x7b, 0x6e, 0xd8, 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, 0x14, - 0xf4, 0x40, 0xe7, 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, 0x49, 0xae, 0x13, - 0xa4, 0x75, 0x38, 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, 0x86, 0xa4, 0xac, 0xaa, 0xa3, - 0x34, 0x89, 0xca, 0x2e, 0xe9, 0xc1, 0xfe, 0xf2, 0x51, 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, - 0xed, 0xd9, 0xb7, 0x4a, 0xb2, 0xb2, 0x61, 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, - 0xdc, 0x60, 0x6c, 0x41, 0x76, 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, - 0xac, 0x9d, 0xe0, 0x62, 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, - 0xd2, 0x7c, 0x0a, 0x7c, 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, 0xda, - 0x15, 0x91, 0xde, 0x21, 0xf5, 0x55, 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, 0x42, 0x44, 0x81, - 0x8c, 0x94, 0xb4, 0x50, 0x1e, 0x20, 0x42, 0x82, 0x98, 0xc2, 0x3b, 0x10, 0x48, 0xec, 0xa6, 0x39, - 0x63, 0x13, 0xa7, 0x01, 0x94, 0x40, 0xff, 0x88, 0x0f, 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, - 0xcb, 0xf6, 0xc8, 0x21, 0x59, 0xaa, 0x38, 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, - 0xc8, 0x03, 0x42, 0x2a, 0x4b, 0xf6, 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, - 0x7e, 0x00, 0xbc, 0x2f, 0x46, 0x96, 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, - 0x8c, 0xc2, 0x05, 0xf7, 0x54, 0x51, 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, 0x99, - 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, 0x50, 0x84, 0xf5, - 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, 0x4c, 0x52, 0x4f, 0x20, 0xa3, 0x61, 0x23, 0x77, 0x12, 0xd3, - 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, 0x70, 0xec, 0x14, 0x91, 0xf9, 0x85, 0x61, 0xd5, 0x7e, 0x98, - 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, + 0xae, 0x02, 0x0d, 0x11, 0x00, 0x76, 0x62, 0x5e, 0x23, 0x30, 0x6f, 0x9b, 0x03, 0x7d, + 0xc7, 0x16, 0x0b, 0xbe, 0xc8, 0xf2, 0xd0, 0x22, 0x4b, 0x6b, 0xbc, 0x54, 0x5d, 0xa9, + 0xd4, 0x93, 0xef, 0xc4, 0x54, 0x96, 0xb2, 0xe2, 0xa8, 0xa8, 0x24, 0x1c, 0x54, 0x40, + 0x29, 0x01, 0x55, 0x00, 0x57, 0x00, 0x51, 0x00, 0xcc, 0x51, 0x73, 0x3a, 0x85, 0x9e, + 0xf7, 0x59, 0xfc, 0xc5, 0xca, 0x6a, 0x7a, 0xd9, 0x82, 0x9c, 0x65, 0xc5, 0x45, 0x92, + 0xe3, 0x0d, 0xf3, 0xef, 0x71, 0xee, 0xdc, 0xd5, 0xa2, 0xe3, 0x48, 0xad, 0xa3, 0xbc, + 0x41, 0x7a, 0x3c, 0xaa, 0xd6, 0xeb, 0xd0, 0x77, 0xea, 0xdc, 0x5d, 0x41, 0x06, 0x50, + 0x1c, 0x49, 0x0f, 0x07, 0x10, 0x05, 0x88, 0x84, 0x94, 0x02, 0xfc, 0x3c, 0xe3, 0x60, + 0x25, 0xc0, 0xcb, 0x0c, 0xb8, 0xa9, 0x73, 0xbc, 0x13, 0x77, 0xc6, 0xe2, 0x20, 0xed, + 0x17, 0x7b, 0x12, 0xdc, 0x24, 0x5a, 0xdf, 0xb4, 0x21, 0x9a, 0xcb, 0x8f, 0xc7, 0x58, + 0x54, 0x11, 0xa9, 0xf1, 0x47, 0x82, 0x9b, 0xba, 0x60, 0xb4, 0x92, 0x28, 0x0e, 0xfb, + 0x8b, 0x1e, 0x92, 0x23, 0x6a, 0xcf, 0xbf, 0xe5, 0x45, 0xb5, 0x7e, 0xeb, 0x81, 0xf1, + 0x78, 0x4b, 0xad, 0x17, 0x4d, 0x81, 0x9f, 0xbc, 0x67, 0xa7, 0x56, 0xee, 0xb4, 0xd9, + 0xe1, 0x95, 0x21, 0x66, 0x0c, 0x95, 0x83, 0x27, 0xde, 0xac, 0x37, 0x20, 0x91, 0x22, + 0x07, 0x0b, 0x91, 0x86, 0x94, 0x1a, 0x7b, 0xf6, 0x4c, 0xb0, 0xc0, 0xe8, 0x2e, 0x49, + 0x65, 0xd6, 0x34, 0x63, 0x0c, 0x88, 0x9b, 0x1c, 0x48, 0xca, 0x2b, 0x34, 0xa9, 0x6b, + 0x99, 0x3b, 0xee, 0x13, 0x3b, 0x7c, 0x93, 0x0b, 0xf7, 0x0d, 0x49, 0x69, 0x18, 0x57, + 0xbe, 0x3b, 0x64, 0x45, 0x1d, 0x92, 0x63, 0x7f, 0xe8, 0xf9, 0xa1, 0x19, 0x7b, 0x7b, + 0x6e, 0xd8, 0xa3, 0x90, 0x23, 0x82, 0xf4, 0xa7, 0xce, 0xc8, 0xf8, 0x90, 0x15, 0xb3, + 0x14, 0xf4, 0x40, 0xe7, 0x02, 0x78, 0xd3, 0x17, 0x71, 0x23, 0xb1, 0x19, 0xad, 0x6b, + 0x49, 0xae, 0x13, 0xa4, 0x75, 0x38, 0x51, 0x47, 0x89, 0x67, 0xb0, 0x39, 0xb4, 0x53, + 0x86, 0xa4, 0xac, 0xaa, 0xa3, 0x34, 0x89, 0xca, 0x2e, 0xe9, 0xc1, 0xfe, 0xf2, 0x51, + 0xc6, 0x51, 0x73, 0xaa, 0xf7, 0x9d, 0x2d, 0xed, 0xd9, 0xb7, 0x4a, 0xb2, 0xb2, 0x61, + 0xe4, 0xef, 0x98, 0xf7, 0xc5, 0xef, 0x51, 0x9b, 0xd8, 0xdc, 0x60, 0x6c, 0x41, 0x76, + 0xaf, 0x78, 0x1a, 0x62, 0xb5, 0x4c, 0x1e, 0x21, 0x39, 0x9a, 0x5f, 0xac, 0x9d, 0xe0, + 0x62, 0xe8, 0xe9, 0x2f, 0x2f, 0x48, 0x02, 0x8d, 0x53, 0xc8, 0x91, 0xf2, 0x1a, 0xd2, + 0x7c, 0x0a, 0x7c, 0x48, 0xbf, 0xda, 0xa9, 0xe3, 0x38, 0xda, 0x34, 0xce, 0x76, 0xa9, + 0xda, 0x15, 0x91, 0xde, 0x21, 0xf5, 0x55, 0x46, 0xa8, 0x21, 0x9d, 0x51, 0xcc, 0x18, + 0x42, 0x44, 0x81, 0x8c, 0x94, 0xb4, 0x50, 0x1e, 0x20, 0x42, 0x82, 0x98, 0xc2, 0x3b, + 0x10, 0x48, 0xec, 0xa6, 0x39, 0x63, 0x13, 0xa7, 0x01, 0x94, 0x40, 0xff, 0x88, 0x0f, + 0x98, 0x07, 0x4a, 0x46, 0x38, 0x05, 0xa9, 0xcb, 0xf6, 0xc8, 0x21, 0x59, 0xaa, 0x38, + 0x45, 0xbf, 0x5c, 0xf8, 0x55, 0x9e, 0x9f, 0x04, 0xed, 0xc8, 0x03, 0x42, 0x2a, 0x4b, + 0xf6, 0x78, 0x7e, 0x23, 0x67, 0x15, 0xa2, 0x79, 0x29, 0xf4, 0x9b, 0x7e, 0x00, 0xbc, + 0x2f, 0x46, 0x96, 0x99, 0xea, 0xf1, 0xee, 0x1c, 0x6e, 0x06, 0x9c, 0xdb, 0xe4, 0x8c, + 0xc2, 0x05, 0xf7, 0x54, 0x51, 0x84, 0xc0, 0x33, 0x02, 0x01, 0xb1, 0x8c, 0x80, 0xdc, + 0x99, 0x8f, 0xcb, 0x46, 0xff, 0xd1, 0x25, 0xb5, 0xb6, 0x3a, 0xf3, 0x25, 0xbe, 0x85, + 0x50, 0x84, 0xf5, 0x86, 0x5a, 0x71, 0xf7, 0xbd, 0xa1, 0x4c, 0x52, 0x4f, 0x20, 0xa3, + 0x61, 0x23, 0x77, 0x12, 0xd3, 0xb1, 0x58, 0x75, 0x22, 0x01, 0x12, 0x70, 0xec, 0x14, + 0x91, 0xf9, 0x85, 0x61, 0xd5, 0x7e, 0x98, 0x84, 0xc9, 0x76, 0x84, 0xbc, 0xb8, 0xfe, + 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, ]; - let (_witness_rows, decoded_literals, _aux_data, fse_aux_tables, huffman_codes) = process::(&encoded, Value::known(Fr::from(123456789))); + let (_witness_rows, decoded_literals, _aux_data, fse_aux_tables, huffman_codes) = + process::(&encoded, Value::known(Fr::from(123456789))); - let decoded_literal_string: String = decoded_literals.iter().filter_map(|&s| char::from_u32(s as u32)).collect(); + let decoded_literal_string: String = decoded_literals + .iter() + .filter_map(|&s| char::from_u32(s as u32)) + .collect(); let expected_literal_string = String::from("Romeo and Juliet\nExcerpt from Act 2, Scene 2\n\nJULIET\nO ,! wherefore art thou?\nDeny thy fatherrefusename;\nOr, ifwilt not, be but sworn my love,\nAnd I'll no longera Capulet.\n\nROMEO\n[Aside] Shall I hear more, or sspeak at this?'Tis that isenemy;\nTyself,gh a Montague.\nWhat's? inor hand,foot,\nNor armaceany opart\nBeing to a man. Osome!in a?which we ca rose\nBy would smell as sweet;\nSo, were he'd,\nRetaindear perfectionhe owes\nWithoitle.dofffor oee\nTake mI t hy word:\nCebe new baptized;\nHencth I never will. manthus bescreen'dnightstumblest on my counsel?\n"); - assert_eq!(decoded_literal_string, expected_literal_string, "Decode the correct literal string"); + assert_eq!( + decoded_literal_string, expected_literal_string, + "Decode the correct literal string" + ); Ok(()) } diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 06600ad366..0d8636ceae 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -1,6 +1,6 @@ use std::{ - collections::{BTreeMap, HashMap}, - io::Cursor + collections::{BTreeMap, HashMap}, + io::Cursor, }; use bitstream_io::{BitRead, BitReader, LittleEndian}; @@ -412,11 +412,11 @@ pub struct HuffmanCodesData { /// Denotes the tuple (max_bitstring_len, Map). type ParsedCanonicalHuffmanCode = (u64, BTreeMap); -/// A representation indexed by bitstring (String) as key for decoding symbols specifically. -/// Huffman code decoding ensures prefix code, thus the explicit articulation of bitstring is necessary. +/// A representation indexed by bitstring (String) as key for decoding symbols specifically. +/// Huffman code decoding ensures prefix code, thus the explicit articulation of bitstring is +/// necessary. type ParsedCanonicalHuffmanCodeBitstringMap = (u64, HashMap); - impl HuffmanCodesData { /// Reconstruct the bitstrings for each symbol based on the canonical Huffman code weights. The /// returned value is tuple of max bitstring length and a map from symbol to its weight and bit @@ -475,32 +475,51 @@ impl HuffmanCodesData { /// parse bit string map pub fn parse_bitstring_map(&self) -> ParsedCanonicalHuffmanCodeBitstringMap { let mut weights: Vec = self.weights.iter().map(|w| w.clone() as usize).collect(); - let sum_weights: usize = weights.iter().filter_map(|&w| if w > 0 { Some(1 << (w - 1)) } else { None }).sum(); + let sum_weights: usize = weights + .iter() + .filter_map(|&w| if w > 0 { Some(1 << (w - 1)) } else { None }) + .sum(); let nearest_pow_2: usize = 1 << (sum_weights - 1).next_power_of_two().trailing_zeros(); weights.push(f64::log2((nearest_pow_2 - sum_weights) as f64).ceil() as usize + 1); let max_number_of_bits = nearest_pow_2.trailing_zeros() as usize; let n = weights.len(); - let bitstring_length: Vec = weights.iter().map(|&w| if w != 0 { max_number_of_bits - w + 1} else { 0 }).collect(); - + let bitstring_length: Vec = weights + .iter() + .map(|&w| { + if w != 0 { + max_number_of_bits - w + 1 + } else { + 0 + } + }) + .collect(); + let mut bitstring_map = HashMap::new(); let mut cur_bit_value = 0; - + for bit_len in (1..=max_number_of_bits).rev() { cur_bit_value += 1; cur_bit_value >>= 1; - + for sym in 0..n { if bitstring_length[sym] == bit_len { - bitstring_map.insert(format!("{:0width$b}", cur_bit_value, width = bit_len), sym as u64); + bitstring_map.insert( + format!("{:0width$b}", cur_bit_value, width = bit_len), + sym as u64, + ); cur_bit_value += 1; } } } - let max_bitstring_len = bitstring_map.keys().map(|k| k.len()).max().expect("Keys have maximum len"); - + let max_bitstring_len = bitstring_map + .keys() + .map(|k| k.len()) + .max() + .expect("Keys have maximum len"); + (max_bitstring_len as u64, bitstring_map) } } @@ -563,7 +582,7 @@ pub struct FseAuxiliaryTableData { } /// Another form of Fse table that has state as key instead of the FseSymbol. -/// In decoding, symbols are emitted from state-chaining. +/// In decoding, symbols are emitted from state-chaining. /// This representation makes it easy to look up decoded symbol from current state. /// Map. type FseStateMapping = BTreeMap; @@ -577,7 +596,10 @@ impl FseAuxiliaryTableData { /// with the reconstructed FSE table. After processing the entire bitstream to reconstruct the /// FSE table, if the read bitstream was not byte aligned, then we discard the 1..8 bits from /// the last byte that we read from. - pub fn reconstruct(src: &[u8], byte_offset: usize) -> std::io::Result<(usize, Vec<(u32, u64)>, Self)> { + pub fn reconstruct( + src: &[u8], + byte_offset: usize, + ) -> std::io::Result<(usize, Vec<(u32, u64)>, Self)> { // construct little-endian bit-reader. let data = src.iter().skip(byte_offset).cloned().collect::>(); let mut reader = BitReader::endian(Cursor::new(&data), LittleEndian); @@ -669,7 +691,10 @@ impl FseAuxiliaryTableData { // read the trailing section if t * N_BITS_PER_BYTE > (offset as usize) { let bits_remaining = t * N_BITS_PER_BYTE - offset as usize; - bit_boundaries.push((offset + bits_remaining as u32, reader.read::(bits_remaining as u32)? as u64)); + bit_boundaries.push(( + offset + bits_remaining as u32, + reader.read::(bits_remaining as u32)? as u64, + )); } Ok(( @@ -686,7 +711,11 @@ impl FseAuxiliaryTableData { /// Convert an FseAuxiliaryTableData into a state-mapped representation. /// This makes it easier to lookup state-chaining during decoding. pub fn parse_state_table(&self) -> FseStateMapping { - let rows: Vec = self.sym_to_states.values().flat_map(|v| v.clone()).collect(); + let rows: Vec = self + .sym_to_states + .values() + .flat_map(|v| v.clone()) + .collect(); let mut state_table: FseStateMapping = BTreeMap::new(); for row in rows { @@ -731,8 +760,6 @@ impl ZstdWitnessRow { } } - - #[cfg(test)] mod tests { use super::*; @@ -782,17 +809,14 @@ mod tests { #[test] fn test_huffman_bitstring_reconstruction() -> std::io::Result<()> { let weights = vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 6, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 2, 0, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, - 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, 1, 1, 1, 2, - 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, - 0, 5, 3, 3, 3, 6, 3, 2, 4, 4, 0, 1, 4, 4, 5, 5, - 2, 0, 4, 4, 5, 3, 1, 3, 1, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 0, 0, 2, 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, 1, 1, 1, 2, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 5, 3, 3, 3, 6, 3, 2, 4, 4, 0, 1, 4, 4, 5, 5, 2, 0, 4, 4, + 5, 3, 1, 3, 1, 3, ] .into_iter() - .map(|w| FseSymbol::from(w) ) + .map(|w| FseSymbol::from(w)) .collect::>(); let huffman_codes_data = HuffmanCodesData { @@ -803,23 +827,73 @@ mod tests { let (max_bitstring_len, bitstring_map) = huffman_codes_data.parse_bitstring_map(); let expected_bitstrings: [(&str, u64); 53] = [ - ("01001", 10), ("110", 32), ("00000000", 33), ("0001100", 39), ("001010", 44), - ("0001101", 46), ("00000001", 50), ("00000010", 58), ("0001110", 59), ("0001111", 63), - ("00000011", 65), ("00000100", 66), ("00000101", 67), ("00000110", 68), ("00000111", 69), - ("00001000", 72), ("0010000", 73), ("00001001", 74), ("00001010", 76), ("00001011", 77), - ("00001100", 78), ("0010001", 79), ("00001101", 82), ("00001110", 83), ("00001111", 84), - ("00010000", 85), ("00010001", 87), ("00010010", 91), ("00010011", 93), ("1000", 97), - ("001011", 98), ("001100", 99), ("001101", 100), ("111", 101), ("001110", 102), - ("0010010", 103), ("01010", 104), ("01011", 105), ("00010100", 107), ("01100", 108), - ("01101", 109), ("1001", 110), ("1010", 111), ("0010011", 112), ("01110", 114), - ("01111", 115), ("1011", 116), ("001111", 117), ("00010101", 118), ("010000", 119), - ("00010110", 120), ("010001", 121), ("00010111", 122), + ("01001", 10), + ("110", 32), + ("00000000", 33), + ("0001100", 39), + ("001010", 44), + ("0001101", 46), + ("00000001", 50), + ("00000010", 58), + ("0001110", 59), + ("0001111", 63), + ("00000011", 65), + ("00000100", 66), + ("00000101", 67), + ("00000110", 68), + ("00000111", 69), + ("00001000", 72), + ("0010000", 73), + ("00001001", 74), + ("00001010", 76), + ("00001011", 77), + ("00001100", 78), + ("0010001", 79), + ("00001101", 82), + ("00001110", 83), + ("00001111", 84), + ("00010000", 85), + ("00010001", 87), + ("00010010", 91), + ("00010011", 93), + ("1000", 97), + ("001011", 98), + ("001100", 99), + ("001101", 100), + ("111", 101), + ("001110", 102), + ("0010010", 103), + ("01010", 104), + ("01011", 105), + ("00010100", 107), + ("01100", 108), + ("01101", 109), + ("1001", 110), + ("1010", 111), + ("0010011", 112), + ("01110", 114), + ("01111", 115), + ("1011", 116), + ("001111", 117), + ("00010101", 118), + ("010000", 119), + ("00010110", 120), + ("010001", 121), + ("00010111", 122), ]; assert_eq!(max_bitstring_len, 8, "max bitstring len is 8"); - assert_eq!(expected_bitstrings.len(), bitstring_map.len(), "# of bitstring is the same"); + assert_eq!( + expected_bitstrings.len(), + bitstring_map.len(), + "# of bitstring is the same" + ); for pair in expected_bitstrings { - assert_eq!(*bitstring_map.get(pair.0).unwrap(), pair.1, "bitstring mapping is correct"); + assert_eq!( + *bitstring_map.get(pair.0).unwrap(), + pair.1, + "bitstring mapping is correct" + ); } Ok(()) From 3fce5325bb1b445bfa1a72256b9d2981525207c9 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Wed, 14 Feb 2024 10:42:16 +0000 Subject: [PATCH 158/165] fmt again --- zkevm-circuits/src/decompression_circuit.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 1976a53198..8395724bdc 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -3114,7 +3114,8 @@ impl DecompressionCircuitConfig { )?; } - // TODO: Should assign sequence section. Dummy row for sequencing section header as of now + // TODO: Should assign sequence section. Dummy row for sequencing section header as + // of now region.assign_advice( || "byte_idx", self.byte_idx, From d506022242ec0429e68a178d658096a18243dc6a Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Wed, 14 Feb 2024 12:42:59 +0000 Subject: [PATCH 159/165] literals header lookup fix --- zkevm-circuits/src/decompression_circuit.rs | 596 ++++++++++-------- .../src/decompression_circuit/dev.rs | 13 +- .../src/decompression_circuit/test.rs | 2 +- zkevm-circuits/src/table/decompression.rs | 9 +- zkevm-circuits/src/witness/zstd/mod.rs | 6 +- 5 files changed, 336 insertions(+), 290 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 8395724bdc..1f666ede27 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -15,7 +15,7 @@ use crate::{ BitstringAccumulationTable, BlockTypeRomTable, FseTable, HuffmanCodesTable, LiteralsHeaderRomTable, LiteralsHeaderTable, TagRomTable, }, - KeccakTable, LookupTable, Pow2Table, PowOfRandTable, RangeTable, U8Table, + BitwiseOpTable, KeccakTable, LookupTable, Pow2Table, PowOfRandTable, RangeTable, U8Table, }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::{ @@ -53,8 +53,16 @@ pub struct DecompressionCircuitConfigArgs { pub bs_acc_table: BitstringAccumulationTable, /// Lookup table to get regenerated and compressed size from LiteralsHeader. pub literals_header_table: LiteralsHeaderTable, + /// Bitwise OP table. + pub bitwise_op_table: BitwiseOpTable, + /// RangeTable for [0, 4). + pub range4: RangeTable<4>, /// RangeTable for [0, 8). pub range8: RangeTable<8>, + /// RangeTable for [0, 16). + pub range16: RangeTable<16>, + /// RangeTable for [0, 64). + pub range64: RangeTable<64>, /// RangeTable for [0; 128). pub range128: RangeTable<128>, /// U8 table, i.e. RangeTable for [0, 1 << 8). @@ -121,7 +129,11 @@ pub struct DecompressionCircuitConfig { lstream_config: LstreamConfig, /// Internal Tables + bitwise_op_table: BitwiseOpTable, + range4: RangeTable<4>, range8: RangeTable<8>, + range16: RangeTable<16>, + range64: RangeTable<64>, range128: RangeTable<128>, range256: RangeTable<256>, tag_rom_table: TagRomTable, @@ -372,7 +384,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { huffman_codes_table, bs_acc_table, literals_header_table, + bitwise_op_table, + range4, range8, + range16, + range64, range128, range256, pow2_table, @@ -1151,190 +1167,201 @@ impl SubCircuitConfig for DecompressionCircuitConfig { // TODO: Block constraints will be examined later // Note: We only verify the 1st row of BlockHeader for tag_value. - // meta.create_gate("DecompressionCircuit: BlockHeader", |meta| { - // let mut cb = BaseConstraintBuilder::default(); - // cb.require_equal( - // "tag_len == 3", - // meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - // N_BLOCK_HEADER_BYTES.expr(), - // ); - // // The lowest bit (as per little-endian representation) is whether the block is the - // // last block in the frame or not. - // // - // // The next 2 bits denote the block type. - // // - // // But block header is expressed in the reverse order, which helps us in calculating - // // the tag_value appropriately. - // cb.require_equal( - // "last block check", - // meta.query_advice(value_bits[7], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), - // meta.query_advice( - // block_gadget.is_last_block, - // Rotation(N_BLOCK_HEADER_BYTES as i32), - // ), - // ); - // let block_type_bit0 = - // meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); - // let block_type_bit1 = - // meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); - // cb.require_zero( - // "block type cannot be RESERVED, i.e. block_type == 3 not possible", - // block_type_bit0.expr() * block_type_bit1.expr(), - // ); - // cb.require_equal( - // "block_idx == 1", - // meta.query_advice(block_gadget.idx, Rotation(N_BLOCK_HEADER_BYTES as i32)), - // 1.expr(), - // ); - // // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear - // with // block type 00 or 01, i.e. the block_type_bit1 is 0. - // cb.condition(not::expr(block_type_bit1), |cb| { - // cb.require_equal( - // "Raw/RLE blocks: tag_len == block_len", - // meta.query_advice(tag_gadget.tag_len, Rotation(N_BLOCK_HEADER_BYTES as i32)), - // meta.query_advice( - // block_gadget.block_len, - // Rotation(N_BLOCK_HEADER_BYTES as i32), - // ), - // ); - // }); - // // Validate that for an RLE block: value_byte == decoded_byte. - // cb.condition(block_type_bit0, |cb| { - // cb.require_equal( - // "for RLE block, value_byte == decoded_byte", - // meta.query_advice(value_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), - // meta.query_advice(decoded_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), - // ); - // }); - // // If this wasn't the first block, then the previous block's last byte should have - // // block's idx == block length. - // // - // // This block is the first block iff the FrameContentSize tag precedes it. However we - // // assume that the block_idx and block_len will be set to 0 for FrameContentSize as - // it // is not part of a "block". - // cb.require_equal( - // "block_idx::prev == block_len::prev", - // meta.query_advice(block_gadget.idx, Rotation::prev()), - // meta.query_advice(block_gadget.block_len, Rotation::prev()), - // ); - // cb.gate(and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), - // ])) - // }); - - // meta.create_gate("DecompressionCircuit: while processing a block", |meta| { - // let mut cb = BaseConstraintBuilder::default(); - // // If byte_idx increments, then block_gadet.idx should also increment. - // cb.require_equal( - // "idx in block increments if byte_idx increments", - // meta.query_advice(block_gadget.idx, Rotation::next()) - // - meta.query_advice(block_gadget.idx, Rotation::cur()), - // meta.query_advice(byte_idx, Rotation::next()) - // - meta.query_advice(byte_idx, Rotation::cur()), - // ); - // cb.require_equal( - // "block_len remains unchanged", - // meta.query_advice(block_gadget.block_len, Rotation::next()), - // meta.query_advice(block_gadget.block_len, Rotation::cur()), - // ); - // cb.require_equal( - // "is_last_block remains unchanged", - // meta.query_advice(block_gadget.is_last_block, Rotation::next()), - // meta.query_advice(block_gadget.is_last_block, Rotation::cur()), - // ); - // cb.gate(and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(block_gadget.is_block, Rotation::cur()), - // meta.query_advice(block_gadget.is_block, Rotation::next()), - // ])) - // }); - - // meta.create_gate("DecompressionCircuit: handle end of other blocks", |meta| { - // let mut cb = BaseConstraintBuilder::default(); - // cb.require_equal( - // "tag_next depending on whether or not this is the last block", - // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - // ZstdTag::BlockHeader.expr(), - // ); - // cb.require_equal( - // "block_idx == block_len", - // meta.query_advice(block_gadget.idx, Rotation::cur()), - // meta.query_advice(block_gadget.block_len, Rotation::cur()), - // ); - // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); - // cb.gate(and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // not::expr(meta.query_advice(is_padding, Rotation::cur())), - // idx_eq_len, - // not::expr(meta.query_advice(block_gadget.is_last_block, Rotation::cur())), - // ])) - // }); - - // meta.create_gate("DecompressionCircuit: handle end of last block", |meta| { - // let mut cb = BaseConstraintBuilder::default(); - // cb.require_equal( - // "tag_next depending on whether or not this is the last block", - // meta.query_advice(tag_gadget.tag_next, Rotation::cur()), - // ZstdTag::Null.expr(), - // ); - // cb.require_equal( - // "decoded_len has been reached if last block", - // meta.query_advice(decoded_len_acc, Rotation::cur()), - // meta.query_advice(decoded_len, Rotation::cur()), - // ); - // cb.require_equal( - // "byte idx has reached the encoded len", - // meta.query_advice(byte_idx, Rotation::cur()), - // meta.query_advice(encoded_len, Rotation::cur()), - // ); - // cb.require_equal( - // "block can end only on Raw/Rle/TODO tag", - // sum::expr([ - // is_raw_block(meta), - // is_rle_block(meta), - // // TODO: there will be other tags where a block ends - // ]), - // 1.expr(), - // ); - // cb.require_equal( - // "block_idx == block_len", - // meta.query_advice(block_gadget.idx, Rotation::cur()), - // meta.query_advice(block_gadget.block_len, Rotation::cur()), - // ); - // let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); - // cb.gate(and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // not::expr(meta.query_advice(is_padding, Rotation::cur())), - // meta.query_advice(block_gadget.is_last_block, Rotation::cur()), - // idx_eq_len, - // ])) - // }); - - // meta.lookup( - // "DecompressionCircuit: BlockHeader (BlockSize == BlockHeader >> 3)", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), - // ]); - // let range_value = meta.query_advice(tag_gadget.tag_value, Rotation::cur()) - // - (meta.query_advice( block_gadget.block_len, Rotation(N_BLOCK_HEADER_BYTES - // as i32), - // ) * 8.expr()); - // vec![(condition * range_value, range8.into())] - // }, - // ); + /* + meta.create_gate("DecompressionCircuit: BlockHeader", |meta| { + let mut cb = BaseConstraintBuilder::default(); + cb.require_equal( + "tag_len == 3", + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + N_BLOCK_HEADER_BYTES.expr(), + ); + // The lowest bit (as per little-endian representation) is whether the block is the + // last block in the frame or not. + // + // The next 2 bits denote the block type. + // + // But block header is expressed in the reverse order, which helps us in calculating + // the tag_value appropriately. + cb.require_equal( + "last block check", + meta.query_advice(value_bits[7], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)), + meta.query_advice( + block_gadget.is_last_block, + Rotation(N_BLOCK_HEADER_BYTES as i32), + ), + ); + let block_type_bit0 = + meta.query_advice(value_bits[6], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); + let block_type_bit1 = + meta.query_advice(value_bits[5], Rotation(N_BLOCK_HEADER_BYTES as i32 - 1)); + cb.require_zero( + "block type cannot be RESERVED, i.e. block_type == 3 not possible", + block_type_bit0.expr() * block_type_bit1.expr(), + ); + cb.require_equal( + "block_idx == 1", + meta.query_advice(block_gadget.idx, Rotation(N_BLOCK_HEADER_BYTES as i32)), + 1.expr(), + ); + // For Raw/RLE blocks, the block_len is equal to the tag_len. These blocks appear + // with block type 00 or 01, i.e. the block_type_bit1 is 0. + cb.condition(not::expr(block_type_bit1), |cb| { + cb.require_equal( + "Raw/RLE blocks: tag_len == block_len", + meta.query_advice(tag_gadget.tag_len, Rotation(N_BLOCK_HEADER_BYTES as i32)), + meta.query_advice( + block_gadget.block_len, + Rotation(N_BLOCK_HEADER_BYTES as i32), + ), + ); + }); + // Validate that for an RLE block: value_byte == decoded_byte. + cb.condition(block_type_bit0, |cb| { + cb.require_equal( + "for RLE block, value_byte == decoded_byte", + meta.query_advice(value_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), + meta.query_advice(decoded_byte, Rotation(N_BLOCK_HEADER_BYTES as i32)), + ); + }); + // If this wasn't the first block, then the previous block's last byte should have + // block's idx == block length. + // + // This block is the first block iff the FrameContentSize tag precedes it. However we + // assume that the block_idx and block_len will be set to 0 for FrameContentSize as + // it is not part of a "block". + cb.require_equal( + "block_idx::prev == block_len::prev", + meta.query_advice(block_gadget.idx, Rotation::prev()), + meta.query_advice(block_gadget.block_len, Rotation::prev()), + ); + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + ])) + }); + */ + + /* + meta.create_gate("DecompressionCircuit: while processing a block", |meta| { + let mut cb = BaseConstraintBuilder::default(); + // If byte_idx increments, then block_gadet.idx should also increment. + cb.require_equal( + "idx in block increments if byte_idx increments", + meta.query_advice(block_gadget.idx, Rotation::next()) + - meta.query_advice(block_gadget.idx, Rotation::cur()), + meta.query_advice(byte_idx, Rotation::next()) + - meta.query_advice(byte_idx, Rotation::cur()), + ); + cb.require_equal( + "block_len remains unchanged", + meta.query_advice(block_gadget.block_len, Rotation::next()), + meta.query_advice(block_gadget.block_len, Rotation::cur()), + ); + cb.require_equal( + "is_last_block remains unchanged", + meta.query_advice(block_gadget.is_last_block, Rotation::next()), + meta.query_advice(block_gadget.is_last_block, Rotation::cur()), + ); + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(block_gadget.is_block, Rotation::cur()), + meta.query_advice(block_gadget.is_block, Rotation::next()), + ])) + }); + */ + + /* + meta.create_gate("DecompressionCircuit: handle end of other blocks", |meta| { + let mut cb = BaseConstraintBuilder::default(); + cb.require_equal( + "tag_next depending on whether or not this is the last block", + meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + ZstdTag::BlockHeader.expr(), + ); + cb.require_equal( + "block_idx == block_len", + meta.query_advice(block_gadget.idx, Rotation::cur()), + meta.query_advice(block_gadget.block_len, Rotation::cur()), + ); + let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + not::expr(meta.query_advice(is_padding, Rotation::cur())), + idx_eq_len, + not::expr(meta.query_advice(block_gadget.is_last_block, Rotation::cur())), + ])) + }); + */ + + /* + meta.create_gate("DecompressionCircuit: handle end of last block", |meta| { + let mut cb = BaseConstraintBuilder::default(); + cb.require_equal( + "tag_next depending on whether or not this is the last block", + meta.query_advice(tag_gadget.tag_next, Rotation::cur()), + ZstdTag::Null.expr(), + ); + cb.require_equal( + "decoded_len has been reached if last block", + meta.query_advice(decoded_len_acc, Rotation::cur()), + meta.query_advice(decoded_len, Rotation::cur()), + ); + cb.require_equal( + "byte idx has reached the encoded len", + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(encoded_len, Rotation::cur()), + ); + cb.require_equal( + "block can end only on Raw/Rle/TODO tag", + sum::expr([ + is_raw_block(meta), + is_rle_block(meta), + // TODO: there will be other tags where a block ends + ]), + 1.expr(), + ); + cb.require_equal( + "block_idx == block_len", + meta.query_advice(block_gadget.idx, Rotation::cur()), + meta.query_advice(block_gadget.block_len, Rotation::cur()), + ); + let (_, idx_eq_len) = block_gadget.idx_cmp_len.expr(meta, None); + cb.gate(and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + not::expr(meta.query_advice(is_padding, Rotation::cur())), + meta.query_advice(block_gadget.is_last_block, Rotation::cur()), + idx_eq_len, + ])) + }); + */ + + /* + meta.lookup( + "DecompressionCircuit: BlockHeader (BlockSize == BlockHeader >> 3)", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + ]); + let range_value = meta.query_advice(tag_gadget.tag_value, Rotation::cur()) + - (meta.query_advice( + block_gadget.block_len, + Rotation(N_BLOCK_HEADER_BYTES as i32), + ) * 8.expr()); + vec![(condition * range_value, range8.into())] + }, + ); + */ meta.lookup_any( "DecompressionCircuit: lookup for tuple (block_type, tag_next)", |meta| { let condition = and::expr([ meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), meta.query_advice(tag_gadget.is_block_header, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), ]); [ meta.query_advice(tag_gadget.tag, Rotation::cur()), @@ -1415,8 +1442,8 @@ impl SubCircuitConfig for DecompressionCircuitConfig { |meta| { let mut cb = BaseConstraintBuilder::default(); - let block_type_bit0 = meta.query_advice(value_bits[7], Rotation::cur()); - let block_type_bit1 = meta.query_advice(value_bits[6], Rotation::cur()); + let block_type_bit0 = meta.query_advice(value_bits[0], Rotation::cur()); + let block_type_bit1 = meta.query_advice(value_bits[1], Rotation::cur()); cb.require_zero( "block type cannot be TREELESS, i.e. block_type == 3 not possible", block_type_bit0 * block_type_bit1, @@ -1435,13 +1462,13 @@ impl SubCircuitConfig for DecompressionCircuitConfig { |meta| { let condition = and::expr([ meta.query_fixed(q_enable, Rotation::cur()), - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), ]); [ meta.query_advice(tag_gadget.tag, Rotation::cur()), - meta.query_advice(value_bits[6], Rotation::cur()), - meta.query_advice(value_bits[7], Rotation::cur()), + meta.query_advice(value_bits[1], Rotation::cur()), + meta.query_advice(value_bits[0], Rotation::cur()), meta.query_advice(tag_gadget.tag_next, Rotation::cur()), ] .into_iter() @@ -1476,79 +1503,87 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); - // TODO: LiteralHeader regen/compr size - // meta.lookup_any( - // "DecompressionCircuit: lookup for LiteralsHeader regen/compr size", - // |meta| { - // let condition = and::expr([ - // meta.query_fixed(q_enable, Rotation::cur()), - // meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - // meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), - // ]); - - // // Which branch are we taking in the literals header decomposition. - // let branch = meta.query_advice(literals_header.branch, Rotation::cur()); - - // // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we - // // already know that block type == 0b11 (TREELESS) will not occur, we can skip - // the // check for not::expr(value_bits[7]). - // let is_compressed = meta.query_advice(value_bits[6], Rotation::cur()); - - // // Is the size format == 0b11. - // let is_size_format_0b11 = - // meta.query_advice(literals_header.sf_max, Rotation::cur()); - - // let byte0 = meta.query_advice(value_byte, Rotation::cur()); - // let byte1 = select::expr( - // is_compressed.expr(), - // meta.query_advice(value_byte, Rotation(1)), - // select::expr( - // meta.query_advice(value_bits[5], Rotation::cur()), - // meta.query_advice(value_byte, Rotation(1)), - // 0.expr(), - // ), - // ); - // let byte2 = select::expr( - // is_compressed.expr(), - // meta.query_advice(value_byte, Rotation(2)), - // select::expr( - // meta.query_advice(value_bits[5], Rotation::cur()), - // meta.query_advice(value_byte, Rotation(2)), - // 0.expr(), - // ), - // ); - // let byte3 = select::expr( - // is_compressed.expr(), - // select::expr( - // meta.query_advice(value_bits[5], Rotation::cur()), - // meta.query_advice(value_byte, Rotation(3)), - // 0.expr(), - // ), - // 0.expr(), - // ); - // let byte4 = select::expr( - // is_compressed * is_size_format_0b11, - // meta.query_advice(value_byte, Rotation(4)), - // 0.expr(), - // ); - - // [ - // meta.query_advice(byte_idx, Rotation::cur()), // byte offset - // branch, // branch - // byte0, // byte0 - // byte1, // byte1 - // byte2, // byte2 - // byte3, // byte3 - // byte4, // byte4 - // meta.query_advice(literals_header.regen_size, Rotation::cur()), // - // regenerated size meta.query_advice(literals_header.compr_size, - // Rotation::cur()), // compressed size ] - // .into_iter() - // .zip(literals_header_table.table_exprs(meta)) - // .map(|(arg, table)| (condition.expr() * arg, table)) - // .collect() - // }, - // ); + meta.lookup_any( + "DecompressionCircuit: lookup for LiteralsHeader regen/compr size", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_literals_header, Rotation::cur()), + meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), + ]); + + // Which branch are we taking in the literals header decomposition. + let branch = meta.query_advice(literals_header.branch, Rotation::cur()); + + // Is it the case of zstd compressed block, i.e. block type == 0b10. Since we + // already know that block type == 0b11 (TREELESS) will not occur, we can skip + // the check for not::expr(value_bits[0]). + let is_compressed = meta.query_advice(value_bits[1], Rotation::cur()); + + // Is the size format == 0b11. + let is_size_format_0b11 = + meta.query_advice(literals_header.sf_max, Rotation::cur()); + let size_format_bit0 = meta.query_advice(value_bits[2], Rotation::cur()); + let size_format_bit1 = meta.query_advice(value_bits[3], Rotation::cur()); + + // Literals header is at least 1 byte for all branches. + let byte0 = meta.query_advice(value_byte, Rotation::cur()); + // Literals header is at least 2 bytes for: + // - zstd compressed block + // - size format 01 / 11 for Raw/RLE block + let byte1 = select::expr( + is_compressed.expr(), + meta.query_advice(value_byte, Rotation(1)), + select::expr( + size_format_bit0.expr(), + meta.query_advice(value_byte, Rotation(1)), + 0.expr(), + ), + ); + // Literals header is at least 3 bytes for: + // - zstd compressed block + // - size format 11 for Raw/RLE block + let byte2 = select::expr( + is_compressed.expr(), + meta.query_advice(value_byte, Rotation(2)), + select::expr( + is_size_format_0b11.expr(), + meta.query_advice(value_byte, Rotation(2)), + 0.expr(), + ), + ); + // Literals header is at least 4 bytes for: + // - zstd compressed block with size format 10 / 11 + let byte3 = select::expr( + is_compressed.expr() * size_format_bit1.expr(), + meta.query_advice(value_byte, Rotation(3)), + 0.expr(), + ); + // Literals header is 5 bytes for: + // - zstd compressed block with size format 11 + let byte4 = select::expr( + is_compressed * is_size_format_0b11, + meta.query_advice(value_byte, Rotation(4)), + 0.expr(), + ); + + [ + meta.query_advice(byte_idx, Rotation::cur()), // byte offset + branch, // branch + byte0, // byte0 + byte1, // byte1 + byte2, // byte2 + byte3, // byte3 + byte4, // byte4 + meta.query_advice(literals_header.regen_size, Rotation::cur()), + meta.query_advice(literals_header.compr_size, Rotation::cur()), + ] + .into_iter() + .zip(literals_header_table.table_exprs(meta)) + .map(|(arg, table)| (condition.expr() * arg, table)) + .collect() + }, + ); meta.create_gate("DecompressionCircuit: LiteralsSection", |meta| { let mut cb = BaseConstraintBuilder::default(); @@ -2555,7 +2590,11 @@ impl SubCircuitConfig for DecompressionCircuitConfig { bitstream_decoder, fse_decoder, lstream_config, + bitwise_op_table, + range4, range8, + range16, + range64, range128, range256, tag_rom_table, @@ -2590,29 +2629,28 @@ impl DecompressionCircuitConfig { self.fse_table.assign(layouter, fse_aux_tables)?; self.huffman_codes_table.assign(layouter, huffman_codes)?; - // TODO: Assining into literals_header_table causes failed table constraints - // let literal_header_offset = witness_rows - // .iter() - // .find(|r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader) - // .unwrap() - // .encoded_data - // .byte_idx; - // let literal_bytes = witness_rows - // .iter() - // .filter(|&r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader) - // .map(|r| r.encoded_data.value_byte) - // .collect::>(); - - // self.literals_header_table.assign( - // layouter, - // &[( - // literal_header_offset, - // literal_bytes.as_slice(), - // aux_data[10], - // aux_data[4], - // aux_data[5], - // )], - // )?; + let literal_header_offset = witness_rows + .iter() + .find(|r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader) + .unwrap() + .encoded_data + .byte_idx; + let literal_bytes = witness_rows + .iter() + .filter(|&r| r.state.tag == ZstdTag::ZstdBlockLiteralsHeader) + .map(|r| r.encoded_data.value_byte) + .collect::>(); + + self.literals_header_table.assign( + layouter, + &[( + literal_header_offset, + literal_bytes.as_slice(), + aux_data[10], + aux_data[4], + aux_data[5], + )], + )?; layouter.assign_region( || "Decompression table region", diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index d6816e3695..7950657486 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -12,7 +12,7 @@ use crate::{ decompression::{ BitstringAccumulationTable, FseTable, HuffmanCodesTable, LiteralsHeaderTable, }, - BitwiseOpTable, KeccakTable, Pow2Table, PowOfRandTable, RangeTable, U8Table, + BitwiseOpTable, KeccakTable, Pow2Table, PowOfRandTable, RangeTable, }, util::{Challenges, SubCircuit, SubCircuitConfig}, }; @@ -61,7 +61,11 @@ impl Circuit for DecompressionCircuit { huffman_codes_table, bs_acc_table, literals_header_table, + bitwise_op_table, + range4, range8, + range16, + range64, range128, range256, pow2_table, @@ -79,7 +83,12 @@ impl Circuit for DecompressionCircuit { mut layouter: impl Layouter, ) -> Result<(), Error> { let challenges = &config.1.values(&layouter); + + config.0.bitwise_op_table.load(&mut layouter)?; + config.0.range4.load(&mut layouter)?; config.0.range8.load(&mut layouter)?; + config.0.range16.load(&mut layouter)?; + config.0.range64.load(&mut layouter)?; config.0.range128.load(&mut layouter)?; config.0.range256.load(&mut layouter)?; config.0.tag_rom_table.load(&mut layouter)?; @@ -87,7 +96,7 @@ impl Circuit for DecompressionCircuit { config.0.block_type_rom_table.load(&mut layouter)?; config.0.pow2_table.load(&mut layouter)?; config.0.literals_header_rom_table.load(&mut layouter)?; - // config.0.literals_header_table.dev_load(layouter, literals_headers)?; + self.synthesize_sub(&config.0, challenges, &mut layouter) } } diff --git a/zkevm-circuits/src/decompression_circuit/test.rs b/zkevm-circuits/src/decompression_circuit/test.rs index 60fdb52a51..fc4205d618 100644 --- a/zkevm-circuits/src/decompression_circuit/test.rs +++ b/zkevm-circuits/src/decompression_circuit/test.rs @@ -72,7 +72,7 @@ fn test_work_example_decompression() { _data: Default::default(), }; - let mock_prover = MockProver::run(16, &decompression_circuit, vec![]); + let mock_prover = MockProver::run(18, &decompression_circuit, vec![]); let mock_prover = mock_prover.unwrap(); if let Err(errors) = mock_prover.verify_par() { diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index b492fe198f..5761c27451 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -2278,8 +2278,7 @@ pub struct LiteralsHeaderRomTable { /// - block_type == Raw/RLE and size_format == 00 or 10 /// - block_type == Raw/RLE and size_format == 01 /// - block_type == Raw/RLE and size_format == 11 - /// - block_type == Compressed and size_format == 00 - /// - block_type == Compressed and size_format == 01 + /// - block_type == Compressed and size_format == 00 or 01 /// - block_type == Compressed and size_format == 10 /// - block_type == Compressed and size_format == 11 branch: Column, @@ -2346,9 +2345,9 @@ impl LiteralsHeaderRomTable { [1, 0, 1, 0, 2, 0, 1, 0], // RLE: 2 bytes header [1, 0, 1, 1, 3, 0, 2, 1], // RLE: 3 bytes header [0, 1, 0, 0, 3, 0, 3, 0], // Compressed: 3 bytes header - [0, 1, 1, 0, 3, 1, 4, 0], // Compressed: 3 bytes header - [0, 1, 0, 1, 4, 1, 5, 0], // Compressed: 4 bytes header - [0, 1, 1, 1, 5, 1, 6, 1], // Compressed: 5 bytes header + [0, 1, 1, 0, 3, 1, 3, 0], // Compressed: 3 bytes header + [0, 1, 0, 1, 4, 1, 4, 0], // Compressed: 4 bytes header + [0, 1, 1, 1, 5, 1, 5, 1], // Compressed: 5 bytes header ] .iter() .enumerate() diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 75cdeaf9db..f003290acf 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -865,9 +865,9 @@ fn process_block_zstd_literals_header( }, BlockType::ZstdCompressedBlock => match size_format { 0b00 => [2, 10, 10, 1, 3, 3], - 0b01 => [2, 10, 10, 4, 3, 4], - 0b10 => [2, 14, 14, 4, 4, 5], - 0b11 => [2, 18, 18, 4, 5, 6], + 0b01 => [2, 10, 10, 4, 3, 3], + 0b10 => [2, 14, 14, 4, 4, 4], + 0b11 => [2, 18, 18, 4, 5, 5], _ => unreachable!("size_format out of bound"), }, _ => unreachable!("BlockType::Reserved unexpected or treeless literal section"), From 41896ff6468ccb2b0825cd6f60cfb98a27cc4e74 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 10:34:20 -0500 Subject: [PATCH 160/165] clippy --- zkevm-circuits/src/decompression_circuit.rs | 22 +++-- .../src/decompression_circuit/test.rs | 9 ++- zkevm-circuits/src/table/decompression.rs | 51 ++++++------ zkevm-circuits/src/witness/zstd/mod.rs | 81 ++++++++----------- zkevm-circuits/src/witness/zstd/types.rs | 4 +- zkevm-circuits/src/witness/zstd/util.rs | 6 +- 6 files changed, 80 insertions(+), 93 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 1f666ede27..85aa1d5d4c 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -15,7 +15,7 @@ use crate::{ BitstringAccumulationTable, BlockTypeRomTable, FseTable, HuffmanCodesTable, LiteralsHeaderRomTable, LiteralsHeaderTable, TagRomTable, }, - BitwiseOpTable, KeccakTable, LookupTable, Pow2Table, PowOfRandTable, RangeTable, U8Table, + BitwiseOpTable, KeccakTable, LookupTable, Pow2Table, PowOfRandTable, RangeTable, }, util::{Challenges, SubCircuit, SubCircuitConfig}, witness::{ @@ -26,7 +26,6 @@ use crate::{ }; use array_init::array_init; use eth_types::Field; -use ff::BitViewSized; use gadgets::{ binary_number::{BinaryNumberChip, BinaryNumberConfig}, comparator::{ComparatorChip, ComparatorConfig, ComparatorInstruction}, @@ -2621,7 +2620,6 @@ impl DecompressionCircuitConfig { huffman_codes: Vec, challenges: &Challenges>, ) -> Result<(), Error> { - let mut jump_table_idx: usize = 0; let mut rand_pow: Vec> = vec![Value::known(F::one())]; self.bitstring_accumulation_table @@ -2665,7 +2663,7 @@ impl DecompressionCircuitConfig { last_byte_idx = row.encoded_data.byte_idx as usize; while tag_len >= rand_pow.len() { - let tail = rand_pow.last().expect("Tail exists").clone(); + let tail = *rand_pow.last().expect("Tail exists"); rand_pow.push(tail * challenges.keccak_input()); } @@ -2828,13 +2826,13 @@ impl DecompressionCircuitConfig { || "tag_gadget.tag_idx", self.tag_gadget.tag_idx, i, - || Value::known(F::from(row.state.tag_idx as u64)), + || Value::known(F::from(row.state.tag_idx)), )?; region.assign_advice( || "tag_gadget.tag_len", self.tag_gadget.tag_len, i, - || Value::known(F::from(row.state.tag_len as u64)), + || Value::known(F::from(row.state.tag_len)), )?; region.assign_advice( || "tag_gadget.is_reverse", @@ -2901,12 +2899,12 @@ impl DecompressionCircuitConfig { )?; let max_tag_len = row.state.max_tag_len; - let mlen_lt_0x20_chip = LtChip::construct(self.tag_gadget.mlen_lt_0x20.clone()); + let mlen_lt_0x20_chip = LtChip::construct(self.tag_gadget.mlen_lt_0x20); mlen_lt_0x20_chip.assign( &mut region, i, F::from(max_tag_len), - F::from(0x20 as u64), + F::from(0x20), )?; let is_block_header = (row.state.tag == ZstdTag::BlockHeader) as u64; @@ -3049,7 +3047,7 @@ impl DecompressionCircuitConfig { || "bitstream_decoder.bit_value", self.bitstream_decoder.bit_value, i, - || Value::known(F::from(row.bitstream_read_data.bit_value as u64)), + || Value::known(F::from(row.bitstream_read_data.bit_value)), )?; region.assign_advice( || "bitstream_decoder.is_nil", @@ -3092,19 +3090,19 @@ impl DecompressionCircuitConfig { || "fse_decoder.state", self.fse_decoder.state, i, - || Value::known(F::from(row.fse_data.state as u64)), + || Value::known(F::from(row.fse_data.state)), )?; region.assign_advice( || "fse_decoder.baseline", self.fse_decoder.baseline, i, - || Value::known(F::from(row.fse_data.baseline as u64)), + || Value::known(F::from(row.fse_data.baseline)), )?; region.assign_advice( || "fse_decoder.symbol", self.fse_decoder.symbol, i, - || Value::known(F::from(row.fse_data.symbol as u64)), + || Value::known(F::from(row.fse_data.symbol)), )?; // Lstream Config diff --git a/zkevm-circuits/src/decompression_circuit/test.rs b/zkevm-circuits/src/decompression_circuit/test.rs index fc4205d618..59b863dd5f 100644 --- a/zkevm-circuits/src/decompression_circuit/test.rs +++ b/zkevm-circuits/src/decompression_circuit/test.rs @@ -1,8 +1,8 @@ -use crate::decompression_circuit::DecompressionCircuit; -use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; - #[test] fn test_basic() { + use crate::decompression_circuit::DecompressionCircuit; + use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; + let circuit = DecompressionCircuit::::default(); let mock_prover = MockProver::run(17, &circuit, vec![]); assert!(mock_prover.is_ok()); @@ -16,6 +16,9 @@ fn test_basic() { #[test] fn test_work_example_decompression() { + use crate::decompression_circuit::DecompressionCircuit; + use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; + let compressed: Vec = vec![ // 0x28, 0xb5, 0x2f, 0xfd, // magic numbers are removed 0x60, // Originally 0x64. unset the checksum bit. diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs index 5761c27451..18d104bdc4 100644 --- a/zkevm-circuits/src/table/decompression.rs +++ b/zkevm-circuits/src/table/decompression.rs @@ -1412,7 +1412,7 @@ impl BitstringAccumulationTable { pub fn assign( &self, layouter: &mut impl Layouter, - witness_rows: &Vec>, + witness_rows: &[ZstdWitnessRow], ) -> Result<(), Error> { assert!(!witness_rows.is_empty()); @@ -1446,8 +1446,6 @@ impl BitstringAccumulationTable { }) .collect::>(); - let last_row = accumulation_rows.last().expect("Last row expected"); - layouter.assign_region( || "Bitstring Accumulation Table", |mut region| { @@ -1473,102 +1471,101 @@ impl BitstringAccumulationTable { let mut acc: u64 = 0; let mut bitstring_len: u64 = 0; - for bit_idx in 0..16 { + for (bit_idx, bit) in bits.into_iter().enumerate().take(16) { region.assign_fixed( - || format!("q_enable"), + || "q_enable", self.q_enabled, offset + bit_idx, || Value::known(F::one()), )?; region.assign_advice( - || format!("byte_offset"), + || "byte_offset", self.byte_offset, offset + bit_idx, || Value::known(F::from(huffman_offset)), )?; region.assign_advice( - || format!("byte_idx_1"), + || "byte_idx_1", self.byte_idx_1, offset + bit_idx, || Value::known(F::from(row.0 as u64)), )?; region.assign_advice( - || format!("byte_idx_2"), + || "byte_idx_2", self.byte_idx_2, offset + bit_idx, || Value::known(F::from(next_row.0 as u64)), )?; region.assign_advice( - || format!("byte_1"), + || "byte_1", self.byte_1, offset + bit_idx, - || Value::known(F::from(row.1 as u64)), + || Value::known(F::from(row.1)), )?; region.assign_advice( - || format!("byte_2"), + || "byte_2", self.byte_2, offset + bit_idx, - || Value::known(F::from(next_row.1 as u64)), + || Value::known(F::from(next_row.1)), )?; region.assign_fixed( - || format!("bit_index"), + || "bit_index", self.bit_index, offset + bit_idx, || Value::known(F::from(bit_idx as u64)), )?; region.assign_fixed( - || format!("q_first"), + || "q_first", self.q_first, offset + bit_idx, || Value::known(F::from((bit_idx == 0) as u64)), )?; - let bit = bits[bit_idx] as u64; if bit_idx >= row.2 && bit_idx <= row.3 { - acc = acc * 2 + bit; + acc = acc * 2 + (bit as u64); bitstring_len += 1; } region.assign_advice( - || format!("bit"), + || "bit", self.bit, offset + bit_idx, - || Value::known(F::from(bit)), + || Value::known(F::from(bit as u64)), )?; region.assign_advice( - || format!("bit_value_acc"), + || "bit_value_acc", self.bit_value_acc, offset + bit_idx, || Value::known(F::from(acc)), )?; region.assign_advice( - || format!("bit_value"), + || "bit_value", self.bit_value, offset + bit_idx, || Value::known(F::from(row.4)), )?; region.assign_advice( - || format!("bitstring_len"), + || "bitstring_len", self.bitstring_len, offset + bit_idx, || Value::known(F::from(bitstring_len)), )?; region.assign_advice( - || format!("from_start"), + || "from_start", self.from_start, offset + bit_idx, || Value::known(F::from((bit_idx <= row.3) as u64)), )?; region.assign_advice( - || format!("until_end"), + || "until_end", self.until_end, offset + bit_idx, || Value::known(F::from((bit_idx >= row.2) as u64)), )?; region.assign_advice( - || format!("is_reverse"), + || "is_reverse", self.is_reverse, offset + bit_idx, - || Value::known(F::from(row.5 as u64)), + || Value::known(F::from(row.5)), )?; } @@ -1577,13 +1574,13 @@ impl BitstringAccumulationTable { } region.assign_fixed( - || format!("q_first"), + || "q_first", self.q_first, offset, || Value::known(F::one()), )?; region.assign_advice( - || format!("byte_idx_1"), + || "byte_idx_1", self.byte_idx_1, offset, || Value::known(F::from(last_byte_idx as u64)), diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index f003290acf..c883db0bbb 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -36,8 +36,7 @@ const TAG_MAX_LEN: [(ZstdTag, u64); 13] = [ fn lookup_max_tag_len(tag: ZstdTag) -> u64 { TAG_MAX_LEN .iter() - .filter(|record| record.0 == tag) - .next() + .find(|record| record.0 == tag) .unwrap() .1 } @@ -130,8 +129,6 @@ fn process_frame_header( .expect("FrameContentSize bytes expected"); let aux_2 = fhd_value_rlc; - let value_rlc_fcs = fhd_value_rlc * randomness + fhd_value_rlc; - ( byte_offset + 1 + fcs_tag_len, std::iter::once(ZstdWitnessRow { @@ -571,7 +568,7 @@ fn process_block_raw( table_size: 0, sym_to_states: BTreeMap::default(), }; - let mut huffman_weights = HuffmanCodesData { + let huffman_weights = HuffmanCodesData { byte_offset: 0, weights: vec![], }; @@ -624,7 +621,7 @@ fn process_block_rle( table_size: 0, sym_to_states: BTreeMap::default(), }; - let mut huffman_weights = HuffmanCodesData { + let huffman_weights = HuffmanCodesData { byte_offset: 0, weights: vec![], }; @@ -776,11 +773,12 @@ fn process_block_zstd( let mut literals: Vec = vec![]; - for idx in 0..n_streams { + // for idx in 0..n_streams { + for (idx, l_len) in lstream_lens.iter().enumerate().take(n_streams) { let (byte_offset, rows, symbols) = process_block_zstd_lstream( src, stream_offset, - lstream_lens[idx] as usize, + *l_len as usize, huffman_rows.last().expect("last row should exist"), randomness, idx, @@ -1017,9 +1015,9 @@ fn process_block_zstd_huffman_code( tag: ZstdTag::ZstdBlockFseCode, tag_next, max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockFseCode), - tag_len: 0 as u64, /* There's no information at this point about the length of FSE + tag_len: 0_u64, /* There's no information at this point about the length of FSE * table bytes. So this value has to be modified later. */ - tag_idx: 1 as u64, + tag_idx: 1_u64, tag_value: Value::default(), // Must be changed after FSE table length is known tag_value_acc: Value::default(), // Must be changed after FSE table length is known is_tag_change: true, @@ -1029,7 +1027,7 @@ fn process_block_zstd_huffman_code( encoded_data: EncodedData { byte_idx: (byte_offset + 1) as u64, encoded_len, - value_byte: header_byte.clone(), + value_byte: header_byte, value_rlc, reverse: false, ..Default::default() @@ -1047,7 +1045,7 @@ fn process_block_zstd_huffman_code( // Recover the FSE table for generating Huffman weights let (n_fse_bytes, bit_boundaries, table) = - FseAuxiliaryTableData::reconstruct(&src, byte_offset + 1) + FseAuxiliaryTableData::reconstruct(src, byte_offset + 1) .expect("Reconstructing FSE table should not fail."); // Witness generation @@ -1128,8 +1126,8 @@ fn process_block_zstd_huffman_code( to_pos.0 as usize, to_pos.1 as usize, value.clone(), - current_tag_value_acc.clone(), - current_tag_rlc_acc.clone(), + current_tag_value_acc, + current_tag_rlc_acc, 0, n_acc, ) @@ -1156,7 +1154,7 @@ fn process_block_zstd_huffman_code( max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockFseCode), tag_len: (n_fse_bytes + 1) as u64, tag_idx: (row.1 + 1) as u64, // count the huffman header byte - tag_value: tag_value, + tag_value, tag_value_acc: row.6, is_tag_change: false, tag_rlc, @@ -1270,8 +1268,7 @@ fn process_block_zstd_huffman_code( let aux_1 = next_value_rlc_acc.clone(); let aux_2 = witness_rows[witness_rows.len() - 1] .encoded_data - .value_rlc - .clone(); + .value_rlc; let mut padding_end_idx: usize = 0; while huffman_bitstream[padding_end_idx] == 0 { @@ -1285,8 +1282,8 @@ fn process_block_zstd_huffman_code( tag_next, max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockHuffmanCode), tag_len: n_huffman_code_bytes as u64, - tag_idx: 1 as u64, - tag_value: tag_value, + tag_idx: 1_u64, + tag_value, tag_value_acc: next_tag_value_acc, is_tag_change: true, tag_rlc, @@ -1303,7 +1300,6 @@ fn process_block_zstd_huffman_code( reverse_idx: (n_huffman_code_bytes - (current_byte_idx - 1)) as u64, aux_1, aux_2, - ..Default::default() }, bitstream_read_data: BitstreamReadRow { bit_value: 1u64, @@ -1357,7 +1353,7 @@ fn process_block_zstd_huffman_code( // Lookup the FSE table row for the state let fse_row = fse_state_table - .get(&(next_state as u64)) + .get(&{ next_state }) .expect("next state should be in fse table"); // Decode the symbol @@ -1372,7 +1368,7 @@ fn process_block_zstd_huffman_code( max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockHuffmanCode), tag_len: (n_huffman_code_bytes) as u64, tag_idx: current_byte_idx as u64, - tag_value: tag_value, + tag_value, tag_value_acc: next_tag_value_acc, is_tag_change: false, tag_rlc, @@ -1389,7 +1385,6 @@ fn process_block_zstd_huffman_code( reverse_idx: (n_huffman_code_bytes - (current_byte_idx - 1)) as u64, aux_1, aux_2, - ..Default::default() }, bitstream_read_data: BitstreamReadRow { bit_value: bitstring_value, @@ -1399,7 +1394,7 @@ fn process_block_zstd_huffman_code( }, fse_data: FseTableRow { idx: fse_table_idx, - state: next_state as u64, + state: next_state, symbol: fse_row.0, baseline: fse_row.1, num_bits: fse_row.2, @@ -1637,7 +1632,7 @@ fn process_block_zstd_lstream( // Decide the next tag let tag_next = match stream_idx { - 0 | 1 | 2 => ZstdTag::ZstdBlockLstream, + 0..=2 => ZstdTag::ZstdBlockLstream, 3 => ZstdTag::ZstdBlockSequenceHeader, _ => unreachable!("stream_idx value out of range"), }; @@ -1648,7 +1643,6 @@ fn process_block_zstd_lstream( } let mut next_tag_value_acc = tag_value_acc.next().unwrap(); - let mut next_value_rlc_acc = value_rlc_acc.next().unwrap(); let mut next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); // Add a witness row for leading 0s and sentinel 1-bit @@ -1659,7 +1653,7 @@ fn process_block_zstd_lstream( max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockLstream), tag_len: len as u64, tag_idx: current_byte_idx as u64, - tag_value: tag_value, + tag_value, tag_value_acc: next_tag_value_acc, is_tag_change: true, tag_rlc, @@ -1676,18 +1670,17 @@ fn process_block_zstd_lstream( reverse_idx: (len - (current_byte_idx - 1)) as u64, aux_1, aux_2: tag_value, - ..Default::default() }, huffman_data: HuffmanData { byte_offset: huffman_code_byte_offset as u64, bit_value: 1u8, - stream_idx: stream_idx, + stream_idx, k: (0, padding_end_idx as u8), }, bitstream_read_data: BitstreamReadRow { bit_value: 1u64, bit_start_idx: 0usize, - bit_end_idx: padding_end_idx as usize, + bit_end_idx: padding_end_idx, is_zero_bit_read: false, }, decoded_data: DecodedData { @@ -1710,7 +1703,6 @@ fn process_block_zstd_lstream( // Update accumulator if current_byte_idx > last_byte_idx { next_tag_value_acc = tag_value_acc.next().unwrap(); - next_value_rlc_acc = value_rlc_acc.next().unwrap(); next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); last_byte_idx = current_byte_idx; } @@ -1723,10 +1715,9 @@ fn process_block_zstd_lstream( while current_bit_idx < len * N_BITS_PER_BYTE { if huffman_bitstring_map.contains_key(bitstring_acc.as_str()) { - let sym = huffman_bitstring_map + let sym = *huffman_bitstring_map .get(bitstring_acc.as_str()) - .unwrap() - .clone(); + .unwrap(); decoded_symbols.push(sym); let from_byte_idx = current_byte_idx; @@ -1772,18 +1763,17 @@ fn process_block_zstd_lstream( reverse_idx: (len - from_byte_idx + 1) as u64, aux_1, aux_2: tag_value, - ..Default::default() }, huffman_data: HuffmanData { byte_offset: huffman_code_byte_offset as u64, bit_value: u8::from_str_radix(bitstring_acc.as_str(), 2).unwrap(), - stream_idx: stream_idx, + stream_idx, k: (from_bit_idx.rem_euclid(8) as u8, end_bit_idx as u8), }, bitstream_read_data: BitstreamReadRow { bit_value: u8::from_str_radix(bitstring_acc.as_str(), 2).unwrap() as u64, - bit_start_idx: from_bit_idx.rem_euclid(8) as usize, - bit_end_idx: end_bit_idx as usize, + bit_start_idx: from_bit_idx.rem_euclid(8), + bit_end_idx: end_bit_idx, is_zero_bit_read: false, }, decoded_data: DecodedData { @@ -1799,7 +1789,6 @@ fn process_block_zstd_lstream( // Update accumulator if current_byte_idx > last_byte_idx && current_byte_idx <= len { next_tag_value_acc = tag_value_acc.next().unwrap(); - next_value_rlc_acc = value_rlc_acc.next().unwrap(); next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); last_byte_idx = current_byte_idx; } @@ -1809,9 +1798,9 @@ fn process_block_zstd_lstream( cur_bitstring_len = 0; } else { if lstream_bits[current_bit_idx + cur_bitstring_len] > 0 { - bitstring_acc.push_str("1"); + bitstring_acc.push('1'); } else { - bitstring_acc.push_str("0"); + bitstring_acc.push('0'); } cur_bitstring_len += 1; @@ -1972,7 +1961,7 @@ mod tests { encoder.finish()? }; - let (_witness_rows, _decoded_literals, _aux_data, fse_aux_tables, huffman_codes) = + let (_witness_rows, _decoded_literals, _aux_data, _fse_aux_tables, _huffman_codes) = process::(&compressed, Value::known(Fr::from(123456789))); Ok(()) @@ -2001,7 +1990,7 @@ mod tests { _fse_size, _fse_accuracy, _n_huffman_bitstream_bytes, - fse_aux_data, + _fse_aux_data, ) = process_block_zstd_huffman_code::( &input, 0, @@ -2018,7 +2007,7 @@ mod tests { 5, 3, 1, 3, 1, 3, ] .into_iter() - .map(|w| FseSymbol::from(w)) + .map(FseSymbol::from) .collect::>(); assert_eq!( @@ -2043,7 +2032,7 @@ mod tests { 2, 0, 4, 4, 5, 3, 1, 3, 1, 3, ] .into_iter() - .map(|w| FseSymbol::from(w)) + .map(FseSymbol::from) .collect::>(), }; @@ -2129,7 +2118,7 @@ mod tests { 0x4e, 0x53, 0xa5, 0x06, 0x82, 0x14, 0x95, 0x51, ]; - let (_witness_rows, decoded_literals, _aux_data, fse_aux_tables, huffman_codes) = + let (_witness_rows, decoded_literals, _aux_data, _fse_aux_tables, _huffman_codes) = process::(&encoded, Value::known(Fr::from(123456789))); let decoded_literal_string: String = decoded_literals diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 0d8636ceae..df8c558843 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -474,7 +474,7 @@ impl HuffmanCodesData { /// parse bit string map pub fn parse_bitstring_map(&self) -> ParsedCanonicalHuffmanCodeBitstringMap { - let mut weights: Vec = self.weights.iter().map(|w| w.clone() as usize).collect(); + let mut weights: Vec = self.weights.iter().map(|w| *w as usize).collect(); let sum_weights: usize = weights .iter() .filter_map(|&w| if w > 0 { Some(1 << (w - 1)) } else { None }) @@ -816,7 +816,7 @@ mod tests { 5, 3, 1, 3, 1, 3, ] .into_iter() - .map(|w| FseSymbol::from(w)) + .map(FseSymbol::from) .collect::>(); let huffman_codes_data = HuffmanCodesData { diff --git a/zkevm-circuits/src/witness/zstd/util.rs b/zkevm-circuits/src/witness/zstd/util.rs index 7f5b7b33e3..07cacb3f12 100644 --- a/zkevm-circuits/src/witness/zstd/util.rs +++ b/zkevm-circuits/src/witness/zstd/util.rs @@ -121,8 +121,8 @@ pub fn le_bits_to_value(bits: &[u8]) -> u64 { assert!(bits.len() <= 32); let mut m: u64 = 1; - bits.into_iter().fold(0, |mut acc, b| { - acc = acc + (*b as u64) * m; + bits.iter().fold(0, |mut acc, b| { + acc += (*b as u64) * m; m *= 2; acc }) @@ -131,7 +131,7 @@ pub fn le_bits_to_value(bits: &[u8]) -> u64 { pub fn be_bits_to_value(bits: &[u8]) -> u64 { assert!(bits.len() <= 32); - bits.into_iter().fold(0, |mut acc, b| { + bits.iter().fold(0, |mut acc, b| { acc = acc * 2 + *b as u64; acc }) From 90ca1e769d556f82ea9e6762f09317b25f01e64a Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 22:50:40 -0500 Subject: [PATCH 161/165] clippy --- zkevm-circuits/src/decompression_circuit.rs | 2 +- zkevm-circuits/src/witness/zstd/mod.rs | 11 ++--------- zkevm-circuits/src/witness/zstd/types.rs | 4 ++-- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index 85aa1d5d4c..c4b33dfefe 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -2820,7 +2820,7 @@ impl DecompressionCircuitConfig { || "tag_gadget.max_len", self.tag_gadget.max_len, i, - || Value::known(F::from(row.state.max_tag_len as u64)), + || Value::known(F::from(row.state.max_tag_len)), )?; region.assign_advice( || "tag_gadget.tag_idx", diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index c883db0bbb..5a0ee3db74 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -1125,7 +1125,7 @@ fn process_block_zstd_huffman_code( from_pos.1 as usize, to_pos.0 as usize, to_pos.1 as usize, - value.clone(), + *value, current_tag_value_acc, current_tag_rlc_acc, 0, @@ -1265,7 +1265,7 @@ fn process_block_zstd_huffman_code( let next_value_rlc_acc = value_rlc_iter.next().unwrap(); let mut next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); - let aux_1 = next_value_rlc_acc.clone(); + let aux_1 = next_value_rlc_acc; let aux_2 = witness_rows[witness_rows.len() - 1] .encoded_data .value_rlc; @@ -1597,13 +1597,6 @@ fn process_block_zstd_lstream( // accumulators let aux_1 = last_row.encoded_data.value_rlc; - let mut value_rlc_acc = src.iter().skip(byte_offset).take(len).rev().scan( - last_row.encoded_data.value_rlc, - |acc, &byte| { - *acc = *acc * randomness + Value::known(F::from(byte as u64)); - Some(*acc) - }, - ); let multiplier = (0..last_row.state.tag_len).fold(Value::known(F::one()), |acc, _| acc * randomness); let value_rlc = last_row.encoded_data.value_rlc * multiplier + last_row.state.tag_rlc; diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index df8c558843..d841df688e 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -503,8 +503,8 @@ impl HuffmanCodesData { cur_bit_value += 1; cur_bit_value >>= 1; - for sym in 0..n { - if bitstring_length[sym] == bit_len { + for (sym, b_len) in bitstring_length.iter().enumerate().take(n) { + if *b_len == bit_len { bitstring_map.insert( format!("{:0width$b}", cur_bit_value, width = bit_len), sym as u64, From a698b095c56760a705bdaffd2034bf6616e6d90b Mon Sep 17 00:00:00 2001 From: darth-cy Date: Wed, 14 Feb 2024 23:22:03 -0500 Subject: [PATCH 162/165] clippy --- zkevm-circuits/src/witness/zstd/mod.rs | 72 ++++++-------------------- 1 file changed, 16 insertions(+), 56 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 5a0ee3db74..4ad9965eb2 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -531,6 +531,8 @@ fn process_rle_bytes( ) } +type BlockProcessingResult = (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData); + fn process_block_raw( src: &[u8], byte_offset: usize, @@ -538,15 +540,7 @@ fn process_block_raw( randomness: Value, block_size: usize, last_block: bool, -) -> ( - usize, - Vec>, - Vec, - Vec, - Vec, - FseAuxiliaryTableData, - HuffmanCodesData, -) { +) -> BlockProcessingResult { let tag_next = if last_block { ZstdTag::Null } else { @@ -591,15 +585,7 @@ fn process_block_rle( randomness: Value, block_size: usize, last_block: bool, -) -> ( - usize, - Vec>, - Vec, - Vec, - Vec, - FseAuxiliaryTableData, - HuffmanCodesData, -) { +) -> BlockProcessingResult { let tag_next = if last_block { ZstdTag::Null } else { @@ -645,15 +631,7 @@ fn process_block_zstd( randomness: Value, block_size: usize, last_block: bool, -) -> ( - usize, - Vec>, - Vec, - Vec, - Vec, - FseAuxiliaryTableData, - HuffmanCodesData, -) { +) -> BlockProcessingResult { let mut witness_rows = vec![]; // 1-5 bytes LiteralSectionHeader @@ -828,20 +806,14 @@ fn process_block_zstd( ) } +type LiteralsHeaderProcessingResult = (usize, Vec>, BlockType, usize, usize, usize, (u64, bool)); + fn process_block_zstd_literals_header( src: &[u8], byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> ( - usize, - Vec>, - BlockType, - usize, - usize, - usize, - (u64, bool), -) { +) -> LiteralsHeaderProcessingResult { let lh_bytes = src .iter() .skip(byte_offset) @@ -970,25 +942,15 @@ fn process_block_zstd_literals_header( ) } +type HuffmanCodeProcessingResult = (usize, Vec>, HuffmanCodesData, usize, usize, Value, usize, u64, u64, u64, FseAuxiliaryTableData); + fn process_block_zstd_huffman_code( src: &[u8], byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, n_streams: usize, -) -> ( - usize, - Vec>, - HuffmanCodesData, - usize, - usize, - Value, - usize, - u64, - u64, - u64, - FseAuxiliaryTableData, -) { +) -> HuffmanCodeProcessingResult { // Preserve this value for later construction of HuffmanCodesDataTable let huffman_code_byte_offset = byte_offset; @@ -1563,6 +1525,7 @@ fn process_block_zstd_huffman_jump_table( } } +#[allow(clippy::too_many_arguments)] fn process_block_zstd_lstream( src: &[u8], byte_offset: usize, @@ -1806,17 +1769,14 @@ fn process_block_zstd_lstream( (byte_offset + len, witness_rows, decoded_symbols) } +/// Result for processing multiple blocks from compressed data +pub type MultiBlockProcessResult = (Vec>, Vec, Vec, Vec, Vec); + /// Process a slice of bytes into decompression circuit witness rows pub fn process( src: &[u8], randomness: Value, -) -> ( - Vec>, - Vec, - Vec, - Vec, - Vec, -) { +) -> MultiBlockProcessResult { let mut witness_rows = vec![]; let mut literals: Vec = vec![]; let mut aux_data: Vec = vec![]; From c07da092d624d78376acddfee72bb75348fe2cd3 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 15 Feb 2024 05:51:17 -0500 Subject: [PATCH 163/165] Clippy --- zkevm-circuits/src/witness/zstd/mod.rs | 25 +++++++++++++----------- zkevm-circuits/src/witness/zstd/types.rs | 3 ++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index 4ad9965eb2..bc48972a48 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -213,21 +213,13 @@ fn process_frame_header( ) } +type AggregateBlockResult = (usize, Vec>, bool, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData); fn process_block( src: &[u8], byte_offset: usize, last_row: &ZstdWitnessRow, randomness: Value, -) -> ( - usize, - Vec>, - bool, - Vec, - Vec, - Vec, - FseAuxiliaryTableData, - HuffmanCodesData, -) { +) -> AggregateBlockResult { let mut witness_rows = vec![]; let (byte_offset, rows, last_block, block_type, block_size) = @@ -635,6 +627,7 @@ fn process_block_zstd( let mut witness_rows = vec![]; // 1-5 bytes LiteralSectionHeader + let literals_header_result: LiteralsHeaderProcessingResult = process_block_zstd_literals_header::(src, byte_offset, last_row, randomness); let ( byte_offset, rows, @@ -643,7 +636,17 @@ fn process_block_zstd( regen_size, compressed_size, (branch, sf_max), - ) = process_block_zstd_literals_header::(src, byte_offset, last_row, randomness); + ) = literals_header_result; + // let ( + // byte_offset, + // rows, + // literals_block_type, + // n_streams, + // regen_size, + // compressed_size, + // (branch, sf_max), + // ) = process_block_zstd_literals_header::(src, byte_offset, last_row, randomness); + witness_rows.extend_from_slice(&rows); let mut fse_aux_table = FseAuxiliaryTableData { byte_offset: 0, diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index d841df688e..00ad3f3abd 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -586,6 +586,7 @@ pub struct FseAuxiliaryTableData { /// This representation makes it easy to look up decoded symbol from current state. /// Map. type FseStateMapping = BTreeMap; +type ReconstructedFse = (usize, Vec<(u32, u64)>, FseAuxiliaryTableData); impl FseAuxiliaryTableData { #[allow(non_snake_case)] @@ -599,7 +600,7 @@ impl FseAuxiliaryTableData { pub fn reconstruct( src: &[u8], byte_offset: usize, - ) -> std::io::Result<(usize, Vec<(u32, u64)>, Self)> { + ) -> std::io::Result { // construct little-endian bit-reader. let data = src.iter().skip(byte_offset).cloned().collect::>(); let mut reader = BitReader::endian(Cursor::new(&data), LittleEndian); From dea3e76209792527fa9a505566ab09ff09c80c49 Mon Sep 17 00:00:00 2001 From: darth-cy Date: Thu, 15 Feb 2024 05:54:38 -0500 Subject: [PATCH 164/165] clippy --- zkevm-circuits/src/witness/zstd/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index bc48972a48..d1d5f4cc99 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -615,6 +615,8 @@ fn process_block_rle( ) } +type LiteralsBlockResult = (usize, Vec>, Vec, Vec, Vec); + #[allow(unused_variables)] fn process_block_zstd( src: &[u8], @@ -659,13 +661,7 @@ fn process_block_zstd( }; // Depending on the literals block type, decode literals section accordingly - let (bytes_offset, rows, literals, lstream_len, aux_data): ( - usize, - Vec>, - Vec, - Vec, - Vec, - ) = match literals_block_type { + let literals_block_result: LiteralsBlockResult = match literals_block_type { BlockType::RawBlock => { let (byte_offset, rows) = process_raw_bytes( src, @@ -787,6 +783,7 @@ fn process_block_zstd( } _ => unreachable!("Invalid literals section BlockType"), }; + let (bytes_offset, rows, literals, lstream_len, aux_data) = literals_block_result; witness_rows.extend_from_slice(&rows); ( From 1570ed289acf388b9b2848165769a8d311c5fb2c Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Thu, 15 Feb 2024 12:02:16 +0000 Subject: [PATCH 165/165] decoded literals table | refactor tables module --- zkevm-circuits/src/decompression_circuit.rs | 88 +- .../src/decompression_circuit/dev.rs | 6 +- .../src/decompression_circuit/test.rs | 2 +- zkevm-circuits/src/table/decompression.rs | 2371 ----------------- .../bitstring_accumulation_table.rs | 557 ++++ .../decompression/block_type_rom_table.rs | 115 + .../decompression/decoded_literals_table.rs | 172 ++ .../src/table/decompression/fse_table.rs | 528 ++++ .../decompression/huffman_codes_table.rs | 563 ++++ .../literals_header_rom_table.rs | 123 + .../decompression/literals_header_table.rs | 451 ++++ zkevm-circuits/src/table/decompression/mod.rs | 20 + .../src/table/decompression/tag_rom_table.rs | 91 + zkevm-circuits/src/witness/zstd/mod.rs | 77 +- zkevm-circuits/src/witness/zstd/types.rs | 17 +- 15 files changed, 2735 insertions(+), 2446 deletions(-) delete mode 100644 zkevm-circuits/src/table/decompression.rs create mode 100644 zkevm-circuits/src/table/decompression/bitstring_accumulation_table.rs create mode 100644 zkevm-circuits/src/table/decompression/block_type_rom_table.rs create mode 100644 zkevm-circuits/src/table/decompression/decoded_literals_table.rs create mode 100644 zkevm-circuits/src/table/decompression/fse_table.rs create mode 100644 zkevm-circuits/src/table/decompression/huffman_codes_table.rs create mode 100644 zkevm-circuits/src/table/decompression/literals_header_rom_table.rs create mode 100644 zkevm-circuits/src/table/decompression/literals_header_table.rs create mode 100644 zkevm-circuits/src/table/decompression/mod.rs create mode 100644 zkevm-circuits/src/table/decompression/tag_rom_table.rs diff --git a/zkevm-circuits/src/decompression_circuit.rs b/zkevm-circuits/src/decompression_circuit.rs index c4b33dfefe..99767d25ed 100644 --- a/zkevm-circuits/src/decompression_circuit.rs +++ b/zkevm-circuits/src/decompression_circuit.rs @@ -12,8 +12,8 @@ use crate::{ evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, table::{ decompression::{ - BitstringAccumulationTable, BlockTypeRomTable, FseTable, HuffmanCodesTable, - LiteralsHeaderRomTable, LiteralsHeaderTable, TagRomTable, + BitstringAccumulationTable, BlockTypeRomTable, DecodedLiteralsTable, FseTable, + HuffmanCodesTable, LiteralsHeaderRomTable, LiteralsHeaderTable, TagRomTable, }, BitwiseOpTable, KeccakTable, LookupTable, Pow2Table, PowOfRandTable, RangeTable, }, @@ -52,6 +52,8 @@ pub struct DecompressionCircuitConfigArgs { pub bs_acc_table: BitstringAccumulationTable, /// Lookup table to get regenerated and compressed size from LiteralsHeader. pub literals_header_table: LiteralsHeaderTable, + /// Lookup table to validate decoded literal bytes. + pub decoded_literals_table: DecodedLiteralsTable, /// Bitwise OP table. pub bitwise_op_table: BitwiseOpTable, /// RangeTable for [0, 4). @@ -144,6 +146,7 @@ pub struct DecompressionCircuitConfig { bitstring_accumulation_table: BitstringAccumulationTable, fse_table: FseTable, huffman_codes_table: HuffmanCodesTable, + decoded_literals_table: DecodedLiteralsTable, } /// Block level details are specified in these columns. @@ -383,6 +386,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { huffman_codes_table, bs_acc_table, literals_header_table, + decoded_literals_table, bitwise_op_table, range4, range8, @@ -1622,21 +1626,14 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlock Raw bytes", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "value_byte == decoded_byte", - meta.query_advice(value_byte, Rotation::cur()), - meta.query_advice(decoded_byte, Rotation::cur()), - ); - cb.condition( - meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()), - |cb| { - cb.require_equal( - "tag_len == regen_size", - meta.query_advice(tag_gadget.tag_len, Rotation::cur()), - meta.query_advice(literals_header.regen_size, Rotation::prev()), - ); - }, - ); + let is_first = meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()); + cb.condition(is_first, |cb| { + cb.require_equal( + "tag_len == regen_size", + meta.query_advice(tag_gadget.tag_len, Rotation::cur()), + meta.query_advice(literals_header.regen_size, Rotation::prev()), + ); + }); cb.require_equal( "byte_idx increments", meta.query_advice(byte_idx, Rotation::cur()), @@ -1657,30 +1654,20 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.create_gate("DecompressionCircuit: ZstdBlock RLE bytes", |meta| { let mut cb = BaseConstraintBuilder::default(); - cb.require_equal( - "value_byte == decoded_byte", - meta.query_advice(value_byte, Rotation::cur()), - meta.query_advice(decoded_byte, Rotation::cur()), - ); - let is_tag_change = meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()); - cb.condition(is_tag_change.expr(), |cb| { + let is_first = meta.query_advice(tag_gadget.is_tag_change, Rotation::cur()); + cb.condition(is_first.expr(), |cb| { cb.require_equal( "tag_len == regen_size", meta.query_advice(tag_gadget.tag_len, Rotation::cur()), meta.query_advice(literals_header.regen_size, Rotation::prev()), ); }); - cb.condition(not::expr(is_tag_change), |cb| { + cb.condition(not::expr(is_first), |cb| { cb.require_equal( "byte_idx remains the same", meta.query_advice(byte_idx, Rotation::cur()), meta.query_advice(byte_idx, Rotation::prev()), ); - cb.require_equal( - "decoded byte remains the same", - meta.query_advice(decoded_byte, Rotation::cur()), - meta.query_advice(decoded_byte, Rotation::prev()), - ); }); cb.gate(and::expr([ @@ -2267,12 +2254,6 @@ impl SubCircuitConfig for DecompressionCircuitConfig { meta.query_advice(lstream_config.lstream, Rotation::prev()), ); - cb.require_equal( - "decoded byte is the decoded symbol", - meta.query_advice(decoded_byte, Rotation::cur()), - meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), - ); - cb.gate(and::expr([ meta.query_fixed(q_enable, Rotation::cur()), meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), @@ -2356,6 +2337,29 @@ impl SubCircuitConfig for DecompressionCircuitConfig { }, ); + // TODO: to be enabled once DecodedLiteralsTable has been assigned witness to. + /* + meta.lookup_any( + "DecompressionCircuit: ZstdBlockLstream (decoded literal byte)", + |meta| { + let condition = and::expr([ + meta.query_fixed(q_enable, Rotation::cur()), + meta.query_advice(tag_gadget.is_lstream, Rotation::cur()), + not::expr(meta.query_advice(tag_gadget.is_tag_change, Rotation::cur())), + ]); + [ + meta.query_advice(huffman_tree_config.huffman_tree_idx, Rotation::cur()), + meta.query_advice(byte_idx, Rotation::cur()), + meta.query_advice(bitstream_decoder.decoded_symbol, Rotation::cur()), + ] + .into_iter() + .zip(decoded_literals_table.table_exprs(meta)) + .map(|(value, table)| (condition.expr() * value, table)) + .collect() + }, + ); + */ + meta.lookup_any("DecompressionCircuit: bitstring (start)", |meta| { let condition = and::expr([ meta.query_fixed(q_enable, Rotation::cur()), @@ -2605,6 +2609,7 @@ impl SubCircuitConfig for DecompressionCircuitConfig { bitstring_accumulation_table: bs_acc_table, fse_table, huffman_codes_table, + decoded_literals_table, } } } @@ -2650,6 +2655,10 @@ impl DecompressionCircuitConfig { )], )?; + // TODO: pass decoded literals along with boundaries (literal lengths calculated while + // applying the Sequences FSE tables). + // self.decoded_literals_table.assign(layouter)?; + layouter.assign_region( || "Decompression table region", |mut region| { @@ -2922,12 +2931,7 @@ impl DecompressionCircuitConfig { let is_huffman_tree_section = is_fse_code + is_huffman_code + is_jumptable + is_lstream; - let is_output = (row.state.tag == ZstdTag::RawBlockBytes - || row.state.tag == ZstdTag::RleBlockBytes - || row.state.tag == ZstdTag::ZstdBlockLiteralsRawBytes - || row.state.tag == ZstdTag::ZstdBlockLiteralsRleBytes - || row.state.tag == ZstdTag::ZstdBlockLstream) - as u64; + let is_output = row.state.tag.is_output() as u64; region.assign_advice( || "tag_gadget.is_output", self.tag_gadget.is_output, diff --git a/zkevm-circuits/src/decompression_circuit/dev.rs b/zkevm-circuits/src/decompression_circuit/dev.rs index 7950657486..6308410122 100644 --- a/zkevm-circuits/src/decompression_circuit/dev.rs +++ b/zkevm-circuits/src/decompression_circuit/dev.rs @@ -10,7 +10,8 @@ use crate::{ }, table::{ decompression::{ - BitstringAccumulationTable, FseTable, HuffmanCodesTable, LiteralsHeaderTable, + BitstringAccumulationTable, DecodedLiteralsTable, FseTable, HuffmanCodesTable, + LiteralsHeaderTable, }, BitwiseOpTable, KeccakTable, Pow2Table, PowOfRandTable, RangeTable, }, @@ -52,6 +53,8 @@ impl Circuit for DecompressionCircuit { range16, range64, ); + let decoded_literals_table = + DecodedLiteralsTable::construct(meta, challenge_exprs.clone(), range256); let config = DecompressionCircuitConfig::new( meta, @@ -61,6 +64,7 @@ impl Circuit for DecompressionCircuit { huffman_codes_table, bs_acc_table, literals_header_table, + decoded_literals_table, bitwise_op_table, range4, range8, diff --git a/zkevm-circuits/src/decompression_circuit/test.rs b/zkevm-circuits/src/decompression_circuit/test.rs index 59b863dd5f..ae2e5ed43a 100644 --- a/zkevm-circuits/src/decompression_circuit/test.rs +++ b/zkevm-circuits/src/decompression_circuit/test.rs @@ -18,7 +18,7 @@ fn test_basic() { fn test_work_example_decompression() { use crate::decompression_circuit::DecompressionCircuit; use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; - + let compressed: Vec = vec![ // 0x28, 0xb5, 0x2f, 0xfd, // magic numbers are removed 0x60, // Originally 0x64. unset the checksum bit. diff --git a/zkevm-circuits/src/table/decompression.rs b/zkevm-circuits/src/table/decompression.rs deleted file mode 100644 index 18d104bdc4..0000000000 --- a/zkevm-circuits/src/table/decompression.rs +++ /dev/null @@ -1,2371 +0,0 @@ -//! Tables with constraints used for verification of zstd decoding from Huffman Codes and FSE -//! codes. - -use array_init::array_init; -use eth_types::Field; -use gadgets::{ - binary_number::{BinaryNumberChip, BinaryNumberConfig}, - comparator::{ComparatorChip, ComparatorConfig, ComparatorInstruction}, - impl_expr, - is_equal::{IsEqualChip, IsEqualConfig}, - util::{and, not, select, Expr}, -}; -use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, - poly::Rotation, -}; -use strum::IntoEnumIterator; -use strum_macros::EnumIter; - -use crate::{ - evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, - table::BitwiseOp, - witness::{ - value_bits_le, FseAuxiliaryTableData, FseSymbol, HuffmanCodesData, TagRomTableRow, ZstdTag, - ZstdWitnessRow, N_BITS_SYMBOL, N_MAX_SYMBOLS, - }, -}; - -use super::{BitwiseOpTable, LookupTable, Pow2Table, RangeTable, U8Table}; - -/// An auxiliary table used to ensure that the FSE table was reconstructed appropriately. Contrary -/// to the FseTable where the state is incremental, in the Auxiliary table we club together rows by -/// symbol. Which means, we will have rows with symbol s0 (and varying, but not necessarily -/// incremental states) clubbed together, followed by symbol s1 and so on. -/// -/// | State | Symbol | Baseline | Nb | Baseline Mark | -/// |-------|--------|----------|-----|---------------| -/// | 0x00 | s0 | ... | ... | 0 | -/// | 0x01 | s0 | ... | ... | 0 | -/// | 0x02 | s0 | ... | ... | 0 | -/// | ... | s0 | ... | ... | ... | -/// | 0x1d | s0 | ... | ... | 0 | -/// | 0x03 | s1 -> | 0x10 | ... | 0 | -/// | 0x0c | s1 -> | 0x18 | ... | 0 | -/// | 0x11 | s1 -> | 0x00 | ... | 1 | -/// | 0x15 | s1 -> | 0x04 | ... | 1 | -/// | 0x1a | s1 -> | 0x08 | ... | 1 | -/// | 0x1e | s1 -> | 0x0c | ... | 1 | -/// | 0x08 | s2 | ... | ... | 0 | -/// | ... | ... | ... | ... | 0 | -/// | 0x09 | s6 | ... | ... | 0 | -/// -/// Above is a representation of this table. Primarily we are interested in verifying that: -/// - next state (for the same symbol) was assigned correctly -/// - the number of times this symbol appears is assigned correctly -/// -/// For more details, refer the [FSE reconstruction][doclink] section. -/// -/// [doclink]: https://nigeltao.github.io/blog/2022/zstandard-part-5-fse.html#fse-reconstruction -#[derive(Clone, Debug)] -pub struct FseTable { - /// Fixed column to denote whether the constraints will be enabled or not. - pub q_enabled: Column, - /// The byte offset within the data instance where the encoded FSE table begins. This is - /// 1-indexed, i.e. byte_offset == 1 at the first byte. - pub byte_offset: Column, - /// Helper gadget to know when we are done handling a single canonical Huffman code. - pub byte_offset_cmp: ComparatorConfig, - /// The size of the FSE table that starts at byte_offset. - pub table_size: Column, - /// Helper column for (table_size >> 1). - pub table_size_rs_1: Column, - /// Helper column for (table_size >> 3). - pub table_size_rs_3: Column, - /// Incremental index. - pub idx: Column, - /// The symbol (weight) assigned to this state. - pub symbol: Column, - /// Helper gadget to know whether the symbol is the same or not. - pub symbol_eq: IsEqualConfig, - /// Represents the number of times this symbol appears in the FSE table. This value does not - /// change while the symbol in the table remains the same. - pub symbol_count: Column, - /// An accumulator that resets to 1 each time we encounter a new symbol in the Auxiliary table - /// and increments by 1 while the symbol remains the same. On the row where symbol' != symbol - /// we have: symbol_count == symbol_count_acc. - pub symbol_count_acc: Column, - /// The state in FSE. In the Auxiliary table, it does not increment by 1. Instead, it follows: - /// - state'' == state + table_size_rs_1 + table_size_rs_3 + 3 - /// - state' == state'' & (table_size - 1) - /// - /// where state' is the next row's state. - pub state: Column, - /// Denotes the baseline field. - pub baseline: Column, - /// Helper column to mark the baseline observed at the last occurence of a symbol. - pub last_baseline: Column, - /// The number of bits to be read from bitstream at this state. - pub nb: Column, - /// The smaller power of two assigned to this state. The following must hold: - /// - 2 ^ nb == SPoT. - pub spot: Column, - /// An accumulator over SPoT value. - pub spot_acc: Column, - /// Helper column to remember the smallest spot for that symbol. - pub smallest_spot: Column, - /// Helper boolean column which is set only from baseline == 0x00. - pub baseline_mark: Column, -} - -impl FseTable { - /// Construct the auxiliary table for FSE codes. - pub fn construct( - meta: &mut ConstraintSystem, - bitwise_op_table: BitwiseOpTable, - pow2_table: Pow2Table, - range_table: RangeTable<8>, - u8_table: U8Table, - ) -> Self { - let q_enabled = meta.fixed_column(); - let byte_offset = meta.advice_column(); - let symbol = meta.advice_column(); - let spot = meta.advice_column(); - let smallest_spot = meta.advice_column(); - let table = Self { - q_enabled, - byte_offset, - byte_offset_cmp: ComparatorChip::configure( - meta, - |meta| meta.query_fixed(q_enabled, Rotation::cur()), - |meta| meta.query_advice(byte_offset, Rotation::cur()), - |meta| meta.query_advice(byte_offset, Rotation::next()), - u8_table.into(), - ), - table_size: meta.advice_column(), - table_size_rs_1: meta.advice_column(), - table_size_rs_3: meta.advice_column(), - idx: meta.advice_column(), - symbol, - symbol_eq: IsEqualChip::configure( - meta, - |meta| meta.query_fixed(q_enabled, Rotation::cur()), - |meta| meta.query_advice(symbol, Rotation::cur()), - |meta| meta.query_advice(symbol, Rotation::next()), - ), - symbol_count: meta.advice_column(), - symbol_count_acc: meta.advice_column(), - state: meta.advice_column(), - baseline: meta.advice_column(), - last_baseline: meta.advice_column(), - nb: meta.advice_column(), - spot, - spot_acc: meta.advice_column(), - smallest_spot, - baseline_mark: meta.advice_column(), - }; - - // All rows. - meta.create_gate("FseAuxiliaryTable: all rows", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - cb.require_boolean( - "baseline_mark == [0, 1]", - meta.query_advice(table.baseline_mark, Rotation::cur()), - ); - - let (gt, eq) = table.byte_offset_cmp.expr(meta, None); - cb.require_equal("byte offset is increasing", gt + eq, 1.expr()); - - cb.gate(meta.query_fixed(table.q_enabled, Rotation::cur())) - }); - - // Validate SPoT assignment: all rows. - meta.lookup_any("FseAuxiliaryTable: SPoT == 2 ^ Nb", |meta| { - let condition = meta.query_fixed(table.q_enabled, Rotation::cur()); - - [ - meta.query_advice(table.nb, Rotation::cur()), - meta.query_advice(table.spot, Rotation::cur()), - ] - .into_iter() - .zip(pow2_table.table_exprs(meta)) - .map(|(input, table)| (input * condition.clone(), table)) - .collect::>() - }); - - // Constraints while traversing an FSE table. - meta.create_gate("FseAuxiliaryTable: table size and helper columns", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // Table size, and the right-shifted helper values remain unchanged. - for col in [ - table.table_size, - table.table_size_rs_1, - table.table_size_rs_3, - ] { - cb.require_equal( - "while byte_offset' == byte_offset: table_size and helpers remain unchanged", - meta.query_advice(col, Rotation::next()), - meta.query_advice(col, Rotation::cur()), - ); - } - - // Index is incremental. - cb.require_equal( - "idx' == idx + 1", - meta.query_advice(table.idx, Rotation::next()), - meta.query_advice(table.idx, Rotation::cur()) + 1.expr(), - ); - - cb.require_boolean( - "symbol' == symbol or symbol' == symbol + 1", - meta.query_advice(table.symbol, Rotation::next()) - - meta.query_advice(table.symbol, Rotation::cur()), - ); - - let (_gt, eq) = table.byte_offset_cmp.expr(meta, None); - cb.gate(and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - eq, - ])) - }); - - // Constraints for last row of an FSE table. - meta.create_gate("FseAuxiliaryTable: table shift right ops", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // Constraint for table_size >> 1. - cb.require_boolean( - "table_size >> 1", - meta.query_advice(table.table_size, Rotation::cur()) - - (meta.query_advice(table.table_size_rs_1, Rotation::cur()) * 2.expr()), - ); - - // Constraint for idx == table_size. - cb.require_equal( - "idx == table_size", - meta.query_advice(table.idx, Rotation::cur()), - meta.query_advice(table.table_size, Rotation::cur()), - ); - - let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); - cb.gate(and::expr([ - meta.query_fixed(q_enabled, Rotation::cur()), - gt, - ])) - }); - - // Constraint for table_size >> 3. Only check on the last row. - meta.lookup("FseAuxiliaryTable: table shift right ops", |meta| { - let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); - let condition = and::expr([meta.query_fixed(q_enabled, Rotation::cur()), gt]); - - let range_value = meta.query_advice(table.table_size, Rotation::cur()) - - (meta.query_advice(table.table_size_rs_3, Rotation::cur()) * 8.expr()); - - vec![(condition * range_value, range_table.into())] - }); - - // Constraint for state' calculation. We wish to constrain: - // - // - state' == state'' & (table_size - 1) - // - state'' == state + (table_size >> 3) + (table_size >> 1) + 3 - meta.lookup_any("FseAuxiliaryTable: next state computation", |meta| { - let (_gt, eq) = table.byte_offset_cmp.expr(meta, None); - let condition = and::expr([meta.query_fixed(table.q_enabled, Rotation::cur()), eq]); - - let lhs = meta.query_advice(table.state, Rotation::cur()) - + meta.query_advice(table.table_size_rs_3, Rotation::cur()) - + meta.query_advice(table.table_size_rs_1, Rotation::cur()) - + 3.expr(); - let rhs = meta.query_advice(table.table_size, Rotation::cur()) - 1.expr(); - let output = meta.query_advice(table.state, Rotation::next()); - - [BitwiseOp::AND.expr(), lhs, rhs, output] - .into_iter() - .zip(bitwise_op_table.table_exprs(meta)) - .map(|(input, table)| (input * condition.clone(), table)) - .collect::>() - }); - - // Constraints for same FSE table and same symbol. - meta.create_gate("FseAuxiliaryTable: symbol' == symbol", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // Symbol's count remains unchanged while symbol remained unchanged. - cb.require_equal( - "if symbol' == symbol: symbol_count' == symbol_count", - meta.query_advice(table.symbol_count, Rotation::next()), - meta.query_advice(table.symbol_count, Rotation::cur()), - ); - - // SPoT at baseline == 0x00 remains unchanged over these rows. - cb.require_equal( - "if symbol' == symbol: smallest SPoT is unchanged", - meta.query_advice(table.smallest_spot, Rotation::next()), - meta.query_advice(table.smallest_spot, Rotation::cur()), - ); - - // last baseline remains unchanged over these rows. - cb.require_equal( - "if symbol' == symbol: last baseline is unchanged", - meta.query_advice(table.last_baseline, Rotation::next()), - meta.query_advice(table.last_baseline, Rotation::cur()), - ); - - // Symbol count accumulator increments. - cb.require_equal( - "if symbol' == symbol: symbol count accumulator increments", - meta.query_advice(table.symbol_count_acc, Rotation::next()), - meta.query_advice(table.symbol_count_acc, Rotation::cur()) + 1.expr(), - ); - - // SPoT accumulation. - cb.require_equal( - "SPoT_acc::next == SPoT_acc::cur + SPoT::next", - meta.query_advice(table.spot_acc, Rotation::next()), - meta.query_advice(table.spot_acc, Rotation::cur()) - + meta.query_advice(table.spot, Rotation::next()), - ); - - // baseline_mark can only transition from 0 to 1 once. - cb.require_boolean( - "baseline_mark transition", - meta.query_advice(table.baseline_mark, Rotation::next()) - - meta.query_advice(table.baseline_mark, Rotation::cur()), - ); - - let is_next_baseline_0x00 = meta.query_advice(table.baseline_mark, Rotation::next()) - - meta.query_advice(table.baseline_mark, Rotation::cur()); - cb.condition(is_next_baseline_0x00.expr(), |cb| { - cb.require_equal( - "baseline::next == 0x00", - meta.query_advice(table.baseline, Rotation::next()), - 0x00.expr(), - ); - }); - cb.condition(not::expr(is_next_baseline_0x00.expr()), |cb| { - cb.require_equal( - "baseline::next == baseline::cur + spot::cur", - meta.query_advice(table.baseline, Rotation::next()), - meta.query_advice(table.baseline, Rotation::cur()) - + meta.query_advice(table.spot, Rotation::cur()), - ); - }); - - let (_gt, eq) = table.byte_offset_cmp.expr(meta, None); - cb.gate(and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - eq, - table.symbol_eq.expr(), - ])) - }); - - // Constraints when symbol changes in an FSE table, i.e. symbol' != symbol. - meta.create_gate("FseAuxiliaryTable: symbol' != symbol", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // Constraint for idx == table_size. - cb.require_equal( - "symbol_count_acc == symbol_count", - meta.query_advice(table.symbol_count_acc, Rotation::cur()), - meta.query_advice(table.symbol_count, Rotation::cur()), - ); - - // SPoT accumulator == table_size at the end of processing the symbol. - cb.require_equal( - "SPoT_acc == table_size", - meta.query_advice(table.spot_acc, Rotation::cur()), - meta.query_advice(table.table_size, Rotation::cur()), - ); - - // The SPoT at baseline == 0x00 matches this SPoT. - cb.require_equal( - "last symbol occurrence => SPoT == SPoT at baseline 0x00", - meta.query_advice(table.smallest_spot, Rotation::cur()), - meta.query_advice(table.spot, Rotation::cur()), - ); - - // last baseline matches. - cb.require_equal( - "baseline == last_baseline", - meta.query_advice(table.baseline, Rotation::cur()), - meta.query_advice(table.last_baseline, Rotation::cur()), - ); - - cb.gate(and::expr([ - meta.query_fixed(q_enabled, Rotation::cur()), - not::expr(table.symbol_eq.expr()), - ])) - }); - - // Constraints for the first occurence of a particular symbol in the table. - meta.create_gate("FseAuxiliaryTable: new symbol", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - let is_baseline_marked = meta.query_advice(table.baseline_mark, Rotation::cur()); - cb.condition(is_baseline_marked.expr(), |cb| { - cb.require_equal( - "baseline == 0x00", - meta.query_advice(table.baseline, Rotation::cur()), - 0x00.expr(), - ); - }); - - cb.condition(not::expr(is_baseline_marked.expr()), |cb| { - cb.require_equal( - "baseline == last_baseline + smallest_spot", - meta.query_advice(table.baseline, Rotation::cur()), - meta.query_advice(table.last_baseline, Rotation::cur()) - + meta.query_advice(table.smallest_spot, Rotation::cur()), - ); - }); - - let symbol_prev = meta.query_advice(table.symbol, Rotation::prev()); - let symbol_cur = meta.query_advice(table.symbol, Rotation::cur()); - cb.gate(and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - not::expr( - table - .symbol_eq - .expr_at(meta, Rotation::prev(), symbol_prev, symbol_cur), - ), - ])) - }); - - debug_assert!(meta.degree() <= 9); - - table - } - - /// Load witness. - pub fn assign( - &self, - layouter: &mut impl Layouter, - data: Vec, - ) -> Result<(), Error> { - layouter.assign_region( - || "FseAuxiliaryTable: dev load", - |mut region| { - let mut offset = 0; - for table in data.iter() { - let byte_offset = Value::known(F::from(table.byte_offset)); - let table_size = Value::known(F::from(table.table_size)); - let table_size_rs_1 = Value::known(F::from(table.table_size >> 1)); - let table_size_rs_3 = Value::known(F::from(table.table_size >> 3)); - for (&symbol, rows) in table.sym_to_states.iter() { - let symbol_count = rows.len() as u64; - let smallest_spot = rows - .iter() - .map(|fse_row| 1 << fse_row.num_bits) - .min() - .expect("symbol should have at least 1 row"); - let spot_acc_iter = rows.iter().scan(0, |spot_acc, fse_row| { - *spot_acc += 1 << fse_row.num_bits; - Some(*spot_acc) - }); - // TODO: byte_offset_cmp - // TODO: symbol_eq - // TODO: baseline_mark - // TODO: last_baseline - // TODO: q_enabled - for (i, (fse_row, spot_acc)) in rows.iter().zip(spot_acc_iter).enumerate() { - for (annotation, col, value) in [ - ("byte_offset", self.byte_offset, byte_offset), - ("table_size", self.table_size, table_size), - ("table_size_rs_1", self.table_size_rs_1, table_size_rs_1), - ("table_size_rs_3", self.table_size_rs_3, table_size_rs_3), - ("symbol", self.symbol, Value::known(F::from(symbol as u64))), - ( - "symbol_count", - self.symbol_count, - Value::known(F::from(symbol_count)), - ), - ( - "symbol_count_acc", - self.symbol_count_acc, - Value::known(F::from(i as u64 + 1)), - ), - ("state", self.state, Value::known(F::from(fse_row.state))), - ( - "baseline", - self.baseline, - Value::known(F::from(fse_row.baseline)), - ), - ("nb", self.nb, Value::known(F::from(fse_row.num_bits))), - ( - "spot", - self.spot, - Value::known(F::from(1 << fse_row.num_bits)), - ), - ( - "smallest_spot", - self.smallest_spot, - Value::known(F::from(smallest_spot)), - ), - ("spot_acc", self.spot_acc, Value::known(F::from(spot_acc))), - ("idx", self.idx, Value::known(F::from(fse_row.idx))), - ] { - region.assign_advice( - || format!("FseAuxiliaryTable: {}", annotation), - col, - offset, - || value, - )?; - } - offset += 1; - } - } - } - - Ok(()) - }, - ) - } -} - -impl FseTable { - /// Lookup table expressions for (state, symbol) tuple check. - pub fn table_exprs_state_check(&self, meta: &mut VirtualCells) -> Vec> { - vec![ - meta.query_advice(self.byte_offset, Rotation::cur()), - meta.query_advice(self.table_size, Rotation::cur()), - meta.query_advice(self.state, Rotation::cur()), - meta.query_advice(self.symbol, Rotation::cur()), - meta.query_advice(self.baseline, Rotation::cur()), - meta.query_advice(self.nb, Rotation::cur()), - ] - } - - /// Lookup table expressions for (symbol, symbol_count) tuple check. - pub fn table_exprs_symbol_count_check(&self, meta: &mut VirtualCells) -> Vec> { - vec![ - meta.query_advice(self.byte_offset, Rotation::cur()), - meta.query_advice(self.table_size, Rotation::cur()), - meta.query_advice(self.symbol, Rotation::cur()), - meta.query_advice(self.symbol_count, Rotation::cur()), - ] - } -} - -/// The Huffman codes table maps the canonical weights (symbols as per FseTable) to the Huffman -/// codes. -#[derive(Clone, Debug)] -pub struct HuffmanCodesTable { - /// Fixed column to denote whether the constraints will be enabled or not. - pub q_enabled: Column, - /// Fixed column to mark the first row in the table. - pub q_first: Column, - /// Set when this is the start of a new huffman code. - pub is_start: Column, - /// The byte offset within the data instance where the encoded FSE table begins. This is - /// 1-indexed, i.e. byte_offset == 1 at the first byte. - pub byte_offset: Column, - /// Helper gadget to know when we are done handling a single canonical Huffman code. - pub byte_offset_cmp: ComparatorConfig, - /// The byte that is being encoded by a Huffman code. - pub symbol: Column, - /// The weight assigned to this symbol as per the canonical Huffman code weights. - pub weight: Column, - /// A binary representation of the weight's value. - pub weight_bits: BinaryNumberConfig, - /// An accumulator over the weight values. - pub weight_acc: Column, - /// Helper column to denote 2 ^ (weight - 1). - pub pow2_weight: Column, - /// The sum of canonical Huffman code weights. This value does not change over the rows for a - /// specific Huffman code. - pub sum_weights: Column, - /// The maximum length of a bitstring as per this Huffman code. Again, this value does not - /// change over the rows for a specific Huffman code. - pub max_bitstring_len: Column, - /// As per Huffman coding, every symbol is mapped to a bit value, which is then represented in - /// binary form (padded) of length bitstring_len. - pub bit_value: Column, - /// The last seen bit_value for each symbol in this Huffman coding. - pub last_bit_values: [Column; N_MAX_SYMBOLS], - /// The last_bit_values assigned at the first row of a table. - pub first_lbvs: [Column; N_MAX_SYMBOLS], -} - -impl HuffmanCodesTable { - /// Construct the huffman codes table. - pub fn construct( - meta: &mut ConstraintSystem, - pow2_table: Pow2Table, - u8_table: U8Table, - ) -> Self { - let q_enabled = meta.fixed_column(); - let byte_offset = meta.advice_column(); - let weight = meta.advice_column(); - let table = Self { - q_enabled, - q_first: meta.fixed_column(), - byte_offset, - byte_offset_cmp: ComparatorChip::configure( - meta, - |meta| meta.query_fixed(q_enabled, Rotation::cur()), - |meta| meta.query_advice(byte_offset, Rotation::cur()), - |meta| meta.query_advice(byte_offset, Rotation::next()), - u8_table.into(), - ), - is_start: meta.advice_column(), - symbol: meta.advice_column(), - weight, - weight_bits: BinaryNumberChip::configure(meta, q_enabled, Some(weight.into())), - pow2_weight: meta.advice_column(), - weight_acc: meta.advice_column(), - sum_weights: meta.advice_column(), - max_bitstring_len: meta.advice_column(), - bit_value: meta.advice_column(), - last_bit_values: array_init(|_| meta.advice_column()), - first_lbvs: array_init(|_| meta.advice_column()), - }; - - // TODO: constrain is_start - - // All rows - meta.create_gate("HuffmanCodesTable: all rows", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - let (gt, eq) = table.byte_offset_cmp.expr(meta, None); - cb.require_equal("byte_offset' >= byte_offset", gt + eq, 1.expr()); - - // Weight == 0 implies the bit value is 0. - cb.condition( - table - .weight_bits - .value_equals(FseSymbol::S0, Rotation::cur())(meta), - |cb| { - cb.require_zero( - "bit value == 0", - meta.query_advice(table.bit_value, Rotation::cur()), - ); - }, - ); - - // Last bit value at weight == 0 is also 0. - cb.require_zero( - "last_bit_values[0] == 0", - meta.query_advice( - table.last_bit_values[FseSymbol::S0 as usize], - Rotation::cur(), - ), - ); - - cb.gate(meta.query_fixed(table.q_enabled, Rotation::cur())) - }); - - // The first row of the HuffmanCodesTable. - meta.create_gate("HuffmanCodesTable: first (fixed) row", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // Canonical Huffman code starts with the weight of the first symbol, i.e. 0x00. - cb.require_equal( - "symbol == 0x00", - meta.query_advice(table.symbol, Rotation::cur()), - 0x00.expr(), - ); - - // Weight accumulation starts with the first weight. - cb.require_equal( - "weight_acc == 2^(weight - 1)", - meta.query_advice(table.weight_acc, Rotation::cur()), - meta.query_advice(table.pow2_weight, Rotation::cur()), - ); - - // Constrain the last bit_value of the maximum bitstring length. Maximum bitstring - // length implies weight == 1. - cb.require_zero( - "if first row: last_bit_values[1] == 0", - meta.query_advice( - table.last_bit_values[FseSymbol::S1 as usize], - Rotation::cur(), - ), - ); - - // Do an equality check for the last_bit_values at the first row. - for i in FseSymbol::iter() { - cb.require_equal( - "last bit value at the first row equality check", - meta.query_advice(table.last_bit_values[i as usize], Rotation::cur()), - meta.query_advice(table.first_lbvs[i as usize], Rotation::cur()), - ); - } - - cb.gate(and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - meta.query_fixed(table.q_first, Rotation::cur()), - ])) - }); - - // While we are processing the weights of a particular canonical Huffman code - // representation, i.e. byte_offset == byte_offset'. - meta.create_gate( - "HuffmanCodesTable: traversing a canonical huffman coding table", - |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // Sum of weights remains the same across all rows. - cb.require_equal( - "sum_weights' == sum_weights", - meta.query_advice(table.sum_weights, Rotation::next()), - meta.query_advice(table.sum_weights, Rotation::cur()), - ); - - // Maximum bitstring length remains the same across all rows. - cb.require_equal( - "max_bitstring_len' == max_bitstring_len", - meta.query_advice(table.max_bitstring_len, Rotation::next()), - meta.query_advice(table.max_bitstring_len, Rotation::cur()), - ); - - // The first row's last_bit_values remain the same. - for col in table.first_lbvs { - cb.require_equal( - "first_lbvs[i]' == first_lbvs[i]", - meta.query_advice(col, Rotation::next()), - meta.query_advice(col, Rotation::cur()), - ); - } - - // Weight accumulation is assigned correctly. - cb.require_equal( - "weight_acc' == weight_acc + 2^(weight - 1)", - meta.query_advice(table.weight_acc, Rotation::next()), - meta.query_advice(table.weight_acc, Rotation::cur()) - + meta.query_advice(table.pow2_weight, Rotation::next()), - ); - - // pow2_weight is assigned correctly for weight == 0. - cb.condition( - table - .weight_bits - .value_equals(FseSymbol::S0, Rotation::cur())(meta), - |cb| { - cb.require_zero( - "pow2_weight == 0 if weight == 0", - meta.query_advice(table.pow2_weight, Rotation::cur()), - ); - }, - ); - - // For all rows (except the first row of a canonical Huffman code representation, we - // want to ensure the last_bit_values was assigned correctly. - let is_start = meta.query_advice(table.is_start, Rotation::cur()); - cb.condition(not::expr(is_start.expr()), |cb| { - for (symbol, &last_bit_value) in - FseSymbol::iter().zip(table.last_bit_values.iter()) - { - cb.require_equal( - "last_bit_value_i::cur == last_bit_value::prev + (weight::cur == i)", - meta.query_advice(last_bit_value, Rotation::cur()), - meta.query_advice(last_bit_value, Rotation::prev()) - + table.weight_bits.value_equals(symbol, Rotation::cur())(meta), - ); - } - }); - - let (_gt, eq) = table.byte_offset_cmp.expr(meta, None); - cb.gate(and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - eq, - ])) - }, - ); - - // For every row, we want the pow2_weight column to be assigned correctly. We want: - // - // pow2_weight == 2^(weight - 1). - // - // Note that this is valid only if weight > 0. For weight == 0, we want pow2_weight == 0. - meta.lookup_any("HuffmanCodesTable: pow2_weight assignment", |meta| { - let condition = and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - not::expr(table - .weight_bits - .value_equals(FseSymbol::S0, Rotation::cur())( - meta - )), - // TODO: add padding column. - ]); - - let exponent = meta.query_advice(table.weight, Rotation::cur()) - 1.expr(); - let exponentiation = meta.query_advice(table.pow2_weight, Rotation::cur()); - - [exponent, exponentiation] - .into_iter() - .zip(pow2_table.table_exprs(meta)) - .map(|(input, table)| (input * condition.clone(), table)) - .collect::>() - }); - - // When we end processing a huffman code, i.e. the byte_offset changes. No need to check if - // the next row is padding or not. - meta.create_gate("HuffmanCodesTable: end of huffman code", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // The total sum of weights is in fact the accumulated weight. - cb.require_equal( - "sum_weights == weight_acc", - meta.query_advice(table.sum_weights, Rotation::cur()), - meta.query_advice(table.weight_acc, Rotation::cur()), - ); - - // We want to check the following: - // - // if lbv_1: The last bit_value for weight i on the first row. - // if lbv_2: The last bit_value for weight i+1 on the last row. - // - // then lbv_2 == (lbv_1 + 1) // 2 - // i.e. lbv_2 * 2 - lbv_1 is boolean. - // - // Note: we only do this check for weight > 0, hence we skip the FseSymbol::S0. - for i in [ - FseSymbol::S1, - FseSymbol::S2, - FseSymbol::S3, - FseSymbol::S4, - FseSymbol::S5, - FseSymbol::S6, - ] { - let i = i as usize; - let lbv_1 = meta.query_advice(table.first_lbvs[i], Rotation::cur()); - let lbv_2 = meta.query_advice(table.last_bit_values[i + 1], Rotation::cur()); - cb.require_boolean( - "last bit value check for weights i and i+1 on the first and last rows", - lbv_2 * 2.expr() - lbv_1, - ); - } - - let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); - cb.gate(and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - gt, - ])) - }); - - // The weight for the last symbol is assigned appropriately. The weight for the last - // symbol should satisfy: - // - // last_weight == log2(nearest_pow2 - sum_weights) + 1 - // where nearest_pow2 is the nearest power of 2 greater than the sum of weights so far. - // - // i.e. 2^(last_weight - 1) + sum_weights == 2^(max_bitstring_len) - meta.lookup_any("HuffmanCodesTable: weight of the last symbol", |meta| { - let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); - let condition = and::expr([meta.query_fixed(table.q_enabled, Rotation::cur()), gt]); - - let exponent = meta.query_advice(table.max_bitstring_len, Rotation::cur()); - let exponentiation = meta.query_advice(table.pow2_weight, Rotation::cur()) - + meta.query_advice(table.sum_weights, Rotation::prev()); - - [exponent, exponentiation] - .into_iter() - .zip(pow2_table.table_exprs(meta)) - .map(|(input, table)| (input * condition.clone(), table)) - .collect::>() - }); - - // When we transition from one Huffman code to another, i.e. the byte_offset changes. We - // also check that the next row is not a padding row. - // - // TODO: add the padding column. - meta.create_gate("HuffmanCodesTable: new huffman code", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // Marks the start of a new huffman code. - cb.require_equal( - "is_start == 1", - meta.query_advice(table.is_start, Rotation::next()), - 1.expr(), - ); - - // Canonical Huffman code starts with the weight of the first symbol, i.e. 0x00. - cb.require_equal( - "symbol == 0x00", - meta.query_advice(table.symbol, Rotation::next()), - 0x00.expr(), - ); - - // Weight accumulation starts with the first weight. - cb.require_equal( - "weight_acc == 2^(weight - 1)", - meta.query_advice(table.weight_acc, Rotation::next()), - meta.query_advice(table.pow2_weight, Rotation::next()), - ); - - // Constrain the last bit_value of the maximum bitstring length. Maximum bitstring - // length implies weight == 1. - cb.require_zero( - "if first row: last_bit_values[1] == 0", - meta.query_advice( - table.last_bit_values[FseSymbol::S1 as usize], - Rotation::next(), - ), - ); - - // Do an equality check for the last_bit_values at the first row. - for i in FseSymbol::iter() { - cb.require_equal( - "last bit value at the first row equality check", - meta.query_advice(table.last_bit_values[i as usize], Rotation::next()), - meta.query_advice(table.first_lbvs[i as usize], Rotation::next()), - ); - } - - let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); - cb.gate(and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - meta.query_fixed(table.q_enabled, Rotation::next()), - gt, - ])) - }); - - debug_assert!(meta.degree() <= 9); - - table - } - - /// Load witness to the huffman codes table: dev mode. - pub fn assign( - &self, - layouter: &mut impl Layouter, - data: Vec, - ) -> Result<(), Error> { - layouter.assign_region( - || "HuffmanCodesTable: dev load", - |mut region| { - let weight_bits = BinaryNumberChip::construct(self.weight_bits); - let mut offset = 0; - for code in data.iter() { - let byte_offset = Value::known(F::from(code.byte_offset)); - let (max_bitstring_len, sym_map) = code.parse_canonical(); - - let max_bitstring_len = Value::known(F::from(max_bitstring_len)); - let sum_weights = Value::known(F::from( - sym_map - .values() - .map(|(weight, _bit_value)| weight) - .sum::(), - )); - let weight_acc_iter = sym_map.values().scan(0, |acc, (weight, _bit_value)| { - *acc += weight; - Some(*acc) - }); - - for (i, weight_acc) in weight_acc_iter.enumerate() { - region.assign_advice( - || "HuffmanCodesTable: weight_acc", - self.weight_acc, - offset + i, - || Value::known(F::from(weight_acc)), - )?; - } - for (&symbol, &(weight, bit_value)) in sym_map.iter() { - for (annotation, column, value) in [ - ("byte_offset", self.byte_offset, byte_offset), - ( - "max_bitstring_len", - self.max_bitstring_len, - max_bitstring_len, - ), - ("sum_weights", self.sum_weights, sum_weights), - ("symbol", self.symbol, Value::known(F::from(symbol))), - ("weight", self.weight, Value::known(F::from(weight))), - ( - "bit_value", - self.bit_value, - Value::known(F::from(bit_value)), - ), - ( - "pow2_weight", - self.pow2_weight, - Value::known(F::from(if weight > 0 { - (weight - 1).pow(2) - } else { - 0 - })), - ), - ] { - region.assign_advice( - || format!("HuffmanCodesTable: {annotation}"), - column, - offset, - || value, - )?; - } - let fse_symbol: FseSymbol = (weight as usize).into(); - weight_bits.assign(&mut region, offset, &fse_symbol)?; - - offset += 1; - } - - // TODO: assign last_bit_values - } - - // Assign the byte offset comparison gadget. - let cmp_chip = ComparatorChip::construct(self.byte_offset_cmp.clone()); - offset = 0; - - // if there is a single table. - if data.len() == 1 { - let byte_offset = data[0].byte_offset; - let n_rows = data[0].weights.len() + 1; - for _ in 0..n_rows - 1 { - cmp_chip.assign( - &mut region, - offset, - F::from(byte_offset), - F::from(byte_offset), - )?; - offset += 1; - } - cmp_chip.assign(&mut region, offset, F::from(byte_offset), F::zero())?; - } - - // if there are multiple tables. - if data.len() > 1 { - for window in data.windows(2) { - let byte_offset_1 = window[0].byte_offset; - let byte_offset_2 = window[1].byte_offset; - let n_rows = window[0].weights.len() + 1; - for _ in 0..n_rows - 1 { - cmp_chip.assign( - &mut region, - offset, - F::from(byte_offset_1), - F::from(byte_offset_1), - )?; - offset += 1; - } - cmp_chip.assign( - &mut region, - offset, - F::from(byte_offset_1), - F::from(byte_offset_2), - )?; - offset += 1; - } - // handle the last table. - if let Some(last_table) = data.last() { - let byte_offset = last_table.byte_offset; - let n_rows = last_table.weights.len() + 1; - for _ in 0..n_rows - 1 { - cmp_chip.assign( - &mut region, - offset, - F::from(byte_offset), - F::from(byte_offset), - )?; - offset += 1; - } - cmp_chip.assign(&mut region, offset, F::from(byte_offset), F::zero())?; - } - } - - Ok(()) - }, - ) - } -} - -impl HuffmanCodesTable { - /// Lookup the canonical weight assigned to a symbol in the Huffman code with the header at - /// the given byte_offset. - pub fn table_exprs_canonical_weight(&self, meta: &mut VirtualCells) -> Vec> { - vec![ - meta.query_advice(self.byte_offset, Rotation::cur()), - meta.query_advice(self.symbol, Rotation::cur()), - meta.query_advice(self.weight, Rotation::cur()), - ] - } - - /// Lookup the number of symbols that are present in the canonical representation of the - /// Huffman code. - pub fn table_exprs_weights_count(&self, meta: &mut VirtualCells) -> Vec> { - vec![ - meta.query_advice(self.byte_offset, Rotation::cur()), - meta.query_advice(self.symbol, Rotation::cur()), - // TODO: add is_last to mark the last row of a specific Huffman code. - ] - } -} - -/// An auxiliary table for the Huffman Codes. In Huffman coding a symbol (byte) is mapped to a -/// bitstring of particular length such that more frequently occuring symbols are mapped to -/// bitstrings of smaller lengths. -/// -/// We already have the symbols and their bit_value in the HuffmanCodesTable. However, we still -/// need to validate that the bit_value is in fact assigned correctly. Since bitstrings may not be -/// byte-aligned, i.e. a bitstring can span over 2 bytes (assuming a maximum bitstring length of 8) -/// we need to make sure that the bit_value is in fact the binary value represented by the bits of -/// that bitstring. -#[derive(Clone, Debug)] -pub struct BitstringAccumulationTable { - /// Fixed column to denote whether the constraints will be enabled or not. - pub q_enabled: Column, - /// The byte offset within the data instance where the encoded FSE table begins. This is - /// 1-indexed, i.e. byte_offset == 1 at the first byte. - pub byte_offset: Column, - /// The byte offset of byte_1 in the zstd encoded data. byte_idx' == byte_idx - /// while 0 <= bit_index < 15. At bit_index == 15, byte_idx' == byte_idx + 1. - pub byte_idx_1: Column, - /// The byte offset of byte_2 in the zstd encoded data. byte_idx' == byte_idx - /// while 0 <= bit_index < 15. At bit_index == 15, byte_idx' == byte_idx + 1. - /// - /// We also have byte_idx_2 == byte_idx_1 + 1. - pub byte_idx_2: Column, - /// The byte value at byte_idx_1. - pub byte_1: Column, - /// The byte value at byte_idx_2. - pub byte_2: Column, - /// The index within these 2 bytes, i.e. 0 <= bit_index <= 15. bit_index increments until its - /// 15 and then is reset to 0. Repeats while we finish bitstring accumulation of all bitstrings - /// used in the Huffman codes. - pub bit_index: Column, - /// Helper column to know the start of a new chunk of 2 bytes, this is a fixed column as well - /// as it is set only on bit_index == 0. - pub q_first: Column, - /// The bit at bit_index. Accumulation of bits from 0 <= bit_index <= 7 denotes byte_1. - /// Accumulation of 8 <= bit_index <= 15 denotes byte_2. - pub bit: Column, - /// The final value of the bit accumulation for the set bits. - pub bit_value: Column, - /// The length of the bitstring, i.e. the number of bits that were set. - pub bitstring_len: Column, - /// The accumulator over bits from is_start to is_end, i.e. while is_set == 1. - pub bit_value_acc: Column, - /// Boolean that is set from start of bit chunk to bit_index == 15. - pub from_start: Column, - /// Boolean that is set from bit_index == 0 to end of bit chunk. - pub until_end: Column, - /// Boolean to mark if the bitstring is a part of bytes that are read from front-to-back or - /// back-to-front. For the back-to-front case, the is_reverse boolean is set. - pub is_reverse: Column, -} - -impl BitstringAccumulationTable { - /// Construct the bitstring accumulation table. - pub fn construct(meta: &mut ConstraintSystem) -> Self { - let q_enabled = meta.fixed_column(); - let table = Self { - q_enabled, - byte_offset: meta.advice_column(), - byte_idx_1: meta.advice_column(), - byte_idx_2: meta.advice_column(), - byte_1: meta.advice_column(), - byte_2: meta.advice_column(), - bit_index: meta.fixed_column(), - q_first: meta.fixed_column(), - bit: meta.advice_column(), - bit_value: meta.advice_column(), - bitstring_len: meta.advice_column(), - bit_value_acc: meta.advice_column(), - from_start: meta.advice_column(), - until_end: meta.advice_column(), - is_reverse: meta.advice_column(), - }; - - meta.create_gate("BitstringAccumulationTable: bit_index == 0", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - let bits = (0..16) - .map(|i| meta.query_advice(table.bit, Rotation(i))) - .collect::>>(); - - cb.require_equal( - "byte1 is the binary accumulation of 0 <= bit_index <= 7", - meta.query_advice(table.byte_1, Rotation::cur()), - select::expr( - meta.query_advice(table.is_reverse, Rotation::cur()), - bits[7].expr() - + bits[6].expr() * 2.expr() - + bits[5].expr() * 4.expr() - + bits[4].expr() * 8.expr() - + bits[3].expr() * 16.expr() - + bits[2].expr() * 32.expr() - + bits[1].expr() * 64.expr() - + bits[0].expr() * 128.expr(), - bits[0].expr() - + bits[1].expr() * 2.expr() - + bits[2].expr() * 4.expr() - + bits[3].expr() * 8.expr() - + bits[4].expr() * 16.expr() - + bits[5].expr() * 32.expr() - + bits[6].expr() * 64.expr() - + bits[7].expr() * 128.expr(), - ), - ); - - cb.require_equal( - "byte2 is the binary accumulation of 8 <= bit_index <= 15", - meta.query_advice(table.byte_2, Rotation::cur()), - select::expr( - meta.query_advice(table.is_reverse, Rotation::cur()), - bits[15].expr() - + bits[14].expr() * 2.expr() - + bits[13].expr() * 4.expr() - + bits[12].expr() * 8.expr() - + bits[11].expr() * 16.expr() - + bits[10].expr() * 32.expr() - + bits[9].expr() * 64.expr() - + bits[8].expr() * 128.expr(), - bits[8].expr() - + bits[9].expr() * 2.expr() - + bits[10].expr() * 4.expr() - + bits[11].expr() * 8.expr() - + bits[12].expr() * 16.expr() - + bits[13].expr() * 32.expr() - + bits[14].expr() * 64.expr() - + bits[15].expr() * 128.expr(), - ), - ); - - cb.require_boolean( - "is_reverse is boolean", - meta.query_advice(table.is_reverse, Rotation::cur()), - ); - - // TODO: Possibly exclude jump table bytes as they create a gap in byte_idx between - // huffman code and lstreams - cb.require_boolean( - "byte2 == byte1 or byte2 == byte1 + 1", - meta.query_advice(table.byte_idx_2, Rotation::cur()) - - meta.query_advice(table.byte_idx_1, Rotation::cur()), - ); - - cb.gate(and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - meta.query_fixed(table.q_first, Rotation::cur()), - ])) - }); - - debug_assert!(meta.degree() <= 9); - - meta.create_gate("BitstringAccumulationTable: bit_index > 0", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // Constrain columns that are unchanged from 0 < bit_idx < 16. - for col in [ - table.byte_offset, - table.byte_idx_1, - table.byte_idx_2, - table.byte_1, - table.byte_2, - table.bit_value, - table.is_reverse, - ] { - cb.require_equal( - "unchanged columns from 0 < bit_idx < 16", - meta.query_advice(col, Rotation::cur()), - meta.query_advice(col, Rotation::prev()), - ); - } - - let is_last = meta.query_fixed(table.q_first, Rotation::next()); - cb.condition(is_last, |cb| { - cb.require_equal( - "byte_idx_1' == byte_idx_2", - meta.query_advice(table.byte_idx_1, Rotation::next()), - meta.query_advice(table.byte_idx_2, Rotation::cur()), - ); - }); - - cb.gate(and::expr([ - meta.query_fixed(table.q_enabled, Rotation::cur()), - not::expr(meta.query_fixed(table.q_first, Rotation::cur())), - ])) - }); - - debug_assert!(meta.degree() <= 9); - - // Consider a bit chunk from bit_index == 4 to bit_index == 9. We will have: - // - // | bit index | from start | until end | bitstring len | bit | bit value acc | - // |-----------|------------|-----------|---------------|-----|---------------| - // | 0 | 1 | 0 | 0 | 0 | 0 | - // | 1 | 1 | 0 | 0 | 0 | 0 | - // | 2 | 1 | 0 | 0 | 1 | 0 | - // | 3 | 1 | 0 | 0 | 0 | 0 | - // | 4 -> | 1 | 1 | 1 | 1 | 1 | - // | 5 -> | 1 | 1 | 2 | 0 | 1 | - // | 6 -> | 1 | 1 | 3 | 1 | 5 | - // | 7 -> | 1 | 1 | 4 | 1 | 13 | - // | 8 -> | 1 | 1 | 5 | 0 | 13 | - // | 9 -> | 1 | 1 | 6 | 1 | 45 | - // | 10 | 0 | 1 | 6 | 0 | 45 | - // | 11 | 0 | 1 | 6 | 0 | 45 | - // | 12 | 0 | 1 | 6 | 0 | 45 | - // | 13 | 0 | 1 | 6 | 1 | 45 | - // | 14 | 0 | 1 | 6 | 1 | 45 | - // | 15 | 0 | 1 | 6 | 0 | 45 | - // - // The bits for the bitstring are where from_start == until_end == 1. - meta.create_gate("BitstringAccumulationTable: bit value", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - // Columns from_start and until_end are boolean. - cb.require_boolean( - "from_start is boolean", - meta.query_advice(table.from_start, Rotation::cur()), - ); - cb.require_boolean( - "until_end is boolean", - meta.query_advice(table.until_end, Rotation::cur()), - ); - - // Column from_start transitions from 1 to 0 only once. - let is_first = meta.query_fixed(table.q_first, Rotation::cur()); - cb.condition(is_first.expr(), |cb| { - cb.require_equal( - "if q_first == True: from_start == 1", - meta.query_advice(table.from_start, Rotation::cur()), - 1.expr(), - ); - }); - cb.condition(not::expr(is_first.expr()), |cb| { - cb.require_boolean( - "from_start transitions from 1 to 0 only once", - meta.query_advice(table.from_start, Rotation::prev()) - - meta.query_advice(table.from_start, Rotation::cur()), - ); - }); - - // Column until_end transitions from 0 to 1 only once. - let is_last = meta.query_fixed(table.q_first, Rotation::next()); - cb.condition(is_last.expr(), |cb| { - cb.require_equal( - "if q_first::next == True: until_end == 1", - meta.query_advice(table.until_end, Rotation::cur()), - 1.expr(), - ); - }); - cb.condition(not::expr(is_last.expr()), |cb| { - cb.require_boolean( - "until_end transitions from 0 to 1 only once", - meta.query_advice(table.until_end, Rotation::next()) - - meta.query_advice(table.until_end, Rotation::cur()), - ); - }); - - // Constraints at meaningful bits. - let is_set = and::expr([ - meta.query_advice(table.from_start, Rotation::cur()), - meta.query_advice(table.until_end, Rotation::cur()), - ]); - cb.condition(is_first.expr() * is_set.expr(), |cb| { - cb.require_equal( - "if is_first && is_set: bit == bit_value_acc", - meta.query_advice(table.bit, Rotation::cur()), - meta.query_advice(table.bit_value_acc, Rotation::cur()), - ); - cb.require_equal( - "if is_first && is_set: bitstring_len == 1", - meta.query_advice(table.bitstring_len, Rotation::cur()), - 1.expr(), - ); - }); - cb.condition(not::expr(is_first) * is_set, |cb| { - cb.require_equal( - "is_set: bit_value_acc == bit_value_acc::prev * 2 + bit", - meta.query_advice(table.bit_value_acc, Rotation::cur()), - meta.query_advice(table.bit_value_acc, Rotation::prev()) * 2.expr() - + meta.query_advice(table.bit, Rotation::cur()), - ); - cb.require_equal( - "is_set: bitstring_len == bitstring_len::prev + 1", - meta.query_advice(table.bitstring_len, Rotation::cur()), - meta.query_advice(table.bitstring_len, Rotation::prev()) + 1.expr(), - ); - }); - - // Constraints at bits to be ignored (at the start). - let is_ignored = not::expr(meta.query_advice(table.until_end, Rotation::cur())); - cb.condition(is_ignored, |cb| { - cb.require_zero( - "while until_end == 0: bitstring_len == 0", - meta.query_advice(table.bitstring_len, Rotation::cur()), - ); - cb.require_zero( - "while until_end == 0: bit_value_acc == 0", - meta.query_advice(table.bit_value_acc, Rotation::cur()), - ); - }); - - // Constraints at bits to be ignored (towards the end). - let is_ignored = not::expr(meta.query_advice(table.from_start, Rotation::cur())); - cb.condition(is_ignored, |cb| { - cb.require_equal( - "bitstring_len unchanged at the last ignored bits", - meta.query_advice(table.bitstring_len, Rotation::cur()), - meta.query_advice(table.bitstring_len, Rotation::prev()), - ); - cb.require_equal( - "bit_value_acc unchanged at the last ignored bits", - meta.query_advice(table.bit_value_acc, Rotation::cur()), - meta.query_advice(table.bit_value_acc, Rotation::prev()), - ); - }); - - cb.gate(meta.query_fixed(table.q_enabled, Rotation::cur())) - }); - - debug_assert!(meta.degree() <= 9); - - table - } - - /// Load witness to the table: dev mode. - pub fn assign( - &self, - layouter: &mut impl Layouter, - witness_rows: &[ZstdWitnessRow], - ) -> Result<(), Error> { - assert!(!witness_rows.is_empty()); - - // Get the byte at which FSE is described - // TODO: Determining huffman offset in a multi-block scenario. - let huffman_offset = witness_rows - .iter() - .find(|&r| r.state.tag == ZstdTag::ZstdBlockFseCode) - .unwrap() - .encoded_data - .byte_idx; - - // Extract bit accumulation-related info from the rows - let accumulation_rows = witness_rows - .iter() - .filter(|&r| { - r.state.tag == ZstdTag::ZstdBlockFseCode - || r.state.tag == ZstdTag::ZstdBlockHuffmanCode - || r.state.tag == ZstdTag::ZstdBlockJumpTable - || r.state.tag == ZstdTag::ZstdBlockLstream - }) - .map(|r| { - ( - r.encoded_data.byte_idx as usize, - r.encoded_data.value_byte as u64, - r.bitstream_read_data.bit_start_idx, - r.bitstream_read_data.bit_end_idx, - r.bitstream_read_data.bit_value, - r.state.tag.is_reverse() as u64, // is_reverse - ) - }) - .collect::>(); - - layouter.assign_region( - || "Bitstring Accumulation Table", - |mut region| { - let mut offset: usize = 0; - let mut last_byte_idx: usize = 0; - for rows in accumulation_rows.windows(2) { - let row = rows[0]; - let next_row = rows[1]; - let byte_1_bits = value_bits_le(row.1 as u8); - let byte_2_bits = value_bits_le(next_row.1 as u8); - let bits = if row.5 > 0 { - // reversed - [ - byte_1_bits.into_iter().rev().collect::>(), - byte_2_bits.into_iter().rev().collect::>(), - ] - .concat() - } else { - // not reversed - [byte_1_bits, byte_2_bits].concat() - }; - - let mut acc: u64 = 0; - let mut bitstring_len: u64 = 0; - - for (bit_idx, bit) in bits.into_iter().enumerate().take(16) { - region.assign_fixed( - || "q_enable", - self.q_enabled, - offset + bit_idx, - || Value::known(F::one()), - )?; - region.assign_advice( - || "byte_offset", - self.byte_offset, - offset + bit_idx, - || Value::known(F::from(huffman_offset)), - )?; - region.assign_advice( - || "byte_idx_1", - self.byte_idx_1, - offset + bit_idx, - || Value::known(F::from(row.0 as u64)), - )?; - region.assign_advice( - || "byte_idx_2", - self.byte_idx_2, - offset + bit_idx, - || Value::known(F::from(next_row.0 as u64)), - )?; - region.assign_advice( - || "byte_1", - self.byte_1, - offset + bit_idx, - || Value::known(F::from(row.1)), - )?; - region.assign_advice( - || "byte_2", - self.byte_2, - offset + bit_idx, - || Value::known(F::from(next_row.1)), - )?; - region.assign_fixed( - || "bit_index", - self.bit_index, - offset + bit_idx, - || Value::known(F::from(bit_idx as u64)), - )?; - region.assign_fixed( - || "q_first", - self.q_first, - offset + bit_idx, - || Value::known(F::from((bit_idx == 0) as u64)), - )?; - - if bit_idx >= row.2 && bit_idx <= row.3 { - acc = acc * 2 + (bit as u64); - bitstring_len += 1; - } - region.assign_advice( - || "bit", - self.bit, - offset + bit_idx, - || Value::known(F::from(bit as u64)), - )?; - region.assign_advice( - || "bit_value_acc", - self.bit_value_acc, - offset + bit_idx, - || Value::known(F::from(acc)), - )?; - region.assign_advice( - || "bit_value", - self.bit_value, - offset + bit_idx, - || Value::known(F::from(row.4)), - )?; - region.assign_advice( - || "bitstring_len", - self.bitstring_len, - offset + bit_idx, - || Value::known(F::from(bitstring_len)), - )?; - region.assign_advice( - || "from_start", - self.from_start, - offset + bit_idx, - || Value::known(F::from((bit_idx <= row.3) as u64)), - )?; - region.assign_advice( - || "until_end", - self.until_end, - offset + bit_idx, - || Value::known(F::from((bit_idx >= row.2) as u64)), - )?; - region.assign_advice( - || "is_reverse", - self.is_reverse, - offset + bit_idx, - || Value::known(F::from(row.5)), - )?; - } - - offset += 16; - last_byte_idx = next_row.0; - } - - region.assign_fixed( - || "q_first", - self.q_first, - offset, - || Value::known(F::one()), - )?; - region.assign_advice( - || "byte_idx_1", - self.byte_idx_1, - offset, - || Value::known(F::from(last_byte_idx as u64)), - )?; - - Ok(()) - }, - )?; - - Ok(()) - } -} - -impl LookupTable for BitstringAccumulationTable { - fn columns(&self) -> Vec> { - vec![ - self.byte_offset.into(), - self.byte_idx_1.into(), - self.byte_idx_2.into(), - self.byte_1.into(), - self.byte_2.into(), - self.bit_value.into(), - self.bitstring_len.into(), - self.bit_index.into(), - self.from_start.into(), - self.until_end.into(), - self.is_reverse.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("byte_offset"), - String::from("byte_idx_1"), - String::from("byte_idx_2"), - String::from("byte_1"), - String::from("byte_2"), - String::from("bit_value"), - String::from("bitstring_len"), - String::from("bit_index"), - String::from("from_start"), - String::from("until_end"), - String::from("is_reverse"), - ] - } -} - -/// Different branches that can be taken while calculating regenerated size and compressed size in -/// the Literals Header. -#[derive(Clone, Copy, Debug, EnumIter)] -pub enum LiteralsHeaderBranch { - /// Raw/RLE block type with size_format 00 or 10. - RawRle0 = 0, - /// Raw/RLE block type with size format 10. - RawRle1, - /// Raw/RLE block type with size format 11. - RawRle2, - /// Compressed block type with size format 00 or 01. - Compressed0, - /// Compressed block type with size format 10. - Compressed1, - /// Compressed block type with size format 11. - Compressed2, -} - -impl_expr!(LiteralsHeaderBranch); - -impl From for LiteralsHeaderBranch { - fn from(value: u64) -> Self { - match value { - 0 => Self::RawRle0, - 1 => Self::RawRle1, - 2 => Self::RawRle2, - 3 => Self::Compressed0, - 4 => Self::Compressed1, - 5 => Self::Compressed2, - _ => unreachable!("LiteralsHeaderBranch only from 0..=5"), - } - } -} - -impl From for usize { - fn from(value: LiteralsHeaderBranch) -> Self { - value as usize - } -} - -/// Helper table to calculate regenerated and compressed size from the Literals Header. -#[derive(Clone, Debug)] -pub struct LiteralsHeaderTable { - /// Whether to enable. - pub q_enable: Column, - /// Byte offset at which this literals header is located. - pub byte_offset: Column, - /// The branch taken for this literals header. - pub branch: Column, - /// To identify the branch. - pub branch_bits: BinaryNumberConfig, - /// The first byte of the literals header. - pub byte0: Column, - /// The second byte. - pub byte1: Column, - /// The third byte. - pub byte2: Column, - /// The fourth byte. - pub byte3: Column, - /// The fifth byte. - pub byte4: Column, - /// byte0 >> 3. - pub byte0_rs_3: Column, - /// byte0 >> 4. - pub byte0_rs_4: Column, - /// byte1 >> 6. - pub byte1_rs_6: Column, - /// byte1 & 0b111111. - pub byte1_and_63: Column, - /// byte2 >> 2. - pub byte2_rs_2: Column, - /// byte2 >> 6. - pub byte2_rs_6: Column, - /// byte2 & 0b11. - pub byte2_and_3: Column, - /// byte2 & 0b111111. - pub byte2_and_63: Column, - /// Regenerated size. - pub regen_size: Column, - /// Compressed size. - pub compr_size: Column, -} - -impl LiteralsHeaderTable { - /// Construct and constrain the literals header table. - pub fn construct( - meta: &mut ConstraintSystem, - bitwise_op_table: BitwiseOpTable, - range4: RangeTable<4>, - range8: RangeTable<8>, - range16: RangeTable<16>, - range64: RangeTable<64>, - ) -> Self { - let q_enable = meta.fixed_column(); - let branch = meta.advice_column(); - let table = Self { - q_enable, - byte_offset: meta.advice_column(), - branch, - branch_bits: BinaryNumberChip::configure(meta, q_enable, Some(branch.into())), - byte0: meta.advice_column(), - byte1: meta.advice_column(), - byte2: meta.advice_column(), - byte3: meta.advice_column(), - byte4: meta.advice_column(), - byte0_rs_3: meta.advice_column(), - byte0_rs_4: meta.advice_column(), - byte1_rs_6: meta.advice_column(), - byte1_and_63: meta.advice_column(), - byte2_rs_2: meta.advice_column(), - byte2_rs_6: meta.advice_column(), - byte2_and_3: meta.advice_column(), - byte2_and_63: meta.advice_column(), - regen_size: meta.advice_column(), - compr_size: meta.advice_column(), - }; - - macro_rules! is_branch { - ($var:ident, $branch_variant:ident) => { - let $var = |meta: &mut VirtualCells| { - table - .branch_bits - .value_equals(LiteralsHeaderBranch::$branch_variant, Rotation::cur())( - meta - ) - }; - }; - } - - is_branch!(branch0, RawRle0); - is_branch!(branch1, RawRle1); - is_branch!(branch2, RawRle2); - is_branch!(branch3, Compressed0); - is_branch!(branch4, Compressed1); - is_branch!(branch5, Compressed2); - - meta.create_gate("LiteralsHeaderTable", |meta| { - let mut cb = BaseConstraintBuilder::default(); - - let byte0_rs_3 = meta.query_advice(table.byte0_rs_3, Rotation::cur()); - let byte0_rs_4 = meta.query_advice(table.byte0_rs_4, Rotation::cur()); - let byte1_ls_4 = meta.query_advice(table.byte1, Rotation::cur()) * 16.expr(); - let byte1_and_63_ls_4 = - meta.query_advice(table.byte1_and_63, Rotation::cur()) * 16.expr(); - let byte1_rs_6 = meta.query_advice(table.byte1_rs_6, Rotation::cur()); - let byte2_rs_2 = meta.query_advice(table.byte2_rs_2, Rotation::cur()); - let byte2_rs_6 = meta.query_advice(table.byte2_rs_6, Rotation::cur()); - let byte2_ls_2 = meta.query_advice(table.byte2, Rotation::cur()) * 4.expr(); - let byte2_ls_12 = meta.query_advice(table.byte2, Rotation::cur()) * 4096.expr(); - let byte2_and_3_ls_12 = - meta.query_advice(table.byte2_and_3, Rotation::cur()) * 4096.expr(); - let byte2_and_63_ls_12 = - meta.query_advice(table.byte2_and_63, Rotation::cur()) * 4096.expr(); - let byte3_ls_6 = meta.query_advice(table.byte3, Rotation::cur()) * 64.expr(); - let byte3_ls_2 = meta.query_advice(table.byte3, Rotation::cur()) * 4.expr(); - let byte4_ls_10 = meta.query_advice(table.byte4, Rotation::cur()) * 1024.expr(); - - // regen_size == lh_byte[0] >> 3. - // compr_size == 0. - cb.condition(branch0(meta), |cb| { - cb.require_equal( - "branch0: regenerated size", - meta.query_advice(table.regen_size, Rotation::cur()), - byte0_rs_3, - ); - cb.require_zero( - "branch0: compressed size", - meta.query_advice(table.compr_size, Rotation::cur()), - ); - for col in [table.byte1, table.byte2, table.byte3, table.byte4] { - cb.require_zero("byte[i] == 0", meta.query_advice(col, Rotation::cur())); - } - }); - - // regen_size == (lh_byte[0] >> 4) + (lh_byte[1] << 4). - // compr_size == 0. - cb.condition(branch1(meta), |cb| { - cb.require_equal( - "branch1: regenerated size", - meta.query_advice(table.regen_size, Rotation::cur()), - byte0_rs_4.expr() + byte1_ls_4.expr(), - ); - cb.require_zero( - "branch1: compressed size", - meta.query_advice(table.compr_size, Rotation::cur()), - ); - for col in [table.byte2, table.byte3, table.byte4] { - cb.require_zero("byte[i] == 0", meta.query_advice(col, Rotation::cur())); - } - }); - - // regen_size == (lh_byte[0] >> 4) + (lh_byte[1] << 4) + (lh_byte[2] << 12). - // compr_size == 0. - cb.condition(branch2(meta), |cb| { - cb.require_equal( - "branch2: regenerated size", - meta.query_advice(table.regen_size, Rotation::cur()), - byte0_rs_4.expr() + byte1_ls_4.expr() + byte2_ls_12, - ); - cb.require_zero( - "branch2: compressed size", - meta.query_advice(table.compr_size, Rotation::cur()), - ); - for col in [table.byte3, table.byte4] { - cb.require_zero("byte[i] == 0", meta.query_advice(col, Rotation::cur())); - } - }); - - // regen_size == (lh_byte[0] >> 4) + ((lh_byte[1] & 0b111111) << 4). - // compr_size == (lh_byte[1] >> 6) + (lh_byte[2] << 2). - cb.condition(branch3(meta), |cb| { - cb.require_equal( - "branch3: regenerated size", - meta.query_advice(table.regen_size, Rotation::cur()), - byte0_rs_4.expr() + byte1_and_63_ls_4, - ); - cb.require_equal( - "branch3: compressed size", - meta.query_advice(table.compr_size, Rotation::cur()), - byte1_rs_6 + byte2_ls_2.expr(), - ); - for col in [table.byte3, table.byte4] { - cb.require_zero("byte[i] == 0", meta.query_advice(col, Rotation::cur())); - } - }); - - // regen_size == (lh_byte[0] >> 4) + (lh_byte[1] << 4) + ((lh_byte[2] & 0b11) << 12). - // compr_size == (lh_byte[2] >> 2) + (lh_byte[3] << 6). - cb.condition(branch4(meta), |cb| { - cb.require_equal( - "branch4: regenerated size", - meta.query_advice(table.regen_size, Rotation::cur()), - byte0_rs_4.expr() + byte1_ls_4.expr() + byte2_and_3_ls_12, - ); - cb.require_equal( - "branch4: compressed size", - meta.query_advice(table.compr_size, Rotation::cur()), - byte2_rs_2 + byte3_ls_6, - ); - cb.require_zero( - "byte[i] == 0", - meta.query_advice(table.byte4, Rotation::cur()), - ); - }); - - // regen_size == (lh_byte[0] >> 4) + (lh_byte[1] << 4) + ((lh_byte[2] & 0b111111) << - // 12). compr_size == (lh_byte[2] >> 6) + (lh_byte[3] << 2) + (lh_byte[4] << - // 10). - cb.condition(branch5(meta), |cb| { - cb.require_equal( - "branch5: regenerated size", - meta.query_advice(table.regen_size, Rotation::cur()), - byte0_rs_4 + byte1_ls_4 + byte2_and_63_ls_12, - ); - cb.require_equal( - "branch5: compressed size", - meta.query_advice(table.compr_size, Rotation::cur()), - byte2_rs_6 + byte3_ls_2 + byte4_ls_10, - ); - }); - - cb.gate(meta.query_fixed(table.q_enable, Rotation::cur())) - }); - meta.lookup("LiteralsHeaderTable: byte0 >> 3", |meta| { - let condition = meta.query_fixed(table.q_enable, Rotation::cur()); - let range_value = meta.query_advice(table.byte0, Rotation::cur()) - - (meta.query_advice(table.byte0_rs_3, Rotation::cur()) * 8.expr()); - - vec![(condition * range_value, range8.into())] - }); - meta.lookup("LiteralsHeaderTable: byte0 >> 4", |meta| { - let condition = meta.query_fixed(table.q_enable, Rotation::cur()); - let range_value = meta.query_advice(table.byte0, Rotation::cur()) - - (meta.query_advice(table.byte0_rs_4, Rotation::cur()) * 16.expr()); - - vec![(condition * range_value, range16.into())] - }); - meta.lookup("LiteralsHeaderTable: byte1 >> 6", |meta| { - let condition = meta.query_fixed(table.q_enable, Rotation::cur()); - let range_value = meta.query_advice(table.byte1, Rotation::cur()) - - (meta.query_advice(table.byte1_rs_6, Rotation::cur()) * 64.expr()); - - vec![(condition * range_value, range64.into())] - }); - meta.lookup("LiteralsHeaderTable: byte2 >> 2", |meta| { - let condition = meta.query_fixed(table.q_enable, Rotation::cur()); - let range_value = meta.query_advice(table.byte2, Rotation::cur()) - - (meta.query_advice(table.byte2_rs_2, Rotation::cur()) * 4.expr()); - - vec![(condition * range_value, range4.into())] - }); - meta.lookup("LiteralsHeaderTable: byte2 >> 6", |meta| { - let condition = meta.query_fixed(table.q_enable, Rotation::cur()); - let range_value = meta.query_advice(table.byte2, Rotation::cur()) - - (meta.query_advice(table.byte2_rs_6, Rotation::cur()) * 64.expr()); - - vec![(condition * range_value, range64.into())] - }); - meta.lookup_any("LiteralsHeaderTable: byte1 & 63", |meta| { - let condition = and::expr([ - meta.query_fixed(table.q_enable, Rotation::cur()), - not::expr(branch0(meta)), - ]); - [ - BitwiseOp::AND.expr(), - meta.query_advice(table.byte1, Rotation::cur()), - 63.expr(), - meta.query_advice(table.byte1_and_63, Rotation::cur()), - ] - .into_iter() - .zip(bitwise_op_table.table_exprs(meta)) - .map(|(input, table)| (input * condition.clone(), table)) - .collect::>() - }); - meta.lookup_any("LiteralsHeaderTable: byte2 & 3", |meta| { - let condition = meta.query_fixed(table.q_enable, Rotation::cur()); - [ - BitwiseOp::AND.expr(), - meta.query_advice(table.byte2, Rotation::cur()), - 3.expr(), - meta.query_advice(table.byte2_and_3, Rotation::cur()), - ] - .into_iter() - .zip(bitwise_op_table.table_exprs(meta)) - .map(|(input, table)| (input * condition.clone(), table)) - .collect::>() - }); - meta.lookup_any("LiteralsHeaderTable: byte2 & 63", |meta| { - let condition = meta.query_fixed(table.q_enable, Rotation::cur()); - [ - BitwiseOp::AND.expr(), - meta.query_advice(table.byte2, Rotation::cur()), - 63.expr(), - meta.query_advice(table.byte2_and_63, Rotation::cur()), - ] - .into_iter() - .zip(bitwise_op_table.table_exprs(meta)) - .map(|(input, table)| (input * condition.clone(), table)) - .collect::>() - }); - - debug_assert!(meta.degree() <= 9); - - table - } - - /// Assign witness to the literals header table. - pub fn assign( - &self, - layouter: &mut impl Layouter, - literals_headers: &[(u64, &[u8], u64, u64, u64)], /* (byte_offset, bytes, branch, - * regen_size, compr_size) */ - ) -> Result<(), Error> { - layouter.assign_region( - || "LiteralsHeaderTable", - |mut region| { - for (offset, &(byte_offset, header, branch, regen_size, compr_size)) in - literals_headers.iter().enumerate() - { - assert!(header.len() <= 5); - let [byte0, byte1, byte2, byte3, byte4] = [0, 1, 2, 3, 4] - .map(|i| header.get(i).cloned().map_or(0u64, |byte| byte as u64)); - region.assign_fixed( - || "q_enable", - self.q_enable, - offset, - || Value::known(F::one()), - )?; - for (col, value, annotation) in [ - (self.byte_offset, byte_offset, "byte_offset"), - (self.branch, branch, "branch"), - (self.byte0, byte0, "byte0"), - (self.byte1, byte1, "byte1"), - (self.byte2, byte2, "byte2"), - (self.byte3, byte3, "byte3"), - (self.byte4, byte4, "byte4"), - (self.byte0_rs_3, byte0 >> 3, "byte0_rs_3"), - (self.byte0_rs_4, byte0 >> 4, "byte0_rs_4"), - (self.byte1_rs_6, byte1 >> 6, "byte1_rs_6"), - (self.byte1_and_63, byte1 & 63, "byte1_and_63"), - (self.byte2_rs_2, byte2 >> 2, "byte2_rs_2"), - (self.byte2_rs_6, byte2 >> 6, "byte2_rs_6"), - (self.byte2_and_3, byte2 & 3, "byte2_and_3"), - (self.byte2_and_63, byte2 & 63, "byte2_and_63"), - (self.regen_size, regen_size, "regen_size"), - (self.compr_size, compr_size, "compr_size"), - ] { - region.assign_advice( - || annotation, - col, - offset, - || Value::known(F::from(value)), - )?; - } - let branch_chip = BinaryNumberChip::construct(self.branch_bits); - branch_chip.assign(&mut region, offset, &LiteralsHeaderBranch::from(branch))?; - } - - Ok(()) - }, - ) - } -} - -impl LookupTable for LiteralsHeaderTable { - fn columns(&self) -> Vec> { - vec![ - self.byte_offset.into(), - self.branch.into(), - self.byte0.into(), - self.byte1.into(), - self.byte2.into(), - self.byte3.into(), - self.byte4.into(), - self.regen_size.into(), - self.compr_size.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("byte_offset"), - String::from("branch"), - String::from("byte0"), - String::from("byte1"), - String::from("byte2"), - String::from("byte3"), - String::from("byte4"), - String::from("regen_size"), - String::from("compr_size"), - ] - } -} - -/// Read-only Memory table for the Decompression circuit. This table allows us a lookup argument -/// from the Decompression circuit to check if a given row can occur depending on the row's tag, -/// next tag and tag length. -#[derive(Clone, Copy, Debug)] -pub struct TagRomTable { - /// Tag of the current field being decoded. - pub tag: Column, - /// Tag of the following field when the current field is finished decoding. - pub tag_next: Column, - /// The maximum length in terms of number of bytes that the current tag can take up. - pub max_len: Column, - /// Whether this tag outputs a decoded byte or not. - pub is_output: Column, - /// Whether this tag belongs to a ``block`` in zstd or not. - pub is_block: Column, - /// Whether this tag is processed back-to-front, i.e. in reverse order. - pub is_reverse: Column, -} - -impl LookupTable for TagRomTable { - fn columns(&self) -> Vec> { - vec![ - self.tag.into(), - self.tag_next.into(), - self.max_len.into(), - self.is_output.into(), - self.is_block.into(), - self.is_reverse.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("tag"), - String::from("tag_next"), - String::from("max_len"), - String::from("is_output"), - String::from("is_block"), - String::from("is_reverse"), - ] - } -} - -impl TagRomTable { - /// Construct the ROM table. - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - tag: meta.fixed_column(), - tag_next: meta.fixed_column(), - max_len: meta.fixed_column(), - is_output: meta.fixed_column(), - is_block: meta.fixed_column(), - is_reverse: meta.fixed_column(), - } - } - - /// Load the ROM table. - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "Zstd ROM table", - |mut region| { - for (offset, row) in TagRomTableRow::rows().iter().enumerate() { - for (&column, (value, annotation)) in - >::fixed_columns(self).iter().zip( - row.values::() - .into_iter() - .zip(>::annotations(self).iter()), - ) - { - region.assign_fixed( - || format!("{annotation} at offset={offset}"), - column, - offset, - || value, - )?; - } - } - - Ok(()) - }, - ) - } -} - -/// Read-only Memory table for the Decompression circuit. This table allows us a lookup argument -/// from the Decompression circuit to check if the next tag is correct based on which block type we -/// have encountered in the block header. Block type is denoted by 2 bits in the block header. -#[derive(Clone, Copy, Debug)] -pub struct BlockTypeRomTable { - /// Current tag. - tag: Column, - /// Lower bit. - lo_bit: Column, - /// Higher bit. - hi_bit: Column, - /// Tag that follows. - tag_next: Column, -} - -impl LookupTable for BlockTypeRomTable { - fn columns(&self) -> Vec> { - vec![ - self.tag.into(), - self.lo_bit.into(), - self.hi_bit.into(), - self.tag_next.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("tag"), - String::from("lo_bit"), - String::from("hi_bit"), - String::from("tag_next"), - ] - } -} - -impl BlockTypeRomTable { - /// Construct the ROM table. - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - tag: meta.fixed_column(), - lo_bit: meta.fixed_column(), - hi_bit: meta.fixed_column(), - tag_next: meta.fixed_column(), - } - } - - /// Load the ROM table. - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "Zstd BlockType ROM table", - |mut region| { - for (i, &(tag, lo_bit, hi_bit, tag_next)) in [ - (ZstdTag::BlockHeader, 0, 0, ZstdTag::RawBlockBytes), - (ZstdTag::BlockHeader, 0, 1, ZstdTag::RleBlockBytes), - (ZstdTag::BlockHeader, 1, 0, ZstdTag::ZstdBlockLiteralsHeader), - ( - ZstdTag::ZstdBlockLiteralsHeader, - 0, - 0, - ZstdTag::ZstdBlockLiteralsRawBytes, - ), - ( - ZstdTag::ZstdBlockLiteralsHeader, - 0, - 1, - ZstdTag::ZstdBlockLiteralsRleBytes, - ), - ( - ZstdTag::ZstdBlockLiteralsHeader, - 1, - 0, - ZstdTag::ZstdBlockFseCode, - ), - ] - .iter() - .enumerate() - { - region.assign_fixed( - || "tag", - self.tag, - i, - || Value::known(F::from(tag as u64)), - )?; - region.assign_fixed( - || "lo_bit", - self.lo_bit, - i, - || Value::known(F::from(lo_bit)), - )?; - region.assign_fixed( - || "hi_bit", - self.hi_bit, - i, - || Value::known(F::from(hi_bit)), - )?; - region.assign_fixed( - || "tag_next", - self.tag_next, - i, - || Value::known(F::from(tag_next as u64)), - )?; - } - Ok(()) - }, - ) - } -} - -/// Read-only memory table for zstd block's literals header. -#[derive(Clone, Copy, Debug)] -pub struct LiteralsHeaderRomTable { - /// Block type first bit. - block_type_bit0: Column, - /// Block type second bit. - block_type_bit1: Column, - /// Size format first bit. - size_format_bit0: Column, - /// Size format second bit. - size_format_bit1: Column, - /// Number of bytes occupied by the literals header. - n_bytes_header: Column, - /// Number of literal streams to be decoded. - n_lstreams: Column, - /// The branch we take to decompose the literals header. There are a total of 7 branches that - /// can be used to decompose the literals header, namely: - /// - /// - block_type == Raw/RLE and size_format == 00 or 10 - /// - block_type == Raw/RLE and size_format == 01 - /// - block_type == Raw/RLE and size_format == 11 - /// - block_type == Compressed and size_format == 00 or 01 - /// - block_type == Compressed and size_format == 10 - /// - block_type == Compressed and size_format == 11 - branch: Column, - // size format == 0b11? - is_size_format_0b11: Column, -} - -impl LookupTable for LiteralsHeaderRomTable { - fn columns(&self) -> Vec> { - vec![ - self.block_type_bit0.into(), - self.block_type_bit1.into(), - self.size_format_bit0.into(), - self.size_format_bit1.into(), - self.n_bytes_header.into(), - self.n_lstreams.into(), - self.branch.into(), - self.is_size_format_0b11.into(), - ] - } - - fn annotations(&self) -> Vec { - vec![ - String::from("block_type_bit0"), - String::from("block_type_bit1"), - String::from("size_format_bit0"), - String::from("size_format_bit1"), - String::from("n_bytes_header"), - String::from("n_lstreams"), - String::from("branch"), - String::from("is_size_format_0b11"), - ] - } -} - -impl LiteralsHeaderRomTable { - /// Construct the ROM table. - pub fn construct(meta: &mut ConstraintSystem) -> Self { - Self { - block_type_bit0: meta.fixed_column(), - block_type_bit1: meta.fixed_column(), - size_format_bit0: meta.fixed_column(), - size_format_bit1: meta.fixed_column(), - n_bytes_header: meta.fixed_column(), - n_lstreams: meta.fixed_column(), - branch: meta.fixed_column(), - is_size_format_0b11: meta.fixed_column(), - } - } - - /// Load the ROM table. - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "LiteralsHeader ROM table", - |mut region| { - // Refer: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#literals_section_header - for (i, row) in [ - [0, 0, 0, 0, 1, 0, 0, 0], // Raw: 1 byte header - [0, 0, 0, 1, 1, 0, 0, 0], // Raw: 1 byte header - [0, 0, 1, 0, 2, 0, 1, 0], // Raw: 2 bytes header - [0, 0, 1, 1, 3, 0, 2, 1], // Raw: 3 bytes header - [1, 0, 0, 0, 1, 0, 0, 0], // RLE: 1 byte header - [1, 0, 0, 1, 1, 0, 0, 0], // RLE: 1 byte header - [1, 0, 1, 0, 2, 0, 1, 0], // RLE: 2 bytes header - [1, 0, 1, 1, 3, 0, 2, 1], // RLE: 3 bytes header - [0, 1, 0, 0, 3, 0, 3, 0], // Compressed: 3 bytes header - [0, 1, 1, 0, 3, 1, 3, 0], // Compressed: 3 bytes header - [0, 1, 0, 1, 4, 1, 4, 0], // Compressed: 4 bytes header - [0, 1, 1, 1, 5, 1, 5, 1], // Compressed: 5 bytes header - ] - .iter() - .enumerate() - { - for (&column, (&value, annotation)) in - >::fixed_columns(self).iter().zip( - row.iter() - .zip(>::annotations(self).iter()), - ) - { - region.assign_fixed( - || format!("{annotation} at offset={i}"), - column, - i, - || Value::known(F::from(value)), - )?; - } - } - - Ok(()) - }, - ) - } -} diff --git a/zkevm-circuits/src/table/decompression/bitstring_accumulation_table.rs b/zkevm-circuits/src/table/decompression/bitstring_accumulation_table.rs new file mode 100644 index 0000000000..0dee39192f --- /dev/null +++ b/zkevm-circuits/src/table/decompression/bitstring_accumulation_table.rs @@ -0,0 +1,557 @@ +use eth_types::Field; +use gadgets::util::{and, not, select, Expr}; +use halo2_proofs::{ + circuit::{Layouter, Value}, + plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed}, + poly::Rotation, +}; + +use crate::{ + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + table::LookupTable, + witness::{value_bits_le, ZstdTag, ZstdWitnessRow}, +}; + +/// An auxiliary table for the Huffman Codes. In Huffman coding a symbol (byte) is mapped to a +/// bitstring of particular length such that more frequently occuring symbols are mapped to +/// bitstrings of smaller lengths. +/// +/// We already have the symbols and their bit_value in the HuffmanCodesTable. However, we still +/// need to validate that the bit_value is in fact assigned correctly. Since bitstrings may not be +/// byte-aligned, i.e. a bitstring can span over 2 bytes (assuming a maximum bitstring length of 8) +/// we need to make sure that the bit_value is in fact the binary value represented by the bits of +/// that bitstring. +#[derive(Clone, Debug)] +pub struct BitstringAccumulationTable { + /// Fixed column to denote whether the constraints will be enabled or not. + pub q_enabled: Column, + /// The byte offset within the data instance where the encoded FSE table begins. This is + /// 1-indexed, i.e. byte_offset == 1 at the first byte. + pub byte_offset: Column, + /// The byte offset of byte_1 in the zstd encoded data. byte_idx' == byte_idx + /// while 0 <= bit_index < 15. At bit_index == 15, byte_idx' == byte_idx + 1. + pub byte_idx_1: Column, + /// The byte offset of byte_2 in the zstd encoded data. byte_idx' == byte_idx + /// while 0 <= bit_index < 15. At bit_index == 15, byte_idx' == byte_idx + 1. + /// + /// We also have byte_idx_2 == byte_idx_1 + 1. + pub byte_idx_2: Column, + /// The byte value at byte_idx_1. + pub byte_1: Column, + /// The byte value at byte_idx_2. + pub byte_2: Column, + /// The index within these 2 bytes, i.e. 0 <= bit_index <= 15. bit_index increments until its + /// 15 and then is reset to 0. Repeats while we finish bitstring accumulation of all bitstrings + /// used in the Huffman codes. + pub bit_index: Column, + /// Helper column to know the start of a new chunk of 2 bytes, this is a fixed column as well + /// as it is set only on bit_index == 0. + pub q_first: Column, + /// The bit at bit_index. Accumulation of bits from 0 <= bit_index <= 7 denotes byte_1. + /// Accumulation of 8 <= bit_index <= 15 denotes byte_2. + pub bit: Column, + /// The final value of the bit accumulation for the set bits. + pub bit_value: Column, + /// The length of the bitstring, i.e. the number of bits that were set. + pub bitstring_len: Column, + /// The accumulator over bits from is_start to is_end, i.e. while is_set == 1. + pub bit_value_acc: Column, + /// Boolean that is set from start of bit chunk to bit_index == 15. + pub from_start: Column, + /// Boolean that is set from bit_index == 0 to end of bit chunk. + pub until_end: Column, + /// Boolean to mark if the bitstring is a part of bytes that are read from front-to-back or + /// back-to-front. For the back-to-front case, the is_reverse boolean is set. + pub is_reverse: Column, +} + +impl BitstringAccumulationTable { + /// Construct the bitstring accumulation table. + pub fn construct(meta: &mut ConstraintSystem) -> Self { + let q_enabled = meta.fixed_column(); + let table = Self { + q_enabled, + byte_offset: meta.advice_column(), + byte_idx_1: meta.advice_column(), + byte_idx_2: meta.advice_column(), + byte_1: meta.advice_column(), + byte_2: meta.advice_column(), + bit_index: meta.fixed_column(), + q_first: meta.fixed_column(), + bit: meta.advice_column(), + bit_value: meta.advice_column(), + bitstring_len: meta.advice_column(), + bit_value_acc: meta.advice_column(), + from_start: meta.advice_column(), + until_end: meta.advice_column(), + is_reverse: meta.advice_column(), + }; + + meta.create_gate("BitstringAccumulationTable: bit_index == 0", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + let bits = (0..16) + .map(|i| meta.query_advice(table.bit, Rotation(i))) + .collect::>>(); + + cb.require_equal( + "byte1 is the binary accumulation of 0 <= bit_index <= 7", + meta.query_advice(table.byte_1, Rotation::cur()), + select::expr( + meta.query_advice(table.is_reverse, Rotation::cur()), + bits[7].expr() + + bits[6].expr() * 2.expr() + + bits[5].expr() * 4.expr() + + bits[4].expr() * 8.expr() + + bits[3].expr() * 16.expr() + + bits[2].expr() * 32.expr() + + bits[1].expr() * 64.expr() + + bits[0].expr() * 128.expr(), + bits[0].expr() + + bits[1].expr() * 2.expr() + + bits[2].expr() * 4.expr() + + bits[3].expr() * 8.expr() + + bits[4].expr() * 16.expr() + + bits[5].expr() * 32.expr() + + bits[6].expr() * 64.expr() + + bits[7].expr() * 128.expr(), + ), + ); + + cb.require_equal( + "byte2 is the binary accumulation of 8 <= bit_index <= 15", + meta.query_advice(table.byte_2, Rotation::cur()), + select::expr( + meta.query_advice(table.is_reverse, Rotation::cur()), + bits[15].expr() + + bits[14].expr() * 2.expr() + + bits[13].expr() * 4.expr() + + bits[12].expr() * 8.expr() + + bits[11].expr() * 16.expr() + + bits[10].expr() * 32.expr() + + bits[9].expr() * 64.expr() + + bits[8].expr() * 128.expr(), + bits[8].expr() + + bits[9].expr() * 2.expr() + + bits[10].expr() * 4.expr() + + bits[11].expr() * 8.expr() + + bits[12].expr() * 16.expr() + + bits[13].expr() * 32.expr() + + bits[14].expr() * 64.expr() + + bits[15].expr() * 128.expr(), + ), + ); + + cb.require_boolean( + "is_reverse is boolean", + meta.query_advice(table.is_reverse, Rotation::cur()), + ); + + // TODO: Possibly exclude jump table bytes as they create a gap in byte_idx between + // huffman code and lstreams + cb.require_boolean( + "byte2 == byte1 or byte2 == byte1 + 1", + meta.query_advice(table.byte_idx_2, Rotation::cur()) + - meta.query_advice(table.byte_idx_1, Rotation::cur()), + ); + + cb.gate(and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + meta.query_fixed(table.q_first, Rotation::cur()), + ])) + }); + + debug_assert!(meta.degree() <= 9); + + meta.create_gate("BitstringAccumulationTable: bit_index > 0", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // Constrain columns that are unchanged from 0 < bit_idx < 16. + for col in [ + table.byte_offset, + table.byte_idx_1, + table.byte_idx_2, + table.byte_1, + table.byte_2, + table.bit_value, + table.is_reverse, + ] { + cb.require_equal( + "unchanged columns from 0 < bit_idx < 16", + meta.query_advice(col, Rotation::cur()), + meta.query_advice(col, Rotation::prev()), + ); + } + + let is_last = meta.query_fixed(table.q_first, Rotation::next()); + cb.condition(is_last, |cb| { + cb.require_equal( + "byte_idx_1' == byte_idx_2", + meta.query_advice(table.byte_idx_1, Rotation::next()), + meta.query_advice(table.byte_idx_2, Rotation::cur()), + ); + }); + + cb.gate(and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + not::expr(meta.query_fixed(table.q_first, Rotation::cur())), + ])) + }); + + debug_assert!(meta.degree() <= 9); + + // Consider a bit chunk from bit_index == 4 to bit_index == 9. We will have: + // + // | bit index | from start | until end | bitstring len | bit | bit value acc | + // |-----------|------------|-----------|---------------|-----|---------------| + // | 0 | 1 | 0 | 0 | 0 | 0 | + // | 1 | 1 | 0 | 0 | 0 | 0 | + // | 2 | 1 | 0 | 0 | 1 | 0 | + // | 3 | 1 | 0 | 0 | 0 | 0 | + // | 4 -> | 1 | 1 | 1 | 1 | 1 | + // | 5 -> | 1 | 1 | 2 | 0 | 1 | + // | 6 -> | 1 | 1 | 3 | 1 | 5 | + // | 7 -> | 1 | 1 | 4 | 1 | 13 | + // | 8 -> | 1 | 1 | 5 | 0 | 13 | + // | 9 -> | 1 | 1 | 6 | 1 | 45 | + // | 10 | 0 | 1 | 6 | 0 | 45 | + // | 11 | 0 | 1 | 6 | 0 | 45 | + // | 12 | 0 | 1 | 6 | 0 | 45 | + // | 13 | 0 | 1 | 6 | 1 | 45 | + // | 14 | 0 | 1 | 6 | 1 | 45 | + // | 15 | 0 | 1 | 6 | 0 | 45 | + // + // The bits for the bitstring are where from_start == until_end == 1. + meta.create_gate("BitstringAccumulationTable: bit value", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // Columns from_start and until_end are boolean. + cb.require_boolean( + "from_start is boolean", + meta.query_advice(table.from_start, Rotation::cur()), + ); + cb.require_boolean( + "until_end is boolean", + meta.query_advice(table.until_end, Rotation::cur()), + ); + + // Column from_start transitions from 1 to 0 only once. + let is_first = meta.query_fixed(table.q_first, Rotation::cur()); + cb.condition(is_first.expr(), |cb| { + cb.require_equal( + "if q_first == True: from_start == 1", + meta.query_advice(table.from_start, Rotation::cur()), + 1.expr(), + ); + }); + cb.condition(not::expr(is_first.expr()), |cb| { + cb.require_boolean( + "from_start transitions from 1 to 0 only once", + meta.query_advice(table.from_start, Rotation::prev()) + - meta.query_advice(table.from_start, Rotation::cur()), + ); + }); + + // Column until_end transitions from 0 to 1 only once. + let is_last = meta.query_fixed(table.q_first, Rotation::next()); + cb.condition(is_last.expr(), |cb| { + cb.require_equal( + "if q_first::next == True: until_end == 1", + meta.query_advice(table.until_end, Rotation::cur()), + 1.expr(), + ); + }); + cb.condition(not::expr(is_last.expr()), |cb| { + cb.require_boolean( + "until_end transitions from 0 to 1 only once", + meta.query_advice(table.until_end, Rotation::next()) + - meta.query_advice(table.until_end, Rotation::cur()), + ); + }); + + // Constraints at meaningful bits. + let is_set = and::expr([ + meta.query_advice(table.from_start, Rotation::cur()), + meta.query_advice(table.until_end, Rotation::cur()), + ]); + cb.condition(is_first.expr() * is_set.expr(), |cb| { + cb.require_equal( + "if is_first && is_set: bit == bit_value_acc", + meta.query_advice(table.bit, Rotation::cur()), + meta.query_advice(table.bit_value_acc, Rotation::cur()), + ); + cb.require_equal( + "if is_first && is_set: bitstring_len == 1", + meta.query_advice(table.bitstring_len, Rotation::cur()), + 1.expr(), + ); + }); + cb.condition(not::expr(is_first) * is_set, |cb| { + cb.require_equal( + "is_set: bit_value_acc == bit_value_acc::prev * 2 + bit", + meta.query_advice(table.bit_value_acc, Rotation::cur()), + meta.query_advice(table.bit_value_acc, Rotation::prev()) * 2.expr() + + meta.query_advice(table.bit, Rotation::cur()), + ); + cb.require_equal( + "is_set: bitstring_len == bitstring_len::prev + 1", + meta.query_advice(table.bitstring_len, Rotation::cur()), + meta.query_advice(table.bitstring_len, Rotation::prev()) + 1.expr(), + ); + }); + + // Constraints at bits to be ignored (at the start). + let is_ignored = not::expr(meta.query_advice(table.until_end, Rotation::cur())); + cb.condition(is_ignored, |cb| { + cb.require_zero( + "while until_end == 0: bitstring_len == 0", + meta.query_advice(table.bitstring_len, Rotation::cur()), + ); + cb.require_zero( + "while until_end == 0: bit_value_acc == 0", + meta.query_advice(table.bit_value_acc, Rotation::cur()), + ); + }); + + // Constraints at bits to be ignored (towards the end). + let is_ignored = not::expr(meta.query_advice(table.from_start, Rotation::cur())); + cb.condition(is_ignored, |cb| { + cb.require_equal( + "bitstring_len unchanged at the last ignored bits", + meta.query_advice(table.bitstring_len, Rotation::cur()), + meta.query_advice(table.bitstring_len, Rotation::prev()), + ); + cb.require_equal( + "bit_value_acc unchanged at the last ignored bits", + meta.query_advice(table.bit_value_acc, Rotation::cur()), + meta.query_advice(table.bit_value_acc, Rotation::prev()), + ); + }); + + cb.gate(meta.query_fixed(table.q_enabled, Rotation::cur())) + }); + + debug_assert!(meta.degree() <= 9); + + table + } + + /// Load witness to the table: dev mode. + pub fn assign( + &self, + layouter: &mut impl Layouter, + witness_rows: &[ZstdWitnessRow], + ) -> Result<(), Error> { + assert!(!witness_rows.is_empty()); + + // Get the byte at which FSE is described + // TODO: Determining huffman offset in a multi-block scenario. + let huffman_offset = witness_rows + .iter() + .find(|&r| r.state.tag == ZstdTag::ZstdBlockFseCode) + .unwrap() + .encoded_data + .byte_idx; + + // Extract bit accumulation-related info from the rows + let accumulation_rows = witness_rows + .iter() + .filter(|&r| { + r.state.tag == ZstdTag::ZstdBlockFseCode + || r.state.tag == ZstdTag::ZstdBlockHuffmanCode + || r.state.tag == ZstdTag::ZstdBlockJumpTable + || r.state.tag == ZstdTag::ZstdBlockLstream + }) + .map(|r| { + ( + r.encoded_data.byte_idx as usize, + r.encoded_data.value_byte as u64, + r.bitstream_read_data.bit_start_idx, + r.bitstream_read_data.bit_end_idx, + r.bitstream_read_data.bit_value, + r.state.tag.is_reverse() as u64, // is_reverse + ) + }) + .collect::>(); + + layouter.assign_region( + || "Bitstring Accumulation Table", + |mut region| { + let mut offset: usize = 0; + let mut last_byte_idx: usize = 0; + for rows in accumulation_rows.windows(2) { + let row = rows[0]; + let next_row = rows[1]; + let byte_1_bits = value_bits_le(row.1 as u8); + let byte_2_bits = value_bits_le(next_row.1 as u8); + let bits = if row.5 > 0 { + // reversed + [ + byte_1_bits.into_iter().rev().collect::>(), + byte_2_bits.into_iter().rev().collect::>(), + ] + .concat() + } else { + // not reversed + [byte_1_bits, byte_2_bits].concat() + }; + + let mut acc: u64 = 0; + let mut bitstring_len: u64 = 0; + + for (bit_idx, bit) in bits.into_iter().enumerate().take(16) { + region.assign_fixed( + || "q_enable", + self.q_enabled, + offset + bit_idx, + || Value::known(F::one()), + )?; + region.assign_advice( + || "byte_offset", + self.byte_offset, + offset + bit_idx, + || Value::known(F::from(huffman_offset)), + )?; + region.assign_advice( + || "byte_idx_1", + self.byte_idx_1, + offset + bit_idx, + || Value::known(F::from(row.0 as u64)), + )?; + region.assign_advice( + || "byte_idx_2", + self.byte_idx_2, + offset + bit_idx, + || Value::known(F::from(next_row.0 as u64)), + )?; + region.assign_advice( + || "byte_1", + self.byte_1, + offset + bit_idx, + || Value::known(F::from(row.1)), + )?; + region.assign_advice( + || "byte_2", + self.byte_2, + offset + bit_idx, + || Value::known(F::from(next_row.1)), + )?; + region.assign_fixed( + || "bit_index", + self.bit_index, + offset + bit_idx, + || Value::known(F::from(bit_idx as u64)), + )?; + region.assign_fixed( + || "q_first", + self.q_first, + offset + bit_idx, + || Value::known(F::from((bit_idx == 0) as u64)), + )?; + + if bit_idx >= row.2 && bit_idx <= row.3 { + acc = acc * 2 + (bit as u64); + bitstring_len += 1; + } + region.assign_advice( + || "bit", + self.bit, + offset + bit_idx, + || Value::known(F::from(bit as u64)), + )?; + region.assign_advice( + || "bit_value_acc", + self.bit_value_acc, + offset + bit_idx, + || Value::known(F::from(acc)), + )?; + region.assign_advice( + || "bit_value", + self.bit_value, + offset + bit_idx, + || Value::known(F::from(row.4)), + )?; + region.assign_advice( + || "bitstring_len", + self.bitstring_len, + offset + bit_idx, + || Value::known(F::from(bitstring_len)), + )?; + region.assign_advice( + || "from_start", + self.from_start, + offset + bit_idx, + || Value::known(F::from((bit_idx <= row.3) as u64)), + )?; + region.assign_advice( + || "until_end", + self.until_end, + offset + bit_idx, + || Value::known(F::from((bit_idx >= row.2) as u64)), + )?; + region.assign_advice( + || "is_reverse", + self.is_reverse, + offset + bit_idx, + || Value::known(F::from(row.5)), + )?; + } + + offset += 16; + last_byte_idx = next_row.0; + } + + region.assign_fixed( + || "q_first", + self.q_first, + offset, + || Value::known(F::one()), + )?; + region.assign_advice( + || "byte_idx_1", + self.byte_idx_1, + offset, + || Value::known(F::from(last_byte_idx as u64)), + )?; + + Ok(()) + }, + )?; + + Ok(()) + } +} + +impl LookupTable for BitstringAccumulationTable { + fn columns(&self) -> Vec> { + vec![ + self.byte_offset.into(), + self.byte_idx_1.into(), + self.byte_idx_2.into(), + self.byte_1.into(), + self.byte_2.into(), + self.bit_value.into(), + self.bitstring_len.into(), + self.bit_index.into(), + self.from_start.into(), + self.until_end.into(), + self.is_reverse.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("byte_offset"), + String::from("byte_idx_1"), + String::from("byte_idx_2"), + String::from("byte_1"), + String::from("byte_2"), + String::from("bit_value"), + String::from("bitstring_len"), + String::from("bit_index"), + String::from("from_start"), + String::from("until_end"), + String::from("is_reverse"), + ] + } +} diff --git a/zkevm-circuits/src/table/decompression/block_type_rom_table.rs b/zkevm-circuits/src/table/decompression/block_type_rom_table.rs new file mode 100644 index 0000000000..f74a5bad96 --- /dev/null +++ b/zkevm-circuits/src/table/decompression/block_type_rom_table.rs @@ -0,0 +1,115 @@ +use eth_types::Field; +use halo2_proofs::{ + circuit::{Layouter, Value}, + plonk::{Any, Column, ConstraintSystem, Error, Fixed}, +}; + +use crate::{table::LookupTable, witness::ZstdTag}; + +/// Read-only Memory table for the Decompression circuit. This table allows us a lookup argument +/// from the Decompression circuit to check if the next tag is correct based on which block type we +/// have encountered in the block header. Block type is denoted by 2 bits in the block header. +#[derive(Clone, Copy, Debug)] +pub struct BlockTypeRomTable { + /// Current tag. + tag: Column, + /// Lower bit. + lo_bit: Column, + /// Higher bit. + hi_bit: Column, + /// Tag that follows. + tag_next: Column, +} + +impl LookupTable for BlockTypeRomTable { + fn columns(&self) -> Vec> { + vec![ + self.tag.into(), + self.lo_bit.into(), + self.hi_bit.into(), + self.tag_next.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("tag"), + String::from("lo_bit"), + String::from("hi_bit"), + String::from("tag_next"), + ] + } +} + +impl BlockTypeRomTable { + /// Construct the ROM table. + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + tag: meta.fixed_column(), + lo_bit: meta.fixed_column(), + hi_bit: meta.fixed_column(), + tag_next: meta.fixed_column(), + } + } + + /// Load the ROM table. + pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + layouter.assign_region( + || "Zstd BlockType ROM table", + |mut region| { + for (i, &(tag, lo_bit, hi_bit, tag_next)) in [ + (ZstdTag::BlockHeader, 0, 0, ZstdTag::RawBlockBytes), + (ZstdTag::BlockHeader, 0, 1, ZstdTag::RleBlockBytes), + (ZstdTag::BlockHeader, 1, 0, ZstdTag::ZstdBlockLiteralsHeader), + ( + ZstdTag::ZstdBlockLiteralsHeader, + 0, + 0, + ZstdTag::ZstdBlockLiteralsRawBytes, + ), + ( + ZstdTag::ZstdBlockLiteralsHeader, + 0, + 1, + ZstdTag::ZstdBlockLiteralsRleBytes, + ), + ( + ZstdTag::ZstdBlockLiteralsHeader, + 1, + 0, + ZstdTag::ZstdBlockFseCode, + ), + ] + .iter() + .enumerate() + { + region.assign_fixed( + || "tag", + self.tag, + i, + || Value::known(F::from(tag as u64)), + )?; + region.assign_fixed( + || "lo_bit", + self.lo_bit, + i, + || Value::known(F::from(lo_bit)), + )?; + region.assign_fixed( + || "hi_bit", + self.hi_bit, + i, + || Value::known(F::from(hi_bit)), + )?; + region.assign_fixed( + || "tag_next", + self.tag_next, + i, + || Value::known(F::from(tag_next as u64)), + )?; + } + Ok(()) + }, + ) + } +} diff --git a/zkevm-circuits/src/table/decompression/decoded_literals_table.rs b/zkevm-circuits/src/table/decompression/decoded_literals_table.rs new file mode 100644 index 0000000000..5da15297d6 --- /dev/null +++ b/zkevm-circuits/src/table/decompression/decoded_literals_table.rs @@ -0,0 +1,172 @@ +use eth_types::Field; +use gadgets::{ + comparator::{ComparatorChip, ComparatorConfig}, + util::{and, not, Expr}, +}; +use halo2_proofs::{ + circuit::Layouter, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, SecondPhase}, + poly::Rotation, +}; + +use crate::{ + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + table::{LookupTable, RangeTable}, + util::Challenges, +}; + +/// Table that consists of every decoded literal byte. Depending on the literals length from +/// sequences execution, we also accumulate RLC over contiguous bytes. +#[derive(Clone, Debug)] +pub struct DecodedLiteralsTable { + q_enable: Column, + q_first: Column, + huffman_byte_offset: Column, + huffman_byte_offset_cmp: ComparatorConfig, + byte_offset: Column, + is_boundary: Column, + decoded_byte: Column, + decoded_literals_length: Column, + decoded_literals_rlc: Column, +} + +impl DecodedLiteralsTable { + /// Construct and constrain the decoded literals table. + pub fn construct( + meta: &mut ConstraintSystem, + challenges: Challenges>, + range256: RangeTable<256>, + ) -> Self { + let q_enable = meta.fixed_column(); + let huffman_byte_offset = meta.advice_column(); + let table = Self { + q_enable, + q_first: meta.fixed_column(), + huffman_byte_offset, + huffman_byte_offset_cmp: ComparatorChip::configure( + meta, + |meta| meta.query_fixed(q_enable, Rotation::cur()), + |meta| meta.query_advice(huffman_byte_offset, Rotation::prev()), + |meta| meta.query_advice(huffman_byte_offset, Rotation::cur()), + range256.into(), + ), + byte_offset: meta.advice_column(), + is_boundary: meta.advice_column(), + decoded_byte: meta.advice_column(), + decoded_literals_length: meta.advice_column(), + decoded_literals_rlc: meta.advice_column_in(SecondPhase), + }; + + meta.create_gate("DecodedLiteralsTable: first row", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + cb.require_equal( + "init decoded literals RLC", + meta.query_advice(table.decoded_literals_rlc, Rotation::cur()), + meta.query_advice(table.decoded_byte, Rotation::cur()), + ); + cb.require_equal( + "init decoded literals length", + meta.query_advice(table.decoded_literals_length, Rotation::cur()), + 1.expr(), + ); + + cb.gate(and::expr([ + meta.query_fixed(table.q_enable, Rotation::cur()), + meta.query_fixed(table.q_first, Rotation::cur()), + ])) + }); + + meta.create_gate("DecodedLiteralsTable: all rows", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + cb.require_boolean( + "is_boundary is boolean", + meta.query_advice(table.is_boundary, Rotation::cur()), + ); + + cb.gate(meta.query_fixed(table.q_enable, Rotation::cur())) + }); + + meta.create_gate("DecodedLiteralsTable: instance of huffman code", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + cb.require_boolean( + "byte_offset is increasing", + meta.query_advice(table.byte_offset, Rotation::cur()) + - meta.query_advice(table.byte_offset, Rotation::prev()), + ); + + let crossed_boundary = meta.query_advice(table.is_boundary, Rotation::prev()); + + // if not boundary, continue RLC. + cb.condition(not::expr(crossed_boundary.expr()), |cb| { + cb.require_equal( + "no boundary: continue decoded literals RLC", + meta.query_advice(table.decoded_literals_rlc, Rotation::cur()), + meta.query_advice(table.decoded_literals_rlc, Rotation::prev()) + * challenges.keccak_input() + + meta.query_advice(table.decoded_byte, Rotation::cur()), + ); + cb.require_equal( + "no boundary: continue decoded literals length", + meta.query_advice(table.decoded_literals_length, Rotation::cur()), + meta.query_advice(table.decoded_literals_length, Rotation::prev()) + 1.expr(), + ); + }); + + // if boundary, reset RLC. + cb.condition(crossed_boundary.expr(), |cb| { + cb.require_equal( + "crossed boundary: reset decoded literals RLC", + meta.query_advice(table.decoded_literals_rlc, Rotation::cur()), + meta.query_advice(table.decoded_byte, Rotation::cur()), + ); + cb.require_equal( + "crossed boundary: reset decoded literals length", + meta.query_advice(table.decoded_literals_length, Rotation::cur()), + 1.expr(), + ); + }); + + let (_lt, huffman_code_unchanged) = table.huffman_byte_offset_cmp.expr(meta, None); + cb.gate(and::expr([ + meta.query_fixed(table.q_enable, Rotation::cur()), + huffman_code_unchanged, + ])) + }); + + meta.lookup("DecodedLiteralsTable: decoded byte", |meta| { + let condition = meta.query_fixed(table.q_enable, Rotation::cur()); + vec![( + condition * meta.query_advice(table.decoded_byte, Rotation::cur()), + range256.into(), + )] + }); + + table + } + + /// Load witness to the table: dev mode. + pub fn assign(&self, _layouter: &mut impl Layouter) -> Result<(), Error> { + unimplemented!() + } +} + +impl LookupTable for DecodedLiteralsTable { + fn columns(&self) -> Vec> { + vec![ + self.huffman_byte_offset.into(), + self.byte_offset.into(), + self.decoded_byte.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("huffman_byte_offset"), + String::from("byte_offset"), + String::from("decoded_byte"), + ] + } +} diff --git a/zkevm-circuits/src/table/decompression/fse_table.rs b/zkevm-circuits/src/table/decompression/fse_table.rs new file mode 100644 index 0000000000..a4d5f0b8c6 --- /dev/null +++ b/zkevm-circuits/src/table/decompression/fse_table.rs @@ -0,0 +1,528 @@ +use eth_types::Field; +use gadgets::{ + comparator::{ComparatorChip, ComparatorConfig}, + is_equal::{IsEqualChip, IsEqualConfig}, + util::{and, not, Expr}, +}; +use halo2_proofs::{ + circuit::{Layouter, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, + poly::Rotation, +}; + +use crate::{ + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + table::{BitwiseOp, BitwiseOpTable, LookupTable, Pow2Table, RangeTable}, + witness::FseAuxiliaryTableData, +}; + +/// An auxiliary table used to ensure that the FSE table was reconstructed appropriately. Contrary +/// to the FseTable where the state is incremental, in the Auxiliary table we club together rows by +/// symbol. Which means, we will have rows with symbol s0 (and varying, but not necessarily +/// incremental states) clubbed together, followed by symbol s1 and so on. +/// +/// | State | Symbol | Baseline | Nb | Baseline Mark | +/// |-------|--------|----------|-----|---------------| +/// | 0x00 | s0 | ... | ... | 0 | +/// | 0x01 | s0 | ... | ... | 0 | +/// | 0x02 | s0 | ... | ... | 0 | +/// | ... | s0 | ... | ... | ... | +/// | 0x1d | s0 | ... | ... | 0 | +/// | 0x03 | s1 -> | 0x10 | ... | 0 | +/// | 0x0c | s1 -> | 0x18 | ... | 0 | +/// | 0x11 | s1 -> | 0x00 | ... | 1 | +/// | 0x15 | s1 -> | 0x04 | ... | 1 | +/// | 0x1a | s1 -> | 0x08 | ... | 1 | +/// | 0x1e | s1 -> | 0x0c | ... | 1 | +/// | 0x08 | s2 | ... | ... | 0 | +/// | ... | ... | ... | ... | 0 | +/// | 0x09 | s6 | ... | ... | 0 | +/// +/// Above is a representation of this table. Primarily we are interested in verifying that: +/// - next state (for the same symbol) was assigned correctly +/// - the number of times this symbol appears is assigned correctly +/// +/// For more details, refer the [FSE reconstruction][doclink] section. +/// +/// [doclink]: https://nigeltao.github.io/blog/2022/zstandard-part-5-fse.html#fse-reconstruction +#[derive(Clone, Debug)] +pub struct FseTable { + /// Fixed column to denote whether the constraints will be enabled or not. + pub q_enabled: Column, + /// The byte offset within the data instance where the encoded FSE table begins. This is + /// 1-indexed, i.e. byte_offset == 1 at the first byte. + pub byte_offset: Column, + /// Helper gadget to know when we are done handling a single canonical Huffman code. + pub byte_offset_cmp: ComparatorConfig, + /// The size of the FSE table that starts at byte_offset. + pub table_size: Column, + /// Helper column for (table_size >> 1). + pub table_size_rs_1: Column, + /// Helper column for (table_size >> 3). + pub table_size_rs_3: Column, + /// Incremental index. + pub idx: Column, + /// The symbol (weight) assigned to this state. + pub symbol: Column, + /// Helper gadget to know whether the symbol is the same or not. + pub symbol_eq: IsEqualConfig, + /// Represents the number of times this symbol appears in the FSE table. This value does not + /// change while the symbol in the table remains the same. + pub symbol_count: Column, + /// An accumulator that resets to 1 each time we encounter a new symbol in the Auxiliary table + /// and increments by 1 while the symbol remains the same. On the row where symbol' != symbol + /// we have: symbol_count == symbol_count_acc. + pub symbol_count_acc: Column, + /// The state in FSE. In the Auxiliary table, it does not increment by 1. Instead, it follows: + /// - state'' == state + table_size_rs_1 + table_size_rs_3 + 3 + /// - state' == state'' & (table_size - 1) + /// + /// where state' is the next row's state. + pub state: Column, + /// Denotes the baseline field. + pub baseline: Column, + /// Helper column to mark the baseline observed at the last occurence of a symbol. + pub last_baseline: Column, + /// The number of bits to be read from bitstream at this state. + pub nb: Column, + /// The smaller power of two assigned to this state. The following must hold: + /// - 2 ^ nb == SPoT. + pub spot: Column, + /// An accumulator over SPoT value. + pub spot_acc: Column, + /// Helper column to remember the smallest spot for that symbol. + pub smallest_spot: Column, + /// Helper boolean column which is set only from baseline == 0x00. + pub baseline_mark: Column, +} + +impl FseTable { + /// Construct the auxiliary table for FSE codes. + pub fn construct( + meta: &mut ConstraintSystem, + bitwise_op_table: BitwiseOpTable, + pow2_table: Pow2Table, + range8: RangeTable<8>, + range256: RangeTable<256>, + ) -> Self { + let q_enabled = meta.fixed_column(); + let byte_offset = meta.advice_column(); + let symbol = meta.advice_column(); + let spot = meta.advice_column(); + let smallest_spot = meta.advice_column(); + let table = Self { + q_enabled, + byte_offset, + byte_offset_cmp: ComparatorChip::configure( + meta, + |meta| meta.query_fixed(q_enabled, Rotation::cur()), + |meta| meta.query_advice(byte_offset, Rotation::cur()), + |meta| meta.query_advice(byte_offset, Rotation::next()), + range256.into(), + ), + table_size: meta.advice_column(), + table_size_rs_1: meta.advice_column(), + table_size_rs_3: meta.advice_column(), + idx: meta.advice_column(), + symbol, + symbol_eq: IsEqualChip::configure( + meta, + |meta| meta.query_fixed(q_enabled, Rotation::cur()), + |meta| meta.query_advice(symbol, Rotation::cur()), + |meta| meta.query_advice(symbol, Rotation::next()), + ), + symbol_count: meta.advice_column(), + symbol_count_acc: meta.advice_column(), + state: meta.advice_column(), + baseline: meta.advice_column(), + last_baseline: meta.advice_column(), + nb: meta.advice_column(), + spot, + spot_acc: meta.advice_column(), + smallest_spot, + baseline_mark: meta.advice_column(), + }; + + // All rows. + meta.create_gate("FseAuxiliaryTable: all rows", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + cb.require_boolean( + "baseline_mark == [0, 1]", + meta.query_advice(table.baseline_mark, Rotation::cur()), + ); + + let (gt, eq) = table.byte_offset_cmp.expr(meta, None); + cb.require_equal("byte offset is increasing", gt + eq, 1.expr()); + + cb.gate(meta.query_fixed(table.q_enabled, Rotation::cur())) + }); + + // Validate SPoT assignment: all rows. + meta.lookup_any("FseAuxiliaryTable: SPoT == 2 ^ Nb", |meta| { + let condition = meta.query_fixed(table.q_enabled, Rotation::cur()); + + [ + meta.query_advice(table.nb, Rotation::cur()), + meta.query_advice(table.spot, Rotation::cur()), + ] + .into_iter() + .zip(pow2_table.table_exprs(meta)) + .map(|(input, table)| (input * condition.clone(), table)) + .collect::>() + }); + + // Constraints while traversing an FSE table. + meta.create_gate("FseAuxiliaryTable: table size and helper columns", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // Table size, and the right-shifted helper values remain unchanged. + for col in [ + table.table_size, + table.table_size_rs_1, + table.table_size_rs_3, + ] { + cb.require_equal( + "while byte_offset' == byte_offset: table_size and helpers remain unchanged", + meta.query_advice(col, Rotation::next()), + meta.query_advice(col, Rotation::cur()), + ); + } + + // Index is incremental. + cb.require_equal( + "idx' == idx + 1", + meta.query_advice(table.idx, Rotation::next()), + meta.query_advice(table.idx, Rotation::cur()) + 1.expr(), + ); + + cb.require_boolean( + "symbol' == symbol or symbol' == symbol + 1", + meta.query_advice(table.symbol, Rotation::next()) + - meta.query_advice(table.symbol, Rotation::cur()), + ); + + let (_gt, eq) = table.byte_offset_cmp.expr(meta, None); + cb.gate(and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + eq, + ])) + }); + + // Constraints for last row of an FSE table. + meta.create_gate("FseAuxiliaryTable: table shift right ops", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // Constraint for table_size >> 1. + cb.require_boolean( + "table_size >> 1", + meta.query_advice(table.table_size, Rotation::cur()) + - (meta.query_advice(table.table_size_rs_1, Rotation::cur()) * 2.expr()), + ); + + // Constraint for idx == table_size. + cb.require_equal( + "idx == table_size", + meta.query_advice(table.idx, Rotation::cur()), + meta.query_advice(table.table_size, Rotation::cur()), + ); + + let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); + cb.gate(and::expr([ + meta.query_fixed(q_enabled, Rotation::cur()), + gt, + ])) + }); + + // Constraint for table_size >> 3. Only check on the last row. + meta.lookup("FseAuxiliaryTable: table shift right ops", |meta| { + let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); + let condition = and::expr([meta.query_fixed(q_enabled, Rotation::cur()), gt]); + + let range_value = meta.query_advice(table.table_size, Rotation::cur()) + - (meta.query_advice(table.table_size_rs_3, Rotation::cur()) * 8.expr()); + + vec![(condition * range_value, range8.into())] + }); + + // Constraint for state' calculation. We wish to constrain: + // + // - state' == state'' & (table_size - 1) + // - state'' == state + (table_size >> 3) + (table_size >> 1) + 3 + meta.lookup_any("FseAuxiliaryTable: next state computation", |meta| { + let (_gt, eq) = table.byte_offset_cmp.expr(meta, None); + let condition = and::expr([meta.query_fixed(table.q_enabled, Rotation::cur()), eq]); + + let lhs = meta.query_advice(table.state, Rotation::cur()) + + meta.query_advice(table.table_size_rs_3, Rotation::cur()) + + meta.query_advice(table.table_size_rs_1, Rotation::cur()) + + 3.expr(); + let rhs = meta.query_advice(table.table_size, Rotation::cur()) - 1.expr(); + let output = meta.query_advice(table.state, Rotation::next()); + + [BitwiseOp::AND.expr(), lhs, rhs, output] + .into_iter() + .zip(bitwise_op_table.table_exprs(meta)) + .map(|(input, table)| (input * condition.clone(), table)) + .collect::>() + }); + + // Constraints for same FSE table and same symbol. + meta.create_gate("FseAuxiliaryTable: symbol' == symbol", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // Symbol's count remains unchanged while symbol remained unchanged. + cb.require_equal( + "if symbol' == symbol: symbol_count' == symbol_count", + meta.query_advice(table.symbol_count, Rotation::next()), + meta.query_advice(table.symbol_count, Rotation::cur()), + ); + + // SPoT at baseline == 0x00 remains unchanged over these rows. + cb.require_equal( + "if symbol' == symbol: smallest SPoT is unchanged", + meta.query_advice(table.smallest_spot, Rotation::next()), + meta.query_advice(table.smallest_spot, Rotation::cur()), + ); + + // last baseline remains unchanged over these rows. + cb.require_equal( + "if symbol' == symbol: last baseline is unchanged", + meta.query_advice(table.last_baseline, Rotation::next()), + meta.query_advice(table.last_baseline, Rotation::cur()), + ); + + // Symbol count accumulator increments. + cb.require_equal( + "if symbol' == symbol: symbol count accumulator increments", + meta.query_advice(table.symbol_count_acc, Rotation::next()), + meta.query_advice(table.symbol_count_acc, Rotation::cur()) + 1.expr(), + ); + + // SPoT accumulation. + cb.require_equal( + "SPoT_acc::next == SPoT_acc::cur + SPoT::next", + meta.query_advice(table.spot_acc, Rotation::next()), + meta.query_advice(table.spot_acc, Rotation::cur()) + + meta.query_advice(table.spot, Rotation::next()), + ); + + // baseline_mark can only transition from 0 to 1 once. + cb.require_boolean( + "baseline_mark transition", + meta.query_advice(table.baseline_mark, Rotation::next()) + - meta.query_advice(table.baseline_mark, Rotation::cur()), + ); + + let is_next_baseline_0x00 = meta.query_advice(table.baseline_mark, Rotation::next()) + - meta.query_advice(table.baseline_mark, Rotation::cur()); + cb.condition(is_next_baseline_0x00.expr(), |cb| { + cb.require_equal( + "baseline::next == 0x00", + meta.query_advice(table.baseline, Rotation::next()), + 0x00.expr(), + ); + }); + cb.condition(not::expr(is_next_baseline_0x00.expr()), |cb| { + cb.require_equal( + "baseline::next == baseline::cur + spot::cur", + meta.query_advice(table.baseline, Rotation::next()), + meta.query_advice(table.baseline, Rotation::cur()) + + meta.query_advice(table.spot, Rotation::cur()), + ); + }); + + let (_gt, eq) = table.byte_offset_cmp.expr(meta, None); + cb.gate(and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + eq, + table.symbol_eq.expr(), + ])) + }); + + // Constraints when symbol changes in an FSE table, i.e. symbol' != symbol. + meta.create_gate("FseAuxiliaryTable: symbol' != symbol", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // Constraint for idx == table_size. + cb.require_equal( + "symbol_count_acc == symbol_count", + meta.query_advice(table.symbol_count_acc, Rotation::cur()), + meta.query_advice(table.symbol_count, Rotation::cur()), + ); + + // SPoT accumulator == table_size at the end of processing the symbol. + cb.require_equal( + "SPoT_acc == table_size", + meta.query_advice(table.spot_acc, Rotation::cur()), + meta.query_advice(table.table_size, Rotation::cur()), + ); + + // The SPoT at baseline == 0x00 matches this SPoT. + cb.require_equal( + "last symbol occurrence => SPoT == SPoT at baseline 0x00", + meta.query_advice(table.smallest_spot, Rotation::cur()), + meta.query_advice(table.spot, Rotation::cur()), + ); + + // last baseline matches. + cb.require_equal( + "baseline == last_baseline", + meta.query_advice(table.baseline, Rotation::cur()), + meta.query_advice(table.last_baseline, Rotation::cur()), + ); + + cb.gate(and::expr([ + meta.query_fixed(q_enabled, Rotation::cur()), + not::expr(table.symbol_eq.expr()), + ])) + }); + + // Constraints for the first occurence of a particular symbol in the table. + meta.create_gate("FseAuxiliaryTable: new symbol", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + let is_baseline_marked = meta.query_advice(table.baseline_mark, Rotation::cur()); + cb.condition(is_baseline_marked.expr(), |cb| { + cb.require_equal( + "baseline == 0x00", + meta.query_advice(table.baseline, Rotation::cur()), + 0x00.expr(), + ); + }); + + cb.condition(not::expr(is_baseline_marked.expr()), |cb| { + cb.require_equal( + "baseline == last_baseline + smallest_spot", + meta.query_advice(table.baseline, Rotation::cur()), + meta.query_advice(table.last_baseline, Rotation::cur()) + + meta.query_advice(table.smallest_spot, Rotation::cur()), + ); + }); + + let symbol_prev = meta.query_advice(table.symbol, Rotation::prev()); + let symbol_cur = meta.query_advice(table.symbol, Rotation::cur()); + cb.gate(and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + not::expr( + table + .symbol_eq + .expr_at(meta, Rotation::prev(), symbol_prev, symbol_cur), + ), + ])) + }); + + debug_assert!(meta.degree() <= 9); + + table + } + + /// Load witness. + pub fn assign( + &self, + layouter: &mut impl Layouter, + data: Vec, + ) -> Result<(), Error> { + layouter.assign_region( + || "FseAuxiliaryTable: dev load", + |mut region| { + let mut offset = 0; + for table in data.iter() { + let byte_offset = Value::known(F::from(table.byte_offset)); + let table_size = Value::known(F::from(table.table_size)); + let table_size_rs_1 = Value::known(F::from(table.table_size >> 1)); + let table_size_rs_3 = Value::known(F::from(table.table_size >> 3)); + for (&symbol, rows) in table.sym_to_states.iter() { + let symbol_count = rows.len() as u64; + let smallest_spot = rows + .iter() + .map(|fse_row| 1 << fse_row.num_bits) + .min() + .expect("symbol should have at least 1 row"); + let spot_acc_iter = rows.iter().scan(0, |spot_acc, fse_row| { + *spot_acc += 1 << fse_row.num_bits; + Some(*spot_acc) + }); + // TODO: byte_offset_cmp + // TODO: symbol_eq + // TODO: baseline_mark + // TODO: last_baseline + // TODO: q_enabled + for (i, (fse_row, spot_acc)) in rows.iter().zip(spot_acc_iter).enumerate() { + for (annotation, col, value) in [ + ("byte_offset", self.byte_offset, byte_offset), + ("table_size", self.table_size, table_size), + ("table_size_rs_1", self.table_size_rs_1, table_size_rs_1), + ("table_size_rs_3", self.table_size_rs_3, table_size_rs_3), + ("symbol", self.symbol, Value::known(F::from(symbol as u64))), + ( + "symbol_count", + self.symbol_count, + Value::known(F::from(symbol_count)), + ), + ( + "symbol_count_acc", + self.symbol_count_acc, + Value::known(F::from(i as u64 + 1)), + ), + ("state", self.state, Value::known(F::from(fse_row.state))), + ( + "baseline", + self.baseline, + Value::known(F::from(fse_row.baseline)), + ), + ("nb", self.nb, Value::known(F::from(fse_row.num_bits))), + ( + "spot", + self.spot, + Value::known(F::from(1 << fse_row.num_bits)), + ), + ( + "smallest_spot", + self.smallest_spot, + Value::known(F::from(smallest_spot)), + ), + ("spot_acc", self.spot_acc, Value::known(F::from(spot_acc))), + ("idx", self.idx, Value::known(F::from(fse_row.idx))), + ] { + region.assign_advice( + || format!("FseAuxiliaryTable: {}", annotation), + col, + offset, + || value, + )?; + } + offset += 1; + } + } + } + + Ok(()) + }, + ) + } +} + +impl FseTable { + /// Lookup table expressions for (state, symbol) tuple check. + pub fn table_exprs_state_check(&self, meta: &mut VirtualCells) -> Vec> { + vec![ + meta.query_advice(self.byte_offset, Rotation::cur()), + meta.query_advice(self.table_size, Rotation::cur()), + meta.query_advice(self.state, Rotation::cur()), + meta.query_advice(self.symbol, Rotation::cur()), + meta.query_advice(self.baseline, Rotation::cur()), + meta.query_advice(self.nb, Rotation::cur()), + ] + } + + /// Lookup table expressions for (symbol, symbol_count) tuple check. + pub fn table_exprs_symbol_count_check(&self, meta: &mut VirtualCells) -> Vec> { + vec![ + meta.query_advice(self.byte_offset, Rotation::cur()), + meta.query_advice(self.table_size, Rotation::cur()), + meta.query_advice(self.symbol, Rotation::cur()), + meta.query_advice(self.symbol_count, Rotation::cur()), + ] + } +} diff --git a/zkevm-circuits/src/table/decompression/huffman_codes_table.rs b/zkevm-circuits/src/table/decompression/huffman_codes_table.rs new file mode 100644 index 0000000000..6f9ad11570 --- /dev/null +++ b/zkevm-circuits/src/table/decompression/huffman_codes_table.rs @@ -0,0 +1,563 @@ +use array_init::array_init; +use eth_types::Field; +use gadgets::{ + binary_number::{BinaryNumberChip, BinaryNumberConfig}, + comparator::{ComparatorChip, ComparatorConfig, ComparatorInstruction}, + util::{and, not, Expr}, +}; +use halo2_proofs::{ + circuit::{Layouter, Value}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, + poly::Rotation, +}; +use strum::IntoEnumIterator; + +use crate::{ + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + table::{LookupTable, Pow2Table, RangeTable}, + witness::{FseSymbol, HuffmanCodesData, N_BITS_SYMBOL, N_MAX_SYMBOLS}, +}; + +/// The Huffman codes table maps the canonical weights (symbols as per FseTable) to the Huffman +/// codes. +#[derive(Clone, Debug)] +pub struct HuffmanCodesTable { + /// Fixed column to denote whether the constraints will be enabled or not. + pub q_enabled: Column, + /// Fixed column to mark the first row in the table. + pub q_first: Column, + /// Set when this is the start of a new huffman code. + pub is_start: Column, + /// The byte offset within the data instance where the encoded FSE table begins. This is + /// 1-indexed, i.e. byte_offset == 1 at the first byte. + pub byte_offset: Column, + /// Helper gadget to know when we are done handling a single canonical Huffman code. + pub byte_offset_cmp: ComparatorConfig, + /// The byte that is being encoded by a Huffman code. + pub symbol: Column, + /// The weight assigned to this symbol as per the canonical Huffman code weights. + pub weight: Column, + /// A binary representation of the weight's value. + pub weight_bits: BinaryNumberConfig, + /// An accumulator over the weight values. + pub weight_acc: Column, + /// Helper column to denote 2 ^ (weight - 1). + pub pow2_weight: Column, + /// The sum of canonical Huffman code weights. This value does not change over the rows for a + /// specific Huffman code. + pub sum_weights: Column, + /// The maximum length of a bitstring as per this Huffman code. Again, this value does not + /// change over the rows for a specific Huffman code. + pub max_bitstring_len: Column, + /// As per Huffman coding, every symbol is mapped to a bit value, which is then represented in + /// binary form (padded) of length bitstring_len. + pub bit_value: Column, + /// The last seen bit_value for each symbol in this Huffman coding. + pub last_bit_values: [Column; N_MAX_SYMBOLS], + /// The last_bit_values assigned at the first row of a table. + pub first_lbvs: [Column; N_MAX_SYMBOLS], +} + +impl HuffmanCodesTable { + /// Construct the huffman codes table. + pub fn construct( + meta: &mut ConstraintSystem, + pow2_table: Pow2Table, + range256: RangeTable<256>, + ) -> Self { + let q_enabled = meta.fixed_column(); + let byte_offset = meta.advice_column(); + let weight = meta.advice_column(); + let table = Self { + q_enabled, + q_first: meta.fixed_column(), + byte_offset, + byte_offset_cmp: ComparatorChip::configure( + meta, + |meta| meta.query_fixed(q_enabled, Rotation::cur()), + |meta| meta.query_advice(byte_offset, Rotation::cur()), + |meta| meta.query_advice(byte_offset, Rotation::next()), + range256.into(), + ), + is_start: meta.advice_column(), + symbol: meta.advice_column(), + weight, + weight_bits: BinaryNumberChip::configure(meta, q_enabled, Some(weight.into())), + pow2_weight: meta.advice_column(), + weight_acc: meta.advice_column(), + sum_weights: meta.advice_column(), + max_bitstring_len: meta.advice_column(), + bit_value: meta.advice_column(), + last_bit_values: array_init(|_| meta.advice_column()), + first_lbvs: array_init(|_| meta.advice_column()), + }; + + // TODO: constrain is_start + + // All rows + meta.create_gate("HuffmanCodesTable: all rows", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + let (gt, eq) = table.byte_offset_cmp.expr(meta, None); + cb.require_equal("byte_offset' >= byte_offset", gt + eq, 1.expr()); + + // Weight == 0 implies the bit value is 0. + cb.condition( + table + .weight_bits + .value_equals(FseSymbol::S0, Rotation::cur())(meta), + |cb| { + cb.require_zero( + "bit value == 0", + meta.query_advice(table.bit_value, Rotation::cur()), + ); + }, + ); + + // Last bit value at weight == 0 is also 0. + cb.require_zero( + "last_bit_values[0] == 0", + meta.query_advice( + table.last_bit_values[FseSymbol::S0 as usize], + Rotation::cur(), + ), + ); + + cb.gate(meta.query_fixed(table.q_enabled, Rotation::cur())) + }); + + // The first row of the HuffmanCodesTable. + meta.create_gate("HuffmanCodesTable: first (fixed) row", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // Canonical Huffman code starts with the weight of the first symbol, i.e. 0x00. + cb.require_equal( + "symbol == 0x00", + meta.query_advice(table.symbol, Rotation::cur()), + 0x00.expr(), + ); + + // Weight accumulation starts with the first weight. + cb.require_equal( + "weight_acc == 2^(weight - 1)", + meta.query_advice(table.weight_acc, Rotation::cur()), + meta.query_advice(table.pow2_weight, Rotation::cur()), + ); + + // Constrain the last bit_value of the maximum bitstring length. Maximum bitstring + // length implies weight == 1. + cb.require_zero( + "if first row: last_bit_values[1] == 0", + meta.query_advice( + table.last_bit_values[FseSymbol::S1 as usize], + Rotation::cur(), + ), + ); + + // Do an equality check for the last_bit_values at the first row. + for i in FseSymbol::iter() { + cb.require_equal( + "last bit value at the first row equality check", + meta.query_advice(table.last_bit_values[i as usize], Rotation::cur()), + meta.query_advice(table.first_lbvs[i as usize], Rotation::cur()), + ); + } + + cb.gate(and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + meta.query_fixed(table.q_first, Rotation::cur()), + ])) + }); + + // While we are processing the weights of a particular canonical Huffman code + // representation, i.e. byte_offset == byte_offset'. + meta.create_gate( + "HuffmanCodesTable: traversing a canonical huffman coding table", + |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // Sum of weights remains the same across all rows. + cb.require_equal( + "sum_weights' == sum_weights", + meta.query_advice(table.sum_weights, Rotation::next()), + meta.query_advice(table.sum_weights, Rotation::cur()), + ); + + // Maximum bitstring length remains the same across all rows. + cb.require_equal( + "max_bitstring_len' == max_bitstring_len", + meta.query_advice(table.max_bitstring_len, Rotation::next()), + meta.query_advice(table.max_bitstring_len, Rotation::cur()), + ); + + // The first row's last_bit_values remain the same. + for col in table.first_lbvs { + cb.require_equal( + "first_lbvs[i]' == first_lbvs[i]", + meta.query_advice(col, Rotation::next()), + meta.query_advice(col, Rotation::cur()), + ); + } + + // Weight accumulation is assigned correctly. + cb.require_equal( + "weight_acc' == weight_acc + 2^(weight - 1)", + meta.query_advice(table.weight_acc, Rotation::next()), + meta.query_advice(table.weight_acc, Rotation::cur()) + + meta.query_advice(table.pow2_weight, Rotation::next()), + ); + + // pow2_weight is assigned correctly for weight == 0. + cb.condition( + table + .weight_bits + .value_equals(FseSymbol::S0, Rotation::cur())(meta), + |cb| { + cb.require_zero( + "pow2_weight == 0 if weight == 0", + meta.query_advice(table.pow2_weight, Rotation::cur()), + ); + }, + ); + + // For all rows (except the first row of a canonical Huffman code representation, we + // want to ensure the last_bit_values was assigned correctly. + let is_start = meta.query_advice(table.is_start, Rotation::cur()); + cb.condition(not::expr(is_start.expr()), |cb| { + for (symbol, &last_bit_value) in + FseSymbol::iter().zip(table.last_bit_values.iter()) + { + cb.require_equal( + "last_bit_value_i::cur == last_bit_value::prev + (weight::cur == i)", + meta.query_advice(last_bit_value, Rotation::cur()), + meta.query_advice(last_bit_value, Rotation::prev()) + + table.weight_bits.value_equals(symbol, Rotation::cur())(meta), + ); + } + }); + + let (_gt, eq) = table.byte_offset_cmp.expr(meta, None); + cb.gate(and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + eq, + ])) + }, + ); + + // For every row, we want the pow2_weight column to be assigned correctly. We want: + // + // pow2_weight == 2^(weight - 1). + // + // Note that this is valid only if weight > 0. For weight == 0, we want pow2_weight == 0. + meta.lookup_any("HuffmanCodesTable: pow2_weight assignment", |meta| { + let condition = and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + not::expr(table + .weight_bits + .value_equals(FseSymbol::S0, Rotation::cur())( + meta + )), + // TODO: add padding column. + ]); + + let exponent = meta.query_advice(table.weight, Rotation::cur()) - 1.expr(); + let exponentiation = meta.query_advice(table.pow2_weight, Rotation::cur()); + + [exponent, exponentiation] + .into_iter() + .zip(pow2_table.table_exprs(meta)) + .map(|(input, table)| (input * condition.clone(), table)) + .collect::>() + }); + + // When we end processing a huffman code, i.e. the byte_offset changes. No need to check if + // the next row is padding or not. + meta.create_gate("HuffmanCodesTable: end of huffman code", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // The total sum of weights is in fact the accumulated weight. + cb.require_equal( + "sum_weights == weight_acc", + meta.query_advice(table.sum_weights, Rotation::cur()), + meta.query_advice(table.weight_acc, Rotation::cur()), + ); + + // We want to check the following: + // + // if lbv_1: The last bit_value for weight i on the first row. + // if lbv_2: The last bit_value for weight i+1 on the last row. + // + // then lbv_2 == (lbv_1 + 1) // 2 + // i.e. lbv_2 * 2 - lbv_1 is boolean. + // + // Note: we only do this check for weight > 0, hence we skip the FseSymbol::S0. + for i in [ + FseSymbol::S1, + FseSymbol::S2, + FseSymbol::S3, + FseSymbol::S4, + FseSymbol::S5, + FseSymbol::S6, + ] { + let i = i as usize; + let lbv_1 = meta.query_advice(table.first_lbvs[i], Rotation::cur()); + let lbv_2 = meta.query_advice(table.last_bit_values[i + 1], Rotation::cur()); + cb.require_boolean( + "last bit value check for weights i and i+1 on the first and last rows", + lbv_2 * 2.expr() - lbv_1, + ); + } + + let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); + cb.gate(and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + gt, + ])) + }); + + // The weight for the last symbol is assigned appropriately. The weight for the last + // symbol should satisfy: + // + // last_weight == log2(nearest_pow2 - sum_weights) + 1 + // where nearest_pow2 is the nearest power of 2 greater than the sum of weights so far. + // + // i.e. 2^(last_weight - 1) + sum_weights == 2^(max_bitstring_len) + meta.lookup_any("HuffmanCodesTable: weight of the last symbol", |meta| { + let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); + let condition = and::expr([meta.query_fixed(table.q_enabled, Rotation::cur()), gt]); + + let exponent = meta.query_advice(table.max_bitstring_len, Rotation::cur()); + let exponentiation = meta.query_advice(table.pow2_weight, Rotation::cur()) + + meta.query_advice(table.sum_weights, Rotation::prev()); + + [exponent, exponentiation] + .into_iter() + .zip(pow2_table.table_exprs(meta)) + .map(|(input, table)| (input * condition.clone(), table)) + .collect::>() + }); + + // When we transition from one Huffman code to another, i.e. the byte_offset changes. We + // also check that the next row is not a padding row. + // + // TODO: add the padding column. + meta.create_gate("HuffmanCodesTable: new huffman code", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + // Marks the start of a new huffman code. + cb.require_equal( + "is_start == 1", + meta.query_advice(table.is_start, Rotation::next()), + 1.expr(), + ); + + // Canonical Huffman code starts with the weight of the first symbol, i.e. 0x00. + cb.require_equal( + "symbol == 0x00", + meta.query_advice(table.symbol, Rotation::next()), + 0x00.expr(), + ); + + // Weight accumulation starts with the first weight. + cb.require_equal( + "weight_acc == 2^(weight - 1)", + meta.query_advice(table.weight_acc, Rotation::next()), + meta.query_advice(table.pow2_weight, Rotation::next()), + ); + + // Constrain the last bit_value of the maximum bitstring length. Maximum bitstring + // length implies weight == 1. + cb.require_zero( + "if first row: last_bit_values[1] == 0", + meta.query_advice( + table.last_bit_values[FseSymbol::S1 as usize], + Rotation::next(), + ), + ); + + // Do an equality check for the last_bit_values at the first row. + for i in FseSymbol::iter() { + cb.require_equal( + "last bit value at the first row equality check", + meta.query_advice(table.last_bit_values[i as usize], Rotation::next()), + meta.query_advice(table.first_lbvs[i as usize], Rotation::next()), + ); + } + + let (gt, _eq) = table.byte_offset_cmp.expr(meta, None); + cb.gate(and::expr([ + meta.query_fixed(table.q_enabled, Rotation::cur()), + meta.query_fixed(table.q_enabled, Rotation::next()), + gt, + ])) + }); + + debug_assert!(meta.degree() <= 9); + + table + } + + /// Load witness to the huffman codes table: dev mode. + pub fn assign( + &self, + layouter: &mut impl Layouter, + data: Vec, + ) -> Result<(), Error> { + layouter.assign_region( + || "HuffmanCodesTable: dev load", + |mut region| { + let weight_bits = BinaryNumberChip::construct(self.weight_bits); + let mut offset = 0; + for code in data.iter() { + let byte_offset = Value::known(F::from(code.byte_offset)); + let (max_bitstring_len, sym_map) = code.parse_canonical(); + + let max_bitstring_len = Value::known(F::from(max_bitstring_len)); + let sum_weights = Value::known(F::from( + sym_map + .values() + .map(|(weight, _bit_value)| weight) + .sum::(), + )); + let weight_acc_iter = sym_map.values().scan(0, |acc, (weight, _bit_value)| { + *acc += weight; + Some(*acc) + }); + + for (i, weight_acc) in weight_acc_iter.enumerate() { + region.assign_advice( + || "HuffmanCodesTable: weight_acc", + self.weight_acc, + offset + i, + || Value::known(F::from(weight_acc)), + )?; + } + for (&symbol, &(weight, bit_value)) in sym_map.iter() { + for (annotation, column, value) in [ + ("byte_offset", self.byte_offset, byte_offset), + ( + "max_bitstring_len", + self.max_bitstring_len, + max_bitstring_len, + ), + ("sum_weights", self.sum_weights, sum_weights), + ("symbol", self.symbol, Value::known(F::from(symbol))), + ("weight", self.weight, Value::known(F::from(weight))), + ( + "bit_value", + self.bit_value, + Value::known(F::from(bit_value)), + ), + ( + "pow2_weight", + self.pow2_weight, + Value::known(F::from(if weight > 0 { + (weight - 1).pow(2) + } else { + 0 + })), + ), + ] { + region.assign_advice( + || format!("HuffmanCodesTable: {annotation}"), + column, + offset, + || value, + )?; + } + let fse_symbol: FseSymbol = (weight as usize).into(); + weight_bits.assign(&mut region, offset, &fse_symbol)?; + + offset += 1; + } + + // TODO: assign last_bit_values + } + + // Assign the byte offset comparison gadget. + let cmp_chip = ComparatorChip::construct(self.byte_offset_cmp.clone()); + offset = 0; + + // if there is a single table. + if data.len() == 1 { + let byte_offset = data[0].byte_offset; + let n_rows = data[0].weights.len() + 1; + for _ in 0..n_rows - 1 { + cmp_chip.assign( + &mut region, + offset, + F::from(byte_offset), + F::from(byte_offset), + )?; + offset += 1; + } + cmp_chip.assign(&mut region, offset, F::from(byte_offset), F::zero())?; + } + + // if there are multiple tables. + if data.len() > 1 { + for window in data.windows(2) { + let byte_offset_1 = window[0].byte_offset; + let byte_offset_2 = window[1].byte_offset; + let n_rows = window[0].weights.len() + 1; + for _ in 0..n_rows - 1 { + cmp_chip.assign( + &mut region, + offset, + F::from(byte_offset_1), + F::from(byte_offset_1), + )?; + offset += 1; + } + cmp_chip.assign( + &mut region, + offset, + F::from(byte_offset_1), + F::from(byte_offset_2), + )?; + offset += 1; + } + // handle the last table. + if let Some(last_table) = data.last() { + let byte_offset = last_table.byte_offset; + let n_rows = last_table.weights.len() + 1; + for _ in 0..n_rows - 1 { + cmp_chip.assign( + &mut region, + offset, + F::from(byte_offset), + F::from(byte_offset), + )?; + offset += 1; + } + cmp_chip.assign(&mut region, offset, F::from(byte_offset), F::zero())?; + } + } + + Ok(()) + }, + ) + } +} + +impl HuffmanCodesTable { + /// Lookup the canonical weight assigned to a symbol in the Huffman code with the header at + /// the given byte_offset. + pub fn table_exprs_canonical_weight(&self, meta: &mut VirtualCells) -> Vec> { + vec![ + meta.query_advice(self.byte_offset, Rotation::cur()), + meta.query_advice(self.symbol, Rotation::cur()), + meta.query_advice(self.weight, Rotation::cur()), + ] + } + + /// Lookup the number of symbols that are present in the canonical representation of the + /// Huffman code. + pub fn table_exprs_weights_count(&self, meta: &mut VirtualCells) -> Vec> { + vec![ + meta.query_advice(self.byte_offset, Rotation::cur()), + meta.query_advice(self.symbol, Rotation::cur()), + // TODO: add is_last to mark the last row of a specific Huffman code. + ] + } +} diff --git a/zkevm-circuits/src/table/decompression/literals_header_rom_table.rs b/zkevm-circuits/src/table/decompression/literals_header_rom_table.rs new file mode 100644 index 0000000000..c0e69a9d73 --- /dev/null +++ b/zkevm-circuits/src/table/decompression/literals_header_rom_table.rs @@ -0,0 +1,123 @@ +use eth_types::Field; +use halo2_proofs::{ + circuit::{Layouter, Value}, + plonk::{Any, Column, ConstraintSystem, Error, Fixed}, +}; + +use crate::table::LookupTable; + +/// Read-only memory table for zstd block's literals header. +#[derive(Clone, Copy, Debug)] +pub struct LiteralsHeaderRomTable { + /// Block type first bit. + block_type_bit0: Column, + /// Block type second bit. + block_type_bit1: Column, + /// Size format first bit. + size_format_bit0: Column, + /// Size format second bit. + size_format_bit1: Column, + /// Number of bytes occupied by the literals header. + n_bytes_header: Column, + /// Number of literal streams to be decoded. + n_lstreams: Column, + /// The branch we take to decompose the literals header. There are a total of 7 branches that + /// can be used to decompose the literals header, namely: + /// + /// - block_type == Raw/RLE and size_format == 00 or 10 + /// - block_type == Raw/RLE and size_format == 01 + /// - block_type == Raw/RLE and size_format == 11 + /// - block_type == Compressed and size_format == 00 or 01 + /// - block_type == Compressed and size_format == 10 + /// - block_type == Compressed and size_format == 11 + branch: Column, + // size format == 0b11? + is_size_format_0b11: Column, +} + +impl LookupTable for LiteralsHeaderRomTable { + fn columns(&self) -> Vec> { + vec![ + self.block_type_bit0.into(), + self.block_type_bit1.into(), + self.size_format_bit0.into(), + self.size_format_bit1.into(), + self.n_bytes_header.into(), + self.n_lstreams.into(), + self.branch.into(), + self.is_size_format_0b11.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("block_type_bit0"), + String::from("block_type_bit1"), + String::from("size_format_bit0"), + String::from("size_format_bit1"), + String::from("n_bytes_header"), + String::from("n_lstreams"), + String::from("branch"), + String::from("is_size_format_0b11"), + ] + } +} + +impl LiteralsHeaderRomTable { + /// Construct the ROM table. + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + block_type_bit0: meta.fixed_column(), + block_type_bit1: meta.fixed_column(), + size_format_bit0: meta.fixed_column(), + size_format_bit1: meta.fixed_column(), + n_bytes_header: meta.fixed_column(), + n_lstreams: meta.fixed_column(), + branch: meta.fixed_column(), + is_size_format_0b11: meta.fixed_column(), + } + } + + /// Load the ROM table. + pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + layouter.assign_region( + || "LiteralsHeader ROM table", + |mut region| { + // Refer: https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#literals_section_header + for (i, row) in [ + [0, 0, 0, 0, 1, 0, 0, 0], // Raw: 1 byte header + [0, 0, 0, 1, 1, 0, 0, 0], // Raw: 1 byte header + [0, 0, 1, 0, 2, 0, 1, 0], // Raw: 2 bytes header + [0, 0, 1, 1, 3, 0, 2, 1], // Raw: 3 bytes header + [1, 0, 0, 0, 1, 0, 0, 0], // RLE: 1 byte header + [1, 0, 0, 1, 1, 0, 0, 0], // RLE: 1 byte header + [1, 0, 1, 0, 2, 0, 1, 0], // RLE: 2 bytes header + [1, 0, 1, 1, 3, 0, 2, 1], // RLE: 3 bytes header + [0, 1, 0, 0, 3, 0, 3, 0], // Compressed: 3 bytes header + [0, 1, 1, 0, 3, 1, 3, 0], // Compressed: 3 bytes header + [0, 1, 0, 1, 4, 1, 4, 0], // Compressed: 4 bytes header + [0, 1, 1, 1, 5, 1, 5, 1], // Compressed: 5 bytes header + ] + .iter() + .enumerate() + { + for (&column, (&value, annotation)) in + >::fixed_columns(self).iter().zip( + row.iter() + .zip(>::annotations(self).iter()), + ) + { + region.assign_fixed( + || format!("{annotation} at offset={i}"), + column, + i, + || Value::known(F::from(value)), + )?; + } + } + + Ok(()) + }, + ) + } +} diff --git a/zkevm-circuits/src/table/decompression/literals_header_table.rs b/zkevm-circuits/src/table/decompression/literals_header_table.rs new file mode 100644 index 0000000000..666c936c67 --- /dev/null +++ b/zkevm-circuits/src/table/decompression/literals_header_table.rs @@ -0,0 +1,451 @@ +use eth_types::Field; +use gadgets::{ + binary_number::{BinaryNumberChip, BinaryNumberConfig}, + impl_expr, + util::{and, not, Expr}, +}; +use halo2_proofs::{ + circuit::{Layouter, Value}, + plonk::{Advice, Any, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, + poly::Rotation, +}; +use strum_macros::EnumIter; + +use crate::{ + evm_circuit::util::constraint_builder::{BaseConstraintBuilder, ConstrainBuilderCommon}, + table::{BitwiseOp, BitwiseOpTable, LookupTable, RangeTable}, +}; + +/// Different branches that can be taken while calculating regenerated size and compressed size in +/// the Literals Header. +#[derive(Clone, Copy, Debug, EnumIter)] +pub enum LiteralsHeaderBranch { + /// Raw/RLE block type with size_format 00 or 10. + RawRle0 = 0, + /// Raw/RLE block type with size format 10. + RawRle1, + /// Raw/RLE block type with size format 11. + RawRle2, + /// Compressed block type with size format 00 or 01. + Compressed0, + /// Compressed block type with size format 10. + Compressed1, + /// Compressed block type with size format 11. + Compressed2, +} + +impl_expr!(LiteralsHeaderBranch); + +impl From for LiteralsHeaderBranch { + fn from(value: u64) -> Self { + match value { + 0 => Self::RawRle0, + 1 => Self::RawRle1, + 2 => Self::RawRle2, + 3 => Self::Compressed0, + 4 => Self::Compressed1, + 5 => Self::Compressed2, + _ => unreachable!("LiteralsHeaderBranch only from 0..=5"), + } + } +} + +impl From for usize { + fn from(value: LiteralsHeaderBranch) -> Self { + value as usize + } +} + +/// Helper table to calculate regenerated and compressed size from the Literals Header. +#[derive(Clone, Debug)] +pub struct LiteralsHeaderTable { + /// Whether to enable. + pub q_enable: Column, + /// Byte offset at which this literals header is located. + pub byte_offset: Column, + /// The branch taken for this literals header. + pub branch: Column, + /// To identify the branch. + pub branch_bits: BinaryNumberConfig, + /// The first byte of the literals header. + pub byte0: Column, + /// The second byte. + pub byte1: Column, + /// The third byte. + pub byte2: Column, + /// The fourth byte. + pub byte3: Column, + /// The fifth byte. + pub byte4: Column, + /// byte0 >> 3. + pub byte0_rs_3: Column, + /// byte0 >> 4. + pub byte0_rs_4: Column, + /// byte1 >> 6. + pub byte1_rs_6: Column, + /// byte1 & 0b111111. + pub byte1_and_63: Column, + /// byte2 >> 2. + pub byte2_rs_2: Column, + /// byte2 >> 6. + pub byte2_rs_6: Column, + /// byte2 & 0b11. + pub byte2_and_3: Column, + /// byte2 & 0b111111. + pub byte2_and_63: Column, + /// Regenerated size. + pub regen_size: Column, + /// Compressed size. + pub compr_size: Column, +} + +impl LiteralsHeaderTable { + /// Construct and constrain the literals header table. + pub fn construct( + meta: &mut ConstraintSystem, + bitwise_op_table: BitwiseOpTable, + range4: RangeTable<4>, + range8: RangeTable<8>, + range16: RangeTable<16>, + range64: RangeTable<64>, + ) -> Self { + let q_enable = meta.fixed_column(); + let branch = meta.advice_column(); + let table = Self { + q_enable, + byte_offset: meta.advice_column(), + branch, + branch_bits: BinaryNumberChip::configure(meta, q_enable, Some(branch.into())), + byte0: meta.advice_column(), + byte1: meta.advice_column(), + byte2: meta.advice_column(), + byte3: meta.advice_column(), + byte4: meta.advice_column(), + byte0_rs_3: meta.advice_column(), + byte0_rs_4: meta.advice_column(), + byte1_rs_6: meta.advice_column(), + byte1_and_63: meta.advice_column(), + byte2_rs_2: meta.advice_column(), + byte2_rs_6: meta.advice_column(), + byte2_and_3: meta.advice_column(), + byte2_and_63: meta.advice_column(), + regen_size: meta.advice_column(), + compr_size: meta.advice_column(), + }; + + macro_rules! is_branch { + ($var:ident, $branch_variant:ident) => { + let $var = |meta: &mut VirtualCells| { + table + .branch_bits + .value_equals(LiteralsHeaderBranch::$branch_variant, Rotation::cur())( + meta + ) + }; + }; + } + + is_branch!(branch0, RawRle0); + is_branch!(branch1, RawRle1); + is_branch!(branch2, RawRle2); + is_branch!(branch3, Compressed0); + is_branch!(branch4, Compressed1); + is_branch!(branch5, Compressed2); + + meta.create_gate("LiteralsHeaderTable", |meta| { + let mut cb = BaseConstraintBuilder::default(); + + let byte0_rs_3 = meta.query_advice(table.byte0_rs_3, Rotation::cur()); + let byte0_rs_4 = meta.query_advice(table.byte0_rs_4, Rotation::cur()); + let byte1_ls_4 = meta.query_advice(table.byte1, Rotation::cur()) * 16.expr(); + let byte1_and_63_ls_4 = + meta.query_advice(table.byte1_and_63, Rotation::cur()) * 16.expr(); + let byte1_rs_6 = meta.query_advice(table.byte1_rs_6, Rotation::cur()); + let byte2_rs_2 = meta.query_advice(table.byte2_rs_2, Rotation::cur()); + let byte2_rs_6 = meta.query_advice(table.byte2_rs_6, Rotation::cur()); + let byte2_ls_2 = meta.query_advice(table.byte2, Rotation::cur()) * 4.expr(); + let byte2_ls_12 = meta.query_advice(table.byte2, Rotation::cur()) * 4096.expr(); + let byte2_and_3_ls_12 = + meta.query_advice(table.byte2_and_3, Rotation::cur()) * 4096.expr(); + let byte2_and_63_ls_12 = + meta.query_advice(table.byte2_and_63, Rotation::cur()) * 4096.expr(); + let byte3_ls_6 = meta.query_advice(table.byte3, Rotation::cur()) * 64.expr(); + let byte3_ls_2 = meta.query_advice(table.byte3, Rotation::cur()) * 4.expr(); + let byte4_ls_10 = meta.query_advice(table.byte4, Rotation::cur()) * 1024.expr(); + + // regen_size == lh_byte[0] >> 3. + // compr_size == 0. + cb.condition(branch0(meta), |cb| { + cb.require_equal( + "branch0: regenerated size", + meta.query_advice(table.regen_size, Rotation::cur()), + byte0_rs_3, + ); + cb.require_zero( + "branch0: compressed size", + meta.query_advice(table.compr_size, Rotation::cur()), + ); + for col in [table.byte1, table.byte2, table.byte3, table.byte4] { + cb.require_zero("byte[i] == 0", meta.query_advice(col, Rotation::cur())); + } + }); + + // regen_size == (lh_byte[0] >> 4) + (lh_byte[1] << 4). + // compr_size == 0. + cb.condition(branch1(meta), |cb| { + cb.require_equal( + "branch1: regenerated size", + meta.query_advice(table.regen_size, Rotation::cur()), + byte0_rs_4.expr() + byte1_ls_4.expr(), + ); + cb.require_zero( + "branch1: compressed size", + meta.query_advice(table.compr_size, Rotation::cur()), + ); + for col in [table.byte2, table.byte3, table.byte4] { + cb.require_zero("byte[i] == 0", meta.query_advice(col, Rotation::cur())); + } + }); + + // regen_size == (lh_byte[0] >> 4) + (lh_byte[1] << 4) + (lh_byte[2] << 12). + // compr_size == 0. + cb.condition(branch2(meta), |cb| { + cb.require_equal( + "branch2: regenerated size", + meta.query_advice(table.regen_size, Rotation::cur()), + byte0_rs_4.expr() + byte1_ls_4.expr() + byte2_ls_12, + ); + cb.require_zero( + "branch2: compressed size", + meta.query_advice(table.compr_size, Rotation::cur()), + ); + for col in [table.byte3, table.byte4] { + cb.require_zero("byte[i] == 0", meta.query_advice(col, Rotation::cur())); + } + }); + + // regen_size == (lh_byte[0] >> 4) + ((lh_byte[1] & 0b111111) << 4). + // compr_size == (lh_byte[1] >> 6) + (lh_byte[2] << 2). + cb.condition(branch3(meta), |cb| { + cb.require_equal( + "branch3: regenerated size", + meta.query_advice(table.regen_size, Rotation::cur()), + byte0_rs_4.expr() + byte1_and_63_ls_4, + ); + cb.require_equal( + "branch3: compressed size", + meta.query_advice(table.compr_size, Rotation::cur()), + byte1_rs_6 + byte2_ls_2.expr(), + ); + for col in [table.byte3, table.byte4] { + cb.require_zero("byte[i] == 0", meta.query_advice(col, Rotation::cur())); + } + }); + + // regen_size == (lh_byte[0] >> 4) + (lh_byte[1] << 4) + ((lh_byte[2] & 0b11) << 12). + // compr_size == (lh_byte[2] >> 2) + (lh_byte[3] << 6). + cb.condition(branch4(meta), |cb| { + cb.require_equal( + "branch4: regenerated size", + meta.query_advice(table.regen_size, Rotation::cur()), + byte0_rs_4.expr() + byte1_ls_4.expr() + byte2_and_3_ls_12, + ); + cb.require_equal( + "branch4: compressed size", + meta.query_advice(table.compr_size, Rotation::cur()), + byte2_rs_2 + byte3_ls_6, + ); + cb.require_zero( + "byte[i] == 0", + meta.query_advice(table.byte4, Rotation::cur()), + ); + }); + + // regen_size == (lh_byte[0] >> 4) + (lh_byte[1] << 4) + ((lh_byte[2] & 0b111111) << + // 12). compr_size == (lh_byte[2] >> 6) + (lh_byte[3] << 2) + (lh_byte[4] << + // 10). + cb.condition(branch5(meta), |cb| { + cb.require_equal( + "branch5: regenerated size", + meta.query_advice(table.regen_size, Rotation::cur()), + byte0_rs_4 + byte1_ls_4 + byte2_and_63_ls_12, + ); + cb.require_equal( + "branch5: compressed size", + meta.query_advice(table.compr_size, Rotation::cur()), + byte2_rs_6 + byte3_ls_2 + byte4_ls_10, + ); + }); + + cb.gate(meta.query_fixed(table.q_enable, Rotation::cur())) + }); + meta.lookup("LiteralsHeaderTable: byte0 >> 3", |meta| { + let condition = meta.query_fixed(table.q_enable, Rotation::cur()); + let range_value = meta.query_advice(table.byte0, Rotation::cur()) + - (meta.query_advice(table.byte0_rs_3, Rotation::cur()) * 8.expr()); + + vec![(condition * range_value, range8.into())] + }); + meta.lookup("LiteralsHeaderTable: byte0 >> 4", |meta| { + let condition = meta.query_fixed(table.q_enable, Rotation::cur()); + let range_value = meta.query_advice(table.byte0, Rotation::cur()) + - (meta.query_advice(table.byte0_rs_4, Rotation::cur()) * 16.expr()); + + vec![(condition * range_value, range16.into())] + }); + meta.lookup("LiteralsHeaderTable: byte1 >> 6", |meta| { + let condition = meta.query_fixed(table.q_enable, Rotation::cur()); + let range_value = meta.query_advice(table.byte1, Rotation::cur()) + - (meta.query_advice(table.byte1_rs_6, Rotation::cur()) * 64.expr()); + + vec![(condition * range_value, range64.into())] + }); + meta.lookup("LiteralsHeaderTable: byte2 >> 2", |meta| { + let condition = meta.query_fixed(table.q_enable, Rotation::cur()); + let range_value = meta.query_advice(table.byte2, Rotation::cur()) + - (meta.query_advice(table.byte2_rs_2, Rotation::cur()) * 4.expr()); + + vec![(condition * range_value, range4.into())] + }); + meta.lookup("LiteralsHeaderTable: byte2 >> 6", |meta| { + let condition = meta.query_fixed(table.q_enable, Rotation::cur()); + let range_value = meta.query_advice(table.byte2, Rotation::cur()) + - (meta.query_advice(table.byte2_rs_6, Rotation::cur()) * 64.expr()); + + vec![(condition * range_value, range64.into())] + }); + meta.lookup_any("LiteralsHeaderTable: byte1 & 63", |meta| { + let condition = and::expr([ + meta.query_fixed(table.q_enable, Rotation::cur()), + not::expr(branch0(meta)), + ]); + [ + BitwiseOp::AND.expr(), + meta.query_advice(table.byte1, Rotation::cur()), + 63.expr(), + meta.query_advice(table.byte1_and_63, Rotation::cur()), + ] + .into_iter() + .zip(bitwise_op_table.table_exprs(meta)) + .map(|(input, table)| (input * condition.clone(), table)) + .collect::>() + }); + meta.lookup_any("LiteralsHeaderTable: byte2 & 3", |meta| { + let condition = meta.query_fixed(table.q_enable, Rotation::cur()); + [ + BitwiseOp::AND.expr(), + meta.query_advice(table.byte2, Rotation::cur()), + 3.expr(), + meta.query_advice(table.byte2_and_3, Rotation::cur()), + ] + .into_iter() + .zip(bitwise_op_table.table_exprs(meta)) + .map(|(input, table)| (input * condition.clone(), table)) + .collect::>() + }); + meta.lookup_any("LiteralsHeaderTable: byte2 & 63", |meta| { + let condition = meta.query_fixed(table.q_enable, Rotation::cur()); + [ + BitwiseOp::AND.expr(), + meta.query_advice(table.byte2, Rotation::cur()), + 63.expr(), + meta.query_advice(table.byte2_and_63, Rotation::cur()), + ] + .into_iter() + .zip(bitwise_op_table.table_exprs(meta)) + .map(|(input, table)| (input * condition.clone(), table)) + .collect::>() + }); + + debug_assert!(meta.degree() <= 9); + + table + } + + /// Assign witness to the literals header table. + pub fn assign( + &self, + layouter: &mut impl Layouter, + literals_headers: &[(u64, &[u8], u64, u64, u64)], /* (byte_offset, bytes, branch, + * regen_size, compr_size) */ + ) -> Result<(), Error> { + layouter.assign_region( + || "LiteralsHeaderTable", + |mut region| { + for (offset, &(byte_offset, header, branch, regen_size, compr_size)) in + literals_headers.iter().enumerate() + { + assert!(header.len() <= 5); + let [byte0, byte1, byte2, byte3, byte4] = [0, 1, 2, 3, 4] + .map(|i| header.get(i).cloned().map_or(0u64, |byte| byte as u64)); + region.assign_fixed( + || "q_enable", + self.q_enable, + offset, + || Value::known(F::one()), + )?; + for (col, value, annotation) in [ + (self.byte_offset, byte_offset, "byte_offset"), + (self.branch, branch, "branch"), + (self.byte0, byte0, "byte0"), + (self.byte1, byte1, "byte1"), + (self.byte2, byte2, "byte2"), + (self.byte3, byte3, "byte3"), + (self.byte4, byte4, "byte4"), + (self.byte0_rs_3, byte0 >> 3, "byte0_rs_3"), + (self.byte0_rs_4, byte0 >> 4, "byte0_rs_4"), + (self.byte1_rs_6, byte1 >> 6, "byte1_rs_6"), + (self.byte1_and_63, byte1 & 63, "byte1_and_63"), + (self.byte2_rs_2, byte2 >> 2, "byte2_rs_2"), + (self.byte2_rs_6, byte2 >> 6, "byte2_rs_6"), + (self.byte2_and_3, byte2 & 3, "byte2_and_3"), + (self.byte2_and_63, byte2 & 63, "byte2_and_63"), + (self.regen_size, regen_size, "regen_size"), + (self.compr_size, compr_size, "compr_size"), + ] { + region.assign_advice( + || annotation, + col, + offset, + || Value::known(F::from(value)), + )?; + } + let branch_chip = BinaryNumberChip::construct(self.branch_bits); + branch_chip.assign(&mut region, offset, &LiteralsHeaderBranch::from(branch))?; + } + + Ok(()) + }, + ) + } +} + +impl LookupTable for LiteralsHeaderTable { + fn columns(&self) -> Vec> { + vec![ + self.byte_offset.into(), + self.branch.into(), + self.byte0.into(), + self.byte1.into(), + self.byte2.into(), + self.byte3.into(), + self.byte4.into(), + self.regen_size.into(), + self.compr_size.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("byte_offset"), + String::from("branch"), + String::from("byte0"), + String::from("byte1"), + String::from("byte2"), + String::from("byte3"), + String::from("byte4"), + String::from("regen_size"), + String::from("compr_size"), + ] + } +} diff --git a/zkevm-circuits/src/table/decompression/mod.rs b/zkevm-circuits/src/table/decompression/mod.rs new file mode 100644 index 0000000000..1672565453 --- /dev/null +++ b/zkevm-circuits/src/table/decompression/mod.rs @@ -0,0 +1,20 @@ +//! Tables with constraints used for verification of zstd decoding from Huffman Codes and FSE +//! codes. + +mod bitstring_accumulation_table; +mod block_type_rom_table; +mod decoded_literals_table; +mod fse_table; +mod huffman_codes_table; +mod literals_header_rom_table; +mod literals_header_table; +mod tag_rom_table; + +pub use bitstring_accumulation_table::BitstringAccumulationTable; +pub use block_type_rom_table::BlockTypeRomTable; +pub use decoded_literals_table::DecodedLiteralsTable; +pub use fse_table::FseTable; +pub use huffman_codes_table::HuffmanCodesTable; +pub use literals_header_rom_table::LiteralsHeaderRomTable; +pub use literals_header_table::{LiteralsHeaderBranch, LiteralsHeaderTable}; +pub use tag_rom_table::TagRomTable; diff --git a/zkevm-circuits/src/table/decompression/tag_rom_table.rs b/zkevm-circuits/src/table/decompression/tag_rom_table.rs new file mode 100644 index 0000000000..b83d2867d4 --- /dev/null +++ b/zkevm-circuits/src/table/decompression/tag_rom_table.rs @@ -0,0 +1,91 @@ +use eth_types::Field; +use halo2_proofs::{ + circuit::Layouter, + plonk::{Any, Column, ConstraintSystem, Error, Fixed}, +}; + +use crate::{table::LookupTable, witness::TagRomTableRow}; + +/// Read-only Memory table for the Decompression circuit. This table allows us a lookup argument +/// from the Decompression circuit to check if a given row can occur depending on the row's tag, +/// next tag and tag length. +#[derive(Clone, Copy, Debug)] +pub struct TagRomTable { + /// Tag of the current field being decoded. + pub tag: Column, + /// Tag of the following field when the current field is finished decoding. + pub tag_next: Column, + /// The maximum length in terms of number of bytes that the current tag can take up. + pub max_len: Column, + /// Whether this tag outputs a decoded byte or not. + pub is_output: Column, + /// Whether this tag belongs to a ``block`` in zstd or not. + pub is_block: Column, + /// Whether this tag is processed back-to-front, i.e. in reverse order. + pub is_reverse: Column, +} + +impl LookupTable for TagRomTable { + fn columns(&self) -> Vec> { + vec![ + self.tag.into(), + self.tag_next.into(), + self.max_len.into(), + self.is_output.into(), + self.is_block.into(), + self.is_reverse.into(), + ] + } + + fn annotations(&self) -> Vec { + vec![ + String::from("tag"), + String::from("tag_next"), + String::from("max_len"), + String::from("is_output"), + String::from("is_block"), + String::from("is_reverse"), + ] + } +} + +impl TagRomTable { + /// Construct the ROM table. + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + tag: meta.fixed_column(), + tag_next: meta.fixed_column(), + max_len: meta.fixed_column(), + is_output: meta.fixed_column(), + is_block: meta.fixed_column(), + is_reverse: meta.fixed_column(), + } + } + + /// Load the ROM table. + pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { + layouter.assign_region( + || "Zstd ROM table", + |mut region| { + for (offset, row) in TagRomTableRow::rows().iter().enumerate() { + for (&column, (value, annotation)) in + >::fixed_columns(self).iter().zip( + row.values::() + .into_iter() + .zip(>::annotations(self).iter()), + ) + { + region.assign_fixed( + || format!("{annotation} at offset={offset}"), + column, + offset, + || value, + )?; + } + } + + Ok(()) + }, + ) + } +} diff --git a/zkevm-circuits/src/witness/zstd/mod.rs b/zkevm-circuits/src/witness/zstd/mod.rs index d1d5f4cc99..ac79734b84 100644 --- a/zkevm-circuits/src/witness/zstd/mod.rs +++ b/zkevm-circuits/src/witness/zstd/mod.rs @@ -34,11 +34,7 @@ const TAG_MAX_LEN: [(ZstdTag, u64); 13] = [ ]; fn lookup_max_tag_len(tag: ZstdTag) -> u64 { - TAG_MAX_LEN - .iter() - .find(|record| record.0 == tag) - .unwrap() - .1 + TAG_MAX_LEN.iter().find(|record| record.0 == tag).unwrap().1 } /// FrameHeaderDescriptor and FrameContentSize @@ -213,7 +209,16 @@ fn process_frame_header( ) } -type AggregateBlockResult = (usize, Vec>, bool, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData); +type AggregateBlockResult = ( + usize, + Vec>, + bool, + Vec, + Vec, + Vec, + FseAuxiliaryTableData, + HuffmanCodesData, +); fn process_block( src: &[u8], byte_offset: usize, @@ -523,7 +528,15 @@ fn process_rle_bytes( ) } -type BlockProcessingResult = (usize, Vec>, Vec, Vec, Vec, FseAuxiliaryTableData, HuffmanCodesData); +type BlockProcessingResult = ( + usize, + Vec>, + Vec, + Vec, + Vec, + FseAuxiliaryTableData, + HuffmanCodesData, +); fn process_block_raw( src: &[u8], @@ -629,7 +642,8 @@ fn process_block_zstd( let mut witness_rows = vec![]; // 1-5 bytes LiteralSectionHeader - let literals_header_result: LiteralsHeaderProcessingResult = process_block_zstd_literals_header::(src, byte_offset, last_row, randomness); + let literals_header_result: LiteralsHeaderProcessingResult = + process_block_zstd_literals_header::(src, byte_offset, last_row, randomness); let ( byte_offset, rows, @@ -806,7 +820,15 @@ fn process_block_zstd( ) } -type LiteralsHeaderProcessingResult = (usize, Vec>, BlockType, usize, usize, usize, (u64, bool)); +type LiteralsHeaderProcessingResult = ( + usize, + Vec>, + BlockType, + usize, + usize, + usize, + (u64, bool), +); fn process_block_zstd_literals_header( src: &[u8], @@ -942,7 +964,19 @@ fn process_block_zstd_literals_header( ) } -type HuffmanCodeProcessingResult = (usize, Vec>, HuffmanCodesData, usize, usize, Value, usize, u64, u64, u64, FseAuxiliaryTableData); +type HuffmanCodeProcessingResult = ( + usize, + Vec>, + HuffmanCodesData, + usize, + usize, + Value, + usize, + u64, + u64, + u64, + FseAuxiliaryTableData, +); fn process_block_zstd_huffman_code( src: &[u8], @@ -978,7 +1012,7 @@ fn process_block_zstd_huffman_code( tag_next, max_tag_len: lookup_max_tag_len(ZstdTag::ZstdBlockFseCode), tag_len: 0_u64, /* There's no information at this point about the length of FSE - * table bytes. So this value has to be modified later. */ + * table bytes. So this value has to be modified later. */ tag_idx: 1_u64, tag_value: Value::default(), // Must be changed after FSE table length is known tag_value_acc: Value::default(), // Must be changed after FSE table length is known @@ -1228,9 +1262,7 @@ fn process_block_zstd_huffman_code( let mut next_tag_rlc_acc = tag_rlc_iter.next().unwrap(); let aux_1 = next_value_rlc_acc; - let aux_2 = witness_rows[witness_rows.len() - 1] - .encoded_data - .value_rlc; + let aux_2 = witness_rows[witness_rows.len() - 1].encoded_data.value_rlc; let mut padding_end_idx: usize = 0; while huffman_bitstream[padding_end_idx] == 0 { @@ -1671,9 +1703,7 @@ fn process_block_zstd_lstream( while current_bit_idx < len * N_BITS_PER_BYTE { if huffman_bitstring_map.contains_key(bitstring_acc.as_str()) { - let sym = *huffman_bitstring_map - .get(bitstring_acc.as_str()) - .unwrap(); + let sym = *huffman_bitstring_map.get(bitstring_acc.as_str()).unwrap(); decoded_symbols.push(sym); let from_byte_idx = current_byte_idx; @@ -1770,13 +1800,16 @@ fn process_block_zstd_lstream( } /// Result for processing multiple blocks from compressed data -pub type MultiBlockProcessResult = (Vec>, Vec, Vec, Vec, Vec); +pub type MultiBlockProcessResult = ( + Vec>, + Vec, + Vec, + Vec, + Vec, +); /// Process a slice of bytes into decompression circuit witness rows -pub fn process( - src: &[u8], - randomness: Value, -) -> MultiBlockProcessResult { +pub fn process(src: &[u8], randomness: Value) -> MultiBlockProcessResult { let mut witness_rows = vec![]; let mut literals: Vec = vec![]; let mut aux_data: Vec = vec![]; diff --git a/zkevm-circuits/src/witness/zstd/types.rs b/zkevm-circuits/src/witness/zstd/types.rs index 00ad3f3abd..9e0d722682 100644 --- a/zkevm-circuits/src/witness/zstd/types.rs +++ b/zkevm-circuits/src/witness/zstd/types.rs @@ -224,7 +224,8 @@ pub enum ZstdTag { } impl ZstdTag { - fn is_output(&self) -> bool { + /// Whether this tag produces an output or not. + pub fn is_output(&self) -> bool { match self { Self::Null => false, Self::FrameHeaderDescriptor => false, @@ -233,18 +234,19 @@ impl ZstdTag { Self::RawBlockBytes => true, Self::RleBlockBytes => true, Self::ZstdBlockLiteralsHeader => false, - Self::ZstdBlockLiteralsRawBytes => true, - Self::ZstdBlockLiteralsRleBytes => true, + Self::ZstdBlockLiteralsRawBytes => false, + Self::ZstdBlockLiteralsRleBytes => false, Self::ZstdBlockFseCode => false, Self::ZstdBlockHuffmanCode => false, Self::ZstdBlockJumpTable => false, - Self::ZstdBlockLstream => true, + Self::ZstdBlockLstream => false, Self::ZstdBlockSequenceHeader => false, // TODO: more tags } } - fn is_block(&self) -> bool { + /// Whether this tag is a part of block or not. + pub fn is_block(&self) -> bool { match self { Self::Null => false, Self::FrameHeaderDescriptor => false, @@ -597,10 +599,7 @@ impl FseAuxiliaryTableData { /// with the reconstructed FSE table. After processing the entire bitstream to reconstruct the /// FSE table, if the read bitstream was not byte aligned, then we discard the 1..8 bits from /// the last byte that we read from. - pub fn reconstruct( - src: &[u8], - byte_offset: usize, - ) -> std::io::Result { + pub fn reconstruct(src: &[u8], byte_offset: usize) -> std::io::Result { // construct little-endian bit-reader. let data = src.iter().skip(byte_offset).cloned().collect::>(); let mut reader = BitReader::endian(Cursor::new(&data), LittleEndian);