diff --git a/Cargo.lock b/Cargo.lock index 47775d2f4c..e01fc30b4e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1017,16 +1017,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo-platform" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87a0c0e6148f11f01f32650a2ea02d532b2ad4e81d8bd41e6e565b5adc5e6082" -dependencies = [ - "serde", - "serde_core", -] - [[package]] name = "cargo_metadata" version = "0.18.1" @@ -1034,7 +1024,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", - "cargo-platform 0.1.9", + "cargo-platform", "semver 1.0.27", "serde", "serde_json", @@ -1048,21 +1038,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ "camino", - "cargo-platform 0.1.9", - "semver 1.0.27", - "serde", - "serde_json", - "thiserror 2.0.18", -] - -[[package]] -name = "cargo_metadata" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" -dependencies = [ - "camino", - "cargo-platform 0.3.2", + "cargo-platform", "semver 1.0.27", "serde", "serde_json", @@ -2069,38 +2045,14 @@ dependencies = [ "serde", ] -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core 0.20.11", - "darling_macro 0.20.11", -] - [[package]] name = "darling" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.114", + "darling_core", + "darling_macro", ] [[package]] @@ -2117,24 +2069,13 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core 0.20.11", - "quote", - "syn 2.0.114", -] - [[package]] name = "darling_macro" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core 0.21.3", + "darling_core", "quote", "syn 2.0.114", ] @@ -2268,37 +2209,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "derive_builder" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" -dependencies = [ - "darling 0.20.11", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" -dependencies = [ - "derive_builder_core", - "syn 2.0.114", -] - [[package]] name = "derive_more" version = "1.0.0" @@ -5560,7 +5470,7 @@ dependencies = [ "tracing-subscriber", "tracing-tree", "utoipa", - "vergen 8.3.1", + "vergen", ] [[package]] @@ -5948,7 +5858,7 @@ dependencies = [ "serde_json", "thiserror 2.0.18", "utoipa", - "vergen 8.3.1", + "vergen", ] [[package]] @@ -6475,60 +6385,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "nym-gateway-probe" -version = "1.18.0" -dependencies = [ - "anyhow", - "base64 0.22.1", - "bincode", - "bs58", - "bytes", - "clap", - "futures", - "hex", - "nym-api-requests", - "nym-authenticator-client", - "nym-authenticator-requests", - "nym-bandwidth-controller", - "nym-bin-common", - "nym-client-core", - "nym-config", - "nym-connection-monitor", - "nym-credential-utils", - "nym-credentials", - "nym-credentials-interface", - "nym-crypto", - "nym-http-api-client", - "nym-http-api-client-macro", - "nym-ip-packet-client", - "nym-ip-packet-requests", - "nym-kkt-ciphersuite", - "nym-lp", - "nym-mixnet-contract-common", - "nym-network-defaults", - "nym-node-requests", - "nym-node-status-client", - "nym-registration-client", - "nym-registration-common", - "nym-sdk", - "nym-topology", - "nym-validator-client", - "pnet_packet", - "rand 0.8.5", - "serde", - "serde_json", - "thiserror 2.0.18", - "time", - "tokio", - "tokio-util", - "tracing", - "tracing-subscriber", - "url", - "vergen-gitcl", - "x25519-dalek", -] - [[package]] name = "nym-gateway-requests" version = "1.20.1" @@ -10559,7 +10415,7 @@ version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ - "darling 0.21.3", + "darling", "proc-macro2", "quote", "syn 2.0.114", @@ -12890,58 +12746,6 @@ dependencies = [ "time", ] -[[package]] -name = "vergen" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b849a1f6d8639e8de261e81ee0fc881e3e3620db1af9f2e0da015d4382ceaf75" -dependencies = [ - "anyhow", - "cargo_metadata 0.23.1", - "derive_builder", - "regex", - "rustc_version 0.4.1", - "rustversion", - "time", - "vergen-lib 9.1.0", -] - -[[package]] -name = "vergen-gitcl" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9dfc1de6eb2e08a4ddf152f1b179529638bedc0ea95e6d667c014506377aefe" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", - "time", - "vergen 9.1.0", - "vergen-lib 0.1.6", -] - -[[package]] -name = "vergen-lib" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b07e6010c0f3e59fcb164e0163834597da68d1f864e2b8ca49f74de01e9c166" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", -] - -[[package]] -name = "vergen-lib" -version = "9.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34a29ba7e9c59e62f229ae1932fb1b8fb8a6fdcc99215a641913f5f5a59a569" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", -] - [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index 1c119808b0..b67f1da34f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -173,7 +173,7 @@ members = [ "wasm/mix-fetch", "wasm/node-tester", "wasm/zknym-lib", - "nym-gateway-probe", + # "nym-gateway-probe", "integration-tests", "common/nym-lp-transport", "common/nym-kkt-ciphersuite", ] diff --git a/common/nym-kkt/src/carrier.rs b/common/nym-kkt/src/carrier.rs index 6358fe6f3b..6f795f4c9f 100644 --- a/common/nym-kkt/src/carrier.rs +++ b/common/nym-kkt/src/carrier.rs @@ -2,6 +2,7 @@ use libcrux_chacha20poly1305::TAG_LEN; use libcrux_psq::handshake::types::DHPublicKey; use nym_crypto::hkdf::blake3::{derive_key_blake3, derive_key_blake3_multi_input}; use std::fmt::{Debug, Formatter}; +use std::sync::atomic::{AtomicU64, Ordering}; use zeroize::Zeroize; use crate::{ @@ -14,8 +15,8 @@ const MAX_PAYLOAD_LEN: usize = 65535; pub struct Carrier { tx_key: [u8; 32], rx_key: [u8; 32], - tx_counter: u64, - rx_counter: u64, + tx_counter: AtomicU64, + rx_counter: AtomicU64, } impl Debug for Carrier { @@ -29,21 +30,9 @@ impl Debug for Carrier { } } -fn increment_nonce(nonce: &mut u64) -> Result<(), KKTError> { - match nonce.checked_add(1) { - Some(incremented_nonce) => { - *nonce = incremented_nonce; - Ok(()) - } - None => Err(KKTError::AEADError { - info: "Nonce maxed out.", - }), - } -} - -fn as_nonce_bytes(nonce: u64) -> [u8; 12] { +fn as_nonce_bytes(nonce: &AtomicU64) -> [u8; 12] { let mut bytes = [0u8; 12]; - let nonce_bytes = nonce.to_le_bytes(); + let nonce_bytes = nonce.load(Ordering::Relaxed).to_le_bytes(); bytes[4..].clone_from_slice(&nonce_bytes); bytes } @@ -54,14 +43,11 @@ impl Carrier { role: KKTRole, kkt_session_id: &[u8; KKT_SESSION_ID_LEN], responder_public_key: &DHPublicKey, - responder_encapsulation_key: &EncapsulationKey, + encoded_encapsulation_key: &[u8], ) -> Result { let mut salt = derive_key_blake3_multi_input( "nym-kkt-carrier-kdf-main", - &[ - responder_encapsulation_key.encode().as_ref(), - responder_public_key.as_ref(), - ], + &[encoded_encapsulation_key, responder_public_key.as_ref()], kkt_session_id, ); @@ -83,18 +69,18 @@ impl Carrier { KKTRole::Initiator | KKTRole::AnonymousInitiator => Self { tx_key: k1, rx_key: k2, - tx_counter: 1, - rx_counter: 1, + tx_counter: AtomicU64::new(1), + rx_counter: AtomicU64::new(1), }, KKTRole::Responder => Self { tx_key: k2, rx_key: k1, - tx_counter: 1, - rx_counter: 1, + tx_counter: AtomicU64::new(1), + rx_counter: AtomicU64::new(1), }, }) } - pub fn encrypt(&mut self, plaintext: &[u8]) -> Result, KKTError> { + pub fn encrypt(&self, plaintext: &[u8]) -> Result, KKTError> { if plaintext.len() > MAX_PAYLOAD_LEN { return Err(KKTError::AEADError { info: "Plaintext too large", @@ -106,14 +92,14 @@ impl Carrier { plaintext, &mut output_buffer, b"kkt-carrier-v1", - &as_nonce_bytes(self.tx_counter), + &as_nonce_bytes(&self.tx_counter), )?; - increment_nonce(&mut self.tx_counter)?; + self.tx_counter.fetch_add(1, Ordering::Relaxed); Ok(output_buffer) } - pub fn decrypt(&mut self, ciphertext: &[u8]) -> Result, KKTError> { + pub fn decrypt(&self, ciphertext: &[u8]) -> Result, KKTError> { if ciphertext.len() > MAX_PAYLOAD_LEN + TAG_LEN { return Err(KKTError::AEADError { info: "Ciphertext too large", @@ -125,10 +111,10 @@ impl Carrier { &mut output_buffer, ciphertext, b"kkt-carrier-v1", - &as_nonce_bytes(self.rx_counter), + &as_nonce_bytes(&self.rx_counter), )?; - increment_nonce(&mut self.rx_counter)?; + self.rx_counter.fetch_add(1, Ordering::Relaxed); Ok(output_buffer) } diff --git a/common/nym-kkt/src/ciphersuite.rs b/common/nym-kkt/src/ciphersuite.rs index 3f86f1f6d4..1b86fa68dc 100644 --- a/common/nym-kkt/src/ciphersuite.rs +++ b/common/nym-kkt/src/ciphersuite.rs @@ -17,10 +17,10 @@ pub enum EncapsulationKey { impl EncapsulationKey { pub fn kem(&self) -> KEM { match self { - DecapsulationKey::MlKem768(_) => KEM::MlKem768, - DecapsulationKey::XWing(_) => KEM::XWing, - DecapsulationKey::X25519(_) => KEM::X25519, - DecapsulationKey::McEliece(_) => KEM::McEliece, + EncapsulationKey::MlKem768(_) => KEM::MlKem768, + EncapsulationKey::XWing(_) => KEM::XWing, + EncapsulationKey::X25519(_) => KEM::X25519, + EncapsulationKey::McEliece(_) => KEM::McEliece, } } } @@ -145,41 +145,90 @@ pub const fn map_kem_to_libcrux_kem(kem: KEM) -> Result { } } -#[derive(Debug)] -pub struct KemKeyPair { - encapsulation_key: EncapsulationKey, - decapsulation_key: DecapsulationKey, +pub enum KemKeyPair { + MlKem768 { + encapsulation_key: libcrux_kem::MlKem768PublicKey, + decapsulation_key: libcrux_kem::MlKem768PrivateKey, + }, + XWing { + encapsulation_key: libcrux_kem::PublicKey, + decapsulation_key: libcrux_kem::PrivateKey, + }, + X25519 { + encapsulation_key: libcrux_kem::PublicKey, + decapsulation_key: libcrux_kem::PrivateKey, + }, + McEliece { + encapsulation_key: libcrux_psq::classic_mceliece::PublicKey, + decapsulation_key: libcrux_psq::classic_mceliece::SecretKey, + }, } +impl Debug for KemKeyPair { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } +} + +// #[derive(Debug)] +// pub struct KemKeyPair { +// encapsulation_key: EncapsulationKey, +// decapsulation_key: DecapsulationKey, +// } + impl KemKeyPair { pub fn kem(&self) -> KEM { - self.encapsulation_key.kem() + match self { + KemKeyPair::MlKem768 { .. } => KEM::MlKem768, + KemKeyPair::XWing { .. } => KEM::XWing, + KemKeyPair::X25519 { .. } => KEM::X25519, + KemKeyPair::McEliece { .. } => KEM::McEliece, + } } - pub fn encapsulation_key(&self) -> &EncapsulationKey { - &self.encapsulation_key - } + // pub fn encapsulation_key(&self) -> &EncapsulationKey { + // &self.encapsulation_key + // } + // + // pub fn decapsulation_key(&self) -> &DecapsulationKey { + // &self.decapsulation_key + // } - pub fn decapsulation_key(&self) -> &DecapsulationKey { - &self.decapsulation_key + pub fn encoded_encapsulation_key(&self) -> Vec { + match self { + KemKeyPair::MlKem768 { + encapsulation_key, .. + } => encapsulation_key.as_slice().to_vec(), + KemKeyPair::XWing { + encapsulation_key, .. + } => encapsulation_key.encode(), + KemKeyPair::X25519 { + encapsulation_key, .. + } => encapsulation_key.encode(), + KemKeyPair::McEliece { + encapsulation_key, .. + } => encapsulation_key.as_ref().to_vec(), + } } } impl From for KemKeyPair { fn from(keypair: MlKem768KeyPair) -> Self { let (sk, pk) = keypair.into_parts(); - KemKeyPair { - encapsulation_key: EncapsulationKey::MlKem768(pk), - decapsulation_key: DecapsulationKey::MlKem768(sk), - } + todo!() + // KemKeyPair { + // encapsulation_key: EncapsulationKey::MlKem768(pk), + // decapsulation_key: DecapsulationKey::MlKem768(sk), + // } } } impl From for KemKeyPair { fn from(keypair: libcrux_psq::classic_mceliece::KeyPair) -> Self { - KemKeyPair { - encapsulation_key: EncapsulationKey::McEliece(keypair.pk), - decapsulation_key: DecapsulationKey::McEliece(keypair.sk), - } + todo!() + // KemKeyPair { + // encapsulation_key: EncapsulationKey::McEliece(keypair.pk), + // decapsulation_key: DecapsulationKey::McEliece(keypair.sk), + // } } } diff --git a/common/nym-kkt/src/session.rs b/common/nym-kkt/src/session.rs index 07a0b0df1f..bfc298eae3 100644 --- a/common/nym-kkt/src/session.rs +++ b/common/nym-kkt/src/session.rs @@ -204,21 +204,21 @@ pub fn responder_process( own_context: &mut KKTContext, session_id: KKTSessionId, signing_key: &ed25519::PrivateKey, - encapsulation_key: &EncapsulationKey, + encoded_encapsulation_key: &[u8], ) -> Result { - let body = encapsulation_key.encode(); + let body = encoded_encapsulation_key; let context_bytes = own_context.encode()?; let mut bytes_to_sign = Vec::with_capacity(own_context.full_message_len() - own_context.signature_len()); bytes_to_sign.extend_from_slice(&own_context.encode()?); - bytes_to_sign.extend_from_slice(&body); + bytes_to_sign.extend_from_slice(body); bytes_to_sign.extend_from_slice(&session_id); let signature = signing_key.sign(bytes_to_sign).to_bytes(); - Ok(KKTFrame::new(context_bytes, &body, session_id, &signature)) + Ok(KKTFrame::new(context_bytes, body, session_id, &signature)) } fn check_compatibility( diff --git a/common/nym-lp/src/message.rs b/common/nym-lp/src/message.rs index ca0c751637..a743ab0644 100644 --- a/common/nym-lp/src/message.rs +++ b/common/nym-lp/src/message.rs @@ -8,7 +8,7 @@ use num_enum::{IntoPrimitive, TryFromPrimitive}; use nym_crypto::asymmetric::{ed25519, x25519}; use rand::RngCore; use serde::{Deserialize, Serialize}; -use std::fmt::{self, Display}; +use std::fmt::{self, Display, write}; /// Data structure for the ClientHello message #[derive(Debug, Clone, Serialize, Deserialize)] @@ -464,7 +464,6 @@ impl Display for LpMessage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { LpMessage::Busy => write!(f, "Busy"), - LpMessage::Handshake(_) => write!(f, "Handshake"), LpMessage::EncryptedData(_) => write!(f, "EncryptedData"), LpMessage::ClientHello(_) => write!(f, "ClientHello"), LpMessage::KKTRequest(_) => write!(f, "KKTRequest"), @@ -477,34 +476,16 @@ impl Display for LpMessage { LpMessage::SubsessionKK2(_) => write!(f, "SubsessionKK2"), LpMessage::SubsessionReady(_) => write!(f, "SubsessionReady"), LpMessage::SubsessionAbort => write!(f, "SubsessionAbort"), + LpMessage::PSQRequest(_) => write!(f, "PSQRequest"), + LpMessage::PSQResponse(_) => write!(f, "PSQResponse"), } } } impl LpMessage { - pub fn payload(&self) -> &[u8] { - match self { - LpMessage::Busy => &[], - LpMessage::Handshake(payload) => payload.0.as_slice(), - LpMessage::EncryptedData(payload) => payload.0.as_slice(), - LpMessage::ClientHello(_) => &[], // Structured data, serialized in encode_content - LpMessage::KKTRequest(payload) => payload.0.as_slice(), - LpMessage::KKTResponse(payload) => payload.0.as_slice(), - LpMessage::ForwardPacket(_) => &[], // Structured data, serialized in encode_content - LpMessage::Collision => &[], - LpMessage::Ack => &[], - LpMessage::SubsessionRequest => &[], - LpMessage::SubsessionKK1(_) => &[], // Structured data, serialized in encode_content - LpMessage::SubsessionKK2(_) => &[], // Structured data, serialized in encode_content - LpMessage::SubsessionReady(_) => &[], // Structured data, serialized in encode_content - LpMessage::SubsessionAbort => &[], - } - } - pub fn is_empty(&self) -> bool { match self { LpMessage::Busy => true, - LpMessage::Handshake(payload) => payload.0.is_empty(), LpMessage::EncryptedData(payload) => payload.0.is_empty(), LpMessage::ClientHello(_) => false, // Always has data LpMessage::KKTRequest(payload) => payload.0.is_empty(), @@ -517,13 +498,16 @@ impl LpMessage { LpMessage::SubsessionKK2(_) => false, // Always has payload LpMessage::SubsessionReady(_) => false, // Always has receiver_index LpMessage::SubsessionAbort => true, // Empty signal + LpMessage::PSQRequest(payload) => true, // Always had data (?) + LpMessage::PSQResponse(payload) => true, // Always had data (?) } } pub fn len(&self) -> usize { match self { LpMessage::Busy => 0, - LpMessage::Handshake(payload) => payload.len(), + LpMessage::PSQRequest(payload) => payload.len(), + LpMessage::PSQResponse(payload) => payload.len(), LpMessage::EncryptedData(payload) => payload.len(), LpMessage::ClientHello(payload) => payload.len(), LpMessage::KKTRequest(payload) => payload.len(), @@ -542,7 +526,8 @@ impl LpMessage { pub fn typ(&self) -> MessageType { match self { LpMessage::Busy => MessageType::Busy, - LpMessage::Handshake(_) => MessageType::Handshake, + LpMessage::PSQRequest(_) => todo!(), + LpMessage::PSQResponse(_) => todo!(), LpMessage::EncryptedData(_) => MessageType::EncryptedData, LpMessage::ClientHello(_) => MessageType::ClientHello, LpMessage::KKTRequest(_) => MessageType::KKTRequest, @@ -561,7 +546,8 @@ impl LpMessage { pub fn encode_content(&self, dst: &mut BytesMut) { match self { LpMessage::Busy => { /* No content */ } - LpMessage::Handshake(payload) => payload.encode(dst), + LpMessage::PSQRequest(payload) => payload.encode(dst), + LpMessage::PSQResponse(payload) => payload.encode(dst), LpMessage::EncryptedData(payload) => payload.encode(dst), LpMessage::ClientHello(data) => data.encode(dst), LpMessage::KKTRequest(payload) => payload.encode(dst), @@ -587,7 +573,7 @@ impl LpMessage { content.ensure_empty()?; Ok(LpMessage::Busy) } - MessageType::Handshake => Ok(LpMessage::Handshake(HandshakeData::decode(content)?)), + MessageType::Handshake => todo!(), MessageType::EncryptedData => Ok(LpMessage::EncryptedData( EncryptedDataPayload::decode(content)?, )), diff --git a/common/nym-lp/src/peer.rs b/common/nym-lp/src/peer.rs index 853edaeab4..ecd7bef158 100644 --- a/common/nym-lp/src/peer.rs +++ b/common/nym-lp/src/peer.rs @@ -20,7 +20,8 @@ use crate::psq::build_responder; /// encapsulating all the known information and keys. #[derive(Clone)] pub struct LpLocalPeer { - pub(crate) ciphersuite: Arc, + pub(crate) ciphersuite: Ciphersuite, + /// Local Ed25519 keys for PSQ authentication pub(crate) ed25519: Arc, @@ -43,7 +44,7 @@ impl LpLocalPeer { let initiator_x25519_keypair = DHKeyPair::from(initiator_libcrux_x25519_private_key); LpLocalPeer { - ciphersuite: Arc::new(ciphersuite), + ciphersuite, ed25519, x25519: Arc::new(initiator_x25519_keypair), kem_keypairs: Default::default(), @@ -78,18 +79,10 @@ impl LpLocalPeer { ); let mut expected_kem_key_digests = HashMap::new(); - - if let Some(mlkem_key) = &self.mlkem { + for (kem, kem_key) in &self.kem_keypairs { expected_kem_key_digests.insert( - KEM::MlKem768, - nym_kkt::key_utils::produce_key_digests(&mlkem_key.1.encode()), - ); - } - - if let Some(mceliece_key) = &self.mceliece { - expected_kem_key_digests.insert( - KEM::McEliece, - nym_kkt::key_utils::produce_key_digests(&mceliece_key.1.encode()), + *kem, + nym_kkt::key_utils::produce_key_digests(&kem_key.encoded_encapsulation_key()), ); } diff --git a/common/nym-lp/src/psq.rs b/common/nym-lp/src/psq.rs index 9a065b9322..5140d086a2 100644 --- a/common/nym-lp/src/psq.rs +++ b/common/nym-lp/src/psq.rs @@ -85,41 +85,31 @@ pub fn build_initiator<'a>( // which we already obtained matching on the ciphersuite kem type in `LpSession::new` pub fn build_responder<'a>( local_x25519_keys: &'a DHKeyPair, - local_kem_keys: &'a Arc, + local_kem_keys: &'a KemKeyPair, ) -> Responder<'a, rand09::rngs::ThreadRng> { - let responder_cbuilder = match ciphersuite.kem() { - KEM::MlKem768 => match (local_kem_decapsulation_key, local_kem_encapsulation_key) { - ( - DecapsulationKey::MlKem768(ml_kem_private_key), - EncapsulationKey::MlKem768(ml_kem_public_key), - ) => CiphersuiteBuilder::new( - CiphersuiteName::X25519_MLKEM768_X25519_CHACHA20POLY1305_HKDFSHA256, - ) - .longterm_mlkem_encapsulation_key(ml_kem_public_key) - .longterm_mlkem_decapsulation_key(ml_kem_private_key), - _ => panic!( - "wrong key type passed (local_kem_encapsulation_key should be EncapsulationKey::MlKem768 and local_kem_decapsulation_key should be DecapsulationKey::MlKem768)" - ), - }, - KEM::McEliece => match (local_kem_decapsulation_key, local_kem_encapsulation_key) { - ( - DecapsulationKey::McEliece(mceliece_private_key), - EncapsulationKey::McEliece(mceliece_public_key), - ) => CiphersuiteBuilder::new( - CiphersuiteName::X25519_CLASSICMCELIECE_X25519_CHACHA20POLY1305_HKDFSHA256, - ) - .longterm_cmc_encapsulation_key(mceliece_public_key) - .longterm_cmc_decapsulation_key(mceliece_private_key), - _ => panic!( - "wrong key type passed (local_kem_encapsulation_key should be EncapsulationKey::McEliece and local_kem_decapsulation_key should be DecapsulationKey::McEliece)" - ), - }, - _ => panic!("undefined"), - }; - let responder_ciphersuite = responder_cbuilder - .longterm_x25519_keys(local_x25519_keys) - .build_responder_ciphersuite() - .unwrap(); + let responder_ciphersuite = match local_kem_keys { + KemKeyPair::MlKem768 { + encapsulation_key, + decapsulation_key, + } => CiphersuiteBuilder::new( + CiphersuiteName::X25519_MLKEM768_X25519_CHACHA20POLY1305_HKDFSHA256, + ) + .longterm_mlkem_encapsulation_key(encapsulation_key) + .longterm_mlkem_decapsulation_key(decapsulation_key), + KemKeyPair::McEliece { + encapsulation_key, + decapsulation_key, + } => CiphersuiteBuilder::new( + CiphersuiteName::X25519_CLASSICMCELIECE_X25519_CHACHA20POLY1305_HKDFSHA256, + ) + .longterm_cmc_encapsulation_key(encapsulation_key) + .longterm_cmc_decapsulation_key(decapsulation_key), + KemKeyPair::XWing { .. } => panic!("unsupported"), + KemKeyPair::X25519 { .. } => panic!("unsupported"), + } + .longterm_x25519_keys(local_x25519_keys) + .build_responder_ciphersuite() + .unwrap(); PrincipalBuilder::new(rand09::rng()) .outer_aad(AAD_RESPONDER) diff --git a/common/nym-lp/src/session.rs b/common/nym-lp/src/session.rs index 2bb6c319fc..319db635d4 100644 --- a/common/nym-lp/src/session.rs +++ b/common/nym-lp/src/session.rs @@ -9,6 +9,7 @@ use crate::codec::OuterAeadKey; use crate::message::{EncryptedDataPayload, HandshakeData, PSQRequestData, PSQResponseData}; use std::fmt::Debug; +use std::ops::Deref; // noiserm use crate::noise_protocol::{NoiseError, NoiseProtocol, ReadResult}; use crate::packet::LpHeader; @@ -29,7 +30,7 @@ use libcrux_psq::{ use nym_crypto::asymmetric::{ed25519, x25519}; use nym_kkt::KKT_RESPONSE_AAD; use nym_kkt::carrier::Carrier; -use nym_kkt::ciphersuite::{Ciphersuite, DecapsulationKey, EncapsulationKey, KEM}; +use nym_kkt::ciphersuite::{Ciphersuite, DecapsulationKey, EncapsulationKey, KEM, KemKeyPair}; use nym_kkt::context::KKTContext; use nym_kkt::encryption::{ KKTSessionSecret, decrypt_initial_kkt_frame, decrypt_kkt_frame, encrypt_initial_kkt_frame, @@ -114,6 +115,18 @@ pub enum KKTState { }, } +impl KKTState { + pub fn carrier_mut(&mut self) -> Result<&mut Carrier, LpError> { + match &mut self { + KKTState::NotStarted | KKTState::InitiatorWaiting { .. } => { + Err(LpError::KKTError("incomplete KKT exchange".to_string())) + } + KKTState::Completed { carrier, .. } => Ok(carrier), + KKTState::ResponderProcessed { carrier } => Ok(carrier), + } + } +} + impl std::fmt::Debug for KKTState { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -188,16 +201,16 @@ impl<'a> std::fmt::Debug for PSQState<'a> { /// 4. Handshake completes, transport mode available /// 5. Transport operations (`encrypt_data`/`decrypt_data`) check `psk_injected` flag for safety pub struct LpSession<'a> { - id: u32, + id: [u8; 4], /// Flag indicating if this session acts as the Noise protocol initiator. is_initiator: bool, /// KKT (KEM Key Transfer) exchange state - kkt_state: Mutex, + kkt_state: KKTState, /// PSQ (Post-Quantum Secure PSK) handshake state - psq_state: Mutex>, + psq_state: PSQState<'a>, /// PSQ session psq_session: Mutex>, @@ -243,14 +256,14 @@ pub struct LpSession<'a> { negotiated_version: std::sync::atomic::AtomicU8, } -impl Debug for LpSession { +impl<'a> Debug for LpSession<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("LpSession") .field("id", &self.id) .field("is_initiator", &self.is_initiator) .field("kkt_state", &self.kkt_state) .field("psq_state", &self.psq_state) - .field("psq_session", &self.psq_session) + .field("psq_session", &"") .field("carrier", &self.carrier) .field("sending_counter", &self.sending_counter) .field("receiving_counter", &self.receiving_counter) @@ -267,7 +280,7 @@ impl Debug for LpSession { impl<'a> LpSession<'a> { pub fn id(&self) -> u32 { - self.id + u32::from_le_bytes(self.id) } /// Returns true if this session was created as the initiator. @@ -307,32 +320,13 @@ impl<'a> LpSession<'a> { } // can we do this without a clone? - pub fn local_kem_encapsulation_key(&self) -> Result { - Ok(match self.local_peer.ciphersuite.kem() { - KEM::MlKem768 => match &self.local_peer.mlkem { - Some(kp) => match **kp { - (DecapsulationKey::MlKem768(_), EncapsulationKey::MlKem768(_)) => kp.1.clone(), - _ => { - return Err(LpError::ResponderWithMissingKEMKey); - } - }, - None => return Err(LpError::ResponderWithMissingKEMKey), - }, - KEM::McEliece => match &self.local_peer.mceliece { - Some(kp) => match **kp { - (DecapsulationKey::McEliece(_), EncapsulationKey::McEliece(_)) => kp.1.clone(), - _ => { - return Err(LpError::ResponderWithMissingKEMKey); - } - }, - None => { - return Err(LpError::ResponderWithMissingKEMKey); - } - }, - kem => { - return Err(LpError::KKTError(format!("Unsupported KEM: {:?}", kem))); - } - }) + pub fn local_kem_keys(&self) -> Result<&KemKeyPair, LpError> { + let kem = self.local_peer.ciphersuite.kem(); + + self.local_peer + .kem_key(kem) + .ok_or_else(|| LpError::ResponderWithMissingKEMKey { kem }) + .map(|keys| keys.deref()) } /// Returns the remote X25519 public key. @@ -400,7 +394,7 @@ impl<'a> LpSession<'a> { pub fn new( id: u32, is_initiator: bool, - kkt_ciphersuite: &Ciphersuite, + kkt_ciphersuite: Ciphersuite, local_peer: LpLocalPeer, remote_peer: LpRemotePeer, ) -> Result { @@ -523,16 +517,14 @@ impl<'a> LpSession<'a> { /// * `Some(Ok(LpMessage::KKTRequest))` - KKT request ready to send /// * `Some(Err(LpError))` - Error creating KKT request /// * `None` - KKT not applicable (responder, or already completed) - pub fn prepare_kkt_request(&self) -> Option> { - let mut kkt_state = self.kkt_state.lock(); - + pub fn prepare_kkt_request(&mut self) -> Option> { // Only initiator creates KKT requests, and only when not started - if !self.is_initiator || !matches!(*kkt_state, KKTState::NotStarted) { + if !self.is_initiator || !matches!(self.kkt_state, KKTState::NotStarted) { return None; } let mut rng = rand09::rng(); - match anonymous_initiator_process(&mut rng, *self.local_peer.ciphersuite) { + match anonymous_initiator_process(&mut rng, self.local_peer.ciphersuite) { Ok((context, kkt_frame)) => { match encrypt_initial_kkt_frame( &mut rng, @@ -541,7 +533,7 @@ impl<'a> LpSession<'a> { ) { Ok((session_secret, encrypted_request_bytes)) => { // Store context for response validation - *kkt_state = KKTState::InitiatorWaiting { + self.kkt_state = KKTState::InitiatorWaiting { context, session_secret, }; @@ -596,11 +588,9 @@ impl<'a> LpSession<'a> { /// * `Ok(())` - KKT exchange completed, KEM key stored /// * `Err(LpError)` - Signature verification failed, hash mismatch, or invalid state /// - pub fn process_kkt_response(&self, encrypted_response_bytes: &[u8]) -> Result<(), LpError> { - let mut kkt_state = self.kkt_state.lock(); - + pub fn process_kkt_response(&mut self, encrypted_response_bytes: &[u8]) -> Result<(), LpError> { // Extract context from waiting state - let (mut context, session_secret) = match &*kkt_state { + let (mut context, session_secret) = match &self.kkt_state { KKTState::InitiatorWaiting { context, session_secret, @@ -629,29 +619,27 @@ impl<'a> LpSession<'a> { context.role(), &response_frame.session_id(), &self.remote_x25519_public(), - &remote_encapsulation_key, + &remote_encapsulation_key.encode(), )?; (initiator_carrier, remote_encapsulation_key) } Err(e) => { return Err(LpError::Internal(format!( - "KKT response handling failure: {:?}", - e + "KKT response handling failure: {e:?}", ))); } } } Err(e) => { return Err(LpError::Internal(format!( - "KKT response decryption failure: {:?}", - e + "KKT response decryption failure: {e:?}", ))); } }; // Store the authenticated KEM key - *kkt_state = KKTState::Completed { + self.kkt_state = KKTState::Completed { kem_pk: Box::new(remote_encapsulation_key), carrier: initiator_carrier, }; @@ -672,24 +660,23 @@ impl<'a> LpSession<'a> { /// /// * `Ok(LpMessage::KKTResponse)` - Signed KKT response ready to send /// * `Err(LpError)` - Signature verification failed or invalid request - pub fn process_kkt_request(&self, request_bytes: &[u8]) -> Result { + pub fn process_kkt_request(&mut self, request_bytes: &[u8]) -> Result { let mut rng = rand09::rng(); - let mut kkt_state = self.kkt_state.lock(); - let (session_secret, request_frame, remote_context) = decrypt_initial_kkt_frame(self.local_peer.x25519().sk(), request_bytes)?; let (mut context, _) = responder_ingest_message(&remote_context, None, None, &request_frame)?; - let local_kem_key: EncapsulationKey = self.local_kem_encapsulation_key()?; + let local_kem_keys = self.local_kem_keys()?; + let encoded_encapsulation_key = local_kem_keys.encoded_encapsulation_key(); let response_frame = responder_process( &mut context, request_frame.session_id(), self.local_peer.ed25519().private_key(), - &local_kem_key, + &encoded_encapsulation_key, )?; let response_bytes = @@ -700,12 +687,12 @@ impl<'a> LpSession<'a> { context.role(), &response_frame.session_id(), self.local_x25519_public(), - &local_kem_key, + &encoded_encapsulation_key, )?; // Mark KKT as processed // Responder doesn't store the kem_pk since they already have their own KEM keypair - *kkt_state = KKTState::ResponderProcessed { + self.kkt_state = KKTState::ResponderProcessed { carrier: responder_carrier, }; @@ -729,17 +716,14 @@ impl<'a> LpSession<'a> { /// /// * `None` if no message needs to be sent currently (e.g., waiting for peer, or handshake complete). /// * `Some(LpError)` if there's an error within the Noise protocol or PSQ. - pub fn prepare_handshake_message(&self) -> Option> { + pub fn prepare_handshake_message(&'a mut self) -> Option> { // PSQ always runs for initiator on first message - let mut psq_state = self.psq_state.lock(); - - if !self.is_initiator || !matches!(*psq_state, PSQState::NotStarted) { + if !self.is_initiator || !matches!(self.psq_state, PSQState::NotStarted) { return None; } // Extract KEM public key from completed KKT exchange // PSQ requires the authenticated KEM key obtained via KKT protocol - let kkt_state = self.kkt_state.lock(); - let (remote_kem, mut carrier) = match &*kkt_state { + let (remote_kem, carrier) = match &self.kkt_state { KKTState::Completed { kem_pk, carrier } => (kem_pk, carrier), _ => { return Some(Err(LpError::KKTError( @@ -749,25 +733,21 @@ impl<'a> LpSession<'a> { }; // Generate PSQ payload and PSK using KKT-authenticated KEM key - let session_context = self.id.to_le_bytes(); - let mut psq_initiator = build_initiator( &self.local_peer.ciphersuite, - &session_context, + &self.id, &self.local_peer.x25519, self.remote_x25519_public(), - &remote_kem, + remote_kem, ); let psq_request = initiator_process(&mut psq_initiator); let encrypted_psq_request = carrier.encrypt(&psq_request).unwrap(); - *psq_state = PSQState::InitiatorWaiting { + self.psq_state = PSQState::InitiatorWaiting { initiator: psq_initiator, }; - drop(psq_state); // Release lock - Some(Ok(LpMessage::PSQRequest(PSQRequestData( encrypted_psq_request, )))) @@ -919,7 +899,7 @@ impl<'a> LpSession<'a> { } /// Checks if the Noise handshake phase is complete. - pub fn is_handshake_complete(&self) -> bool { + pub fn is_handshake_complete(&'a self) -> bool { todo!() // self.noise_state.lock().is_handshake_finished() } @@ -928,7 +908,7 @@ impl<'a> LpSession<'a> { /// /// This is the raw KEM output from PSQ before Blake3 KDF combination. /// Used for deriving subsession PSKs to maintain PQ protection. - pub fn pq_shared_secret(&self) -> Option<[u8; 32]> { + pub fn pq_shared_secret(&'a self) -> Option<[u8; 32]> { todo!() // self.pq_shared_secret.lock().as_ref().map(|s| *s.as_bytes()) } @@ -1037,7 +1017,7 @@ impl<'a> LpSession<'a> { /// Test-only method to set KKT state to Completed with a mock KEM key. /// This allows tests to bypass KKT exchange and directly test PSQ handshake. #[cfg(test)] - pub(crate) fn set_kkt_completed_for_test(&self, remote_x25519_pub: &DHPublicKey) { + pub(crate) fn set_kkt_completed_for_test(&mut self, remote_x25519_pub: &DHPublicKey) { // Convert remote X25519 public key to EncapsulationKey for testing let remote_kem_bytes = remote_x25519_pub.as_ref(); let libcrux_public_key = @@ -1045,8 +1025,7 @@ impl<'a> LpSession<'a> { .expect("Test KEM key conversion failed"); let kem_pk = EncapsulationKey::X25519(libcrux_public_key); - let mut kkt_state = self.kkt_state.lock(); - *kkt_state = KKTState::Completed { + self.kkt_state = KKTState::Completed { kem_pk: Box::new(kem_pk), }; } diff --git a/common/nym-lp/src/session_manager.rs b/common/nym-lp/src/session_manager.rs index d1b2c6eece..26e5c2207d 100644 --- a/common/nym-lp/src/session_manager.rs +++ b/common/nym-lp/src/session_manager.rs @@ -11,8 +11,10 @@ use crate::peer::{LpLocalPeer, LpRemotePeer}; use crate::state_machine::{LpAction, LpInput, LpState, LpStateBare}; use crate::{LpError, LpMessage, LpSession, LpStateMachine}; use dashmap::DashMap; +use dashmap::mapref::one::{Ref, RefMut}; #[cfg(test)] use libcrux_psq::handshake::types::DHPublicKey; +use nym_kkt::ciphersuite::Ciphersuite; /// Manages the lifecycle of Lewes Protocol sessions. /// @@ -37,8 +39,14 @@ impl<'a> SessionManager<'a> { } } - pub fn process_input(&self, lp_id: u32, input: LpInput) -> Result, LpError> { - self.with_state_machine_mut(lp_id, |sm| sm.process_input(input).transpose())? + pub fn process_input( + &'a self, + lp_id: u32, + input: LpInput, + ) -> Result, LpError> { + self.state_machine_mut(lp_id)? + .process_input(input) + .transpose() } pub fn add(&self, session: LpSession<'a>) -> Result<(), LpError> { @@ -51,131 +59,170 @@ impl<'a> SessionManager<'a> { Ok(()) } - pub fn handshaking(&self, lp_id: u32) -> Result { + pub fn handshaking(&'a self, lp_id: u32) -> Result { Ok(self.get_state(lp_id)? == LpStateBare::Handshaking) } - pub fn should_initiate_handshake(&self, lp_id: u32) -> Result { + pub fn should_initiate_handshake(&'a self, lp_id: u32) -> Result { Ok(self.ready_to_handshake(lp_id)? || self.closed(lp_id)?) } - pub fn ready_to_handshake(&self, lp_id: u32) -> Result { + pub fn ready_to_handshake(&'a self, lp_id: u32) -> Result { Ok(self.get_state(lp_id)? == LpStateBare::ReadyToHandshake) } - pub fn closed(&self, lp_id: u32) -> Result { + pub fn closed(&'a self, lp_id: u32) -> Result { Ok(self.get_state(lp_id)? == LpStateBare::Closed) } - pub fn transport(&self, lp_id: u32) -> Result { + pub fn transport(&'a self, lp_id: u32) -> Result { Ok(self.get_state(lp_id)? == LpStateBare::Transport) } #[cfg(test)] - fn get_state_machine_id(&self, lp_id: u32) -> Result { - self.with_state_machine(lp_id, |sm| sm.id())? + fn get_state_machine_id(&'a self, lp_id: u32) -> Result { + self.state_machine(lp_id)?.id() } - pub fn get_state(&self, lp_id: u32) -> Result { - self.with_state_machine(lp_id, |sm| Ok(sm.bare_state()))? + pub fn get_state(&'a self, lp_id: u32) -> Result { + Ok(self.state_machine(lp_id)?.bare_state()) } - pub fn receiving_counter_quick_check(&self, lp_id: u32, counter: u64) -> Result<(), LpError> { - self.with_state_machine(lp_id, |sm| { - sm.session()?.receiving_counter_quick_check(counter) - })? + pub fn receiving_counter_quick_check( + &'a self, + lp_id: u32, + counter: u64, + ) -> Result<(), LpError> { + self.state_machine_mut(lp_id)? + .session()? + .receiving_counter_quick_check(counter) } - pub fn receiving_counter_mark(&self, lp_id: u32, counter: u64) -> Result<(), LpError> { - self.with_state_machine(lp_id, |sm| sm.session()?.receiving_counter_mark(counter))? + pub fn receiving_counter_mark(&'a self, lp_id: u32, counter: u64) -> Result<(), LpError> { + self.state_machine(lp_id)? + .session()? + .receiving_counter_mark(counter) } - pub fn start_handshake(&self, lp_id: u32) -> Option> { - self.prepare_handshake_message(lp_id) + // pub fn start_handshake(&'a self, lp_id: u32) -> Option> { + // self.prepare_handshake_message(lp_id) + // } + // + // pub fn prepare_handshake_message(&'a self, lp_id: u32) -> Option> { + // self.with_state_machine(lp_id, |sm| sm.session().ok()?.prepare_handshake_message()) + // .ok()? + // } + + pub fn is_handshake_complete(&'a self, lp_id: u32) -> Result { + Ok(self + .state_machine(lp_id)? + .session()? + .is_handshake_complete()) } - pub fn prepare_handshake_message(&self, lp_id: u32) -> Option> { - self.with_state_machine(lp_id, |sm| sm.session().ok()?.prepare_handshake_message()) - .ok()? + pub fn next_counter(&'a self, lp_id: u32) -> Result { + Ok(self.state_machine_mut(lp_id)?.session()?.next_counter()) } - pub fn is_handshake_complete(&self, lp_id: u32) -> Result { - self.with_state_machine(lp_id, |sm| Ok(sm.session()?.is_handshake_complete()))? + pub fn decrypt_data(&'a self, lp_id: u32, message: &LpMessage) -> Result, LpError> { + self.state_machine(lp_id)? + .session()? + .decrypt_data(message) + .map_err(LpError::NoiseError) } - pub fn next_counter(&self, lp_id: u32) -> Result { - self.with_state_machine(lp_id, |sm| Ok(sm.session()?.next_counter()))? + pub fn encrypt_data(&'a self, lp_id: u32, message: &[u8]) -> Result { + self.state_machine(lp_id)? + .session()? + .encrypt_data(message) + .map_err(LpError::NoiseError) } - pub fn decrypt_data(&self, lp_id: u32, message: &LpMessage) -> Result, LpError> { - self.with_state_machine(lp_id, |sm| { - sm.session()? - .decrypt_data(message) - .map_err(LpError::NoiseError) - })? - } - - pub fn encrypt_data(&self, lp_id: u32, message: &[u8]) -> Result { - self.with_state_machine(lp_id, |sm| { - sm.session()? - .encrypt_data(message) - .map_err(LpError::NoiseError) - })? - } - - pub fn current_packet_cnt(&self, lp_id: u32) -> Result<(u64, u64), LpError> { - self.with_state_machine(lp_id, |sm| Ok(sm.session()?.current_packet_cnt()))? + pub fn current_packet_cnt(&'a self, lp_id: u32) -> Result<(u64, u64), LpError> { + Ok(self.state_machine(lp_id)?.session()?.current_packet_cnt()) } pub fn process_handshake_message( - &self, + &'a self, lp_id: u32, message: &LpMessage, ) -> Result { - self.with_state_machine(lp_id, |sm| sm.session()?.process_handshake_message(message))? + self.state_machine(lp_id)? + .session()? + .process_handshake_message(message) } - pub fn session_count(&self) -> usize { + pub fn session_count(&'a self) -> usize { self.state_machines.len() } - pub fn state_machine_exists(&self, lp_id: u32) -> bool { + pub fn state_machine_exists(&'a self, lp_id: u32) -> bool { self.state_machines.contains_key(&lp_id) } - pub fn with_state_machine(&self, lp_id: u32, f: F) -> Result - where - F: FnOnce(&LpStateMachine) -> R, - { - if let Some(sm) = self.state_machines.get(&lp_id) { - Ok(f(&sm)) - } else { - Err(LpError::StateMachineNotFound { lp_id }) - } - // self.state_machines.get(&lp_id).map(|sm_ref| f(&*sm_ref)) // Lock held only during closure execution + // this method must NOT be used without some serious considerations, + // in particular the value MUST NOT be held across await points + // (even if the compiler is fine with it) + // as it could lead to a deadlock + #[doc(hidden)] + fn state_machine(&'a self, lp_id: u32) -> Result, LpError> { + self.state_machines + .get(&lp_id) + .ok_or_else(|| LpError::StateMachineNotFound { lp_id }) } - // For mutable access (like running process_input) - pub fn with_state_machine_mut(&self, lp_id: u32, f: F) -> Result - where - F: FnOnce(&mut LpStateMachine) -> R, // Closure takes mutable ref - { - if let Some(mut sm) = self.state_machines.get_mut(&lp_id) { - Ok(f(&mut sm)) - } else { - Err(LpError::StateMachineNotFound { lp_id }) - } + // this method must NOT be used without some serious considerations, + // in particular the value MUST NOT be held across await points + // (even if the compiler is fine with it) + // as it could lead to a deadlock + #[doc(hidden)] + fn state_machine_mut(&'a self, lp_id: u32) -> Result, LpError> { + self.state_machines + .get_mut(&lp_id) + .ok_or_else(|| LpError::StateMachineNotFound { lp_id }) } + // pub fn with_state_machine(&'a self, lp_id: u32, f: F) -> Result + // where + // F: FnOnce(&LpStateMachine) -> R, + // { + // if let Some(sm) = self.state_machines.get(&lp_id) { + // Ok(f(&sm)) + // } else { + // Err(LpError::StateMachineNotFound { lp_id }) + // } + // // self.state_machines.get(&lp_id).map(|sm_ref| f(&*sm_ref)) // Lock held only during closure execution + // } + // + // // For mutable access (like running process_input) + // pub fn with_state_machine_mut(&'a self, lp_id: u32, f: F) -> Result + // where + // F: FnOnce(&mut LpStateMachine) -> R, // Closure takes mutable ref + // { + // if let Some(mut sm) = self.state_machines.get_mut(&lp_id) { + // Ok(f(&mut sm)) + // } else { + // Err(LpError::StateMachineNotFound { lp_id }) + // } + // } + pub fn create_session_state_machine( &self, receiver_index: u32, is_initiator: bool, + ciphersuite: Ciphersuite, local_peer: LpLocalPeer, remote_peer: LpRemotePeer, salt: &[u8; 32], ) -> Result { - let sm = LpStateMachine::new(receiver_index, is_initiator, local_peer, remote_peer, salt)?; + let sm = LpStateMachine::new( + receiver_index, + is_initiator, + ciphersuite, + local_peer, + remote_peer, + salt, + )?; self.state_machines.insert(receiver_index, sm); Ok(receiver_index) @@ -196,10 +243,10 @@ impl<'a> SessionManager<'a> { lp_id: u32, remote_x25519_pub: &DHPublicKey, ) -> Result<(), LpError> { - self.with_state_machine(lp_id, |sm| { - sm.session()?.set_kkt_completed_for_test(remote_x25519_pub); - Ok(()) - })? + self.state_machine_mut(lp_id)? + .session()? + .set_kkt_completed_for_test(remote_x25519_pub); + Ok(()) } } diff --git a/common/nym-lp/src/state_machine.rs b/common/nym-lp/src/state_machine.rs index 29a165592c..03a07273a6 100644 --- a/common/nym-lp/src/state_machine.rs +++ b/common/nym-lp/src/state_machine.rs @@ -23,6 +23,7 @@ use crate::{ }; use bytes::{Buf, Bytes}; use num_enum::{IntoPrimitive, TryFromPrimitive}; +use nym_kkt::ciphersuite::Ciphersuite; use std::mem; use tracing::debug; @@ -259,19 +260,22 @@ impl<'a> LpStateMachine<'a> { pub fn new( receiver_index: u32, is_initiator: bool, + ciphersuite: Ciphersuite, local_peer: LpLocalPeer, remote_peer: LpRemotePeer, salt: &[u8; 32], ) -> Result { // Create the session with both Ed25519 (for PSQ auth) and derived X25519 keys (for Noise) // receiver_index is client-proposed, passed through directly - let session = LpSession::new(receiver_index, is_initiator, local_peer, remote_peer, salt)?; - Ok(LpStateMachine { - state: LpState::ReadyToHandshake { - session: Box::new(session), - }, - }) + todo!() + // let session = LpSession::new(receiver_index, is_initiator,ciphersuite, local_peer, remote_peer, salt)?; + // + // Ok(LpStateMachine { + // state: LpState::ReadyToHandshake { + // session: Box::new(session), + // }, + // }) } /// Creates a state machine in Transport state from a completed subsession handshake. @@ -300,7 +304,10 @@ impl<'a> LpStateMachine<'a> { } /// Processes an input event and returns a list of actions to perform. - pub fn process_input(&mut self, input: LpInput) -> Option> { + pub fn process_input<'b: 'a>( + &'b mut self, + input: LpInput, + ) -> Option> { // 1. Replace current state with a placeholder, taking ownership of the real current state. let current_state = mem::take(&mut self.state); @@ -309,7 +316,7 @@ impl<'a> LpStateMachine<'a> { // 2. Match on the owned current_state. Each arm calculates and returns the NEXT state. let next_state = match (current_state, input) { // --- ReadyToHandshake State --- - (LpState::ReadyToHandshake { session }, LpInput::StartHandshake) => { + (LpState::ReadyToHandshake { mut session }, LpInput::StartHandshake) => { if session.is_initiator() { // Initiator starts by requesting KEM key via KKT match session.prepare_kkt_request() { @@ -349,7 +356,7 @@ impl<'a> LpStateMachine<'a> { } // --- KKTExchange State --- - (LpState::KKTExchange { session }, LpInput::ReceivePacket(packet)) => { + (LpState::KKTExchange { mut session }, LpInput::ReceivePacket(packet)) => { // Check if packet lp_id matches our session if packet.header.receiver_idx() != session.id() { result_action = Some(Err(LpError::UnknownSessionId(packet.header.receiver_idx()))); @@ -429,7 +436,7 @@ impl<'a> LpStateMachine<'a> { } // --- Handshaking State --- - (LpState::Handshaking { session }, LpInput::ReceivePacket(packet)) => { + (LpState::Handshaking { mut session }, LpInput::ReceivePacket(packet)) => { // Check if packet lp_id matches our session if packet.header.receiver_idx() != session.id() { result_action = Some(Err(LpError::UnknownSessionId(packet.header.receiver_idx())));