...

Source file src/github.com/ProtonMail/go-crypto/internal/byteutil/byteutil.go

Documentation: github.com/ProtonMail/go-crypto/internal/byteutil

     1  // Copyright (C) 2019 ProtonTech AG
     2  // This file contains necessary tools for the aex and ocb packages.
     3  //
     4  // These functions SHOULD NOT be used elsewhere, since they are optimized for
     5  // specific input nature in the EAX and OCB modes of operation.
     6  
     7  package byteutil
     8  
     9  // GfnDouble computes 2 * input in the field of 2^n elements.
    10  // The irreducible polynomial in the finite field for n=128 is
    11  // x^128 + x^7 + x^2 + x + 1 (equals 0x87)
    12  // Constant-time execution in order to avoid side-channel attacks
    13  func GfnDouble(input []byte) []byte {
    14  	if len(input) != 16 {
    15  		panic("Doubling in GFn only implemented for n = 128")
    16  	}
    17  	// If the first bit is zero, return 2L = L << 1
    18  	// Else return (L << 1) xor 0^120 10000111
    19  	shifted := ShiftBytesLeft(input)
    20  	shifted[15] ^= ((input[0] >> 7) * 0x87)
    21  	return shifted
    22  }
    23  
    24  // ShiftBytesLeft outputs the byte array corresponding to x << 1 in binary.
    25  func ShiftBytesLeft(x []byte) []byte {
    26  	l := len(x)
    27  	dst := make([]byte, l)
    28  	for i := 0; i < l-1; i++ {
    29  		dst[i] = (x[i] << 1) | (x[i+1] >> 7)
    30  	}
    31  	dst[l-1] = x[l-1] << 1
    32  	return dst
    33  }
    34  
    35  // ShiftNBytesLeft puts in dst the byte array corresponding to x << n in binary.
    36  func ShiftNBytesLeft(dst, x []byte, n int) {
    37  	// Erase first n / 8 bytes
    38  	copy(dst, x[n/8:])
    39  
    40  	// Shift the remaining n % 8 bits
    41  	bits := uint(n % 8)
    42  	l := len(dst)
    43  	for i := 0; i < l-1; i++ {
    44  		dst[i] = (dst[i] << bits) | (dst[i+1] >> uint(8-bits))
    45  	}
    46  	dst[l-1] = dst[l-1] << bits
    47  
    48  	// Append trailing zeroes
    49  	dst = append(dst, make([]byte, n/8)...)
    50  }
    51  
    52  // XorBytesMut assumes equal input length, replaces X with X XOR Y
    53  func XorBytesMut(X, Y []byte) {
    54  	for i := 0; i < len(X); i++ {
    55  		X[i] ^= Y[i]
    56  	}
    57  }
    58  
    59  // XorBytes assumes equal input length, puts X XOR Y into Z
    60  func XorBytes(Z, X, Y []byte) {
    61  	for i := 0; i < len(X); i++ {
    62  		Z[i] = X[i] ^ Y[i]
    63  	}
    64  }
    65  
    66  // RightXor XORs smaller input (assumed Y) at the right of the larger input (assumed X)
    67  func RightXor(X, Y []byte) []byte {
    68  	offset := len(X) - len(Y)
    69  	xored := make([]byte, len(X))
    70  	copy(xored, X)
    71  	for i := 0; i < len(Y); i++ {
    72  		xored[offset+i] ^= Y[i]
    73  	}
    74  	return xored
    75  }
    76  
    77  // SliceForAppend takes a slice and a requested number of bytes. It returns a
    78  // slice with the contents of the given slice followed by that many bytes and a
    79  // second slice that aliases into it and contains only the extra bytes. If the
    80  // original slice has sufficient capacity then no allocation is performed.
    81  func SliceForAppend(in []byte, n int) (head, tail []byte) {
    82  	if total := len(in) + n; cap(in) >= total {
    83  		head = in[:total]
    84  	} else {
    85  		head = make([]byte, total)
    86  		copy(head, in)
    87  	}
    88  	tail = head[len(in):]
    89  	return
    90  }
    91  

View as plain text