diff --git a/geth-utils/gethutil/mpt/witness/leaf.go b/geth-utils/gethutil/mpt/witness/leaf.go index 88cdb89980..84772c8fc8 100644 --- a/geth-utils/gethutil/mpt/witness/leaf.go +++ b/geth-utils/gethutil/mpt/witness/leaf.go @@ -580,12 +580,8 @@ func prepareStorageLeafNode(leafS, leafC, constructedLeaf, neighbourNode []byte, return node } -func equipLeafWithWrongExtension(leafNode Node, keyBefore, keyMiddle, keyAfter, nibblesMiddle, nibblesAfter []byte) Node { +func equipLeafWithWrongExtension(leafNode Node, keyMiddle, keyAfter, nibblesMiddle, nibblesAfter []byte) Node { l := len(leafNode.Values) - // The rows which are used for nibbles (it means there are checks for values being < 16) - // in the modified extension node cases are omitted. - leafNode.Values[l-modifiedExtensionNodeRowLen - 1] = keyBefore - leafNode.Values[l-modifiedExtensionNodeRowLen] = keyMiddle startNibblePos := 2 // we don't need any nibbles for case keyLen = 1 if len(keyMiddle) > 1 { diff --git a/geth-utils/gethutil/mpt/witness/prepare_witness.go b/geth-utils/gethutil/mpt/witness/prepare_witness.go index f3db30a932..0d7f9a7eb0 100644 --- a/geth-utils/gethutil/mpt/witness/prepare_witness.go +++ b/geth-utils/gethutil/mpt/witness/prepare_witness.go @@ -516,12 +516,6 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh [] start := keyIndex - len(nibbles) - nibblesBefore := newKey[0:start] - if len(nibblesBefore) % 2 == 1 { - nibblesBefore = append(nibblesBefore, 0) - } - keyBefore := trie.HexToKeybytes(nibblesBefore) - nibblesMiddle := newKey[start:keyIndex] keyMiddle := []byte{160} keyMiddle = append(keyMiddle, trie.HexToCompact(nibblesMiddle)...) @@ -545,7 +539,7 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh [] dummyLeaf := []byte{248,108,157,52,45,53,199,120,18,165,14,109,22,4,141,198,233,128,219,44,247,218,241,231,2,206,125,246,58,246,15,3,184,76,248,74,4,134,85,156,208,108,8,0,160,86,232,31,23,27,204,85,166,255,131,69,230,146,192,248,110,91,72,224,27,153,108,173,192,1,98,47,181,227,99,180,33,160,197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112} node := prepareAccountLeafNode(addr, addrh, dummyLeaf, dummyLeaf, dummyLeaf, nil, addr_nibbles, false, false, false) - node = equipLeafWithWrongExtension(node, keyBefore, keyMiddle, keyAfter, nibblesMiddle, nibblesAfter) + node = equipLeafWithWrongExtension(node, keyMiddle, keyAfter, nibblesMiddle, nibblesAfter) nodes = append(nodes, node) } else { diff --git a/zkevm-circuits/src/mpt_circuit/account_leaf.rs b/zkevm-circuits/src/mpt_circuit/account_leaf.rs index ebac85bd67..5f95565614 100644 --- a/zkevm-circuits/src/mpt_circuit/account_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/account_leaf.rs @@ -16,15 +16,15 @@ use crate::{ circuit_tools::{ cached_region::CachedRegion, cell_manager::Cell, - constraint_builder::{RLCChainable, RLCChainableRev, RLCable}, + constraint_builder::{RLCChainableRev, RLCable}, gadgets::IsEqualGadget, }, evm_circuit::util::from_bytes, mpt_circuit::{ helpers::{ - ext_key_rlc_expr, key_memory, leaf_key_rlc, main_memory, num_nibbles, parent_memory, DriftedGadget, Indexable, IsPlaceholderLeafGadget, KeyData, MPTConstraintBuilder, ParentData, WrongGadget, KECCAK + ext_key_rlc_expr, key_memory, main_memory, num_nibbles, parent_memory, DriftedGadget, Indexable, IsPlaceholderLeafGadget, KeyData, MPTConstraintBuilder, ParentData, WrongExtNodeGadget, WrongLeafGadget, KECCAK }, - param::{EMPTY_TRIE_HASH, KEY_LEN_IN_NIBBLES, KEY_PREFIX_ODD, RLP_LIST_LONG, RLP_LONG}, + param::{EMPTY_TRIE_HASH, KEY_LEN_IN_NIBBLES, RLP_LIST_LONG, RLP_LONG}, MPTConfig, MPTContext, MptMemory, RlpItemType, }, table::MPTProofType, @@ -43,7 +43,8 @@ pub(crate) struct AccountLeafConfig { value_list_rlp_bytes: [[Cell; 2]; 2], is_placeholder_leaf: [IsPlaceholderLeafGadget; 2], drifted: DriftedGadget, - wrong: WrongGadget, + wrong_leaf: WrongLeafGadget, + wrong_ext_node: WrongExtNodeGadget, is_non_existing_account_proof: IsEqualGadget, is_account_delete_mod: IsEqualGadget, is_nonce_mod: IsEqualGadget, @@ -367,7 +368,7 @@ impl AccountLeafConfig { ); // Wrong leaf handling - config.wrong = WrongGadget::construct( + config.wrong_leaf = WrongLeafGadget::construct( cb, key_item.hash_rlc(), config.is_non_existing_account_proof.expr(), @@ -377,11 +378,10 @@ impl AccountLeafConfig { config.is_placeholder_leaf[true.idx()].expr(), config.parent_data[true.idx()].is_extension.expr(), config.key_data[true.idx()].clone(), - config.key_data_prev.clone(), &cb.key_r.expr(), ); - // TODO: wrong extension node gadget + // Wrong extension node handling let wrong_ext_middle = ctx.rlp_item(meta, cb, AccountRowType::LongExtNodeKey as usize, RlpItemType::Key); let wrong_ext_middle_nibbles = @@ -391,63 +391,20 @@ impl AccountLeafConfig { let wrong_ext_after_nibbles = ctx.rlp_item(meta, cb, AccountRowType::ShortExtNodeNibbles as usize, RlpItemType::Nibbles); - // In the wrong extension node, AccountRowType::Wrong stores the bytes of the key nibbles - // up until the extension node. - let (mut rlc, _) = wrong_bytes.rlc_chain_data(); - // The nibbles stored in the Wrong row (up until the extension node) - // need to be the same as the nibbles in the path. - require!(rlc => config.key_data_prev.rlc.expr()); - - // We have a key split into three parts in - // the wrong extension node case, meaning that there the first part parity doesn't - // tell us about the parity of the second part (depends on the third part as well). - - let data0 = [wrong_ext_middle.clone(), wrong_ext_middle_nibbles.clone()]; - rlc = rlc - + ext_key_rlc_expr( - cb, - wrong_ext_middle, - config.key_data_prev.mult.expr(), - config.key_data[1].is_odd.expr(), - config.key_data_prev.is_odd.expr(), - data0 - .iter() - .map(|item| item.bytes_be()) - .collect::>() - .try_into() - .unwrap(), - &cb.key_r.expr(), - ); - - // odd odd -> even - // odd even -> odd - // even odd -> odd - // even even -> even - let after_two_parts_is_odd = - xor::expr(config.key_data_prev.is_odd.expr(), config.key_data[1].is_odd.expr()); - - // The total number of nibbles is odd, thus: - let third_part_is_odd = after_two_parts_is_odd.clone(); - - let data1 = [wrong_ext_after.clone(), wrong_ext_after_nibbles.clone()]; - rlc = rlc - + ext_key_rlc_expr( - cb, - wrong_ext_after, - config.key_data[1].mult.expr(), - third_part_is_odd, - after_two_parts_is_odd, - data1 - .iter() - .map(|item| item.bytes_be()) - .collect::>() - .try_into() - .unwrap(), - &cb.key_r.expr(), - ); - - require!(key_item.hash_rlc() => rlc); - + config.wrong_ext_node = WrongExtNodeGadget::construct( + cb, + key_item.hash_rlc(), + config.is_non_existing_account_proof.expr(), + &wrong_ext_middle, + &wrong_ext_middle_nibbles, + &wrong_ext_after, + &wrong_ext_after_nibbles, + config.parent_data[true.idx()].is_extension.expr(), + config.key_data[true.idx()].clone(), + config.key_data_prev.clone(), + &cb.key_r.expr(), + ); + // Anything following this node is below the account // TODO(Brecht): For non-existing accounts it should be impossible to prove // storage leaves unless it's also a non-existing proof? @@ -775,7 +732,7 @@ impl AccountLeafConfig { 2, // 2 instead of 1 because default values have already been stored above )?; } - self.wrong.assign( + self.wrong_leaf.assign( region, offset, is_non_existing_proof, diff --git a/zkevm-circuits/src/mpt_circuit/helpers.rs b/zkevm-circuits/src/mpt_circuit/helpers.rs index ce186b98ca..3eaac4cecf 100644 --- a/zkevm-circuits/src/mpt_circuit/helpers.rs +++ b/zkevm-circuits/src/mpt_circuit/helpers.rs @@ -1215,12 +1215,12 @@ impl DriftedGadget { /// Handles wrong leaves #[derive(Clone, Debug, Default)] -pub struct WrongGadget { +pub struct WrongLeafGadget { wrong_rlp_key: ListKeyGadget, is_key_equal: IsEqualGadget, } -impl WrongGadget { +impl WrongLeafGadget { #[allow(clippy::too_many_arguments)] pub(crate) fn construct( cb: &mut MPTConstraintBuilder, @@ -1232,54 +1232,164 @@ impl WrongGadget { is_placeholder: Expression, is_parent_extension: Expression, key_data: KeyData, - key_data_prev: KeyData, r: &Expression, ) -> Self { - let mut config = WrongGadget::default(); + let mut config = WrongLeafGadget::default(); circuit!([meta, cb.base], { - // Get the previous key data - ifx! {and::expr(&[is_non_existing, not!(is_placeholder)]) => { + ifx! {and::expr(&[is_non_existing, not!(is_placeholder), not!(is_parent_extension)]) => { config.wrong_rlp_key = ListKeyGadget::construct(cb, expected_item); - ifx! {not!(is_parent_extension) => { - let key_rlc_wrong = key_data.rlc.expr() + config.wrong_rlp_key.key.expr( - cb, - config.wrong_rlp_key.key_value.clone(), - key_data.mult.expr(), - key_data.is_odd.expr(), - r, - ); - // Check that it's the key as expected - require!(key_rlc_wrong => expected_key.clone()); - - // Now make sure this address is different than the one of the leaf - config.is_key_equal = IsEqualGadget::construct( - &mut cb.base, - key_rlc.expr(), - expected_key.clone(), - ); - require!(config.is_key_equal.expr() => false); - // Make sure the lengths of the keys are the same - require!(config.wrong_rlp_key.key_value.len() => key_value.len()); - } elsex { - let key_rlc_wrong = key_data_prev.rlc.expr() + config.wrong_rlp_key.key.expr( + let key_rlc_wrong = key_data.rlc.expr() + config.wrong_rlp_key.key.expr( + cb, + config.wrong_rlp_key.key_value.clone(), + key_data.mult.expr(), + key_data.is_odd.expr(), + r, + ); + // Check that it's the key as expected + require!(key_rlc_wrong => expected_key.clone()); + + // Now make sure this address is different than the one of the leaf + config.is_key_equal = IsEqualGadget::construct( + &mut cb.base, + key_rlc.expr(), + expected_key.clone(), + ); + require!(config.is_key_equal.expr() => false); + // Make sure the lengths of the keys are the same + require!(config.wrong_rlp_key.key_value.len() => key_value.len()); + }} + config + }) + } + + #[allow(clippy::too_many_arguments)] + pub(crate) fn assign( + &self, + region: &mut CachedRegion<'_, '_, F>, + offset: usize, + is_non_existing: bool, + key_rlc: &[F], + list_bytes: &[u8], + expected_item: &RLPItemWitness, + for_placeholder_s: bool, + is_parent_extension: bool, + key_data: KeyDataWitness, + key_data_prev: KeyDataWitness, + r: F, + ) -> Result<(F, F), Error> { + if is_non_existing { + let wrong_witness = + self.wrong_rlp_key + .assign(region, offset, list_bytes, expected_item)?; + let key_rlc_wrong: F; + if !is_parent_extension { + (key_rlc_wrong, _) = wrong_witness.key.key( + wrong_witness.key_item.clone(), + key_data.rlc, + key_data.mult, + r, + ); + } else { + (key_rlc_wrong, _) = wrong_witness.key.key( + wrong_witness.key_item.clone(), + key_data_prev.rlc, + key_data_prev.mult, + r, + ); + } + + let is_key_equal_witness = self.is_key_equal.assign( + region, + offset, + key_rlc[for_placeholder_s.idx()], + key_rlc_wrong, + )?; + + // When key is not equal, we have a non existing account + Ok((key_rlc_wrong, is_key_equal_witness.neg())) + } else { + // existing account + Ok((key_rlc[for_placeholder_s.idx()], false.scalar())) + } + } +} + +/// Handles wrong extension nodes +#[derive(Clone, Debug, Default)] +pub struct WrongExtNodeGadget { + wrong_rlp_key: ListKeyGadget, + is_key_equal: IsEqualGadget, +} + +impl WrongExtNodeGadget { + #[allow(clippy::too_many_arguments)] + pub(crate) fn construct( + cb: &mut MPTConstraintBuilder, + expected_key: Expression, + is_non_existing: Expression, + wrong_ext_middle: &RLPItemView, + wrong_ext_middle_nibbles: &RLPItemView, + wrong_ext_after: &RLPItemView, + wrong_ext_after_nibbles: &RLPItemView, + is_parent_extension: Expression, + key_data: KeyData, + key_data_prev: KeyData, + r: &Expression, + ) -> Self { + let mut config = WrongExtNodeGadget::default(); + circuit!([meta, cb.base], { + // TODO: distinguish between wrong extension node / wrong leaf / nil leaf + ifx! {and::expr(&[is_non_existing, is_parent_extension]) => { + // We have a key split into three parts, + // meaning that there the first part parity doesn't + // tell us about the parity of the second part (depends on the third part as well). + + let data0 = [wrong_ext_middle.clone(), wrong_ext_middle_nibbles.clone()]; + let mut rlc = key_data_prev.rlc.expr() + + ext_key_rlc_expr( cb, - config.wrong_rlp_key.key_value.clone(), + wrong_ext_middle.clone(), key_data_prev.mult.expr(), + key_data.is_odd.expr(), key_data_prev.is_odd.expr(), - r, + data0 + .iter() + .map(|item| item.bytes_be()) + .collect::>() + .try_into() + .unwrap(), + &cb.key_r.expr(), ); - // Check that it's the key as expected - require!(key_rlc_wrong => expected_key.clone()); - // We don't need to check `is_key_equal = false` because we have the extension node - // above, not the leaf - the two nodes are different without checking the key. + // odd odd -> even + // odd even -> odd + // even odd -> odd + // even even -> even + let after_two_parts_is_odd = + xor::expr(key_data_prev.is_odd.expr(), key_data.is_odd.expr()); - // We don't need to check that the lengths of the keys are the same because - // they are actually different in this case - one leaf is in the extension node's - // branch (and its path is longer due to extension nibbles), one ("wrong", but with - // the correct address/key) is not in the extension node's branch. - }} + // The total number of nibbles is odd, thus: + let third_part_is_odd = after_two_parts_is_odd.clone(); + + let data1 = [wrong_ext_after.clone(), wrong_ext_after_nibbles.clone()]; + rlc = rlc + + ext_key_rlc_expr( + cb, + wrong_ext_after.clone(), + key_data.mult.expr(), + third_part_is_odd, + after_two_parts_is_odd, + data1 + .iter() + .map(|item| item.bytes_be()) + .collect::>() + .try_into() + .unwrap(), + &cb.key_r.expr(), + ); + + require!(rlc => expected_key); }} config }) diff --git a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs index f7656588f5..c48c2192e3 100644 --- a/zkevm-circuits/src/mpt_circuit/storage_leaf.rs +++ b/zkevm-circuits/src/mpt_circuit/storage_leaf.rs @@ -29,7 +29,7 @@ use crate::{ }; use super::{ - helpers::{Indexable, KeyDataWitness, ListKeyGadget, WrongGadget}, + helpers::{Indexable, KeyDataWitness, ListKeyGadget, WrongLeafGadget}, mod_extension::ModExtensionGadget, rlp_gadgets::{RLPItemWitness, RLPValueGadget}, witness_row::{Node, StorageRowType}, @@ -48,7 +48,7 @@ pub(crate) struct StorageLeafConfig { is_not_hashed: [LtGadget; 2], is_placeholder_leaf: [IsPlaceholderLeafGadget; 2], drifted: DriftedGadget, - wrong: WrongGadget, + wrong: WrongLeafGadget, is_storage_mod_proof: IsEqualGadget, is_non_existing_storage_proof: IsEqualGadget, is_mod_extension: [Cell; 2], @@ -287,7 +287,7 @@ impl StorageLeafConfig { ); // Wrong leaf / extension node handling - config.wrong = WrongGadget::construct( + config.wrong = WrongLeafGadget::construct( cb, key_item.hash_rlc(), config.is_non_existing_storage_proof.expr(), @@ -297,7 +297,6 @@ impl StorageLeafConfig { config.is_placeholder_leaf[true.idx()].expr(), config.parent_data[true.idx()].is_extension.expr(), config.key_data[true.idx()].clone(), - config.key_data_prev.clone(), &cb.key_r.expr(), );