diff --git a/src/compiler/evm_frontend/evm_imported.cpp b/src/compiler/evm_frontend/evm_imported.cpp index ff5462c99..d298b8dd6 100644 --- a/src/compiler/evm_frontend/evm_imported.cpp +++ b/src/compiler/evm_frontend/evm_imported.cpp @@ -5,6 +5,7 @@ #include "common/errors.h" #include "evm/gas_storage_cost.h" #include "evm/interpreter.h" +#include "evm/keccak_cache.h" #include "host/evm/crypto.h" #include "runtime/evm_instance.h" #include "runtime/evm_module.h" @@ -15,45 +16,7 @@ namespace { -static constexpr uint32_t KeccakCacheSlots = 16; -static constexpr uint32_t KeccakCacheMaxInputLen = 128; - -struct KeccakCacheEntry { - uint8_t Input[KeccakCacheMaxInputLen]; - uint32_t InputLen = 0; - evmc::bytes32 Result; - bool Valid = false; -}; - -struct KeccakCache { - KeccakCacheEntry Slots[KeccakCacheSlots]; - uint32_t NextSlot = 0; - - const evmc::bytes32 *lookup(const uint8_t *Data, uint32_t Len) const { - if (Len > KeccakCacheMaxInputLen) - return nullptr; - for (uint32_t I = 0; I < KeccakCacheSlots; ++I) { - auto &S = Slots[I]; - if (S.Valid && S.InputLen == Len && - std::memcmp(S.Input, Data, Len) == 0) { - return &S.Result; - } - } - return nullptr; - } - - void insert(const uint8_t *Data, uint32_t Len, const evmc::bytes32 &Result) { - if (Len > KeccakCacheMaxInputLen) - return; - auto &S = Slots[NextSlot]; - std::memcpy(S.Input, Data, Len); - S.InputLen = Len; - S.Result = Result; - S.Valid = true; - NextSlot = (NextSlot + 1) % KeccakCacheSlots; - } -}; - +using zen::evm::KeccakCache; static thread_local KeccakCache TLKeccakCache; } // namespace diff --git a/src/evm/keccak_cache.h b/src/evm/keccak_cache.h new file mode 100644 index 000000000..76159664a --- /dev/null +++ b/src/evm/keccak_cache.h @@ -0,0 +1,56 @@ +// Copyright (C) 2025 the DTVM authors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef ZEN_EVM_KECCAK_CACHE_H +#define ZEN_EVM_KECCAK_CACHE_H + +#include +#include +#include + +namespace zen { +namespace evm { + +static constexpr uint32_t KeccakCacheSlots = 16; +static constexpr uint32_t KeccakCacheMaxInputLen = 128; + +struct KeccakCacheEntry { + uint8_t Input[KeccakCacheMaxInputLen]; + uint32_t InputLen = 0; + evmc::bytes32 Result; + bool Valid = false; +}; + +struct KeccakCache { + KeccakCacheEntry Slots[KeccakCacheSlots]; + uint32_t NextSlot = 0; + + const evmc::bytes32 *lookup(const uint8_t *Data, uint32_t Len) const { + if (Len > KeccakCacheMaxInputLen) + return nullptr; + for (uint32_t I = 0; I < KeccakCacheSlots; ++I) { + auto &S = Slots[I]; + if (S.Valid && S.InputLen == Len && + std::memcmp(S.Input, Data, Len) == 0) { + return &S.Result; + } + } + return nullptr; + } + + void insert(const uint8_t *Data, uint32_t Len, const evmc::bytes32 &Result) { + if (Len > KeccakCacheMaxInputLen) + return; + auto &S = Slots[NextSlot]; + std::memcpy(S.Input, Data, Len); + S.InputLen = Len; + S.Result = Result; + S.Valid = true; + NextSlot = (NextSlot + 1) % KeccakCacheSlots; + } +}; + +} // namespace evm +} // namespace zen + +#endif // ZEN_EVM_KECCAK_CACHE_H diff --git a/src/evm/opcode_handlers.cpp b/src/evm/opcode_handlers.cpp index cad5226d5..c06743e2c 100644 --- a/src/evm/opcode_handlers.cpp +++ b/src/evm/opcode_handlers.cpp @@ -5,11 +5,14 @@ #include "common/errors.h" #include "evm/gas_storage_cost.h" #include "evm/interpreter.h" +#include "evm/keccak_cache.h" #include "evmc/evmc.h" #include "evmc/instructions.h" #include "host/evm/crypto.h" #include "runtime/evm_instance.h" +static thread_local zen::evm::KeccakCache TLKeccakCache; + thread_local zen::evm::EVMFrame *zen::evm::EVMResource::CurrentFrame = nullptr; thread_local zen::evm::InterpreterExecContext *zen::evm::EVMResource::CurrentContext = nullptr; @@ -832,9 +835,21 @@ void Keccak256Handler::doExecute() { const uint8_t *InputData = Frame->Memory.data() + MemOffset; + // Keccak cache: avoid recomputing hash for repeated inputs (e.g. storage + // slot keys in ERC20 transfer). + const uint32_t Len32 = static_cast(DataLength); + if (const evmc::bytes32 *Cached = TLKeccakCache.lookup(InputData, Len32)) { + Frame->push(intx::be::load(*Cached)); + return; + } + uint8_t HashResult[32]; host::evm::crypto::keccak256(InputData, DataLength, HashResult); + evmc::bytes32 HashBytes; + std::memcpy(HashBytes.bytes, HashResult, 32); + TLKeccakCache.insert(InputData, Len32, HashBytes); + const auto ResultValue = intx::be::load(HashResult); Frame->push(ResultValue); }