Black Lives Matter. Support the Equal Justice Initiative.

Source file src/crypto/cipher/xor_generic.go

Documentation: crypto/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  //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  }
    93  

View as plain text