Skip to content

Commit 377ed98

Browse files
committed
feat: add tests from github.com/jsign/verkle-test-vectors
1 parent 3178b63 commit 377ed98

File tree

10 files changed

+417
-92
lines changed

10 files changed

+417
-92
lines changed

verkle/src/account.rs

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use alloy_primitives::{Address, B128, B256, U256};
2+
use banderwagon::Fr;
3+
4+
use crate::{
5+
committer::DEFAULT_COMMITER,
6+
constants::{
7+
BALANCE_LEAF_KEY, CODE_KECCAK_LEAF_KEY, CODE_OFFSET, CODE_SIZE_LEAF_KEY,
8+
HEADER_STORAGE_OFFSET, MAIN_STORAGE_OFFSET, NONCE_LEAF_KEY, VERKLE_NODE_WIDTH_U256,
9+
VERSION_LEAF_KEY,
10+
},
11+
stem::Stem,
12+
utils::fr_to_b256,
13+
TrieKey, TrieValue,
14+
};
15+
16+
pub struct AccountStorageLayout {
17+
pub address: Address,
18+
base_storage_stem: Stem,
19+
}
20+
21+
impl AccountStorageLayout {
22+
pub fn new(address: Address) -> Self {
23+
Self {
24+
address,
25+
base_storage_stem: tree_key(address, U256::ZERO, 0).into(),
26+
}
27+
}
28+
29+
pub fn version_key(&self) -> TrieKey {
30+
TrieKey::from_stem_and_last_byte(&self.base_storage_stem, VERSION_LEAF_KEY)
31+
}
32+
33+
pub fn balance_key(&self) -> TrieKey {
34+
TrieKey::from_stem_and_last_byte(&self.base_storage_stem, BALANCE_LEAF_KEY)
35+
}
36+
37+
pub fn nonce_key(&self) -> TrieKey {
38+
TrieKey::from_stem_and_last_byte(&self.base_storage_stem, NONCE_LEAF_KEY)
39+
}
40+
41+
pub fn code_hash_key(&self) -> TrieKey {
42+
TrieKey::from_stem_and_last_byte(&self.base_storage_stem, CODE_KECCAK_LEAF_KEY)
43+
}
44+
45+
pub fn code_size_key(&self) -> TrieKey {
46+
TrieKey::from_stem_and_last_byte(&self.base_storage_stem, CODE_SIZE_LEAF_KEY)
47+
}
48+
49+
pub fn storage_slot_key(&self, storage_key: U256) -> TrieKey {
50+
let pos = if storage_key < CODE_OFFSET - HEADER_STORAGE_OFFSET {
51+
HEADER_STORAGE_OFFSET + storage_key
52+
} else {
53+
MAIN_STORAGE_OFFSET + storage_key
54+
};
55+
tree_key(
56+
self.address,
57+
pos / VERKLE_NODE_WIDTH_U256,
58+
(pos % VERKLE_NODE_WIDTH_U256).byte(0),
59+
)
60+
}
61+
62+
pub fn code_key(&self, chunk_id: usize) -> TrieKey {
63+
let pos = CODE_OFFSET + U256::from(chunk_id);
64+
tree_key(
65+
self.address,
66+
pos / VERKLE_NODE_WIDTH_U256,
67+
(pos % VERKLE_NODE_WIDTH_U256).byte(0),
68+
)
69+
}
70+
71+
pub fn chunkify_code(&self, code: &[u8]) -> Vec<(TrieKey, TrieValue)> {
72+
const PUSH_OFFSET: u8 = 95;
73+
const PUSH1: u8 = PUSH_OFFSET + 1;
74+
const PUSH32: u8 = PUSH_OFFSET + 32;
75+
76+
let mut remaining_push_data = 0u8;
77+
let mut result = vec![];
78+
for (chunk_id, chunk) in code.chunks(31).enumerate() {
79+
let mut value = Vec::with_capacity(32);
80+
value.push(remaining_push_data.min(31));
81+
value.extend(chunk);
82+
value.resize(32, 0);
83+
result.push((self.code_key(chunk_id), TrieValue::from_le_slice(&value)));
84+
85+
for chunk_byte in chunk {
86+
if remaining_push_data > 0 {
87+
remaining_push_data -= 1;
88+
} else if (PUSH1..=PUSH32).contains(chunk_byte) {
89+
remaining_push_data = chunk_byte - PUSH_OFFSET;
90+
}
91+
}
92+
}
93+
result
94+
}
95+
}
96+
97+
fn tree_key(address: Address, tree_index: U256, sub_index: u8) -> TrieKey {
98+
let address_bytes = *B256::left_padding_from(address.as_slice());
99+
let tree_index_bytes = tree_index.to_le_bytes::<32>();
100+
101+
let scalars = [
102+
2u128 + 256 * 64,
103+
u128::from_le_bytes(B128::from_slice(&address_bytes[..16]).0),
104+
u128::from_le_bytes(B128::from_slice(&address_bytes[16..]).0),
105+
u128::from_le_bytes(B128::from_slice(&tree_index_bytes[..16]).0),
106+
u128::from_le_bytes(B128::from_slice(&tree_index_bytes[16..]).0),
107+
]
108+
.map(Fr::from);
109+
let commitment = DEFAULT_COMMITER.commit_lagrange(&scalars);
110+
let hash_commitment = commitment.map_to_scalar_field();
111+
112+
let mut key = fr_to_b256(&hash_commitment);
113+
key[31] = sub_index;
114+
key.into()
115+
}

verkle/src/constants.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1 +1,14 @@
1+
use alloy_primitives::U256;
2+
13
pub const VERKLE_NODE_WIDTH: usize = 256;
4+
pub const VERKLE_NODE_WIDTH_U256: U256 = U256::from_limbs([256, 0, 0, 0]);
5+
6+
// Storage layout parameters
7+
pub const VERSION_LEAF_KEY: u8 = 0;
8+
pub const BALANCE_LEAF_KEY: u8 = 1;
9+
pub const NONCE_LEAF_KEY: u8 = 2;
10+
pub const CODE_KECCAK_LEAF_KEY: u8 = 3;
11+
pub const CODE_SIZE_LEAF_KEY: u8 = 4;
12+
pub const HEADER_STORAGE_OFFSET: U256 = U256::from_limbs([64, 0, 0, 0]);
13+
pub const CODE_OFFSET: U256 = U256::from_limbs([128, 0, 0, 0]);
14+
pub const MAIN_STORAGE_OFFSET: U256 = U256::from_limbs([0, 0, 0, 2u64.pow(56)]);

verkle/src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ use alloy_primitives::{B256, U256};
22
use derive_more::{Constructor, Deref, From, Index};
33

44
use banderwagon::Fr;
5+
use stem::Stem;
56
pub use trie::Trie;
67

8+
pub mod account;
79
mod committer;
810
mod constants;
911
pub mod crs;
@@ -20,6 +22,12 @@ type Db = dyn db::Db<Fr, Vec<u8>>;
2022
pub struct TrieKey(B256);
2123

2224
impl TrieKey {
25+
pub fn from_stem_and_last_byte(stem: &Stem, last_byte: u8) -> Self {
26+
let mut key = B256::right_padding_from(stem.as_slice());
27+
key[B256::len_bytes() - 1] = last_byte;
28+
key.into()
29+
}
30+
2331
pub fn length() -> usize {
2432
B256::len_bytes()
2533
}

verkle/src/nodes/branch.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ impl Default for BranchNode {
6464
}
6565

6666
impl NodeTrait for BranchNode {
67-
fn commitment(&self) -> Fr {
67+
fn hash_commitment(&self) -> Fr {
6868
self.cp.map_to_scalar_field()
6969
}
7070
}
@@ -83,7 +83,7 @@ impl Encode for BranchNode {
8383
if node.is_empty() {
8484
None
8585
} else {
86-
Some((index as u8, fr_to_b256(&node.commitment())))
86+
Some((index as u8, fr_to_b256(&node.hash_commitment())))
8787
}
8888
})
8989
.collect();

verkle/src/nodes/leaf.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,12 @@ impl LeafNode {
6363
&self.stem
6464
}
6565

66-
fn calculate_commitment(&self) -> Fr {
67-
let c = self.const_cp
66+
fn calculate_commitment(&self) -> Element {
67+
self.const_cp
6868
+ DEFAULT_COMMITER.commit_sparse(vec![
6969
(2, self.cp1.map_to_scalar_field()),
7070
(3, self.cp2.map_to_scalar_field()),
71-
]);
72-
c.map_to_scalar_field()
71+
])
7372
}
7473

7574
pub fn get(&self, index: u8) -> Option<&TrieValue> {
@@ -119,12 +118,13 @@ impl LeafNode {
119118
}
120119

121120
impl NodeTrait for LeafNode {
122-
fn commitment(&self) -> Fr {
123-
self.c.unwrap_or_else(|| self.calculate_commitment())
121+
fn hash_commitment(&self) -> Fr {
122+
self.c
123+
.unwrap_or_else(|| self.calculate_commitment().map_to_scalar_field())
124124
}
125125

126126
fn commit(&mut self) -> Fr {
127-
self.c = self.c.or_else(|| Some(self.calculate_commitment()));
127+
self.c = Some(self.hash_commitment());
128128
self.c.expect("Value must be present")
129129
}
130130
}

verkle/src/nodes/node.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ use crate::{Db, TrieKey, TrieValue};
1010
use super::{BranchNode, LeafNode};
1111

1212
pub trait NodeTrait {
13-
fn commitment(&self) -> Fr;
13+
fn hash_commitment(&self) -> Fr;
1414

1515
fn commit(&mut self) -> Fr {
16-
self.commitment()
16+
self.hash_commitment()
1717
}
1818
}
1919

@@ -25,11 +25,11 @@ pub enum Node {
2525
}
2626

2727
impl NodeTrait for Node {
28-
fn commitment(&self) -> Fr {
28+
fn hash_commitment(&self) -> Fr {
2929
match self {
3030
Node::Empty => Fr::zero(),
31-
Node::Branch(branch_node) => branch_node.commitment(),
32-
Node::Leaf(leaf_node) => leaf_node.commitment(),
31+
Node::Branch(branch_node) => branch_node.hash_commitment(),
32+
Node::Leaf(leaf_node) => leaf_node.hash_commitment(),
3333
Node::Commitment(c) => *c,
3434
}
3535
}
@@ -50,12 +50,12 @@ impl Node {
5050
}
5151

5252
pub fn check(&self, commitment: &Fr) -> Result<()> {
53-
if &self.commitment() == commitment {
53+
if &self.hash_commitment() == commitment {
5454
Ok(())
5555
} else {
5656
Err(anyhow!(
5757
"Node's commitment {:?} doesn't match expected {commitment:?}",
58-
self.commitment()
58+
self.hash_commitment()
5959
))
6060
}
6161
}

verkle/src/stem.rs

+17-9
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,42 @@ use ssz::{Decode, Encode};
33

44
use crate::TrieKey;
55

6-
const STEM_LENGTH: usize = 31;
7-
86
#[derive(PartialEq, Eq, AsRef, Deref, Index)]
9-
pub struct Stem([u8; STEM_LENGTH]);
7+
pub struct Stem([u8; Self::STEM_LENGTH]);
8+
9+
impl Stem {
10+
const STEM_LENGTH: usize = 31;
11+
}
1012

1113
impl From<&TrieKey> for Stem {
1214
fn from(key: &TrieKey) -> Self {
13-
let mut stem = [0u8; STEM_LENGTH];
14-
stem.copy_from_slice(&key[..STEM_LENGTH]);
15+
let mut stem = [0u8; Self::STEM_LENGTH];
16+
stem.copy_from_slice(&key[..Self::STEM_LENGTH]);
1517
Stem(stem)
1618
}
1719
}
1820

21+
impl From<TrieKey> for Stem {
22+
fn from(key: TrieKey) -> Self {
23+
Self::from(&key)
24+
}
25+
}
26+
1927
impl Encode for Stem {
2028
fn is_ssz_fixed_len() -> bool {
2129
true
2230
}
2331

2432
fn ssz_fixed_len() -> usize {
25-
STEM_LENGTH
33+
Self::STEM_LENGTH
2634
}
2735

2836
fn ssz_append(&self, buf: &mut Vec<u8>) {
2937
buf.extend(self.as_ref())
3038
}
3139

3240
fn ssz_bytes_len(&self) -> usize {
33-
STEM_LENGTH
41+
Self::STEM_LENGTH
3442
}
3543
}
3644

@@ -40,15 +48,15 @@ impl Decode for Stem {
4048
}
4149

4250
fn ssz_fixed_len() -> usize {
43-
STEM_LENGTH
51+
Self::STEM_LENGTH
4452
}
4553

4654
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
4755
match <[u8; 31]>::try_from(bytes) {
4856
Ok(stem) => Ok(Self(stem)),
4957
Err(_) => Err(ssz::DecodeError::InvalidByteLength {
5058
len: bytes.len(),
51-
expected: STEM_LENGTH,
59+
expected: Self::STEM_LENGTH,
5260
}),
5361
}
5462
}

verkle/src/trie.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
use alloy_primitives::B256;
1+
use alloy_primitives::{keccak256, Address, B256, U256};
22
use anyhow::Result;
33
use banderwagon::Fr;
44

55
use crate::{
6+
account::AccountStorageLayout,
67
nodes::{BranchNode, Node},
78
utils::{b256_to_fr, fr_to_b256},
89
Db, TrieKey, TrieValue,
@@ -45,6 +46,43 @@ impl Trie {
4546
pub fn root_hash_commitment(&mut self) -> Result<Fr> {
4647
self.root.write_and_commit(self.db.as_mut())
4748
}
49+
50+
pub fn create_eoa(&mut self, address: Address, balance: U256, nonce: u64) -> Result<()> {
51+
let storage = AccountStorageLayout::new(address);
52+
self.insert(storage.version_key(), TrieValue::ZERO)?;
53+
self.insert(storage.balance_key(), balance)?;
54+
self.insert(storage.nonce_key(), TrieValue::from(nonce))?;
55+
self.insert(
56+
storage.code_hash_key(),
57+
TrieValue::from_le_slice(
58+
hex::decode("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")?
59+
.as_slice(),
60+
),
61+
)?;
62+
Ok(())
63+
}
64+
65+
pub fn create_sc(
66+
&mut self,
67+
address: Address,
68+
balance: U256,
69+
nonce: u64,
70+
code: Vec<u8>,
71+
) -> Result<()> {
72+
let storage = AccountStorageLayout::new(address);
73+
self.insert(storage.version_key(), TrieValue::ZERO)?;
74+
self.insert(storage.balance_key(), balance)?;
75+
self.insert(storage.nonce_key(), TrieValue::from(nonce))?;
76+
self.insert(
77+
storage.code_hash_key(),
78+
TrieValue::from_le_bytes(keccak256(&code).0),
79+
)?;
80+
self.insert(storage.code_size_key(), TrieValue::from(code.len()))?;
81+
for (chunk_key, chunk_value) in storage.chunkify_code(&code) {
82+
self.insert(chunk_key, chunk_value)?;
83+
}
84+
Ok(())
85+
}
4886
}
4987

5088
#[cfg(test)]

0 commit comments

Comments
 (0)