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

randombit / botan / 13776460423

10 Mar 2025 11:00PM UTC coverage: 91.641% (-0.02%) from 91.665%
13776460423

push

github

web-flow
Merge pull request #4765 from randombit/jack/swar-base32

Implement SWAR based base32 encoding

95874 of 104619 relevant lines covered (91.64%)

11254446.13 hits per line

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

55.15
/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

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

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

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

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

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

34
namespace Botan_CLI {
35

36
class PerfTest_Hex final : public PerfTest {
×
37
   public:
38
      void go(const PerfConfig& config) override {
×
39
         for(size_t buf_size : config.buffer_sizes()) {
×
40
            std::vector<uint8_t> ibuf(buf_size);
×
41
            std::vector<uint8_t> rbuf(buf_size);
×
42
            const size_t olen = 2 * buf_size;
×
43

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

46
            auto dec_timer = config.make_timer("hex", olen, "decode", "", olen);
×
47

48
            const auto msec = config.runtime();
×
49

50
            while(enc_timer->under(msec) && dec_timer->under(msec)) {
×
51
               config.rng().randomize(ibuf);
×
52

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

55
               dec_timer->run([&]() { Botan::hex_decode(rbuf.data(), hex); });
×
56
               BOTAN_ASSERT(rbuf == ibuf, "Encode/decode round trip ok");
×
57
            }
×
58

59
            config.record_result(*enc_timer);
×
60
            config.record_result(*dec_timer);
×
61
         }
×
62
      }
×
63
};
64

65
BOTAN_REGISTER_PERF_TEST("hex", PerfTest_Hex);
×
66

67
#if defined(BOTAN_HAS_BASE32_CODEC)
68
class PerfTest_Base32 final : public PerfTest {
×
69
   public:
70
      void go(const PerfConfig& config) override {
×
71
         for(size_t buf_size : config.buffer_sizes()) {
×
72
            std::vector<uint8_t> ibuf(buf_size);
×
73
            std::vector<uint8_t> rbuf(buf_size);
×
74
            const size_t olen = Botan::base32_encode_max_output(ibuf.size());
×
75

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

78
            auto dec_timer = config.make_timer("base32", olen, "decode", "", olen);
×
79

80
            const auto msec = config.runtime();
×
81

82
            while(enc_timer->under(msec) && dec_timer->under(msec)) {
×
83
               config.rng().randomize(ibuf);
×
84

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

87
               dec_timer->run([&]() { Botan::base32_decode(rbuf.data(), b32); });
×
88
               BOTAN_ASSERT(rbuf == ibuf, "Encode/decode round trip ok");
×
89
            }
×
90

91
            config.record_result(*enc_timer);
×
92
            config.record_result(*dec_timer);
×
93
         }
×
94
      }
×
95
};
96

97
BOTAN_REGISTER_PERF_TEST("base32", PerfTest_Base32);
×
98

99
#endif
100

101
#if defined(BOTAN_HAS_BASE64_CODEC)
102
class PerfTest_Base64 final : public PerfTest {
×
103
   public:
104
      void go(const PerfConfig& config) override {
×
105
         for(size_t buf_size : config.buffer_sizes()) {
×
106
            std::vector<uint8_t> ibuf(buf_size);
×
107
            std::vector<uint8_t> rbuf(buf_size);
×
108
            const size_t olen = Botan::base64_encode_max_output(ibuf.size());
×
109

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

112
            auto dec_timer = config.make_timer("base64", olen, "decode", "", olen);
×
113

114
            const auto msec = config.runtime();
×
115

116
            while(enc_timer->under(msec) && dec_timer->under(msec)) {
×
117
               config.rng().randomize(ibuf);
×
118

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

121
               dec_timer->run([&]() { Botan::base64_decode(rbuf.data(), b64); });
×
122
               BOTAN_ASSERT(rbuf == ibuf, "Encode/decode round trip ok");
×
123
            }
×
124

125
            config.record_result(*enc_timer);
×
126
            config.record_result(*dec_timer);
×
127
         }
×
128
      }
×
129
};
130

131
BOTAN_REGISTER_PERF_TEST("base64", PerfTest_Base64);
×
132

133
#endif
134

135
#if defined(BOTAN_HAS_FPE_FE1)
136

137
class PerfTest_FpeFe1 final : public PerfTest {
1✔
138
   public:
139
      void go(const PerfConfig& config) override {
1✔
140
         const auto n = Botan::BigInt::from_u64(1000000000000000);
1✔
141

142
         auto enc_timer = config.make_timer("FPE_FE1 encrypt");
2✔
143
         auto dec_timer = config.make_timer("FPE_FE1 decrypt");
2✔
144

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

148
         auto x = Botan::BigInt::one();
1✔
149

150
         Botan::FPE_FE1 fpe_fe1(n);
1✔
151
         fpe_fe1.set_key(key);
1✔
152

153
         auto runtime = config.runtime();
1✔
154

155
         while(enc_timer->under(runtime)) {
5✔
156
            enc_timer->start();
4✔
157
            x = fpe_fe1.encrypt(x, tweak.data(), tweak.size());
4✔
158
            enc_timer->stop();
4✔
159
         }
160
         config.record_result(*enc_timer);
1✔
161

162
         for(size_t i = 0; i != enc_timer->events(); ++i) {
5✔
163
            dec_timer->start();
4✔
164
            x = fpe_fe1.decrypt(x, tweak.data(), tweak.size());
4✔
165
            dec_timer->stop();
4✔
166
         }
167
         config.record_result(*dec_timer);
1✔
168

169
         BOTAN_ASSERT(x == 1, "FPE works");
1✔
170
      }
4✔
171
};
172

173
BOTAN_REGISTER_PERF_TEST("fpe_fe1", PerfTest_FpeFe1);
1✔
174

175
#endif
176

177
#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
178
class PerfTest_Rfc3394 final : public PerfTest {
1✔
179
      void go(const PerfConfig& config) override {
1✔
180
         auto wrap_timer = config.make_timer("RFC3394 AES-256 key wrap");
2✔
181
         auto unwrap_timer = config.make_timer("RFC3394 AES-256 key unwrap");
2✔
182

183
         const Botan::SymmetricKey kek(config.rng(), 32);
1✔
184
         Botan::secure_vector<uint8_t> key(64, 0);
1✔
185

186
         const auto runtime = config.runtime();
1✔
187

188
         while(wrap_timer->under(runtime)) {
10✔
189
            wrap_timer->start();
9✔
190
            key = Botan::rfc3394_keywrap(key, kek);
18✔
191
            wrap_timer->stop();
9✔
192

193
            unwrap_timer->start();
9✔
194
            key = Botan::rfc3394_keyunwrap(key, kek);
18✔
195
            unwrap_timer->stop();
9✔
196

197
            key[0] += 1;
9✔
198
         }
199

200
         config.record_result(*wrap_timer);
1✔
201
         config.record_result(*unwrap_timer);
2✔
202
      }
3✔
203
};
204

205
BOTAN_REGISTER_PERF_TEST("rfc3394", PerfTest_Rfc3394);
1✔
206

207
#endif
208

209
#if defined(BOTAN_HAS_ZFEC)
210

211
class PerfTest_Zfec final : public PerfTest {
1✔
212
   public:
213
      void go(const PerfConfig& config) override {
1✔
214
         const size_t k = 4;
1✔
215
         const size_t n = 16;
1✔
216

217
         Botan::ZFEC zfec(k, n);
1✔
218

219
         const size_t share_size = 256 * 1024;
1✔
220

221
         std::vector<uint8_t> input(share_size * k);
1✔
222
         config.rng().randomize(input.data(), input.size());
1✔
223

224
         std::vector<uint8_t> output(share_size * n);
1✔
225

226
         auto enc_fn = [&](size_t share, const uint8_t buf[], size_t len) {
17✔
227
            std::memcpy(&output[share * share_size], buf, len);
16✔
228
         };
17✔
229

230
         const auto msec = config.runtime();
1✔
231

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

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

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

238
         config.record_result(*enc_timer);
1✔
239

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

242
         std::map<size_t, const uint8_t*> shares;
1✔
243
         for(size_t i = 0; i != n; ++i) {
17✔
244
            shares[i] = &output[share_size * i];
16✔
245
         }
246

247
         // remove data shares to make decoding maximally expensive:
248
         while(shares.size() != k) {
13✔
249
            shares.erase(shares.begin());
12✔
250
         }
251

252
         std::vector<uint8_t> recovered(share_size * k);
1✔
253

254
         auto dec_fn = [&](size_t share, const uint8_t buf[], size_t len) {
5✔
255
            std::memcpy(&recovered[share * share_size], buf, len);
4✔
256
         };
5✔
257

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

260
         config.record_result(*dec_timer);
1✔
261

262
         if(recovered != input) {
1✔
263
            config.error_output() << "ZFEC recovery failed\n";
×
264
         }
265
      }
4✔
266
};
267

268
BOTAN_REGISTER_PERF_TEST("zfec", PerfTest_Zfec);
1✔
269

270
#endif
271

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