Source file src/crypto/cipher/xor_generic.go

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

View as plain text