• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 23486908132

24 Mar 2026 10:53AM UTC coverage: 89.449% (-2.4%) from 91.889%
23486908132

push

github

web-flow
Merge pull request #5479 from randombit/jack/aria-hwaes

Add ARIA implementation using hardware AES instructions

105058 of 117450 relevant lines covered (89.45%)

11951797.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.17
/src/lib/block/twofish/twofish.cpp
1
/*
2
* Twofish
3
* (C) 1999-2007,2017,2026 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/internal/twofish.h>
9

10
#include <botan/internal/ct_utils.h>
11
#include <botan/internal/loadstor.h>
12
#include <botan/internal/rotate.h>
13

14
#if defined(BOTAN_HAS_CPUID)
15
   #include <botan/internal/cpuid.h>
16
#endif
17

18
namespace Botan {
19

20
namespace {
21

22
namespace Twofish_KS {
23

24
// Twofish q-permutation derived from four 4-bit sboxes
25
// ("Twofish: A 128-Bit Block Cipher", section 4.3.5)
26
consteval std::array<uint8_t, 256> twofish_q_perm(std::array<uint8_t, 16> t0,
27
                                                  std::array<uint8_t, 16> t1,
28
                                                  std::array<uint8_t, 16> t2,
29
                                                  std::array<uint8_t, 16> t3) noexcept {
30
   std::array<uint8_t, 256> Q = {};
31
   for(size_t x = 0; x != 256; ++x) {
32
      const uint8_t a0 = static_cast<uint8_t>((x >> 4) & 0x0F);
33
      const uint8_t b0 = static_cast<uint8_t>(x & 0x0F);
34

35
      const uint8_t a1 = a0 ^ b0;
36
      const uint8_t b1 = a0 ^ ((b0 >> 1) | ((b0 & 1) << 3)) ^ ((8 * a0) & 0x0F);
37

38
      const uint8_t a2 = t0[a1];
39
      const uint8_t b2 = t1[b1];
40

41
      const uint8_t a3 = a2 ^ b2;
42
      const uint8_t b3 = a2 ^ ((b2 >> 1) | ((b2 & 1) << 3)) ^ ((8 * a2) & 0x0F);
43

44
      const uint8_t a4 = t2[a3];
45
      const uint8_t b4 = t3[b3];
46

47
      Q[x] = static_cast<uint8_t>((b4 << 4) | a4);
48
   }
49
   return Q;
50
}
51

52
// clang-format off
53
alignas(256) constexpr auto Q0 = twofish_q_perm(
54
   {8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4},
55
   {14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13},
56
   {11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1},
57
   {13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10});
58

59
alignas(256) constexpr auto Q1 = twofish_q_perm(
60
   {2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5},
61
   {1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8},
62
   {4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15},
63
   {11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10});
64

65
// clang-format on
66

67
/*
68
* MDS matrix multiplication (Twofish paper Section 4.2)
69
*
70
* MDS = [01, EF, 5B, 5B]
71
*       [5B, EF, EF, 01]
72
*       [EF, 5B, 01, EF]
73
*       [EF, 01, EF, 5B]
74
*
75
* The MDS coefficients are 01, 5B, and EF. These were chosen so that
76
*
77
*   5B = 1 + 1/x^2
78
*   EF = 1 + 1/x + 1/x^2
79
*
80
* in GF(2^8) mod x^8+x^6+x^5+x^3+1, where 1/x is computed by shifting
81
* right and conditionally XORing with 0xB4 (which is itself just the
82
* irreducible polynomial 0x169 shifted right by 1).
83
*
84
* This property of the MDS constants is described (briefly) in Section 7.3
85
* of the Twofish paper.
86
*/
87

88
inline uint8_t mds_div_x(uint8_t q) {
5,214,720✔
89
   return (q >> 1) ^ (CT::value_barrier<uint8_t>(q & 1) * 0xB4);
5,214,720✔
90
}
91

92
inline uint32_t mds0(uint8_t q) {
1,236,480✔
93
   const uint8_t q_div_x = mds_div_x(q);
1,231,660✔
94
   const uint8_t q5b = q ^ mds_div_x(q_div_x);
1,236,480✔
95
   const uint8_t qef = q5b ^ q_div_x;
1,236,480✔
96
   return make_uint32(qef, qef, q5b, q);
1,236,480✔
97
}
98

99
inline uint32_t mds1(uint8_t q) {
1,326,080✔
100
   const uint8_t q_div_x = mds_div_x(q);
1,326,080✔
101
   const uint8_t q5b = q ^ mds_div_x(q_div_x);
1,326,080✔
102
   const uint8_t qef = q5b ^ q_div_x;
1,326,080✔
103
   return make_uint32(q, q5b, qef, qef);
1,326,080✔
104
}
105

106
inline uint32_t mds2(uint8_t q) {
1,326,080✔
107
   const uint8_t q_div_x = mds_div_x(q);
1,326,080✔
108
   const uint8_t q5b = q ^ mds_div_x(q_div_x);
1,326,080✔
109
   const uint8_t qef = q5b ^ q_div_x;
1,326,080✔
110
   return make_uint32(qef, q, qef, q5b);
1,326,080✔
111
}
112

113
inline uint32_t mds3(uint8_t q) {
1,326,080✔
114
   const uint8_t q_div_x = mds_div_x(q);
1,326,080✔
115
   const uint8_t q5b = q ^ mds_div_x(q_div_x);
1,326,080✔
116
   const uint8_t qef = q5b ^ q_div_x;
1,326,080✔
117
   return make_uint32(q5b, qef, q, q5b);
1,326,080✔
118
}
119

120
// Constant-time GF(2^8) multiply in the RS field (irreducible polynomial 0x14D)
121
inline uint32_t gf_mul_rs32(uint32_t rs, uint8_t k) {
134,504✔
122
   constexpr uint32_t lo_bit = 0x01010101;
134,504✔
123
   constexpr uint32_t mask = 0x7F7F7F7F;
134,504✔
124
   constexpr uint32_t poly = 0x4D;
134,504✔
125

126
   uint32_t r = 0;
134,504✔
127
   for(size_t i = 0; i != 8; ++i) {
1,210,536✔
128
      const auto k_lo = CT::Mask<uint32_t>::expand(k & 1);
1,076,032✔
129
      r ^= k_lo.if_set_return(rs);
1,076,032✔
130
      rs = ((rs & mask) << 1) ^ (((rs >> 7) & lo_bit) * poly);
1,076,032✔
131
      k >>= 1;
1,076,032✔
132
   }
133
   return r;
134,504✔
134
}
135

136
}  // namespace Twofish_KS
137

138
inline void TF_E(
334,080✔
139
   uint32_t A, uint32_t B, uint32_t& C, uint32_t& D, uint32_t RK1, uint32_t RK2, const secure_vector<uint32_t>& SB) {
140
   uint32_t X = SB[get_byte<3>(A)] ^ SB[256 + get_byte<2>(A)] ^ SB[512 + get_byte<1>(A)] ^ SB[768 + get_byte<0>(A)];
334,080✔
141
   uint32_t Y = SB[get_byte<0>(B)] ^ SB[256 + get_byte<3>(B)] ^ SB[512 + get_byte<2>(B)] ^ SB[768 + get_byte<1>(B)];
334,080✔
142

143
   X += Y;
334,080✔
144
   Y += X;
334,080✔
145

146
   X += RK1;
334,080✔
147
   Y += RK2;
334,080✔
148

149
   C = rotr<1>(C ^ X);
334,080✔
150
   D = rotl<1>(D) ^ Y;
334,080✔
151
}
334,080✔
152

153
inline void TF_D(
176,800✔
154
   uint32_t A, uint32_t B, uint32_t& C, uint32_t& D, uint32_t RK1, uint32_t RK2, const secure_vector<uint32_t>& SB) {
155
   uint32_t X = SB[get_byte<3>(A)] ^ SB[256 + get_byte<2>(A)] ^ SB[512 + get_byte<1>(A)] ^ SB[768 + get_byte<0>(A)];
176,800✔
156
   uint32_t Y = SB[get_byte<0>(B)] ^ SB[256 + get_byte<3>(B)] ^ SB[512 + get_byte<2>(B)] ^ SB[768 + get_byte<1>(B)];
176,800✔
157

158
   X += Y;
176,800✔
159
   Y += X;
176,800✔
160

161
   X += RK1;
176,800✔
162
   Y += RK2;
176,800✔
163

164
   C = rotl<1>(C) ^ X;
176,800✔
165
   D = rotr<1>(D ^ Y);
176,800✔
166
}
176,800✔
167

168
}  // namespace
169

170
/*
171
* Twofish Encryption
172
*/
173
void Twofish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
16,342✔
174
   assert_key_material_set();
16,342✔
175

176
#if defined(BOTAN_HAS_TWOFISH_AVX512)
177
   if(!m_QS.empty()) {
14,698✔
178
      while(blocks >= 16) {
×
179
         avx512_encrypt_16(in, out);
×
180
         in += 16 * BLOCK_SIZE;
×
181
         out += 16 * BLOCK_SIZE;
×
182
         blocks -= 16;
×
183
      }
184
   }
185
#endif
186

187
   while(blocks >= 2) {
18,714✔
188
      uint32_t A0 = 0;
4,016✔
189
      uint32_t B0 = 0;
4,016✔
190
      uint32_t C0 = 0;
4,016✔
191
      uint32_t D0 = 0;
4,016✔
192
      uint32_t A1 = 0;
4,016✔
193
      uint32_t B1 = 0;
4,016✔
194
      uint32_t C1 = 0;
4,016✔
195
      uint32_t D1 = 0;
4,016✔
196
      load_le(in, A0, B0, C0, D0, A1, B1, C1, D1);
4,016✔
197

198
      A0 ^= m_RK[0];
4,016✔
199
      A1 ^= m_RK[0];
4,016✔
200
      B0 ^= m_RK[1];
4,016✔
201
      B1 ^= m_RK[1];
4,016✔
202
      C0 ^= m_RK[2];
4,016✔
203
      C1 ^= m_RK[2];
4,016✔
204
      D0 ^= m_RK[3];
4,016✔
205
      D1 ^= m_RK[3];
4,016✔
206

207
      for(size_t k = 8; k != 40; k += 4) {
36,144✔
208
         TF_E(A0, B0, C0, D0, m_RK[k + 0], m_RK[k + 1], m_SB);
32,128✔
209
         TF_E(A1, B1, C1, D1, m_RK[k + 0], m_RK[k + 1], m_SB);
32,128✔
210

211
         TF_E(C0, D0, A0, B0, m_RK[k + 2], m_RK[k + 3], m_SB);
32,128✔
212
         TF_E(C1, D1, A1, B1, m_RK[k + 2], m_RK[k + 3], m_SB);
32,128✔
213
      }
214

215
      C0 ^= m_RK[4];
4,016✔
216
      C1 ^= m_RK[4];
4,016✔
217
      D0 ^= m_RK[5];
4,016✔
218
      D1 ^= m_RK[5];
4,016✔
219
      A0 ^= m_RK[6];
4,016✔
220
      A1 ^= m_RK[6];
4,016✔
221
      B0 ^= m_RK[7];
4,016✔
222
      B1 ^= m_RK[7];
4,016✔
223

224
      store_le(out, C0, D0, A0, B0, C1, D1, A1, B1);
4,016✔
225

226
      blocks -= 2;
4,016✔
227
      out += 2 * BLOCK_SIZE;
4,016✔
228
      in += 2 * BLOCK_SIZE;
4,016✔
229
   }
230

231
   if(blocks > 0) {
14,698✔
232
      uint32_t A = 0;
12,848✔
233
      uint32_t B = 0;
12,848✔
234
      uint32_t C = 0;
12,848✔
235
      uint32_t D = 0;
12,848✔
236
      load_le(in, A, B, C, D);
12,848✔
237

238
      A ^= m_RK[0];
12,848✔
239
      B ^= m_RK[1];
12,848✔
240
      C ^= m_RK[2];
12,848✔
241
      D ^= m_RK[3];
12,848✔
242

243
      for(size_t k = 8; k != 40; k += 4) {
115,632✔
244
         TF_E(A, B, C, D, m_RK[k], m_RK[k + 1], m_SB);
102,784✔
245
         TF_E(C, D, A, B, m_RK[k + 2], m_RK[k + 3], m_SB);
102,784✔
246
      }
247

248
      C ^= m_RK[4];
12,848✔
249
      D ^= m_RK[5];
12,848✔
250
      A ^= m_RK[6];
12,848✔
251
      B ^= m_RK[7];
12,848✔
252

253
      store_le(out, C, D, A, B);
12,848✔
254
   }
255
}
14,698✔
256

257
/*
258
* Twofish Decryption
259
*/
260
void Twofish::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
8,174✔
261
   assert_key_material_set();
8,174✔
262

263
#if defined(BOTAN_HAS_TWOFISH_AVX512)
264
   if(!m_QS.empty()) {
6,722✔
265
      while(blocks >= 16) {
×
266
         avx512_decrypt_16(in, out);
×
267
         in += 16 * BLOCK_SIZE;
×
268
         out += 16 * BLOCK_SIZE;
×
269
         blocks -= 16;
×
270
      }
271
   }
272
#endif
273

274
   while(blocks >= 2) {
9,502✔
275
      uint32_t A0 = 0;
2,780✔
276
      uint32_t B0 = 0;
2,780✔
277
      uint32_t C0 = 0;
2,780✔
278
      uint32_t D0 = 0;
2,780✔
279
      uint32_t A1 = 0;
2,780✔
280
      uint32_t B1 = 0;
2,780✔
281
      uint32_t C1 = 0;
2,780✔
282
      uint32_t D1 = 0;
2,780✔
283
      load_le(in, A0, B0, C0, D0, A1, B1, C1, D1);
2,780✔
284

285
      A0 ^= m_RK[4];
2,780✔
286
      A1 ^= m_RK[4];
2,780✔
287
      B0 ^= m_RK[5];
2,780✔
288
      B1 ^= m_RK[5];
2,780✔
289
      C0 ^= m_RK[6];
2,780✔
290
      C1 ^= m_RK[6];
2,780✔
291
      D0 ^= m_RK[7];
2,780✔
292
      D1 ^= m_RK[7];
2,780✔
293

294
      for(size_t k = 40; k != 8; k -= 4) {
25,020✔
295
         TF_D(A0, B0, C0, D0, m_RK[k - 2], m_RK[k - 1], m_SB);
22,240✔
296
         TF_D(A1, B1, C1, D1, m_RK[k - 2], m_RK[k - 1], m_SB);
22,240✔
297

298
         TF_D(C0, D0, A0, B0, m_RK[k - 4], m_RK[k - 3], m_SB);
22,240✔
299
         TF_D(C1, D1, A1, B1, m_RK[k - 4], m_RK[k - 3], m_SB);
22,240✔
300
      }
301

302
      C0 ^= m_RK[0];
2,780✔
303
      C1 ^= m_RK[0];
2,780✔
304
      D0 ^= m_RK[1];
2,780✔
305
      D1 ^= m_RK[1];
2,780✔
306
      A0 ^= m_RK[2];
2,780✔
307
      A1 ^= m_RK[2];
2,780✔
308
      B0 ^= m_RK[3];
2,780✔
309
      B1 ^= m_RK[3];
2,780✔
310

311
      store_le(out, C0, D0, A0, B0, C1, D1, A1, B1);
2,780✔
312

313
      blocks -= 2;
2,780✔
314
      out += 2 * BLOCK_SIZE;
2,780✔
315
      in += 2 * BLOCK_SIZE;
2,780✔
316
   }
317

318
   if(blocks > 0) {
6,722✔
319
      uint32_t A = 0;
5,490✔
320
      uint32_t B = 0;
5,490✔
321
      uint32_t C = 0;
5,490✔
322
      uint32_t D = 0;
5,490✔
323
      load_le(in, A, B, C, D);
5,490✔
324

325
      A ^= m_RK[4];
5,490✔
326
      B ^= m_RK[5];
5,490✔
327
      C ^= m_RK[6];
5,490✔
328
      D ^= m_RK[7];
5,490✔
329

330
      for(size_t k = 40; k != 8; k -= 4) {
49,410✔
331
         TF_D(A, B, C, D, m_RK[k - 2], m_RK[k - 1], m_SB);
43,920✔
332
         TF_D(C, D, A, B, m_RK[k - 4], m_RK[k - 3], m_SB);
43,920✔
333
      }
334

335
      C ^= m_RK[0];
5,490✔
336
      D ^= m_RK[1];
5,490✔
337
      A ^= m_RK[2];
5,490✔
338
      B ^= m_RK[3];
5,490✔
339

340
      store_le(out, C, D, A, B);
5,490✔
341
   }
342
}
6,722✔
343

344
bool Twofish::has_keying_material() const {
31,691✔
345
   return !m_SB.empty();
31,691✔
346
}
347

348
std::string Twofish::provider() const {
723✔
349
#if defined(BOTAN_HAS_TWOFISH_AVX512)
350
   if(CPUID::has(CPUID::Feature::AVX512, CPUID::Feature::GFNI)) {
723✔
351
      return "avx512";
×
352
   }
353
#endif
354
   return "base";
723✔
355
}
356

357
size_t Twofish::parallelism() const {
3,541✔
358
#if defined(BOTAN_HAS_TWOFISH_AVX512)
359
   if(CPUID::has(CPUID::Feature::AVX512, CPUID::Feature::GFNI)) {
3,541✔
360
      return 16;
×
361
   }
362
#endif
363
   return 1;
364
}
365

366
/*
367
* Twofish Key Schedule
368
*/
369
void Twofish::key_schedule(std::span<const uint8_t> key) {
4,480✔
370
   using namespace Twofish_KS;
4,480✔
371

372
   // Reed-Solomon matrix for key schedule (Twofish paper Section 4.3)
373
   // in column-major form
374

375
   // clang-format off
376
   constexpr uint32_t RS32[8] = {
4,480✔
377
      0x01A402A4,
378
      0xA456A155,
379
      0x5582FC87,
380
      0x87F3C15A,
381
      0x5A1E4758,
382
      0x58C6AEDB,
383
      0xDB683D9E,
384
      0x9EE51903
385
   };
386
   // clang-format on
387

388
   m_RK.resize(40);
4,480✔
389

390
   secure_vector<uint8_t> S(16);
4,480✔
391

392
   for(size_t i = 0; i != key.size(); ++i) {
138,984✔
393
      const uint8_t ki = key[i];
134,504✔
394
      const size_t s_off = 4 * (i / 8);
134,504✔
395

396
      const uint32_t p = gf_mul_rs32(RS32[i % 8], ki);
134,504✔
397

398
      S[s_off + 0] ^= get_byte<0>(p);
134,504✔
399
      S[s_off + 1] ^= get_byte<1>(p);
134,504✔
400
      S[s_off + 2] ^= get_byte<2>(p);
134,504✔
401
      S[s_off + 3] ^= get_byte<3>(p);
134,504✔
402
   }
403

404
   secure_vector<uint8_t> QS(1024);
4,480✔
405

406
   if(key.size() == 16) {
4,480✔
407
      for(size_t i = 0; i != 256; ++i) {
111,281✔
408
         QS[i] = Q1[Q0[Q0[i] ^ S[0]] ^ S[4]];
110,848✔
409
         QS[256 + i] = Q0[Q0[Q1[i] ^ S[1]] ^ S[5]];
110,848✔
410
         QS[512 + i] = Q1[Q1[Q0[i] ^ S[2]] ^ S[6]];
110,848✔
411
         QS[768 + i] = Q0[Q1[Q1[i] ^ S[3]] ^ S[7]];
110,848✔
412
      }
413

414
      for(size_t i = 0; i < 40; i += 2) {
9,093✔
415
         uint32_t X = mds0(Q1[Q0[Q0[i] ^ key[8]] ^ key[0]]) ^ mds1(Q0[Q0[Q1[i] ^ key[9]] ^ key[1]]) ^
8,660✔
416
                      mds2(Q1[Q1[Q0[i] ^ key[10]] ^ key[2]]) ^ mds3(Q0[Q1[Q1[i] ^ key[11]] ^ key[3]]);
8,660✔
417
         uint32_t Y = mds0(Q1[Q0[Q0[i + 1] ^ key[12]] ^ key[4]]) ^ mds1(Q0[Q0[Q1[i + 1] ^ key[13]] ^ key[5]]) ^
8,660✔
418
                      mds2(Q1[Q1[Q0[i + 1] ^ key[14]] ^ key[6]]) ^ mds3(Q0[Q1[Q1[i + 1] ^ key[15]] ^ key[7]]);
8,660✔
419
         Y = rotl<8>(Y);
8,660✔
420
         X += Y;
8,660✔
421
         Y += X;
8,660✔
422

423
         m_RK[i] = X;
8,660✔
424
         m_RK[i + 1] = rotl<9>(Y);
8,660✔
425
      }
426
   } else if(key.size() == 24) {
4,047✔
427
      for(size_t i = 0; i != 256; ++i) {
61,937✔
428
         QS[i] = Q1[Q0[Q0[Q1[i] ^ S[0]] ^ S[4]] ^ S[8]];
61,696✔
429
         QS[256 + i] = Q0[Q0[Q1[Q1[i] ^ S[1]] ^ S[5]] ^ S[9]];
61,696✔
430
         QS[512 + i] = Q1[Q1[Q0[Q0[i] ^ S[2]] ^ S[6]] ^ S[10]];
61,696✔
431
         QS[768 + i] = Q0[Q1[Q1[Q0[i] ^ S[3]] ^ S[7]] ^ S[11]];
61,696✔
432
      }
433

434
      for(size_t i = 0; i < 40; i += 2) {
5,061✔
435
         uint32_t X =
4,820✔
436
            mds0(Q1[Q0[Q0[Q1[i] ^ key[16]] ^ key[8]] ^ key[0]]) ^ mds1(Q0[Q0[Q1[Q1[i] ^ key[17]] ^ key[9]] ^ key[1]]) ^
4,820✔
437
            mds2(Q1[Q1[Q0[Q0[i] ^ key[18]] ^ key[10]] ^ key[2]]) ^ mds3(Q0[Q1[Q1[Q0[i] ^ key[19]] ^ key[11]] ^ key[3]]);
4,820✔
438
         uint32_t Y = mds0(Q1[Q0[Q0[Q1[i + 1] ^ key[20]] ^ key[12]] ^ key[4]]) ^
4,820✔
439
                      mds1(Q0[Q0[Q1[Q1[i + 1] ^ key[21]] ^ key[13]] ^ key[5]]) ^
4,820✔
440
                      mds2(Q1[Q1[Q0[Q0[i + 1] ^ key[22]] ^ key[14]] ^ key[6]]) ^
4,820✔
441
                      mds3(Q0[Q1[Q1[Q0[i + 1] ^ key[23]] ^ key[15]] ^ key[7]]);
4,820✔
442
         Y = rotl<8>(Y);
4,820✔
443
         X += Y;
4,820✔
444
         Y += X;
4,820✔
445

446
         m_RK[i] = X;
4,820✔
447
         m_RK[i + 1] = rotl<9>(Y);
4,820✔
448
      }
449
   } else if(key.size() == 32) {
3,806✔
450
      for(size_t i = 0; i != 256; ++i) {
978,142✔
451
         QS[i] = Q1[Q0[Q0[Q1[Q1[i] ^ S[0]] ^ S[4]] ^ S[8]] ^ S[12]];
974,336✔
452
         QS[256 + i] = Q0[Q0[Q1[Q1[Q0[i] ^ S[1]] ^ S[5]] ^ S[9]] ^ S[13]];
974,336✔
453
         QS[512 + i] = Q1[Q1[Q0[Q0[Q0[i] ^ S[2]] ^ S[6]] ^ S[10]] ^ S[14]];
974,336✔
454
         QS[768 + i] = Q0[Q1[Q1[Q0[Q1[i] ^ S[3]] ^ S[7]] ^ S[11]] ^ S[15]];
974,336✔
455
      }
456

457
      for(size_t i = 0; i < 40; i += 2) {
79,926✔
458
         uint32_t X = mds0(Q1[Q0[Q0[Q1[Q1[i] ^ key[24]] ^ key[16]] ^ key[8]] ^ key[0]]) ^
76,120✔
459
                      mds1(Q0[Q0[Q1[Q1[Q0[i] ^ key[25]] ^ key[17]] ^ key[9]] ^ key[1]]) ^
76,120✔
460
                      mds2(Q1[Q1[Q0[Q0[Q0[i] ^ key[26]] ^ key[18]] ^ key[10]] ^ key[2]]) ^
76,120✔
461
                      mds3(Q0[Q1[Q1[Q0[Q1[i] ^ key[27]] ^ key[19]] ^ key[11]] ^ key[3]]);
76,120✔
462
         uint32_t Y = mds0(Q1[Q0[Q0[Q1[Q1[i + 1] ^ key[28]] ^ key[20]] ^ key[12]] ^ key[4]]) ^
76,120✔
463
                      mds1(Q0[Q0[Q1[Q1[Q0[i + 1] ^ key[29]] ^ key[21]] ^ key[13]] ^ key[5]]) ^
76,120✔
464
                      mds2(Q1[Q1[Q0[Q0[Q0[i + 1] ^ key[30]] ^ key[22]] ^ key[14]] ^ key[6]]) ^
76,120✔
465
                      mds3(Q0[Q1[Q1[Q0[Q1[i + 1] ^ key[31]] ^ key[23]] ^ key[15]] ^ key[7]]);
76,120✔
466
         Y = rotl<8>(Y);
76,120✔
467
         X += Y;
76,120✔
468
         Y += X;
76,120✔
469

470
         m_RK[i] = X;
76,120✔
471
         m_RK[i + 1] = rotl<9>(Y);
76,120✔
472
      }
473
   }
474

475
   m_SB.resize(1024);
4,480✔
476
   for(size_t i = 0; i != 256; ++i) {
1,151,360✔
477
      m_SB[i] = mds0(QS[i]);
1,146,880✔
478
      m_SB[256 + i] = mds1(QS[256 + i]);
1,146,880✔
479
      m_SB[512 + i] = mds2(QS[512 + i]);
1,146,880✔
480
      m_SB[768 + i] = mds3(QS[768 + i]);
1,146,880✔
481
   }
482

483
#if defined(BOTAN_HAS_TWOFISH_AVX512)
484
   if(CPUID::has(CPUID::Feature::AVX512, CPUID::Feature::GFNI)) {
4,480✔
485
      m_QS = std::move(QS);
×
486
   }
487
#endif
488
}
8,960✔
489

490
/*
491
* Clear memory of sensitive data
492
*/
493
void Twofish::clear() {
2,738✔
494
   zap(m_SB);
2,738✔
495
   zap(m_RK);
2,738✔
496
   zap(m_QS);
2,738✔
497
}
2,738✔
498

499
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc