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

randombit / botan / 13219090513

08 Feb 2025 08:36PM UTC coverage: 91.652% (-0.002%) from 91.654%
13219090513

push

github

web-flow
Merge pull request #4650 from randombit/jack/header-minimization

Reorganize code and reduce header dependencies

94833 of 103471 relevant lines covered (91.65%)

11224601.24 hits per line

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

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

7
#include "perf.h"
8
#include <set>
9

10
#include <botan/symkey.h>
11

12
#if defined(BOTAN_HAS_BLOCK_CIPHER)
13
   #include <botan/block_cipher.h>
14
#endif
15

16
#if defined(BOTAN_HAS_CIPHER_MODES)
17
   #include <botan/cipher_mode.h>
18
#endif
19

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

24
#if defined(BOTAN_HAS_HASH)
25
   #include <botan/hash.h>
26
#endif
27

28
#if defined(BOTAN_HAS_MAC)
29
   #include <botan/mac.h>
30
#endif
31

32
#if defined(BOTAN_HAS_XOF)
33
   #include <botan/xof.h>
34
#endif
35

36
namespace Botan_CLI {
37

38
#if defined(BOTAN_HAS_BLOCK_CIPHER)
39
class PerfTest_BlockCipher final : public PerfTest {
40
   public:
41
      PerfTest_BlockCipher(std::string_view alg) : m_alg(alg) {}
4✔
42

43
      void go(const PerfConfig& config) override {
4✔
44
         for(const auto& provider : Botan::BlockCipher::providers(m_alg)) {
8✔
45
            if(auto cipher = Botan::BlockCipher::create(m_alg, provider)) {
4✔
46
               bench_stream_cipher(config, *cipher);
4✔
47
            }
4✔
48
         }
4✔
49
      }
4✔
50

51
      static bool has_impl_for(std::string_view alg) { return !Botan::BlockCipher::providers(alg).empty(); }
7✔
52

53
   private:
54
      void bench_stream_cipher(const PerfConfig& config, Botan::BlockCipher& cipher) {
4✔
55
         auto& rng = config.rng();
4✔
56
         const auto runtime = config.runtime();
4✔
57
         const auto provider = cipher.provider();
4✔
58

59
         auto ks_timer = config.make_timer(cipher.name(), 1, "key schedule", provider);
8✔
60

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

64
         const size_t bs = cipher.block_size();
4✔
65
         std::set<size_t> buf_sizes_in_blocks;
4✔
66
         for(size_t buf_size : config.buffer_sizes()) {
9✔
67
            if(buf_size % bs == 0) {
5✔
68
               buf_sizes_in_blocks.insert(buf_size);
5✔
69
            } else {
70
               buf_sizes_in_blocks.insert(buf_size + bs - (buf_size % bs));
×
71
            }
72
         }
73

74
         for(size_t buf_size : buf_sizes_in_blocks) {
9✔
75
            std::vector<uint8_t> buffer(buf_size);
5✔
76
            const size_t mult = std::max<size_t>(1, 65536 / buf_size);
5✔
77
            const size_t blocks = buf_size / bs;
5✔
78

79
            auto encrypt_timer = config.make_timer(cipher.name(), mult * buffer.size(), "encrypt", provider, buf_size);
10✔
80
            auto decrypt_timer = config.make_timer(cipher.name(), mult * buffer.size(), "decrypt", provider, buf_size);
10✔
81

82
            encrypt_timer->run_until_elapsed(runtime, [&]() {
5✔
83
               for(size_t i = 0; i != mult; ++i) {
16,848✔
84
                  cipher.encrypt_n(&buffer[0], &buffer[0], blocks);
16,768✔
85
               }
86
            });
80✔
87
            config.record_result(*encrypt_timer);
5✔
88

89
            decrypt_timer->run_until_elapsed(runtime, [&]() {
5✔
90
               for(size_t i = 0; i != mult; ++i) {
16,720✔
91
                  cipher.decrypt_n(&buffer[0], &buffer[0], blocks);
16,640✔
92
               }
93
            });
80✔
94
            config.record_result(*decrypt_timer);
10✔
95
         }
10✔
96
      }
8✔
97

98
      std::string m_alg;
99
};
100
#endif
101

102
#if defined(BOTAN_HAS_CIPHER_MODES)
103
class PerfTest_CipherMode final : public PerfTest {
104
   public:
105
      PerfTest_CipherMode(std::string_view alg) : m_alg(alg) {}
1✔
106

107
      void go(const PerfConfig& config) override {
1✔
108
         for(const auto& provider : Botan::Cipher_Mode::providers(m_alg)) {
2✔
109
            if(auto enc = Botan::Cipher_Mode::create(m_alg, Botan::Cipher_Dir::Encryption, provider)) {
1✔
110
               auto dec = Botan::Cipher_Mode::create_or_throw(m_alg, Botan::Cipher_Dir::Decryption, provider);
1✔
111
               bench_cipher_mode(config, *enc, *dec);
1✔
112
            }
2✔
113
         }
1✔
114
      }
1✔
115

116
      static bool has_impl_for(std::string_view alg) { return !Botan::Cipher_Mode::providers(alg).empty(); }
3✔
117

118
   private:
119
      void bench_cipher_mode(const PerfConfig& config, Botan::Cipher_Mode& enc, Botan::Cipher_Mode& dec) {
1✔
120
         auto& rng = config.rng();
1✔
121
         const auto runtime = config.runtime();
1✔
122
         const auto provider = enc.provider();
1✔
123

124
         auto ks_timer = config.make_timer(enc.name(), 1, "key schedule", provider);
2✔
125

126
         const Botan::SymmetricKey key(config.rng(), enc.key_spec().maximum_keylength());
1✔
127

128
         ks_timer->run([&]() { enc.set_key(key); });
2✔
129
         ks_timer->run([&]() { dec.set_key(key); });
2✔
130

131
         config.record_result(*ks_timer);
1✔
132

133
         for(auto buf_size : config.buffer_sizes()) {
2✔
134
            Botan::secure_vector<uint8_t> buffer = rng.random_vec(buf_size);
1✔
135
            const size_t mult = std::max<size_t>(1, 65536 / buf_size);
1✔
136

137
            auto encrypt_timer = config.make_timer(enc.name(), mult * buffer.size(), "encrypt", provider, buf_size);
2✔
138
            auto decrypt_timer = config.make_timer(dec.name(), mult * buffer.size(), "decrypt", provider, buf_size);
2✔
139

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

142
            if(buf_size >= enc.minimum_final_size()) {
1✔
143
               encrypt_timer->run_until_elapsed(runtime, [&]() {
2✔
144
                  for(size_t i = 0; i != mult; ++i) {
260✔
145
                     enc.start(iv);
256✔
146
                     enc.finish(buffer);
256✔
147
                     buffer.resize(buf_size);  // remove any tag or padding
256✔
148
                  }
149
               });
4✔
150

151
               while(decrypt_timer->under(runtime)) {
5✔
152
                  if(!iv.empty()) {
4✔
153
                     iv[iv.size() - 1] += 1;
4✔
154
                  }
155

156
                  // Create a valid ciphertext/tag for decryption to run on
157
                  buffer.resize(buf_size);
4✔
158
                  enc.start(iv);
4✔
159
                  enc.finish(buffer);
4✔
160

161
                  Botan::secure_vector<uint8_t> dbuffer;
4✔
162

163
                  decrypt_timer->run([&]() {
4✔
164
                     for(size_t i = 0; i != mult; ++i) {
260✔
165
                        dbuffer = buffer;
256✔
166
                        dec.start(iv);
256✔
167
                        dec.finish(dbuffer);
256✔
168
                     }
169
                  });
4✔
170
               }
4✔
171
            }
172

173
            config.record_result(*encrypt_timer);
1✔
174
            config.record_result(*decrypt_timer);
2✔
175
         }
4✔
176
      }
1✔
177

178
      std::string m_alg;
179
};
180
#endif
181

182
#if defined(BOTAN_HAS_STREAM_CIPHER)
183
class PerfTest_StreamCipher final : public PerfTest {
184
   public:
185
      PerfTest_StreamCipher(std::string_view alg) : m_alg(alg) {}
1✔
186

187
      void go(const PerfConfig& config) override {
1✔
188
         for(const auto& provider : Botan::StreamCipher::providers(m_alg)) {
2✔
189
            if(auto cipher = Botan::StreamCipher::create(m_alg, provider)) {
1✔
190
               bench_stream_cipher(config, *cipher);
1✔
191
            }
1✔
192
         }
1✔
193
      }
1✔
194

195
      static bool has_impl_for(std::string_view alg) { return !Botan::StreamCipher::providers(alg).empty(); }
8✔
196

197
   private:
198
      void bench_stream_cipher(const PerfConfig& config, Botan::StreamCipher& cipher) {
1✔
199
         auto& rng = config.rng();
1✔
200
         const auto runtime = config.runtime();
1✔
201
         const auto provider = cipher.provider();
1✔
202

203
         for(auto buf_size : config.buffer_sizes()) {
2✔
204
            const Botan::SymmetricKey key(rng, cipher.maximum_keylength());
1✔
205
            cipher.set_key(key);
1✔
206

207
            if(cipher.valid_iv_length(12)) {
1✔
208
               const Botan::InitializationVector iv(rng, 12);
1✔
209
               cipher.set_iv(iv.begin(), iv.size());
1✔
210
            }
1✔
211

212
            auto buffer = rng.random_vec(buf_size);
1✔
213

214
            const size_t mult = std::max<size_t>(1, 65536 / buf_size);
1✔
215

216
            auto encrypt_timer = config.make_timer(cipher.name(), mult * buffer.size(), "encrypt", provider, buf_size);
2✔
217

218
            encrypt_timer->run_until_elapsed(runtime, [&]() {
1✔
219
               for(size_t i = 0; i != mult; ++i) {
910✔
220
                  cipher.encipher(buffer);
896✔
221
               }
222
            });
14✔
223

224
            config.record_result(*encrypt_timer);
1✔
225

226
            auto ks_timer =
1✔
227
               config.make_timer(cipher.name(), mult * buffer.size(), "write_keystream", provider, buf_size);
2✔
228

229
            while(ks_timer->under(runtime)) {
20✔
230
               ks_timer->run([&]() {
19✔
231
                  for(size_t i = 0; i != mult; ++i) {
1,235✔
232
                     cipher.write_keystream(buffer.data(), buffer.size());
1,216✔
233
                  }
234
               });
19✔
235
            }
236

237
            config.record_result(*ks_timer);
2✔
238
         }
3✔
239
      }
1✔
240

241
      std::string m_alg;
242
};
243
#endif
244

245
#if defined(BOTAN_HAS_HASH)
246
class PerfTest_HashFunction final : public PerfTest {
247
   public:
248
      PerfTest_HashFunction(std::string_view alg) : m_alg(alg) {}
1✔
249

250
      void go(const PerfConfig& config) override {
1✔
251
         for(const auto& provider : Botan::HashFunction::providers(m_alg)) {
2✔
252
            if(auto hash = Botan::HashFunction::create(m_alg, provider)) {
1✔
253
               bench_hash_fn(config, *hash);
1✔
254
            }
1✔
255
         }
1✔
256
      }
1✔
257

258
      static bool has_impl_for(std::string_view alg) { return !Botan::HashFunction::providers(alg).empty(); }
2✔
259

260
   private:
261
      void bench_hash_fn(const PerfConfig& config, Botan::HashFunction& hash) {
1✔
262
         std::vector<uint8_t> output(hash.output_length());
1✔
263
         const auto provider = hash.provider();
1✔
264
         const auto runtime = config.runtime();
1✔
265

266
         for(auto buf_size : config.buffer_sizes()) {
2✔
267
            const auto buffer = config.rng().random_vec(buf_size);
1✔
268

269
            const size_t mult = std::max<size_t>(1, 65536 / buf_size);
1✔
270

271
            auto timer = config.make_timer(hash.name(), mult * buffer.size(), "hash", provider, buf_size);
2✔
272
            timer->run_until_elapsed(runtime, [&]() {
1✔
273
               for(size_t i = 0; i != mult; ++i) {
260✔
274
                  hash.update(buffer);
256✔
275
                  hash.final(output.data());
512✔
276
               }
277
            });
4✔
278
            config.record_result(*timer);
2✔
279
         }
2✔
280
      }
2✔
281

282
      std::string m_alg;
283
};
284
#endif
285

286
#if defined(BOTAN_HAS_MAC)
287
class PerfTest_MessageAuthenticationCode final : public PerfTest {
288
   public:
289
      PerfTest_MessageAuthenticationCode(std::string_view alg) : m_alg(alg) {}
1✔
290

291
      void go(const PerfConfig& config) override {
1✔
292
         for(const auto& provider : Botan::MessageAuthenticationCode::providers(m_alg)) {
2✔
293
            if(auto mac = Botan::MessageAuthenticationCode::create(m_alg, provider)) {
1✔
294
               bench_mac_fn(config, *mac);
1✔
295
            }
1✔
296
         }
1✔
297
      }
1✔
298

299
      static bool has_impl_for(std::string_view alg) {
1✔
300
         return !Botan::MessageAuthenticationCode::providers(alg).empty();
1✔
301
      }
302

303
   private:
304
      void bench_mac_fn(const PerfConfig& config, Botan::MessageAuthenticationCode& mac) {
1✔
305
         std::vector<uint8_t> output(mac.output_length());
1✔
306
         const auto provider = mac.provider();
1✔
307
         const auto runtime = config.runtime();
1✔
308
         auto& rng = config.rng();
1✔
309

310
         for(auto buf_size : config.buffer_sizes()) {
2✔
311
            Botan::secure_vector<uint8_t> buffer = rng.random_vec(buf_size);
1✔
312
            const size_t mult = std::max<size_t>(1, 65536 / buf_size);
1✔
313

314
            const Botan::SymmetricKey key(rng, mac.maximum_keylength());
1✔
315
            mac.set_key(key);
1✔
316

317
            auto timer = config.make_timer(mac.name(), mult * buffer.size(), "mac", provider, buf_size);
2✔
318
            timer->run_until_elapsed(runtime, [&]() {
1✔
319
               for(size_t i = 0; i != mult; ++i) {
195✔
320
                  if(mac.fresh_key_required_per_message()) {
192✔
321
                     mac.set_key(key);
×
322
                  }
323
                  mac.start(nullptr, 0);
192✔
324
                  mac.update(buffer);
192✔
325
                  mac.final(output.data());
384✔
326
               }
327
            });
3✔
328

329
            config.record_result(*timer);
2✔
330
         }
3✔
331
      }
2✔
332

333
      std::string m_alg;
334
};
335
#endif
336

337
#if defined(BOTAN_HAS_XOF)
338
class PerfTest_XOF final : public PerfTest {
339
   public:
340
      PerfTest_XOF(std::string_view alg) : m_alg(alg) {}
×
341

342
      void go(const PerfConfig& config) override {
×
343
         for(const auto& provider : Botan::XOF::providers(m_alg)) {
×
344
            if(auto xof = Botan::XOF::create(m_alg, provider)) {
×
345
               bench_xof_fn(config, *xof);
×
346
            }
×
347
         }
×
348
      }
×
349

350
      static bool has_impl_for(std::string_view alg) { return !Botan::XOF::providers(alg).empty(); }
8✔
351

352
   private:
353
      void bench_xof_fn(const PerfConfig& config, Botan::XOF& xof) {
×
354
         const auto runtime = config.runtime();
×
355
         const auto provider = xof.provider();
×
356

357
         for(size_t buf_size : config.buffer_sizes()) {
×
358
            auto in = config.rng().random_vec(buf_size);
×
359
            Botan::secure_vector<uint8_t> out(buf_size);
×
360

361
            auto in_timer = config.make_timer(xof.name(), in.size(), "input", provider, buf_size);
×
362
            in_timer->run_until_elapsed(runtime / 2, [&]() { xof.update(in); });
×
363

364
            auto out_timer = config.make_timer(xof.name(), out.size(), "output", provider, buf_size);
×
365
            out_timer->run_until_elapsed(runtime / 2, [&] { xof.output(out); });
×
366

367
            config.record_result(*in_timer);
×
368
            config.record_result(*out_timer);
×
369
         }
×
370
      }
×
371

372
      std::string m_alg;
373
};
374
#endif
375

376
//static
377
std::unique_ptr<PerfTest> PerfTest::get_sym(const std::string& alg) {
8✔
378
#if defined(BOTAN_HAS_XOF)
379
   if(PerfTest_XOF::has_impl_for(alg)) {
8✔
380
      return std::make_unique<PerfTest_XOF>(alg);
×
381
   }
382
#endif
383

384
#if defined(BOTAN_HAS_STREAM_CIPHER)
385
   if(PerfTest_StreamCipher::has_impl_for(alg)) {
8✔
386
      return std::make_unique<PerfTest_StreamCipher>(alg);
1✔
387
   }
388
#endif
389

390
#if defined(BOTAN_HAS_BLOCK_CIPHER)
391
   if(PerfTest_BlockCipher::has_impl_for(alg)) {
7✔
392
      return std::make_unique<PerfTest_BlockCipher>(alg);
4✔
393
   }
394
#endif
395

396
#if defined(BOTAN_HAS_CIPHER_MODES)
397
   if(PerfTest_CipherMode::has_impl_for(alg)) {
3✔
398
      return std::make_unique<PerfTest_CipherMode>(alg);
1✔
399
   }
400
#endif
401

402
#if defined(BOTAN_HAS_HASH)
403
   if(PerfTest_HashFunction::has_impl_for(alg)) {
2✔
404
      return std::make_unique<PerfTest_HashFunction>(alg);
1✔
405
   }
406
#endif
407

408
#if defined(BOTAN_HAS_MAC)
409
   if(PerfTest_MessageAuthenticationCode::has_impl_for(alg)) {
1✔
410
      return std::make_unique<PerfTest_MessageAuthenticationCode>(alg);
1✔
411
   }
412
#endif
413

414
   BOTAN_UNUSED(alg);
×
415
   return {};
×
416
}
417

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

© 2026 Coveralls, Inc