Home | History | Annotate | Download | only in cipher
      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