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

randombit / botan / 11844561993

14 Nov 2024 07:58PM UTC coverage: 91.178% (+0.1%) from 91.072%
11844561993

Pull #4435

github

web-flow
Merge 81dcb29da into e430f157a
Pull Request #4435: Test duration values ​​are now presented in seconds with six digits of precision. Tests without time measurements have been edited.

91856 of 100744 relevant lines covered (91.18%)

9311006.71 hits per line

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

94.63
/src/tests/test_bigint.cpp
1
/*
2
* (C) 2009,2015,2016 Jack Lloyd
3
* (C) 2024           Fabian Albert, René Meusel -  Rohde & Schwarz Cybersecurity
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include "tests.h"
9

10
#if defined(BOTAN_HAS_NUMBERTHEORY)
11
   #include "test_rng.h"
12
   #include <botan/bigint.h>
13
   #include <botan/numthry.h>
14
   #include <botan/reducer.h>
15
   #include <botan/internal/ct_utils.h>
16
   #include <botan/internal/divide.h>
17
   #include <botan/internal/fmt.h>
18
   #include <botan/internal/mp_core.h>
19
   #include <botan/internal/parsing.h>
20
   #include <botan/internal/primality.h>
21
   #include <botan/internal/stl_util.h>
22
#endif
23

24
namespace Botan_Tests {
25

26
namespace {
27

28
#if defined(BOTAN_HAS_NUMBERTHEORY)
29

30
using Botan::BigInt;
31

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

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

43
         return results;
1✔
44
      }
×
45

46
   private:
47
      static Test::Result test_bigint_sizes() {
1✔
48
         Test::Result result("BigInt size functions");
1✔
49
         result.start_timer();
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--;
48✔
78
            }
79
         }
12✔
80

81
         result.end_timer();
1✔
82
         return result;
1✔
83
      }
×
84

85
      static Test::Result test_random_prime() {
1✔
86
         Test::Result result("BigInt prime generation");
1✔
87
         result.start_timer();
1✔
88

89
         auto rng = Test::new_rng("random_prime");
1✔
90

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

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

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

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

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

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

120
         result.end_timer();
1✔
121
         return result;
1✔
122
      }
3✔
123

124
      static Test::Result test_encode() {
1✔
125
         Test::Result result("BigInt encoding functions");
1✔
126
         result.start_timer();
1✔
127

128
         const auto n1 = Botan::BigInt::from_u64(0xffff);
1✔
129
         const auto n2 = Botan::BigInt::from_u64(1023);
1✔
130

131
         const auto encoded_n1 = n1.serialize(256);
1✔
132
         const auto encoded_n2 = n2.serialize(256);
1✔
133
         const auto expected = Botan::concat(encoded_n1, encoded_n2);
1✔
134

135
         const auto encoded_n1_n2 = BigInt::encode_fixed_length_int_pair(n1, n2, 256);
1✔
136
         result.test_eq("encode_fixed_length_int_pair", encoded_n1_n2, expected);
1✔
137

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

144
         result.end_timer();
1✔
145
         return result;
1✔
146
      }
6✔
147

148
      static Test::Result test_get_substring() {
1✔
149
         Test::Result result("BigInt get_substring");
1✔
150
         result.start_timer();
1✔
151

152
         const size_t rbits = 1024;
1✔
153

154
         auto rng = Test::new_rng("get_substring");
1✔
155

156
         const Botan::BigInt r(*rng, rbits);
1✔
157

158
         for(size_t wlen = 1; wlen <= 32; ++wlen) {
33✔
159
            for(size_t offset = 0; offset != rbits + 64; ++offset) {
34,848✔
160
               const uint32_t val = r.get_substring(offset, wlen);
34,816✔
161

162
               Botan::BigInt t = r >> offset;
34,816✔
163
               t.mask_bits(wlen);
34,816✔
164

165
               const uint32_t cmp = t.to_u32bit();
34,816✔
166

167
               result.test_eq("Same value", size_t(val), size_t(cmp));
69,632✔
168
            }
34,816✔
169
         }
170

171
         result.end_timer();
1✔
172
         return result;
1✔
173
      }
2✔
174

175
      static Test::Result test_bigint_io() {
1✔
176
         Test::Result result("BigInt IO operators");
1✔
177
         result.start_timer();
1✔
178

179
         const std::map<std::string, Botan::BigInt> str_to_val = {{"-13", -Botan::BigInt(13)},
2✔
180
                                                                  {"0", Botan::BigInt(0)},
2✔
181
                                                                  {"0x13", Botan::BigInt(0x13)},
2✔
182
                                                                  {"1", Botan::BigInt(1)},
2✔
183
                                                                  {"4294967297", Botan::BigInt(2147483648) * 2 + 1}};
10✔
184

185
         for(const auto& vec : str_to_val) {
6✔
186
            Botan::BigInt n;
5✔
187
            std::istringstream iss;
5✔
188

189
            iss.str(vec.first);
5✔
190
            iss >> n;
5✔
191
            result.test_eq("input '" + vec.first + "'", n, vec.second);
15✔
192
         }
10✔
193

194
         auto check_bigint_formatting = [&](const Botan::BigInt& n,
6✔
195
                                            const std::string& dec,
196
                                            const std::string& hex,
197
                                            const std::string& neg_dec,
198
                                            const std::string& neg_hex) {
199
            std::ostringstream oss;
5✔
200
            oss << n;
5✔
201
            result.test_eq("output decimal", oss.str(), dec);
10✔
202

203
            oss.str("");
10✔
204
            oss << (-n);
5✔
205
            result.test_eq("output negative decimal", oss.str(), neg_dec);
10✔
206

207
            oss.str("");
10✔
208
            oss << std::hex << n;
5✔
209
            result.test_eq("output hex", oss.str(), hex);
10✔
210

211
            oss.str("");
10✔
212
            oss << std::hex << (-n);
5✔
213
            result.test_eq("output negative hex", oss.str(), neg_hex);
10✔
214
         };
5✔
215

216
         check_bigint_formatting(Botan::BigInt(33), "33", "0x21", "-33", "-0x21");
2✔
217
         check_bigint_formatting(Botan::BigInt::from_s32(-33), "-33", "-0x21", "33", "0x21");
2✔
218
         check_bigint_formatting(Botan::BigInt(255), "255", "0xFF", "-255", "-0xFF");
2✔
219
         check_bigint_formatting(Botan::BigInt(0), "0", "0x00", "0", "0x00");
2✔
220
         check_bigint_formatting(Botan::BigInt(5), "5", "0x05", "-5", "-0x05");
2✔
221

222
         result.test_throws("octal output not supported", [&]() {
2✔
223
            Botan::BigInt n(5);
1✔
224
            std::ostringstream oss;
1✔
225
            oss << std::oct << n;
1✔
226
         });
1✔
227

228
         result.end_timer();
1✔
229
         return result;
1✔
230
      }
6✔
231
};
232

233
BOTAN_REGISTER_TEST("math", "bigint_unit", BigInt_Unit_Tests);
234

235
class BigInt_Cmp_Test final : public Text_Based_Test {
×
236
   public:
237
      BigInt_Cmp_Test() : Text_Based_Test("bn/cmp.vec", "X,Y,R") {}
2✔
238

239
      Test::Result run_one_test(const std::string& op, const VarMap& vars) override {
19✔
240
         Test::Result result("BigInt Comparison " + op);
19✔
241
         result.start_timer();
19✔
242

243
         const BigInt x = vars.get_req_bn("X");
19✔
244
         const BigInt y = vars.get_req_bn("Y");
19✔
245
         const bool expected = vars.get_req_bool("R");
19✔
246

247
         if(op == "EQ") {
19✔
248
            result.confirm("Values equal", x == y, expected);
12✔
249
         } else if(op == "LT") {
13✔
250
            result.confirm("Values LT", x < y, expected);
12✔
251

252
            if(expected) {
6✔
253
               result.confirm("If LT then reverse is GT", y >= x);
4✔
254
            } else {
255
               result.confirm("If not LT then GTE", x >= y);
8✔
256
            }
257
         } else if(op == "LTE") {
7✔
258
            result.confirm("Values LTE", x <= y, expected);
14✔
259

260
            if(expected) {
7✔
261
               result.confirm("If LTE then either LT or EQ", x < y || x == y);
13✔
262
            } else {
263
               result.confirm("If not LTE then GT", x > y);
6✔
264
            }
265
         } else {
266
            throw Test_Error("Unknown BigInt comparison type " + op);
×
267
         }
268

269
         result.end_timer();
19✔
270
         return result;
19✔
271
      }
38✔
272
};
273

274
BOTAN_REGISTER_TEST("math", "bn_cmp", BigInt_Cmp_Test);
275

276
class BigInt_Add_Test final : public Text_Based_Test {
×
277
   public:
278
      BigInt_Add_Test() : Text_Based_Test("bn/add.vec", "In1,In2,Output") {}
2✔
279

280
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
78✔
281
         Test::Result result("BigInt Addition");
78✔
282
         result.start_timer();
78✔
283

284
         using Botan::BigInt;
78✔
285

286
         const BigInt a = vars.get_req_bn("In1");
78✔
287
         const BigInt b = vars.get_req_bn("In2");
78✔
288
         const BigInt c = vars.get_req_bn("Output");
78✔
289

290
         result.test_eq("a + b", a + b, c);
156✔
291
         result.test_eq("b + a", b + a, c);
156✔
292

293
         BigInt e = a;
78✔
294
         e += b;
78✔
295
         result.test_eq("a += b", e, c);
78✔
296

297
         e = b;
78✔
298
         e += a;
78✔
299
         result.test_eq("b += a", e, c);
78✔
300

301
         result.end_timer();
78✔
302
         return result;
78✔
303
      }
312✔
304
};
305

306
BOTAN_REGISTER_TEST("math", "bn_add", BigInt_Add_Test);
307

308
class BigInt_Sub_Test final : public Text_Based_Test {
×
309
   public:
310
      BigInt_Sub_Test() : Text_Based_Test("bn/sub.vec", "In1,In2,Output") {}
2✔
311

312
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
77✔
313
         Test::Result result("BigInt Subtraction");
77✔
314
         result.start_timer();
77✔
315

316
         const BigInt a = vars.get_req_bn("In1");
77✔
317
         const BigInt b = vars.get_req_bn("In2");
77✔
318
         const BigInt c = vars.get_req_bn("Output");
77✔
319

320
         result.test_eq("a - b", a - b, c);
154✔
321

322
         BigInt e = a;
77✔
323
         e -= b;
77✔
324
         result.test_eq("a -= b", e, c);
77✔
325

326
         result.end_timer();
77✔
327
         return result;
77✔
328
      }
308✔
329
};
330

331
BOTAN_REGISTER_TEST("math", "bn_sub", BigInt_Sub_Test);
332

333
class BigInt_Mul_Test final : public Text_Based_Test {
×
334
   public:
335
      BigInt_Mul_Test() : Text_Based_Test("bn/mul.vec", "In1,In2,Output") {}
2✔
336

337
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
104✔
338
         Test::Result result("BigInt Multiply");
104✔
339
         result.start_timer();
104✔
340

341
         const BigInt a = vars.get_req_bn("In1");
104✔
342
         const BigInt b = vars.get_req_bn("In2");
104✔
343
         const BigInt c = vars.get_req_bn("Output");
104✔
344

345
         result.test_eq("a * b", a * b, c);
208✔
346
         result.test_eq("b * a", b * a, c);
208✔
347

348
         BigInt e = a;
104✔
349
         e *= b;
104✔
350
         result.test_eq("a *= b", e, c);
104✔
351

352
         e = b;
104✔
353
         e *= a;
104✔
354
         result.test_eq("b *= a", e, c);
104✔
355

356
         result.end_timer();
104✔
357
         return result;
104✔
358
      }
416✔
359
};
360

361
BOTAN_REGISTER_TEST("math", "bn_mul", BigInt_Mul_Test);
362

363
class BigInt_Sqr_Test final : public Text_Based_Test {
×
364
   public:
365
      BigInt_Sqr_Test() : Text_Based_Test("bn/sqr.vec", "Input,Output") {}
2✔
366

367
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
21✔
368
         Test::Result result("BigInt Square");
21✔
369
         result.start_timer();
21✔
370

371
         const BigInt input = vars.get_req_bn("Input");
21✔
372
         const BigInt output = vars.get_req_bn("Output");
21✔
373

374
         result.test_eq("a * a", input * input, output);
42✔
375
         result.test_eq("sqr(a)", square(input), output);
42✔
376

377
         result.end_timer();
21✔
378
         return result;
21✔
379
      }
42✔
380
};
381

382
BOTAN_REGISTER_TEST("math", "bn_sqr", BigInt_Sqr_Test);
383

384
class BigInt_Div_Test final : public Text_Based_Test {
×
385
   public:
386
      BigInt_Div_Test() : Text_Based_Test("bn/divide.vec", "In1,In2,Output") {}
2✔
387

388
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
783✔
389
         Test::Result result("BigInt Divide");
783✔
390
         result.start_timer();
783✔
391

392
         const BigInt a = vars.get_req_bn("In1");
783✔
393
         const BigInt b = vars.get_req_bn("In2");
783✔
394
         const BigInt c = vars.get_req_bn("Output");
783✔
395

396
         result.test_eq("a / b", a / b, c);
1,566✔
397

398
         BigInt e = a;
783✔
399
         e /= b;
783✔
400
         result.test_eq("a /= b", e, c);
783✔
401

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

406
            Botan::BigInt ct_q;
404✔
407
            Botan::word ct_r;
404✔
408
            Botan::ct_divide_word(a, bw, ct_q, ct_r);
404✔
409
            result.test_eq("ct_divide_word q", ct_q, c);
404✔
410
            result.test_eq("ct_divide_word r", ct_q * b + ct_r, a);
2,020✔
411
         }
404✔
412

413
         Botan::BigInt ct_q, ct_r;
783✔
414
         Botan::ct_divide(a, b, ct_q, ct_r);
783✔
415
         result.test_eq("ct_divide q", ct_q, c);
783✔
416
         result.test_eq("ct_divide r", ct_q * b + ct_r, a);
2,349✔
417

418
         result.end_timer();
783✔
419
         return result;
783✔
420
      }
4,696✔
421
};
422

423
BOTAN_REGISTER_TEST("math", "bn_div", BigInt_Div_Test);
424

425
class BigInt_Mod_Test final : public Text_Based_Test {
×
426
   public:
427
      BigInt_Mod_Test() : Text_Based_Test("bn/mod.vec", "In1,In2,Output") {}
2✔
428

429
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
76✔
430
         Test::Result result("BigInt Mod");
76✔
431
         result.start_timer();
76✔
432

433
         const BigInt a = vars.get_req_bn("In1");
76✔
434
         const BigInt b = vars.get_req_bn("In2");
76✔
435
         const BigInt expected = vars.get_req_bn("Output");
76✔
436

437
         result.test_eq("a % b", a % b, expected);
152✔
438

439
         BigInt e = a;
76✔
440
         e %= b;
76✔
441
         result.test_eq("a %= b", e, expected);
76✔
442

443
         const Botan::Modular_Reducer mod_b(b);
76✔
444
         result.test_eq("Barrett", mod_b.reduce(a), expected);
152✔
445

446
         // if b fits into a Botan::word test %= operator for words
447
         if(b.sig_words() == 1) {
76✔
448
            const Botan::word b_word = b.word_at(0);
30✔
449

450
            e = a;
30✔
451
            e %= b_word;
30✔
452
            result.test_eq("a %= b (as word)", e, expected);
30✔
453

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

456
            Botan::BigInt ct_q;
30✔
457
            Botan::word ct_r;
30✔
458
            Botan::ct_divide_word(a, b.word_at(0), ct_q, ct_r);
60✔
459
            result.test_eq("ct_divide_u8 r", ct_r, expected);
82✔
460
         }
30✔
461

462
         Botan::BigInt ct_q, ct_r;
76✔
463
         Botan::ct_divide(a, b, ct_q, ct_r);
76✔
464
         result.test_eq("ct_divide r", ct_r, expected);
76✔
465

466
         result.end_timer();
76✔
467
         return result;
76✔
468
      }
453✔
469
};
470

471
BOTAN_REGISTER_TEST("math", "bn_mod", BigInt_Mod_Test);
472

473
class BigInt_GCD_Test final : public Text_Based_Test {
×
474
   public:
475
      BigInt_GCD_Test() : Text_Based_Test("bn/gcd.vec", "X,Y,GCD") {}
2✔
476

477
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
182✔
478
         Test::Result result("BigInt GCD");
182✔
479
         result.start_timer();
182✔
480

481
         const BigInt x = vars.get_req_bn("X");
182✔
482
         const BigInt y = vars.get_req_bn("Y");
182✔
483
         const BigInt expected = vars.get_req_bn("GCD");
182✔
484

485
         const BigInt g1 = Botan::gcd(x, y);
182✔
486
         result.test_eq("gcd", g1, expected);
182✔
487

488
         const BigInt g2 = Botan::gcd(y, x);
182✔
489
         result.test_eq("gcd", g2, expected);
182✔
490

491
         result.end_timer();
182✔
492
         return result;
182✔
493
      }
910✔
494
};
495

496
BOTAN_REGISTER_TEST("math", "bn_gcd", BigInt_GCD_Test);
497

498
class BigInt_Jacobi_Test final : public Text_Based_Test {
×
499
   public:
500
      BigInt_Jacobi_Test() : Text_Based_Test("bn/jacobi.vec", "A,N,J") {}
2✔
501

502
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
698✔
503
         Test::Result result("BigInt Jacobi");
698✔
504
         result.start_timer();
698✔
505

506
         const BigInt a = vars.get_req_bn("A");
698✔
507
         const BigInt n = vars.get_req_bn("N");
698✔
508
         const std::string expected = vars.get_req_str("J");
698✔
509

510
         const int32_t j = Botan::jacobi(a, n);
698✔
511

512
         if(j == 0) {
698✔
513
            result.test_eq("jacobi", expected, "0");
314✔
514
         } else if(j == -1) {
541✔
515
            result.test_eq("jacobi", expected, "-1");
614✔
516
         } else {
517
            result.test_eq("jacobi", expected, "1");
468✔
518
         }
519

520
         result.end_timer();
698✔
521
         return result;
698✔
522
      }
2,094✔
523
};
524

525
BOTAN_REGISTER_TEST("math", "bn_jacobi", BigInt_Jacobi_Test);
526

527
class BigInt_Lshift_Test final : public Text_Based_Test {
×
528
   public:
529
      BigInt_Lshift_Test() : Text_Based_Test("bn/lshift.vec", "Value,Shift,Output") {}
2✔
530

531
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
50✔
532
         Test::Result result("BigInt Lshift");
50✔
533
         result.start_timer();
50✔
534

535
         const BigInt value = vars.get_req_bn("Value");
50✔
536
         const size_t shift = vars.get_req_bn("Shift").to_u32bit();
100✔
537
         const BigInt output = vars.get_req_bn("Output");
50✔
538

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

541
         BigInt e = value;
50✔
542
         e <<= shift;
50✔
543
         result.test_eq("a <<= s", e, output);
50✔
544

545
         result.end_timer();
50✔
546
         return result;
50✔
547
      }
150✔
548
};
549

550
BOTAN_REGISTER_TEST("math", "bn_lshift", BigInt_Lshift_Test);
551

552
class BigInt_Rshift_Test final : public Text_Based_Test {
×
553
   public:
554
      BigInt_Rshift_Test() : Text_Based_Test("bn/rshift.vec", "Value,Shift,Output") {}
2✔
555

556
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
53✔
557
         Test::Result result("BigInt Rshift");
53✔
558
         result.start_timer();
53✔
559

560
         const BigInt value = vars.get_req_bn("Value");
53✔
561
         const size_t shift = vars.get_req_bn("Shift").to_u32bit();
106✔
562
         const BigInt output = vars.get_req_bn("Output");
53✔
563

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

566
         BigInt e = value;
53✔
567
         e >>= shift;
53✔
568
         result.test_eq("a >>= s", e, output);
53✔
569

570
         result.end_timer();
53✔
571
         return result;
53✔
572
      }
159✔
573
};
574

575
BOTAN_REGISTER_TEST("math", "bn_rshift", BigInt_Rshift_Test);
576

577
Test::Result test_const_time_left_shift() {
1✔
578
   Test::Result result("BigInt const time shift");
1✔
579

580
   const size_t bits = Test::run_long_tests() ? 4096 : 2048;
1✔
581

582
   auto rng = Test::new_rng("const_time_left_shift");
1✔
583

584
   result.start_timer();
1✔
585

586
   Botan::BigInt a = Botan::BigInt::with_capacity(bits / sizeof(Botan::word));
1✔
587
   for(size_t i = 0; i < bits; ++i) {
4,097✔
588
      if(rng->next_byte() & 1) {
4,096✔
589
         a.set_bit(i);
4,096✔
590
      }
591
   }
592

593
   for(size_t i = 0; i < bits; ++i) {
4,097✔
594
      auto ct = a;
4,096✔
595
      auto chk = a;
4,096✔
596
      Botan::CT::poison(ct);
4,096✔
597
      ct.ct_shift_left(i);
4,096✔
598
      Botan::CT::unpoison(ct);
4,096✔
599
      chk <<= i;
4,096✔
600
      result.test_eq(Botan::fmt("ct << {}", i), ct, chk);
8,192✔
601
   }
8,192✔
602

603
   result.end_timer();
1✔
604
   return result;
1✔
605
}
2✔
606

607
class BigInt_Powmod_Test final : public Text_Based_Test {
×
608
   public:
609
      BigInt_Powmod_Test() : Text_Based_Test("bn/powmod.vec", "Base,Exponent,Modulus,Output") {}
2✔
610

611
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
47✔
612
         Test::Result result("BigInt Powmod");
47✔
613
         result.start_timer();
47✔
614

615
         const BigInt base = vars.get_req_bn("Base");
47✔
616
         const BigInt exponent = vars.get_req_bn("Exponent");
47✔
617
         const BigInt modulus = vars.get_req_bn("Modulus");
47✔
618
         const BigInt expected = vars.get_req_bn("Output");
47✔
619

620
         result.test_eq("power_mod", Botan::power_mod(base, exponent, modulus), expected);
94✔
621
         result.end_timer();
47✔
622
         return result;
47✔
623
      }
188✔
624
};
625

626
BOTAN_REGISTER_TEST("math", "bn_powmod", BigInt_Powmod_Test);
627

628
class BigInt_IsPrime_Test final : public Text_Based_Test {
×
629
   public:
630
      BigInt_IsPrime_Test() : Text_Based_Test("bn/isprime.vec", "X") {}
2✔
631

632
      Test::Result run_one_test(const std::string& header, const VarMap& vars) override {
132✔
633
         if(header != "Prime" && header != "NonPrime") {
132✔
634
            throw Test_Error("Bad header for prime test " + header);
×
635
         }
636

637
         const BigInt value = vars.get_req_bn("X");
132✔
638
         const bool is_prime = (header == "Prime");
132✔
639

640
         Test::Result result("BigInt Test " + header);
132✔
641
         result.start_timer();
132✔
642
         result.test_eq("is_prime", Botan::is_prime(value, this->rng()), is_prime);
132✔
643
         result.end_timer();
132✔
644
         return result;
132✔
645
      }
132✔
646
};
647

648
BOTAN_REGISTER_TEST("math", "bn_isprime", BigInt_IsPrime_Test);
649

650
class BigInt_IsSquare_Test final : public Text_Based_Test {
×
651
   public:
652
      BigInt_IsSquare_Test() : Text_Based_Test("bn/perfect_square.vec", "X,R") {}
2✔
653

654
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
7✔
655
         const BigInt value = vars.get_req_bn("X");
7✔
656
         const BigInt expected = vars.get_req_bn("R");
7✔
657
         const BigInt computed = Botan::is_perfect_square(value);
7✔
658

659
         Test::Result result("BigInt IsSquare");
7✔
660
         result.start_timer();
7✔
661
         result.test_eq("is_perfect_square", computed, expected);
7✔
662
         result.end_timer();
7✔
663
         return result;
7✔
664
      }
21✔
665
};
666

667
BOTAN_REGISTER_TEST("math", "bn_issquare", BigInt_IsSquare_Test);
668

669
class BigInt_Sqrt_Modulo_Prime_Test final : public Text_Based_Test {
×
670
   public:
671
      BigInt_Sqrt_Modulo_Prime_Test() : Text_Based_Test("bn/sqrt_modulo_prime.vec", "Input,Modulus,Output") {}
2✔
672

673
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
17✔
674
         Test::Result result("BigInt Sqrt Modulo Prime");
17✔
675
         result.start_timer();
17✔
676

677
         const Botan::BigInt a = vars.get_req_bn("Input");
17✔
678
         const Botan::BigInt p = vars.get_req_bn("Modulus");
17✔
679
         const Botan::BigInt exp = vars.get_req_bn("Output");
17✔
680

681
         const Botan::BigInt a_sqrt = Botan::sqrt_modulo_prime(a, p);
17✔
682

683
         result.test_eq("sqrt_modulo_prime", a_sqrt, exp);
17✔
684

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

690
         result.end_timer();
17✔
691
         return result;
17✔
692
      }
68✔
693
};
694

695
BOTAN_REGISTER_TEST("math", "bn_sqrt_modulo_prime", BigInt_Sqrt_Modulo_Prime_Test);
696

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

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

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

709
         const Botan::BigInt a_inv = Botan::inverse_mod(a, mod);
138✔
710

711
         result.test_eq("inverse_mod", a_inv, expected);
138✔
712

713
         if(a_inv > 1) {
138✔
714
            result.test_eq("inverse ok", (a * a_inv) % mod, 1);
415✔
715
         }
716
         /*
717
         else if((a % mod) > 0)
718
            {
719
            result.confirm("no inverse with gcd > 1", gcd(a, mod) > 1);
720
            }
721
         */
722
         result.end_timer();
138✔
723
         return result;
138✔
724
      }
552✔
725
};
726

727
BOTAN_REGISTER_TEST("math", "bn_invmod", BigInt_InvMod_Test);
728

729
class BigInt_Rand_Test final : public Text_Based_Test {
×
730
   public:
731
      BigInt_Rand_Test() : Text_Based_Test("bn/random.vec", "Seed,Min,Max,Output") {}
2✔
732

733
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
4✔
734
         Test::Result result("BigInt Random");
4✔
735
         result.start_timer();
4✔
736

737
         const std::vector<uint8_t> seed = vars.get_req_bin("Seed");
4✔
738
         const Botan::BigInt min = vars.get_req_bn("Min");
4✔
739
         const Botan::BigInt max = vars.get_req_bn("Max");
4✔
740
         const Botan::BigInt expected = vars.get_req_bn("Output");
4✔
741

742
         Fixed_Output_RNG rng(seed);
4✔
743
         Botan::BigInt generated = BigInt::random_integer(rng, min, max);
4✔
744

745
         result.test_eq("random_integer KAT", generated, expected);
4✔
746

747
         result.end_timer();
4✔
748
         return result;
4✔
749
      }
20✔
750
};
751

752
BOTAN_REGISTER_TEST("math", "bn_rand", BigInt_Rand_Test);
753

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

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

767
         Test::Result result("Lucas primality test");
1✔
768
         result.start_timer();
1✔
769

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

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

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

784
         result.end_timer();
1✔
785
         return {result};
2✔
786
      }
2✔
787
};
788

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

791
class DSA_ParamGen_Test final : public Text_Based_Test {
×
792
   public:
793
      DSA_ParamGen_Test() : Text_Based_Test("bn/dsa_gen.vec", "P,Q,Counter,Seed") {}
2✔
794

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

799
         const Botan::BigInt exp_P = vars.get_req_bn("P");
20✔
800
         const Botan::BigInt exp_Q = vars.get_req_bn("Q");
20✔
801

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

804
         if(header_parts.size() != 2) {
20✔
805
            throw Test_Error("Unexpected header '" + header + "' in DSA param gen test");
×
806
         }
807

808
         const size_t p_bits = Botan::to_u32bit(header_parts[1]);
20✔
809
         const size_t q_bits = Botan::to_u32bit(header_parts[0]);
20✔
810

811
         Test::Result result("DSA Parameter Generation");
20✔
812
         result.start_timer();
20✔
813

814
         try {
20✔
815
            Botan::BigInt gen_P, gen_Q;
20✔
816
            if(Botan::generate_dsa_primes(this->rng(), gen_P, gen_Q, p_bits, q_bits, seed, offset)) {
20✔
817
               result.test_eq("P", gen_P, exp_P);
20✔
818
               result.test_eq("Q", gen_Q, exp_Q);
40✔
819
            } else {
820
               result.test_failure("Seed did not generate a DSA parameter");
×
821
            }
822
         } catch(Botan::Lookup_Error&) {}
40✔
823

824
         result.end_timer();
20✔
825
         return result;
40✔
826
      }
80✔
827
};
828

829
BOTAN_REGISTER_TEST("math", "dsa_param", DSA_ParamGen_Test);
830

831
std::vector<Test::Result> test_bigint_serialization() {
1✔
832
   auto rng = Test::new_rng("test_bigint_serialization");
1✔
833

834
   return {
1✔
835
      CHECK("BigInt binary serialization",
836
            [](Test::Result& res) {
1✔
837
               res.start_timer();
1✔
838
               Botan::BigInt a(0x1234567890ABCDEF);
1✔
839
               auto enc = a.serialize();
1✔
840
               res.test_eq("BigInt::serialize", enc, Botan::hex_decode("1234567890ABCDEF"));
2✔
841

842
               auto enc10 = a.serialize(10);
1✔
843
               res.test_eq("BigInt::serialize", enc10, Botan::hex_decode("00001234567890ABCDEF"));
2✔
844

845
               res.test_throws("BigInt::serialize rejects short output", [&]() { a.serialize(7); });
3✔
846
               res.end_timer();
1✔
847
            }),
3✔
848

849
      CHECK("BigInt truncated/padded binary serialization",
850
            [&](Test::Result& res) {
1✔
851
               res.start_timer();
1✔
852
               Botan::BigInt a(0xFEDCBA9876543210);
1✔
853

854
               std::vector<uint8_t> enc1(a.bytes() - 1);
1✔
855
               a.binary_encode(enc1.data(), enc1.size());
1✔
856
               res.test_eq("BigInt::binary_encode", enc1, Botan::hex_decode("DCBA9876543210"));
2✔
857

858
               std::vector<uint8_t> enc2(a.bytes() - 3);
1✔
859
               a.binary_encode(enc2.data(), enc2.size());
1✔
860
               res.test_eq("BigInt::binary_encode", enc2, Botan::hex_decode("9876543210"));
2✔
861

862
               std::vector<uint8_t> enc3(a.bytes() + 1);
1✔
863
               a.binary_encode(enc3.data(), enc3.size());
1✔
864
               res.test_eq("BigInt::binary_encode", enc3, Botan::hex_decode("00FEDCBA9876543210"));
2✔
865

866
               // make sure that the padding is actually written
867
               std::vector<uint8_t> enc4(a.bytes() + 3);
1✔
868
               rng->randomize(enc4);
1✔
869
               a.binary_encode(enc4.data(), enc4.size());
1✔
870
               res.test_eq("BigInt::binary_encode", enc4, Botan::hex_decode("000000FEDCBA9876543210"));
2✔
871

872
               Botan::BigInt b(Botan::hex_decode("FEDCBA9876543210BAADC0FFEE"));
1✔
873

874
               std::vector<uint8_t> enc5(b.bytes() + 12);
1✔
875
               rng->randomize(enc5);
1✔
876
               b.binary_encode(enc5.data(), enc5.size());
1✔
877
               res.test_eq("BigInt::binary_encode",
2✔
878
                           enc5,
879
                           Botan::hex_decode("000000000000000000000000FEDCBA9876543210BAADC0FFEE"));
1✔
880
               res.end_timer();
1✔
881
            }),
7✔
882
   };
3✔
883
}
2✔
884

885
BOTAN_REGISTER_TEST_FN("math", "bignum_auxiliary", test_const_time_left_shift, test_bigint_serialization);
886

887
#endif
888

889
}  // namespace
890

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