diff --git a/common/bitutil/bitutil.go b/common/bitutil/bitutil.go index dd0b9c28b69..0da339616c7 100644 --- a/common/bitutil/bitutil.go +++ b/common/bitutil/bitutil.go @@ -8,6 +8,7 @@ package bitutil import ( + "crypto/subtle" "runtime" "unsafe" ) @@ -15,42 +16,15 @@ import ( const wordSize = int(unsafe.Sizeof(uintptr(0))) const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x" -// XORBytes xors the bytes in a and b. The destination is assumed to have enough -// space. Returns the number of bytes xor'd. +// XORBytes xors the bytes in a and b and writes the result into dst. +// The number of bytes XORed is min(len(a), len(b)), and that value is returned. +// +// dst must have length >= min(len(a), len(b)) or the function will panic. +// dst may exactly overlap with a or with b, but partial overlaps are not allowed. +// +// Deprecated: use crypto/subtle.XORBytes. func XORBytes(dst, a, b []byte) int { - if supportsUnaligned { - return fastXORBytes(dst, a, b) - } - return safeXORBytes(dst, a, b) -} - -// fastXORBytes xors in bulk. It only works on architectures that support -// unaligned read/writes. -func fastXORBytes(dst, a, b []byte) int { - n := min(len(b), len(a)) - w := n / wordSize - if w > 0 { - dw := *(*[]uintptr)(unsafe.Pointer(&dst)) - aw := *(*[]uintptr)(unsafe.Pointer(&a)) - bw := *(*[]uintptr)(unsafe.Pointer(&b)) - for i := 0; i < w; i++ { - dw[i] = aw[i] ^ bw[i] - } - } - for i := n - n%wordSize; i < n; i++ { - dst[i] = a[i] ^ b[i] - } - return n -} - -// safeXORBytes xors one by one. It works on all architectures, independent if -// it supports unaligned read/writes or not. -func safeXORBytes(dst, a, b []byte) int { - n := min(len(b), len(a)) - for i := 0; i < n; i++ { - dst[i] = a[i] ^ b[i] - } - return n + return subtle.XORBytes(dst, a, b) } // ANDBytes ands the bytes in a and b. The destination is assumed to have enough diff --git a/common/bitutil/bitutil_test.go b/common/bitutil/bitutil_test.go index 94bd3ec3b47..c2945c5a8d3 100644 --- a/common/bitutil/bitutil_test.go +++ b/common/bitutil/bitutil_test.go @@ -29,7 +29,7 @@ func TestXOR(t *testing.T) { d2 := make([]byte, 1023+alignD)[alignD:] XORBytes(d1, p, q) - safeXORBytes(d2, p, q) + naiveXOR(d2, p, q) if !bytes.Equal(d1, d2) { t.Error("not equal", d1, d2) } @@ -38,6 +38,15 @@ func TestXOR(t *testing.T) { } } +// naiveXOR xors bytes one by one. +func naiveXOR(dst, a, b []byte) int { + n := min(len(b), len(a)) + for i := range n { + dst[i] = a[i] ^ b[i] + } + return n +} + // Tests that bitwise AND works for various alignments. func TestAND(t *testing.T) { for alignP := 0; alignP < 2; alignP++ { @@ -136,7 +145,7 @@ func benchmarkBaseXOR(b *testing.B, size int) { p, q := make([]byte, size), make([]byte, size) for i := 0; i < b.N; i++ { - safeXORBytes(p, p, q) + naiveXOR(p, p, q) } } diff --git a/execution/protocol/rules/ethash/algorithm.go b/execution/protocol/rules/ethash/algorithm.go index 2a8ec53e3e5..5191c851913 100644 --- a/execution/protocol/rules/ethash/algorithm.go +++ b/execution/protocol/rules/ethash/algorithm.go @@ -20,6 +20,7 @@ package ethash import ( + "crypto/subtle" "encoding/binary" "hash" "math/big" @@ -33,7 +34,6 @@ import ( "golang.org/x/crypto/sha3" "github.com/erigontech/erigon/common" - "github.com/erigontech/erigon/common/bitutil" "github.com/erigontech/erigon/common/crypto" "github.com/erigontech/erigon/common/dbg" "github.com/erigontech/erigon/common/length" @@ -239,7 +239,7 @@ func generateCache(dest []uint32, epoch uint64, seed []byte) { dstOff = j * hashBytes xorOff = (binary.LittleEndian.Uint32(cache[dstOff:]) % uint32(rows)) * hashBytes ) - bitutil.XORBytes(temp, cache[srcOff:srcOff+hashBytes], cache[xorOff:xorOff+hashBytes]) + subtle.XORBytes(temp, cache[srcOff:srcOff+hashBytes], cache[xorOff:xorOff+hashBytes]) keccak512(cache[dstOff:], temp) atomic.AddUint32(&progress, 1)