Skip to content

Commit a0fb810

Browse files
authored
trie/bintrie: fix overflow management in slot key computation (#33951)
The computation of `MAIN_STORAGE_OFFSET` was incorrect, causing the last byte of the stem to be dropped. This means that there would be a collision in the hash computation (at the preimage level, not a hash collision of course) if two keys were only differing at byte 31.
1 parent 344ce84 commit a0fb810

File tree

2 files changed

+36
-18
lines changed

2 files changed

+36
-18
lines changed

core/genesis_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
308308
},
309309
}
310310

311-
expected := common.FromHex("b94812c1674dcf4f2bc98f4503d15f4cc674265135bcf3be6e4417b60881042a")
311+
expected := common.FromHex("1fd154971d9a386c4ec75fe7138c17efb569bfc2962e46e94a376ba997e3fadc")
312312
got := genesis.ToBlock().Root().Bytes()
313313
if !bytes.Equal(got, expected) {
314314
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)

trie/bintrie/key_encoding.go

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,26 @@ var (
4747
)
4848

4949
func GetBinaryTreeKey(addr common.Address, key []byte) []byte {
50+
return getBinaryTreeKey(addr, key, false)
51+
}
52+
53+
func getBinaryTreeKey(addr common.Address, offset []byte, overflow bool) []byte {
5054
hasher := sha256.New()
5155
hasher.Write(zeroHash[:12])
5256
hasher.Write(addr[:])
53-
hasher.Write(key[:31])
54-
hasher.Write([]byte{0})
57+
var buf [32]byte
58+
// key is big endian, hashed value is little endian
59+
for i := range offset[:31] {
60+
buf[i] = offset[30-i]
61+
}
62+
if overflow {
63+
// Overflow detected when adding MAIN_STORAGE_OFFSET,
64+
// reporting it in the shifter 32 byte value.
65+
buf[31] = 1
66+
}
67+
hasher.Write(buf[:])
5568
k := hasher.Sum(nil)
56-
k[31] = key[31]
69+
k[31] = offset[31]
5770
return k
5871
}
5972

@@ -69,24 +82,29 @@ func GetBinaryTreeKeyCodeHash(addr common.Address) []byte {
6982
return GetBinaryTreeKey(addr, k[:])
7083
}
7184

72-
func GetBinaryTreeKeyStorageSlot(address common.Address, key []byte) []byte {
73-
var k [32]byte
85+
func GetBinaryTreeKeyStorageSlot(address common.Address, slotnum []byte) []byte {
86+
var offset [32]byte
7487

7588
// Case when the key belongs to the account header
76-
if bytes.Equal(key[:31], zeroHash[:31]) && key[31] < 64 {
77-
k[31] = 64 + key[31]
78-
return GetBinaryTreeKey(address, k[:])
89+
if bytes.Equal(slotnum[:31], zeroHash[:31]) && slotnum[31] < 64 {
90+
offset[31] = 64 + slotnum[31]
91+
return GetBinaryTreeKey(address, offset[:])
7992
}
8093

81-
// Set the main storage offset
82-
// note that the first 64 bytes of the main offset storage
83-
// are unreachable, which is consistent with the spec and
84-
// what verkle does.
85-
k[0] = 1 // 1 << 248
86-
copy(k[1:], key[:31])
87-
k[31] = key[31]
88-
89-
return GetBinaryTreeKey(address, k[:])
94+
// Set the main storage offset offset = MAIN_STORAGE_OFFSET + slotnum
95+
// * Note that MAIN_STORAGE_OFFSET is 1 << 248, so the number
96+
// can overflow into a 33rd byte, but since the value is
97+
// shifted by one byte in getBinaryTreeKey, this only takes
98+
// note of the overflow, and the value will be added after
99+
// the shift, in order to avoid allocating an extra byte.
100+
// * Note that the first 64 bytes of the main offset storage
101+
// are unreachable, which is consistent with the spec.
102+
// * Note that `slotnum` is big-endian
103+
overflow := slotnum[0] == 255
104+
copy(offset[:], slotnum)
105+
offset[0] += 1 // 1 << 248, handle overflow out of band
106+
107+
return getBinaryTreeKey(address, offset[:], overflow)
90108
}
91109

92110
func GetBinaryTreeKeyCodeChunk(address common.Address, chunknr *uint256.Int) []byte {

0 commit comments

Comments
 (0)