diff --git a/Cargo.toml b/Cargo.toml index 4940179019..9836d57c07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -174,8 +174,9 @@ members = [ "wasm/node-tester", "wasm/zknym-lib", # "nym-gateway-probe", - "integration-tests", "common/nym-lp-transport", "common/nym-kkt-ciphersuite", - "common/nym-lp-sandbox" + "integration-tests", + "common/nym-lp-transport", + "common/nym-kkt-ciphersuite", ] default-members = [ diff --git a/common/nym-kkt/src/responder.rs b/common/nym-kkt/src/responder.rs index 4027cb4e36..7fb5edce4d 100644 --- a/common/nym-kkt/src/responder.rs +++ b/common/nym-kkt/src/responder.rs @@ -50,9 +50,9 @@ impl<'a> KKTResponder<'a> { }) } else if mlkem_encapsulation_key.is_none() && mceliece_encapsulation_key.is_none() { - return Err(KKTError::FunctionInputError { + Err(KKTError::FunctionInputError { info: "Did not provide an encapsulation key when instanciating a KKTResponder.", - }); + }) } else { Ok(Self { x25519_keypair, diff --git a/common/nym-lp-sandbox/Cargo.toml b/common/nym-lp-sandbox/Cargo.toml deleted file mode 100644 index eb04b78f51..0000000000 --- a/common/nym-lp-sandbox/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -name = "nym-lp-sandbox" -version = "0.1.0" -edition = { workspace = true } -license = { workspace = true } -publish = false - -[dependencies] -thiserror = { workspace = true } -parking_lot = { workspace = true } -snow = { workspace = true } -bs58 = { workspace = true } -serde = { workspace = true } -bytes = { workspace = true } -dashmap = { workspace = true } -sha2 = { workspace = true } -tracing = { workspace = true } -rand = { workspace = true } -rand09 = { workspace = true } - - -nym-crypto = { path = "../crypto", features = ["hashing", "asymmetric"] } -nym-kkt = { path = "../nym-kkt" } -nym-lp-common = { path = "../nym-lp-common" } - -nym-kkt-ciphersuite = { path ="../nym-kkt-ciphersuite" } - -# libcrux dependencies for PSQ (Post-Quantum PSK derivation) -libcrux-psq = { workspace = true, features = ["test-utils"] } -libcrux-kem = { workspace = true } -tls_codec = { workspace = true } -num_enum = { workspace = true } -chacha20poly1305 = { workspace = true } -zeroize = { workspace = true, features = ["zeroize_derive"] } - -[dev-dependencies] -criterion = { version = "0.5", features = ["html_reports"] } -rand_chacha = "0.3" -nym-crypto = { path = "../crypto", features = ["rand"] } -nym-test-utils = { workspace = true } - - diff --git a/common/nym-lp-sandbox/src/lib.rs b/common/nym-lp-sandbox/src/lib.rs deleted file mode 100644 index 1a02595840..0000000000 --- a/common/nym-lp-sandbox/src/lib.rs +++ /dev/null @@ -1,262 +0,0 @@ -#[cfg(test)] -mod tests { - - use libcrux_psq::{ - Channel, IntoSession, - handshake::{ - builders::{CiphersuiteBuilder, PrincipalBuilder}, - ciphersuites::CiphersuiteName, - types::{Authenticator, PQEncapsulationKey}, - }, - session::{Session, SessionBinding}, - }; - use nym_kkt::{ - initiator::KKTInitiator, - key_utils::{ - generate_keypair_mceliece, generate_keypair_mlkem, generate_keypair_x25519, - hash_encapsulation_key, - }, - responder::KKTResponder, - }; - use nym_kkt_ciphersuite::{Ciphersuite, HashFunction, HashLength, KEM, SignatureScheme}; - - #[test] - fn test_e2e_client_node() { - let mut rng = rand09::rng(); - - // we should add these as consts - let aad_initiator_outer = b"Test Data I Outer"; - let aad_initiator_inner = b"Test Data I Inner"; - let aad_responder = b"Test Data R"; - let ctx = b"Test Context"; - - // generate responder x25519 keys - let responder_x25519_keypair = generate_keypair_x25519(&mut rng); - let hash_function = HashFunction::Blake3; - // generate kem public keys - - let responder_mlkem_keypair = generate_keypair_mlkem(&mut rng); - let responder_mceliece_keypair = generate_keypair_mceliece(&mut rng); - - let r_dir_hash_mlkem = hash_encapsulation_key( - // &ciphersuite.hash_function(), - &hash_function, - // ciphersuite.hash_len(), - HashLength::Default.value(), - responder_mlkem_keypair.1.as_slice().as_slice(), - ); - - let _r_dir_hash_mceliece = hash_encapsulation_key( - // &ciphersuite.hash_function(), - &hash_function, - // ciphersuite.hash_len(), - HashLength::Default.value(), - responder_mceliece_keypair.1.as_ref(), - ); - - let kkt_responder = KKTResponder::new( - &responder_x25519_keypair, - Some(&responder_mlkem_keypair.1), - Some(&responder_mceliece_keypair.1), - &[ - HashFunction::Blake3, - HashFunction::SHA256, - HashFunction::Shake128, - HashFunction::Shake256, - ], - &[1], - &[SignatureScheme::Ed25519], - ) - .unwrap(); - - // OneWay - MlKem - let psq_ciphersuite = CiphersuiteName::X25519_MLKEM768_X25519_AESGCM128_HKDFSHA256; - - let responder_ciphersuite = CiphersuiteBuilder::new(psq_ciphersuite) - .longterm_x25519_keys(&responder_x25519_keypair) - .longterm_mlkem_encapsulation_key(&responder_mlkem_keypair.1) - .longterm_mlkem_decapsulation_key(&responder_mlkem_keypair.0) - .build_responder_ciphersuite() - .unwrap(); - - let mut responder = PrincipalBuilder::new(rand09::rng()) - .context(ctx) - .outer_aad(aad_responder) - .recent_keys_upper_bound(30) - .build_responder(responder_ciphersuite) - .unwrap(); - - let ciphersuite = Ciphersuite::resolve_ciphersuite( - KEM::MlKem768, - hash_function, - SignatureScheme::Ed25519, - None, - ) - .unwrap(); - - let (mut initiator, request_bytes) = KKTInitiator::generate_one_way_request( - &mut rng, - &ciphersuite, - &responder_x25519_keypair.pk, - &r_dir_hash_mlkem, - 1u8, - ) - .unwrap(); - - let (response_bytes, _) = kkt_responder.process_request(&request_bytes).unwrap(); - - let (i_obtained_key, _) = initiator.process_response(&response_bytes).unwrap(); - - assert_eq!( - i_obtained_key, - responder_mlkem_keypair.1.as_slice().as_slice(), - ); - - let mlkem_key = - libcrux_kem::MlKem768PublicKey::try_from(i_obtained_key.as_slice()).unwrap(); - - let initiator_psq_keys = generate_keypair_x25519(&mut rng); - let initiator_cbuilder = CiphersuiteBuilder::new(psq_ciphersuite) - .longterm_x25519_keys(&initiator_psq_keys) - .peer_longterm_x25519_pk(&responder_x25519_keypair.pk) - .peer_longterm_mlkem_pk(&mlkem_key); - - let initiator_ciphersuite = initiator_cbuilder.build_initiator_ciphersuite().unwrap(); - - let mut msg_channel = vec![0u8; 8192]; - let mut payload_buf_responder = vec![0u8; 4096]; - let mut payload_buf_initiator = vec![0u8; 4096]; - - let mut initiator = PrincipalBuilder::new(rand09::rng()) - .outer_aad(aad_initiator_outer) - .inner_aad(aad_initiator_inner) - .context(ctx) - .build_registration_initiator(initiator_ciphersuite) - .unwrap(); - - // Send first message - let registration_payload_initiator = b"Registration_init"; - let len_i = initiator - .write_message(registration_payload_initiator, &mut msg_channel) - .unwrap(); - - // Read first message - let (len_r_deserialized, len_r_payload) = responder - .read_message(&msg_channel, &mut payload_buf_responder) - .unwrap(); - - // We read the same amount of data. - assert_eq!(len_r_deserialized, len_i); - assert_eq!(len_r_payload, registration_payload_initiator.len()); - assert_eq!( - &payload_buf_responder[0..len_r_payload], - registration_payload_initiator - ); - - // Get the authenticator out here, so we can deserialize the session later. - let Some(initiator_authenticator) = responder.initiator_authenticator() else { - panic!("No initiator authenticator found") - }; - - // Respond - let registration_payload_responder = b"Registration_respond"; - let len_r = responder - .write_message(registration_payload_responder, &mut msg_channel) - .unwrap(); - - // Finalize on registration initiator - let (len_i_deserialized, len_i_payload) = initiator - .read_message(&msg_channel, &mut payload_buf_initiator) - .unwrap(); - - // We read the same amount of data. - assert_eq!(len_r, len_i_deserialized); - assert_eq!(registration_payload_responder.len(), len_i_payload); - assert_eq!( - &payload_buf_initiator[0..len_i_payload], - registration_payload_responder - ); - - // Ready for transport mode - assert!(initiator.is_handshake_finished()); - assert!(responder.is_handshake_finished()); - - let i_transport = initiator.into_session().unwrap(); - let r_transport = responder.into_session().unwrap(); - - // test serialization, deserialization - let mut session_storage = vec![0u8; 4096]; - i_transport - .serialize( - &mut session_storage, - SessionBinding { - initiator_authenticator: &Authenticator::Dh(initiator_psq_keys.pk), - responder_ecdh_pk: &responder_x25519_keypair.pk, - responder_pq_pk: Some(PQEncapsulationKey::MlKem(&mlkem_key)), - }, - ) - .unwrap(); - let mut i_transport = Session::deserialize( - &session_storage, - SessionBinding { - initiator_authenticator: &Authenticator::Dh(initiator_psq_keys.pk), - responder_ecdh_pk: &responder_x25519_keypair.pk, - responder_pq_pk: Some(PQEncapsulationKey::MlKem(&mlkem_key)), - }, - ) - .unwrap(); - - r_transport - .serialize( - &mut session_storage, - SessionBinding { - initiator_authenticator: &initiator_authenticator, - responder_ecdh_pk: &responder_x25519_keypair.pk, - responder_pq_pk: Some(PQEncapsulationKey::MlKem(&mlkem_key)), - }, - ) - .unwrap(); - let mut r_transport = Session::deserialize( - &session_storage, - SessionBinding { - initiator_authenticator: &initiator_authenticator, - responder_ecdh_pk: &responder_x25519_keypair.pk, - responder_pq_pk: Some(PQEncapsulationKey::MlKem(&mlkem_key)), - }, - ) - .unwrap(); - - let mut channel_i = i_transport.transport_channel().unwrap(); - let mut channel_r = r_transport.transport_channel().unwrap(); - - assert_eq!(channel_i.identifier(), channel_r.identifier()); - - let app_data_i = b"Derived session hey".as_slice(); - let app_data_r = b"Derived session ho".as_slice(); - - let len_i = channel_i - .write_message(app_data_i, &mut msg_channel) - .unwrap(); - - let (len_r_deserialized, len_r_payload) = channel_r - .read_message(&msg_channel, &mut payload_buf_responder) - .unwrap(); - - // We read the same amount of data. - assert_eq!(len_r_deserialized, len_i); - assert_eq!(len_r_payload, app_data_i.len()); - assert_eq!(&payload_buf_responder[0..len_r_payload], app_data_i); - - let len_r = channel_r - .write_message(app_data_r, &mut msg_channel) - .unwrap(); - - let (len_i_deserialized, len_i_payload) = channel_i - .read_message(&msg_channel, &mut payload_buf_initiator) - .unwrap(); - - assert_eq!(len_r, len_i_deserialized); - assert_eq!(app_data_r.len(), len_i_payload); - assert_eq!(&payload_buf_initiator[0..len_i_payload], app_data_r); - } -} diff --git a/common/nym-lp/src/lib.rs b/common/nym-lp/src/lib.rs index cd7bc34340..75f1bf3916 100644 --- a/common/nym-lp/src/lib.rs +++ b/common/nym-lp/src/lib.rs @@ -34,9 +34,10 @@ pub const NOISE_PATTERN: &str = "Noise_XKpsk3_25519_ChaChaPoly_SHA256"; pub const NOISE_PSK_INDEX: u8 = 3; #[cfg(test)] -pub fn kem_list() -> Vec { - use nym_kkt::ciphersuite::KEM; - vec![KEM::MlKem768, KEM::McEliece, KEM::X25519] +pub fn kem_list() -> Vec { + todo!() + // use nym_kkt::ciphersuite::KEM; + // vec![KEM::MlKem768, KEM::McEliece, KEM::X25519] } #[cfg(any(feature = "mock", test))] @@ -48,106 +49,107 @@ pub struct SessionsMock { #[cfg(any(feature = "mock", test))] impl SessionsMock { pub fn mock_post_handshake(session_id: u32) -> SessionsMock { - use crate::peer::mock_peers; - use nym_kkt::ciphersuite::{DecapsulationKey, EncapsulationKey}; - - let (init, resp) = mock_peers(); - let resp_remote = resp.as_remote(); - let init_remote = init.as_remote(); - let salt = [42u8; 32]; - let session_id_bytes = session_id.to_le_bytes(); - - // skip KKT by just deriving the kem key locally - let kem_keys = resp.kem_psq.as_ref().unwrap(); - - let libcrux_private_key = libcrux_kem::PrivateKey::decode( - libcrux_kem::Algorithm::X25519, - kem_keys.private_key().as_bytes(), - ) - .unwrap(); - let decapsulation_key = DecapsulationKey::X25519(libcrux_private_key); - - let libcrux_public_key = libcrux_kem::PublicKey::decode( - libcrux_kem::Algorithm::X25519, - kem_keys.public_key().as_bytes(), - ) - .unwrap(); - let encapsulation_key = EncapsulationKey::X25519(libcrux_public_key); - - // INIT -> RESP: PSQ MSG1 - let psq_initiator = crate::psk::psq_initiator_create_message( - init.x25519.private_key(), - &resp_remote.x25519_public, - &encapsulation_key, - init.ed25519.private_key(), - init.ed25519.public_key(), - &salt, - &session_id_bytes, - ) - .unwrap(); - - let psk = psq_initiator.psk; - let psq_payload = psq_initiator.payload; - let outer_aead_key = crate::codec::OuterAeadKey::from_psk(&psk); - - let noise_state_init = snow::Builder::new(crate::noise_protocol::NoiseProtocol::params()) - .local_private_key(init.x25519().private_key().as_bytes()) - .remote_public_key(resp_remote.x25519_public.as_bytes()) - .psk(crate::NOISE_PSK_INDEX, &psk) - .build_initiator() - .unwrap(); - let mut noise_protocol_init = crate::noise_protocol::NoiseProtocol::new(noise_state_init); - let noise_msg1 = noise_protocol_init.get_bytes_to_send().unwrap().unwrap(); - - let psq_responder = crate::psk::psq_responder_process_message( - resp.x25519.private_key(), - &init_remote.x25519_public, - (&decapsulation_key, &encapsulation_key), - &init_remote.ed25519_public, - &psq_payload, - &salt, - &session_id_bytes, - ) - .unwrap(); - - let noise_state_resp = snow::Builder::new(crate::noise_protocol::NoiseProtocol::params()) - .local_private_key(resp.x25519().private_key().as_bytes()) - .remote_public_key(init_remote.x25519_public.as_bytes()) - .psk(crate::NOISE_PSK_INDEX, &psk) - .build_responder() - .unwrap(); - let mut noise_protocol_resp = crate::noise_protocol::NoiseProtocol::new(noise_state_resp); - noise_protocol_resp.read_message(&noise_msg1).unwrap(); - - let noise_msg2 = noise_protocol_resp.get_bytes_to_send().unwrap().unwrap(); - noise_protocol_init.read_message(&noise_msg2).unwrap(); - let noise_msg3 = noise_protocol_init.get_bytes_to_send().unwrap().unwrap(); - - assert!(noise_protocol_init.is_handshake_finished()); - - noise_protocol_resp.read_message(&noise_msg3).unwrap(); - assert!(noise_protocol_resp.is_handshake_finished()); - - SessionsMock { - initiator: LpSession::new( - session_id, - 1, - outer_aead_key.clone(), - init, - resp_remote, - crate::session::PqSharedSecret::new(psq_initiator.pq_shared_secret), - noise_protocol_init, - ), - responder: LpSession::new( - session_id, - 1, - outer_aead_key, - resp, - init_remote, - crate::session::PqSharedSecret::new(psq_responder.pq_shared_secret), - noise_protocol_resp, - ), - } + todo!() + // use crate::peer::mock_peers; + // use nym_kkt::ciphersuite::{DecapsulationKey, EncapsulationKey}; + // + // let (init, resp) = mock_peers(); + // let resp_remote = resp.as_remote(); + // let init_remote = init.as_remote(); + // let salt = [42u8; 32]; + // let session_id_bytes = session_id.to_le_bytes(); + // + // // skip KKT by just deriving the kem key locally + // let kem_keys = resp.kem_psq.as_ref().unwrap(); + // + // let libcrux_private_key = libcrux_kem::PrivateKey::decode( + // libcrux_kem::Algorithm::X25519, + // kem_keys.private_key().as_bytes(), + // ) + // .unwrap(); + // let decapsulation_key = DecapsulationKey::X25519(libcrux_private_key); + // + // let libcrux_public_key = libcrux_kem::PublicKey::decode( + // libcrux_kem::Algorithm::X25519, + // kem_keys.public_key().as_bytes(), + // ) + // .unwrap(); + // let encapsulation_key = EncapsulationKey::X25519(libcrux_public_key); + // + // // INIT -> RESP: PSQ MSG1 + // let psq_initiator = crate::psk::psq_initiator_create_message( + // init.x25519.private_key(), + // &resp_remote.x25519_public, + // &encapsulation_key, + // init.ed25519.private_key(), + // init.ed25519.public_key(), + // &salt, + // &session_id_bytes, + // ) + // .unwrap(); + // + // let psk = psq_initiator.psk; + // let psq_payload = psq_initiator.payload; + // let outer_aead_key = crate::codec::OuterAeadKey::from_psk(&psk); + // + // let noise_state_init = snow::Builder::new(crate::noise_protocol::NoiseProtocol::params()) + // .local_private_key(init.x25519().private_key().as_bytes()) + // .remote_public_key(resp_remote.x25519_public.as_bytes()) + // .psk(crate::NOISE_PSK_INDEX, &psk) + // .build_initiator() + // .unwrap(); + // let mut noise_protocol_init = crate::noise_protocol::NoiseProtocol::new(noise_state_init); + // let noise_msg1 = noise_protocol_init.get_bytes_to_send().unwrap().unwrap(); + // + // let psq_responder = crate::psk::psq_responder_process_message( + // resp.x25519.private_key(), + // &init_remote.x25519_public, + // (&decapsulation_key, &encapsulation_key), + // &init_remote.ed25519_public, + // &psq_payload, + // &salt, + // &session_id_bytes, + // ) + // .unwrap(); + // + // let noise_state_resp = snow::Builder::new(crate::noise_protocol::NoiseProtocol::params()) + // .local_private_key(resp.x25519().private_key().as_bytes()) + // .remote_public_key(init_remote.x25519_public.as_bytes()) + // .psk(crate::NOISE_PSK_INDEX, &psk) + // .build_responder() + // .unwrap(); + // let mut noise_protocol_resp = crate::noise_protocol::NoiseProtocol::new(noise_state_resp); + // noise_protocol_resp.read_message(&noise_msg1).unwrap(); + // + // let noise_msg2 = noise_protocol_resp.get_bytes_to_send().unwrap().unwrap(); + // noise_protocol_init.read_message(&noise_msg2).unwrap(); + // let noise_msg3 = noise_protocol_init.get_bytes_to_send().unwrap().unwrap(); + // + // assert!(noise_protocol_init.is_handshake_finished()); + // + // noise_protocol_resp.read_message(&noise_msg3).unwrap(); + // assert!(noise_protocol_resp.is_handshake_finished()); + // + // SessionsMock { + // initiator: LpSession::new( + // session_id, + // 1, + // outer_aead_key.clone(), + // init, + // resp_remote, + // crate::session::PqSharedSecret::new(psq_initiator.pq_shared_secret), + // noise_protocol_init, + // ), + // responder: LpSession::new( + // session_id, + // 1, + // outer_aead_key, + // resp, + // init_remote, + // crate::session::PqSharedSecret::new(psq_responder.pq_shared_secret), + // noise_protocol_resp, + // ), + // } } // we just need a dummy 'valid' session for simpler tests @@ -174,7 +176,7 @@ mod tests { use crate::session_manager::SessionManager; use crate::{LpError, SessionsMock, kem_list, mock_session_for_test}; use bytes::BytesMut; - use nym_kkt::ciphersuite::{Ciphersuite, HashFunction, SignatureScheme}; + use nym_kkt_ciphersuite::{Ciphersuite, HashFunction, SignatureScheme}; // Import the new standalone functions use crate::codec::{parse_lp_packet, serialize_lp_packet}; @@ -288,118 +290,119 @@ mod tests { let mut remote_manager = SessionManager::new(); for kem in kem_list() { - // Generate Ed25519 keypairs for PSQ authentication - let (init, resp) = mock_peers(kem); - - let mut ciphersuite = Ciphersuite::resolve_ciphersuite( - kem, - HashFunction::Blake3, - SignatureScheme::Ed25519, - None, - ); - - // Use fixed receiver_index for deterministic test - let receiver_index: u32 = 54321; - - let sessions = SessionsMock::mock_post_handshake(receiver_index); - let local_session = sessions.initiator; - let remote_session = sessions.responder; - - // Create a session via manager - let _ = local_manager.create_session_state_machine(local_session); - let _ = remote_manager.create_session_state_machine(remote_session); - - // === Packet 1 (Counter 0 - Should succeed) === - let packet1 = LpPacket { - header: LpHeader { - protocol_version: 1, - reserved: [0u8; 3], - receiver_idx: receiver_index, - counter: 0, - }, - message: LpMessage::Busy, - trailer: [0u8; TRAILER_LEN], - }; - - // Serialize - let mut buf1 = BytesMut::new(); - serialize_lp_packet(&packet1, &mut buf1, None).unwrap(); - - // Parse - let parsed_packet1 = parse_lp_packet(&buf1, None).unwrap(); - - // Process via SessionManager method (which should handle checks + marking) - // NOTE: We might need a method on SessionManager/LpSession like `process_incoming_packet` - // that encapsulates parse -> check -> process_noise -> mark. - // For now, we simulate the steps using the retrieved session. - - // Perform replay check - local_manager - .receiving_counter_quick_check(receiver_index, parsed_packet1.header.counter) - .expect("Packet 1 check failed"); - // Mark received - local_manager - .receiving_counter_mark(receiver_index, parsed_packet1.header.counter) - .expect("Packet 1 mark failed"); - - // === Packet 2 (Counter 1 - Should succeed on same session) === - let packet2 = LpPacket { - header: LpHeader { - protocol_version: 1, - reserved: [0u8; 3], - receiver_idx: receiver_index, - counter: 1, - }, - message: LpMessage::Busy, - trailer: [0u8; TRAILER_LEN], - }; - - // Serialize - let mut buf2 = BytesMut::new(); - serialize_lp_packet(&packet2, &mut buf2, None).unwrap(); - - // Parse - let parsed_packet2 = parse_lp_packet(&buf2, None).unwrap(); - - // Perform replay check - local_manager - .receiving_counter_quick_check(receiver_index, parsed_packet2.header.counter) - .expect("Packet 2 check failed"); - // Mark received - local_manager - .receiving_counter_mark(receiver_index, parsed_packet2.header.counter) - .expect("Packet 2 mark failed"); - - // === Packet 3 (Counter 0 - Replay, should fail check) === - let packet3 = LpPacket { - header: LpHeader { - protocol_version: 1, - reserved: [0u8; 3], - receiver_idx: receiver_index, - counter: 0, // Replay of first packet - }, - message: LpMessage::Busy, - trailer: [0u8; TRAILER_LEN], - }; - - // Serialize - let mut buf3 = BytesMut::new(); - serialize_lp_packet(&packet3, &mut buf3, None).unwrap(); - - // Parse - let parsed_packet3 = parse_lp_packet(&buf3, None).unwrap(); - - // Perform replay check (should fail) - let replay_result = local_manager - .receiving_counter_quick_check(receiver_index, parsed_packet3.header.counter); - assert!(replay_result.is_err()); - match replay_result.unwrap_err() { - LpError::Replay(e) => { - assert!(matches!(e, crate::replay::ReplayError::DuplicateCounter)); - } - e => panic!("Expected replay error for packet 3, got {:?}", e), - } - // Do not mark received + todo!() + // // Generate Ed25519 keypairs for PSQ authentication + // let (init, resp) = mock_peers(kem); + // + // let mut ciphersuite = Ciphersuite::resolve_ciphersuite( + // kem, + // HashFunction::Blake3, + // SignatureScheme::Ed25519, + // None, + // ); + // + // // Use fixed receiver_index for deterministic test + // let receiver_index: u32 = 54321; + // + // let sessions = SessionsMock::mock_post_handshake(receiver_index); + // let local_session = sessions.initiator; + // let remote_session = sessions.responder; + // + // // Create a session via manager + // let _ = local_manager.create_session_state_machine(local_session); + // let _ = remote_manager.create_session_state_machine(remote_session); + // + // // === Packet 1 (Counter 0 - Should succeed) === + // let packet1 = LpPacket { + // header: LpHeader { + // protocol_version: 1, + // reserved: [0u8; 3], + // receiver_idx: receiver_index, + // counter: 0, + // }, + // message: LpMessage::Busy, + // trailer: [0u8; TRAILER_LEN], + // }; + // + // // Serialize + // let mut buf1 = BytesMut::new(); + // serialize_lp_packet(&packet1, &mut buf1, None).unwrap(); + // + // // Parse + // let parsed_packet1 = parse_lp_packet(&buf1, None).unwrap(); + // + // // Process via SessionManager method (which should handle checks + marking) + // // NOTE: We might need a method on SessionManager/LpSession like `process_incoming_packet` + // // that encapsulates parse -> check -> process_noise -> mark. + // // For now, we simulate the steps using the retrieved session. + // + // // Perform replay check + // local_manager + // .receiving_counter_quick_check(receiver_index, parsed_packet1.header.counter) + // .expect("Packet 1 check failed"); + // // Mark received + // local_manager + // .receiving_counter_mark(receiver_index, parsed_packet1.header.counter) + // .expect("Packet 1 mark failed"); + // + // // === Packet 2 (Counter 1 - Should succeed on same session) === + // let packet2 = LpPacket { + // header: LpHeader { + // protocol_version: 1, + // reserved: [0u8; 3], + // receiver_idx: receiver_index, + // counter: 1, + // }, + // message: LpMessage::Busy, + // trailer: [0u8; TRAILER_LEN], + // }; + // + // // Serialize + // let mut buf2 = BytesMut::new(); + // serialize_lp_packet(&packet2, &mut buf2, None).unwrap(); + // + // // Parse + // let parsed_packet2 = parse_lp_packet(&buf2, None).unwrap(); + // + // // Perform replay check + // local_manager + // .receiving_counter_quick_check(receiver_index, parsed_packet2.header.counter) + // .expect("Packet 2 check failed"); + // // Mark received + // local_manager + // .receiving_counter_mark(receiver_index, parsed_packet2.header.counter) + // .expect("Packet 2 mark failed"); + // + // // === Packet 3 (Counter 0 - Replay, should fail check) === + // let packet3 = LpPacket { + // header: LpHeader { + // protocol_version: 1, + // reserved: [0u8; 3], + // receiver_idx: receiver_index, + // counter: 0, // Replay of first packet + // }, + // message: LpMessage::Busy, + // trailer: [0u8; TRAILER_LEN], + // }; + // + // // Serialize + // let mut buf3 = BytesMut::new(); + // serialize_lp_packet(&packet3, &mut buf3, None).unwrap(); + // + // // Parse + // let parsed_packet3 = parse_lp_packet(&buf3, None).unwrap(); + // + // // Perform replay check (should fail) + // let replay_result = local_manager + // .receiving_counter_quick_check(receiver_index, parsed_packet3.header.counter); + // assert!(replay_result.is_err()); + // match replay_result.unwrap_err() { + // LpError::Replay(e) => { + // assert!(matches!(e, crate::replay::ReplayError::DuplicateCounter)); + // } + // e => panic!("Expected replay error for packet 3, got {:?}", e), + // } + // // Do not mark received } } } diff --git a/common/nym-lp/src/psk.rs b/common/nym-lp/src/psk.rs index 92a3573e10..6cc40b3b35 100644 --- a/common/nym-lp/src/psk.rs +++ b/common/nym-lp/src/psk.rs @@ -517,268 +517,272 @@ mod tests { #[test] fn test_psk_derivation_is_symmetric() { - let keypair_1 = generate_x25519_keypair(); - let keypair_2 = generate_x25519_keypair(); - let salt = [2u8; 32]; - - let mut rng = &mut rand09::rng(); - let (_kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); - let enc_key = EncapsulationKey::X25519(kem_pk); - let dec_key = DecapsulationKey::X25519(_kem_sk); - - // Client derives PSK - let (client_psk, ciphertext) = - derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_2.pk, &enc_key, &salt).unwrap(); - - // Gateway derives PSK from their perspective - let gateway_psk = derive_psk_with_psq_responder( - keypair_2.sk(), - &keypair_1.pk, - (&dec_key, &enc_key), - &ciphertext, - &salt, - ) - .unwrap(); - - assert_eq!( - client_psk, gateway_psk, - "Both sides should derive identical PSK" - ); + todo!() + // let keypair_1 = generate_x25519_keypair(); + // let keypair_2 = generate_x25519_keypair(); + // let salt = [2u8; 32]; + // + // let mut rng = &mut rand09::rng(); + // let (_kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); + // let enc_key = EncapsulationKey::X25519(kem_pk); + // let dec_key = DecapsulationKey::X25519(_kem_sk); + // + // // Client derives PSK + // let (client_psk, ciphertext) = + // derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_2.pk, &enc_key, &salt).unwrap(); + // + // // Gateway derives PSK from their perspective + // let gateway_psk = derive_psk_with_psq_responder( + // keypair_2.sk(), + // &keypair_1.pk, + // (&dec_key, &enc_key), + // &ciphertext, + // &salt, + // ) + // .unwrap(); + // + // assert_eq!( + // client_psk, gateway_psk, + // "Both sides should derive identical PSK" + // ); } #[test] fn test_different_salts_produce_different_psks() { - let keypair_1 = generate_x25519_keypair(); - let keypair_2 = generate_x25519_keypair(); - - let salt1 = [1u8; 32]; - let salt2 = [2u8; 32]; - let mut rng = &mut rand09::rng(); - let (_kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); - let enc_key = EncapsulationKey::X25519(kem_pk); - - let psk1 = - derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_2.pk, &enc_key, &salt1).unwrap(); - let psk2 = - derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_2.pk, &enc_key, &salt2).unwrap(); - - assert_ne!(psk1, psk2, "Different salts should produce different PSKs"); + todo!() + // let keypair_1 = generate_x25519_keypair(); + // let keypair_2 = generate_x25519_keypair(); + // + // let salt1 = [1u8; 32]; + // let salt2 = [2u8; 32]; + // let mut rng = &mut rand09::rng(); + // let (_kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); + // let enc_key = EncapsulationKey::X25519(kem_pk); + // + // let psk1 = + // derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_2.pk, &enc_key, &salt1).unwrap(); + // let psk2 = + // derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_2.pk, &enc_key, &salt2).unwrap(); + // + // assert_ne!(psk1, psk2, "Different salts should produce different PSKs"); } #[test] fn test_different_keys_produce_different_psks() { - let keypair_1 = generate_x25519_keypair(); - let keypair_2 = generate_x25519_keypair(); - let keypair_3 = generate_x25519_keypair(); - let salt = [3u8; 32]; - - let mut rng = &mut rand09::rng(); - let (_kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); - let enc_key = EncapsulationKey::X25519(kem_pk); - - let psk1 = - derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_2.pk, &enc_key, &salt).unwrap(); - let psk2 = - derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_3.pk, &enc_key, &salt).unwrap(); - - assert_ne!( - psk1, psk2, - "Different remote keys should produce different PSKs" - ); + todo!() + // let keypair_1 = generate_x25519_keypair(); + // let keypair_2 = generate_x25519_keypair(); + // let keypair_3 = generate_x25519_keypair(); + // let salt = [3u8; 32]; + // + // let mut rng = &mut rand09::rng(); + // let (_kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); + // let enc_key = EncapsulationKey::X25519(kem_pk); + // + // let psk1 = + // derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_2.pk, &enc_key, &salt).unwrap(); + // let psk2 = + // derive_psk_with_psq_initiator(keypair_1.sk(), &keypair_3.pk, &enc_key, &salt).unwrap(); + // + // assert_ne!( + // psk1, psk2, + // "Different remote keys should produce different PSKs" + // ); } - // PSQ-enhanced PSK tests - use nym_kkt::ciphersuite::{DecapsulationKey, EncapsulationKey, KEM}; - use nym_kkt::key_utils::generate_keypair_libcrux; - #[test] fn test_psq_derivation_deterministic() { - let mut rng = rand09::rng(); - - // Generate X25519 keypairs for Noise - let client_keypair = generate_x25519_keypair(); - let gateway_keypair = generate_x25519_keypair(); - - // Generate KEM keypair for PSQ - let (kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); - let enc_key = EncapsulationKey::X25519(kem_pk); - let dec_key = DecapsulationKey::X25519(kem_sk); - - let salt = [1u8; 32]; - - // Derive PSK twice with same inputs (initiator side) - let (_psk1, ct1) = derive_psk_with_psq_initiator( - client_keypair.sk(), - &gateway_keypair.pk, - &enc_key, - &salt, - ) - .unwrap(); - - let (_psk2, _ct2) = derive_psk_with_psq_initiator( - client_keypair.sk(), - &gateway_keypair.pk, - &enc_key, - &salt, - ) - .unwrap(); - - // PSKs will be different due to randomness in PSQ, but ciphertexts too - // This test verifies the function is deterministic given the SAME ciphertext - let psk_responder1 = derive_psk_with_psq_responder( - gateway_keypair.sk(), - &client_keypair.pk, - (&dec_key, &enc_key), - &ct1, - &salt, - ) - .unwrap(); - - let psk_responder2 = derive_psk_with_psq_responder( - gateway_keypair.sk(), - &client_keypair.pk, - (&dec_key, &enc_key), - &ct1, // Same ciphertext - &salt, - ) - .unwrap(); - - assert_eq!( - psk_responder1, psk_responder2, - "Same ciphertext should produce same PSK" - ); + todo!() + // let mut rng = rand09::rng(); + // + // // Generate X25519 keypairs for Noise + // let client_keypair = generate_x25519_keypair(); + // let gateway_keypair = generate_x25519_keypair(); + // + // // Generate KEM keypair for PSQ + // let (kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); + // let enc_key = EncapsulationKey::X25519(kem_pk); + // let dec_key = DecapsulationKey::X25519(kem_sk); + // + // let salt = [1u8; 32]; + // + // // Derive PSK twice with same inputs (initiator side) + // let (_psk1, ct1) = derive_psk_with_psq_initiator( + // client_keypair.sk(), + // &gateway_keypair.pk, + // &enc_key, + // &salt, + // ) + // .unwrap(); + // + // let (_psk2, _ct2) = derive_psk_with_psq_initiator( + // client_keypair.sk(), + // &gateway_keypair.pk, + // &enc_key, + // &salt, + // ) + // .unwrap(); + // + // // PSKs will be different due to randomness in PSQ, but ciphertexts too + // // This test verifies the function is deterministic given the SAME ciphertext + // let psk_responder1 = derive_psk_with_psq_responder( + // gateway_keypair.sk(), + // &client_keypair.pk, + // (&dec_key, &enc_key), + // &ct1, + // &salt, + // ) + // .unwrap(); + // + // let psk_responder2 = derive_psk_with_psq_responder( + // gateway_keypair.sk(), + // &client_keypair.pk, + // (&dec_key, &enc_key), + // &ct1, // Same ciphertext + // &salt, + // ) + // .unwrap(); + // + // assert_eq!( + // psk_responder1, psk_responder2, + // "Same ciphertext should produce same PSK" + // ); } #[test] fn test_psq_derivation_symmetric() { - let mut rng = rand09::rng(); - - // Generate X25519 keypairs for Noise - let client_keypair = generate_x25519_keypair(); - let gateway_keypair = generate_x25519_keypair(); - - // Generate KEM keypair for PSQ - let (kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); - let enc_key = EncapsulationKey::X25519(kem_pk); - let dec_key = DecapsulationKey::X25519(kem_sk); - - let salt = [2u8; 32]; - - // Client derives PSK (initiator) - let (client_psk, ciphertext) = derive_psk_with_psq_initiator( - client_keypair.sk(), - &gateway_keypair.pk, - &enc_key, - &salt, - ) - .unwrap(); - - // Gateway derives PSK from ciphertext (responder) - let gateway_psk = derive_psk_with_psq_responder( - gateway_keypair.sk(), - &client_keypair.pk, - (&dec_key, &enc_key), - &ciphertext, - &salt, - ) - .unwrap(); - - assert_eq!( - client_psk, gateway_psk, - "Both sides should derive identical PSK via PSQ" - ); + todo!() + // let mut rng = rand09::rng(); + // + // // Generate X25519 keypairs for Noise + // let client_keypair = generate_x25519_keypair(); + // let gateway_keypair = generate_x25519_keypair(); + // + // // Generate KEM keypair for PSQ + // let (kem_sk, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); + // let enc_key = EncapsulationKey::X25519(kem_pk); + // let dec_key = DecapsulationKey::X25519(kem_sk); + // + // let salt = [2u8; 32]; + // + // // Client derives PSK (initiator) + // let (client_psk, ciphertext) = derive_psk_with_psq_initiator( + // client_keypair.sk(), + // &gateway_keypair.pk, + // &enc_key, + // &salt, + // ) + // .unwrap(); + // + // // Gateway derives PSK from ciphertext (responder) + // let gateway_psk = derive_psk_with_psq_responder( + // gateway_keypair.sk(), + // &client_keypair.pk, + // (&dec_key, &enc_key), + // &ciphertext, + // &salt, + // ) + // .unwrap(); + // + // assert_eq!( + // client_psk, gateway_psk, + // "Both sides should derive identical PSK via PSQ" + // ); } #[test] fn test_different_kem_keys_different_psk() { - let mut rng = rand09::rng(); - - let client_keypair = generate_x25519_keypair(); - let gateway_keypair = generate_x25519_keypair(); - - // Two different KEM keypairs - let (_, kem_pk1) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); - let (_, kem_pk2) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); - - let enc_key1 = EncapsulationKey::X25519(kem_pk1); - let enc_key2 = EncapsulationKey::X25519(kem_pk2); - - let salt = [3u8; 32]; - - let (psk1, _) = derive_psk_with_psq_initiator( - client_keypair.sk(), - &gateway_keypair.pk, - &enc_key1, - &salt, - ) - .unwrap(); - - let (psk2, _) = derive_psk_with_psq_initiator( - client_keypair.sk(), - &gateway_keypair.pk, - &enc_key2, - &salt, - ) - .unwrap(); - - assert_ne!( - psk1, psk2, - "Different KEM keys should produce different PSKs" - ); + todo!() + // let mut rng = rand09::rng(); + // + // let client_keypair = generate_x25519_keypair(); + // let gateway_keypair = generate_x25519_keypair(); + // + // // Two different KEM keypairs + // let (_, kem_pk1) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); + // let (_, kem_pk2) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); + // + // let enc_key1 = EncapsulationKey::X25519(kem_pk1); + // let enc_key2 = EncapsulationKey::X25519(kem_pk2); + // + // let salt = [3u8; 32]; + // + // let (psk1, _) = derive_psk_with_psq_initiator( + // client_keypair.sk(), + // &gateway_keypair.pk, + // &enc_key1, + // &salt, + // ) + // .unwrap(); + // + // let (psk2, _) = derive_psk_with_psq_initiator( + // client_keypair.sk(), + // &gateway_keypair.pk, + // &enc_key2, + // &salt, + // ) + // .unwrap(); + // + // assert_ne!( + // psk1, psk2, + // "Different KEM keys should produce different PSKs" + // ); } #[test] fn test_psq_psk_output_length() { - let mut rng = rand09::rng(); - - let client_keypair = generate_x25519_keypair(); - let gateway_keypair = generate_x25519_keypair(); - - let (_, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); - let enc_key = EncapsulationKey::X25519(kem_pk); - - let salt = [4u8; 32]; - - let (psk, _) = derive_psk_with_psq_initiator( - client_keypair.sk(), - &gateway_keypair.pk, - &enc_key, - &salt, - ) - .unwrap(); - - assert_eq!(psk.len(), 32, "PSQ PSK should be exactly 32 bytes"); + todo!() + // let mut rng = rand09::rng(); + // + // let client_keypair = generate_x25519_keypair(); + // let gateway_keypair = generate_x25519_keypair(); + // + // let (_, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); + // let enc_key = EncapsulationKey::X25519(kem_pk); + // + // let salt = [4u8; 32]; + // + // let (psk, _) = derive_psk_with_psq_initiator( + // client_keypair.sk(), + // &gateway_keypair.pk, + // &enc_key, + // &salt, + // ) + // .unwrap(); + // + // assert_eq!(psk.len(), 32, "PSQ PSK should be exactly 32 bytes"); } #[test] fn test_psq_different_salts_different_psks() { - let mut rng = rand09::rng(); - - let client_keypair = generate_x25519_keypair(); - let gateway_keypair = generate_x25519_keypair(); - - let (_, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); - let enc_key = EncapsulationKey::X25519(kem_pk); - - let salt1 = [1u8; 32]; - let salt2 = [2u8; 32]; - - let (psk1, _) = derive_psk_with_psq_initiator( - client_keypair.sk(), - &gateway_keypair.pk, - &enc_key, - &salt1, - ) - .unwrap(); - - let (psk2, _) = derive_psk_with_psq_initiator( - client_keypair.sk(), - &gateway_keypair.pk, - &enc_key, - &salt2, - ) - .unwrap(); - - assert_ne!(psk1, psk2, "Different salts should produce different PSKs"); + todo!() + // let mut rng = rand09::rng(); + // + // let client_keypair = generate_x25519_keypair(); + // let gateway_keypair = generate_x25519_keypair(); + // + // let (_, kem_pk) = generate_keypair_libcrux(&mut rng, KEM::X25519).unwrap(); + // let enc_key = EncapsulationKey::X25519(kem_pk); + // + // let salt1 = [1u8; 32]; + // let salt2 = [2u8; 32]; + // + // let (psk1, _) = derive_psk_with_psq_initiator( + // client_keypair.sk(), + // &gateway_keypair.pk, + // &enc_key, + // &salt1, + // ) + // .unwrap(); + // + // let (psk2, _) = derive_psk_with_psq_initiator( + // client_keypair.sk(), + // &gateway_keypair.pk, + // &enc_key, + // &salt2, + // ) + // .unwrap(); + // + // assert_ne!(psk1, psk2, "Different salts should produce different PSKs"); } } diff --git a/common/nym-lp/src/psq/mod.rs b/common/nym-lp/src/psq/mod.rs index cf67127396..3e8506f1dc 100644 --- a/common/nym-lp/src/psq/mod.rs +++ b/common/nym-lp/src/psq/mod.rs @@ -29,10 +29,10 @@ use rand09::rngs::ThreadRng; use std::fmt::Debug; -const AAD_INITIATOR_OUTER: &[u8] = b"Test Data I Outer"; -const AAD_INITIATOR_INNER: &[u8] = b"Test Data I Inner"; -const AAD_RESPONDER: &[u8] = b"Test Data R"; -const SESSION_CONTEXT: &[u8] = b"Test Context"; +pub(crate) const AAD_INITIATOR_OUTER: &[u8] = b"NYM-PSQ-AAD-INIT-OUTER-V1"; +pub(crate) const AAD_INITIATOR_INNER: &[u8] = b"NYM-PSQ-AAD-INIT-INNER-V1"; +pub(crate) const AAD_RESPONDER: &[u8] = b"NYM-PSQ-AAD-RESP-V1"; +pub(crate) const SESSION_CONTEXT: &[u8] = b"NYM-PSQ-SESSION-CONTEXT-V1"; pub enum PSQState<'a> { Initiator(RegistrationInitiator<'a, ThreadRng>), @@ -313,8 +313,17 @@ mod tests { use crate::peer::mock_peers; use crate::psq::helpers::LpTransportHandshakeExt; use crate::psq::responder::DEFAULT_TIMESTAMP_TOLERANCE; + use libcrux_psq::IntoSession; + use libcrux_psq::handshake::types::{Authenticator, PQEncapsulationKey}; + use libcrux_psq::session::{Session, SessionBinding}; use mock_instant::thread_local::MockClock; - use nym_kkt::ciphersuite::{HashFunction, HashLength, KEM, SignatureScheme}; + use nym_kkt::initiator::KKTInitiator; + use nym_kkt::key_utils::{ + generate_keypair_mceliece, generate_keypair_mlkem, generate_keypair_x25519, + hash_encapsulation_key, + }; + use nym_kkt::responder::KKTResponder; + use nym_kkt_ciphersuite::{HashFunction, HashLength, SignatureScheme}; use nym_test_utils::mocks::async_read_write::MockIOStream; use nym_test_utils::traits::{Leak, TimeboxedSpawnable}; use std::time::Duration; @@ -331,146 +340,391 @@ mod tests { #[tokio::test] async fn e2e_psq_handshake() -> anyhow::Result<()> { - let conn_init = MockIOStream::default(); - let conn_resp = conn_init.try_get_remote_handle(); - - // leak the connections (JUST FOR THE PURPOSE OF THIS TEST!) - // so they'd get 'static lifetime - let conn_init = conn_init.leak(); - let conn_resp = conn_resp.leak(); - - let ciphersuite = Ciphersuite::new( - KEM::X25519, - HashFunction::Blake3, - SignatureScheme::Ed25519, - HashLength::Default, - ); - - let (init, resp) = mock_peers(); - let resp_remote = resp.as_remote(); - - let handshake_init = PSQHandshakeState::new(conn_init, ciphersuite, init) - .with_protocol_version(1) - .with_remote_peer(resp_remote); - let handshake_resp = PSQHandshakeState::new(conn_resp, ciphersuite, resp); - - let resp_fut = handshake_resp.complete_as_responder().spawn_timeboxed(); - let init_fut = handshake_init.complete_as_initiator().spawn_timeboxed(); - - let (session_init, session_resp) = join!(init_fut, resp_fut); - - let session_init = session_init???; - let session_resp = session_resp???; - - assert_eq!(session_init.id(), session_resp.id()); - assert_eq!( - session_init.outer_aead_key().as_bytes(), - session_resp.outer_aead_key().as_bytes() - ); - assert_eq!( - session_init.pq_shared_secret().as_bytes(), - session_resp.pq_shared_secret().as_bytes() - ); - - Ok(()) + todo!() + // let conn_init = MockIOStream::default(); + // let conn_resp = conn_init.try_get_remote_handle(); + // + // // leak the connections (JUST FOR THE PURPOSE OF THIS TEST!) + // // so they'd get 'static lifetime + // let conn_init = conn_init.leak(); + // let conn_resp = conn_resp.leak(); + // + // let ciphersuite = Ciphersuite::new( + // KEM::X25519, + // HashFunction::Blake3, + // SignatureScheme::Ed25519, + // HashLength::Default, + // ); + // + // let (init, resp) = mock_peers(); + // let resp_remote = resp.as_remote(); + // + // let handshake_init = PSQHandshakeState::new(conn_init, ciphersuite, init) + // .with_protocol_version(1) + // .with_remote_peer(resp_remote); + // let handshake_resp = PSQHandshakeState::new(conn_resp, ciphersuite, resp); + // + // let resp_fut = handshake_resp.complete_as_responder().spawn_timeboxed(); + // let init_fut = handshake_init.complete_as_initiator().spawn_timeboxed(); + // + // let (session_init, session_resp) = join!(init_fut, resp_fut); + // + // let session_init = session_init???; + // let session_resp = session_resp???; + // + // assert_eq!(session_init.id(), session_resp.id()); + // assert_eq!( + // session_init.outer_aead_key().as_bytes(), + // session_resp.outer_aead_key().as_bytes() + // ); + // assert_eq!( + // session_init.pq_shared_secret().as_bytes(), + // session_resp.pq_shared_secret().as_bytes() + // ); + // + // Ok(()) } #[tokio::test] async fn preparing_client_hello_initiator() -> anyhow::Result<()> { - let mut conn_init = MockIOStream::default(); - let mut conn_resp = conn_init.try_get_remote_handle(); - - let ciphersuite = Ciphersuite::new( - KEM::X25519, - HashFunction::Blake3, - SignatureScheme::Ed25519, - HashLength::Default, - ); - let (init, resp) = mock_peers(); - let resp_remote = resp.as_remote(); - - // as initiator - let mut handshake_init = PSQHandshakeState::new(&mut conn_init, ciphersuite, init) - .with_protocol_version(1) - .with_remote_peer(resp_remote); - - // you can generate and send (valid) client hello as initiator - let client_hello = handshake_init.send_client_hello().await?; - let LpMessage::ClientHello(received_client_hello) = - conn_resp.receive_packet(None).await?.message - else { - panic!("wrong message type"); - }; - assert_eq!(client_hello, received_client_hello); - Ok(()) + todo!() + // let mut conn_init = MockIOStream::default(); + // let mut conn_resp = conn_init.try_get_remote_handle(); + // + // let ciphersuite = Ciphersuite::new( + // KEM::X25519, + // HashFunction::Blake3, + // SignatureScheme::Ed25519, + // HashLength::Default, + // ); + // let (init, resp) = mock_peers(); + // let resp_remote = resp.as_remote(); + // + // // as initiator + // let mut handshake_init = PSQHandshakeState::new(&mut conn_init, ciphersuite, init) + // .with_protocol_version(1) + // .with_remote_peer(resp_remote); + // + // // you can generate and send (valid) client hello as initiator + // let client_hello = handshake_init.send_client_hello().await?; + // let LpMessage::ClientHello(received_client_hello) = + // conn_resp.receive_packet(None).await?.message + // else { + // panic!("wrong message type"); + // }; + // assert_eq!(client_hello, received_client_hello); + // Ok(()) } // essentially make sure you can't accidentally trigger the handshake as the responder #[tokio::test] async fn preparing_client_hello_responder() -> anyhow::Result<()> { - let conn_init = MockIOStream::default(); - let mut conn_resp = conn_init.try_get_remote_handle(); - - let ciphersuite = Ciphersuite::new( - KEM::X25519, - HashFunction::Blake3, - SignatureScheme::Ed25519, - HashLength::Default, - ); - let (_, resp) = mock_peers(); - - // as initiator - let mut handshake_resp = PSQHandshakeState::new(&mut conn_resp, ciphersuite, resp); - - // you can generate and send (valid) client hello as initiator - let sending_res = handshake_resp.send_client_hello().await; - assert!(sending_res.is_err()); - Ok(()) + todo!() + // let conn_init = MockIOStream::default(); + // let mut conn_resp = conn_init.try_get_remote_handle(); + // + // let ciphersuite = Ciphersuite::new( + // KEM::X25519, + // HashFunction::Blake3, + // SignatureScheme::Ed25519, + // HashLength::Default, + // ); + // let (_, resp) = mock_peers(); + // + // // as initiator + // let mut handshake_resp = PSQHandshakeState::new(&mut conn_resp, ciphersuite, resp); + // + // // you can generate and send (valid) client hello as initiator + // let sending_res = handshake_resp.send_client_hello().await; + // assert!(sending_res.is_err()); + // Ok(()) } #[tokio::test] async fn test_receive_client_hello_timestamp_too_skewed() -> anyhow::Result<()> { - let current_time = Duration::from_secs(10000); - MockClock::set_system_time(current_time); + todo!() + // let current_time = Duration::from_secs(10000); + // MockClock::set_system_time(current_time); + // + // let too_old = current_time - DEFAULT_TIMESTAMP_TOLERANCE - Duration::from_secs(1); + // let too_recent = current_time + DEFAULT_TIMESTAMP_TOLERANCE + Duration::from_secs(1); + // + // let ciphersuite = Ciphersuite::new( + // KEM::X25519, + // HashFunction::Blake3, + // SignatureScheme::Ed25519, + // HashLength::Default, + // ); + // + // // TOO OLD + // let mut conn_init = MockIOStream::default(); + // let mut conn_resp = conn_init.try_get_remote_handle(); + // let (init, resp) = mock_peers(); + // + // let mut handshake_resp = PSQHandshakeState::new(&mut conn_resp, ciphersuite, resp); + // let client_hello_too_old = init.build_client_hello_data(too_old.as_secs()); + // + // conn_init + // .send_packet(client_hello_too_old.into_lp_packet(1), None) + // .await?; + // let err = handshake_resp.receive_client_hello().await.unwrap_err(); + // assert!(err.to_string().contains("too old")); + // + // // TOO RECENT + // let mut conn_init = MockIOStream::default(); + // let mut conn_resp = conn_init.try_get_remote_handle(); + // let (init, resp) = mock_peers(); + // + // let mut handshake_resp = PSQHandshakeState::new(&mut conn_resp, ciphersuite, resp); + // let client_hello_too_recent = init.build_client_hello_data(too_recent.as_secs()); + // + // conn_init + // .send_packet(client_hello_too_recent.into_lp_packet(1), None) + // .await?; + // let err = handshake_resp.receive_client_hello().await.unwrap_err(); + // + // assert!(err.to_string().contains("too future")); + // Ok(()) + } - let too_old = current_time - DEFAULT_TIMESTAMP_TOLERANCE - Duration::from_secs(1); - let too_recent = current_time + DEFAULT_TIMESTAMP_TOLERANCE + Duration::from_secs(1); + // plain test without any wrappers + #[test] + fn e2e_test_plain() { + let mut rng = rand09::rng(); - let ciphersuite = Ciphersuite::new( - KEM::X25519, - HashFunction::Blake3, - SignatureScheme::Ed25519, - HashLength::Default, + // we should add these as consts + let aad_initiator_outer = b"Test Data I Outer"; + let aad_initiator_inner = b"Test Data I Inner"; + let aad_responder = b"Test Data R"; + let ctx = b"Test Context"; + + // generate responder x25519 keys + let responder_x25519_keypair = generate_keypair_x25519(&mut rng); + let hash_function = HashFunction::Blake3; + // generate kem public keys + + let responder_mlkem_keypair = generate_keypair_mlkem(&mut rng); + let responder_mceliece_keypair = generate_keypair_mceliece(&mut rng); + + let r_dir_hash_mlkem = hash_encapsulation_key( + // &ciphersuite.hash_function(), + hash_function, + // ciphersuite.hash_len(), + HashLength::Default.value(), + responder_mlkem_keypair.1.as_slice().as_slice(), ); - // TOO OLD - let mut conn_init = MockIOStream::default(); - let mut conn_resp = conn_init.try_get_remote_handle(); - let (init, resp) = mock_peers(); + let _r_dir_hash_mceliece = hash_encapsulation_key( + // &ciphersuite.hash_function(), + hash_function, + // ciphersuite.hash_len(), + HashLength::Default.value(), + responder_mceliece_keypair.1.as_ref(), + ); - let mut handshake_resp = PSQHandshakeState::new(&mut conn_resp, ciphersuite, resp); - let client_hello_too_old = init.build_client_hello_data(too_old.as_secs()); + let kkt_responder = KKTResponder::new( + &responder_x25519_keypair, + Some(&responder_mlkem_keypair.1), + Some(&responder_mceliece_keypair.1), + &[ + HashFunction::Blake3, + HashFunction::SHA256, + HashFunction::Shake128, + HashFunction::Shake256, + ], + &[1], + &[SignatureScheme::Ed25519], + ) + .unwrap(); - conn_init - .send_packet(client_hello_too_old.into_lp_packet(1), None) - .await?; - let err = handshake_resp.receive_client_hello().await.unwrap_err(); - assert!(err.to_string().contains("too old")); + // OneWay - MlKem + let psq_ciphersuite = CiphersuiteName::X25519_MLKEM768_X25519_AESGCM128_HKDFSHA256; - // TOO RECENT - let mut conn_init = MockIOStream::default(); - let mut conn_resp = conn_init.try_get_remote_handle(); - let (init, resp) = mock_peers(); + let responder_ciphersuite = CiphersuiteBuilder::new(psq_ciphersuite) + .longterm_x25519_keys(&responder_x25519_keypair) + .longterm_mlkem_encapsulation_key(&responder_mlkem_keypair.1) + .longterm_mlkem_decapsulation_key(&responder_mlkem_keypair.0) + .build_responder_ciphersuite() + .unwrap(); - let mut handshake_resp = PSQHandshakeState::new(&mut conn_resp, ciphersuite, resp); - let client_hello_too_recent = init.build_client_hello_data(too_recent.as_secs()); + let mut responder = PrincipalBuilder::new(rand09::rng()) + .context(ctx) + .outer_aad(aad_responder) + .recent_keys_upper_bound(30) + .build_responder(responder_ciphersuite) + .unwrap(); - conn_init - .send_packet(client_hello_too_recent.into_lp_packet(1), None) - .await?; - let err = handshake_resp.receive_client_hello().await.unwrap_err(); + let ciphersuite = Ciphersuite::resolve_ciphersuite( + KEM::MlKem768, + hash_function, + SignatureScheme::Ed25519, + None, + ) + .unwrap(); - assert!(err.to_string().contains("too future")); - Ok(()) + let (mut initiator, request_bytes) = KKTInitiator::generate_one_way_request( + &mut rng, + &ciphersuite, + &responder_x25519_keypair.pk, + &r_dir_hash_mlkem, + 1u8, + ) + .unwrap(); + + let (response_bytes, _) = kkt_responder.process_request(&request_bytes).unwrap(); + + let (i_obtained_key, _) = initiator.process_response(&response_bytes).unwrap(); + + assert_eq!( + i_obtained_key, + responder_mlkem_keypair.1.as_slice().as_slice(), + ); + + let mlkem_key = + libcrux_kem::MlKem768PublicKey::try_from(i_obtained_key.as_slice()).unwrap(); + + let initiator_psq_keys = generate_keypair_x25519(&mut rng); + let initiator_cbuilder = CiphersuiteBuilder::new(psq_ciphersuite) + .longterm_x25519_keys(&initiator_psq_keys) + .peer_longterm_x25519_pk(&responder_x25519_keypair.pk) + .peer_longterm_mlkem_pk(&mlkem_key); + + let initiator_ciphersuite = initiator_cbuilder.build_initiator_ciphersuite().unwrap(); + + let mut msg_channel = vec![0u8; 8192]; + let mut payload_buf_responder = vec![0u8; 4096]; + let mut payload_buf_initiator = vec![0u8; 4096]; + + let mut initiator = PrincipalBuilder::new(rand09::rng()) + .outer_aad(aad_initiator_outer) + .inner_aad(aad_initiator_inner) + .context(ctx) + .build_registration_initiator(initiator_ciphersuite) + .unwrap(); + + // Send first message + let registration_payload_initiator = b"Registration_init"; + let len_i = initiator + .write_message(registration_payload_initiator, &mut msg_channel) + .unwrap(); + + // Read first message + let (len_r_deserialized, len_r_payload) = responder + .read_message(&msg_channel, &mut payload_buf_responder) + .unwrap(); + + // We read the same amount of data. + assert_eq!(len_r_deserialized, len_i); + assert_eq!(len_r_payload, registration_payload_initiator.len()); + assert_eq!( + &payload_buf_responder[0..len_r_payload], + registration_payload_initiator + ); + + // Get the authenticator out here, so we can deserialize the session later. + let Some(initiator_authenticator) = responder.initiator_authenticator() else { + panic!("No initiator authenticator found") + }; + + // Respond + let registration_payload_responder = b"Registration_respond"; + let len_r = responder + .write_message(registration_payload_responder, &mut msg_channel) + .unwrap(); + + // Finalize on registration initiator + let (len_i_deserialized, len_i_payload) = initiator + .read_message(&msg_channel, &mut payload_buf_initiator) + .unwrap(); + + // We read the same amount of data. + assert_eq!(len_r, len_i_deserialized); + assert_eq!(registration_payload_responder.len(), len_i_payload); + assert_eq!( + &payload_buf_initiator[0..len_i_payload], + registration_payload_responder + ); + + // Ready for transport mode + assert!(initiator.is_handshake_finished()); + assert!(responder.is_handshake_finished()); + + let i_transport = initiator.into_session().unwrap(); + let r_transport = responder.into_session().unwrap(); + + // test serialization, deserialization + let mut session_storage = vec![0u8; 4096]; + i_transport + .serialize( + &mut session_storage, + SessionBinding { + initiator_authenticator: &Authenticator::Dh(initiator_psq_keys.pk), + responder_ecdh_pk: &responder_x25519_keypair.pk, + responder_pq_pk: Some(PQEncapsulationKey::MlKem(&mlkem_key)), + }, + ) + .unwrap(); + let mut i_transport = Session::deserialize( + &session_storage, + SessionBinding { + initiator_authenticator: &Authenticator::Dh(initiator_psq_keys.pk), + responder_ecdh_pk: &responder_x25519_keypair.pk, + responder_pq_pk: Some(PQEncapsulationKey::MlKem(&mlkem_key)), + }, + ) + .unwrap(); + + r_transport + .serialize( + &mut session_storage, + SessionBinding { + initiator_authenticator: &initiator_authenticator, + responder_ecdh_pk: &responder_x25519_keypair.pk, + responder_pq_pk: Some(PQEncapsulationKey::MlKem(&mlkem_key)), + }, + ) + .unwrap(); + let mut r_transport = Session::deserialize( + &session_storage, + SessionBinding { + initiator_authenticator: &initiator_authenticator, + responder_ecdh_pk: &responder_x25519_keypair.pk, + responder_pq_pk: Some(PQEncapsulationKey::MlKem(&mlkem_key)), + }, + ) + .unwrap(); + + let mut channel_i = i_transport.transport_channel().unwrap(); + let mut channel_r = r_transport.transport_channel().unwrap(); + + assert_eq!(channel_i.identifier(), channel_r.identifier()); + + let app_data_i = b"Derived session hey".as_slice(); + let app_data_r = b"Derived session ho".as_slice(); + + let len_i = channel_i + .write_message(app_data_i, &mut msg_channel) + .unwrap(); + + let (len_r_deserialized, len_r_payload) = channel_r + .read_message(&msg_channel, &mut payload_buf_responder) + .unwrap(); + + // We read the same amount of data. + assert_eq!(len_r_deserialized, len_i); + assert_eq!(len_r_payload, app_data_i.len()); + assert_eq!(&payload_buf_responder[0..len_r_payload], app_data_i); + + let len_r = channel_r + .write_message(app_data_r, &mut msg_channel) + .unwrap(); + + let (len_i_deserialized, len_i_payload) = channel_i + .read_message(&msg_channel, &mut payload_buf_initiator) + .unwrap(); + + assert_eq!(len_r, len_i_deserialized); + assert_eq!(app_data_r.len(), len_i_payload); + assert_eq!(&payload_buf_initiator[0..len_i_payload], app_data_r); } } diff --git a/common/nym-lp/src/session.rs b/common/nym-lp/src/session.rs index a810c650f0..ddf93938f4 100644 --- a/common/nym-lp/src/session.rs +++ b/common/nym-lp/src/session.rs @@ -609,7 +609,7 @@ impl SubsessionHandshake { #[cfg(test)] mod tests { use super::*; - use crate::{SessionsMock, replay::ReplayError, sessions_for_tests}; + use crate::{SessionsMock, kem_list, replay::ReplayError, sessions_for_tests}; use rand::thread_rng; // Helper function to generate keypairs for tests @@ -619,18 +619,19 @@ mod tests { #[test] fn test_session_creation() { - let mut session = sessions_for_tests().0; - for kem in kem_list() { - let session = sessions_for_tests(kem).0; - - // Initial counter should be zero - let counter = session.next_counter(); - assert_eq!(counter, 0); - - // Counter should increment - let counter = session.next_counter(); - assert_eq!(counter, 1); - } + todo!() + // let mut session = sessions_for_tests().0; + // for kem in kem_list() { + // let session = sessions_for_tests(kem).0; + // + // // Initial counter should be zero + // let counter = session.next_counter(); + // assert_eq!(counter, 0); + // + // // Counter should increment + // let counter = session.next_counter(); + // assert_eq!(counter, 1); + // } } // NOTE: These tests are obsolete after removing optional KEM parameters. @@ -650,69 +651,72 @@ mod tests { #[test] fn test_replay_protection_sequential() { - for kem in kem_list() { - let mut session = sessions_for_tests(kem).1; - - // Sequential counters should be accepted - assert!(session.receiving_counter_quick_check(0).is_ok()); - assert!(session.receiving_counter_mark(0).is_ok()); - - assert!(session.receiving_counter_quick_check(1).is_ok()); - assert!(session.receiving_counter_mark(1).is_ok()); - - // Duplicates should be rejected - assert!(session.receiving_counter_quick_check(0).is_err()); - let err = session.receiving_counter_mark(0).unwrap_err(); - match err { - LpError::Replay(replay_error) => { - assert!(matches!(replay_error, ReplayError::DuplicateCounter)); - } - _ => panic!("Expected replay error"), - } - } + todo!() + // for kem in kem_list() { + // let mut session = sessions_for_tests(kem).1; + // + // // Sequential counters should be accepted + // assert!(session.receiving_counter_quick_check(0).is_ok()); + // assert!(session.receiving_counter_mark(0).is_ok()); + // + // assert!(session.receiving_counter_quick_check(1).is_ok()); + // assert!(session.receiving_counter_mark(1).is_ok()); + // + // // Duplicates should be rejected + // assert!(session.receiving_counter_quick_check(0).is_err()); + // let err = session.receiving_counter_mark(0).unwrap_err(); + // match err { + // LpError::Replay(replay_error) => { + // assert!(matches!(replay_error, ReplayError::DuplicateCounter)); + // } + // _ => panic!("Expected replay error"), + // } + // } } #[test] fn test_replay_protection_out_of_order() { - for kem in kem_list() { - let mut session = sessions_for_tests(kem).1; - - // Receive packets in order - assert!(session.receiving_counter_mark(0).is_ok()); - assert!(session.receiving_counter_mark(1).is_ok()); - assert!(session.receiving_counter_mark(2).is_ok()); - - // Skip ahead - assert!(session.receiving_counter_mark(10).is_ok()); - - // Can still receive out-of-order packets within window - assert!(session.receiving_counter_quick_check(5).is_ok()); - assert!(session.receiving_counter_mark(5).is_ok()); - - // But duplicates are still rejected - assert!(session.receiving_counter_quick_check(5).is_err()); - assert!(session.receiving_counter_mark(5).is_err()); - } + todo!() + // for kem in kem_list() { + // let mut session = sessions_for_tests(kem).1; + // + // // Receive packets in order + // assert!(session.receiving_counter_mark(0).is_ok()); + // assert!(session.receiving_counter_mark(1).is_ok()); + // assert!(session.receiving_counter_mark(2).is_ok()); + // + // // Skip ahead + // assert!(session.receiving_counter_mark(10).is_ok()); + // + // // Can still receive out-of-order packets within window + // assert!(session.receiving_counter_quick_check(5).is_ok()); + // assert!(session.receiving_counter_mark(5).is_ok()); + // + // // But duplicates are still rejected + // assert!(session.receiving_counter_quick_check(5).is_err()); + // assert!(session.receiving_counter_mark(5).is_err()); + // } } #[test] fn test_packet_stats() { - for kem in kem_list() { - let mut session = sessions_for_tests(kem).1; - - // Initial stats - let (next, received) = session.current_packet_cnt(); - assert_eq!(next, 0); - assert_eq!(received, 0); - - // After receiving packets - assert!(session.receiving_counter_mark(0).is_ok()); - assert!(session.receiving_counter_mark(1).is_ok()); - - let (next, received) = session.current_packet_cnt(); - assert_eq!(next, 2); - assert_eq!(received, 2); - } + todo!() + // for kem in kem_list() { + // let mut session = sessions_for_tests(kem).1; + // + // // Initial stats + // let (next, received) = session.current_packet_cnt(); + // assert_eq!(next, 0); + // assert_eq!(received, 0); + // + // // After receiving packets + // assert!(session.receiving_counter_mark(0).is_ok()); + // assert!(session.receiving_counter_mark(1).is_ok()); + // + // let (next, received) = session.current_packet_cnt(); + // assert_eq!(next, 2); + // assert_eq!(received, 2); + // } } /* @@ -754,47 +758,48 @@ mod tests { /// Test that X25519 keys are correctly converted to KEM format #[test] fn test_x25519_to_kem_conversion() { - use nym_kkt::ciphersuite::EncapsulationKey; - - let initiator_keys = generate_x25519_keypair(); - let responder_keys = generate_x25519_keypair(); - - // Verify we can convert X25519 public key to KEM format (as done in session.rs) - let x25519_public_bytes = responder_keys.public_key().as_bytes(); - let libcrux_public_key = - libcrux_kem::PublicKey::decode(libcrux_kem::Algorithm::X25519, x25519_public_bytes) - .expect("X25519 public key should convert to libcrux PublicKey"); - - let _kem_key = EncapsulationKey::X25519(libcrux_public_key); - - // Verify we can convert X25519 private key to KEM format - let x25519_private_bytes = initiator_keys.private_key().to_bytes(); - let _libcrux_private_key = - libcrux_kem::PrivateKey::decode(libcrux_kem::Algorithm::X25519, &x25519_private_bytes) - .expect("X25519 private key should convert to libcrux PrivateKey"); - - // Successful conversion is sufficient - actual encapsulation is tested in psk.rs - // (libcrux_kem::PrivateKey is an enum with no len() method, conversion success is enough) + todo!() + // + // let initiator_keys = generate_x25519_keypair(); + // let responder_keys = generate_x25519_keypair(); + // + // // Verify we can convert X25519 public key to KEM format (as done in session.rs) + // let x25519_public_bytes = responder_keys.public_key().as_bytes(); + // let libcrux_public_key = + // libcrux_kem::PublicKey::decode(libcrux_kem::Algorithm::X25519, x25519_public_bytes) + // .expect("X25519 public key should convert to libcrux PublicKey"); + // + // let _kem_key = EncapsulationKey::X25519(libcrux_public_key); + // + // // Verify we can convert X25519 private key to KEM format + // let x25519_private_bytes = initiator_keys.private_key().to_bytes(); + // let _libcrux_private_key = + // libcrux_kem::PrivateKey::decode(libcrux_kem::Algorithm::X25519, &x25519_private_bytes) + // .expect("X25519 private key should convert to libcrux PrivateKey"); + // + // // Successful conversion is sufficient - actual encapsulation is tested in psk.rs + // // (libcrux_kem::PrivateKey is an enum with no len() method, conversion success is enough) } #[test] fn test_demote_sets_read_only() { - let sessions = SessionsMock::mock_post_handshake(12345); - let mut session = sessions.initiator; - for kem in kem_list() { - let session = create_handshake_test_session(kem, 12345u32, true); - - // Initially not read-only - assert!(!session.is_read_only()); - assert!(session.successor_session_id().is_none()); - - // Demote the session - session.demote(99999); - - // Now read-only with successor - assert!(session.is_read_only()); - assert_eq!(session.successor_session_id(), Some(99999)); - } + todo!() + // let sessions = SessionsMock::mock_post_handshake(12345); + // let mut session = sessions.initiator; + // for kem in kem_list() { + // let session = create_handshake_test_session(kem, 12345u32, true); + // + // // Initially not read-only + // assert!(!session.is_read_only()); + // assert!(session.successor_session_id().is_none()); + // + // // Demote the session + // session.demote(99999); + // + // // Now read-only with successor + // assert!(session.is_read_only()); + // assert_eq!(session.successor_session_id(), Some(99999)); + // } } #[test]