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

randombit / botan / 27456950099

12 Jun 2026 07:59PM UTC coverage: 89.424% (+0.05%) from 89.378%
27456950099

push

github

web-flow
Merge pull request #5663 from randombit/jack/dns-uri-ip-fixes

Bugfixes and enhancements for DNSName, URI, IPv4Address, IPv6Address

111165 of 124312 relevant lines covered (89.42%)

10989620.56 hits per line

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

87.38
/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 <algorithm>
15
   #include <future>
16
   #include <sstream>
17
#endif
18

19
namespace Botan_Tests {
20

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

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

30
namespace {
31

32
constexpr size_t ConcurrentThreads = 10;  // arbitrary
33

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

39
      const std::string& algo_name() const { return m_pk_algo; }
24✔
40

41
      const std::string& op_params() const { return m_op_params; }
572✔
42

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

54
         return Test::Result(name.str());
134✔
55
      }
67✔
56

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

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

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

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

86
   const auto operations_remaining_at_start = privkey.remaining_operations();
14✔
87

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

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

99
   Botan::PK_Verifier verifier(pubkey, tc.op_params());
14✔
100

101
   std::vector<std::vector<uint8_t>> signatures;
14✔
102

103
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
154✔
104
      try {
140✔
105
         auto signature = futures[i].get();
140✔
106

107
         if(signature.empty()) {
140✔
108
            result.test_failure(Botan::fmt("Thread {} produced empty signature", i));
×
109
         } else {
110
            const bool valid = verifier.verify_message(test_message, signature);
140✔
111
            result.test_is_true(Botan::fmt("Thread {} signature is valid", i), valid);
140✔
112
            signatures.push_back(std::move(signature));
140✔
113
         }
114
      } catch(std::exception& e) {
140✔
115
         result.test_failure(Botan::fmt("Thread {} failed: {}", i, e.what()));
×
116
      }
×
117
   }
118

119
   if(privkey.stateful_operation()) {
14✔
120
      // Stateful schemes sign deterministically for a given index, so a
121
      // duplicate signature over the same message indicates index reuse
122
      std::sort(signatures.begin(), signatures.end());
2✔
123
      const bool unique = std::adjacent_find(signatures.begin(), signatures.end()) == signatures.end();
2✔
124
      result.test_is_true("Stateful key used a distinct index for each signature", unique);
2✔
125
   }
126

127
   if(operations_remaining_at_start.has_value()) {
14✔
128
      result.test_is_true("Private key should be stateful", privkey.stateful_operation());
2✔
129
      const auto left_at_end = privkey.remaining_operations();
2✔
130

131
      if(left_at_end.has_value()) {
2✔
132
         result.test_u64_lt(
2✔
133
            "Number of operations went down", left_at_end.value(), operations_remaining_at_start.value());
2✔
134

135
         const uint64_t consumed = operations_remaining_at_start.value() - left_at_end.value();
2✔
136

137
         result.test_u64_eq(
2✔
138
            "Private key should have consumed exactly ConcurrentThreads many operations", consumed, ConcurrentThreads);
139
      } else {
140
         result.test_failure("Private key remaining_operations should return something both times");
×
141
      }
142
   } else {
143
      result.test_is_false("Private key should not be stateful", privkey.stateful_operation());
12✔
144
   }
145

146
   return result;
28✔
147
}
42✔
148

149
Test::Result test_concurrent_verification(const ConcurrentPkTestCase& tc,
14✔
150
                                          const Botan::Private_Key& privkey,
151
                                          const Botan::Public_Key& pubkey) {
152
   auto result = tc.result("verification");
14✔
153
   auto rng = Test::new_rng(result.who());
14✔
154
   const auto test_message = rng->random_vec(32);
14✔
155

156
   Botan::PK_Signer signer(privkey, *rng, tc.op_params());
14✔
157
   const auto signature = signer.sign_message(test_message, *rng);
14✔
158

159
   std::vector<std::future<bool>> futures;
14✔
160
   futures.reserve(ConcurrentThreads);
14✔
161

162
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
154✔
163
      futures.push_back(std::async(std::launch::async, [&]() -> bool {
280✔
164
         Botan::PK_Verifier verifier(pubkey, tc.op_params());
140✔
165
         return verifier.verify_message(test_message, signature);
280✔
166
      }));
140✔
167
   }
168

169
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
154✔
170
      try {
140✔
171
         const bool valid = futures[i].get();
140✔
172
         result.test_is_true(Botan::fmt("Thread {} verification succeeded", i), valid);
280✔
173
      } catch(std::exception& e) {
×
174
         result.test_failure(Botan::fmt("Thread {} threw: {}", i, e.what()));
×
175
      }
×
176
   }
177

178
   return result;
28✔
179
}
56✔
180

181
Test::Result test_concurrent_encryption(const ConcurrentPkTestCase& tc,
2✔
182
                                        const Botan::Private_Key& privkey,
183
                                        const Botan::Public_Key& pubkey) {
184
   auto result = tc.result("encryption");
2✔
185
   auto rng = Test::new_rng(result.who());
2✔
186
   const auto test_message = rng->random_vec(32);
2✔
187

188
   std::vector<std::future<std::vector<uint8_t>>> futures;
2✔
189
   futures.reserve(ConcurrentThreads);
2✔
190

191
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
22✔
192
      futures.push_back(std::async(std::launch::async, [&, i]() -> std::vector<uint8_t> {
40✔
193
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
20✔
194
         const Botan::PK_Encryptor_EME encryptor(pubkey, *thread_rng, tc.op_params());
20✔
195
         return encryptor.encrypt(test_message, *thread_rng);
20✔
196
      }));
40✔
197
   }
198

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

201
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
22✔
202
      try {
20✔
203
         const auto ciphertext = futures[i].get();
20✔
204
         const auto plaintext = decryptor.decrypt(ciphertext);
20✔
205
         result.test_bin_eq(Botan::fmt("Thread {} decrypts correctly", i), plaintext, test_message);
40✔
206
      } catch(std::exception& e) {
40✔
207
         result.test_failure(Botan::fmt("Thread {} encrypt threw: {}", i, e.what()));
×
208
      }
×
209
   }
210

211
   return result;
4✔
212
}
6✔
213

214
Test::Result test_concurrent_decryption(const ConcurrentPkTestCase& tc,
2✔
215
                                        const Botan::Private_Key& privkey,
216
                                        const Botan::Public_Key& pubkey) {
217
   auto result = tc.result("decryption");
2✔
218
   auto rng = Test::new_rng(result.who());
2✔
219
   const auto test_message = rng->random_vec(32);
2✔
220

221
   const Botan::PK_Encryptor_EME encryptor(pubkey, *rng, tc.op_params());
2✔
222
   const auto ciphertext = encryptor.encrypt(test_message, *rng);
2✔
223

224
   std::vector<std::future<Botan::secure_vector<uint8_t>>> futures;
2✔
225
   futures.reserve(ConcurrentThreads);
2✔
226

227
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
22✔
228
      futures.push_back(std::async(std::launch::async, [&, i]() -> Botan::secure_vector<uint8_t> {
40✔
229
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
20✔
230
         const Botan::PK_Decryptor_EME decryptor(privkey, *thread_rng, tc.op_params());
20✔
231
         return decryptor.decrypt(ciphertext);
20✔
232
      }));
40✔
233
   }
234

235
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
22✔
236
      try {
20✔
237
         const auto plaintext = futures[i].get();
20✔
238
         result.test_bin_eq(Botan::fmt("Thread {} decrypts correctly", i), plaintext, test_message);
40✔
239
      } catch(std::exception& e) {
20✔
240
         result.test_failure(Botan::fmt("Thread {} decrypt threw: {}", i, e.what()));
×
241
      }
×
242
   }
243

244
   return result;
4✔
245
}
8✔
246

247
Test::Result test_concurrent_kem_encap(const ConcurrentPkTestCase& tc,
8✔
248
                                       const Botan::Private_Key& privkey,
249
                                       const Botan::Public_Key& pubkey) {
250
   auto result = tc.result("KEM encapsulate");
8✔
251
   auto rng = Test::new_rng(result.who());
8✔
252

253
   std::vector<std::future<Botan::KEM_Encapsulation>> futures;
8✔
254
   futures.reserve(ConcurrentThreads);
8✔
255

256
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
88✔
257
      futures.push_back(std::async(std::launch::async, [&, i]() -> Botan::KEM_Encapsulation {
160✔
258
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
80✔
259
         Botan::PK_KEM_Encryptor encryptor(pubkey, tc.op_params());
80✔
260
         return encryptor.encrypt(*thread_rng);
80✔
261
      }));
160✔
262
   }
263

264
   Botan::PK_KEM_Decryptor decryptor(privkey, *rng, tc.op_params());
8✔
265

266
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
88✔
267
      try {
80✔
268
         const auto kr = futures[i].get();
80✔
269
         const auto shared_key = decryptor.decrypt(kr.encapsulated_shared_key(), 32);
80✔
270
         result.test_bin_eq(Botan::fmt("Thread {} shared key matches", i), shared_key, kr.shared_key());
160✔
271
      } catch(std::exception& e) {
80✔
272
         result.test_failure(Botan::fmt("Thread {} encapsulate threw: {}", i, e.what()));
×
273
      }
×
274
   }
275

276
   return result;
16✔
277
}
16✔
278

279
Test::Result test_concurrent_kem_decap(const ConcurrentPkTestCase& tc,
8✔
280
                                       const Botan::Private_Key& privkey,
281
                                       const Botan::Public_Key& pubkey) {
282
   auto result = tc.result("KEM decapsulate");
8✔
283
   auto rng = Test::new_rng(result.who());
8✔
284

285
   Botan::PK_KEM_Encryptor encryptor(pubkey, tc.op_params());
8✔
286
   auto kem_enc = encryptor.encrypt(*rng);
8✔
287

288
   std::vector<std::future<Botan::secure_vector<uint8_t>>> futures;
8✔
289
   futures.reserve(ConcurrentThreads);
8✔
290

291
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
88✔
292
      futures.push_back(std::async(std::launch::async, [&, i]() -> Botan::secure_vector<uint8_t> {
160✔
293
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
80✔
294
         Botan::PK_KEM_Decryptor decryptor(privkey, *thread_rng, tc.op_params());
80✔
295
         return decryptor.decrypt(kem_enc.encapsulated_shared_key(), 0);
80✔
296
      }));
160✔
297
   }
298

299
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
88✔
300
      try {
80✔
301
         const auto shared_key = futures[i].get();
80✔
302
         result.test_bin_eq(Botan::fmt("Thread {} shared key matches", i), shared_key, kem_enc.shared_key());
160✔
303
      } catch(std::exception& e) {
80✔
304
         result.test_failure(Botan::fmt("Thread {} decapsulate threw: {}", i, e.what()));
×
305
      }
×
306
   }
307

308
   return result;
16✔
309
}
16✔
310

311
Test::Result test_concurrent_key_agreement(const ConcurrentPkTestCase& tc) {
4✔
312
   auto result = tc.result("key agreement");
4✔
313

314
   auto rng = Test::new_rng(result.who());
4✔
315
   auto our_key = tc.try_create_key(*rng);
4✔
316
   if(!our_key) {
4✔
317
      result.test_note("Skipping due to missing algorithm");
×
318
      return result;
×
319
   }
320

321
   auto peer_key = tc.try_create_key(*rng);
4✔
322

323
   const auto* our_ka_key = dynamic_cast<Botan::PK_Key_Agreement_Key*>(our_key.get());
4✔
324
   const auto* peer_ka_key = dynamic_cast<Botan::PK_Key_Agreement_Key*>(peer_key.get());
4✔
325
   if(our_ka_key == nullptr || peer_ka_key == nullptr) {
4✔
326
      result.test_failure("Key does not support key agreement");
×
327
      return result;
328
   }
329

330
   const auto peer_public = peer_ka_key->public_value();
4✔
331

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

336
   std::vector<std::future<std::vector<uint8_t>>> futures;
4✔
337
   futures.reserve(ConcurrentThreads);
4✔
338

339
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
44✔
340
      futures.push_back(std::async(std::launch::async, [&, i]() -> std::vector<uint8_t> {
80✔
341
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
40✔
342
         const Botan::PK_Key_Agreement ka(*our_key, *thread_rng, tc.op_params());
40✔
343
         return Botan::unlock(ka.derive_key(32, peer_public).bits_of());
120✔
344
      }));
80✔
345
   }
346

347
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
44✔
348
      try {
40✔
349
         const auto shared_secret = futures[i].get();
40✔
350
         result.test_bin_eq(Botan::fmt("Thread {} shared secret matches", i), shared_secret, reference_secret);
80✔
351
      } catch(std::exception& e) {
40✔
352
         result.test_failure(Botan::fmt("Thread {} threw: {}", i, e.what()));
×
353
      }
×
354
   }
355

356
   return result;
4✔
357
}
24✔
358

359
Test::Result test_concurrent_key_generation(const ConcurrentPkTestCase& tc) {
15✔
360
   auto result = tc.result("key generation");
15✔
361

362
   auto rng = Test::new_rng(result.who());
15✔
363

364
   if(tc.try_create_key(*rng) == nullptr) {
30✔
365
      result.test_note("Keygen not available");
×
366
      return result;
×
367
   }
368

369
   std::vector<std::future<std::unique_ptr<Botan::Private_Key>>> futures;
15✔
370
   futures.reserve(ConcurrentThreads);
15✔
371

372
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
165✔
373
      futures.push_back(std::async(std::launch::async, [&, i]() -> std::unique_ptr<Botan::Private_Key> {
300✔
374
         auto thread_rng = Test::new_rng(Botan::fmt("{} thread {}", result.who(), i));
150✔
375
         return tc.try_create_key(*thread_rng);
150✔
376
      }));
150✔
377
   }
378

379
   for(size_t i = 0; i != ConcurrentThreads; ++i) {
165✔
380
      try {
150✔
381
         const auto sk = futures[i].get();
150✔
382
         result.test_not_null(Botan::fmt("Thread {} generated a key", i), sk.get());
150✔
383

384
         if(sk) {
150✔
385
            result.test_is_true(Botan::fmt("Thread {} generated key seems valid", i), sk->check_key(*rng, true));
300✔
386
         }
387
      } catch(std::exception& e) {
150✔
388
         result.test_failure(Botan::fmt("Thread {} threw: {}", i, e.what()));
×
389
      }
×
390
   }
391

392
   return result;
15✔
393
}
30✔
394

395
class Concurrent_Public_Key_Operations_Test : public Test {
1✔
396
   public:
397
      std::vector<Test::Result> run() override {
1✔
398
         std::vector<Test::Result> results;
1✔
399

400
         concurrent_signing_and_verification_tests(results);
1✔
401
         concurrent_encryption_tests(results);
1✔
402
         concurrent_kem_tests(results);
1✔
403
         concurrent_key_agreement_tests(results);
1✔
404
         concurrent_key_generation_tests(results);
1✔
405

406
         return results;
1✔
407
      }
×
408

409
   private:
410
      void concurrent_signing_and_verification_tests(std::vector<Test::Result>& results) {
1✔
411
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
412
            ConcurrentPkTestCase("RSA", "1536", "PKCS1v15(SHA-256)"),
413
            ConcurrentPkTestCase("ECDSA", "secp256r1", "SHA-256"),
414
            ConcurrentPkTestCase("ECKCDSA", "secp256r1", "SHA-256"),
415
            ConcurrentPkTestCase("ECGDSA", "secp256r1", "SHA-256"),
416
            ConcurrentPkTestCase("DSA", "dsa/jce/1024", "SHA-256"),
417
            ConcurrentPkTestCase("SM2", "sm2p256v1", "SM3"),
418
            ConcurrentPkTestCase("Ed25519", "", "Pure"),
419
            ConcurrentPkTestCase("Ed448", "", "Pure"),
420
            ConcurrentPkTestCase("ML-DSA", "ML-DSA-4x4"),
421
            ConcurrentPkTestCase("Dilithium", "Dilithium-4x4-r3"),
422
            ConcurrentPkTestCase("Dilithium", "Dilithium-4x4-AES-r3"),
423
            ConcurrentPkTestCase("SLH-DSA", "SLH-DSA-SHA2-128f"),
424
            ConcurrentPkTestCase("HSS-LMS", "SHA-256,HW(5,8)"),
425
            ConcurrentPkTestCase("XMSS", "XMSS-SHA2_10_256"),
426
         };
15✔
427

428
         for(const auto& tc : test_cases) {
15✔
429
            auto rng = Test::new_rng(tc.algo_name());
14✔
430

431
            if(auto privkey = tc.try_create_key(*rng)) {
14✔
432
               auto pubkey = privkey->public_key();
14✔
433
               results.push_back(test_concurrent_signing(tc, *privkey, *pubkey));
28✔
434
               results.push_back(test_concurrent_verification(tc, *privkey, *pubkey));
28✔
435
            } else {
14✔
436
               results.push_back(tc.skip_missing("signing"));
×
437
            }
14✔
438
         }
14✔
439
      }
3✔
440

441
      void concurrent_encryption_tests(std::vector<Test::Result>& results) {
1✔
442
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
443
            ConcurrentPkTestCase("RSA", "1536", "OAEP(SHA-256)"),
444
            ConcurrentPkTestCase("ElGamal", "modp/ietf/1536", "PKCS1v15"),
445
         };
3✔
446

447
         for(const auto& tc : test_cases) {
3✔
448
            auto rng = Test::new_rng(tc.algo_name());
2✔
449

450
            if(auto privkey = tc.try_create_key(*rng)) {
2✔
451
               auto pubkey = privkey->public_key();
2✔
452
               results.push_back(test_concurrent_encryption(tc, *privkey, *pubkey));
4✔
453
               results.push_back(test_concurrent_decryption(tc, *privkey, *pubkey));
4✔
454
            } else {
2✔
455
               results.push_back(tc.skip_missing("encryption"));
×
456
            }
2✔
457
         }
2✔
458
      }
3✔
459

460
      void concurrent_kem_tests(std::vector<Test::Result>& results) {
1✔
461
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
462
            ConcurrentPkTestCase("RSA", "1536", "Raw"),
463
            ConcurrentPkTestCase("ClassicMcEliece", "348864f", "Raw"),
464
            ConcurrentPkTestCase("McEliece", "1632,33", "Raw"),
465
            ConcurrentPkTestCase("FrodoKEM", "FrodoKEM-640-SHAKE", "Raw"),
466
            ConcurrentPkTestCase("FrodoKEM", "FrodoKEM-640-AES", "Raw"),
467
            ConcurrentPkTestCase("ML-KEM", "ML-KEM-512", "Raw"),
468
            ConcurrentPkTestCase("Kyber", "Kyber-512-90s-r3", "Raw"),
469
            ConcurrentPkTestCase("Kyber", "Kyber-512-r3", "Raw"),
470
         };
9✔
471

472
         for(const auto& tc : test_cases) {
9✔
473
            auto rng = Test::new_rng(tc.algo_name());
8✔
474
            if(auto privkey = tc.try_create_key(*rng)) {
8✔
475
               auto pubkey = privkey->public_key();
8✔
476
               results.push_back(test_concurrent_kem_encap(tc, *privkey, *pubkey));
16✔
477
               results.push_back(test_concurrent_kem_decap(tc, *privkey, *pubkey));
16✔
478
            } else {
8✔
479
               results.push_back(tc.skip_missing("KEM encapsulate"));
×
480
            }
8✔
481
         }
8✔
482
      }
3✔
483

484
      void concurrent_key_agreement_tests(std::vector<Test::Result>& results) {
1✔
485
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
486
            ConcurrentPkTestCase("DH", "modp/ietf/1536", "Raw"),
487
            ConcurrentPkTestCase("ECDH", "secp256r1", "Raw"),
488
            ConcurrentPkTestCase("X25519", "", "Raw"),
489
            ConcurrentPkTestCase("X448", "", "Raw"),
490
         };
5✔
491

492
         for(const auto& tc : test_cases) {
5✔
493
            results.push_back(test_concurrent_key_agreement(tc));
8✔
494
         }
495
      }
3✔
496

497
      void concurrent_key_generation_tests(std::vector<Test::Result>& results) {
1✔
498
         const std::vector<ConcurrentPkTestCase> test_cases = {
1✔
499
            ConcurrentPkTestCase("ClassicMcEliece", "348864f"),
500
            ConcurrentPkTestCase("DH", "modp/ietf/1536"),
501
            ConcurrentPkTestCase("DSA", "dsa/jce/1024"),
502
            ConcurrentPkTestCase("ECDH", "secp256r1"),
503
            ConcurrentPkTestCase("ECDSA", "secp256r1"),
504
            ConcurrentPkTestCase("ECGDSA", "secp256r1"),
505
            ConcurrentPkTestCase("ECKCDSA", "secp256r1"),
506
            ConcurrentPkTestCase("Ed25519", ""),
507
            ConcurrentPkTestCase("Ed448", ""),
508
            ConcurrentPkTestCase("HSS-LMS", "SHA-256,HW(5,8)"),
509
            ConcurrentPkTestCase("RSA", "1536"),
510
            ConcurrentPkTestCase("SLH-DSA", "SLH-DSA-SHA2-128f"),
511
            ConcurrentPkTestCase("SM2", "sm2p256v1"),
512
            ConcurrentPkTestCase("X25519", ""),
513
            ConcurrentPkTestCase("X448", ""),
514
         };
16✔
515

516
         for(const auto& tc : test_cases) {
16✔
517
            results.push_back(test_concurrent_key_generation(tc));
30✔
518
         }
519
      }
3✔
520
};
521

522
BOTAN_REGISTER_SERIALIZED_TEST("pubkey", "pk_concurrent_ops", Concurrent_Public_Key_Operations_Test);
523

524
}  // namespace
525

526
#endif
527

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