#![deny(unsafe_code)]
#![deny(missing_docs)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::panic)]
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[non_exhaustive]
pub enum CompositionError {
#[error("Failed to verify composition security")]
VerificationFailed,
#[error("Invalid proof structure")]
InvalidProofStructure,
}
#[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>,
}
pub fn verify_hybrid_kem_security() -> Result<HybridSecurityProof, CompositionError> {
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(),
];
Ok(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.";
pub fn verify_hybrid_signature_security() -> Result<HybridSecurityProof, CompositionError> {
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(),
];
Ok(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)]
#[allow(clippy::unwrap_used)] #[allow(clippy::expect_used)] mod tests {
use super::*;
#[test]
fn test_verify_hybrid_kem_security_succeeds() {
let result = verify_hybrid_kem_security();
assert!(result.is_ok(), "Hybrid KEM security verification should succeed");
let proof = result.unwrap();
assert_eq!(proof.security_level, HybridSecurityLevel::PostQuantum);
assert!(!proof.description.is_empty());
assert!(!proof.proof.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_verify_hybrid_signature_security_succeeds() {
let result = verify_hybrid_signature_security();
assert!(result.is_ok(), "Hybrid signature security verification should succeed");
let proof = result.unwrap();
assert_eq!(proof.security_level, HybridSecurityLevel::PostQuantum);
assert!(!proof.description.is_empty());
assert!(!proof.proof.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_security_level_succeeds() {
let proof = verify_hybrid_kem_security().unwrap();
assert_eq!(proof.security_level, HybridSecurityLevel::PostQuantum);
}
#[test]
fn test_hybrid_signature_security_level_succeeds() {
let proof = verify_hybrid_signature_security().unwrap();
assert_eq!(proof.security_level, HybridSecurityLevel::PostQuantum);
}
#[test]
fn test_hybrid_kem_proof_structure_has_non_empty_steps_succeeds() {
let proof = verify_hybrid_kem_security().unwrap();
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 = verify_hybrid_signature_security().unwrap();
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_composition_error_types_fails() {
let err1 = CompositionError::VerificationFailed;
assert_eq!(err1.to_string(), "Failed to verify composition security");
let err2 = CompositionError::InvalidProofStructure;
assert_eq!(err2.to_string(), "Invalid proof structure");
}
#[test]
fn test_hybrid_security_proof_clone_succeeds() {
let proof = verify_hybrid_kem_security().unwrap();
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_verification_succeeds() {
let result = verify_hybrid_kem_security();
assert!(result.is_ok());
let proof = result.unwrap();
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_verification_succeeds() {
let result = verify_hybrid_signature_security();
assert!(result.is_ok());
let proof = result.unwrap();
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"));
}
}