Botan 3.13.0
Crypto and TLS for C&
zfec_gfni.cpp
Go to the documentation of this file.
1/*
2* (C) 2026 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/zfec.h>
8
9#include <botan/internal/bit_ops.h>
10#include <botan/internal/isa_extn.h>
11#include <array>
12#include <immintrin.h>
13
14namespace Botan {
15
16namespace {
17
18/*
19* Multiplication by a fixed y in GF(2^8) is linear over GF(2), so it can be
20* expressed as an 8x8 bit matrix, which vgf2p8affineqb applies to each of
21* the 64 bytes of a vector. Column b of the matrix is y*x^b reduced by the
22* field polynomial; qword byte r holds the row producing output bit (7 - r).
23*/
24consteval std::array<uint64_t, 256> zfec_gfni_mul_matrix() {
25 std::array<uint64_t, 256> tbl = {};
26
27 for(size_t y = 0; y != 256; ++y) {
28 uint64_t q = 0;
29 for(size_t r = 0; r != 8; ++r) {
30 const size_t out_bit = 7 - r;
31 uint8_t byte_r = 0;
32 for(size_t b = 0; b != 8; ++b) {
33 const uint8_t prod = poly_mul<0x1D>(static_cast<uint8_t>(1U << b), static_cast<uint8_t>(y));
34 if(((prod >> out_bit) & 1) != 0) {
35 byte_r |= static_cast<uint8_t>(1U << b);
36 }
37 }
38 q |= static_cast<uint64_t>(byte_r) << (8 * r);
39 }
40 tbl[y] = q;
41 }
42
43 return tbl;
44}
45
46alignas(256) constexpr auto ZFEC_GFNI_MUL_MATRIX = zfec_gfni_mul_matrix();
47
48} // namespace
49
50/*
51* Computes z[] = x[0][] * y[0] + x[1][] * y[1] + ... + x[k-1][] * y[k-1]
52*/
53BOTAN_FN_ISA_AVX512_GFNI void ZFEC::linear_combination_gfni(
54 uint8_t z[], const uint8_t* const x[], const uint8_t y[], size_t k, size_t size) {
55 size_t off = 0;
56
57 while(off + 128 <= size) {
58 __m512i acc0 = _mm512_setzero_si512();
59 __m512i acc1 = _mm512_setzero_si512();
60
61 for(size_t j = 0; j != k; ++j) {
62 const __m512i mat = _mm512_set1_epi64(static_cast<int64_t>(ZFEC_GFNI_MUL_MATRIX[y[j]]));
63 const __m512i x0 = _mm512_loadu_si512(x[j] + off);
64 const __m512i x1 = _mm512_loadu_si512(x[j] + off + 64);
65 acc0 = _mm512_xor_si512(acc0, _mm512_gf2p8affine_epi64_epi8(x0, mat, 0));
66 acc1 = _mm512_xor_si512(acc1, _mm512_gf2p8affine_epi64_epi8(x1, mat, 0));
67 }
68
69 _mm512_storeu_si512(z + off, acc0);
70 _mm512_storeu_si512(z + off + 64, acc1);
71
72 off += 128;
73 }
74
75 while(off + 64 <= size) {
76 __m512i acc = _mm512_setzero_si512();
77
78 for(size_t j = 0; j != k; ++j) {
79 const __m512i mat = _mm512_set1_epi64(static_cast<int64_t>(ZFEC_GFNI_MUL_MATRIX[y[j]]));
80 acc = _mm512_xor_si512(acc, _mm512_gf2p8affine_epi64_epi8(_mm512_loadu_si512(x[j] + off), mat, 0));
81 }
82
83 _mm512_storeu_si512(z + off, acc);
84
85 off += 64;
86 }
87
88 if(off < size) {
89 const __mmask64 mask = (uint64_t(1) << (size - off)) - 1;
90
91 __m512i acc = _mm512_setzero_si512();
92
93 for(size_t j = 0; j != k; ++j) {
94 const __m512i mat = _mm512_set1_epi64(static_cast<int64_t>(ZFEC_GFNI_MUL_MATRIX[y[j]]));
95 const __m512i xv = _mm512_maskz_loadu_epi8(mask, x[j] + off);
96 acc = _mm512_xor_si512(acc, _mm512_gf2p8affine_epi64_epi8(xv, mat, 0));
97 }
98
99 _mm512_mask_storeu_epi8(z + off, mask, acc);
100 }
101}
102
103} // namespace Botan
constexpr T poly_mul(T x, uint8_t y)
Definition bit_ops.h:306