1#[cfg(feature = "alloc")]
8extern crate alloc;
9#[cfg(all(feature = "alloc", not(feature = "std")))]
10use alloc::string::String;
11#[cfg(feature = "alloc")]
12use alloc::vec::Vec;
13
14#[cfg(feature = "cb-kem")]
16use lib_q_cb_kem::LibQCbKemProvider;
17#[cfg(feature = "alloc")]
18use lib_q_core::api::{
19 Algorithm,
20 CryptoProvider,
21 KemOperations,
22};
23#[cfg(feature = "alloc")]
24use lib_q_core::error::{
25 Error,
26 Result,
27};
28#[cfg(feature = "alloc")]
29use lib_q_core::security::SecurityValidator;
30#[cfg(all(feature = "alloc", feature = "ml-kem"))]
31use lib_q_core::traits::Kem;
32#[cfg(feature = "alloc")]
33use lib_q_core::traits::{
34 KemKeypair,
35 KemPublicKey,
36 KemSecretKey,
37};
38#[cfg(feature = "hqc")]
40use lib_q_hqc::LibQHqcProvider;
41
42#[cfg(feature = "ml-kem")]
44use crate::ml_kem::{
45 MlKem512Impl,
46 MlKem768Impl,
47 MlKem1024Impl,
48};
49
50#[cfg(feature = "alloc")]
55#[derive(Clone)]
56pub struct LibQKemProvider {
57 security_validator: SecurityValidator,
58}
59
60#[cfg(feature = "alloc")]
61impl core::fmt::Debug for LibQKemProvider {
62 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
63 f.debug_struct("LibQKemProvider")
64 .field("security_validator", &"<SecurityValidator>")
65 .finish()
66 }
67}
68
69#[cfg(feature = "alloc")]
70impl LibQKemProvider {
71 pub fn new() -> Result<Self> {
81 Ok(Self {
82 security_validator: SecurityValidator::new()?,
83 })
84 }
85
86 pub fn security_validator(&self) -> &SecurityValidator {
88 &self.security_validator
89 }
90}
91
92#[cfg(feature = "alloc")]
93impl KemOperations for LibQKemProvider {
94 fn generate_keypair(
95 &self,
96 algorithm: Algorithm,
97 randomness: Option<&[u8]>,
98 ) -> Result<KemKeypair> {
99 self.security_validator
101 .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
102
103 if let Some(rng) = randomness {
105 self.security_validator.validate_randomness(rng)?;
106 }
107
108 match algorithm {
110 #[cfg(feature = "ml-kem")]
112 Algorithm::MlKem512 => {
113 let kem = MlKem512Impl::default();
114 kem.generate_keypair()
115 }
116 #[cfg(feature = "ml-kem")]
117 Algorithm::MlKem768 => {
118 let kem = MlKem768Impl::default();
119 kem.generate_keypair()
120 }
121 #[cfg(feature = "ml-kem")]
122 Algorithm::MlKem1024 => {
123 let kem = MlKem1024Impl::default();
124 kem.generate_keypair()
125 }
126
127 #[cfg(feature = "cb-kem")]
129 Algorithm::CbKem348864 |
130 Algorithm::CbKem460896 |
131 Algorithm::CbKem6688128 |
132 Algorithm::CbKem6960119 |
133 Algorithm::CbKem8192128 => {
134 let cb_kem_provider = LibQCbKemProvider::new()?;
135 cb_kem_provider.generate_keypair(algorithm, randomness)
136 }
137
138 #[cfg(feature = "hqc")]
140 Algorithm::Hqc128 | Algorithm::Hqc192 | Algorithm::Hqc256 => {
141 let hqc_provider = LibQHqcProvider::new()?;
142 hqc_provider.generate_keypair(algorithm, randomness)
143 }
144
145 #[cfg(not(feature = "ml-kem"))]
147 Algorithm::MlKem512 | Algorithm::MlKem768 | Algorithm::MlKem1024 => {
148 Err(Error::NotImplemented {
149 feature: String::from("ML-KEM implementations require 'ml-kem' feature flag"),
150 })
151 }
152 #[cfg(not(feature = "cb-kem"))]
153 Algorithm::CbKem348864 |
154 Algorithm::CbKem460896 |
155 Algorithm::CbKem6688128 |
156 Algorithm::CbKem6960119 |
157 Algorithm::CbKem8192128 => Err(Error::NotImplemented {
158 feature: String::from("CB-KEM implementations require 'cb-kem' feature flag"),
159 }),
160 #[cfg(not(feature = "hqc"))]
161 Algorithm::Hqc128 | Algorithm::Hqc192 | Algorithm::Hqc256 => {
162 Err(Error::NotImplemented {
163 feature: String::from("HQC implementations require 'hqc' feature flag"),
164 })
165 }
166 _ => Err(Error::InvalidAlgorithm {
167 algorithm: "Algorithm not supported for KEM operations",
168 }),
169 }
170 }
171
172 fn encapsulate(
173 &self,
174 algorithm: Algorithm,
175 public_key: &KemPublicKey,
176 randomness: Option<&[u8]>,
177 ) -> Result<(Vec<u8>, Vec<u8>)> {
178 self.security_validator
180 .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
181
182 self.security_validator
184 .validate_public_key(algorithm, public_key.as_bytes())?;
185
186 if let Some(rng) = randomness {
188 self.security_validator.validate_randomness(rng)?;
189 }
190
191 match algorithm {
193 #[cfg(feature = "ml-kem")]
195 Algorithm::MlKem512 => {
196 let kem = MlKem512Impl::default();
197 kem.encapsulate(public_key)
198 }
199 #[cfg(feature = "ml-kem")]
200 Algorithm::MlKem768 => {
201 let kem = MlKem768Impl::default();
202 kem.encapsulate(public_key)
203 }
204 #[cfg(feature = "ml-kem")]
205 Algorithm::MlKem1024 => {
206 let kem = MlKem1024Impl::default();
207 kem.encapsulate(public_key)
208 }
209
210 #[cfg(feature = "cb-kem")]
212 Algorithm::CbKem348864 |
213 Algorithm::CbKem460896 |
214 Algorithm::CbKem6688128 |
215 Algorithm::CbKem6960119 |
216 Algorithm::CbKem8192128 => {
217 let cb_kem_provider = LibQCbKemProvider::new()?;
218 cb_kem_provider.encapsulate(algorithm, public_key, randomness)
219 }
220
221 #[cfg(feature = "hqc")]
223 Algorithm::Hqc128 | Algorithm::Hqc192 | Algorithm::Hqc256 => {
224 let hqc_provider = LibQHqcProvider::new()?;
225 hqc_provider.encapsulate(algorithm, public_key, randomness)
226 }
227
228 #[cfg(not(feature = "ml-kem"))]
230 Algorithm::MlKem512 | Algorithm::MlKem768 | Algorithm::MlKem1024 => {
231 Err(Error::NotImplemented {
232 feature: String::from("ML-KEM implementations require 'ml-kem' feature flag"),
233 })
234 }
235 #[cfg(not(feature = "cb-kem"))]
236 Algorithm::CbKem348864 |
237 Algorithm::CbKem460896 |
238 Algorithm::CbKem6688128 |
239 Algorithm::CbKem6960119 |
240 Algorithm::CbKem8192128 => Err(Error::NotImplemented {
241 feature: String::from("CB-KEM implementations require 'cb-kem' feature flag"),
242 }),
243 #[cfg(not(feature = "hqc"))]
244 Algorithm::Hqc128 | Algorithm::Hqc192 | Algorithm::Hqc256 => {
245 Err(Error::NotImplemented {
246 feature: String::from("HQC implementations require 'hqc' feature flag"),
247 })
248 }
249 _ => Err(Error::InvalidAlgorithm {
250 algorithm: "Algorithm not supported for KEM operations",
251 }),
252 }
253 }
254
255 fn decapsulate(
256 &self,
257 algorithm: Algorithm,
258 secret_key: &KemSecretKey,
259 ciphertext: &[u8],
260 ) -> Result<Vec<u8>> {
261 self.security_validator
263 .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
264
265 self.security_validator
267 .validate_secret_key(algorithm, secret_key.as_bytes())?;
268
269 self.security_validator
271 .validate_ciphertext(algorithm, ciphertext)?;
272
273 match algorithm {
275 #[cfg(feature = "ml-kem")]
277 Algorithm::MlKem512 => {
278 let kem = MlKem512Impl::default();
279 kem.decapsulate(secret_key, ciphertext)
280 }
281 #[cfg(feature = "ml-kem")]
282 Algorithm::MlKem768 => {
283 let kem = MlKem768Impl::default();
284 kem.decapsulate(secret_key, ciphertext)
285 }
286 #[cfg(feature = "ml-kem")]
287 Algorithm::MlKem1024 => {
288 let kem = MlKem1024Impl::default();
289 kem.decapsulate(secret_key, ciphertext)
290 }
291
292 #[cfg(feature = "cb-kem")]
294 Algorithm::CbKem348864 |
295 Algorithm::CbKem460896 |
296 Algorithm::CbKem6688128 |
297 Algorithm::CbKem6960119 |
298 Algorithm::CbKem8192128 => {
299 let cb_kem_provider = LibQCbKemProvider::new()?;
300 cb_kem_provider.decapsulate(algorithm, secret_key, ciphertext)
301 }
302
303 #[cfg(feature = "hqc")]
305 Algorithm::Hqc128 | Algorithm::Hqc192 | Algorithm::Hqc256 => {
306 let hqc_provider = LibQHqcProvider::new()?;
307 hqc_provider.decapsulate(algorithm, secret_key, ciphertext)
308 }
309
310 #[cfg(not(feature = "ml-kem"))]
312 Algorithm::MlKem512 | Algorithm::MlKem768 | Algorithm::MlKem1024 => {
313 Err(Error::NotImplemented {
314 feature: String::from("ML-KEM implementations require 'ml-kem' feature flag"),
315 })
316 }
317 #[cfg(not(feature = "cb-kem"))]
318 Algorithm::CbKem348864 |
319 Algorithm::CbKem460896 |
320 Algorithm::CbKem6688128 |
321 Algorithm::CbKem6960119 |
322 Algorithm::CbKem8192128 => Err(Error::NotImplemented {
323 feature: String::from("CB-KEM implementations require 'cb-kem' feature flag"),
324 }),
325 #[cfg(not(feature = "hqc"))]
326 Algorithm::Hqc128 | Algorithm::Hqc192 | Algorithm::Hqc256 => {
327 Err(Error::NotImplemented {
328 feature: String::from("HQC implementations require 'hqc' feature flag"),
329 })
330 }
331
332 _ => Err(Error::InvalidAlgorithm {
333 algorithm: "Algorithm not supported for KEM operations",
334 }),
335 }
336 }
337
338 fn derive_public_key(
339 &self,
340 algorithm: Algorithm,
341 secret_key: &KemSecretKey,
342 ) -> Result<KemPublicKey> {
343 self.security_validator
345 .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
346
347 self.security_validator
349 .validate_secret_key(algorithm, secret_key.as_bytes())?;
350
351 match algorithm {
353 #[cfg(feature = "ml-kem")]
355 Algorithm::MlKem512 => {
356 let kem = MlKem512Impl::default();
357 kem.derive_public_key(secret_key)
358 }
359 #[cfg(feature = "ml-kem")]
360 Algorithm::MlKem768 => {
361 let kem = MlKem768Impl::default();
362 kem.derive_public_key(secret_key)
363 }
364 #[cfg(feature = "ml-kem")]
365 Algorithm::MlKem1024 => {
366 let kem = MlKem1024Impl::default();
367 kem.derive_public_key(secret_key)
368 }
369
370 #[cfg(feature = "cb-kem")]
372 Algorithm::CbKem348864 |
373 Algorithm::CbKem460896 |
374 Algorithm::CbKem6688128 |
375 Algorithm::CbKem6960119 |
376 Algorithm::CbKem8192128 => {
377 let cb_kem_provider = LibQCbKemProvider::new()?;
378 cb_kem_provider.derive_public_key(algorithm, secret_key)
379 }
380
381 #[cfg(feature = "hqc")]
383 Algorithm::Hqc128 | Algorithm::Hqc192 | Algorithm::Hqc256 => {
384 let hqc_provider = LibQHqcProvider::new()?;
385 hqc_provider.derive_public_key(algorithm, secret_key)
386 }
387
388 #[cfg(not(feature = "ml-kem"))]
390 Algorithm::MlKem512 | Algorithm::MlKem768 | Algorithm::MlKem1024 => {
391 Err(Error::NotImplemented {
392 feature: String::from("ML-KEM implementations require 'ml-kem' feature flag"),
393 })
394 }
395 #[cfg(not(feature = "cb-kem"))]
396 Algorithm::CbKem348864 |
397 Algorithm::CbKem460896 |
398 Algorithm::CbKem6688128 |
399 Algorithm::CbKem6960119 |
400 Algorithm::CbKem8192128 => Err(Error::NotImplemented {
401 feature: String::from("CB-KEM implementations require 'cb-kem' feature flag"),
402 }),
403 #[cfg(not(feature = "hqc"))]
404 Algorithm::Hqc128 | Algorithm::Hqc192 | Algorithm::Hqc256 => {
405 Err(Error::NotImplemented {
406 feature: String::from("HQC implementations require 'hqc' feature flag"),
407 })
408 }
409
410 _ => Err(Error::InvalidAlgorithm {
411 algorithm: "Algorithm not supported for KEM operations",
412 }),
413 }
414 }
415}
416
417#[cfg(feature = "alloc")]
418impl CryptoProvider for LibQKemProvider {
419 fn kem(&self) -> Option<&dyn KemOperations> {
420 Some(self)
421 }
422
423 fn signature(&self) -> Option<&dyn lib_q_core::api::SignatureOperations> {
424 None
425 }
426
427 fn hash(&self) -> Option<&dyn lib_q_core::api::HashOperations> {
428 None
429 }
430
431 fn aead(&self) -> Option<&dyn lib_q_core::api::AeadOperations> {
432 None
433 }
434}
435
436#[cfg(all(test, feature = "alloc"))]
437mod tests {
438 use super::*;
439
440 #[test]
441 fn test_provider_creation() {
442 let provider = LibQKemProvider::new();
443 assert!(provider.is_ok(), "Provider should be created successfully");
444 }
445
446 #[test]
447 fn test_provider_security_validator() {
448 let provider = LibQKemProvider::new().unwrap();
449 let _validator = provider.security_validator();
450 }
452
453 #[test]
454 fn test_provider_unsupported_algorithm() {
455 let provider = LibQKemProvider::new().unwrap();
456 let result = provider.generate_keypair(Algorithm::Sha3_256, None);
457 assert!(
458 result.is_err(),
459 "Should return error for unsupported algorithm"
460 );
461
462 if let Err(Error::InvalidAlgorithm { .. }) = result {
463 } else {
465 panic!("Expected InvalidAlgorithm error");
466 }
467 }
468
469 #[test]
470 fn test_provider_unsupported_algorithm_for_all_kem_operations() {
471 let provider = LibQKemProvider::new().unwrap();
472 let public_key = KemPublicKey::new(Vec::new());
473 let secret_key = KemSecretKey::new(Vec::new());
474
475 let encapsulate_result = provider.encapsulate(Algorithm::Sha3_256, &public_key, None);
476 assert!(matches!(
477 encapsulate_result,
478 Err(Error::InvalidAlgorithm { .. })
479 ));
480
481 let decapsulate_result = provider.decapsulate(Algorithm::Sha3_256, &secret_key, &[]);
482 assert!(matches!(
483 decapsulate_result,
484 Err(Error::InvalidAlgorithm { .. })
485 ));
486
487 let derive_result = provider.derive_public_key(Algorithm::Sha3_256, &secret_key);
488 assert!(matches!(derive_result, Err(Error::InvalidAlgorithm { .. })));
489 }
490
491 #[test]
492 fn test_provider_feature_flag_handling() {
493 let _provider = LibQKemProvider::new().unwrap();
494
495 #[cfg(not(feature = "ml-kem"))]
497 {
498 let result = _provider.generate_keypair(Algorithm::MlKem512, None);
499 assert!(
500 result.is_err(),
501 "Should return error when feature flag is not enabled"
502 );
503
504 if let Err(Error::NotImplemented { feature }) = result {
505 assert!(
506 feature.contains("ML-KEM implementations require 'ml-kem' feature flag"),
507 "Error should mention feature flag requirement"
508 );
509 } else {
510 panic!("Expected NotImplemented error");
511 }
512 }
513 }
514
515 #[test]
516 fn test_provider_algorithm_routing() {
517 let _provider = LibQKemProvider::new().unwrap();
518
519 #[cfg(feature = "ml-kem")]
521 {
522 let result = _provider.generate_keypair(Algorithm::MlKem512, None);
523 match result {
525 Ok(_) => {
526 }
528 Err(Error::NotImplemented { .. }) => {
529 }
531 Err(Error::RandomGenerationFailed { .. }) => {
532 }
534 Err(e) => {
535 panic!("Unexpected error type: {:?}", e);
536 }
537 }
538 }
539 }
540
541 #[test]
542 fn test_provider_full_kem_cycle() {
543 #[cfg(feature = "ml-kem")]
544 {
545 let provider = LibQKemProvider::new().unwrap();
546
547 let keypair = provider
549 .generate_keypair(Algorithm::MlKem512, None)
550 .unwrap();
551
552 let (ciphertext, shared_secret1) = provider
554 .encapsulate(Algorithm::MlKem512, &keypair.public_key, None)
555 .unwrap();
556
557 let shared_secret2 = provider
559 .decapsulate(Algorithm::MlKem512, &keypair.secret_key, &ciphertext)
560 .unwrap();
561
562 assert_eq!(
564 shared_secret1, shared_secret2,
565 "Shared secrets should match"
566 );
567
568 assert_eq!(
570 ciphertext.len(),
571 768,
572 "ML-KEM-512 ciphertext should be 768 bytes"
573 );
574 assert_eq!(shared_secret1.len(), 32, "Shared secret should be 32 bytes");
575 }
576 }
577
578 #[test]
579 fn test_crypto_provider_trait_exposes_only_kem_operations() {
580 let provider = LibQKemProvider::new().unwrap();
581 let crypto_provider: &dyn CryptoProvider = &provider;
582 assert!(crypto_provider.kem().is_some());
583 assert!(crypto_provider.signature().is_none());
584 assert!(crypto_provider.hash().is_none());
585 assert!(crypto_provider.aead().is_none());
586 }
587}