#![deny(unsafe_code)]
#![deny(missing_docs)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::panic)]
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HybridSecurityLevel {
Classical,
QuantumResistant,
PostQuantum,
}
#[derive(Debug, Clone)]
pub struct HybridSecurityProof {
pub security_level: HybridSecurityLevel,
pub description: String,
pub proof: Vec<String>,
}
#[must_use = "the returned HybridSecurityProof documents the construction's security claim"]
pub fn describe_hybrid_kem_security() -> HybridSecurityProof {
let proof_steps = vec![
"ML-KEM IND-CCA2 claim: ML-KEM (FIPS 203) encaps/decaps are used directly; Module-LWE hardness is preserved.".to_string(),
"ECDH IND-CPA claim: X25519 key agreement is used directly; CDH hardness is preserved.".to_string(),
"Composition claim: HKDF-SHA256(ML-KEM_ss || ECDH_ss) is a dual-PRF combiner (Bindel et al., PQCrypto 2019). Security holds if either component secret is pseudorandom.".to_string(),
"Conclusion: Breaking the hybrid KEM requires breaking BOTH ML-KEM and ECDH simultaneously.".to_string(),
];
HybridSecurityProof {
security_level: HybridSecurityLevel::PostQuantum,
description: "Hybrid KEM combines ML-KEM (IND-CCA2, Module-LWE) with X25519 ECDH (IND-CPA, CDH) through HKDF-SHA256 dual-PRF combiner. These are documented security claims, not runtime proofs.".to_string(),
proof: proof_steps,
}
}
const _ML_KEM_IND_CCA2_CLAIM: &str = "ML-KEM IND-CCA2 security is preserved: \
the hybrid construction uses ML-KEM encaps/decaps directly without modification.";
const _ECDH_IND_CPA_CLAIM: &str = "ECDH IND-CPA security is preserved: \
the hybrid construction uses X25519 key agreement directly without modification.";
#[must_use = "the returned HybridSecurityProof documents the construction's security claim"]
pub fn describe_hybrid_signature_security() -> HybridSecurityProof {
let proof_steps = vec![
"ML-DSA EUF-CMA claim: ML-DSA (FIPS 204) sign/verify are used directly; Module-SIS hardness is preserved.".to_string(),
"Ed25519 EUF-CMA claim: Ed25519 sign/verify are used directly; ECDLP hardness is preserved.".to_string(),
"Composition claim: Hybrid signature is (σ_MLDSA, σ_Ed25519) with AND-verification. Forgery requires breaking both EUF-CMA schemes simultaneously.".to_string(),
"Conclusion: Breaking the hybrid signature requires breaking BOTH ML-DSA and Ed25519 simultaneously.".to_string(),
];
HybridSecurityProof {
security_level: HybridSecurityLevel::PostQuantum,
description: "Hybrid signature combines ML-DSA (EUF-CMA, Module-SIS) with Ed25519 (EUF-CMA, ECDLP) via AND-composition. These are documented security claims, not runtime proofs.".to_string(),
proof: proof_steps,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_describe_hybrid_kem_security_returns_post_quantum_claim() {
let proof = describe_hybrid_kem_security();
assert_eq!(proof.security_level, HybridSecurityLevel::PostQuantum);
assert!(!proof.description.is_empty());
assert!(proof.proof.len() >= 4);
let proof_text = proof.proof.join(" ");
assert!(proof_text.contains("ML-KEM IND-CCA2"));
assert!(proof_text.contains("ECDH IND-CPA"));
assert!(proof_text.contains("Composition claim"));
}
#[test]
fn test_describe_hybrid_signature_security_returns_post_quantum_claim() {
let proof = describe_hybrid_signature_security();
assert_eq!(proof.security_level, HybridSecurityLevel::PostQuantum);
assert!(!proof.description.is_empty());
assert!(proof.proof.len() >= 4);
let proof_text = proof.proof.join(" ");
assert!(proof_text.contains("ML-DSA EUF-CMA"));
assert!(proof_text.contains("Ed25519 EUF-CMA"));
assert!(proof_text.contains("Composition claim"));
}
#[test]
fn test_security_claims_exist_and_are_non_empty_succeeds() {
assert!(!_ML_KEM_IND_CCA2_CLAIM.is_empty());
assert!(!_ECDH_IND_CPA_CLAIM.is_empty());
assert!(_ML_KEM_IND_CCA2_CLAIM.contains("IND-CCA2"));
assert!(_ECDH_IND_CPA_CLAIM.contains("IND-CPA"));
}
#[test]
fn test_hybrid_kem_proof_structure_has_non_empty_steps_succeeds() {
let proof = describe_hybrid_kem_security();
assert!(!proof.proof.is_empty());
for step in &proof.proof {
assert!(!step.is_empty(), "Proof step should not be empty");
assert!(step.len() > 10, "Proof step should have meaningful content");
}
}
#[test]
fn test_hybrid_signature_proof_structure_succeeds() {
let proof = describe_hybrid_signature_security();
assert!(!proof.proof.is_empty());
for step in &proof.proof {
assert!(!step.is_empty(), "Proof step should not be empty");
assert!(step.len() > 10, "Proof step should have meaningful content");
}
}
#[test]
fn test_security_level_variants_succeeds() {
let _classical = HybridSecurityLevel::Classical;
let _quantum_resistant = HybridSecurityLevel::QuantumResistant;
let _post_quantum = HybridSecurityLevel::PostQuantum;
}
#[test]
fn test_hybrid_security_proof_clone_succeeds() {
let proof = describe_hybrid_kem_security();
let proof_clone = proof.clone();
assert_eq!(proof.security_level, proof_clone.security_level);
assert_eq!(proof.description, proof_clone.description);
assert_eq!(proof.proof, proof_clone.proof);
}
#[test]
fn test_full_hybrid_kem_description_text_succeeds() {
let proof = describe_hybrid_kem_security();
let proof_text = proof.proof.join("\n");
assert!(proof_text.contains("ML-KEM IND-CCA2 claim"));
assert!(proof_text.contains("ECDH IND-CPA claim"));
assert!(proof_text.contains("dual-PRF combiner"));
assert!(proof_text.contains("breaking BOTH"));
}
#[test]
fn test_full_hybrid_signature_description_text_succeeds() {
let proof = describe_hybrid_signature_security();
let proof_text = proof.proof.join("\n");
assert!(proof_text.contains("ML-DSA EUF-CMA claim"));
assert!(proof_text.contains("Ed25519 EUF-CMA claim"));
assert!(proof_text.contains("AND-verification"));
assert!(proof.description.contains("AND-composition"));
}
}