wip
This commit is contained in:
Generated
+8
-204
@@ -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
@@ -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",
|
||||
]
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)?,
|
||||
)),
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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())));
|
||||
|
||||
Reference in New Issue
Block a user