From 45fc107c734a5c77bdc7971cd025c81a8d1e479e Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Wed, 2 Nov 2022 21:12:42 +0800 Subject: [PATCH 01/15] pass keccak test --- zkevm-circuits/src/keccak_circuit.rs | 4 +- .../src/keccak_circuit/keccak_packed_multi.rs | 242 ++++++++++++++++-- zkevm-circuits/src/table.rs | 43 +++- 3 files changed, 263 insertions(+), 26 deletions(-) diff --git a/zkevm-circuits/src/keccak_circuit.rs b/zkevm-circuits/src/keccak_circuit.rs index 832997c23b..2bed937cb9 100644 --- a/zkevm-circuits/src/keccak_circuit.rs +++ b/zkevm-circuits/src/keccak_circuit.rs @@ -1,9 +1,9 @@ //! The keccak circuit implementation. /// Keccak bit -pub mod keccak_bit; +//pub mod keccak_bit; /// Keccak packed -pub mod keccak_packed; +//pub mod keccak_packed; /// Keccak packed multi pub mod keccak_packed_multi; /// Util diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 4837093721..6dcbc0e9b1 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -29,10 +29,13 @@ const RHO_PI_LOOKUP_RANGE: usize = 4; const CHI_BASE_LOOKUP_RANGE: usize = 5; fn get_num_rows_per_round() -> usize { + 8 + /* var("ROWS") .unwrap_or_else(|_| "5".to_string()) .parse() .expect("Cannot parse ROWS env var as usize") + */ } fn get_num_bits_per_absorb_lookup() -> usize { @@ -69,6 +72,7 @@ pub(crate) struct SqueezeData { #[derive(Clone, Debug, PartialEq)] pub(crate) struct KeccakRow { q_enable: bool, + q_enable_row: bool, q_round: bool, q_absorb: bool, q_round_last: bool, @@ -80,6 +84,9 @@ pub(crate) struct KeccakRow { length: usize, data_rlc: F, hash_rlc: F, + bytes_left: F, // from len to 1 + hash_counter: F, // 0 when first row, then 1,2,3,.. + value: F, // byte } /// Part @@ -314,7 +321,13 @@ impl CellManager { /// KeccakConfig #[derive(Clone, Debug)] pub struct KeccakPackedConfig { + // q_enable only on the first row of valid rounds, + // while q_enable_row on every row of valid rounds + // q_enable_row can be optimzied out using expression like + // (1..get_num_rows_per_round() as i32).map(|i| meta.query_fixed(q_enable, Rotation(-i))).fold(0.expr(), |acc, elem| acc + elem), + // now we keep it here to make codes easier to read q_enable: Column, + q_enable_row: Column, q_first: Column, q_round: Column, q_absorb: Column, @@ -330,6 +343,7 @@ pub struct KeccakPackedConfig { normalize_6: [TableColumn; 2], chi_base_table: [TableColumn; 2], pack_table: [TableColumn; 2], + //is_final: Column, _marker: PhantomData, } @@ -779,6 +793,7 @@ mod transform_to { impl KeccakPackedConfig { pub(crate) fn configure(meta: &mut ConstraintSystem, r: Expression) -> Self { let q_enable = meta.fixed_column(); + let q_enable_row = meta.fixed_column(); let q_first = meta.fixed_column(); let q_round = meta.fixed_column(); let q_absorb = meta.fixed_column(); @@ -789,10 +804,18 @@ impl KeccakPackedConfig { let keccak_table = KeccakTable::construct(meta); let is_final = keccak_table.is_enabled; + //let is_final = meta.advice_column(); let length = keccak_table.input_len; let data_rlc = keccak_table.input_rlc; let hash_rlc = keccak_table.output_rlc; + /* + meta.create_gate("is_enabled in keccak table", |meta| { + + vec![meta.query_advice(is_final, Rotation::cur()) * meta.query_fixed(q_enable, Rotation::cur()) + - meta.query_advice(keccak_table.is_enabled, Rotation::cur())] + }); + */ let normalize_3 = array_init::array_init(|_| meta.lookup_table_column()); let normalize_4 = array_init::array_init(|_| meta.lookup_table_column()); let normalize_6 = array_init::array_init(|_| meta.lookup_table_column()); @@ -1319,6 +1342,121 @@ impl KeccakPackedConfig { cb.gate(meta.query_fixed(q_first, Rotation::cur())) }); + let q = |col: Column, meta: &mut VirtualCells<'_, F>| { + meta.query_fixed(col.clone(), Rotation::cur()) + }; + let q_r = |col: Column, meta: &mut VirtualCells<'_, F>| { + (0..get_num_rows_per_round() as i32) + .map(|i| meta.query_fixed(col, Rotation(-i))) + .fold(0.expr(), |acc, elem| acc + elem) + }; + let q_round_trailing = |col: Column, meta: &mut VirtualCells<'_, F>| { + (1..get_num_rows_per_round() as i32) + .map(|i| meta.query_fixed(col, Rotation(-i))) + .fold(0.expr(), |acc, elem| acc + elem) + }; + let q_prev = |col: Column, meta: &mut VirtualCells<'_, F>| { + meta.query_fixed(col.clone(), Rotation::prev()) + }; + let q_prev_r = |col: Column, meta: &mut VirtualCells<'_, F>| { + meta.query_fixed(col.clone(), Rotation(-(get_num_rows_per_round() as i32))) + }; +/* + input is "12345678abc" + offset value bytes_left is_padding q_enable q_padding_last + 8 1 11 0 1 0 + 9 2 10 0 0 0 + 10 3 9 0 0 0 + 11 4 8 0 0 0 + 12 5 7 0 0 0 + 13 6 6 0 0 0 + 14 7 5 0 0 0 + 15 8 4 0 0 0 // 1st round end + 16 a 3 0 1 1 // 2nd round start + 17 b 2 0 0 0 + 18 c 1 0 0 0 + 19 0 0 1 0 0 + 20 0 0 1 0 0 + 21 0 0 1 0 0 + 22 0 0 1 0 0 + 23 0 0 1 0 0 // 2nd round end + + */ + + meta.create_gate("counter", |meta| { + let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); + + cb.condition(q_r(q_first, meta), |cb| { + cb.require_zero("hash_counter needs to be zero on the first row", meta.query_advice(keccak_table.hash_counter, Rotation::cur())); + }); + cb.condition(q(q_enable, meta) * q_prev_r(q_absorb, meta), |cb| { + let counter = meta.query_advice(keccak_table.hash_counter, Rotation::cur()); + let counter_prev = meta.query_advice(keccak_table.hash_counter, Rotation::prev()); + cb.require_equal("hash_counter increases by 1 after each hash input", counter_prev + 1.expr(), counter); + }); + cb.condition(q_r(q_enable, meta) - q_r(q_first, meta) - q(q_enable, meta) * q_prev_r(q_absorb, meta), |cb| { + let counter = meta.query_advice(keccak_table.hash_counter, Rotation::cur()); + let counter_prev = meta.query_advice(keccak_table.hash_counter, Rotation::prev()); + cb.require_equal("hash_counter keeps same when no new hash input", counter_prev, counter); + }); + cb.gate(1.expr()) + }); + meta.create_gate("byte_value", |meta| { + let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); + for idx in 0..get_num_rows_per_round() { + cb.condition(not::expr(is_paddings[idx].expr()), |cb| { + cb.require_equal("input byte", + input_bytes[idx].expr.clone(), + meta.query_advice(keccak_table.byte_value, Rotation::cur()) + ); + }); + } + cb.gate(q(q_enable, meta)) + }); + meta.create_gate("bytes_left", |meta| { + let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); + // TODO: is this needed? + cb.condition(q_r(q_first, meta), |cb| { + cb.require_zero("bytes_left needs to be zero on the first row", meta.query_advice(keccak_table.bytes_left, Rotation::cur())); + }); + // is_paddings only be true when + + + cb.condition(q(q_padding, meta) /*- q_prev_r(q_absorb, meta)*/, |cb| { + + for i in 0..get_num_rows_per_round() { + let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation(i as i32)); + let bytes_left_next = meta.query_advice(keccak_table.bytes_left, Rotation(i as i32 + 1)); + cb.require_equal("if not padding, bytes_left decreases by 1, else, stay same", bytes_left_next, bytes_left.clone() - not::expr(is_paddings[i].expr())); + // cb.require_zero("bytes_left should be 0 when padding", bytes_left * is_paddings[i].expr()); + } + //cb.require_equal("bytes_left decreases by 1 for each row", bytes_left_next + 1.expr(), bytes_left); + // let counter_prev = meta.query_advice(keccak_table.hash_counter, Rotation::prev()); + }); + /* + cb.condition(q(q_padding_last, meta), |cb| { + for i in 0..get_num_rows_per_round() { + + let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); + let bytes_left_next = meta.query_advice(keccak_table.bytes_left, Rotation::next()); + + cb.require_equal("bytes_left decreases by 1 when not padding", bytes_left_next, bytes_left.clone() - not::expr(is_paddings[i].expr())); + cb.require_zero("bytes_left should be 0 when padding", bytes_left * is_paddings[i].expr()); + } + }); + */ + cb.condition(q_r(q_enable, meta) - q_r(q_padding, meta) - q_r(q_first, meta), |cb| { + let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); + let bytes_left_next = meta.query_advice(keccak_table.bytes_left, Rotation::next()); + cb.require_equal("bytes_left should stay same on non absorb round", bytes_left, bytes_left_next); + }); + cb.condition(q(q_enable, meta) * meta.query_advice(is_final, Rotation::cur()), |cb| { + let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); + cb.require_zero("bytes_left should be 0 when is_final", bytes_left); + }); + cb.gate(1.expr()) + }); + // Enforce logic for when this block is the last block for a hash let last_is_padding_in_block = is_paddings.last().unwrap().at_offset( meta, @@ -1326,18 +1464,38 @@ impl KeccakPackedConfig { ); meta.create_gate("is final", |meta| { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - cb.require_equal( - "is_final needs to be the same as the last is_padding in the block", - meta.query_advice(is_final, Rotation::cur()), - last_is_padding_in_block.expr(), - ); // All absorb rows except the first row - cb.gate( + cb.condition( meta.query_fixed(q_absorb, Rotation::cur()) - meta.query_fixed(q_first, Rotation::cur()), - ) + |cb| { + cb.require_equal( + "is_final needs to be the same as the last is_padding in the block", + meta.query_advice(is_final, Rotation::cur()), + last_is_padding_in_block.expr(), + ); + }, + ); + // For all the rows of a round, only the first row can have `is_final == 1`. + // TODO: debug q_enable_row? + cb.condition( + q_round_trailing(q_enable, meta), + //meta.query_fixed(q_enable_row, Rotation::cur()) - + // meta.query_fixed(q_enable, Rotation::cur()), + //(1..get_num_rows_per_round() as i32) + //.map(|i| meta.query_fixed(q_enable, Rotation(-i))) + // .fold(0.expr(), |acc, elem| acc + elem), + |cb| { + cb.require_zero( + "is_final only when q_enable", + meta.query_advice(is_final, Rotation::cur()), + ); + }, + ); + cb.gate(1.expr()) }); + // Padding // May be cleaner to do this padding logic in the byte conversion lookup but // currently easier to do it like this. @@ -1429,6 +1587,14 @@ impl KeccakPackedConfig { cb.gate(1.expr()) }); + let slot_selector = |meta: &mut VirtualCells<'_, F>, q_col| { + let mut exp = 0.expr(); + for i in 0..get_num_rows_per_round() { + exp = exp + meta.query_fixed(q_col, Rotation(i as i32)); + } + exp + }; + // Length and input data rlc meta.create_gate("length and data rlc", |meta| { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); @@ -1520,6 +1686,7 @@ impl KeccakPackedConfig { KeccakPackedConfig { q_enable, + q_enable_row, q_first, q_round, q_absorb, @@ -1534,6 +1701,7 @@ impl KeccakPackedConfig { normalize_6, chi_base_table, pack_table, + //is_final, _marker: PhantomData, } } @@ -1601,6 +1769,9 @@ impl KeccakPackedConfig { row.data_rlc, F::from(row.length as u64), row.hash_rlc, + F::from(row.hash_counter), + F::from(row.value), + F::from(row.bytes_left), ], )?; @@ -1619,6 +1790,15 @@ impl KeccakPackedConfig { )?; } + /* + region.assign_advice( + || format!("assign is_final {}", offset), + self.is_final, + offset, + || Value::known(F::from(row.is_final) * F::from(row.q_enable)), + )?; + */ + // Round constant region.assign_fixed( || format!("assign round cst {}", offset), @@ -1645,7 +1825,7 @@ impl KeccakPackedConfig { } } -fn keccak(rows: &mut Vec>, bytes: &[u8], r: F) { +fn keccak(counter: usize, rows: &mut Vec>, bytes: &[u8], r: F) { let mut bits = into_bits(bytes); let mut s = [[F::zero(); 5]; 5]; let absorb_positions = get_absorb_positions(); @@ -1964,25 +2144,47 @@ fn keccak(rows: &mut Vec>, bytes: &[u8], r: F) { } for round in 0..NUM_ROUNDS + 1 { - let is_final = is_final_block && round == NUM_ROUNDS; let round_cst = pack_u64(ROUND_CST[round]); for row_idx in 0..get_num_rows_per_round() { + let byte_idx = round * 8 + row_idx; + let byte = if byte_idx >= bytes.len() { + 0 + } else { + bytes[byte_idx] + }; + let bytes_left = if byte_idx >= bytes.len() { + 0 + } else { + bytes.len() - byte_idx + }; rows.push(KeccakRow { q_enable: row_idx == 0, + q_enable_row: true, q_round: row_idx == 0 && round < NUM_ROUNDS, q_absorb: row_idx == 0 && round == NUM_ROUNDS, q_round_last: row_idx == 0 && round == NUM_ROUNDS, q_padding: row_idx == 0 && round < NUM_WORDS_TO_ABSORB, q_padding_last: row_idx == 0 && round == NUM_WORDS_TO_ABSORB - 1, round_cst, - is_final, + is_final: is_final_block && round == NUM_ROUNDS && row_idx == 0, length: round_lengths[round], data_rlc: round_data_rlcs[round], - hash_rlc, + hash_rlc: hash_rlc, // + F::from_u128(row_idx as u128), cell_values: regions[round].rows[row_idx].clone(), + value: F::from_u128(byte as u128), + // from len to 1 + bytes_left: F::from_u128(bytes_left as u128), // + 1? + hash_counter: F::from_u128(counter as u128), }); + { + let mut r = rows.last().unwrap().clone(); + r.cell_values.clear(); + println!("offset {:?} row {:?}", rows.len() - 1, r); + } } + println!(" = = = = = = "); } + println!(" ====================== "); } let hash_bytes = s @@ -2008,6 +2210,7 @@ fn multi_keccak(bytes: &[Vec], r: F) -> Vec> { for idx in 0..get_num_rows_per_round() { rows.push(KeccakRow { q_enable: idx == 0, + q_enable_row: true, q_round: false, q_absorb: idx == 0, q_round_last: false, @@ -2019,10 +2222,13 @@ fn multi_keccak(bytes: &[Vec], r: F) -> Vec> { data_rlc: F::zero(), hash_rlc: F::zero(), cell_values: Vec::new(), + hash_counter: F::zero(), + value: F::zero(), + bytes_left: F::zero(), }); } - for bytes in bytes { - keccak(&mut rows, bytes, r); + for (idx, bytes) in bytes.iter().enumerate() { + keccak(idx + 1, &mut rows, bytes, r); } rows } @@ -2050,13 +2256,13 @@ mod tests { #[test] fn packed_multi_keccak_simple() { - let k = 10; + let k = 11; let inputs = vec![ vec![], - (0u8..1).collect::>(), - (0u8..135).collect::>(), - (0u8..136).collect::>(), - (0u8..200).collect::>(), + //(0u8..1).collect::>(), + //(0u8..135).collect::>(), + //(0u8..136).collect::>(), + //(0u8..200).collect::>(), ]; verify::(k, inputs, true); } diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 5b4ce2de51..d76e6ee29e 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -725,6 +725,12 @@ pub struct KeccakTable { pub input_len: Column, /// RLC of the hash result pub output_rlc: Column, // RLC of hash of input bytes + /// .. + pub hash_counter: Column, + /// .. + pub byte_value: Column, + /// .. + pub bytes_left: Column, } impl KeccakTable { @@ -735,14 +741,18 @@ impl KeccakTable { input_rlc: meta.advice_column_in(SecondPhase), input_len: meta.advice_column(), output_rlc: meta.advice_column_in(SecondPhase), + hash_counter: meta.advice_column(), + byte_value: meta.advice_column(), + bytes_left: meta.advice_column(), } } /// Generate the keccak table assignments from a byte array input. pub fn assignments( + counter: usize, input: &[u8], challenges: &Challenges>, - ) -> Vec<[Value; 4]> { + ) -> Vec<[Value; 7]> { let input_rlc = challenges .keccak_input() .map(|challenge| rlc::value(input.iter().rev(), challenge)); @@ -757,12 +767,30 @@ impl KeccakTable { ) }); - vec![[ + let mut assignments = Vec::new(); + for (idx, byte) in input.iter().enumerate() { + assignments.push([ + + Value::known(F::zero()), + Value::known(F::zero()), + Value::known(F::zero()), + Value::known(F::zero()), + Value::known(F::from_u128(counter as u128)), + Value::known(F::from_u128(*byte as u128)), + Value::known(F::from_u128((input.len() - idx) as u128)), + + ]); + } + assignments.push([ Value::known(F::one()), input_rlc, Value::known(input_len), output_rlc, - ]] + Value::known(F::zero()), + Value::known(F::zero()), + Value::known(F::zero()), + ]); + assignments } /// Assign a table row for keccak table @@ -770,7 +798,7 @@ impl KeccakTable { &self, region: &mut Region, offset: usize, - values: [F; 4], + values: [F; 7], ) -> Result<(), Error> { for (column, value) in self.columns().iter().zip(values.iter()) { region.assign_advice( @@ -806,8 +834,8 @@ impl KeccakTable { offset += 1; let keccak_table_columns = self.columns(); - for input in inputs.clone() { - for row in Self::assignments(input, challenges) { + for (idx, input) in inputs.clone().into_iter().enumerate() { + for row in Self::assignments(idx + 1, input, challenges) { // let mut column_index = 0; for (column, value) in keccak_table_columns.iter().zip_eq(row) { region.assign_advice( @@ -833,6 +861,9 @@ impl DynamicTableColumns for KeccakTable { self.input_rlc, self.input_len, self.output_rlc, + self.hash_counter, + self.byte_value, + self.bytes_left, ] } } From 8288cd2cd820c1c611655dbbc1caef5df2f1e3fb Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Wed, 2 Nov 2022 21:27:20 +0800 Subject: [PATCH 02/15] fix --- zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs | 2 +- zkevm-circuits/src/super_circuit.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 37e905296e..b30e5fd4f0 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -354,7 +354,7 @@ impl Config { enable.clone(), meta.query_advice(keccak_table.is_enabled, Rotation::cur()), )]; - for (i, column) in keccak_table.columns().iter().skip(1).enumerate() { + for (i, column) in keccak_table.columns().iter().take(4).skip(1).enumerate() { constraints.push(( enable.clone() * meta.query_advice(lookup_columns[i], Rotation::cur()), meta.query_advice(*column, Rotation::cur()), diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index a14cc295fc..a5308c0b35 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -444,7 +444,9 @@ mod super_circuit_tests { let chain_id = (*MOCK_CHAIN_ID).as_u64(); let bytecode = bytecode! { - GAS + PUSH32(100) + PUSH32(0) + SHA3 STOP }; @@ -481,6 +483,7 @@ mod super_circuit_tests { let (k, circuit, instance) = SuperCircuit::<_, 1, 32, 256>::build(block, &mut ChaCha20Rng::seed_from_u64(2)) .unwrap(); + println!("k is {}", k); let prover = MockProver::run(k, &circuit, instance).unwrap(); let res = prover.verify_par(); if let Err(err) = res { From cef22a5d6b864752246b43b4249221fa9ddc514a Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 3 Nov 2022 15:17:52 +0800 Subject: [PATCH 03/15] fixed --- .../src/keccak_circuit/keccak_packed_multi.rs | 230 +++++++++++------- zkevm-circuits/src/table.rs | 16 +- 2 files changed, 152 insertions(+), 94 deletions(-) diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 6dcbc0e9b1..b42a606da4 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -22,7 +22,7 @@ use halo2_proofs::{ use log::{debug, info}; use std::{env::var, marker::PhantomData, vec}; -const MAX_DEGREE: usize = 3; +const MAX_DEGREE: usize = 4; const ABSORB_LOOKUP_RANGE: usize = 3; const THETA_C_LOOKUP_RANGE: usize = 6; const RHO_PI_LOOKUP_RANGE: usize = 4; @@ -324,8 +324,9 @@ pub struct KeccakPackedConfig { // q_enable only on the first row of valid rounds, // while q_enable_row on every row of valid rounds // q_enable_row can be optimzied out using expression like - // (1..get_num_rows_per_round() as i32).map(|i| meta.query_fixed(q_enable, Rotation(-i))).fold(0.expr(), |acc, elem| acc + elem), - // now we keep it here to make codes easier to read + // (1..get_num_rows_per_round() as i32).map(|i| meta.query_fixed(q_enable, + // Rotation(-i))).fold(0.expr(), |acc, elem| acc + elem), now we keep it here to make codes + // easier to read q_enable: Column, q_enable_row: Column, q_first: Column, @@ -809,10 +810,10 @@ impl KeccakPackedConfig { let data_rlc = keccak_table.input_rlc; let hash_rlc = keccak_table.output_rlc; - /* + /* meta.create_gate("is_enabled in keccak table", |meta| { - - vec![meta.query_advice(is_final, Rotation::cur()) * meta.query_fixed(q_enable, Rotation::cur()) + + vec![meta.query_advice(is_final, Rotation::cur()) * meta.query_fixed(q_enable, Rotation::cur()) - meta.query_advice(keccak_table.is_enabled, Rotation::cur())] }); */ @@ -1347,13 +1348,13 @@ impl KeccakPackedConfig { }; let q_r = |col: Column, meta: &mut VirtualCells<'_, F>| { (0..get_num_rows_per_round() as i32) - .map(|i| meta.query_fixed(col, Rotation(-i))) - .fold(0.expr(), |acc, elem| acc + elem) + .map(|i| meta.query_fixed(col, Rotation(-i))) + .fold(0.expr(), |acc, elem| acc + elem) }; let q_round_trailing = |col: Column, meta: &mut VirtualCells<'_, F>| { (1..get_num_rows_per_round() as i32) - .map(|i| meta.query_fixed(col, Rotation(-i))) - .fold(0.expr(), |acc, elem| acc + elem) + .map(|i| meta.query_fixed(col, Rotation(-i))) + .fold(0.expr(), |acc, elem| acc + elem) }; let q_prev = |col: Column, meta: &mut VirtualCells<'_, F>| { meta.query_fixed(col.clone(), Rotation::prev()) @@ -1361,99 +1362,154 @@ impl KeccakPackedConfig { let q_prev_r = |col: Column, meta: &mut VirtualCells<'_, F>| { meta.query_fixed(col.clone(), Rotation(-(get_num_rows_per_round() as i32))) }; -/* - input is "12345678abc" - offset value bytes_left is_padding q_enable q_padding_last - 8 1 11 0 1 0 - 9 2 10 0 0 0 - 10 3 9 0 0 0 - 11 4 8 0 0 0 - 12 5 7 0 0 0 - 13 6 6 0 0 0 - 14 7 5 0 0 0 - 15 8 4 0 0 0 // 1st round end - 16 a 3 0 1 1 // 2nd round start - 17 b 2 0 0 0 - 18 c 1 0 0 0 - 19 0 0 1 0 0 - 20 0 0 1 0 0 - 21 0 0 1 0 0 - 22 0 0 1 0 0 - 23 0 0 1 0 0 // 2nd round end - - */ + /* + input is "12345678abc" + offset value bytes_left is_padding q_enable q_padding_last + 8 1 11 0 1 0 + 9 2 10 0 0 0 + 10 3 9 0 0 0 + 11 4 8 0 0 0 + 12 5 7 0 0 0 + 13 6 6 0 0 0 + 14 7 5 0 0 0 + 15 8 4 0 0 0 // 1st round end + 16 a 3 0 1 1 // 2nd round start + 17 b 2 0 0 0 + 18 c 1 0 0 0 + 19 0 0 1 0 0 + 20 0 0 1 0 0 + 21 0 0 1 0 0 + 22 0 0 1 0 0 + 23 0 0 1 0 0 // 2nd round end + + */ meta.create_gate("counter", |meta| { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - + cb.condition(q_r(q_first, meta), |cb| { - cb.require_zero("hash_counter needs to be zero on the first row", meta.query_advice(keccak_table.hash_counter, Rotation::cur())); - }); - cb.condition(q(q_enable, meta) * q_prev_r(q_absorb, meta), |cb| { - let counter = meta.query_advice(keccak_table.hash_counter, Rotation::cur()); - let counter_prev = meta.query_advice(keccak_table.hash_counter, Rotation::prev()); - cb.require_equal("hash_counter increases by 1 after each hash input", counter_prev + 1.expr(), counter); - }); - cb.condition(q_r(q_enable, meta) - q_r(q_first, meta) - q(q_enable, meta) * q_prev_r(q_absorb, meta), |cb| { - let counter = meta.query_advice(keccak_table.hash_counter, Rotation::cur()); - let counter_prev = meta.query_advice(keccak_table.hash_counter, Rotation::prev()); - cb.require_equal("hash_counter keeps same when no new hash input", counter_prev, counter); + cb.require_zero( + "hash_counter needs to be zero on the first row", + meta.query_advice(keccak_table.hash_counter, Rotation::cur()), + ); }); + cb.condition( + (q(q_enable, meta) - q(q_first, meta)) + * meta.query_advice(is_final, Rotation(-(get_num_rows_per_round() as i32))), + |cb| { + let counter = meta.query_advice(keccak_table.hash_counter, Rotation::cur()); + let counter_prev = + meta.query_advice(keccak_table.hash_counter, Rotation::prev()); + cb.require_equal( + "hash_counter increases by 1 after each hash input", + counter_prev + 1.expr(), + counter, + ); + }, + ); + cb.condition( + q_r(q_enable, meta) + - q_r(q_first, meta) + - q(q_enable, meta) * q_prev_r(q_absorb, meta), + |cb| { + let counter = meta.query_advice(keccak_table.hash_counter, Rotation::cur()); + let counter_prev = + meta.query_advice(keccak_table.hash_counter, Rotation::prev()); + cb.require_equal( + "hash_counter keeps same when no new hash input", + counter_prev, + counter, + ); + }, + ); cb.gate(1.expr()) }); meta.create_gate("byte_value", |meta| { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); for idx in 0..get_num_rows_per_round() { - cb.condition(not::expr(is_paddings[idx].expr()), |cb| { - cb.require_equal("input byte", - input_bytes[idx].expr.clone(), - meta.query_advice(keccak_table.byte_value, Rotation::cur()) + cb.condition( + q_r(q_padding, meta) * not::expr(is_paddings[idx].expr()), + |cb| { + cb.require_equal( + "input byte", + input_bytes[idx].expr.clone(), + meta.query_advice(keccak_table.byte_value, Rotation(idx as i32)), + ); + }, ); - }); } cb.gate(q(q_enable, meta)) }); meta.create_gate("bytes_left", |meta| { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - // TODO: is this needed? + // TODO: is this needed? cb.condition(q_r(q_first, meta), |cb| { - cb.require_zero("bytes_left needs to be zero on the first row", meta.query_advice(keccak_table.bytes_left, Rotation::cur())); + cb.require_zero( + "bytes_left needs to be zero on the first row", + meta.query_advice(keccak_table.bytes_left, Rotation::cur()), + ); }); - // is_paddings only be true when - - - cb.condition(q(q_padding, meta) /*- q_prev_r(q_absorb, meta)*/, |cb| { + // is_paddings only be true when - for i in 0..get_num_rows_per_round() { - let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation(i as i32)); - let bytes_left_next = meta.query_advice(keccak_table.bytes_left, Rotation(i as i32 + 1)); - cb.require_equal("if not padding, bytes_left decreases by 1, else, stay same", bytes_left_next, bytes_left.clone() - not::expr(is_paddings[i].expr())); - // cb.require_zero("bytes_left should be 0 when padding", bytes_left * is_paddings[i].expr()); - } - //cb.require_equal("bytes_left decreases by 1 for each row", bytes_left_next + 1.expr(), bytes_left); - // let counter_prev = meta.query_advice(keccak_table.hash_counter, Rotation::prev()); - }); - /* + cb.condition( + q(q_padding, meta), /* - q(q_padding_last, meta) */ + |cb| { + for i in 0..get_num_rows_per_round() { + let bytes_left = + meta.query_advice(keccak_table.bytes_left, Rotation(i as i32)); + let bytes_left_next = + meta.query_advice(keccak_table.bytes_left, Rotation(i as i32 + 1)); + cb.require_equal( + "if not padding, bytes_left decreases by 1, else, stay same", + bytes_left_next, + bytes_left.clone() - (not::expr(is_paddings[i].expr())), + ); + // cb.require_zero("bytes_left should be 0 when + // padding", bytes_left * is_paddings[i].expr()); + } + //cb.require_equal("bytes_left decreases by 1 for each + // row", bytes_left_next + 1.expr(), bytes_left); + // let counter_prev = + // meta.query_advice(keccak_table.hash_counter, + // Rotation::prev()); + }, + ); + /* cb.condition(q(q_padding_last, meta), |cb| { for i in 0..get_num_rows_per_round() { let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); let bytes_left_next = meta.query_advice(keccak_table.bytes_left, Rotation::next()); - + cb.require_equal("bytes_left decreases by 1 when not padding", bytes_left_next, bytes_left.clone() - not::expr(is_paddings[i].expr())); cb.require_zero("bytes_left should be 0 when padding", bytes_left * is_paddings[i].expr()); } }); */ - cb.condition(q_r(q_enable, meta) - q_r(q_padding, meta) - q_r(q_first, meta), |cb| { - let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); - let bytes_left_next = meta.query_advice(keccak_table.bytes_left, Rotation::next()); - cb.require_equal("bytes_left should stay same on non absorb round", bytes_left, bytes_left_next); - }); - cb.condition(q(q_enable, meta) * meta.query_advice(is_final, Rotation::cur()), |cb| { - let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); - cb.require_zero("bytes_left should be 0 when is_final", bytes_left); - }); + // offset 1400 row KeccakRow { q_enable: true, q_enable_row: true, q_round: + // false, q_absorb: true, q_round_last: true, q_padding: false, q_padding_last: + // false, + cb.condition( + (q_r(q_enable, meta) - q_r(q_padding, meta) - q_r(q_first, meta)) + * meta.query_advice(is_final, Rotation::next()), + |cb| { + let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); + let bytes_left_next = + meta.query_advice(keccak_table.bytes_left, Rotation::next()); + cb.require_equal( + "bytes_left should stay same on non absorb round", + bytes_left, + bytes_left_next, + ); + }, + ); + cb.condition( + q(q_enable, meta) * meta.query_advice(is_final, Rotation::cur()), + |cb| { + let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); + cb.require_zero("bytes_left should be 0 when is_final", bytes_left); + }, + ); cb.gate(1.expr()) }); @@ -1480,11 +1536,11 @@ impl KeccakPackedConfig { // TODO: debug q_enable_row? cb.condition( q_round_trailing(q_enable, meta), - //meta.query_fixed(q_enable_row, Rotation::cur()) - - // meta.query_fixed(q_enable, Rotation::cur()), + //meta.query_fixed(q_enable_row, Rotation::cur()) - + // meta.query_fixed(q_enable, Rotation::cur()), //(1..get_num_rows_per_round() as i32) - //.map(|i| meta.query_fixed(q_enable, Rotation(-i))) - // .fold(0.expr(), |acc, elem| acc + elem), + //.map(|i| meta.query_fixed(q_enable, Rotation(-i))) + // .fold(0.expr(), |acc, elem| acc + elem), |cb| { cb.require_zero( "is_final only when q_enable", @@ -1495,7 +1551,6 @@ impl KeccakPackedConfig { cb.gate(1.expr()) }); - // Padding // May be cleaner to do this padding logic in the byte conversion lookup but // currently easier to do it like this. @@ -1790,7 +1845,7 @@ impl KeccakPackedConfig { )?; } - /* + /* region.assign_advice( || format!("assign is_final {}", offset), self.is_final, @@ -2146,7 +2201,12 @@ fn keccak(counter: usize, rows: &mut Vec>, bytes: &[u8], for round in 0..NUM_ROUNDS + 1 { let round_cst = pack_u64(ROUND_CST[round]); for row_idx in 0..get_num_rows_per_round() { - let byte_idx = round * 8 + row_idx; + let byte_idx = if round < NUM_WORDS_TO_ABSORB { + round * 8 + row_idx + } else { + NUM_WORDS_TO_ABSORB * 8 + } + idx * NUM_WORDS_TO_ABSORB * 8; + let byte = if byte_idx >= bytes.len() { 0 } else { @@ -2259,10 +2319,10 @@ mod tests { let k = 11; let inputs = vec![ vec![], - //(0u8..1).collect::>(), - //(0u8..135).collect::>(), - //(0u8..136).collect::>(), - //(0u8..200).collect::>(), + (0u8..1).collect::>(), + (0u8..135).collect::>(), + (0u8..136).collect::>(), + (0u8..200).collect::>(), ]; verify::(k, inputs, true); } diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index d76e6ee29e..933f16a63e 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -770,15 +770,13 @@ impl KeccakTable { let mut assignments = Vec::new(); for (idx, byte) in input.iter().enumerate() { assignments.push([ - - Value::known(F::zero()), - Value::known(F::zero()), - Value::known(F::zero()), - Value::known(F::zero()), - Value::known(F::from_u128(counter as u128)), - Value::known(F::from_u128(*byte as u128)), - Value::known(F::from_u128((input.len() - idx) as u128)), - + Value::known(F::zero()), + Value::known(F::zero()), + Value::known(F::zero()), + Value::known(F::zero()), + Value::known(F::from_u128(counter as u128)), + Value::known(F::from_u128(*byte as u128)), + Value::known(F::from_u128((input.len() - idx) as u128)), ]); } assignments.push([ From 92ce92a80cc5c1ad6dad50d9b3b5848459277229 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 3 Nov 2022 15:50:34 +0800 Subject: [PATCH 04/15] fix sha3.. --- bus-mapping/src/circuit_input_builder.rs | 4 ++-- bus-mapping/src/circuit_input_builder/execution.rs | 6 ++++-- .../src/bytecode_circuit/bytecode_unroller.rs | 10 ++++++---- zkevm-circuits/src/evm_circuit/table.rs | 6 ++++++ 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index c46a1ba13e..85dc6df16d 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -271,6 +271,8 @@ impl<'a> CircuitInputBuilder { /// block. pub fn keccak_inputs(&self) -> Result>, Error> { let mut keccak_inputs = Vec::new(); + // EVM Circuit + keccak_inputs.extend_from_slice(&self.block.sha3_inputs); // Tx Circuit let txs: Vec = self.block.txs.iter().map(|tx| tx.into()).collect(); keccak_inputs.extend_from_slice(&keccak_inputs_tx_circuit( @@ -281,8 +283,6 @@ impl<'a> CircuitInputBuilder { for bytecode in self.code_db.0.values() { keccak_inputs.push(bytecode.clone()); } - // EVM Circuit - keccak_inputs.extend_from_slice(&self.block.sha3_inputs); // MPT Circuit // TODO https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/696 Ok(keccak_inputs) diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index 875e5b936f..4a92fcdcc8 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -167,6 +167,8 @@ pub enum CopyDataType { /// scenario where we wish to accumulate the value (RLC) over all rows. /// This is used for Copy Lookup from SHA3 opcode verification. RlcAcc, + /// + SHA3, } impl From for usize { @@ -252,10 +254,10 @@ impl CopyEvent { .checked_sub(self.src_addr) .unwrap_or_default(), ), - CopyDataType::RlcAcc | CopyDataType::TxLog => unreachable!(), + CopyDataType::RlcAcc | CopyDataType::TxLog | CopyDataType::SHA3=> unreachable!(), }; let destination_rw_increase = match self.dst_type { - CopyDataType::RlcAcc | CopyDataType::Bytecode => 0, + CopyDataType::RlcAcc | CopyDataType::Bytecode |CopyDataType::SHA3 => 0, CopyDataType::TxLog | CopyDataType::Memory => u64::try_from(step_index).unwrap() / 2, CopyDataType::TxCalldata => unreachable!(), }; diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index b30e5fd4f0..5a3e8d1b6a 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -16,6 +16,7 @@ use halo2_proofs::{ }, poly::Rotation, }; +use itertools::zip; use keccak256::plain::Keccak; use std::vec; @@ -349,15 +350,16 @@ impl Config { meta.query_advice(is_final, Rotation::cur()), not::expr(meta.query_advice(padding, Rotation::cur())), ]); - let lookup_columns = vec![hash_input_rlc, code_length, bytecode_table.code_hash]; + let lookup_input_columns = vec![hash_input_rlc, code_length, bytecode_table.code_hash]; + let lookup_table_columns = vec![keccak_table.input_rlc, keccak_table.input_len, keccak_table.output_rlc]; let mut constraints = vec![( enable.clone(), meta.query_advice(keccak_table.is_enabled, Rotation::cur()), )]; - for (i, column) in keccak_table.columns().iter().take(4).skip(1).enumerate() { + for (input_column, table_column) in zip(lookup_input_columns, lookup_table_columns) { constraints.push(( - enable.clone() * meta.query_advice(lookup_columns[i], Rotation::cur()), - meta.query_advice(*column, Rotation::cur()), + enable.clone() * meta.query_advice(input_column, Rotation::cur()), + meta.query_advice(table_column, Rotation::cur()), )) } constraints diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index 222b4dbf40..500c7520a5 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -389,6 +389,12 @@ impl Lookup { input_rlc.clone(), input_len.clone(), output_rlc.clone(), + //self.hash_counter, + //self.byte_value, + //self.bytes_left, + 1.expr(), + 0.expr(), + 0.expr(), ], Self::ExpTable { identifier, From 2be7b131ea8fb43bccac4988e41d7a194dad0b43 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 3 Nov 2022 16:40:18 +0800 Subject: [PATCH 05/15] pass sha3 opcode test; TODO: super circuit; add copy<->sha3 lookup --- .../src/circuit_input_builder/block.rs | 3 ++ .../src/circuit_input_builder/execution.rs | 5 +++ .../circuit_input_builder/input_state_ref.rs | 1 + bus-mapping/src/evm/opcodes/sha3.rs | 4 ++ .../src/evm_circuit/execution/sha3.rs | 7 ++-- zkevm-circuits/src/evm_circuit/step.rs | 5 +++ zkevm-circuits/src/evm_circuit/table.rs | 20 ++++------ .../src/evm_circuit/util/common_gadget.rs | 1 + .../evm_circuit/util/constraint_builder.rs | 9 +++-- .../src/keccak_circuit/keccak_packed_multi.rs | 21 +++++++++-- zkevm-circuits/src/table.rs | 37 ++++++++++--------- zkevm-circuits/src/witness/step.rs | 3 ++ 12 files changed, 76 insertions(+), 40 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/block.rs b/bus-mapping/src/circuit_input_builder/block.rs index c508c76fe5..8dbb460e16 100644 --- a/bus-mapping/src/circuit_input_builder/block.rs +++ b/bus-mapping/src/circuit_input_builder/block.rs @@ -22,6 +22,8 @@ pub struct BlockContext { pub(crate) call_map: HashMap, /// Total gas used by previous transactions in this block. pub(crate) cumulative_gas_used: u64, + /// .. + pub(crate) hash_counter: usize, } impl Default for BlockContext { @@ -37,6 +39,7 @@ impl BlockContext { rwc: RWCounter::new(), call_map: HashMap::new(), cumulative_gas_used: 0, + hash_counter: 0, } } } diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index 4a92fcdcc8..961c8ce97f 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -44,6 +44,8 @@ pub struct ExecStep { pub bus_mapping_instance: Vec, /// Error generated by this step pub error: Option, + /// .. + pub hash_counter: usize, } impl ExecStep { @@ -54,6 +56,7 @@ impl ExecStep { rwc: RWCounter, reversible_write_counter: usize, log_id: usize, + hash_counter: usize, ) -> Self { ExecStep { exec_state: ExecState::Op(step.op), @@ -69,6 +72,7 @@ impl ExecStep { log_id, bus_mapping_instance: Vec::new(), error: None, + hash_counter, } } @@ -97,6 +101,7 @@ impl Default for ExecStep { log_id: 0, bus_mapping_instance: Vec::new(), error: None, + hash_counter: 0, } } } diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index bbd312adab..c1cfb0beda 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -53,6 +53,7 @@ impl<'a> CircuitInputStateRef<'a> { self.block_ctx.rwc, call_ctx.reversible_write_counter, self.tx_ctx.log_id, + self.block_ctx.hash_counter, )) } diff --git a/bus-mapping/src/evm/opcodes/sha3.rs b/bus-mapping/src/evm/opcodes/sha3.rs index d40a55aeb5..341e08da7b 100644 --- a/bus-mapping/src/evm/opcodes/sha3.rs +++ b/bus-mapping/src/evm/opcodes/sha3.rs @@ -19,6 +19,7 @@ impl Opcode for Sha3 { ) -> Result, Error> { let geth_step = &geth_steps[0]; let mut exec_step = state.new_step(geth_step)?; + state.block_ctx.hash_counter += 1; let expected_sha3 = geth_steps[1].stack.last()?; @@ -141,6 +142,9 @@ pub mod sha3_tests { } // append SHA3 related opcodes at the tail end. let code_tail = bytecode! { + PUSH32(size) + PUSH32(offset) + SHA3 PUSH32(size) PUSH32(offset) SHA3 diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 039857bd14..4e647fc21f 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -1,4 +1,4 @@ -use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; +use bus_mapping::{circuit_input_builder::{CopyDataType}, evm::OpcodeId}; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; use gadgets::util::{not, Expr}; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -66,7 +66,7 @@ impl ExecutionGadget for Sha3Gadget { cb.require_zero("copy_rwc_inc == 0 for size = 0", copy_rwc_inc.expr()); cb.require_zero("rlc_acc == 0 for size = 0", rlc_acc.expr()); }); - cb.keccak_table_lookup(rlc_acc.expr(), memory_address.length(), sha3_rlc.expr()); + cb.keccak_table_lookup(cb.curr.state.hash_counter.expr() + 1.expr(), sha3_rlc.expr()); let memory_expansion = MemoryExpansionGadget::construct( cb, @@ -87,6 +87,7 @@ impl ExecutionGadget for Sha3Gadget { gas_left: Transition::Delta( -(OpcodeId::SHA3.constant_gas_cost().expr() + memory_copier_gas.gas_cost()), ), + hash_counter: Transition::Delta(1.expr()), ..Default::default() }; let same_context = SameContextGadget::construct(cb, opcode, step_state_transition); @@ -171,7 +172,7 @@ mod tests { TestContext::<2, 1>::simple_ctx_with_bytecode(code).unwrap(), None, CircuitsParams { - max_rws: 5500, + max_rws: 11000, ..Default::default() } ), diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index c0ff700e5c..5a61d668bb 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -451,6 +451,8 @@ pub(crate) struct StepState { pub(crate) reversible_write_counter: Cell, /// The counter for log index pub(crate) log_id: Cell, + /// + pub(crate) hash_counter: Cell, } #[derive(Clone, Debug)] @@ -489,6 +491,7 @@ impl Step { memory_word_size: cell_manager.query_cell(CellType::Storage), reversible_write_counter: cell_manager.query_cell(CellType::Storage), log_id: cell_manager.query_cell(CellType::Storage), + hash_counter: cell_manager.query_cell(CellType::Storage), } }; Self { @@ -567,6 +570,8 @@ impl Step { self.state .log_id .assign(region, offset, Value::known(F::from(step.log_id as u64)))?; + self.state.hash_counter + .assign(region, offset, Value::known(F::from(step.hash_counter as u64)))?; Ok(()) } } diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index 500c7520a5..d3d231fed3 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -260,9 +260,9 @@ pub(crate) enum Lookup { /// Lookup to keccak table. KeccakTable { /// Accumulator to the input. - input_rlc: Expression, + hash_counter: Expression, /// Length of input that is being hashed. - input_len: Expression, + //input_len: Expression, /// Output (hash) until this state. This is the RLC representation of /// the final output keccak256 hash of the input. output_rlc: Expression, @@ -381,20 +381,16 @@ impl Lookup { rwc_inc.clone(), ], Self::KeccakTable { - input_rlc, - input_len, + hash_counter, output_rlc, } => vec![ 1.expr(), // is_enabled - input_rlc.clone(), - input_len.clone(), + //input_rlc.clone(), + //input_len.clone(), output_rlc.clone(), - //self.hash_counter, - //self.byte_value, - //self.bytes_left, - 1.expr(), - 0.expr(), - 0.expr(), + hash_counter.clone(), + //0.expr(), // byte_value + //0.expr(), // bytes_left ], Self::ExpTable { identifier, diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index 525fddd1e1..fc74f6d2e0 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -175,6 +175,7 @@ impl RestoreContextGadget { memory_word_size: To(caller_memory_word_size.expr()), reversible_write_counter: To(reversible_write_counter), log_id: Same, + ..Default::default() }); Self { diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index 7494606514..057c06dbe6 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -55,6 +55,7 @@ pub(crate) struct StepStateTransition { pub(crate) memory_word_size: Transition>, pub(crate) reversible_write_counter: Transition>, pub(crate) log_id: Transition>, + pub(crate) hash_counter: Transition>, } impl StepStateTransition { @@ -80,6 +81,7 @@ impl StepStateTransition { memory_word_size: Transition::Any, reversible_write_counter: Transition::Any, log_id: Transition::Any, + hash_counter: Transition::Any, } } } @@ -491,6 +493,7 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { constrain!(memory_word_size); constrain!(reversible_write_counter); constrain!(log_id); + constrain!(hash_counter); } // Fixed @@ -1214,15 +1217,13 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { pub(crate) fn keccak_table_lookup( &mut self, - input_rlc: Expression, - input_len: Expression, + hash_counter: Expression, output_rlc: Expression, ) { self.add_lookup( "keccak lookup", Lookup::KeccakTable { - input_rlc, - input_len, + hash_counter, output_rlc, }, ); diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index b42a606da4..8a7887086c 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -1821,14 +1821,27 @@ impl KeccakPackedConfig { offset, [ F::from(row.is_final), - row.data_rlc, - F::from(row.length as u64), + //row.data_rlc, + //F::from(row.length as u64), row.hash_rlc, F::from(row.hash_counter), - F::from(row.value), - F::from(row.bytes_left), + //F::from(row.value), + //F::from(row.bytes_left), ], )?; + for (column, value) in [ + (self.keccak_table.input_rlc, row.data_rlc), + (self.keccak_table.input_len, F::from(row.length as u64)), + (self.keccak_table.byte_value, F::from(row.value)), + (self.keccak_table.bytes_left, F::from(row.bytes_left)), + ] { + region.assign_advice( + || format!("assign {}", offset), + column, + offset, + || Value::known(value), + )?; + } // Cell values for (idx, (bit, column)) in row diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 933f16a63e..b33f5e7ebe 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -752,7 +752,7 @@ impl KeccakTable { counter: usize, input: &[u8], challenges: &Challenges>, - ) -> Vec<[Value; 7]> { + ) -> Vec<[Value; 3]> { let input_rlc = challenges .keccak_input() .map(|challenge| rlc::value(input.iter().rev(), challenge)); @@ -771,23 +771,25 @@ impl KeccakTable { for (idx, byte) in input.iter().enumerate() { assignments.push([ Value::known(F::zero()), - Value::known(F::zero()), - Value::known(F::zero()), + //Value::known(F::zero()), + //Value::known(F::zero()), Value::known(F::zero()), Value::known(F::from_u128(counter as u128)), - Value::known(F::from_u128(*byte as u128)), - Value::known(F::from_u128((input.len() - idx) as u128)), + //Value::known(F::from_u128(*byte as u128)), + //Value::known(F::from_u128((input.len() - idx) as u128)), ]); } - assignments.push([ + let final_row = [ Value::known(F::one()), - input_rlc, - Value::known(input_len), + //input_rlc, + //Value::known(input_len), output_rlc, - Value::known(F::zero()), - Value::known(F::zero()), - Value::known(F::zero()), - ]); + Value::known(F::from_u128(counter as u128)), + //Value::known(F::zero()), + //Value::known(F::zero()), + ]; + //println!("final row {:?}", final_row); + assignments.push(final_row); assignments } @@ -796,8 +798,9 @@ impl KeccakTable { &self, region: &mut Region, offset: usize, - values: [F; 7], + values: [F; 3], ) -> Result<(), Error> { + //println!("keccak table assign row {:?}", values); for (column, value) in self.columns().iter().zip(values.iter()) { region.assign_advice( || format!("assign {}", offset), @@ -856,12 +859,12 @@ impl DynamicTableColumns for KeccakTable { fn columns(&self) -> Vec> { vec![ self.is_enabled, - self.input_rlc, - self.input_len, + //self.input_rlc, + //self.input_len, self.output_rlc, self.hash_counter, - self.byte_value, - self.bytes_left, + //self.byte_value, + //self.bytes_left, ] } } diff --git a/zkevm-circuits/src/witness/step.rs b/zkevm-circuits/src/witness/step.rs index 603cf92f33..3197d219ff 100644 --- a/zkevm-circuits/src/witness/step.rs +++ b/zkevm-circuits/src/witness/step.rs @@ -40,6 +40,8 @@ pub struct ExecStep { pub log_id: usize, /// The opcode corresponds to the step pub opcode: Option, + /// .. + pub hash_counter: usize, } impl ExecStep { @@ -237,5 +239,6 @@ pub(super) fn step_convert(step: &circuit_input_builder::ExecStep) -> ExecStep { memory_size: step.memory_size as u64, reversible_write_counter: step.reversible_write_counter, log_id: step.log_id, + hash_counter: step.hash_counter, } } From 98c271b2bc403d751e93a513ed302e579f0a8b46 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 3 Nov 2022 17:07:14 +0800 Subject: [PATCH 06/15] all done!; testing... --- .../src/circuit_input_builder/execution.rs | 16 +++--- .../src/circuit_input_builder/tracer_tests.rs | 2 +- bus-mapping/src/evm/opcodes/sha3.rs | 6 +-- .../src/bytecode_circuit/bytecode_unroller.rs | 8 ++- .../src/evm_circuit/execution/sha3.rs | 13 +++-- zkevm-circuits/src/evm_circuit/step.rs | 9 ++-- .../src/keccak_circuit/keccak_packed_multi.rs | 22 ++++---- zkevm-circuits/src/super_circuit.rs | 51 +++++++++++++++---- zkevm-circuits/src/table.rs | 6 +-- 9 files changed, 86 insertions(+), 47 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index 961c8ce97f..42784b7e37 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -163,17 +163,17 @@ pub enum CopyDataType { /// When the source for the copy event is the bytecode table. Bytecode = 1, /// When the source/destination for the copy event is memory. - Memory, + Memory = 2, /// When the source for the copy event is tx's calldata. - TxCalldata, + TxCalldata = 3, /// When the destination for the copy event is tx's log. - TxLog, + TxLog = 4, + /// + SHA3 = 5, /// When the destination rows are not directly for copying but for a special /// scenario where we wish to accumulate the value (RLC) over all rows. /// This is used for Copy Lookup from SHA3 opcode verification. - RlcAcc, - /// - SHA3, + RlcAcc = 6, } impl From for usize { @@ -259,10 +259,10 @@ impl CopyEvent { .checked_sub(self.src_addr) .unwrap_or_default(), ), - CopyDataType::RlcAcc | CopyDataType::TxLog | CopyDataType::SHA3=> unreachable!(), + CopyDataType::RlcAcc | CopyDataType::TxLog | CopyDataType::SHA3 => unreachable!(), }; let destination_rw_increase = match self.dst_type { - CopyDataType::RlcAcc | CopyDataType::Bytecode |CopyDataType::SHA3 => 0, + CopyDataType::RlcAcc | CopyDataType::Bytecode | CopyDataType::SHA3 => 0, CopyDataType::TxLog | CopyDataType::Memory => u64::try_from(step_index).unwrap() / 2, CopyDataType::TxCalldata => unreachable!(), }; diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index 583c990783..8729eb6d6f 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -54,7 +54,7 @@ impl CircuitInputBuilderTx { }; let call_ctx = tx_ctx.call_ctx().unwrap(); - let exec_step = ExecStep::new(geth_step, call_ctx, RWCounter::new(), 0, prev_log_id); + let exec_step = ExecStep::new(geth_step, call_ctx, RWCounter::new(), 0, prev_log_id, 0); Self { builder, tx, diff --git a/bus-mapping/src/evm/opcodes/sha3.rs b/bus-mapping/src/evm/opcodes/sha3.rs index 341e08da7b..7499fd82c7 100644 --- a/bus-mapping/src/evm/opcodes/sha3.rs +++ b/bus-mapping/src/evm/opcodes/sha3.rs @@ -19,7 +19,6 @@ impl Opcode for Sha3 { ) -> Result, Error> { let geth_step = &geth_steps[0]; let mut exec_step = state.new_step(geth_step)?; - state.block_ctx.hash_counter += 1; let expected_sha3 = geth_steps[1].stack.last()?; @@ -69,13 +68,14 @@ impl Opcode for Sha3 { src_type: CopyDataType::Memory, src_id: NumberOrHash::Number(call_id), dst_addr: 0, - dst_type: CopyDataType::RlcAcc, - dst_id: NumberOrHash::Number(call_id), + dst_type: CopyDataType::SHA3, + dst_id: NumberOrHash::Number(state.block_ctx.hash_counter + 1), log_id: None, rw_counter_start, bytes: steps, }); + state.block_ctx.hash_counter += 1; Ok(vec![exec_step]) } } diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 5a3e8d1b6a..f493ef0df7 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -2,7 +2,7 @@ use crate::{ evm_circuit::util::{ and, constraint_builder::BaseConstraintBuilder, not, or, select, RandomLinearCombination, }, - table::{BytecodeFieldTag, BytecodeTable, DynamicTableColumns, KeccakTable}, + table::{BytecodeFieldTag, BytecodeTable, KeccakTable}, util::{Challenges, Expr}, }; use bus_mapping::evm::OpcodeId; @@ -351,7 +351,11 @@ impl Config { not::expr(meta.query_advice(padding, Rotation::cur())), ]); let lookup_input_columns = vec![hash_input_rlc, code_length, bytecode_table.code_hash]; - let lookup_table_columns = vec![keccak_table.input_rlc, keccak_table.input_len, keccak_table.output_rlc]; + let lookup_table_columns = vec![ + keccak_table.input_rlc, + keccak_table.input_len, + keccak_table.output_rlc, + ]; let mut constraints = vec![( enable.clone(), meta.query_advice(keccak_table.is_enabled, Rotation::cur()), diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 4e647fc21f..030e186369 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -1,4 +1,4 @@ -use bus_mapping::{circuit_input_builder::{CopyDataType}, evm::OpcodeId}; +use bus_mapping::{circuit_input_builder::CopyDataType, evm::OpcodeId}; use eth_types::{evm_types::GasCost, Field, ToLittleEndian, ToScalar}; use gadgets::util::{not, Expr}; use halo2_proofs::{circuit::Value, plonk::Error}; @@ -52,13 +52,13 @@ impl ExecutionGadget for Sha3Gadget { cb.copy_table_lookup( cb.curr.state.call_id.expr(), CopyDataType::Memory.expr(), - cb.curr.state.call_id.expr(), - CopyDataType::RlcAcc.expr(), + cb.curr.state.hash_counter.expr() + 1.expr(), + CopyDataType::SHA3.expr(), memory_address.offset(), memory_address.address(), 0.expr(), // dst_addr for CopyDataType::RlcAcc is 0. memory_address.length(), - rlc_acc.expr(), + 0.expr(), copy_rwc_inc.expr(), ); }); @@ -66,7 +66,10 @@ impl ExecutionGadget for Sha3Gadget { cb.require_zero("copy_rwc_inc == 0 for size = 0", copy_rwc_inc.expr()); cb.require_zero("rlc_acc == 0 for size = 0", rlc_acc.expr()); }); - cb.keccak_table_lookup(cb.curr.state.hash_counter.expr() + 1.expr(), sha3_rlc.expr()); + cb.keccak_table_lookup( + cb.curr.state.hash_counter.expr() + 1.expr(), + sha3_rlc.expr(), + ); let memory_expansion = MemoryExpansionGadget::construct( cb, diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index 5a61d668bb..74cffcb945 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -451,7 +451,7 @@ pub(crate) struct StepState { pub(crate) reversible_write_counter: Cell, /// The counter for log index pub(crate) log_id: Cell, - /// + /// pub(crate) hash_counter: Cell, } @@ -570,8 +570,11 @@ impl Step { self.state .log_id .assign(region, offset, Value::known(F::from(step.log_id as u64)))?; - self.state.hash_counter - .assign(region, offset, Value::known(F::from(step.hash_counter as u64)))?; + self.state.hash_counter.assign( + region, + offset, + Value::known(F::from(step.hash_counter as u64)), + )?; Ok(()) } } diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 8a7887086c..5bf665f12e 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -20,7 +20,7 @@ use halo2_proofs::{ poly::Rotation, }; use log::{debug, info}; -use std::{env::var, marker::PhantomData, vec}; +use std::{marker::PhantomData, vec}; const MAX_DEGREE: usize = 4; const ABSORB_LOOKUP_RANGE: usize = 3; @@ -1344,7 +1344,7 @@ impl KeccakPackedConfig { }); let q = |col: Column, meta: &mut VirtualCells<'_, F>| { - meta.query_fixed(col.clone(), Rotation::cur()) + meta.query_fixed(col, Rotation::cur()) }; let q_r = |col: Column, meta: &mut VirtualCells<'_, F>| { (0..get_num_rows_per_round() as i32) @@ -1356,11 +1356,11 @@ impl KeccakPackedConfig { .map(|i| meta.query_fixed(col, Rotation(-i))) .fold(0.expr(), |acc, elem| acc + elem) }; - let q_prev = |col: Column, meta: &mut VirtualCells<'_, F>| { - meta.query_fixed(col.clone(), Rotation::prev()) + let _q_prev = |col: Column, meta: &mut VirtualCells<'_, F>| { + meta.query_fixed(col, Rotation::prev()) }; let q_prev_r = |col: Column, meta: &mut VirtualCells<'_, F>| { - meta.query_fixed(col.clone(), Rotation(-(get_num_rows_per_round() as i32))) + meta.query_fixed(col, Rotation(-(get_num_rows_per_round() as i32))) }; /* input is "12345678abc" @@ -1642,7 +1642,7 @@ impl KeccakPackedConfig { cb.gate(1.expr()) }); - let slot_selector = |meta: &mut VirtualCells<'_, F>, q_col| { + let _slot_selector = |meta: &mut VirtualCells<'_, F>, q_col| { let mut exp = 0.expr(); for i in 0..get_num_rows_per_round() { exp = exp + meta.query_fixed(q_col, Rotation(i as i32)); @@ -1824,7 +1824,7 @@ impl KeccakPackedConfig { //row.data_rlc, //F::from(row.length as u64), row.hash_rlc, - F::from(row.hash_counter), + row.hash_counter, //F::from(row.value), //F::from(row.bytes_left), ], @@ -1832,9 +1832,9 @@ impl KeccakPackedConfig { for (column, value) in [ (self.keccak_table.input_rlc, row.data_rlc), (self.keccak_table.input_len, F::from(row.length as u64)), - (self.keccak_table.byte_value, F::from(row.value)), - (self.keccak_table.bytes_left, F::from(row.bytes_left)), - ] { + (self.keccak_table.byte_value, row.value), + (self.keccak_table.bytes_left, row.bytes_left), + ] { region.assign_advice( || format!("assign {}", offset), column, @@ -2242,7 +2242,7 @@ fn keccak(counter: usize, rows: &mut Vec>, bytes: &[u8], is_final: is_final_block && round == NUM_ROUNDS && row_idx == 0, length: round_lengths[round], data_rlc: round_data_rlcs[round], - hash_rlc: hash_rlc, // + F::from_u128(row_idx as u128), + hash_rlc, // + F::from_u128(row_idx as u128), cell_values: regions[round].rows[row_idx].clone(), value: F::from_u128(byte as u128), // from len to 1 diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index a5308c0b35..3875f51a0f 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -54,7 +54,7 @@ use crate::bytecode_circuit::bytecode_unroller::{ unroll, Config as BytecodeConfig, UnrolledBytecode, }; -use crate::copy_circuit::CopyCircuit; +use crate::copy_circuit::{CopyCircuit}; use crate::evm_circuit::{table::FixedTableTag, EvmCircuit}; use crate::exp_circuit::ExpCircuit; use crate::keccak_circuit::keccak_packed_multi::KeccakPackedConfig as KeccakConfig; @@ -65,17 +65,19 @@ use crate::tx_circuit::{TxCircuit, TxCircuitConfig}; use crate::util::Challenges; use crate::witness::{block_convert, Block, MptUpdates}; -use bus_mapping::circuit_input_builder::CircuitInputBuilder; +use bus_mapping::circuit_input_builder::{CircuitInputBuilder, CopyDataType}; use bus_mapping::mock::BlockData; use eth_types::geth_types::{self, GethData, Transaction}; use eth_types::Field; use ethers_core::types::H256; +use gadgets::util::not; use halo2_proofs::arithmetic::CurveAffine; use halo2_proofs::halo2curves::{ bn256::Fr, group::{Curve, Group}, secp256k1::Secp256k1Affine, }; +use halo2_proofs::poly::Rotation; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, plonk::{Circuit, ConstraintSystem, Error, Expression}, @@ -200,6 +202,38 @@ impl keccak circuit + meta.lookup_any("copy<->keccak", |meta| { + let enabled = meta.query_fixed(copy_circuit.q_enable, Rotation::cur()) + * not::expr(meta.query_selector(copy_circuit.q_step)) + * copy_table + .tag + .value_equals(CopyDataType::SHA3, Rotation::cur())(meta); + + vec![ + ( + enabled.clone() * meta.query_advice(copy_table.id, Rotation::cur()), + meta.query_advice(keccak_table.hash_counter, Rotation::cur()), + ), + ( + enabled.clone() * meta.query_advice(copy_table.bytes_left, Rotation::cur()), + meta.query_advice(keccak_table.bytes_left, Rotation::cur()), + ), + ( + enabled * meta.query_advice(copy_circuit.value, Rotation::cur()), + meta.query_advice(keccak_table.byte_value, Rotation::cur()), + ), + ] + }); Self::Config { tx_table: tx_table.clone(), @@ -211,15 +245,7 @@ impl>, ) -> Vec<[Value; 3]> { - let input_rlc = challenges + let _input_rlc = challenges .keccak_input() .map(|challenge| rlc::value(input.iter().rev(), challenge)); - let input_len = F::from(input.len() as u64); + let _input_len = F::from(input.len() as u64); let mut keccak = Keccak::default(); keccak.update(input); let output = keccak.digest(); @@ -768,7 +768,7 @@ impl KeccakTable { }); let mut assignments = Vec::new(); - for (idx, byte) in input.iter().enumerate() { + for (_idx, _byte) in input.iter().enumerate() { assignments.push([ Value::known(F::zero()), //Value::known(F::zero()), From 27a18c395b129f6ffe0b5de51b476392be29e4fe Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 24 Nov 2022 16:00:40 +0800 Subject: [PATCH 07/15] rename to hash_id --- .../src/circuit_input_builder/block.rs | 4 +-- .../src/circuit_input_builder/execution.rs | 8 +++--- .../circuit_input_builder/input_state_ref.rs | 2 +- bus-mapping/src/evm/opcodes/sha3.rs | 4 +-- .../src/evm_circuit/execution/sha3.rs | 6 ++-- zkevm-circuits/src/evm_circuit/step.rs | 8 +++--- zkevm-circuits/src/evm_circuit/table.rs | 6 ++-- .../evm_circuit/util/constraint_builder.rs | 10 +++---- .../src/keccak_circuit/keccak_packed_multi.rs | 28 +++++++++---------- zkevm-circuits/src/super_circuit.rs | 2 +- zkevm-circuits/src/table.rs | 6 ++-- zkevm-circuits/src/witness/step.rs | 4 +-- 12 files changed, 44 insertions(+), 44 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder/block.rs b/bus-mapping/src/circuit_input_builder/block.rs index 8dbb460e16..0309f89ecf 100644 --- a/bus-mapping/src/circuit_input_builder/block.rs +++ b/bus-mapping/src/circuit_input_builder/block.rs @@ -23,7 +23,7 @@ pub struct BlockContext { /// Total gas used by previous transactions in this block. pub(crate) cumulative_gas_used: u64, /// .. - pub(crate) hash_counter: usize, + pub(crate) hash_id: usize, } impl Default for BlockContext { @@ -39,7 +39,7 @@ impl BlockContext { rwc: RWCounter::new(), call_map: HashMap::new(), cumulative_gas_used: 0, - hash_counter: 0, + hash_id: 0, } } } diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index 42784b7e37..2bcc15048d 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -45,7 +45,7 @@ pub struct ExecStep { /// Error generated by this step pub error: Option, /// .. - pub hash_counter: usize, + pub hash_id: usize, } impl ExecStep { @@ -56,7 +56,7 @@ impl ExecStep { rwc: RWCounter, reversible_write_counter: usize, log_id: usize, - hash_counter: usize, + hash_id: usize, ) -> Self { ExecStep { exec_state: ExecState::Op(step.op), @@ -72,7 +72,7 @@ impl ExecStep { log_id, bus_mapping_instance: Vec::new(), error: None, - hash_counter, + hash_id, } } @@ -101,7 +101,7 @@ impl Default for ExecStep { log_id: 0, bus_mapping_instance: Vec::new(), error: None, - hash_counter: 0, + hash_id: 0, } } } diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index c1cfb0beda..1dede4b30e 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -53,7 +53,7 @@ impl<'a> CircuitInputStateRef<'a> { self.block_ctx.rwc, call_ctx.reversible_write_counter, self.tx_ctx.log_id, - self.block_ctx.hash_counter, + self.block_ctx.hash_id, )) } diff --git a/bus-mapping/src/evm/opcodes/sha3.rs b/bus-mapping/src/evm/opcodes/sha3.rs index 7499fd82c7..83447006b8 100644 --- a/bus-mapping/src/evm/opcodes/sha3.rs +++ b/bus-mapping/src/evm/opcodes/sha3.rs @@ -69,13 +69,13 @@ impl Opcode for Sha3 { src_id: NumberOrHash::Number(call_id), dst_addr: 0, dst_type: CopyDataType::SHA3, - dst_id: NumberOrHash::Number(state.block_ctx.hash_counter + 1), + dst_id: NumberOrHash::Number(state.block_ctx.hash_id + 1), log_id: None, rw_counter_start, bytes: steps, }); - state.block_ctx.hash_counter += 1; + state.block_ctx.hash_id += 1; Ok(vec![exec_step]) } } diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 030e186369..1df00d355e 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -52,7 +52,7 @@ impl ExecutionGadget for Sha3Gadget { cb.copy_table_lookup( cb.curr.state.call_id.expr(), CopyDataType::Memory.expr(), - cb.curr.state.hash_counter.expr() + 1.expr(), + cb.curr.state.hash_id.expr() + 1.expr(), CopyDataType::SHA3.expr(), memory_address.offset(), memory_address.address(), @@ -67,7 +67,7 @@ impl ExecutionGadget for Sha3Gadget { cb.require_zero("rlc_acc == 0 for size = 0", rlc_acc.expr()); }); cb.keccak_table_lookup( - cb.curr.state.hash_counter.expr() + 1.expr(), + cb.curr.state.hash_id.expr() + 1.expr(), sha3_rlc.expr(), ); @@ -90,7 +90,7 @@ impl ExecutionGadget for Sha3Gadget { gas_left: Transition::Delta( -(OpcodeId::SHA3.constant_gas_cost().expr() + memory_copier_gas.gas_cost()), ), - hash_counter: Transition::Delta(1.expr()), + hash_id: Transition::Delta(1.expr()), ..Default::default() }; let same_context = SameContextGadget::construct(cb, opcode, step_state_transition); diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index 74cffcb945..75b7bd500c 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -452,7 +452,7 @@ pub(crate) struct StepState { /// The counter for log index pub(crate) log_id: Cell, /// - pub(crate) hash_counter: Cell, + pub(crate) hash_id: Cell, } #[derive(Clone, Debug)] @@ -491,7 +491,7 @@ impl Step { memory_word_size: cell_manager.query_cell(CellType::Storage), reversible_write_counter: cell_manager.query_cell(CellType::Storage), log_id: cell_manager.query_cell(CellType::Storage), - hash_counter: cell_manager.query_cell(CellType::Storage), + hash_id: cell_manager.query_cell(CellType::Storage), } }; Self { @@ -570,10 +570,10 @@ impl Step { self.state .log_id .assign(region, offset, Value::known(F::from(step.log_id as u64)))?; - self.state.hash_counter.assign( + self.state.hash_id.assign( region, offset, - Value::known(F::from(step.hash_counter as u64)), + Value::known(F::from(step.hash_id as u64)), )?; Ok(()) } diff --git a/zkevm-circuits/src/evm_circuit/table.rs b/zkevm-circuits/src/evm_circuit/table.rs index d3d231fed3..e8cf8b7c6c 100644 --- a/zkevm-circuits/src/evm_circuit/table.rs +++ b/zkevm-circuits/src/evm_circuit/table.rs @@ -260,7 +260,7 @@ pub(crate) enum Lookup { /// Lookup to keccak table. KeccakTable { /// Accumulator to the input. - hash_counter: Expression, + hash_id: Expression, /// Length of input that is being hashed. //input_len: Expression, /// Output (hash) until this state. This is the RLC representation of @@ -381,14 +381,14 @@ impl Lookup { rwc_inc.clone(), ], Self::KeccakTable { - hash_counter, + hash_id, output_rlc, } => vec![ 1.expr(), // is_enabled //input_rlc.clone(), //input_len.clone(), output_rlc.clone(), - hash_counter.clone(), + hash_id.clone(), //0.expr(), // byte_value //0.expr(), // bytes_left ], diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index 057c06dbe6..611405ea04 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -55,7 +55,7 @@ pub(crate) struct StepStateTransition { pub(crate) memory_word_size: Transition>, pub(crate) reversible_write_counter: Transition>, pub(crate) log_id: Transition>, - pub(crate) hash_counter: Transition>, + pub(crate) hash_id: Transition>, } impl StepStateTransition { @@ -81,7 +81,7 @@ impl StepStateTransition { memory_word_size: Transition::Any, reversible_write_counter: Transition::Any, log_id: Transition::Any, - hash_counter: Transition::Any, + hash_id: Transition::Any, } } } @@ -493,7 +493,7 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { constrain!(memory_word_size); constrain!(reversible_write_counter); constrain!(log_id); - constrain!(hash_counter); + constrain!(hash_id); } // Fixed @@ -1217,13 +1217,13 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { pub(crate) fn keccak_table_lookup( &mut self, - hash_counter: Expression, + hash_id: Expression, output_rlc: Expression, ) { self.add_lookup( "keccak lookup", Lookup::KeccakTable { - hash_counter, + hash_id, output_rlc, }, ); diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 5bf665f12e..5e3a487e0b 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -29,7 +29,7 @@ const RHO_PI_LOOKUP_RANGE: usize = 4; const CHI_BASE_LOOKUP_RANGE: usize = 5; fn get_num_rows_per_round() -> usize { - 8 + 10 /* var("ROWS") .unwrap_or_else(|_| "5".to_string()) @@ -85,7 +85,7 @@ pub(crate) struct KeccakRow { data_rlc: F, hash_rlc: F, bytes_left: F, // from len to 1 - hash_counter: F, // 0 when first row, then 1,2,3,.. + hash_id: F, // 0 when first row, then 1,2,3,.. value: F, // byte } @@ -1389,19 +1389,19 @@ impl KeccakPackedConfig { cb.condition(q_r(q_first, meta), |cb| { cb.require_zero( - "hash_counter needs to be zero on the first row", - meta.query_advice(keccak_table.hash_counter, Rotation::cur()), + "hash_id needs to be zero on the first row", + meta.query_advice(keccak_table.hash_id, Rotation::cur()), ); }); cb.condition( (q(q_enable, meta) - q(q_first, meta)) * meta.query_advice(is_final, Rotation(-(get_num_rows_per_round() as i32))), |cb| { - let counter = meta.query_advice(keccak_table.hash_counter, Rotation::cur()); + let counter = meta.query_advice(keccak_table.hash_id, Rotation::cur()); let counter_prev = - meta.query_advice(keccak_table.hash_counter, Rotation::prev()); + meta.query_advice(keccak_table.hash_id, Rotation::prev()); cb.require_equal( - "hash_counter increases by 1 after each hash input", + "hash_id increases by 1 after each hash input", counter_prev + 1.expr(), counter, ); @@ -1412,11 +1412,11 @@ impl KeccakPackedConfig { - q_r(q_first, meta) - q(q_enable, meta) * q_prev_r(q_absorb, meta), |cb| { - let counter = meta.query_advice(keccak_table.hash_counter, Rotation::cur()); + let counter = meta.query_advice(keccak_table.hash_id, Rotation::cur()); let counter_prev = - meta.query_advice(keccak_table.hash_counter, Rotation::prev()); + meta.query_advice(keccak_table.hash_id, Rotation::prev()); cb.require_equal( - "hash_counter keeps same when no new hash input", + "hash_id keeps same when no new hash input", counter_prev, counter, ); @@ -1470,7 +1470,7 @@ impl KeccakPackedConfig { //cb.require_equal("bytes_left decreases by 1 for each // row", bytes_left_next + 1.expr(), bytes_left); // let counter_prev = - // meta.query_advice(keccak_table.hash_counter, + // meta.query_advice(keccak_table.hash_id, // Rotation::prev()); }, ); @@ -1824,7 +1824,7 @@ impl KeccakPackedConfig { //row.data_rlc, //F::from(row.length as u64), row.hash_rlc, - row.hash_counter, + row.hash_id, //F::from(row.value), //F::from(row.bytes_left), ], @@ -2247,7 +2247,7 @@ fn keccak(counter: usize, rows: &mut Vec>, bytes: &[u8], value: F::from_u128(byte as u128), // from len to 1 bytes_left: F::from_u128(bytes_left as u128), // + 1? - hash_counter: F::from_u128(counter as u128), + hash_id: F::from_u128(counter as u128), }); { let mut r = rows.last().unwrap().clone(); @@ -2295,7 +2295,7 @@ fn multi_keccak(bytes: &[Vec], r: F) -> Vec> { data_rlc: F::zero(), hash_rlc: F::zero(), cell_values: Vec::new(), - hash_counter: F::zero(), + hash_id: F::zero(), value: F::zero(), bytes_left: F::zero(), }); diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 3875f51a0f..807acb32d8 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -222,7 +222,7 @@ impl, // RLC of hash of input bytes /// .. - pub hash_counter: Column, + pub hash_id: Column, /// .. pub byte_value: Column, /// .. @@ -741,7 +741,7 @@ impl KeccakTable { input_rlc: meta.advice_column_in(SecondPhase), input_len: meta.advice_column(), output_rlc: meta.advice_column_in(SecondPhase), - hash_counter: meta.advice_column(), + hash_id: meta.advice_column(), byte_value: meta.advice_column(), bytes_left: meta.advice_column(), } @@ -862,7 +862,7 @@ impl DynamicTableColumns for KeccakTable { //self.input_rlc, //self.input_len, self.output_rlc, - self.hash_counter, + self.hash_id, //self.byte_value, //self.bytes_left, ] diff --git a/zkevm-circuits/src/witness/step.rs b/zkevm-circuits/src/witness/step.rs index 3197d219ff..a3a6ab28fc 100644 --- a/zkevm-circuits/src/witness/step.rs +++ b/zkevm-circuits/src/witness/step.rs @@ -41,7 +41,7 @@ pub struct ExecStep { /// The opcode corresponds to the step pub opcode: Option, /// .. - pub hash_counter: usize, + pub hash_id: usize, } impl ExecStep { @@ -239,6 +239,6 @@ pub(super) fn step_convert(step: &circuit_input_builder::ExecStep) -> ExecStep { memory_size: step.memory_size as u64, reversible_write_counter: step.reversible_write_counter, log_id: step.log_id, - hash_counter: step.hash_counter, + hash_id: step.hash_id, } } From 260222ef5d5e30f54f7730fa5bcde2952836e8f7 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 24 Nov 2022 16:21:13 +0800 Subject: [PATCH 08/15] towards hash as counter --- bus-mapping/src/circuit_input_builder.rs | 4 ++-- bus-mapping/src/circuit_input_builder/block.rs | 3 --- bus-mapping/src/circuit_input_builder/execution.rs | 5 ----- bus-mapping/src/circuit_input_builder/input_state_ref.rs | 1 - bus-mapping/src/circuit_input_builder/tracer_tests.rs | 2 +- bus-mapping/src/evm/opcodes/sha3.rs | 6 +----- zkevm-circuits/src/evm_circuit/execution/sha3.rs | 5 ++--- zkevm-circuits/src/evm_circuit/step.rs | 8 -------- zkevm-circuits/src/evm_circuit/util/common_gadget.rs | 1 - zkevm-circuits/src/evm_circuit/util/constraint_builder.rs | 3 --- zkevm-circuits/src/witness/step.rs | 3 --- 11 files changed, 6 insertions(+), 35 deletions(-) diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 58f810db8b..0a7c8e9347 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -276,8 +276,6 @@ impl<'a> CircuitInputBuilder { /// block. pub fn keccak_inputs(&self) -> Result>, Error> { let mut keccak_inputs = Vec::new(); - // EVM Circuit - keccak_inputs.extend_from_slice(&self.block.sha3_inputs); // Tx Circuit let txs: Vec = self.block.txs.iter().map(|tx| tx.into()).collect(); keccak_inputs.extend_from_slice(&keccak_inputs_tx_circuit( @@ -288,6 +286,8 @@ impl<'a> CircuitInputBuilder { for bytecode in self.code_db.0.values() { keccak_inputs.push(bytecode.clone()); } + // EVM Circuit + keccak_inputs.extend_from_slice(&self.block.sha3_inputs); // MPT Circuit // TODO https://github.com/privacy-scaling-explorations/zkevm-circuits/issues/696 Ok(keccak_inputs) diff --git a/bus-mapping/src/circuit_input_builder/block.rs b/bus-mapping/src/circuit_input_builder/block.rs index 04181f0943..8e87e6fb35 100644 --- a/bus-mapping/src/circuit_input_builder/block.rs +++ b/bus-mapping/src/circuit_input_builder/block.rs @@ -22,8 +22,6 @@ pub struct BlockContext { pub(crate) call_map: HashMap, /// Total gas used by previous transactions in this block. pub(crate) cumulative_gas_used: u64, - /// .. - pub(crate) hash_id: usize, } impl Default for BlockContext { @@ -39,7 +37,6 @@ impl BlockContext { rwc: RWCounter::new(), call_map: HashMap::new(), cumulative_gas_used: 0, - hash_id: 0, } } } diff --git a/bus-mapping/src/circuit_input_builder/execution.rs b/bus-mapping/src/circuit_input_builder/execution.rs index 2bcc15048d..e7e101be3f 100644 --- a/bus-mapping/src/circuit_input_builder/execution.rs +++ b/bus-mapping/src/circuit_input_builder/execution.rs @@ -44,8 +44,6 @@ pub struct ExecStep { pub bus_mapping_instance: Vec, /// Error generated by this step pub error: Option, - /// .. - pub hash_id: usize, } impl ExecStep { @@ -56,7 +54,6 @@ impl ExecStep { rwc: RWCounter, reversible_write_counter: usize, log_id: usize, - hash_id: usize, ) -> Self { ExecStep { exec_state: ExecState::Op(step.op), @@ -72,7 +69,6 @@ impl ExecStep { log_id, bus_mapping_instance: Vec::new(), error: None, - hash_id, } } @@ -101,7 +97,6 @@ impl Default for ExecStep { log_id: 0, bus_mapping_instance: Vec::new(), error: None, - hash_id: 0, } } } diff --git a/bus-mapping/src/circuit_input_builder/input_state_ref.rs b/bus-mapping/src/circuit_input_builder/input_state_ref.rs index 430a5d3614..724e897290 100644 --- a/bus-mapping/src/circuit_input_builder/input_state_ref.rs +++ b/bus-mapping/src/circuit_input_builder/input_state_ref.rs @@ -53,7 +53,6 @@ impl<'a> CircuitInputStateRef<'a> { self.block_ctx.rwc, call_ctx.reversible_write_counter, self.tx_ctx.log_id, - self.block_ctx.hash_id, )) } diff --git a/bus-mapping/src/circuit_input_builder/tracer_tests.rs b/bus-mapping/src/circuit_input_builder/tracer_tests.rs index e245da0ef1..5d43d0ef62 100644 --- a/bus-mapping/src/circuit_input_builder/tracer_tests.rs +++ b/bus-mapping/src/circuit_input_builder/tracer_tests.rs @@ -54,7 +54,7 @@ impl CircuitInputBuilderTx { }; let call_ctx = tx_ctx.call_ctx().unwrap(); - let exec_step = ExecStep::new(geth_step, call_ctx, RWCounter::new(), 0, prev_log_id, 0); + let exec_step = ExecStep::new(geth_step, call_ctx, RWCounter::new(), 0, prev_log_id); Self { builder, tx, diff --git a/bus-mapping/src/evm/opcodes/sha3.rs b/bus-mapping/src/evm/opcodes/sha3.rs index 83447006b8..136d1de7d9 100644 --- a/bus-mapping/src/evm/opcodes/sha3.rs +++ b/bus-mapping/src/evm/opcodes/sha3.rs @@ -69,13 +69,12 @@ impl Opcode for Sha3 { src_id: NumberOrHash::Number(call_id), dst_addr: 0, dst_type: CopyDataType::SHA3, - dst_id: NumberOrHash::Number(state.block_ctx.hash_id + 1), + dst_id: NumberOrHash::Hash(sha3.into()), log_id: None, rw_counter_start, bytes: steps, }); - state.block_ctx.hash_id += 1; Ok(vec![exec_step]) } } @@ -142,9 +141,6 @@ pub mod sha3_tests { } // append SHA3 related opcodes at the tail end. let code_tail = bytecode! { - PUSH32(size) - PUSH32(offset) - SHA3 PUSH32(size) PUSH32(offset) SHA3 diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index abb817a581..44613264b6 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -52,7 +52,7 @@ impl ExecutionGadget for Sha3Gadget { cb.copy_table_lookup( cb.curr.state.call_id.expr(), CopyDataType::Memory.expr(), - cb.curr.state.hash_id.expr() + 1.expr(), + sha3_rlc.expr(), CopyDataType::SHA3.expr(), memory_address.offset(), memory_address.address(), @@ -67,7 +67,7 @@ impl ExecutionGadget for Sha3Gadget { cb.require_zero("rlc_acc == 0 for size = 0", rlc_acc.expr()); }); cb.keccak_table_lookup( - cb.curr.state.hash_id.expr() + 1.expr(), + sha3_rlc.expr(), sha3_rlc.expr(), ); @@ -86,7 +86,6 @@ impl ExecutionGadget for Sha3Gadget { gas_left: Transition::Delta( -(OpcodeId::SHA3.constant_gas_cost().expr() + memory_copier_gas.gas_cost()), ), - hash_id: Transition::Delta(1.expr()), ..Default::default() }; let same_context = SameContextGadget::construct(cb, opcode, step_state_transition); diff --git a/zkevm-circuits/src/evm_circuit/step.rs b/zkevm-circuits/src/evm_circuit/step.rs index 6cd6cad12c..b95f3dc424 100644 --- a/zkevm-circuits/src/evm_circuit/step.rs +++ b/zkevm-circuits/src/evm_circuit/step.rs @@ -446,8 +446,6 @@ pub(crate) struct StepState { pub(crate) reversible_write_counter: Cell, /// The counter for log index pub(crate) log_id: Cell, - /// - pub(crate) hash_id: Cell, } #[derive(Clone, Debug)] @@ -486,7 +484,6 @@ impl Step { memory_word_size: cell_manager.query_cell(CellType::Storage), reversible_write_counter: cell_manager.query_cell(CellType::Storage), log_id: cell_manager.query_cell(CellType::Storage), - hash_id: cell_manager.query_cell(CellType::Storage), } }; Self { @@ -565,11 +562,6 @@ impl Step { self.state .log_id .assign(region, offset, Value::known(F::from(step.log_id as u64)))?; - self.state.hash_id.assign( - region, - offset, - Value::known(F::from(step.hash_id as u64)), - )?; Ok(()) } } diff --git a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs index fc74f6d2e0..525fddd1e1 100644 --- a/zkevm-circuits/src/evm_circuit/util/common_gadget.rs +++ b/zkevm-circuits/src/evm_circuit/util/common_gadget.rs @@ -175,7 +175,6 @@ impl RestoreContextGadget { memory_word_size: To(caller_memory_word_size.expr()), reversible_write_counter: To(reversible_write_counter), log_id: Same, - ..Default::default() }); Self { diff --git a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs index 611405ea04..359fbfaed8 100644 --- a/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs +++ b/zkevm-circuits/src/evm_circuit/util/constraint_builder.rs @@ -55,7 +55,6 @@ pub(crate) struct StepStateTransition { pub(crate) memory_word_size: Transition>, pub(crate) reversible_write_counter: Transition>, pub(crate) log_id: Transition>, - pub(crate) hash_id: Transition>, } impl StepStateTransition { @@ -81,7 +80,6 @@ impl StepStateTransition { memory_word_size: Transition::Any, reversible_write_counter: Transition::Any, log_id: Transition::Any, - hash_id: Transition::Any, } } } @@ -493,7 +491,6 @@ impl<'a, F: Field> ConstraintBuilder<'a, F> { constrain!(memory_word_size); constrain!(reversible_write_counter); constrain!(log_id); - constrain!(hash_id); } // Fixed diff --git a/zkevm-circuits/src/witness/step.rs b/zkevm-circuits/src/witness/step.rs index 55bb8020e3..037ffcb0cc 100644 --- a/zkevm-circuits/src/witness/step.rs +++ b/zkevm-circuits/src/witness/step.rs @@ -40,8 +40,6 @@ pub struct ExecStep { pub log_id: usize, /// The opcode corresponds to the step pub opcode: Option, - /// .. - pub hash_id: usize, } impl ExecStep { @@ -239,6 +237,5 @@ pub(super) fn step_convert(step: &circuit_input_builder::ExecStep) -> ExecStep { memory_size: step.memory_size as u64, reversible_write_counter: step.reversible_write_counter, log_id: step.log_id, - hash_id: step.hash_id, } } From 1a502191f0719cbd7d2118656391f64b7f64d8f8 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 24 Nov 2022 16:49:26 +0800 Subject: [PATCH 09/15] basic new counter pass --- .../src/keccak_circuit/keccak_packed_multi.rs | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index f0ca0f1559..224255c474 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -29,7 +29,8 @@ const RHO_PI_LOOKUP_RANGE: usize = 4; const CHI_BASE_LOOKUP_RANGE: usize = 5; fn get_num_rows_per_round() -> usize { - 10 + 8 + //10 /* .unwrap_or_else(|_| "5".to_string()) .parse() @@ -1384,7 +1385,7 @@ impl KeccakPackedConfig { */ - meta.create_gate("counter", |meta| { + meta.create_gate("hash_id", |meta| { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); cb.condition(q_r(q_first, meta), |cb| { @@ -1395,15 +1396,14 @@ impl KeccakPackedConfig { }); cb.condition( (q(q_enable, meta) - q(q_first, meta)) - * meta.query_advice(is_final, Rotation(-(get_num_rows_per_round() as i32))), + * meta.query_advice(is_final, Rotation::cur()), |cb| { - let counter = meta.query_advice(keccak_table.hash_id, Rotation::cur()); - let counter_prev = - meta.query_advice(keccak_table.hash_id, Rotation::prev()); + let hash_id = meta.query_advice(keccak_table.hash_id, Rotation::cur()); + let hash_rlc = meta.query_advice(hash_rlc, Rotation::cur()); cb.require_equal( - "hash_id increases by 1 after each hash input", - counter_prev + 1.expr(), - counter, + "hash_id == hash_output", + hash_rlc, + hash_id, ); }, ); @@ -1893,7 +1893,7 @@ impl KeccakPackedConfig { } } -fn keccak(counter: usize, rows: &mut Vec>, bytes: &[u8], r: F) { +fn keccak(rows: &mut Vec>, bytes: &[u8], r: F) { let mut bits = into_bits(bytes); let mut s = [[F::zero(); 5]; 5]; let absorb_positions = get_absorb_positions(); @@ -1907,6 +1907,10 @@ fn keccak(counter: usize, rows: &mut Vec>, bytes: &[u8], } bits.push(1); + + let mut hash_out: [u8; 32] = ethers_core::utils::keccak256(bytes); + hash_out.reverse(); + let hash_id = rlc::value(&hash_out, r); let mut length = 0usize; let mut data_rlc = F::zero(); let chunks = bits.chunks(RATE_IN_BITS); @@ -2181,6 +2185,7 @@ fn keccak(counter: usize, rows: &mut Vec>, bytes: &[u8], .flat_map(|a| to_bytes::value(&unpack(a[0]))) .rev() .collect::>(); + debug_assert_eq!(hash_bytes_le, hash_out.to_vec()); rlc::value(&hash_bytes_le, r) } else { F::zero() @@ -2247,7 +2252,7 @@ fn keccak(counter: usize, rows: &mut Vec>, bytes: &[u8], value: F::from_u128(byte as u128), // from len to 1 bytes_left: F::from_u128(bytes_left as u128), // + 1? - hash_id: F::from_u128(counter as u128), + hash_id, }); { let mut r = rows.last().unwrap().clone(); @@ -2305,8 +2310,8 @@ fn multi_keccak( }); } // Actual keccaks - for (idx, bytes) in bytes.iter().enumerate() { - keccak(idx + 1, &mut rows, bytes, r); + for bytes in bytes.iter() { + keccak(&mut rows, bytes, r); } if let Some(capacity) = capacity { // Pad with no data hashes to the expected capacity From d522eee47250e6802af82ff66dc889f6e81b3c46 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 24 Nov 2022 23:09:31 +0800 Subject: [PATCH 10/15] pass --- .../src/keccak_circuit/keccak_packed_multi.rs | 63 +++++++++++-------- zkevm-circuits/src/super_circuit.rs | 8 +-- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 224255c474..7e403c0523 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -29,8 +29,8 @@ const RHO_PI_LOOKUP_RANGE: usize = 4; const CHI_BASE_LOOKUP_RANGE: usize = 5; fn get_num_rows_per_round() -> usize { - 8 - //10 + //8 + 28 /* .unwrap_or_else(|_| "5".to_string()) .parse() @@ -1347,6 +1347,11 @@ impl KeccakPackedConfig { let q = |col: Column, meta: &mut VirtualCells<'_, F>| { meta.query_fixed(col, Rotation::cur()) }; + let q_first8 = |meta: &mut VirtualCells<'_, F>| { + (0..8 as i32) + .map(|i| meta.query_fixed(q_enable, Rotation(-i))) + .fold(0.expr(), |acc, elem| acc + elem) + }; let q_r = |col: Column, meta: &mut VirtualCells<'_, F>| { (0..get_num_rows_per_round() as i32) .map(|i| meta.query_fixed(col, Rotation(-i))) @@ -1364,24 +1369,29 @@ impl KeccakPackedConfig { meta.query_fixed(col, Rotation(-(get_num_rows_per_round() as i32))) }; /* + get_num_rows_per_round = 18 input is "12345678abc" - offset value bytes_left is_padding q_enable q_padding_last - 8 1 11 0 1 0 - 9 2 10 0 0 0 - 10 3 9 0 0 0 - 11 4 8 0 0 0 - 12 5 7 0 0 0 - 13 6 6 0 0 0 - 14 7 5 0 0 0 - 15 8 4 0 0 0 // 1st round end - 16 a 3 0 1 1 // 2nd round start - 17 b 2 0 0 0 - 18 c 1 0 0 0 - 19 0 0 1 0 0 - 20 0 0 1 0 0 - 21 0 0 1 0 0 - 22 0 0 1 0 0 - 23 0 0 1 0 0 // 2nd round end + be careful: is_paddings is not column here! It is [Cell; 8]. + offset value bytes_left is_paddings q_enable q_padding_last + 18 1 11 0 1 0 + 19 2 10 0 0 0 + 20 3 9 0 0 0 + 21 4 8 0 0 0 + 22 5 7 0 0 0 + 23 6 6 0 0 0 + 24 7 5 0 0 0 + 25 8 4 0 0 0 + 26 8 4 NA 0 0 + ... + 35 8 4 NA 0 0 // 1st round end + 36 a 3 0 1 1 // 2nd round start + 37 b 2 0 0 0 + 38 c 1 0 0 0 + 39 0 0 1 0 0 + 40 0 0 1 0 0 + 41 0 0 1 0 0 + 42 0 0 1 0 0 + 43 0 0 1 0 0 */ @@ -1428,11 +1438,12 @@ impl KeccakPackedConfig { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); for idx in 0..get_num_rows_per_round() { cb.condition( - q_r(q_padding, meta) * not::expr(is_paddings[idx].expr()), + //meta.query_fixed(q_padding, Rotation(-(idx as i32))), + q(q_padding, meta) * not::expr(is_paddings[std::cmp::min(idx, 7)].expr()), |cb| { cb.require_equal( "input byte", - input_bytes[idx].expr.clone(), + input_bytes[std::cmp::min(idx, 7)].expr.clone(), meta.query_advice(keccak_table.byte_value, Rotation(idx as i32)), ); }, @@ -1450,7 +1461,6 @@ impl KeccakPackedConfig { ); }); // is_paddings only be true when - cb.condition( q(q_padding, meta), /* - q(q_padding_last, meta) */ |cb| { @@ -1459,10 +1469,13 @@ impl KeccakPackedConfig { meta.query_advice(keccak_table.bytes_left, Rotation(i as i32)); let bytes_left_next = meta.query_advice(keccak_table.bytes_left, Rotation(i as i32 + 1)); + // real input only when !is_paddings[i] && i < 8 cb.require_equal( "if not padding, bytes_left decreases by 1, else, stay same", bytes_left_next, - bytes_left.clone() - (not::expr(is_paddings[i].expr())), + bytes_left.clone() - if (i < 7 || i == get_num_rows_per_round() - 1) { + not::expr(is_paddings[std::cmp::min(i, 7)].expr()) + } else { 0.expr() }, ); // cb.require_zero("bytes_left should be 0 when // padding", bytes_left * is_paddings[i].expr()); @@ -2220,7 +2233,7 @@ fn keccak(rows: &mut Vec>, bytes: &[u8], r: F) { let round_cst = pack_u64(ROUND_CST[round]); for row_idx in 0..get_num_rows_per_round() { let byte_idx = if round < NUM_WORDS_TO_ABSORB { - round * 8 + row_idx + round * 8 + std::cmp::min(row_idx, 7) } else { NUM_WORDS_TO_ABSORB * 8 } + idx * NUM_WORDS_TO_ABSORB * 8; @@ -2349,7 +2362,7 @@ mod tests { #[test] fn packed_multi_keccak_simple() { - let k = 11; + let k = 14; let inputs = vec![ vec![], (0u8..1).collect::>(), diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 5ac2579a5b..7ef8f86a7e 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -216,7 +216,7 @@ impl keccak circuit meta.lookup_any("copy<->keccak", |meta| { - let enabled = meta.query_fixed(copy_circuit.q_enable, Rotation::cur()) + let input_enabled = meta.query_fixed(copy_circuit.q_enable, Rotation::cur()) * not::expr(meta.query_selector(copy_circuit.q_step)) * copy_table .tag @@ -224,15 +224,15 @@ impl Date: Thu, 24 Nov 2022 23:16:25 +0800 Subject: [PATCH 11/15] byte_left == 0 when is_padding --- .../src/keccak_circuit/keccak_packed_multi.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 7e403c0523..9d737a29be 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -1373,17 +1373,17 @@ impl KeccakPackedConfig { input is "12345678abc" be careful: is_paddings is not column here! It is [Cell; 8]. offset value bytes_left is_paddings q_enable q_padding_last - 18 1 11 0 1 0 - 19 2 10 0 0 0 + 18 1 11 0 1 0 + 19 2 10 0 0 0 20 3 9 0 0 0 21 4 8 0 0 0 22 5 7 0 0 0 23 6 6 0 0 0 24 7 5 0 0 0 25 8 4 0 0 0 - 26 8 4 NA 0 0 + 26 8 4 NA 0 0 ... - 35 8 4 NA 0 0 // 1st round end + 35 8 4 NA 0 0 // 1st round end 36 a 3 0 1 1 // 2nd round start 37 b 2 0 0 0 38 c 1 0 0 0 @@ -1477,8 +1477,7 @@ impl KeccakPackedConfig { not::expr(is_paddings[std::cmp::min(i, 7)].expr()) } else { 0.expr() }, ); - // cb.require_zero("bytes_left should be 0 when - // padding", bytes_left * is_paddings[i].expr()); + cb.require_zero("bytes_left should be 0 when padding", bytes_left * is_paddings[std::cmp::min(i, 7)].expr()); } //cb.require_equal("bytes_left decreases by 1 for each // row", bytes_left_next + 1.expr(), bytes_left); From da0cc82eaf80eb1f5f6823d7e9fcc9bee56535ad Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 24 Nov 2022 23:23:32 +0800 Subject: [PATCH 12/15] fix sha3 --- zkevm-circuits/src/table.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 5e024c066e..39ae2c3605 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -757,7 +757,6 @@ impl KeccakTable { /// Generate the keccak table assignments from a byte array input. pub fn assignments( - counter: usize, input: &[u8], challenges: &Challenges>, ) -> Vec<[Value; 3]> { @@ -782,7 +781,7 @@ impl KeccakTable { //Value::known(F::zero()), //Value::known(F::zero()), Value::known(F::zero()), - Value::known(F::from_u128(counter as u128)), + output_rlc, //Value::known(F::from_u128(*byte as u128)), //Value::known(F::from_u128((input.len() - idx) as u128)), ]); @@ -792,7 +791,7 @@ impl KeccakTable { //input_rlc, //Value::known(input_len), output_rlc, - Value::known(F::from_u128(counter as u128)), + output_rlc, //Value::known(F::zero()), //Value::known(F::zero()), ]; @@ -843,8 +842,8 @@ impl KeccakTable { offset += 1; let keccak_table_columns = self.columns(); - for (idx, input) in inputs.clone().into_iter().enumerate() { - for row in Self::assignments(idx + 1, input, challenges) { + for input in inputs.clone() { + for row in Self::assignments(input, challenges) { // let mut column_index = 0; for (column, value) in keccak_table_columns.iter().zip_eq(row) { region.assign_advice( From b6c48d536c281830beac60105894a39d5f931137 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 24 Nov 2022 23:29:55 +0800 Subject: [PATCH 13/15] lint --- .../src/evm_circuit/execution/sha3.rs | 5 +-- .../src/keccak_circuit/keccak_packed_multi.rs | 40 +++++++++---------- zkevm-circuits/src/super_circuit.rs | 7 ++-- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/zkevm-circuits/src/evm_circuit/execution/sha3.rs b/zkevm-circuits/src/evm_circuit/execution/sha3.rs index 44613264b6..88615ee73b 100644 --- a/zkevm-circuits/src/evm_circuit/execution/sha3.rs +++ b/zkevm-circuits/src/evm_circuit/execution/sha3.rs @@ -66,10 +66,7 @@ impl ExecutionGadget for Sha3Gadget { cb.require_zero("copy_rwc_inc == 0 for size = 0", copy_rwc_inc.expr()); cb.require_zero("rlc_acc == 0 for size = 0", rlc_acc.expr()); }); - cb.keccak_table_lookup( - sha3_rlc.expr(), - sha3_rlc.expr(), - ); + cb.keccak_table_lookup(sha3_rlc.expr(), sha3_rlc.expr()); let memory_expansion = MemoryExpansionGadget::construct(cb, [memory_address.address()]); let memory_copier_gas = MemoryCopierGasGadget::construct( diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 9d737a29be..fd536f2c6c 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -84,9 +84,9 @@ pub(crate) struct KeccakRow { length: usize, data_rlc: F, hash_rlc: F, - bytes_left: F, // from len to 1 - hash_id: F, // 0 when first row, then 1,2,3,.. - value: F, // byte + bytes_left: F, // from len to 1 + hash_id: F, // 0 when first row, then 1,2,3,.. + value: F, // byte } /// Part @@ -1347,8 +1347,8 @@ impl KeccakPackedConfig { let q = |col: Column, meta: &mut VirtualCells<'_, F>| { meta.query_fixed(col, Rotation::cur()) }; - let q_first8 = |meta: &mut VirtualCells<'_, F>| { - (0..8 as i32) + let _q_first8 = |meta: &mut VirtualCells<'_, F>| { + (0..8_i32) .map(|i| meta.query_fixed(q_enable, Rotation(-i))) .fold(0.expr(), |acc, elem| acc + elem) }; @@ -1357,7 +1357,7 @@ impl KeccakPackedConfig { .map(|i| meta.query_fixed(col, Rotation(-i))) .fold(0.expr(), |acc, elem| acc + elem) }; - let q_round_trailing = |col: Column, meta: &mut VirtualCells<'_, F>| { + let _q_round_trailing = |col: Column, meta: &mut VirtualCells<'_, F>| { (1..get_num_rows_per_round() as i32) .map(|i| meta.query_fixed(col, Rotation(-i))) .fold(0.expr(), |acc, elem| acc + elem) @@ -1380,8 +1380,8 @@ impl KeccakPackedConfig { 22 5 7 0 0 0 23 6 6 0 0 0 24 7 5 0 0 0 - 25 8 4 0 0 0 - 26 8 4 NA 0 0 + 25 8 4 0 0 0 + 26 8 4 NA 0 0 ... 35 8 4 NA 0 0 // 1st round end 36 a 3 0 1 1 // 2nd round start @@ -1410,11 +1410,7 @@ impl KeccakPackedConfig { |cb| { let hash_id = meta.query_advice(keccak_table.hash_id, Rotation::cur()); let hash_rlc = meta.query_advice(hash_rlc, Rotation::cur()); - cb.require_equal( - "hash_id == hash_output", - hash_rlc, - hash_id, - ); + cb.require_equal("hash_id == hash_output", hash_rlc, hash_id); }, ); cb.condition( @@ -1423,8 +1419,7 @@ impl KeccakPackedConfig { - q(q_enable, meta) * q_prev_r(q_absorb, meta), |cb| { let counter = meta.query_advice(keccak_table.hash_id, Rotation::cur()); - let counter_prev = - meta.query_advice(keccak_table.hash_id, Rotation::prev()); + let counter_prev = meta.query_advice(keccak_table.hash_id, Rotation::prev()); cb.require_equal( "hash_id keeps same when no new hash input", counter_prev, @@ -1473,11 +1468,17 @@ impl KeccakPackedConfig { cb.require_equal( "if not padding, bytes_left decreases by 1, else, stay same", bytes_left_next, - bytes_left.clone() - if (i < 7 || i == get_num_rows_per_round() - 1) { - not::expr(is_paddings[std::cmp::min(i, 7)].expr()) - } else { 0.expr() }, + bytes_left.clone() + - if i < 7 || i == get_num_rows_per_round() - 1 { + not::expr(is_paddings[std::cmp::min(i, 7)].expr()) + } else { + 0.expr() + }, + ); + cb.require_zero( + "bytes_left should be 0 when padding", + bytes_left * is_paddings[std::cmp::min(i, 7)].expr(), ); - cb.require_zero("bytes_left should be 0 when padding", bytes_left * is_paddings[std::cmp::min(i, 7)].expr()); } //cb.require_equal("bytes_left decreases by 1 for each // row", bytes_left_next + 1.expr(), bytes_left); @@ -1919,7 +1920,6 @@ fn keccak(rows: &mut Vec>, bytes: &[u8], r: F) { } bits.push(1); - let mut hash_out: [u8; 32] = ethers_core::utils::keccak256(bytes); hash_out.reverse(); let hash_id = rlc::value(&hash_out, r); diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 7ef8f86a7e..5387d86a20 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -54,7 +54,7 @@ use crate::bytecode_circuit::bytecode_unroller::{ unroll, Config as BytecodeConfig, UnrolledBytecode, }; -use crate::copy_circuit::{CopyCircuit}; +use crate::copy_circuit::CopyCircuit; use crate::evm_circuit::{table::FixedTableTag, EvmCircuit}; use crate::exp_circuit::ExpCircuitConfig; use crate::keccak_circuit::keccak_packed_multi::KeccakPackedConfig as KeccakConfig; @@ -64,8 +64,8 @@ use crate::table::{BlockTable, BytecodeTable, CopyTable, ExpTable, MptTable, RwT use crate::tx_circuit::{TxCircuit, TxCircuitConfig}; use crate::util::Challenges; use crate::witness::{block_convert, Block, MptUpdates}; -use bus_mapping::circuit_input_builder::{CircuitInputBuilder, CircuitsParams}; use bus_mapping::circuit_input_builder::CopyDataType; +use bus_mapping::circuit_input_builder::{CircuitInputBuilder, CircuitsParams}; use bus_mapping::mock::BlockData; use eth_types::geth_types::{self, GethData, Transaction}; use eth_types::Field; @@ -228,7 +228,8 @@ impl Date: Fri, 25 Nov 2022 09:44:28 +0800 Subject: [PATCH 14/15] fix tests; TODO: super circuit test --- circuit-benchmarks/src/lib.rs | 8 --- .../src/bytecode_circuit/bytecode_unroller.rs | 9 +++- zkevm-circuits/src/bytecode_circuit/dev.rs | 1 + .../src/keccak_circuit/keccak_packed_multi.rs | 10 ++-- zkevm-circuits/src/super_circuit.rs | 6 +-- zkevm-circuits/src/table.rs | 53 ++++++++++++------- 6 files changed, 51 insertions(+), 36 deletions(-) diff --git a/circuit-benchmarks/src/lib.rs b/circuit-benchmarks/src/lib.rs index c6238d95d3..d0084f3732 100644 --- a/circuit-benchmarks/src/lib.rs +++ b/circuit-benchmarks/src/lib.rs @@ -16,14 +16,6 @@ pub mod tx_circuit; #[cfg(feature = "benches")] pub mod super_circuit; -#[cfg(test)] -#[cfg(feature = "benches")] -pub mod bit_keccak; - -#[cfg(test)] -#[cfg(feature = "benches")] -pub mod packed_keccak; - #[cfg(test)] #[cfg(feature = "benches")] pub mod packed_multi_keccak; diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 8afd927615..96981752e7 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -799,10 +799,15 @@ mod tests { } /// Tests a circuit with incomplete bytecode + #[ignore = "keccak rows larger than bytecode rows"] #[test] fn bytecode_incomplete() { - let k = 9; - test_bytecode_circuit_unrolled::(k, vec![unroll(vec![7u8; 2usize.pow(k) + 1])], false); + let k = 12; + test_bytecode_circuit_unrolled::( + k - 3, + vec![unroll(vec![7u8; 2usize.pow(k) + 1])], + false, + ); } /// Tests multiple bytecodes in a single circuit diff --git a/zkevm-circuits/src/bytecode_circuit/dev.rs b/zkevm-circuits/src/bytecode_circuit/dev.rs index 6a79d74709..ad5d58a68a 100644 --- a/zkevm-circuits/src/bytecode_circuit/dev.rs +++ b/zkevm-circuits/src/bytecode_circuit/dev.rs @@ -103,6 +103,7 @@ pub fn test_bytecode_circuit_unrolled( bytecodes: Vec>, success: bool, ) { + let k = k + 3; let circuit = BytecodeCircuitTester:: { bytecodes, size: 2usize.pow(k), diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index fd536f2c6c..4f37087d5d 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -1834,14 +1834,15 @@ impl KeccakPackedConfig { offset, [ F::from(row.is_final), - //row.data_rlc, - //F::from(row.length as u64), + row.data_rlc, + F::from(row.length as u64), row.hash_rlc, row.hash_id, - //F::from(row.value), - //F::from(row.bytes_left), + row.value, + row.bytes_left, ], )?; + /* for (column, value) in [ (self.keccak_table.input_rlc, row.data_rlc), (self.keccak_table.input_len, F::from(row.length as u64)), @@ -1855,6 +1856,7 @@ impl KeccakPackedConfig { || Value::known(value), )?; } + */ // Cell values for (idx, (bit, column)) in row diff --git a/zkevm-circuits/src/super_circuit.rs b/zkevm-circuits/src/super_circuit.rs index 5387d86a20..c233930670 100644 --- a/zkevm-circuits/src/super_circuit.rs +++ b/zkevm-circuits/src/super_circuit.rs @@ -480,10 +480,10 @@ mod super_circuit_tests { let chain_id = (*MOCK_CHAIN_ID).as_u64(); let bytecode = bytecode! { - PUSH32(100) - PUSH32(0) + PUSH32(100) // size + PUSH32(0) // offset SHA3 - PUSH32(100) + PUSH32(200) PUSH32(0) SHA3 STOP diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 39ae2c3605..879148d190 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -755,15 +755,27 @@ impl KeccakTable { } } + fn all_columns(&self) -> Vec> { + vec![ + self.is_enabled, + self.input_rlc, + self.input_len, + self.output_rlc, + self.hash_id, + self.byte_value, + self.bytes_left, + ] + } + /// Generate the keccak table assignments from a byte array input. pub fn assignments( input: &[u8], challenges: &Challenges>, - ) -> Vec<[Value; 3]> { - let _input_rlc = challenges + ) -> Vec<[Value; 7]> { + let input_rlc = challenges .keccak_input() .map(|challenge| rlc::value(input.iter().rev(), challenge)); - let _input_len = F::from(input.len() as u64); + let input_len = F::from(input.len() as u64); let mut keccak = Keccak::default(); keccak.update(input); let output = keccak.digest(); @@ -775,25 +787,27 @@ impl KeccakTable { }); let mut assignments = Vec::new(); - for (_idx, _byte) in input.iter().enumerate() { + // used for "id based keccak". the input part of keccak circuit + for (idx, byte) in input.iter().enumerate() { assignments.push([ - Value::known(F::zero()), - //Value::known(F::zero()), - //Value::known(F::zero()), - Value::known(F::zero()), + Value::known(F::zero()), // is_final + Value::known(F::zero()), // place holder + Value::known(F::zero()), // place holder + Value::known(F::zero()), // place holder output_rlc, - //Value::known(F::from_u128(*byte as u128)), - //Value::known(F::from_u128((input.len() - idx) as u128)), + Value::known(F::from_u128(*byte as u128)), + Value::known(F::from_u128((input.len() - idx) as u128)), ]); } + // used for "rlc based keccak". the output part of keccak circuit let final_row = [ Value::known(F::one()), - //input_rlc, - //Value::known(input_len), + input_rlc, + Value::known(input_len), output_rlc, - output_rlc, - //Value::known(F::zero()), - //Value::known(F::zero()), + output_rlc, // place holder + Value::known(F::zero()), // place holder + Value::known(F::zero()), // place holder ]; //println!("final row {:?}", final_row); assignments.push(final_row); @@ -805,10 +819,10 @@ impl KeccakTable { &self, region: &mut Region, offset: usize, - values: [F; 3], + values: [F; 7], ) -> Result<(), Error> { //println!("keccak table assign row {:?}", values); - for (column, value) in self.columns().iter().zip(values.iter()) { + for (column, value) in self.all_columns().iter().zip_eq(values.iter()) { region.assign_advice( || format!("assign {}", offset), *column, @@ -831,7 +845,7 @@ impl KeccakTable { || "keccak table", |mut region| { let mut offset = 0; - for column in self.columns() { + for column in self.all_columns() { region.assign_advice( || "keccak table all-zero row", column, @@ -841,7 +855,7 @@ impl KeccakTable { } offset += 1; - let keccak_table_columns = self.columns(); + let keccak_table_columns = self.all_columns(); for input in inputs.clone() { for row in Self::assignments(input, challenges) { // let mut column_index = 0; @@ -863,6 +877,7 @@ impl KeccakTable { } impl DynamicTableColumns for KeccakTable { + // only used in evm circuit fn columns(&self) -> Vec> { vec![ self.is_enabled, From 33336c605b8ed0b3df1c17590484e2bc78e960f7 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Fri, 25 Nov 2022 10:55:44 +0800 Subject: [PATCH 15/15] clean codes --- .../src/keccak_circuit/keccak_packed_multi.rs | 175 ++++++------------ 1 file changed, 53 insertions(+), 122 deletions(-) diff --git a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs index 4f37087d5d..33bd378fef 100644 --- a/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs +++ b/zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs @@ -20,6 +20,7 @@ use halo2_proofs::{ poly::Rotation, }; use log::{debug, info}; +use std::env::var; use std::{marker::PhantomData, vec}; const MAX_DEGREE: usize = 4; @@ -29,13 +30,10 @@ const RHO_PI_LOOKUP_RANGE: usize = 4; const CHI_BASE_LOOKUP_RANGE: usize = 5; fn get_num_rows_per_round() -> usize { - //8 - 28 - /* - .unwrap_or_else(|_| "5".to_string()) + var("KECCAK_ROWS") + .unwrap_or_else(|_| "25".to_string()) .parse() .expect("Cannot parse KECCAK_ROWS env var as usize") - */ } fn get_num_bits_per_absorb_lookup() -> usize { @@ -344,7 +342,6 @@ pub struct KeccakPackedConfig { normalize_6: [TableColumn; 2], chi_base_table: [TableColumn; 2], pack_table: [TableColumn; 2], - //is_final: Column, _marker: PhantomData, } @@ -806,18 +803,10 @@ impl KeccakPackedConfig { let keccak_table = KeccakTable::construct(meta); let is_final = keccak_table.is_enabled; - //let is_final = meta.advice_column(); let length = keccak_table.input_len; let data_rlc = keccak_table.input_rlc; let hash_rlc = keccak_table.output_rlc; - /* - meta.create_gate("is_enabled in keccak table", |meta| { - - vec![meta.query_advice(is_final, Rotation::cur()) * meta.query_fixed(q_enable, Rotation::cur()) - - meta.query_advice(keccak_table.is_enabled, Rotation::cur())] - }); - */ let normalize_3 = array_init::array_init(|_| meta.lookup_table_column()); let normalize_4 = array_init::array_init(|_| meta.lookup_table_column()); let normalize_6 = array_init::array_init(|_| meta.lookup_table_column()); @@ -1344,36 +1333,29 @@ impl KeccakPackedConfig { cb.gate(meta.query_fixed(q_first, Rotation::cur())) }); + // some utility query functions let q = |col: Column, meta: &mut VirtualCells<'_, F>| { meta.query_fixed(col, Rotation::cur()) }; - let _q_first8 = |meta: &mut VirtualCells<'_, F>| { - (0..8_i32) - .map(|i| meta.query_fixed(q_enable, Rotation(-i))) - .fold(0.expr(), |acc, elem| acc + elem) - }; - let q_r = |col: Column, meta: &mut VirtualCells<'_, F>| { + let q_in_round = |col: Column, meta: &mut VirtualCells<'_, F>| { (0..get_num_rows_per_round() as i32) .map(|i| meta.query_fixed(col, Rotation(-i))) .fold(0.expr(), |acc, elem| acc + elem) }; - let _q_round_trailing = |col: Column, meta: &mut VirtualCells<'_, F>| { - (1..get_num_rows_per_round() as i32) - .map(|i| meta.query_fixed(col, Rotation(-i))) - .fold(0.expr(), |acc, elem| acc + elem) - }; - let _q_prev = |col: Column, meta: &mut VirtualCells<'_, F>| { - meta.query_fixed(col, Rotation::prev()) - }; - let q_prev_r = |col: Column, meta: &mut VirtualCells<'_, F>| { + let q_prev_round = |col: Column, meta: &mut VirtualCells<'_, F>| { meta.query_fixed(col, Rotation(-(get_num_rows_per_round() as i32))) }; /* - get_num_rows_per_round = 18 - input is "12345678abc" - be careful: is_paddings is not column here! It is [Cell; 8]. + eg: + data: + get_num_rows_per_round: 18 + input: "12345678abc" + + table: + Note[1]: be careful: is_paddings is not column here! It is [Cell; 8]. + offset value bytes_left is_paddings q_enable q_padding_last - 18 1 11 0 1 0 + 18 1 11 0 1 0 // 1st round begin 19 2 10 0 0 0 20 3 9 0 0 0 21 4 8 0 0 0 @@ -1384,7 +1366,7 @@ impl KeccakPackedConfig { 26 8 4 NA 0 0 ... 35 8 4 NA 0 0 // 1st round end - 36 a 3 0 1 1 // 2nd round start + 36 a 3 0 1 1 // 2nd round begin 37 b 2 0 0 0 38 c 1 0 0 0 39 0 0 1 0 0 @@ -1398,7 +1380,7 @@ impl KeccakPackedConfig { meta.create_gate("hash_id", |meta| { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - cb.condition(q_r(q_first, meta), |cb| { + cb.condition(q_in_round(q_first, meta), |cb| { cb.require_zero( "hash_id needs to be zero on the first row", meta.query_advice(keccak_table.hash_id, Rotation::cur()), @@ -1414,9 +1396,9 @@ impl KeccakPackedConfig { }, ); cb.condition( - q_r(q_enable, meta) - - q_r(q_first, meta) - - q(q_enable, meta) * q_prev_r(q_absorb, meta), + q_in_round(q_enable, meta) + - q_in_round(q_first, meta) + - q(q_enable, meta) * q_prev_round(q_absorb, meta), |cb| { let counter = meta.query_advice(keccak_table.hash_id, Rotation::cur()); let counter_prev = meta.query_advice(keccak_table.hash_id, Rotation::prev()); @@ -1433,7 +1415,6 @@ impl KeccakPackedConfig { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); for idx in 0..get_num_rows_per_round() { cb.condition( - //meta.query_fixed(q_padding, Rotation(-(idx as i32))), q(q_padding, meta) * not::expr(is_paddings[std::cmp::min(idx, 7)].expr()), |cb| { cb.require_equal( @@ -1449,61 +1430,39 @@ impl KeccakPackedConfig { meta.create_gate("bytes_left", |meta| { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); // TODO: is this needed? - cb.condition(q_r(q_first, meta), |cb| { + cb.condition(q_in_round(q_first, meta), |cb| { cb.require_zero( "bytes_left needs to be zero on the first row", meta.query_advice(keccak_table.bytes_left, Rotation::cur()), ); }); // is_paddings only be true when - cb.condition( - q(q_padding, meta), /* - q(q_padding_last, meta) */ - |cb| { - for i in 0..get_num_rows_per_round() { - let bytes_left = - meta.query_advice(keccak_table.bytes_left, Rotation(i as i32)); - let bytes_left_next = - meta.query_advice(keccak_table.bytes_left, Rotation(i as i32 + 1)); - // real input only when !is_paddings[i] && i < 8 - cb.require_equal( - "if not padding, bytes_left decreases by 1, else, stay same", - bytes_left_next, - bytes_left.clone() - - if i < 7 || i == get_num_rows_per_round() - 1 { - not::expr(is_paddings[std::cmp::min(i, 7)].expr()) - } else { - 0.expr() - }, - ); - cb.require_zero( - "bytes_left should be 0 when padding", - bytes_left * is_paddings[std::cmp::min(i, 7)].expr(), - ); - } - //cb.require_equal("bytes_left decreases by 1 for each - // row", bytes_left_next + 1.expr(), bytes_left); - // let counter_prev = - // meta.query_advice(keccak_table.hash_id, - // Rotation::prev()); - }, - ); - /* - cb.condition(q(q_padding_last, meta), |cb| { + cb.condition(q(q_padding, meta), |cb| { for i in 0..get_num_rows_per_round() { - - let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); - let bytes_left_next = meta.query_advice(keccak_table.bytes_left, Rotation::next()); - - cb.require_equal("bytes_left decreases by 1 when not padding", bytes_left_next, bytes_left.clone() - not::expr(is_paddings[i].expr())); - cb.require_zero("bytes_left should be 0 when padding", bytes_left * is_paddings[i].expr()); + let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation(i as i32)); + let bytes_left_next = + meta.query_advice(keccak_table.bytes_left, Rotation(i as i32 + 1)); + // real input only when !is_paddings[i] && i < 8 + cb.require_equal( + "if not padding, bytes_left decreases by 1, else, stay same", + bytes_left_next, + bytes_left.clone() + - if i < 7 || i == get_num_rows_per_round() - 1 { + not::expr(is_paddings[std::cmp::min(i, 7)].expr()) + } else { + 0.expr() + }, + ); + cb.require_zero( + "bytes_left should be 0 when padding", + bytes_left * is_paddings[std::cmp::min(i, 7)].expr(), + ); } }); - */ - // offset 1400 row KeccakRow { q_enable: true, q_enable_row: true, q_round: - // false, q_absorb: true, q_round_last: true, q_padding: false, q_padding_last: - // false, cb.condition( - (q_r(q_enable, meta) - q_r(q_padding, meta) - q_r(q_first, meta)) + (q_in_round(q_enable, meta) + - q_in_round(q_padding, meta) + - q_in_round(q_first, meta)) * meta.query_advice(is_final, Rotation::next()), |cb| { let bytes_left = meta.query_advice(keccak_table.bytes_left, Rotation::cur()); @@ -1651,14 +1610,6 @@ impl KeccakPackedConfig { cb.gate(1.expr()) }); - let _slot_selector = |meta: &mut VirtualCells<'_, F>, q_col| { - let mut exp = 0.expr(); - for i in 0..get_num_rows_per_round() { - exp = exp + meta.query_fixed(q_col, Rotation(i as i32)); - } - exp - }; - // Length and input data rlc meta.create_gate("length and data rlc", |meta| { let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); @@ -1765,7 +1716,6 @@ impl KeccakPackedConfig { normalize_6, chi_base_table, pack_table, - //is_final, _marker: PhantomData, } } @@ -1842,21 +1792,6 @@ impl KeccakPackedConfig { row.bytes_left, ], )?; - /* - for (column, value) in [ - (self.keccak_table.input_rlc, row.data_rlc), - (self.keccak_table.input_len, F::from(row.length as u64)), - (self.keccak_table.byte_value, row.value), - (self.keccak_table.bytes_left, row.bytes_left), - ] { - region.assign_advice( - || format!("assign {}", offset), - column, - offset, - || Value::known(value), - )?; - } - */ // Cell values for (idx, (bit, column)) in row @@ -1873,15 +1808,6 @@ impl KeccakPackedConfig { )?; } - /* - region.assign_advice( - || format!("assign is_final {}", offset), - self.is_final, - offset, - || Value::known(F::from(row.is_final) * F::from(row.q_enable)), - )?; - */ - // Round constant region.assign_fixed( || format!("assign round cst {}", offset), @@ -2261,22 +2187,27 @@ fn keccak(rows: &mut Vec>, bytes: &[u8], r: F) { is_final: is_final_block && round == NUM_ROUNDS && row_idx == 0, length: round_lengths[round], data_rlc: round_data_rlcs[round], - hash_rlc, // + F::from_u128(row_idx as u128), + hash_rlc, cell_values: regions[round].rows[row_idx].clone(), value: F::from_u128(byte as u128), // from len to 1 - bytes_left: F::from_u128(bytes_left as u128), // + 1? + bytes_left: F::from_u128(bytes_left as u128), hash_id, }); { let mut r = rows.last().unwrap().clone(); r.cell_values.clear(); - println!("offset {:?} row {:?}", rows.len() - 1, r); + log::trace!( + "offset {:?} row idx {} row {:?}", + rows.len() - 1, + row_idx, + r + ); } } - println!(" = = = = = = "); + log::trace!(" = = = = = = round {} end", round); } - println!(" ====================== "); + log::trace!(" ====================== chunk {} end", idx); } let hash_bytes = s