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

randombit / botan / 22282816555

22 Feb 2026 06:28PM UTC coverage: 90.334% (+0.001%) from 90.333%
22282816555

Pull #5382

github

web-flow
Merge b5d330001 into 516662327
Pull Request #5382: Generalize XMSS_Index_Registry and use it for LMS as well

103020 of 114044 relevant lines covered (90.33%)

11708077.91 hits per line

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

87.12
/src/tests/test_concurrent_pk.cpp
1
/*
2
* (C) 2026 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "tests.h"
8

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

18
namespace Botan_Tests {
19

20
#if defined(BOTAN_HAS_PUBLIC_KEY_CRYPTO) && defined(BOTAN_TARGET_OS_HAS_THREADS)
21

22
/*
23
* Test that public key operations (signing, verification, encryption, decryption, KEM, key
24
* agreement) with a shared key from multiple threads produce correct results without racing.
25
*
26
* TODO: Add concurrent test for ECIES handling
27
*/
28

29
namespace {
30

31
constexpr size_t ConcurrentThreads = 10;  // arbitrary
32

33
class ConcurrentPkTestCase {
34
   public:
35
      ConcurrentPkTestCase(std::string_view pk_algo, std::string_view keygen_params, std::string_view op_params = "") :
37✔
36
            m_pk_algo(pk_algo), m_keygen_params(keygen_params), m_op_params(op_params) {}
111✔
37

38
      const std::string& algo_name() const { return m_pk_algo; }
18✔
39

40
      const std::string& op_params() const { return m_op_params; }
440✔
41

42
      Test::Result result(std::string_view operation) const {
55✔
43
         std::ostringstream name;
55✔
44
         name << "Concurrent " << m_pk_algo;
55✔
45
         if(!m_keygen_params.empty()) {
55✔
46
            name << " " << m_keygen_params;
45✔
47
         }
48
         if(!m_op_params.empty()) {
55✔
49
            name << " " << m_op_params;
34✔
50
         }
51
         name << " " << operation;
55✔
52

53
         return Test::Result(name.str());
110✔
54
      }
55✔
55

56
      Test::Result skip_missing(std::string_view operation) const {
×
57
         auto result = this->result(operation);
×
58
         result.test_note("Skipping due to missing algorithm", this->algo_name());
×
59
         return result;
×
60
      }
×
61

62
      std::unique_ptr<Botan::Private_Key> try_create_key(Botan::RandomNumberGenerator& rng) const {
191✔
63
         try {
191✔
64
            return Botan::create_private_key(m_pk_algo, rng, m_keygen_params);
191✔
65
         } catch(Botan::Lookup_Error&) {
×
66
            return nullptr;
×
67
         } catch(Botan::Not_Implemented&) {
×
68
            return nullptr;
×
69
         }
×
70
      }
71

72
   private:
73
      std::string m_pk_algo;
74
      std::string m_keygen_params;
75
      std::string m_op_params;
76
};
77

78
Test::Result test_concurrent_signing(const ConcurrentPkTestCase& tc,
11✔
79
                                     const Botan::Private_Key& privkey,
80
                                     const Botan::Public_Key& pubkey) {
81
   auto result = tc.result("signing");
11✔
82
   auto rng = Test::new_rng(result.who());
11✔
83
   const auto test_message = rng->random_vec(32);
11✔
84

85
   const auto operations_remaining_at_start = privkey.remaining_operations();
11✔
86

87
   std::vector<std::future<std::vector<uint8_t>>> futures;
11✔
88
   futures.reserve(ConcurrentThreads);
11✔
89

90
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
121✔
91
      futures.push_back(std::async(std::launch::async, [&, i]() -> std::vector<uint8_t> {
220✔
92
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
110✔
93
         Botan::PK_Signer signer(privkey, *thread_rng, tc.op_params());
110✔
94
         return signer.sign_message(test_message, *thread_rng);
110✔
95
      }));
220✔
96
   }
97

98
   Botan::PK_Verifier verifier(pubkey, tc.op_params());
11✔
99

100
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
121✔
101
      try {
110✔
102
         const auto signature = futures[i].get();
110✔
103

104
         if(signature.empty()) {
110✔
105
            result.test_failure(Botan::fmt("Thread {} produced empty signature", i));
×
106
         } else {
107
            const bool valid = verifier.verify_message(test_message, signature);
110✔
108
            result.test_is_true(Botan::fmt("Thread {} signature is valid", i), valid);
220✔
109
         }
110
      } catch(std::exception& e) {
110✔
111
         result.test_failure(Botan::fmt("Thread {} failed: {}", i, e.what()));
×
112
      }
×
113
   }
114

115
   if(operations_remaining_at_start.has_value()) {
11✔
116
      result.test_is_true("Private key should be stateful", privkey.stateful_operation());
2✔
117
      const auto left_at_end = privkey.remaining_operations();
2✔
118

119
      if(left_at_end.has_value()) {
2✔
120
         result.test_u64_lt(
2✔
121
            "Number of operations went down", left_at_end.value(), operations_remaining_at_start.value());
2✔
122

123
         const uint64_t consumed = operations_remaining_at_start.value() - left_at_end.value();
2✔
124

125
         result.test_u64_eq(
2✔
126
            "Private key should have consumed exactly ConcurrentThreads many operations", consumed, ConcurrentThreads);
127
      } else {
128
         result.test_failure("Private key remaining_operations should return something both times");
×
129
      }
130
   } else {
131
      result.test_is_false("Private key should not be stateful", privkey.stateful_operation());
9✔
132
   }
133

134
   return result;
22✔
135
}
33✔
136

137
Test::Result test_concurrent_verification(const ConcurrentPkTestCase& tc,
11✔
138
                                          const Botan::Private_Key& privkey,
139
                                          const Botan::Public_Key& pubkey) {
140
   auto result = tc.result("verification");
22✔
141
   auto rng = Test::new_rng(result.who());
11✔
142
   const auto test_message = rng->random_vec(32);
11✔
143

144
   Botan::PK_Signer signer(privkey, *rng, tc.op_params());
11✔
145
   const auto signature = signer.sign_message(test_message, *rng);
11✔
146

147
   std::vector<std::future<bool>> futures;
11✔
148
   futures.reserve(ConcurrentThreads);
11✔
149

150
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
121✔
151
      futures.push_back(std::async(std::launch::async, [&]() -> bool {
220✔
152
         Botan::PK_Verifier verifier(pubkey, tc.op_params());
110✔
153
         return verifier.verify_message(test_message, signature);
220✔
154
      }));
110✔
155
   }
156

157
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
121✔
158
      try {
110✔
159
         const bool valid = futures[i].get();
110✔
160
         result.test_is_true(Botan::fmt("Thread {} verification succeeded", i), valid);
220✔
161
      } catch(std::exception& e) {
×
162
         result.test_failure(Botan::fmt("Thread {} threw: {}", i, e.what()));
×
163
      }
×
164
   }
165

166
   return result;
22✔
167
}
44✔
168

169
Test::Result test_concurrent_encryption(const ConcurrentPkTestCase& tc,
2✔
170
                                        const Botan::Private_Key& privkey,
171
                                        const Botan::Public_Key& pubkey) {
172
   auto result = tc.result("encryption");
2✔
173
   auto rng = Test::new_rng(result.who());
2✔
174
   const auto test_message = rng->random_vec(32);
2✔
175

176
   std::vector<std::future<std::vector<uint8_t>>> futures;
2✔
177
   futures.reserve(ConcurrentThreads);
2✔
178

179
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
22✔
180
      futures.push_back(std::async(std::launch::async, [&, i]() -> std::vector<uint8_t> {
40✔
181
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
20✔
182
         const Botan::PK_Encryptor_EME encryptor(pubkey, *thread_rng, tc.op_params());
20✔
183
         return encryptor.encrypt(test_message, *thread_rng);
20✔
184
      }));
40✔
185
   }
186

187
   const Botan::PK_Decryptor_EME decryptor(privkey, *rng, tc.op_params());
2✔
188

189
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
22✔
190
      try {
20✔
191
         const auto ciphertext = futures[i].get();
20✔
192
         const auto plaintext = decryptor.decrypt(ciphertext);
20✔
193
         result.test_bin_eq(Botan::fmt("Thread {} decrypts correctly", i), plaintext, test_message);
40✔
194
      } catch(std::exception& e) {
40✔
195
         result.test_failure(Botan::fmt("Thread {} encrypt threw: {}", i, e.what()));
×
196
      }
×
197
   }
198

199
   return result;
4✔
200
}
6✔
201

202
Test::Result test_concurrent_decryption(const ConcurrentPkTestCase& tc,
2✔
203
                                        const Botan::Private_Key& privkey,
204
                                        const Botan::Public_Key& pubkey) {
205
   auto result = tc.result("decryption");
2✔
206
   auto rng = Test::new_rng(result.who());
2✔
207
   const auto test_message = rng->random_vec(32);
2✔
208

209
   const Botan::PK_Encryptor_EME encryptor(pubkey, *rng, tc.op_params());
2✔
210
   const auto ciphertext = encryptor.encrypt(test_message, *rng);
2✔
211

212
   std::vector<std::future<Botan::secure_vector<uint8_t>>> futures;
2✔
213
   futures.reserve(ConcurrentThreads);
2✔
214

215
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
22✔
216
      futures.push_back(std::async(std::launch::async, [&, i]() -> Botan::secure_vector<uint8_t> {
40✔
217
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
20✔
218
         const Botan::PK_Decryptor_EME decryptor(privkey, *thread_rng, tc.op_params());
20✔
219
         return decryptor.decrypt(ciphertext);
20✔
220
      }));
40✔
221
   }
222

223
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
22✔
224
      try {
20✔
225
         const auto plaintext = futures[i].get();
20✔
226
         result.test_bin_eq(Botan::fmt("Thread {} decrypts correctly", i), plaintext, test_message);
40✔
227
      } catch(std::exception& e) {
20✔
228
         result.test_failure(Botan::fmt("Thread {} decrypt threw: {}", i, e.what()));
×
229
      }
×
230
   }
231

232
   return result;
4✔
233
}
8✔
234

235
Test::Result test_concurrent_kem_encap(const ConcurrentPkTestCase& tc,
5✔
236
                                       const Botan::Private_Key& privkey,
237
                                       const Botan::Public_Key& pubkey) {
238
   auto result = tc.result("KEM encapsulate");
5✔
239
   auto rng = Test::new_rng(result.who());
5✔
240

241
   std::vector<std::future<Botan::KEM_Encapsulation>> futures;
5✔
242
   futures.reserve(ConcurrentThreads);
5✔
243

244
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
55✔
245
      futures.push_back(std::async(std::launch::async, [&, i]() -> Botan::KEM_Encapsulation {
100✔
246
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
50✔
247
         Botan::PK_KEM_Encryptor encryptor(pubkey, tc.op_params());
50✔
248
         return encryptor.encrypt(*thread_rng);
50✔
249
      }));
100✔
250
   }
251

252
   Botan::PK_KEM_Decryptor decryptor(privkey, *rng, tc.op_params());
5✔
253

254
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
55✔
255
      try {
50✔
256
         const auto kr = futures[i].get();
50✔
257
         const auto shared_key = decryptor.decrypt(kr.encapsulated_shared_key(), 32);
50✔
258
         result.test_bin_eq(Botan::fmt("Thread {} shared key matches", i), shared_key, kr.shared_key());
100✔
259
      } catch(std::exception& e) {
50✔
260
         result.test_failure(Botan::fmt("Thread {} encapsulate threw: {}", i, e.what()));
×
261
      }
×
262
   }
263

264
   return result;
10✔
265
}
10✔
266

267
Test::Result test_concurrent_kem_decap(const ConcurrentPkTestCase& tc,
5✔
268
                                       const Botan::Private_Key& privkey,
269
                                       const Botan::Public_Key& pubkey) {
270
   auto result = tc.result("KEM decapsulate");
5✔
271
   auto rng = Test::new_rng(result.who());
5✔
272

273
   Botan::PK_KEM_Encryptor encryptor(pubkey, tc.op_params());
5✔
274
   auto kem_enc = encryptor.encrypt(*rng);
5✔
275

276
   std::vector<std::future<Botan::secure_vector<uint8_t>>> futures;
5✔
277
   futures.reserve(ConcurrentThreads);
5✔
278

279
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
55✔
280
      futures.push_back(std::async(std::launch::async, [&, i]() -> Botan::secure_vector<uint8_t> {
100✔
281
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
50✔
282
         Botan::PK_KEM_Decryptor decryptor(privkey, *thread_rng, tc.op_params());
50✔
283
         return decryptor.decrypt(kem_enc.encapsulated_shared_key(), 0);
50✔
284
      }));
100✔
285
   }
286

287
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
55✔
288
      try {
50✔
289
         const auto shared_key = futures[i].get();
50✔
290
         result.test_bin_eq(Botan::fmt("Thread {} shared key matches", i), shared_key, kem_enc.shared_key());
100✔
291
      } catch(std::exception& e) {
50✔
292
         result.test_failure(Botan::fmt("Thread {} decapsulate threw: {}", i, e.what()));
×
293
      }
×
294
   }
295

296
   return result;
10✔
297
}
10✔
298

299
Test::Result test_concurrent_key_agreement(const ConcurrentPkTestCase& tc) {
4✔
300
   auto result = tc.result("key agreement");
4✔
301

302
   auto rng = Test::new_rng(result.who());
4✔
303
   auto our_key = tc.try_create_key(*rng);
4✔
304
   if(!our_key) {
4✔
305
      result.test_note("Skipping due to missing algorithm");
×
306
      return result;
×
307
   }
308

309
   auto peer_key = tc.try_create_key(*rng);
4✔
310

311
   const auto* our_ka_key = dynamic_cast<Botan::PK_Key_Agreement_Key*>(our_key.get());
4✔
312
   const auto* peer_ka_key = dynamic_cast<Botan::PK_Key_Agreement_Key*>(peer_key.get());
4✔
313
   if(our_ka_key == nullptr || peer_ka_key == nullptr) {
4✔
314
      result.test_failure("Key does not support key agreement");
×
315
      return result;
316
   }
317

318
   const auto peer_public = peer_ka_key->public_value();
4✔
319

320
   // Compute reference shared secret single-threaded
321
   const Botan::PK_Key_Agreement ref_ka(*our_key, *rng, tc.op_params());
4✔
322
   const auto reference_secret = ref_ka.derive_key(32, peer_public).bits_of();
8✔
323

324
   std::vector<std::future<std::vector<uint8_t>>> futures;
4✔
325
   futures.reserve(ConcurrentThreads);
4✔
326

327
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
44✔
328
      futures.push_back(std::async(std::launch::async, [&, i]() -> std::vector<uint8_t> {
80✔
329
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
40✔
330
         const Botan::PK_Key_Agreement ka(*our_key, *thread_rng, tc.op_params());
40✔
331
         return Botan::unlock(ka.derive_key(32, peer_public).bits_of());
120✔
332
      }));
80✔
333
   }
334

335
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
44✔
336
      try {
40✔
337
         const auto shared_secret = futures[i].get();
40✔
338
         result.test_bin_eq(Botan::fmt("Thread {} shared secret matches", i), shared_secret, reference_secret);
80✔
339
      } catch(std::exception& e) {
40✔
340
         result.test_failure(Botan::fmt("Thread {} threw: {}", i, e.what()));
×
341
      }
×
342
   }
343

344
   return result;
4✔
345
}
24✔
346

347
Test::Result test_concurrent_key_generation(const ConcurrentPkTestCase& tc) {
15✔
348
   auto result = tc.result("key generation");
15✔
349

350
   auto rng = Test::new_rng(result.who());
15✔
351

352
   if(tc.try_create_key(*rng) == nullptr) {
30✔
353
      result.test_note("Keygen not available");
×
354
      return result;
×
355
   }
356

357
   std::vector<std::future<std::unique_ptr<Botan::Private_Key>>> futures;
15✔
358
   futures.reserve(ConcurrentThreads);
15✔
359

360
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
165✔
361
      futures.push_back(std::async(std::launch::async, [&, i]() -> std::unique_ptr<Botan::Private_Key> {
300✔
362
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
150✔
363
         return tc.try_create_key(*thread_rng);
150✔
364
      }));
150✔
365
   }
366

367
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
165✔
368
      try {
150✔
369
         const auto sk = futures[i].get();
150✔
370
         result.test_not_null(Botan::fmt("Thread {} generated a key", i), sk.get());
150✔
371

372
         if(sk) {
150✔
373
            result.test_is_true(Botan::fmt("Thread {} generated key seems valid", i), sk->check_key(*rng, true));
300✔
374
         }
375
      } catch(std::exception& e) {
150✔
376
         result.test_failure(Botan::fmt("Thread {} threw: {}", i, e.what()));
×
377
      }
×
378
   }
379

380
   return result;
15✔
381
}
30✔
382

383
class Concurrent_Public_Key_Operations_Test : public Test {
1✔
384
   public:
385
      std::vector<Test::Result> run() override {
1✔
386
         std::vector<Test::Result> results;
1✔
387

388
         concurrent_signing_and_verification_tests(results);
1✔
389
         concurrent_encryption_tests(results);
1✔
390
         concurrent_kem_tests(results);
1✔
391
         concurrent_key_agreement_tests(results);
1✔
392
         concurrent_key_generation_tests(results);
1✔
393

394
         return results;
1✔
395
      }
×
396

397
   private:
398
      void concurrent_signing_and_verification_tests(std::vector<Test::Result>& results) {
1✔
399
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
400
            ConcurrentPkTestCase("RSA", "1536", "PKCS1v15(SHA-256)"),
401
            ConcurrentPkTestCase("ECDSA", "secp256r1", "SHA-256"),
402
            ConcurrentPkTestCase("ECKCDSA", "secp256r1", "SHA-256"),
403
            ConcurrentPkTestCase("ECGDSA", "secp256r1", "SHA-256"),
404
            ConcurrentPkTestCase("DSA", "dsa/jce/1024", "SHA-256"),
405
            ConcurrentPkTestCase("SM2", "sm2p256v1", "SM3"),
406
            ConcurrentPkTestCase("Ed25519", "", "Pure"),
407
            ConcurrentPkTestCase("Ed448", "", "Pure"),
408
            ConcurrentPkTestCase("SLH-DSA", "SLH-DSA-SHA2-128f"),
409
            ConcurrentPkTestCase("HSS-LMS", "SHA-256,HW(5,8)"),
410
            ConcurrentPkTestCase("XMSS", "XMSS-SHA2_10_256"),
411
         };
12✔
412

413
         for(const auto& tc : test_cases) {
12✔
414
            auto rng = Test::new_rng(tc.algo_name());
11✔
415

416
            if(auto privkey = tc.try_create_key(*rng)) {
11✔
417
               auto pubkey = privkey->public_key();
11✔
418
               results.push_back(test_concurrent_signing(tc, *privkey, *pubkey));
22✔
419
               results.push_back(test_concurrent_verification(tc, *privkey, *pubkey));
22✔
420
            } else {
11✔
421
               results.push_back(tc.skip_missing("signing"));
×
422
            }
11✔
423
         }
11✔
424
      }
3✔
425

426
      void concurrent_encryption_tests(std::vector<Test::Result>& results) {
1✔
427
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
428
            ConcurrentPkTestCase("RSA", "1536", "OAEP(SHA-256)"),
429
            ConcurrentPkTestCase("ElGamal", "modp/ietf/1536", "PKCS1v15"),
430
         };
3✔
431

432
         for(const auto& tc : test_cases) {
3✔
433
            auto rng = Test::new_rng(tc.algo_name());
2✔
434

435
            if(auto privkey = tc.try_create_key(*rng)) {
2✔
436
               auto pubkey = privkey->public_key();
2✔
437
               results.push_back(test_concurrent_encryption(tc, *privkey, *pubkey));
4✔
438
               results.push_back(test_concurrent_decryption(tc, *privkey, *pubkey));
4✔
439
            } else {
2✔
440
               results.push_back(tc.skip_missing("encryption"));
×
441
            }
2✔
442
         }
2✔
443
      }
3✔
444

445
      void concurrent_kem_tests(std::vector<Test::Result>& results) {
1✔
446
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
447
            ConcurrentPkTestCase("RSA", "1536", "Raw"),
448
            ConcurrentPkTestCase("ClassicMcEliece", "348864f", "Raw"),
449
            ConcurrentPkTestCase("McEliece", "1632,33", "Raw"),
450
            ConcurrentPkTestCase("FrodoKEM", "FrodoKEM-640-SHAKE", "Raw"),
451
            ConcurrentPkTestCase("FrodoKEM", "FrodoKEM-640-AES", "Raw"),
452
         };
6✔
453

454
         for(const auto& tc : test_cases) {
6✔
455
            auto rng = Test::new_rng(tc.algo_name());
5✔
456
            if(auto privkey = tc.try_create_key(*rng)) {
5✔
457
               auto pubkey = privkey->public_key();
5✔
458
               results.push_back(test_concurrent_kem_encap(tc, *privkey, *pubkey));
10✔
459
               results.push_back(test_concurrent_kem_decap(tc, *privkey, *pubkey));
10✔
460
            } else {
5✔
461
               results.push_back(tc.skip_missing("KEM encapsulate"));
×
462
            }
5✔
463
         }
5✔
464
      }
3✔
465

466
      void concurrent_key_agreement_tests(std::vector<Test::Result>& results) {
1✔
467
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
468
            ConcurrentPkTestCase("DH", "modp/ietf/1536", "Raw"),
469
            ConcurrentPkTestCase("ECDH", "secp256r1", "Raw"),
470
            ConcurrentPkTestCase("X25519", "", "Raw"),
471
            ConcurrentPkTestCase("X448", "", "Raw"),
472
         };
5✔
473

474
         for(const auto& tc : test_cases) {
5✔
475
            results.push_back(test_concurrent_key_agreement(tc));
8✔
476
         }
477
      }
3✔
478

479
      void concurrent_key_generation_tests(std::vector<Test::Result>& results) {
1✔
480
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
481
            ConcurrentPkTestCase("ClassicMcEliece", "348864f"),
482
            ConcurrentPkTestCase("DH", "modp/ietf/1536"),
483
            ConcurrentPkTestCase("DSA", "dsa/jce/1024"),
484
            ConcurrentPkTestCase("ECDH", "secp256r1"),
485
            ConcurrentPkTestCase("ECDSA", "secp256r1"),
486
            ConcurrentPkTestCase("ECGDSA", "secp256r1"),
487
            ConcurrentPkTestCase("ECKCDSA", "secp256r1"),
488
            ConcurrentPkTestCase("Ed25519", ""),
489
            ConcurrentPkTestCase("Ed448", ""),
490
            ConcurrentPkTestCase("HSS-LMS", "SHA-256,HW(5,8)"),
491
            ConcurrentPkTestCase("RSA", "1536"),
492
            ConcurrentPkTestCase("SLH-DSA", "SLH-DSA-SHA2-128f"),
493
            ConcurrentPkTestCase("SM2", "sm2p256v1"),
494
            ConcurrentPkTestCase("X25519", ""),
495
            ConcurrentPkTestCase("X448", ""),
496
         };
16✔
497

498
         for(const auto& tc : test_cases) {
16✔
499
            results.push_back(test_concurrent_key_generation(tc));
30✔
500
         }
501
      }
3✔
502
};
503

504
BOTAN_REGISTER_SERIALIZED_TEST("pubkey", "pk_concurrent_ops", Concurrent_Public_Key_Operations_Test);
505

506
}  // namespace
507

508
#endif
509

510
}  // namespace Botan_Tests
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