arb_storage/
slot.rs

1use alloy_primitives::{keccak256, B256, U256};
2
3/// Computes a storage slot using the keccak256-based mapAddress algorithm.
4///
5/// The algorithm: hash(storage_key || key_bytes[0..31]) || key_bytes[31]
6/// This preserves the last byte and hashes only the first 31 bytes.
7pub fn storage_key_map(storage_key: &[u8], offset: u64) -> U256 {
8    const BOUNDARY: usize = 31;
9
10    let mut key_bytes = [0u8; 32];
11    key_bytes[24..32].copy_from_slice(&offset.to_be_bytes());
12
13    let mut buf = [0u8; 64];
14    let sk_len = storage_key.len();
15    buf[..sk_len].copy_from_slice(storage_key);
16    buf[sk_len..sk_len + BOUNDARY].copy_from_slice(&key_bytes[..BOUNDARY]);
17    let h = keccak256(&buf[..sk_len + BOUNDARY]);
18
19    let mut mapped = [0u8; 32];
20    mapped[..BOUNDARY].copy_from_slice(&h.0[..BOUNDARY]);
21    mapped[BOUNDARY] = key_bytes[BOUNDARY];
22    U256::from_be_bytes(mapped)
23}
24
25/// Computes a storage slot for an arbitrary B256 key using the mapAddress algorithm.
26pub fn storage_key_map_b256(storage_key: &[u8], key: &[u8; 32]) -> U256 {
27    const BOUNDARY: usize = 31;
28
29    let mut buf = [0u8; 64];
30    let sk_len = storage_key.len();
31    buf[..sk_len].copy_from_slice(storage_key);
32    buf[sk_len..sk_len + BOUNDARY].copy_from_slice(&key[..BOUNDARY]);
33    let h = keccak256(&buf[..sk_len + BOUNDARY]);
34
35    let mut mapped = [0u8; 32];
36    mapped[..BOUNDARY].copy_from_slice(&h.0[..BOUNDARY]);
37    mapped[BOUNDARY] = key[BOUNDARY];
38    U256::from_be_bytes(mapped)
39}
40
41/// Derive a sub-storage key: `keccak256(parent_key || sub_key)`.
42///
43/// Uses an inline stack buffer to avoid heap allocation. For hot paths where
44/// `sub_key` is a compile-time constant, prefer caching the result.
45pub fn derive_sub_key(parent_key: B256, sub_key: &[u8]) -> B256 {
46    let base_slice: &[u8] = if parent_key == B256::ZERO {
47        &[]
48    } else {
49        parent_key.as_slice()
50    };
51    let base_len = base_slice.len();
52    let sub_len = sub_key.len();
53    if base_len + sub_len <= 64 {
54        let mut buf = [0u8; 64];
55        buf[..base_len].copy_from_slice(base_slice);
56        buf[base_len..base_len + sub_len].copy_from_slice(sub_key);
57        keccak256(&buf[..base_len + sub_len])
58    } else {
59        let mut v = Vec::with_capacity(base_len + sub_len);
60        v.extend_from_slice(base_slice);
61        v.extend_from_slice(sub_key);
62        keccak256(&v)
63    }
64}