#![cfg(feature = "std")]
use lib_q_core::{
Algorithm,
KemContext,
KemPublicKey,
KemSecretKey,
};
use lib_q_hpke::{
HpkeAead,
HpkeCipherSuite,
HpkeContext,
HpkeKdf,
HpkeKem,
HpkeMode,
};
use lib_q_hpke::security::prng::{CryptoRng, Kt128Rng};
use lib_q_kem::LibQKemProvider;
fn random_bytes(rng: &mut Kt128Rng, n: usize) -> Vec<u8> {
let mut v = vec![0u8; n];
rng.fill_bytes(&mut v).unwrap();
v
}
#[test]
fn fuzz_auth_proof_validation() {
let mut rng = Kt128Rng::from_seed(&[0u8; 32]);
for _ in 0..1000 {
let kem = match rng.next_u32().unwrap() % 3 {
0 => HpkeKem::MlKem512,
1 => HpkeKem::MlKem768,
_ => HpkeKem::MlKem1024,
};
let sender_sk = random_bytes(&mut rng, kem.secret_key_len());
let sender_pk = random_bytes(&mut rng, kem.public_key_len());
let recipient_pk = random_bytes(&mut rng, kem.public_key_len());
let encapsulated_key = random_bytes(&mut rng, kem.enc_len());
let shared_secret = random_bytes(&mut rng, kem.shared_secret_len());
let provider = lib_q_hpke::providers::post_quantum::PostQuantumProvider::new();
let sender_sk_obj = KemSecretKey::new(sender_sk.clone());
let sender_pk_obj = KemPublicKey::new(sender_pk.clone());
let recipient_pk_obj = KemPublicKey::new(recipient_pk.clone());
let result = provider.create_auth_proof(
kem,
&sender_sk_obj,
&sender_pk_obj,
&recipient_pk_obj,
&encapsulated_key,
&shared_secret,
&mut rng,
);
match result {
Ok(proof) => {
assert_eq!(proof.len(), provider.get_auth_proof_length(kem));
let verify_result = provider.verify_auth_proof(
kem,
&sender_pk_obj,
&sender_sk_obj,
&encapsulated_key,
&shared_secret,
&proof,
);
assert!(verify_result.is_ok(), "Valid auth proof should verify successfully");
}
Err(_) => {
}
}
}
}
#[test]
fn fuzz_invalid_auth_proof_detection() {
let mut rng = Kt128Rng::from_seed(&[1u8; 32]);
for _ in 0..1000 {
let kem = HpkeKem::MlKem512;
let sender_sk = random_bytes(&mut rng, kem.secret_key_len());
let sender_pk = random_bytes(&mut rng, kem.public_key_len());
let recipient_pk = random_bytes(&mut rng, kem.public_key_len());
let encapsulated_key = random_bytes(&mut rng, kem.enc_len());
let shared_secret = random_bytes(&mut rng, kem.shared_secret_len());
let provider = lib_q_hpke::providers::post_quantum::PostQuantumProvider::new();
let sender_sk_obj = KemSecretKey::new(sender_sk);
let sender_pk_obj = KemPublicKey::new(sender_pk);
let invalid_proof_len = (rng.next_u32().unwrap() % 63) as usize + 1;
let invalid_proof = random_bytes(&mut rng, invalid_proof_len);
let verify_result = provider.verify_auth_proof(
kem,
&sender_pk_obj,
&sender_sk_obj,
&encapsulated_key,
&shared_secret,
&invalid_proof,
);
assert!(verify_result.is_err(), "Invalid auth proof should be rejected");
}
}
#[test]
fn fuzz_key_validation_edge_cases() {
let mut rng = Kt128Rng::from_seed(&[2u8; 32]);
for _ in 0..1000 {
let kem = HpkeKem::MlKem512;
let provider = lib_q_hpke::providers::post_quantum::PostQuantumProvider::new();
let invalid_sizes = vec![
0, 1, 7, 15, 31, 33, 63, 65, 127, 129, 255, 257, 511, 513, 1023, 1025,
];
for &size in &invalid_sizes {
let invalid_key = random_bytes(&mut rng, size);
let pk_result = provider.validate_key(kem, &invalid_key, false);
assert!(pk_result.is_err(), "Invalid public key size should be rejected");
let sk_result = provider.validate_key(kem, &invalid_key, true);
assert!(sk_result.is_err(), "Invalid secret key size should be rejected");
}
}
}
#[test]
fn fuzz_zero_key_rejection() {
let _rng = Kt128Rng::from_seed(&[3u8; 32]);
for _ in 0..100 {
let kem = HpkeKem::MlKem512;
let provider = lib_q_hpke::providers::post_quantum::PostQuantumProvider::new();
let zero_pk = vec![0u8; kem.public_key_len()];
let zero_sk = vec![0u8; kem.secret_key_len()];
let pk_result = provider.validate_key(kem, &zero_pk, false);
assert!(pk_result.is_err(), "Zero public key should be rejected");
let sk_result = provider.validate_key(kem, &zero_sk, true);
assert!(sk_result.is_err(), "Zero secret key should be rejected");
}
}
#[test]
fn fuzz_aead_key_validation() {
let mut rng = Kt128Rng::from_seed(&[4u8; 32]);
for _ in 0..1000 {
let aead = HpkeAead::Saturnin256;
let provider = lib_q_hpke::providers::post_quantum::PostQuantumProvider::new();
let invalid_sizes = vec![0, 1, 7, 15, 31, 33, 63, 65, 127, 129];
for &size in &invalid_sizes {
let invalid_key = random_bytes(&mut rng, size);
let nonce = vec![0u8; aead.nonce_len()];
let plaintext = b"test message";
let encrypt_result = provider.seal(aead, &invalid_key, &nonce, b"", plaintext);
assert!(encrypt_result.is_err(), "Invalid AEAD key should be rejected");
let decrypt_result = provider.open(aead, &invalid_key, &nonce, b"", plaintext);
assert!(decrypt_result.is_err(), "Invalid AEAD key should be rejected");
}
}
}
#[test]
fn fuzz_nonce_validation() {
let mut rng = Kt128Rng::from_seed(&[5u8; 32]);
for _ in 0..1000 {
let aead = HpkeAead::Saturnin256;
let provider = lib_q_hpke::providers::post_quantum::PostQuantumProvider::new();
let key = vec![1u8; aead.key_len()]; let plaintext = b"test message";
let invalid_sizes = vec![0, 1, 7, 15, 17, 31, 33, 63, 65];
for &size in &invalid_sizes {
let invalid_nonce = random_bytes(&mut rng, size);
let encrypt_result = provider.seal(aead, &key, &invalid_nonce, b"", plaintext);
assert!(encrypt_result.is_err(), "Invalid nonce should be rejected");
let decrypt_result = provider.open(aead, &key, &invalid_nonce, b"", plaintext);
assert!(decrypt_result.is_err(), "Invalid nonce should be rejected");
}
}
}
#[test]
fn fuzz_ciphertext_length_validation() {
let mut rng = Kt128Rng::from_seed(&[6u8; 32]);
for _ in 0..1000 {
let aead = HpkeAead::Saturnin256;
let provider = lib_q_hpke::providers::post_quantum::PostQuantumProvider::new();
let key = vec![1u8; aead.key_len()];
let nonce = vec![0u8; aead.nonce_len()];
let plaintext = b"test message";
let invalid_sizes = vec![0, 1, 7, 15, 31, 33, 63, 65, 127, 129];
for &size in &invalid_sizes {
let invalid_ciphertext = random_bytes(&mut rng, size);
let decrypt_result = provider.open(aead, &key, &nonce, b"", &invalid_ciphertext);
assert!(decrypt_result.is_err(), "Invalid ciphertext length should be rejected");
}
}
}
#[test]
fn fuzz_hpke_context_state_transitions() {
let mut rng = Kt128Rng::from_seed(&[7u8; 32]);
for _ in 0..100 {
let provider = Box::new(LibQKemProvider::new().expect("Failed to create KEM provider"));
let mut hpke_ctx = HpkeContext::with_provider(provider);
let mut kem_ctx = KemContext::with_provider(Box::new(LibQKemProvider::new().expect("Failed to create KEM provider")));
let keypair = kem_ctx.generate_keypair(Algorithm::MlKem512, None).unwrap();
let recipient_pk = KemPublicKey::new(keypair.public_key().as_bytes().to_vec());
let recipient_sk = KemSecretKey::new(keypair.secret_key().as_bytes().to_vec());
let info_len = (rng.next_u32().unwrap() % 1024) as usize;
let info = random_bytes(&mut rng, info_len);
let setup_result = hpke_ctx.setup_sender(&recipient_pk, &info);
match setup_result {
Ok(mut sender_ctx) => {
for _ in 0..10 {
let msg_len = (rng.next_u32().unwrap() % 1024) as usize;
let message = random_bytes(&mut rng, msg_len);
let aad_len = (rng.next_u32().unwrap() % 512) as usize;
let aad = random_bytes(&mut rng, aad_len);
let encrypt_result = sender_ctx.seal(&aad, &message);
match encrypt_result {
Ok(_) => {
}
Err(_) => {
break;
}
}
}
}
Err(_) => {
}
}
}
}
#[test]
fn fuzz_sequence_number_overflow() {
let provider = Box::new(LibQKemProvider::new().expect("Failed to create KEM provider"));
let mut hpke_ctx = HpkeContext::with_provider(provider);
let mut kem_ctx = KemContext::with_provider(Box::new(LibQCryptoProvider::new()));
let keypair = kem_ctx.generate_keypair(Algorithm::MlKem512).unwrap();
let recipient_pk = KemPublicKey::new(keypair.public_key().as_bytes().to_vec());
let mut sender_ctx = hpke_ctx.setup_sender(&recipient_pk, b"test info").unwrap();
sender_ctx.sequence_number = u32::MAX - 5;
for i in 0..10 {
let message = format!("test message {}", i);
let result = sender_ctx.seal(b"", message.as_bytes());
if i < 5 {
assert!(result.is_ok(), "Encryption should succeed before overflow");
} else {
assert!(result.is_err(), "Encryption should fail after sequence overflow");
}
}
assert_eq!(sender_ctx.state, lib_q_hpke::HpkeContextState::NeedsRekey);
}
#[test]
fn fuzz_memory_safety_large_inputs() {
let mut rng = Kt128Rng::from_seed(&[8u8; 32]);
for _ in 0..10 {
let provider = Box::new(LibQKemProvider::new().expect("Failed to create KEM provider"));
let mut hpke_ctx = HpkeContext::with_provider(provider);
let mut kem_ctx = KemContext::with_provider(Box::new(LibQKemProvider::new().expect("Failed to create KEM provider")));
let keypair = kem_ctx.generate_keypair(Algorithm::MlKem512, None).unwrap();
let recipient_pk = KemPublicKey::new(keypair.public_key().as_bytes().to_vec());
let recipient_sk = KemSecretKey::new(keypair.secret_key().as_bytes().to_vec());
let large_msg_size = (rng.next_u32().unwrap() % (65536 - 1024)) as usize + 1024;
let large_message = random_bytes(&mut rng, large_msg_size);
let large_aad = random_bytes(&mut rng, 1024);
let large_info = random_bytes(&mut rng, 1024);
let encrypt_result = hpke_ctx.seal(&recipient_pk, &large_info, &large_aad, &large_message);
match encrypt_result {
Ok((encapsulated_key, ciphertext)) => {
let decrypt_result = hpke_ctx.open(
&encapsulated_key,
&recipient_sk,
&large_info,
&large_aad,
&ciphertext,
);
assert!(decrypt_result.is_ok(), "Decryption should succeed for valid encryption");
let decrypted = decrypt_result.unwrap();
assert_eq!(decrypted, large_message, "Decrypted message should match original");
}
Err(_) => {
}
}
}
}