mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 04:06:18 +08:00
internal/subtle xor 简化代码,去除重复 #75
This commit is contained in:
parent
1b200746af
commit
4f511e2125
24
internal/subtle/xor.go
Normal file
24
internal/subtle/xor.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2022 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 subtle
|
||||||
|
|
||||||
|
// XORBytes sets dst[i] = x[i] ^ y[i] for all i < n = min(len(x), len(y)),
|
||||||
|
// returning n, the number of bytes written to dst.
|
||||||
|
// If dst does not have length at least n,
|
||||||
|
// XORBytes panics without writing anything to dst.
|
||||||
|
func XORBytes(dst, x, y []byte) int {
|
||||||
|
n := len(x)
|
||||||
|
if len(y) < n {
|
||||||
|
n = len(y)
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if n > len(dst) {
|
||||||
|
panic("subtle.XORBytes: dst too short")
|
||||||
|
}
|
||||||
|
xorBytes(&dst[0], &x[0], &y[0], n) // arch-specific
|
||||||
|
return n
|
||||||
|
}
|
@ -10,22 +10,5 @@ import "golang.org/x/sys/cpu"
|
|||||||
|
|
||||||
var useAVX2 = cpu.X86.HasAVX2
|
var useAVX2 = cpu.X86.HasAVX2
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
if n > len(dst) {
|
|
||||||
panic("subtle.XORBytes: dst too short")
|
|
||||||
}
|
|
||||||
xorBytes(&dst[0], &a[0], &b[0], n) // amd64 must have SSE2
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func xorBytes(dst, a, b *byte, n int)
|
func xorBytes(dst, a, b *byte, n int)
|
||||||
|
@ -6,23 +6,5 @@
|
|||||||
|
|
||||||
package subtle
|
package subtle
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
if n > len(dst) {
|
|
||||||
panic("subtle.XORBytes: dst too short")
|
|
||||||
}
|
|
||||||
|
|
||||||
xorBytes(&dst[0], &a[0], &b[0], n)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func xorBytes(dst, a, b *byte, n int)
|
func xorBytes(dst, a, b *byte, n int)
|
||||||
|
@ -11,63 +11,54 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const wordSize = int(unsafe.Sizeof(uintptr(0)))
|
const wordSize = unsafe.Sizeof(uintptr(0))
|
||||||
|
|
||||||
const supportsUnaligned = runtime.GOARCH == "386" ||
|
const supportsUnaligned = runtime.GOARCH == "386" ||
|
||||||
|
runtime.GOARCH == "amd64" ||
|
||||||
runtime.GOARCH == "ppc64" ||
|
runtime.GOARCH == "ppc64" ||
|
||||||
runtime.GOARCH == "ppc64le" ||
|
runtime.GOARCH == "ppc64le" ||
|
||||||
runtime.GOARCH == "s390x"
|
runtime.GOARCH == "s390x"
|
||||||
|
|
||||||
// XORBytes xors the bytes in a and b. The destination should have enough
|
func xorBytes(dstb, xb, yb *byte, n int) {
|
||||||
// space, otherwise XORBytes will panic. Returns the number of bytes xor'd.
|
// xorBytes assembly is written using pointers and n. Back to slices.
|
||||||
func XORBytes(dst, a, b []byte) int {
|
dst := unsafe.Slice(dstb, n)
|
||||||
n := len(a)
|
x := unsafe.Slice(xb, n)
|
||||||
if len(b) < n {
|
y := unsafe.Slice(yb, n)
|
||||||
n = len(b)
|
|
||||||
}
|
|
||||||
if n == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if n > len(dst) {
|
|
||||||
panic("subtle.XORBytes: dst too short")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
if supportsUnaligned || aligned(dstb, xb, yb) {
|
||||||
case supportsUnaligned:
|
xorLoop(words(dst), words(x), words(y))
|
||||||
fastXORBytes(dst, a, b, n)
|
if uintptr(n)%wordSize == 0 {
|
||||||
default:
|
return
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
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]
|
|
||||||
}
|
}
|
||||||
|
done := n &^ int(wordSize-1)
|
||||||
|
dst = dst[done:]
|
||||||
|
x = x[done:]
|
||||||
|
y = y[done:]
|
||||||
}
|
}
|
||||||
|
xorLoop(dst, x, y)
|
||||||
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.
|
// aligned reports whether dst, x, and y are all word-aligned pointers.
|
||||||
func safeXORBytes(dst, a, b []byte, n int) {
|
func aligned(dst, x, y *byte) bool {
|
||||||
for i := 0; i < n; i++ {
|
return (uintptr(unsafe.Pointer(dst))|uintptr(unsafe.Pointer(x))|uintptr(unsafe.Pointer(y)))&(wordSize-1) == 0
|
||||||
dst[i] = a[i] ^ b[i]
|
}
|
||||||
|
|
||||||
|
// words returns a []uintptr pointing at the same data as x,
|
||||||
|
// with any trailing partial word removed.
|
||||||
|
func words(x []byte) []uintptr {
|
||||||
|
n := uintptr(len(x)) / wordSize
|
||||||
|
if n == 0 {
|
||||||
|
// Avoid creating a *uintptr that refers to data smaller than a uintptr;
|
||||||
|
// see issue 59334.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return unsafe.Slice((*uintptr)(unsafe.Pointer(&x[0])), n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func xorLoop[T byte | uintptr](dst, x, y []T) {
|
||||||
|
x = x[:len(dst)] // remove bounds check in loop
|
||||||
|
y = y[:len(dst)] // remove bounds check in loop
|
||||||
|
for i := range dst {
|
||||||
|
dst[i] = x[i] ^ y[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user