1#[cfg(feature = "alloc")]
6extern crate alloc;
7#[cfg(feature = "alloc")]
8use alloc::{
9 format,
10 string::String,
11 vec,
12 vec::Vec,
13};
14
15use lib_q_core::{
16 Algorithm,
17 CryptoProvider,
18 Error,
19 KemOperations,
20 Result,
21};
22#[cfg(all(feature = "alloc", feature = "random"))]
23use zeroize::Zeroizing;
24
25use crate::hqc_core::{
26 Hqc1,
27 Hqc3,
28 Hqc5,
29 HqcCore,
30};
31
32#[cfg(all(feature = "alloc", feature = "random"))]
37fn kem_encapsulation_rng(randomness: Option<&[u8]>) -> Result<lib_q_random::LibQRng> {
38 use crate::shake256_prng::create_shake256_prng_rng;
39
40 match randomness {
41 Some(seed) => {
42 let mut entropy = [0u8; 48];
43 let n = core::cmp::min(seed.len(), 48);
44 entropy[..n].copy_from_slice(&seed[..n]);
45 Ok(create_shake256_prng_rng(entropy))
46 }
47 None => lib_q_random::LibQRng::new_secure().map_err(|_| Error::InternalError {
48 operation: String::from("RNG initialization"),
49 details: String::from("Failed to initialize secure random number generator"),
50 }),
51 }
52}
53
54#[derive(Debug, Clone, PartialEq)]
56pub struct LibQHqcProvider;
57
58impl LibQHqcProvider {
59 pub fn new() -> Result<Self> {
61 Ok(Self)
62 }
63
64 pub fn name(&self) -> &'static str {
66 "libQ HQC Provider"
67 }
68
69 pub fn priority(&self) -> u32 {
71 100
72 }
73
74 pub fn capabilities(&self) -> Vec<Algorithm> {
76 vec![Algorithm::Hqc128, Algorithm::Hqc192, Algorithm::Hqc256]
77 }
78
79 pub fn supports_algorithm(&self, algorithm: Algorithm) -> bool {
81 matches!(
82 algorithm,
83 Algorithm::Hqc128 | Algorithm::Hqc192 | Algorithm::Hqc256
84 )
85 }
86}
87
88#[cfg(all(feature = "alloc", feature = "random"))]
89impl KemOperations for LibQHqcProvider {
90 fn generate_keypair(
91 &self,
92 algorithm: Algorithm,
93 randomness: Option<&[u8]>,
94 ) -> Result<lib_q_core::KemKeypair> {
95 let mut rng = kem_encapsulation_rng(randomness)?;
96
97 match algorithm {
98 Algorithm::Hqc128 => {
99 let (secret_key, public_key) =
100 Hqc1::generate_keypair(&mut rng).map_err(|e| Error::InternalError {
101 operation: String::from("HQC-128 key generation"),
102 details: format!("Failed to generate HQC-128 keypair: {:?}", e),
103 })?;
104 Ok(lib_q_core::KemKeypair {
105 public_key: lib_q_core::KemPublicKey::new(Vec::from(public_key.as_bytes())),
106 secret_key: lib_q_core::KemSecretKey::new(secret_key.as_bytes()),
107 })
108 }
109 Algorithm::Hqc192 => {
110 let (secret_key, public_key) =
111 Hqc3::generate_keypair(&mut rng).map_err(|e| Error::InternalError {
112 operation: String::from("HQC-192 key generation"),
113 details: format!("Failed to generate HQC-192 keypair: {:?}", e),
114 })?;
115 Ok(lib_q_core::KemKeypair {
116 public_key: lib_q_core::KemPublicKey::new(Vec::from(public_key.as_bytes())),
117 secret_key: lib_q_core::KemSecretKey::new(secret_key.as_bytes()),
118 })
119 }
120 Algorithm::Hqc256 => {
121 let (secret_key, public_key) =
122 Hqc5::generate_keypair(&mut rng).map_err(|e| Error::InternalError {
123 operation: String::from("HQC-256 key generation"),
124 details: format!("Failed to generate HQC-256 keypair: {:?}", e),
125 })?;
126 Ok(lib_q_core::KemKeypair {
127 public_key: lib_q_core::KemPublicKey::new(Vec::from(public_key.as_bytes())),
128 secret_key: lib_q_core::KemSecretKey::new(secret_key.as_bytes()),
129 })
130 }
131 _ => Err(Error::InvalidAlgorithm {
132 algorithm: "Unsupported algorithm",
133 }),
134 }
135 }
136
137 fn encapsulate(
138 &self,
139 algorithm: Algorithm,
140 public_key: &lib_q_core::KemPublicKey,
141 randomness: Option<&[u8]>,
142 ) -> Result<(Vec<u8>, Vec<u8>)> {
143 use crate::hqc_core::{
144 Hqc1PublicKey,
145 Hqc3PublicKey,
146 Hqc5PublicKey,
147 };
148 use crate::hqc_kem::HqcKemPublicKey;
149 use crate::hqc_pke::HqcPkePublicKey;
150 #[allow(unused_imports)] use crate::params::{
152 Hqc1Params,
153 Hqc3Params,
154 Hqc5Params,
155 HqcParams,
156 };
157
158 match algorithm {
159 Algorithm::Hqc128 => {
160 let pke_pk = HqcPkePublicKey::<Hqc1Params>::new(public_key.data.clone());
161 let kem_pk = HqcKemPublicKey::new(pke_pk);
162 let pk = Hqc1PublicKey::new(kem_pk);
163 let mut rng = kem_encapsulation_rng(randomness)?;
164 let (ciphertext, shared_secret) =
165 Hqc1::encapsulate(&pk, &mut rng).map_err(|e| Error::InternalError {
166 operation: String::from("HQC-128 encapsulation"),
167 details: format!("Failed to encapsulate HQC-128: {:?}", e),
168 })?;
169 Ok((ciphertext.as_bytes(), Vec::from(shared_secret.as_bytes())))
170 }
171 Algorithm::Hqc192 => {
172 let pke_pk = HqcPkePublicKey::<Hqc3Params>::new(public_key.data.clone());
173 let kem_pk = HqcKemPublicKey::new(pke_pk);
174 let pk = Hqc3PublicKey::new(kem_pk);
175 let mut rng = kem_encapsulation_rng(randomness)?;
176 let (ciphertext, shared_secret) =
177 Hqc3::encapsulate(&pk, &mut rng).map_err(|e| Error::InternalError {
178 operation: String::from("HQC-192 encapsulation"),
179 details: format!("Failed to encapsulate HQC-192: {:?}", e),
180 })?;
181 Ok((ciphertext.as_bytes(), Vec::from(shared_secret.as_bytes())))
182 }
183 Algorithm::Hqc256 => {
184 let pke_pk = HqcPkePublicKey::<Hqc5Params>::new(public_key.data.clone());
185 let kem_pk = HqcKemPublicKey::new(pke_pk);
186 let pk = Hqc5PublicKey::new(kem_pk);
187 let mut rng = kem_encapsulation_rng(randomness)?;
188 let (ciphertext, shared_secret) =
189 Hqc5::encapsulate(&pk, &mut rng).map_err(|e| Error::InternalError {
190 operation: String::from("HQC-256 encapsulation"),
191 details: format!("Failed to encapsulate HQC-256: {:?}", e),
192 })?;
193 Ok((ciphertext.as_bytes(), Vec::from(shared_secret.as_bytes())))
194 }
195 _ => Err(Error::InvalidAlgorithm {
196 algorithm: "Unsupported algorithm",
197 }),
198 }
199 }
200
201 fn decapsulate(
202 &self,
203 algorithm: Algorithm,
204 secret_key: &lib_q_core::KemSecretKey,
205 ciphertext: &[u8],
206 ) -> Result<Vec<u8>> {
207 use crate::hqc_core::{
208 Hqc1Ciphertext,
209 Hqc1SecretKey,
210 Hqc3Ciphertext,
211 Hqc3SecretKey,
212 Hqc5Ciphertext,
213 Hqc5SecretKey,
214 };
215 use crate::hqc_kem::{
216 HqcKemCiphertext,
217 HqcKemSecretKey,
218 MAX_SECURITY_BYTES,
219 };
220 use crate::hqc_pke::{
221 HqcPkeCiphertext,
222 HqcPkePublicKey,
223 HqcPkeSecretKey,
224 };
225 #[allow(unused_imports)] use crate::params::{
227 Hqc1Params,
228 Hqc3Params,
229 Hqc5Params,
230 HqcParams,
231 };
232
233 match algorithm {
234 Algorithm::Hqc128 => {
235 let sk_bytes = &secret_key.data;
238 if sk_bytes.len() != Hqc1Params::SECRET_KEY_BYTES {
239 return Err(Error::InvalidKeySize {
240 expected: Hqc1Params::SECRET_KEY_BYTES,
241 actual: sk_bytes.len(),
242 });
243 }
244 let ek_pke_bytes = &sk_bytes[..Hqc1Params::PUBLIC_KEY_BYTES];
245 let dk_pke_start = Hqc1Params::PUBLIC_KEY_BYTES;
246 let dk_pke_bytes = &sk_bytes[dk_pke_start..dk_pke_start + 32];
247 let sigma_start = dk_pke_start + 32;
248 let sigma_len = Hqc1Params::K;
249 let mut sigma = Zeroizing::new([0u8; MAX_SECURITY_BYTES]);
250 sigma[..sigma_len].copy_from_slice(&sk_bytes[sigma_start..sigma_start + sigma_len]);
251 let seed_kem_start = sigma_start + sigma_len;
252 let mut seed_kem = Zeroizing::new([0u8; 48]);
253 seed_kem.copy_from_slice(&sk_bytes[seed_kem_start..seed_kem_start + 48]);
254
255 let ek_pke = HqcPkePublicKey::<Hqc1Params>::new(ek_pke_bytes.to_vec());
256 let mut dk_pke_array = Zeroizing::new([0u8; 32]);
257 dk_pke_array.copy_from_slice(dk_pke_bytes);
258 let dk_pke = HqcPkeSecretKey::new(*dk_pke_array);
259 let kem_sk = HqcKemSecretKey::new(ek_pke, dk_pke, *sigma, *seed_kem);
260 let sk = Hqc1SecretKey::new(kem_sk);
261
262 let pke_ct_size = Hqc1Params::VEC_N_SIZE_BYTES + Hqc1Params::VEC_N1N2_SIZE_BYTES;
264 if ciphertext.len() != pke_ct_size + 16 {
265 return Err(Error::InvalidKeySize {
266 expected: pke_ct_size + 16,
267 actual: ciphertext.len(),
268 });
269 }
270 let c_pke_bytes = &ciphertext[..pke_ct_size];
271 let mut salt = Zeroizing::new([0u8; 16]);
272 salt.copy_from_slice(&ciphertext[pke_ct_size..pke_ct_size + 16]);
273 let c_pke = HqcPkeCiphertext::<Hqc1Params>::new(c_pke_bytes.to_vec());
274 let kem_ct = HqcKemCiphertext::new(c_pke, *salt);
275 let ct = Hqc1Ciphertext::new(kem_ct);
276
277 let shared_secret =
278 Hqc1::decapsulate::<lib_q_random::LibQRng>(&sk, &ct).map_err(|e| {
279 Error::InternalError {
280 operation: String::from("HQC-128 decapsulation"),
281 details: format!("Failed to decapsulate HQC-128: {:?}", e),
282 }
283 })?;
284 Ok(Vec::from(shared_secret.as_bytes()))
285 }
286 Algorithm::Hqc192 => {
287 let sk_bytes = &secret_key.data;
289 if sk_bytes.len() != Hqc3Params::SECRET_KEY_BYTES {
290 return Err(Error::InvalidKeySize {
291 expected: Hqc3Params::SECRET_KEY_BYTES,
292 actual: sk_bytes.len(),
293 });
294 }
295 let ek_pke_bytes = &sk_bytes[..Hqc3Params::PUBLIC_KEY_BYTES];
296 let dk_pke_start = Hqc3Params::PUBLIC_KEY_BYTES;
297 let dk_pke_bytes = &sk_bytes[dk_pke_start..dk_pke_start + 32];
298 let sigma_start = dk_pke_start + 32;
299 let sigma_len = Hqc3Params::K;
300 let mut sigma = Zeroizing::new([0u8; MAX_SECURITY_BYTES]);
301 sigma[..sigma_len].copy_from_slice(&sk_bytes[sigma_start..sigma_start + sigma_len]);
302 let seed_kem_start = sigma_start + sigma_len;
303 let mut seed_kem = Zeroizing::new([0u8; 48]);
304 seed_kem.copy_from_slice(&sk_bytes[seed_kem_start..seed_kem_start + 48]);
305
306 let ek_pke = HqcPkePublicKey::<Hqc3Params>::new(ek_pke_bytes.to_vec());
307 let mut dk_pke_array = Zeroizing::new([0u8; 32]);
308 dk_pke_array.copy_from_slice(dk_pke_bytes);
309 let dk_pke = HqcPkeSecretKey::new(*dk_pke_array);
310 let kem_sk = HqcKemSecretKey::new(ek_pke, dk_pke, *sigma, *seed_kem);
311 let sk = Hqc3SecretKey::new(kem_sk);
312
313 let pke_ct_size = Hqc3Params::VEC_N_SIZE_BYTES + Hqc3Params::VEC_N1N2_SIZE_BYTES;
315 if ciphertext.len() != pke_ct_size + 16 {
316 return Err(Error::InvalidKeySize {
317 expected: pke_ct_size + 16,
318 actual: ciphertext.len(),
319 });
320 }
321 let c_pke_bytes = &ciphertext[..pke_ct_size];
322 let mut salt = Zeroizing::new([0u8; 16]);
323 salt.copy_from_slice(&ciphertext[pke_ct_size..pke_ct_size + 16]);
324 let c_pke = HqcPkeCiphertext::<Hqc3Params>::new(c_pke_bytes.to_vec());
325 let kem_ct = HqcKemCiphertext::new(c_pke, *salt);
326 let ct = Hqc3Ciphertext::new(kem_ct);
327
328 let shared_secret =
329 Hqc3::decapsulate::<lib_q_random::LibQRng>(&sk, &ct).map_err(|e| {
330 Error::InternalError {
331 operation: String::from("HQC-192 decapsulation"),
332 details: format!("Failed to decapsulate HQC-192: {:?}", e),
333 }
334 })?;
335 Ok(Vec::from(shared_secret.as_bytes()))
336 }
337 Algorithm::Hqc256 => {
338 let sk_bytes = &secret_key.data;
340 if sk_bytes.len() != Hqc5Params::SECRET_KEY_BYTES {
341 return Err(Error::InvalidKeySize {
342 expected: Hqc5Params::SECRET_KEY_BYTES,
343 actual: sk_bytes.len(),
344 });
345 }
346 let ek_pke_bytes = &sk_bytes[..Hqc5Params::PUBLIC_KEY_BYTES];
347 let dk_pke_start = Hqc5Params::PUBLIC_KEY_BYTES;
348 let dk_pke_bytes = &sk_bytes[dk_pke_start..dk_pke_start + 32];
349 let sigma_start = dk_pke_start + 32;
350 let sigma_len = Hqc5Params::K;
351 let mut sigma = Zeroizing::new([0u8; MAX_SECURITY_BYTES]);
352 sigma[..sigma_len].copy_from_slice(&sk_bytes[sigma_start..sigma_start + sigma_len]);
353 let seed_kem_start = sigma_start + sigma_len;
354 let mut seed_kem = Zeroizing::new([0u8; 48]);
355 seed_kem.copy_from_slice(&sk_bytes[seed_kem_start..seed_kem_start + 48]);
356
357 let ek_pke = HqcPkePublicKey::<Hqc5Params>::new(ek_pke_bytes.to_vec());
358 let mut dk_pke_array = Zeroizing::new([0u8; 32]);
359 dk_pke_array.copy_from_slice(dk_pke_bytes);
360 let dk_pke = HqcPkeSecretKey::new(*dk_pke_array);
361 let kem_sk = HqcKemSecretKey::new(ek_pke, dk_pke, *sigma, *seed_kem);
362 let sk = Hqc5SecretKey::new(kem_sk);
363
364 let pke_ct_size = Hqc5Params::VEC_N_SIZE_BYTES + Hqc5Params::VEC_N1N2_SIZE_BYTES;
366 if ciphertext.len() != pke_ct_size + 16 {
367 return Err(Error::InvalidKeySize {
368 expected: pke_ct_size + 16,
369 actual: ciphertext.len(),
370 });
371 }
372 let c_pke_bytes = &ciphertext[..pke_ct_size];
373 let mut salt = Zeroizing::new([0u8; 16]);
374 salt.copy_from_slice(&ciphertext[pke_ct_size..pke_ct_size + 16]);
375 let c_pke = HqcPkeCiphertext::<Hqc5Params>::new(c_pke_bytes.to_vec());
376 let kem_ct = HqcKemCiphertext::new(c_pke, *salt);
377 let ct = Hqc5Ciphertext::new(kem_ct);
378
379 let shared_secret =
380 Hqc5::decapsulate::<lib_q_random::LibQRng>(&sk, &ct).map_err(|e| {
381 Error::InternalError {
382 operation: String::from("HQC-256 decapsulation"),
383 details: format!("Failed to decapsulate HQC-256: {:?}", e),
384 }
385 })?;
386 Ok(Vec::from(shared_secret.as_bytes()))
387 }
388 _ => Err(Error::InvalidAlgorithm {
389 algorithm: "Unsupported algorithm",
390 }),
391 }
392 }
393
394 fn derive_public_key(
395 &self,
396 algorithm: Algorithm,
397 secret_key: &lib_q_core::KemSecretKey,
398 ) -> Result<lib_q_core::KemPublicKey> {
399 #[allow(unused_imports)] use crate::params::{
401 Hqc1Params,
402 Hqc3Params,
403 Hqc5Params,
404 HqcParams,
405 };
406
407 match algorithm {
408 Algorithm::Hqc128 => {
409 let sk_bytes = &secret_key.data;
411 if sk_bytes.len() != Hqc1Params::SECRET_KEY_BYTES {
412 return Err(Error::InvalidKeySize {
413 expected: Hqc1Params::SECRET_KEY_BYTES,
414 actual: sk_bytes.len(),
415 });
416 }
417
418 let ek_pke_bytes = &sk_bytes[..Hqc1Params::PUBLIC_KEY_BYTES];
421
422 Ok(lib_q_core::KemPublicKey::new(Vec::from(ek_pke_bytes)))
423 }
424 Algorithm::Hqc192 => {
425 let sk_bytes = &secret_key.data;
427 if sk_bytes.len() != Hqc3Params::SECRET_KEY_BYTES {
428 return Err(Error::InvalidKeySize {
429 expected: Hqc3Params::SECRET_KEY_BYTES,
430 actual: sk_bytes.len(),
431 });
432 }
433
434 let ek_pke_bytes = &sk_bytes[..Hqc3Params::PUBLIC_KEY_BYTES];
436
437 Ok(lib_q_core::KemPublicKey::new(Vec::from(ek_pke_bytes)))
438 }
439 Algorithm::Hqc256 => {
440 let sk_bytes = &secret_key.data;
442 if sk_bytes.len() != Hqc5Params::SECRET_KEY_BYTES {
443 return Err(Error::InvalidKeySize {
444 expected: Hqc5Params::SECRET_KEY_BYTES,
445 actual: sk_bytes.len(),
446 });
447 }
448
449 let ek_pke_bytes = &sk_bytes[..Hqc5Params::PUBLIC_KEY_BYTES];
451
452 Ok(lib_q_core::KemPublicKey::new(Vec::from(ek_pke_bytes)))
453 }
454 _ => Err(Error::InvalidAlgorithm {
455 algorithm: "Unsupported algorithm for HQC derive_public_key",
456 }),
457 }
458 }
459}
460
461impl Default for LibQHqcProvider {
462 fn default() -> Self {
463 Self::new().expect("HQC provider should always be creatable")
464 }
465}
466
467#[cfg(all(feature = "alloc", feature = "random"))]
468impl CryptoProvider for LibQHqcProvider {
469 fn kem(&self) -> Option<&dyn KemOperations> {
470 Some(self)
471 }
472
473 fn signature(&self) -> Option<&dyn lib_q_core::SignatureOperations> {
474 None
475 }
476
477 fn hash(&self) -> Option<&dyn lib_q_core::HashOperations> {
478 None
479 }
480
481 fn aead(&self) -> Option<&dyn lib_q_core::AeadOperations> {
482 None
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 #[cfg(feature = "alloc")]
489 extern crate alloc;
490
491 use lib_q_core::Algorithm;
492
493 use super::*;
494
495 #[test]
496 fn test_derive_public_key_hqc128() {
497 let provider = LibQHqcProvider::new().expect("Failed to create provider");
498
499 let keypair = provider
501 .generate_keypair(Algorithm::Hqc128, None)
502 .expect("Failed to generate keypair");
503
504 let derived_pk = provider
506 .derive_public_key(Algorithm::Hqc128, &keypair.secret_key)
507 .expect("Failed to derive public key");
508
509 assert_eq!(
511 derived_pk.data, keypair.public_key.data,
512 "Derived public key should match original public key"
513 );
514 assert_eq!(
515 derived_pk.data.len(),
516 keypair.public_key.data.len(),
517 "Derived public key size should match original"
518 );
519 }
520
521 #[test]
522 fn test_derive_public_key_hqc192() {
523 let provider = LibQHqcProvider::new().expect("Failed to create provider");
524
525 let keypair = provider
527 .generate_keypair(Algorithm::Hqc192, None)
528 .expect("Failed to generate keypair");
529
530 let derived_pk = provider
532 .derive_public_key(Algorithm::Hqc192, &keypair.secret_key)
533 .expect("Failed to derive public key");
534
535 assert_eq!(
537 derived_pk.data, keypair.public_key.data,
538 "Derived public key should match original public key"
539 );
540 assert_eq!(
541 derived_pk.data.len(),
542 keypair.public_key.data.len(),
543 "Derived public key size should match original"
544 );
545 }
546
547 #[test]
548 fn test_derive_public_key_hqc256() {
549 let provider = LibQHqcProvider::new().expect("Failed to create provider");
550
551 let keypair = provider
553 .generate_keypair(Algorithm::Hqc256, None)
554 .expect("Failed to generate keypair");
555
556 let derived_pk = provider
558 .derive_public_key(Algorithm::Hqc256, &keypair.secret_key)
559 .expect("Failed to derive public key");
560
561 assert_eq!(
563 derived_pk.data, keypair.public_key.data,
564 "Derived public key should match original public key"
565 );
566 assert_eq!(
567 derived_pk.data.len(),
568 keypair.public_key.data.len(),
569 "Derived public key size should match original"
570 );
571 }
572
573 #[test]
574 fn test_derive_public_key_invalid_key_size() {
575 let provider = LibQHqcProvider::new().expect("Failed to create provider");
576
577 let invalid_sk = lib_q_core::KemSecretKey::new(alloc::vec![0u8; 100]);
579
580 let result = provider.derive_public_key(Algorithm::Hqc128, &invalid_sk);
582 assert!(result.is_err(), "Should return error for invalid key size");
583 if let Err(Error::InvalidKeySize { .. }) = result {
584 } else {
586 panic!("Expected InvalidKeySize error, got: {:?}", result);
587 }
588 }
589
590 #[test]
591 fn test_derive_public_key_unsupported_algorithm() {
592 let provider = LibQHqcProvider::new().expect("Failed to create provider");
593
594 let keypair = provider
596 .generate_keypair(Algorithm::Hqc128, None)
597 .expect("Failed to generate keypair");
598
599 let result = provider.derive_public_key(Algorithm::MlKem512, &keypair.secret_key);
601 assert!(
602 result.is_err(),
603 "Should return error for unsupported algorithm"
604 );
605 if let Err(Error::InvalidAlgorithm { .. }) = result {
606 } else {
608 panic!("Expected InvalidAlgorithm error, got: {:?}", result);
609 }
610 }
611
612 #[test]
613 fn test_derive_public_key_round_trip_encapsulation() {
614 let provider = LibQHqcProvider::new().expect("Failed to create provider");
615
616 let keypair = provider
617 .generate_keypair(Algorithm::Hqc128, None)
618 .expect("Failed to generate keypair");
619
620 let derived_pk = provider
621 .derive_public_key(Algorithm::Hqc128, &keypair.secret_key)
622 .expect("Failed to derive public key");
623
624 let mut enc_seed = [0u8; 48];
625 enc_seed[0] = 0xC1;
626 let (ciphertext, shared_secret1) = provider
627 .encapsulate(Algorithm::Hqc128, &derived_pk, Some(&enc_seed))
628 .expect("Failed to encapsulate with derived public key");
629
630 let shared_secret2 = provider
631 .decapsulate(Algorithm::Hqc128, &keypair.secret_key, &ciphertext)
632 .expect("Failed to decapsulate");
633
634 assert_eq!(
635 shared_secret1, shared_secret2,
636 "Shared secrets should match when using derived public key"
637 );
638 }
639
640 #[test]
641 fn test_derive_public_key_multiple_round_trips() {
642 let provider = LibQHqcProvider::new().expect("Failed to create provider");
643
644 let keypair = provider
645 .generate_keypair(Algorithm::Hqc192, None)
646 .expect("Failed to generate keypair");
647
648 let derived_pk = provider
649 .derive_public_key(Algorithm::Hqc192, &keypair.secret_key)
650 .expect("Failed to derive public key");
651
652 for i in 0u8..3 {
653 let mut enc_seed = [0u8; 48];
654 enc_seed[0] = i;
655 enc_seed[1] = 0xE5;
656 let (ciphertext, shared_secret1) = provider
657 .encapsulate(Algorithm::Hqc192, &derived_pk, Some(&enc_seed))
658 .expect("Failed to encapsulate");
659
660 let shared_secret2 = provider
661 .decapsulate(Algorithm::Hqc192, &keypair.secret_key, &ciphertext)
662 .expect("Failed to decapsulate");
663
664 assert_eq!(
665 shared_secret1, shared_secret2,
666 "Shared secrets should match in round-trip test"
667 );
668 }
669 }
670
671 #[test]
677 fn test_hqc256_provider_round_trip() {
678 let provider = LibQHqcProvider::new().expect("Failed to create provider");
679
680 let keypair = provider
681 .generate_keypair(Algorithm::Hqc256, None)
682 .expect("Failed to generate HQC-256 keypair");
683
684 let mut enc_seed = [0u8; 48];
685 enc_seed[0] = 0xF5;
686 let (ciphertext, shared_secret1) = provider
687 .encapsulate(Algorithm::Hqc256, &keypair.public_key, Some(&enc_seed))
688 .expect("Failed to encapsulate HQC-256");
689
690 let shared_secret2 = provider
691 .decapsulate(Algorithm::Hqc256, &keypair.secret_key, &ciphertext)
692 .expect("Failed to decapsulate HQC-256");
693
694 assert_eq!(
695 shared_secret1, shared_secret2,
696 "HQC-256 shared secrets must match through the provider round trip"
697 );
698 }
699
700 #[test]
704 fn test_encapsulate_and_decapsulate_reject_unsupported_algorithm() {
705 let provider = LibQHqcProvider::new().expect("Failed to create provider");
706
707 let keypair = provider
708 .generate_keypair(Algorithm::Hqc128, None)
709 .expect("Failed to generate keypair");
710
711 let result = provider.encapsulate(Algorithm::MlKem512, &keypair.public_key, None);
712 assert!(matches!(result, Err(Error::InvalidAlgorithm { .. })));
713
714 let result = provider.decapsulate(Algorithm::MlKem512, &keypair.secret_key, &[0u8; 16]);
715 assert!(matches!(result, Err(Error::InvalidAlgorithm { .. })));
716 }
717
718 #[test]
721 fn test_decapsulate_rejects_undersized_secret_key_all_variants() {
722 let provider = LibQHqcProvider::new().expect("Failed to create provider");
723
724 for algorithm in [Algorithm::Hqc128, Algorithm::Hqc192, Algorithm::Hqc256] {
725 let too_short_sk = lib_q_core::KemSecretKey::new(alloc::vec![0u8; 4]);
726 let result = provider.decapsulate(algorithm, &too_short_sk, &[0u8; 16]);
727 assert!(
728 matches!(result, Err(Error::InvalidKeySize { .. })),
729 "expected InvalidKeySize for {algorithm:?}, got {result:?}"
730 );
731 }
732 }
733
734 #[test]
738 fn test_decapsulate_rejects_undersized_ciphertext_all_variants() {
739 let provider = LibQHqcProvider::new().expect("Failed to create provider");
740
741 for algorithm in [Algorithm::Hqc128, Algorithm::Hqc192, Algorithm::Hqc256] {
742 let keypair = provider
743 .generate_keypair(algorithm, None)
744 .unwrap_or_else(|_| panic!("keygen failed for {algorithm:?}"));
745 let result = provider.decapsulate(algorithm, &keypair.secret_key, &[0u8; 4]);
746 assert!(
747 matches!(result, Err(Error::InvalidKeySize { .. })),
748 "expected InvalidKeySize for {algorithm:?}, got {result:?}"
749 );
750 }
751 }
752
753 #[test]
756 fn test_provider_accessors_and_default() {
757 let provider = LibQHqcProvider::new().expect("Failed to create provider");
758 assert_eq!(provider.name(), "libQ HQC Provider");
759 assert_eq!(provider.priority(), 100);
760 assert_eq!(
761 provider.capabilities(),
762 alloc::vec![Algorithm::Hqc128, Algorithm::Hqc192, Algorithm::Hqc256]
763 );
764 assert!(provider.supports_algorithm(Algorithm::Hqc128));
765 assert!(provider.supports_algorithm(Algorithm::Hqc192));
766 assert!(provider.supports_algorithm(Algorithm::Hqc256));
767 assert!(!provider.supports_algorithm(Algorithm::MlKem512));
768
769 let default_provider: LibQHqcProvider = Default::default();
779 assert_eq!(default_provider, provider);
780 }
781
782 #[test]
784 fn test_provider_crypto_provider_trait_accessors() {
785 let provider = LibQHqcProvider::new().expect("Failed to create provider");
786 assert!(CryptoProvider::kem(&provider).is_some());
787 assert!(CryptoProvider::signature(&provider).is_none());
788 assert!(CryptoProvider::hash(&provider).is_none());
789 assert!(CryptoProvider::aead(&provider).is_none());
790 }
791
792 #[test]
795 fn test_generate_keypair_rejects_unsupported_algorithm() {
796 let provider = LibQHqcProvider::new().expect("Failed to create provider");
797 let result = provider.generate_keypair(Algorithm::MlKem512, None);
798 assert!(matches!(result, Err(Error::InvalidAlgorithm { .. })));
799 }
800
801 #[test]
804 fn test_derive_public_key_invalid_key_size_hqc192_and_hqc256() {
805 let provider = LibQHqcProvider::new().expect("Failed to create provider");
806 let invalid_sk = lib_q_core::KemSecretKey::new(alloc::vec![0u8; 4]);
807
808 let result = provider.derive_public_key(Algorithm::Hqc192, &invalid_sk);
809 assert!(matches!(result, Err(Error::InvalidKeySize { .. })));
810
811 let result = provider.derive_public_key(Algorithm::Hqc256, &invalid_sk);
812 assert!(matches!(result, Err(Error::InvalidKeySize { .. })));
813 }
814
815 #[test]
816 fn test_derive_public_key_all_algorithms() {
817 let provider = LibQHqcProvider::new().expect("Failed to create provider");
818
819 let algorithms = [Algorithm::Hqc128, Algorithm::Hqc192, Algorithm::Hqc256];
820
821 for algorithm in algorithms {
822 let keypair = provider
824 .generate_keypair(algorithm, None)
825 .unwrap_or_else(|_| panic!("Failed to generate keypair for {algorithm:?}"));
826
827 let derived_pk = provider
829 .derive_public_key(algorithm, &keypair.secret_key)
830 .unwrap_or_else(|_| panic!("Failed to derive public key for {algorithm:?}"));
831
832 assert_eq!(
834 derived_pk.data, keypair.public_key.data,
835 "Derived public key should match for {:?}",
836 algorithm
837 );
838 }
839 }
840}