changed ClientHelloData serialisation

the old variant using bincode did not produce constant-length output in some cases
This commit is contained in:
Jędrzej Stuczyński
2026-01-07 15:21:39 +00:00
parent c7cb17d7cf
commit 50fc7a8fbb
2 changed files with 38 additions and 14 deletions
+5 -7
View File
@@ -111,9 +111,7 @@ fn parse_message_from_type_and_content(
content.to_vec(),
))),
MessageType::ClientHello => {
let data: ClientHelloData = lp_bincode_serializer()
.deserialize(content)
.map_err(|e| LpError::DeserializationError(e.to_string()))?;
let data = ClientHelloData::decode(content)?;
Ok(LpMessage::ClientHello(data))
}
MessageType::KKTRequest => Ok(LpMessage::KKTRequest(KKTRequestData(content.to_vec()))),
@@ -791,7 +789,7 @@ mod tests {
}
#[test]
fn test_parse_client_hello_malformed_bincode() {
fn test_parse_client_hello_malformed_data() {
// Create a buffer with ClientHello message type but invalid bincode data
let mut buf = BytesMut::new();
buf.extend_from_slice(&[1, 0, 0, 0]); // Version + reserved
@@ -799,15 +797,15 @@ mod tests {
buf.extend_from_slice(&123u64.to_le_bytes()); // Counter
buf.extend_from_slice(&MessageType::ClientHello.to_u32().to_le_bytes()); // ClientHello type
// Add malformed bincode data (random bytes that won't deserialize to ClientHelloData)
buf.extend_from_slice(&[0xFF; 50]); // Invalid bincode data
// Add data that does not equal to ClientHelloData::LEN
buf.extend_from_slice(&[0xFF; 50]); // invalid data
buf.extend_from_slice(&[0; TRAILER_LEN]); // Trailer
// Attempt to parse
let result = parse_lp_packet(&buf, None);
assert!(result.is_err());
match result {
Err(LpError::DeserializationError(_)) => {} // Expected error
Err(LpError::DeserializationError(msg)) => {} // Expected error
Err(e) => panic!("Expected DeserializationError, got {:?}", e),
Ok(_) => panic!("Expected error, but got Ok"),
}
+33 -7
View File
@@ -1,6 +1,7 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::LpError;
use crate::serialisation::{BincodeOptions, lp_bincode_serializer};
use bytes::{BufMut, BytesMut};
use num_enum::{IntoPrimitive, TryFromPrimitive};
@@ -22,6 +23,8 @@ pub struct ClientHelloData {
}
impl ClientHelloData {
pub const LEN: usize = 100;
/// Generates a new ClientHelloData with fresh salt.
///
/// Salt format: 8 bytes timestamp (u64 LE) + 24 bytes random nonce
@@ -61,6 +64,33 @@ impl ClientHelloData {
timestamp_bytes.copy_from_slice(&self.salt[..8]);
u64::from_le_bytes(timestamp_bytes)
}
pub fn encode(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(Self::LEN);
out.put_u32_le(self.receiver_index);
out.put_slice(&self.client_lp_public_key);
out.put_slice(&self.client_ed25519_public_key);
out.put_slice(&self.salt);
out
}
pub fn decode(b: &[u8]) -> Result<Self, LpError> {
if b.len() != Self::LEN {
return Err(LpError::DeserializationError(format!(
"Expected {} bytes to deserialise ClientHelloData. got {}",
Self::LEN,
b.len()
)));
}
// SAFETY: we checked for valid byte lengths
#[allow(clippy::unwrap_used)]
Ok(ClientHelloData {
receiver_index: u32::from_le_bytes([b[0], b[1], b[2], b[3]]),
client_lp_public_key: b[4..36].try_into().unwrap(),
client_ed25519_public_key: b[36..68].try_into().unwrap(),
salt: b[68..].try_into().unwrap(),
})
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)]
@@ -238,8 +268,8 @@ impl LpMessage {
LpMessage::Busy => 0,
LpMessage::Handshake(payload) => payload.0.len(),
LpMessage::EncryptedData(payload) => payload.0.len(),
// 4 bytes receiver_index + 32 bytes x25519 key + 32 bytes ed25519 key + 32 bytes salt + bincode overhead
LpMessage::ClientHello(_) => 101,
// 4 bytes receiver_index + 32 bytes x25519 key + 32 bytes ed25519 key + 32 bytes salt
LpMessage::ClientHello(_) => ClientHelloData::LEN,
LpMessage::KKTRequest(payload) => payload.0.len(),
LpMessage::KKTResponse(payload) => payload.0.len(),
LpMessage::ForwardPacket(data) => {
@@ -286,11 +316,7 @@ impl LpMessage {
dst.put_slice(&payload.0);
}
LpMessage::ClientHello(data) => {
// Serialize ClientHelloData using bincode
let serialized = lp_bincode_serializer()
.serialize(data)
.expect("Failed to serialize ClientHelloData");
dst.put_slice(&serialized);
dst.put_slice(&data.encode());
}
LpMessage::KKTRequest(payload) => {
dst.put_slice(&payload.0);