diff --git a/crypto/crypto.go b/crypto/crypto.go index 2492165d38..4d69768bc8 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -29,6 +29,7 @@ import ( "math/big" "os" + "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/rlp" @@ -47,6 +48,8 @@ const DigestLength = 32 var ( secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2)) + + keccakState256Cache = fastcache.New(100 * 1024 * 1024) ) var errInvalidPubkey = errors.New("invalid secp256k1 public key") @@ -66,31 +69,56 @@ func NewKeccakState() KeccakState { // HashData hashes the provided data using the KeccakState and returns a 32 byte hash func HashData(kh KeccakState, data []byte) (h common.Hash) { + if hash, ok := keccakState256Cache.HasGet(nil, data); ok { + return common.BytesToHash(hash) + } kh.Reset() kh.Write(data) kh.Read(h[:]) + keccakState256Cache.Set(data, h.Bytes()) return h } // Keccak256 calculates and returns the Keccak256 hash of the input data. func Keccak256(data ...[]byte) []byte { + // Only visit cache when input contains only one []byte to reduce cache overhead + // and avoid complexity of cache calculation. + if len(data) == 1 { + if hash, ok := keccakState256Cache.HasGet(nil, data[0]); ok { + return hash + } + } b := make([]byte, 32) d := NewKeccakState() for _, b := range data { d.Write(b) } d.Read(b) + if len(data) == 1 { + keccakState256Cache.Set(data[0], b) + } return b } // Keccak256Hash calculates and returns the Keccak256 hash of the input data, // converting it to an internal Hash data structure. func Keccak256Hash(data ...[]byte) (h common.Hash) { + // Only visit cache when input contains only one []byte to reduce cache overhead + // and avoid complexity of cache calculation. + if len(data) == 1 { + if hash, ok := keccakState256Cache.HasGet(nil, data[0]); ok { + return common.BytesToHash(hash) + } + } + d := NewKeccakState() for _, b := range data { d.Write(b) } d.Read(h[:]) + if len(data) == 1 { + keccakState256Cache.Set(data[0], h.Bytes()) + } return h }