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_correct::{
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_correct::{
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_correct::{
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_correct::{
208 Hqc1Ciphertext,
209 Hqc1SecretKey,
210 Hqc3Ciphertext,
211 Hqc3SecretKey,
212 Hqc5Ciphertext,
213 Hqc5SecretKey,
214 };
215 use crate::hqc_kem::{
216 HqcKemCiphertext,
217 HqcKemSecretKey,
218 };
219 use crate::hqc_pke::{
220 HqcPkeCiphertext,
221 HqcPkePublicKey,
222 HqcPkeSecretKey,
223 };
224 #[allow(unused_imports)] use crate::params_correct::{
226 Hqc1Params,
227 Hqc3Params,
228 Hqc5Params,
229 HqcParams,
230 };
231
232 match algorithm {
233 Algorithm::Hqc128 => {
234 let sk_bytes = &secret_key.data;
236 if sk_bytes.len() < Hqc1Params::SECRET_KEY_BYTES {
237 return Err(Error::InvalidKeySize {
238 expected: Hqc1Params::SECRET_KEY_BYTES,
239 actual: sk_bytes.len(),
240 });
241 }
242 let ek_pke_bytes = &sk_bytes[..Hqc1Params::PUBLIC_KEY_BYTES];
243 let dk_pke_start = Hqc1Params::PUBLIC_KEY_BYTES;
244 let dk_pke_bytes = &sk_bytes[dk_pke_start..dk_pke_start + 32];
245 let sigma_start = dk_pke_start + 32;
246 let mut sigma = Zeroizing::new([0u8; 16]);
247 sigma.copy_from_slice(&sk_bytes[sigma_start..sigma_start + 16]);
248 let seed_kem_start = sigma_start + 16;
249 let mut seed_kem = Zeroizing::new([0u8; 48]);
250 seed_kem.copy_from_slice(&sk_bytes[seed_kem_start..seed_kem_start + 48]);
251
252 let ek_pke = HqcPkePublicKey::<Hqc1Params>::new(ek_pke_bytes.to_vec());
253 let mut dk_pke_array = Zeroizing::new([0u8; 32]);
254 dk_pke_array.copy_from_slice(dk_pke_bytes);
255 let dk_pke = HqcPkeSecretKey::new(*dk_pke_array);
256 let kem_sk = HqcKemSecretKey::new(ek_pke, dk_pke, *sigma, *seed_kem);
257 let sk = Hqc1SecretKey::new(kem_sk);
258
259 let pke_ct_size = Hqc1Params::VEC_N_SIZE_BYTES + Hqc1Params::VEC_N1N2_SIZE_BYTES;
261 if ciphertext.len() < pke_ct_size + 16 {
262 return Err(Error::InvalidKeySize {
263 expected: pke_ct_size + 16,
264 actual: ciphertext.len(),
265 });
266 }
267 let c_pke_bytes = &ciphertext[..pke_ct_size];
268 let mut salt = Zeroizing::new([0u8; 16]);
269 salt.copy_from_slice(&ciphertext[pke_ct_size..pke_ct_size + 16]);
270 let c_pke = HqcPkeCiphertext::<Hqc1Params>::new(c_pke_bytes.to_vec());
271 let kem_ct = HqcKemCiphertext::new(c_pke, *salt);
272 let ct = Hqc1Ciphertext::new(kem_ct);
273
274 let shared_secret =
275 Hqc1::decapsulate::<lib_q_random::LibQRng>(&sk, &ct).map_err(|e| {
276 Error::InternalError {
277 operation: String::from("HQC-128 decapsulation"),
278 details: format!("Failed to decapsulate HQC-128: {:?}", e),
279 }
280 })?;
281 Ok(Vec::from(shared_secret.as_bytes()))
282 }
283 Algorithm::Hqc192 => {
284 let sk_bytes = &secret_key.data;
286 if sk_bytes.len() < Hqc3Params::SECRET_KEY_BYTES {
287 return Err(Error::InvalidKeySize {
288 expected: Hqc3Params::SECRET_KEY_BYTES,
289 actual: sk_bytes.len(),
290 });
291 }
292 let ek_pke_bytes = &sk_bytes[..Hqc3Params::PUBLIC_KEY_BYTES];
293 let dk_pke_start = Hqc3Params::PUBLIC_KEY_BYTES;
294 let dk_pke_bytes = &sk_bytes[dk_pke_start..dk_pke_start + 32];
295 let sigma_start = dk_pke_start + 32;
296 let mut sigma = Zeroizing::new([0u8; 16]);
297 sigma.copy_from_slice(&sk_bytes[sigma_start..sigma_start + 16]);
298 let seed_kem_start = sigma_start + 16;
299 let mut seed_kem = Zeroizing::new([0u8; 48]);
300 seed_kem.copy_from_slice(&sk_bytes[seed_kem_start..seed_kem_start + 48]);
301
302 let ek_pke = HqcPkePublicKey::<Hqc3Params>::new(ek_pke_bytes.to_vec());
303 let mut dk_pke_array = Zeroizing::new([0u8; 32]);
304 dk_pke_array.copy_from_slice(dk_pke_bytes);
305 let dk_pke = HqcPkeSecretKey::new(*dk_pke_array);
306 let kem_sk = HqcKemSecretKey::new(ek_pke, dk_pke, *sigma, *seed_kem);
307 let sk = Hqc3SecretKey::new(kem_sk);
308
309 let pke_ct_size = Hqc3Params::VEC_N_SIZE_BYTES + Hqc3Params::VEC_N1N2_SIZE_BYTES;
311 if ciphertext.len() < pke_ct_size + 16 {
312 return Err(Error::InvalidKeySize {
313 expected: pke_ct_size + 16,
314 actual: ciphertext.len(),
315 });
316 }
317 let c_pke_bytes = &ciphertext[..pke_ct_size];
318 let mut salt = Zeroizing::new([0u8; 16]);
319 salt.copy_from_slice(&ciphertext[pke_ct_size..pke_ct_size + 16]);
320 let c_pke = HqcPkeCiphertext::<Hqc3Params>::new(c_pke_bytes.to_vec());
321 let kem_ct = HqcKemCiphertext::new(c_pke, *salt);
322 let ct = Hqc3Ciphertext::new(kem_ct);
323
324 let shared_secret =
325 Hqc3::decapsulate::<lib_q_random::LibQRng>(&sk, &ct).map_err(|e| {
326 Error::InternalError {
327 operation: String::from("HQC-192 decapsulation"),
328 details: format!("Failed to decapsulate HQC-192: {:?}", e),
329 }
330 })?;
331 Ok(Vec::from(shared_secret.as_bytes()))
332 }
333 Algorithm::Hqc256 => {
334 let sk_bytes = &secret_key.data;
336 if sk_bytes.len() < Hqc5Params::SECRET_KEY_BYTES {
337 return Err(Error::InvalidKeySize {
338 expected: Hqc5Params::SECRET_KEY_BYTES,
339 actual: sk_bytes.len(),
340 });
341 }
342 let ek_pke_bytes = &sk_bytes[..Hqc5Params::PUBLIC_KEY_BYTES];
343 let dk_pke_start = Hqc5Params::PUBLIC_KEY_BYTES;
344 let dk_pke_bytes = &sk_bytes[dk_pke_start..dk_pke_start + 32];
345 let sigma_start = dk_pke_start + 32;
346 let mut sigma = Zeroizing::new([0u8; 16]);
347 sigma.copy_from_slice(&sk_bytes[sigma_start..sigma_start + 16]);
348 let seed_kem_start = sigma_start + 16;
349 let mut seed_kem = Zeroizing::new([0u8; 48]);
350 seed_kem.copy_from_slice(&sk_bytes[seed_kem_start..seed_kem_start + 48]);
351
352 let ek_pke = HqcPkePublicKey::<Hqc5Params>::new(ek_pke_bytes.to_vec());
353 let mut dk_pke_array = Zeroizing::new([0u8; 32]);
354 dk_pke_array.copy_from_slice(dk_pke_bytes);
355 let dk_pke = HqcPkeSecretKey::new(*dk_pke_array);
356 let kem_sk = HqcKemSecretKey::new(ek_pke, dk_pke, *sigma, *seed_kem);
357 let sk = Hqc5SecretKey::new(kem_sk);
358
359 let pke_ct_size = Hqc5Params::VEC_N_SIZE_BYTES + Hqc5Params::VEC_N1N2_SIZE_BYTES;
361 if ciphertext.len() < pke_ct_size + 16 {
362 return Err(Error::InvalidKeySize {
363 expected: pke_ct_size + 16,
364 actual: ciphertext.len(),
365 });
366 }
367 let c_pke_bytes = &ciphertext[..pke_ct_size];
368 let mut salt = Zeroizing::new([0u8; 16]);
369 salt.copy_from_slice(&ciphertext[pke_ct_size..pke_ct_size + 16]);
370 let c_pke = HqcPkeCiphertext::<Hqc5Params>::new(c_pke_bytes.to_vec());
371 let kem_ct = HqcKemCiphertext::new(c_pke, *salt);
372 let ct = Hqc5Ciphertext::new(kem_ct);
373
374 let shared_secret =
375 Hqc5::decapsulate::<lib_q_random::LibQRng>(&sk, &ct).map_err(|e| {
376 Error::InternalError {
377 operation: String::from("HQC-256 decapsulation"),
378 details: format!("Failed to decapsulate HQC-256: {:?}", e),
379 }
380 })?;
381 Ok(Vec::from(shared_secret.as_bytes()))
382 }
383 _ => Err(Error::InvalidAlgorithm {
384 algorithm: "Unsupported algorithm",
385 }),
386 }
387 }
388
389 fn derive_public_key(
390 &self,
391 algorithm: Algorithm,
392 secret_key: &lib_q_core::KemSecretKey,
393 ) -> Result<lib_q_core::KemPublicKey> {
394 #[allow(unused_imports)] use crate::params_correct::{
396 Hqc1Params,
397 Hqc3Params,
398 Hqc5Params,
399 HqcParams,
400 };
401
402 match algorithm {
403 Algorithm::Hqc128 => {
404 let sk_bytes = &secret_key.data;
406 if sk_bytes.len() < Hqc1Params::SECRET_KEY_BYTES {
407 return Err(Error::InvalidKeySize {
408 expected: Hqc1Params::SECRET_KEY_BYTES,
409 actual: sk_bytes.len(),
410 });
411 }
412
413 let ek_pke_bytes = &sk_bytes[..Hqc1Params::PUBLIC_KEY_BYTES];
416
417 Ok(lib_q_core::KemPublicKey::new(Vec::from(ek_pke_bytes)))
418 }
419 Algorithm::Hqc192 => {
420 let sk_bytes = &secret_key.data;
422 if sk_bytes.len() < Hqc3Params::SECRET_KEY_BYTES {
423 return Err(Error::InvalidKeySize {
424 expected: Hqc3Params::SECRET_KEY_BYTES,
425 actual: sk_bytes.len(),
426 });
427 }
428
429 let ek_pke_bytes = &sk_bytes[..Hqc3Params::PUBLIC_KEY_BYTES];
431
432 Ok(lib_q_core::KemPublicKey::new(Vec::from(ek_pke_bytes)))
433 }
434 Algorithm::Hqc256 => {
435 let sk_bytes = &secret_key.data;
437 if sk_bytes.len() < Hqc5Params::SECRET_KEY_BYTES {
438 return Err(Error::InvalidKeySize {
439 expected: Hqc5Params::SECRET_KEY_BYTES,
440 actual: sk_bytes.len(),
441 });
442 }
443
444 let ek_pke_bytes = &sk_bytes[..Hqc5Params::PUBLIC_KEY_BYTES];
446
447 Ok(lib_q_core::KemPublicKey::new(Vec::from(ek_pke_bytes)))
448 }
449 _ => Err(Error::InvalidAlgorithm {
450 algorithm: "Unsupported algorithm for HQC derive_public_key",
451 }),
452 }
453 }
454}
455
456impl Default for LibQHqcProvider {
457 fn default() -> Self {
458 Self::new().expect("HQC provider should always be creatable")
459 }
460}
461
462#[cfg(all(feature = "alloc", feature = "random"))]
463impl CryptoProvider for LibQHqcProvider {
464 fn kem(&self) -> Option<&dyn KemOperations> {
465 Some(self)
466 }
467
468 fn signature(&self) -> Option<&dyn lib_q_core::SignatureOperations> {
469 None
470 }
471
472 fn hash(&self) -> Option<&dyn lib_q_core::HashOperations> {
473 None
474 }
475
476 fn aead(&self) -> Option<&dyn lib_q_core::AeadOperations> {
477 None
478 }
479}
480
481#[cfg(test)]
482mod tests {
483 #[cfg(feature = "alloc")]
484 extern crate alloc;
485
486 use lib_q_core::Algorithm;
487
488 use super::*;
489
490 #[test]
491 fn test_derive_public_key_hqc128() {
492 let provider = LibQHqcProvider::new().expect("Failed to create provider");
493
494 let keypair = provider
496 .generate_keypair(Algorithm::Hqc128, None)
497 .expect("Failed to generate keypair");
498
499 let derived_pk = provider
501 .derive_public_key(Algorithm::Hqc128, &keypair.secret_key)
502 .expect("Failed to derive public key");
503
504 assert_eq!(
506 derived_pk.data, keypair.public_key.data,
507 "Derived public key should match original public key"
508 );
509 assert_eq!(
510 derived_pk.data.len(),
511 keypair.public_key.data.len(),
512 "Derived public key size should match original"
513 );
514 }
515
516 #[test]
517 fn test_derive_public_key_hqc192() {
518 let provider = LibQHqcProvider::new().expect("Failed to create provider");
519
520 let keypair = provider
522 .generate_keypair(Algorithm::Hqc192, None)
523 .expect("Failed to generate keypair");
524
525 let derived_pk = provider
527 .derive_public_key(Algorithm::Hqc192, &keypair.secret_key)
528 .expect("Failed to derive public key");
529
530 assert_eq!(
532 derived_pk.data, keypair.public_key.data,
533 "Derived public key should match original public key"
534 );
535 assert_eq!(
536 derived_pk.data.len(),
537 keypair.public_key.data.len(),
538 "Derived public key size should match original"
539 );
540 }
541
542 #[test]
543 fn test_derive_public_key_hqc256() {
544 let provider = LibQHqcProvider::new().expect("Failed to create provider");
545
546 let keypair = provider
548 .generate_keypair(Algorithm::Hqc256, None)
549 .expect("Failed to generate keypair");
550
551 let derived_pk = provider
553 .derive_public_key(Algorithm::Hqc256, &keypair.secret_key)
554 .expect("Failed to derive public key");
555
556 assert_eq!(
558 derived_pk.data, keypair.public_key.data,
559 "Derived public key should match original public key"
560 );
561 assert_eq!(
562 derived_pk.data.len(),
563 keypair.public_key.data.len(),
564 "Derived public key size should match original"
565 );
566 }
567
568 #[test]
569 fn test_derive_public_key_invalid_key_size() {
570 let provider = LibQHqcProvider::new().expect("Failed to create provider");
571
572 let invalid_sk = lib_q_core::KemSecretKey::new(alloc::vec![0u8; 100]);
574
575 let result = provider.derive_public_key(Algorithm::Hqc128, &invalid_sk);
577 assert!(result.is_err(), "Should return error for invalid key size");
578 if let Err(Error::InvalidKeySize { .. }) = result {
579 } else {
581 panic!("Expected InvalidKeySize error, got: {:?}", result);
582 }
583 }
584
585 #[test]
586 fn test_derive_public_key_unsupported_algorithm() {
587 let provider = LibQHqcProvider::new().expect("Failed to create provider");
588
589 let keypair = provider
591 .generate_keypair(Algorithm::Hqc128, None)
592 .expect("Failed to generate keypair");
593
594 let result = provider.derive_public_key(Algorithm::MlKem512, &keypair.secret_key);
596 assert!(
597 result.is_err(),
598 "Should return error for unsupported algorithm"
599 );
600 if let Err(Error::InvalidAlgorithm { .. }) = result {
601 } else {
603 panic!("Expected InvalidAlgorithm error, got: {:?}", result);
604 }
605 }
606
607 #[test]
608 fn test_derive_public_key_round_trip_encapsulation() {
609 let provider = LibQHqcProvider::new().expect("Failed to create provider");
610
611 let keypair = provider
612 .generate_keypair(Algorithm::Hqc128, None)
613 .expect("Failed to generate keypair");
614
615 let derived_pk = provider
616 .derive_public_key(Algorithm::Hqc128, &keypair.secret_key)
617 .expect("Failed to derive public key");
618
619 let mut enc_seed = [0u8; 48];
620 enc_seed[0] = 0xC1;
621 let (ciphertext, shared_secret1) = provider
622 .encapsulate(Algorithm::Hqc128, &derived_pk, Some(&enc_seed))
623 .expect("Failed to encapsulate with derived public key");
624
625 let shared_secret2 = provider
626 .decapsulate(Algorithm::Hqc128, &keypair.secret_key, &ciphertext)
627 .expect("Failed to decapsulate");
628
629 assert_eq!(
630 shared_secret1, shared_secret2,
631 "Shared secrets should match when using derived public key"
632 );
633 }
634
635 #[test]
636 fn test_derive_public_key_multiple_round_trips() {
637 let provider = LibQHqcProvider::new().expect("Failed to create provider");
638
639 let keypair = provider
640 .generate_keypair(Algorithm::Hqc192, None)
641 .expect("Failed to generate keypair");
642
643 let derived_pk = provider
644 .derive_public_key(Algorithm::Hqc192, &keypair.secret_key)
645 .expect("Failed to derive public key");
646
647 for i in 0u8..3 {
648 let mut enc_seed = [0u8; 48];
649 enc_seed[0] = i;
650 enc_seed[1] = 0xE5;
651 let (ciphertext, shared_secret1) = provider
652 .encapsulate(Algorithm::Hqc192, &derived_pk, Some(&enc_seed))
653 .expect("Failed to encapsulate");
654
655 let shared_secret2 = provider
656 .decapsulate(Algorithm::Hqc192, &keypair.secret_key, &ciphertext)
657 .expect("Failed to decapsulate");
658
659 assert_eq!(
660 shared_secret1, shared_secret2,
661 "Shared secrets should match in round-trip test"
662 );
663 }
664 }
665
666 #[test]
667 fn test_derive_public_key_all_algorithms() {
668 let provider = LibQHqcProvider::new().expect("Failed to create provider");
669
670 let algorithms = [Algorithm::Hqc128, Algorithm::Hqc192, Algorithm::Hqc256];
671
672 for algorithm in algorithms {
673 let keypair = provider
675 .generate_keypair(algorithm, None)
676 .unwrap_or_else(|_| panic!("Failed to generate keypair for {algorithm:?}"));
677
678 let derived_pk = provider
680 .derive_public_key(algorithm, &keypair.secret_key)
681 .unwrap_or_else(|_| panic!("Failed to derive public key for {algorithm:?}"));
682
683 assert_eq!(
685 derived_pk.data, keypair.public_key.data,
686 "Derived public key should match for {:?}",
687 algorithm
688 );
689 }
690 }
691}