This commit is contained in:
Jędrzej Stuczyński
2026-01-29 12:05:04 +00:00
parent d1acd5b591
commit 261a36e792
11 changed files with 334 additions and 493 deletions
Generated
+8 -204
View File
@@ -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"
+1 -1
View File
@@ -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",
]
+17 -31
View File
@@ -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<Self, KKTError> {
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<Vec<u8>, KKTError> {
pub fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>, 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<Vec<u8>, KKTError> {
pub fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, 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)
}
+71 -22
View File
@@ -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<Algorithm, KKTError> {
}
}
#[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<u8> {
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<MlKem768KeyPair> 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<libcrux_psq::classic_mceliece::KeyPair> 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),
// }
}
}
+4 -4
View File
@@ -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<KKTFrame, KKTError> {
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(
+12 -26
View File
@@ -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)?,
)),
+6 -13
View File
@@ -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<Ciphersuite>,
pub(crate) ciphersuite: Ciphersuite,
/// Local Ed25519 keys for PSQ authentication
pub(crate) ed25519: Arc<ed25519::KeyPair>,
@@ -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()),
);
}
+24 -34
View File
@@ -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<KemKeyPair>,
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)
+54 -75
View File
@@ -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<KKTState>,
kkt_state: KKTState,
/// PSQ (Post-Quantum Secure PSK) handshake state
psq_state: Mutex<PSQState<'a>>,
psq_state: PSQState<'a>,
/// PSQ session
psq_session: Mutex<Option<Session>>,
@@ -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", &"<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<EncapsulationKey, LpError> {
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<Self, LpError> {
@@ -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<Result<LpMessage, LpError>> {
let mut kkt_state = self.kkt_state.lock();
pub fn prepare_kkt_request(&mut self) -> Option<Result<LpMessage, LpError>> {
// 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<LpMessage, LpError> {
pub fn process_kkt_request(&mut self, request_bytes: &[u8]) -> Result<LpMessage, LpError> {
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<Result<LpMessage, LpError>> {
pub fn prepare_handshake_message(&'a mut self) -> Option<Result<LpMessage, LpError>> {
// 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),
};
}
+120 -73
View File
@@ -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<Option<LpAction>, 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<Option<LpAction>, 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<bool, LpError> {
pub fn handshaking(&'a self, lp_id: u32) -> Result<bool, LpError> {
Ok(self.get_state(lp_id)? == LpStateBare::Handshaking)
}
pub fn should_initiate_handshake(&self, lp_id: u32) -> Result<bool, LpError> {
pub fn should_initiate_handshake(&'a self, lp_id: u32) -> Result<bool, LpError> {
Ok(self.ready_to_handshake(lp_id)? || self.closed(lp_id)?)
}
pub fn ready_to_handshake(&self, lp_id: u32) -> Result<bool, LpError> {
pub fn ready_to_handshake(&'a self, lp_id: u32) -> Result<bool, LpError> {
Ok(self.get_state(lp_id)? == LpStateBare::ReadyToHandshake)
}
pub fn closed(&self, lp_id: u32) -> Result<bool, LpError> {
pub fn closed(&'a self, lp_id: u32) -> Result<bool, LpError> {
Ok(self.get_state(lp_id)? == LpStateBare::Closed)
}
pub fn transport(&self, lp_id: u32) -> Result<bool, LpError> {
pub fn transport(&'a self, lp_id: u32) -> Result<bool, LpError> {
Ok(self.get_state(lp_id)? == LpStateBare::Transport)
}
#[cfg(test)]
fn get_state_machine_id(&self, lp_id: u32) -> Result<u32, LpError> {
self.with_state_machine(lp_id, |sm| sm.id())?
fn get_state_machine_id(&'a self, lp_id: u32) -> Result<u32, LpError> {
self.state_machine(lp_id)?.id()
}
pub fn get_state(&self, lp_id: u32) -> Result<LpStateBare, LpError> {
self.with_state_machine(lp_id, |sm| Ok(sm.bare_state()))?
pub fn get_state(&'a self, lp_id: u32) -> Result<LpStateBare, LpError> {
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<Result<LpMessage, LpError>> {
self.prepare_handshake_message(lp_id)
// pub fn start_handshake(&'a self, lp_id: u32) -> Option<Result<LpMessage, LpError>> {
// self.prepare_handshake_message(lp_id)
// }
//
// pub fn prepare_handshake_message(&'a self, lp_id: u32) -> Option<Result<LpMessage, LpError>> {
// 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<bool, LpError> {
Ok(self
.state_machine(lp_id)?
.session()?
.is_handshake_complete())
}
pub fn prepare_handshake_message(&self, lp_id: u32) -> Option<Result<LpMessage, LpError>> {
self.with_state_machine(lp_id, |sm| sm.session().ok()?.prepare_handshake_message())
.ok()?
pub fn next_counter(&'a self, lp_id: u32) -> Result<u64, LpError> {
Ok(self.state_machine_mut(lp_id)?.session()?.next_counter())
}
pub fn is_handshake_complete(&self, lp_id: u32) -> Result<bool, LpError> {
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<Vec<u8>, LpError> {
self.state_machine(lp_id)?
.session()?
.decrypt_data(message)
.map_err(LpError::NoiseError)
}
pub fn next_counter(&self, lp_id: u32) -> Result<u64, LpError> {
self.with_state_machine(lp_id, |sm| Ok(sm.session()?.next_counter()))?
pub fn encrypt_data(&'a self, lp_id: u32, message: &[u8]) -> Result<LpMessage, LpError> {
self.state_machine(lp_id)?
.session()?
.encrypt_data(message)
.map_err(LpError::NoiseError)
}
pub fn decrypt_data(&self, lp_id: u32, message: &LpMessage) -> Result<Vec<u8>, 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<LpMessage, LpError> {
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<ReadResult, LpError> {
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<F, R>(&self, lp_id: u32, f: F) -> Result<R, LpError>
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<Ref<u32, LpStateMachine>, 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<F, R>(&self, lp_id: u32, f: F) -> Result<R, LpError>
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<RefMut<u32, LpStateMachine>, LpError> {
self.state_machines
.get_mut(&lp_id)
.ok_or_else(|| LpError::StateMachineNotFound { lp_id })
}
// pub fn with_state_machine<F, R>(&'a self, lp_id: u32, f: F) -> Result<R, LpError>
// 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<F, R>(&'a self, lp_id: u32, f: F) -> Result<R, LpError>
// 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<u32, LpError> {
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(())
}
}
+17 -10
View File
@@ -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<Self, LpError> {
// 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<Result<LpAction, LpError>> {
pub fn process_input<'b: 'a>(
&'b mut self,
input: LpInput,
) -> Option<Result<LpAction, LpError>> {
// 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())));