Skip to content
Merged
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
12 changes: 10 additions & 2 deletions cmd/devp2p/internal/ethtest/snap.go
Original file line number Diff line number Diff line change
Expand Up @@ -900,12 +900,16 @@ func (s *Suite) snapGetByteCodes(t *utesting.T, tc *byteCodesTest) error {
// that the serving node is missing
var (
bytecodes = res.Codes
hasher = crypto.NewKeccakState()
hash = make([]byte, 32)
codes = make([][]byte, len(req.Hashes))
)

for i, j := 0, 0; i < len(bytecodes); i++ {
// Find the next hash that we've been served, leaving misses with nils
hash := crypto.Keccak256(bytecodes[i])
hasher.Reset()
hasher.Write(bytecodes[i])
hasher.Read(hash)

for j < len(req.Hashes) && !bytes.Equal(hash, req.Hashes[j][:]) {
j++
Expand Down Expand Up @@ -955,12 +959,16 @@ func (s *Suite) snapGetTrieNodes(t *utesting.T, tc *trieNodesTest) error {

// Cross reference the requested trienodes with the response to find gaps
// that the serving node is missing
hasher := crypto.NewKeccakState()
hash := make([]byte, 32)
trienodes := res.Nodes
if got, want := len(trienodes), len(tc.expHashes); got != want {
return fmt.Errorf("wrong trienode count, got %d, want %d", got, want)
}
for i, trienode := range trienodes {
hash := crypto.Keccak256(trienode[:])
hasher.Reset()
hasher.Write(trienode)
hasher.Read(hash)
if got, want := hash, tc.expHashes[i]; !bytes.Equal(got, want[:]) {
t.Logf(" hash %d wrong, got %#x, want %#x\n", i, got, want)
err = fmt.Errorf("hash %d wrong, got %#x, want %#x", i, got, want)
Expand Down
6 changes: 5 additions & 1 deletion cmd/geth/dbcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,8 @@ func checkStateContent(ctx *cli.Context) error {
defer db.Close()
var (
it = rawdb.NewKeyLengthIterator(db.NewIterator(prefix, start), 32)
hasher = crypto.NewKeccakState()
got = make([]byte, 32)
errs int
count int
startTime = time.Now()
Expand All @@ -363,7 +365,9 @@ func checkStateContent(ctx *cli.Context) error {
count++
k := it.Key()
v := it.Value()
got := crypto.Keccak256(v)
hasher.Reset()
hasher.Write(v)
hasher.Read(got)
if !bytes.Equal(k, got) {
errs++
fmt.Printf("Error at %#x\n", k)
Expand Down
10 changes: 8 additions & 2 deletions cmd/geth/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ func traverseRawState(ctx *cli.Context) error {
codes int
lastReport time.Time
start = time.Now()
hasher = crypto.NewKeccakState()
got = make([]byte, 32)
)
accIter, err := t.NodeIterator(nil)
if err != nil {
Expand All @@ -457,7 +459,9 @@ func traverseRawState(ctx *cli.Context) error {
log.Error("Missing trie node(account)", "hash", node)
return errors.New("missing account")
}
got := crypto.Keccak256(blob)
hasher.Reset()
hasher.Write(blob)
hasher.Read(got)
if !bytes.Equal(got, node.Bytes()) {
log.Error("Invalid trie node(account)", "hash", node.Hex(), "value", blob)
return errors.New("invalid account node")
Expand Down Expand Up @@ -496,7 +500,9 @@ func traverseRawState(ctx *cli.Context) error {
log.Error("Missing trie node(storage)", "hash", node)
return errors.New("missing storage")
}
got := crypto.Keccak256(blob)
hasher.Reset()
hasher.Write(blob)
hasher.Read(got)
if !bytes.Equal(got, node.Bytes()) {
log.Error("Invalid trie node(storage)", "hash", node.Hex(), "value", blob)
return errors.New("invalid storage node")
Expand Down
5 changes: 3 additions & 2 deletions cmd/workload/historytestgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,9 @@ func generateHistoryTests(clictx *cli.Context) error {
}

func calcReceiptsHash(rcpt []*types.Receipt) common.Hash {
encoded, _ := rlp.EncodeToBytes(rcpt)
return crypto.Keccak256Hash(encoded)
h := crypto.NewKeccakState()
rlp.Encode(h, rcpt)
return common.Hash(h.Sum(nil))
}

func writeJSON(fileName string, value any) {
Expand Down
18 changes: 15 additions & 3 deletions core/stateless/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,33 @@ import (
//
// Acceleration structures built would need to explicitly validate the witness.
func (w *Witness) MakeHashDB() ethdb.Database {
var memdb = rawdb.NewMemoryDatabase()
var (
memdb = rawdb.NewMemoryDatabase()
hasher = crypto.NewKeccakState()
hash = make([]byte, 32)
)
// Inject all the "block hashes" (i.e. headers) into the ephemeral database
for _, header := range w.Headers {
rawdb.WriteHeader(memdb, header)
}
// Inject all the bytecodes into the ephemeral database
for code := range w.Codes {
blob := []byte(code)
hash := crypto.Keccak256(blob)

hasher.Reset()
hasher.Write(blob)
hasher.Read(hash)

rawdb.WriteCode(memdb, common.BytesToHash(hash), blob)
}
// Inject all the MPT trie nodes into the ephemeral database
for node := range w.State {
blob := []byte(node)
hash := crypto.Keccak256(blob)

hasher.Reset()
hasher.Write(blob)
hasher.Read(hash)

rawdb.WriteLegacyTrieNode(memdb, common.BytesToHash(hash), blob)
}
return memdb
Expand Down
7 changes: 5 additions & 2 deletions core/types/bloom9.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,11 @@ 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) {
hash := crypto.Keccak256(data)
copy(hashbuf[:], hash[:6])
sha := hasherPool.Get().(crypto.KeccakState)
sha.Reset()
sha.Write(data)
sha.Read(hashbuf[:])
hasherPool.Put(sha)
// The actual bits to flip
v1 := byte(1 << (hashbuf[1] & 0x7))
v2 := byte(1 << (hashbuf[3] & 0x7))
Expand Down
22 changes: 18 additions & 4 deletions core/types/hashing.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)

// hasherPool holds LegacyKeccak256 buffer for rlpHash.
var hasherPool = sync.Pool{
New: func() interface{} { return crypto.NewKeccakState() },
}

// encodeBufferPool holds temporary encoder buffers for DeriveSha and TX encoding.
var encodeBufferPool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
Expand All @@ -50,15 +55,24 @@ func getPooledBuffer(size uint64) ([]byte, *bytes.Buffer, error) {

// rlpHash encodes x and hashes the encoded bytes.
func rlpHash(x interface{}) (h common.Hash) {
encoded, _ := rlp.EncodeToBytes(x)
return crypto.Keccak256Hash(encoded)
sha := hasherPool.Get().(crypto.KeccakState)
defer hasherPool.Put(sha)
sha.Reset()
rlp.Encode(sha, x)
sha.Read(h[:])
return h
}

// 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) {
encoded, _ := rlp.EncodeToBytes(x)
return crypto.Keccak256Hash([]byte{prefix}, encoded)
sha := hasherPool.Get().(crypto.KeccakState)
defer hasherPool.Put(sha)
sha.Reset()
sha.Write([]byte{prefix})
rlp.Encode(sha, x)
sha.Read(h[:])
return h
}

// ListHasher defines the interface for computing the hash of a derivable list.
Expand Down
6 changes: 5 additions & 1 deletion core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ type EVM struct {
// jumpDests stores results of JUMPDEST analysis.
jumpDests JumpDestCache

hasher crypto.KeccakState // Keccak256 hasher instance shared across opcodes
hasherBuf common.Hash // Keccak256 hasher result array shared across opcodes

readOnly bool // Whether to throw on stateful modifications
returnData []byte // Last CALL's return data for subsequent reuse
}
Expand All @@ -149,6 +152,7 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time, blockCtx.ArbOSVersion),
jumpDests: newMapJumpDests(),
hasher: crypto.NewKeccakState(),
}
evm.ProcessingHook = DefaultTxProcessor{evm: evm}
evm.precompiles = activePrecompiledContracts(evm.chainRules)
Expand Down Expand Up @@ -699,7 +703,7 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *ui
// The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:]
// instead of the usual sender-and-nonce-hash as the address where the contract is initialized at.
func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, usedMultiGas multigas.MultiGas, err error) {
inithash := crypto.Keccak256Hash(code)
inithash := crypto.HashData(evm.hasher, code)
contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:])
return evm.create(caller, code, gas, endowment, contractAddr, CREATE2)
}
Expand Down
10 changes: 6 additions & 4 deletions core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
Expand Down Expand Up @@ -236,12 +235,15 @@ func opSAR(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
func opKeccak256(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
offset, size := scope.Stack.pop(), scope.Stack.peek()
data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64())
hasherBuf := crypto.Keccak256Hash(data)

evm.hasher.Reset()
evm.hasher.Write(data)
evm.hasher.Read(evm.hasherBuf[:])

if evm.Config.EnablePreimageRecording {
evm.StateDB.AddPreimage(hasherBuf, data)
evm.StateDB.AddPreimage(evm.hasherBuf, data)
}
size.SetBytes(hasherBuf[:])
size.SetBytes(evm.hasherBuf[:])
return nil, nil
}

Expand Down
8 changes: 8 additions & 0 deletions crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ type KeccakState interface {
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) {
kh.Reset()
kh.Write(data)
kh.Read(h[:])
return h
}

// 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})
Expand Down
22 changes: 21 additions & 1 deletion crypto/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ func TestKeccak256Hash(t *testing.T) {
func TestKeccak256Hasher(t *testing.T) {
msg := []byte("abc")
exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Keccak256Hash(in); return h[:] }, msg, exp)
hasher := NewKeccakState()
checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := HashData(hasher, in); return h[:] }, msg, exp)
}

func TestToECDSAErrors(t *testing.T) {
Expand Down Expand Up @@ -313,3 +314,22 @@ func BenchmarkKeccak256Hash(b *testing.B) {
Keccak256Hash(input[:])
}
}

// goos: darwin
// goarch: arm64
// pkg: github.com/ethereum/go-ethereum/crypto
// cpu: Apple M1 Pro
// BenchmarkHashData
// BenchmarkHashData-8 793386 1278 ns/op 32 B/op 1 allocs/op
func BenchmarkHashData(b *testing.B) {
var (
input [512]byte
buffer = NewKeccakState()
)
rand.Read(input[:])

b.ReportAllocs()
for b.Loop() {
HashData(buffer, input[:])
}
}
21 changes: 11 additions & 10 deletions crypto/keccak.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,28 @@ var hasherPool = sync.Pool{
},
}

// keccak256 is a helper that hashes the input data using the provided KeccakState and writes the result to out.
func keccak256(out []byte, data ...[]byte) {
// 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.Reset()
for _, b := range data {
d.Write(b)
}
d.Read(out)
d.Read(b)
hasherPool.Put(d)
}

// Keccak256 calculates and returns the Keccak256 hash of the input data.
func Keccak256(data ...[]byte) []byte {
b := make([]byte, 32)
keccak256(b, data...)
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) {
keccak256(h[:], data...)
d := hasherPool.Get().(KeccakState)
d.Reset()
for _, b := range data {
d.Write(b)
}
d.Read(h[:])
hasherPool.Put(d)
return h
}
25 changes: 20 additions & 5 deletions eth/protocols/snap/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -2672,10 +2672,15 @@ func (s *Syncer) onByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) error

// Cross reference the requested bytecodes with the response to find gaps
// that the serving node is missing
hasher := crypto.NewKeccakState()
hash := make([]byte, 32)

codes := make([][]byte, len(req.hashes))
for i, j := 0, 0; i < len(bytecodes); i++ {
// Find the next hash that we've been served, leaving misses with nils
hash := crypto.Keccak256(bytecodes[i])
hasher.Reset()
hasher.Write(bytecodes[i])
hasher.Read(hash)

for j < len(req.hashes) && !bytes.Equal(hash, req.hashes[j][:]) {
j++
Expand Down Expand Up @@ -2915,12 +2920,16 @@ func (s *Syncer) OnTrieNodes(peer SyncPeer, id uint64, trienodes [][]byte) error
// Cross reference the requested trienodes with the response to find gaps
// that the serving node is missing
var (
nodes = make([][]byte, len(req.hashes))
fills uint64
hasher = crypto.NewKeccakState()
hash = make([]byte, 32)
nodes = make([][]byte, len(req.hashes))
fills uint64
)
for i, j := 0, 0; i < len(trienodes); i++ {
// Find the next hash that we've been served, leaving misses with nils
hash := crypto.Keccak256(trienodes[i])
hasher.Reset()
hasher.Write(trienodes[i])
hasher.Read(hash)

for j < len(req.hashes) && !bytes.Equal(hash, req.hashes[j][:]) {
j++
Expand Down Expand Up @@ -3017,10 +3026,16 @@ func (s *Syncer) onHealByteCodes(peer SyncPeer, id uint64, bytecodes [][]byte) e

// Cross reference the requested bytecodes with the response to find gaps
// that the serving node is missing
hasher := crypto.NewKeccakState()
hash := make([]byte, 32)

codes := make([][]byte, len(req.hashes))
for i, j := 0, 0; i < len(bytecodes); i++ {
// Find the next hash that we've been served, leaving misses with nils
hash := crypto.Keccak256(bytecodes[i])
hasher.Reset()
hasher.Write(bytecodes[i])
hasher.Read(hash)

for j < len(req.hashes) && !bytes.Equal(hash, req.hashes[j][:]) {
j++
}
Expand Down
Loading
Loading