github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/trie/utils/verkle.go (about) 1 // Copyright 2023 go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package utils 18 19 import ( 20 "encoding/binary" 21 "sync" 22 23 "github.com/crate-crypto/go-ipa/bandersnatch/fr" 24 "github.com/ethereum/go-ethereum/common/lru" 25 "github.com/ethereum/go-ethereum/metrics" 26 "github.com/gballet/go-verkle" 27 "github.com/holiman/uint256" 28 ) 29 30 const ( 31 // The spec of verkle key encoding can be found here. 32 // https://notes.ethereum.org/@vbuterin/verkle_tree_eip#Tree-embedding 33 VersionLeafKey = 0 34 BalanceLeafKey = 1 35 NonceLeafKey = 2 36 CodeKeccakLeafKey = 3 37 CodeSizeLeafKey = 4 38 ) 39 40 var ( 41 zero = uint256.NewInt(0) 42 verkleNodeWidthLog2 = 8 43 headerStorageOffset = uint256.NewInt(64) 44 mainStorageOffsetLshVerkleNodeWidth = new(uint256.Int).Lsh(uint256.NewInt(256), 31-uint(verkleNodeWidthLog2)) 45 codeOffset = uint256.NewInt(128) 46 verkleNodeWidth = uint256.NewInt(256) 47 codeStorageDelta = uint256.NewInt(0).Sub(codeOffset, headerStorageOffset) 48 49 index0Point *verkle.Point // pre-computed commitment of polynomial [2+256*64] 50 51 // cacheHitGauge is the metric to track how many cache hit occurred. 52 cacheHitGauge = metrics.NewRegisteredGauge("trie/verkle/cache/hit", nil) 53 54 // cacheMissGauge is the metric to track how many cache miss occurred. 55 cacheMissGauge = metrics.NewRegisteredGauge("trie/verkle/cache/miss", nil) 56 ) 57 58 func init() { 59 // The byte array is the Marshalled output of the point computed as such: 60 // 61 // var ( 62 // config = verkle.GetConfig() 63 // fr verkle.Fr 64 // ) 65 // verkle.FromLEBytes(&fr, []byte{2, 64}) 66 // point := config.CommitToPoly([]verkle.Fr{fr}, 1) 67 index0Point = new(verkle.Point) 68 err := index0Point.SetBytes([]byte{34, 25, 109, 242, 193, 5, 144, 224, 76, 52, 189, 92, 197, 126, 9, 145, 27, 152, 199, 130, 165, 3, 210, 27, 193, 131, 142, 28, 110, 26, 16, 191}) 69 if err != nil { 70 panic(err) 71 } 72 } 73 74 // PointCache is the LRU cache for storing evaluated address commitment. 75 type PointCache struct { 76 lru lru.BasicLRU[string, *verkle.Point] 77 lock sync.RWMutex 78 } 79 80 // NewPointCache returns the cache with specified size. 81 func NewPointCache(maxItems int) *PointCache { 82 return &PointCache{ 83 lru: lru.NewBasicLRU[string, *verkle.Point](maxItems), 84 } 85 } 86 87 // Get returns the cached commitment for the specified address, or computing 88 // it on the flight. 89 func (c *PointCache) Get(addr []byte) *verkle.Point { 90 c.lock.Lock() 91 defer c.lock.Unlock() 92 93 p, ok := c.lru.Get(string(addr)) 94 if ok { 95 cacheHitGauge.Inc(1) 96 return p 97 } 98 cacheMissGauge.Inc(1) 99 p = evaluateAddressPoint(addr) 100 c.lru.Add(string(addr), p) 101 return p 102 } 103 104 // GetStem returns the first 31 bytes of the tree key as the tree stem. It only 105 // works for the account metadata whose treeIndex is 0. 106 func (c *PointCache) GetStem(addr []byte) []byte { 107 p := c.Get(addr) 108 return pointToHash(p, 0)[:31] 109 } 110 111 // GetTreeKey performs both the work of the spec's get_tree_key function, and that 112 // of pedersen_hash: it builds the polynomial in pedersen_hash without having to 113 // create a mostly zero-filled buffer and "type cast" it to a 128-long 16-byte 114 // array. Since at most the first 5 coefficients of the polynomial will be non-zero, 115 // these 5 coefficients are created directly. 116 func GetTreeKey(address []byte, treeIndex *uint256.Int, subIndex byte) []byte { 117 if len(address) < 32 { 118 var aligned [32]byte 119 address = append(aligned[:32-len(address)], address...) 120 } 121 // poly = [2+256*64, address_le_low, address_le_high, tree_index_le_low, tree_index_le_high] 122 var poly [5]fr.Element 123 124 // 32-byte address, interpreted as two little endian 125 // 16-byte numbers. 126 verkle.FromLEBytes(&poly[1], address[:16]) 127 verkle.FromLEBytes(&poly[2], address[16:]) 128 129 // treeIndex must be interpreted as a 32-byte aligned little-endian integer. 130 // e.g: if treeIndex is 0xAABBCC, we need the byte representation to be 0xCCBBAA00...00. 131 // poly[3] = LE({CC,BB,AA,00...0}) (16 bytes), poly[4]=LE({00,00,...}) (16 bytes). 132 // 133 // To avoid unnecessary endianness conversions for go-ipa, we do some trick: 134 // - poly[3]'s byte representation is the same as the *top* 16 bytes (trieIndexBytes[16:]) of 135 // 32-byte aligned big-endian representation (BE({00,...,AA,BB,CC})). 136 // - poly[4]'s byte representation is the same as the *low* 16 bytes (trieIndexBytes[:16]) of 137 // the 32-byte aligned big-endian representation (BE({00,00,...}). 138 trieIndexBytes := treeIndex.Bytes32() 139 verkle.FromBytes(&poly[3], trieIndexBytes[16:]) 140 verkle.FromBytes(&poly[4], trieIndexBytes[:16]) 141 142 cfg := verkle.GetConfig() 143 ret := cfg.CommitToPoly(poly[:], 0) 144 145 // add a constant point corresponding to poly[0]=[2+256*64]. 146 ret.Add(ret, index0Point) 147 148 return pointToHash(ret, subIndex) 149 } 150 151 // GetTreeKeyWithEvaluatedAddress is basically identical to GetTreeKey, the only 152 // difference is a part of polynomial is already evaluated. 153 // 154 // Specifically, poly = [2+256*64, address_le_low, address_le_high] is already 155 // evaluated. 156 func GetTreeKeyWithEvaluatedAddress(evaluated *verkle.Point, treeIndex *uint256.Int, subIndex byte) []byte { 157 var poly [5]fr.Element 158 159 poly[0].SetZero() 160 poly[1].SetZero() 161 poly[2].SetZero() 162 163 // little-endian, 32-byte aligned treeIndex 164 var index [32]byte 165 for i := 0; i < len(treeIndex); i++ { 166 binary.LittleEndian.PutUint64(index[i*8:(i+1)*8], treeIndex[i]) 167 } 168 verkle.FromLEBytes(&poly[3], index[:16]) 169 verkle.FromLEBytes(&poly[4], index[16:]) 170 171 cfg := verkle.GetConfig() 172 ret := cfg.CommitToPoly(poly[:], 0) 173 174 // add the pre-evaluated address 175 ret.Add(ret, evaluated) 176 177 return pointToHash(ret, subIndex) 178 } 179 180 // VersionKey returns the verkle tree key of the version field for the specified account. 181 func VersionKey(address []byte) []byte { 182 return GetTreeKey(address, zero, VersionLeafKey) 183 } 184 185 // BalanceKey returns the verkle tree key of the balance field for the specified account. 186 func BalanceKey(address []byte) []byte { 187 return GetTreeKey(address, zero, BalanceLeafKey) 188 } 189 190 // NonceKey returns the verkle tree key of the nonce field for the specified account. 191 func NonceKey(address []byte) []byte { 192 return GetTreeKey(address, zero, NonceLeafKey) 193 } 194 195 // CodeKeccakKey returns the verkle tree key of the code keccak field for 196 // the specified account. 197 func CodeKeccakKey(address []byte) []byte { 198 return GetTreeKey(address, zero, CodeKeccakLeafKey) 199 } 200 201 // CodeSizeKey returns the verkle tree key of the code size field for the 202 // specified account. 203 func CodeSizeKey(address []byte) []byte { 204 return GetTreeKey(address, zero, CodeSizeLeafKey) 205 } 206 207 func codeChunkIndex(chunk *uint256.Int) (*uint256.Int, byte) { 208 var ( 209 chunkOffset = new(uint256.Int).Add(codeOffset, chunk) 210 treeIndex, subIndexMod = new(uint256.Int).DivMod(chunkOffset, verkleNodeWidth, new(uint256.Int)) 211 ) 212 return treeIndex, byte(subIndexMod.Uint64()) 213 } 214 215 // CodeChunkKey returns the verkle tree key of the code chunk for the 216 // specified account. 217 func CodeChunkKey(address []byte, chunk *uint256.Int) []byte { 218 treeIndex, subIndex := codeChunkIndex(chunk) 219 return GetTreeKey(address, treeIndex, subIndex) 220 } 221 222 func storageIndex(bytes []byte) (*uint256.Int, byte) { 223 // If the storage slot is in the header, we need to add the header offset. 224 var key uint256.Int 225 key.SetBytes(bytes) 226 if key.Cmp(codeStorageDelta) < 0 { 227 // This addition is always safe; it can't ever overflow since pos<codeStorageDelta. 228 key.Add(headerStorageOffset, &key) 229 230 // In this branch, the tree-index is zero since we're in the account header, 231 // and the sub-index is the LSB of the modified storage key. 232 return zero, byte(key[0] & 0xFF) 233 } 234 // We first divide by VerkleNodeWidth to create room to avoid an overflow next. 235 key.Rsh(&key, uint(verkleNodeWidthLog2)) 236 237 // We add mainStorageOffset/VerkleNodeWidth which can't overflow. 238 key.Add(&key, mainStorageOffsetLshVerkleNodeWidth) 239 240 // The sub-index is the LSB of the original storage key, since mainStorageOffset 241 // doesn't affect this byte, so we can avoid masks or shifts. 242 return &key, byte(key[0] & 0xFF) 243 } 244 245 // StorageSlotKey returns the verkle tree key of the storage slot for the 246 // specified account. 247 func StorageSlotKey(address []byte, storageKey []byte) []byte { 248 treeIndex, subIndex := storageIndex(storageKey) 249 return GetTreeKey(address, treeIndex, subIndex) 250 } 251 252 // VersionKeyWithEvaluatedAddress returns the verkle tree key of the version 253 // field for the specified account. The difference between VersionKey is the 254 // address evaluation is already computed to minimize the computational overhead. 255 func VersionKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { 256 return GetTreeKeyWithEvaluatedAddress(evaluated, zero, VersionLeafKey) 257 } 258 259 // BalanceKeyWithEvaluatedAddress returns the verkle tree key of the balance 260 // field for the specified account. The difference between BalanceKey is the 261 // address evaluation is already computed to minimize the computational overhead. 262 func BalanceKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { 263 return GetTreeKeyWithEvaluatedAddress(evaluated, zero, BalanceLeafKey) 264 } 265 266 // NonceKeyWithEvaluatedAddress returns the verkle tree key of the nonce 267 // field for the specified account. The difference between NonceKey is the 268 // address evaluation is already computed to minimize the computational overhead. 269 func NonceKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { 270 return GetTreeKeyWithEvaluatedAddress(evaluated, zero, NonceLeafKey) 271 } 272 273 // CodeKeccakKeyWithEvaluatedAddress returns the verkle tree key of the code 274 // keccak for the specified account. The difference between CodeKeccakKey is the 275 // address evaluation is already computed to minimize the computational overhead. 276 func CodeKeccakKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { 277 return GetTreeKeyWithEvaluatedAddress(evaluated, zero, CodeKeccakLeafKey) 278 } 279 280 // CodeSizeKeyWithEvaluatedAddress returns the verkle tree key of the code 281 // size for the specified account. The difference between CodeSizeKey is the 282 // address evaluation is already computed to minimize the computational overhead. 283 func CodeSizeKeyWithEvaluatedAddress(evaluated *verkle.Point) []byte { 284 return GetTreeKeyWithEvaluatedAddress(evaluated, zero, CodeSizeLeafKey) 285 } 286 287 // CodeChunkKeyWithEvaluatedAddress returns the verkle tree key of the code 288 // chunk for the specified account. The difference between CodeChunkKey is the 289 // address evaluation is already computed to minimize the computational overhead. 290 func CodeChunkKeyWithEvaluatedAddress(addressPoint *verkle.Point, chunk *uint256.Int) []byte { 291 treeIndex, subIndex := codeChunkIndex(chunk) 292 return GetTreeKeyWithEvaluatedAddress(addressPoint, treeIndex, subIndex) 293 } 294 295 // StorageSlotKeyWithEvaluatedAddress returns the verkle tree key of the storage 296 // slot for the specified account. The difference between StorageSlotKey is the 297 // address evaluation is already computed to minimize the computational overhead. 298 func StorageSlotKeyWithEvaluatedAddress(evaluated *verkle.Point, storageKey []byte) []byte { 299 treeIndex, subIndex := storageIndex(storageKey) 300 return GetTreeKeyWithEvaluatedAddress(evaluated, treeIndex, subIndex) 301 } 302 303 func pointToHash(evaluated *verkle.Point, suffix byte) []byte { 304 // The output of Byte() is big endian for banderwagon. This 305 // introduces an imbalance in the tree, because hashes are 306 // elements of a 253-bit field. This means more than half the 307 // tree would be empty. To avoid this problem, use a little 308 // endian commitment and chop the MSB. 309 bytes := evaluated.Bytes() 310 for i := 0; i < 16; i++ { 311 bytes[31-i], bytes[i] = bytes[i], bytes[31-i] 312 } 313 bytes[31] = suffix 314 return bytes[:] 315 } 316 317 func evaluateAddressPoint(address []byte) *verkle.Point { 318 if len(address) < 32 { 319 var aligned [32]byte 320 address = append(aligned[:32-len(address)], address...) 321 } 322 var poly [3]fr.Element 323 324 poly[0].SetZero() 325 326 // 32-byte address, interpreted as two little endian 327 // 16-byte numbers. 328 verkle.FromLEBytes(&poly[1], address[:16]) 329 verkle.FromLEBytes(&poly[2], address[16:]) 330 331 cfg := verkle.GetConfig() 332 ret := cfg.CommitToPoly(poly[:], 0) 333 334 // add a constant point 335 ret.Add(ret, index0Point) 336 return ret 337 }