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

randombit / botan / 15805862055

22 Jun 2025 10:58AM UTC coverage: 90.556% (-0.005%) from 90.561%
15805862055

Pull #4941

github

web-flow
Merge ec912e1c7 into cc35cab91
Pull Request #4941: Test: GCC's Stack Scrubbing on aarch64

98791 of 109094 relevant lines covered (90.56%)

12355948.55 hits per line

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

94.21
/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);
3✔
99

100
         p = Botan::random_prime(*rng, 3);
1✔
101
         result.confirm("Only two 3-bit primes", p == 5 || p == 7);
4✔
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 {
783✔
370
         Test::Result result("BigInt Divide");
783✔
371

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

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

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

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

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

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

398
         return result;
783✔
399
      }
783✔
400
};
401

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

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

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

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

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

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

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

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

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

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

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

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

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

452
         result.test_eq("a % b", a % b, expected);
158✔
453

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

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

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

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

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

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

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

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

486
         return result;
79✔
487
      }
79✔
488
};
489

490
BOTAN_REGISTER_TEST("math", "bn_mod", BigInt_Mod_Test);
491

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

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

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

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

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

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

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

535
         return {result};
3✔
536
      }
2✔
537
};
538

539
BOTAN_REGISTER_TEST("math", "barrett_redc", Barrett_Redc_Test);
540

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

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

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

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

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

558
         return result;
182✔
559
      }
182✔
560
};
561

562
BOTAN_REGISTER_TEST("math", "bn_gcd", BigInt_GCD_Test);
563

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

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

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

575
         const int32_t j = Botan::jacobi(a, n);
698✔
576

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

585
         return result;
1,396✔
586
      }
698✔
587
};
588

589
BOTAN_REGISTER_TEST("math", "bn_jacobi", BigInt_Jacobi_Test);
590

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

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

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

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

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

608
         return result;
50✔
609
      }
50✔
610
};
611

612
BOTAN_REGISTER_TEST("math", "bn_lshift", BigInt_Lshift_Test);
613

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

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

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

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

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

631
         return result;
53✔
632
      }
53✔
633
};
634

635
BOTAN_REGISTER_TEST("math", "bn_rshift", BigInt_Rshift_Test);
636

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

641
   auto rng = Test::new_rng("const_time_left_shift");
1✔
642

643
   result.start_timer();
1✔
644

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

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

662
   result.end_timer();
1✔
663

664
   return result;
2✔
665
}
2✔
666

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

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

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

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

684
BOTAN_REGISTER_TEST("math", "bn_powmod", BigInt_Powmod_Test);
685

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

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

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

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

701
         return result;
132✔
702
      }
132✔
703
};
704

705
BOTAN_REGISTER_TEST("math", "bn_isprime", BigInt_IsPrime_Test);
706

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

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

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

722
BOTAN_REGISTER_TEST("math", "bn_issquare", BigInt_IsSquare_Test);
723

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

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

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

735
         const Botan::BigInt a_sqrt = Botan::sqrt_modulo_prime(a, p);
17✔
736

737
         result.test_eq("sqrt_modulo_prime", a_sqrt, exp);
17✔
738

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

744
         return result;
17✔
745
      }
17✔
746
};
747

748
BOTAN_REGISTER_TEST("math", "bn_sqrt_modulo_prime", BigInt_Sqrt_Modulo_Prime_Test);
749

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

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

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

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

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

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

779
         return result;
138✔
780
      }
138✔
781
};
782

783
BOTAN_REGISTER_TEST("math", "bn_invmod", BigInt_InvMod_Test);
784

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

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

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

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

800
         result.test_eq("random_integer KAT", generated, expected);
4✔
801

802
         return result;
8✔
803
      }
8✔
804
};
805

806
BOTAN_REGISTER_TEST("math", "bn_rand", BigInt_Rand_Test);
807

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

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

821
         Test::Result result("Lucas primality test");
1✔
822

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

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

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

837
         return {result};
2✔
838
      }
2✔
839
};
840

841
BOTAN_REGISTER_TEST("math", "bn_lucas", Lucas_Primality_Test);
842

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

848
         Test::Result result("RSA compute exponent");
1✔
849

850
         const auto e = Botan::BigInt::from_u64(65537);
1✔
851

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

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

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

873
            if(p_idx == q_idx) {
4,000✔
874
               continue;
9✔
875
            }
876

877
            const auto& p = random_primes[p_idx];
3,991✔
878
            const auto& q = random_primes[q_idx];
3,991✔
879

880
            auto phi_n = lcm(p - 1, q - 1);
3,991✔
881

882
            auto d = Botan::compute_rsa_secret_exponent(e, phi_n, p, q);
3,991✔
883

884
            auto one = (e * d) % phi_n;
3,991✔
885

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

889
         return {result};
3✔
890
      }
2✔
891
};
892

893
BOTAN_REGISTER_TEST("math", "rsa_compute_d", RSA_Compute_Exp_Test);
894

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

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

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

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

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

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

915
         Test::Result result("DSA Parameter Generation");
20✔
916

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

927
         return result;
40✔
928
      }
40✔
929
};
930

931
BOTAN_REGISTER_TEST("math", "dsa_param", DSA_ParamGen_Test);
932

933
std::vector<Test::Result> test_bigint_serialization() {
1✔
934
   auto rng = Test::new_rng("test_bigint_serialization");
1✔
935

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

943
               auto enc10 = a.serialize(10);
1✔
944
               res.test_eq("BigInt::serialize", enc10, Botan::hex_decode("00001234567890ABCDEF"));
2✔
945

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

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

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

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

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

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

971
               Botan::BigInt b(Botan::hex_decode("FEDCBA9876543210BAADC0FFEE"));
1✔
972

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

983
BOTAN_REGISTER_TEST_FN("math", "bignum_auxiliary", test_const_time_left_shift, test_bigint_serialization);
984

985
#endif
986

987
}  // namespace
988

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