...

Source file src/pkg/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	// +build !amd64,!ppc64,!ppc64le
     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