Skip to content

Commit 88abee0

Browse files
Giulio2002AskAlexSharovyperbasisCopilotSharovBot
authored
Performance: use NEON accelerated keccak (#19092)
Switch to https://github.com/erigontech/fastkeccak --------- Co-authored-by: Alex Sharov <AskAlexSharov@gmail.com> Co-authored-by: yperbasis <andrey.ashikhmin@gmail.com> Co-authored-by: Andrew Ashikhmin <34320705+yperbasis@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: SharovBot <sharovbot@erigon.tech> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 523b9e6 commit 88abee0

35 files changed

+115
-139
lines changed

common/address.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"fmt"
2424
"math/big"
2525

26-
"golang.org/x/crypto/sha3"
26+
keccak "github.com/erigontech/fastkeccak"
2727

2828
"github.com/erigontech/erigon/common/hexutil"
2929
"github.com/erigontech/erigon/common/length"
@@ -77,7 +77,7 @@ func (a *Address) checksumHex() []byte {
7777
buf := a.hex()
7878

7979
// compute checksum
80-
sha := sha3.NewLegacyKeccak256()
80+
sha := keccak.NewFastKeccak()
8181
//nolint:errcheck
8282
sha.Write(buf[2:])
8383
hash := sha.Sum(nil)

common/crypto/crypto.go

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ import (
2727
"encoding/hex"
2828
"errors"
2929
"fmt"
30-
"hash"
3130
"io"
3231
"math/big"
3332
"os"
3433
"sync"
3534

35+
keccak "github.com/erigontech/fastkeccak"
3636
"github.com/holiman/uint256"
3737
"golang.org/x/crypto/sha3"
3838

@@ -67,16 +67,8 @@ type EllipticCurve interface {
6767
Unmarshal(data []byte) (x, y *big.Int)
6868
}
6969

70-
// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports
71-
// Read to get a variable amount of data from the hash state. Read is faster than Sum
72-
// because it doesn't copy the internal state, but also modifies the internal state.
73-
type KeccakState interface {
74-
hash.Hash
75-
Read([]byte) (int, error)
76-
}
77-
7870
// HashData hashes the provided data using the KeccakState and returns a 32 byte hash
79-
func HashData(kh KeccakState, data []byte) (h common.Hash) {
71+
func HashData(kh keccak.KeccakState, data []byte) (h common.Hash) {
8072
kh.Reset()
8173
//nolint:errcheck
8274
kh.Write(data)
@@ -325,14 +317,14 @@ func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
325317
// hasherPool holds LegacyKeccak hashers.
326318
var hasherPool = sync.Pool{
327319
New: func() any {
328-
return sha3.NewLegacyKeccak256()
320+
return keccak.NewFastKeccak()
329321
},
330322
}
331323

332324
// NewKeccakState creates a new KeccakState
333-
func NewKeccakState() KeccakState {
334-
h := hasherPool.Get().(KeccakState)
325+
func NewKeccakState() keccak.KeccakState {
326+
h := hasherPool.Get().(keccak.KeccakState)
335327
h.Reset()
336328
return h
337329
}
338-
func ReturnToPool(h KeccakState) { hasherPool.Put(h) }
330+
func ReturnToPool(h keccak.KeccakState) { hasherPool.Put(h) }

common/hasher.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,18 @@
1717
package common
1818

1919
import (
20-
"hash"
2120
"sync"
2221

23-
"golang.org/x/crypto/sha3"
22+
keccak "github.com/erigontech/fastkeccak"
2423
)
2524

26-
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
27-
// Read to get a variable amount of data from the hash state. Read is faster than Sum
28-
// because it doesn't copy the internal state, but also modifies the internal state.
29-
type keccakState interface {
30-
hash.Hash
31-
Read([]byte) (int, error)
32-
}
33-
3425
type Hasher struct {
35-
Sha keccakState
26+
Sha keccak.KeccakState
3627
}
3728

3829
var hashersPool = sync.Pool{
3930
New: func() any {
40-
return &Hasher{Sha: sha3.NewLegacyKeccak256().(keccakState)}
31+
return &Hasher{Sha: keccak.NewFastKeccak()}
4132
},
4233
}
4334

db/kv/kvcache/cache.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ import (
2929
"time"
3030

3131
"github.com/c2h5oh/datasize"
32+
keccak "github.com/erigontech/fastkeccak"
3233
btree2 "github.com/tidwall/btree"
33-
"golang.org/x/crypto/sha3"
3434

3535
"github.com/erigontech/erigon/common"
3636
"github.com/erigontech/erigon/db/kv"
@@ -198,7 +198,7 @@ func New(cfg CoherentConfig) *Coherent {
198198
roots: map[uint64]*CoherentRoot{},
199199
stateEvict: &ThreadSafeEvictionList{l: NewList()},
200200
codeEvict: &ThreadSafeEvictionList{l: NewList()},
201-
hasher: sha3.NewLegacyKeccak256(),
201+
hasher: keccak.NewFastKeccak(),
202202
cfg: cfg,
203203
miss: metrics.GetOrCreateCounter(fmt.Sprintf(`cache_total{result="miss",name="%s"}`, cfg.MetricsLabel)),
204204
hits: metrics.GetOrCreateCounter(fmt.Sprintf(`cache_total{result="hit",name="%s"}`, cfg.MetricsLabel)),

db/kv/kvcache/cache_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ import (
2525
"testing"
2626
"time"
2727

28+
keccak "github.com/erigontech/fastkeccak"
2829
"github.com/holiman/uint256"
2930
"github.com/stretchr/testify/require"
30-
"golang.org/x/crypto/sha3"
3131

3232
"github.com/erigontech/erigon/common"
3333
"github.com/erigontech/erigon/common/log/v3"
@@ -509,7 +509,7 @@ func TestOnNewBlockCodeHashKey(t *testing.T) {
509509

510510
require.Len(elems, 1)
511511

512-
h := sha3.NewLegacyKeccak256()
512+
h := keccak.NewFastKeccak()
513513
h.Write(code)
514514
expectedKey := h.Sum(nil)
515515

db/rawdb/accessors_chain_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ import (
2525
"math/big"
2626
"testing"
2727

28+
keccak "github.com/erigontech/fastkeccak"
2829
"github.com/holiman/uint256"
2930
"github.com/stretchr/testify/require"
30-
"golang.org/x/crypto/sha3"
3131

3232
"github.com/erigontech/erigon/common"
3333
"github.com/erigontech/erigon/common/crypto"
@@ -349,7 +349,7 @@ func TestHeaderStorage(t *testing.T) {
349349
if entry := rawdb.ReadHeaderRLP(tx, header.Hash(), header.Number.Uint64()); entry == nil {
350350
t.Fatalf("Stored header RLP not found")
351351
} else {
352-
hasher := sha3.NewLegacyKeccak256()
352+
hasher := keccak.NewFastKeccak()
353353
hasher.Write(entry)
354354

355355
if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() {
@@ -397,7 +397,7 @@ func TestBodyStorage(t *testing.T) {
397397
}
398398

399399
// Create a test body to move around the database and make sure it's really new
400-
hasher := sha3.NewLegacyKeccak256()
400+
hasher := keccak.NewFastKeccak()
401401
_ = rlp.Encode(hasher, body)
402402
hash := common.BytesToHash(hasher.Sum(nil))
403403
header := &types.Header{Number: *common.Num1}
@@ -421,7 +421,7 @@ func TestBodyStorage(t *testing.T) {
421421
if err != nil {
422422
log.Error("ReadBodyRLP failed", "err", err)
423423
}
424-
hasher := sha3.NewLegacyKeccak256()
424+
hasher := keccak.NewFastKeccak()
425425
hasher.Write(bodyRlp)
426426

427427
if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash {

db/snaptype2/headers_freezer.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"runtime"
88
"time"
99

10+
keccak "github.com/erigontech/fastkeccak"
11+
1012
"github.com/erigontech/erigon/common"
1113
"github.com/erigontech/erigon/common/crypto"
1214
"github.com/erigontech/erigon/common/dbg"
@@ -90,7 +92,7 @@ func (f *HeaderFreezer) Freeze(ctx context.Context, blockFrom, blockTo state.Roo
9092
var _ state.IndexKeyFactory = (*HeaderAccessorIndexKeyFactory)(nil)
9193

9294
type HeaderAccessorIndexKeyFactory struct {
93-
s crypto.KeccakState
95+
s keccak.KeccakState
9496
h common.Hash
9597
}
9698

execution/commitment/bin_patricia_hashed.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ package commitment
9999
//
100100
//func NewBinPatriciaHashed(accountKeyLen int, ctx PatriciaContext, tmpdir string) *BinPatriciaHashed {
101101
// bph := &BinPatriciaHashed{
102-
// keccak: sha3.NewLegacyKeccak256().(keccakState),
103-
// keccak2: sha3.NewLegacyKeccak256().(keccakState),
102+
// keccak: keccak.NewFastKeccak(),
103+
// keccak2: keccak.NewFastKeccak(),
104104
// accountKeyLen: accountKeyLen,
105105
// accountFn: wrapAccountStorageFn(ctx.GetAccount),
106106
// storageFn: wrapAccountStorageFn(ctx.GetStorage),

execution/commitment/commitment.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ import (
3030
"sync/atomic"
3131
"unsafe"
3232

33+
keccak "github.com/erigontech/fastkeccak"
3334
"github.com/google/btree"
3435
"github.com/holiman/uint256"
35-
"golang.org/x/crypto/sha3"
3636

3737
"github.com/erigontech/erigon/common"
3838
"github.com/erigontech/erigon/common/crypto"
@@ -1106,7 +1106,7 @@ func (branchData BranchData) Validate(branchKey []byte) error {
11061106
if err = validateAfterMap(afterMap, row); err != nil {
11071107
return err
11081108
}
1109-
if err = validatePlainKeys(branchKey, row, sha3.NewLegacyKeccak256().(keccakState)); err != nil {
1109+
if err = validatePlainKeys(branchKey, row, keccak.NewFastKeccak()); err != nil {
11101110
return err
11111111
}
11121112
return nil
@@ -1126,7 +1126,7 @@ func validateAfterMap(afterMap uint16, row [16]*cell) error {
11261126
return nil
11271127
}
11281128

1129-
func validatePlainKeys(branchKey []byte, row [16]*cell, keccak keccakState) error {
1129+
func validatePlainKeys(branchKey []byte, row [16]*cell, keccak keccak.KeccakState) error {
11301130
uncompactedBranchKey := uncompactNibbles(branchKey)
11311131
if HasTerm(uncompactedBranchKey) {
11321132
uncompactedBranchKey = uncompactedBranchKey[:len(uncompactedBranchKey)-1]

execution/commitment/hex_patricia_hashed.go

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"encoding/hex"
2424
"errors"
2525
"fmt"
26-
"hash"
2726
"io"
2827
"math/bits"
2928
"runtime"
@@ -32,7 +31,7 @@ import (
3231
"sync/atomic"
3332
"time"
3433

35-
"golang.org/x/crypto/sha3"
34+
keccak "github.com/erigontech/fastkeccak"
3635

3736
"github.com/erigontech/erigon/common"
3837
"github.com/erigontech/erigon/common/crypto"
@@ -48,14 +47,6 @@ import (
4847
"github.com/erigontech/erigon/execution/types/accounts"
4948
)
5049

51-
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
52-
// Read to get a variable amount of data from the hash state. Read is faster than Sum
53-
// because it doesn't copy the internal state, but also modifies the internal state.
54-
type keccakState interface {
55-
hash.Hash
56-
Read([]byte) (int, error)
57-
}
58-
5950
// DomainPutter is an interface for putting data into domains.
6051
// Used by commitment to write branch data.
6152
type DomainPutter = stateifs.DomainPutter
@@ -82,8 +73,8 @@ type HexPatriciaHashed struct {
8273
branchBefore [128]bool // For each row, whether there was a branch node in the database loaded in unfold
8374
touchMap [128]uint16 // For each row, bitmap of cells that were either present before modification, or modified or deleted
8475
afterMap [128]uint16 // For each row, bitmap of cells that were present after modification
85-
keccak keccakState
86-
keccak2 keccakState
76+
keccak keccak.KeccakState
77+
keccak2 keccak.KeccakState
8778
rootChecked bool // Set to false if it is not known whether the root is empty, set to true if it is checked
8879
rootTouched bool
8980
rootPresent bool
@@ -133,8 +124,8 @@ func (hph *HexPatriciaHashed) SpawnSubTrie(ctx PatriciaContext, forNibble int) *
133124
func NewHexPatriciaHashed(accountKeyLen int16, ctx PatriciaContext) *HexPatriciaHashed {
134125
hph := &HexPatriciaHashed{
135126
ctx: ctx,
136-
keccak: sha3.NewLegacyKeccak256().(keccakState),
137-
keccak2: sha3.NewLegacyKeccak256().(keccakState),
127+
keccak: keccak.NewFastKeccak(),
128+
keccak2: keccak.NewFastKeccak(),
138129
accountKeyLen: accountKeyLen,
139130
auxBuffer: bytes.NewBuffer(make([]byte, 8192)),
140131
hadToLoadL: make(map[uint64]skipStat),
@@ -207,11 +198,11 @@ var (
207198
emptyRootHashBytes = empty.RootHash.Bytes()
208199
)
209200

210-
func (cell *cell) hashAccKey(keccak keccakState, depth int16, hashBuf []byte) error {
201+
func (cell *cell) hashAccKey(keccak keccak.KeccakState, depth int16, hashBuf []byte) error {
211202
return hashKey(keccak, cell.accountAddr[:cell.accountAddrLen], cell.hashedExtension[:], depth, hashBuf)
212203
}
213204

214-
func (cell *cell) hashStorageKey(keccak keccakState, accountKeyLen, downOffset int16, hashedKeyOffset int16, hashBuf []byte) error {
205+
func (cell *cell) hashStorageKey(keccak keccak.KeccakState, accountKeyLen, downOffset int16, hashedKeyOffset int16, hashBuf []byte) error {
215206
return hashKey(keccak, cell.storageAddr[accountKeyLen:cell.storageAddrLen], cell.hashedExtension[downOffset:], hashedKeyOffset, hashBuf)
216207
}
217208

@@ -376,7 +367,7 @@ func (cell *cell) fillFromLowerCell(lowCell *cell, lowDepth int16, preExtension
376367
cell.loaded = lowCell.loaded
377368
}
378369

379-
func (cell *cell) deriveHashedKeys(depth int16, keccak keccakState, accountKeyLen int16, hashBuf []byte) error {
370+
func (cell *cell) deriveHashedKeys(depth int16, keccak keccak.KeccakState, accountKeyLen int16, hashBuf []byte) error {
380371
extraLen := int16(0)
381372
if cell.accountAddrLen > 0 {
382373
if depth > 64 {

0 commit comments

Comments
 (0)