main
Raw Download raw file
 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
 7package 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
13func 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.
25func 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.
36func 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 replaces X with X XOR Y. len(X) must be >= len(Y).
53func XorBytesMut(X, Y []byte) {
54	for i := 0; i < len(Y); i++ {
55		X[i] ^= Y[i]
56	}
57}
58
59// XorBytes puts X XOR Y into Z. len(Z) and len(X) must be >= len(Y).
60func XorBytes(Z, X, Y []byte) {
61	for i := 0; i < len(Y); 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)
67func 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.
81func 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}