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"
     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 
     23 	w := n / wordSize
     24 	if w > 0 {
     25 		dw := *(*[]uintptr)(unsafe.Pointer(&dst))
     26 		aw := *(*[]uintptr)(unsafe.Pointer(&a))
     27 		bw := *(*[]uintptr)(unsafe.Pointer(&b))
     28 		for i := 0; i < w; i++ {
     29 			dw[i] = aw[i] ^ bw[i]
     30 		}
     31 	}
     32 
     33 	for i := (n - n%wordSize); i < n; i++ {
     34 		dst[i] = a[i] ^ b[i]
     35 	}
     36 
     37 	return n
     38 }
     39 
     40 func safeXORBytes(dst, a, b []byte) int {
     41 	n := len(a)
     42 	if len(b) < n {
     43 		n = len(b)
     44 	}
     45 	for i := 0; i < n; i++ {
     46 		dst[i] = a[i] ^ b[i]
     47 	}
     48 	return n
     49 }
     50 
     51 // xorBytes xors the bytes in a and b. The destination is assumed to have enough
     52 // space. Returns the number of bytes xor'd.
     53 func xorBytes(dst, a, b []byte) int {
     54 	if supportsUnaligned {
     55 		return fastXORBytes(dst, a, b)
     56 	} else {
     57 		// TODO(hanwen): if (dst, a, b) have common alignment
     58 		// we could still try fastXORBytes. It is not clear
     59 		// how often this happens, and it's only worth it if
     60 		// the block encryption itself is hardware
     61 		// accelerated.
     62 		return safeXORBytes(dst, a, b)
     63 	}
     64 }
     65 
     66 // fastXORWords XORs multiples of 4 or 8 bytes (depending on architecture.)
     67 // The arguments are assumed to be of equal length.
     68 func fastXORWords(dst, a, b []byte) {
     69 	dw := *(*[]uintptr)(unsafe.Pointer(&dst))
     70 	aw := *(*[]uintptr)(unsafe.Pointer(&a))
     71 	bw := *(*[]uintptr)(unsafe.Pointer(&b))
     72 	n := len(b) / wordSize
     73 	for i := 0; i < n; i++ {
     74 		dw[i] = aw[i] ^ bw[i]
     75 	}
     76 }
     77 
     78 func xorWords(dst, a, b []byte) {
     79 	if supportsUnaligned {
     80 		fastXORWords(dst, a, b)
     81 	} else {
     82 		safeXORBytes(dst, a, b)
     83 	}
     84 }
     85