Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 2 additions & 39 deletions src/compiler/evm_frontend/evm_imported.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down
56 changes: 56 additions & 0 deletions src/evm/keccak_cache.h
Original file line number Diff line number Diff line change
@@ -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 <cstdint>
#include <cstring>
#include <evmc/evmc.hpp>

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
15 changes: 15 additions & 0 deletions src/evm/opcode_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<uint32_t>(DataLength);
if (const evmc::bytes32 *Cached = TLKeccakCache.lookup(InputData, Len32)) {
Frame->push(intx::be::load<intx::uint256>(*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<intx::uint256>(HashResult);
Frame->push(ResultValue);
}
Expand Down
Loading