aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/cipher
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2022-08-05 13:34:29 -0400
committerGopher Robot <gobot@golang.org>2022-08-17 18:47:33 +0000
commit57d05512feebed4fbe1e7a19305c8722a4ac627f (patch)
treed76190998eba10aa0750666a99a5ebfa4eb8e35b /src/crypto/cipher
parent90466e1ddf0e4305bc56f6eac61a690704e6fab8 (diff)
downloadgo-57d05512feebed4fbe1e7a19305c8722a4ac627f.tar.xz
crypto/subtle: add XORBytes
Export cipher.xorBytes as subtle.XORBytes, for proposal #53021, to provide fast XOR to cryptography libraries outside crypto/cipher. Along with the move, implement the alignment check TODO in xor_generic.go, so that systems with neither unaligned accesses nor custom assembly can still XOR a word at a time in word-based algorithms like GCM. This removes the need for the separate cipher.xorWords. Fixes #53021. Change-Id: I58f80a922f1cff671b5ebc6168eb046e702b5a4c Reviewed-on: https://go-review.googlesource.com/c/go/+/421435 TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Alan Donovan <adonovan@google.com> Reviewed-by: Filippo Valsorda <filippo@golang.org>
Diffstat (limited to 'src/crypto/cipher')
-rw-r--r--src/crypto/cipher/cbc.go11
-rw-r--r--src/crypto/cipher/cfb.go7
-rw-r--r--src/crypto/cipher/ctr.go7
-rw-r--r--src/crypto/cipher/export_test.go1
-rw-r--r--src/crypto/cipher/gcm.go6
-rw-r--r--src/crypto/cipher/ofb.go7
-rw-r--r--src/crypto/cipher/xor_amd64.go27
-rw-r--r--src/crypto/cipher/xor_amd64.s54
-rw-r--r--src/crypto/cipher/xor_arm64.go29
-rw-r--r--src/crypto/cipher/xor_arm64.s67
-rw-r--r--src/crypto/cipher/xor_generic.go91
-rw-r--r--src/crypto/cipher/xor_ppc64x.go29
-rw-r--r--src/crypto/cipher/xor_ppc64x.s87
-rw-r--r--src/crypto/cipher/xor_test.go75
14 files changed, 25 insertions, 473 deletions
diff --git a/src/crypto/cipher/cbc.go b/src/crypto/cipher/cbc.go
index 1ce165e791..fe774c116e 100644
--- a/src/crypto/cipher/cbc.go
+++ b/src/crypto/cipher/cbc.go
@@ -11,7 +11,10 @@
package cipher
-import "crypto/internal/alias"
+import (
+ "crypto/internal/alias"
+ "crypto/subtle"
+)
type cbc struct {
b Block
@@ -80,7 +83,7 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
for len(src) > 0 {
// Write the xor to dst, then encrypt in place.
- xorBytes(dst[:x.blockSize], src[:x.blockSize], iv)
+ subtle.XORBytes(dst[:x.blockSize], src[:x.blockSize], iv)
x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize])
// Move to the next block with this block as the next iv.
@@ -162,7 +165,7 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
// Loop over all but the first block.
for start > 0 {
x.b.Decrypt(dst[start:end], src[start:end])
- xorBytes(dst[start:end], dst[start:end], src[prev:start])
+ subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start])
end = start
start = prev
@@ -171,7 +174,7 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
// The first block is special because it uses the saved iv.
x.b.Decrypt(dst[start:end], src[start:end])
- xorBytes(dst[start:end], dst[start:end], x.iv)
+ subtle.XORBytes(dst[start:end], dst[start:end], x.iv)
// Set the new iv to the first block we copied earlier.
x.iv, x.tmp = x.tmp, x.iv
diff --git a/src/crypto/cipher/cfb.go b/src/crypto/cipher/cfb.go
index 33615b01d5..aae3575da1 100644
--- a/src/crypto/cipher/cfb.go
+++ b/src/crypto/cipher/cfb.go
@@ -6,7 +6,10 @@
package cipher
-import "crypto/internal/alias"
+import (
+ "crypto/internal/alias"
+ "crypto/subtle"
+)
type cfb struct {
b Block
@@ -37,7 +40,7 @@ func (x *cfb) XORKeyStream(dst, src []byte) {
// able to match CTR/OFB performance.
copy(x.next[x.outUsed:], src)
}
- n := xorBytes(dst, src, x.out[x.outUsed:])
+ n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
if !x.decrypt {
copy(x.next[x.outUsed:], dst)
}
diff --git a/src/crypto/cipher/ctr.go b/src/crypto/cipher/ctr.go
index 3b8e32a9a4..2b434ef832 100644
--- a/src/crypto/cipher/ctr.go
+++ b/src/crypto/cipher/ctr.go
@@ -12,7 +12,10 @@
package cipher
-import "crypto/internal/alias"
+import (
+ "crypto/internal/alias"
+ "crypto/subtle"
+)
type ctr struct {
b Block
@@ -83,7 +86,7 @@ func (x *ctr) XORKeyStream(dst, src []byte) {
if x.outUsed >= len(x.out)-x.b.BlockSize() {
x.refill()
}
- n := xorBytes(dst, src, x.out[x.outUsed:])
+ n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
dst = dst[n:]
src = src[n:]
x.outUsed += n
diff --git a/src/crypto/cipher/export_test.go b/src/crypto/cipher/export_test.go
index beb9bf5d23..5ecd67b28b 100644
--- a/src/crypto/cipher/export_test.go
+++ b/src/crypto/cipher/export_test.go
@@ -5,6 +5,5 @@
package cipher
// Export internal functions for testing.
-var XorBytes = xorBytes
var NewCBCGenericEncrypter = newCBCGenericEncrypter
var NewCBCGenericDecrypter = newCBCGenericDecrypter
diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go
index a23ebb1d90..477d26a0e0 100644
--- a/src/crypto/cipher/gcm.go
+++ b/src/crypto/cipher/gcm.go
@@ -373,7 +373,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
g.cipher.Encrypt(mask[:], counter[:])
gcmInc32(counter)
- xorWords(out, in, mask[:])
+ subtle.XORBytes(out, in, mask[:])
out = out[gcmBlockSize:]
in = in[gcmBlockSize:]
}
@@ -381,7 +381,7 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
if len(in) > 0 {
g.cipher.Encrypt(mask[:], counter[:])
gcmInc32(counter)
- xorBytes(out, in, mask[:])
+ subtle.XORBytes(out, in, mask[:])
}
}
@@ -423,5 +423,5 @@ func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]
binary.BigEndian.PutUint64(out, y.low)
binary.BigEndian.PutUint64(out[8:], y.high)
- xorWords(out, out, tagMask[:])
+ subtle.XORBytes(out, out, tagMask[:])
}
diff --git a/src/crypto/cipher/ofb.go b/src/crypto/cipher/ofb.go
index 64e34a9676..1195fdd45a 100644
--- a/src/crypto/cipher/ofb.go
+++ b/src/crypto/cipher/ofb.go
@@ -6,7 +6,10 @@
package cipher
-import "crypto/internal/alias"
+import (
+ "crypto/internal/alias"
+ "crypto/subtle"
+)
type ofb struct {
b Block
@@ -66,7 +69,7 @@ func (x *ofb) XORKeyStream(dst, src []byte) {
if x.outUsed >= len(x.out)-x.b.BlockSize() {
x.refill()
}
- n := xorBytes(dst, src, x.out[x.outUsed:])
+ n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
dst = dst[n:]
src = src[n:]
x.outUsed += n
diff --git a/src/crypto/cipher/xor_amd64.go b/src/crypto/cipher/xor_amd64.go
deleted file mode 100644
index a595acc017..0000000000
--- a/src/crypto/cipher/xor_amd64.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cipher
-
-// xorBytes xors the bytes in a and b. The destination should have enough
-// space, otherwise xorBytes will panic. Returns the number of bytes xor'd.
-func xorBytes(dst, a, b []byte) int {
- n := len(a)
- if len(b) < n {
- n = len(b)
- }
- if n == 0 {
- return 0
- }
- _ = dst[n-1]
- xorBytesSSE2(&dst[0], &a[0], &b[0], n) // amd64 must have SSE2
- return n
-}
-
-func xorWords(dst, a, b []byte) {
- xorBytes(dst, a, b)
-}
-
-//go:noescape
-func xorBytesSSE2(dst, a, b *byte, n int)
diff --git a/src/crypto/cipher/xor_amd64.s b/src/crypto/cipher/xor_amd64.s
deleted file mode 100644
index 780d37a06e..0000000000
--- a/src/crypto/cipher/xor_amd64.s
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "textflag.h"
-
-// func xorBytesSSE2(dst, a, b *byte, n int)
-TEXT ·xorBytesSSE2(SB), NOSPLIT, $0
- MOVQ dst+0(FP), BX
- MOVQ a+8(FP), SI
- MOVQ b+16(FP), CX
- MOVQ n+24(FP), DX
- TESTQ $15, DX // AND 15 & len, if not zero jump to not_aligned.
- JNZ not_aligned
-
-aligned:
- MOVQ $0, AX // position in slices
-
-loop16b:
- MOVOU (SI)(AX*1), X0 // XOR 16byte forwards.
- MOVOU (CX)(AX*1), X1
- PXOR X1, X0
- MOVOU X0, (BX)(AX*1)
- ADDQ $16, AX
- CMPQ DX, AX
- JNE loop16b
- RET
-
-loop_1b:
- SUBQ $1, DX // XOR 1byte backwards.
- MOVB (SI)(DX*1), DI
- MOVB (CX)(DX*1), AX
- XORB AX, DI
- MOVB DI, (BX)(DX*1)
- TESTQ $7, DX // AND 7 & len, if not zero jump to loop_1b.
- JNZ loop_1b
- CMPQ DX, $0 // if len is 0, ret.
- JE ret
- TESTQ $15, DX // AND 15 & len, if zero jump to aligned.
- JZ aligned
-
-not_aligned:
- TESTQ $7, DX // AND $7 & len, if not zero jump to loop_1b.
- JNE loop_1b
- SUBQ $8, DX // XOR 8bytes backwards.
- MOVQ (SI)(DX*1), DI
- MOVQ (CX)(DX*1), AX
- XORQ AX, DI
- MOVQ DI, (BX)(DX*1)
- CMPQ DX, $16 // if len is greater or equal 16 here, it must be aligned.
- JGE aligned
-
-ret:
- RET
diff --git a/src/crypto/cipher/xor_arm64.go b/src/crypto/cipher/xor_arm64.go
deleted file mode 100644
index 35a785a8a1..0000000000
--- a/src/crypto/cipher/xor_arm64.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cipher
-
-// xorBytes xors the bytes in a and b. The destination should have enough
-// space, otherwise xorBytes will panic. Returns the number of bytes xor'd.
-func xorBytes(dst, a, b []byte) int {
- n := len(a)
- if len(b) < n {
- n = len(b)
- }
- if n == 0 {
- return 0
- }
- // make sure dst has enough space
- _ = dst[n-1]
-
- xorBytesARM64(&dst[0], &a[0], &b[0], n)
- return n
-}
-
-func xorWords(dst, a, b []byte) {
- xorBytes(dst, a, b)
-}
-
-//go:noescape
-func xorBytesARM64(dst, a, b *byte, n int)
diff --git a/src/crypto/cipher/xor_arm64.s b/src/crypto/cipher/xor_arm64.s
deleted file mode 100644
index 669852d7eb..0000000000
--- a/src/crypto/cipher/xor_arm64.s
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "textflag.h"
-
-// func xorBytesARM64(dst, a, b *byte, n int)
-TEXT ·xorBytesARM64(SB), NOSPLIT|NOFRAME, $0
- MOVD dst+0(FP), R0
- MOVD a+8(FP), R1
- MOVD b+16(FP), R2
- MOVD n+24(FP), R3
- CMP $64, R3
- BLT tail
-loop_64:
- VLD1.P 64(R1), [V0.B16, V1.B16, V2.B16, V3.B16]
- VLD1.P 64(R2), [V4.B16, V5.B16, V6.B16, V7.B16]
- VEOR V0.B16, V4.B16, V4.B16
- VEOR V1.B16, V5.B16, V5.B16
- VEOR V2.B16, V6.B16, V6.B16
- VEOR V3.B16, V7.B16, V7.B16
- VST1.P [V4.B16, V5.B16, V6.B16, V7.B16], 64(R0)
- SUBS $64, R3
- CMP $64, R3
- BGE loop_64
-tail:
- // quick end
- CBZ R3, end
- TBZ $5, R3, less_than32
- VLD1.P 32(R1), [V0.B16, V1.B16]
- VLD1.P 32(R2), [V2.B16, V3.B16]
- VEOR V0.B16, V2.B16, V2.B16
- VEOR V1.B16, V3.B16, V3.B16
- VST1.P [V2.B16, V3.B16], 32(R0)
-less_than32:
- TBZ $4, R3, less_than16
- LDP.P 16(R1), (R11, R12)
- LDP.P 16(R2), (R13, R14)
- EOR R11, R13, R13
- EOR R12, R14, R14
- STP.P (R13, R14), 16(R0)
-less_than16:
- TBZ $3, R3, less_than8
- MOVD.P 8(R1), R11
- MOVD.P 8(R2), R12
- EOR R11, R12, R12
- MOVD.P R12, 8(R0)
-less_than8:
- TBZ $2, R3, less_than4
- MOVWU.P 4(R1), R13
- MOVWU.P 4(R2), R14
- EORW R13, R14, R14
- MOVWU.P R14, 4(R0)
-less_than4:
- TBZ $1, R3, less_than2
- MOVHU.P 2(R1), R15
- MOVHU.P 2(R2), R16
- EORW R15, R16, R16
- MOVHU.P R16, 2(R0)
-less_than2:
- TBZ $0, R3, end
- MOVBU (R1), R17
- MOVBU (R2), R19
- EORW R17, R19, R19
- MOVBU R19, (R0)
-end:
- RET
diff --git a/src/crypto/cipher/xor_generic.go b/src/crypto/cipher/xor_generic.go
deleted file mode 100644
index 43517a8e20..0000000000
--- a/src/crypto/cipher/xor_generic.go
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build !amd64 && !ppc64 && !ppc64le && !arm64
-
-package cipher
-
-import (
- "runtime"
- "unsafe"
-)
-
-// xorBytes xors the bytes in a and b. The destination should have enough
-// space, otherwise xorBytes will panic. Returns the number of bytes xor'd.
-func xorBytes(dst, a, b []byte) int {
- n := len(a)
- if len(b) < n {
- n = len(b)
- }
- if n == 0 {
- return 0
- }
-
- switch {
- case supportsUnaligned:
- fastXORBytes(dst, a, b, n)
- default:
- // TODO(hanwen): if (dst, a, b) have common alignment
- // we could still try fastXORBytes. It is not clear
- // how often this happens, and it's only worth it if
- // the block encryption itself is hardware
- // accelerated.
- safeXORBytes(dst, a, b, n)
- }
- return n
-}
-
-const wordSize = int(unsafe.Sizeof(uintptr(0)))
-const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x"
-
-// fastXORBytes xors in bulk. It only works on architectures that
-// support unaligned read/writes.
-// n needs to be smaller or equal than the length of a and b.
-func fastXORBytes(dst, a, b []byte, n int) {
- // Assert dst has enough space
- _ = dst[n-1]
-
- 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]
- }
-}
-
-// n needs to be smaller or equal than the length of a and b.
-func safeXORBytes(dst, a, b []byte, n int) {
- for i := 0; i < n; i++ {
- dst[i] = a[i] ^ b[i]
- }
-}
-
-// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
-// The arguments are assumed to be of equal length.
-func fastXORWords(dst, a, b []byte) {
- dw := *(*[]uintptr)(unsafe.Pointer(&dst))
- aw := *(*[]uintptr)(unsafe.Pointer(&a))
- bw := *(*[]uintptr)(unsafe.Pointer(&b))
- n := len(b) / wordSize
- for i := 0; i < n; i++ {
- dw[i] = aw[i] ^ bw[i]
- }
-}
-
-// fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
-// The slice arguments a and b are assumed to be of equal length.
-func xorWords(dst, a, b []byte) {
- if supportsUnaligned {
- fastXORWords(dst, a, b)
- } else {
- safeXORBytes(dst, a, b, len(b))
- }
-}
diff --git a/src/crypto/cipher/xor_ppc64x.go b/src/crypto/cipher/xor_ppc64x.go
deleted file mode 100644
index f81eec531d..0000000000
--- a/src/crypto/cipher/xor_ppc64x.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build ppc64 || ppc64le
-
-package cipher
-
-// xorBytes xors the bytes in a and b. The destination should have enough
-// space, otherwise xorBytes will panic. Returns the number of bytes xor'd.
-func xorBytes(dst, a, b []byte) int {
- n := len(a)
- if len(b) < n {
- n = len(b)
- }
- if n == 0 {
- return 0
- }
- _ = dst[n-1]
- xorBytesVSX(&dst[0], &a[0], &b[0], n)
- return n
-}
-
-func xorWords(dst, a, b []byte) {
- xorBytes(dst, a, b)
-}
-
-//go:noescape
-func xorBytesVSX(dst, a, b *byte, n int)
diff --git a/src/crypto/cipher/xor_ppc64x.s b/src/crypto/cipher/xor_ppc64x.s
deleted file mode 100644
index a2ec95c0be..0000000000
--- a/src/crypto/cipher/xor_ppc64x.s
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-//go:build ppc64 || ppc64le
-
-#include "textflag.h"
-
-// func xorBytesVSX(dst, a, b *byte, n int)
-TEXT ·xorBytesVSX(SB), NOSPLIT, $0
- MOVD dst+0(FP), R3 // R3 = dst
- MOVD a+8(FP), R4 // R4 = a
- MOVD b+16(FP), R5 // R5 = b
- MOVD n+24(FP), R6 // R6 = n
-
- CMPU R6, $32, CR7 // Check if n ≥ 32 bytes
- MOVD R0, R8 // R8 = index
- CMPU R6, $8, CR6 // Check if 8 ≤ n < 32 bytes
- BLT CR6, small // Smaller than 8
- BLT CR7, xor16 // Case for 16 ≤ n < 32 bytes
-
- // Case for n ≥ 32 bytes
-preloop32:
- SRD $5, R6, R7 // Setup loop counter
- MOVD R7, CTR
- MOVD $16, R10
- ANDCC $31, R6, R9 // Check for tailing bytes for later
-loop32:
- LXVD2X (R4)(R8), VS32 // VS32 = a[i,...,i+15]
- LXVD2X (R4)(R10), VS34
- LXVD2X (R5)(R8), VS33 // VS33 = b[i,...,i+15]
- LXVD2X (R5)(R10), VS35
- XXLXOR VS32, VS33, VS32 // VS34 = a[] ^ b[]
- XXLXOR VS34, VS35, VS34
- STXVD2X VS32, (R3)(R8) // Store to dst
- STXVD2X VS34, (R3)(R10)
- ADD $32, R8 // Update index
- ADD $32, R10
- BC 16, 0, loop32 // bdnz loop16
-
- BEQ CR0, done
-
- MOVD R9, R6
- CMP R6, $8
- BLT small
-xor16:
- CMP R6, $16
- BLT xor8
- LXVD2X (R4)(R8), VS32
- LXVD2X (R5)(R8), VS33
- XXLXOR VS32, VS33, VS32
- STXVD2X VS32, (R3)(R8)
- ADD $16, R8
- ADD $-16, R6
- CMP R6, $8
- BLT small
-xor8:
- // Case for 8 ≤ n < 16 bytes
- MOVD (R4)(R8), R14 // R14 = a[i,...,i+7]
- MOVD (R5)(R8), R15 // R15 = b[i,...,i+7]
- XOR R14, R15, R16 // R16 = a[] ^ b[]
- SUB $8, R6 // n = n - 8
- MOVD R16, (R3)(R8) // Store to dst
- ADD $8, R8
-
- // Check if we're finished
- CMP R6, R0
- BGT small
- RET
-
- // Case for n < 8 bytes and tailing bytes from the
- // previous cases.
-small:
- CMP R6, R0
- BEQ done
- MOVD R6, CTR // Setup loop counter
-
-loop:
- MOVBZ (R4)(R8), R14 // R14 = a[i]
- MOVBZ (R5)(R8), R15 // R15 = b[i]
- XOR R14, R15, R16 // R16 = a[i] ^ b[i]
- MOVB R16, (R3)(R8) // Store to dst
- ADD $1, R8
- BC 16, 0, loop // bdnz loop
-
-done:
- RET
diff --git a/src/crypto/cipher/xor_test.go b/src/crypto/cipher/xor_test.go
deleted file mode 100644
index 4f829e9461..0000000000
--- a/src/crypto/cipher/xor_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cipher_test
-
-import (
- "bytes"
- "crypto/cipher"
- "crypto/rand"
- "fmt"
- "io"
- "testing"
-)
-
-func TestXOR(t *testing.T) {
- for j := 1; j <= 1024; j++ {
- if testing.Short() && j > 16 {
- break
- }
- for alignP := 0; alignP < 2; alignP++ {
- for alignQ := 0; alignQ < 2; alignQ++ {
- for alignD := 0; alignD < 2; alignD++ {
- p := make([]byte, j)[alignP:]
- q := make([]byte, j)[alignQ:]
- d1 := make([]byte, j+alignD)[alignD:]
- d2 := make([]byte, j+alignD)[alignD:]
- if _, err := io.ReadFull(rand.Reader, p); err != nil {
- t.Fatal(err)
- }
- if _, err := io.ReadFull(rand.Reader, q); err != nil {
- t.Fatal(err)
- }
- cipher.XorBytes(d1, p, q)
- n := min(p, q)
- for i := 0; i < n; i++ {
- d2[i] = p[i] ^ q[i]
- }
- if !bytes.Equal(d1, d2) {
- t.Logf("p: %#v", p)
- t.Logf("q: %#v", q)
- t.Logf("expect: %#v", d2)
- t.Logf("result: %#v", d1)
- t.Fatal("not equal")
- }
- }
- }
- }
- }
-}
-
-func min(a, b []byte) int {
- n := len(a)
- if len(b) < n {
- n = len(b)
- }
- return n
-}
-
-func BenchmarkXORBytes(b *testing.B) {
- dst := make([]byte, 1<<15)
- data0 := make([]byte, 1<<15)
- data1 := make([]byte, 1<<15)
- sizes := []int64{1 << 3, 1 << 7, 1 << 11, 1 << 15}
- for _, size := range sizes {
- b.Run(fmt.Sprintf("%dBytes", size), func(b *testing.B) {
- s0 := data0[:size]
- s1 := data1[:size]
- b.SetBytes(int64(size))
- for i := 0; i < b.N; i++ {
- cipher.XorBytes(dst, s0, s1)
- }
- })
- }
-}