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

randombit / botan / 11498012984

24 Oct 2024 11:06AM UTC coverage: 91.138% (-0.002%) from 91.14%
11498012984

push

github

web-flow
Merge pull request #4405 from randombit/jack/fix-ks-bench

Fix write_keystream benchmark

91058 of 99912 relevant lines covered (91.14%)

9432482.01 hits per line

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

88.29
/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
#if defined(BOTAN_HAS_BLOCK_CIPHER)
11
   #include <botan/block_cipher.h>
12
#endif
13

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

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

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

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

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

34
namespace Botan_CLI {
35

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

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

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

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

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

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

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

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

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

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

87
            decrypt_timer->run_until_elapsed(runtime, [&]() {
5✔
88
               for(size_t i = 0; i != mult; ++i) {
17,874✔
89
                  cipher.decrypt_n(&buffer[0], &buffer[0], blocks);
17,792✔
90
               }
91
            });
82✔
92
            config.record_result(*decrypt_timer);
5✔
93
         }
10✔
94
      }
8✔
95

96
      std::string m_alg;
97
};
98
#endif
99

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

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

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

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

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

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

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

129
         config.record_result(*ks_timer);
1✔
130

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

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

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

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

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

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

159
                  Botan::secure_vector<uint8_t> dbuffer;
4✔
160

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

171
            config.record_result(*encrypt_timer);
1✔
172
            config.record_result(*decrypt_timer);
2✔
173
         }
2✔
174
      }
1✔
175

176
      std::string m_alg;
177
};
178
#endif
179

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

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

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

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

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

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

210
            auto buffer = rng.random_vec(buf_size);
1✔
211

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

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

216
            encrypt_timer->run_until_elapsed(runtime, [&]() {
1✔
217
               for(size_t i = 0; i != mult; ++i) {
975✔
218
                  cipher.encipher(buffer);
960✔
219
               }
220
            });
15✔
221

222
            config.record_result(*encrypt_timer);
1✔
223

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

227
            while(ks_timer->under(runtime)) {
28✔
228
               ks_timer->run([&]() {
27✔
229
                  for(size_t i = 0; i != mult; ++i) {
1,755✔
230
                     cipher.write_keystream(buffer.data(), buffer.size());
1,728✔
231
                  }
232
               });
27✔
233
            }
234

235
            config.record_result(*ks_timer);
1✔
236
         }
3✔
237
      }
1✔
238

239
      std::string m_alg;
240
};
241
#endif
242

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

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

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

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

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

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

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

280
      std::string m_alg;
281
};
282
#endif
283

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

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

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

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

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

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

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

327
            config.record_result(*timer);
1✔
328
         }
3✔
329
      }
2✔
330

331
      std::string m_alg;
332
};
333
#endif
334

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

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

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

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

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

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

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

365
            config.record_result(*in_timer);
×
366
            config.record_result(*out_timer);
×
367
         }
×
368
      }
×
369

370
      std::string m_alg;
371
};
372
#endif
373

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

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

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

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

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

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

412
   return {};
×
413
}
414

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