github.com/emmansun/gmsm@v0.29.1/internal/subtle/xor_generic.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 // 5 //go:build purego || !(amd64 || arm64 || s390x || ppc64 || ppc64le || riscv64) 6 7 package subtle 8 9 import ( 10 "runtime" 11 "unsafe" 12 ) 13 14 const wordSize = unsafe.Sizeof(uintptr(0)) 15 16 const supportsUnaligned = runtime.GOARCH == "386" || 17 runtime.GOARCH == "amd64" || 18 runtime.GOARCH == "ppc64" || 19 runtime.GOARCH == "ppc64le" || 20 runtime.GOARCH == "s390x" 21 22 func xorBytes(dstb, xb, yb *byte, n int) { 23 // xorBytes assembly is written using pointers and n. Back to slices. 24 dst := unsafe.Slice(dstb, n) 25 x := unsafe.Slice(xb, n) 26 y := unsafe.Slice(yb, n) 27 28 if supportsUnaligned || aligned(dstb, xb, yb) { 29 xorLoop(words(dst), words(x), words(y)) 30 if uintptr(n)%wordSize == 0 { 31 return 32 } 33 done := n &^ int(wordSize-1) 34 dst = dst[done:] 35 x = x[done:] 36 y = y[done:] 37 } 38 xorLoop(dst, x, y) 39 } 40 41 // aligned reports whether dst, x, and y are all word-aligned pointers. 42 func aligned(dst, x, y *byte) bool { 43 return (uintptr(unsafe.Pointer(dst))|uintptr(unsafe.Pointer(x))|uintptr(unsafe.Pointer(y)))&(wordSize-1) == 0 44 } 45 46 // words returns a []uintptr pointing at the same data as x, 47 // with any trailing partial word removed. 48 func words(x []byte) []uintptr { 49 n := uintptr(len(x)) / wordSize 50 if n == 0 { 51 // Avoid creating a *uintptr that refers to data smaller than a uintptr; 52 // see issue 59334. 53 return nil 54 } 55 return unsafe.Slice((*uintptr)(unsafe.Pointer(&x[0])), n) 56 } 57 58 func xorLoop[T byte | uintptr](dst, x, y []T) { 59 x = x[:len(dst)] // remove bounds check in loop 60 y = y[:len(dst)] // remove bounds check in loop 61 for i := range dst { 62 dst[i] = x[i] ^ y[i] 63 } 64 }