1
0
mirror of synced 2025-03-01 07:50:38 +00:00

Just use priv/pubkey as Node ID in the mock mix message encoding (#912)

* Just use priv/pubkey as Node ID in the mock mix message encoding

* do not convert private key to public key in mix service
This commit is contained in:
Youngjoon Lee 2024-11-08 08:14:34 +07:00 committed by GitHub
parent 1c62ced9ea
commit 7b984a4e29
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 32 additions and 38 deletions

View File

@ -3,21 +3,20 @@ use crate::{Error, MixMessage};
//
/// A mock implementation of the Sphinx encoding.
const PRIVATE_KEY_SIZE: usize = 32;
const PUBLIC_KEY_SIZE: usize = 32;
const NODE_ID_SIZE: usize = 32;
const PADDED_PAYLOAD_SIZE: usize = 2048;
const PAYLOAD_PADDING_SEPARATOR: u8 = 0x01;
const PAYLOAD_PADDING_SEPARATOR_SIZE: usize = 1;
const MAX_LAYERS: usize = 5;
pub const MESSAGE_SIZE: usize = PUBLIC_KEY_SIZE * MAX_LAYERS + PADDED_PAYLOAD_SIZE;
pub const MESSAGE_SIZE: usize = NODE_ID_SIZE * MAX_LAYERS + PADDED_PAYLOAD_SIZE;
#[derive(Clone, Debug)]
pub struct MockMixMessage;
impl MixMessage for MockMixMessage {
type PublicKey = [u8; PUBLIC_KEY_SIZE];
type PrivateKey = [u8; PRIVATE_KEY_SIZE];
type PublicKey = [u8; NODE_ID_SIZE];
type PrivateKey = [u8; NODE_ID_SIZE];
const DROP_MESSAGE: &'static [u8] = &[0; MESSAGE_SIZE];
/// The length of the encoded message is fixed to [`MESSAGE_SIZE`] bytes.
@ -25,7 +24,9 @@ impl MixMessage for MockMixMessage {
/// The payload is zero-padded to the end.
///
fn build_message(payload: &[u8], public_keys: &[Self::PublicKey]) -> Result<Vec<u8>, Error> {
if public_keys.is_empty() || public_keys.len() > MAX_LAYERS {
// In this mock, we don't encrypt anything. So, we use public key as just a node ID.
let node_ids = public_keys;
if node_ids.is_empty() || node_ids.len() > MAX_LAYERS {
return Err(Error::InvalidNumberOfLayers);
}
if payload.len() > PADDED_PAYLOAD_SIZE - PAYLOAD_PADDING_SEPARATOR_SIZE {
@ -34,11 +35,11 @@ impl MixMessage for MockMixMessage {
let mut message: Vec<u8> = Vec::with_capacity(MESSAGE_SIZE);
public_keys.iter().for_each(|public_key| {
message.extend(public_key);
node_ids.iter().for_each(|node_id| {
message.extend(node_id);
});
// If there is any remaining layers, fill them with zeros.
(0..MAX_LAYERS - public_keys.len()).for_each(|_| message.extend(&[0; PUBLIC_KEY_SIZE]));
(0..MAX_LAYERS - node_ids.len()).for_each(|_| message.extend(&[0; NODE_ID_SIZE]));
// Append payload with padding
message.extend(payload);
@ -58,16 +59,15 @@ impl MixMessage for MockMixMessage {
return Err(Error::InvalidMixMessage);
}
let public_key =
x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(*private_key))
.to_bytes();
if message[0..PUBLIC_KEY_SIZE] != public_key {
// In this mock, we don't decrypt anything. So, we use private key as just a node ID.
let node_id = private_key;
if &message[0..NODE_ID_SIZE] != node_id {
return Err(Error::MsgUnwrapNotAllowed);
}
// If this is the last layer
if message[PUBLIC_KEY_SIZE..PUBLIC_KEY_SIZE * 2] == [0; PUBLIC_KEY_SIZE] {
let padded_payload = &message[PUBLIC_KEY_SIZE * MAX_LAYERS..];
if message[NODE_ID_SIZE..NODE_ID_SIZE * 2] == [0; NODE_ID_SIZE] {
let padded_payload = &message[NODE_ID_SIZE * MAX_LAYERS..];
// remove the payload padding
match padded_payload
.iter()
@ -81,9 +81,9 @@ impl MixMessage for MockMixMessage {
}
let mut new_message: Vec<u8> = Vec::with_capacity(MESSAGE_SIZE);
new_message.extend(&message[PUBLIC_KEY_SIZE..PUBLIC_KEY_SIZE * MAX_LAYERS]);
new_message.extend(&[0; PUBLIC_KEY_SIZE]);
new_message.extend(&message[PUBLIC_KEY_SIZE * MAX_LAYERS..]); // padded payload
new_message.extend(&message[NODE_ID_SIZE..NODE_ID_SIZE * MAX_LAYERS]);
new_message.extend(&[0; NODE_ID_SIZE]);
new_message.extend(&message[NODE_ID_SIZE * MAX_LAYERS..]); // padded payload
Ok((new_message, false))
}
}
@ -94,31 +94,23 @@ mod tests {
#[test]
fn message() {
let private_keys = [
x25519_dalek::StaticSecret::random(),
x25519_dalek::StaticSecret::random(),
x25519_dalek::StaticSecret::random(),
];
let public_keys = private_keys
.iter()
.map(|k| x25519_dalek::PublicKey::from(k).to_bytes())
.collect::<Vec<_>>();
let node_ids = (0..3).map(|i| [i; NODE_ID_SIZE]).collect::<Vec<_>>();
let payload = [7; 10];
let message = MockMixMessage::build_message(&payload, &public_keys).unwrap();
let message = MockMixMessage::build_message(&payload, &node_ids).unwrap();
assert_eq!(message.len(), MESSAGE_SIZE);
let (message, is_fully_unwrapped) =
MockMixMessage::unwrap_message(&message, &private_keys[0].to_bytes()).unwrap();
MockMixMessage::unwrap_message(&message, &node_ids[0]).unwrap();
assert!(!is_fully_unwrapped);
assert_eq!(message.len(), MESSAGE_SIZE);
let (message, is_fully_unwrapped) =
MockMixMessage::unwrap_message(&message, &private_keys[1].to_bytes()).unwrap();
MockMixMessage::unwrap_message(&message, &node_ids[1]).unwrap();
assert!(!is_fully_unwrapped);
assert_eq!(message.len(), MESSAGE_SIZE);
let (unwrapped_payload, is_fully_unwrapped) =
MockMixMessage::unwrap_message(&message, &private_keys[2].to_bytes()).unwrap();
MockMixMessage::unwrap_message(&message, &node_ids[2]).unwrap();
assert!(is_fully_unwrapped);
assert_eq!(unwrapped_payload, payload);
}

View File

@ -337,7 +337,9 @@ pub fn new_mix_configs(listening_addresses: Vec<Multiaddr>) -> Vec<TestMixSettin
.iter()
.map(|(backend, private_key)| Node {
address: backend.listening_address.clone(),
public_key: x25519_dalek::PublicKey::from(private_key).to_bytes(),
// We use private key as a public key because the `MockMixMessage` doesn't differentiate between them.
// TODO: Convert private key to public key properly once the real MixMessage is implemented.
public_key: private_key.to_bytes(),
})
.collect::<Vec<_>>();

View File

@ -20,7 +20,6 @@ serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["macros", "sync"] }
tokio-stream = "0.1"
tracing = "0.1"
x25519-dalek = { version = "2", features = ["getrandom", "static_secrets"] }
[features]
default = []

View File

@ -228,10 +228,9 @@ pub struct MixConfig<BackendSettings> {
impl<BackendSettings> MixConfig<BackendSettings> {
fn membership(&self) -> Membership<MockMixMessage> {
let public_key = x25519_dalek::PublicKey::from(&x25519_dalek::StaticSecret::from(
self.message_blend.cryptographic_processor.private_key,
))
.to_bytes();
// We use private key as a public key because the `MockMixMessage` doesn't differentiate between them.
// TODO: Convert private key to public key properly once the real MixMessage is implemented.
let public_key = self.message_blend.cryptographic_processor.private_key;
Membership::new(self.membership.clone(), public_key)
}
}

View File

@ -51,7 +51,9 @@ fn mix_nodes(configs: &[GeneralMixConfig]) -> Vec<Node<<MockMixMessage as MixMes
.iter()
.map(|config| Node {
address: config.backend.listening_address.clone(),
public_key: x25519_dalek::PublicKey::from(&config.private_key).to_bytes(),
// We use private key as a public key because the `MockMixMessage` doesn't differentiate between them.
// TODO: Convert private key to public key properly once the real MixMessage is implemented.
public_key: config.private_key.to_bytes(),
})
.collect()
}