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

randombit / botan / 11638273797

02 Nov 2024 12:30AM UTC coverage: 91.08% (+0.008%) from 91.072%
11638273797

push

github

web-flow
Merge pull request #4413 from randombit/jack/add-iterator-checks

Add iterator debugging to CI

90403 of 99257 relevant lines covered (91.08%)

9466616.65 hits per line

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

94.06
/src/tests/test_bigint.cpp
1
/*
2
* (C) 2009,2015,2016 Jack Lloyd
3
* (C) 2024           Fabian Albert, 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_NUMBERTHEORY)
11
   #include "test_rng.h"
12
   #include <botan/bigint.h>
13
   #include <botan/numthry.h>
14
   #include <botan/reducer.h>
15
   #include <botan/internal/ct_utils.h>
16
   #include <botan/internal/divide.h>
17
   #include <botan/internal/fmt.h>
18
   #include <botan/internal/mp_core.h>
19
   #include <botan/internal/parsing.h>
20
   #include <botan/internal/primality.h>
21
   #include <botan/internal/stl_util.h>
22
#endif
23

24
namespace Botan_Tests {
25

26
namespace {
27

28
#if defined(BOTAN_HAS_NUMBERTHEORY)
29

30
using Botan::BigInt;
31

32
class BigInt_Unit_Tests final : public Test {
×
33
   public:
34
      std::vector<Test::Result> run() override {
1✔
35
         std::vector<Test::Result> results;
1✔
36

37
         results.push_back(test_bigint_sizes());
2✔
38
         results.push_back(test_random_prime());
2✔
39
         results.push_back(test_encode());
2✔
40
         results.push_back(test_bigint_io());
2✔
41
         results.push_back(test_get_substring());
2✔
42

43
         return results;
1✔
44
      }
×
45

46
   private:
47
      static Test::Result test_bigint_sizes() {
1✔
48
         Test::Result result("BigInt size functions");
1✔
49

50
         for(size_t bit : {1, 8, 16, 31, 32, 64, 97, 128, 179, 192, 512, 521}) {
13✔
51
            BigInt a;
12✔
52

53
            a.set_bit(bit);
12✔
54

55
            // Test 2^n and 2^n-1
56
            for(size_t i = 0; i != 2; ++i) {
36✔
57
               const size_t exp_bits = bit + 1 - i;
24✔
58
               result.test_eq("BigInt::bits", a.bits(), exp_bits);
24✔
59
               result.test_eq(
24✔
60
                  "BigInt::bytes", a.bytes(), (exp_bits % 8 == 0) ? (exp_bits / 8) : (exp_bits + 8 - exp_bits % 8) / 8);
24✔
61

62
               if(bit == 1 && i == 1) {
24✔
63
                  result.test_is_eq("BigInt::to_u32bit zero", a.to_u32bit(), static_cast<uint32_t>(1));
2✔
64
               } else if(bit <= 31 || (bit == 32 && i == 1)) {
23✔
65
                  result.test_is_eq(
8✔
66
                     "BigInt::to_u32bit", a.to_u32bit(), static_cast<uint32_t>((uint64_t(1) << bit) - i));
16✔
67
               } else {
68
                  try {
15✔
69
                     a.to_u32bit();
15✔
70
                     result.test_failure("BigInt::to_u32bit roundtripped out of range value");
×
71
                  } catch(std::exception&) {
15✔
72
                     result.test_success("BigInt::to_u32bit rejected out of range");
15✔
73
                  }
15✔
74
               }
75

76
               a--;
48✔
77
            }
78
         }
12✔
79

80
         return result;
1✔
81
      }
×
82

83
      static Test::Result test_random_prime() {
1✔
84
         Test::Result result("BigInt prime generation");
1✔
85

86
         auto rng = Test::new_rng("random_prime");
1✔
87

88
         result.test_throws(
2✔
89
            "Invalid bit size", "random_prime: Can't make a prime of 0 bits", [&]() { Botan::random_prime(*rng, 0); });
2✔
90
         result.test_throws(
2✔
91
            "Invalid bit size", "random_prime: Can't make a prime of 1 bits", [&]() { Botan::random_prime(*rng, 1); });
2✔
92
         result.test_throws("Invalid arg", "random_prime Invalid value for equiv/modulo", [&]() {
2✔
93
            Botan::random_prime(*rng, 2, 1, 0, 2);
1✔
94
         });
×
95

96
         BigInt p = Botan::random_prime(*rng, 2);
1✔
97
         result.confirm("Only two 2-bit primes", p == 2 || p == 3);
4✔
98

99
         p = Botan::random_prime(*rng, 3);
2✔
100
         result.confirm("Only two 3-bit primes", p == 5 || p == 7);
4✔
101

102
         p = Botan::random_prime(*rng, 4);
2✔
103
         result.confirm("Only two 4-bit primes", p == 11 || p == 13);
3✔
104

105
         for(size_t bits = 5; bits <= 32; ++bits) {
29✔
106
            p = Botan::random_prime(*rng, bits);
56✔
107
            result.test_eq("Expected bit size", p.bits(), bits);
28✔
108
            result.test_eq("P is prime", Botan::is_prime(p, *rng), true);
56✔
109
         }
110

111
         const size_t safe_prime_bits = 65;
1✔
112
         const BigInt safe_prime = Botan::random_safe_prime(*rng, safe_prime_bits);
1✔
113
         result.test_eq("Safe prime size", safe_prime.bits(), safe_prime_bits);
1✔
114
         result.confirm("P is prime", Botan::is_prime(safe_prime, *rng));
2✔
115
         result.confirm("(P-1)/2 is prime", Botan::is_prime((safe_prime - 1) / 2, *rng));
3✔
116

117
         return result;
1✔
118
      }
3✔
119

120
      static Test::Result test_encode() {
1✔
121
         Test::Result result("BigInt encoding functions");
1✔
122

123
         const auto n1 = Botan::BigInt::from_u64(0xffff);
1✔
124
         const auto n2 = Botan::BigInt::from_u64(1023);
1✔
125

126
         const auto encoded_n1 = n1.serialize(256);
1✔
127
         const auto encoded_n2 = n2.serialize(256);
1✔
128
         const auto expected = Botan::concat(encoded_n1, encoded_n2);
1✔
129

130
         const auto encoded_n1_n2 = BigInt::encode_fixed_length_int_pair(n1, n2, 256);
1✔
131
         result.test_eq("encode_fixed_length_int_pair", encoded_n1_n2, expected);
1✔
132

133
         for(size_t i = 0; i < 256 - n1.bytes(); ++i) {
255✔
134
            if(encoded_n1[i] != 0) {
254✔
135
               result.test_failure("BigInt::serialize", "no zero byte");
×
136
            }
137
         }
138

139
         return result;
1✔
140
      }
6✔
141

142
      static Test::Result test_get_substring() {
1✔
143
         Test::Result result("BigInt get_substring");
1✔
144

145
         const size_t rbits = 1024;
1✔
146

147
         auto rng = Test::new_rng("get_substring");
1✔
148

149
         const Botan::BigInt r(*rng, rbits);
1✔
150

151
         for(size_t wlen = 1; wlen <= 32; ++wlen) {
33✔
152
            for(size_t offset = 0; offset != rbits + 64; ++offset) {
34,848✔
153
               const uint32_t val = r.get_substring(offset, wlen);
34,816✔
154

155
               Botan::BigInt t = r >> offset;
34,816✔
156
               t.mask_bits(wlen);
34,816✔
157

158
               const uint32_t cmp = t.to_u32bit();
34,816✔
159

160
               result.test_eq("Same value", size_t(val), size_t(cmp));
69,632✔
161
            }
34,816✔
162
         }
163

164
         return result;
1✔
165
      }
2✔
166

167
      static Test::Result test_bigint_io() {
1✔
168
         Test::Result result("BigInt IO operators");
1✔
169

170
         const std::map<std::string, Botan::BigInt> str_to_val = {{"-13", -Botan::BigInt(13)},
1✔
171
                                                                  {"0", Botan::BigInt(0)},
2✔
172
                                                                  {"0x13", Botan::BigInt(0x13)},
2✔
173
                                                                  {"1", Botan::BigInt(1)},
2✔
174
                                                                  {"4294967297", Botan::BigInt(2147483648) * 2 + 1}};
10✔
175

176
         for(const auto& vec : str_to_val) {
6✔
177
            Botan::BigInt n;
5✔
178
            std::istringstream iss;
5✔
179

180
            iss.str(vec.first);
5✔
181
            iss >> n;
5✔
182
            result.test_eq("input '" + vec.first + "'", n, vec.second);
15✔
183
         }
10✔
184

185
         auto check_bigint_formatting = [&](const Botan::BigInt& n,
6✔
186
                                            const std::string& dec,
187
                                            const std::string& hex,
188
                                            const std::string& neg_dec,
189
                                            const std::string& neg_hex) {
190
            std::ostringstream oss;
5✔
191
            oss << n;
5✔
192
            result.test_eq("output decimal", oss.str(), dec);
10✔
193

194
            oss.str("");
10✔
195
            oss << (-n);
5✔
196
            result.test_eq("output negative decimal", oss.str(), neg_dec);
10✔
197

198
            oss.str("");
10✔
199
            oss << std::hex << n;
5✔
200
            result.test_eq("output hex", oss.str(), hex);
10✔
201

202
            oss.str("");
10✔
203
            oss << std::hex << (-n);
5✔
204
            result.test_eq("output negative hex", oss.str(), neg_hex);
10✔
205
         };
5✔
206

207
         check_bigint_formatting(Botan::BigInt(33), "33", "0x21", "-33", "-0x21");
2✔
208
         check_bigint_formatting(Botan::BigInt::from_s32(-33), "-33", "-0x21", "33", "0x21");
2✔
209
         check_bigint_formatting(Botan::BigInt(255), "255", "0xFF", "-255", "-0xFF");
2✔
210
         check_bigint_formatting(Botan::BigInt(0), "0", "0x00", "0", "0x00");
2✔
211
         check_bigint_formatting(Botan::BigInt(5), "5", "0x05", "-5", "-0x05");
2✔
212

213
         result.test_throws("octal output not supported", [&]() {
2✔
214
            Botan::BigInt n(5);
1✔
215
            std::ostringstream oss;
1✔
216
            oss << std::oct << n;
1✔
217
         });
1✔
218

219
         return result;
1✔
220
      }
6✔
221
};
222

223
BOTAN_REGISTER_TEST("math", "bigint_unit", BigInt_Unit_Tests);
224

225
class BigInt_Cmp_Test final : public Text_Based_Test {
×
226
   public:
227
      BigInt_Cmp_Test() : Text_Based_Test("bn/cmp.vec", "X,Y,R") {}
2✔
228

229
      Test::Result run_one_test(const std::string& op, const VarMap& vars) override {
19✔
230
         Test::Result result("BigInt Comparison " + op);
19✔
231

232
         const BigInt x = vars.get_req_bn("X");
19✔
233
         const BigInt y = vars.get_req_bn("Y");
19✔
234
         const bool expected = vars.get_req_bool("R");
19✔
235

236
         if(op == "EQ") {
19✔
237
            result.confirm("Values equal", x == y, expected);
12✔
238
         } else if(op == "LT") {
13✔
239
            result.confirm("Values LT", x < y, expected);
12✔
240

241
            if(expected) {
6✔
242
               result.confirm("If LT then reverse is GT", y >= x);
4✔
243
            } else {
244
               result.confirm("If not LT then GTE", x >= y);
8✔
245
            }
246
         } else if(op == "LTE") {
7✔
247
            result.confirm("Values LTE", x <= y, expected);
14✔
248

249
            if(expected) {
7✔
250
               result.confirm("If LTE then either LT or EQ", x < y || x == y);
13✔
251
            } else {
252
               result.confirm("If not LTE then GT", x > y);
6✔
253
            }
254
         } else {
255
            throw Test_Error("Unknown BigInt comparison type " + op);
×
256
         }
257

258
         return result;
19✔
259
      }
38✔
260
};
261

262
BOTAN_REGISTER_TEST("math", "bn_cmp", BigInt_Cmp_Test);
263

264
class BigInt_Add_Test final : public Text_Based_Test {
×
265
   public:
266
      BigInt_Add_Test() : Text_Based_Test("bn/add.vec", "In1,In2,Output") {}
2✔
267

268
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
78✔
269
         Test::Result result("BigInt Addition");
78✔
270

271
         using Botan::BigInt;
78✔
272

273
         const BigInt a = vars.get_req_bn("In1");
78✔
274
         const BigInt b = vars.get_req_bn("In2");
78✔
275
         const BigInt c = vars.get_req_bn("Output");
78✔
276

277
         result.test_eq("a + b", a + b, c);
156✔
278
         result.test_eq("b + a", b + a, c);
156✔
279

280
         BigInt e = a;
78✔
281
         e += b;
78✔
282
         result.test_eq("a += b", e, c);
78✔
283

284
         e = b;
78✔
285
         e += a;
78✔
286
         result.test_eq("b += a", e, c);
78✔
287

288
         return result;
78✔
289
      }
312✔
290
};
291

292
BOTAN_REGISTER_TEST("math", "bn_add", BigInt_Add_Test);
293

294
class BigInt_Sub_Test final : public Text_Based_Test {
×
295
   public:
296
      BigInt_Sub_Test() : Text_Based_Test("bn/sub.vec", "In1,In2,Output") {}
2✔
297

298
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
77✔
299
         Test::Result result("BigInt Subtraction");
77✔
300

301
         const BigInt a = vars.get_req_bn("In1");
77✔
302
         const BigInt b = vars.get_req_bn("In2");
77✔
303
         const BigInt c = vars.get_req_bn("Output");
77✔
304

305
         result.test_eq("a - b", a - b, c);
154✔
306

307
         BigInt e = a;
77✔
308
         e -= b;
77✔
309
         result.test_eq("a -= b", e, c);
77✔
310

311
         return result;
77✔
312
      }
308✔
313
};
314

315
BOTAN_REGISTER_TEST("math", "bn_sub", BigInt_Sub_Test);
316

317
class BigInt_Mul_Test final : public Text_Based_Test {
×
318
   public:
319
      BigInt_Mul_Test() : Text_Based_Test("bn/mul.vec", "In1,In2,Output") {}
2✔
320

321
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
104✔
322
         Test::Result result("BigInt Multiply");
104✔
323

324
         const BigInt a = vars.get_req_bn("In1");
104✔
325
         const BigInt b = vars.get_req_bn("In2");
104✔
326
         const BigInt c = vars.get_req_bn("Output");
104✔
327

328
         result.test_eq("a * b", a * b, c);
208✔
329
         result.test_eq("b * a", b * a, c);
208✔
330

331
         BigInt e = a;
104✔
332
         e *= b;
104✔
333
         result.test_eq("a *= b", e, c);
104✔
334

335
         e = b;
104✔
336
         e *= a;
104✔
337
         result.test_eq("b *= a", e, c);
104✔
338

339
         return result;
104✔
340
      }
416✔
341
};
342

343
BOTAN_REGISTER_TEST("math", "bn_mul", BigInt_Mul_Test);
344

345
class BigInt_Sqr_Test final : public Text_Based_Test {
×
346
   public:
347
      BigInt_Sqr_Test() : Text_Based_Test("bn/sqr.vec", "Input,Output") {}
2✔
348

349
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
21✔
350
         Test::Result result("BigInt Square");
21✔
351

352
         const BigInt input = vars.get_req_bn("Input");
21✔
353
         const BigInt output = vars.get_req_bn("Output");
21✔
354

355
         result.test_eq("a * a", input * input, output);
42✔
356
         result.test_eq("sqr(a)", square(input), output);
42✔
357

358
         return result;
21✔
359
      }
42✔
360
};
361

362
BOTAN_REGISTER_TEST("math", "bn_sqr", BigInt_Sqr_Test);
363

364
class BigInt_Div_Test final : public Text_Based_Test {
×
365
   public:
366
      BigInt_Div_Test() : Text_Based_Test("bn/divide.vec", "In1,In2,Output") {}
2✔
367

368
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
783✔
369
         Test::Result result("BigInt Divide");
783✔
370

371
         const BigInt a = vars.get_req_bn("In1");
783✔
372
         const BigInt b = vars.get_req_bn("In2");
783✔
373
         const BigInt c = vars.get_req_bn("Output");
783✔
374

375
         result.test_eq("a / b", a / b, c);
1,566✔
376

377
         BigInt e = a;
783✔
378
         e /= b;
783✔
379
         result.test_eq("a /= b", e, c);
783✔
380

381
         if(b.sig_words() == 1) {
783✔
382
            const Botan::word bw = b.word_at(0);
404✔
383
            result.test_eq("bw ok", Botan::BigInt::from_word(bw), b);
808✔
384

385
            Botan::BigInt ct_q;
404✔
386
            Botan::word ct_r;
404✔
387
            Botan::ct_divide_word(a, bw, ct_q, ct_r);
404✔
388
            result.test_eq("ct_divide_word q", ct_q, c);
404✔
389
            result.test_eq("ct_divide_word r", ct_q * b + ct_r, a);
2,020✔
390
         }
404✔
391

392
         Botan::BigInt ct_q, ct_r;
783✔
393
         Botan::ct_divide(a, b, ct_q, ct_r);
783✔
394
         result.test_eq("ct_divide q", ct_q, c);
783✔
395
         result.test_eq("ct_divide r", ct_q * b + ct_r, a);
2,349✔
396

397
         return result;
783✔
398
      }
4,696✔
399
};
400

401
BOTAN_REGISTER_TEST("math", "bn_div", BigInt_Div_Test);
402

403
class BigInt_Mod_Test final : public Text_Based_Test {
×
404
   public:
405
      BigInt_Mod_Test() : Text_Based_Test("bn/mod.vec", "In1,In2,Output") {}
2✔
406

407
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
76✔
408
         Test::Result result("BigInt Mod");
76✔
409

410
         const BigInt a = vars.get_req_bn("In1");
76✔
411
         const BigInt b = vars.get_req_bn("In2");
76✔
412
         const BigInt expected = vars.get_req_bn("Output");
76✔
413

414
         result.test_eq("a % b", a % b, expected);
152✔
415

416
         BigInt e = a;
76✔
417
         e %= b;
76✔
418
         result.test_eq("a %= b", e, expected);
76✔
419

420
         const Botan::Modular_Reducer mod_b(b);
76✔
421
         result.test_eq("Barrett", mod_b.reduce(a), expected);
152✔
422

423
         // if b fits into a Botan::word test %= operator for words
424
         if(b.sig_words() == 1) {
76✔
425
            const Botan::word b_word = b.word_at(0);
30✔
426

427
            e = a;
30✔
428
            e %= b_word;
30✔
429
            result.test_eq("a %= b (as word)", e, expected);
30✔
430

431
            result.test_eq("a % b (as word)", a % b_word, expected);
60✔
432

433
            Botan::BigInt ct_q;
30✔
434
            Botan::word ct_r;
30✔
435
            Botan::ct_divide_word(a, b.word_at(0), ct_q, ct_r);
60✔
436
            result.test_eq("ct_divide_u8 r", ct_r, expected);
82✔
437
         }
30✔
438

439
         Botan::BigInt ct_q, ct_r;
76✔
440
         Botan::ct_divide(a, b, ct_q, ct_r);
76✔
441
         result.test_eq("ct_divide r", ct_r, expected);
76✔
442

443
         return result;
76✔
444
      }
453✔
445
};
446

447
BOTAN_REGISTER_TEST("math", "bn_mod", BigInt_Mod_Test);
448

449
class BigInt_GCD_Test final : public Text_Based_Test {
×
450
   public:
451
      BigInt_GCD_Test() : Text_Based_Test("bn/gcd.vec", "X,Y,GCD") {}
2✔
452

453
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
182✔
454
         Test::Result result("BigInt GCD");
182✔
455

456
         const BigInt x = vars.get_req_bn("X");
182✔
457
         const BigInt y = vars.get_req_bn("Y");
182✔
458
         const BigInt expected = vars.get_req_bn("GCD");
182✔
459

460
         const BigInt g1 = Botan::gcd(x, y);
182✔
461
         result.test_eq("gcd", g1, expected);
182✔
462

463
         const BigInt g2 = Botan::gcd(y, x);
182✔
464
         result.test_eq("gcd", g2, expected);
182✔
465

466
         return result;
182✔
467
      }
910✔
468
};
469

470
BOTAN_REGISTER_TEST("math", "bn_gcd", BigInt_GCD_Test);
471

472
class BigInt_Jacobi_Test final : public Text_Based_Test {
×
473
   public:
474
      BigInt_Jacobi_Test() : Text_Based_Test("bn/jacobi.vec", "A,N,J") {}
2✔
475

476
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
698✔
477
         Test::Result result("BigInt Jacobi");
698✔
478

479
         const BigInt a = vars.get_req_bn("A");
698✔
480
         const BigInt n = vars.get_req_bn("N");
698✔
481
         const std::string expected = vars.get_req_str("J");
698✔
482

483
         const int32_t j = Botan::jacobi(a, n);
698✔
484

485
         if(j == 0) {
698✔
486
            result.test_eq("jacobi", expected, "0");
314✔
487
         } else if(j == -1) {
541✔
488
            result.test_eq("jacobi", expected, "-1");
614✔
489
         } else {
490
            result.test_eq("jacobi", expected, "1");
468✔
491
         }
492

493
         return result;
698✔
494
      }
2,094✔
495
};
496

497
BOTAN_REGISTER_TEST("math", "bn_jacobi", BigInt_Jacobi_Test);
498

499
class BigInt_Lshift_Test final : public Text_Based_Test {
×
500
   public:
501
      BigInt_Lshift_Test() : Text_Based_Test("bn/lshift.vec", "Value,Shift,Output") {}
2✔
502

503
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
50✔
504
         Test::Result result("BigInt Lshift");
50✔
505

506
         const BigInt value = vars.get_req_bn("Value");
50✔
507
         const size_t shift = vars.get_req_bn("Shift").to_u32bit();
100✔
508
         const BigInt output = vars.get_req_bn("Output");
50✔
509

510
         result.test_eq("a << s", value << shift, output);
100✔
511

512
         BigInt e = value;
50✔
513
         e <<= shift;
50✔
514
         result.test_eq("a <<= s", e, output);
50✔
515

516
         return result;
50✔
517
      }
150✔
518
};
519

520
BOTAN_REGISTER_TEST("math", "bn_lshift", BigInt_Lshift_Test);
521

522
class BigInt_Rshift_Test final : public Text_Based_Test {
×
523
   public:
524
      BigInt_Rshift_Test() : Text_Based_Test("bn/rshift.vec", "Value,Shift,Output") {}
2✔
525

526
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
53✔
527
         Test::Result result("BigInt Rshift");
53✔
528

529
         const BigInt value = vars.get_req_bn("Value");
53✔
530
         const size_t shift = vars.get_req_bn("Shift").to_u32bit();
106✔
531
         const BigInt output = vars.get_req_bn("Output");
53✔
532

533
         result.test_eq("a >> s", value >> shift, output);
106✔
534

535
         BigInt e = value;
53✔
536
         e >>= shift;
53✔
537
         result.test_eq("a >>= s", e, output);
53✔
538

539
         return result;
53✔
540
      }
159✔
541
};
542

543
BOTAN_REGISTER_TEST("math", "bn_rshift", BigInt_Rshift_Test);
544

545
Test::Result test_const_time_left_shift() {
1✔
546
   Test::Result result("BigInt const time shift");
1✔
547
   const size_t bits = Test::run_long_tests() ? 4096 : 2048;
1✔
548

549
   auto rng = Test::new_rng("const_time_left_shift");
1✔
550

551
   result.start_timer();
1✔
552

553
   Botan::BigInt a = Botan::BigInt::with_capacity(bits / sizeof(Botan::word));
1✔
554
   for(size_t i = 0; i < bits; ++i) {
4,097✔
555
      if(rng->next_byte() & 1) {
4,096✔
556
         a.set_bit(i);
4,096✔
557
      }
558
   }
559

560
   for(size_t i = 0; i < bits; ++i) {
4,097✔
561
      auto ct = a;
4,096✔
562
      auto chk = a;
4,096✔
563
      Botan::CT::poison(ct);
4,096✔
564
      ct.ct_shift_left(i);
4,096✔
565
      Botan::CT::unpoison(ct);
4,096✔
566
      chk <<= i;
4,096✔
567
      result.test_eq(Botan::fmt("ct << {}", i), ct, chk);
8,192✔
568
   }
8,192✔
569

570
   result.end_timer();
1✔
571

572
   return result;
1✔
573
}
2✔
574

575
class BigInt_Powmod_Test final : public Text_Based_Test {
×
576
   public:
577
      BigInt_Powmod_Test() : Text_Based_Test("bn/powmod.vec", "Base,Exponent,Modulus,Output") {}
2✔
578

579
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
47✔
580
         Test::Result result("BigInt Powmod");
47✔
581

582
         const BigInt base = vars.get_req_bn("Base");
47✔
583
         const BigInt exponent = vars.get_req_bn("Exponent");
47✔
584
         const BigInt modulus = vars.get_req_bn("Modulus");
47✔
585
         const BigInt expected = vars.get_req_bn("Output");
47✔
586

587
         result.test_eq("power_mod", Botan::power_mod(base, exponent, modulus), expected);
94✔
588
         return result;
47✔
589
      }
188✔
590
};
591

592
BOTAN_REGISTER_TEST("math", "bn_powmod", BigInt_Powmod_Test);
593

594
class BigInt_IsPrime_Test final : public Text_Based_Test {
×
595
   public:
596
      BigInt_IsPrime_Test() : Text_Based_Test("bn/isprime.vec", "X") {}
2✔
597

598
      Test::Result run_one_test(const std::string& header, const VarMap& vars) override {
132✔
599
         if(header != "Prime" && header != "NonPrime") {
132✔
600
            throw Test_Error("Bad header for prime test " + header);
×
601
         }
602

603
         const BigInt value = vars.get_req_bn("X");
132✔
604
         const bool is_prime = (header == "Prime");
132✔
605

606
         Test::Result result("BigInt Test " + header);
132✔
607
         result.test_eq("is_prime", Botan::is_prime(value, this->rng()), is_prime);
132✔
608

609
         return result;
132✔
610
      }
132✔
611
};
612

613
BOTAN_REGISTER_TEST("math", "bn_isprime", BigInt_IsPrime_Test);
614

615
class BigInt_IsSquare_Test final : public Text_Based_Test {
×
616
   public:
617
      BigInt_IsSquare_Test() : Text_Based_Test("bn/perfect_square.vec", "X,R") {}
2✔
618

619
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
7✔
620
         const BigInt value = vars.get_req_bn("X");
7✔
621
         const BigInt expected = vars.get_req_bn("R");
7✔
622
         const BigInt computed = Botan::is_perfect_square(value);
7✔
623

624
         Test::Result result("BigInt IsSquare");
7✔
625
         result.test_eq("is_perfect_square", computed, expected);
7✔
626
         return result;
7✔
627
      }
21✔
628
};
629

630
BOTAN_REGISTER_TEST("math", "bn_issquare", BigInt_IsSquare_Test);
631

632
class BigInt_Sqrt_Modulo_Prime_Test final : public Text_Based_Test {
×
633
   public:
634
      BigInt_Sqrt_Modulo_Prime_Test() : Text_Based_Test("bn/sqrt_modulo_prime.vec", "Input,Modulus,Output") {}
2✔
635

636
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
17✔
637
         Test::Result result("BigInt Sqrt Modulo Prime");
17✔
638

639
         const Botan::BigInt a = vars.get_req_bn("Input");
17✔
640
         const Botan::BigInt p = vars.get_req_bn("Modulus");
17✔
641
         const Botan::BigInt exp = vars.get_req_bn("Output");
17✔
642

643
         const Botan::BigInt a_sqrt = Botan::sqrt_modulo_prime(a, p);
17✔
644

645
         result.test_eq("sqrt_modulo_prime", a_sqrt, exp);
17✔
646

647
         if(a_sqrt > 1) {
17✔
648
            const Botan::BigInt a_sqrt2 = (a_sqrt * a_sqrt) % p;
8✔
649
            result.test_eq("square correct", a_sqrt2, a);
16✔
650
         }
8✔
651

652
         return result;
17✔
653
      }
68✔
654
};
655

656
BOTAN_REGISTER_TEST("math", "bn_sqrt_modulo_prime", BigInt_Sqrt_Modulo_Prime_Test);
657

658
class BigInt_InvMod_Test final : public Text_Based_Test {
×
659
   public:
660
      BigInt_InvMod_Test() : Text_Based_Test("bn/invmod.vec", "Input,Modulus,Output") {}
2✔
661

662
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
138✔
663
         Test::Result result("BigInt InvMod");
138✔
664

665
         const Botan::BigInt a = vars.get_req_bn("Input");
138✔
666
         const Botan::BigInt mod = vars.get_req_bn("Modulus");
138✔
667
         const Botan::BigInt expected = vars.get_req_bn("Output");
138✔
668

669
         const Botan::BigInt a_inv = Botan::inverse_mod(a, mod);
138✔
670

671
         result.test_eq("inverse_mod", a_inv, expected);
138✔
672

673
         if(a_inv > 1) {
138✔
674
            result.test_eq("inverse ok", (a * a_inv) % mod, 1);
415✔
675
         }
676
         /*
677
         else if((a % mod) > 0)
678
            {
679
            result.confirm("no inverse with gcd > 1", gcd(a, mod) > 1);
680
            }
681
         */
682

683
         return result;
138✔
684
      }
552✔
685
};
686

687
BOTAN_REGISTER_TEST("math", "bn_invmod", BigInt_InvMod_Test);
688

689
class BigInt_Rand_Test final : public Text_Based_Test {
×
690
   public:
691
      BigInt_Rand_Test() : Text_Based_Test("bn/random.vec", "Seed,Min,Max,Output") {}
2✔
692

693
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
4✔
694
         Test::Result result("BigInt Random");
4✔
695

696
         const std::vector<uint8_t> seed = vars.get_req_bin("Seed");
4✔
697
         const Botan::BigInt min = vars.get_req_bn("Min");
4✔
698
         const Botan::BigInt max = vars.get_req_bn("Max");
4✔
699
         const Botan::BigInt expected = vars.get_req_bn("Output");
4✔
700

701
         Fixed_Output_RNG rng(seed);
4✔
702
         Botan::BigInt generated = BigInt::random_integer(rng, min, max);
4✔
703

704
         result.test_eq("random_integer KAT", generated, expected);
4✔
705

706
         return result;
4✔
707
      }
20✔
708
};
709

710
BOTAN_REGISTER_TEST("math", "bn_rand", BigInt_Rand_Test);
711

712
class Lucas_Primality_Test final : public Test {
×
713
   public:
714
      std::vector<Test::Result> run() override {
1✔
715
         const uint32_t lucas_max = (Test::run_long_tests() ? 100000 : 6000);
1✔
716

717
         // OEIS A217120
718
         std::set<uint32_t> lucas_pp{
1✔
719
            323,   377,   1159,  1829,  3827,  5459,  5777,  9071,  9179,  10877, 11419, 11663, 13919, 14839, 16109,
720
            16211, 18407, 18971, 19043, 22499, 23407, 24569, 25199, 25877, 26069, 27323, 32759, 34943, 35207, 39059,
721
            39203, 39689, 40309, 44099, 46979, 47879, 50183, 51983, 53663, 56279, 58519, 60377, 63881, 69509, 72389,
722
            73919, 75077, 77219, 79547, 79799, 82983, 84419, 86063, 90287, 94667, 97019, 97439,
723
         };
1✔
724

725
         Test::Result result("Lucas primality test");
1✔
726

727
         for(uint32_t i = 3; i <= lucas_max; i += 2) {
50,000✔
728
            Botan::Modular_Reducer mod_i(i);
49,999✔
729
            const bool passes_lucas = Botan::is_lucas_probable_prime(i, mod_i);
49,999✔
730
            const bool is_prime = Botan::is_prime(i, this->rng());
49,999✔
731

732
            const bool is_lucas_pp = (is_prime == false && passes_lucas == true);
49,999✔
733

734
            if(is_lucas_pp) {
49,999✔
735
               result.confirm("Lucas pseudoprime is in list", lucas_pp.count(i) == 1);
171✔
736
            } else {
737
               result.confirm("Lucas non-pseudoprime is not in list", !lucas_pp.contains(i));
149,826✔
738
            }
739
         }
49,999✔
740

741
         return {result};
2✔
742
      }
2✔
743
};
744

745
BOTAN_REGISTER_TEST("math", "bn_lucas", Lucas_Primality_Test);
746

747
class DSA_ParamGen_Test final : public Text_Based_Test {
×
748
   public:
749
      DSA_ParamGen_Test() : Text_Based_Test("bn/dsa_gen.vec", "P,Q,Counter,Seed") {}
2✔
750

751
      Test::Result run_one_test(const std::string& header, const VarMap& vars) override {
20✔
752
         const std::vector<uint8_t> seed = vars.get_req_bin("Seed");
20✔
753
         const size_t offset = vars.get_req_sz("Counter");
20✔
754

755
         const Botan::BigInt exp_P = vars.get_req_bn("P");
20✔
756
         const Botan::BigInt exp_Q = vars.get_req_bn("Q");
20✔
757

758
         const std::vector<std::string> header_parts = Botan::split_on(header, ',');
20✔
759

760
         if(header_parts.size() != 2) {
20✔
761
            throw Test_Error("Unexpected header '" + header + "' in DSA param gen test");
×
762
         }
763

764
         const size_t p_bits = Botan::to_u32bit(header_parts[1]);
20✔
765
         const size_t q_bits = Botan::to_u32bit(header_parts[0]);
20✔
766

767
         Test::Result result("DSA Parameter Generation");
20✔
768

769
         try {
20✔
770
            Botan::BigInt gen_P, gen_Q;
20✔
771
            if(Botan::generate_dsa_primes(this->rng(), gen_P, gen_Q, p_bits, q_bits, seed, offset)) {
20✔
772
               result.test_eq("P", gen_P, exp_P);
20✔
773
               result.test_eq("Q", gen_Q, exp_Q);
40✔
774
            } else {
775
               result.test_failure("Seed did not generate a DSA parameter");
×
776
            }
777
         } catch(Botan::Lookup_Error&) {}
40✔
778

779
         return result;
40✔
780
      }
80✔
781
};
782

783
BOTAN_REGISTER_TEST("math", "dsa_param", DSA_ParamGen_Test);
784

785
std::vector<Test::Result> test_bigint_serialization() {
1✔
786
   auto rng = Test::new_rng("test_bigint_serialization");
1✔
787

788
   return {
1✔
789
      CHECK("BigInt binary serialization",
790
            [](Test::Result& res) {
1✔
791
               Botan::BigInt a(0x1234567890ABCDEF);
1✔
792
               auto enc = a.serialize();
1✔
793
               res.test_eq("BigInt::serialize", enc, Botan::hex_decode("1234567890ABCDEF"));
2✔
794

795
               auto enc10 = a.serialize(10);
1✔
796
               res.test_eq("BigInt::serialize", enc10, Botan::hex_decode("00001234567890ABCDEF"));
2✔
797

798
               res.test_throws("BigInt::serialize rejects short output", [&]() { a.serialize(7); });
4✔
799
            }),
3✔
800

801
      CHECK("BigInt truncated/padded binary serialization",
802
            [&](Test::Result& res) {
1✔
803
               Botan::BigInt a(0xFEDCBA9876543210);
1✔
804

805
               std::vector<uint8_t> enc1(a.bytes() - 1);
1✔
806
               a.binary_encode(enc1.data(), enc1.size());
1✔
807
               res.test_eq("BigInt::binary_encode", enc1, Botan::hex_decode("DCBA9876543210"));
2✔
808

809
               std::vector<uint8_t> enc2(a.bytes() - 3);
1✔
810
               a.binary_encode(enc2.data(), enc2.size());
1✔
811
               res.test_eq("BigInt::binary_encode", enc2, Botan::hex_decode("9876543210"));
2✔
812

813
               std::vector<uint8_t> enc3(a.bytes() + 1);
1✔
814
               a.binary_encode(enc3.data(), enc3.size());
1✔
815
               res.test_eq("BigInt::binary_encode", enc3, Botan::hex_decode("00FEDCBA9876543210"));
2✔
816

817
               // make sure that the padding is actually written
818
               std::vector<uint8_t> enc4(a.bytes() + 3);
1✔
819
               rng->randomize(enc4);
1✔
820
               a.binary_encode(enc4.data(), enc4.size());
1✔
821
               res.test_eq("BigInt::binary_encode", enc4, Botan::hex_decode("000000FEDCBA9876543210"));
2✔
822

823
               Botan::BigInt b(Botan::hex_decode("FEDCBA9876543210BAADC0FFEE"));
1✔
824

825
               std::vector<uint8_t> enc5(b.bytes() + 12);
1✔
826
               rng->randomize(enc5);
1✔
827
               b.binary_encode(enc5.data(), enc5.size());
1✔
828
               res.test_eq("BigInt::binary_encode",
2✔
829
                           enc5,
830
                           Botan::hex_decode("000000000000000000000000FEDCBA9876543210BAADC0FFEE"));
2✔
831
            }),
7✔
832
   };
3✔
833
}
2✔
834

835
BOTAN_REGISTER_TEST_FN("math", "bignum_auxiliary", test_const_time_left_shift, test_bigint_serialization);
836

837
#endif
838

839
}  // namespace
840

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

© 2025 Coveralls, Inc