go-ethereum/crypto/keccak/keccak_arm64.go
2026-04-08 08:58:00 +05:30

109 lines
No EOL
2.5 KiB
Go

//go:build arm64 && !purego
package keccak
import (
"runtime"
"golang.org/x/crypto/sha3"
"golang.org/x/sys/cpu"
)
// Apple Silicon always has Armv8.2-A SHA3 extensions (VEOR3, VRAX1, VXAR, VBCAX).
// On other ARM64 platforms, detect at runtime via CPU feature flags.
// When SHA3 is unavailable, falls back to x/crypto/sha3.
var useSHA3 = runtime.GOOS == "darwin" || runtime.GOOS == "ios" || cpu.ARM64.HasSHA3
//go:noescape
func keccakF1600(a *[200]byte)
//go:noescape
func xorAndPermute(state *[200]byte, buf *byte)
// Sum256 computes the Keccak-256 hash of data. Zero heap allocations when SHA3 is available.
func Sum256(data []byte) [32]byte {
if !useSHA3 {
return sum256XCrypto(data)
}
return sum256Sponge(data)
}
func sum256XCrypto(data []byte) [32]byte {
h := sha3.NewLegacyKeccak256()
h.Write(data)
var out [32]byte
h.Sum(out[:0])
return out
}
// Hasher is a streaming Keccak-256 hasher.
// Uses NEON SHA3 assembly when available, x/crypto/sha3 otherwise.
type Hasher struct {
sponge
xc KeccakState // x/crypto fallback
}
// Reset resets the hasher to its initial state.
func (h *Hasher) Reset() {
if useSHA3 {
h.sponge.Reset()
} else {
if h.xc == nil {
h.xc = sha3.NewLegacyKeccak256().(KeccakState)
} else {
h.xc.Reset()
}
}
}
// Write absorbs data into the hasher.
// Panics if called after Read.
func (h *Hasher) Write(p []byte) (int, error) {
if !useSHA3 {
if h.xc == nil {
h.xc = sha3.NewLegacyKeccak256().(KeccakState)
}
return h.xc.Write(p)
}
return h.sponge.Write(p)
}
// Sum256 finalizes and returns the 32-byte Keccak-256 digest.
// Does not modify the hasher state.
func (h *Hasher) Sum256() [32]byte {
if !useSHA3 {
if h.xc == nil {
return Sum256(nil)
}
var out [32]byte
h.xc.Sum(out[:0])
return out
}
return h.sponge.Sum256()
}
// Sum appends the current Keccak-256 digest to b and returns the resulting slice.
// Does not modify the hasher state.
func (h *Hasher) Sum(b []byte) []byte {
if !useSHA3 {
if h.xc == nil {
d := Sum256(nil)
return append(b, d[:]...)
}
return h.xc.Sum(b)
}
return h.sponge.Sum(b)
}
// Read squeezes an arbitrary number of bytes from the sponge.
// On the first call, it pads and permutes, transitioning from absorbing to squeezing.
// Subsequent calls to Write will panic. It never returns an error.
func (h *Hasher) Read(out []byte) (int, error) {
if !useSHA3 {
if h.xc == nil {
h.xc = sha3.NewLegacyKeccak256().(KeccakState)
}
return h.xc.Read(out)
}
return h.sponge.Read(out)
}