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

randombit / botan / 5131409391

31 May 2023 09:53AM UTC coverage: 92.013% (+0.001%) from 92.012%
5131409391

Pull #3549

github

web-flow
Merge fbf754778 into 1cbeffafb
Pull Request #3549: SPHINCS+

76845 of 83515 relevant lines covered (92.01%)

12227963.65 hits per line

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

94.02
/src/cli/speed.cpp
1
/*
2
* (C) 2009,2010,2014,2015,2017,2018 Jack Lloyd
3
* (C) 2015 Simon Warta (Kullo GmbH)
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include "../tests/test_rng.h"  // FIXME
9
#include "cli.h"
10

11
#include <algorithm>
12
#include <chrono>
13
#include <functional>
14
#include <iomanip>
15
#include <map>
16
#include <set>
17
#include <sstream>
18

19
// Always available:
20
#include <botan/entropy_src.h>
21
#include <botan/version.h>
22
#include <botan/internal/cpuid.h>
23
#include <botan/internal/os_utils.h>
24
#include <botan/internal/timer.h>
25

26
#if defined(BOTAN_HAS_BIGINT)
27
   #include <botan/bigint.h>
28
   #include <botan/internal/divide.h>
29
#endif
30

31
#if defined(BOTAN_HAS_BLOCK_CIPHER)
32
   #include <botan/block_cipher.h>
33
#endif
34

35
#if defined(BOTAN_HAS_STREAM_CIPHER)
36
   #include <botan/stream_cipher.h>
37
#endif
38

39
#if defined(BOTAN_HAS_HASH)
40
   #include <botan/hash.h>
41
#endif
42

43
#if defined(BOTAN_HAS_CIPHER_MODES)
44
   #include <botan/cipher_mode.h>
45
#endif
46

47
#if defined(BOTAN_HAS_MAC)
48
   #include <botan/mac.h>
49
#endif
50

51
#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
52
   #include <botan/auto_rng.h>
53
#endif
54

55
#if defined(BOTAN_HAS_SYSTEM_RNG)
56
   #include <botan/system_rng.h>
57
#endif
58

59
#if defined(BOTAN_HAS_HMAC_DRBG)
60
   #include <botan/hmac_drbg.h>
61
#endif
62

63
#if defined(BOTAN_HAS_PROCESSOR_RNG)
64
   #include <botan/processor_rng.h>
65
#endif
66

67
#if defined(BOTAN_HAS_CHACHA_RNG)
68
   #include <botan/chacha_rng.h>
69
#endif
70

71
#if defined(BOTAN_HAS_FPE_FE1)
72
   #include <botan/fpe_fe1.h>
73
#endif
74

75
#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
76
   #include <botan/rfc3394.h>
77
#endif
78

79
#if defined(BOTAN_HAS_COMPRESSION)
80
   #include <botan/compression.h>
81
#endif
82

83
#if defined(BOTAN_HAS_POLY_DBL)
84
   #include <botan/internal/poly_dbl.h>
85
#endif
86

87
#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
88
   #include <botan/pk_algs.h>
89
   #include <botan/pkcs8.h>
90
   #include <botan/pubkey.h>
91
   #include <botan/x509_key.h>
92
   #include <botan/internal/workfactor.h>
93
#endif
94

95
#if defined(BOTAN_HAS_NUMBERTHEORY)
96
   #include <botan/numthry.h>
97
   #include <botan/reducer.h>
98
   #include <botan/internal/curve_nistp.h>
99
   #include <botan/internal/primality.h>
100
#endif
101

102
#if defined(BOTAN_HAS_ECC_GROUP)
103
   #include <botan/ec_group.h>
104
#endif
105

106
#if defined(BOTAN_HAS_DL_GROUP)
107
   #include <botan/dl_group.h>
108
#endif
109

110
#if defined(BOTAN_HAS_MCELIECE)
111
   #include <botan/mceliece.h>
112
#endif
113

114
#if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S)
115
   #include <botan/kyber.h>
116
#endif
117

118
#if defined(BOTAN_HAS_DILITHIUM) || defined(BOTAN_HAS_DILITHIUM_AES)
119
   #include <botan/dilithium.h>
120
#endif
121

122
#if defined(BOTAN_HAS_SPHINCS_PLUS)
123
   #include <botan/sphincsplus.h>
124
#endif
125

126
#if defined(BOTAN_HAS_ECDSA)
127
   #include <botan/ecdsa.h>
128
#endif
129

130
#if defined(BOTAN_HAS_BCRYPT)
131
   #include <botan/bcrypt.h>
132
#endif
133

134
#if defined(BOTAN_HAS_PASSHASH9)
135
   #include <botan/passhash9.h>
136
#endif
137

138
#if defined(BOTAN_HAS_PASSWORD_HASHING)
139
   #include <botan/pwdhash.h>
140
#endif
141

142
#if defined(BOTAN_HAS_ZFEC)
143
   #include <botan/zfec.h>
144
#endif
145

146
namespace Botan_CLI {
147

148
using Botan::Timer;
149

150
namespace {
151

152
class JSON_Output final {
2✔
153
   public:
154
      void add(const Timer& timer) { m_results.push_back(timer); }
2✔
155

156
      std::string print() const {
1✔
157
         std::ostringstream out;
1✔
158

159
         out << "[\n";
1✔
160

161
         for(size_t i = 0; i != m_results.size(); ++i) {
3✔
162
            const Timer& t = m_results[i];
2✔
163

164
            out << "{"
2✔
165
                << "\"algo\": \"" << t.get_name() << "\", "
2✔
166
                << "\"op\": \"" << t.doing() << "\", "
4✔
167
                << "\"events\": " << t.events() << ", ";
6✔
168

169
            if(t.cycles_consumed() > 0) {
4✔
170
               out << "\"cycles\": " << t.cycles_consumed() << ", ";
4✔
171
            }
172

173
            if(t.buf_size() > 0) {
2✔
174
               out << "\"bps\": " << static_cast<uint64_t>(t.events() / (t.value() / 1000000000.0)) << ", ";
2✔
175
               out << "\"buf_size\": " << t.buf_size() << ", ";
2✔
176
            }
177

178
            out << "\"nanos\": " << t.value() << "}";
2✔
179

180
            if(i != m_results.size() - 1) {
2✔
181
               out << ",";
1✔
182
            }
183

184
            out << "\n";
2✔
185
         }
186
         out << "]\n";
1✔
187

188
         return out.str();
2✔
189
      }
1✔
190

191
   private:
192
      std::vector<Timer> m_results;
193
};
194

195
class Summary final {
1✔
196
   public:
197
      Summary() = default;
1✔
198

199
      void add(const Timer& t) {
2✔
200
         if(t.buf_size() == 0) {
2✔
201
            m_ops_entries.push_back(t);
×
202
         } else {
203
            m_bps_entries[std::make_pair(t.doing(), t.get_name())].push_back(t);
4✔
204
         }
205
      }
2✔
206

207
      std::string print() {
1✔
208
         const size_t name_padding = 35;
1✔
209
         const size_t op_name_padding = 16;
1✔
210
         const size_t op_padding = 16;
1✔
211

212
         std::ostringstream result_ss;
1✔
213
         result_ss << std::fixed;
1✔
214

215
         if(!m_bps_entries.empty()) {
1✔
216
            result_ss << "\n";
1✔
217

218
            // add table header
219
            result_ss << std::setw(name_padding) << std::left << "algo" << std::setw(op_name_padding) << std::left
1✔
220
                      << "operation";
1✔
221

222
            for(const Timer& t : m_bps_entries.begin()->second) {
2✔
223
               result_ss << std::setw(op_padding) << std::right << (std::to_string(t.buf_size()) + " bytes");
2✔
224
            }
225
            result_ss << "\n";
1✔
226

227
            // add table entries
228
            for(const auto& entry : m_bps_entries) {
3✔
229
               if(entry.second.empty()) {
2✔
230
                  continue;
×
231
               }
232

233
               result_ss << std::setw(name_padding) << std::left << (entry.first.second) << std::setw(op_name_padding)
2✔
234
                         << std::left << (entry.first.first);
2✔
235

236
               for(const Timer& t : entry.second) {
4✔
237
                  if(t.events() == 0) {
2✔
238
                     result_ss << std::setw(op_padding) << std::right << "N/A";
×
239
                  } else {
240
                     result_ss << std::setw(op_padding) << std::right << std::setprecision(2)
2✔
241
                               << (t.bytes_per_second() / 1000.0);
2✔
242
                  }
243
               }
244

245
               result_ss << "\n";
2✔
246
            }
247

248
            result_ss << "\n[results are the number of 1000s bytes processed per second]\n";
1✔
249
         }
250

251
         if(!m_ops_entries.empty()) {
1✔
252
            result_ss << std::setprecision(6) << "\n";
×
253

254
            // sort entries
255
            std::sort(m_ops_entries.begin(), m_ops_entries.end());
×
256

257
            // add table header
258
            result_ss << std::setw(name_padding) << std::left << "algo" << std::setw(op_name_padding) << std::left
×
259
                      << "operation" << std::setw(op_padding) << std::right << "sec/op" << std::setw(op_padding)
×
260
                      << std::right << "op/sec"
×
261
                      << "\n";
×
262

263
            // add table entries
264
            for(const Timer& entry : m_ops_entries) {
×
265
               result_ss << std::setw(name_padding) << std::left << entry.get_name() << std::setw(op_name_padding)
×
266
                         << std::left << entry.doing() << std::setw(op_padding) << std::right
×
267
                         << entry.seconds_per_event() << std::setw(op_padding) << std::right
×
268
                         << entry.events_per_second() << "\n";
×
269
            }
270
         }
271

272
         return result_ss.str();
2✔
273
      }
1✔
274

275
   private:
276
      std::map<std::pair<std::string, std::string>, std::vector<Timer>> m_bps_entries;
277
      std::vector<Timer> m_ops_entries;
278
};
279

280
std::vector<size_t> unique_buffer_sizes(const std::string& cmdline_arg) {
34✔
281
   const size_t MAX_BUF_SIZE = 64 * 1024 * 1024;
34✔
282

283
   std::set<size_t> buf;
34✔
284
   for(const std::string& size_str : Command::split_on(cmdline_arg, ',')) {
66✔
285
      size_t x = 0;
35✔
286
      try {
35✔
287
         size_t converted = 0;
35✔
288
         x = static_cast<size_t>(std::stoul(size_str, &converted, 0));
35✔
289

290
         if(converted != size_str.size()) {
34✔
291
            throw CLI_Usage_Error("Invalid integer");
×
292
         }
293
      } catch(std::exception&) {
1✔
294
         throw CLI_Usage_Error("Invalid integer value '" + size_str + "' for option buf-size");
3✔
295
      }
1✔
296

297
      if(x == 0) {
34✔
298
         throw CLI_Usage_Error("Cannot have a zero-sized buffer");
3✔
299
      }
300

301
      if(x > MAX_BUF_SIZE) {
33✔
302
         throw CLI_Usage_Error("Specified buffer size is too large");
3✔
303
      }
304

305
      buf.insert(x);
32✔
306
   }
34✔
307

308
   return std::vector<size_t>(buf.begin(), buf.end());
34✔
309
}
31✔
310

311
}  // namespace
312

313
class Speed final : public Command {
×
314
   public:
315
      Speed() :
35✔
316
            Command(
317
               "speed --msec=500 --format=default --ecc-groups= --provider= --buf-size=1024 --clear-cpuid= --cpu-clock-speed=0 --cpu-clock-ratio=1.0 *algos") {
70✔
318
      }
35✔
319

320
      static std::vector<std::string> default_benchmark_list() {
×
321
         /*
322
         This is not intended to be exhaustive: it just hits the high
323
         points of the most interesting or widely used algorithms.
324
         */
325

326
         return {/* Block ciphers */
×
327
                 "AES-128",
328
                 "AES-192",
329
                 "AES-256",
330
                 "ARIA-128",
331
                 "ARIA-192",
332
                 "ARIA-256",
333
                 "Blowfish",
334
                 "CAST-128",
335
                 "Camellia-128",
336
                 "Camellia-192",
337
                 "Camellia-256",
338
                 "DES",
339
                 "TripleDES",
340
                 "GOST-28147-89",
341
                 "IDEA",
342
                 "Noekeon",
343
                 "SHACAL2",
344
                 "SM4",
345
                 "Serpent",
346
                 "Threefish-512",
347
                 "Twofish",
348

349
                 /* Cipher modes */
350
                 "AES-128/CBC",
351
                 "AES-128/CTR-BE",
352
                 "AES-128/EAX",
353
                 "AES-128/OCB",
354
                 "AES-128/GCM",
355
                 "AES-128/XTS",
356
                 "AES-128/SIV",
357

358
                 "Serpent/CBC",
359
                 "Serpent/CTR-BE",
360
                 "Serpent/EAX",
361
                 "Serpent/OCB",
362
                 "Serpent/GCM",
363
                 "Serpent/XTS",
364
                 "Serpent/SIV",
365

366
                 "ChaCha20Poly1305",
367

368
                 /* Stream ciphers */
369
                 "RC4",
370
                 "Salsa20",
371
                 "ChaCha20",
372

373
                 /* Hashes */
374
                 "SHA-1",
375
                 "SHA-256",
376
                 "SHA-512",
377
                 "SHA-3(256)",
378
                 "SHA-3(512)",
379
                 "RIPEMD-160",
380
                 "Skein-512",
381
                 "Blake2b",
382
                 "Whirlpool",
383

384
                 /* MACs */
385
                 "CMAC(AES-128)",
386
                 "HMAC(SHA-256)",
387

388
                 /* pubkey */
389
                 "RSA",
390
                 "DH",
391
                 "ECDH",
392
                 "ECDSA",
393
                 "Ed25519",
394
                 "Curve25519",
395
                 "McEliece",
396
                 "Kyber",
397
                 "SPHINCS+"};
×
398
      }
399

400
      std::string group() const override { return "misc"; }
1✔
401

402
      std::string description() const override { return "Measures the speed of algorithms"; }
1✔
403

404
      void go() override {
34✔
405
         std::chrono::milliseconds msec(get_arg_sz("msec"));
34✔
406
         const std::string provider = get_arg("provider");
34✔
407
         std::vector<std::string> ecc_groups = Command::split_on(get_arg("ecc-groups"), ',');
71✔
408
         const std::string format = get_arg("format");
34✔
409
         const std::string clock_ratio = get_arg("cpu-clock-ratio");
37✔
410
         m_clock_speed = get_arg_sz("cpu-clock-speed");
34✔
411

412
         m_clock_cycle_ratio = std::strtod(clock_ratio.c_str(), nullptr);
34✔
413

414
         /*
415
         * This argument is intended to be the ratio between the cycle counter
416
         * and the actual machine cycles. It is extremely unlikely that there is
417
         * any machine where the cycle counter increments faster than the actual
418
         * clock.
419
         */
420
         if(m_clock_cycle_ratio < 0.0 || m_clock_cycle_ratio > 1.0) {
34✔
421
            throw CLI_Usage_Error("Unlikely CPU clock ratio of " + clock_ratio);
×
422
         }
423

424
         m_clock_cycle_ratio = 1.0 / m_clock_cycle_ratio;
34✔
425

426
         if(m_clock_speed != 0 && Botan::OS::get_cpu_cycle_counter() != 0) {
34✔
427
            error_output() << "The --cpu-clock-speed option is only intended to be used on "
×
428
                              "platforms without access to a cycle counter.\n"
429
                              "Expected incorrect results\n\n";
×
430
         }
431

432
         if(format == "table") {
34✔
433
            m_summary = std::make_unique<Summary>();
1✔
434
         } else if(format == "json") {
33✔
435
            m_json = std::make_unique<JSON_Output>();
1✔
436
         } else if(format != "default") {
32✔
437
            throw CLI_Usage_Error("Unknown --format type '" + format + "'");
×
438
         }
439

440
#if defined(BOTAN_HAS_ECC_GROUP)
441
         if(ecc_groups.empty()) {
34✔
442
            ecc_groups = {"secp256r1", "brainpool256r1", "secp384r1", "brainpool384r1", "secp521r1", "brainpool512r1"};
272✔
443
         } else if(ecc_groups.size() == 1 && ecc_groups[0] == "all") {
×
444
            auto all = Botan::EC_Group::known_named_groups();
×
445
            ecc_groups.assign(all.begin(), all.end());
×
446
         }
×
447
#endif
448

449
         std::vector<std::string> algos = get_arg_list("algos");
37✔
450

451
         const std::vector<size_t> buf_sizes = unique_buffer_sizes(get_arg("buf-size"));
68✔
452

453
         for(const std::string& cpuid_to_clear : Command::split_on(get_arg("clear-cpuid"), ',')) {
32✔
454
            auto bits = Botan::CPUID::bit_from_string(cpuid_to_clear);
1✔
455
            if(bits.empty()) {
1✔
456
               error_output() << "Warning don't know CPUID flag '" << cpuid_to_clear << "'\n";
1✔
457
            }
458

459
            for(auto bit : bits) {
1✔
460
               Botan::CPUID::clear_cpuid_bit(bit);
×
461
            }
462
         }
32✔
463

464
         if(verbose() || m_summary) {
31✔
465
            output() << Botan::version_string() << "\n"
2✔
466
                     << "CPUID: " << Botan::CPUID::to_string() << "\n\n";
3✔
467
         }
468

469
         const bool using_defaults = (algos.empty());
31✔
470
         if(using_defaults) {
31✔
471
            algos = default_benchmark_list();
×
472
         }
473

474
         for(const auto& algo : algos) {
81✔
475
            using namespace std::placeholders;
50✔
476

477
            if(false) {
50✔
478
               // Since everything might be disabled, need a block to else if from
479
            }
480
#if defined(BOTAN_HAS_HASH)
481
            else if(!Botan::HashFunction::providers(algo).empty()) {
50✔
482
               bench_providers_of<Botan::HashFunction>(
1✔
483
                  algo, provider, msec, buf_sizes, std::bind(&Speed::bench_hash, this, _1, _2, _3, _4));
2✔
484
            }
485
#endif
486
#if defined(BOTAN_HAS_BLOCK_CIPHER)
487
            else if(!Botan::BlockCipher::providers(algo).empty()) {
49✔
488
               bench_providers_of<Botan::BlockCipher>(
4✔
489
                  algo, provider, msec, buf_sizes, std::bind(&Speed::bench_block_cipher, this, _1, _2, _3, _4));
8✔
490
            }
491
#endif
492
#if defined(BOTAN_HAS_STREAM_CIPHER)
493
            else if(!Botan::StreamCipher::providers(algo).empty()) {
45✔
494
               bench_providers_of<Botan::StreamCipher>(
1✔
495
                  algo, provider, msec, buf_sizes, std::bind(&Speed::bench_stream_cipher, this, _1, _2, _3, _4));
2✔
496
            }
497
#endif
498
#if defined(BOTAN_HAS_CIPHER_MODES)
499
            else if(auto enc = Botan::Cipher_Mode::create(algo, Botan::Cipher_Dir::Encryption, provider)) {
44✔
500
               auto dec = Botan::Cipher_Mode::create_or_throw(algo, Botan::Cipher_Dir::Decryption, provider);
1✔
501
               bench_cipher_mode(*enc, *dec, msec, buf_sizes);
1✔
502
            }
1✔
503
#endif
504
#if defined(BOTAN_HAS_MAC)
505
            else if(!Botan::MessageAuthenticationCode::providers(algo).empty()) {
43✔
506
               bench_providers_of<Botan::MessageAuthenticationCode>(
1✔
507
                  algo, provider, msec, buf_sizes, std::bind(&Speed::bench_mac, this, _1, _2, _3, _4));
2✔
508
            }
509
#endif
510
#if defined(BOTAN_HAS_RSA)
511
            else if(algo == "RSA") {
42✔
512
               bench_rsa(provider, msec);
1✔
513
            } else if(algo == "RSA_keygen") {
41✔
514
               bench_rsa_keygen(provider, msec);
1✔
515
            }
516
#endif
517
#if defined(BOTAN_HAS_ECDSA)
518
            else if(algo == "ECDSA") {
40✔
519
               bench_ecdsa(ecc_groups, provider, msec);
1✔
520
            } else if(algo == "ecdsa_recovery") {
39✔
521
               bench_ecdsa_recovery(ecc_groups, provider, msec);
1✔
522
            }
523
#endif
524
#if defined(BOTAN_HAS_SM2)
525
            else if(algo == "SM2") {
38✔
526
               bench_sm2(ecc_groups, provider, msec);
1✔
527
            }
528
#endif
529
#if defined(BOTAN_HAS_ECKCDSA)
530
            else if(algo == "ECKCDSA") {
37✔
531
               bench_eckcdsa(ecc_groups, provider, msec);
1✔
532
            }
533
#endif
534
#if defined(BOTAN_HAS_GOST_34_10_2001)
535
            else if(algo == "GOST-34.10") {
36✔
536
               bench_gost_3410(provider, msec);
1✔
537
            }
538
#endif
539
#if defined(BOTAN_HAS_ECGDSA)
540
            else if(algo == "ECGDSA") {
35✔
541
               bench_ecgdsa(ecc_groups, provider, msec);
1✔
542
            }
543
#endif
544
#if defined(BOTAN_HAS_ED25519)
545
            else if(algo == "Ed25519") {
34✔
546
               bench_ed25519(provider, msec);
1✔
547
            }
548
#endif
549
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
550
            else if(algo == "DH") {
33✔
551
               bench_dh(provider, msec);
1✔
552
            }
553
#endif
554
#if defined(BOTAN_HAS_DSA)
555
            else if(algo == "DSA") {
32✔
556
               bench_dsa(provider, msec);
1✔
557
            }
558
#endif
559
#if defined(BOTAN_HAS_ELGAMAL)
560
            else if(algo == "ElGamal") {
31✔
561
               bench_elgamal(provider, msec);
1✔
562
            }
563
#endif
564
#if defined(BOTAN_HAS_ECDH)
565
            else if(algo == "ECDH") {
30✔
566
               bench_ecdh(ecc_groups, provider, msec);
1✔
567
            }
568
#endif
569
#if defined(BOTAN_HAS_CURVE_25519)
570
            else if(algo == "Curve25519") {
29✔
571
               bench_curve25519(provider, msec);
1✔
572
            }
573
#endif
574
#if defined(BOTAN_HAS_MCELIECE)
575
            else if(algo == "McEliece") {
28✔
576
               bench_mceliece(provider, msec);
1✔
577
            }
578
#endif
579
#if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S)
580
            else if(algo == "Kyber") {
27✔
581
               bench_kyber(provider, msec);
1✔
582
            }
583
#endif
584
#if defined(BOTAN_HAS_DILITHIUM) || defined(BOTAN_HAS_DILITHIUM_AES)
585
            else if(algo == "Dilithium") {
26✔
586
               bench_dilithium(provider, msec);
1✔
587
            }
588
#endif
589
#if defined(BOTAN_HAS_XMSS_RFC8391)
590
            else if(algo == "XMSS") {
25✔
591
               bench_xmss(provider, msec);
1✔
592
            }
593
#endif
594
#if defined(BOTAN_HAS_SPHINCS_PLUS)
595
            else if(algo == "SPHINCS+") {
24✔
596
               bench_sphincs_plus(provider, msec);
×
597
            }
598
#endif
599
#if defined(BOTAN_HAS_SCRYPT)
600
            else if(algo == "scrypt") {
24✔
601
               bench_scrypt(provider, msec);
1✔
602
            }
603
#endif
604
#if defined(BOTAN_HAS_ARGON2)
605
            else if(algo == "argon2") {
23✔
606
               bench_argon2(provider, msec);
1✔
607
            }
608
#endif
609
#if defined(BOTAN_HAS_BCRYPT)
610
            else if(algo == "bcrypt") {
22✔
611
               bench_bcrypt();
1✔
612
            }
613
#endif
614
#if defined(BOTAN_HAS_PASSHASH9)
615
            else if(algo == "passhash9") {
21✔
616
               bench_passhash9();
1✔
617
            }
618
#endif
619
#if defined(BOTAN_HAS_ZFEC)
620
            else if(algo == "zfec") {
20✔
621
               bench_zfec(msec);
1✔
622
            }
623
#endif
624
#if defined(BOTAN_HAS_POLY_DBL)
625
            else if(algo == "poly_dbl") {
19✔
626
               bench_poly_dbl(msec);
1✔
627
            }
628
#endif
629

630
#if defined(BOTAN_HAS_DL_GROUP)
631
            else if(algo == "modexp") {
18✔
632
               bench_modexp(msec);
1✔
633
            }
634
#endif
635

636
#if defined(BOTAN_HAS_BIGINT)
637
            else if(algo == "mp_mul") {
17✔
638
               bench_mp_mul(msec);
1✔
639
            } else if(algo == "mp_div") {
16✔
640
               bench_mp_div(msec);
1✔
641
            } else if(algo == "mp_div10") {
15✔
642
               bench_mp_div10(msec);
1✔
643
            }
644
#endif
645

646
#if defined(BOTAN_HAS_NUMBERTHEORY)
647
            else if(algo == "primality_test") {
14✔
648
               bench_primality_tests(msec);
1✔
649
            } else if(algo == "random_prime") {
13✔
650
               bench_random_prime(msec);
1✔
651
            } else if(algo == "inverse_mod") {
12✔
652
               bench_inverse_mod(msec);
1✔
653
            } else if(algo == "bn_redc") {
11✔
654
               bench_bn_redc(msec);
1✔
655
            } else if(algo == "nistp_redc") {
10✔
656
               bench_nistp_redc(msec);
1✔
657
            }
658
#endif
659

660
#if defined(BOTAN_HAS_FPE_FE1)
661
            else if(algo == "fpe_fe1") {
9✔
662
               bench_fpe_fe1(msec);
1✔
663
            }
664
#endif
665

666
#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
667
            else if(algo == "rfc3394") {
8✔
668
               bench_rfc3394(msec);
1✔
669
            }
670
#endif
671

672
#if defined(BOTAN_HAS_ECC_GROUP)
673
            else if(algo == "ecc_mult") {
7✔
674
               bench_ecc_mult(ecc_groups, msec);
1✔
675
            } else if(algo == "ecc_ops") {
6✔
676
               bench_ecc_ops(ecc_groups, msec);
1✔
677
            } else if(algo == "ecc_init") {
5✔
678
               bench_ecc_init(ecc_groups, msec);
1✔
679
            } else if(algo == "os2ecp") {
4✔
680
               bench_os2ecp(ecc_groups, msec);
1✔
681
            }
682
#endif
683
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
684
            else if(algo == "ec_h2c") {
3✔
685
               bench_ec_h2c(msec);
1✔
686
            }
687
#endif
688
            else if(algo == "RNG") {
2✔
689
#if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
690
               Botan::AutoSeeded_RNG auto_rng;
1✔
691
               bench_rng(auto_rng, "AutoSeeded_RNG (with reseed)", msec, buf_sizes);
1✔
692
#endif
693

694
#if defined(BOTAN_HAS_SYSTEM_RNG)
695
               bench_rng(Botan::system_rng(), "System_RNG", msec, buf_sizes);
1✔
696
#endif
697

698
#if defined(BOTAN_HAS_PROCESSOR_RNG)
699
               if(Botan::Processor_RNG::available()) {
1✔
700
                  Botan::Processor_RNG hwrng;
1✔
701
                  bench_rng(hwrng, "Processor_RNG", msec, buf_sizes);
2✔
702
               }
1✔
703
#endif
704

705
#if defined(BOTAN_HAS_HMAC_DRBG)
706
               for(std::string hash : {"SHA-256", "SHA-384", "SHA-512"}) {
4✔
707
                  Botan::HMAC_DRBG hmac_drbg(hash);
3✔
708
                  bench_rng(hmac_drbg, hmac_drbg.name(), msec, buf_sizes);
3✔
709
               }
3✔
710
#endif
711

712
#if defined(BOTAN_HAS_CHACHA_RNG)
713
               // Provide a dummy seed
714
               Botan::ChaCha_RNG chacha_rng(Botan::secure_vector<uint8_t>(32));
1✔
715
               bench_rng(chacha_rng, "ChaCha_RNG", msec, buf_sizes);
1✔
716
#endif
717

718
            } else if(algo == "entropy") {
2✔
719
               bench_entropy_sources(msec);
1✔
720
            } else {
721
               if(verbose() || !using_defaults) {
×
722
                  error_output() << "Unknown algorithm '" << algo << "'\n";
×
723
               }
724
            }
44✔
725
         }
726

727
         if(m_json) {
31✔
728
            output() << m_json->print();
3✔
729
         }
730
         if(m_summary) {
31✔
731
            output() << m_summary->print() << "\n";
3✔
732
         }
733

734
         if(verbose() && m_clock_speed == 0 && m_cycles_consumed > 0 && m_ns_taken > 0) {
31✔
735
            const double seconds = static_cast<double>(m_ns_taken) / 1000000000;
×
736
            const double Hz = static_cast<double>(m_cycles_consumed) / seconds;
×
737
            const double MHz = Hz / 1000000;
×
738
            output() << "\nEstimated clock speed " << MHz << " MHz\n";
×
739
         }
740
      }
40✔
741

742
   private:
743
      size_t m_clock_speed = 0;
744
      double m_clock_cycle_ratio = 0.0;
745
      uint64_t m_cycles_consumed = 0;
746
      uint64_t m_ns_taken = 0;
747
      std::unique_ptr<Summary> m_summary;
748
      std::unique_ptr<JSON_Output> m_json;
749

750
      void record_result(const std::unique_ptr<Timer>& t) {
467✔
751
         m_ns_taken += t->value();
467✔
752
         m_cycles_consumed += t->cycles_consumed();
467✔
753
         if(m_json) {
467✔
754
            m_json->add(*t);
2✔
755
         } else {
756
            output() << t->to_string() << std::flush;
465✔
757
            if(m_summary) {
465✔
758
               m_summary->add(*t);
2✔
759
            }
760
         }
761
      }
467✔
762

763
      template <typename T>
764
      using bench_fn = std::function<void(T&, std::string, std::chrono::milliseconds, const std::vector<size_t>&)>;
765

766
      template <typename T>
767
      void bench_providers_of(const std::string& algo,
7✔
768
                              const std::string& provider, /* user request, if any */
769
                              const std::chrono::milliseconds runtime,
770
                              const std::vector<size_t>& buf_sizes,
771
                              bench_fn<T> bench_one) {
772
         for(const auto& prov : T::providers(algo)) {
14✔
773
            if(provider.empty() || provider == prov) {
7✔
774
               auto p = T::create(algo, prov);
7✔
775

776
               if(p) {
7✔
777
                  bench_one(*p, prov, runtime, buf_sizes);
14✔
778
               }
779
            }
7✔
780
         }
781
      }
7✔
782

783
      std::unique_ptr<Timer> make_timer(const std::string& name,
471✔
784
                                        uint64_t event_mult = 1,
785
                                        const std::string& what = "",
786
                                        const std::string& provider = "",
787
                                        size_t buf_size = 0) {
788
         return std::make_unique<Timer>(name, provider, what, event_mult, buf_size, m_clock_cycle_ratio, m_clock_speed);
252✔
789
      }
790

791
      std::unique_ptr<Timer> make_timer(const std::string& algo, const std::string& provider, const std::string& what) {
212✔
792
         return make_timer(algo, 1, what, provider, 0);
212✔
793
      }
794

795
#if defined(BOTAN_HAS_BLOCK_CIPHER)
796
      void bench_block_cipher(Botan::BlockCipher& cipher,
4✔
797
                              const std::string& provider,
798
                              std::chrono::milliseconds runtime,
799
                              const std::vector<size_t>& buf_sizes) {
800
         auto ks_timer = make_timer(cipher.name(), provider, "key schedule");
8✔
801

802
         const Botan::SymmetricKey key(rng(), cipher.maximum_keylength());
4✔
803
         ks_timer->run([&]() { cipher.set_key(key); });
8✔
804

805
         const size_t bs = cipher.block_size();
4✔
806
         std::set<size_t> buf_sizes_in_blocks;
4✔
807
         for(size_t buf_size : buf_sizes) {
9✔
808
            if(buf_size % bs == 0) {
5✔
809
               buf_sizes_in_blocks.insert(buf_size);
10✔
810
            } else {
811
               buf_sizes_in_blocks.insert(buf_size + bs - (buf_size % bs));
×
812
            }
813
         }
814

815
         for(size_t buf_size : buf_sizes_in_blocks) {
9✔
816
            std::vector<uint8_t> buffer(buf_size);
5✔
817
            const size_t blocks = buf_size / bs;
5✔
818

819
            auto encrypt_timer = make_timer(cipher.name(), buffer.size(), "encrypt", provider, buf_size);
10✔
820
            auto decrypt_timer = make_timer(cipher.name(), buffer.size(), "decrypt", provider, buf_size);
10✔
821

822
            encrypt_timer->run_until_elapsed(runtime, [&]() { cipher.encrypt_n(&buffer[0], &buffer[0], blocks); });
2,523✔
823
            record_result(encrypt_timer);
5✔
824

825
            decrypt_timer->run_until_elapsed(runtime, [&]() { cipher.decrypt_n(&buffer[0], &buffer[0], blocks); });
2,527✔
826
            record_result(decrypt_timer);
5✔
827
         }
10✔
828
      }
8✔
829
#endif
830

831
#if defined(BOTAN_HAS_STREAM_CIPHER)
832
      void bench_stream_cipher(Botan::StreamCipher& cipher,
1✔
833
                               const std::string& provider,
834
                               const std::chrono::milliseconds runtime,
835
                               const std::vector<size_t>& buf_sizes) {
836
         for(auto buf_size : buf_sizes) {
2✔
837
            Botan::secure_vector<uint8_t> buffer = rng().random_vec(buf_size);
1✔
838

839
            auto encrypt_timer = make_timer(cipher.name(), buffer.size(), "encrypt", provider, buf_size);
2✔
840

841
            const Botan::SymmetricKey key(rng(), cipher.maximum_keylength());
1✔
842
            cipher.set_key(key);
1✔
843

844
            if(cipher.valid_iv_length(12)) {
1✔
845
               const Botan::InitializationVector iv(rng(), 12);
1✔
846
               cipher.set_iv(iv.begin(), iv.size());
1✔
847
            }
1✔
848

849
            while(encrypt_timer->under(runtime)) {
742✔
850
               encrypt_timer->run([&]() { cipher.encipher(buffer); });
1,482✔
851
            }
852

853
            record_result(encrypt_timer);
1✔
854

855
            if(verbose()) {
1✔
856
               auto ks_timer = make_timer(cipher.name(), buffer.size(), "write_keystream", provider, buf_size);
×
857

858
               while(ks_timer->under(runtime)) {
×
859
                  ks_timer->run([&]() { cipher.write_keystream(buffer.data(), buffer.size()); });
×
860
               }
861
               record_result(ks_timer);
×
862
            }
×
863
         }
2✔
864
      }
1✔
865
#endif
866

867
#if defined(BOTAN_HAS_HASH)
868
      void bench_hash(Botan::HashFunction& hash,
1✔
869
                      const std::string& provider,
870
                      const std::chrono::milliseconds runtime,
871
                      const std::vector<size_t>& buf_sizes) {
872
         std::vector<uint8_t> output(hash.output_length());
1✔
873

874
         for(auto buf_size : buf_sizes) {
2✔
875
            Botan::secure_vector<uint8_t> buffer = rng().random_vec(buf_size);
1✔
876

877
            auto timer = make_timer(hash.name(), buffer.size(), "hash", provider, buf_size);
2✔
878
            timer->run_until_elapsed(runtime, [&]() {
1✔
879
               hash.update(buffer);
128✔
880
               hash.final(output.data());
128✔
881
            });
128✔
882
            record_result(timer);
1✔
883
         }
2✔
884
      }
1✔
885
#endif
886

887
#if defined(BOTAN_HAS_MAC)
888
      void bench_mac(Botan::MessageAuthenticationCode& mac,
1✔
889
                     const std::string& provider,
890
                     const std::chrono::milliseconds runtime,
891
                     const std::vector<size_t>& buf_sizes) {
892
         std::vector<uint8_t> output(mac.output_length());
1✔
893

894
         for(auto buf_size : buf_sizes) {
2✔
895
            Botan::secure_vector<uint8_t> buffer = rng().random_vec(buf_size);
1✔
896

897
            const Botan::SymmetricKey key(rng(), mac.maximum_keylength());
1✔
898
            mac.set_key(key);
1✔
899
            mac.start(nullptr, 0);
1✔
900

901
            auto timer = make_timer(mac.name(), buffer.size(), "mac", provider, buf_size);
2✔
902
            timer->run_until_elapsed(runtime, [&]() { mac.update(buffer); });
141✔
903
            timer->run([&]() { mac.final(output.data()); });
2✔
904
            record_result(timer);
1✔
905
         }
3✔
906
      }
1✔
907
#endif
908

909
#if defined(BOTAN_HAS_CIPHER_MODES)
910
      void bench_cipher_mode(Botan::Cipher_Mode& enc,
1✔
911
                             Botan::Cipher_Mode& dec,
912
                             const std::chrono::milliseconds runtime,
913
                             const std::vector<size_t>& buf_sizes) {
914
         auto ks_timer = make_timer(enc.name(), enc.provider(), "key schedule");
2✔
915

916
         const Botan::SymmetricKey key(rng(), enc.key_spec().maximum_keylength());
1✔
917

918
         ks_timer->run([&]() { enc.set_key(key); });
2✔
919
         ks_timer->run([&]() { dec.set_key(key); });
2✔
920

921
         record_result(ks_timer);
1✔
922

923
         for(auto buf_size : buf_sizes) {
2✔
924
            Botan::secure_vector<uint8_t> buffer = rng().random_vec(buf_size);
1✔
925

926
            auto encrypt_timer = make_timer(enc.name(), buffer.size(), "encrypt", enc.provider(), buf_size);
2✔
927
            auto decrypt_timer = make_timer(dec.name(), buffer.size(), "decrypt", dec.provider(), buf_size);
2✔
928

929
            Botan::secure_vector<uint8_t> iv = rng().random_vec(enc.default_nonce_length());
1✔
930

931
            if(buf_size >= enc.minimum_final_size()) {
1✔
932
               while(encrypt_timer->under(runtime) && decrypt_timer->under(runtime)) {
86✔
933
                  // Must run in this order, or AEADs will reject the ciphertext
934
                  encrypt_timer->run([&]() {
85✔
935
                     enc.start(iv);
85✔
936
                     enc.finish(buffer);
85✔
937
                  });
85✔
938

939
                  decrypt_timer->run([&]() {
85✔
940
                     dec.start(iv);
85✔
941
                     dec.finish(buffer);
85✔
942
                  });
85✔
943

944
                  if(!iv.empty()) {
85✔
945
                     iv[iv.size() - 1] += 1;
85✔
946
                  }
947
               }
948
            }
949

950
            record_result(encrypt_timer);
1✔
951
            record_result(decrypt_timer);
1✔
952
         }
2✔
953
      }
1✔
954
#endif
955

956
      void bench_rng(Botan::RandomNumberGenerator& rng,
7✔
957
                     const std::string& rng_name,
958
                     const std::chrono::milliseconds runtime,
959
                     const std::vector<size_t>& buf_sizes) {
960
         for(auto buf_size : buf_sizes) {
14✔
961
            Botan::secure_vector<uint8_t> buffer(buf_size);
7✔
962

963
#if defined(BOTAN_HAS_SYSTEM_RNG)
964
            rng.reseed_from_rng(Botan::system_rng(), 256);
7✔
965
#endif
966

967
            auto timer = make_timer(rng_name, buffer.size(), "generate", "", buf_size);
7✔
968
            timer->run_until_elapsed(runtime, [&]() { rng.randomize(buffer.data(), buffer.size()); });
919✔
969
            record_result(timer);
7✔
970
         }
14✔
971
      }
7✔
972

973
      void bench_entropy_sources(const std::chrono::milliseconds /*unused*/) {
1✔
974
         Botan::Entropy_Sources& srcs = Botan::Entropy_Sources::global_sources();
1✔
975

976
         for(auto src : srcs.enabled_sources()) {
5✔
977
            size_t entropy_bits = 0;
4✔
978
            Botan_Tests::SeedCapturing_RNG rng;
4✔
979

980
            auto timer = make_timer(src, "", "bytes");
8✔
981
            timer->run([&]() { entropy_bits = srcs.poll_just(rng, src); });
8✔
982

983
            size_t compressed_size = 0;
4✔
984

985
#if defined(BOTAN_HAS_ZLIB)
986
            auto comp = Botan::Compression_Algorithm::create("zlib");
4✔
987

988
            if(comp) {
4✔
989
               Botan::secure_vector<uint8_t> compressed;
4✔
990
               compressed.assign(rng.seed_material().begin(), rng.seed_material().end());
4✔
991
               comp->start(9);
4✔
992
               comp->finish(compressed);
4✔
993

994
               compressed_size = compressed.size();
4✔
995
            }
4✔
996
#endif
997

998
            std::ostringstream msg;
4✔
999

1000
            msg << "Entropy source " << src << " output " << rng.seed_material().size() << " bytes"
4✔
1001
                << " estimated entropy " << entropy_bits << " in " << timer->milliseconds() << " ms";
4✔
1002

1003
            if(compressed_size > 0) {
4✔
1004
               msg << " output compressed to " << compressed_size << " bytes";
4✔
1005
            }
1006

1007
            msg << " total samples " << rng.samples() << "\n";
4✔
1008

1009
            timer->set_custom_msg(msg.str());
8✔
1010

1011
            record_result(timer);
4✔
1012
         }
13✔
1013
      }
1✔
1014

1015
#if defined(BOTAN_HAS_ECC_GROUP)
1016
      void bench_ecc_ops(const std::vector<std::string>& groups, const std::chrono::milliseconds runtime) {
1✔
1017
         for(const std::string& group_name : groups) {
7✔
1018
            const Botan::EC_Group ec_group(group_name);
6✔
1019

1020
            auto add_timer = make_timer(group_name + " add");
15✔
1021
            auto addf_timer = make_timer(group_name + " addf");
15✔
1022
            auto dbl_timer = make_timer(group_name + " dbl");
15✔
1023

1024
            const Botan::EC_Point& base_point = ec_group.get_base_point();
6✔
1025

1026
            // create a non-affine point
1027
            const auto random_k = Botan::BigInt::from_u64(0x4E6F537465707E);
6✔
1028
            Botan::EC_Point non_affine_pt = ec_group.get_base_point() * random_k;
6✔
1029
            Botan::EC_Point pt = ec_group.get_base_point();
6✔
1030

1031
            std::vector<Botan::BigInt> ws(Botan::EC_Point::WORKSPACE_SIZE);
6✔
1032

1033
            while(add_timer->under(runtime) && addf_timer->under(runtime) && dbl_timer->under(runtime)) {
826✔
1034
               dbl_timer->run([&]() { pt.mult2(ws); });
1,640✔
1035
               add_timer->run([&]() { pt.add(non_affine_pt, ws); });
1,640✔
1036
               addf_timer->run([&]() { pt.add_affine(base_point, ws); });
1,640✔
1037
            }
1038

1039
            record_result(dbl_timer);
6✔
1040
            record_result(add_timer);
6✔
1041
            record_result(addf_timer);
6✔
1042
         }
12✔
1043
      }
1✔
1044

1045
      void bench_ecc_init(const std::vector<std::string>& groups, const std::chrono::milliseconds runtime) {
1✔
1046
         for(std::string group_name : groups) {
7✔
1047
            auto timer = make_timer(group_name + " initialization");
18✔
1048

1049
            while(timer->under(runtime)) {
12✔
1050
               Botan::EC_Group::clear_registered_curve_data();
6✔
1051
               timer->run([&]() { Botan::EC_Group group(group_name); });
12✔
1052
            }
1053

1054
            record_result(timer);
6✔
1055
         }
6✔
1056
      }
1✔
1057

1058
      void bench_ecc_mult(const std::vector<std::string>& groups, const std::chrono::milliseconds runtime) {
1✔
1059
         for(const std::string& group_name : groups) {
7✔
1060
            const Botan::EC_Group ec_group(group_name);
6✔
1061

1062
            auto mult_timer = make_timer(group_name + " Montgomery ladder");
18✔
1063
            auto blinded_mult_timer = make_timer(group_name + " blinded comb");
18✔
1064
            auto blinded_var_mult_timer = make_timer(group_name + " blinded window");
18✔
1065

1066
            const Botan::EC_Point& base_point = ec_group.get_base_point();
6✔
1067

1068
            std::vector<Botan::BigInt> ws;
6✔
1069

1070
            while(mult_timer->under(runtime) && blinded_mult_timer->under(runtime) &&
12✔
1071
                  blinded_var_mult_timer->under(runtime)) {
6✔
1072
               const Botan::BigInt scalar(rng(), ec_group.get_p_bits());
6✔
1073

1074
               const Botan::EC_Point r1 = mult_timer->run([&]() { return base_point * scalar; });
18✔
1075

1076
               const Botan::EC_Point r2 =
6✔
1077
                  blinded_mult_timer->run([&]() { return ec_group.blinded_base_point_multiply(scalar, rng(), ws); });
12✔
1078

1079
               const Botan::EC_Point r3 = blinded_var_mult_timer->run(
6✔
1080
                  [&]() { return ec_group.blinded_var_point_multiply(base_point, scalar, rng(), ws); });
12✔
1081

1082
               BOTAN_ASSERT_EQUAL(r1, r2, "Same point computed by Montgomery and comb");
6✔
1083
               BOTAN_ASSERT_EQUAL(r1, r3, "Same point computed by Montgomery and window");
6✔
1084
            }
12✔
1085

1086
            record_result(mult_timer);
6✔
1087
            record_result(blinded_mult_timer);
6✔
1088
            record_result(blinded_var_mult_timer);
6✔
1089
         }
6✔
1090
      }
1✔
1091

1092
      void bench_os2ecp(const std::vector<std::string>& groups, const std::chrono::milliseconds runtime) {
1✔
1093
         for(const std::string& group_name : groups) {
7✔
1094
            auto uncmp_timer = make_timer("OS2ECP uncompressed " + group_name);
18✔
1095
            auto cmp_timer = make_timer("OS2ECP compressed " + group_name);
18✔
1096

1097
            const Botan::EC_Group ec_group(group_name);
6✔
1098

1099
            while(uncmp_timer->under(runtime) && cmp_timer->under(runtime)) {
12✔
1100
               const Botan::BigInt k(rng(), 256);
6✔
1101
               const Botan::EC_Point p = ec_group.get_base_point() * k;
6✔
1102
               const std::vector<uint8_t> os_cmp = p.encode(Botan::EC_Point_Format::Compressed);
6✔
1103
               const std::vector<uint8_t> os_uncmp = p.encode(Botan::EC_Point_Format::Uncompressed);
6✔
1104

1105
               uncmp_timer->run([&]() { ec_group.OS2ECP(os_uncmp); });
12✔
1106
               cmp_timer->run([&]() { ec_group.OS2ECP(os_cmp); });
12✔
1107
            }
18✔
1108

1109
            record_result(uncmp_timer);
6✔
1110
            record_result(cmp_timer);
6✔
1111
         }
6✔
1112
      }
1✔
1113

1114
#endif
1115

1116
#if defined(BOTAN_HAS_EC_HASH_TO_CURVE)
1117
      void bench_ec_h2c(const std::chrono::milliseconds runtime) {
1✔
1118
         for(std::string group_name : {"secp256r1", "secp384r1", "secp521r1"}) {
4✔
1119
            auto h2c_ro_timer = make_timer(group_name + "-RO", "", "hash to curve");
6✔
1120
            auto h2c_nu_timer = make_timer(group_name + "-NU", "", "hash to curve");
6✔
1121

1122
            const Botan::EC_Group group(group_name);
3✔
1123

1124
            while(h2c_ro_timer->under(runtime)) {
6✔
1125
               std::vector<uint8_t> input(32);
3✔
1126

1127
               rng().randomize(input.data(), input.size());
3✔
1128

1129
               const Botan::EC_Point p1 = h2c_ro_timer->run(
3✔
1130
                  [&]() { return group.hash_to_curve("SHA-256", input.data(), input.size(), nullptr, 0, true); });
6✔
1131

1132
               BOTAN_ASSERT_NOMSG(p1.on_the_curve());
3✔
1133

1134
               const Botan::EC_Point p2 = h2c_nu_timer->run(
3✔
1135
                  [&]() { return group.hash_to_curve("SHA-256", input.data(), input.size(), nullptr, 0, false); });
6✔
1136

1137
               BOTAN_ASSERT_NOMSG(p2.on_the_curve());
3✔
1138
            }
6✔
1139

1140
            record_result(h2c_ro_timer);
3✔
1141
            record_result(h2c_nu_timer);
3✔
1142
         }
3✔
1143
      }
1✔
1144
#endif
1145

1146
#if defined(BOTAN_HAS_FPE_FE1)
1147

1148
      void bench_fpe_fe1(const std::chrono::milliseconds runtime) {
1✔
1149
         const auto n = Botan::BigInt::from_u64(1000000000000000);
1✔
1150

1151
         auto enc_timer = make_timer("FPE_FE1 encrypt");
2✔
1152
         auto dec_timer = make_timer("FPE_FE1 decrypt");
2✔
1153

1154
         const Botan::SymmetricKey key(rng(), 32);
1✔
1155
         const std::vector<uint8_t> tweak(8);  // 8 zeros
1✔
1156

1157
         auto x = Botan::BigInt::one();
1✔
1158

1159
         Botan::FPE_FE1 fpe_fe1(n);
1✔
1160
         fpe_fe1.set_key(key);
1✔
1161

1162
         while(enc_timer->under(runtime)) {
3✔
1163
            enc_timer->start();
2✔
1164
            x = fpe_fe1.encrypt(x, tweak.data(), tweak.size());
2✔
1165
            enc_timer->stop();
2✔
1166
         }
1167

1168
         for(size_t i = 0; i != enc_timer->events(); ++i) {
3✔
1169
            dec_timer->start();
2✔
1170
            x = fpe_fe1.decrypt(x, tweak.data(), tweak.size());
2✔
1171
            dec_timer->stop();
2✔
1172
         }
1173

1174
         BOTAN_ASSERT(x == 1, "FPE works");
1✔
1175

1176
         record_result(enc_timer);
1✔
1177
         record_result(dec_timer);
1✔
1178
      }
5✔
1179
#endif
1180

1181
#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
1182

1183
      void bench_rfc3394(const std::chrono::milliseconds runtime) {
1✔
1184
         auto wrap_timer = make_timer("RFC3394 AES-256 key wrap");
3✔
1185
         auto unwrap_timer = make_timer("RFC3394 AES-256 key unwrap");
3✔
1186

1187
         const Botan::SymmetricKey kek(rng(), 32);
1✔
1188
         Botan::secure_vector<uint8_t> key(64, 0);
1✔
1189

1190
         while(wrap_timer->under(runtime)) {
38✔
1191
            wrap_timer->start();
37✔
1192
            key = Botan::rfc3394_keywrap(key, kek);
74✔
1193
            wrap_timer->stop();
37✔
1194

1195
            unwrap_timer->start();
37✔
1196
            key = Botan::rfc3394_keyunwrap(key, kek);
74✔
1197
            unwrap_timer->stop();
37✔
1198

1199
            key[0] += 1;
37✔
1200
         }
1201

1202
         record_result(wrap_timer);
1✔
1203
         record_result(unwrap_timer);
1✔
1204
      }
2✔
1205
#endif
1206

1207
#if defined(BOTAN_HAS_BIGINT)
1208

1209
      void bench_mp_mul(const std::chrono::milliseconds runtime) {
1✔
1210
         std::chrono::milliseconds runtime_per_size = runtime;
1✔
1211
         for(size_t bits : {256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096}) {
10✔
1212
            auto mul_timer = make_timer("BigInt mul " + std::to_string(bits));
18✔
1213
            auto sqr_timer = make_timer("BigInt sqr " + std::to_string(bits));
18✔
1214

1215
            const Botan::BigInt y(rng(), bits);
9✔
1216
            Botan::secure_vector<Botan::word> ws;
9✔
1217

1218
            while(mul_timer->under(runtime_per_size)) {
4,470✔
1219
               Botan::BigInt x(rng(), bits);
4,461✔
1220

1221
               sqr_timer->start();
4,461✔
1222
               x.square(ws);
4,461✔
1223
               sqr_timer->stop();
4,461✔
1224

1225
               x.mask_bits(bits);
4,461✔
1226

1227
               mul_timer->start();
4,461✔
1228
               x.mul(y, ws);
4,461✔
1229
               mul_timer->stop();
4,461✔
1230
            }
4,461✔
1231

1232
            record_result(mul_timer);
9✔
1233
            record_result(sqr_timer);
9✔
1234
         }
18✔
1235
      }
1✔
1236

1237
      void bench_mp_div(const std::chrono::milliseconds runtime) {
1✔
1238
         std::chrono::milliseconds runtime_per_size = runtime;
1✔
1239

1240
         for(size_t n_bits : {256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096}) {
10✔
1241
            const size_t q_bits = n_bits / 2;
9✔
1242
            const std::string bit_descr = std::to_string(n_bits) + "/" + std::to_string(q_bits);
18✔
1243

1244
            auto div_timer = make_timer("BigInt div " + bit_descr);
27✔
1245
            auto ct_div_timer = make_timer("BigInt ct_div " + bit_descr);
27✔
1246

1247
            Botan::BigInt y;
9✔
1248
            Botan::BigInt x;
9✔
1249
            Botan::secure_vector<Botan::word> ws;
9✔
1250

1251
            Botan::BigInt q1, r1, q2, r2;
9✔
1252

1253
            while(ct_div_timer->under(runtime_per_size)) {
46✔
1254
               x.randomize(rng(), n_bits);
37✔
1255
               y.randomize(rng(), q_bits);
37✔
1256

1257
               div_timer->start();
37✔
1258
               Botan::vartime_divide(x, y, q1, r1);
37✔
1259
               div_timer->stop();
37✔
1260

1261
               ct_div_timer->start();
37✔
1262
               Botan::ct_divide(x, y, q2, r2);
37✔
1263
               ct_div_timer->stop();
37✔
1264

1265
               BOTAN_ASSERT_EQUAL(q1, q2, "Quotient ok");
37✔
1266
               BOTAN_ASSERT_EQUAL(r1, r2, "Remainder ok");
83✔
1267
            }
1268

1269
            record_result(div_timer);
9✔
1270
            record_result(ct_div_timer);
9✔
1271
         }
54✔
1272
      }
1✔
1273

1274
      void bench_mp_div10(const std::chrono::milliseconds runtime) {
1✔
1275
         std::chrono::milliseconds runtime_per_size = runtime;
1✔
1276

1277
         for(size_t n_bits : {256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096}) {
10✔
1278
            const std::string bit_descr = std::to_string(n_bits) + "/10";
9✔
1279

1280
            auto div_timer = make_timer("BigInt div " + bit_descr);
27✔
1281
            auto ct_div_timer = make_timer("BigInt ct_div " + bit_descr);
27✔
1282

1283
            Botan::BigInt x;
9✔
1284
            Botan::secure_vector<Botan::word> ws;
9✔
1285

1286
            const auto ten = Botan::BigInt::from_word(10);
9✔
1287
            Botan::BigInt q1, r1, q2;
9✔
1288
            Botan::word r2;
1289

1290
            while(ct_div_timer->under(runtime_per_size)) {
258✔
1291
               x.randomize(rng(), n_bits);
249✔
1292

1293
               div_timer->start();
249✔
1294
               Botan::vartime_divide(x, ten, q1, r1);
249✔
1295
               div_timer->stop();
249✔
1296

1297
               ct_div_timer->start();
249✔
1298
               Botan::ct_divide_word(x, 10, q2, r2);
249✔
1299
               ct_div_timer->stop();
249✔
1300

1301
               BOTAN_ASSERT_EQUAL(q1, q2, "Quotient ok");
249✔
1302
               BOTAN_ASSERT_EQUAL(r1, r2, "Remainder ok");
507✔
1303
            }
1304

1305
            record_result(div_timer);
9✔
1306
            record_result(ct_div_timer);
9✔
1307
         }
45✔
1308
      }
1✔
1309

1310
#endif
1311

1312
#if defined(BOTAN_HAS_DL_GROUP)
1313

1314
      void bench_modexp(const std::chrono::milliseconds runtime) {
1✔
1315
         for(size_t group_bits : {1024, 1536, 2048, 3072, 4096}) {
6✔
1316
            const std::string group_bits_str = std::to_string(group_bits);
5✔
1317
            const Botan::DL_Group group("modp/srp/" + group_bits_str);
5✔
1318

1319
            const size_t e_bits = Botan::dl_exponent_size(group_bits);
5✔
1320
            const size_t f_bits = group_bits - 1;
5✔
1321

1322
            const Botan::BigInt random_e(rng(), e_bits);
5✔
1323
            const Botan::BigInt random_f(rng(), f_bits);
5✔
1324

1325
            auto e_timer = make_timer(group_bits_str + " short exponent");
15✔
1326
            auto f_timer = make_timer(group_bits_str + "  full exponent");
15✔
1327

1328
            while(f_timer->under(runtime)) {
10✔
1329
               e_timer->run([&]() { group.power_g_p(random_e); });
10✔
1330
               f_timer->run([&]() { group.power_g_p(random_f); });
10✔
1331
            }
1332

1333
            record_result(e_timer);
5✔
1334
            record_result(f_timer);
5✔
1335
         }
20✔
1336
      }
1✔
1337
#endif
1338

1339
#if defined(BOTAN_HAS_NUMBERTHEORY)
1340
      void bench_nistp_redc(const std::chrono::milliseconds runtime) {
1✔
1341
         Botan::secure_vector<Botan::word> ws;
1✔
1342

1343
         auto p192_timer = make_timer("P-192 redc");
2✔
1344
         Botan::BigInt r192(rng(), 192 * 2 - 1);
1✔
1345
         while(p192_timer->under(runtime)) {
2,700✔
1346
            Botan::BigInt r = r192;
2,699✔
1347
            p192_timer->run([&]() { Botan::redc_p192(r, ws); });
5,398✔
1348
            r192 += 1;
2,699✔
1349
         }
2,699✔
1350
         record_result(p192_timer);
1✔
1351

1352
         auto p224_timer = make_timer("P-224 redc");
2✔
1353
         Botan::BigInt r224(rng(), 224 * 2 - 1);
1✔
1354
         while(p224_timer->under(runtime)) {
2,276✔
1355
            Botan::BigInt r = r224;
2,275✔
1356
            p224_timer->run([&]() { Botan::redc_p224(r, ws); });
4,550✔
1357
            r224 += 1;
2,275✔
1358
         }
2,275✔
1359
         record_result(p224_timer);
1✔
1360

1361
         auto p256_timer = make_timer("P-256 redc");
2✔
1362
         Botan::BigInt r256(rng(), 256 * 2 - 1);
1✔
1363
         while(p256_timer->under(runtime)) {
2,622✔
1364
            Botan::BigInt r = r256;
2,621✔
1365
            p256_timer->run([&]() { Botan::redc_p256(r, ws); });
5,242✔
1366
            r256 += 1;
2,621✔
1367
         }
2,621✔
1368
         record_result(p256_timer);
1✔
1369

1370
         auto p384_timer = make_timer("P-384 redc");
2✔
1371
         Botan::BigInt r384(rng(), 384 * 2 - 1);
1✔
1372
         while(p384_timer->under(runtime)) {
2,382✔
1373
            Botan::BigInt r = r384;
2,381✔
1374
            p384_timer->run([&]() { Botan::redc_p384(r384, ws); });
4,762✔
1375
            r384 += 1;
2,381✔
1376
         }
2,381✔
1377
         record_result(p384_timer);
1✔
1378

1379
         auto p521_timer = make_timer("P-521 redc");
2✔
1380
         Botan::BigInt r521(rng(), 521 * 2 - 1);
1✔
1381
         while(p521_timer->under(runtime)) {
1,610✔
1382
            Botan::BigInt r = r521;
1,609✔
1383
            p521_timer->run([&]() { Botan::redc_p521(r521, ws); });
3,218✔
1384
            r521 += 1;
1,609✔
1385
         }
1,609✔
1386
         record_result(p521_timer);
1✔
1387
      }
6✔
1388

1389
      void bench_bn_redc(const std::chrono::milliseconds runtime) {
1✔
1390
         for(size_t bitsize : {512, 1024, 2048, 4096}) {
5✔
1391
            Botan::BigInt p(rng(), bitsize);
4✔
1392

1393
            std::string bit_str = std::to_string(bitsize);
4✔
1394
            auto barrett_timer = make_timer("Barrett-" + bit_str);
8✔
1395
            auto schoolbook_timer = make_timer("Schoolbook-" + bit_str);
8✔
1396

1397
            Botan::Modular_Reducer mod_p(p);
4✔
1398

1399
            while(schoolbook_timer->under(runtime)) {
53✔
1400
               const Botan::BigInt x(rng(), p.bits() * 2 - 2);
49✔
1401

1402
               const Botan::BigInt r1 = barrett_timer->run([&] { return mod_p.reduce(x); });
98✔
1403
               const Botan::BigInt r2 = schoolbook_timer->run([&] { return x % p; });
98✔
1404

1405
               BOTAN_ASSERT(r1 == r2, "Computed different results");
49✔
1406
            }
147✔
1407

1408
            record_result(barrett_timer);
4✔
1409
            record_result(schoolbook_timer);
4✔
1410
         }
8✔
1411
      }
1✔
1412

1413
      void bench_inverse_mod(const std::chrono::milliseconds runtime) {
1✔
1414
         for(size_t bits : {256, 384, 512, 1024, 2048}) {
6✔
1415
            const std::string bit_str = std::to_string(bits);
5✔
1416

1417
            auto timer = make_timer("inverse_mod-" + bit_str);
12✔
1418
            auto gcd_timer = make_timer("gcd-" + bit_str);
10✔
1419

1420
            while(timer->under(runtime) && gcd_timer->under(runtime)) {
11✔
1421
               const Botan::BigInt x(rng(), bits - 1);
6✔
1422
               Botan::BigInt mod(rng(), bits);
6✔
1423

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

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

1428
               if(x_inv == 0) {
6✔
1429
                  BOTAN_ASSERT(g != 1, "Inversion only fails if gcd(x, mod) > 1");
1✔
1430
               } else {
1431
                  BOTAN_ASSERT(g == 1, "Inversion succeeds only if gcd != 1");
5✔
1432
                  const Botan::BigInt check = (x_inv * x) % mod;
5✔
1433
                  BOTAN_ASSERT_EQUAL(check, 1, "Const time inversion correct");
5✔
1434
               }
5✔
1435
            }
24✔
1436

1437
            record_result(timer);
5✔
1438
            record_result(gcd_timer);
5✔
1439
         }
5✔
1440
      }
1✔
1441

1442
      void bench_primality_tests(const std::chrono::milliseconds runtime) {
1✔
1443
         for(size_t bits : {256, 512, 1024}) {
4✔
1444
            auto mr_timer = make_timer("Miller-Rabin-" + std::to_string(bits));
9✔
1445
            auto bpsw_timer = make_timer("Bailie-PSW-" + std::to_string(bits));
6✔
1446
            auto lucas_timer = make_timer("Lucas-" + std::to_string(bits));
6✔
1447

1448
            Botan::BigInt n = Botan::random_prime(rng(), bits);
3✔
1449

1450
            while(lucas_timer->under(runtime)) {
6✔
1451
               Botan::Modular_Reducer mod_n(n);
3✔
1452

1453
               mr_timer->run([&]() { return Botan::is_miller_rabin_probable_prime(n, mod_n, rng(), 2); });
6✔
1454

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

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

1459
               n += 2;
3✔
1460
            }
3✔
1461

1462
            record_result(mr_timer);
3✔
1463
            record_result(bpsw_timer);
3✔
1464
            record_result(lucas_timer);
3✔
1465
         }
3✔
1466
      }
1✔
1467

1468
      void bench_random_prime(const std::chrono::milliseconds runtime) {
1✔
1469
         const auto coprime = Botan::BigInt::from_word(0x10001);
1✔
1470

1471
         for(size_t bits : {256, 384, 512, 768, 1024, 1536}) {
7✔
1472
            auto genprime_timer = make_timer("random_prime " + std::to_string(bits));
18✔
1473
            auto gensafe_timer = make_timer("random_safe_prime " + std::to_string(bits));
18✔
1474
            auto is_prime_timer = make_timer("is_prime " + std::to_string(bits));
12✔
1475

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

1479
               if(!is_prime_timer->run([&] { return Botan::is_prime(p, rng(), 64, true); })) {
12✔
1480
                  error_output() << "Generated prime " << p << " which failed a primality test";
×
1481
               }
1482

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

1485
               if(!is_prime_timer->run([&] { return Botan::is_prime(sg, rng(), 64, true); })) {
12✔
1486
                  error_output() << "Generated safe prime " << sg << " which failed a primality test";
×
1487
               }
1488

1489
               if(!is_prime_timer->run([&] { return Botan::is_prime(sg / 2, rng(), 64, true); })) {
18✔
1490
                  error_output() << "Generated prime " << sg / 2 << " which failed a primality test";
×
1491
               }
1492

1493
               // Now test p+2, p+4, ... which may or may not be prime
1494
               for(size_t i = 2; i <= 64; i += 2) {
198✔
1495
                  is_prime_timer->run([&]() { Botan::is_prime(p + i, rng(), 64, true); });
576✔
1496
               }
1497
            }
12✔
1498

1499
            record_result(genprime_timer);
6✔
1500
            record_result(gensafe_timer);
6✔
1501
            record_result(is_prime_timer);
6✔
1502
         }
6✔
1503
      }
1✔
1504
#endif
1505

1506
#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
1507
      void bench_pk_enc(const Botan::Private_Key& key,
4✔
1508
                        const std::string& nm,
1509
                        const std::string& provider,
1510
                        const std::string& padding,
1511
                        std::chrono::milliseconds msec) {
1512
         std::vector<uint8_t> plaintext, ciphertext;
4✔
1513

1514
         Botan::PK_Encryptor_EME enc(key, rng(), padding, provider);
4✔
1515
         Botan::PK_Decryptor_EME dec(key, rng(), padding, provider);
4✔
1516

1517
         auto enc_timer = make_timer(nm + " " + padding, provider, "encrypt");
12✔
1518
         auto dec_timer = make_timer(nm + " " + padding, provider, "decrypt");
12✔
1519

1520
         while(enc_timer->under(msec) || dec_timer->under(msec)) {
12✔
1521
            // Generate a new random ciphertext to decrypt
1522
            if(ciphertext.empty() || enc_timer->under(msec)) {
4✔
1523
               rng().random_vec(plaintext, enc.maximum_input_size());
4✔
1524
               ciphertext = enc_timer->run([&]() { return enc.encrypt(plaintext, rng()); });
12✔
1525
            }
1526

1527
            if(dec_timer->under(msec)) {
4✔
1528
               const auto dec_pt = dec_timer->run([&]() { return dec.decrypt(ciphertext); });
12✔
1529

1530
               if(!(Botan::unlock(dec_pt) == plaintext))  // sanity check
8✔
1531
               {
1532
                  error_output() << "Bad roundtrip in PK encrypt/decrypt bench\n";
×
1533
               }
1534
            }
4✔
1535
         }
1536

1537
         record_result(enc_timer);
4✔
1538
         record_result(dec_timer);
4✔
1539
      }
12✔
1540

1541
      void bench_pk_ka(const std::string& algo,
14✔
1542
                       const std::string& nm,
1543
                       const std::string& params,
1544
                       const std::string& provider,
1545
                       std::chrono::milliseconds msec) {
1546
         const std::string kdf = "KDF2(SHA-256)";  // arbitrary choice
14✔
1547

1548
         auto keygen_timer = make_timer(nm, provider, "keygen");
28✔
1549

1550
         std::unique_ptr<Botan::Private_Key> key1(
14✔
1551
            keygen_timer->run([&] { return Botan::create_private_key(algo, rng(), params); }));
28✔
1552
         std::unique_ptr<Botan::Private_Key> key2(
14✔
1553
            keygen_timer->run([&] { return Botan::create_private_key(algo, rng(), params); }));
28✔
1554

1555
         record_result(keygen_timer);
14✔
1556

1557
         const Botan::PK_Key_Agreement_Key& ka_key1 = dynamic_cast<const Botan::PK_Key_Agreement_Key&>(*key1);
14✔
1558
         const Botan::PK_Key_Agreement_Key& ka_key2 = dynamic_cast<const Botan::PK_Key_Agreement_Key&>(*key2);
14✔
1559

1560
         Botan::PK_Key_Agreement ka1(ka_key1, rng(), kdf, provider);
14✔
1561
         Botan::PK_Key_Agreement ka2(ka_key2, rng(), kdf, provider);
14✔
1562

1563
         const std::vector<uint8_t> ka1_pub = ka_key1.public_value();
14✔
1564
         const std::vector<uint8_t> ka2_pub = ka_key2.public_value();
14✔
1565

1566
         auto ka_timer = make_timer(nm, provider, "key agreements");
28✔
1567

1568
         while(ka_timer->under(msec)) {
32✔
1569
            Botan::SymmetricKey symkey1 = ka_timer->run([&]() { return ka1.derive_key(32, ka2_pub); });
36✔
1570
            Botan::SymmetricKey symkey2 = ka_timer->run([&]() { return ka2.derive_key(32, ka1_pub); });
36✔
1571

1572
            if(symkey1 != symkey2) {
18✔
1573
               error_output() << "Key agreement mismatch in PK bench\n";
×
1574
            }
1575
         }
36✔
1576

1577
         record_result(ka_timer);
14✔
1578
      }
70✔
1579

1580
      void bench_pk_kem(const Botan::Private_Key& key,
11✔
1581
                        const std::string& nm,
1582
                        const std::string& provider,
1583
                        const std::string& kdf,
1584
                        std::chrono::milliseconds msec) {
1585
         Botan::PK_KEM_Decryptor dec(key, rng(), kdf, provider);
11✔
1586
         Botan::PK_KEM_Encryptor enc(key, kdf, provider);
11✔
1587

1588
         auto kem_enc_timer = make_timer(nm, provider, "KEM encrypt");
22✔
1589
         auto kem_dec_timer = make_timer(nm, provider, "KEM decrypt");
22✔
1590

1591
         while(kem_enc_timer->under(msec) && kem_dec_timer->under(msec)) {
35✔
1592
            Botan::secure_vector<uint8_t> encap_key, enc_shared_key;
24✔
1593
            Botan::secure_vector<uint8_t> salt = rng().random_vec(16);
24✔
1594

1595
            kem_enc_timer->start();
24✔
1596
            enc.encrypt(encap_key, enc_shared_key, 64, rng(), salt);
24✔
1597
            kem_enc_timer->stop();
24✔
1598

1599
            kem_dec_timer->start();
24✔
1600
            Botan::secure_vector<uint8_t> dec_shared_key = dec.decrypt(encap_key, 64, salt);
24✔
1601
            kem_dec_timer->stop();
24✔
1602

1603
            if(enc_shared_key != dec_shared_key) {
24✔
1604
               error_output() << "KEM mismatch in PK bench\n";
×
1605
            }
1606
         }
96✔
1607

1608
         record_result(kem_enc_timer);
11✔
1609
         record_result(kem_dec_timer);
11✔
1610
      }
11✔
1611

1612
      void bench_pk_sig_ecc(const std::string& algo,
6✔
1613
                            const std::string& emsa,
1614
                            const std::string& provider,
1615
                            const std::vector<std::string>& params,
1616
                            std::chrono::milliseconds msec) {
1617
         for(std::string grp : params) {
32✔
1618
            const std::string nm = grp.empty() ? algo : (algo + "-" + grp);
26✔
1619

1620
            auto keygen_timer = make_timer(nm, provider, "keygen");
52✔
1621

1622
            std::unique_ptr<Botan::Private_Key> key(
26✔
1623
               keygen_timer->run([&] { return Botan::create_private_key(algo, rng(), grp); }));
52✔
1624

1625
            record_result(keygen_timer);
26✔
1626
            bench_pk_sig(*key, nm, provider, emsa, msec);
26✔
1627
         }
48✔
1628
      }
6✔
1629

1630
      size_t bench_pk_sig(const Botan::Private_Key& key,
40✔
1631
                          const std::string& nm,
1632
                          const std::string& provider,
1633
                          const std::string& padding,
1634
                          std::chrono::milliseconds msec) {
1635
         std::vector<uint8_t> message, signature, bad_signature;
40✔
1636

1637
         Botan::PK_Signer sig(key, rng(), padding, Botan::Signature_Format::Standard, provider);
40✔
1638
         Botan::PK_Verifier ver(key, padding, Botan::Signature_Format::Standard, provider);
40✔
1639

1640
         auto sig_timer = make_timer(nm + " " + padding, provider, "sign");
119✔
1641
         auto ver_timer = make_timer(nm + " " + padding, provider, "verify");
119✔
1642

1643
         size_t invalid_sigs = 0;
40✔
1644

1645
         while(ver_timer->under(msec) || sig_timer->under(msec)) {
168✔
1646
            if(signature.empty() || sig_timer->under(msec)) {
88✔
1647
               /*
1648
               Length here is kind of arbitrary, but 48 bytes fits into a single
1649
               hash block so minimizes hashing overhead versus the PK op itself.
1650
               */
1651
               rng().random_vec(message, 48);
55✔
1652

1653
               signature = sig_timer->run([&]() { return sig.sign_message(message, rng()); });
165✔
1654

1655
               bad_signature = signature;
55✔
1656
               bad_signature[rng().next_byte() % bad_signature.size()] ^= rng().next_nonzero_byte();
55✔
1657
            }
1658

1659
            if(ver_timer->under(msec)) {
88✔
1660
               const bool verified = ver_timer->run([&] { return ver.verify_message(message, signature); });
150✔
1661

1662
               if(!verified) {
75✔
1663
                  invalid_sigs += 1;
×
1664
               }
1665

1666
               const bool verified_bad = ver_timer->run([&] { return ver.verify_message(message, bad_signature); });
150✔
1667

1668
               if(verified_bad) {
75✔
1669
                  error_output() << "Bad signature accepted in " << nm << " signature bench\n";
×
1670
               }
1671
            }
1672
         }
1673

1674
         if(invalid_sigs > 0) {
40✔
1675
            error_output() << invalid_sigs << " generated signatures rejected in " << nm << " signature bench\n";
×
1676
         }
1677

1678
         const size_t events = static_cast<size_t>(std::min(sig_timer->events(), ver_timer->events()));
40✔
1679

1680
         record_result(sig_timer);
40✔
1681
         record_result(ver_timer);
40✔
1682

1683
         return events;
80✔
1684
      }
160✔
1685
#endif
1686

1687
#if defined(BOTAN_HAS_RSA)
1688
      void bench_rsa_keygen(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1689
         for(size_t keylen : {1024, 2048, 3072, 4096}) {
5✔
1690
            const std::string nm = "RSA-" + std::to_string(keylen);
4✔
1691
            auto keygen_timer = make_timer(nm, provider, "keygen");
8✔
1692

1693
            while(keygen_timer->under(msec)) {
8✔
1694
               std::unique_ptr<Botan::Private_Key> key(
4✔
1695
                  keygen_timer->run([&] { return Botan::create_private_key("RSA", rng(), std::to_string(keylen)); }));
8✔
1696

1697
               BOTAN_ASSERT(key->check_key(rng(), true), "Key is ok");
4✔
1698
            }
4✔
1699

1700
            record_result(keygen_timer);
4✔
1701
         }
4✔
1702
      }
1✔
1703

1704
      void bench_rsa(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1705
         for(size_t keylen : {1024, 2048, 3072, 4096}) {
5✔
1706
            const std::string nm = "RSA-" + std::to_string(keylen);
4✔
1707

1708
            auto keygen_timer = make_timer(nm, provider, "keygen");
8✔
1709

1710
            std::unique_ptr<Botan::Private_Key> key(
4✔
1711
               keygen_timer->run([&] { return Botan::create_private_key("RSA", rng(), std::to_string(keylen)); }));
8✔
1712

1713
            record_result(keygen_timer);
4✔
1714

1715
            // Using PKCS #1 padding so OpenSSL provider can play along
1716
            bench_pk_sig(*key, nm, provider, "EMSA-PKCS1-v1_5(SHA-256)", msec);
8✔
1717

1718
            //bench_pk_sig(*key, nm, provider, "PSSR(SHA-256)", msec);
1719
            //bench_pk_enc(*key, nm, provider, "EME-PKCS1-v1_5", msec);
1720
            //bench_pk_enc(*key, nm, provider, "OAEP(SHA-1)", msec);
1721
         }
4✔
1722
      }
1✔
1723
#endif
1724

1725
#if defined(BOTAN_HAS_ECDSA)
1726
      void bench_ecdsa(const std::vector<std::string>& groups,
1✔
1727
                       const std::string& provider,
1728
                       std::chrono::milliseconds msec) {
1729
         return bench_pk_sig_ecc("ECDSA", "SHA-256", provider, groups, msec);
2✔
1730
      }
1731

1732
      void bench_ecdsa_recovery(const std::vector<std::string>& groups,
1✔
1733
                                const std::string& /*unused*/,
1734
                                std::chrono::milliseconds msec) {
1735
         for(const std::string& group_name : groups) {
7✔
1736
            Botan::EC_Group group(group_name);
6✔
1737
            auto recovery_timer = make_timer("ECDSA recovery " + group_name);
18✔
1738

1739
            while(recovery_timer->under(msec)) {
12✔
1740
               Botan::ECDSA_PrivateKey key(rng(), group);
6✔
1741

1742
               std::vector<uint8_t> message(group.get_order_bits() / 8);
6✔
1743
               rng().randomize(message.data(), message.size());
6✔
1744

1745
               Botan::PK_Signer signer(key, rng(), "Raw");
6✔
1746
               signer.update(message);
6✔
1747
               std::vector<uint8_t> signature = signer.signature(rng());
6✔
1748

1749
               Botan::PK_Verifier verifier(key, "Raw", Botan::Signature_Format::Standard, "base");
6✔
1750
               verifier.update(message);
6✔
1751
               BOTAN_ASSERT(verifier.check_signature(signature), "Valid signature");
6✔
1752

1753
               Botan::BigInt r(signature.data(), signature.size() / 2);
6✔
1754
               Botan::BigInt s(signature.data() + signature.size() / 2, signature.size() / 2);
6✔
1755

1756
               const uint8_t v = key.recovery_param(message, r, s);
6✔
1757

1758
               recovery_timer->run([&]() {
6✔
1759
                  Botan::ECDSA_PublicKey pubkey(group, message, r, s, v);
6✔
1760
                  BOTAN_ASSERT(pubkey.public_point() == key.public_point(), "Recovered public key");
6✔
1761
               });
6✔
1762
            }
24✔
1763

1764
            record_result(recovery_timer);
6✔
1765
         }
6✔
1766
      }
1✔
1767

1768
#endif
1769

1770
#if defined(BOTAN_HAS_ECKCDSA)
1771
      void bench_eckcdsa(const std::vector<std::string>& groups,
1✔
1772
                         const std::string& provider,
1773
                         std::chrono::milliseconds msec) {
1774
         return bench_pk_sig_ecc("ECKCDSA", "SHA-256", provider, groups, msec);
2✔
1775
      }
1776
#endif
1777

1778
#if defined(BOTAN_HAS_GOST_34_10_2001)
1779
      void bench_gost_3410(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1780
         return bench_pk_sig_ecc("GOST-34.10", "GOST-34.11", provider, {"gost_256A"}, msec);
3✔
1781
      }
1782
#endif
1783

1784
#if defined(BOTAN_HAS_SM2)
1785
      void bench_sm2(const std::vector<std::string>& groups,
1✔
1786
                     const std::string& provider,
1787
                     std::chrono::milliseconds msec) {
1788
         return bench_pk_sig_ecc("SM2_Sig", "SM3", provider, groups, msec);
2✔
1789
      }
1790
#endif
1791

1792
#if defined(BOTAN_HAS_ECGDSA)
1793
      void bench_ecgdsa(const std::vector<std::string>& groups,
1✔
1794
                        const std::string& provider,
1795
                        std::chrono::milliseconds msec) {
1796
         return bench_pk_sig_ecc("ECGDSA", "SHA-256", provider, groups, msec);
2✔
1797
      }
1798
#endif
1799

1800
#if defined(BOTAN_HAS_ED25519)
1801
      void bench_ed25519(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1802
         return bench_pk_sig_ecc("Ed25519", "Pure", provider, std::vector<std::string>{""}, msec);
3✔
1803
      }
1804
#endif
1805

1806
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
1807
      void bench_dh(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1808
         for(size_t bits : {1024, 1536, 2048, 3072, 4096, 6144, 8192}) {
8✔
1809
            bench_pk_ka("DH", "DH-" + std::to_string(bits), "modp/ietf/" + std::to_string(bits), provider, msec);
14✔
1810
         }
1811
      }
1✔
1812
#endif
1813

1814
#if defined(BOTAN_HAS_DSA)
1815
      void bench_dsa(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1816
         for(size_t bits : {1024, 2048, 3072}) {
4✔
1817
            const std::string nm = "DSA-" + std::to_string(bits);
3✔
1818

1819
            const std::string params = (bits == 1024) ? "dsa/jce/1024" : ("dsa/botan/" + std::to_string(bits));
3✔
1820

1821
            auto keygen_timer = make_timer(nm, provider, "keygen");
6✔
1822

1823
            std::unique_ptr<Botan::Private_Key> key(
3✔
1824
               keygen_timer->run([&] { return Botan::create_private_key("DSA", rng(), params); }));
6✔
1825

1826
            record_result(keygen_timer);
3✔
1827

1828
            bench_pk_sig(*key, nm, provider, "SHA-256", msec);
6✔
1829
         }
3✔
1830
      }
1✔
1831
#endif
1832

1833
#if defined(BOTAN_HAS_ELGAMAL)
1834
      void bench_elgamal(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1835
         for(size_t keylen : {1024, 2048, 3072, 4096}) {
5✔
1836
            const std::string nm = "ElGamal-" + std::to_string(keylen);
4✔
1837

1838
            const std::string params = "modp/ietf/" + std::to_string(keylen);
4✔
1839

1840
            auto keygen_timer = make_timer(nm, provider, "keygen");
8✔
1841

1842
            std::unique_ptr<Botan::Private_Key> key(
4✔
1843
               keygen_timer->run([&] { return Botan::create_private_key("ElGamal", rng(), params); }));
8✔
1844

1845
            record_result(keygen_timer);
4✔
1846

1847
            bench_pk_enc(*key, nm, provider, "EME-PKCS1-v1_5", msec);
8✔
1848
         }
4✔
1849
      }
1✔
1850
#endif
1851

1852
#if defined(BOTAN_HAS_ECDH)
1853
      void bench_ecdh(const std::vector<std::string>& groups,
1✔
1854
                      const std::string& provider,
1855
                      std::chrono::milliseconds msec) {
1856
         for(const std::string& grp : groups) {
7✔
1857
            bench_pk_ka("ECDH", "ECDH-" + grp, grp, provider, msec);
15✔
1858
         }
1859
      }
1✔
1860
#endif
1861

1862
#if defined(BOTAN_HAS_CURVE_25519)
1863
      void bench_curve25519(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1864
         bench_pk_ka("Curve25519", "Curve25519", "", provider, msec);
2✔
1865
      }
1✔
1866
#endif
1867

1868
#if defined(BOTAN_HAS_MCELIECE)
1869
      void bench_mceliece(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1870
         /*
1871
         SL=80 n=1632 t=33 - 59 KB pubkey 140 KB privkey
1872
         SL=107 n=2480 t=45 - 128 KB pubkey 300 KB privkey
1873
         SL=128 n=2960 t=57 - 195 KB pubkey 459 KB privkey
1874
         SL=147 n=3408 t=67 - 265 KB pubkey 622 KB privkey
1875
         SL=191 n=4624 t=95 - 516 KB pubkey 1234 KB privkey
1876
         SL=256 n=6624 t=115 - 942 KB pubkey 2184 KB privkey
1877
         */
1878

1879
         const std::vector<std::pair<size_t, size_t>> mce_params = {
1✔
1880
            {2480, 45}, {2960, 57}, {3408, 67}, {4624, 95}, {6624, 115}};
1✔
1881

1882
         for(auto params : mce_params) {
6✔
1883
            size_t n = params.first;
5✔
1884
            size_t t = params.second;
5✔
1885

1886
            const std::string nm = "McEliece-" + std::to_string(n) + "," + std::to_string(t) +
10✔
1887
                                   " (WF=" + std::to_string(Botan::mceliece_work_factor(n, t)) + ")";
15✔
1888

1889
            auto keygen_timer = make_timer(nm, provider, "keygen");
10✔
1890

1891
            std::unique_ptr<Botan::Private_Key> key =
5✔
1892
               keygen_timer->run([&] { return std::make_unique<Botan::McEliece_PrivateKey>(rng(), n, t); });
10✔
1893

1894
            record_result(keygen_timer);
5✔
1895
            bench_pk_kem(*key, nm, provider, "KDF2(SHA-256)", msec);
10✔
1896
         }
10✔
1897
      }
1✔
1898
#endif
1899

1900
#if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S)
1901
      void bench_kyber(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1902
         const Botan::KyberMode::Mode all_modes[] = {
1✔
1903
            Botan::KyberMode::Kyber512,
1904
            Botan::KyberMode::Kyber512_90s,
1905
            Botan::KyberMode::Kyber768,
1906
            Botan::KyberMode::Kyber768_90s,
1907
            Botan::KyberMode::Kyber1024,
1908
            Botan::KyberMode::Kyber1024_90s,
1909
         };
1910

1911
         for(auto modet : all_modes) {
7✔
1912
            Botan::KyberMode mode(modet);
6✔
1913

1914
   #if !defined(BOTAN_HAS_KYBER)
1915
            if(mode.is_modern())
1916
               continue;
1917
   #endif
1918

1919
   #if !defined(BOTAN_HAS_KYBER_90S)
1920
            if(mode.is_90s())
1921
               continue;
1922
   #endif
1923

1924
            auto keygen_timer = make_timer(mode.to_string(), provider, "keygen");
15✔
1925

1926
            auto key = keygen_timer->run([&] { return Botan::Kyber_PrivateKey(rng(), mode); });
12✔
1927

1928
            record_result(keygen_timer);
6✔
1929

1930
            bench_pk_kem(key, mode.to_string(), provider, "KDF2(SHA-256)", msec);
12✔
1931
         }
6✔
1932
      }
1✔
1933
#endif
1934

1935
#if defined(BOTAN_HAS_DILITHIUM) || defined(BOTAN_HAS_DILITHIUM_AES)
1936
      void bench_dilithium(const std::string& provider, std::chrono::milliseconds msec) {
1✔
1937
         const Botan::DilithiumMode::Mode all_modes[] = {Botan::DilithiumMode::Dilithium4x4,
1✔
1938
                                                         Botan::DilithiumMode::Dilithium4x4_AES,
1939
                                                         Botan::DilithiumMode::Dilithium6x5,
1940
                                                         Botan::DilithiumMode::Dilithium6x5_AES,
1941
                                                         Botan::DilithiumMode::Dilithium8x7,
1942
                                                         Botan::DilithiumMode::Dilithium8x7_AES};
1943

1944
         for(auto modet : all_modes) {
7✔
1945
            Botan::DilithiumMode mode(modet);
6✔
1946

1947
   #if !defined(BOTAN_HAS_DILITHIUM)
1948
            if(mode.is_modern())
1949
               continue;
1950
   #endif
1951

1952
   #if !defined(BOTAN_HAS_DILITHIUM_AES)
1953
            if(mode.is_aes())
1954
               continue;
1955
   #endif
1956

1957
            auto keygen_timer = make_timer(mode.to_string(), provider, "keygen");
18✔
1958

1959
            auto key = keygen_timer->run([&] { return Botan::Dilithium_PrivateKey(rng(), mode); });
12✔
1960

1961
            record_result(keygen_timer);
6✔
1962

1963
            bench_pk_sig(key, mode.to_string(), provider, "", msec);
12✔
1964
         }
6✔
1965
      }
1✔
1966
#endif
1967

1968
#if defined(BOTAN_HAS_SPHINCS_PLUS)
1969
      void bench_sphincs_plus(const std::string& provider, std::chrono::milliseconds msec) {
×
1970
         // Sphincs_Parameter_Set set, Sphincs_Hash_Type hash
1971
         std::vector<std::string> sphincs_params{"SphincsPlus-sha2-128s-r3.1",
×
1972
                                                 "SphincsPlus-sha2-128f-r3.1",
1973
                                                 "SphincsPlus-sha2-192s-r3.1",
1974
                                                 "SphincsPlus-sha2-192f-r3.1",
1975
                                                 "SphincsPlus-sha2-256s-r3.1",
1976
                                                 "SphincsPlus-sha2-256f-r3.1",
1977
                                                 "SphincsPlus-shake-128s-r3.1",
1978
                                                 "SphincsPlus-shake-128f-r3.1",
1979
                                                 "SphincsPlus-shake-192s-r3.1",
1980
                                                 "SphincsPlus-shake-192f-r3.1",
1981
                                                 "SphincsPlus-shake-256s-r3.1",
1982
                                                 "SphincsPlus-shake-256f-r3.1"};
×
1983

1984
         for(auto params : sphincs_params) {
×
1985
            try {
×
1986
               auto keygen_timer = make_timer(params, provider, "keygen");
×
1987

1988
               std::unique_ptr<Botan::Private_Key> key(
×
1989
                  keygen_timer->run([&] { return Botan::create_private_key("SPHINCS+", rng(), params); }));
×
1990

1991
               record_result(keygen_timer);
×
1992
               if(bench_pk_sig(*key, params, provider, "", msec) == 1)
×
1993
                  break;
1994
            } catch(Botan::Not_Implemented&) { continue; }
×
1995
         }
×
1996
      }
×
1997
#endif
1998

1999
#if defined(BOTAN_HAS_XMSS_RFC8391)
2000
      void bench_xmss(const std::string& provider, std::chrono::milliseconds msec) {
1✔
2001
         /*
2002
         We only test H10 signatures here since already they are quite slow (a
2003
         few seconds per signature). On a fast machine, H16 signatures take 1-2
2004
         minutes to generate and H20 signatures take 5-10 minutes to generate
2005
         */
2006
         std::vector<std::string> xmss_params{
1✔
2007
            "XMSS-SHA2_10_256",
2008
            "XMSS-SHAKE_10_256",
2009
            "XMSS-SHA2_10_512",
2010
            "XMSS-SHAKE_10_512",
2011
         };
5✔
2012

2013
         for(std::string params : xmss_params) {
1✔
2014
            auto keygen_timer = make_timer(params, provider, "keygen");
2✔
2015

2016
            std::unique_ptr<Botan::Private_Key> key(
1✔
2017
               keygen_timer->run([&] { return Botan::create_private_key("XMSS", rng(), params); }));
2✔
2018

2019
            record_result(keygen_timer);
1✔
2020
            if(bench_pk_sig(*key, params, provider, "", msec) == 1) {
1✔
2021
               break;
2022
            }
2023
         }
2✔
2024
      }
1✔
2025
#endif
2026

2027
#if defined(BOTAN_HAS_ZFEC)
2028
      void bench_zfec(std::chrono::milliseconds msec) {
1✔
2029
         const size_t k = 4;
1✔
2030
         const size_t n = 16;
1✔
2031

2032
         Botan::ZFEC zfec(k, n);
1✔
2033

2034
         const size_t share_size = 256 * 1024;
1✔
2035

2036
         std::vector<uint8_t> input(share_size * k);
1✔
2037
         rng().randomize(input.data(), input.size());
1✔
2038

2039
         std::vector<uint8_t> output(share_size * n);
1✔
2040

2041
         auto enc_fn = [&](size_t share, const uint8_t buf[], size_t len) {
17✔
2042
            std::memcpy(&output[share * share_size], buf, len);
16✔
2043
         };
1✔
2044

2045
         auto enc_timer =
1✔
2046
            make_timer("zfec " + std::to_string(k) + "/" + std::to_string(n), input.size(), "encode", "", input.size());
2✔
2047

2048
         enc_timer->run_until_elapsed(msec, [&]() { zfec.encode(input.data(), input.size(), enc_fn); });
3✔
2049

2050
         record_result(enc_timer);
1✔
2051

2052
         auto dec_timer =
1✔
2053
            make_timer("zfec " + std::to_string(k) + "/" + std::to_string(n), input.size(), "decode", "", input.size());
2✔
2054

2055
         std::map<size_t, const uint8_t*> shares;
1✔
2056
         for(size_t i = 0; i != n; ++i) {
17✔
2057
            shares[i] = &output[share_size * i];
16✔
2058
         }
2059

2060
         // remove data shares to make decoding maximally expensive:
2061
         while(shares.size() != k) {
13✔
2062
            shares.erase(shares.begin());
12✔
2063
         }
2064

2065
         std::vector<uint8_t> recovered(share_size * k);
1✔
2066

2067
         auto dec_fn = [&](size_t share, const uint8_t buf[], size_t len) {
5✔
2068
            std::memcpy(&recovered[share * share_size], buf, len);
4✔
2069
         };
1✔
2070

2071
         dec_timer->run_until_elapsed(msec, [&]() { zfec.decode_shares(shares, share_size, dec_fn); });
3✔
2072

2073
         record_result(dec_timer);
1✔
2074

2075
         if(recovered != input) {
1✔
2076
            error_output() << "ZFEC recovery failed\n";
×
2077
         }
2078
      }
4✔
2079

2080
#endif
2081

2082
#if defined(BOTAN_HAS_POLY_DBL)
2083
      void bench_poly_dbl(std::chrono::milliseconds msec) {
1✔
2084
         for(size_t sz : {8, 16, 24, 32, 64, 128}) {
7✔
2085
            auto be_timer = make_timer("poly_dbl_be_" + std::to_string(sz));
12✔
2086
            auto le_timer = make_timer("poly_dbl_le_" + std::to_string(sz));
12✔
2087

2088
            std::vector<uint8_t> buf(sz);
6✔
2089
            rng().randomize(buf.data(), sz);
6✔
2090

2091
            be_timer->run_until_elapsed(msec, [&]() { Botan::poly_double_n(buf.data(), buf.data(), sz); });
18,026✔
2092
            le_timer->run_until_elapsed(msec, [&]() { Botan::poly_double_n_le(buf.data(), buf.data(), sz); });
20,754✔
2093

2094
            record_result(be_timer);
6✔
2095
            record_result(le_timer);
6✔
2096
         }
6✔
2097
      }
1✔
2098
#endif
2099

2100
#if defined(BOTAN_HAS_BCRYPT)
2101

2102
      void bench_bcrypt() {
1✔
2103
         const std::string password = "not a very good password";
1✔
2104

2105
         for(uint8_t work_factor = 4; work_factor <= 14; ++work_factor) {
12✔
2106
            auto timer = make_timer("bcrypt wf=" + std::to_string(work_factor));
22✔
2107

2108
            timer->run([&] { Botan::generate_bcrypt(password, rng(), work_factor); });
22✔
2109

2110
            record_result(timer);
11✔
2111
         }
11✔
2112
      }
1✔
2113
#endif
2114

2115
#if defined(BOTAN_HAS_PASSHASH9)
2116

2117
      void bench_passhash9() {
1✔
2118
         const std::string password = "not a very good password";
1✔
2119

2120
         for(uint8_t alg = 0; alg <= 4; ++alg) {
6✔
2121
            if(Botan::is_passhash9_alg_supported(alg) == false) {
5✔
2122
               continue;
×
2123
            }
2124

2125
            for(auto work_factor : {10, 15}) {
15✔
2126
               auto timer = make_timer("passhash9 alg=" + std::to_string(alg) + " wf=" + std::to_string(work_factor));
30✔
2127

2128
               timer->run([&] { Botan::generate_passhash9(password, rng(), static_cast<uint8_t>(work_factor), alg); });
20✔
2129

2130
               record_result(timer);
10✔
2131
            }
10✔
2132
         }
2133
      }
1✔
2134
#endif
2135

2136
#if defined(BOTAN_HAS_SCRYPT)
2137

2138
      void bench_scrypt(const std::string& /*provider*/, std::chrono::milliseconds msec) {
1✔
2139
         auto pwdhash_fam = Botan::PasswordHashFamily::create_or_throw("Scrypt");
1✔
2140

2141
         for(size_t N : {8192, 16384, 32768, 65536}) {
5✔
2142
            for(size_t r : {1, 8, 16}) {
16✔
2143
               for(size_t p : {1}) {
12✔
2144
                  auto pwdhash = pwdhash_fam->from_params(N, r, p);
12✔
2145

2146
                  auto scrypt_timer =
12✔
2147
                     make_timer("scrypt-" + std::to_string(N) + "-" + std::to_string(r) + "-" + std::to_string(p) +
24✔
2148
                                " (" + std::to_string(pwdhash->total_memory_usage() / (1024 * 1024)) + " MiB)");
60✔
2149

2150
                  uint8_t out[64];
12✔
2151
                  uint8_t salt[8];
12✔
2152
                  rng().randomize(salt, sizeof(salt));
12✔
2153

2154
                  while(scrypt_timer->under(msec)) {
24✔
2155
                     scrypt_timer->run([&] {
12✔
2156
                        pwdhash->derive_key(out, sizeof(out), "password", 8, salt, sizeof(salt));
12✔
2157

2158
                        Botan::copy_mem(salt, out, 8);
12✔
2159
                     });
12✔
2160
                  }
2161

2162
                  record_result(scrypt_timer);
12✔
2163

2164
                  if(scrypt_timer->events() == 1) {
12✔
2165
                     break;
2166
                  }
2167
               }
24✔
2168
            }
2169
         }
2170
      }
1✔
2171

2172
#endif
2173

2174
#if defined(BOTAN_HAS_ARGON2)
2175

2176
      void bench_argon2(const std::string& /*provider*/, std::chrono::milliseconds msec) {
1✔
2177
         auto pwhash_fam = Botan::PasswordHashFamily::create_or_throw("Argon2id");
1✔
2178

2179
         for(size_t M : {8 * 1024, 64 * 1024, 256 * 1024}) {
4✔
2180
            for(size_t t : {1, 4}) {
9✔
2181
               for(size_t p : {1, 4}) {
18✔
2182
                  auto pwhash = pwhash_fam->from_params(M, t, p);
12✔
2183
                  auto timer = make_timer(pwhash->to_string());
36✔
2184

2185
                  uint8_t out[64];
12✔
2186
                  uint8_t salt[16];
12✔
2187
                  rng().randomize(salt, sizeof(salt));
12✔
2188

2189
                  while(timer->under(msec)) {
24✔
2190
                     timer->run([&] { pwhash->derive_key(out, sizeof(out), "password", 8, salt, sizeof(salt)); });
24✔
2191
                  }
2192

2193
                  record_result(timer);
12✔
2194
               }
24✔
2195
            }
2196
         }
2197
      }
1✔
2198

2199
#endif
2200
};
2201

2202
BOTAN_REGISTER_COMMAND("speed", Speed);
35✔
2203

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

© 2025 Coveralls, Inc