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

randombit / botan / 21783203606

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

Pull #5295

github

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

102233 of 113507 relevant lines covered (90.07%)

11542227.95 hits per line

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

20.78
/src/cli/perf_misc.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 <cstring>
9

10
// Always available:
11
#include <botan/assert.h>
12
#include <botan/hex.h>
13
#include <botan/rng.h>
14
#include <botan/internal/fmt.h>
15

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

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

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

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

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

36
#if defined(BOTAN_HAS_ZFEC)
37
   #include <botan/zfec.h>
38
#endif
39

40
namespace Botan_CLI {
41

42
class PerfTest_Hex final : public PerfTest {
×
43
   public:
44
      void go(const PerfConfig& config) override {
×
45
         for(const size_t buf_size : config.buffer_sizes()) {
×
46
            std::vector<uint8_t> ibuf(buf_size);
×
47
            std::vector<uint8_t> rbuf(buf_size);
×
48
            const size_t olen = 2 * buf_size;
×
49

50
            auto enc_timer = config.make_timer("hex", ibuf.size(), "encode", "", ibuf.size());
×
51

52
            auto dec_timer = config.make_timer("hex", olen, "decode", "", olen);
×
53

54
            const auto msec = config.runtime();
×
55

56
            while(enc_timer->under(msec) && dec_timer->under(msec)) {
×
57
               config.rng().randomize(ibuf);
×
58

59
               std::string hex = enc_timer->run([&]() { return Botan::hex_encode(ibuf); });
×
60

61
               dec_timer->run([&]() { Botan::hex_decode(rbuf.data(), hex); });
×
62
               BOTAN_ASSERT(rbuf == ibuf, "Encode/decode round trip ok");
×
63
            }
×
64

65
            config.record_result(*enc_timer);
×
66
            config.record_result(*dec_timer);
×
67
         }
×
68
      }
×
69
};
70

71
BOTAN_REGISTER_PERF_TEST("hex", PerfTest_Hex);
×
72

73
#if defined(BOTAN_HAS_BASE32_CODEC)
74
class PerfTest_Base32 final : public PerfTest {
×
75
   public:
76
      void go(const PerfConfig& config) override {
×
77
         for(const size_t buf_size : config.buffer_sizes()) {
×
78
            std::vector<uint8_t> ibuf(buf_size);
×
79
            std::vector<uint8_t> rbuf(buf_size);
×
80
            const size_t olen = Botan::base32_encode_max_output(ibuf.size());
×
81

82
            auto enc_timer = config.make_timer("base32", ibuf.size(), "encode", "", ibuf.size());
×
83

84
            auto dec_timer = config.make_timer("base32", olen, "decode", "", olen);
×
85

86
            const auto msec = config.runtime();
×
87

88
            while(enc_timer->under(msec) && dec_timer->under(msec)) {
×
89
               config.rng().randomize(ibuf);
×
90

91
               std::string b32 = enc_timer->run([&]() { return Botan::base32_encode(ibuf); });
×
92

93
               dec_timer->run([&]() { Botan::base32_decode(rbuf.data(), b32); });
×
94
               BOTAN_ASSERT(rbuf == ibuf, "Encode/decode round trip ok");
×
95
            }
×
96

97
            config.record_result(*enc_timer);
×
98
            config.record_result(*dec_timer);
×
99
         }
×
100
      }
×
101
};
102

103
BOTAN_REGISTER_PERF_TEST("base32", PerfTest_Base32);
×
104

105
#endif
106

107
#if defined(BOTAN_HAS_BASE64_CODEC)
108
class PerfTest_Base64 final : public PerfTest {
×
109
   public:
110
      void go(const PerfConfig& config) override {
×
111
         for(const size_t buf_size : config.buffer_sizes()) {
×
112
            std::vector<uint8_t> ibuf(buf_size);
×
113
            std::vector<uint8_t> rbuf(buf_size);
×
114
            const size_t olen = Botan::base64_encode_max_output(ibuf.size());
×
115

116
            auto enc_timer = config.make_timer("base64", ibuf.size(), "encode", "", ibuf.size());
×
117

118
            auto dec_timer = config.make_timer("base64", olen, "decode", "", olen);
×
119

120
            const auto msec = config.runtime();
×
121

122
            while(enc_timer->under(msec) && dec_timer->under(msec)) {
×
123
               config.rng().randomize(ibuf);
×
124

125
               std::string b64 = enc_timer->run([&]() { return Botan::base64_encode(ibuf); });
×
126

127
               dec_timer->run([&]() { Botan::base64_decode(rbuf.data(), b64); });
×
128
               BOTAN_ASSERT(rbuf == ibuf, "Encode/decode round trip ok");
×
129
            }
×
130

131
            config.record_result(*enc_timer);
×
132
            config.record_result(*dec_timer);
×
133
         }
×
134
      }
×
135
};
136

137
BOTAN_REGISTER_PERF_TEST("base64", PerfTest_Base64);
×
138

139
#endif
140

141
#if defined(BOTAN_HAS_BASE58_CODEC)
142
class PerfTest_Base58 final : public PerfTest {
×
143
   public:
144
      void go(const PerfConfig& config) override {
×
145
         for(const size_t buf_size : config.buffer_sizes()) {
×
146
            std::vector<uint8_t> ibuf(buf_size);
×
147

148
            auto enc_timer = config.make_timer("base58", ibuf.size(), "encode", "", ibuf.size());
×
149
            auto dec_timer = config.make_timer("base58", ibuf.size(), "decode", "", ibuf.size());
×
150

151
            const auto msec = config.runtime();
×
152

153
            while(enc_timer->under(msec) && dec_timer->under(msec)) {
×
154
               config.rng().randomize(ibuf);
×
155

156
               const std::string b58 = enc_timer->run([&]() { return Botan::base58_encode(ibuf); });
×
157
               const auto rbuf = dec_timer->run([&] { return Botan::base58_decode(b58); });
×
158
               BOTAN_ASSERT(rbuf == ibuf, "Encode/decode round trip ok");
×
159
            }
×
160

161
            config.record_result(*enc_timer);
×
162
            config.record_result(*dec_timer);
×
163
         }
×
164
      }
×
165
};
166

167
BOTAN_REGISTER_PERF_TEST("base58", PerfTest_Base58);
×
168

169
#endif
170

171
#if defined(BOTAN_HAS_FPE_FE1)
172

173
class PerfTest_FpeFe1 final : public PerfTest {
×
174
   public:
175
      void go(const PerfConfig& config) override {
×
176
         const auto n = Botan::BigInt::from_u64(1000000000000000);
×
177

178
         auto enc_timer = config.make_timer("FPE_FE1 encrypt");
×
179
         auto dec_timer = config.make_timer("FPE_FE1 decrypt");
×
180

181
         const Botan::SymmetricKey key(config.rng(), 32);
×
182
         const std::vector<uint8_t> tweak(8);  // 8 zeros
×
183

184
         auto x = Botan::BigInt::one();
×
185

186
         Botan::FPE_FE1 fpe_fe1(n);
×
187
         fpe_fe1.set_key(key);
×
188

189
         auto runtime = config.runtime();
×
190

191
         while(enc_timer->under(runtime)) {
×
192
            enc_timer->start();
×
193
            x = fpe_fe1.encrypt(x, tweak.data(), tweak.size());
×
194
            enc_timer->stop();
×
195
         }
196
         config.record_result(*enc_timer);
×
197

198
         for(size_t i = 0; i != enc_timer->events(); ++i) {
×
199
            dec_timer->start();
×
200
            x = fpe_fe1.decrypt(x, tweak.data(), tweak.size());
×
201
            dec_timer->stop();
×
202
         }
203
         config.record_result(*dec_timer);
×
204

205
         BOTAN_ASSERT(x == 1, "FPE works");
×
206
      }
×
207
};
208

209
BOTAN_REGISTER_PERF_TEST("fpe_fe1", PerfTest_FpeFe1);
×
210

211
#endif
212

213
#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
214
class PerfTest_Rfc3394 final : public PerfTest {
×
215
      void go(const PerfConfig& config) override {
×
216
         auto wrap_timer = config.make_timer("RFC3394 AES-256 key wrap");
×
217
         auto unwrap_timer = config.make_timer("RFC3394 AES-256 key unwrap");
×
218

219
         const Botan::SymmetricKey kek(config.rng(), 32);
×
220
         Botan::secure_vector<uint8_t> key(64, 0);
×
221

222
         const auto runtime = config.runtime();
×
223

224
         while(wrap_timer->under(runtime)) {
×
225
            wrap_timer->start();
×
226
            key = Botan::rfc3394_keywrap(key, kek);
×
227
            wrap_timer->stop();
×
228

229
            unwrap_timer->start();
×
230
            key = Botan::rfc3394_keyunwrap(key, kek);
×
231
            unwrap_timer->stop();
×
232

233
            key[0] += 1;
×
234
         }
235

236
         config.record_result(*wrap_timer);
×
237
         config.record_result(*unwrap_timer);
×
238
      }
×
239
};
240

241
BOTAN_REGISTER_PERF_TEST("rfc3394", PerfTest_Rfc3394);
×
242

243
#endif
244

245
#if defined(BOTAN_HAS_ZFEC)
246

247
class PerfTest_Zfec final : public PerfTest {
1✔
248
   public:
249
      void go(const PerfConfig& config) override {
1✔
250
         const size_t k = 4;
1✔
251
         const size_t n = 16;
1✔
252

253
         Botan::ZFEC zfec(k, n);
1✔
254

255
         const size_t share_size = 256 * 1024;
1✔
256

257
         std::vector<uint8_t> input(share_size * k);
1✔
258
         config.rng().randomize(input.data(), input.size());
1✔
259

260
         std::vector<uint8_t> output(share_size * n);
1✔
261

262
         auto enc_fn = [&](size_t share, const uint8_t buf[], size_t len) {
17✔
263
            std::memcpy(&output[share * share_size], buf, len);
16✔
264
         };
17✔
265

266
         const auto msec = config.runtime();
1✔
267

268
         const std::string alg = Botan::fmt("zfec {}/{}", k, n);
1✔
269

270
         auto enc_timer = config.make_timer(alg, input.size(), "encode", "", input.size());
1✔
271

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

274
         config.record_result(*enc_timer);
1✔
275

276
         auto dec_timer = config.make_timer(alg, input.size(), "decode", "", input.size());
1✔
277

278
         std::map<size_t, const uint8_t*> shares;
1✔
279
         for(size_t i = 0; i != n; ++i) {
17✔
280
            shares[i] = &output[share_size * i];
16✔
281
         }
282

283
         // remove data shares to make decoding maximally expensive:
284
         while(shares.size() != k) {
13✔
285
            shares.erase(shares.begin());
12✔
286
         }
287

288
         std::vector<uint8_t> recovered(share_size * k);
1✔
289

290
         auto dec_fn = [&](size_t share, const uint8_t buf[], size_t len) {
5✔
291
            std::memcpy(&recovered[share * share_size], buf, len);
4✔
292
         };
5✔
293

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

296
         config.record_result(*dec_timer);
1✔
297

298
         if(recovered != input) {
1✔
299
            config.error_output() << "ZFEC recovery failed\n";
×
300
         }
301
      }
4✔
302
};
303

304
BOTAN_REGISTER_PERF_TEST("zfec", PerfTest_Zfec);
1✔
305

306
#endif
307

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