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 (!amd64 && !arm64 && !ppc64 && !ppc64le) || purego 6 7package subtle 8 9import ( 10 "runtime" 11 "unsafe" 12) 13 14const wordSize = unsafe.Sizeof(uintptr(0)) 15 16const supportsUnaligned = runtime.GOARCH == "386" || 17 runtime.GOARCH == "amd64" || 18 runtime.GOARCH == "ppc64" || 19 runtime.GOARCH == "ppc64le" || 20 runtime.GOARCH == "s390x" 21 22func 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. 42func 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. 48func 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 58func 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} 65