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