mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 07:37:20 +00:00
common/bitutil: deprecate XORBytes in favor of stdlib crypto/subtle (#33331)
XORBytes was added to package crypto/subtle in Go 1.20, and it's faster than our bitutil.XORBytes. There is only one use of this function across go-ethereum so we can simply deprecate the custom implementation. --------- Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
parent
af47d9b472
commit
31f9c9ff75
3 changed files with 26 additions and 43 deletions
|
|
@ -8,6 +8,7 @@
|
||||||
package bitutil
|
package bitutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/subtle"
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
@ -17,46 +18,16 @@ const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" |
|
||||||
|
|
||||||
// XORBytes xors the bytes in a and b. The destination is assumed to have enough
|
// XORBytes xors the bytes in a and b. The destination is assumed to have enough
|
||||||
// space. Returns the number of bytes xor'd.
|
// space. Returns the number of bytes xor'd.
|
||||||
|
//
|
||||||
|
// If dst does not have length at least n,
|
||||||
|
// XORBytes panics without writing anything to dst.
|
||||||
|
//
|
||||||
|
// dst and x or y may overlap exactly or not at all,
|
||||||
|
// otherwise XORBytes may panic.
|
||||||
|
//
|
||||||
|
// Deprecated: use crypto/subtle.XORBytes
|
||||||
func XORBytes(dst, a, b []byte) int {
|
func XORBytes(dst, a, b []byte) int {
|
||||||
if supportsUnaligned {
|
return subtle.XORBytes(dst, a, b)
|
||||||
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 := len(a)
|
|
||||||
if len(b) < n {
|
|
||||||
n = len(b)
|
|
||||||
}
|
|
||||||
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 := len(a)
|
|
||||||
if len(b) < n {
|
|
||||||
n = len(b)
|
|
||||||
}
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
dst[i] = a[i] ^ b[i]
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ANDBytes ands the bytes in a and b. The destination is assumed to have enough
|
// ANDBytes ands the bytes in a and b. The destination is assumed to have enough
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ func TestXOR(t *testing.T) {
|
||||||
d2 := make([]byte, 1023+alignD)[alignD:]
|
d2 := make([]byte, 1023+alignD)[alignD:]
|
||||||
|
|
||||||
XORBytes(d1, p, q)
|
XORBytes(d1, p, q)
|
||||||
safeXORBytes(d2, p, q)
|
naiveXOR(d2, p, q)
|
||||||
if !bytes.Equal(d1, d2) {
|
if !bytes.Equal(d1, d2) {
|
||||||
t.Error("not equal", d1, d2)
|
t.Error("not equal", d1, d2)
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +38,18 @@ func TestXOR(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// naiveXOR xors bytes one by one.
|
||||||
|
func naiveXOR(dst, a, b []byte) int {
|
||||||
|
n := len(a)
|
||||||
|
if len(b) < n {
|
||||||
|
n = len(b)
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
dst[i] = a[i] ^ b[i]
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that bitwise AND works for various alignments.
|
// Tests that bitwise AND works for various alignments.
|
||||||
func TestAND(t *testing.T) {
|
func TestAND(t *testing.T) {
|
||||||
for alignP := 0; alignP < 2; alignP++ {
|
for alignP := 0; alignP < 2; alignP++ {
|
||||||
|
|
@ -134,7 +146,7 @@ func benchmarkBaseXOR(b *testing.B, size int) {
|
||||||
p, q := make([]byte, size), make([]byte, size)
|
p, q := make([]byte, size), make([]byte, size)
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
safeXORBytes(p, p, q)
|
naiveXOR(p, p, q)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"crypto/subtle"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -33,7 +34,6 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/bitutil"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/ecies"
|
"github.com/ethereum/go-ethereum/crypto/ecies"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
@ -677,6 +677,6 @@ func exportPubkey(pub *ecies.PublicKey) []byte {
|
||||||
|
|
||||||
func xor(one, other []byte) (xor []byte) {
|
func xor(one, other []byte) (xor []byte) {
|
||||||
xor = make([]byte, len(one))
|
xor = make([]byte, len(one))
|
||||||
bitutil.XORBytes(xor, one, other)
|
subtle.XORBytes(xor, one, other)
|
||||||
return xor
|
return xor
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue