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

randombit / botan / 23591805450

26 Mar 2026 11:25AM UTC coverage: 89.514% (+0.02%) from 89.49%
23591805450

Pull #5451

github

web-flow
Merge d4d4afeab into f42220269
Pull Request #5451: MLDSA-composite

106304 of 118757 relevant lines covered (89.51%)

12472589.86 hits per line

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

55.63
/src/cli/perf_pk_sig.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

9
#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
10
   #include <botan/pk_algs.h>
11
   #include <botan/pubkey.h>
12
   #include <botan/rng.h>
13
   #include <botan/internal/fmt.h>
14
#endif
15

16
#if defined(BOTAN_HAS_MLDSA_COMPOSITE)
17
   #include <botan/mldsa_comp.h>
18
   #include <botan/mldsa_comp_parameters.h>
19
#endif
20

21
namespace Botan_CLI {
22

23
namespace {
24

25
#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO)
26

27
class PerfTest_PKSig : public PerfTest {
9✔
28
   public:
29
      virtual std::string algo() const = 0;
30

31
      virtual std::string hash() const { return "SHA-256"; }
4✔
32

33
      virtual std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const { return {""}; }
2✔
34

35
      void go(const PerfConfig& config) override {
9✔
36
         const std::string alg = this->algo();
9✔
37
         const std::string padding = this->hash();
9✔
38

39
         const auto params = this->keygen_params(config);
9✔
40

41
         for(const auto& param : params) {
37✔
42
            const std::string nm = this->format_name(alg, param);
28✔
43
            bench_pk_sig(config, nm, alg, param, padding);
56✔
44
         }
28✔
45
      }
9✔
46

47
      static void bench_pk_sig(const PerfConfig& config,
28✔
48
                               const std::string& nm,
49
                               const std::string& alg,
50
                               const std::string& param,
51
                               const std::string& padding,
52
                               const std::string& provider = "") {
53
         auto& rng = config.rng();
28✔
54
         const auto msec = config.runtime();
55

56
         auto keygen_timer = config.make_timer(nm, 1, "keygen");
56✔
57

58
         auto sk = keygen_timer->run([&] { return Botan::create_private_key(alg, rng, param); });
56✔
59

60
         if(sk != nullptr) {
28✔
61
            while(keygen_timer->under(msec)) {
78✔
62
               sk = keygen_timer->run([&] { return Botan::create_private_key(alg, rng, param); });
150✔
63
            }
64

65
            config.record_result(*keygen_timer);
28✔
66

67
            auto pk = sk->public_key();
28✔
68

69
            std::vector<uint8_t> message;
28✔
70
            std::vector<uint8_t> signature;
28✔
71
            std::vector<uint8_t> bad_signature;
28✔
72

73
            Botan::PK_Signer sig(*sk, rng, padding, Botan::Signature_Format::Standard, provider);
28✔
74
            Botan::PK_Verifier ver(*pk, padding, Botan::Signature_Format::Standard, provider);
28✔
75

76
            auto sig_timer = config.make_timer(nm, 1, "sign");
56✔
77
            auto ver_timer = config.make_timer(nm, 1, "verify");
56✔
78

79
            size_t invalid_sigs = 0;
28✔
80

81
            while(ver_timer->under(msec) || sig_timer->under(msec)) {
171✔
82
               if(signature.empty() || sig_timer->under(msec)) {
115✔
83
                  /*
84
                  Length here is kind of arbitrary, but 48 bytes fits into a single
85
                  hash block so minimizes hashing overhead versus the PK op itself.
86
                  */
87
                  rng.random_vec(message, 48);
112✔
88

89
                  signature = sig_timer->run([&]() { return sig.sign_message(message, rng); });
224✔
90

91
                  bad_signature = signature;
112✔
92
                  bad_signature[rng.next_byte() % bad_signature.size()] ^= rng.next_nonzero_byte();
112✔
93
               }
94

95
               if(ver_timer->under(msec)) {
115✔
96
                  const bool verified = ver_timer->run([&] { return ver.verify_message(message, signature); });
88✔
97

98
                  if(!verified) {
44✔
99
                     invalid_sigs += 1;
×
100
                  }
101

102
                  const bool verified_bad = ver_timer->run([&] { return ver.verify_message(message, bad_signature); });
88✔
103

104
                  if(verified_bad) {
44✔
105
                     config.error_output() << "Bad signature accepted in " << nm << " signature bench\n";
×
106
                  }
107
               }
108
            }
109

110
            if(invalid_sigs > 0) {
28✔
111
               config.error_output() << invalid_sigs << " generated signatures rejected in " << nm
×
112
                                     << " signature bench\n";
×
113
            }
114
            config.record_result(*sig_timer);
28✔
115
            config.record_result(*ver_timer);
56✔
116
         }
56✔
117
      }
28✔
118
};
119

120
#endif
121

122
#if defined(BOTAN_HAS_DSA)
123

124
class PerfTest_DSA final : public PerfTest_PKSig {
1✔
125
   public:
126
      std::string algo() const override { return "DSA"; }
1✔
127

128
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override {
1✔
129
         return {"dsa/jce/1024", "dsa/botan/2048", "dsa/botan/3072"};
1✔
130
      }
131

132
      std::string format_name(const std::string& alg, const std::string& param) const override {
3✔
133
         return Botan::fmt("{}-{}", alg, param.substr(param.find_last_of('/') + 1));
6✔
134
      }
135
};
136

137
BOTAN_REGISTER_PERF_TEST("DSA", PerfTest_DSA);
1✔
138

139
#endif
140

141
#if defined(BOTAN_HAS_RSA)
142

143
class PerfTest_RSA final : public PerfTest_PKSig {
×
144
   public:
145
      std::string algo() const override { return "RSA"; }
×
146

147
      std::string hash() const override { return "PKCS1v15(SHA-256)"; }
×
148

149
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override {
×
150
         return {"1024", "2048", "3072", "4096"};
×
151
      }
152
};
153

154
BOTAN_REGISTER_PERF_TEST("RSA", PerfTest_RSA);
×
155

156
#endif
157

158
#if defined(BOTAN_HAS_ECDSA)
159

160
class PerfTest_ECDSA final : public PerfTest_PKSig {
1✔
161
   public:
162
      std::string algo() const override { return "ECDSA"; }
1✔
163

164
      std::vector<std::string> keygen_params(const PerfConfig& config) const override { return config.ecc_groups(); }
1✔
165
};
166

167
BOTAN_REGISTER_PERF_TEST("ECDSA", PerfTest_ECDSA);
1✔
168

169
#endif
170

171
#if defined(BOTAN_HAS_ECKCDSA)
172

173
class PerfTest_ECKCDSA final : public PerfTest_PKSig {
1✔
174
   public:
175
      std::string algo() const override { return "ECKCDSA"; }
1✔
176

177
      std::vector<std::string> keygen_params(const PerfConfig& config) const override { return config.ecc_groups(); }
1✔
178
};
179

180
BOTAN_REGISTER_PERF_TEST("ECKCDSA", PerfTest_ECKCDSA);
1✔
181

182
#endif
183

184
#if defined(BOTAN_HAS_ECGDSA)
185

186
class PerfTest_ECGDSA final : public PerfTest_PKSig {
1✔
187
   public:
188
      std::string algo() const override { return "ECGDSA"; }
1✔
189

190
      std::vector<std::string> keygen_params(const PerfConfig& config) const override { return config.ecc_groups(); }
1✔
191
};
192

193
BOTAN_REGISTER_PERF_TEST("ECGDSA", PerfTest_ECGDSA);
1✔
194

195
#endif
196

197
#if defined(BOTAN_HAS_GOST_34_10_2001) && defined(BOTAN_HAS_GOST_34_11)
198

199
class PerfTest_Gost3410 final : public PerfTest_PKSig {
1✔
200
   public:
201
      std::string algo() const override { return "GOST-34.10"; }
1✔
202

203
      std::string hash() const override { return "GOST-34.11"; }
1✔
204

205
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override { return {"gost_256A"}; }
1✔
206
};
207

208
BOTAN_REGISTER_PERF_TEST("GOST-34.10", PerfTest_Gost3410);
1✔
209

210
#endif
211

212
#if defined(BOTAN_HAS_SM2) && defined(BOTAN_HAS_SM3)
213

214
class PerfTest_SM2 final : public PerfTest_PKSig {
1✔
215
   public:
216
      std::string algo() const override { return "SM2"; }
1✔
217

218
      std::string hash() const override { return "SM3"; }
1✔
219

220
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override { return {"sm2p256v1"}; }
1✔
221
};
222

223
BOTAN_REGISTER_PERF_TEST("SM2", PerfTest_SM2);
1✔
224

225
#endif
226

227
#if defined(BOTAN_HAS_ED25519)
228

229
class PerfTest_Ed25519 final : public PerfTest_PKSig {
1✔
230
   public:
231
      std::string algo() const override { return "Ed25519"; }
1✔
232

233
      std::string hash() const override { return "Pure"; }
1✔
234
};
235

236
BOTAN_REGISTER_PERF_TEST("Ed25519", PerfTest_Ed25519);
1✔
237

238
#endif
239

240
#if defined(BOTAN_HAS_ED448)
241

242
class PerfTest_Ed448 final : public PerfTest_PKSig {
1✔
243
   public:
244
      std::string algo() const override { return "Ed448"; }
1✔
245

246
      std::string hash() const override { return "Pure"; }
1✔
247
};
248

249
BOTAN_REGISTER_PERF_TEST("Ed448", PerfTest_Ed448);
1✔
250

251
#endif
252

253
#if defined(BOTAN_HAS_XMSS_RFC8391)
254

255
class PerfTest_XMSS final : public PerfTest_PKSig {
×
256
   public:
257
      std::string algo() const override { return "XMSS"; }
×
258

259
      std::string hash() const override { return ""; }
×
260

261
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override {
×
262
         /*
263
         We only test H10 signatures here since already they are quite slow (a
264
         few seconds per signature). On a fast machine, H16 signatures take 1-2
265
         minutes to generate and H20 signatures take 5-10 minutes to generate
266
         */
267
         return {
×
268
            "XMSS-SHA2_10_256",
269
            "XMSS-SHAKE_10_256",
270
            "XMSS-SHA2_10_512",
271
            "XMSS-SHAKE_10_512",
272
         };
×
273
      }
274
};
275

276
BOTAN_REGISTER_PERF_TEST("XMSS", PerfTest_XMSS);
×
277

278
#endif
279

280
#if defined(BOTAN_HAS_HSS_LMS)
281

282
class PerfTest_HSS_LMS final : public PerfTest_PKSig {
×
283
   public:
284
      std::string algo() const override { return "HSS-LMS"; }
×
285

286
      std::string hash() const override { return ""; }
×
287

288
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override {
×
289
         // At first we compare instances with multiple hash functions. LMS trees with
290
         // height 10 are suitable, since they can be used for enough signatures and are
291
         // fast enough for speed testing.
292
         // Afterward, setups with multiple HSS layers are tested
293
         return {"SHA-256,HW(10,1)",
×
294
                 "SHAKE-256(256),HW(10,1)",
295
                 "SHAKE-256(192),HW(10,1)",
296
                 "Truncated(SHA-256,192),HW(10,1)",
297
                 "SHA-256,HW(10,1),HW(10,1)",
298
                 "SHA-256,HW(10,1),HW(10,1),HW(10,1)"};
×
299
      }
300
};
301

302
BOTAN_REGISTER_PERF_TEST("HSS-LMS", PerfTest_HSS_LMS);
×
303

304
#endif
305

306
#if defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHA2) || defined(BOTAN_HAS_SPHINCS_PLUS_WITH_SHAKE)
307

308
class PerfTest_SPHINCSp final : public PerfTest_PKSig {
×
309
   public:
310
      std::string algo() const override { return "SPHINCS+"; }
×
311

312
      std::string hash() const override { return ""; }
×
313

314
      std::string format_name(const std::string& alg, const std::string& param) const override {
×
315
         return alg + param.substr(11);
×
316
      }
317

318
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override {
×
319
         return {"SphincsPlus-sha2-128s-r3.1",
×
320
                 "SphincsPlus-sha2-128f-r3.1",
321
                 "SphincsPlus-sha2-192s-r3.1",
322
                 "SphincsPlus-sha2-192f-r3.1",
323
                 "SphincsPlus-sha2-256s-r3.1",
324
                 "SphincsPlus-sha2-256f-r3.1",
325
                 "SphincsPlus-shake-128s-r3.1",
326
                 "SphincsPlus-shake-128f-r3.1",
327
                 "SphincsPlus-shake-192s-r3.1",
328
                 "SphincsPlus-shake-192f-r3.1",
329
                 "SphincsPlus-shake-256s-r3.1",
330
                 "SphincsPlus-shake-256f-r3.1"};
×
331
      }
332
};
333

334
BOTAN_REGISTER_PERF_TEST("SPHINCS+", PerfTest_SPHINCSp);
×
335

336
#endif
337

338
#if defined(BOTAN_HAS_SLH_DSA_WITH_SHA2) || defined(BOTAN_HAS_SLH_DSA_WITH_SHAKE)
339

340
class PerfTest_SLH_DSA final : public PerfTest_PKSig {
×
341
   public:
342
      std::string algo() const override { return "SLH-DSA"; }
×
343

344
      std::string hash() const override { return ""; }
×
345

346
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override {
×
347
         return {"SLH-DSA-SHA2-128s",
×
348
                 "SLH-DSA-SHA2-128f",
349
                 "SLH-DSA-SHA2-192s",
350
                 "SLH-DSA-SHA2-192f",
351
                 "SLH-DSA-SHA2-256s",
352
                 "SLH-DSA-SHA2-256f",
353
                 "SLH-DSA-SHAKE-128s",
354
                 "SLH-DSA-SHAKE-128f",
355
                 "SLH-DSA-SHAKE-192s",
356
                 "SLH-DSA-SHAKE-192f",
357
                 "SLH-DSA-SHAKE-256s",
358
                 "SLH-DSA-SHAKE-256f"};
×
359
      }
360
};
361

362
BOTAN_REGISTER_PERF_TEST("SLH-DSA", PerfTest_SLH_DSA);
×
363

364
#endif
365

366
#if defined(BOTAN_HAS_DILITHIUM) || defined(BOTAN_HAS_DILITHIUM_AES)
367

368
class PerfTest_Dilithium final : public PerfTest_PKSig {
×
369
   public:
370
      std::string algo() const override { return "Dilithium"; }
×
371

372
      std::string hash() const override { return ""; }
×
373

374
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override {
×
375
         return {
×
376
            "Dilithium-4x4-r3",
377
            "Dilithium-4x4-AES-r3",
378
            "Dilithium-6x5-r3",
379
            "Dilithium-6x5-AES-r3",
380
            "Dilithium-8x7-r3",
381
            "Dilithium-8x7-AES-r3",
382
         };
×
383
      }
384
};
385

386
BOTAN_REGISTER_PERF_TEST("Dilithium", PerfTest_Dilithium);
×
387

388
#endif
389

390
#if defined(BOTAN_HAS_ML_DSA)
391

392
class PerfTest_ML_DSA final : public PerfTest_PKSig {
1✔
393
   public:
394
      std::string algo() const override { return "ML-DSA"; }
1✔
395

396
      std::string hash() const override { return ""; }
1✔
397

398
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override {
1✔
399
         return {
1✔
400
            "ML-DSA-4x4",
401
            "ML-DSA-6x5",
402
            "ML-DSA-8x7",
403
         };
1✔
404
      }
405
};
406

407
BOTAN_REGISTER_PERF_TEST("ML-DSA", PerfTest_ML_DSA);
1✔
408

409
#endif
410

411
}  // namespace
412

413
#if defined(BOTAN_HAS_MLDSA_COMPOSITE)
414

415
template <Botan::MLDSA_Composite_Param::id_t A>
416
class PerfTest_MLDSA_Composite final : public PerfTest_PKSig {
×
417
   public:
418
      std::string algo() const override { return Botan::MLDSA_Composite_Param::from_id_or_throw(A).id_str(); }
×
419

420
      std::string hash() const override { return ""; }
×
421

422
      std::vector<std::string> keygen_params(const PerfConfig& /*config*/) const override {
×
423
         return {Botan::MLDSA_Composite_Param::from_id_or_throw(A).id_str()};
×
424
      }
×
425
};
426

427
// NOLINTNEXTLINE(cppcoreguidelines-macro-usag)
428
   #define BOTAN_REGISTER_PERF_TEST_TMPL(name, Perf_Class)                                   \
429
      /* NOLINTNEXTLINE(cert-err58-cpp) */                                                   \
430
      const Botan_CLI::PerfTest::Registration reg_perf_##Perf_Class##_##name(                \
431
         #name, []() -> std::unique_ptr<Botan_CLI::PerfTest> {                               \
432
            /* NOLINTNEXTLINE(bugprone-macro-parentheses) */                                 \
433
            return std::make_unique<Perf_Class<Botan::MLDSA_Composite_Param::id_t::name>>(); \
434
         })
435

436
   #if defined(BOTAN_HAS_RSA)
437
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA44_RSA2048_PKCS15_SHA256, PerfTest_MLDSA_Composite);
×
438
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA65_RSA3072_PKCS15_SHA512, PerfTest_MLDSA_Composite);
×
439
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA65_RSA4096_PKCS15_SHA512, PerfTest_MLDSA_Composite);
×
440
   #endif
441
   #if defined(BOTAN_HAS_PSS)
442
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA44_RSA2048_PSS_SHA256, PerfTest_MLDSA_Composite);
×
443
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA65_RSA3072_PSS_SHA512, PerfTest_MLDSA_Composite);
×
444
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA65_RSA4096_PSS_SHA512, PerfTest_MLDSA_Composite);
×
445
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA87_RSA3072_PSS_SHA512, PerfTest_MLDSA_Composite);
×
446
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA87_RSA4096_PSS_SHA512, PerfTest_MLDSA_Composite);
×
447
   #endif
448
   #if defined(BOTAN_HAS_ECDSA)
449
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA44_ECDSA_P256_SHA256, PerfTest_MLDSA_Composite);
×
450
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA65_ECDSA_P256_SHA512, PerfTest_MLDSA_Composite);
×
451
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA65_ECDSA_P384_SHA512, PerfTest_MLDSA_Composite);
×
452
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA65_ECDSA_brainpoolP256r1_SHA512, PerfTest_MLDSA_Composite);
×
453
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA87_ECDSA_P384_SHA512, PerfTest_MLDSA_Composite);
×
454
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA87_ECDSA_brainpoolP384r1_SHA512, PerfTest_MLDSA_Composite);
×
455
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA87_ECDSA_P521_SHA512, PerfTest_MLDSA_Composite);
×
456
   #endif
457
   #if defined(BOTAN_HAS_ED25519)
458
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA44_Ed25519_SHA512, PerfTest_MLDSA_Composite);
×
459
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA65_Ed25519_SHA512, PerfTest_MLDSA_Composite);
×
460
   #endif
461
   #if defined(BOTAN_HAS_ED448)
462
BOTAN_REGISTER_PERF_TEST_TMPL(MLDSA87_Ed448_SHAKE256, PerfTest_MLDSA_Composite);
×
463
   #endif
464
#endif
465

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