Botan 3.13.0
Crypto and TLS for C&
streebog_avx512_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/internal/streebog.h>
8
9#include <botan/internal/bit_ops.h>
10#include <botan/internal/isa_extn.h>
11#include <botan/internal/streebog_const.h>
12#include <array>
13#include <immintrin.h>
14
15namespace Botan {
16
17namespace {
18
19consteval std::array<std::array<uint64_t, 8>, 8> streebog_avx512_affine_table() {
20 auto gfni_mul_matrix = [](uint8_t c) -> uint64_t {
21 uint64_t q = 0;
22 for(size_t r = 0; r != 8; ++r) {
23 const size_t out_bit = 7 - r;
24 uint8_t byte_r = 0;
25 for(size_t b = 0; b != 8; ++b) {
26 const uint8_t prod = poly_mul<0x1D>(static_cast<uint8_t>(1U << b), c); // c * alpha^b
27 if(((prod >> out_bit) & 1) != 0) {
28 byte_r |= static_cast<uint8_t>(1U << b);
29 }
30 }
31 q |= static_cast<uint64_t>(byte_r) << (8 * r);
32 }
33 return q;
34 };
35
36 std::array<std::array<uint64_t, 8>, 8> tbl = {};
37 for(size_t j = 0; j != 8; ++j) {
38 for(size_t k = 0; k != 8; ++k) {
39 tbl[j][k] = gfni_mul_matrix(static_cast<uint8_t>(STREEBOG_L[j] >> (8 * k)));
40 }
41 }
42 return tbl;
43}
44
45alignas(256) constexpr auto STREEBOG_AVX512_AFFINE = streebog_avx512_affine_table();
46
47consteval std::array<uint8_t, 64> streebog_transpose_idx() {
48 std::array<uint8_t, 64> idx = {};
49 for(size_t i = 0; i != 8; ++i) {
50 for(size_t k = 0; k != 8; ++k) {
51 idx[8 * i + k] = static_cast<uint8_t>(8 * k + i);
52 }
53 }
54 return idx;
55}
56
57BOTAN_FN_ISA_AVX512_GFNI BOTAN_FORCE_INLINE __m512i streebog_sbox(__m512i x) {
58 // Load the constant tables
59 const __m512i S0 = _mm512_loadu_si512(&STREEBOG_S[0]);
60 const __m512i S1 = _mm512_loadu_si512(&STREEBOG_S[64]);
61 const __m512i S2 = _mm512_loadu_si512(&STREEBOG_S[128]);
62 const __m512i S3 = _mm512_loadu_si512(&STREEBOG_S[192]);
63
64 // Select from both halves then blend
65 const __m512i lo = _mm512_permutex2var_epi8(S0, x, S1);
66 const __m512i hi = _mm512_permutex2var_epi8(S2, x, S3);
67 const __mmask64 m = _mm512_movepi8_mask(x);
68 return _mm512_mask_blend_epi8(m, lo, hi);
69}
70
71BOTAN_FN_ISA_AVX512_GFNI BOTAN_FORCE_INLINE __m512i streebog_lps(__m512i x) {
72 alignas(64) constexpr auto STREEBOG_TIDX = streebog_transpose_idx();
73
74 const __m512i sx = streebog_sbox(x);
75 __m512i mt = _mm512_setzero_si512();
76 for(size_t i = 0; i != 8; ++i) {
77 const __m512i idx = _mm512_set1_epi64(static_cast<long long>(i));
78 const __m512i ci = _mm512_loadu_si512(STREEBOG_AVX512_AFFINE[i].data());
79 mt = _mm512_xor_si512(mt, _mm512_gf2p8affine_epi64_epi8(_mm512_permutexvar_epi64(idx, sx), ci, 0));
80 }
81 return _mm512_permutexvar_epi8(_mm512_loadu_si512(STREEBOG_TIDX.data()), mt);
82}
83
84BOTAN_FN_ISA_AVX512_GFNI BOTAN_FORCE_INLINE void streebog_lps_x2(__m512i& a, __m512i& b) {
85 alignas(64) constexpr auto STREEBOG_TIDX = streebog_transpose_idx();
86
87 const __m512i sa = streebog_sbox(a);
88 const __m512i sb = streebog_sbox(b);
89 __m512i ma = _mm512_setzero_si512();
90 __m512i mb = _mm512_setzero_si512();
91 for(size_t i = 0; i != 8; ++i) {
92 const __m512i idx = _mm512_set1_epi64(static_cast<long long>(i));
93 const __m512i ci = _mm512_loadu_si512(STREEBOG_AVX512_AFFINE[i].data());
94 ma = _mm512_xor_si512(ma, _mm512_gf2p8affine_epi64_epi8(_mm512_permutexvar_epi64(idx, sa), ci, 0));
95 mb = _mm512_xor_si512(mb, _mm512_gf2p8affine_epi64_epi8(_mm512_permutexvar_epi64(idx, sb), ci, 0));
96 }
97 const __m512i tidx = _mm512_loadu_si512(STREEBOG_TIDX.data());
98 a = _mm512_permutexvar_epi8(tidx, ma);
99 b = _mm512_permutexvar_epi8(tidx, mb);
100}
101
102} // namespace
103
104void BOTAN_FN_ISA_AVX512_GFNI Streebog::compress_64_avx512_gfni(uint64_t h[8], const uint64_t M[8], uint64_t N) {
105 auto streebog_rc_table = []() consteval -> std::array<std::array<uint64_t, 8>, 12> {
106 std::array<std::array<uint64_t, 8>, 12> tbl = {};
107 for(size_t i = 0; i != 12; ++i) {
108 for(size_t j = 0; j != 8; ++j) {
109 tbl[i][j] = STREEBOG_C[i][7 - j];
110 }
111 }
112 return tbl;
113 };
114
115 alignas(64) constexpr auto STREEBOG_RC = streebog_rc_table();
116
117 const __m512i hv = _mm512_loadu_si512(h);
118 const __m512i mv = _mm512_loadu_si512(M);
119
120 __m512i hN = streebog_lps(_mm512_xor_si512(hv, _mm512_maskz_set1_epi64(0x01, static_cast<long long>(N))));
121 __m512i a = hN;
122 hN = _mm512_xor_si512(hN, mv);
123
124 for(size_t i = 0; i != 12; ++i) {
125 a = _mm512_xor_si512(a, _mm512_loadu_si512(STREEBOG_RC[i].data()));
126 streebog_lps_x2(a, hN);
127 hN = _mm512_xor_si512(hN, a);
128 }
129
130 _mm512_storeu_si512(h, _mm512_xor_si512(_mm512_xor_si512(hv, hN), mv));
131}
132
133} // namespace Botan
#define BOTAN_FORCE_INLINE
Definition compiler.h:87
const constexpr uint8_t STREEBOG_S[256]
constexpr T poly_mul(T x, uint8_t y)
Definition bit_ops.h:306
constexpr uint64_t STREEBOG_C[12][8]
constexpr uint64_t STREEBOG_L[8]