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

randombit / botan / 38448057099

13 Oct 2026 04:10PM UTC coverage: 89.941% (-2.3%) from 92.197%
38448057099

push

github

web-flow
Merge pull request #6029 from randombit/jack/require-vsx

Require VSX (POWER8) support for SIMD

131906 of 146658 relevant lines covered (89.94%)

9367906.88 hits per line

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

99.36
/src/tests/test_simd.cpp
1
/*
2
* (C) 2017 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "tests.h"
8

9
#include <botan/hex.h>
10
#include <botan/strong_type.h>
11
#include <botan/internal/bswap.h>
12
#include <botan/internal/concat_util.h>
13
#include <botan/internal/isa_extn.h>
14
#include <botan/internal/loadstor.h>
15
#include <botan/internal/rotate.h>
16

17
#if defined(BOTAN_HAS_SIMD_4X32)
18
   #include <botan/internal/simd_4x32.h>
19
#endif
20

21
#if defined(BOTAN_HAS_SIMD_2X64)
22
   #include <botan/internal/simd_2x64.h>
23
#endif
24

25
#if defined(BOTAN_HAS_SIMD_8X32)
26
   #include <botan/internal/simd_8x32.h>
27
#endif
28

29
#if defined(BOTAN_HAS_CPUID)
30
   #include <botan/internal/cpuid.h>
31
#endif
32

33
namespace Botan_Tests {
34

35
namespace {
36

37
#if defined(BOTAN_HAS_SIMD_4X32) && defined(BOTAN_HAS_CPUID)
38

39
class SIMD_4X32_Tests final : public Test {
1 ✔
40
   public:
41
      std::vector<Test::Result> run() override {
1 ✔
42
         if(!Botan::CPUID::has(Botan::CPUID::Feature::SIMD_4X32)) {
1 ✔
43
            return {Test::Result::Note("simd_4x32", "Skipping tests due to missing SIMD support at runtime")};
×
44
         } else {
45
            return {test_simd_4x32()};
2 ✔
46
         }
47
      }
1 ✔
48

49
   private:
50
      Test::Result BOTAN_FN_ISA_SIMD_4X32 test_simd_4x32() {
1 ✔
51
         Test::Result result("SIMD_4x32");
1 ✔
52

53
         const uint32_t pat1 = 0xAABBCCDD;
1 ✔
54
         const uint32_t pat2 = 0x87654321;
1 ✔
55
         const uint32_t pat3 = 0x01234567;
1 ✔
56
         const uint32_t pat4 = 0xC0D0E0F0;
1 ✔
57

58
         // pat1 + pat{1,2,3,4}
59
         // precomputed to avoid integer overflow warnings
60
         const uint32_t pat1_1 = 0x557799BA;
1 ✔
61
         const uint32_t pat1_2 = 0x32210FFE;
1 ✔
62
         const uint32_t pat1_3 = 0xABDF1244;
1 ✔
63
         const uint32_t pat1_4 = 0x6B8CADCD;
1 ✔
64

65
         test_eq(result, "default init", Botan::SIMD_4x32(), 0, 0, 0, 0);
1 ✔
66
         test_eq(result, "SIMD scalar constructor", Botan::SIMD_4x32(1, 2, 3, 4), 1, 2, 3, 4);
1 ✔
67

68
         const Botan::SIMD_4x32 splat = Botan::SIMD_4x32::splat(pat1);
1 ✔
69

70
         test_eq(result, "splat", splat, pat1, pat1, pat1, pat1);
1 ✔
71

72
         const Botan::SIMD_4x32 input(pat1, pat2, pat3, pat4);
1 ✔
73

74
         result.test_u32_eq("SIMD_4x32::extract_word<0>", input.extract_word<0>(), pat1);
1 ✔
75
         result.test_u32_eq("SIMD_4x32::extract_word<1>", input.extract_word<1>(), pat2);
1 ✔
76
         result.test_u32_eq("SIMD_4x32::extract_word<2>", input.extract_word<2>(), pat3);
1 ✔
77
         result.test_u32_eq("SIMD_4x32::extract_word<3>", input.extract_word<3>(), pat4);
1 ✔
78

79
         const Botan::SIMD_4x32 rol = input.rotl<3>();
1 ✔
80

81
         test_eq(result,
1 ✔
82
                 "rotl",
83
                 rol,
84
                 Botan::rotl<3>(pat1),
85
                 Botan::rotl<3>(pat2),
86
                 Botan::rotl<3>(pat3),
87
                 Botan::rotl<3>(pat4));
88

89
         const Botan::SIMD_4x32 ror = input.rotr<9>();
1 ✔
90

91
         test_eq(result,
1 ✔
92
                 "rotr",
93
                 ror,
94
                 Botan::rotr<9>(pat1),
95
                 Botan::rotr<9>(pat2),
96
                 Botan::rotr<9>(pat3),
97
                 Botan::rotr<9>(pat4));
98

99
         Botan::SIMD_4x32 add = input + splat;
1 ✔
100
         test_eq(result, "add +", add, pat1_1, pat1_2, pat1_3, pat1_4);
1 ✔
101

102
         add -= splat;
1 ✔
103
         test_eq(result, "sub -=", add, pat1, pat2, pat3, pat4);
1 ✔
104

105
         add += splat;
1 ✔
106
         test_eq(result, "add +=", add, pat1_1, pat1_2, pat1_3, pat1_4);
1 ✔
107

108
         test_eq(result, "xor", input ^ splat, 0, pat2 ^ pat1, pat3 ^ pat1, pat4 ^ pat1);
1 ✔
109
         test_eq(result, "or", input | splat, pat1, pat2 | pat1, pat3 | pat1, pat4 | pat1);
1 ✔
110
         test_eq(result, "and", input & splat, pat1, pat2 & pat1, pat3 & pat1, pat4 & pat1);
1 ✔
111

112
         Botan::SIMD_4x32 blender = input;
1 ✔
113
         blender |= splat;
1 ✔
114
         test_eq(result, "|=", blender, pat1, pat2 | pat1, pat3 | pat1, pat4 | pat1);
1 ✔
115
         blender &= splat;
1 ✔
116
         test_eq(result, "&=", blender, pat1, pat1, pat1, pat1);
1 ✔
117
         blender ^= splat;
1 ✔
118
         test_eq(result, "^=", blender, 0, 0, 0, 0);
1 ✔
119

120
         blender = ~blender;
1 ✔
121
         test_eq(result, "~", blender, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF);
1 ✔
122

123
         blender = blender.shr<23>();
1 ✔
124
         test_eq(result, ">>", blender, 0x1FF, 0x1FF, 0x1FF, 0x1FF);
1 ✔
125

126
         blender = blender.shl<27>();
1 ✔
127
         test_eq(result, "<<", blender, 0xF8000000, 0xF8000000, 0xF8000000, 0xF8000000);
1 ✔
128

129
         blender = ~blender;
1 ✔
130
         test_eq(result, "~", blender, 0x7FFFFFF, 0x7FFFFFF, 0x7FFFFFF, 0x7FFFFFF);
1 ✔
131

132
         blender = input.andc(~blender);
1 ✔
133
         test_eq(
1 ✔
134
            result, "andc", blender, ~pat1 & 0xF8000000, ~pat2 & 0xF8000000, ~pat3 & 0xF8000000, ~pat4 & 0xF8000000);
135

136
         test_eq(result,
1 ✔
137
                 "bswap",
138
                 input.bswap(),
1 ✔
139
                 Botan::reverse_bytes(pat1),
140
                 Botan::reverse_bytes(pat2),
141
                 Botan::reverse_bytes(pat3),
142
                 Botan::reverse_bytes(pat4));
143

144
         test_eq(result,
1 ✔
145
                 "reverse_all_bytes",
146
                 Botan::SIMD_4x32(0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F).reverse_all_bytes(),
1 ✔
147
                 0x0F0E0D0C,
148
                 0x0B0A0908,
149
                 0x07060504,
150
                 0x03020100);
151

152
         Botan::SIMD_4x32 t1(pat1, pat2, pat3, pat4);
1 ✔
153
         Botan::SIMD_4x32 t2(pat1 + 1, pat2 + 1, pat3 + 1, pat4 + 1);
1 ✔
154
         Botan::SIMD_4x32 t3(pat1 + 2, pat2 + 2, pat3 + 2, pat4 + 2);
1 ✔
155
         Botan::SIMD_4x32 t4(pat1 + 3, pat2 + 3, pat3 + 3, pat4 + 3);
1 ✔
156

157
         Botan::SIMD_4x32::transpose(t1, t2, t3, t4);
1 ✔
158

159
         test_eq(result, "transpose t1", t1, pat1, pat1 + 1, pat1 + 2, pat1 + 3);
1 ✔
160
         test_eq(result, "transpose t2", t2, pat2, pat2 + 1, pat2 + 2, pat2 + 3);
1 ✔
161
         test_eq(result, "transpose t3", t3, pat3, pat3 + 1, pat3 + 2, pat3 + 3);
1 ✔
162
         test_eq(result, "transpose t4", t4, pat4, pat4 + 1, pat4 + 2, pat4 + 3);
1 ✔
163

164
         test_eq(result, "shift left 1", input.shift_elems_left<1>(), 0, pat1, pat2, pat3);
1 ✔
165
         test_eq(result, "shift left 2", input.shift_elems_left<2>(), 0, 0, pat1, pat2);
1 ✔
166
         test_eq(result, "shift left 3", input.shift_elems_left<3>(), 0, 0, 0, pat1);
1 ✔
167

168
         test_eq(result, "shift right 1", input.shift_elems_right<1>(), pat2, pat3, pat4, 0);
1 ✔
169
         test_eq(result, "shift right 2", input.shift_elems_right<2>(), pat3, pat4, 0, 0);
1 ✔
170
         test_eq(result, "shift right 3", input.shift_elems_right<3>(), pat4, 0, 0, 0);
1 ✔
171

172
         const auto ch = [](uint32_t m, uint32_t a, uint32_t b) -> uint32_t { return (m & a) | (~m & b); };
1 ✔
173
         const auto maj = [](uint32_t x, uint32_t y, uint32_t z) -> uint32_t { return (x & y) | (x & z) | (y & z); };
1 ✔
174
         const Botan::SIMD_4x32 rot1(pat2, pat3, pat4, pat1);
1 ✔
175
         const Botan::SIMD_4x32 rot2(pat3, pat4, pat1, pat2);
1 ✔
176

177
         test_eq(result,
1 ✔
178
                 "choose",
179
                 Botan::SIMD_4x32::choose(input, rot1, rot2),
1 ✔
180
                 ch(pat1, pat2, pat3),
181
                 ch(pat2, pat3, pat4),
182
                 ch(pat3, pat4, pat1),
183
                 ch(pat4, pat1, pat2));
184

185
         test_eq(result,
1 ✔
186
                 "majority",
187
                 Botan::SIMD_4x32::majority(input, rot1, rot2),
1 ✔
188
                 maj(pat1, pat2, pat3),
189
                 maj(pat2, pat3, pat4),
190
                 maj(pat3, pat4, pat1),
191
                 maj(pat4, pat1, pat2));
192

193
         // Test load/stores SIMD wrapper types
194
         const auto simd_le_in = Botan::hex_decode("ABCDEF01234567890123456789ABCDEF");
1 ✔
195
         const auto simd_be_in = Botan::hex_decode("0123456789ABCDEFABCDEF0123456789");
1 ✔
196
         const auto simd_le_array_in = Botan::concat(simd_le_in, simd_be_in);
1 ✔
197
         const auto simd_be_array_in = Botan::concat(simd_be_in, simd_le_in);
1 ✔
198

199
         const auto simd_le = Botan::load_le<Botan::SIMD_4x32>(simd_le_in);
1 ✔
200
         const auto simd_be = Botan::load_be<Botan::SIMD_4x32>(simd_be_in);
1 ✔
201
         const auto simd_le_array = Botan::load_le<std::array<Botan::SIMD_4x32, 2>>(simd_le_array_in);
1 ✔
202
         const auto simd_be_array = Botan::load_be<std::array<Botan::SIMD_4x32, 2>>(simd_be_array_in);
1 ✔
203

204
         auto simd_le_vec = Botan::store_le<std::vector<uint8_t>>(simd_le);
1 ✔
205
         auto simd_be_vec = Botan::store_be(simd_be);
1 ✔
206
         auto simd_le_array_vec = Botan::store_le<std::vector<uint8_t>>(simd_le_array);
1 ✔
207
         auto simd_be_array_vec = Botan::store_be(simd_be_array);
1 ✔
208

209
         result.test_bin_eq("roundtrip SIMD little-endian", simd_le_vec, simd_le_in);
1 ✔
210
         result.test_bin_eq(
1 ✔
211
            "roundtrip SIMD big-endian", std::vector(simd_be_vec.begin(), simd_be_vec.end()), simd_be_in);
1 ✔
212
         result.test_bin_eq("roundtrip SIMD array little-endian", simd_le_array_vec, simd_le_array_in);
1 ✔
213
         result.test_bin_eq("roundtrip SIMD array big-endian",
1 ✔
214
                            std::vector(simd_be_array_vec.begin(), simd_be_array_vec.end()),
1 ✔
215
                            simd_be_array_in);
216

217
         using StrongSIMD = Botan::Strong<Botan::SIMD_4x32, struct StrongSIMD_>;
1 ✔
218
         const auto simd_le_strong = Botan::load_le<StrongSIMD>(simd_le_in);
1 ✔
219
         const auto simd_be_strong = Botan::load_be<StrongSIMD>(simd_be_in);
1 ✔
220

221
         result.test_bin_eq(
1 ✔
222
            "roundtrip SIMD strong little-endian", Botan::store_le<std::vector<uint8_t>>(simd_le_strong), simd_le_in);
1 ✔
223
         result.test_bin_eq(
1 ✔
224
            "roundtrip SIMD strong big-endian", Botan::store_be<std::vector<uint8_t>>(simd_be_strong), simd_be_in);
1 ✔
225

226
         return {result};
2 ✔
227
      }
6 ✔
228

229
      static void BOTAN_FN_ISA_SIMD_4X32 test_eq(Test::Result& result,
33 ✔
230
                                                 const std::string& op,
231
                                                 const Botan::SIMD_4x32& simd,
232
                                                 uint32_t exp0,
233
                                                 uint32_t exp1,
234
                                                 uint32_t exp2,
235
                                                 uint32_t exp3) {
236
         uint8_t arr_be[16 + 15];
33 ✔
237
         uint8_t arr_be2[16 + 15];
33 ✔
238
         uint8_t arr_le[16 + 15];
33 ✔
239
         uint8_t arr_le2[16 + 15];
33 ✔
240

241
         for(size_t misalignment = 0; misalignment != 16; ++misalignment) {
561 ✔
242
            uint8_t* mem_be = arr_be + misalignment;
528 ✔
243
            uint8_t* mem_be2 = arr_be2 + misalignment;
528 ✔
244
            uint8_t* mem_le = arr_le + misalignment;
528 ✔
245
            uint8_t* mem_le2 = arr_le2 + misalignment;
528 ✔
246

247
            simd.store_be(mem_be);
528 ✔
248

249
            result.test_u32_eq(
1,056 ✔
250
               "SIMD_4x32 " + op + " elem0 BE", Botan::make_uint32(mem_be[0], mem_be[1], mem_be[2], mem_be[3]), exp0);
1,584 ✔
251
            result.test_u32_eq(
528 ✔
252
               "SIMD_4x32 " + op + " elem1 BE", Botan::make_uint32(mem_be[4], mem_be[5], mem_be[6], mem_be[7]), exp1);
1,584 ✔
253
            result.test_u32_eq(
528 ✔
254
               "SIMD_4x32 " + op + " elem2 BE", Botan::make_uint32(mem_be[8], mem_be[9], mem_be[10], mem_be[11]), exp2);
1,584 ✔
255
            result.test_u32_eq("SIMD_4x32 " + op + " elem3 BE",
1,056 ✔
256
                               Botan::make_uint32(mem_be[12], mem_be[13], mem_be[14], mem_be[15]),
528 ✔
257
                               exp3);
258

259
            // Check load_be+store_be results in same value
260
            const Botan::SIMD_4x32 reloaded_be = Botan::SIMD_4x32::load_be(mem_be);
528 ✔
261
            reloaded_be.store_be(mem_be2);
528 ✔
262
            result.test_bin_eq("SIMD_4x32 load_be", {mem_be, 16}, {mem_be2, 16});
528 ✔
263

264
            simd.store_le(mem_le);
528 ✔
265

266
            result.test_u32_eq(
1,056 ✔
267
               "SIMD_4x32 " + op + " elem0 LE", Botan::make_uint32(mem_le[3], mem_le[2], mem_le[1], mem_le[0]), exp0);
1,584 ✔
268
            result.test_u32_eq(
528 ✔
269
               "SIMD_4x32 " + op + " elem1 LE", Botan::make_uint32(mem_le[7], mem_le[6], mem_le[5], mem_le[4]), exp1);
1,584 ✔
270
            result.test_u32_eq(
528 ✔
271
               "SIMD_4x32 " + op + " elem2 LE", Botan::make_uint32(mem_le[11], mem_le[10], mem_le[9], mem_le[8]), exp2);
1,584 ✔
272
            result.test_u32_eq("SIMD_4x32 " + op + " elem3 LE",
1,056 ✔
273
                               Botan::make_uint32(mem_le[15], mem_le[14], mem_le[13], mem_le[12]),
528 ✔
274
                               exp3);
275

276
            // Check load_le+store_le results in same value
277
            const Botan::SIMD_4x32 reloaded_le = Botan::SIMD_4x32::load_le(mem_le);
528 ✔
278
            reloaded_le.store_le(mem_le2);
528 ✔
279
            result.test_bin_eq("SIMD_4x32 load_le", {mem_le, 16}, {mem_le2, 16});
528 ✔
280
         }
281
      }
33 ✔
282
};
283

284
BOTAN_REGISTER_TEST("utils", "simd_4x32", SIMD_4X32_Tests);
285
#endif
286

287
#if defined(BOTAN_HAS_SIMD_2X64) && defined(BOTAN_HAS_CPUID)
288

289
class SIMD_2X64_Tests final : public Test {
1 ✔
290
   public:
291
      std::vector<Test::Result> BOTAN_FN_ISA_SIMD_2X64 run() override {
1 ✔
292
         if(!Botan::CPUID::has(Botan::CPUID::Feature::SIMD_2X64)) {
1 ✔
293
            return {Test::Result::Note("simd_2x64", "Skipping tests due to missing SIMD support at runtime")};
×
294
         } else {
295
            return {test_simd_2x64()};
2 ✔
296
         }
297
      }
1 ✔
298

299
   private:
300
      Test::Result BOTAN_FN_ISA_SIMD_2X64 test_simd_2x64() {
1 ✔
301
         Test::Result result("SIMD_2x64");
1 ✔
302

303
         const uint64_t pat1 = 0x2F8C91D4A37E5C10;
1 ✔
304
         const uint64_t pat2 = 0x1B74A6F8C29D1345;
1 ✔
305

306
         const uint64_t pat1_1 = pat1 + pat1;
1 ✔
307
         const uint64_t pat1_2 = pat1 + pat2;
1 ✔
308

309
         test_eq(result, "default init", Botan::SIMD_2x64(), 0, 0);
1 ✔
310
         test_eq(result, "SIMD scalar constructor", Botan::SIMD_2x64(1, 2), 1, 2);
1 ✔
311

312
         const auto input = Botan::SIMD_2x64(pat1, pat2);
1 ✔
313
         const auto splat = Botan::SIMD_2x64(pat1, pat1);
1 ✔
314

315
         const auto rotl = input.rotl<3>();
1 ✔
316
         test_eq(result, "rotl", rotl, Botan::rotl<3>(pat1), Botan::rotl<3>(pat2));
1 ✔
317

318
         const auto rotr = input.rotr<9>();
1 ✔
319
         test_eq(result, "rotr", rotr, Botan::rotr<9>(pat1), Botan::rotr<9>(pat2));
1 ✔
320

321
         test_eq(result, "rotr<8>", input.rotr<8>(), Botan::rotr<8>(pat1), Botan::rotr<8>(pat2));
1 ✔
322
         test_eq(result, "rotr<16>", input.rotr<16>(), Botan::rotr<16>(pat1), Botan::rotr<16>(pat2));
1 ✔
323
         test_eq(result, "rotr<24>", input.rotr<24>(), Botan::rotr<24>(pat1), Botan::rotr<24>(pat2));
1 ✔
324
         test_eq(result, "rotr<32>", input.rotr<32>(), Botan::rotr<32>(pat1), Botan::rotr<32>(pat2));
1 ✔
325

326
         const auto add = input + splat;
1 ✔
327
         test_eq(result, "add +", add, pat1_1, pat1_2);
1 ✔
328

329
         test_eq(result, "xor", input ^ splat, 0, pat2 ^ pat1);
1 ✔
330

331
         auto shifter = Botan::SIMD_2x64(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
1 ✔
332
         shifter = shifter.shr<23>();
1 ✔
333
         test_eq(result, ">>", shifter, 0x1FFFFFFFFFF, 0x1FFFFFFFFFF);
1 ✔
334

335
         shifter = shifter.shl<27>();
1 ✔
336
         test_eq(result, "<<", shifter, 0xFFFFFFFFF8000000, 0xFFFFFFFFF8000000);
1 ✔
337

338
         shifter = input.andc(shifter);
1 ✔
339
         test_eq(result, "andc", shifter, ~pat1 & 0xFFFFFFFFF8000000, ~pat2 & 0xFFFFFFFFF8000000);
1 ✔
340

341
         test_eq(result, "bswap", input.bswap(), Botan::reverse_bytes(pat1), Botan::reverse_bytes(pat2));
1 ✔
342

343
         test_eq(result,
1 ✔
344
                 "reverse_all_bytes",
345
                 Botan::SIMD_2x64(0x0001020304050607, 0x08090a0b0c0d0e0f).reverse_all_bytes(),
1 ✔
346
                 0x0f0e0d0c0b0a0908,
347
                 0x0706050403020100);
348

349
         test_eq(result, "swap_lanes", Botan::SIMD_2x64(pat1, pat2).swap_lanes(), pat2, pat1);
1 ✔
350

351
         test_eq(result, "splat", Botan::SIMD_2x64::splat(pat2), pat2, pat2);
1 ✔
352

353
         const uint64_t native_words[2] = {pat1, pat2};
1 ✔
354
         test_eq(result, "load_native", Botan::SIMD_2x64::load_native(native_words), pat1, pat2);
1 ✔
355
         uint64_t native_out[2] = {0, 0};
1 ✔
356
         input.store_native(native_out);
1 ✔
357
         result.test_u64_eq("store_native word 0", native_out[0], pat1);
1 ✔
358
         result.test_u64_eq("store_native word 1", native_out[1], pat2);
1 ✔
359

360
         const uint64_t pat3 = 0x8E1C35D27F0B9A64;
1 ✔
361
         const auto other = Botan::SIMD_2x64(pat2, pat3);
1 ✔
362

363
         test_eq(result, "alignr8", Botan::SIMD_2x64::alignr8(input, other), pat3, pat1);
1 ✔
364

365
         const auto ch = [](uint64_t m, uint64_t a, uint64_t b) -> uint64_t { return (m & a) | (~m & b); };
1 ✔
366
         const auto maj = [](uint64_t x, uint64_t y, uint64_t z) -> uint64_t { return (x & y) | (x & z) | (y & z); };
1 ✔
367
         const auto mul2_32 = [](uint64_t x, uint64_t y) -> uint64_t {
1 ✔
368
            return 2 * static_cast<uint64_t>(static_cast<uint32_t>(x)) * static_cast<uint32_t>(y);
369
         };
370

371
         const auto third = Botan::SIMD_2x64(pat3, pat1);
1 ✔
372
         test_eq(result,
1 ✔
373
                 "choose",
374
                 Botan::SIMD_2x64::choose(input, other, third),
1 ✔
375
                 ch(pat1, pat2, pat3),
376
                 ch(pat2, pat3, pat1));
377
         test_eq(result,
1 ✔
378
                 "majority",
379
                 Botan::SIMD_2x64::majority(input, other, third),
1 ✔
380
                 maj(pat1, pat2, pat3),
381
                 maj(pat2, pat3, pat1));
382
         test_eq(result, "mul2_32", Botan::SIMD_2x64::mul2_32(input, other), mul2_32(pat1, pat2), mul2_32(pat2, pat3));
1 ✔
383

384
         const auto interleave_a = Botan::SIMD_2x64(0x1111111122222222, 0x3333333344444444);
1 ✔
385
         const auto interleave_b = Botan::SIMD_2x64(0x5555555566666666, 0x7777777788888888);
1 ✔
386
         test_eq(result,
1 ✔
387
                 "interleave_high",
388
                 Botan::SIMD_2x64::interleave_high(interleave_a, interleave_b),
1 ✔
389
                 0x3333333344444444,
390
                 0x7777777788888888);
391

392
         test_eq(result,
1 ✔
393
                 "interleave_low",
394
                 Botan::SIMD_2x64::interleave_low(interleave_a, interleave_b),
1 ✔
395
                 0x1111111122222222,
396
                 0x5555555566666666);
397

398
         test_eq(result, "all_ones", Botan::SIMD_2x64::all_ones(), 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
1 ✔
399

400
         // Test load/stores SIMD wrapper types
401
         const auto simd_le_in = Botan::hex_decode("ABCDEF01234567890123456789ABCDEF");
1 ✔
402
         const auto simd_be_in = Botan::hex_decode("0123456789ABCDEFABCDEF0123456789");
1 ✔
403
         const auto simd_le_array_in = Botan::concat(simd_le_in, simd_be_in);
1 ✔
404
         const auto simd_be_array_in = Botan::concat(simd_be_in, simd_le_in);
1 ✔
405

406
         const auto simd_le = Botan::load_le<Botan::SIMD_2x64>(simd_le_in);
1 ✔
407
         const auto simd_be = Botan::load_be<Botan::SIMD_2x64>(simd_be_in);
1 ✔
408
         const auto simd_le_array = Botan::load_le<std::array<Botan::SIMD_2x64, 2>>(simd_le_array_in);
1 ✔
409
         const auto simd_be_array = Botan::load_be<std::array<Botan::SIMD_2x64, 2>>(simd_be_array_in);
1 ✔
410

411
         auto simd_le_vec = Botan::store_le<std::vector<uint8_t>>(simd_le);
1 ✔
412
         auto simd_be_vec = Botan::store_be(simd_be);
1 ✔
413
         auto simd_le_array_vec = Botan::store_le<std::vector<uint8_t>>(simd_le_array);
1 ✔
414
         auto simd_be_array_vec = Botan::store_be(simd_be_array);
1 ✔
415

416
         result.test_bin_eq("roundtrip SIMD little-endian", simd_le_vec, simd_le_in);
1 ✔
417
         result.test_bin_eq(
1 ✔
418
            "roundtrip SIMD big-endian", std::vector(simd_be_vec.begin(), simd_be_vec.end()), simd_be_in);
1 ✔
419
         result.test_bin_eq("roundtrip SIMD array little-endian", simd_le_array_vec, simd_le_array_in);
1 ✔
420
         result.test_bin_eq("roundtrip SIMD array big-endian",
1 ✔
421
                            std::vector(simd_be_array_vec.begin(), simd_be_array_vec.end()),
1 ✔
422
                            simd_be_array_in);
423

424
         using StrongSIMD = Botan::Strong<Botan::SIMD_2x64, struct StrongSIMD_>;
1 ✔
425
         const auto simd_le_strong = Botan::load_le<StrongSIMD>(simd_le_in);
1 ✔
426
         const auto simd_be_strong = Botan::load_be<StrongSIMD>(simd_be_in);
1 ✔
427

428
         result.test_bin_eq(
1 ✔
429
            "roundtrip SIMD strong little-endian", Botan::store_le<std::vector<uint8_t>>(simd_le_strong), simd_le_in);
1 ✔
430
         result.test_bin_eq(
1 ✔
431
            "roundtrip SIMD strong big-endian", Botan::store_be<std::vector<uint8_t>>(simd_be_strong), simd_be_in);
1 ✔
432

433
         return {result};
2 ✔
434
      }
6 ✔
435

436
   private:
437
      static void BOTAN_FN_ISA_SIMD_2X64
438
      test_eq(Test::Result& result, const std::string& op, const Botan::SIMD_2x64& simd, uint64_t exp0, uint64_t exp1) {
25 ✔
439
         uint8_t arr_be[16 + 15];
25 ✔
440
         uint8_t arr_be2[16 + 15];
25 ✔
441
         uint8_t arr_le[16 + 15];
25 ✔
442
         uint8_t arr_le2[16 + 15];
25 ✔
443

444
         for(size_t misalignment = 0; misalignment != 16; ++misalignment) {
425 ✔
445
            uint8_t* mem_be = arr_be + misalignment;
400 ✔
446
            uint8_t* mem_be2 = arr_be2 + misalignment;
400 ✔
447
            uint8_t* mem_le = arr_le + misalignment;
400 ✔
448
            uint8_t* mem_le2 = arr_le2 + misalignment;
400 ✔
449

450
            simd.store_be(mem_be);
400 ✔
451

452
            result.test_u64_eq(
800 ✔
453
               "SIMD_2x64 " + op + " elem0 BE",
1,200 ✔
454
               Botan::make_uint64(
455
                  mem_be[0], mem_be[1], mem_be[2], mem_be[3], mem_be[4], mem_be[5], mem_be[6], mem_be[7]),
456
               exp0);
457
            result.test_u64_eq(
400 ✔
458
               "SIMD_2x64 " + op + " elem1 BE",
1,200 ✔
459
               Botan::make_uint64(
460
                  mem_be[8], mem_be[9], mem_be[10], mem_be[11], mem_be[12], mem_be[13], mem_be[14], mem_be[15]),
400 ✔
461
               exp1);
462

463
            // Check load_be+store_be results in same value
464
            const Botan::SIMD_2x64 reloaded_be = Botan::SIMD_2x64::load_be(mem_be);
400 ✔
465
            reloaded_be.store_be(mem_be2);
400 ✔
466
            result.test_bin_eq("SIMD_2x64 load_be", {mem_be, 16}, {mem_be2, 16});
400 ✔
467

468
            simd.store_le(mem_le);
400 ✔
469

470
            result.test_u64_eq(
800 ✔
471
               "SIMD_2x64 " + op + " elem0 LE",
1,200 ✔
472
               Botan::make_uint64(
473
                  mem_le[7], mem_le[6], mem_le[5], mem_le[4], mem_le[3], mem_le[2], mem_le[1], mem_le[0]),
474
               exp0);
475
            result.test_u64_eq(
400 ✔
476
               "SIMD_2x64 " + op + " elem1 LE",
1,200 ✔
477
               Botan::make_uint64(
478
                  mem_le[15], mem_le[14], mem_le[13], mem_le[12], mem_le[11], mem_le[10], mem_le[9], mem_le[8]),
400 ✔
479
               exp1);
480

481
            // Check load_le+store_le results in same value
482
            const Botan::SIMD_2x64 reloaded_le = Botan::SIMD_2x64::load_le(mem_le);
400 ✔
483
            reloaded_le.store_le(mem_le2);
400 ✔
484
            result.test_bin_eq("SIMD_2x64 load_le", {mem_le, 16}, {mem_le2, 16});
400 ✔
485
         }
486
      }
25 ✔
487
};
488

489
BOTAN_REGISTER_TEST("utils", "simd_2x64", SIMD_2X64_Tests);
490
#endif
491

492
#if defined(BOTAN_HAS_SIMD_8X32) && defined(BOTAN_HAS_CPUID)
493

494
class SIMD_8X32_Tests final : public Test {
1 ✔
495
   public:
496
      std::vector<Test::Result> run() override {
1 ✔
497
         if(!Botan::CPUID::has(Botan::CPUID::Feature::SIMD_8X32)) {
1 ✔
498
            return {Test::Result::Note("simd_8x32", "Skipping tests due to missing SIMD support at runtime")};
×
499
         } else {
500
            return {test_simd_8x32()};
2 ✔
501
         }
502
      }
1 ✔
503

504
   private:
505
      using W8 = std::array<uint32_t, 8>;
506

507
      Test::Result BOTAN_FN_ISA_SIMD_8X32 test_simd_8x32() {
1 ✔
508
         Test::Result result("SIMD_8x32");
1 ✔
509

510
         const W8 pat = {
1 ✔
511
            0xAABBCCDD, 0x87654321, 0x01234567, 0xC0D0E0F0, 0x13579BDF, 0x2468ACE0, 0xFEDCBA98, 0x76543210};
512

513
         test_eq(result, "default init", Botan::SIMD_8x32(), W8{0, 0, 0, 0, 0, 0, 0, 0});
1 ✔
514
         test_eq(result, "scalar constructor", Botan::SIMD_8x32(1, 2, 3, 4, 5, 6, 7, 8), W8{1, 2, 3, 4, 5, 6, 7, 8});
1 ✔
515
         test_eq(result, "4 word constructor", Botan::SIMD_8x32(1, 2, 3, 4), W8{1, 2, 3, 4, 1, 2, 3, 4});
1 ✔
516
         test_eq(result, "array constructor", Botan::SIMD_8x32(pat.data()), pat);
1 ✔
517
         test_eq(result, "splat", Botan::SIMD_8x32::splat(pat[0]), splat8(pat[0]));
1 ✔
518

519
         const Botan::SIMD_8x32 input(pat.data());
1 ✔
520
         const Botan::SIMD_8x32 splat = Botan::SIMD_8x32::splat(pat[0]);
1 ✔
521

522
         test_eq(result, "rotl<3>", input.rotl<3>(), map(pat, [](uint32_t x) { return Botan::rotl<3>(x); }));
1 ✔
523
         test_eq(result, "rotl<8>", input.rotl<8>(), map(pat, [](uint32_t x) { return Botan::rotl<8>(x); }));
1 ✔
524
         test_eq(result, "rotl<16>", input.rotl<16>(), map(pat, [](uint32_t x) { return Botan::rotl<16>(x); }));
1 ✔
525
         test_eq(result, "rotl<24>", input.rotl<24>(), map(pat, [](uint32_t x) { return Botan::rotl<24>(x); }));
1 ✔
526
         test_eq(result, "rotr<9>", input.rotr<9>(), map(pat, [](uint32_t x) { return Botan::rotr<9>(x); }));
1 ✔
527

528
         test_eq(result, "sigma0", input.sigma0(), map(pat, [](uint32_t x) {
1 ✔
529
                    return Botan::rotr<2>(x) ^ Botan::rotr<13>(x) ^ Botan::rotr<22>(x);
8 ✔
530
                 }));
531
         test_eq(result, "sigma1", input.sigma1(), map(pat, [](uint32_t x) {
1 ✔
532
                    return Botan::rotr<6>(x) ^ Botan::rotr<11>(x) ^ Botan::rotr<25>(x);
8 ✔
533
                 }));
534

535
         test_eq(
1 ✔
536
            result, "add +", input + splat, zip(pat, splat8(pat[0]), [](uint32_t x, uint32_t y) { return x + y; }));
1 ✔
537
         test_eq(
1 ✔
538
            result, "sub -", input - splat, zip(pat, splat8(pat[0]), [](uint32_t x, uint32_t y) { return x - y; }));
1 ✔
539
         test_eq(result, "xor", input ^ splat, zip(pat, splat8(pat[0]), [](uint32_t x, uint32_t y) { return x ^ y; }));
1 ✔
540
         test_eq(result, "or", input | splat, zip(pat, splat8(pat[0]), [](uint32_t x, uint32_t y) { return x | y; }));
1 ✔
541
         test_eq(result, "and", input & splat, zip(pat, splat8(pat[0]), [](uint32_t x, uint32_t y) { return x & y; }));
1 ✔
542

543
         Botan::SIMD_8x32 acc = input;
1 ✔
544
         acc += splat;
1 ✔
545
         test_eq(result, "+=", acc, zip(pat, splat8(pat[0]), [](uint32_t x, uint32_t y) { return x + y; }));
1 ✔
546
         acc -= splat;
1 ✔
547
         test_eq(result, "-=", acc, pat);
1 ✔
548
         acc |= splat;
1 ✔
549
         test_eq(result, "|=", acc, zip(pat, splat8(pat[0]), [](uint32_t x, uint32_t y) { return x | y; }));
1 ✔
550
         acc &= splat;
1 ✔
551
         test_eq(result, "&=", acc, splat8(pat[0]));
1 ✔
552
         acc ^= splat;
1 ✔
553
         test_eq(result, "^=", acc, W8{0, 0, 0, 0, 0, 0, 0, 0});
1 ✔
554
         acc ^= pat[1];
1 ✔
555
         test_eq(result, "^= u32", acc, splat8(pat[1]));
1 ✔
556

557
         test_eq(result, "~", ~input, map(pat, [](uint32_t x) { return ~x; }));
1 ✔
558
         test_eq(result, "shl<5>", input.shl<5>(), map(pat, [](uint32_t x) { return x << 5; }));
1 ✔
559
         test_eq(result, "shr<7>", input.shr<7>(), map(pat, [](uint32_t x) { return x >> 7; }));
1 ✔
560
         test_eq(
1 ✔
561
            result, "andc", input.andc(splat), zip(pat, splat8(pat[0]), [](uint32_t x, uint32_t y) { return ~x & y; }));
1 ✔
562

563
         test_eq(result, "bswap", input.bswap(), map(pat, [](uint32_t x) { return Botan::reverse_bytes(x); }));
1 ✔
564
         test_eq(
1 ✔
565
            result, "rev_words", input.rev_words(), W8{pat[3], pat[2], pat[1], pat[0], pat[7], pat[6], pat[5], pat[4]});
1 ✔
566
         test_eq(result, "reverse", input.reverse(), input.rev_words().bswap());
2 ✔
567

568
         const auto lo_mask = Botan::SIMD_8x32(0xFFFFFFFF, 0, 0xFFFFFFFF, 0, 0, 0xFFFFFFFF, 0, 0xFFFFFFFF);
1 ✔
569
         test_eq(result,
1 ✔
570
                 "choose",
571
                 Botan::SIMD_8x32::choose(lo_mask, input, splat),
1 ✔
572
                 W8{pat[0], pat[0], pat[2], pat[0], pat[0], pat[5], pat[0], pat[7]});
1 ✔
573

574
         const auto maj_x =
1 ✔
575
            Botan::SIMD_8x32(0xF0F0F0F0, 0x00000000, 0xFFFFFFFF, 0x12345678, 0xF0F0F0F0, 0, 0xFFFFFFFF, 0x12345678);
1 ✔
576
         const auto maj_y = Botan::SIMD_8x32(
1 ✔
577
            0xFF00FF00, 0xFFFFFFFF, 0xFFFFFFFF, 0x0F0F0F0F, 0xFF00FF00, 0xFFFFFFFF, 0xFFFFFFFF, 0x0F0F0F0F);
1 ✔
578
         const auto maj_z =
1 ✔
579
            Botan::SIMD_8x32(0xAAAAAAAA, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xAAAAAAAA, 0, 0, 0xFFFFFFFF);
1 ✔
580
         test_eq(result,
1 ✔
581
                 "majority",
582
                 Botan::SIMD_8x32::majority(maj_x, maj_y, maj_z),
1 ✔
583
                 W8{(0xF0F0F0F0 & 0xFF00FF00) | (0xF0F0F0F0 & 0xAAAAAAAA) | (0xFF00FF00 & 0xAAAAAAAA),
1 ✔
584
                    0,
585
                    0xFFFFFFFF,
586
                    (0x12345678 & 0x0F0F0F0F) | (0x12345678 & 0xFFFFFFFF) | (0x0F0F0F0F & 0xFFFFFFFF),
587
                    (0xF0F0F0F0 & 0xFF00FF00) | (0xF0F0F0F0 & 0xAAAAAAAA) | (0xFF00FF00 & 0xAAAAAAAA),
588
                    0,
589
                    0xFFFFFFFF,
590
                    (0x12345678 & 0x0F0F0F0F) | (0x12345678 & 0xFFFFFFFF) | (0x0F0F0F0F & 0xFFFFFFFF)});
591

592
         const auto ult_a = Botan::SIMD_8x32(0, 1, 0x80000000, 0xFFFFFFFF, 5, 0x7FFFFFFF, 0x80000001, 0x80000000);
1 ✔
593
         const auto ult_b = Botan::SIMD_8x32(1, 0, 0x7FFFFFFF, 0xFFFFFFFF, 5, 0x80000000, 0x80000000, 0x80000001);
1 ✔
594
         test_eq(
1 ✔
595
            result, "unsigned_lt", ult_a.unsigned_lt(ult_b), W8{0xFFFFFFFF, 0, 0, 0, 0, 0xFFFFFFFF, 0, 0xFFFFFFFF});
1 ✔
596

597
         test_eq(result,
1 ✔
598
                 "shift_elems_left<1>",
599
                 input.shift_elems_left<1>(),
1 ✔
600
                 W8{0, pat[0], pat[1], pat[2], 0, pat[4], pat[5], pat[6]});
1 ✔
601
         test_eq(
1 ✔
602
            result, "shift_elems_left<2>", input.shift_elems_left<2>(), W8{0, 0, pat[0], pat[1], 0, 0, pat[4], pat[5]});
1 ✔
603
         test_eq(result, "shift_elems_left<3>", input.shift_elems_left<3>(), W8{0, 0, 0, pat[0], 0, 0, 0, pat[4]});
1 ✔
604
         test_eq(result,
1 ✔
605
                 "shift_elems_right<1>",
606
                 input.shift_elems_right<1>(),
1 ✔
607
                 W8{pat[1], pat[2], pat[3], 0, pat[5], pat[6], pat[7], 0});
1 ✔
608
         test_eq(result,
1 ✔
609
                 "shift_elems_right<2>",
610
                 input.shift_elems_right<2>(),
1 ✔
611
                 W8{pat[2], pat[3], 0, 0, pat[6], pat[7], 0, 0});
1 ✔
612
         test_eq(result, "shift_elems_right<3>", input.shift_elems_right<3>(), W8{pat[3], 0, 0, 0, pat[7], 0, 0, 0});
1 ✔
613

614
         const Botan::SIMD_8x32 other(11, 12, 13, 14, 15, 16, 17, 18);
1 ✔
615
         test_eq(result,
1 ✔
616
                 "alignr8",
617
                 Botan::SIMD_8x32::alignr8(other, input),
1 ✔
618
                 W8{pat[2], pat[3], 11, 12, pat[6], pat[7], 15, 16});
1 ✔
619

620
         // Byte shuffle within each lane: reverse the byte order of each 32-bit word (ie bswap)
621
         const Botan::SIMD_8x32 bswap_idx(0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F);
1 ✔
622
         test_eq(result, "byte_shuffle bswap", Botan::SIMD_8x32::byte_shuffle(input, bswap_idx), input.bswap());
2 ✔
623
         // Byte shuffle within each lane: reverse the byte order of the whole lane
624
         const Botan::SIMD_8x32 rev_idx(0x0C0D0E0F, 0x08090A0B, 0x04050607, 0x00010203);
1 ✔
625
         test_eq(result, "byte_shuffle reverse", Botan::SIMD_8x32::byte_shuffle(input, rev_idx), input.reverse());
2 ✔
626
         // Broadcast the first word of each lane
627
         const Botan::SIMD_8x32 splat_idx(0x03020100, 0x03020100, 0x03020100, 0x03020100);
1 ✔
628
         test_eq(result,
1 ✔
629
                 "byte_shuffle splat",
630
                 Botan::SIMD_8x32::byte_shuffle(input, splat_idx),
1 ✔
631
                 W8{pat[0], pat[0], pat[0], pat[0], pat[4], pat[4], pat[4], pat[4]});
1 ✔
632

633
         test_eq(result,
1 ✔
634
                 "swap_halves",
635
                 input.swap_halves(),
1 ✔
636
                 W8{pat[4], pat[5], pat[6], pat[7], pat[0], pat[1], pat[2], pat[3]});
1 ✔
637

638
         // Masked shuffle: reverse the bytes of the first word of each half, zero the rest
639
         const Botan::SIMD_8x32 mrev_idx(0x00010203, 0xFFFFFFFF, 0x80808080, 0xFFFFFFFF);
1 ✔
640
         test_eq(result,
1 ✔
641
                 "masked_byte_shuffle",
642
                 Botan::SIMD_8x32::masked_byte_shuffle(input, mrev_idx),
1 ✔
643
                 W8{Botan::reverse_bytes(pat[0]), 0, 0, 0, Botan::reverse_bytes(pat[4]), 0, 0, 0});
1 ✔
644
         // Bits 4-6 of an index are ignored, unless the top bit is set
645
         const Botan::SIMD_8x32 mzero_idx(0x73727170, 0x0F0E0D0C, 0xC7C6C5C4, 0x0B0A0908);
1 ✔
646
         test_eq(result,
1 ✔
647
                 "masked_byte_shuffle high bits",
648
                 Botan::SIMD_8x32::masked_byte_shuffle(input, mzero_idx),
1 ✔
649
                 W8{pat[0], pat[3], 0, pat[2], pat[4], pat[7], 0, pat[6]});
1 ✔
650

651
         // Load xtime input at runtime, otherwise MSVC performs in incorrect constant folding
652
         const auto xt_bytes = Botan::hex_decode("1020408001020408C0007FFFEC763B1D1020408001020408C0007FFFEC763B1D");
1 ✔
653
         const auto xt_in = Botan::SIMD_8x32::load_le(xt_bytes.data());
1 ✔
654
         test_eq(result,
1 ✔
655
                 "xtime<0x1D>",
656
                 xt_in.xtime<0x1D>(),
1 ✔
657
                 W8{0x1D804020, 0x10080402, 0xE3FE009D, 0x3A76ECC5, 0x1D804020, 0x10080402, 0xE3FE009D, 0x3A76ECC5});
1 ✔
658
         test_eq(result,
1 ✔
659
                 "xtime<0x1B>",
660
                 xt_in.xtime<0x1B>(),
1 ✔
661
                 W8{0x1B804020, 0x10080402, 0xE5FE009B, 0x3A76ECC3, 0x1B804020, 0x10080402, 0xE5FE009B, 0x3A76ECC3});
1 ✔
662

663
         Botan::SIMD_8x32 t0(pat[0], pat[1], pat[2], pat[3], pat[4], pat[5], pat[6], pat[7]);
1 ✔
664
         Botan::SIMD_8x32 t1(
1 ✔
665
            pat[0] + 1, pat[1] + 1, pat[2] + 1, pat[3] + 1, pat[4] + 1, pat[5] + 1, pat[6] + 1, pat[7] + 1);
1 ✔
666
         Botan::SIMD_8x32 t2(
1 ✔
667
            pat[0] + 2, pat[1] + 2, pat[2] + 2, pat[3] + 2, pat[4] + 2, pat[5] + 2, pat[6] + 2, pat[7] + 2);
1 ✔
668
         Botan::SIMD_8x32 t3(
1 ✔
669
            pat[0] + 3, pat[1] + 3, pat[2] + 3, pat[3] + 3, pat[4] + 3, pat[5] + 3, pat[6] + 3, pat[7] + 3);
1 ✔
670

671
         Botan::SIMD_8x32::transpose(t0, t1, t2, t3);
1 ✔
672

673
         test_eq(result,
1 ✔
674
                 "transpose4 t0",
675
                 t0,
676
                 W8{pat[0], pat[0] + 1, pat[0] + 2, pat[0] + 3, pat[4], pat[4] + 1, pat[4] + 2, pat[4] + 3});
1 ✔
677
         test_eq(result,
1 ✔
678
                 "transpose4 t1",
679
                 t1,
680
                 W8{pat[1], pat[1] + 1, pat[1] + 2, pat[1] + 3, pat[5], pat[5] + 1, pat[5] + 2, pat[5] + 3});
1 ✔
681
         test_eq(result,
1 ✔
682
                 "transpose4 t2",
683
                 t2,
684
                 W8{pat[2], pat[2] + 1, pat[2] + 2, pat[2] + 3, pat[6], pat[6] + 1, pat[6] + 2, pat[6] + 3});
1 ✔
685
         test_eq(result,
1 ✔
686
                 "transpose4 t3",
687
                 t3,
688
                 W8{pat[3], pat[3] + 1, pat[3] + 2, pat[3] + 3, pat[7], pat[7] + 1, pat[7] + 2, pat[7] + 3});
1 ✔
689

690
         // Fill 8 registers with r*8+c and check that the 8x8 transpose gives c*8+r
691
         Botan::SIMD_8x32 m[8];
9 ✔
692
         for(uint32_t r = 0; r != 8; ++r) {
9 ✔
693
            m[r] = Botan::SIMD_8x32(r * 8, r * 8 + 1, r * 8 + 2, r * 8 + 3, r * 8 + 4, r * 8 + 5, r * 8 + 6, r * 8 + 7);
8 ✔
694
         }
695
         Botan::SIMD_8x32::transpose(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7]);
1 ✔
696
         for(uint32_t c = 0; c != 8; ++c) {
9 ✔
697
            test_eq(result, "transpose8", m[c], W8{c, 8 + c, 16 + c, 24 + c, 32 + c, 40 + c, 48 + c, 56 + c});
16 ✔
698
         }
699

700
         // Load/store variants
701
         const auto in32 = Botan::hex_decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
1 ✔
702
         const auto le = Botan::SIMD_8x32::load_le(in32.data());
1 ✔
703
         test_eq(result,
1 ✔
704
                 "load_le",
705
                 le,
706
                 W8{0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x13121110, 0x17161514, 0x1B1A1918, 0x1F1E1D1C});
1 ✔
707
         const auto be = Botan::SIMD_8x32::load_be(in32.data());
1 ✔
708
         test_eq(result,
1 ✔
709
                 "load_be",
710
                 be,
711
                 W8{0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F, 0x10111213, 0x14151617, 0x18191A1B, 0x1C1D1E1F});
1 ✔
712

713
         const auto b128 = Botan::SIMD_8x32::load_le128(in32.data());
1 ✔
714
         test_eq(result,
1 ✔
715
                 "load_le128 broadcast",
716
                 b128,
717
                 W8{0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C});
1 ✔
718
         const auto b128w = Botan::SIMD_8x32::load_le128(reinterpret_cast<const uint32_t*>(in32.data()));
1 ✔
719
         test_eq(result,
1 ✔
720
                 "load_le128 broadcast u32",
721
                 b128w,
722
                 W8{0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C, 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C});
1 ✔
723

724
         // NOLINTBEGIN(*-container-data-pointer)
725
         const auto le2 = Botan::SIMD_8x32::load_le128(reinterpret_cast<const uint32_t*>(&in32[16]),
1 ✔
726
                                                       reinterpret_cast<const uint32_t*>(&in32[0]));
1 ✔
727
         test_eq(result,
1 ✔
728
                 "load_le128 two u32 ptrs",
729
                 le2,
730
                 W8{0x13121110, 0x17161514, 0x1B1A1918, 0x1F1E1D1C, 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C});
1 ✔
731
         const auto be2 = Botan::SIMD_8x32::load_be128(&in32[16], &in32[0]);
1 ✔
732
         test_eq(result,
1 ✔
733
                 "load_be128 two ptrs",
734
                 be2,
735
                 W8{0x10111213, 0x14151617, 0x18191A1B, 0x1C1D1E1F, 0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F});
1 ✔
736

737
         uint8_t out16[16];
1 ✔
738
         le2.store_le128(out16);
1 ✔
739
         result.test_bin_eq(
1 ✔
740
            "store_le128 low", std::span<const uint8_t>(out16), std::span<const uint8_t>(&in32[16], 16));
1 ✔
741

742
         uint32_t out32a[4];
1 ✔
743
         uint32_t out32b[4];
1 ✔
744
         le2.store_le128(out32a, out32b);
1 ✔
745
         result.test_bin_eq("store_le128 two u32 ptrs (low)",
1 ✔
746
                            std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(out32a), 16),
747
                            std::span<const uint8_t>(&in32[16], 16));
1 ✔
748
         result.test_bin_eq("store_le128 two u32 ptrs (high)",
1 ✔
749
                            std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(out32b), 16),
750
                            std::span<const uint8_t>(&in32[0], 16));
1 ✔
751
         // NOLINTEND(*-container-data-pointer)
752

753
         return result;
1 ✔
754
      }
2 ✔
755

756
      static W8 splat8(uint32_t x) { return W8{x, x, x, x, x, x, x, x}; }
3 ✔
757

758
      template <typename F>
759
      static W8 map(const W8& a, F f) {
11 ✔
760
         W8 r{};
11 ✔
761
         for(size_t i = 0; i != 8; ++i) {
99 ✔
762
            r[i] = f(a[i]);
88 ✔
763
         }
764
         return r;
765
      }
766

767
      template <typename F>
768
      static W8 zip(const W8& a, const W8& b, F f) {
8 ✔
769
         W8 r{};
8 ✔
770
         for(size_t i = 0; i != 8; ++i) {
72 ✔
771
            r[i] = f(a[i], b[i]);
64 ✔
772
         }
773
         return r;
774
      }
775

776
      static void BOTAN_FN_ISA_SIMD_8X32 test_eq(Test::Result& result,
3 ✔
777
                                                 const std::string& op,
778
                                                 const Botan::SIMD_8x32& simd,
779
                                                 const Botan::SIMD_8x32& expected) {
780
         W8 exp{};
3 ✔
781
         expected.store_le(exp.data());
3 ✔
782
         test_eq(result, op, simd, exp);
3 ✔
783
      }
784

785
      static void BOTAN_FN_ISA_SIMD_8X32 test_eq(Test::Result& result,
66 ✔
786
                                                 const std::string& op,
787
                                                 const Botan::SIMD_8x32& simd,
788
                                                 const W8& expected) {
789
         uint8_t arr_be[32 + 31];
66 ✔
790
         uint8_t arr_be2[32 + 31];
66 ✔
791
         uint8_t arr_le[32 + 31];
66 ✔
792
         uint8_t arr_le2[32 + 31];
66 ✔
793

794
         for(size_t misalignment = 0; misalignment < 32; misalignment += 5) {
528 ✔
795
            uint8_t* mem_be = arr_be + misalignment;
462 ✔
796
            uint8_t* mem_be2 = arr_be2 + misalignment;
462 ✔
797
            uint8_t* mem_le = arr_le + misalignment;
462 ✔
798
            uint8_t* mem_le2 = arr_le2 + misalignment;
462 ✔
799

800
            simd.store_be(mem_be);
462 ✔
801
            simd.store_le(mem_le);
462 ✔
802

803
            for(size_t i = 0; i != 8; ++i) {
4,158 ✔
804
               result.test_u32_eq("SIMD_8x32 " + op + " elem" + std::to_string(i) + " BE",
14,784 ✔
805
                                  Botan::load_be<uint32_t>(mem_be, i),
806
                                  expected[i]);
3,696 ✔
807
               result.test_u32_eq("SIMD_8x32 " + op + " elem" + std::to_string(i) + " LE",
14,784 ✔
808
                                  Botan::load_le<uint32_t>(mem_le, i),
809
                                  expected[i]);
3,696 ✔
810
            }
811

812
            // Check load_be+store_be results in same value
813
            Botan::SIMD_8x32::load_be(mem_be).store_be(mem_be2);
462 ✔
814
            result.test_bin_eq("SIMD_8x32 load_be", {mem_be, 32}, {mem_be2, 32});
462 ✔
815

816
            // Check load_le+store_le results in same value
817
            Botan::SIMD_8x32::load_le(mem_le).store_le(mem_le2);
462 ✔
818
            result.test_bin_eq("SIMD_8x32 load_le", {mem_le, 32}, {mem_le2, 32});
462 ✔
819
         }
820

821
         // Also check the uint32_t store overload
822
         W8 words{};
66 ✔
823
         simd.store_le(words.data());
66 ✔
824
         result.test_is_true("SIMD_8x32 " + op + " store_le u32", words == expected);
198 ✔
825
      }
66 ✔
826
};
827

828
BOTAN_REGISTER_TEST("utils", "simd_8x32", SIMD_8X32_Tests);
829
#endif
830

831
}  // namespace
832

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

© 2026 Coveralls, Inc