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

randombit / botan / 37723301502

07 Oct 2026 01:16PM UTC coverage: 89.903% (-0.01%) from 89.915%
37723301502

push

github

web-flow
Merge pull request #5999 from randombit/jack/base64-avx512

Add a AVX-512 path for base64 encoding and decoding

131000 of 145712 relevant lines covered (89.9%)

9262170.72 hits per line

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

48.39
/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
namespace {
43

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

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

54
            auto dec_timer = config.make_timer("hex", olen, "decode", "", olen);
×
55

56
            const auto msec = config.runtime();
×
57

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

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

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

67
            config.record_result(*enc_timer);
×
68
            config.record_result(*dec_timer);
×
69
         }
×
70
      }
×
71
};
72

73
BOTAN_REGISTER_PERF_TEST("hex", PerfTest_Hex);
×
74

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

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

86
            auto dec_timer = config.make_timer("base32", olen, "decode", "", olen);
×
87

88
            const auto msec = config.runtime();
×
89

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

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

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

99
            config.record_result(*enc_timer);
×
100
            config.record_result(*dec_timer);
×
101
         }
×
102
      }
×
103
};
104

105
BOTAN_REGISTER_PERF_TEST("base32", PerfTest_Base32);
×
106

107
#endif
108

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

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

120
            auto dec_timer = config.make_timer("base64", olen, "decode", "", olen);
×
121

122
            const auto msec = config.runtime();
×
123

124
            config.rng().randomize(ibuf);
×
125

126
            // Check the roundtrip once, outside of the timed loop
127
            Botan::base64_decode(rbuf.data(), Botan::base64_encode(ibuf));
×
128
            BOTAN_ASSERT(rbuf == ibuf, "Encode/decode round trip ok");
×
129

130
            while(enc_timer->under(msec) && dec_timer->under(msec)) {
×
131
               const std::string b64 = enc_timer->run([&]() { return Botan::base64_encode(ibuf); });
×
132

133
               dec_timer->run([&]() { Botan::base64_decode(rbuf.data(), b64); });
×
134
            }
×
135

136
            config.record_result(*enc_timer);
×
137
            config.record_result(*dec_timer);
×
138
         }
×
139
      }
×
140
};
141

142
BOTAN_REGISTER_PERF_TEST("base64", PerfTest_Base64);
×
143

144
#endif
145

146
#if defined(BOTAN_HAS_BASE58_CODEC)
147
class PerfTest_Base58 final : public PerfTest {
×
148
   public:
149
      void go(const PerfConfig& config) override {
×
150
         for(const size_t buf_size : config.buffer_sizes()) {
×
151
            std::vector<uint8_t> ibuf(buf_size);
×
152

153
            auto enc_timer = config.make_timer("base58", ibuf.size(), "encode", "", ibuf.size());
×
154
            auto dec_timer = config.make_timer("base58", ibuf.size(), "decode", "", ibuf.size());
×
155

156
            const auto msec = config.runtime();
×
157

158
            while(enc_timer->under(msec) && dec_timer->under(msec)) {
×
159
               config.rng().randomize(ibuf);
×
160

161
               const std::string b58 = enc_timer->run([&]() { return Botan::base58_encode(ibuf); });
×
162
               const auto rbuf = dec_timer->run([&] { return Botan::base58_decode(b58); });
×
163
               BOTAN_ASSERT(rbuf == ibuf, "Encode/decode round trip ok");
×
164
            }
×
165

166
            config.record_result(*enc_timer);
×
167
            config.record_result(*dec_timer);
×
168
         }
×
169
      }
×
170
};
171

172
BOTAN_REGISTER_PERF_TEST("base58", PerfTest_Base58);
×
173

174
#endif
175

176
#if defined(BOTAN_HAS_FPE_FE1)
177

178
class PerfTest_FpeFe1 final : public PerfTest {
1 ✔
179
   public:
180
      void go(const PerfConfig& config) override {
1 ✔
181
         const auto n = Botan::BigInt::from_u64(1000000000000000);
1 ✔
182

183
         auto enc_timer = config.make_timer("FPE_FE1 encrypt");
2 ✔
184
         auto dec_timer = config.make_timer("FPE_FE1 decrypt");
2 ✔
185

186
         const Botan::SymmetricKey key(config.rng(), 32);
1 ✔
187
         const std::vector<uint8_t> tweak(8);  // 8 zeros
1 ✔
188

189
         auto x = Botan::BigInt::one();
1 ✔
190

191
         Botan::FPE_FE1 fpe_fe1(n);
1 ✔
192
         fpe_fe1.set_key(key);
1 ✔
193

194
         const auto runtime = config.runtime();
1 ✔
195

196
         while(enc_timer->under(runtime)) {
27 ✔
197
            enc_timer->start();
26 ✔
198
            x = fpe_fe1.encrypt(x, tweak.data(), tweak.size());
26 ✔
199
            enc_timer->stop();
26 ✔
200
         }
201
         config.record_result(*enc_timer);
1 ✔
202

203
         for(size_t i = 0; i != enc_timer->events(); ++i) {
27 ✔
204
            dec_timer->start();
26 ✔
205
            x = fpe_fe1.decrypt(x, tweak.data(), tweak.size());
26 ✔
206
            dec_timer->stop();
26 ✔
207
         }
208
         config.record_result(*dec_timer);
1 ✔
209

210
         BOTAN_ASSERT(x == 1, "FPE works");
1 ✔
211
      }
4 ✔
212
};
213

214
BOTAN_REGISTER_PERF_TEST("fpe_fe1", PerfTest_FpeFe1);
1 ✔
215

216
#endif
217

218
#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
219
class PerfTest_Rfc3394 final : public PerfTest {
1 ✔
220
      void go(const PerfConfig& config) override {
1 ✔
221
         auto wrap_timer = config.make_timer("RFC3394 AES-256 key wrap");
2 ✔
222
         auto unwrap_timer = config.make_timer("RFC3394 AES-256 key unwrap");
2 ✔
223

224
         const Botan::SymmetricKey kek(config.rng(), 32);
1 ✔
225
         Botan::secure_vector<uint8_t> key(64, 0);
1 ✔
226

227
         const auto runtime = config.runtime();
1 ✔
228

229
         while(wrap_timer->under(runtime)) {
108 ✔
230
            wrap_timer->start();
107 ✔
231
            key = Botan::rfc3394_keywrap(key, kek);
214 ✔
232
            wrap_timer->stop();
107 ✔
233

234
            unwrap_timer->start();
107 ✔
235
            key = Botan::rfc3394_keyunwrap(key, kek);
214 ✔
236
            unwrap_timer->stop();
107 ✔
237

238
            key[0] += 1;
107 ✔
239
         }
240

241
         config.record_result(*wrap_timer);
1 ✔
242
         config.record_result(*unwrap_timer);
2 ✔
243
      }
3 ✔
244
};
245

246
BOTAN_REGISTER_PERF_TEST("rfc3394", PerfTest_Rfc3394);
1 ✔
247

248
#endif
249

250
#if defined(BOTAN_HAS_ZFEC)
251

252
class PerfTest_Zfec final : public PerfTest {
1 ✔
253
   public:
254
      void go(const PerfConfig& config) override {
1 ✔
255
         const size_t k = 4;
1 ✔
256
         const size_t n = 16;
1 ✔
257

258
         Botan::ZFEC zfec(k, n);
1 ✔
259

260
         const size_t share_size = 256 * 1024;
1 ✔
261

262
         std::vector<uint8_t> input(share_size * k);
1 ✔
263
         config.rng().randomize(input.data(), input.size());
1 ✔
264

265
         std::vector<uint8_t> output(share_size * n);
1 ✔
266

267
         auto enc_fn = [&](size_t share, const uint8_t buf[], size_t len) {
17 ✔
268
            std::memcpy(&output[share * share_size], buf, len);
16 ✔
269
         };
17 ✔
270

271
         const auto msec = config.runtime();
1 ✔
272

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

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

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

279
         config.record_result(*enc_timer);
1 ✔
280

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

283
         std::map<size_t, const uint8_t*> shares;
1 ✔
284
         for(size_t i = 0; i != n; ++i) {
17 ✔
285
            shares[i] = &output[share_size * i];
16 ✔
286
         }
287

288
         // remove data shares to make decoding maximally expensive:
289
         while(shares.size() != k) {
13 ✔
290
            shares.erase(shares.begin());
12 ✔
291
         }
292

293
         std::vector<uint8_t> recovered(share_size * k);
1 ✔
294

295
         auto dec_fn = [&](size_t share, const uint8_t buf[], size_t len) {
5 ✔
296
            std::memcpy(&recovered[share * share_size], buf, len);
4 ✔
297
         };
5 ✔
298

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

301
         config.record_result(*dec_timer);
1 ✔
302

303
         if(recovered != input) {
1 ✔
304
            config.error_output() << "ZFEC recovery failed\n";
×
305
         }
306
      }
4 ✔
307
};
308

309
BOTAN_REGISTER_PERF_TEST("zfec", PerfTest_Zfec);
1 ✔
310

311
#endif
312

313
}  // namespace
314

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

© 2026 Coveralls, Inc