mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
crypto: refactor Keccak256Hash to reduce allocations
This commit is contained in:
parent
189f9d0b17
commit
e0530706c7
13 changed files with 92 additions and 55 deletions
|
|
@ -155,8 +155,7 @@ func ecrecover(header *types.Header, sigcache *sigLRU) (common.Address, error) {
|
|||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
var signer common.Address
|
||||
copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
|
||||
signer := crypto.Keccak256Address(pubkey[1:])
|
||||
|
||||
sigcache.Add(hash, signer)
|
||||
return signer, nil
|
||||
|
|
@ -644,9 +643,9 @@ func (c *Clique) Close() error {
|
|||
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
func SealHash(header *types.Header) (hash common.Hash) {
|
||||
hasher := keccak.NewLegacyKeccak256()
|
||||
hasher := keccak.NewLegacyKeccak256State()
|
||||
encodeSigHeader(hasher, header)
|
||||
hasher.(crypto.KeccakState).Read(hash[:])
|
||||
hasher.Read(hash[:])
|
||||
return hash
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common/bitutil"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||
)
|
||||
|
||||
type bytesBacked interface {
|
||||
|
|
@ -141,7 +141,7 @@ func Bloom9(data []byte) []byte {
|
|||
|
||||
// bloomValues returns the bytes (index-value pairs) to set for the given data
|
||||
func bloomValues(data []byte, hashbuf *[6]byte) (uint, byte, uint, byte, uint, byte) {
|
||||
sha := hasherPool.Get().(crypto.KeccakState)
|
||||
sha := hasherPool.Get().(*keccak.KeccakState)
|
||||
sha.Reset()
|
||||
sha.Write(data)
|
||||
sha.Read(hashbuf[:])
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
|
|
@ -55,7 +56,7 @@ func getPooledBuffer(size uint64) ([]byte, *bytes.Buffer, error) {
|
|||
|
||||
// rlpHash encodes x and hashes the encoded bytes.
|
||||
func rlpHash(x interface{}) (h common.Hash) {
|
||||
sha := hasherPool.Get().(crypto.KeccakState)
|
||||
sha := hasherPool.Get().(*keccak.KeccakState)
|
||||
defer hasherPool.Put(sha)
|
||||
sha.Reset()
|
||||
rlp.Encode(sha, x)
|
||||
|
|
@ -66,7 +67,7 @@ func rlpHash(x interface{}) (h common.Hash) {
|
|||
// prefixedRlpHash writes the prefix into the hasher before rlp-encoding x.
|
||||
// It's used for typed transactions.
|
||||
func prefixedRlpHash(prefix byte, x interface{}) (h common.Hash) {
|
||||
sha := hasherPool.Get().(crypto.KeccakState)
|
||||
sha := hasherPool.Get().(*keccak.KeccakState)
|
||||
defer hasherPool.Put(sha)
|
||||
sha.Reset()
|
||||
sha.Write([]byte{prefix})
|
||||
|
|
|
|||
|
|
@ -498,8 +498,9 @@ func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (commo
|
|||
if len(pub) == 0 || pub[0] != 4 {
|
||||
return common.Address{}, errors.New("invalid public key")
|
||||
}
|
||||
hash := crypto.Keccak256Hash(pub[1:])
|
||||
var addr common.Address
|
||||
copy(addr[:], crypto.Keccak256(pub[1:])[12:])
|
||||
copy(addr[:], hash[12:])
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,9 +136,7 @@ func (a *SetCodeAuthorization) Authority() (common.Address, error) {
|
|||
if len(pub) == 0 || pub[0] != 4 {
|
||||
return common.Address{}, errors.New("invalid public key")
|
||||
}
|
||||
var addr common.Address
|
||||
copy(addr[:], crypto.Keccak256(pub[1:])[12:])
|
||||
return addr, nil
|
||||
return crypto.Keccak256Address(pub[1:]), nil
|
||||
}
|
||||
|
||||
// copy creates a deep copy of the transaction data and initializes all fields.
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
// the first byte of pubkey is bitcoin heritage
|
||||
return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil
|
||||
return common.LeftPadBytes(crypto.Keccak256Address(pubKey[1:]).Bytes(), 32), nil
|
||||
}
|
||||
|
||||
func (c *ecrecover) Name() string {
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ import (
|
|||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
|
|
@ -59,16 +59,8 @@ type EllipticCurve interface {
|
|||
Unmarshal(data []byte) (x, y *big.Int)
|
||||
}
|
||||
|
||||
// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports
|
||||
// Read to get a variable amount of data from the hash state. Read is faster than Sum
|
||||
// because it doesn't copy the internal state, but also modifies the internal state.
|
||||
type KeccakState interface {
|
||||
hash.Hash
|
||||
Read([]byte) (int, error)
|
||||
}
|
||||
|
||||
// HashData hashes the provided data using the KeccakState and returns a 32 byte hash
|
||||
func HashData(kh KeccakState, data []byte) (h common.Hash) {
|
||||
func HashData(kh *keccak.KeccakState, data []byte) (h common.Hash) {
|
||||
kh.Reset()
|
||||
kh.Write(data)
|
||||
kh.Read(h[:])
|
||||
|
|
@ -78,7 +70,7 @@ func HashData(kh KeccakState, data []byte) (h common.Hash) {
|
|||
// CreateAddress creates an ethereum address given the bytes and the nonce
|
||||
func CreateAddress(b common.Address, nonce uint64) common.Address {
|
||||
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
|
||||
return common.BytesToAddress(Keccak256(data)[12:])
|
||||
return Keccak256Address(data)
|
||||
}
|
||||
|
||||
// CreateAddress2 creates an ethereum address given the address bytes, initial
|
||||
|
|
@ -252,7 +244,7 @@ func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
|
|||
|
||||
func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
|
||||
pubBytes := FromECDSAPub(&p)
|
||||
return common.BytesToAddress(Keccak256(pubBytes[1:])[12:])
|
||||
return Keccak256Address(pubBytes[1:])
|
||||
}
|
||||
|
||||
func zeroBytes(bytes []byte) {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,20 @@ func BenchmarkSha3(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func BenchmarkSha3_2(b *testing.B) {
|
||||
a := []byte("hello world")
|
||||
for b.Loop() {
|
||||
Keccak256Hash(a)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkKeccak256Address(b *testing.B) {
|
||||
a := []byte("hello world hello world hello world") // 36 bytes to simulate pubkey
|
||||
for b.Loop() {
|
||||
Keccak256Address(a)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalPubkey(t *testing.T) {
|
||||
key, err := UnmarshalPubkey(nil)
|
||||
if err != errInvalidPubkey || key != nil {
|
||||
|
|
|
|||
|
|
@ -26,20 +26,20 @@ import (
|
|||
)
|
||||
|
||||
// NewKeccakState creates a new KeccakState
|
||||
func NewKeccakState() KeccakState {
|
||||
return keccak.NewLegacyKeccak256().(KeccakState)
|
||||
func NewKeccakState() *keccak.KeccakState {
|
||||
return keccak.NewLegacyKeccak256State()
|
||||
}
|
||||
|
||||
var hasherPool = sync.Pool{
|
||||
New: func() any {
|
||||
return keccak.NewLegacyKeccak256().(KeccakState)
|
||||
return keccak.NewLegacyKeccak256State()
|
||||
},
|
||||
}
|
||||
|
||||
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
||||
func Keccak256(data ...[]byte) []byte {
|
||||
b := make([]byte, 32)
|
||||
d := hasherPool.Get().(KeccakState)
|
||||
d := hasherPool.Get().(*keccak.KeccakState)
|
||||
d.Reset()
|
||||
for _, b := range data {
|
||||
d.Write(b)
|
||||
|
|
@ -51,8 +51,19 @@ func Keccak256(data ...[]byte) []byte {
|
|||
|
||||
// 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) {
|
||||
d := hasherPool.Get().(KeccakState)
|
||||
func Keccak256Hash(data []byte) (h common.Hash) {
|
||||
d := hasherPool.Get().(*keccak.KeccakState)
|
||||
d.Reset()
|
||||
d.Write(data)
|
||||
d.Read(h[:])
|
||||
hasherPool.Put(d)
|
||||
return h
|
||||
}
|
||||
|
||||
// Keccak256HashV calculates and returns the Keccak256 hash of the input data,
|
||||
// converting it to an internal Hash data structure.
|
||||
func Keccak256HashV(data ...[]byte) (h common.Hash) {
|
||||
d := hasherPool.Get().(*keccak.KeccakState)
|
||||
d.Reset()
|
||||
for _, b := range data {
|
||||
d.Write(b)
|
||||
|
|
@ -61,3 +72,11 @@ func Keccak256Hash(data ...[]byte) (h common.Hash) {
|
|||
hasherPool.Put(d)
|
||||
return h
|
||||
}
|
||||
|
||||
// Keccak256Address calculates the Keccak256 hash of the input data and
|
||||
// returns the last 20 bytes as an address.
|
||||
func Keccak256Address(data []byte) (a common.Address) {
|
||||
hash := Keccak256Hash(data)
|
||||
copy(a[:], hash[12:])
|
||||
return a
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,6 @@ func (d *state) Read(out []byte) (n int, err error) {
|
|||
}
|
||||
|
||||
n = len(out)
|
||||
|
||||
// Now, do the squeezing.
|
||||
for len(out) > 0 {
|
||||
// Apply the permutation if we've squeezed the sponge dry.
|
||||
|
|
@ -157,6 +156,16 @@ func (d *state) Read(out []byte) (n int, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// Sum256 finalizes the hash and returns the 256-bit digest.
|
||||
// Returns the result by value to avoid heap allocation.
|
||||
func (d *state) Sum256() (out [32]byte) {
|
||||
if d.state == spongeAbsorbing {
|
||||
d.padAndPermute()
|
||||
}
|
||||
copy(out[:], d.a[:32])
|
||||
return out
|
||||
}
|
||||
|
||||
// Sum applies padding to the hash state and then squeezes out the desired
|
||||
// number of output bytes. It panics if any output has already been read.
|
||||
func (d *state) Sum(in []byte) []byte {
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ type testBackend struct {
|
|||
}
|
||||
|
||||
func fakeBlockHash(txh common.Hash) common.Hash {
|
||||
return crypto.Keccak256Hash([]byte("testblock"), txh.Bytes())
|
||||
return crypto.Keccak256HashV([]byte("testblock"), txh.Bytes())
|
||||
}
|
||||
|
||||
func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend {
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/crypto/keccak"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// hasher is a type used for the trie Hash operation. A hasher has some
|
||||
// internal preallocated temp space
|
||||
type hasher struct {
|
||||
sha crypto.KeccakState
|
||||
sha *keccak.KeccakState
|
||||
tmp []byte
|
||||
encbuf rlp.EncoderBuffer
|
||||
parallel bool // Whether to use parallel threads when hashing
|
||||
|
|
|
|||
|
|
@ -102,14 +102,16 @@ func NewStateTrie(id *ID, db database.NodeDatabase) (*StateTrie, error) {
|
|||
// This function will omit any encountered error but just
|
||||
// print out an error message.
|
||||
func (t *StateTrie) MustGet(key []byte) []byte {
|
||||
return t.trie.MustGet(crypto.Keccak256(key))
|
||||
hk := crypto.Keccak256Hash(key)
|
||||
return t.trie.MustGet(hk[:])
|
||||
}
|
||||
|
||||
// GetAccount attempts to retrieve an account with provided account address.
|
||||
// If the specified account is not in the trie, nil will be returned.
|
||||
// If a trie node is not found in the database, a MissingNodeError is returned.
|
||||
func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
|
||||
res, err := t.trie.Get(crypto.Keccak256(address.Bytes()))
|
||||
hk := crypto.Keccak256Hash(address.Bytes())
|
||||
res, err := t.trie.Get(hk[:])
|
||||
if res == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -146,7 +148,8 @@ func (t *StateTrie) PrefetchAccount(addresses []common.Address) error {
|
|||
// If the specified storage slot is not in the trie, nil will be returned.
|
||||
// If a trie node is not found in the database, a MissingNodeError is returned.
|
||||
func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
|
||||
enc, err := t.trie.Get(crypto.Keccak256(key))
|
||||
hk := crypto.Keccak256Hash(key)
|
||||
enc, err := t.trie.Get(hk[:])
|
||||
if err != nil || len(enc) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -182,10 +185,10 @@ func (t *StateTrie) GetNode(path []byte) ([]byte, int, error) {
|
|||
// This function will omit any encountered error but just print out an
|
||||
// error message.
|
||||
func (t *StateTrie) MustUpdate(key, value []byte) {
|
||||
hk := crypto.Keccak256(key)
|
||||
t.trie.MustUpdate(hk, value)
|
||||
hk := crypto.Keccak256Hash(key)
|
||||
t.trie.MustUpdate(hk[:], value)
|
||||
if t.preimages != nil {
|
||||
t.secKeyCache[common.Hash(hk)] = common.CopyBytes(key)
|
||||
t.secKeyCache[hk] = common.CopyBytes(key)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -198,30 +201,30 @@ func (t *StateTrie) MustUpdate(key, value []byte) {
|
|||
//
|
||||
// If a node is not found in the database, a MissingNodeError is returned.
|
||||
func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error {
|
||||
hk := crypto.Keccak256(key)
|
||||
hk := crypto.Keccak256Hash(key)
|
||||
v, _ := rlp.EncodeToBytes(value)
|
||||
err := t.trie.Update(hk, v)
|
||||
err := t.trie.Update(hk[:], v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t.preimages != nil {
|
||||
t.secKeyCache[common.Hash(hk)] = common.CopyBytes(key)
|
||||
t.secKeyCache[hk] = common.CopyBytes(key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateAccount will abstract the write of an account to the secure trie.
|
||||
func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount, _ int) error {
|
||||
hk := crypto.Keccak256(address.Bytes())
|
||||
hk := crypto.Keccak256Hash(address.Bytes())
|
||||
data, err := rlp.EncodeToBytes(acc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := t.trie.Update(hk, data); err != nil {
|
||||
if err := t.trie.Update(hk[:], data); err != nil {
|
||||
return err
|
||||
}
|
||||
if t.preimages != nil {
|
||||
t.secKeyCache[common.Hash(hk)] = address.Bytes()
|
||||
t.secKeyCache[hk] = address.Bytes()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -233,31 +236,31 @@ func (t *StateTrie) UpdateContractCode(_ common.Address, _ common.Hash, _ []byte
|
|||
// MustDelete removes any existing value for key from the trie. This function
|
||||
// will omit any encountered error but just print out an error message.
|
||||
func (t *StateTrie) MustDelete(key []byte) {
|
||||
hk := crypto.Keccak256(key)
|
||||
hk := crypto.Keccak256Hash(key)
|
||||
if t.preimages != nil {
|
||||
delete(t.secKeyCache, common.Hash(hk))
|
||||
delete(t.secKeyCache, hk)
|
||||
}
|
||||
t.trie.MustDelete(hk)
|
||||
t.trie.MustDelete(hk[:])
|
||||
}
|
||||
|
||||
// DeleteStorage removes any existing storage slot from the trie.
|
||||
// If the specified trie node is not in the trie, nothing will be changed.
|
||||
// If a node is not found in the database, a MissingNodeError is returned.
|
||||
func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
|
||||
hk := crypto.Keccak256(key)
|
||||
hk := crypto.Keccak256Hash(key)
|
||||
if t.preimages != nil {
|
||||
delete(t.secKeyCache, common.Hash(hk))
|
||||
delete(t.secKeyCache, hk)
|
||||
}
|
||||
return t.trie.Delete(hk)
|
||||
return t.trie.Delete(hk[:])
|
||||
}
|
||||
|
||||
// DeleteAccount abstracts an account deletion from the trie.
|
||||
func (t *StateTrie) DeleteAccount(address common.Address) error {
|
||||
hk := crypto.Keccak256(address.Bytes())
|
||||
hk := crypto.Keccak256Hash(address.Bytes())
|
||||
if t.preimages != nil {
|
||||
delete(t.secKeyCache, common.Hash(hk))
|
||||
delete(t.secKeyCache, hk)
|
||||
}
|
||||
return t.trie.Delete(hk)
|
||||
return t.trie.Delete(hk[:])
|
||||
}
|
||||
|
||||
// GetKey returns the sha3 preimage of a hashed key that was
|
||||
|
|
|
|||
Loading…
Reference in a new issue