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

randombit / botan / 12890812993

21 Jan 2025 11:51AM UTC coverage: 91.215% (-0.001%) from 91.216%
12890812993

push

github

web-flow
Merge pull request #4579 from randombit/jack/dl-group-depr

Deprecate a couple of functions in DL_Group

93551 of 102561 relevant lines covered (91.21%)

11644986.68 hits per line

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

98.4
/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
#if defined(BOTAN_HAS_BIGINT)
10
   #include <botan/bigint.h>
11
   #include <botan/internal/divide.h>
12
#endif
13

14
#if defined(BOTAN_HAS_NUMBERTHEORY)
15
   #include <botan/numthry.h>
16
   #include <botan/reducer.h>
17
   #include <botan/internal/primality.h>
18
#endif
19

20
#if defined(BOTAN_HAS_DL_GROUP)
21
   #include <botan/dl_group.h>
22
#endif
23

24
namespace Botan_CLI {
25

26
#if defined(BOTAN_HAS_BIGINT)
27

28
class PerfTest_MpMul final : public PerfTest {
1✔
29
   public:
30
      void go(const PerfConfig& config) override {
1✔
31
         std::chrono::milliseconds runtime_per_size = config.runtime();
1✔
32

33
         for(size_t bits : {256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096}) {
10✔
34
            auto mul_timer = config.make_timer("BigInt mul " + std::to_string(bits));
18✔
35
            auto sqr_timer = config.make_timer("BigInt sqr " + std::to_string(bits));
18✔
36

37
            const Botan::BigInt y(config.rng(), bits);
9✔
38
            Botan::secure_vector<Botan::word> ws;
9✔
39

40
            while(mul_timer->under(runtime_per_size)) {
9,391✔
41
               Botan::BigInt x(config.rng(), bits);
9,382✔
42

43
               sqr_timer->start();
9,382✔
44
               x.square(ws);
9,382✔
45
               sqr_timer->stop();
9,382✔
46

47
               x.mask_bits(bits);
9,382✔
48

49
               mul_timer->start();
9,382✔
50
               x.mul(y, ws);
9,382✔
51
               mul_timer->stop();
9,382✔
52
            }
9,382✔
53

54
            config.record_result(*mul_timer);
9✔
55
            config.record_result(*sqr_timer);
18✔
56
         }
27✔
57
      }
1✔
58
};
59

60
BOTAN_REGISTER_PERF_TEST("mp_mul", PerfTest_MpMul);
1✔
61

62
class PerfTest_MpDiv final : public PerfTest {
1✔
63
   public:
64
      void go(const PerfConfig& config) override {
1✔
65
         std::chrono::milliseconds runtime_per_size = config.runtime();
1✔
66

67
         for(size_t n_bits : {256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096}) {
10✔
68
            const size_t q_bits = n_bits / 2;
9✔
69
            const std::string bit_descr = std::to_string(n_bits) + "/" + std::to_string(q_bits);
27✔
70

71
            auto div_timer = config.make_timer("BigInt div " + bit_descr);
18✔
72
            auto ct_div_timer = config.make_timer("BigInt ct_div " + bit_descr);
18✔
73

74
            Botan::BigInt y;
9✔
75
            Botan::BigInt x;
9✔
76
            Botan::secure_vector<Botan::word> ws;
9✔
77

78
            Botan::BigInt q1, r1, q2, r2;
9✔
79

80
            while(ct_div_timer->under(runtime_per_size)) {
9✔
81
               x.randomize(config.rng(), n_bits);
94✔
82
               y.randomize(config.rng(), q_bits);
94✔
83

84
               div_timer->start();
94✔
85
               Botan::vartime_divide(x, y, q1, r1);
94✔
86
               div_timer->stop();
94✔
87

88
               ct_div_timer->start();
94✔
89
               Botan::ct_divide(x, y, q2, r2);
94✔
90
               ct_div_timer->stop();
94✔
91

92
               BOTAN_ASSERT_EQUAL(q1, q2, "Quotient ok");
94✔
93
               BOTAN_ASSERT_EQUAL(r1, r2, "Remainder ok");
197✔
94
            }
95

96
            config.record_result(*div_timer);
9✔
97
            config.record_result(*ct_div_timer);
18✔
98
         }
63✔
99
      }
1✔
100
};
101

102
BOTAN_REGISTER_PERF_TEST("mp_div", PerfTest_MpDiv);
1✔
103

104
class PerfTest_MpDiv10 final : public PerfTest {
1✔
105
   public:
106
      void go(const PerfConfig& config) override {
1✔
107
         std::chrono::milliseconds runtime_per_size = config.runtime();
1✔
108

109
         for(size_t n_bits : {256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096}) {
10✔
110
            const std::string bit_descr = std::to_string(n_bits) + "/10";
18✔
111

112
            auto div_timer = config.make_timer("BigInt div " + bit_descr);
18✔
113
            auto ct_div_timer = config.make_timer("BigInt ct_div " + bit_descr);
18✔
114

115
            Botan::BigInt x;
9✔
116
            Botan::secure_vector<Botan::word> ws;
9✔
117

118
            const auto ten = Botan::BigInt::from_word(10);
9✔
119
            Botan::BigInt q1, r1, q2;
9✔
120
            Botan::word r2;
9✔
121

122
            while(ct_div_timer->under(runtime_per_size)) {
9✔
123
               x.randomize(config.rng(), n_bits);
723✔
124

125
               div_timer->start();
723✔
126
               Botan::vartime_divide(x, ten, q1, r1);
723✔
127
               div_timer->stop();
723✔
128

129
               ct_div_timer->start();
723✔
130
               Botan::ct_divide_word(x, 10, q2, r2);
723✔
131
               ct_div_timer->stop();
723✔
132

133
               BOTAN_ASSERT_EQUAL(q1, q2, "Quotient ok");
723✔
134
               BOTAN_ASSERT_EQUAL(r1, r2, "Remainder ok");
1,455✔
135
            }
136

137
            config.record_result(*div_timer);
9✔
138
            config.record_result(*ct_div_timer);
18✔
139
         }
54✔
140
      }
1✔
141
};
142

143
BOTAN_REGISTER_PERF_TEST("mp_div10", PerfTest_MpDiv10);
1✔
144

145
#endif
146

147
#if defined(BOTAN_HAS_NUMBERTHEORY)
148

149
class PerfTest_BnRedc final : public PerfTest {
1✔
150
   public:
151
      void go(const PerfConfig& config) override {
1✔
152
         const auto runtime = config.runtime();
1✔
153

154
         for(size_t bitsize : {512, 1024, 2048, 4096}) {
5✔
155
            Botan::BigInt p(config.rng(), bitsize);
4✔
156

157
            std::string bit_str = std::to_string(bitsize);
4✔
158
            auto barrett_timer = config.make_timer("Barrett-" + bit_str);
8✔
159
            auto schoolbook_timer = config.make_timer("Schoolbook-" + bit_str);
8✔
160

161
            Botan::Modular_Reducer mod_p(p);
4✔
162

163
            while(schoolbook_timer->under(runtime)) {
84✔
164
               const Botan::BigInt x(config.rng(), p.bits() * 2 - 2);
80✔
165

166
               const Botan::BigInt r1 = barrett_timer->run([&] { return mod_p.reduce(x); });
160✔
167
               const Botan::BigInt r2 = schoolbook_timer->run([&] { return x % p; });
160✔
168

169
               BOTAN_ASSERT(r1 == r2, "Computed different results");
80✔
170
            }
171

172
            config.record_result(*barrett_timer);
4✔
173
            config.record_result(*schoolbook_timer);
4✔
174
         }
12✔
175
      }
1✔
176
};
177

178
BOTAN_REGISTER_PERF_TEST("bn_redc", PerfTest_BnRedc);
1✔
179

180
class PerfTest_InvMod final : public PerfTest {
1✔
181
   public:
182
      void go(const PerfConfig& config) override {
1✔
183
         const auto runtime = config.runtime();
1✔
184

185
         for(size_t bits : {256, 384, 512, 1024, 2048}) {
6✔
186
            const std::string bit_str = std::to_string(bits);
5✔
187

188
            auto timer = config.make_timer("inverse_mod-" + bit_str);
10✔
189
            auto gcd_timer = config.make_timer("gcd-" + bit_str);
10✔
190

191
            while(timer->under(runtime) && gcd_timer->under(runtime)) {
11✔
192
               const Botan::BigInt x(config.rng(), bits - 1);
6✔
193
               Botan::BigInt mod(config.rng(), bits);
6✔
194

195
               const Botan::BigInt x_inv = timer->run([&] { return Botan::inverse_mod(x, mod); });
12✔
196

197
               const Botan::BigInt g = gcd_timer->run([&] { return gcd(x, mod); });
12✔
198

199
               if(x_inv == 0) {
6✔
200
                  BOTAN_ASSERT(g != 1, "Inversion only fails if gcd(x, mod) > 1");
1✔
201
               } else {
202
                  BOTAN_ASSERT(g == 1, "Inversion succeeds only if gcd != 1");
5✔
203
                  const Botan::BigInt check = (x_inv * x) % mod;
5✔
204
                  BOTAN_ASSERT_EQUAL(check, 1, "Const time inversion correct");
5✔
205
               }
5✔
206
            }
23✔
207

208
            config.record_result(*timer);
5✔
209
            config.record_result(*gcd_timer);
10✔
210
         }
5✔
211
      }
1✔
212
};
213

214
BOTAN_REGISTER_PERF_TEST("inverse_mod", PerfTest_InvMod);
1✔
215

216
class PerfTest_IsPrime final : public PerfTest {
1✔
217
   public:
218
      void go(const PerfConfig& config) override {
1✔
219
         const auto runtime = config.runtime();
1✔
220

221
         for(size_t bits : {256, 512, 1024}) {
4✔
222
            auto mr_timer = config.make_timer("Miller-Rabin-" + std::to_string(bits));
6✔
223
            auto bpsw_timer = config.make_timer("Bailie-PSW-" + std::to_string(bits));
6✔
224
            auto lucas_timer = config.make_timer("Lucas-" + std::to_string(bits));
6✔
225

226
            Botan::BigInt n = Botan::random_prime(config.rng(), bits);
3✔
227

228
            while(lucas_timer->under(runtime)) {
6✔
229
               Botan::Modular_Reducer mod_n(n);
3✔
230

231
               mr_timer->run([&]() { return Botan::is_miller_rabin_probable_prime(n, mod_n, config.rng(), 2); });
6✔
232

233
               bpsw_timer->run([&]() { return Botan::is_bailie_psw_probable_prime(n, mod_n); });
6✔
234

235
               lucas_timer->run([&]() { return Botan::is_lucas_probable_prime(n, mod_n); });
6✔
236

237
               n += 2;
3✔
238
            }
3✔
239

240
            config.record_result(*mr_timer);
3✔
241
            config.record_result(*bpsw_timer);
3✔
242
            config.record_result(*lucas_timer);
6✔
243
         }
9✔
244
      }
1✔
245
};
246

247
BOTAN_REGISTER_PERF_TEST("primality_test", PerfTest_IsPrime);
1✔
248

249
class PerfTest_RandomPrime final : public PerfTest {
1✔
250
   public:
251
      void go(const PerfConfig& config) override {
1✔
252
         const auto coprime = Botan::BigInt::from_word(0x10001);
1✔
253
         const auto runtime = config.runtime();
1✔
254

255
         auto& rng = config.rng();
1✔
256

257
         for(size_t bits : {256, 384, 512, 768, 1024, 1536}) {
7✔
258
            auto genprime_timer = config.make_timer("random_prime " + std::to_string(bits));
12✔
259
            auto gensafe_timer = config.make_timer("random_safe_prime " + std::to_string(bits));
12✔
260
            auto is_prime_timer = config.make_timer("is_prime " + std::to_string(bits));
12✔
261

262
            while(gensafe_timer->under(runtime)) {
12✔
263
               const Botan::BigInt p = genprime_timer->run([&] { return Botan::random_prime(rng, bits, coprime); });
12✔
264

265
               if(!is_prime_timer->run([&] { return Botan::is_prime(p, rng, 64, true); })) {
12✔
266
                  config.error_output() << "Generated prime " << p << " which failed a primality test";
×
267
               }
268

269
               const Botan::BigInt sg = gensafe_timer->run([&] { return Botan::random_safe_prime(rng, bits); });
12✔
270

271
               if(!is_prime_timer->run([&] { return Botan::is_prime(sg, rng, 64, true); })) {
12✔
272
                  config.error_output() << "Generated safe prime " << sg << " which failed a primality test";
×
273
               }
274

275
               if(!is_prime_timer->run([&] { return Botan::is_prime(sg / 2, rng, 64, true); })) {
18✔
276
                  config.error_output() << "Generated prime " << sg / 2 << " which failed a primality test";
×
277
               }
278

279
               // Now test p+2, p+4, ... which may or may not be prime
280
               for(size_t i = 2; i <= 64; i += 2) {
198✔
281
                  is_prime_timer->run([&]() { Botan::is_prime(p + i, rng, 64, true); });
576✔
282
               }
283
            }
12✔
284

285
            config.record_result(*genprime_timer);
6✔
286
            config.record_result(*gensafe_timer);
6✔
287
            config.record_result(*is_prime_timer);
12✔
288
         }
12✔
289
      }
1✔
290
};
291

292
BOTAN_REGISTER_PERF_TEST("random_prime", PerfTest_RandomPrime);
1✔
293

294
#endif
295

296
#if defined(BOTAN_HAS_DL_GROUP)
297

298
class PerfTest_ModExp final : public PerfTest {
1✔
299
   public:
300
      void go(const PerfConfig& config) override {
1✔
301
         for(size_t group_bits : {1024, 1536, 2048, 3072, 4096, 6144, 8192}) {
8✔
302
            const std::string group_name = "modp/ietf/" + std::to_string(group_bits);
14✔
303
            const Botan::DL_Group group(group_name);
7✔
304

305
            const size_t e_bits = group.exponent_bits();
7✔
306
            const size_t f_bits = group_bits - 1;
7✔
307

308
            const Botan::BigInt random_e(config.rng(), e_bits);
7✔
309
            const Botan::BigInt random_f(config.rng(), f_bits);
7✔
310

311
            auto e_timer = config.make_timer(group_name + " short exp");
14✔
312
            auto f_timer = config.make_timer(group_name + "  full exp");
14✔
313

314
            while(f_timer->under(config.runtime())) {
15✔
315
               e_timer->run([&]() { group.power_g_p(random_e, e_bits); });
16✔
316
               f_timer->run([&]() { group.power_g_p(random_f, f_bits); });
16✔
317
            }
318

319
            config.record_result(*e_timer);
7✔
320
            config.record_result(*f_timer);
14✔
321
         }
35✔
322
      }
1✔
323
};
324

325
BOTAN_REGISTER_PERF_TEST("modexp", PerfTest_ModExp);
1✔
326

327
#endif
328

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