From 6a42a8dd4957774b78681ac2f5fc5eaab1468776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 5 Mar 2026 10:56:26 +0000 Subject: [PATCH] chore: add unit test for mutual KKT --- Cargo.lock | 1 + common/nym-kkt/Cargo.toml | 1 + common/nym-kkt/src/lib.rs | 181 +++++++++++++++++++++++++------------- 3 files changed, 124 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f36a3c1716..1eda93555c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6833,6 +6833,7 @@ dependencies = [ "nym-kkt-ciphersuite", "nym-kkt-context", "nym-pemstore", + "nym-test-utils", "rand 0.9.2", "rand_chacha 0.9.0", "strum", diff --git a/common/nym-kkt/Cargo.toml b/common/nym-kkt/Cargo.toml index 38ddd37582..02c9f50d49 100644 --- a/common/nym-kkt/Cargo.toml +++ b/common/nym-kkt/Cargo.toml @@ -30,6 +30,7 @@ libcrux-ml-kem = { workspace = true } [dev-dependencies] rand_chacha = "0.9.0" anyhow = { workspace = true } +nym-test-utils = { workspace = true } [lints] diff --git a/common/nym-kkt/src/lib.rs b/common/nym-kkt/src/lib.rs index b4100602b5..b7905160a6 100644 --- a/common/nym-kkt/src/lib.rs +++ b/common/nym-kkt/src/lib.rs @@ -16,10 +16,6 @@ pub use nym_kkt_context as context; #[cfg(test)] mod test { - use nym_kkt_ciphersuite::{Ciphersuite, HashFunction, HashLength, KEM, SignatureScheme}; - use rand09::RngCore; - use std::collections::BTreeMap; - use crate::keys::KEMKeys; use crate::{ initiator::KKTInitiator, @@ -29,9 +25,13 @@ mod test { }, responder::KKTResponder, }; + use nym_kkt_ciphersuite::{Ciphersuite, HashFunction, HashLength, KEM, SignatureScheme}; + use nym_test_utils::helpers::deterministic_rng_09; + use rand09::RngCore; + use std::collections::BTreeMap; #[test] - fn test_kkt_psq_e2e_encrypted_carrier() { + fn test_kkt_psq_e2e_one_way_encrypted_carrier() { let mut rng = rand09::rng(); let mut payload: Vec = vec![0u8; 900_000]; @@ -47,7 +47,6 @@ mod test { HashFunction::Shake256, ] { // generate kem public keys - let responder_mlkem_keypair = generate_keypair_mlkem(&mut rng); let responder_mceliece_keypair = generate_keypair_mceliece(&mut rng); @@ -64,20 +63,6 @@ mod test { HashLength::Default.value(), responder_kem.mc_eliece_encapsulation_key().as_ref(), ); - let initiator_mlkem_keypair = generate_keypair_mlkem(&mut rng); - let initiator_mceliece_keypair = generate_keypair_mceliece(&mut rng); - - let _i_dir_hash_mlkem = hash_encapsulation_key( - hash_function, - HashLength::Default.value(), - initiator_mlkem_keypair.public_key().as_slice(), - ); - - let _i_dir_hash_mceliece = hash_encapsulation_key( - hash_function, - HashLength::Default.value(), - initiator_mceliece_keypair.pk.as_ref(), - ); let init_hashes = BTreeMap::new(); @@ -128,41 +113,6 @@ mod test { responder_kem.ml_kem768_encapsulation_key().as_slice(), ) } - // Mutual - MlKem - { - let ciphersuite = Ciphersuite::resolve_ciphersuite( - KEM::MlKem768, - hash_function, - SignatureScheme::Ed25519, - None, - ) - .unwrap(); - let (mut initiator, request) = KKTInitiator::generate_one_way_request( - &mut rng, - ciphersuite, - &responder_x25519_keypair.pk, - &r_dir_hash_mlkem, - 1u8, - Some(payload.clone()), - ) - .unwrap(); - - let processed_request = responder.process_request(request, payload.len()).unwrap(); - - assert_eq!(processed_request.request_payload, payload); - - // if we keep unverified keys, this should change - assert!(processed_request.remote_encapsulation_key.is_none()); - - let processed_response = initiator - .process_response(processed_request.response, 0) - .unwrap(); - - assert_eq!( - processed_response.encapsulation_key.as_bytes(), - responder_kem.ml_kem768_encapsulation_key().as_slice(), - ) - } // OneWay - McEliece { @@ -195,7 +145,110 @@ mod test { responder_kem.mc_eliece_encapsulation_key().as_ref() ) } + } + } + + #[test] + fn test_kkt_psq_e2e_mutual_encrypted_carrier() { + let mut rng = deterministic_rng_09(); + + let mut payload: Vec = vec![0u8; 50000]; + rng.fill_bytes(&mut payload); + + // generate kem public keys + let initiator_mlkem_keypair = generate_keypair_mlkem(&mut rng); + let initiator_mceliece_keypair = generate_keypair_mceliece(&mut rng); + + let responder_mlkem_keypair = generate_keypair_mlkem(&mut rng); + let responder_mceliece_keypair = generate_keypair_mceliece(&mut rng); + + let responder_x25519_keypair = generate_lp_keypair_x25519(&mut rng); + + let initiator_kem = KEMKeys::new(initiator_mceliece_keypair, initiator_mlkem_keypair); + let responder_kem = KEMKeys::new(responder_mceliece_keypair, responder_mlkem_keypair); + + let init_hashes = initiator_kem.encapsulation_keys_digests(); + + let responder = KKTResponder::new( + &responder_x25519_keypair, + &responder_kem, + &init_hashes, + &[ + HashFunction::Blake3, + HashFunction::SHA256, + HashFunction::Shake128, + HashFunction::Shake256, + ], + &[SignatureScheme::Ed25519], + &[1], + ) + .unwrap(); + + for hash_function in [ + HashFunction::Blake3, + HashFunction::SHA256, + HashFunction::Shake128, + HashFunction::Shake256, + ] { + let r_dir_hash_mlkem = hash_encapsulation_key( + hash_function, + HashLength::Default.value(), + responder_kem.ml_kem768_encapsulation_key().as_slice(), + ); + + let r_dir_hash_mceliece = hash_encapsulation_key( + hash_function, + HashLength::Default.value(), + responder_kem.mc_eliece_encapsulation_key().as_ref(), + ); + // Mutual - MlKem + { + let ciphersuite = Ciphersuite::resolve_ciphersuite( + KEM::MlKem768, + hash_function, + SignatureScheme::Ed25519, + None, + ) + .unwrap(); + let (mut initiator, request) = KKTInitiator::generate_mutual_request( + &mut rng, + ciphersuite, + initiator_kem + .encoded_encapsulation_key(KEM::MlKem768) + .unwrap(), + &responder_x25519_keypair.pk, + &r_dir_hash_mlkem, + 1u8, + Some(payload.clone()), + ) + .unwrap(); + + let processed_request = responder.process_request(request, payload.len()).unwrap(); + + assert_eq!(processed_request.request_payload, payload); + assert_eq!( + processed_request + .remote_encapsulation_key + .unwrap() + .as_bytes(), + initiator_kem + .encapsulation_key(KEM::MlKem768) + .unwrap() + .as_bytes() + ); + + let processed_response = initiator + .process_response(processed_request.response, 0) + .unwrap(); + + assert_eq!( + processed_response.encapsulation_key.as_bytes(), + responder_kem.ml_kem768_encapsulation_key().as_slice(), + ) + } + + // Mutual - McEliece is not supported due to the key being too large { let ciphersuite = Ciphersuite::resolve_ciphersuite( KEM::McEliece, @@ -204,9 +257,12 @@ mod test { None, ) .unwrap(); - let (mut initiator, request) = KKTInitiator::generate_one_way_request( + let (mut initiator, request) = KKTInitiator::generate_mutual_request( &mut rng, ciphersuite, + initiator_kem + .encoded_encapsulation_key(KEM::McEliece) + .unwrap(), &responder_x25519_keypair.pk, &r_dir_hash_mceliece, 1u8, @@ -217,9 +273,16 @@ mod test { let processed_request = responder.process_request(request, payload.len()).unwrap(); assert_eq!(processed_request.request_payload, payload); - - // if we keep unverified keys, this should change - assert!(processed_request.remote_encapsulation_key.is_none()); + assert_eq!( + processed_request + .remote_encapsulation_key + .unwrap() + .as_bytes(), + initiator_kem + .encapsulation_key(KEM::McEliece) + .unwrap() + .as_bytes() + ); let processed_response = initiator .process_response(processed_request.response, 0)