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

randombit / botan / 37879904758

09 Oct 2026 12:32AM UTC coverage: 92.188% (+2.3%) from 89.903%
37879904758

push

github

web-flow
Merge pull request #5964 from randombit/jack/ml-kem-avx2

Add AVX2 implementation of ML-KEM NTT, inverse NTT, and mul

134868 of 146297 relevant lines covered (92.19%)

8763146.96 hits per line

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

99.6
/src/tests/test_utils_bitvector.cpp
1
/*
2
 * (C) 2023-2024 Jack Lloyd
3
 * (C) 2023-2024 René Meusel, Rohde & Schwarz Cybersecurity
4
 *
5
 * Botan is released under the Simplified BSD License (see license.txt)
6
 */
7

8
#include "tests.h"
9

10
#if defined(BOTAN_HAS_BITVECTOR)
11
   #include <botan/hex.h>
12
   #include <botan/rng.h>
13
   #include <botan/internal/bitvector.h>
14
   #include <botan/internal/fmt.h>
15
   #include <algorithm>
16
   #include <limits>
17
   #include <numeric>
18
   #include <set>
19
#endif
20

21
namespace Botan_Tests {
22

23
namespace {
24

25
#if defined(BOTAN_HAS_BITVECTOR)
26

27
/// Returns a random number in the range [min, max)
28
size_t rand_in_range(Botan::RandomNumberGenerator& rng, size_t min, size_t max) {
63 ✔
29
   if(min == max) {
63 ✔
30
      return min;
31
   }
32

33
   const size_t val = Botan::load_le<size_t>(rng.random_array<sizeof(size_t)>());
62 ✔
34
   return min + (val % (max - min));
62 ✔
35
}
36

37
/// Returns @p n integers smaller than @p upper_bound in random order
38
std::vector<size_t> rand_indices(Botan::RandomNumberGenerator& rng, size_t n, size_t upper_bound) {
3 ✔
39
   const auto shuffle = [&](std::vector<size_t>& v) {
6 ✔
40
      // Fisher-Yates shuffle
41
      if(v.size() < 2) {
3 ✔
42
         return;
43
      }
44
      for(size_t i = 0; i < v.size() - 1; ++i) {
59 ✔
45
         const auto j = rand_in_range(rng, i, v.size());
57 ✔
46
         std::swap(v[i], v[j]);
57 ✔
47
      }
48
   };
3 ✔
49

50
   std::vector<size_t> indices(upper_bound);
3 ✔
51
   std::iota(indices.begin(), indices.end(), 0);
3 ✔
52
   shuffle(indices);
3 ✔
53
   indices.resize(n);
3 ✔
54
   return indices;
3 ✔
55
}
×
56

57
/// Create an empty bitvector of random size and chose a random number of points of interests
58
std::pair<Botan::bitvector, std::set<size_t>> rnd_bitvector_with_rnd_pois(Botan::RandomNumberGenerator& rng) {
3 ✔
59
   const Botan::bitvector bv(rand_in_range(rng, 0, 65));
3 ✔
60
   const size_t no_poi = rand_in_range(rng, 0, bv.size());
3 ✔
61
   auto points_of_interest = rand_indices(rng, no_poi, bv.size());
3 ✔
62

63
   return {bv, {points_of_interest.begin(), points_of_interest.end()}};
6 ✔
64
}
5 ✔
65

66
template <size_t mod>
67
auto pattern_generator(size_t offset = 0) {
98 ✔
68
   return [i = offset]() mutable -> bool {
6,997 ✔
69
      const bool result = (i % mod) != 0;
6,997 ✔
70
      ++i;
6,997 ✔
71
      return result;
72
   };
73
}
74

75
std::vector<Test::Result> test_bitvector_bitwise_accessors(Botan::RandomNumberGenerator& rng) {
1 ✔
76
   return {
1 ✔
77
      CHECK("default constructed bitvector",
78
            [](auto& result) {
1 ✔
79
               const Botan::bitvector bv;
1 ✔
80
               result.test_is_true("default constructed bitvector is empty", bv.empty());
1 ✔
81
               result.test_sz_eq("default constructed bitvector has zero size", bv.size(), size_t(0));
1 ✔
82
            }),
1 ✔
83

84
      CHECK("preallocated construction of bitvector",
85
            [](auto& result) {
1 ✔
86
               Botan::bitvector bv(10);
1 ✔
87
               result.test_is_true("allocated bitvector is not empty", !bv.empty());
1 ✔
88
               result.test_sz_eq("allocated bitvector has allocated size", bv.size(), size_t(10));
1 ✔
89
               for(size_t i = 0; i < 10; ++i) {
11 ✔
90
                  result.test_is_true("bit not set yet", !bv.at(i));
10 ✔
91
               }
92
            }),
1 ✔
93

94
      CHECK("setting bits",
95
            [&](auto& result) {
1 ✔
96
               auto [bv, ones] = rnd_bitvector_with_rnd_pois(rng);
1 ✔
97

98
               for(const size_t i : ones) {
1 ✔
99
                  if(rng.next_byte() % 2 == 0) {
×
100
                     bv.set(i);
×
101
                  } else {
102
                     bv.at(i) = true;
×
103
                  }
104
               }
105
               for(size_t i = 0; i < bv.size(); ++i) {
1 ✔
106
                  result.test_is_true(Botan::fmt("bit {} in expected state", i), bv.at(i) == ones.contains(i));
×
107
               }
108
            }),
1 ✔
109

110
      CHECK("unsetting bits",
111
            [&](auto& result) {
1 ✔
112
               auto [bv, zeros] = rnd_bitvector_with_rnd_pois(rng);
1 ✔
113
               for(auto b : bv) {
32 ✔
114
                  b.set();
30 ✔
115
               }
116

117
               for(const size_t i : zeros) {
24 ✔
118
                  if(rng.next_byte() % 2 == 0) {
23 ✔
119
                     bv.unset(i);
14 ✔
120
                  } else {
121
                     bv.at(i) = false;
9 ✔
122
                  }
123
               }
124
               for(size_t i = 0; i < bv.size(); ++i) {
31 ✔
125
                  result.test_is_true(Botan::fmt("bit {} in expected state", i), bv.at(i) == !zeros.contains(i));
90 ✔
126
               }
127
            }),
1 ✔
128

129
      CHECK("flipping bits",
130
            [&](auto& result) {
1 ✔
131
               auto [bv, ones] = rnd_bitvector_with_rnd_pois(rng);
1 ✔
132

133
               for(size_t i = 0; i < bv.size(); ++i) {
30 ✔
134
                  if(std::find(ones.begin(), ones.end(), i) == ones.end()) {
58 ✔
135
                     bv.set(i);
19 ✔
136
                  }
137
                  bv.flip(i);
29 ✔
138
               }
139
               for(size_t i = 0; i < bv.size(); ++i) {
30 ✔
140
                  result.test_is_true(Botan::fmt("bit {} in expected state", i), bv.at(i) == ones.contains(i));
116 ✔
141
               }
142
            }),
1 ✔
143

144
      CHECK("accessors validate offsets",
145
            [](auto& result) {
1 ✔
146
               Botan::bitvector bv(10);
1 ✔
147
               result.template test_throws<Botan::Invalid_Argument>(
1 ✔
148
                  ".at() const out of range", [&] { const_cast<const decltype(bv)&>(bv).at(10); });
2 ✔
149
               result.template test_throws<Botan::Invalid_Argument>(".at() out of range", [&] { bv.at(10); });
2 ✔
150
               result.template test_throws<Botan::Invalid_Argument>(".set() out of range", [&] { bv.set(10); });
2 ✔
151
               result.template test_throws<Botan::Invalid_Argument>(".unset() out of range", [&] { bv.unset(10); });
2 ✔
152
               result.template test_throws<Botan::Invalid_Argument>(".flip() out of range", [&] { bv.flip(10); });
2 ✔
153
            }),
1 ✔
154

155
      CHECK("multiblock handling",
156
            [](auto& result) {
1 ✔
157
               Botan::bitvector bv(128);
1 ✔
158
               result.test_sz_eq("has more than 64 bits", bv.size(), 128);
1 ✔
159
               bv.set(1).set(63).set(64).set(127);
1 ✔
160
               for(size_t i = 0; i < bv.size(); ++i) {
129 ✔
161
                  const bool expected = (i == 1 || i == 63 || i == 64 || i == 127);
128 ✔
162
                  result.test_bool_eq(Botan::fmt("bit {} in expected state", i), bv.at(i), expected);
256 ✔
163
               }
164
            }),
1 ✔
165

166
      CHECK("subscript operator",
167
            [](auto& result) {
1 ✔
168
               Botan::bitvector bv(128);
1 ✔
169
               bv[0].set();
1 ✔
170
               bv[1] = true;
1 ✔
171
               bv[2].flip();
1 ✔
172
               bv[64] = true;
1 ✔
173
               bv[80] = true;
1 ✔
174
               result.test_is_true("bit 0", bv[0]);
1 ✔
175
               result.test_is_true("bit 1", bv[1]);
1 ✔
176
               result.test_is_true("bit 2", bv[2]);
1 ✔
177
               result.test_is_true("bit 3", !bv[3]);
1 ✔
178
               result.test_is_true("bit 64", bv[64]);
1 ✔
179
               result.test_is_true("bit 80", bv[80]);
1 ✔
180
            }),
1 ✔
181

182
      CHECK("subscript operator does not validate offsets",
183
            [](auto& result) {
1 ✔
184
               Botan::bitvector bv(10);
1 ✔
185
               result.template test_throws<Botan::Invalid_Argument>(".at() out of range", [&] { bv.at(10); });
2 ✔
186
               // Technically the next line is undefined behaviour.
187
               // Though, the current implementation detail won't
188
               // cause issues, which might change!
189
               result.test_no_throw("subscript out of range", [&] { bv[10]; });
1 ✔
190
            }),
1 ✔
191

192
      CHECK("bitwise assignment modifiers",
193
            [](auto& result) {
1 ✔
194
               Botan::bitvector bv(4);
1 ✔
195

196
               result.require("precondition", !bv[0] && !bv[1]);
1 ✔
197
               bv[0] &= 1;  // NOLINT(*-use-bool-literals)
1 ✔
198
               result.test_is_true("bv[0] still 0", !bv[0]);
1 ✔
199
               bv[0].set();
1 ✔
200
               bv[0] &= 1;  // NOLINT(*-use-bool-literals)
1 ✔
201
               result.test_is_true("bv[0] still 1", bv[0]);
1 ✔
202
               bv[0] &= false;
1 ✔
203
               result.test_is_true("bv[0] now 0 again", !bv[0]);
1 ✔
204
               bv[0] &= !bv[1];
1 ✔
205
               result.test_is_true("bv[0] still 0 once more", !bv[0]);
1 ✔
206

207
               result.require("precondition 2", !bv[1] && !bv[2]);
1 ✔
208
               bv[1] |= 1;  // NOLINT(modernize-use-bool-literals)
1 ✔
209
               result.test_is_true("bv[1] is now 1", bv[1]);
1 ✔
210
               bv[1] |= 0;  // NOLINT(modernize-use-bool-literals)
1 ✔
211
               result.test_is_true("bv[1] is still 1", bv[1]);
1 ✔
212
               bv[1].unset();
1 ✔
213
               bv[1] |= false;
1 ✔
214
               result.test_is_true("bv[1] is 0", !bv[1]);
1 ✔
215
               bv[1] |= !bv[2];
1 ✔
216
               result.test_is_true("bv[1] is 1 again", bv[1]);
1 ✔
217

218
               result.require("precondition 3", !bv[2] && !bv[3]);
1 ✔
219
               bv[2] ^= 0;  // NOLINT(modernize-use-bool-literals)
1 ✔
220
               result.test_is_true("bv[2] is still 0", !bv[2]);
1 ✔
221
               bv[2] ^= true;
1 ✔
222
               result.test_is_true("bv[2] is now 1", bv[2]);
1 ✔
223
               bv[2] ^= !bv[3];
1 ✔
224
               result.test_is_true("bv[2] is 0 again", !bv[2]);
1 ✔
225
            }),
1 ✔
226

227
      CHECK("CT::Choice bit modifiers",
228
            [](auto& result) {
1 ✔
229
               Botan::bitvector bv(6);
1 ✔
230

231
               bv[0] = Botan::CT::Choice::yes();
1 ✔
232
               bv[1] = Botan::CT::Choice::no();
1 ✔
233
               bv[2] |= Botan::CT::Choice::yes();
1 ✔
234
               bv[3].set();
1 ✔
235
               bv[3] &= Botan::CT::Choice::no();
1 ✔
236
               bv[4] ^= Botan::CT::Choice::yes();
1 ✔
237

238
               result.test_is_true("CT::Choice assignment set", bv[0]);
1 ✔
239
               result.test_is_true("CT::Choice assignment cleared", !bv[1]);
1 ✔
240
               result.test_is_true("CT::Choice or", bv[2]);
1 ✔
241
               result.test_is_true("CT::Choice and", !bv[3]);
1 ✔
242
               result.test_is_true("CT::Choice xor", bv[4]);
1 ✔
243
               result.test_is_true("CT::Choice untouched", !bv[5]);
1 ✔
244
            }),
1 ✔
245
   };
12 ✔
246
}
1 ✔
247

248
std::vector<Test::Result> test_bitvector_capacity(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
249
   return {
1 ✔
250
      CHECK("default constructed bitvector",
251
            [](auto& result) {
1 ✔
252
               const Botan::bitvector bv;
1 ✔
253
               result.test_is_true("empty", bv.empty());
1 ✔
254
               result.test_sz_eq("no size", bv.size(), size_t(0));
1 ✔
255
               result.test_sz_eq("no capacity", bv.capacity(), size_t(0));
1 ✔
256
            }),
1 ✔
257

258
      CHECK("allocated bitvector has capacity",
259
            [](auto& result) {
1 ✔
260
               const Botan::bitvector bv(1);
1 ✔
261
               result.test_is_true("empty", !bv.empty());
1 ✔
262
               result.test_sz_eq("small size", bv.size(), size_t(1));
1 ✔
263
               result.test_sz_gte("a little capacity", bv.capacity(), size_t(8));
1 ✔
264
            }),
1 ✔
265

266
      CHECK("reserved bitvector has capacity",
267
            [](auto& result) {
1 ✔
268
               Botan::bitvector bv;
1 ✔
269
               result.test_sz_eq("no size", bv.size(), size_t(0));
1 ✔
270
               result.test_sz_eq("no capacity", bv.capacity(), size_t(0));
1 ✔
271

272
               bv.reserve(64);
1 ✔
273
               result.test_sz_eq("no size", bv.size(), size_t(0));
1 ✔
274
               result.test_sz_gte("no capacity", bv.capacity(), size_t(64));
1 ✔
275

276
               bv.reserve(128);
1 ✔
277
               result.test_sz_eq("no size", bv.size(), size_t(0));
1 ✔
278
               result.test_sz_gte("no capacity", bv.capacity(), size_t(128));
1 ✔
279
            }),
1 ✔
280

281
      CHECK("push_back() extends bitvector",
282
            [](Test::Result& result) {
1 ✔
283
               Botan::bitvector bv;
1 ✔
284
               result.test_is_true("empty", bv.empty());
1 ✔
285
               result.test_sz_eq("no size", bv.size(), size_t(0));
1 ✔
286

287
               bv.push_back(true);
1 ✔
288
               bv.push_back(false);
1 ✔
289
               bv.push_back(true);
1 ✔
290
               bv.push_back(false);
1 ✔
291
               bv.push_back(Botan::CT::Choice::yes());
1 ✔
292
               bv.push_back(Botan::CT::Choice::no());
1 ✔
293

294
               result.test_is_true("not empty", !bv.empty());
1 ✔
295
               result.test_sz_eq("some size", bv.size(), size_t(6));
1 ✔
296
               result.test_sz_gte("capacity is typically bigger than size", bv.capacity(), size_t(8));
1 ✔
297

298
               result.test_is_true("bit 0", bv.at(0));
1 ✔
299
               result.test_is_true("bit 1", !bv.at(1));
1 ✔
300
               result.test_is_true("bit 2", bv.at(2));
1 ✔
301
               result.test_is_true("bit 3", !bv.at(3));
1 ✔
302
               result.test_is_true("bit 4", bv.at(4));
1 ✔
303
               result.test_is_true("bit 5", !bv.at(5));
1 ✔
304

305
               result.test_throws("bit 6 is not yet allocated", [&] { bv.at(6); });
2 ✔
306
            }),
1 ✔
307

308
      CHECK("pop_back() shortens bitvector",
309
            [](Test::Result& result) {
1 ✔
310
               Botan::bitvector bv;
1 ✔
311
               bv.push_back(true);
1 ✔
312
               bv.push_back(false);
1 ✔
313
               bv.push_back(true);
1 ✔
314
               bv.push_back(false);
1 ✔
315
               result.test_is_true("last is false", !bv.back());
1 ✔
316

317
               bv.pop_back();
1 ✔
318
               result.test_sz_eq("size() == 3", bv.size(), 3);
1 ✔
319
               result.test_is_true("last is true", bv.back());
1 ✔
320

321
               bv.pop_back();
1 ✔
322
               result.test_sz_eq("size() == 2", bv.size(), 2);
1 ✔
323
               result.test_is_true("last is false", !bv.back());
1 ✔
324

325
               bv.pop_back();
1 ✔
326
               result.test_sz_eq("size() == 1", bv.size(), 1);
1 ✔
327
               result.test_is_true("last is true", bv.back());
1 ✔
328
               result.test_is_true("first is true", bv.front());
1 ✔
329

330
               bv.pop_back();
1 ✔
331
               result.test_is_true("empty", bv.empty());
1 ✔
332

333
               result.test_throws("bit 4 is not yet allocated", [&] { bv.at(4); });
2 ✔
334
            }),
1 ✔
335

336
      CHECK("resize()",
337
            [](auto& result) {
1 ✔
338
               Botan::bitvector bv(10);
1 ✔
339
               bv[0] = true;
1 ✔
340
               bv[5] = true;
1 ✔
341
               bv[9] = true;
1 ✔
342

343
               bv.resize(8);
1 ✔
344
               result.test_sz_eq("size is reduced", bv.size(), size_t(8));
1 ✔
345

346
               for(size_t i = 0; i < bv.size(); ++i) {
9 ✔
347
                  const bool expected = (i == 0 || i == 5);
8 ✔
348
                  result.test_bool_eq(Botan::fmt("{} is as expected", i), bv[i], expected);
16 ✔
349
               }
350

351
               bv.resize(0);
1 ✔
352
               result.test_is_true("resize(0) empties buffer", bv.empty());
1 ✔
353

354
               bv.resize(8);
1 ✔
355
               result.test_is_true("0 is false", !bv[0]);
1 ✔
356
               result.test_is_true("5 is false", !bv[5]);
1 ✔
357
            }),
1 ✔
358

359
      CHECK("binary bitwise and comparison operators",
360
            [](Test::Result& result) {
1 ✔
361
               Botan::bitvector a(8);
1 ✔
362
               a.set(0).set(3);
1 ✔
363
               Botan::bitvector b(8);
1 ✔
364
               b.set(1).set(3);
1 ✔
365
               Botan::bitvector c(8);
1 ✔
366
               c.set(0).set(3);  // same is a
1 ✔
367

368
               result.test_is_true("equal bitvectors compare equal", a == c);
2 ✔
369
               result.test_is_true("different bitvectors do not compare equal", !(a == b));
2 ✔
370
               result.test_is_true("different bitvectors compare not equal", a != b);
2 ✔
371
               result.test_is_true("equal bitvectors do not compare not equal", !(a != c));
2 ✔
372

373
               auto or_ab = a | b;
1 ✔
374
               result.test_is_true("OR sets union bit 0", or_ab.at(0).is_set());
1 ✔
375
               result.test_is_true("OR sets union bit 1", or_ab.at(1).is_set());
1 ✔
376
               result.test_is_true("OR sets union bit 3", or_ab.at(3).is_set());
1 ✔
377
               result.test_is_true("OR leaves unset bit 2", !or_ab.at(2).is_set());
1 ✔
378

379
               auto and_ab = a & b;
1 ✔
380
               result.test_is_true("AND keeps common bit 3", and_ab.at(3).is_set());
1 ✔
381
               result.test_is_true("AND clears non-common bit 0", !and_ab.at(0).is_set());
1 ✔
382
               result.test_is_true("AND clears non-common bit 1", !and_ab.at(1).is_set());
1 ✔
383

384
               auto xor_ab = a ^ b;
1 ✔
385
               result.test_is_true("XOR sets differing bit 0", xor_ab.at(0).is_set());
1 ✔
386
               result.test_is_true("XOR sets differing bit 1", xor_ab.at(1).is_set());
1 ✔
387
               result.test_is_true("XOR clears common bit 3", !xor_ab.at(3).is_set());
1 ✔
388
            }),
6 ✔
389

390
      CHECK("comparison and reduction of empty bitvectors",
391
            [](Test::Result& result) {
1 ✔
392
               const Botan::bitvector empty1;
1 ✔
393
               const Botan::bitvector empty2;
1 ✔
394
               result.test_is_true("empty is empty", empty1.empty());
1 ✔
395
               result.test_sz_eq("empty has zero size", empty1.size(), size_t(0));
1 ✔
396

397
               // Full-range reductions on an empty bitvector must not throw or
398
               // terminate (the underlying buffer may be null).
399
               result.test_is_true("empty none()", empty1.none());
1 ✔
400
               result.test_is_true("empty none_vartime()", empty1.none_vartime());
1 ✔
401
               result.test_is_true("empty !any()", !empty1.any());
1 ✔
402
               result.test_is_true("empty !any_vartime()", !empty1.any_vartime());
1 ✔
403
               result.test_is_true("empty all()", empty1.all());
1 ✔
404
               result.test_is_true("empty all_vartime()", empty1.all_vartime());
1 ✔
405
               result.test_sz_eq("empty hamming_weight()", empty1.hamming_weight(), size_t(0));
1 ✔
406

407
               // Two empty bitvectors compare equal. equals() is constant-time
408
               // and noexcept, so a throw here would call std::terminate().
409
               result.test_is_true("empty equals empty", empty1.equals(empty2));
1 ✔
410
               result.test_is_true("empty equals_vartime empty", empty1.equals_vartime(empty2));
2 ✔
411
               result.test_is_true("empty == empty", empty1 == empty2);
2 ✔
412
               result.test_is_true("empty not != empty", !(empty1 != empty2));
2 ✔
413

414
               // Mismatched sizes must compare unequal without touching blocks.
415
               const Botan::bitvector nonempty(8);
1 ✔
416
               result.test_is_true("empty does not equal non-empty", !empty1.equals(nonempty));
1 ✔
417
               result.test_is_true("empty does not equal_vartime non-empty", !empty1.equals_vartime(nonempty));
2 ✔
418
               result.test_is_true("empty != non-empty", empty1 != nonempty);
2 ✔
419

420
               // Same coverage for the secure allocator, whose empty buffer is
421
               // likewise potentially null.
422
               const Botan::secure_bitvector sempty1;
1 ✔
423
               const Botan::secure_bitvector sempty2;
1 ✔
424
               result.test_is_true("empty secure none()", sempty1.none());
1 ✔
425
               result.test_is_true("empty secure equals empty", sempty1.equals(sempty2));
1 ✔
426
               result.test_is_true("empty secure == empty", sempty1 == sempty2);
2 ✔
427
            }),
2 ✔
428
   };
9 ✔
429
}
1 ✔
430

431
std::vector<Test::Result> test_bitvector_subvector(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
432
   auto make_bitpattern = [&]<typename T>(T& bitvector, size_t pattern_offset = 0) {
22 ✔
433
      auto next = pattern_generator<3>(pattern_offset);
21 ✔
434

435
      if constexpr(std::unsigned_integral<T>) {
436
         for(size_t i = 0; i < sizeof(T) * 8; ++i) {
316 ✔
437
            bitvector |= static_cast<T>(next()) << i;
304 ✔
438
         }
439
      } else {
440
         for(auto& i : bitvector) {
1,746 ✔
441
            i = next();
864 ✔
442
         }
443
      }
444
   };
9 ✔
445

446
   auto bitpattern_at = [&]<std::unsigned_integral T>(T /* ignored */, size_t pattern_offset) -> T {
13 ✔
447
      T bitvector = 0;
12 ✔
448
      make_bitpattern(bitvector, pattern_offset);
24 ✔
449
      return bitvector;
450
   };
1 ✔
451

452
   auto check_bitpattern = [&](auto& result, auto& bitvector, size_t offset = 0) {
46 ✔
453
      using bv_t = std::remove_cvref_t<decltype(bitvector)>;
454
      auto next = pattern_generator<3>(offset);
45 ✔
455

456
      if constexpr(std::unsigned_integral<bv_t>) {
457
         for(size_t i = 0; i < sizeof(bv_t) * 8; ++i) {
496 ✔
458
            result.test_bool_eq(Botan::fmt("{} is as expected", i), (bitvector & (bv_t(1) << i)) != 0, next());
960 ✔
459
         }
460
      } else {
461
         for(size_t i = 0; i < bitvector.size(); ++i) {
2,182 ✔
462
            result.test_bool_eq(Botan::fmt("{} is as expected", i), bitvector[i], next());
4,306 ✔
463
         }
464
      }
465
   };
45 ✔
466

467
   auto check_bitpattern_with_zero_region = [&](auto& result, auto& bitvector, std::pair<size_t, size_t> zero_region) {
13 ✔
468
      auto next = pattern_generator<3>();
12 ✔
469
      for(size_t i = 0; i < bitvector.size(); ++i) {
1,212 ✔
470
         const bool i_in_range = (zero_region.first <= i && i < zero_region.second);
1,200 ✔
471
         const bool expected = next();
1,200 ✔
472
         result.test_bool_eq(Botan::fmt("{} is as expected", i), bitvector[i], !i_in_range && expected);
2,400 ✔
473
      }
474
   };
12 ✔
475

476
   return {
1 ✔
477
      CHECK("range errors are caught",
478
            [&](auto& result) {
1 ✔
479
               const Botan::bitvector bv(100);
1 ✔
480
               result.template test_throws<Botan::Invalid_Argument>("out of range", [&] { bv.subvector(0, 101); });
2 ✔
481
               result.template test_throws<Botan::Invalid_Argument>("out of range", [&] { bv.subvector(90, 11); });
2 ✔
482
               result.template test_throws<Botan::Invalid_Argument>("out of range", [&] { bv.subvector(100, 1); });
2 ✔
483
               result.template test_throws<Botan::Invalid_Argument>("out of range", [&] { bv.subvector(101, 0); });
2 ✔
484
            }),
1 ✔
485

486
      CHECK("empty copy is allowed",
487
            [&](auto& result) {
1 ✔
488
               const Botan::bitvector bv1(100);
1 ✔
489
               const auto bv2 = bv1.subvector(0, 0);
1 ✔
490
               result.test_sz_eq("empty at 0", bv2.size(), size_t(0));
1 ✔
491
               const auto bv3 = bv1.subvector(10, 0);
1 ✔
492
               result.test_sz_eq("empty at 10", bv3.size(), size_t(0));
1 ✔
493
               const auto bv4 = bv1.subvector(100, 0);
1 ✔
494
               result.test_sz_eq("empty at 100", bv3.size(), size_t(0));
1 ✔
495
            }),
2 ✔
496

497
      CHECK("byte-aligned copy",
498
            [&](auto& result) {
1 ✔
499
               Botan::bitvector bv1(100);
1 ✔
500
               make_bitpattern(bv1);
1 ✔
501

502
               auto bv2 = bv1.subvector(16, 58);
1 ✔
503
               result.test_sz_eq("size is as requested", bv2.size(), size_t(58));
1 ✔
504
               check_bitpattern(result, bv2, 16);
1 ✔
505

506
               auto bv3 = bv1.subvector(32);  // copy until the end
1 ✔
507
               result.test_sz_eq("size is as expected", bv3.size(), size_t(68));
1 ✔
508
               check_bitpattern(result, bv3, 32);
1 ✔
509
            }),
3 ✔
510

511
      CHECK("byte-aligned 2",
512
            [&](auto& result) {
1 ✔
513
               Botan::bitvector bv1(100);
1 ✔
514
               make_bitpattern(bv1);
1 ✔
515

516
               auto bv2 = bv1.subvector(8, 91);
1 ✔
517
               result.test_sz_eq("size is as expected", bv2.size(), size_t(91));
1 ✔
518
               check_bitpattern(result, bv2, 8);
1 ✔
519

520
               auto bv3 = bv1.subvector(16, 58);
1 ✔
521
               result.test_sz_eq("size is as requested", bv3.size(), size_t(58));
1 ✔
522
               check_bitpattern(result, bv3, 16);
1 ✔
523

524
               auto bv4 = bv1.subvector(24);  // copy until the end
1 ✔
525
               result.test_sz_eq("size is as expected", bv4.size(), size_t(100 - 24));
1 ✔
526
               check_bitpattern(result, bv4, 24);
1 ✔
527

528
               auto bv5 = bv1.subvector(32);  // copy until the end
1 ✔
529
               result.test_sz_eq("size is as expected", bv5.size(), size_t(100 - 32));
1 ✔
530
               check_bitpattern(result, bv5, 32);
1 ✔
531

532
               auto bv6 = bv1.subvector(48, 51);  // copy until the end
1 ✔
533
               result.test_sz_eq("size is as expected", bv6.size(), size_t(51));
1 ✔
534
               check_bitpattern(result, bv6, 48);
1 ✔
535
            }),
6 ✔
536

537
      CHECK("byte-aligned copy must zero-out unused bits",
538
            [&](auto& result) {
1 ✔
539
               Botan::bitvector bv1(100);
1 ✔
540
               make_bitpattern(bv1);
1 ✔
541

542
               auto bv2 = bv1.subvector(16, 17);
1 ✔
543
               result.test_sz_eq("size is as requested", bv2.size(), size_t(17));
1 ✔
544
               check_bitpattern(result, bv2, 16);
1 ✔
545

546
               bv2.resize(32);
1 ✔
547
               for(size_t i = 17; i < bv2.size(); ++i) {
16 ✔
548
                  result.test_is_true("tail is zero", !bv2[i]);
15 ✔
549
               }
550
            }),
2 ✔
551

552
      CHECK("unaligned copy",
553
            [&](auto& result) {
1 ✔
554
               Botan::bitvector bv1(100);
1 ✔
555
               make_bitpattern(bv1);
1 ✔
556

557
               auto bv2 = bv1.subvector(19, 69);
1 ✔
558
               result.test_sz_eq("size is as requested", bv2.size(), size_t(69));
1 ✔
559
               check_bitpattern(result, bv2, 19);
1 ✔
560

561
               auto bv3 = bv1.subvector(21);  // copy until the end
1 ✔
562
               result.test_sz_eq("size is as expected", bv3.size(), size_t(79));
1 ✔
563
               check_bitpattern(result, bv3, 21);
1 ✔
564

565
               auto bv4 = bv1.subvector(1, 16);
1 ✔
566
               result.test_sz_eq("size is as expected", bv4.size(), size_t(16));
1 ✔
567
               check_bitpattern(result, bv4, 1);
1 ✔
568

569
               auto bv5 = bv1.subvector(1, 32);
1 ✔
570
               result.test_sz_eq("size is as expected", bv5.size(), size_t(32));
1 ✔
571
               check_bitpattern(result, bv5, 1);
1 ✔
572

573
               auto bv6 = bv5.subvector(1, 12);
1 ✔
574
               result.test_sz_eq("size is as expected", bv6.size(), size_t(12));
1 ✔
575
               check_bitpattern(result, bv6, 1 + 1);
1 ✔
576

577
               auto bv7 = bv1.subvector(17, 67);
1 ✔
578
               result.test_sz_eq("size is as expected", bv7.size(), size_t(67));
1 ✔
579
               check_bitpattern(result, bv7, 17);
1 ✔
580

581
               auto bv8 = bv1.subvector(33);  // copy until the end
1 ✔
582
               result.test_sz_eq("size is as expected", bv8.size(), size_t(67));
1 ✔
583
               check_bitpattern(result, bv8, 33);
1 ✔
584
            }),
8 ✔
585

586
      CHECK("unaligned copy at the exact end of the buffer",
587
            [&](auto& result) {
1 ✔
588
               // Regression test: the block-wise processing must not read past
589
               // the underlying buffer when the copied range ends exactly at
590
               // the buffer's end. Best checked with a sanitizer build.
591
               Botan::bitvector bv1(64);
1 ✔
592
               make_bitpattern(bv1);
1 ✔
593

594
               auto bv2 = bv1.subvector(3, 61);
1 ✔
595
               result.test_sz_eq("size is as requested", bv2.size(), size_t(61));
1 ✔
596
               check_bitpattern(result, bv2, 3);
1 ✔
597

598
               auto bv3 = bv1.subvector(1, 63);
1 ✔
599
               result.test_sz_eq("size is as requested", bv3.size(), size_t(63));
1 ✔
600
               check_bitpattern(result, bv3, 1);
1 ✔
601
            }),
3 ✔
602

603
      CHECK("byte-aligned unsigned integer subvector",
604
            [&](auto& result) {
1 ✔
605
               Botan::bitvector bv1(100);
1 ✔
606
               make_bitpattern(bv1);
1 ✔
607

608
               const auto u8_0 = bv1.subvector<uint8_t>(0);
1 ✔
609
               const auto u8_32 = bv1.subvector<uint8_t>(32);
1 ✔
610
               check_bitpattern(result, u8_0, 0);
1 ✔
611
               check_bitpattern(result, u8_32, 32);
1 ✔
612

613
               const auto u16_0 = bv1.subvector<uint16_t>(0);
1 ✔
614
               const auto u16_56 = bv1.subvector<uint16_t>(56);
1 ✔
615
               check_bitpattern(result, u16_0, 0);
1 ✔
616
               check_bitpattern(result, u16_56, 56);
1 ✔
617

618
               const auto u32_0 = bv1.subvector<uint32_t>(0);
1 ✔
619
               const auto u32_48 = bv1.subvector<uint32_t>(48);
1 ✔
620
               check_bitpattern(result, u32_0, 0);
1 ✔
621
               check_bitpattern(result, u32_48, 48);
1 ✔
622

623
               const auto u64_0 = bv1.subvector<uint64_t>(0);
1 ✔
624
               const auto u64_32 = bv1.subvector<uint64_t>(32);
1 ✔
625
               check_bitpattern(result, u64_0, 0);
1 ✔
626
               check_bitpattern(result, u64_32, 32);
1 ✔
627

628
               result.test_throws("out of range (uint8_t)", [&] { bv1.subvector<uint8_t>(93); });
2 ✔
629
               result.test_throws("out of range (uint16_t)", [&] { bv1.subvector<uint16_t>(85); });
2 ✔
630
               result.test_throws("out of range (uint32_t)", [&] { bv1.subvector<uint32_t>(69); });
2 ✔
631
               result.test_throws("out of range (uint64_t)", [&] { bv1.subvector<uint64_t>(37); });
2 ✔
632
            }),
1 ✔
633

634
      CHECK("unaligned unsigned integer subvector",
635
            [&](Test::Result& result) {
1 ✔
636
               Botan::bitvector bv1(100);
1 ✔
637
               make_bitpattern(bv1);
1 ✔
638

639
               const auto u8_3 = bv1.subvector<uint8_t>(3);
1 ✔
640
               const auto u8_92 = bv1.subvector<uint8_t>(92);
1 ✔
641
               check_bitpattern(result, u8_3, 3);
1 ✔
642
               check_bitpattern(result, u8_92, 92);
1 ✔
643

644
               const auto u16_7 = bv1.subvector<uint16_t>(7);
1 ✔
645
               const auto u16_84 = bv1.subvector<uint16_t>(84);
1 ✔
646
               check_bitpattern(result, u16_7, 7);
1 ✔
647
               check_bitpattern(result, u16_84, 84);
1 ✔
648

649
               const auto u32_11 = bv1.subvector<uint32_t>(11);
1 ✔
650
               const auto u32_68 = bv1.subvector<uint32_t>(68);
1 ✔
651
               check_bitpattern(result, u32_11, 11);
1 ✔
652
               check_bitpattern(result, u32_68, 68);
1 ✔
653

654
               const auto u64_21 = bv1.subvector<uint64_t>(21);
1 ✔
655
               const auto u64_36 = bv1.subvector<uint64_t>(36);
1 ✔
656
               check_bitpattern(result, u64_21, 21);
1 ✔
657
               check_bitpattern(result, u64_36, 36);
1 ✔
658
            }),
1 ✔
659

660
      CHECK("byte-aligned unsigned integer subvector replacement",
661
            [&](auto& result) {
1 ✔
662
               Botan::bitvector bv1(100);
1 ✔
663
               make_bitpattern(bv1);
1 ✔
664

665
               bv1.subvector_replace(0, uint8_t(0));
1 ✔
666
               check_bitpattern_with_zero_region(result, bv1, {0, 8});
1 ✔
667
               bv1.subvector_replace(0, bitpattern_at(uint8_t(0), 0));
2 ✔
668
               check_bitpattern(result, bv1);
1 ✔
669

670
               bv1.subvector_replace(32, uint8_t(0));
1 ✔
671
               check_bitpattern_with_zero_region(result, bv1, {32, 32 + 8});
1 ✔
672
               bv1.subvector_replace(32, bitpattern_at(uint8_t(0), 32));
2 ✔
673
               check_bitpattern(result, bv1);
1 ✔
674

675
               bv1.subvector_replace(56, uint16_t(0));
1 ✔
676
               check_bitpattern_with_zero_region(result, bv1, {56, 56 + 16});
1 ✔
677
               bv1.subvector_replace(56, bitpattern_at(uint16_t(0), 56));
2 ✔
678
               check_bitpattern(result, bv1);
1 ✔
679

680
               bv1.subvector_replace(48, uint32_t(0));
1 ✔
681
               check_bitpattern_with_zero_region(result, bv1, {48, 48 + 32});
1 ✔
682
               bv1.subvector_replace(48, bitpattern_at(uint32_t(0), 48));
2 ✔
683
               check_bitpattern(result, bv1);
1 ✔
684

685
               bv1.subvector_replace(16, uint64_t(0));
1 ✔
686
               check_bitpattern_with_zero_region(result, bv1, {16, 16 + 64});
1 ✔
687
               bv1.subvector_replace(16, bitpattern_at(uint64_t(0), 16));
2 ✔
688
               check_bitpattern(result, bv1);
1 ✔
689

690
               result.test_throws("out of range (uint8_t)", [&] { bv1.subvector_replace<uint8_t>(93, 42); });
2 ✔
691
               result.test_throws("out of range (uint16_t)", [&] { bv1.subvector_replace<uint16_t>(85, 42); });
2 ✔
692
               result.test_throws("out of range (uint32_t)", [&] { bv1.subvector_replace<uint32_t>(69, 42); });
2 ✔
693
               result.test_throws("out of range (uint64_t)", [&] { bv1.subvector_replace<uint64_t>(37, 42); });
2 ✔
694
            }),
1 ✔
695

696
      CHECK("unaligned unsigned integer subvector replacement",
697
            [&](auto& result) {
1 ✔
698
               Botan::bitvector bv1(100);
1 ✔
699
               make_bitpattern(bv1);
1 ✔
700

701
               bv1.subvector_replace(3, uint8_t(0));
1 ✔
702
               check_bitpattern_with_zero_region(result, bv1, {3, 3 + 8});
1 ✔
703
               bv1.subvector_replace(3, bitpattern_at(uint8_t(0), 3));
2 ✔
704
               check_bitpattern(result, bv1);
1 ✔
705

706
               bv1.subvector_replace(92, uint8_t(0));
1 ✔
707
               check_bitpattern_with_zero_region(result, bv1, {92, 92 + 8});
1 ✔
708
               bv1.subvector_replace(92, bitpattern_at(uint8_t(0), 92));
2 ✔
709
               check_bitpattern(result, bv1);
1 ✔
710

711
               bv1.subvector_replace(7, uint16_t(0));
1 ✔
712
               check_bitpattern_with_zero_region(result, bv1, {7, 7 + 16});
1 ✔
713
               bv1.subvector_replace(7, bitpattern_at(uint16_t(0), 7));
2 ✔
714
               check_bitpattern(result, bv1);
1 ✔
715

716
               bv1.subvector_replace(84, uint16_t(0));
1 ✔
717
               check_bitpattern_with_zero_region(result, bv1, {84, 84 + 16});
1 ✔
718
               bv1.subvector_replace(84, bitpattern_at(uint16_t(0), 84));
2 ✔
719
               check_bitpattern(result, bv1);
1 ✔
720

721
               bv1.subvector_replace(11, uint32_t(0));
1 ✔
722
               check_bitpattern_with_zero_region(result, bv1, {11, 11 + 32});
1 ✔
723
               bv1.subvector_replace(11, bitpattern_at(uint32_t(0), 11));
2 ✔
724
               check_bitpattern(result, bv1);
1 ✔
725

726
               bv1.subvector_replace(68, uint32_t(0));
1 ✔
727
               check_bitpattern_with_zero_region(result, bv1, {68, 68 + 32});
1 ✔
728
               bv1.subvector_replace(68, bitpattern_at(uint32_t(0), 68));
2 ✔
729
               check_bitpattern(result, bv1);
1 ✔
730

731
               bv1.subvector_replace(21, uint64_t(0));
1 ✔
732
               check_bitpattern_with_zero_region(result, bv1, {21, 21 + 64});
1 ✔
733
               bv1.subvector_replace(21, bitpattern_at(uint64_t(0), 21));
2 ✔
734
               check_bitpattern(result, bv1);
1 ✔
735
            }),
1 ✔
736
   };
12 ✔
737
}
1 ✔
738

739
std::vector<Test::Result> test_bitvector_global_modifiers_and_predicates(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
740
   auto make_bitpattern = [](auto& bitvector) {
3 ✔
741
      auto next = pattern_generator<5>();
2 ✔
742
      for(auto& i : bitvector) {
400 ✔
743
         i = next();
198 ✔
744
      }
745
   };
2 ✔
746

747
   auto check_bitpattern = [](auto& result, auto& bitvector) {
2 ✔
748
      auto next = pattern_generator<5>();
1 ✔
749
      for(size_t i = 0; i < bitvector.size(); ++i) {
100 ✔
750
         result.test_bool_eq(Botan::fmt("{} is as expected", i), bitvector[i], next());
198 ✔
751
      }
752
   };
1 ✔
753

754
   auto check_flipped_bitpattern = [](auto& result, auto& bitvector) {
2 ✔
755
      auto next = pattern_generator<5>();
1 ✔
756
      for(size_t i = 0; i < bitvector.size(); ++i) {
100 ✔
757
         result.test_bool_eq(Botan::fmt("{} is as expected", i), bitvector[i], !next());
198 ✔
758
      }
759
   };
1 ✔
760

761
   return {
1 ✔
762
      CHECK("one bit",
763
            [](auto& result) {
1 ✔
764
               Botan::bitvector bv;
1 ✔
765
               bv.push_back(true);
1 ✔
766

767
               bv.flip();
1 ✔
768
               result.test_is_true("bit is flipped", !bv[0]);
1 ✔
769

770
               // check that unused bits aren't flipped
771
               bv.resize(8);
1 ✔
772
               for(auto&& b : bv) {
10 ✔
773
                  result.test_is_true("all bits are false", !b);
8 ✔
774
               }
775
               bv.resize(1);
1 ✔
776

777
               bv.flip();
1 ✔
778
               result.test_is_true("bit is flipped again", bv[0]);
1 ✔
779
            }),
1 ✔
780

781
      CHECK("bits in many blocks",
782
            [&](auto& result) {
1 ✔
783
               Botan::bitvector bv(99);
1 ✔
784

785
               make_bitpattern(bv);
1 ✔
786
               bv.flip();
1 ✔
787
               check_flipped_bitpattern(result, bv);
1 ✔
788

789
               bv = ~bv;
2 ✔
790
               check_bitpattern(result, bv);
1 ✔
791

792
               bv.resize(112);
1 ✔
793
               for(size_t i = 99; i < bv.size(); ++i) {
14 ✔
794
                  result.test_is_true("just-allocated bit is not set", !bv[i]);
13 ✔
795
               }
796
            }),
1 ✔
797

798
      CHECK("set and unset",
799
            [&](auto& result) {
1 ✔
800
               Botan::bitvector bv(99);
1 ✔
801

802
               make_bitpattern(bv);
1 ✔
803
               bv.set();
1 ✔
804
               bv.resize(128);
1 ✔
805
               for(size_t i = 0; i < bv.size(); ++i) {
129 ✔
806
                  const bool expected = (i < 99);
128 ✔
807
                  result.test_bool_eq("only set bits are set", bv[i], expected);
128 ✔
808
               }
809

810
               bv.unset();
1 ✔
811
               for(auto&& b : bv) {
130 ✔
812
                  result.test_is_true("bit is not set", !b);
128 ✔
813
               }
814
            }),
1 ✔
815

816
      CHECK("any, none and all",
817
            [&](auto& result) {
1 ✔
818
               Botan::bitvector bv(99);
1 ✔
819

820
               result.test_is_true("default construction yields all-zero", bv.none_vartime());
1 ✔
821
               result.test_is_true("default construction yields all-zero 2", !bv.any_vartime());
1 ✔
822
               result.test_is_true("default construction yields all-zero 3", !bv.all_vartime());
1 ✔
823
               result.test_is_true("default construction yields all-zero 4", bv.none());
1 ✔
824
               result.test_is_true("default construction yields all-zero 5", !bv.any());
1 ✔
825
               result.test_is_true("default construction yields all-zero 6", !bv.all());
1 ✔
826

827
               bv.set(42);
1 ✔
828
               result.test_is_true("setting a bit means there's a bit set", !bv.none_vartime());
1 ✔
829
               result.test_is_true("setting a bit means there's a bit set 2", bv.any_vartime());
1 ✔
830
               result.test_is_true("setting a bit means there's not all bits set", !bv.all_vartime());
1 ✔
831
               result.test_is_true("setting a bit means there's a bit set 3", !bv.none());
1 ✔
832
               result.test_is_true("setting a bit means there's a bit set 4", bv.any());
1 ✔
833
               result.test_is_true("setting a bit means there's not all bits set 2", !bv.all());
1 ✔
834

835
               bv.set();
1 ✔
836
               result.test_is_true("setting all bits means there's a bit set", !bv.none_vartime());
1 ✔
837
               result.test_is_true("setting all bits means there's a bit set 2", bv.any_vartime());
1 ✔
838
               result.test_is_true("setting all bits means all bits are set", bv.all_vartime());
1 ✔
839
               result.test_is_true("setting all bits means there's a bit set 3", !bv.none());
1 ✔
840
               result.test_is_true("setting all bits means there's a bit set 4", bv.any());
1 ✔
841
               result.test_is_true("setting all bits means all bits are set 2", bv.all());
1 ✔
842

843
               bv.unset(97);
1 ✔
844
               result.test_is_true("a single 0 at the end means that there's a bit set", !bv.none_vartime());
1 ✔
845
               result.test_is_true("a single 0 at the end means that there are bits set", bv.any_vartime());
1 ✔
846
               result.test_is_true("a single 0 at the end means that there are not all bits set", !bv.all_vartime());
1 ✔
847
               result.test_is_true("a single 0 at the end means that there's a bit set 2", !bv.none());
1 ✔
848
               result.test_is_true("a single 0 at the end means that there are bits set 2", bv.any());
1 ✔
849
               result.test_is_true("a single 0 at the end means that there are not all bits set 2", !bv.all());
1 ✔
850

851
               bv.unset();
1 ✔
852
               result.test_is_true("unsetting all bits means there's no bit set", bv.none_vartime());
1 ✔
853
               result.test_is_true("unsetting all bits means there's no bit set 2", !bv.any_vartime());
1 ✔
854
               result.test_is_true("unsetting all bits means there's not all bits set", !bv.all_vartime());
1 ✔
855
               result.test_is_true("unsetting all bits means there's no bit set 3", bv.none());
1 ✔
856
               result.test_is_true("unsetting all bits means there's no bit set 4", !bv.any());
1 ✔
857
               result.test_is_true("unsetting all bits means there's not all bits set 2", !bv.all());
1 ✔
858
            }),
1 ✔
859

860
      CHECK("hamming weight oddness",
861
            [](auto& result) {
1 ✔
862
               const auto even = Botan::hex_decode("FE3410CB0278E4D26602");
1 ✔
863
               const auto odd = Botan::hex_decode("BB2418C2B4F288921203");
1 ✔
864

865
               result.test_is_true("odd hamming", Botan::bitvector(odd).has_odd_hamming_weight().as_bool());
2 ✔
866
               result.test_is_true("even hamming", !Botan::bitvector(even).has_odd_hamming_weight().as_bool());
2 ✔
867
            }),
2 ✔
868

869
      CHECK("hamming weight",
870
            [](auto& result) {
1 ✔
871
               const auto naive_count = [](const auto& v) {
5 ✔
872
                  size_t weight = 0;
5 ✔
873
                  for(const auto& bit : v) {
440 ✔
874
                     weight += bit.template as<size_t>();
430 ✔
875
                  }
876
                  return weight;
5 ✔
877
               };
878

879
               // the last three bits of this bitvector are set, then there's a gap
880
               auto bv = Botan::bitvector(Botan::hex_decode("FE3410CB0278E4D26602E0"));
2 ✔
881
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(37));
1 ✔
882
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1 ✔
883

884
               bv.pop_back();
1 ✔
885
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(36));
1 ✔
886
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1 ✔
887

888
               bv.pop_back();
1 ✔
889
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(35));
1 ✔
890
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1 ✔
891

892
               bv.pop_back();
1 ✔
893
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(34));
1 ✔
894
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1 ✔
895

896
               bv.pop_back();
1 ✔
897
               result.test_sz_eq("hamming weight", bv.hamming_weight(), size_t(34));
1 ✔
898
               result.test_sz_eq("hamming weight", bv.hamming_weight(), naive_count(bv));
1 ✔
899
            }),
1 ✔
900
   };
7 ✔
901
}
1 ✔
902

903
std::vector<Test::Result> test_bitvector_set_range(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
904
   auto check_set_range = [](auto& result, const auto& bitvector, size_t offset, size_t length) {
15 ✔
905
      for(size_t i = 0; i < bitvector.size(); ++i) {
3,102 ✔
906
         const bool in_range = (offset <= i && i < offset + length);
3,088 ✔
907
         result.test_bool_eq(Botan::fmt("bit {} is as expected", i), bitvector[i], in_range);
6,176 ✔
908
      }
909
   };
14 ✔
910

911
   auto check_set_range_in_pattern = [](auto& result, const auto& bitvector, size_t offset, size_t length) {
4 ✔
912
      auto next = pattern_generator<3>();
3 ✔
913
      for(size_t i = 0; i < bitvector.size(); ++i) {
303 ✔
914
         const bool in_range = (offset <= i && i < offset + length);
300 ✔
915
         const bool pattern_bit = next();  // must be evaluated unconditionally
300 ✔
916
         result.test_bool_eq(Botan::fmt("bit {} is as expected", i), bitvector[i], in_range || pattern_bit);
600 ✔
917
      }
918
   };
3 ✔
919

920
   auto make_bitpattern = [](auto& bitvector) {
6 ✔
921
      auto next = pattern_generator<3>();
5 ✔
922
      for(auto& i : bitvector) {
1,010 ✔
923
         i = next();
500 ✔
924
      }
925
   };
5 ✔
926

927
   return {
1 ✔
928
      CHECK("set_range with zero length is a no-op",
929
            [&](auto& result) {
1 ✔
930
               Botan::bitvector bv(100);
1 ✔
931
               make_bitpattern(bv);
1 ✔
932
               const auto before = bv;
1 ✔
933

934
               result.test_no_throw("empty range at the beginning", [&] { bv.set_range(0, 0); });
2 ✔
935
               result.test_no_throw("empty range in the middle", [&] { bv.set_range(50, 0); });
2 ✔
936
               result.test_no_throw("empty range at the end", [&] { bv.set_range(100, 0); });
2 ✔
937
               result.test_is_true("bitvector was not modified", bv.equals(before));
1 ✔
938
            }),
2 ✔
939

940
      CHECK("set_range on empty bitvector",
941
            [](auto& result) {
1 ✔
942
               Botan::bitvector bv;
1 ✔
943
               result.test_no_throw("empty range", [&] { bv.set_range(0, 0); });
2 ✔
944
               result.template test_throws<Botan::Invalid_Argument>("non-empty range", [&] { bv.set_range(0, 1); });
2 ✔
945
            }),
1 ✔
946

947
      CHECK("byte-aligned set_range",
948
            [&](auto& result) {
1 ✔
949
               Botan::bitvector bv1(100);
1 ✔
950
               bv1.set_range(8, 16);
1 ✔
951
               check_set_range(result, bv1, 8, 16);
1 ✔
952

953
               Botan::bitvector bv2(100);
1 ✔
954
               bv2.set_range(16, 64);
1 ✔
955
               check_set_range(result, bv2, 16, 64);
1 ✔
956

957
               Botan::bitvector bv3(100);
1 ✔
958
               bv3.set_range(0, 8);
1 ✔
959
               check_set_range(result, bv3, 0, 8);
1 ✔
960

961
               Botan::bitvector bv4(100);
1 ✔
962
               bv4.set_range(96, 4);
1 ✔
963
               check_set_range(result, bv4, 96, 4);
1 ✔
964
            }),
4 ✔
965

966
      CHECK("unaligned set_range",
967
            [&](auto& result) {
1 ✔
968
               Botan::bitvector bv1(100);
1 ✔
969
               bv1.set_range(3, 5);
1 ✔
970
               check_set_range(result, bv1, 3, 5);
1 ✔
971

972
               Botan::bitvector bv2(100);
1 ✔
973
               bv2.set_range(13, 47);
1 ✔
974
               check_set_range(result, bv2, 13, 47);
1 ✔
975

976
               Botan::bitvector bv3(100);
1 ✔
977
               bv3.set_range(1, 99);
1 ✔
978
               check_set_range(result, bv3, 1, 99);
1 ✔
979

980
               Botan::bitvector bv4(100);
1 ✔
981
               bv4.set_range(99, 1);
1 ✔
982
               check_set_range(result, bv4, 99, 1);
1 ✔
983
            }),
4 ✔
984

985
      CHECK("set_range over the entire bitvector",
986
            [&](auto& result) {
1 ✔
987
               Botan::bitvector bv(100);
1 ✔
988
               bv.set_range(0, 100);
1 ✔
989
               result.test_is_true("all bits are set", bv.all_vartime());
1 ✔
990
               result.test_sz_eq("hamming weight is 100", bv.hamming_weight(), size_t(100));
1 ✔
991
            }),
1 ✔
992

993
      CHECK("set_range spanning many blocks",
994
            [&](auto& result) {
1 ✔
995
               Botan::bitvector bv1(1000);
1 ✔
996
               bv1.set_range(0, 1000);
1 ✔
997
               result.test_is_true("all bits are set", bv1.all_vartime());
1 ✔
998

999
               Botan::bitvector bv2(1000);
1 ✔
1000
               bv2.set_range(64, 512);
1 ✔
1001
               check_set_range(result, bv2, 64, 512);
1 ✔
1002

1003
               Botan::bitvector bv3(1000);
1 ✔
1004
               bv3.set_range(7, 913);
1 ✔
1005
               check_set_range(result, bv3, 7, 913);
1 ✔
1006
            }),
3 ✔
1007

1008
      CHECK("set_range at the exact end of the buffer",
1009
            [&](auto& result) {
1 ✔
1010
               // Regression test: the block-wise processing must not read or
1011
               // write past the underlying buffer when a range ends exactly at
1012
               // the buffer's end. Best checked with a sanitizer build.
1013
               Botan::bitvector bv16(16);
1 ✔
1014
               bv16.set_range(0, 16);
1 ✔
1015
               result.test_is_true("all bits set (16 bits)", bv16.all_vartime());
1 ✔
1016

1017
               Botan::bitvector bv32(32);
1 ✔
1018
               bv32.set_range(0, 32);
1 ✔
1019
               result.test_is_true("all bits set (32 bits)", bv32.all_vartime());
1 ✔
1020

1021
               Botan::bitvector bv64(64);
1 ✔
1022
               bv64.set_range(0, 64);
1 ✔
1023
               result.test_is_true("all bits set (64 bits)", bv64.all_vartime());
1 ✔
1024

1025
               Botan::bitvector bv128(128);
1 ✔
1026
               bv128.set_range(64, 64);
1 ✔
1027
               check_set_range(result, bv128, 64, 64);
1 ✔
1028

1029
               Botan::bitvector bvu1(64);
1 ✔
1030
               bvu1.set_range(3, 61);
1 ✔
1031
               check_set_range(result, bvu1, 3, 61);
1 ✔
1032

1033
               Botan::bitvector bvu2(64);
1 ✔
1034
               bvu2.set_range(0, 61);
1 ✔
1035
               check_set_range(result, bvu2, 0, 61);
1 ✔
1036

1037
               Botan::bitvector bvu3(32);
1 ✔
1038
               bvu3.set_range(5, 27);
1 ✔
1039
               check_set_range(result, bvu3, 5, 27);
1 ✔
1040
            }),
7 ✔
1041

1042
      CHECK("set_range preserves bits outside the range",
1043
            [&](auto& result) {
1 ✔
1044
               Botan::bitvector bv1(100);
1 ✔
1045
               make_bitpattern(bv1);
1 ✔
1046
               bv1.set_range(16, 32);
1 ✔
1047
               check_set_range_in_pattern(result, bv1, 16, 32);
1 ✔
1048

1049
               Botan::bitvector bv2(100);
1 ✔
1050
               make_bitpattern(bv2);
1 ✔
1051
               bv2.set_range(19, 43);
1 ✔
1052
               check_set_range_in_pattern(result, bv2, 19, 43);
1 ✔
1053

1054
               Botan::bitvector bv3(100);
1 ✔
1055
               make_bitpattern(bv3);
1 ✔
1056
               bv3.set_range(1, 98);
1 ✔
1057
               check_set_range_in_pattern(result, bv3, 1, 98);
1 ✔
1058
            }),
3 ✔
1059

1060
      CHECK(
1061
         "set_range validates its arguments",
1062
         [&](auto& result) {
1 ✔
1063
            Botan::bitvector bv(100);
1 ✔
1064
            make_bitpattern(bv);
1 ✔
1065
            const auto before = bv;
1 ✔
1066

1067
            result.template test_throws<Botan::Invalid_Argument>("offset out of range", [&] { bv.set_range(101, 0); });
2 ✔
1068
            result.template test_throws<Botan::Invalid_Argument>("range end out of range",
1 ✔
1069
                                                                 [&] { bv.set_range(100, 1); });
2 ✔
1070
            result.template test_throws<Botan::Invalid_Argument>("length out of range", [&] { bv.set_range(0, 101); });
2 ✔
1071
            result.template test_throws<Botan::Invalid_Argument>("offset + length out of range",
1 ✔
1072
                                                                 [&] { bv.set_range(90, 11); });
2 ✔
1073
            result.template test_throws<Botan::Invalid_Argument>(
1 ✔
1074
               "offset + length overflowing", [&] { bv.set_range(1, std::numeric_limits<size_t>::max()); });
2 ✔
1075

1076
            result.test_is_true("bitvector was not modified", bv.equals(before));
1 ✔
1077
         }),
2 ✔
1078
   };
10 ✔
1079
}
1 ✔
1080

1081
std::vector<Test::Result> test_bitvector_unset_range(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
1082
   auto check_unset_range = [](auto& result, const auto& bitvector, size_t offset, size_t length) {
15 ✔
1083
      for(size_t i = 0; i < bitvector.size(); ++i) {
3,102 ✔
1084
         const bool in_range = (offset <= i && i < offset + length);
3,088 ✔
1085
         result.test_bool_eq(Botan::fmt("bit {} is as expected", i), bitvector[i], !in_range);
6,176 ✔
1086
      }
1087
   };
14 ✔
1088

1089
   auto check_unset_range_in_pattern = [](auto& result, const auto& bitvector, size_t offset, size_t length) {
4 ✔
1090
      auto next = pattern_generator<3>();
3 ✔
1091
      for(size_t i = 0; i < bitvector.size(); ++i) {
303 ✔
1092
         const bool in_range = (offset <= i && i < offset + length);
300 ✔
1093
         const bool pattern_bit = next();  // must be evaluated unconditionally
300 ✔
1094
         result.test_bool_eq(Botan::fmt("bit {} is as expected", i), bitvector[i], !in_range && pattern_bit);
600 ✔
1095
      }
1096
   };
3 ✔
1097

1098
   auto make_bitpattern = [](auto& bitvector) {
6 ✔
1099
      auto next = pattern_generator<3>();
5 ✔
1100
      for(auto& i : bitvector) {
1,010 ✔
1101
         i = next();
500 ✔
1102
      }
1103
   };
5 ✔
1104

1105
   return {
1 ✔
1106
      CHECK("unset_range with zero length is a no-op",
1107
            [&](auto& result) {
1 ✔
1108
               Botan::bitvector bv(100);
1 ✔
1109
               make_bitpattern(bv);
1 ✔
1110
               const auto before = bv;
1 ✔
1111

1112
               result.test_no_throw("empty range at the beginning", [&] { bv.unset_range(0, 0); });
2 ✔
1113
               result.test_no_throw("empty range in the middle", [&] { bv.unset_range(50, 0); });
2 ✔
1114
               result.test_no_throw("empty range at the end", [&] { bv.unset_range(100, 0); });
2 ✔
1115
               result.test_is_true("bitvector was not modified", bv.equals(before));
1 ✔
1116
            }),
2 ✔
1117

1118
      CHECK("unset_range on empty bitvector",
1119
            [](auto& result) {
1 ✔
1120
               Botan::bitvector bv;
1 ✔
1121
               result.test_no_throw("empty range", [&] { bv.unset_range(0, 0); });
2 ✔
1122
               result.template test_throws<Botan::Invalid_Argument>("non-empty range", [&] { bv.unset_range(0, 1); });
2 ✔
1123
            }),
1 ✔
1124

1125
      CHECK("byte-aligned unset_range",
1126
            [&](auto& result) {
1 ✔
1127
               Botan::bitvector bv1(100);
1 ✔
1128
               bv1.set();
1 ✔
1129
               bv1.unset_range(8, 16);
1 ✔
1130
               check_unset_range(result, bv1, 8, 16);
1 ✔
1131

1132
               Botan::bitvector bv2(100);
1 ✔
1133
               bv2.set();
1 ✔
1134
               bv2.unset_range(16, 64);
1 ✔
1135
               check_unset_range(result, bv2, 16, 64);
1 ✔
1136

1137
               Botan::bitvector bv3(100);
1 ✔
1138
               bv3.set();
1 ✔
1139
               bv3.unset_range(0, 8);
1 ✔
1140
               check_unset_range(result, bv3, 0, 8);
1 ✔
1141

1142
               Botan::bitvector bv4(100);
1 ✔
1143
               bv4.set();
1 ✔
1144
               bv4.unset_range(96, 4);
1 ✔
1145
               check_unset_range(result, bv4, 96, 4);
1 ✔
1146
            }),
4 ✔
1147

1148
      CHECK("unaligned unset_range",
1149
            [&](auto& result) {
1 ✔
1150
               Botan::bitvector bv1(100);
1 ✔
1151
               bv1.set();
1 ✔
1152
               bv1.unset_range(3, 5);
1 ✔
1153
               check_unset_range(result, bv1, 3, 5);
1 ✔
1154

1155
               Botan::bitvector bv2(100);
1 ✔
1156
               bv2.set();
1 ✔
1157
               bv2.unset_range(13, 47);
1 ✔
1158
               check_unset_range(result, bv2, 13, 47);
1 ✔
1159

1160
               Botan::bitvector bv3(100);
1 ✔
1161
               bv3.set();
1 ✔
1162
               bv3.unset_range(1, 99);
1 ✔
1163
               check_unset_range(result, bv3, 1, 99);
1 ✔
1164

1165
               Botan::bitvector bv4(100);
1 ✔
1166
               bv4.set();
1 ✔
1167
               bv4.unset_range(99, 1);
1 ✔
1168
               check_unset_range(result, bv4, 99, 1);
1 ✔
1169
            }),
4 ✔
1170

1171
      CHECK("unset_range over the entire bitvector",
1172
            [&](auto& result) {
1 ✔
1173
               Botan::bitvector bv(100);
1 ✔
1174
               bv.set();
1 ✔
1175
               bv.unset_range(0, 100);
1 ✔
1176
               result.test_is_true("no bits are set", bv.none_vartime());
1 ✔
1177
               result.test_sz_eq("hamming weight is 0", bv.hamming_weight(), size_t(0));
1 ✔
1178
            }),
1 ✔
1179

1180
      CHECK("unset_range spanning many blocks",
1181
            [&](auto& result) {
1 ✔
1182
               Botan::bitvector bv1(1000);
1 ✔
1183
               bv1.set();
1 ✔
1184
               bv1.unset_range(0, 1000);
1 ✔
1185
               result.test_is_true("no bits are set", bv1.none_vartime());
1 ✔
1186

1187
               Botan::bitvector bv2(1000);
1 ✔
1188
               bv2.set();
1 ✔
1189
               bv2.unset_range(64, 512);
1 ✔
1190
               check_unset_range(result, bv2, 64, 512);
1 ✔
1191

1192
               Botan::bitvector bv3(1000);
1 ✔
1193
               bv3.set();
1 ✔
1194
               bv3.unset_range(7, 913);
1 ✔
1195
               check_unset_range(result, bv3, 7, 913);
1 ✔
1196
            }),
3 ✔
1197

1198
      CHECK("unset_range at the exact end of the buffer",
1199
            [&](auto& result) {
1 ✔
1200
               // Regression test: the block-wise processing must not read or
1201
               // write past the underlying buffer when a range ends exactly at
1202
               // the buffer's end. Best checked with a sanitizer build.
1203
               Botan::bitvector bv16(16);
1 ✔
1204
               bv16.set();
1 ✔
1205
               bv16.unset_range(0, 16);
1 ✔
1206
               result.test_is_true("no bits set (16 bits)", bv16.none_vartime());
1 ✔
1207

1208
               Botan::bitvector bv32(32);
1 ✔
1209
               bv32.set();
1 ✔
1210
               bv32.unset_range(0, 32);
1 ✔
1211
               result.test_is_true("no bits set (32 bits)", bv32.none_vartime());
1 ✔
1212

1213
               Botan::bitvector bv64(64);
1 ✔
1214
               bv64.set();
1 ✔
1215
               bv64.unset_range(0, 64);
1 ✔
1216
               result.test_is_true("no bits set (64 bits)", bv64.none_vartime());
1 ✔
1217

1218
               Botan::bitvector bv128(128);
1 ✔
1219
               bv128.set();
1 ✔
1220
               bv128.unset_range(64, 64);
1 ✔
1221
               check_unset_range(result, bv128, 64, 64);
1 ✔
1222

1223
               Botan::bitvector bvu1(64);
1 ✔
1224
               bvu1.set();
1 ✔
1225
               bvu1.unset_range(3, 61);
1 ✔
1226
               check_unset_range(result, bvu1, 3, 61);
1 ✔
1227

1228
               Botan::bitvector bvu2(64);
1 ✔
1229
               bvu2.set();
1 ✔
1230
               bvu2.unset_range(0, 61);
1 ✔
1231
               check_unset_range(result, bvu2, 0, 61);
1 ✔
1232

1233
               Botan::bitvector bvu3(32);
1 ✔
1234
               bvu3.set();
1 ✔
1235
               bvu3.unset_range(5, 27);
1 ✔
1236
               check_unset_range(result, bvu3, 5, 27);
1 ✔
1237
            }),
7 ✔
1238

1239
      CHECK("unset_range preserves bits outside the range",
1240
            [&](auto& result) {
1 ✔
1241
               Botan::bitvector bv1(100);
1 ✔
1242
               make_bitpattern(bv1);
1 ✔
1243
               bv1.unset_range(16, 32);
1 ✔
1244
               check_unset_range_in_pattern(result, bv1, 16, 32);
1 ✔
1245

1246
               Botan::bitvector bv2(100);
1 ✔
1247
               make_bitpattern(bv2);
1 ✔
1248
               bv2.unset_range(19, 43);
1 ✔
1249
               check_unset_range_in_pattern(result, bv2, 19, 43);
1 ✔
1250

1251
               Botan::bitvector bv3(100);
1 ✔
1252
               make_bitpattern(bv3);
1 ✔
1253
               bv3.unset_range(1, 98);
1 ✔
1254
               check_unset_range_in_pattern(result, bv3, 1, 98);
1 ✔
1255
            }),
3 ✔
1256

1257
      CHECK("unset_range validates its arguments",
1258
            [&](auto& result) {
1 ✔
1259
               Botan::bitvector bv(100);
1 ✔
1260
               make_bitpattern(bv);
1 ✔
1261
               const auto before = bv;
1 ✔
1262

1263
               result.template test_throws<Botan::Invalid_Argument>("offset out of range",
1 ✔
1264
                                                                    [&] { bv.unset_range(101, 0); });
2 ✔
1265
               result.template test_throws<Botan::Invalid_Argument>("range end out of range",
1 ✔
1266
                                                                    [&] { bv.unset_range(100, 1); });
2 ✔
1267
               result.template test_throws<Botan::Invalid_Argument>("length out of range",
1 ✔
1268
                                                                    [&] { bv.unset_range(0, 101); });
2 ✔
1269
               result.template test_throws<Botan::Invalid_Argument>("offset + length out of range",
1 ✔
1270
                                                                    [&] { bv.unset_range(90, 11); });
2 ✔
1271
               result.template test_throws<Botan::Invalid_Argument>(
1 ✔
1272
                  "offset + length overflowing", [&] { bv.unset_range(1, std::numeric_limits<size_t>::max()); });
2 ✔
1273

1274
               result.test_is_true("bitvector was not modified", bv.equals(before));
1 ✔
1275
            }),
2 ✔
1276
   };
10 ✔
1277
}
1 ✔
1278

1279
std::vector<Test::Result> test_bitvector_binary_operators(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
1280
   auto check_set = [](auto& result, auto bits, std::vector<size_t> set_bits) {
13 ✔
1281
      for(size_t i = 0; i < bits.size(); ++i) {
252 ✔
1282
         const bool should_be_set = std::find(set_bits.begin(), set_bits.end(), i) != set_bits.end();
240 ✔
1283
         result.test_bool_eq(
240 ✔
1284
            Botan::fmt("{} should {}be set", i, (!should_be_set ? "not " : "")), bits[i], should_be_set);
661 ✔
1285
      }
1286
   };
12 ✔
1287

1288
   auto is_secure_allocator = []<template <typename> typename AllocatorT>(auto& result,
7 ✔
1289
                                                                          const Botan::bitvector_base<AllocatorT>&) {
1290
      result.test_is_true("allocator is Botan::secure_allocator<>",
12 ✔
1291
                          std::same_as<Botan::secure_allocator<uint8_t>, AllocatorT<uint8_t>>);
1292
   };
1293

1294
   auto is_standard_allocator = []<template <typename> typename AllocatorT>(auto& result,
4 ✔
1295
                                                                            const Botan::bitvector_base<AllocatorT>&) {
1296
      result.test_is_true("allocator is std::allocator<>", std::same_as<std::allocator<uint8_t>, AllocatorT<uint8_t>>);
6 ✔
1297
   };
1298

1299
   return {
1 ✔
1300
      CHECK("bitwise_equals",
1301
            [&](auto& result) {
1 ✔
1302
               Botan::bitvector lhs(20);
1 ✔
1303
               lhs.set(0).set(4).set(15).set(16).set(19);
1 ✔
1304
               Botan::bitvector rhs(20);
1 ✔
1305
               rhs.set(1).set(4).set(16).set(17).set(18);
1 ✔
1306

1307
               result.test_is_false("Not equal bitvectors", lhs.equals_vartime(rhs));
1 ✔
1308
               result.test_is_false("Not equal bitvectors 2", lhs.equals(rhs));
1 ✔
1309

1310
               lhs.unset().set(13);
1 ✔
1311
               rhs.unset().set(13);
1 ✔
1312

1313
               result.test_is_true("equal bitvectors", lhs.equals_vartime(rhs));
1 ✔
1314
               result.test_is_true("equal bitvectors 2", lhs.equals(rhs));
1 ✔
1315
            }),
2 ✔
1316

1317
      CHECK("bitwise OR",
1318
            [&](auto& result) {
1 ✔
1319
               Botan::bitvector lhs(20);
1 ✔
1320
               lhs.set(0).set(4).set(15).set(16).set(19);
1 ✔
1321
               Botan::bitvector rhs(20);
1 ✔
1322
               rhs.set(1).set(4).set(16).set(17).set(18);
1 ✔
1323
               Botan::bitvector unary(20);
1 ✔
1324
               unary.set(8);
1 ✔
1325

1326
               Botan::bitvector res = lhs | rhs;
1 ✔
1327
               check_set(result, res, {0, 1, 4, 15, 16, 17, 18, 19});
4 ✔
1328

1329
               res |= unary;
1 ✔
1330
               check_set(result, res, {0, 1, 4, 8, 15, 16, 17, 18, 19});
3 ✔
1331

1332
               is_standard_allocator(result, res);
1 ✔
1333
            }),
4 ✔
1334

1335
      CHECK("bitwise AND",
1336
            [&](auto& result) {
1 ✔
1337
               Botan::bitvector lhs(20);
1 ✔
1338
               lhs.set(0).set(4).set(15).set(16).set(18);
1 ✔
1339
               Botan::bitvector rhs(20);
1 ✔
1340
               rhs.set(1).set(4).set(16).set(17).set(18);
1 ✔
1341
               Botan::bitvector unary(20);
1 ✔
1342
               unary.set(8).set(16);
1 ✔
1343

1344
               Botan::bitvector res = lhs & rhs;
1 ✔
1345
               check_set(result, res, {4, 16, 18});
4 ✔
1346

1347
               res &= unary;
1 ✔
1348
               check_set(result, res, {16});
3 ✔
1349

1350
               is_standard_allocator(result, res);
1 ✔
1351
            }),
4 ✔
1352

1353
      CHECK("bitwise XOR",
1354
            [&](auto& result) {
1 ✔
1355
               Botan::bitvector lhs(20);
1 ✔
1356
               lhs.set(0).set(4).set(15).set(16).set(18);
1 ✔
1357
               Botan::bitvector rhs(20);
1 ✔
1358
               rhs.set(1).set(4).set(16).set(17).set(18);
1 ✔
1359
               Botan::bitvector unary(20);
1 ✔
1360
               unary.set(8).set(16);
1 ✔
1361

1362
               Botan::bitvector res = lhs ^ rhs;
1 ✔
1363
               check_set(result, res, {0, 1, 15, 17});
4 ✔
1364

1365
               res ^= unary;
1 ✔
1366
               check_set(result, res, {0, 1, 8, 15, 16, 17});
3 ✔
1367

1368
               is_standard_allocator(result, res);
1 ✔
1369
            }),
4 ✔
1370

1371
      CHECK("bitwise operators with heterogeneous allocators",
1372
            [&](auto& result) {
1 ✔
1373
               Botan::bitvector lhs(20);
1 ✔
1374
               lhs.set(0).set(4).set(15).set(16).set(18);
1 ✔
1375
               Botan::secure_bitvector rhs(20);
1 ✔
1376
               rhs.set(1).set(4).set(16).set(17).set(18);
1 ✔
1377
               Botan::bitvector unary(20);
1 ✔
1378
               unary.set(8).set(16);
1 ✔
1379

1380
               const auto res1 = lhs | rhs;
1 ✔
1381
               is_secure_allocator(result, res1);
1 ✔
1382
               check_set(result, res1, {0, 1, 4, 15, 16, 17, 18});
3 ✔
1383

1384
               const auto res2 = rhs | lhs;
1 ✔
1385
               is_secure_allocator(result, res2);
1 ✔
1386
               check_set(result, res2, {0, 1, 4, 15, 16, 17, 18});
3 ✔
1387

1388
               const auto res3 = lhs & rhs;
1 ✔
1389
               is_secure_allocator(result, res3);
1 ✔
1390
               check_set(result, res3, {4, 16, 18});
3 ✔
1391

1392
               const auto res4 = rhs & lhs;
1 ✔
1393
               is_secure_allocator(result, res4);
1 ✔
1394
               check_set(result, res4, {4, 16, 18});
3 ✔
1395

1396
               const auto res5 = lhs ^ rhs;
1 ✔
1397
               is_secure_allocator(result, res5);
1 ✔
1398
               check_set(result, res5, {0, 1, 15, 17});
3 ✔
1399

1400
               const auto res6 = rhs ^ lhs;
1 ✔
1401
               is_secure_allocator(result, res6);
1 ✔
1402
               check_set(result, res6, {0, 1, 15, 17});
4 ✔
1403
            }),
9 ✔
1404
   };
6 ✔
1405
}
1 ✔
1406

1407
std::vector<Test::Result> test_bitvector_serialization(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
1408
   constexpr uint8_t outlen = 64;
1 ✔
1409
   const auto bytearray = [] {
1 ✔
1410
      std::array<uint8_t, outlen> out{};
1411
      for(uint8_t i = 0; i < outlen; ++i) {
1412
         out[i] = i;
1413
      }
1414
      return out;
1415
   }();
1416

1417
   auto validate_bytewise = [](auto& result, const auto& bv, std::span<const uint8_t> bytes) {
3 ✔
1418
      for(size_t i = 0; i < bytes.size(); ++i) {
129 ✔
1419
         const uint8_t b = (static_cast<uint8_t>(bv[0 + i * 8]) << 0) | (static_cast<uint8_t>(bv[1 + i * 8]) << 1) |
127 ✔
1420
                           (static_cast<uint8_t>(bv[2 + i * 8]) << 2) | (static_cast<uint8_t>(bv[3 + i * 8]) << 3) |
127 ✔
1421
                           (static_cast<uint8_t>(bv[4 + i * 8]) << 4) | (static_cast<uint8_t>(bv[5 + i * 8]) << 5) |
127 ✔
1422
                           (static_cast<uint8_t>(bv[6 + i * 8]) << 6) | (static_cast<uint8_t>(bv[7 + i * 8]) << 7);
127 ✔
1423

1424
         result.test_sz_eq(
254 ✔
1425
            Botan::fmt("byte {} is as expected", i), static_cast<size_t>(b), static_cast<size_t>(bytes[i]));
127 ✔
1426
      }
1427
   };
2 ✔
1428

1429
   return {
1 ✔
1430
      CHECK("empty byte-array",
1431
            [](auto& result) {
1 ✔
1432
               std::vector<uint8_t> bytes;
1 ✔
1433
               result.require("empty buffer", bytes.empty());
1 ✔
1434

1435
               const Botan::bitvector bv(bytes);
1 ✔
1436
               result.test_is_true("empty bit vector", bv.empty());
1 ✔
1437

1438
               const auto rendered = bv.to_bytes();
1 ✔
1439
               result.test_is_true("empty bit vector renders an empty buffer", rendered.empty());
1 ✔
1440
            }),
1 ✔
1441

1442
      CHECK("to_bytes() uses secure_allocator if necessary",
1443
            [](auto& result) {
1 ✔
1444
               const Botan::bitvector bv;
1 ✔
1445
               const Botan::secure_bitvector sbv;
1 ✔
1446

1447
               auto rbv = bv.to_bytes();    // NOLINT(*-const-correctness) decltype is under test
1 ✔
1448
               auto rsbv = sbv.to_bytes();  // NOLINT(*-const-correctness) decltype is under test
1 ✔
1449

1450
               result.test_is_true("ordinary bitvector uses ordinary std::vector",
1 ✔
1451
                                   std::is_same_v<std::vector<uint8_t>, decltype(rbv)>);
1452
               result.test_is_true("secure bitvector uses secure_vector",
1 ✔
1453
                                   std::is_same_v<Botan::secure_vector<uint8_t>, decltype(rsbv)>);
1454
            }),
1 ✔
1455

1456
      CHECK("load all bits from byte-array (aligned data)",
1457
            [&](auto& result) {
1 ✔
1458
               const Botan::bitvector bv(bytearray);
1 ✔
1459
               validate_bytewise(result, bv, bytearray);
1 ✔
1460

1461
               const auto rbv = bv.to_bytes();
1 ✔
1462
               result.test_is_true("uint8_t rendered correctly", std::ranges::equal(bytearray, rbv));
2 ✔
1463
            }),
2 ✔
1464

1465
      CHECK("load all bits from byte-array (unaligned blocks)",
1466
            [&](auto& result) {
1 ✔
1467
               std::array<uint8_t, 63> unaligned_bytearray{};
1 ✔
1468
               Botan::copy_mem(unaligned_bytearray, std::span{bytearray}.first<unaligned_bytearray.size()>());
1 ✔
1469

1470
               const Botan::bitvector bv(unaligned_bytearray);
1 ✔
1471
               validate_bytewise(result, bv, unaligned_bytearray);
1 ✔
1472

1473
               const auto rbv = bv.to_bytes();
1 ✔
1474
               result.test_is_true("uint8_t rendered correctly", std::ranges::equal(unaligned_bytearray, rbv));
1 ✔
1475
            }),
3 ✔
1476

1477
      CHECK("load bits from byte-array (unaligned data)",
1478
            [&](auto& result) {
1 ✔
1479
               constexpr size_t bits_to_load = 31;
1 ✔
1480
               constexpr size_t bytes_to_load = Botan::ceil_tobytes(bits_to_load);
1 ✔
1481

1482
               Botan::bitvector bv(bytearray, bits_to_load);
1 ✔
1483

1484
               for(size_t i = 0; i < bits_to_load; ++i) {
32 ✔
1485
                  const bool expected = (i == 8) || (i == 17) || (i == 24) || (i == 25);
31 ✔
1486
                  result.test_bool_eq(Botan::fmt("bit {} is correct", i), bv.at(i), expected);
62 ✔
1487
               }
1488

1489
               const auto rbv = bv.to_bytes();
1 ✔
1490
               std::array<uint8_t, bytes_to_load> expected_bytes{};
1 ✔
1491
               Botan::copy_mem(expected_bytes, std::span{bytearray}.first<bytes_to_load>());
1 ✔
1492
               expected_bytes.back() &= (uint8_t(1) << (bits_to_load % 8)) - 1;
1 ✔
1493
               result.test_is_true("uint8_t rendered correctly", std::ranges::equal(expected_bytes, rbv));
1 ✔
1494
            }),
2 ✔
1495

1496
      CHECK("to_bytes(std::span) can handle non-zero out-memory",
1497
            [&](auto& result) {
1 ✔
1498
               constexpr size_t bits_to_load = 33;
1 ✔
1499
               constexpr size_t bytes_to_load = Botan::ceil_tobytes(bits_to_load);
1 ✔
1500

1501
               Botan::bitvector bv(bytearray, bits_to_load);
1 ✔
1502
               bv.set(32);
1 ✔
1503

1504
               std::array<uint8_t, bytes_to_load> out = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1 ✔
1505
               bv.to_bytes(out);
1 ✔
1506

1507
               result.test_u8_eq("uint8_t rendered correctly", out[4], 0x01);
1 ✔
1508
            }),
1 ✔
1509
   };
7 ✔
1510
}
1 ✔
1511

1512
std::vector<Test::Result> test_bitvector_constant_time_operations(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
1513
   constexpr Botan::CT::Choice yes = Botan::CT::Choice::yes();
1 ✔
1514
   constexpr Botan::CT::Choice no = Botan::CT::Choice::no();
1 ✔
1515

1516
   return {
1 ✔
1517
      CHECK("conditional XOR, block aligned",
1518
            [&](auto& result) {
1 ✔
1519
               Botan::bitvector bv1(Botan::hex_decode("BAADF00DCAFEBEEF"));
2 ✔
1520
               const Botan::secure_bitvector bv2(Botan::hex_decode("CAFEBEEFC001B33F"));
2 ✔
1521
               const auto initial_bv1 = bv1;
1 ✔
1522
               const auto xor_result = bv1 ^ bv2;
1 ✔
1523

1524
               bv1.ct_conditional_xor(no, bv2);
1 ✔
1525
               result.test_is_true("no change after false condition", bv1 == initial_bv1);
1 ✔
1526

1527
               bv1.ct_conditional_xor(yes, bv2);
1 ✔
1528
               result.test_is_true("XORed if condition was true", bv1 == xor_result);
1 ✔
1529
            }),
4 ✔
1530

1531
      CHECK("conditional XOR, byte aligned",
1532
            [&](auto& result) {
1 ✔
1533
               Botan::bitvector bv1(Botan::hex_decode("BAADF00DCAFEBEEF42"));
2 ✔
1534
               const Botan::secure_bitvector bv2(Botan::hex_decode("CAFEBEEFC001B33F13"));
2 ✔
1535
               const auto initial_bv1 = bv1;
1 ✔
1536
               const auto xor_result = bv1 ^ bv2;
1 ✔
1537

1538
               bv1.ct_conditional_xor(no, bv2);
1 ✔
1539
               result.test_is_true("no change after false condition", bv1 == initial_bv1);
1 ✔
1540

1541
               bv1.ct_conditional_xor(yes, bv2);
1 ✔
1542
               result.test_is_true("XORed if condition was true", bv1 == xor_result);
1 ✔
1543
            }),
4 ✔
1544

1545
      CHECK("conditional XOR, no alignment",
1546
            [&](auto& result) {
1 ✔
1547
               Botan::bitvector bv1(Botan::hex_decode("BAADF00DCAFEBEEF42"));
1 ✔
1548
               bv1.push_back(true);
1 ✔
1549
               bv1.push_back(false);
1 ✔
1550
               Botan::secure_bitvector bv2(Botan::hex_decode("CAFEBEEFC001B33F13"));
1 ✔
1551
               bv2.push_back(false);
1 ✔
1552
               bv2.push_back(false);
1 ✔
1553

1554
               const auto initial_bv1 = bv1;
1 ✔
1555
               const auto xor_result = bv1 ^ bv2;
1 ✔
1556

1557
               bv1.ct_conditional_xor(no, bv2);
1 ✔
1558
               result.test_is_true("no change after false condition", bv1 == initial_bv1);
1 ✔
1559

1560
               bv1.ct_conditional_xor(yes, bv2);
1 ✔
1561
               result.test_is_true("XORed if condition was true", bv1 == xor_result);
1 ✔
1562
            }),
4 ✔
1563
   };
4 ✔
1564
}
1 ✔
1565

1566
std::vector<Test::Result> test_bitvector_conditional_xor_workload(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
1567
   Test::Result res("Conditional XOR, Gauss Workload");
1 ✔
1568

1569
   auto rng = Test::new_rng("Conditional XOR, Gauss Workload");
1 ✔
1570

1571
   const size_t matrix_rows = 1664;
1 ✔
1572
   const size_t matrix_columns = 8192;
1 ✔
1573

1574
   std::vector<Botan::bitvector> bitvec_vec;
1 ✔
1575
   bitvec_vec.reserve(matrix_rows);
1 ✔
1576
   for(size_t i = 0; i < matrix_rows; ++i) {
1,665 ✔
1577
      bitvec_vec.push_back(Botan::bitvector(rng->random_vec(matrix_columns / 8)));
4,992 ✔
1578
   }
1579

1580
   // Simulate #ops of Gaussian Elimination
1581
   const size_t total_iter = matrix_rows * (3 * matrix_rows - 1) / 2;
1 ✔
1582
   const auto start = Test::timestamp();
1 ✔
1583
   for(size_t i = 0; i < total_iter; ++i) {
4,152,513 ✔
1584
      const auto choice = Botan::CT::Choice::from_int(static_cast<uint8_t>(rng->next_byte() % 2));
4,152,512 ✔
1585
      bitvec_vec.at(i % matrix_rows).ct_conditional_xor(choice, bitvec_vec.at(rng->next_byte() % matrix_rows));
4,152,512 ✔
1586
   }
1587
   res.set_ns_consumed(Test::timestamp() - start);
1 ✔
1588

1589
   res.test_is_true("Prevent compiler from optimizing away",
2 ✔
1590
                    bitvec_vec.at(0).any_vartime() || bitvec_vec.at(0).none_vartime());
1 ✔
1591
   return {res};
3 ✔
1592
}
3 ✔
1593

1594
std::vector<Test::Result> test_bitvector_iterators(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
1595
   return {
1 ✔
1596
      CHECK("Iterators: range-based for loop",
1597
            [](auto& result) {
1 ✔
1598
               Botan::bitvector bv(6);
1 ✔
1599
               bv.set(0).set(3).set(4);
1 ✔
1600

1601
               for(size_t i = 0; const auto& ref : bv) {
8 ✔
1602
                  const bool expected = i == 0 || i == 3 || i == 4;
6 ✔
1603
                  result.test_bool_eq(Botan::fmt("bit {} is as expected", i), ref, expected);
6 ✔
1604
                  ++i;
6 ✔
1605
               }
1606

1607
               for(size_t i = 0; const auto& ref : bv) {
8 ✔
1608
                  const bool expected = i == 0 || i == 3 || i == 4;
6 ✔
1609
                  result.test_bool_eq(Botan::fmt("const bit {} is as expected", i), ref, expected);
6 ✔
1610
                  ++i;
6 ✔
1611
               }
1612

1613
               for(auto ref : bv) {
14 ✔
1614
                  ref = true;
6 ✔
1615
               }
1616

1617
               result.test_is_true("all bits are set", bv.all_vartime());
1 ✔
1618
            }),
1 ✔
1619

1620
      CHECK("Iterators: bare usage",
1621
            [](auto& result) {
1 ✔
1622
               Botan::bitvector bv(6);
1 ✔
1623
               bv.set(0).set(3).set(4);
1 ✔
1624

1625
               size_t i = 0;
1 ✔
1626
               for(auto itr = bv.begin(); itr != bv.end(); ++itr, ++i) {
7 ✔
1627
                  const bool expected = i == 0 || i == 3 || i == 4;
6 ✔
1628
                  result.test_bool_eq(Botan::fmt("bit {} is as expected", i), *itr, expected);
12 ✔
1629
               }
1630

1631
               i = 0;
1 ✔
1632
               for(auto itr = bv.cbegin(); itr != bv.cend(); itr++, ++i) {
7 ✔
1633
                  const bool expected = i == 0 || i == 3 || i == 4;
6 ✔
1634
                  result.test_bool_eq(Botan::fmt("const bit {} is as expected", i), itr->is_set(), expected);
12 ✔
1635
               }
1636

1637
               i = 6;
1 ✔
1638
               auto ritr = bv.end();
1 ✔
1639
               // NOLINTNEXTLINE(*-avoid-do-while)
1640
               do {
1641
                  --ritr;
6 ✔
1642
                  --i;
6 ✔
1643
                  const bool expected = i == 0 || i == 3 || i == 4;
6 ✔
1644
                  result.test_bool_eq(Botan::fmt("reverse bit {} is as expected", i), *ritr, expected);
6 ✔
1645
               } while(ritr != bv.begin());
11 ✔
1646

1647
               for(auto& itr : bv) {
8 ✔
1648
                  itr.flip();
6 ✔
1649
               }
1650

1651
               i = 0;
1 ✔
1652
               for(auto itr = bv.begin(); itr != bv.end(); ++itr, ++i) {
7 ✔
1653
                  const bool expected = i == 1 || i == 2 || i == 5;
6 ✔
1654
                  result.test_bool_eq(Botan::fmt("flipped bit {} is as expected", i), *itr, expected);
12 ✔
1655
               }
1656
            }),
1 ✔
1657

1658
      CHECK("Iterators: std::distance and std::advance",
1659
            [](auto& result) {
1 ✔
1660
               Botan::bitvector bv(6);
1 ✔
1661
               result.test_sz_eq("distance", static_cast<size_t>(std::distance(bv.begin(), bv.end())), 6);
2 ✔
1662
               result.test_sz_eq("const distance", static_cast<size_t>(std::distance(bv.cbegin(), bv.cend())), 6);
2 ✔
1663

1664
               auto b = bv.begin();
1 ✔
1665
               std::advance(b, 3);
1 ✔
1666
               result.test_sz_eq("half distance", static_cast<size_t>(std::distance(bv.begin(), b)), 3);
2 ✔
1667
            }),
1 ✔
1668

1669
      CHECK("Iterators: large bitvector",
1670
            [](auto& result) {
1 ✔
1671
               Botan::bitvector bv(500);
1 ✔
1672

1673
               for(auto itr = bv.begin(); itr != bv.end(); ++itr) {
1,001 ✔
1674
                  if(std::distance(bv.begin(), itr) % 2 == 0) {
1,000 ✔
1675
                     itr->set();
250 ✔
1676
                  }
1677
                  if(std::distance(bv.begin(), itr) % 3 == 0) {
1,000 ✔
1678
                     *itr = true;
167 ✔
1679
                  }
1680
               }
1681

1682
               for(size_t i = 0; const auto& bit : bv) {
502 ✔
1683
                  const bool expected = (i % 2 == 0) || (i % 3 == 0);
500 ✔
1684
                  result.test_bool_eq(Botan::fmt("bit {} is as expected", i), bit, expected);
500 ✔
1685
                  ++i;
500 ✔
1686
               }
1687
            }),
1 ✔
1688

1689
      CHECK("Iterators: satiesfies C++20 concepts",
1690
            [](auto& result) {
1 ✔
1691
               Botan::secure_bitvector bv(42);
1 ✔
1692
               auto ro_itr = bv.cbegin();  // NOLINT(*-const-correctness) decltype is under test
1 ✔
1693
               auto rw_itr = bv.begin();   // NOLINT(*-const-correctness) decltype is under test
1 ✔
1694

1695
               using ro = decltype(ro_itr);
1696
               using rw = decltype(rw_itr);
1697

1698
               result.test_is_true("ro input iterator", std::input_iterator<ro>);
1 ✔
1699
               result.test_is_true("rw input iterator", std::input_iterator<rw>);
1 ✔
1700
               result.test_is_true("ro is not an output iterator", !std::output_iterator<ro, bool>);
1 ✔
1701
               result.test_is_true("rw output iterator", std::output_iterator<rw, bool>);
1 ✔
1702
               result.test_is_true("ro bidirectional iterator", std::bidirectional_iterator<ro>);
1 ✔
1703
               result.test_is_true("rw bidirectional iterator", std::bidirectional_iterator<rw>);
1 ✔
1704
               result.test_is_true("ro not a contiguous iterator", !std::contiguous_iterator<ro>);
1 ✔
1705
               result.test_is_true("rw not a contiguous iterator", !std::contiguous_iterator<rw>);
1 ✔
1706
            }),
1 ✔
1707
   };
6 ✔
1708
}
1 ✔
1709

1710
using TestBitvector = Botan::Strong<Botan::bitvector, struct TestBitvector_>;
1711
using TestSecureBitvector = Botan::Strong<Botan::secure_bitvector, struct TestBitvector_>;
1712
using TestUInt32 = Botan::Strong<uint32_t, struct TestUInt32_>;
1713

1714
std::vector<Test::Result> test_bitvector_strongtype_adapter(Botan::RandomNumberGenerator& /*rng*/) {
1 ✔
1715
   Test::Result result("Bitvector in strong type");
1 ✔
1716

1717
   TestBitvector bv1(33);
1 ✔
1718

1719
   result.test_is_true("bv1 is not empty", !bv1.empty());
1 ✔
1720
   result.test_sz_eq("bv1 has size 33", bv1.size(), size_t(33));
1 ✔
1721

1722
   bv1[0] = true;
1 ✔
1723
   bv1.at(1) = true;
1 ✔
1724
   bv1.set(2);
1 ✔
1725
   bv1.unset(3);
1 ✔
1726
   bv1.flip(4);
1 ✔
1727
   bv1.push_back(true);
1 ✔
1728
   bv1.push_back(false);
1 ✔
1729
   bv1.pop_back();
1 ✔
1730

1731
   result.test_is_true("bv1 front is set", bv1.front());
1 ✔
1732
   result.test_is_true("bv1 back is set", bv1.back());
1 ✔
1733
   result.test_is_true("bv1 has some one bits", bv1.any_vartime());
1 ✔
1734
   result.test_is_true("bv1 is not all zero", !bv1.none_vartime());
1 ✔
1735
   result.test_is_true("bv1 is not all one", !bv1.all_vartime());
1 ✔
1736

1737
   result.test_is_true("hamming weight of bv1", bv1.has_odd_hamming_weight().as_bool());
1 ✔
1738

1739
   for(size_t i = 0; const bool bit : bv1) {
36 ✔
1740
      const bool expected = (i == 0 || i == 1 || i == 2 || i == 4 || i == 33);
34 ✔
1741
      result.test_is_true(Botan::fmt("bv1 bit {} is set", i), bit == expected);
34 ✔
1742
      ++i;
34 ✔
1743
   }
1744

1745
   bv1.flip();
1 ✔
1746

1747
   for(size_t i = 0; const bool bit : bv1) {
36 ✔
1748
      const bool expected = (i == 0 || i == 1 || i == 2 || i == 4 || i == 33);
34 ✔
1749
      result.test_is_true(Botan::fmt("bv1 bit {} is set", i), bit != expected);
34 ✔
1750
      ++i;
34 ✔
1751
   }
1752

1753
   const auto bv2 = bv1.as<TestSecureBitvector>();
1 ✔
1754

1755
   auto bv3 = bv1 | bv2;  // NOLINT(*-const-correctness) decltype is under test
1 ✔
1756
   result.test_is_true("bv3 is a secure_bitvector", std::same_as<Botan::secure_bitvector, decltype(bv3)>);
1 ✔
1757

1758
   auto bv4 = bv2.subvector<TestSecureBitvector>(0, 5);  // NOLINT(*-const-correctness) decltype is under test
1 ✔
1759
   result.test_is_true("bv4 is a TestSecureBitvector", std::same_as<TestSecureBitvector, decltype(bv4)>);
1 ✔
1760

1761
   auto bv5 = bv2.subvector<TestUInt32>(1);
1 ✔
1762
   result.test_is_true("bv5 is a TestUInt32", std::same_as<TestUInt32, decltype(bv5)>);
1 ✔
1763
   result.test_u32_eq("bv5 has expected value", bv5.get(), 0xFFFFFFF4);
1 ✔
1764

1765
   const auto str = bv4.to_string();
1 ✔
1766
   result.test_str_eq("bv4 to_string", str, "00010");
1 ✔
1767

1768
   return {result};
3 ✔
1769
}
6 ✔
1770

1771
class BitVector_Tests final : public Test {
1 ✔
1772
   public:
1773
      std::vector<Test::Result> run() override {
1 ✔
1774
         std::vector<Test::Result> results;
1 ✔
1775
         auto& rng = Test::rng();
1 ✔
1776

1777
         const std::vector<std::function<std::vector<Test::Result>(Botan::RandomNumberGenerator&)>> funcs{
1 ✔
1778
            test_bitvector_bitwise_accessors,
1779
            test_bitvector_capacity,
1780
            test_bitvector_subvector,
1781
            test_bitvector_global_modifiers_and_predicates,
1782
            test_bitvector_set_range,
1783
            test_bitvector_unset_range,
1784
            test_bitvector_binary_operators,
1785
            test_bitvector_serialization,
1786
            test_bitvector_constant_time_operations,
1787
            test_bitvector_conditional_xor_workload,
1788
            test_bitvector_iterators,
1789
            test_bitvector_strongtype_adapter,
1790
         };
13 ✔
1791

1792
         for(const auto& test_func : funcs) {
13 ✔
1793
            auto fn_results = test_func(rng);
12 ✔
1794
            results.insert(results.end(), fn_results.begin(), fn_results.end());
12 ✔
1795
         }
12 ✔
1796

1797
         return results;
1 ✔
1798
      }
2 ✔
1799
};
1800

1801
BOTAN_REGISTER_TEST("utils", "bitvector", BitVector_Tests);
1802

1803
#endif
1804

1805
}  // namespace
1806

1807
}  // 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