From b80ffe98a5451eb040d320550414d0888930a8d9 Mon Sep 17 00:00:00 2001 From: Sahil-4555 Date: Tue, 13 Jan 2026 10:43:26 +0530 Subject: [PATCH] Revert "rm bitutil xorbytes helper func" This reverts commit 121c43075e7ae11272a39d4bdcd635ff05c48085. --- common/bitutil/bitutil.go | 14 ++++++++ common/bitutil/bitutil_test.go | 65 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/common/bitutil/bitutil.go b/common/bitutil/bitutil.go index 99a8c2ee18..578da1cf49 100644 --- a/common/bitutil/bitutil.go +++ b/common/bitutil/bitutil.go @@ -8,6 +8,7 @@ package bitutil import ( + "crypto/subtle" "runtime" "unsafe" ) @@ -15,6 +16,19 @@ 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. +// +// 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 { + return subtle.XORBytes(dst, a, b) +} // ANDBytes ands the bytes in a and b. The destination is assumed to have enough // space. Returns the number of bytes and'd. diff --git a/common/bitutil/bitutil_test.go b/common/bitutil/bitutil_test.go index 0cad12bda7..1748029794 100644 --- a/common/bitutil/bitutil_test.go +++ b/common/bitutil/bitutil_test.go @@ -11,6 +11,45 @@ import ( "testing" ) +// Tests that bitwise XOR works for various alignments. +func TestXOR(t *testing.T) { + for alignP := 0; alignP < 2; alignP++ { + for alignQ := 0; alignQ < 2; alignQ++ { + for alignD := 0; alignD < 2; alignD++ { + p := make([]byte, 1023)[alignP:] + q := make([]byte, 1023)[alignQ:] + + for i := 0; i < len(p); i++ { + p[i] = byte(i) + } + for i := 0; i < len(q); i++ { + q[i] = byte(len(q) - i) + } + d1 := make([]byte, 1023+alignD)[alignD:] + d2 := make([]byte, 1023+alignD)[alignD:] + + XORBytes(d1, p, q) + naiveXOR(d2, p, q) + if !bytes.Equal(d1, d2) { + t.Error("not equal", d1, d2) + } + } + } + } +} + +// 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. func TestAND(t *testing.T) { for alignP := 0; alignP < 2; alignP++ { @@ -85,6 +124,32 @@ func TestTest(t *testing.T) { } } +// Benchmarks the potentially optimized XOR performance. +func BenchmarkFastXOR1KB(b *testing.B) { benchmarkFastXOR(b, 1024) } +func BenchmarkFastXOR2KB(b *testing.B) { benchmarkFastXOR(b, 2048) } +func BenchmarkFastXOR4KB(b *testing.B) { benchmarkFastXOR(b, 4096) } + +func benchmarkFastXOR(b *testing.B, size int) { + p, q := make([]byte, size), make([]byte, size) + + for i := 0; i < b.N; i++ { + XORBytes(p, p, q) + } +} + +// Benchmarks the baseline XOR performance. +func BenchmarkBaseXOR1KB(b *testing.B) { benchmarkBaseXOR(b, 1024) } +func BenchmarkBaseXOR2KB(b *testing.B) { benchmarkBaseXOR(b, 2048) } +func BenchmarkBaseXOR4KB(b *testing.B) { benchmarkBaseXOR(b, 4096) } + +func benchmarkBaseXOR(b *testing.B, size int) { + p, q := make([]byte, size), make([]byte, size) + + for i := 0; i < b.N; i++ { + naiveXOR(p, p, q) + } +} + // Benchmarks the potentially optimized AND performance. func BenchmarkFastAND1KB(b *testing.B) { benchmarkFastAND(b, 1024) } func BenchmarkFastAND2KB(b *testing.B) { benchmarkFastAND(b, 2048) }