Botan 3.11.1
Crypto and TLS for C&
simd_hwaes.h
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#ifndef BOTAN_SIMD_HWAES_H_
8#define BOTAN_SIMD_HWAES_H_
9
10#include <botan/internal/gfni_utils.h>
11#include <botan/internal/isa_extn.h>
12#include <botan/internal/simd_4x32.h>
13
14namespace Botan {
15
16/**
17* Apply the AES S-box to each byte of the input vector.
18*/
19inline SIMD_4x32 BOTAN_FN_ISA_HWAES hw_aes_sbox(SIMD_4x32 x) {
20 // Undo the ShiftRows with a byte shuffle implementing InvShiftRows
21 const auto inv_sr = SIMD_4x32(0x070A0D00, 0x0B0E0104, 0x0F020508, 0x0306090C);
22
23#if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY)
24 auto enc = SIMD_4x32(_mm_aesenclast_si128(x.raw(), _mm_setzero_si128()));
25#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
26 auto enc = SIMD_4x32(vreinterpretq_u32_u8(vaeseq_u8(vreinterpretq_u8_u32(x.raw()), vdupq_n_u8(0))));
27#else
28 #error "hw_aes_sbox not implemented for this architecture"
29#endif
30
31 return SIMD_4x32::byte_shuffle(enc, inv_sr);
32}
33
34/**
35* Apply the AES inverse S-box to each byte of the input vector.
36*/
37inline SIMD_4x32 BOTAN_FN_ISA_HWAES hw_aes_inv_sbox(SIMD_4x32 x) {
38 // Undo the InvShiftRows with a byte shuffle implementing ShiftRows
39 const auto sr = SIMD_4x32(0x0F0A0500, 0x030E0904, 0x07020D08, 0x0B06010C);
40
41#if defined(BOTAN_TARGET_ARCH_IS_X86_FAMILY)
42 auto dec = SIMD_4x32(_mm_aesdeclast_si128(x.raw(), _mm_setzero_si128()));
43#elif defined(BOTAN_TARGET_ARCH_IS_ARM64)
44 auto dec = SIMD_4x32(vreinterpretq_u32_u8(vaesdq_u8(vreinterpretq_u8_u32(x.raw()), vdupq_n_u8(0))));
45#else
46 #error "hw_aes_inv_sbox not implemented for this architecture"
47#endif
48
49 return SIMD_4x32::byte_shuffle(dec, sr);
50}
51
52namespace detail {
53
54/*
55* GF(2) matrix-vector multiply: returns M*x where M is a GFNI matrix
56* and x is an 8-bit vector. Both use GFNI bit numbering convention.
57*/
58consteval uint8_t gf2_mat_vec(uint64_t M, uint8_t x) {
59 uint8_t result = 0;
60 for(size_t i = 0; i != 8; ++i) {
61 uint8_t bit = 0;
62 for(size_t j = 0; j != 8; ++j) {
63 if(((M >> (56 - 8 * i + j)) & 1) == 1) {
64 bit ^= (x >> j) & 1;
65 }
66 }
67 result |= bit << i;
68 }
69 return result;
70}
71
72/*
73* GF(2) 8x8 matrix multiplication: returns A*B in GFNI format.
74*/
75consteval uint64_t gf2_mat_mul(uint64_t A, uint64_t B) {
76 uint64_t result = 0;
77 for(size_t i = 0; i != 8; ++i) {
78 for(size_t j = 0; j != 8; ++j) {
79 uint8_t bit = 0;
80 for(size_t k = 0; k != 8; ++k) {
81 auto a_ik = static_cast<uint8_t>((A >> (56 - 8 * i + k)) & 1);
82 auto b_kj = static_cast<uint8_t>((B >> (56 - 8 * k + j)) & 1);
83 bit ^= a_ik & b_kj;
84 }
85 if(bit != 0) {
86 result |= uint64_t(1) << (56 - 8 * i + j);
87 }
88 }
89 }
90 return result;
91}
92
93// AES affine matrix in GFNI format
94constexpr uint64_t AES_AFF = gfni_matrix(R"(
95 1 0 0 0 1 1 1 1
96 1 1 0 0 0 1 1 1
97 1 1 1 0 0 0 1 1
98 1 1 1 1 0 0 0 1
99 1 1 1 1 1 0 0 0
100 0 1 1 1 1 1 0 0
101 0 0 1 1 1 1 1 0
102 0 0 0 1 1 1 1 1)");
103constexpr uint8_t AES_C = 0x63;
104
105// AES inverse affine matrix in GFNI format
106constexpr uint64_t AES_AFF_INV = gfni_matrix(R"(
107 0 0 1 0 0 1 0 1
108 1 0 0 1 0 0 1 0
109 0 1 0 0 1 0 0 1
110 1 0 1 0 0 1 0 0
111 0 1 0 1 0 0 1 0
112 0 0 1 0 1 0 0 1
113 1 0 0 1 0 1 0 0
114 0 1 0 0 1 0 1 0)");
115constexpr uint8_t AES_C_INV = 0x05;
116
117} // namespace detail
118
119/**
120* Lookup tables for GF(2) affine transformations
121*/
123 public:
124 consteval Gf2AffineTransformation(uint64_t M, uint8_t c) : lo{}, hi{} {
125 for(size_t i = 0; i != 16; ++i) {
126 // Low nibble table includes the constant addition
127 const uint8_t lo_val = detail::gf2_mat_vec(M, static_cast<uint8_t>(i)) ^ c;
128 const uint8_t hi_val = detail::gf2_mat_vec(M, static_cast<uint8_t>(i << 4));
129
130 lo[i / 4] |= static_cast<uint32_t>(lo_val) << (8 * (i % 4));
131 hi[i / 4] |= static_cast<uint32_t>(hi_val) << (8 * (i % 4));
132 }
133 }
134
135 /**
136 * Derive tables used for computing an affine transform after the application of an
137 * AES sbox.
138 */
139 static consteval Gf2AffineTransformation post_sbox(uint64_t M, uint8_t c) {
140 const auto comb_M = detail::gf2_mat_mul(M, detail::AES_AFF_INV);
141 const auto comb_c = static_cast<uint8_t>(detail::gf2_mat_vec(comb_M, detail::AES_C) ^ c);
142 return Gf2AffineTransformation(comb_M, comb_c);
143 }
144
145 /**
146 * Derive tables used for computing an affine transform after the application of an
147 * AES inverse sbox.
148 */
149 static consteval Gf2AffineTransformation post_inv_sbox(uint64_t M, uint8_t c) {
150 const auto comb_mat = detail::gf2_mat_mul(detail::AES_AFF, M);
151 const auto comb_c = detail::gf2_mat_vec(detail::AES_AFF, static_cast<uint8_t>(c ^ detail::AES_C_INV));
152 return Gf2AffineTransformation(comb_mat, comb_c);
153 }
154
155 inline SIMD_4x32 BOTAN_FN_ISA_HWAES affine_transform(SIMD_4x32 x) const {
156 const SIMD_4x32 tbl_lo(lo[0], lo[1], lo[2], lo[3]);
157 const SIMD_4x32 tbl_hi(hi[0], hi[1], hi[2], hi[3]);
158 const auto lo_mask = SIMD_4x32::splat_u8(0x0F);
159
160 return SIMD_4x32::byte_shuffle(tbl_lo, lo_mask & x) ^ SIMD_4x32::byte_shuffle(tbl_hi, lo_mask & x.shr<4>());
161 }
162
163 private:
164 uint32_t lo[4];
165 uint32_t hi[4];
166};
167
168} // namespace Botan
169
170#endif
SIMD_4x32 BOTAN_FN_ISA_HWAES affine_transform(SIMD_4x32 x) const
Definition simd_hwaes.h:155
static consteval Gf2AffineTransformation post_sbox(uint64_t M, uint8_t c)
Definition simd_hwaes.h:139
consteval Gf2AffineTransformation(uint64_t M, uint8_t c)
Definition simd_hwaes.h:124
static consteval Gf2AffineTransformation post_inv_sbox(uint64_t M, uint8_t c)
Definition simd_hwaes.h:149
SIMD_4x32 BOTAN_FN_ISA_SIMD_4X32 shr() const noexcept
Definition simd_4x32.h:520
static SIMD_4x32 BOTAN_FN_ISA_SIMD_4X32 byte_shuffle(const SIMD_4x32 &tbl, const SIMD_4x32 &idx)
Definition simd_4x32.h:803
native_simd_type BOTAN_FN_ISA_SIMD_4X32 raw() const noexcept
Definition simd_4x32.h:942
static SIMD_4x32 BOTAN_FN_ISA_SIMD_4X32 splat_u8(uint8_t B) noexcept
Definition simd_4x32.h:144
constexpr uint64_t AES_AFF
Definition simd_hwaes.h:94
consteval uint8_t gf2_mat_vec(uint64_t M, uint8_t x)
Definition simd_hwaes.h:58
consteval uint64_t gf2_mat_mul(uint64_t A, uint64_t B)
Definition simd_hwaes.h:75
constexpr uint64_t AES_AFF_INV
Definition simd_hwaes.h:106
constexpr uint8_t AES_C_INV
Definition simd_hwaes.h:115
constexpr uint8_t AES_C
Definition simd_hwaes.h:103
consteval uint64_t gfni_matrix(std::string_view s)
Definition gfni_utils.h:17
SIMD_4x32 BOTAN_FN_ISA_HWAES hw_aes_inv_sbox(SIMD_4x32 x)
Definition simd_hwaes.h:37
SIMD_4x32 BOTAN_FN_ISA_HWAES hw_aes_sbox(SIMD_4x32 x)
Definition simd_hwaes.h:19