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

randombit / botan / 17241471766

26 Aug 2025 02:35PM UTC coverage: 90.658% (-0.005%) from 90.663%
17241471766

push

github

web-flow
Merge pull request #5075 from randombit/jack/typos-ci

Add a typos CI job

100192 of 110516 relevant lines covered (90.66%)

12246253.89 hits per line

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

94.24
/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/internal/barrett.h>
15
   #include <botan/internal/ct_utils.h>
16
   #include <botan/internal/divide.h>
17
   #include <botan/internal/fmt.h>
18
   #include <botan/internal/mod_inv.h>
19
   #include <botan/internal/mp_core.h>
20
   #include <botan/internal/parsing.h>
21
   #include <botan/internal/primality.h>
22
   #include <botan/internal/stl_util.h>
23
#endif
24

25
namespace Botan_Tests {
26

27
namespace {
28

29
#if defined(BOTAN_HAS_NUMBERTHEORY)
30

31
using Botan::BigInt;
32

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

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

44
         return results;
1✔
45
      }
×
46

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

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

54
            a.set_bit(bit);
12✔
55

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

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

77
               a--;
24✔
78
            }
79
         }
12✔
80

81
         return result;
1✔
82
      }
×
83

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

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

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

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

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

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

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

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

118
         return result;
2✔
119
      }
2✔
120

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

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

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

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

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

140
         return result;
2✔
141
      }
4✔
142

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

146
         const size_t rbits = 1024;
1✔
147

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

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

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

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

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

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

165
         return result;
2✔
166
      }
2✔
167

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

259
         return result;
19✔
260
      }
19✔
261
};
262

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

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

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

272
         using Botan::BigInt;
78✔
273

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

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

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

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

289
         return result;
78✔
290
      }
78✔
291
};
292

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

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

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

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

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

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

312
         return result;
77✔
313
      }
77✔
314
};
315

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

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

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

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

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

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

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

340
         return result;
104✔
341
      }
104✔
342
};
343

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

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

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

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

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

359
         return result;
21✔
360
      }
21✔
361
};
362

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

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

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

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

376
         result.test_eq("a / b", a / b, c);
1,572✔
377

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

382
         if(b.sig_words() == 1 && b.is_positive()) {
786✔
383
            const Botan::word bw = b.word_at(0);
405✔
384
            result.test_eq("Low word correct", Botan::BigInt::from_word(bw), b);
810✔
385

386
            Botan::BigInt ct_q;
405✔
387
            Botan::word ct_r = 0;
405✔
388
            Botan::ct_divide_word(a, bw, ct_q, ct_r);
405✔
389
            result.test_eq("ct_divide_word q", ct_q, c);
405✔
390
            result.test_eq("ct_divide_word r", ct_q * b + ct_r, a);
1,215✔
391
         }
405✔
392

393
         Botan::BigInt ct_q;
786✔
394
         Botan::BigInt ct_r;
786✔
395
         Botan::ct_divide(a, b, ct_q, ct_r);
786✔
396
         result.test_eq("ct_divide q", ct_q, c);
786✔
397
         result.test_eq("ct_divide r", ct_q * b + ct_r, a);
1,572✔
398

399
         return result;
786✔
400
      }
786✔
401
};
402

403
BOTAN_REGISTER_TEST("math", "bn_div", BigInt_Div_Test);
404

405
class BigInt_DivPow2k_Test final : public Test {
×
406
   public:
407
      std::vector<Test::Result> run() override {
1✔
408
         Test::Result result("BigInt ct_divide_pow2k");
1✔
409

410
         for(size_t k = 2; k != 128; ++k) {
127✔
411
            auto div1 = Botan::ct_divide_pow2k(k, 1);
126✔
412
            result.test_eq("ct_divide_pow2k div 1", div1, Botan::BigInt::power_of_2(k));
252✔
413

414
            auto div2 = Botan::ct_divide_pow2k(k, 2);
126✔
415
            result.test_eq("ct_divide_pow2k div 2", div2, Botan::BigInt::power_of_2(k - 1));
252✔
416

417
            auto div4 = Botan::ct_divide_pow2k(k, 4);
126✔
418
            result.test_eq("ct_divide_pow2k div 4", div4, Botan::BigInt::power_of_2(k - 2));
252✔
419
         }
126✔
420

421
         for(size_t k = 4; k != 512; ++k) {
509✔
422
            const BigInt pow2k = BigInt::power_of_2(k);
508✔
423

424
            for(size_t y_bits = k / 2; y_bits <= (k + 2); ++y_bits) {
67,564✔
425
               const BigInt y(rng(), y_bits, false);
67,056✔
426
               if(y.is_zero()) {
134,112✔
427
                  continue;
×
428
               }
429
               const BigInt ct_pow2k = ct_divide_pow2k(k, y);
67,056✔
430
               const BigInt ref = BigInt::power_of_2(k) / y;
67,056✔
431

432
               result.test_eq("ct_divide_pow2k matches Knuth division", ct_pow2k, ref);
67,056✔
433
            }
67,056✔
434
         }
508✔
435

436
         return {result};
3✔
437
      }
2✔
438
};
439

440
BOTAN_REGISTER_TEST("math", "bn_div_pow2k", BigInt_DivPow2k_Test);
441

442
class BigInt_Mod_Test final : public Text_Based_Test {
×
443
   public:
444
      BigInt_Mod_Test() : Text_Based_Test("bn/mod.vec", "In1,In2,Output") {}
2✔
445

446
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
80✔
447
         Test::Result result("BigInt Mod");
80✔
448

449
         const BigInt a = vars.get_req_bn("In1");
80✔
450
         const BigInt b = vars.get_req_bn("In2");
80✔
451
         const BigInt expected = vars.get_req_bn("Output");
80✔
452

453
         result.test_eq("a % b", a % b, expected);
160✔
454

455
         BigInt e = a;
80✔
456
         e %= b;
80✔
457
         result.test_eq("a %= b", e, expected);
80✔
458

459
         if(a.is_positive() && a < (b * b)) {
80✔
460
            auto mod_b_pub = Botan::Barrett_Reduction::for_public_modulus(b);
43✔
461
            result.test_eq("Barrett public", mod_b_pub.reduce(a), expected);
86✔
462

463
            auto mod_b_sec = Botan::Barrett_Reduction::for_secret_modulus(b);
43✔
464
            result.test_eq("Barrett secret", mod_b_sec.reduce(a), expected);
86✔
465
         }
86✔
466

467
         // if b fits into a Botan::word test %= operator for words
468
         if(b.sig_words() == 1) {
80✔
469
            const Botan::word b_word = b.word_at(0);
34✔
470

471
            e = a;
34✔
472
            e %= b_word;
34✔
473
            result.test_eq("a %= b (as word)", e, expected);
34✔
474

475
            result.test_eq("a % b (as word)", a % b_word, expected);
68✔
476

477
            Botan::BigInt ct_q;
34✔
478
            Botan::word ct_r = 0;
34✔
479
            Botan::ct_divide_word(a, b.word_at(0), ct_q, ct_r);
68✔
480
            result.test_eq("ct_divide_u8 r", ct_r, expected);
68✔
481
         }
34✔
482

483
         Botan::BigInt ct_q;
80✔
484
         Botan::BigInt ct_r;
80✔
485
         Botan::ct_divide(a, b, ct_q, ct_r);
80✔
486
         result.test_eq("ct_divide r", ct_r, expected);
80✔
487

488
         return result;
80✔
489
      }
80✔
490
};
491

492
BOTAN_REGISTER_TEST("math", "bn_mod", BigInt_Mod_Test);
493

494
class Barrett_Redc_Test final : public Test {
×
495
   public:
496
      std::vector<Test::Result> run() override {
1✔
497
         Test::Result result("Barrett reduction");
1✔
498

499
         for(size_t t = 0; t != 10000; ++t) {
10,001✔
500
            const auto mod = [&]() {
30,000✔
501
               if(t <= 16) {
10,000✔
502
                  return BigInt::from_u64(t) + 1;
34✔
503
               } else {
504
                  const size_t bits = (t / 4) + 2;
9,983✔
505

506
                  if(t % 4 == 0) {
9,983✔
507
                     return BigInt::power_of_2(bits);
2,495✔
508
                  } else if(t % 4 == 1) {
7,488✔
509
                     return BigInt::power_of_2(bits) - 1;
4,992✔
510
                  } else if(t % 4 == 2) {
4,992✔
511
                     return BigInt::power_of_2(bits) + 1;
4,992✔
512
                  } else {
513
                     Botan::BigInt b;
2,496✔
514
                     b.randomize(rng(), bits, true);
2,496✔
515
                     return b;
2,496✔
516
                  }
2,496✔
517
               }
518
            }();
10,000✔
519

520
            const size_t mod_bits = mod.bits();
10,000✔
521
            auto barrett = Botan::Barrett_Reduction::for_public_modulus(mod);
10,000✔
522

523
            for(size_t i = 0; i != 10; ++i) {
110,000✔
524
               const auto input = [&]() {
×
525
                  Botan::BigInt b;
100,000✔
526
                  b.randomize(rng(), 2 * mod_bits, false);
100,000✔
527
                  return b;
100,000✔
528
               }();
100,000✔
529

530
               const auto reduced_ref = input % mod;
100,000✔
531
               const auto reduced_barrett = barrett.reduce(input);
100,000✔
532

533
               result.test_eq("Barrett reduction matches variable time division", reduced_barrett, reduced_ref);
100,000✔
534
            }
100,000✔
535
         }
10,000✔
536

537
         return {result};
3✔
538
      }
2✔
539
};
540

541
BOTAN_REGISTER_TEST("math", "barrett_redc", Barrett_Redc_Test);
542

543
class BigInt_GCD_Test final : public Text_Based_Test {
×
544
   public:
545
      BigInt_GCD_Test() : Text_Based_Test("bn/gcd.vec", "X,Y,GCD") {}
2✔
546

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

550
         const BigInt x = vars.get_req_bn("X");
182✔
551
         const BigInt y = vars.get_req_bn("Y");
182✔
552
         const BigInt expected = vars.get_req_bn("GCD");
182✔
553

554
         const BigInt g1 = Botan::gcd(x, y);
182✔
555
         result.test_eq("gcd", g1, expected);
182✔
556

557
         const BigInt g2 = Botan::gcd(y, x);
182✔
558
         result.test_eq("gcd", g2, expected);
182✔
559

560
         return result;
182✔
561
      }
182✔
562
};
563

564
BOTAN_REGISTER_TEST("math", "bn_gcd", BigInt_GCD_Test);
565

566
class BigInt_Jacobi_Test final : public Text_Based_Test {
×
567
   public:
568
      BigInt_Jacobi_Test() : Text_Based_Test("bn/jacobi.vec", "A,N,J") {}
2✔
569

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

573
         const BigInt a = vars.get_req_bn("A");
698✔
574
         const BigInt n = vars.get_req_bn("N");
698✔
575
         const std::string expected = vars.get_req_str("J");
698✔
576

577
         const int32_t j = Botan::jacobi(a, n);
698✔
578

579
         if(j == 0) {
698✔
580
            result.test_eq("jacobi", expected, "0");
314✔
581
         } else if(j == -1) {
541✔
582
            result.test_eq("jacobi", expected, "-1");
614✔
583
         } else {
584
            result.test_eq("jacobi", expected, "1");
468✔
585
         }
586

587
         return result;
1,396✔
588
      }
698✔
589
};
590

591
BOTAN_REGISTER_TEST("math", "bn_jacobi", BigInt_Jacobi_Test);
592

593
class BigInt_Lshift_Test final : public Text_Based_Test {
×
594
   public:
595
      BigInt_Lshift_Test() : Text_Based_Test("bn/lshift.vec", "Value,Shift,Output") {}
2✔
596

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

600
         const BigInt value = vars.get_req_bn("Value");
50✔
601
         const size_t shift = vars.get_req_bn("Shift").to_u32bit();
50✔
602
         const BigInt output = vars.get_req_bn("Output");
50✔
603

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

606
         BigInt e = value;
50✔
607
         e <<= shift;
50✔
608
         result.test_eq("a <<= s", e, output);
50✔
609

610
         return result;
50✔
611
      }
50✔
612
};
613

614
BOTAN_REGISTER_TEST("math", "bn_lshift", BigInt_Lshift_Test);
615

616
class BigInt_Rshift_Test final : public Text_Based_Test {
×
617
   public:
618
      BigInt_Rshift_Test() : Text_Based_Test("bn/rshift.vec", "Value,Shift,Output") {}
2✔
619

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

623
         const BigInt value = vars.get_req_bn("Value");
53✔
624
         const size_t shift = vars.get_req_bn("Shift").to_u32bit();
53✔
625
         const BigInt output = vars.get_req_bn("Output");
53✔
626

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

629
         BigInt e = value;
53✔
630
         e >>= shift;
53✔
631
         result.test_eq("a >>= s", e, output);
53✔
632

633
         return result;
53✔
634
      }
53✔
635
};
636

637
BOTAN_REGISTER_TEST("math", "bn_rshift", BigInt_Rshift_Test);
638

639
Test::Result test_const_time_left_shift() {
1✔
640
   Test::Result result("BigInt const time shift");
1✔
641
   const size_t bits = Test::run_long_tests() ? 4096 : 2048;
1✔
642

643
   auto rng = Test::new_rng("const_time_left_shift");
1✔
644

645
   result.start_timer();
1✔
646

647
   Botan::BigInt a = Botan::BigInt::with_capacity(bits / sizeof(Botan::word));
1✔
648
   for(size_t i = 0; i < bits; ++i) {
4,097✔
649
      if(rng->next_byte() % 2 == 1) {
4,096✔
650
         a.set_bit(i);
4,096✔
651
      }
652
   }
653

654
   for(size_t i = 0; i < bits; ++i) {
4,097✔
655
      auto ct = a;
4,096✔
656
      auto chk = a;
4,096✔
657
      Botan::CT::poison(ct);
4,096✔
658
      ct.ct_shift_left(i);
4,096✔
659
      Botan::CT::unpoison(ct);
4,096✔
660
      chk <<= i;
4,096✔
661
      result.test_eq(Botan::fmt("ct << {}", i), ct, chk);
4,096✔
662
   }
4,096✔
663

664
   result.end_timer();
1✔
665

666
   return result;
2✔
667
}
2✔
668

669
class BigInt_Powmod_Test final : public Text_Based_Test {
×
670
   public:
671
      BigInt_Powmod_Test() : Text_Based_Test("bn/powmod.vec", "Base,Exponent,Modulus,Output") {}
2✔
672

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

676
         const BigInt base = vars.get_req_bn("Base");
47✔
677
         const BigInt exponent = vars.get_req_bn("Exponent");
47✔
678
         const BigInt modulus = vars.get_req_bn("Modulus");
47✔
679
         const BigInt expected = vars.get_req_bn("Output");
47✔
680

681
         result.test_eq("power_mod", Botan::power_mod(base, exponent, modulus), expected);
94✔
682
         return result;
47✔
683
      }
47✔
684
};
685

686
BOTAN_REGISTER_TEST("math", "bn_powmod", BigInt_Powmod_Test);
687

688
class BigInt_IsPrime_Test final : public Text_Based_Test {
×
689
   public:
690
      BigInt_IsPrime_Test() : Text_Based_Test("bn/isprime.vec", "X") {}
2✔
691

692
      Test::Result run_one_test(const std::string& header, const VarMap& vars) override {
132✔
693
         if(header != "Prime" && header != "NonPrime") {
132✔
694
            throw Test_Error("Bad header for prime test " + header);
×
695
         }
696

697
         const BigInt value = vars.get_req_bn("X");
132✔
698
         const bool is_prime = (header == "Prime");
132✔
699

700
         Test::Result result("BigInt Test " + header);
132✔
701
         result.test_eq("is_prime", Botan::is_prime(value, this->rng()), is_prime);
132✔
702

703
         return result;
132✔
704
      }
132✔
705
};
706

707
BOTAN_REGISTER_TEST("math", "bn_isprime", BigInt_IsPrime_Test);
708

709
class BigInt_IsSquare_Test final : public Text_Based_Test {
×
710
   public:
711
      BigInt_IsSquare_Test() : Text_Based_Test("bn/perfect_square.vec", "X,R") {}
2✔
712

713
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
7✔
714
         const BigInt value = vars.get_req_bn("X");
7✔
715
         const BigInt expected = vars.get_req_bn("R");
7✔
716
         const BigInt computed = Botan::is_perfect_square(value);
7✔
717

718
         Test::Result result("BigInt IsSquare");
7✔
719
         result.test_eq("is_perfect_square", computed, expected);
7✔
720
         return result;
7✔
721
      }
7✔
722
};
723

724
BOTAN_REGISTER_TEST("math", "bn_issquare", BigInt_IsSquare_Test);
725

726
class BigInt_Sqrt_Modulo_Prime_Test final : public Text_Based_Test {
×
727
   public:
728
      BigInt_Sqrt_Modulo_Prime_Test() : Text_Based_Test("bn/sqrt_modulo_prime.vec", "Input,Modulus,Output") {}
2✔
729

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

733
         const Botan::BigInt a = vars.get_req_bn("Input");
17✔
734
         const Botan::BigInt p = vars.get_req_bn("Modulus");
17✔
735
         const Botan::BigInt exp = vars.get_req_bn("Output");
17✔
736

737
         const Botan::BigInt a_sqrt = Botan::sqrt_modulo_prime(a, p);
17✔
738

739
         result.test_eq("sqrt_modulo_prime", a_sqrt, exp);
17✔
740

741
         if(a_sqrt > 1) {
17✔
742
            const Botan::BigInt a_sqrt2 = (a_sqrt * a_sqrt) % p;
8✔
743
            result.test_eq("square correct", a_sqrt2, a);
8✔
744
         }
8✔
745

746
         return result;
17✔
747
      }
17✔
748
};
749

750
BOTAN_REGISTER_TEST("math", "bn_sqrt_modulo_prime", BigInt_Sqrt_Modulo_Prime_Test);
751

752
class BigInt_InvMod_Test final : public Text_Based_Test {
×
753
   public:
754
      BigInt_InvMod_Test() : Text_Based_Test("bn/invmod.vec", "Input,Modulus,Output") {}
2✔
755

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

759
         const Botan::BigInt a = vars.get_req_bn("Input");
138✔
760
         const Botan::BigInt mod = vars.get_req_bn("Modulus");
138✔
761
         const Botan::BigInt expected = vars.get_req_bn("Output");
138✔
762

763
         result.test_eq("inverse_mod", Botan::inverse_mod(a, mod), expected);
276✔
764

765
         if(a < mod && a > 0 && a < mod) {
398✔
766
            auto g = Botan::inverse_mod_general(a, mod);
128✔
767
            if(g.has_value()) {
128✔
768
               result.test_eq("inverse_mod_general", g.value(), expected);
87✔
769
               result.test_eq("inverse works", ((g.value() * a) % mod), BigInt::one());
261✔
770
            } else {
771
               result.confirm("inverse_mod_general", expected.is_zero());
82✔
772
            }
773

774
            if(Botan::is_prime(mod, rng()) && mod != 2) {
136✔
775
               BOTAN_ASSERT_NOMSG(expected > 0);
7✔
776
               result.test_eq("inverse_mod_secret_prime", Botan::inverse_mod_secret_prime(a, mod), expected);
14✔
777
               result.test_eq("inverse_mod_public_prime", Botan::inverse_mod_public_prime(a, mod), expected);
14✔
778
            }
779
         }
128✔
780

781
         return result;
138✔
782
      }
138✔
783
};
784

785
BOTAN_REGISTER_TEST("math", "bn_invmod", BigInt_InvMod_Test);
786

787
class BigInt_Rand_Test final : public Text_Based_Test {
×
788
   public:
789
      BigInt_Rand_Test() : Text_Based_Test("bn/random.vec", "Seed,Min,Max,Output") {}
2✔
790

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

794
         const std::vector<uint8_t> seed = vars.get_req_bin("Seed");
4✔
795
         const Botan::BigInt min = vars.get_req_bn("Min");
4✔
796
         const Botan::BigInt max = vars.get_req_bn("Max");
4✔
797
         const Botan::BigInt expected = vars.get_req_bn("Output");
4✔
798

799
         Fixed_Output_RNG rng(seed);
4✔
800
         Botan::BigInt generated = BigInt::random_integer(rng, min, max);
4✔
801

802
         result.test_eq("random_integer KAT", generated, expected);
4✔
803

804
         return result;
8✔
805
      }
8✔
806
};
807

808
BOTAN_REGISTER_TEST("math", "bn_rand", BigInt_Rand_Test);
809

810
class Lucas_Primality_Test final : public Test {
×
811
   public:
812
      std::vector<Test::Result> run() override {
1✔
813
         const uint32_t lucas_max = (Test::run_long_tests() ? 100000 : 10000) + 1;
1✔
814

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

823
         Test::Result result("Lucas primality test");
1✔
824

825
         for(uint32_t i = 3; i <= lucas_max; i += 2) {
50,001✔
826
            auto mod_i = Botan::Barrett_Reduction::for_public_modulus(i);
50,000✔
827
            const bool passes_lucas = Botan::is_lucas_probable_prime(i, mod_i);
50,000✔
828
            const bool is_prime = Botan::is_prime(i, this->rng());
50,000✔
829

830
            const bool is_lucas_pp = (is_prime == false && passes_lucas == true);
50,000✔
831

832
            if(is_lucas_pp) {
50,000✔
833
               result.confirm("Lucas pseudoprime is in list", lucas_pp.count(i) == 1);
171✔
834
            } else {
835
               result.confirm("Lucas non-pseudoprime is not in list", !lucas_pp.contains(i));
149,829✔
836
            }
837
         }
50,000✔
838

839
         return {result};
2✔
840
      }
2✔
841
};
842

843
BOTAN_REGISTER_TEST("math", "bn_lucas", Lucas_Primality_Test);
844

845
class RSA_Compute_Exp_Test : public Test {
×
846
   public:
847
      std::vector<Test::Result> run() override {
1✔
848
         const size_t iter = 4000;
1✔
849

850
         Test::Result result("RSA compute exponent");
1✔
851

852
         const auto e = Botan::BigInt::from_u64(65537);
1✔
853

854
         /*
855
         * Rather than create a fresh p/q for each iteration this test creates
856
         * a pool of primes then selects 2 at random as p/q
857
         */
858

859
         const auto random_primes = [&]() {
3✔
860
            std::vector<Botan::BigInt> rp;
1✔
861
            for(size_t i = 0; i != iter / 10; ++i) {
401✔
862
               size_t bits = (128 + (i % 1024)) % 4096;
400✔
863
               auto p = Botan::random_prime(rng(), bits);
400✔
864
               if(gcd(p - 1, e) == 1) {
800✔
865
                  rp.push_back(p);
400✔
866
               }
867
            }
400✔
868
            return rp;
1✔
869
         }();
1✔
870

871
         for(size_t i = 0; i != iter; ++i) {
4,001✔
872
            const size_t p_idx = random_index(rng(), random_primes.size());
4,000✔
873
            const size_t q_idx = random_index(rng(), random_primes.size());
4,000✔
874

875
            if(p_idx == q_idx) {
4,000✔
876
               continue;
18✔
877
            }
878

879
            const auto& p = random_primes[p_idx];
3,982✔
880
            const auto& q = random_primes[q_idx];
3,982✔
881

882
            auto phi_n = lcm(p - 1, q - 1);
3,982✔
883

884
            auto d = Botan::compute_rsa_secret_exponent(e, phi_n, p, q);
3,982✔
885

886
            auto one = (e * d) % phi_n;
3,982✔
887

888
            result.test_eq("compute_rsa_secret_exponent returned inverse", (e * d) % phi_n, Botan::BigInt::one());
7,964✔
889
         }
3,982✔
890

891
         return {result};
3✔
892
      }
2✔
893
};
894

895
BOTAN_REGISTER_TEST("math", "rsa_compute_d", RSA_Compute_Exp_Test);
896

897
class DSA_ParamGen_Test final : public Text_Based_Test {
×
898
   public:
899
      DSA_ParamGen_Test() : Text_Based_Test("bn/dsa_gen.vec", "P,Q,Counter,Seed") {}
2✔
900

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

905
         const Botan::BigInt exp_P = vars.get_req_bn("P");
20✔
906
         const Botan::BigInt exp_Q = vars.get_req_bn("Q");
20✔
907

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

910
         if(header_parts.size() != 2) {
20✔
911
            throw Test_Error("Unexpected header '" + header + "' in DSA param gen test");
×
912
         }
913

914
         const size_t p_bits = Botan::to_u32bit(header_parts[1]);
20✔
915
         const size_t q_bits = Botan::to_u32bit(header_parts[0]);
20✔
916

917
         Test::Result result("DSA Parameter Generation");
20✔
918

919
         try {
20✔
920
            Botan::BigInt gen_P;
20✔
921
            Botan::BigInt gen_Q;
20✔
922
            if(Botan::generate_dsa_primes(this->rng(), gen_P, gen_Q, p_bits, q_bits, seed, offset)) {
20✔
923
               result.test_eq("P", gen_P, exp_P);
20✔
924
               result.test_eq("Q", gen_Q, exp_Q);
40✔
925
            } else {
926
               result.test_failure("Seed did not generate a DSA parameter");
×
927
            }
928
         } catch(Botan::Lookup_Error&) {}
20✔
929

930
         return result;
40✔
931
      }
40✔
932
};
933

934
BOTAN_REGISTER_TEST("math", "dsa_param", DSA_ParamGen_Test);
935

936
std::vector<Test::Result> test_bigint_serialization() {
1✔
937
   auto rng = Test::new_rng("test_bigint_serialization");
1✔
938

939
   return {
1✔
940
      CHECK("BigInt binary serialization",
941
            [](Test::Result& res) {
1✔
942
               Botan::BigInt a(0x1234567890ABCDEF);
1✔
943
               auto enc = a.serialize();
1✔
944
               res.test_eq("BigInt::serialize", enc, Botan::hex_decode("1234567890ABCDEF"));
2✔
945

946
               auto enc10 = a.serialize(10);
1✔
947
               res.test_eq("BigInt::serialize", enc10, Botan::hex_decode("00001234567890ABCDEF"));
2✔
948

949
               res.test_throws("BigInt::serialize rejects short output", [&]() { a.serialize(7); });
4✔
950
            }),
2✔
951

952
      CHECK("BigInt truncated/padded binary serialization",
953
            [&](Test::Result& res) {
1✔
954
               Botan::BigInt a(0xFEDCBA9876543210);
1✔
955

956
               std::vector<uint8_t> enc1(a.bytes() - 1);
1✔
957
               a.binary_encode(enc1.data(), enc1.size());
1✔
958
               res.test_eq("BigInt::binary_encode", enc1, Botan::hex_decode("DCBA9876543210"));
2✔
959

960
               std::vector<uint8_t> enc2(a.bytes() - 3);
1✔
961
               a.binary_encode(enc2.data(), enc2.size());
1✔
962
               res.test_eq("BigInt::binary_encode", enc2, Botan::hex_decode("9876543210"));
2✔
963

964
               std::vector<uint8_t> enc3(a.bytes() + 1);
1✔
965
               a.binary_encode(enc3.data(), enc3.size());
1✔
966
               res.test_eq("BigInt::binary_encode", enc3, Botan::hex_decode("00FEDCBA9876543210"));
2✔
967

968
               // make sure that the padding is actually written
969
               std::vector<uint8_t> enc4(a.bytes() + 3);
1✔
970
               rng->randomize(enc4);
1✔
971
               a.binary_encode(enc4.data(), enc4.size());
1✔
972
               res.test_eq("BigInt::binary_encode", enc4, Botan::hex_decode("000000FEDCBA9876543210"));
2✔
973

974
               Botan::BigInt b(Botan::hex_decode("FEDCBA9876543210BAADC0FFEE"));
1✔
975

976
               std::vector<uint8_t> enc5(b.bytes() + 12);
1✔
977
               rng->randomize(enc5);
1✔
978
               b.binary_encode(enc5.data(), enc5.size());
1✔
979
               res.test_eq("BigInt::binary_encode",
2✔
980
                           enc5,
981
                           Botan::hex_decode("000000000000000000000000FEDCBA9876543210BAADC0FFEE"));
2✔
982
            }),
5✔
983
   };
3✔
984
}
2✔
985

986
BOTAN_REGISTER_TEST_FN("math", "bignum_auxiliary", test_const_time_left_shift, test_bigint_serialization);
987

988
#endif
989

990
}  // namespace
991

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

© 2026 Coveralls, Inc