mirror of
https://github.com/rocky-linux/peridot.git
synced 2024-12-25 11:58:30 +00:00
93 lines
2.6 KiB
Go
93 lines
2.6 KiB
Go
|
// Copyright (C) 2019 ProtonTech AG
|
||
|
// This file contains necessary tools for the aex and ocb packages.
|
||
|
//
|
||
|
// These functions SHOULD NOT be used elsewhere, since they are optimized for
|
||
|
// specific input nature in the EAX and OCB modes of operation.
|
||
|
|
||
|
package byteutil
|
||
|
|
||
|
// GfnDouble computes 2 * input in the field of 2^n elements.
|
||
|
// The irreducible polynomial in the finite field for n=128 is
|
||
|
// x^128 + x^7 + x^2 + x + 1 (equals 0x87)
|
||
|
// Constant-time execution in order to avoid side-channel attacks
|
||
|
func GfnDouble(input []byte) []byte {
|
||
|
if len(input) != 16 {
|
||
|
panic("Doubling in GFn only implemented for n = 128")
|
||
|
}
|
||
|
// If the first bit is zero, return 2L = L << 1
|
||
|
// Else return (L << 1) xor 0^120 10000111
|
||
|
shifted := ShiftBytesLeft(input)
|
||
|
shifted[15] ^= ((input[0] >> 7) * 0x87)
|
||
|
return shifted
|
||
|
}
|
||
|
|
||
|
// ShiftBytesLeft outputs the byte array corresponding to x << 1 in binary.
|
||
|
func ShiftBytesLeft(x []byte) []byte {
|
||
|
l := len(x)
|
||
|
dst := make([]byte, l)
|
||
|
for i := 0; i < l-1; i++ {
|
||
|
dst[i] = (x[i] << 1) | (x[i+1] >> 7)
|
||
|
}
|
||
|
dst[l-1] = x[l-1] << 1
|
||
|
return dst
|
||
|
}
|
||
|
|
||
|
// ShiftNBytesLeft puts in dst the byte array corresponding to x << n in binary.
|
||
|
func ShiftNBytesLeft(dst, x []byte, n int) {
|
||
|
// Erase first n / 8 bytes
|
||
|
copy(dst, x[n/8:])
|
||
|
|
||
|
// Shift the remaining n % 8 bits
|
||
|
bits := uint(n % 8)
|
||
|
l := len(dst)
|
||
|
for i := 0; i < l-1; i++ {
|
||
|
dst[i] = (dst[i] << bits) | (dst[i+1] >> uint(8 - bits))
|
||
|
}
|
||
|
dst[l-1] = dst[l-1] << bits
|
||
|
|
||
|
// Append trailing zeroes
|
||
|
dst = append(dst, make([]byte, n/8)...)
|
||
|
}
|
||
|
|
||
|
// XorBytesMut assumes equal input length, replaces X with X XOR Y
|
||
|
func XorBytesMut(X, Y []byte) {
|
||
|
for i := 0; i < len(X); i++ {
|
||
|
X[i] ^= Y[i]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// XorBytes assumes equal input length, puts X XOR Y into Z
|
||
|
func XorBytes(Z, X, Y []byte) {
|
||
|
for i := 0; i < len(X); i++ {
|
||
|
Z[i] = X[i] ^ Y[i]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// RightXor XORs smaller input (assumed Y) at the right of the larger input (assumed X)
|
||
|
func RightXor(X, Y []byte) []byte {
|
||
|
offset := len(X) - len(Y)
|
||
|
xored := make([]byte, len(X));
|
||
|
copy(xored, X)
|
||
|
for i := 0; i < len(Y); i++ {
|
||
|
xored[offset + i] ^= Y[i]
|
||
|
}
|
||
|
return xored
|
||
|
}
|
||
|
|
||
|
// SliceForAppend takes a slice and a requested number of bytes. It returns a
|
||
|
// slice with the contents of the given slice followed by that many bytes and a
|
||
|
// second slice that aliases into it and contains only the extra bytes. If the
|
||
|
// original slice has sufficient capacity then no allocation is performed.
|
||
|
func SliceForAppend(in []byte, n int) (head, tail []byte) {
|
||
|
if total := len(in) + n; cap(in) >= total {
|
||
|
head = in[:total]
|
||
|
} else {
|
||
|
head = make([]byte, total)
|
||
|
copy(head, in)
|
||
|
}
|
||
|
tail = head[len(in):]
|
||
|
return
|
||
|
}
|
||
|
|