1#[cfg(feature = "alloc")]
8extern crate alloc;
9#[cfg(feature = "alloc")]
10use alloc::{
11 string::ToString,
12 vec::Vec,
13};
14
15#[cfg(feature = "alloc")]
16use lib_q_core::api::{
17 Algorithm,
18 CryptoProvider,
19 KemOperations,
20};
21#[cfg(feature = "alloc")]
22use lib_q_core::error::{
23 Error,
24 Result,
25};
26#[cfg(feature = "alloc")]
27use lib_q_core::security::SecurityValidator;
28#[cfg(feature = "alloc")]
29use lib_q_core::traits::{
30 KemKeypair,
31 KemPublicKey,
32 KemSecretKey,
33};
34
35#[cfg(feature = "alloc")]
37use crate::{
38 CRYPTO_BYTES,
39 CRYPTO_CIPHERTEXTBYTES,
40 CRYPTO_PUBLICKEYBYTES,
41 CRYPTO_SECRETKEYBYTES,
42 Ciphertext,
43 PublicKey,
44 SecretKey,
45 decapsulate,
46 encapsulate,
47 keypair,
48};
49
50#[cfg(feature = "alloc")]
55#[derive(Clone)]
56pub struct LibQCbKemProvider {
57 security_validator: SecurityValidator,
58}
59
60#[cfg(feature = "alloc")]
61impl core::fmt::Debug for LibQCbKemProvider {
62 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
63 f.debug_struct("LibQCbKemProvider")
64 .field("security_validator", &"<SecurityValidator>")
65 .finish()
66 }
67}
68
69#[cfg(feature = "alloc")]
70impl LibQCbKemProvider {
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 pub fn security_validator_mut(&mut self) -> &mut SecurityValidator {
96 &mut self.security_validator
97 }
98}
99
100#[cfg(feature = "alloc")]
101impl KemOperations for LibQCbKemProvider {
102 fn generate_keypair(
103 &self,
104 algorithm: Algorithm,
105 randomness: Option<&[u8]>,
106 ) -> Result<KemKeypair> {
107 self.security_validator
109 .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
110
111 if let Some(rng) = randomness {
113 self.security_validator.validate_randomness(rng)?;
114 }
115
116 match algorithm {
118 Algorithm::CbKem348864 => self.generate_cb_kem_keypair(
120 CRYPTO_PUBLICKEYBYTES,
121 CRYPTO_SECRETKEYBYTES,
122 randomness,
123 ),
124 Algorithm::CbKem460896 => self.generate_cb_kem_keypair(
125 CRYPTO_PUBLICKEYBYTES,
126 CRYPTO_SECRETKEYBYTES,
127 randomness,
128 ),
129 Algorithm::CbKem6688128 => self.generate_cb_kem_keypair(
130 CRYPTO_PUBLICKEYBYTES,
131 CRYPTO_SECRETKEYBYTES,
132 randomness,
133 ),
134 Algorithm::CbKem6960119 => self.generate_cb_kem_keypair(
135 CRYPTO_PUBLICKEYBYTES,
136 CRYPTO_SECRETKEYBYTES,
137 randomness,
138 ),
139 Algorithm::CbKem8192128 => self.generate_cb_kem_keypair(
140 CRYPTO_PUBLICKEYBYTES,
141 CRYPTO_SECRETKEYBYTES,
142 randomness,
143 ),
144
145 _ => Err(Error::InvalidAlgorithm {
146 algorithm: "Algorithm not supported for Classical McEliece KEM operations",
147 }),
148 }
149 }
150
151 fn encapsulate(
152 &self,
153 algorithm: Algorithm,
154 public_key: &KemPublicKey,
155 randomness: Option<&[u8]>,
156 ) -> Result<(Vec<u8>, Vec<u8>)> {
157 self.security_validator
159 .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
160
161 self.security_validator
163 .validate_key_size(algorithm, public_key.as_bytes(), false)?;
164
165 if let Some(rng) = randomness {
167 self.security_validator.validate_randomness(rng)?;
168 }
169
170 match algorithm {
172 Algorithm::CbKem348864 |
174 Algorithm::CbKem460896 |
175 Algorithm::CbKem6688128 |
176 Algorithm::CbKem6960119 |
177 Algorithm::CbKem8192128 => self.encapsulate_cb_kem(public_key, randomness),
178
179 _ => Err(Error::InvalidAlgorithm {
180 algorithm: "Algorithm not supported for Classical McEliece KEM operations",
181 }),
182 }
183 }
184
185 fn decapsulate(
186 &self,
187 algorithm: Algorithm,
188 secret_key: &KemSecretKey,
189 ciphertext: &[u8],
190 ) -> Result<Vec<u8>> {
191 self.security_validator
193 .validate_algorithm_category(algorithm, lib_q_core::api::AlgorithmCategory::Kem)?;
194
195 self.security_validator
197 .validate_key_size(algorithm, secret_key.as_bytes(), true)?;
198
199 self.security_validator
201 .validate_ciphertext(algorithm, ciphertext)?;
202
203 match algorithm {
205 Algorithm::CbKem348864 |
207 Algorithm::CbKem460896 |
208 Algorithm::CbKem6688128 |
209 Algorithm::CbKem6960119 |
210 Algorithm::CbKem8192128 => self.decapsulate_cb_kem(secret_key, ciphertext),
211
212 _ => Err(Error::InvalidAlgorithm {
213 algorithm: "Algorithm not supported for Classical McEliece KEM operations",
214 }),
215 }
216 }
217
218 fn derive_public_key(
219 &self,
220 _algorithm: Algorithm,
221 _secret_key: &KemSecretKey,
222 ) -> Result<KemPublicKey> {
223 Err(Error::UnsupportedOperation {
226 operation: "Classical McEliece does not support public key derivation from secret key"
227 .to_string(),
228 })
229 }
230}
231
232#[cfg(feature = "alloc")]
233impl LibQCbKemProvider {
234 fn generate_cb_kem_keypair(
236 &self,
237 public_key_size: usize,
238 secret_key_size: usize,
239 randomness: Option<&[u8]>,
240 ) -> Result<KemKeypair> {
241 if public_key_size != CRYPTO_PUBLICKEYBYTES {
243 return Err(Error::InvalidKeySize {
244 expected: CRYPTO_PUBLICKEYBYTES,
245 actual: public_key_size,
246 });
247 }
248 if secret_key_size != CRYPTO_SECRETKEYBYTES {
249 return Err(Error::InvalidKeySize {
250 expected: CRYPTO_SECRETKEYBYTES,
251 actual: secret_key_size,
252 });
253 }
254
255 let mut public_key_buf = [0u8; CRYPTO_PUBLICKEYBYTES];
257 let mut secret_key_buf = [0u8; CRYPTO_SECRETKEYBYTES];
258
259 let (public_key, secret_key) = if let Some(rng_bytes) = randomness {
261 {
264 let mut rng = crate::LibQRng::new_deterministic_from_bytes(rng_bytes);
265 keypair(&mut public_key_buf, &mut secret_key_buf, &mut rng)
266 }
267 } else {
268 {
270 let mut rng = crate::LibQRng::new();
271 keypair(&mut public_key_buf, &mut secret_key_buf, &mut rng)
272 }
273 };
274
275 Ok(KemKeypair::new(
278 Vec::from(public_key.as_array().as_slice()),
279 Vec::from(secret_key.as_array().as_slice()),
280 ))
281 }
282
283 fn encapsulate_cb_kem(
285 &self,
286 public_key: &KemPublicKey,
287 randomness: Option<&[u8]>,
288 ) -> Result<(Vec<u8>, Vec<u8>)> {
289 if public_key.as_bytes().len() != CRYPTO_PUBLICKEYBYTES {
291 return Err(Error::InvalidKeySize {
292 expected: CRYPTO_PUBLICKEYBYTES,
293 actual: public_key.as_bytes().len(),
294 });
295 }
296
297 let mut public_key_buf = [0u8; CRYPTO_PUBLICKEYBYTES];
299 public_key_buf.copy_from_slice(public_key.as_bytes());
300 let public_key = PublicKey::from(&mut public_key_buf);
301
302 let mut shared_secret_buf = [0u8; CRYPTO_BYTES];
304
305 let (ciphertext, shared_secret) = if let Some(rng_bytes) = randomness {
307 {
310 let mut rng = crate::LibQRng::new_deterministic_from_bytes(rng_bytes);
311 encapsulate(&public_key, &mut shared_secret_buf, &mut rng)
312 }
313 } else {
314 {
316 let mut rng = crate::LibQRng::new();
317 encapsulate(&public_key, &mut shared_secret_buf, &mut rng)
318 }
319 };
320
321 Ok((
322 Vec::from(ciphertext.as_array().as_slice()),
323 Vec::from(shared_secret.as_array().as_slice()),
324 ))
325 }
326
327 fn decapsulate_cb_kem(&self, secret_key: &KemSecretKey, ciphertext: &[u8]) -> Result<Vec<u8>> {
329 if secret_key.as_bytes().len() != CRYPTO_SECRETKEYBYTES {
331 return Err(Error::InvalidKeySize {
332 expected: CRYPTO_SECRETKEYBYTES,
333 actual: secret_key.as_bytes().len(),
334 });
335 }
336
337 if ciphertext.len() != CRYPTO_CIPHERTEXTBYTES {
339 return Err(Error::InvalidCiphertextSize {
340 expected: CRYPTO_CIPHERTEXTBYTES,
341 actual: ciphertext.len(),
342 });
343 }
344
345 let mut secret_key_buf = [0u8; CRYPTO_SECRETKEYBYTES];
347 secret_key_buf.copy_from_slice(secret_key.as_bytes());
348 let secret_key = SecretKey::from(&mut secret_key_buf);
349
350 let mut ciphertext_buf = [0u8; CRYPTO_CIPHERTEXTBYTES];
352 ciphertext_buf.copy_from_slice(ciphertext);
353 let ciphertext = Ciphertext::from(ciphertext_buf);
354
355 let mut shared_secret_buf = [0u8; CRYPTO_BYTES];
357
358 let shared_secret = decapsulate(&ciphertext, &secret_key, &mut shared_secret_buf);
360
361 Ok(Vec::from(shared_secret.as_array().as_slice()))
362 }
363}
364
365#[cfg(feature = "alloc")]
366impl CryptoProvider for LibQCbKemProvider {
367 fn kem(&self) -> Option<&dyn KemOperations> {
368 Some(self)
369 }
370
371 fn signature(&self) -> Option<&dyn lib_q_core::api::SignatureOperations> {
372 None
373 }
374
375 fn hash(&self) -> Option<&dyn lib_q_core::api::HashOperations> {
376 None
377 }
378
379 fn aead(&self) -> Option<&dyn lib_q_core::api::AeadOperations> {
380 None
381 }
382}
383
384#[cfg(all(test, feature = "alloc"))]
385mod tests {
386 use super::*;
387
388 fn compiled_cb_kem_algorithm() -> Algorithm {
390 #[cfg(any(feature = "cbkem348864", feature = "cbkem348864f"))]
391 {
392 Algorithm::CbKem348864
393 }
394 #[cfg(all(
395 not(any(feature = "cbkem348864", feature = "cbkem348864f")),
396 any(feature = "cbkem460896", feature = "cbkem460896f"),
397 ))]
398 {
399 Algorithm::CbKem460896
400 }
401 #[cfg(all(
402 not(any(
403 feature = "cbkem348864",
404 feature = "cbkem348864f",
405 feature = "cbkem460896",
406 feature = "cbkem460896f",
407 )),
408 any(feature = "cbkem6688128", feature = "cbkem6688128f"),
409 ))]
410 {
411 Algorithm::CbKem6688128
412 }
413 #[cfg(all(
414 not(any(
415 feature = "cbkem348864",
416 feature = "cbkem348864f",
417 feature = "cbkem460896",
418 feature = "cbkem460896f",
419 feature = "cbkem6688128",
420 feature = "cbkem6688128f",
421 )),
422 any(feature = "cbkem6960119", feature = "cbkem6960119f"),
423 ))]
424 {
425 Algorithm::CbKem6960119
426 }
427 #[cfg(all(
428 not(any(
429 feature = "cbkem348864",
430 feature = "cbkem348864f",
431 feature = "cbkem460896",
432 feature = "cbkem460896f",
433 feature = "cbkem6688128",
434 feature = "cbkem6688128f",
435 feature = "cbkem6960119",
436 feature = "cbkem6960119f",
437 )),
438 any(feature = "cbkem8192128", feature = "cbkem8192128f"),
439 ))]
440 {
441 Algorithm::CbKem8192128
442 }
443 }
444
445 #[test]
446 fn test_provider_creation() {
447 let provider = LibQCbKemProvider::new();
448 assert!(provider.is_ok(), "Provider should be created successfully");
449 }
450
451 #[test]
452 fn test_provider_security_validator() {
453 let provider = LibQCbKemProvider::new().unwrap();
454 let _validator = provider.security_validator();
455 }
457
458 #[test]
459 fn test_provider_security_validator_mut_accessor() {
460 let mut provider = LibQCbKemProvider::new().unwrap();
461 let _validator_mut = provider.security_validator_mut();
462 }
463
464 #[test]
465 fn test_provider_unsupported_algorithm() {
466 let provider = LibQCbKemProvider::new().unwrap();
467 let result = provider.generate_keypair(Algorithm::Sha3_256, None);
468 assert!(
469 result.is_err(),
470 "Should return error for unsupported algorithm"
471 );
472
473 if let Err(Error::InvalidAlgorithm { .. }) = result {
474 } else {
476 panic!("Expected InvalidAlgorithm error");
477 }
478 }
479
480 #[test]
481 fn test_provider_algorithm_routing() {
482 let provider = LibQCbKemProvider::new().unwrap();
483
484 let alg = compiled_cb_kem_algorithm();
486
487 provider
488 .security_validator()
489 .validate_algorithm_category(alg, lib_q_core::api::AlgorithmCategory::Kem)
490 .expect("compiled CB-KEM algorithm should be a KEM");
491
492 #[cfg(any(feature = "cbkem348864", feature = "cbkem348864f"))]
496 {
497 let result = provider.generate_keypair(alg, None);
498 match result {
499 Ok(_) => {}
500 Err(Error::NotImplemented { .. }) => {}
501 Err(Error::RandomGenerationFailed { .. }) => {}
502 Err(e) => panic!("Unexpected error type: {:?}", e),
503 }
504 }
505 }
506
507 #[test]
508 fn test_provider_full_kem_cycle() {
509 #[cfg(feature = "std")]
510 {
511 let provider = LibQCbKemProvider::new().unwrap();
512
513 let alg = compiled_cb_kem_algorithm();
514
515 #[cfg(any(feature = "cbkem348864", feature = "cbkem348864f"))]
520 {
521 let keypair = provider.generate_keypair(alg, None).unwrap();
523
524 let (ciphertext, shared_secret1) = provider
526 .encapsulate(alg, &keypair.public_key, None)
527 .unwrap();
528
529 let shared_secret2 = provider
531 .decapsulate(alg, &keypair.secret_key, &ciphertext)
532 .unwrap();
533
534 assert_eq!(
536 shared_secret1, shared_secret2,
537 "Shared secrets should match"
538 );
539
540 assert_eq!(
542 ciphertext.len(),
543 CRYPTO_CIPHERTEXTBYTES,
544 "Classical McEliece ciphertext should be {} bytes",
545 CRYPTO_CIPHERTEXTBYTES
546 );
547 assert_eq!(
548 shared_secret1.len(),
549 CRYPTO_BYTES,
550 "Shared secret should be {} bytes",
551 CRYPTO_BYTES
552 );
553 }
554
555 #[cfg(not(any(feature = "cbkem348864", feature = "cbkem348864f")))]
556 {
557 provider
558 .security_validator()
559 .validate_algorithm_category(alg, lib_q_core::api::AlgorithmCategory::Kem)
560 .expect("compiled CB-KEM algorithm should be a KEM");
561 }
562 }
563 }
564
565 #[test]
566 fn test_provider_derive_public_key_is_unsupported() {
567 let provider = LibQCbKemProvider::new().unwrap();
568 let secret_key = KemSecretKey::new(Vec::new());
569 let result = provider.derive_public_key(compiled_cb_kem_algorithm(), &secret_key);
570 assert!(matches!(result, Err(Error::UnsupportedOperation { .. })));
571 }
572
573 #[test]
574 fn test_crypto_provider_trait_exposes_only_kem_operations() {
575 let provider = LibQCbKemProvider::new().unwrap();
576 let crypto_provider: &dyn CryptoProvider = &provider;
577 assert!(crypto_provider.kem().is_some());
578 assert!(crypto_provider.signature().is_none());
579 assert!(crypto_provider.hash().is_none());
580 assert!(crypto_provider.aead().is_none());
581 }
582}