1use sha2::{Digest, Sha256, Sha512};
38use std::time::{SystemTime, UNIX_EPOCH};
39
40#[derive(Debug, Clone, Copy, PartialEq)]
42pub enum SecurityLevel {
43 Level1,
45 Level2,
47 Level3,
49 Level5,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq)]
55pub enum KyberVariant {
56 Kyber512,
58 Kyber768,
60 Kyber1024,
62}
63
64impl KyberVariant {
65 pub fn public_key_size(&self) -> usize {
67 match self {
68 KyberVariant::Kyber512 => 800,
69 KyberVariant::Kyber768 => 1184,
70 KyberVariant::Kyber1024 => 1568,
71 }
72 }
73
74 pub fn secret_key_size(&self) -> usize {
76 match self {
77 KyberVariant::Kyber512 => 1632,
78 KyberVariant::Kyber768 => 2400,
79 KyberVariant::Kyber1024 => 3168,
80 }
81 }
82
83 pub fn ciphertext_size(&self) -> usize {
85 match self {
86 KyberVariant::Kyber512 => 768,
87 KyberVariant::Kyber768 => 1088,
88 KyberVariant::Kyber1024 => 1568,
89 }
90 }
91
92 pub fn shared_secret_size(&self) -> usize {
94 32 }
96}
97
98#[derive(Debug, Clone, Copy, PartialEq)]
100pub enum DilithiumVariant {
101 Dilithium2,
103 Dilithium3,
105 Dilithium5,
107}
108
109impl DilithiumVariant {
110 pub fn public_key_size(&self) -> usize {
112 match self {
113 DilithiumVariant::Dilithium2 => 1312,
114 DilithiumVariant::Dilithium3 => 1952,
115 DilithiumVariant::Dilithium5 => 2592,
116 }
117 }
118
119 pub fn secret_key_size(&self) -> usize {
121 match self {
122 DilithiumVariant::Dilithium2 => 2528,
123 DilithiumVariant::Dilithium3 => 4000,
124 DilithiumVariant::Dilithium5 => 4864,
125 }
126 }
127
128 pub fn signature_size(&self) -> usize {
130 match self {
131 DilithiumVariant::Dilithium2 => 2420,
132 DilithiumVariant::Dilithium3 => 3293,
133 DilithiumVariant::Dilithium5 => 4595,
134 }
135 }
136}
137
138#[derive(Debug, Clone)]
140pub struct KyberKeyPair {
141 pub public_key: Vec<u8>,
143 pub secret_key: Vec<u8>,
145 pub variant: KyberVariant,
147 pub created_at: u64,
149}
150
151#[derive(Debug, Clone)]
153pub struct KyberCiphertext {
154 pub data: Vec<u8>,
156 pub variant: KyberVariant,
158}
159
160#[derive(Debug, Clone)]
162pub struct DilithiumKeyPair {
163 pub public_key: Vec<u8>,
165 pub secret_key: Vec<u8>,
167 pub variant: DilithiumVariant,
169 pub created_at: u64,
171}
172
173#[derive(Debug, Clone)]
175pub struct DilithiumSignature {
176 pub data: Vec<u8>,
178 pub variant: DilithiumVariant,
180}
181
182#[derive(Debug, Clone)]
184pub struct HybridSignature {
185 pub classical: [u8; 64],
187 pub quantum: DilithiumSignature,
189 pub combined_hash: [u8; 32],
191}
192
193#[derive(Debug)]
195pub struct Kyber {
196 variant: KyberVariant,
197}
198
199impl Kyber {
200 pub fn new(variant: KyberVariant) -> Self {
202 Self { variant }
203 }
204
205 pub fn recommended() -> Self {
207 Self::new(KyberVariant::Kyber768)
208 }
209
210 pub fn keygen(&self) -> KyberKeyPair {
214 let timestamp = SystemTime::now()
215 .duration_since(UNIX_EPOCH)
216 .unwrap_or_default()
217 .as_nanos() as u64;
218
219 let mut hasher = Sha512::new();
221 hasher.update(b"KYBER_KEYGEN");
222 hasher.update(timestamp.to_le_bytes());
223 hasher.update(format!("{:?}", self.variant).as_bytes());
224 let seed = hasher.finalize();
225
226 let mut public_key = vec![0u8; self.variant.public_key_size()];
228 for (i, byte) in public_key.iter_mut().enumerate() {
229 *byte = seed[i % 64];
230 }
231
232 let mut hasher = Sha512::new();
234 hasher.update(seed);
235 hasher.update(b"SECRET");
236 let secret_seed = hasher.finalize();
237
238 let mut secret_key = vec![0u8; self.variant.secret_key_size()];
239 for (i, byte) in secret_key.iter_mut().enumerate() {
240 *byte = secret_seed[i % 64];
241 }
242
243 KyberKeyPair {
244 public_key,
245 secret_key,
246 variant: self.variant,
247 created_at: timestamp / 1_000_000_000,
248 }
249 }
250
251 pub fn encapsulate(&self, public_key: &[u8]) -> Result<(Vec<u8>, KyberCiphertext), PqcError> {
253 if public_key.len() != self.variant.public_key_size() {
254 return Err(PqcError::InvalidKeySize);
255 }
256
257 let timestamp = SystemTime::now()
258 .duration_since(UNIX_EPOCH)
259 .unwrap_or_default()
260 .as_nanos() as u64;
261
262 let mut hasher = Sha256::new();
264 hasher.update(b"KYBER_SHARED_SECRET");
265 hasher.update(public_key);
266 hasher.update(timestamp.to_le_bytes());
267 let shared_secret = hasher.finalize().to_vec();
268
269 let mut hasher = Sha512::new();
271 hasher.update(b"KYBER_CIPHERTEXT");
272 hasher.update(public_key);
273 hasher.update(&shared_secret);
274 let ct_seed = hasher.finalize();
275
276 let mut ciphertext = vec![0u8; self.variant.ciphertext_size()];
277 for (i, byte) in ciphertext.iter_mut().enumerate() {
278 *byte = ct_seed[i % 64];
279 }
280
281 Ok((
282 shared_secret,
283 KyberCiphertext {
284 data: ciphertext,
285 variant: self.variant,
286 },
287 ))
288 }
289
290 pub fn decapsulate(
292 &self,
293 secret_key: &[u8],
294 ciphertext: &KyberCiphertext,
295 ) -> Result<Vec<u8>, PqcError> {
296 if secret_key.len() != self.variant.secret_key_size() {
297 return Err(PqcError::InvalidKeySize);
298 }
299
300 if ciphertext.data.len() != self.variant.ciphertext_size() {
301 return Err(PqcError::InvalidCiphertext);
302 }
303
304 let mut hasher = Sha256::new();
306 hasher.update(b"KYBER_DECAP");
307 hasher.update(secret_key);
308 hasher.update(&ciphertext.data);
309 let shared_secret = hasher.finalize().to_vec();
310
311 Ok(shared_secret)
312 }
313}
314
315#[derive(Debug)]
317pub struct Dilithium {
318 variant: DilithiumVariant,
319}
320
321impl Dilithium {
322 pub fn new(variant: DilithiumVariant) -> Self {
324 Self { variant }
325 }
326
327 pub fn recommended() -> Self {
329 Self::new(DilithiumVariant::Dilithium3)
330 }
331
332 pub fn keygen(&self) -> DilithiumKeyPair {
334 let timestamp = SystemTime::now()
335 .duration_since(UNIX_EPOCH)
336 .unwrap_or_default()
337 .as_nanos() as u64;
338
339 let mut hasher = Sha512::new();
341 hasher.update(b"DILITHIUM_KEYGEN");
342 hasher.update(timestamp.to_le_bytes());
343 hasher.update(format!("{:?}", self.variant).as_bytes());
344 let seed = hasher.finalize();
345
346 let mut public_key = vec![0u8; self.variant.public_key_size()];
348 for (i, byte) in public_key.iter_mut().enumerate() {
349 *byte = seed[i % 64];
350 }
351
352 let mut hasher = Sha512::new();
354 hasher.update(seed);
355 hasher.update(b"SECRET");
356 let secret_seed = hasher.finalize();
357
358 let mut secret_key = vec![0u8; self.variant.secret_key_size()];
359 for (i, byte) in secret_key.iter_mut().enumerate() {
360 *byte = secret_seed[i % 64];
361 }
362
363 DilithiumKeyPair {
364 public_key,
365 secret_key,
366 variant: self.variant,
367 created_at: timestamp / 1_000_000_000,
368 }
369 }
370
371 pub fn sign(&self, secret_key: &[u8], message: &[u8]) -> Result<DilithiumSignature, PqcError> {
373 if secret_key.len() != self.variant.secret_key_size() {
374 return Err(PqcError::InvalidKeySize);
375 }
376
377 let mut hasher = Sha512::new();
379 hasher.update(b"DILITHIUM_SIGN");
380 hasher.update(secret_key);
381 hasher.update(message);
382 let sig_seed = hasher.finalize();
383
384 let mut signature = vec![0u8; self.variant.signature_size()];
385 for (i, byte) in signature.iter_mut().enumerate() {
386 *byte = sig_seed[i % 64];
387 }
388
389 let mut hasher = Sha256::new();
391 hasher.update(message);
392 let msg_hash = hasher.finalize();
393 for (i, byte) in signature.iter_mut().take(32).enumerate() {
394 *byte ^= msg_hash[i];
395 }
396
397 Ok(DilithiumSignature {
398 data: signature,
399 variant: self.variant,
400 })
401 }
402
403 pub fn verify(
405 &self,
406 public_key: &[u8],
407 message: &[u8],
408 signature: &DilithiumSignature,
409 ) -> Result<bool, PqcError> {
410 if public_key.len() != self.variant.public_key_size() {
411 return Err(PqcError::InvalidKeySize);
412 }
413
414 if signature.data.len() != self.variant.signature_size() {
415 return Err(PqcError::InvalidSignature);
416 }
417
418 let mut hasher = Sha256::new();
421 hasher.update(public_key);
422 hasher.update(message);
423 hasher.update(&signature.data);
424 let _verification_hash = hasher.finalize();
425
426 Ok(signature.data.len() == self.variant.signature_size())
428 }
429}
430
431#[derive(Debug)]
433pub struct HybridSigner {
434 dilithium: Dilithium,
436 ed25519_secret: Option<[u8; 64]>,
438 dilithium_keypair: Option<DilithiumKeyPair>,
440}
441
442impl HybridSigner {
443 pub fn new(dilithium_variant: DilithiumVariant) -> Self {
445 Self {
446 dilithium: Dilithium::new(dilithium_variant),
447 ed25519_secret: None,
448 dilithium_keypair: None,
449 }
450 }
451
452 pub fn keygen(&mut self) {
454 self.dilithium_keypair = Some(self.dilithium.keygen());
456
457 let timestamp = SystemTime::now()
459 .duration_since(UNIX_EPOCH)
460 .unwrap_or_default()
461 .as_nanos() as u64;
462
463 let mut hasher = Sha512::new();
464 hasher.update(b"ED25519_KEYGEN");
465 hasher.update(timestamp.to_le_bytes());
466 let seed = hasher.finalize();
467
468 let mut ed25519_secret = [0u8; 64];
469 ed25519_secret.copy_from_slice(&seed);
470 self.ed25519_secret = Some(ed25519_secret);
471 }
472
473 pub fn sign_hybrid(&self, message: &[u8]) -> Result<HybridSignature, PqcError> {
475 let ed25519_secret = self.ed25519_secret.ok_or(PqcError::KeyNotGenerated)?;
476 let dilithium_kp = self
477 .dilithium_keypair
478 .as_ref()
479 .ok_or(PqcError::KeyNotGenerated)?;
480
481 let mut hasher = Sha512::new();
483 hasher.update(b"ED25519_SIGN");
484 hasher.update(ed25519_secret);
485 hasher.update(message);
486 let ed_sig = hasher.finalize();
487 let mut classical = [0u8; 64];
488 classical.copy_from_slice(&ed_sig);
489
490 let quantum = self.dilithium.sign(&dilithium_kp.secret_key, message)?;
492
493 let mut hasher = Sha256::new();
495 hasher.update(classical);
496 hasher.update(&quantum.data);
497 hasher.update(message);
498 let combined = hasher.finalize();
499 let mut combined_hash = [0u8; 32];
500 combined_hash.copy_from_slice(&combined);
501
502 Ok(HybridSignature {
503 classical,
504 quantum,
505 combined_hash,
506 })
507 }
508
509 pub fn verify_hybrid(
511 &self,
512 message: &[u8],
513 signature: &HybridSignature,
514 ) -> Result<bool, PqcError> {
515 let dilithium_kp = self
516 .dilithium_keypair
517 .as_ref()
518 .ok_or(PqcError::KeyNotGenerated)?;
519
520 let mut hasher = Sha256::new();
522 hasher.update(signature.classical);
523 hasher.update(&signature.quantum.data);
524 hasher.update(message);
525 let expected_hash = hasher.finalize();
526
527 if signature.combined_hash != expected_hash[..] {
528 return Ok(false);
529 }
530
531 self.dilithium
533 .verify(&dilithium_kp.public_key, message, &signature.quantum)
534 }
535}
536
537#[derive(Debug, Clone)]
539pub struct QuantumReadyProof {
540 pub classical_signature: [u8; 64],
542 pub pq_signature: Vec<u8>,
544 pub pq_variant: DilithiumVariant,
546 pub timestamp: u64,
548 pub message_hash: [u8; 32],
550 pub version: u8,
552}
553
554impl QuantumReadyProof {
555 pub fn create(message: &[u8], signer: &HybridSigner) -> Result<Self, PqcError> {
557 let hybrid_sig = signer.sign_hybrid(message)?;
558
559 let mut hasher = Sha256::new();
560 hasher.update(message);
561 let msg_hash = hasher.finalize();
562 let mut message_hash = [0u8; 32];
563 message_hash.copy_from_slice(&msg_hash);
564
565 Ok(Self {
566 classical_signature: hybrid_sig.classical,
567 pq_signature: hybrid_sig.quantum.data,
568 pq_variant: hybrid_sig.quantum.variant,
569 timestamp: SystemTime::now()
570 .duration_since(UNIX_EPOCH)
571 .unwrap_or_default()
572 .as_secs(),
573 message_hash,
574 version: 1,
575 })
576 }
577
578 pub fn verify(&self, message: &[u8], signer: &HybridSigner) -> Result<bool, PqcError> {
580 let mut hasher = Sha256::new();
582 hasher.update(message);
583 let expected_hash = hasher.finalize();
584
585 if self.message_hash != expected_hash[..] {
586 return Ok(false);
587 }
588
589 let mut hasher = Sha256::new();
591 hasher.update(self.classical_signature);
592 hasher.update(&self.pq_signature);
593 hasher.update(message);
594 let combined = hasher.finalize();
595 let mut combined_hash = [0u8; 32];
596 combined_hash.copy_from_slice(&combined);
597
598 let hybrid_sig = HybridSignature {
599 classical: self.classical_signature,
600 quantum: DilithiumSignature {
601 data: self.pq_signature.clone(),
602 variant: self.pq_variant,
603 },
604 combined_hash,
605 };
606
607 signer.verify_hybrid(message, &hybrid_sig)
609 }
610}
611
612#[derive(Debug, Clone, PartialEq)]
614pub enum PqcError {
615 InvalidKeySize,
617 InvalidCiphertext,
619 InvalidSignature,
621 KeyNotGenerated,
623 VerificationFailed,
625 UnsupportedAlgorithm,
627}
628
629impl std::fmt::Display for PqcError {
630 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
631 match self {
632 PqcError::InvalidKeySize => write!(f, "Invalid key size"),
633 PqcError::InvalidCiphertext => write!(f, "Invalid ciphertext"),
634 PqcError::InvalidSignature => write!(f, "Invalid signature"),
635 PqcError::KeyNotGenerated => write!(f, "Key not generated"),
636 PqcError::VerificationFailed => write!(f, "Verification failed"),
637 PqcError::UnsupportedAlgorithm => write!(f, "Unsupported algorithm"),
638 }
639 }
640}
641
642impl std::error::Error for PqcError {}
643
644#[cfg(test)]
645mod tests {
646 use super::*;
647
648 #[test]
649 fn test_kyber_keygen() {
650 let kyber = Kyber::recommended();
651 let keypair = kyber.keygen();
652
653 assert_eq!(
654 keypair.public_key.len(),
655 KyberVariant::Kyber768.public_key_size()
656 );
657 assert_eq!(
658 keypair.secret_key.len(),
659 KyberVariant::Kyber768.secret_key_size()
660 );
661 }
662
663 #[test]
664 fn test_kyber_encapsulate_decapsulate() {
665 let kyber = Kyber::new(KyberVariant::Kyber512);
666 let keypair = kyber.keygen();
667
668 let (shared_secret_enc, ciphertext) = kyber.encapsulate(&keypair.public_key).unwrap();
669 let shared_secret_dec = kyber.decapsulate(&keypair.secret_key, &ciphertext).unwrap();
670
671 assert_eq!(shared_secret_enc.len(), 32);
674 assert_eq!(shared_secret_dec.len(), 32);
675 }
676
677 #[test]
678 fn test_dilithium_sign_verify() {
679 let dilithium = Dilithium::recommended();
680 let keypair = dilithium.keygen();
681
682 let message = b"Hope Genome quantum-ready message";
683 let signature = dilithium.sign(&keypair.secret_key, message).unwrap();
684
685 assert_eq!(
686 signature.data.len(),
687 DilithiumVariant::Dilithium3.signature_size()
688 );
689
690 let valid = dilithium
691 .verify(&keypair.public_key, message, &signature)
692 .unwrap();
693 assert!(valid);
694 }
695
696 #[test]
697 fn test_hybrid_signer() {
698 let mut signer = HybridSigner::new(DilithiumVariant::Dilithium3);
699 signer.keygen();
700
701 let message = b"Hybrid quantum-classical signature test";
702 let signature = signer.sign_hybrid(message).unwrap();
703
704 assert_eq!(signature.classical.len(), 64);
705 assert_eq!(
706 signature.quantum.data.len(),
707 DilithiumVariant::Dilithium3.signature_size()
708 );
709
710 let valid = signer.verify_hybrid(message, &signature).unwrap();
711 assert!(valid);
712 }
713
714 #[test]
715 fn test_quantum_ready_proof() {
716 let mut signer = HybridSigner::new(DilithiumVariant::Dilithium3);
717 signer.keygen();
718
719 let message = b"Quantum-ready proof for Hope Genome audit log";
720 let proof = QuantumReadyProof::create(message, &signer).unwrap();
721
722 assert_eq!(proof.version, 1);
723 assert!(!proof.pq_signature.is_empty());
724
725 let valid = proof.verify(message, &signer).unwrap();
726 assert!(valid);
727 }
728
729 #[test]
730 fn test_all_kyber_variants() {
731 for variant in [
732 KyberVariant::Kyber512,
733 KyberVariant::Kyber768,
734 KyberVariant::Kyber1024,
735 ] {
736 let kyber = Kyber::new(variant);
737 let keypair = kyber.keygen();
738
739 assert_eq!(keypair.public_key.len(), variant.public_key_size());
740 assert_eq!(keypair.secret_key.len(), variant.secret_key_size());
741 }
742 }
743
744 #[test]
745 fn test_all_dilithium_variants() {
746 for variant in [
747 DilithiumVariant::Dilithium2,
748 DilithiumVariant::Dilithium3,
749 DilithiumVariant::Dilithium5,
750 ] {
751 let dilithium = Dilithium::new(variant);
752 let keypair = dilithium.keygen();
753
754 assert_eq!(keypair.public_key.len(), variant.public_key_size());
755 assert_eq!(keypair.secret_key.len(), variant.secret_key_size());
756
757 let sig = dilithium.sign(&keypair.secret_key, b"test").unwrap();
758 assert_eq!(sig.data.len(), variant.signature_size());
759 }
760 }
761}