Botan 3.11.1
Crypto and TLS for C&
seed_hwaes.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/seed.h>
8
9#include <botan/mem_ops.h>
10#include <botan/internal/isa_extn.h>
11#include <botan/internal/simd_4x32.h>
12#include <botan/internal/simd_hwaes.h>
13
14namespace Botan {
15
16namespace SEED_HWAES {
17
18namespace {
19
20BOTAN_FORCE_INLINE BOTAN_FN_ISA_HWAES SIMD_4x32 seed_g(SIMD_4x32 X) {
21 // Field isomorphism from SEED's field (0x163) to AES field (0x11B)
22 constexpr uint64_t pre_a = gfni_matrix(R"(
23 1 1 0 1 0 0 0 0
24 0 0 1 1 0 0 1 1
25 0 0 0 0 1 1 0 1
26 0 1 1 1 0 1 0 0
27 0 1 1 0 1 0 0 0
28 0 0 0 1 1 0 0 0
29 0 0 1 1 1 1 0 0
30 0 0 0 0 1 1 1 0)");
31
32 // AES->SEED field isomorphism composed with S0's affine
33 constexpr uint64_t s0_post_a = gfni_matrix(R"(
34 0 1 0 1 1 0 0 1
35 0 0 1 1 1 0 1 0
36 1 0 0 0 1 1 1 0
37 1 1 0 0 1 0 0 1
38 0 1 0 1 1 0 1 1
39 1 1 1 1 1 0 1 1
40 0 0 1 1 0 1 0 1
41 0 0 0 1 0 1 1 1)");
42 constexpr uint8_t s0_post_c = 0xA9;
43
44 // AES->SEED field isomorphism composed with S1's affine
45 constexpr uint64_t s1_post_a = gfni_matrix(R"(
46 0 0 1 1 0 1 1 0
47 0 1 1 0 0 0 1 0
48 0 1 0 1 1 0 1 1
49 0 0 0 0 0 0 1 1
50 1 1 0 1 0 0 0 0
51 0 1 0 0 1 0 1 1
52 1 1 1 0 1 0 1 1
53 1 1 1 1 0 0 0 1)");
54 constexpr uint8_t s1_post_c = 0x38;
55
56 constexpr auto pre = Gf2AffineTransformation(pre_a, 0x00);
57 constexpr auto post_s0 = Gf2AffineTransformation::post_sbox(s0_post_a, s0_post_c);
58 constexpr auto post_s1 = Gf2AffineTransformation::post_sbox(s1_post_a, s1_post_c);
59
60 // Shared computation for S0(x) and S1(x)
61 const auto sub = hw_aes_sbox(pre.affine_transform(X));
62
63 // Compute S0(x) and S1(x)
64 const auto s0 = post_s0.affine_transform(sub);
65 const auto s1 = post_s1.affine_transform(sub);
66
67 // Blend S0(x) and S1(x) outputs in alternating bytes
68 const auto sbox = SIMD_4x32::byte_blend(0x00FF00FF, s0, s1);
69
70 // Linear mixing step
71 const auto M0 = SIMD_4x32::splat(0x3FCFF3FC);
72 const auto M1 = SIMD_4x32::splat(0xFC3FCFF3);
73 const auto M2 = SIMD_4x32::splat(0xF3FC3FCF);
74 const auto M3 = SIMD_4x32::splat(0xCFF3FC3F);
75
76 // Broadcast each byte of a 32-bit word to all 4 positions
77 const auto SHUF0 = SIMD_4x32(0x00000000, 0x04040404, 0x08080808, 0x0C0C0C0C);
78 const auto SHUF1 = SIMD_4x32(0x01010101, 0x05050505, 0x09090909, 0x0D0D0D0D);
79 const auto SHUF2 = SIMD_4x32(0x02020202, 0x06060606, 0x0A0A0A0A, 0x0E0E0E0E);
80 const auto SHUF3 = SIMD_4x32(0x03030303, 0x07070707, 0x0B0B0B0B, 0x0F0F0F0F);
81
82 auto b0 = SIMD_4x32::byte_shuffle(sbox, SHUF0);
83 auto b1 = SIMD_4x32::byte_shuffle(sbox, SHUF1);
84 auto b2 = SIMD_4x32::byte_shuffle(sbox, SHUF2);
85 auto b3 = SIMD_4x32::byte_shuffle(sbox, SHUF3);
86
87 return (b0 & M0) ^ (b1 & M1) ^ (b2 & M2) ^ (b3 & M3);
88}
89
90BOTAN_FORCE_INLINE BOTAN_FN_ISA_HWAES void seed_round(
91 SIMD_4x32& B0, SIMD_4x32& B1, SIMD_4x32& B2, SIMD_4x32& B3, uint32_t K0, uint32_t K1, uint32_t K2, uint32_t K3) {
92 auto T0 = B2 ^ SIMD_4x32::splat(K0);
93 auto T1 = seed_g(B2 ^ B3 ^ SIMD_4x32::splat(K1));
94 T0 = seed_g(T1 + T0);
95 T1 = seed_g(T1 + T0);
96 B1 ^= T1;
97 B0 ^= T0 + T1;
98
99 T0 = B0 ^ SIMD_4x32::splat(K2);
100 T1 = seed_g(B0 ^ B1 ^ SIMD_4x32::splat(K3));
101 T0 = seed_g(T1 + T0);
102 T1 = seed_g(T1 + T0);
103 B3 ^= T1;
104 B2 ^= T0 + T1;
105}
106
107BOTAN_FN_ISA_HWAES void encrypt_4(const uint8_t ptext[4 * 16], uint8_t ctext[4 * 16], std::span<const uint32_t> RK) {
108 auto B0 = SIMD_4x32::load_be(ptext);
109 auto B1 = SIMD_4x32::load_be(ptext + 16);
110 auto B2 = SIMD_4x32::load_be(ptext + 32);
111 auto B3 = SIMD_4x32::load_be(ptext + 48);
112
113 SIMD_4x32::transpose(B0, B1, B2, B3);
114
115 for(size_t j = 0; j != 8; ++j) {
116 const uint32_t K0 = RK[4 * j];
117 const uint32_t K1 = RK[4 * j + 1];
118 const uint32_t K2 = RK[4 * j + 2];
119 const uint32_t K3 = RK[4 * j + 3];
120
121 seed_round(B0, B1, B2, B3, K0, K1, K2, K3);
122 }
123
124 // Output order: B2, B3, B0, B1
125 SIMD_4x32::transpose(B2, B3, B0, B1);
126
127 B2.store_be(ctext);
128 B3.store_be(ctext + 16);
129 B0.store_be(ctext + 32);
130 B1.store_be(ctext + 48);
131}
132
133BOTAN_FN_ISA_HWAES void decrypt_4(const uint8_t ctext[4 * 16], uint8_t ptext[4 * 16], std::span<const uint32_t> RK) {
134 auto B0 = SIMD_4x32::load_be(ctext);
135 auto B1 = SIMD_4x32::load_be(ctext + 16);
136 auto B2 = SIMD_4x32::load_be(ctext + 32);
137 auto B3 = SIMD_4x32::load_be(ctext + 48);
138
139 SIMD_4x32::transpose(B0, B1, B2, B3);
140
141 for(size_t j = 0; j != 8; ++j) {
142 const uint32_t K0 = RK[30 - 4 * j];
143 const uint32_t K1 = RK[31 - 4 * j];
144 const uint32_t K2 = RK[28 - 4 * j];
145 const uint32_t K3 = RK[29 - 4 * j];
146
147 seed_round(B0, B1, B2, B3, K0, K1, K2, K3);
148 }
149
150 SIMD_4x32::transpose(B2, B3, B0, B1);
151
152 B2.store_be(ptext);
153 B3.store_be(ptext + 16);
154 B0.store_be(ptext + 32);
155 B1.store_be(ptext + 48);
156}
157
158} // namespace
159
160} // namespace SEED_HWAES
161
162void BOTAN_FN_ISA_HWAES SEED::hwaes_encrypt(const uint8_t ptext[], uint8_t ctext[], size_t blocks) const {
163 while(blocks >= 4) {
164 SEED_HWAES::encrypt_4(ptext, ctext, m_K);
165 ptext += 4 * 16;
166 ctext += 4 * 16;
167 blocks -= 4;
168 }
169
170 if(blocks > 0) {
171 uint8_t pbuf[4 * 16] = {0};
172 uint8_t cbuf[4 * 16] = {0};
173 copy_mem(pbuf, ptext, blocks * 16);
174 SEED_HWAES::encrypt_4(pbuf, cbuf, m_K);
175 copy_mem(ctext, cbuf, blocks * 16);
176 }
177}
178
179void BOTAN_FN_ISA_HWAES SEED::hwaes_decrypt(const uint8_t ctext[], uint8_t ptext[], size_t blocks) const {
180 while(blocks >= 4) {
181 SEED_HWAES::decrypt_4(ctext, ptext, m_K);
182 ptext += 4 * 16;
183 ctext += 4 * 16;
184 blocks -= 4;
185 }
186
187 if(blocks > 0) {
188 uint8_t cbuf[4 * 16] = {0};
189 uint8_t pbuf[4 * 16] = {0};
190 copy_mem(cbuf, ctext, blocks * 16);
191 SEED_HWAES::decrypt_4(cbuf, pbuf, m_K);
192 copy_mem(ptext, pbuf, blocks * 16);
193 }
194}
195
196} // namespace Botan
static consteval Gf2AffineTransformation post_sbox(uint64_t M, uint8_t c)
Definition simd_hwaes.h:139
static SIMD_4x32 BOTAN_FN_ISA_SIMD_4X32 load_be(const void *in) noexcept
Definition simd_4x32.h:189
static SIMD_4x32 BOTAN_FN_ISA_SIMD_4X32 byte_shuffle(const SIMD_4x32 &tbl, const SIMD_4x32 &idx)
Definition simd_4x32.h:803
static SIMD_4x32 BOTAN_FN_ISA_SIMD_4X32 byte_blend(const SIMD_4x32 &mask, const SIMD_4x32 &a, const SIMD_4x32 &b) noexcept
Definition simd_4x32.h:772
static SIMD_4x32 BOTAN_FN_ISA_SIMD_4X32 splat(uint32_t B) noexcept
Definition simd_4x32.h:127
static void BOTAN_FN_ISA_SIMD_4X32 transpose(SIMD_4x32 &B0, SIMD_4x32 &B1, SIMD_4x32 &B2, SIMD_4x32 &B3) noexcept
Definition simd_4x32.h:681
void BOTAN_FN_ISA_SIMD_4X32 store_be(uint32_t out[4]) const noexcept
Definition simd_4x32.h:223
#define BOTAN_FORCE_INLINE
Definition compiler.h:87
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
consteval uint64_t gfni_matrix(std::string_view s)
Definition gfni_utils.h:17
SIMD_4x32 BOTAN_FN_ISA_HWAES hw_aes_sbox(SIMD_4x32 x)
Definition simd_hwaes.h:19