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

randombit / botan / 14120723934

28 Mar 2025 02:31AM UTC coverage: 91.539% (+0.004%) from 91.535%
14120723934

Pull #4798

github

web-flow
Merge db2c0eef1 into 70cd16046
Pull Request #4798: Move most architecture-specific logic out of CPUID and into a submodule

95384 of 104200 relevant lines covered (91.54%)

11667903.22 hits per line

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

94.19
/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/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);
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 {
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
         auto mod_b_pub = Botan::Modular_Reducer::for_public_modulus(b);
79✔
459
         result.test_eq("Barrett public", mod_b_pub.reduce(a), expected);
158✔
460

461
         auto mod_b_sec = Botan::Modular_Reducer::for_secret_modulus(b);
79✔
462
         result.test_eq("Barrett secret", mod_b_sec.reduce(a), expected);
158✔
463

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

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

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

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

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

484
         return result;
79✔
485
      }
237✔
486
};
487

488
BOTAN_REGISTER_TEST("math", "bn_mod", BigInt_Mod_Test);
489

490
class BigInt_GCD_Test final : public Text_Based_Test {
×
491
   public:
492
      BigInt_GCD_Test() : Text_Based_Test("bn/gcd.vec", "X,Y,GCD") {}
2✔
493

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

497
         const BigInt x = vars.get_req_bn("X");
182✔
498
         const BigInt y = vars.get_req_bn("Y");
182✔
499
         const BigInt expected = vars.get_req_bn("GCD");
182✔
500

501
         const BigInt g1 = Botan::gcd(x, y);
182✔
502
         result.test_eq("gcd", g1, expected);
182✔
503

504
         const BigInt g2 = Botan::gcd(y, x);
182✔
505
         result.test_eq("gcd", g2, expected);
182✔
506

507
         return result;
182✔
508
      }
182✔
509
};
510

511
BOTAN_REGISTER_TEST("math", "bn_gcd", BigInt_GCD_Test);
512

513
class BigInt_Jacobi_Test final : public Text_Based_Test {
×
514
   public:
515
      BigInt_Jacobi_Test() : Text_Based_Test("bn/jacobi.vec", "A,N,J") {}
2✔
516

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

520
         const BigInt a = vars.get_req_bn("A");
698✔
521
         const BigInt n = vars.get_req_bn("N");
698✔
522
         const std::string expected = vars.get_req_str("J");
698✔
523

524
         const int32_t j = Botan::jacobi(a, n);
698✔
525

526
         if(j == 0) {
698✔
527
            result.test_eq("jacobi", expected, "0");
314✔
528
         } else if(j == -1) {
541✔
529
            result.test_eq("jacobi", expected, "-1");
614✔
530
         } else {
531
            result.test_eq("jacobi", expected, "1");
468✔
532
         }
533

534
         return result;
1,396✔
535
      }
698✔
536
};
537

538
BOTAN_REGISTER_TEST("math", "bn_jacobi", BigInt_Jacobi_Test);
539

540
class BigInt_Lshift_Test final : public Text_Based_Test {
×
541
   public:
542
      BigInt_Lshift_Test() : Text_Based_Test("bn/lshift.vec", "Value,Shift,Output") {}
2✔
543

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

547
         const BigInt value = vars.get_req_bn("Value");
50✔
548
         const size_t shift = vars.get_req_bn("Shift").to_u32bit();
50✔
549
         const BigInt output = vars.get_req_bn("Output");
50✔
550

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

553
         BigInt e = value;
50✔
554
         e <<= shift;
50✔
555
         result.test_eq("a <<= s", e, output);
50✔
556

557
         return result;
50✔
558
      }
50✔
559
};
560

561
BOTAN_REGISTER_TEST("math", "bn_lshift", BigInt_Lshift_Test);
562

563
class BigInt_Rshift_Test final : public Text_Based_Test {
×
564
   public:
565
      BigInt_Rshift_Test() : Text_Based_Test("bn/rshift.vec", "Value,Shift,Output") {}
2✔
566

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

570
         const BigInt value = vars.get_req_bn("Value");
53✔
571
         const size_t shift = vars.get_req_bn("Shift").to_u32bit();
53✔
572
         const BigInt output = vars.get_req_bn("Output");
53✔
573

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

576
         BigInt e = value;
53✔
577
         e >>= shift;
53✔
578
         result.test_eq("a >>= s", e, output);
53✔
579

580
         return result;
53✔
581
      }
53✔
582
};
583

584
BOTAN_REGISTER_TEST("math", "bn_rshift", BigInt_Rshift_Test);
585

586
Test::Result test_const_time_left_shift() {
1✔
587
   Test::Result result("BigInt const time shift");
1✔
588
   const size_t bits = Test::run_long_tests() ? 4096 : 2048;
1✔
589

590
   auto rng = Test::new_rng("const_time_left_shift");
1✔
591

592
   result.start_timer();
1✔
593

594
   Botan::BigInt a = Botan::BigInt::with_capacity(bits / sizeof(Botan::word));
1✔
595
   for(size_t i = 0; i < bits; ++i) {
4,097✔
596
      if(rng->next_byte() & 1) {
4,096✔
597
         a.set_bit(i);
4,096✔
598
      }
599
   }
600

601
   for(size_t i = 0; i < bits; ++i) {
4,097✔
602
      auto ct = a;
4,096✔
603
      auto chk = a;
4,096✔
604
      Botan::CT::poison(ct);
4,096✔
605
      ct.ct_shift_left(i);
4,096✔
606
      Botan::CT::unpoison(ct);
4,096✔
607
      chk <<= i;
4,096✔
608
      result.test_eq(Botan::fmt("ct << {}", i), ct, chk);
4,096✔
609
   }
4,096✔
610

611
   result.end_timer();
1✔
612

613
   return result;
2✔
614
}
2✔
615

616
class BigInt_Powmod_Test final : public Text_Based_Test {
×
617
   public:
618
      BigInt_Powmod_Test() : Text_Based_Test("bn/powmod.vec", "Base,Exponent,Modulus,Output") {}
2✔
619

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

623
         const BigInt base = vars.get_req_bn("Base");
47✔
624
         const BigInt exponent = vars.get_req_bn("Exponent");
47✔
625
         const BigInt modulus = vars.get_req_bn("Modulus");
47✔
626
         const BigInt expected = vars.get_req_bn("Output");
47✔
627

628
         result.test_eq("power_mod", Botan::power_mod(base, exponent, modulus), expected);
94✔
629
         return result;
47✔
630
      }
47✔
631
};
632

633
BOTAN_REGISTER_TEST("math", "bn_powmod", BigInt_Powmod_Test);
634

635
class BigInt_IsPrime_Test final : public Text_Based_Test {
×
636
   public:
637
      BigInt_IsPrime_Test() : Text_Based_Test("bn/isprime.vec", "X") {}
2✔
638

639
      Test::Result run_one_test(const std::string& header, const VarMap& vars) override {
132✔
640
         if(header != "Prime" && header != "NonPrime") {
132✔
641
            throw Test_Error("Bad header for prime test " + header);
×
642
         }
643

644
         const BigInt value = vars.get_req_bn("X");
132✔
645
         const bool is_prime = (header == "Prime");
132✔
646

647
         Test::Result result("BigInt Test " + header);
132✔
648
         result.test_eq("is_prime", Botan::is_prime(value, this->rng()), is_prime);
132✔
649

650
         return result;
132✔
651
      }
132✔
652
};
653

654
BOTAN_REGISTER_TEST("math", "bn_isprime", BigInt_IsPrime_Test);
655

656
class BigInt_IsSquare_Test final : public Text_Based_Test {
×
657
   public:
658
      BigInt_IsSquare_Test() : Text_Based_Test("bn/perfect_square.vec", "X,R") {}
2✔
659

660
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
7✔
661
         const BigInt value = vars.get_req_bn("X");
7✔
662
         const BigInt expected = vars.get_req_bn("R");
7✔
663
         const BigInt computed = Botan::is_perfect_square(value);
7✔
664

665
         Test::Result result("BigInt IsSquare");
7✔
666
         result.test_eq("is_perfect_square", computed, expected);
7✔
667
         return result;
7✔
668
      }
7✔
669
};
670

671
BOTAN_REGISTER_TEST("math", "bn_issquare", BigInt_IsSquare_Test);
672

673
class BigInt_Sqrt_Modulo_Prime_Test final : public Text_Based_Test {
×
674
   public:
675
      BigInt_Sqrt_Modulo_Prime_Test() : Text_Based_Test("bn/sqrt_modulo_prime.vec", "Input,Modulus,Output") {}
2✔
676

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

680
         const Botan::BigInt a = vars.get_req_bn("Input");
17✔
681
         const Botan::BigInt p = vars.get_req_bn("Modulus");
17✔
682
         const Botan::BigInt exp = vars.get_req_bn("Output");
17✔
683

684
         const Botan::BigInt a_sqrt = Botan::sqrt_modulo_prime(a, p);
17✔
685

686
         result.test_eq("sqrt_modulo_prime", a_sqrt, exp);
17✔
687

688
         if(a_sqrt > 1) {
17✔
689
            const Botan::BigInt a_sqrt2 = (a_sqrt * a_sqrt) % p;
8✔
690
            result.test_eq("square correct", a_sqrt2, a);
8✔
691
         }
8✔
692

693
         return result;
17✔
694
      }
17✔
695
};
696

697
BOTAN_REGISTER_TEST("math", "bn_sqrt_modulo_prime", BigInt_Sqrt_Modulo_Prime_Test);
698

699
class BigInt_InvMod_Test final : public Text_Based_Test {
×
700
   public:
701
      BigInt_InvMod_Test() : Text_Based_Test("bn/invmod.vec", "Input,Modulus,Output") {}
2✔
702

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

706
         const Botan::BigInt a = vars.get_req_bn("Input");
138✔
707
         const Botan::BigInt mod = vars.get_req_bn("Modulus");
138✔
708
         const Botan::BigInt expected = vars.get_req_bn("Output");
138✔
709

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

712
         if(a < mod && a > 0 && a < mod) {
398✔
713
            auto g = Botan::inverse_mod_general(a, mod);
128✔
714
            if(g.has_value()) {
128✔
715
               result.test_eq("inverse_mod_general", g.value(), expected);
87✔
716
               result.test_eq("inverse works", ((g.value() * a) % mod), BigInt::one());
261✔
717
            } else {
718
               result.confirm("inverse_mod_general", expected.is_zero());
82✔
719
            }
720

721
            if(Botan::is_prime(mod, rng()) && mod != 2) {
136✔
722
               BOTAN_ASSERT_NOMSG(expected > 0);
7✔
723
               result.test_eq("inverse_mod_secret_prime", Botan::inverse_mod_secret_prime(a, mod), expected);
14✔
724
               result.test_eq("inverse_mod_public_prime", Botan::inverse_mod_public_prime(a, mod), expected);
14✔
725
            }
726
         }
128✔
727

728
         return result;
138✔
729
      }
138✔
730
};
731

732
BOTAN_REGISTER_TEST("math", "bn_invmod", BigInt_InvMod_Test);
733

734
class BigInt_Rand_Test final : public Text_Based_Test {
×
735
   public:
736
      BigInt_Rand_Test() : Text_Based_Test("bn/random.vec", "Seed,Min,Max,Output") {}
2✔
737

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

741
         const std::vector<uint8_t> seed = vars.get_req_bin("Seed");
4✔
742
         const Botan::BigInt min = vars.get_req_bn("Min");
4✔
743
         const Botan::BigInt max = vars.get_req_bn("Max");
4✔
744
         const Botan::BigInt expected = vars.get_req_bn("Output");
4✔
745

746
         Fixed_Output_RNG rng(seed);
4✔
747
         Botan::BigInt generated = BigInt::random_integer(rng, min, max);
4✔
748

749
         result.test_eq("random_integer KAT", generated, expected);
4✔
750

751
         return result;
8✔
752
      }
8✔
753
};
754

755
BOTAN_REGISTER_TEST("math", "bn_rand", BigInt_Rand_Test);
756

757
class Lucas_Primality_Test final : public Test {
×
758
   public:
759
      std::vector<Test::Result> run() override {
1✔
760
         const uint32_t lucas_max = (Test::run_long_tests() ? 100000 : 6000);
1✔
761

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

770
         Test::Result result("Lucas primality test");
1✔
771

772
         for(uint32_t i = 3; i <= lucas_max; i += 2) {
50,000✔
773
            auto mod_i = Botan::Modular_Reducer::for_public_modulus(i);
49,999✔
774
            const bool passes_lucas = Botan::is_lucas_probable_prime(i, mod_i);
49,999✔
775
            const bool is_prime = Botan::is_prime(i, this->rng());
49,999✔
776

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

779
            if(is_lucas_pp) {
49,999✔
780
               result.confirm("Lucas pseudoprime is in list", lucas_pp.count(i) == 1);
171✔
781
            } else {
782
               result.confirm("Lucas non-pseudoprime is not in list", !lucas_pp.contains(i));
149,826✔
783
            }
784
         }
49,999✔
785

786
         return {result};
2✔
787
      }
2✔
788
};
789

790
BOTAN_REGISTER_TEST("math", "bn_lucas", Lucas_Primality_Test);
791

792
class RSA_Compute_Exp_Test : public Test {
×
793
   public:
794
      std::vector<Test::Result> run() override {
1✔
795
         const size_t iter = 4000;
1✔
796

797
         Test::Result result("RSA compute exponent");
1✔
798

799
         const auto e = Botan::BigInt::from_u64(65537);
1✔
800

801
         /*
802
         * Rather than create a fresh p/q for each iteration this test creates
803
         * a pool of primes then selects 2 at random as p/q
804
         */
805

806
         const auto random_primes = [&]() {
3✔
807
            std::vector<Botan::BigInt> rp;
1✔
808
            for(size_t i = 0; i != iter / 10; ++i) {
401✔
809
               size_t bits = (128 + (i % 1024)) % 4096;
400✔
810
               auto p = Botan::random_prime(rng(), bits);
400✔
811
               if(gcd(p - 1, e) == 1) {
800✔
812
                  rp.push_back(p);
400✔
813
               }
814
            }
400✔
815
            return rp;
1✔
816
         }();
1✔
817

818
         for(size_t i = 0; i != iter; ++i) {
4,001✔
819
            const size_t p_idx = random_index(rng(), random_primes.size());
4,000✔
820
            const size_t q_idx = random_index(rng(), random_primes.size());
4,000✔
821

822
            if(p_idx == q_idx) {
4,000✔
823
               continue;
8✔
824
            }
825

826
            const auto& p = random_primes[p_idx];
3,992✔
827
            const auto& q = random_primes[q_idx];
3,992✔
828

829
            auto phi_n = lcm(p - 1, q - 1);
3,992✔
830

831
            auto d = Botan::compute_rsa_secret_exponent(e, phi_n, p, q);
3,992✔
832

833
            auto one = (e * d) % phi_n;
3,992✔
834

835
            result.test_eq("compute_rsa_secret_exponent returned inverse", (e * d) % phi_n, Botan::BigInt::one());
7,984✔
836
         }
3,992✔
837

838
         return {result};
3✔
839
      }
2✔
840
};
841

842
BOTAN_REGISTER_TEST("math", "rsa_compute_d", RSA_Compute_Exp_Test);
843

844
class DSA_ParamGen_Test final : public Text_Based_Test {
×
845
   public:
846
      DSA_ParamGen_Test() : Text_Based_Test("bn/dsa_gen.vec", "P,Q,Counter,Seed") {}
2✔
847

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

852
         const Botan::BigInt exp_P = vars.get_req_bn("P");
20✔
853
         const Botan::BigInt exp_Q = vars.get_req_bn("Q");
20✔
854

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

857
         if(header_parts.size() != 2) {
20✔
858
            throw Test_Error("Unexpected header '" + header + "' in DSA param gen test");
×
859
         }
860

861
         const size_t p_bits = Botan::to_u32bit(header_parts[1]);
20✔
862
         const size_t q_bits = Botan::to_u32bit(header_parts[0]);
20✔
863

864
         Test::Result result("DSA Parameter Generation");
20✔
865

866
         try {
20✔
867
            Botan::BigInt gen_P, gen_Q;
20✔
868
            if(Botan::generate_dsa_primes(this->rng(), gen_P, gen_Q, p_bits, q_bits, seed, offset)) {
20✔
869
               result.test_eq("P", gen_P, exp_P);
20✔
870
               result.test_eq("Q", gen_Q, exp_Q);
40✔
871
            } else {
872
               result.test_failure("Seed did not generate a DSA parameter");
×
873
            }
874
         } catch(Botan::Lookup_Error&) {}
20✔
875

876
         return result;
40✔
877
      }
40✔
878
};
879

880
BOTAN_REGISTER_TEST("math", "dsa_param", DSA_ParamGen_Test);
881

882
std::vector<Test::Result> test_bigint_serialization() {
1✔
883
   auto rng = Test::new_rng("test_bigint_serialization");
1✔
884

885
   return {
1✔
886
      CHECK("BigInt binary serialization",
887
            [](Test::Result& res) {
1✔
888
               Botan::BigInt a(0x1234567890ABCDEF);
1✔
889
               auto enc = a.serialize();
1✔
890
               res.test_eq("BigInt::serialize", enc, Botan::hex_decode("1234567890ABCDEF"));
2✔
891

892
               auto enc10 = a.serialize(10);
1✔
893
               res.test_eq("BigInt::serialize", enc10, Botan::hex_decode("00001234567890ABCDEF"));
2✔
894

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

898
      CHECK("BigInt truncated/padded binary serialization",
899
            [&](Test::Result& res) {
1✔
900
               Botan::BigInt a(0xFEDCBA9876543210);
1✔
901

902
               std::vector<uint8_t> enc1(a.bytes() - 1);
1✔
903
               a.binary_encode(enc1.data(), enc1.size());
1✔
904
               res.test_eq("BigInt::binary_encode", enc1, Botan::hex_decode("DCBA9876543210"));
2✔
905

906
               std::vector<uint8_t> enc2(a.bytes() - 3);
1✔
907
               a.binary_encode(enc2.data(), enc2.size());
1✔
908
               res.test_eq("BigInt::binary_encode", enc2, Botan::hex_decode("9876543210"));
2✔
909

910
               std::vector<uint8_t> enc3(a.bytes() + 1);
1✔
911
               a.binary_encode(enc3.data(), enc3.size());
1✔
912
               res.test_eq("BigInt::binary_encode", enc3, Botan::hex_decode("00FEDCBA9876543210"));
2✔
913

914
               // make sure that the padding is actually written
915
               std::vector<uint8_t> enc4(a.bytes() + 3);
1✔
916
               rng->randomize(enc4);
1✔
917
               a.binary_encode(enc4.data(), enc4.size());
1✔
918
               res.test_eq("BigInt::binary_encode", enc4, Botan::hex_decode("000000FEDCBA9876543210"));
2✔
919

920
               Botan::BigInt b(Botan::hex_decode("FEDCBA9876543210BAADC0FFEE"));
1✔
921

922
               std::vector<uint8_t> enc5(b.bytes() + 12);
1✔
923
               rng->randomize(enc5);
1✔
924
               b.binary_encode(enc5.data(), enc5.size());
1✔
925
               res.test_eq("BigInt::binary_encode",
2✔
926
                           enc5,
927
                           Botan::hex_decode("000000000000000000000000FEDCBA9876543210BAADC0FFEE"));
2✔
928
            }),
5✔
929
   };
3✔
930
}
2✔
931

932
BOTAN_REGISTER_TEST_FN("math", "bignum_auxiliary", test_const_time_left_shift, test_bigint_serialization);
933

934
#endif
935

936
}  // namespace
937

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