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

randombit / botan / 21783203606

07 Feb 2026 04:30PM UTC coverage: 90.068% (-0.005%) from 90.073%
21783203606

Pull #5295

github

web-flow
Merge a6c023b97 into ebf8f0044
Pull Request #5295: Reduce header dependencies in tests and cli

102233 of 113507 relevant lines covered (90.07%)

11542227.95 hits per line

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

0.0
/src/cli/perf_math.cpp
1
/*
2
* (C) 2024 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "perf.h"
8

9
#include <ostream>
10

11
#if defined(BOTAN_HAS_BIGINT)
12
   #include <botan/assert.h>
13
   #include <botan/bigint.h>
14
   #include <botan/internal/divide.h>
15
#endif
16

17
#if defined(BOTAN_HAS_NUMBERTHEORY)
18
   #include <botan/numthry.h>
19
   #include <botan/internal/barrett.h>
20
   #include <botan/internal/primality.h>
21
#endif
22

23
#if defined(BOTAN_HAS_DL_GROUP)
24
   #include <botan/dl_group.h>
25
#endif
26

27
namespace Botan_CLI {
28

29
#if defined(BOTAN_HAS_BIGINT)
30

31
class PerfTest_MpMul final : public PerfTest {
×
32
   public:
33
      void go(const PerfConfig& config) override {
×
34
         const auto runtime_per_size = config.runtime();
×
35

36
         for(const size_t bits : {256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096}) {
×
37
            auto mul_timer = config.make_timer("BigInt mul " + std::to_string(bits));
×
38
            auto sqr_timer = config.make_timer("BigInt sqr " + std::to_string(bits));
×
39

40
            const Botan::BigInt y(config.rng(), bits);
×
41
            Botan::secure_vector<Botan::word> ws;
×
42

43
            while(mul_timer->under(runtime_per_size)) {
×
44
               Botan::BigInt x(config.rng(), bits);
×
45

46
               sqr_timer->start();
×
47
               x.square(ws);
×
48
               sqr_timer->stop();
×
49

50
               x.mask_bits(bits);
×
51

52
               mul_timer->start();
×
53
               x.mul(y, ws);
×
54
               mul_timer->stop();
×
55
            }
×
56

57
            config.record_result(*mul_timer);
×
58
            config.record_result(*sqr_timer);
×
59
         }
×
60
      }
×
61
};
62

63
BOTAN_REGISTER_PERF_TEST("mp_mul", PerfTest_MpMul);
×
64

65
class PerfTest_MpDiv final : public PerfTest {
×
66
   public:
67
      void go(const PerfConfig& config) override {
×
68
         const auto runtime_per_size = config.runtime();
×
69

70
         for(const size_t n_bits : {256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096}) {
×
71
            const size_t q_bits = n_bits / 2;
×
72
            const std::string bit_descr = std::to_string(n_bits) + "/" + std::to_string(q_bits);
×
73

74
            auto div_timer = config.make_timer("BigInt div " + bit_descr);
×
75
            auto ct_div_timer = config.make_timer("BigInt ct_div " + bit_descr);
×
76

77
            Botan::BigInt y;
×
78
            Botan::BigInt x;
×
79
            const Botan::secure_vector<Botan::word> ws;
×
80

81
            Botan::BigInt q1;
×
82
            Botan::BigInt r1;
×
83
            Botan::BigInt q2;
×
84
            Botan::BigInt r2;
×
85

86
            while(ct_div_timer->under(runtime_per_size)) {
×
87
               x.randomize(config.rng(), n_bits);
×
88
               y.randomize(config.rng(), q_bits);
×
89

90
               div_timer->start();
×
91
               Botan::vartime_divide(x, y, q1, r1);
×
92
               div_timer->stop();
×
93

94
               ct_div_timer->start();
×
95
               Botan::ct_divide(x, y, q2, r2);
×
96
               ct_div_timer->stop();
×
97

98
               BOTAN_ASSERT_EQUAL(q1, q2, "Quotient ok");
×
99
               BOTAN_ASSERT_EQUAL(r1, r2, "Remainder ok");
×
100
            }
101

102
            config.record_result(*div_timer);
×
103
            config.record_result(*ct_div_timer);
×
104
         }
×
105
      }
×
106
};
107

108
BOTAN_REGISTER_PERF_TEST("mp_div", PerfTest_MpDiv);
×
109

110
class PerfTest_MpDiv10 final : public PerfTest {
×
111
   public:
112
      void go(const PerfConfig& config) override {
×
113
         const auto runtime_per_size = config.runtime();
×
114

115
         for(const size_t n_bits : {256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096}) {
×
116
            const std::string bit_descr = std::to_string(n_bits) + "/10";
×
117

118
            auto div_timer = config.make_timer("BigInt div " + bit_descr);
×
119
            auto ct_div_timer = config.make_timer("BigInt ct_div " + bit_descr);
×
120

121
            Botan::BigInt x;
×
122
            const Botan::secure_vector<Botan::word> ws;
×
123

124
            const auto ten = Botan::BigInt::from_word(10);
×
125
            Botan::BigInt q1;
×
126
            Botan::BigInt r1;
×
127
            Botan::BigInt q2;
×
128
            Botan::word r2 = 0;
×
129

130
            while(ct_div_timer->under(runtime_per_size)) {
×
131
               x.randomize(config.rng(), n_bits);
×
132

133
               div_timer->start();
×
134
               Botan::vartime_divide(x, ten, q1, r1);
×
135
               div_timer->stop();
×
136

137
               ct_div_timer->start();
×
138
               Botan::ct_divide_word(x, 10, q2, r2);
×
139
               ct_div_timer->stop();
×
140

141
               BOTAN_ASSERT_EQUAL(q1, q2, "Quotient ok");
×
142
               BOTAN_ASSERT_EQUAL(r1, r2, "Remainder ok");
×
143
            }
144

145
            config.record_result(*div_timer);
×
146
            config.record_result(*ct_div_timer);
×
147
         }
×
148
      }
×
149
};
150

151
BOTAN_REGISTER_PERF_TEST("mp_div10", PerfTest_MpDiv10);
×
152

153
#endif
154

155
#if defined(BOTAN_HAS_NUMBERTHEORY)
156

157
class PerfTest_BnRedc final : public PerfTest {
×
158
   public:
159
      void go(const PerfConfig& config) override {
×
160
         const auto runtime = config.runtime();
×
161

162
         for(const size_t bitsize : {256, 512, 1024, 2048, 4096}) {
×
163
            Botan::BigInt p(config.rng(), bitsize);
×
164

165
            const std::string bit_str = std::to_string(bitsize) + " bit ";
×
166
            auto barrett_setup_pub_timer = config.make_timer(bit_str + "Barrett setup public");
×
167
            auto barrett_setup_sec_timer = config.make_timer(bit_str + "Barrett setup secret");
×
168

169
            while(barrett_setup_sec_timer->under(runtime)) {
×
170
               barrett_setup_sec_timer->run([&]() { Botan::Barrett_Reduction::for_secret_modulus(p); });
×
171
               barrett_setup_pub_timer->run([&]() { Botan::Barrett_Reduction::for_public_modulus(p); });
×
172
            }
173

174
            config.record_result(*barrett_setup_pub_timer);
×
175
            config.record_result(*barrett_setup_sec_timer);
×
176

177
            auto mod_p = Botan::Barrett_Reduction::for_public_modulus(p);
×
178

179
            auto barrett_timer = config.make_timer(bit_str + "Barrett redc");
×
180
            auto knuth_timer = config.make_timer(bit_str + "Knuth redc");
×
181
            auto ct_modulo_timer = config.make_timer(bit_str + "ct_modulo");
×
182

183
            while(ct_modulo_timer->under(runtime)) {
×
184
               const Botan::BigInt x(config.rng(), p.bits() * 2 - 1);
×
185

186
               const Botan::BigInt r1 = barrett_timer->run([&] { return mod_p.reduce(x); });
×
187
               const Botan::BigInt r2 = knuth_timer->run([&] { return x % p; });
×
188
               const Botan::BigInt r3 = ct_modulo_timer->run([&] { return Botan::ct_modulo(x, p); });
×
189

190
               BOTAN_ASSERT(r1 == r2, "Computed different results");
×
191
               BOTAN_ASSERT(r1 == r3, "Computed different results");
×
192
            }
×
193

194
            config.record_result(*barrett_timer);
×
195
            config.record_result(*knuth_timer);
×
196
            config.record_result(*ct_modulo_timer);
×
197
         }
×
198
      }
×
199
};
200

201
BOTAN_REGISTER_PERF_TEST("bn_redc", PerfTest_BnRedc);
×
202

203
class PerfTest_InvMod final : public PerfTest {
×
204
   public:
205
      void go(const PerfConfig& config) override {
×
206
         const auto runtime = config.runtime();
×
207

208
         for(const size_t bits : {256, 384, 512, 1024, 2048}) {
×
209
            const std::string bit_str = std::to_string(bits);
×
210

211
            auto timer = config.make_timer("inverse_mod-" + bit_str);
×
212
            auto gcd_timer = config.make_timer("gcd-" + bit_str);
×
213

214
            while(timer->under(runtime) && gcd_timer->under(runtime)) {
×
215
               const Botan::BigInt x(config.rng(), bits - 1);
×
216
               Botan::BigInt mod(config.rng(), bits);
×
217

218
               const Botan::BigInt x_inv = timer->run([&] { return Botan::inverse_mod(x, mod); });
×
219

220
               const Botan::BigInt g = gcd_timer->run([&] { return gcd(x, mod); });
×
221

222
               if(x_inv == 0) {
×
223
                  BOTAN_ASSERT(g != 1, "Inversion only fails if gcd(x, mod) > 1");
×
224
               } else {
225
                  BOTAN_ASSERT(g == 1, "Inversion succeeds only if gcd != 1");
×
226
                  const Botan::BigInt check = (x_inv * x) % mod;
×
227
                  BOTAN_ASSERT_EQUAL(check, 1, "Const time inversion correct");
×
228
               }
×
229
            }
×
230

231
            config.record_result(*timer);
×
232
            config.record_result(*gcd_timer);
×
233
         }
×
234
      }
×
235
};
236

237
BOTAN_REGISTER_PERF_TEST("inverse_mod", PerfTest_InvMod);
×
238

239
class PerfTest_IsPrime final : public PerfTest {
×
240
   public:
241
      void go(const PerfConfig& config) override {
×
242
         const auto runtime = config.runtime();
×
243

244
         for(const size_t bits : {256, 512, 1024}) {
×
245
            auto mr_timer = config.make_timer("Miller-Rabin-" + std::to_string(bits));
×
246
            auto bpsw_timer = config.make_timer("Bailie-PSW-" + std::to_string(bits));
×
247
            auto lucas_timer = config.make_timer("Lucas-" + std::to_string(bits));
×
248

249
            Botan::BigInt n = Botan::random_prime(config.rng(), bits);
×
250

251
            while(lucas_timer->under(runtime)) {
×
252
               auto mod_n = Botan::Barrett_Reduction::for_public_modulus(n);
×
253

254
               mr_timer->run([&]() { return Botan::is_miller_rabin_probable_prime(n, mod_n, config.rng(), 2); });
×
255

256
               bpsw_timer->run([&]() { return Botan::is_bailie_psw_probable_prime(n, mod_n); });
×
257

258
               lucas_timer->run([&]() { return Botan::is_lucas_probable_prime(n, mod_n); });
×
259

260
               n += 2;
×
261
            }
×
262

263
            config.record_result(*mr_timer);
×
264
            config.record_result(*bpsw_timer);
×
265
            config.record_result(*lucas_timer);
×
266
         }
×
267
      }
×
268
};
269

270
BOTAN_REGISTER_PERF_TEST("primality_test", PerfTest_IsPrime);
×
271

272
class PerfTest_RandomPrime final : public PerfTest {
×
273
   public:
274
      void go(const PerfConfig& config) override {
×
275
         const auto coprime = Botan::BigInt::from_word(0x10001);
×
276
         const auto runtime = config.runtime();
×
277

278
         auto& rng = config.rng();
×
279

280
         for(size_t bits : {256, 384, 512, 768, 1024, 1536}) {
×
281
            auto genprime_timer = config.make_timer("random_prime " + std::to_string(bits));
×
282
            auto is_prime_timer = config.make_timer("is_prime " + std::to_string(bits));
×
283

284
            while(genprime_timer->under(runtime) && is_prime_timer->under(runtime)) {
×
285
               const Botan::BigInt p = genprime_timer->run([&] { return Botan::random_prime(rng, bits, coprime); });
×
286

287
               if(!is_prime_timer->run([&] { return Botan::is_prime(p, rng, 64, true); })) {
×
288
                  config.error_output() << "Generated prime " << p << " which failed a primality test";
×
289
               }
290

291
               // Now test p+2, p+4, ... which may or may not be prime
292
               for(size_t i = 2; i <= 64; i += 2) {
×
293
                  is_prime_timer->run([&]() { Botan::is_prime(p + i, rng, 64, true); });
×
294
               }
295
            }
×
296

297
            config.record_result(*genprime_timer);
×
298
            config.record_result(*is_prime_timer);
×
299
         }
×
300
      }
×
301
};
302

303
BOTAN_REGISTER_PERF_TEST("random_prime", PerfTest_RandomPrime);
×
304

305
#endif
306

307
#if defined(BOTAN_HAS_DL_GROUP)
308

309
class PerfTest_ModExp final : public PerfTest {
×
310
   public:
311
      void go(const PerfConfig& config) override {
×
312
         for(const size_t group_bits : {1024, 1536, 2048, 3072, 4096, 6144, 8192}) {
×
313
            const std::string group_name = "modp/ietf/" + std::to_string(group_bits);
×
314
            auto group = Botan::DL_Group::from_name(group_name);
×
315

316
            const size_t e_bits = group.exponent_bits();
×
317
            const size_t f_bits = group_bits - 1;
×
318

319
            const Botan::BigInt random_e(config.rng(), e_bits);
×
320
            const Botan::BigInt random_f(config.rng(), f_bits);
×
321

322
            auto e_timer = config.make_timer(group_name + " short exp");
×
323
            auto f_timer = config.make_timer(group_name + "  full exp");
×
324

325
            while(f_timer->under(config.runtime())) {
×
326
               e_timer->run([&]() { group.power_g_p(random_e, e_bits); });
×
327
               f_timer->run([&]() { group.power_g_p(random_f, f_bits); });
×
328
            }
329

330
            config.record_result(*e_timer);
×
331
            config.record_result(*f_timer);
×
332
         }
×
333
      }
×
334
};
335

336
BOTAN_REGISTER_PERF_TEST("modexp", PerfTest_ModExp);
×
337

338
#endif
339

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

© 2026 Coveralls, Inc