Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
Wrong extension node: selector constraints; wrong extension node gadg…
Browse files Browse the repository at this point in the history
…et added to storage leaf
  • Loading branch information
miha-stopar committed Apr 10, 2024
1 parent 133d8b2 commit 89c3bbb
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 53 deletions.
8 changes: 1 addition & 7 deletions geth-utils/gethutil/mpt/witness/prepare_witness.go
Original file line number Diff line number Diff line change
Expand Up @@ -533,29 +533,23 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh []
key[keyIndex], key[keyIndex], false, false, isExtension, true)
nodes = append(nodes, bNode)

// Let's construct the leaf L1 that will have the correct key (the queried one)
if isAccountProof {
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, keyMiddle, keyAfter, nibblesMiddle, nibblesAfter)

nodes = append(nodes, node)
} else {

// The remaining `key` nibbles are to be stored in the constructed leaf - in our example [1 2 4 ...]
compact := trie.HexToCompact(key[start:])
// Add RLP:
compactLen := byte(len(compact))
rlp2 := 128 + compactLen
rlp1 := 192 + compactLen + 1
// Constructed leaf L1:
dummyLeaf := append([]byte{rlp1, rlp2}, compact...)

// Add dummy value:
dummyLeaf = append(dummyLeaf, 0)

node := prepareStorageLeafNode(dummyLeaf, dummyLeaf, dummyLeaf, nil, storage_key, key, nonExistingStorageProof, false, false, false, false)
node = equipLeafWithWrongExtension(node, keyMiddle, keyAfter, nibblesMiddle, nibblesAfter)
nodes = append(nodes, node)
}
}
Expand Down
3 changes: 1 addition & 2 deletions zkevm-circuits/src/mpt_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ impl<F: Field> MPTConfig<F> {

let mut state_cm = CellManager::new(50, 0);
state_cm.add_columns(meta, &mut cb.base, MptCellType::StoragePhase1, 0, false, 20);
state_cm.add_columns(meta, &mut cb.base, MptCellType::StoragePhase2, 1, false, 7);
state_cm.add_columns(meta, &mut cb.base, MptCellType::StoragePhase2, 1, false, 8);
state_cm.add_columns(meta, &mut cb.base, MptCellType::StoragePhase3, 2, false, 5);
state_cm.add_columns(meta, &mut cb.base, lu(MptTableType::Byte), 0, false, 4);
state_cm.add_columns(meta, &mut cb.base, lu(MptTableType::Fixed), 2, false, 3);
Expand Down Expand Up @@ -771,7 +771,6 @@ mod tests {
#[test]
fn test_mpt() {
let path = "src/mpt_circuit/tests";

let files = fs::read_dir(path).unwrap();
files
.filter_map(Result::ok)
Expand Down
45 changes: 21 additions & 24 deletions zkevm-circuits/src/mpt_circuit/account_leaf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ impl<F: Field> AccountLeafConfig<F> {
// the leaf too - in this case `parent_data.hash` contains the hash of the node above the placeholder
// branch.
ifx! {not!(or::expr(&[config.is_placeholder_leaf[is_s.idx()].expr(), is_wrong_ext_case.clone()])) => {
// ifx! {not!(config.is_placeholder_leaf[is_s.idx()]) => {
let hash = parent_data[is_s.idx()].hash.expr();
require!((1.expr(), leaf_rlc, rlp_key.rlp_list.num_bytes(), hash.lo(), hash.hi()) =>> @KECCAK);
} elsex {
Expand Down Expand Up @@ -374,18 +373,30 @@ impl<F: Field> AccountLeafConfig<F> {
&config.is_mod_extension,
&cb.key_r.expr(),
);

let is_wrong_leaf_case = and::expr(&[config.is_non_existing_account_proof.expr(), not!(config.parent_data[1].is_extension), not!(config.is_placeholder_leaf[1].expr())]);

// When non-existing-proof, it needs to be one of the following cases:
// (1) wrong leaf, (2) wrong extension node, (3) nil leaf - we need to check the sum of these
// three cases is 1.
ifx! {config.is_non_existing_account_proof => {
require!(is_wrong_ext_case.clone() + is_wrong_leaf_case.clone() + config.is_placeholder_leaf[1].expr() => 1.expr());
}}

// When is_last_level_and_wrong_ext_case, the proof type needs to be non-existing
ifx! {is_wrong_ext_case => {
require!(config.is_non_existing_account_proof.expr() => 1.expr());
}}

// Wrong leaf handling
config.wrong_leaf = WrongLeafGadget::construct(
cb,
key_item.hash_rlc(),
config.is_non_existing_account_proof.expr(),
&config.rlp_key[true.idx()].key_value,
&key_rlc[true.idx()],
is_wrong_leaf_case,
&config.rlp_key[1].key_value, // C proof is used for non-existing proof
&key_rlc[1],
&wrong_bytes,
config.is_placeholder_leaf[true.idx()].expr(),
config.parent_data[true.idx()].is_extension.expr(),
config.key_data[true.idx()].clone(),
config.key_data[1].clone(),
&cb.key_r.expr(),
);

Expand All @@ -403,20 +414,6 @@ impl<F: Field> AccountLeafConfig<F> {
// in the case of wrong extension node.
// All other extension_branches (above it) need to have it `false` (constraint in
// extension_branch.rs)
// TODO: Use is_last_level_and_wrong_ext_case as a flag for one of the three cases
// require!(config.parent_data[1].is_last_level_and_wrong_ext_case.expr() => true.expr());
// TODO: use C proof everywhere for non-existing proof.

// TODO: when non-existing-proof, it needs to be one of the following cases:
// wrong leaf, wrong extension node, nil leaf - we need to check the sum of these
// three cases is 1.
// To check whether it's the wrong leaf case - parent is not extension, leaf is not placeholder
// To check whether it's wrong extension node - is_last_level_and_wrong_ext_case = 1, parent is extension
// To check whether it's the nil leaf - use IsPlaceholderLeafGadget

// TODO: when is_last_level_and_wrong_ext_case, the proof type needs to be non-existing
// config.is_non_existing_account_proof.expr(),
// config.parent_data[true.idx()].is_extension.expr(),

config.wrong_ext_node = WrongExtNodeGadget::construct(
cb,
Expand All @@ -426,7 +423,7 @@ impl<F: Field> AccountLeafConfig<F> {
&wrong_ext_middle_nibbles,
&wrong_ext_after,
&wrong_ext_after_nibbles,
config.key_data[true.idx()].clone(),
config.key_data[1].clone(), // C proof is used for non-existing proof
config.key_data_prev.clone(),
);

Expand Down Expand Up @@ -766,7 +763,7 @@ impl<F: Field> AccountLeafConfig<F> {
&account.wrong_rlp_bytes,
&expected_item,
true,
key_data[true.idx()].clone(),
key_data[1].clone(),
region.key_r,
)?;

Expand All @@ -777,7 +774,7 @@ impl<F: Field> AccountLeafConfig<F> {
offset,
wrong_ext_middle,
wrong_ext_middle_nibbles,
key_data[true.idx()].clone(),
key_data[1].clone(),
key_data_prev.clone(),
);

Expand Down
8 changes: 3 additions & 5 deletions zkevm-circuits/src/mpt_circuit/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1241,18 +1241,16 @@ impl<F: Field> WrongLeafGadget<F> {
pub(crate) fn construct(
cb: &mut MPTConstraintBuilder<F>,
expected_key: Expression<F>,
is_non_existing: Expression<F>,
is_wrong_leaf_case: Expression<F>,
key_value: &RLPItemView<F>,
key_rlc: &Expression<F>,
expected_item: &RLPItemView<F>,
is_placeholder: Expression<F>,
is_parent_extension: Expression<F>,
key_data: KeyData<F>,
r: &Expression<F>,
) -> Self {
let mut config = WrongLeafGadget::default();
circuit!([meta, cb.base], {
ifx! {and::expr(&[is_non_existing, not!(is_placeholder), not!(is_parent_extension)]) => {
ifx! {is_wrong_leaf_case => {
config.wrong_rlp_key = ListKeyGadget::construct(cb, expected_item);

let key_rlc_wrong = key_data.rlc.expr() + config.wrong_rlp_key.key.expr(
Expand Down Expand Up @@ -1341,7 +1339,7 @@ impl<F: Field> WrongExtNodeGadget<F> {
circuit!([meta, cb.base], {
ifx! {is_wrong_ext_case => {
// We have a key split into three parts,
// meaning that there the first part parity doesn't
// meaning that 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()];
Expand Down
87 changes: 72 additions & 15 deletions zkevm-circuits/src/mpt_circuit/storage_leaf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ use crate::{
},
mpt_circuit::{
helpers::{
key_memory, main_memory, num_nibbles, parent_memory, DriftedGadget,
IsPlaceholderLeafGadget, KeyData, MPTConstraintBuilder, MainData, ParentData,
ParentDataWitness, KECCAK,
key_memory, main_memory, num_nibbles, parent_memory, DriftedGadget, IsPlaceholderLeafGadget, KeyData, MPTConstraintBuilder, MainData, ParentData, ParentDataWitness, WrongExtNodeGadget, KECCAK
},
param::{EMPTY_TRIE_HASH, KEY_LEN_IN_NIBBLES},
MPTConfig, MPTContext, MptMemory, RlpItemType,
Expand Down Expand Up @@ -49,6 +47,7 @@ pub(crate) struct StorageLeafConfig<F> {
is_placeholder_leaf: [IsPlaceholderLeafGadget<F>; 2],
drifted: DriftedGadget<F>,
wrong_leaf: WrongLeafGadget<F>,
wrong_ext_node: WrongExtNodeGadget<F>,
is_storage_mod_proof: IsEqualGadget<F>,
is_non_existing_storage_proof: IsEqualGadget<F>,
is_mod_extension: [Cell<F>; 2],
Expand Down Expand Up @@ -131,6 +130,8 @@ impl<F: Field> StorageLeafConfig<F> {
MPTProofType::StorageDoesNotExist.expr(),
);

let is_wrong_ext_case = parent_data[1].is_last_level_and_wrong_ext_case.expr();

for is_s in [true, false] {
ifx! {not!(config.is_mod_extension[is_s.idx()].expr()) => {
// Placeholder leaf checks
Expand Down Expand Up @@ -190,7 +191,9 @@ impl<F: Field> StorageLeafConfig<F> {
// Total number of nibbles needs to be KEY_LEN_IN_NIBBLES
let num_nibbles =
num_nibbles::expr(rlp_key.key_value.len(), key_data[is_s.idx()].is_odd.expr());
require!(key_data[is_s.idx()].num_nibbles.expr() + num_nibbles => KEY_LEN_IN_NIBBLES);
ifx! {not!(is_wrong_ext_case) => {
require!(key_data[is_s.idx()].num_nibbles.expr() + num_nibbles => KEY_LEN_IN_NIBBLES);
}}

// Placeholder leaves default to value `0`.
ifx! {is_placeholder_leaf => {
Expand All @@ -199,14 +202,16 @@ impl<F: Field> StorageLeafConfig<F> {

// Make sure the RLP encoding is correct.
// storage = [key, "value"]
require!(rlp_key.rlp_list.len() => key_items[is_s.idx()].num_bytes() + config.rlp_value[is_s.idx()].num_bytes());
ifx! {not!(is_wrong_ext_case) => {
require!(rlp_key.rlp_list.len() => key_items[is_s.idx()].num_bytes() + config.rlp_value[is_s.idx()].num_bytes());
}}

// Check if the leaf is in its parent.
// Check is skipped for placeholder leaves which are dummy leaves.
// Note that the constraint works for the case when there is the placeholder branch above
// the leaf too - in this case `parent_data.hash` contains the hash of the node above the placeholder
// branch.
ifx! {not!(is_placeholder_leaf) => {
ifx! {not!(or::expr(&[config.is_placeholder_leaf[is_s.idx()].expr(), is_wrong_ext_case.clone()])) => {
config.is_not_hashed[is_s.idx()] = LtGadget::construct(&mut cb.base, rlp_key.rlp_list.num_bytes(), 32.expr());
ifx!{or::expr(&[parent_data[is_s.idx()].is_root.expr(), not!(config.is_not_hashed[is_s.idx()])]) => {
// Hashed leaf in parent branch
Expand Down Expand Up @@ -236,7 +241,9 @@ impl<F: Field> StorageLeafConfig<F> {
// Note that this does not hold when there is NonExistingStorageProof wrong leaf scenario,
// in this case there is a non-nil leaf. However, in this case the leaf is not a placeholder,
// so the check below is not triggered.
require!(parent_data[is_s.idx()].rlc.expr() => 128.expr());
ifx! {not!(is_wrong_ext_case) => {
require!(parent_data[is_s.idx()].rlc.expr() => 128.expr());
}}
}}

}}
Expand Down Expand Up @@ -287,20 +294,59 @@ impl<F: Field> StorageLeafConfig<F> {
&cb.key_r.expr(),
);

// Wrong leaf / extension node handling
let is_wrong_leaf_case = and::expr(&[config.is_non_existing_storage_proof.expr(), not!(config.parent_data[1].is_extension), not!(config.is_placeholder_leaf[1].expr())]);

// When non-existing-proof, it needs to be one of the following cases:
// (1) wrong leaf, (2) wrong extension node, (3) nil leaf - we need to check the sum of these
// three cases is 1.
ifx! {config.is_non_existing_storage_proof => {
require!(is_wrong_ext_case.clone() + is_wrong_leaf_case.clone() + config.is_placeholder_leaf[1].expr() => 1.expr());
}}

// When is_last_level_and_wrong_ext_case, the proof type needs to be non-existing
ifx! {is_wrong_ext_case => {
require!(config.is_non_existing_storage_proof.expr() => 1.expr());
}}

// Wrong leaf handling
config.wrong_leaf = WrongLeafGadget::construct(
cb,
key_item.hash_rlc(),
config.is_non_existing_storage_proof.expr(),
&config.rlp_key[true.idx()].key_value,
&key_rlc[true.idx()],
is_wrong_leaf_case,
&config.rlp_key[1].key_value, // C proof is used for non-existing proof
&key_rlc[1],
&expected_item,
config.is_placeholder_leaf[true.idx()].expr(),
config.parent_data[true.idx()].is_extension.expr(),
config.key_data[true.idx()].clone(),
config.key_data[1].clone(),
&cb.key_r.expr(),
);

// Wrong extension node handling
let wrong_ext_middle =
ctx.rlp_item(meta, cb, StorageRowType::LongExtNodeKey as usize, RlpItemType::Key);
let wrong_ext_middle_nibbles =
ctx.rlp_item(meta, cb, StorageRowType::LongExtNodeNibbles as usize, RlpItemType::Nibbles);
let wrong_ext_after =
ctx.rlp_item(meta, cb, StorageRowType::ShortExtNodeKey as usize, RlpItemType::Key);
let wrong_ext_after_nibbles =
ctx.rlp_item(meta, cb, StorageRowType::ShortExtNodeNibbles as usize, RlpItemType::Nibbles);

// The extension_branch in the last level needs has `is_last_level_and_wrong_ext_case = true`
// in the case of wrong extension node.
// All other extension_branches (above it) need to have it `false` (constraint in
// extension_branch.rs)

config.wrong_ext_node = WrongExtNodeGadget::construct(
cb,
key_item.hash_rlc(),
is_wrong_ext_case,
&wrong_ext_middle,
&wrong_ext_middle_nibbles,
&wrong_ext_after,
&wrong_ext_after_nibbles,
config.key_data[1].clone(), // C proof should be used everywhere for non-existing proof
config.key_data_prev.clone(),
);

// Reset the main memory
// This need to be the last node for this proof
MainData::store(
Expand Down Expand Up @@ -573,10 +619,21 @@ impl<F: Field> StorageLeafConfig<F> {
&storage.wrong_rlp_bytes,
&expected_item,
false,
key_data[true.idx()].clone(),
key_data[1].clone(),
region.key_r,
)?;

let wrong_ext_middle = rlp_values[StorageRowType::LongExtNodeKey as usize].clone();
let wrong_ext_middle_nibbles = rlp_values[StorageRowType::LongExtNodeNibbles as usize].clone();
self.wrong_ext_node.assign(
region,
offset,
wrong_ext_middle,
wrong_ext_middle_nibbles,
key_data[1].clone(),
key_data_prev.clone(),
);

// Reset the main memory
MainData::witness_store(
region,
Expand Down

0 comments on commit 89c3bbb

Please sign in to comment.