Skip to main content

lib_q_kem/
provider.rs

1//! lib-Q KEM Provider Implementation
2//!
3//! This module provides the LibQKemProvider that implements the KemOperations
4//! trait and routes KEM operations to the appropriate algorithm implementations
5//! with proper security validation.
6
7#[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// Import Classical McEliece implementations
15#[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// Import HQC implementations
39#[cfg(feature = "hqc")]
40use lib_q_hqc::LibQHqcProvider;
41
42// Import algorithm implementations
43#[cfg(feature = "ml-kem")]
44use crate::ml_kem::{
45    MlKem512Impl,
46    MlKem768Impl,
47    MlKem1024Impl,
48};
49
50/// lib-Q KEM provider implementation
51///
52/// This provider implements KEM operations for lib-Q, including key generation,
53/// encapsulation, and decapsulation with proper security validation and algorithm routing.
54#[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    /// Create a new KEM provider
72    ///
73    /// # Returns
74    ///
75    /// A new instance of LibQKemProvider with security validation initialized.
76    ///
77    /// # Errors
78    ///
79    /// Returns an error if the security validator fails to initialize.
80    pub fn new() -> Result<Self> {
81        Ok(Self {
82            security_validator: SecurityValidator::new()?,
83        })
84    }
85
86    /// Get the security validator
87    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        // Validate algorithm category
100        self.security_validator
101            .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
102
103        // Validate randomness if provided
104        if let Some(rng) = randomness {
105            self.security_validator.validate_randomness(rng)?;
106        }
107
108        // Route to specific algorithm implementation
109        match algorithm {
110            // ML-KEM algorithms
111            #[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            // CB-KEM algorithms
128            #[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            // HQC algorithms
139            #[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            // Handle missing feature flags
146            #[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        // Validate algorithm category
179        self.security_validator
180            .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
181
182        // Validate public key
183        self.security_validator
184            .validate_public_key(algorithm, public_key.as_bytes())?;
185
186        // Validate randomness if provided
187        if let Some(rng) = randomness {
188            self.security_validator.validate_randomness(rng)?;
189        }
190
191        // Route to specific algorithm implementation
192        match algorithm {
193            // ML-KEM algorithms
194            #[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            // CB-KEM algorithms
211            #[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            // HQC algorithms
222            #[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            // Handle missing feature flags
229            #[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        // Validate algorithm category
262        self.security_validator
263            .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
264
265        // Validate secret key
266        self.security_validator
267            .validate_secret_key(algorithm, secret_key.as_bytes())?;
268
269        // Validate ciphertext
270        self.security_validator
271            .validate_ciphertext(algorithm, ciphertext)?;
272
273        // Route to specific algorithm implementation
274        match algorithm {
275            // ML-KEM algorithms
276            #[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            // CB-KEM algorithms
293            #[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            // HQC algorithms
304            #[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            // Handle missing feature flags
311            #[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        // Validate algorithm category
344        self.security_validator
345            .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
346
347        // Validate secret key
348        self.security_validator
349            .validate_secret_key(algorithm, secret_key.as_bytes())?;
350
351        // Route to specific algorithm implementation
352        match algorithm {
353            // ML-KEM algorithms
354            #[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            // CB-KEM algorithms
371            #[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            // HQC algorithms
382            #[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            // Handle missing feature flags
389            #[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        // Security validator should be accessible
451    }
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            // Expected error type
464        } 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        // Test ML-KEM without feature flag
496        #[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        // Test that algorithms are properly routed
520        #[cfg(feature = "ml-kem")]
521        {
522            let result = _provider.generate_keypair(Algorithm::MlKem512, None);
523            // Should either succeed or return NotImplemented (depending on std feature)
524            match result {
525                Ok(_) => {
526                    // Success case - this is expected with std feature
527                }
528                Err(Error::NotImplemented { .. }) => {
529                    // Expected when std feature is not available
530                }
531                Err(Error::RandomGenerationFailed { .. }) => {
532                    // Expected when std feature is not available for randomness generation
533                }
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            // Test full KEM cycle for ML-KEM-512
548            let keypair = provider
549                .generate_keypair(Algorithm::MlKem512, None)
550                .unwrap();
551
552            // Test encapsulation
553            let (ciphertext, shared_secret1) = provider
554                .encapsulate(Algorithm::MlKem512, &keypair.public_key, None)
555                .unwrap();
556
557            // Test decapsulation
558            let shared_secret2 = provider
559                .decapsulate(Algorithm::MlKem512, &keypair.secret_key, &ciphertext)
560                .unwrap();
561
562            // Verify shared secrets match
563            assert_eq!(
564                shared_secret1, shared_secret2,
565                "Shared secrets should match"
566            );
567
568            // Verify sizes are correct
569            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}