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

Commit

Permalink
WrongExtNodeGadget introduced
Browse files Browse the repository at this point in the history
  • Loading branch information
miha-stopar committed Mar 29, 2024
1 parent 8fccf9c commit 46627dd
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 120 deletions.
6 changes: 1 addition & 5 deletions geth-utils/gethutil/mpt/witness/leaf.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
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 @@ -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)...)
Expand All @@ -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 {
Expand Down
87 changes: 22 additions & 65 deletions zkevm-circuits/src/mpt_circuit/account_leaf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -43,7 +43,8 @@ pub(crate) struct AccountLeafConfig<F> {
value_list_rlp_bytes: [[Cell<F>; 2]; 2],
is_placeholder_leaf: [IsPlaceholderLeafGadget<F>; 2],
drifted: DriftedGadget<F>,
wrong: WrongGadget<F>,
wrong_leaf: WrongLeafGadget<F>,
wrong_ext_node: WrongExtNodeGadget<F>,
is_non_existing_account_proof: IsEqualGadget<F>,
is_account_delete_mod: IsEqualGadget<F>,
is_nonce_mod: IsEqualGadget<F>,
Expand Down Expand Up @@ -367,7 +368,7 @@ impl<F: Field> AccountLeafConfig<F> {
);

// Wrong leaf handling
config.wrong = WrongGadget::construct(
config.wrong_leaf = WrongLeafGadget::construct(
cb,
key_item.hash_rlc(),
config.is_non_existing_account_proof.expr(),
Expand All @@ -377,11 +378,10 @@ impl<F: Field> AccountLeafConfig<F> {
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 =
Expand All @@ -391,63 +391,20 @@ impl<F: Field> AccountLeafConfig<F> {
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::<Vec<_>>()
.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::<Vec<_>>()
.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?
Expand Down Expand Up @@ -775,7 +732,7 @@ impl<F: Field> AccountLeafConfig<F> {
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,
Expand Down
188 changes: 149 additions & 39 deletions zkevm-circuits/src/mpt_circuit/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1215,12 +1215,12 @@ impl<F: Field> DriftedGadget<F> {

/// Handles wrong leaves
#[derive(Clone, Debug, Default)]
pub struct WrongGadget<F> {
pub struct WrongLeafGadget<F> {
wrong_rlp_key: ListKeyGadget<F>,
is_key_equal: IsEqualGadget<F>,
}

impl<F: Field> WrongGadget<F> {
impl<F: Field> WrongLeafGadget<F> {
#[allow(clippy::too_many_arguments)]
pub(crate) fn construct(
cb: &mut MPTConstraintBuilder<F>,
Expand All @@ -1232,54 +1232,164 @@ impl<F: Field> WrongGadget<F> {
is_placeholder: Expression<F>,
is_parent_extension: Expression<F>,
key_data: KeyData<F>,
key_data_prev: KeyData<F>,
r: &Expression<F>,
) -> 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<F>,
key_data_prev: KeyDataWitness<F>,
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<F> {
wrong_rlp_key: ListKeyGadget<F>,
is_key_equal: IsEqualGadget<F>,
}

impl<F: Field> WrongExtNodeGadget<F> {
#[allow(clippy::too_many_arguments)]
pub(crate) fn construct(
cb: &mut MPTConstraintBuilder<F>,
expected_key: Expression<F>,
is_non_existing: Expression<F>,
wrong_ext_middle: &RLPItemView<F>,
wrong_ext_middle_nibbles: &RLPItemView<F>,
wrong_ext_after: &RLPItemView<F>,
wrong_ext_after_nibbles: &RLPItemView<F>,
is_parent_extension: Expression<F>,
key_data: KeyData<F>,
key_data_prev: KeyData<F>,
r: &Expression<F>,
) -> 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::<Vec<_>>()
.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::<Vec<_>>()
.try_into()
.unwrap(),
&cb.key_r.expr(),
);

require!(rlc => expected_key);
}}
config
})
Expand Down
Loading

0 comments on commit 46627dd

Please sign in to comment.