github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/crypto/cipher/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 !amd64 && !ppc64 && !ppc64le && !arm64 6 // +build !amd64,!ppc64,!ppc64le,!arm64 7 8 package cipher 9 10 import ( 11 "runtime" 12 "unsafe" 13 ) 14 15 // xorBytes xors the bytes in a and b. The destination should have enough 16 // space, otherwise xorBytes will panic. Returns the number of bytes xor'd. 17 func xorBytes(dst, a, b []byte) int { 18 n := len(a) 19 if len(b) < n { 20 n = len(b) 21 } 22 if n == 0 { 23 return 0 24 } 25 26 switch { 27 case supportsUnaligned: 28 fastXORBytes(dst, a, b, n) 29 default: 30 // TODO(hanwen): if (dst, a, b) have common alignment 31 // we could still try fastXORBytes. It is not clear 32 // how often this happens, and it's only worth it if 33 // the block encryption itself is hardware 34 // accelerated. 35 safeXORBytes(dst, a, b, n) 36 } 37 return n 38 } 39 40 const wordSize = int(unsafe.Sizeof(uintptr(0))) 41 const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x" 42 43 // fastXORBytes xors in bulk. It only works on architectures that 44 // support unaligned read/writes. 45 // n needs to be smaller or equal than the length of a and b. 46 func fastXORBytes(dst, a, b []byte, n int) { 47 // Assert dst has enough space 48 _ = dst[n-1] 49 50 w := n / wordSize 51 if w > 0 { 52 dw := *(*[]uintptr)(unsafe.Pointer(&dst)) 53 aw := *(*[]uintptr)(unsafe.Pointer(&a)) 54 bw := *(*[]uintptr)(unsafe.Pointer(&b)) 55 for i := 0; i < w; i++ { 56 dw[i] = aw[i] ^ bw[i] 57 } 58 } 59 60 for i := (n - n%wordSize); i < n; i++ { 61 dst[i] = a[i] ^ b[i] 62 } 63 } 64 65 // n needs to be smaller or equal than the length of a and b. 66 func safeXORBytes(dst, a, b []byte, n int) { 67 for i := 0; i < n; i++ { 68 dst[i] = a[i] ^ b[i] 69 } 70 } 71 72 // fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.) 73 // The arguments are assumed to be of equal length. 74 func fastXORWords(dst, a, b []byte) { 75 dw := *(*[]uintptr)(unsafe.Pointer(&dst)) 76 aw := *(*[]uintptr)(unsafe.Pointer(&a)) 77 bw := *(*[]uintptr)(unsafe.Pointer(&b)) 78 n := len(b) / wordSize 79 for i := 0; i < n; i++ { 80 dw[i] = aw[i] ^ bw[i] 81 } 82 } 83 84 // fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.) 85 // The slice arguments a and b are assumed to be of equal length. 86 func xorWords(dst, a, b []byte) { 87 if supportsUnaligned { 88 fastXORWords(dst, a, b) 89 } else { 90 safeXORBytes(dst, a, b, len(b)) 91 } 92 }