Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 342883fcbe | |||
| 61a0ee5a19 | |||
| 3956109c7e | |||
| 8d725b13c5 | |||
| 4d166c389b | |||
| 145c3c1223 | |||
| cbd654d6fd | |||
| e7be91a94c | |||
| 582e7d566a | |||
| 6464da5f01 | |||
| d5e77e499b | |||
| f086f9c35a |
@@ -69,7 +69,7 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --workspace --release --all
|
||||
args: --workspace --release --all --features cpucycles
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
|
||||
Generated
+8
-27
@@ -3809,8 +3809,9 @@ dependencies = [
|
||||
"curve25519-dalek",
|
||||
"fastrand",
|
||||
"getrandom 0.2.8",
|
||||
"rand 0.7.3",
|
||||
"rayon",
|
||||
"sphinx-packet 0.1.0 (git+https://github.com/nymtech/sphinx.git)",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -4061,6 +4062,7 @@ dependencies = [
|
||||
"nym-sphinx-addressing",
|
||||
"nym-sphinx-params",
|
||||
"nym-sphinx-types",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4088,7 +4090,9 @@ dependencies = [
|
||||
name = "nym-sphinx-types"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"sphinx-packet 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nym-outfox",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4202,7 +4206,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-vesting-contract"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
dependencies = [
|
||||
"cosmwasm-derive",
|
||||
"cosmwasm-std",
|
||||
@@ -4220,7 +4224,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-vesting-contract-common"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"nym-contracts-common",
|
||||
@@ -5889,29 +5893,6 @@ dependencies = [
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sphinx-packet"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/nymtech/sphinx.git#ca107d94360cdf8bbfbdb12fe5320ed74f80e40c"
|
||||
dependencies = [
|
||||
"aes 0.7.5",
|
||||
"arrayref",
|
||||
"blake2",
|
||||
"bs58",
|
||||
"byteorder",
|
||||
"chacha",
|
||||
"curve25519-dalek",
|
||||
"digest 0.9.0",
|
||||
"hkdf 0.11.0",
|
||||
"hmac 0.11.0",
|
||||
"lioness",
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"rand_distr",
|
||||
"sha2 0.9.9",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
|
||||
@@ -16,6 +16,7 @@ use nym_client_core::client::received_buffer::{
|
||||
};
|
||||
use nym_client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::TaskManager;
|
||||
use nym_validator_client::nyxd::QueryNyxdClient;
|
||||
@@ -119,6 +120,7 @@ impl SocketClient {
|
||||
self_address,
|
||||
shared_lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
None,
|
||||
);
|
||||
|
||||
websocket::Listener::new(config.get_listening_ip(), config.get_listening_port())
|
||||
@@ -178,7 +180,10 @@ impl SocketClient {
|
||||
Ok(started_client.task_manager)
|
||||
}
|
||||
|
||||
pub async fn start_direct(self) -> Result<DirectClient, ClientError> {
|
||||
pub async fn start_direct(
|
||||
self,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Result<DirectClient, ClientError> {
|
||||
if self.config.get_socket_type().is_websocket() {
|
||||
return Err(ClientError::InvalidSocketMode);
|
||||
}
|
||||
@@ -224,6 +229,7 @@ impl SocketClient {
|
||||
reconstructed_receiver,
|
||||
address,
|
||||
shutdown_notifier: started_client.task_manager,
|
||||
packet_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -237,6 +243,7 @@ pub struct DirectClient {
|
||||
|
||||
// we need to keep reference to this guy otherwise things will start dropping
|
||||
shutdown_notifier: TaskManager,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl DirectClient {
|
||||
@@ -257,7 +264,7 @@ impl DirectClient {
|
||||
/// well enough in local tests)
|
||||
pub async fn send_regular_message(&mut self, recipient: Recipient, message: Vec<u8>) {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||
|
||||
self.client_input
|
||||
.input_sender
|
||||
@@ -276,7 +283,8 @@ impl DirectClient {
|
||||
reply_surbs: u32,
|
||||
) {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||
let input_msg =
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||
|
||||
self.client_input
|
||||
.input_sender
|
||||
@@ -290,7 +298,7 @@ impl DirectClient {
|
||||
/// well enough in local tests)
|
||||
pub async fn send_reply(&mut self, recipient_tag: AnonymousSenderTag, message: Vec<u8>) {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane);
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane, self.packet_type);
|
||||
|
||||
self.client_input
|
||||
.input_sender
|
||||
|
||||
@@ -14,6 +14,7 @@ use nym_client_core::client::{
|
||||
use nym_client_websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::connections::{
|
||||
ConnectionCommand, ConnectionCommandSender, ConnectionId, LaneQueueLengths, TransmissionLane,
|
||||
@@ -41,6 +42,7 @@ pub(crate) struct HandlerBuilder {
|
||||
self_full_address: Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl HandlerBuilder {
|
||||
@@ -51,6 +53,7 @@ impl HandlerBuilder {
|
||||
self_full_address: &Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
Self {
|
||||
msg_input,
|
||||
@@ -59,6 +62,7 @@ impl HandlerBuilder {
|
||||
self_full_address: *self_full_address,
|
||||
lane_queue_lengths,
|
||||
reply_controller_sender,
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +77,7 @@ impl HandlerBuilder {
|
||||
received_response_type: Default::default(),
|
||||
lane_queue_lengths: self.lane_queue_lengths.clone(),
|
||||
reply_controller_sender: self.reply_controller_sender.clone(),
|
||||
packet_type: self.packet_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,6 +91,7 @@ pub(crate) struct Handler {
|
||||
received_response_type: ReceivedResponseType,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
reply_controller_sender: ReplyControllerSender,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl Drop for Handler {
|
||||
@@ -160,7 +166,7 @@ impl Handler {
|
||||
});
|
||||
|
||||
// the ack control is now responsible for chunking, etc.
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
@@ -191,7 +197,8 @@ impl Handler {
|
||||
TransmissionLane::ConnectionId(id)
|
||||
});
|
||||
|
||||
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||
let input_msg =
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
@@ -218,7 +225,7 @@ impl Handler {
|
||||
TransmissionLane::ConnectionId(id)
|
||||
});
|
||||
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane);
|
||||
let input_msg = InputMessage::new_reply(recipient_tag, message, lane, self.packet_type);
|
||||
self.msg_input
|
||||
.send(input_msg)
|
||||
.await
|
||||
|
||||
@@ -15,6 +15,7 @@ use nym_client_core::client::{inbound_messages::InputMessage, key_manager::KeyMa
|
||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use nym_task::TaskManager;
|
||||
use rand::rngs::OsRng;
|
||||
@@ -35,6 +36,7 @@ pub struct NymClient {
|
||||
// even though we don't use graceful shutdowns, other components rely on existence of this struct
|
||||
// and if it's dropped, everything will start going offline
|
||||
_task_manager: TaskManager,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@@ -52,6 +54,7 @@ pub struct NymClientBuilder {
|
||||
bandwidth_controller:
|
||||
Option<BandwidthController<FakeClient<DirectSigningNyxdClient>, EphemeralStorage>>,
|
||||
disabled_credentials: bool,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
@@ -66,6 +69,7 @@ impl NymClientBuilder {
|
||||
on_message,
|
||||
bandwidth_controller: None,
|
||||
disabled_credentials: true,
|
||||
packet_type: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +143,7 @@ impl NymClientBuilder {
|
||||
self_address,
|
||||
client_input: Arc::new(client_input),
|
||||
_task_manager: started_client.task_manager,
|
||||
packet_type: self.packet_type,
|
||||
}))
|
||||
})
|
||||
}
|
||||
@@ -190,7 +195,7 @@ impl NymClient {
|
||||
};
|
||||
let lane = TransmissionLane::General;
|
||||
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane);
|
||||
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
|
||||
self.client_input.send_message(input_msg)
|
||||
}
|
||||
|
||||
@@ -219,7 +224,8 @@ impl NymClient {
|
||||
};
|
||||
let lane = TransmissionLane::General;
|
||||
|
||||
let input_msg = InputMessage::new_anonymous(recipient, message, reply_surbs, lane);
|
||||
let input_msg =
|
||||
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
|
||||
self.client_input.send_message(input_msg)
|
||||
}
|
||||
|
||||
@@ -239,7 +245,7 @@ impl NymClient {
|
||||
};
|
||||
let lane = TransmissionLane::General;
|
||||
|
||||
let input_msg = InputMessage::new_reply(sender_tag, message, lane);
|
||||
let input_msg = InputMessage::new_reply(sender_tag, message, lane, self.packet_type);
|
||||
self.client_input.send_message(input_msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +400,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// controller for sending sphinx packets to mixnet (either real traffic or cover traffic)
|
||||
// controller for sending packets to mixnet (either real traffic or cover traffic)
|
||||
// TODO: if we want to send control messages to gateway_client, this CAN'T take the ownership
|
||||
// over it. Perhaps GatewayClient needs to be thread-shareable or have some channel for
|
||||
// requests?
|
||||
@@ -515,11 +515,11 @@ where
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
|
||||
// The sphinx_message_sender is the transmitter for any component generating sphinx packets
|
||||
// The message_sender is the transmitter for any component generating sphinx packets
|
||||
// that are to be sent to the mixnet. They are used by cover traffic stream and real
|
||||
// traffic stream.
|
||||
// The MixTrafficController then sends the actual traffic
|
||||
let sphinx_message_sender =
|
||||
let message_sender =
|
||||
Self::start_mix_traffic_controller(gateway_client, task_manager.subscribe());
|
||||
|
||||
// Channels that the websocket listener can use to signal downstream to the real traffic
|
||||
@@ -541,7 +541,7 @@ where
|
||||
shared_topology_accessor.clone(),
|
||||
ack_receiver,
|
||||
input_receiver,
|
||||
sphinx_message_sender.clone(),
|
||||
message_sender.clone(),
|
||||
reply_storage,
|
||||
reply_controller_sender.clone(),
|
||||
reply_controller_receiver,
|
||||
@@ -560,7 +560,7 @@ where
|
||||
self.key_manager.ack_key(),
|
||||
self_address,
|
||||
shared_topology_accessor.clone(),
|
||||
sphinx_message_sender,
|
||||
message_sender,
|
||||
task_manager.subscribe(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ where
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
next_delay: Pin<Box<wasm_timer::Delay>>,
|
||||
|
||||
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||
/// Channel used for sending prepared nym packets to `MixTrafficController` that sends them
|
||||
/// out to the network without any further delays.
|
||||
mix_tx: BatchMixMessageSender,
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
|
||||
pub type InputMessageSender = tokio::sync::mpsc::Sender<InputMessage>;
|
||||
@@ -41,14 +42,36 @@ pub enum InputMessage {
|
||||
data: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
},
|
||||
|
||||
MessageWrapper {
|
||||
message: Box<InputMessage>,
|
||||
packet_type: PacketType,
|
||||
},
|
||||
}
|
||||
|
||||
impl InputMessage {
|
||||
pub fn new_regular(recipient: Recipient, data: Vec<u8>, lane: TransmissionLane) -> Self {
|
||||
InputMessage::Regular {
|
||||
pub fn new_wrapper(message: InputMessage, packet_type: PacketType) -> Self {
|
||||
InputMessage::MessageWrapper {
|
||||
message: Box::new(message),
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_regular(
|
||||
recipient: Recipient,
|
||||
data: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
let message = InputMessage::Regular {
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
};
|
||||
if let Some(packet_type) = packet_type {
|
||||
InputMessage::new_wrapper(message, packet_type)
|
||||
} else {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,12 +80,18 @@ impl InputMessage {
|
||||
data: Vec<u8>,
|
||||
reply_surbs: u32,
|
||||
lane: TransmissionLane,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
InputMessage::Anonymous {
|
||||
let message = InputMessage::Anonymous {
|
||||
recipient,
|
||||
data,
|
||||
reply_surbs,
|
||||
lane,
|
||||
};
|
||||
if let Some(packet_type) = packet_type {
|
||||
InputMessage::new_wrapper(message, packet_type)
|
||||
} else {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,11 +99,17 @@ impl InputMessage {
|
||||
recipient_tag: AnonymousSenderTag,
|
||||
data: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
InputMessage::Reply {
|
||||
let message = InputMessage::Reply {
|
||||
recipient_tag,
|
||||
data,
|
||||
lane,
|
||||
};
|
||||
if let Some(packet_type) = packet_type {
|
||||
InputMessage::new_wrapper(message, packet_type)
|
||||
} else {
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +118,7 @@ impl InputMessage {
|
||||
InputMessage::Regular { lane, .. }
|
||||
| InputMessage::Anonymous { lane, .. }
|
||||
| InputMessage::Reply { lane, .. } => lane,
|
||||
InputMessage::MessageWrapper { message, .. } => message.lane(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,15 +39,15 @@ where
|
||||
pub fn new(
|
||||
gateway_client: GatewayClient<C, St>,
|
||||
) -> (MixTrafficController<C, St>, BatchMixMessageSender) {
|
||||
let (sphinx_message_sender, sphinx_message_receiver) =
|
||||
let (message_sender, message_receiver) =
|
||||
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
|
||||
(
|
||||
MixTrafficController {
|
||||
gateway_client,
|
||||
mix_rx: sphinx_message_receiver,
|
||||
mix_rx: message_receiver,
|
||||
consecutive_gateway_failure_count: 0,
|
||||
},
|
||||
sphinx_message_sender,
|
||||
message_sender,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+41
-4
@@ -7,6 +7,7 @@ use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||
use log::*;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use rand::{CryptoRng, Rng};
|
||||
|
||||
@@ -57,10 +58,11 @@ where
|
||||
recipient: Recipient,
|
||||
content: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
if let Err(err) = self
|
||||
.message_handler
|
||||
.try_send_plain_message(recipient, content, lane)
|
||||
.try_send_plain_message(recipient, content, lane, packet_type)
|
||||
.await
|
||||
{
|
||||
warn!("failed to send a plain message - {err}")
|
||||
@@ -73,10 +75,11 @@ where
|
||||
content: Vec<u8>,
|
||||
reply_surbs: u32,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) {
|
||||
if let Err(err) = self
|
||||
.message_handler
|
||||
.try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane)
|
||||
.try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane, packet_type)
|
||||
.await
|
||||
{
|
||||
warn!("failed to send a repliable message - {err}")
|
||||
@@ -89,14 +92,17 @@ where
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
} => self.handle_plain_message(recipient, data, lane).await,
|
||||
} => {
|
||||
self.handle_plain_message(recipient, data, lane, PacketType::Mix)
|
||||
.await
|
||||
}
|
||||
InputMessage::Anonymous {
|
||||
recipient,
|
||||
data,
|
||||
reply_surbs,
|
||||
lane,
|
||||
} => {
|
||||
self.handle_repliable_message(recipient, data, reply_surbs, lane)
|
||||
self.handle_repliable_message(recipient, data, reply_surbs, lane, PacketType::Mix)
|
||||
.await
|
||||
}
|
||||
InputMessage::Reply {
|
||||
@@ -106,6 +112,37 @@ where
|
||||
} => {
|
||||
self.handle_reply(recipient_tag, data, lane).await;
|
||||
}
|
||||
InputMessage::MessageWrapper {
|
||||
message,
|
||||
packet_type,
|
||||
} => match *message {
|
||||
InputMessage::Regular {
|
||||
recipient,
|
||||
data,
|
||||
lane,
|
||||
} => {
|
||||
self.handle_plain_message(recipient, data, lane, packet_type)
|
||||
.await
|
||||
}
|
||||
InputMessage::Anonymous {
|
||||
recipient,
|
||||
data,
|
||||
reply_surbs,
|
||||
lane,
|
||||
} => {
|
||||
self.handle_repliable_message(recipient, data, reply_surbs, lane, packet_type)
|
||||
.await
|
||||
}
|
||||
InputMessage::Reply {
|
||||
recipient_tag,
|
||||
data,
|
||||
lane,
|
||||
} => {
|
||||
self.handle_reply(recipient_tag, data, lane).await;
|
||||
}
|
||||
// MessageWrappers can't be nested
|
||||
InputMessage::MessageWrapper { .. } => unimplemented!(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -11,9 +11,9 @@ use crate::client::real_messages_control::real_traffic_stream::RealMessage;
|
||||
use crate::client::replies::reply_controller::ReplyControllerSender;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::chunking::fragment::Fragment;
|
||||
use nym_sphinx::preparer::PreparedFragment;
|
||||
use nym_sphinx::{addressing::clients::Recipient, params::PacketType};
|
||||
use nym_task::connections::TransmissionLane;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::sync::{Arc, Weak};
|
||||
@@ -51,8 +51,10 @@ where
|
||||
) -> Result<PreparedFragment, PreparationError> {
|
||||
debug!("retransmitting normal packet...");
|
||||
|
||||
// TODO: Figure out retransmission packet type signaling
|
||||
|
||||
self.message_handler
|
||||
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data)
|
||||
.try_prepare_single_chunk_for_sending(packet_recipient, chunk_data, PacketType::Mix)
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ use nym_sphinx::anonymous_replies::requests::{AnonymousSenderTag, RepliableMessa
|
||||
use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey};
|
||||
use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
|
||||
use nym_sphinx::message::NymMessage;
|
||||
use nym_sphinx::params::{PacketSize, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx::params::{PacketSize, PacketType, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
|
||||
use nym_sphinx::Delay;
|
||||
use nym_task::connections::TransmissionLane;
|
||||
@@ -406,9 +406,10 @@ where
|
||||
recipient: Recipient,
|
||||
message: Vec<u8>,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(), PreparationError> {
|
||||
let message = NymMessage::new_plain(message);
|
||||
self.try_split_and_send_non_reply_message(message, recipient, lane)
|
||||
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -417,6 +418,7 @@ where
|
||||
message: NymMessage,
|
||||
recipient: Recipient,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(), PreparationError> {
|
||||
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised
|
||||
debug_assert!(!matches!(message, NymMessage::Reply(_)));
|
||||
@@ -442,6 +444,7 @@ where
|
||||
topology,
|
||||
&self.config.ack_key,
|
||||
&recipient,
|
||||
packet_type,
|
||||
)?;
|
||||
|
||||
let real_message =
|
||||
@@ -463,6 +466,7 @@ where
|
||||
&mut self,
|
||||
recipient: Recipient,
|
||||
amount: u32,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(), PreparationError> {
|
||||
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
||||
let (reply_surbs, reply_keys) =
|
||||
@@ -477,6 +481,7 @@ where
|
||||
message,
|
||||
recipient,
|
||||
TransmissionLane::AdditionalReplySurbs,
|
||||
packet_type,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -492,6 +497,7 @@ where
|
||||
message: Vec<u8>,
|
||||
num_reply_surbs: u32,
|
||||
lane: TransmissionLane,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(), SurbWrappedPreparationError> {
|
||||
let sender_tag = self.get_or_create_sender_tag(&recipient);
|
||||
let (reply_surbs, reply_keys) = self
|
||||
@@ -501,7 +507,7 @@ where
|
||||
let message =
|
||||
NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs));
|
||||
|
||||
self.try_split_and_send_non_reply_message(message, recipient, lane)
|
||||
self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
|
||||
.await?;
|
||||
|
||||
log::trace!("storing {} reply keys", reply_keys.len());
|
||||
@@ -514,13 +520,20 @@ where
|
||||
&mut self,
|
||||
recipient: Recipient,
|
||||
chunk: Fragment,
|
||||
packet_type: PacketType,
|
||||
) -> Result<PreparedFragment, PreparationError> {
|
||||
let topology_permit = self.topology_access.get_read_permit().await;
|
||||
let topology = self.get_topology(&topology_permit)?;
|
||||
|
||||
let prepared_fragment = self
|
||||
.message_preparer
|
||||
.prepare_chunk_for_sending(chunk, topology, &self.config.ack_key, &recipient)
|
||||
.prepare_chunk_for_sending(
|
||||
chunk,
|
||||
topology,
|
||||
&self.config.ack_key,
|
||||
&recipient,
|
||||
packet_type,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Ok(prepared_fragment)
|
||||
|
||||
@@ -92,7 +92,7 @@ where
|
||||
// messages.
|
||||
sending_delay_controller: SendingDelayController,
|
||||
|
||||
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||
/// Channel used for sending prepared packets to `MixTrafficController` that sends them
|
||||
/// out to the network without any further delays.
|
||||
mix_tx: BatchMixMessageSender,
|
||||
|
||||
@@ -136,7 +136,7 @@ impl From<PreparedFragment> for RealMessage {
|
||||
|
||||
impl RealMessage {
|
||||
pub(crate) fn packet_size(&self) -> usize {
|
||||
self.mix_packet.sphinx_packet().len()
|
||||
self.mix_packet.packet().len()
|
||||
}
|
||||
|
||||
pub(crate) fn new(mix_packet: MixPacket, fragment_id: FragmentIdentifier) -> Self {
|
||||
@@ -386,7 +386,7 @@ where
|
||||
|
||||
// On every iteration we get new messages from upstream. Given that these come bunched
|
||||
// in `Vec`, this ensures that on average we will fetch messages faster than we can
|
||||
// send, which is a condition for being able to multiplex sphinx packets from multiple
|
||||
// send, which is a condition for being able to multiplex packets from multiple
|
||||
// data streams.
|
||||
match Pin::new(&mut self.real_receiver).poll_recv(cx) {
|
||||
// in the case our real message channel stream was closed, we should also indicate we are closed
|
||||
|
||||
@@ -512,7 +512,11 @@ where
|
||||
let to_send = min(remaining, 100);
|
||||
if let Err(err) = self
|
||||
.message_handler
|
||||
.try_send_additional_reply_surbs(recipient, to_send)
|
||||
.try_send_additional_reply_surbs(
|
||||
recipient,
|
||||
to_send,
|
||||
nym_sphinx::params::PacketType::Mix,
|
||||
)
|
||||
.await
|
||||
{
|
||||
warn!("failed to send additional surbs to {recipient} - {err}");
|
||||
|
||||
@@ -28,7 +28,7 @@ impl SizedData for RealMessage {
|
||||
|
||||
impl SizedData for Fragment {
|
||||
fn data_size(&self) -> usize {
|
||||
// note that raw `Fragment` is smaller than sphinx packet payload
|
||||
// note that raw `Fragment` is smaller than packet payload
|
||||
// as it doesn't include surb-ack or the [shared] key materials
|
||||
self.payload_size()
|
||||
}
|
||||
|
||||
@@ -605,7 +605,7 @@ where
|
||||
fn estimate_required_bandwidth(&self, packets: &[MixPacket]) -> i64 {
|
||||
packets
|
||||
.iter()
|
||||
.map(|packet| packet.sphinx_packet().len())
|
||||
.map(|packet| packet.packet().len())
|
||||
.sum::<usize>() as i64
|
||||
}
|
||||
|
||||
@@ -686,9 +686,9 @@ where
|
||||
if !self.authenticated {
|
||||
return Err(GatewayClientError::NotAuthenticated);
|
||||
}
|
||||
if (mix_packet.sphinx_packet().len() as i64) > self.bandwidth_remaining {
|
||||
if (mix_packet.packet().len() as i64) > self.bandwidth_remaining {
|
||||
return Err(GatewayClientError::NotEnoughBandwidth(
|
||||
mix_packet.sphinx_packet().len() as i64,
|
||||
mix_packet.packet().len() as i64,
|
||||
self.bandwidth_remaining,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::*;
|
||||
use nym_sphinx::framing::codec::SphinxCodec;
|
||||
use nym_sphinx::framing::packet::FramedSphinxPacket;
|
||||
use nym_sphinx::params::PacketMode;
|
||||
use nym_sphinx::{addressing::nodes::NymNodeRoutingAddress, SphinxPacket};
|
||||
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
|
||||
use nym_sphinx::framing::codec::NymCodec;
|
||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::NymPacket;
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::net::SocketAddr;
|
||||
@@ -50,8 +51,8 @@ pub trait SendWithoutResponse {
|
||||
fn send_without_response(
|
||||
&mut self,
|
||||
address: NymNodeRoutingAddress,
|
||||
packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
) -> io::Result<()>;
|
||||
}
|
||||
|
||||
@@ -61,12 +62,12 @@ pub struct Client {
|
||||
}
|
||||
|
||||
struct ConnectionSender {
|
||||
channel: mpsc::Sender<FramedSphinxPacket>,
|
||||
channel: mpsc::Sender<FramedNymPacket>,
|
||||
current_reconnection_attempt: Arc<AtomicU32>,
|
||||
}
|
||||
|
||||
impl ConnectionSender {
|
||||
fn new(channel: mpsc::Sender<FramedSphinxPacket>) -> Self {
|
||||
fn new(channel: mpsc::Sender<FramedNymPacket>) -> Self {
|
||||
ConnectionSender {
|
||||
channel,
|
||||
current_reconnection_attempt: Arc::new(AtomicU32::new(0)),
|
||||
@@ -84,7 +85,7 @@ impl Client {
|
||||
|
||||
async fn manage_connection(
|
||||
address: SocketAddr,
|
||||
receiver: mpsc::Receiver<FramedSphinxPacket>,
|
||||
receiver: mpsc::Receiver<FramedNymPacket>,
|
||||
connection_timeout: Duration,
|
||||
current_reconnection: &AtomicU32,
|
||||
) {
|
||||
@@ -96,7 +97,7 @@ impl Client {
|
||||
debug!("Managed to establish connection to {}", address);
|
||||
// if we managed to connect, reset the reconnection count (whatever it might have been)
|
||||
current_reconnection.store(0, Ordering::Release);
|
||||
Framed::new(stream, SphinxCodec)
|
||||
Framed::new(stream, NymCodec)
|
||||
}
|
||||
Err(err) => {
|
||||
debug!(
|
||||
@@ -148,11 +149,7 @@ impl Client {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_connection(
|
||||
&mut self,
|
||||
address: NymNodeRoutingAddress,
|
||||
pending_packet: FramedSphinxPacket,
|
||||
) {
|
||||
fn make_connection(&mut self, address: NymNodeRoutingAddress, pending_packet: FramedNymPacket) {
|
||||
let (mut sender, receiver) = mpsc::channel(self.config.maximum_connection_buffer_size);
|
||||
|
||||
// this CAN'T fail because we just created the channel which has a non-zero capacity
|
||||
@@ -200,12 +197,12 @@ impl SendWithoutResponse for Client {
|
||||
fn send_without_response(
|
||||
&mut self,
|
||||
address: NymNodeRoutingAddress,
|
||||
packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
) -> io::Result<()> {
|
||||
trace!("Sending packet to {:?}", address);
|
||||
let framed_packet =
|
||||
FramedSphinxPacket::new(packet, packet_mode, self.config.use_legacy_version);
|
||||
FramedNymPacket::new(packet, packet_type, self.config.use_legacy_version);
|
||||
|
||||
if let Some(sender) = self.conn_new.get_mut(&address) {
|
||||
if let Err(err) = sender.channel.try_send(framed_packet) {
|
||||
|
||||
@@ -59,14 +59,14 @@ impl PacketForwarder {
|
||||
trace!("Going to forward packet to {:?}", mix_packet.next_hop());
|
||||
|
||||
let next_hop = mix_packet.next_hop();
|
||||
let packet_mode = mix_packet.packet_mode();
|
||||
let sphinx_packet = mix_packet.into_sphinx_packet();
|
||||
let packet_type = mix_packet.packet_type();
|
||||
let packet = mix_packet.into_packet();
|
||||
// we don't care about responses, we just want to fire packets
|
||||
// as quickly as possible
|
||||
|
||||
if let Err(err) =
|
||||
self.mixnet_client
|
||||
.send_without_response(next_hop, sphinx_packet, packet_mode)
|
||||
.send_without_response(next_hop, packet, packet_type)
|
||||
{
|
||||
debug!("failed to forward the packet - {err}")
|
||||
}
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAckRecoveryError;
|
||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddressError;
|
||||
use nym_sphinx_types::Error as SphinxError;
|
||||
use nym_sphinx_types::{NymPacketError, SphinxError};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum MixProcessingError {
|
||||
#[error("failed to process received packet: {0}")]
|
||||
NymPacketProcessingError(#[from] NymPacketError),
|
||||
|
||||
#[error("failed to process received sphinx packet: {0}")]
|
||||
SphinxProcessingError(#[from] SphinxError),
|
||||
|
||||
#[error("the forward hop address was malformed: {0}")]
|
||||
|
||||
@@ -7,11 +7,11 @@ use log::*;
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
use nym_sphinx_framing::packet::FramedSphinxPacket;
|
||||
use nym_sphinx_params::{PacketMode, PacketSize};
|
||||
use nym_sphinx_framing::packet::FramedNymPacket;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use nym_sphinx_types::{
|
||||
Delay as SphinxDelay, DestinationAddressBytes, NodeAddressBytes, Payload, PrivateKey,
|
||||
ProcessedPacket, SphinxPacket,
|
||||
Delay as SphinxDelay, DestinationAddressBytes, NodeAddressBytes, NymPacket, Payload,
|
||||
PrivateKey, ProcessedPacket,
|
||||
};
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
@@ -53,14 +53,14 @@ impl SphinxPacketProcessor {
|
||||
feature = "cpucycles",
|
||||
instrument(skip(self, packet), fields(cpucycles))
|
||||
)]
|
||||
fn perform_initial_sphinx_packet_processing(
|
||||
fn perform_initial_packet_processing(
|
||||
&self,
|
||||
packet: SphinxPacket,
|
||||
packet: NymPacket,
|
||||
) -> Result<ProcessedPacket, MixProcessingError> {
|
||||
measure!({
|
||||
packet.process(&self.sphinx_key).map_err(|err| {
|
||||
debug!("Failed to unwrap Sphinx packet: {err}");
|
||||
MixProcessingError::SphinxProcessingError(err)
|
||||
MixProcessingError::NymPacketProcessingError(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -72,17 +72,12 @@ impl SphinxPacketProcessor {
|
||||
)]
|
||||
fn perform_initial_unwrapping(
|
||||
&self,
|
||||
received: FramedSphinxPacket,
|
||||
received: FramedNymPacket,
|
||||
) -> Result<ProcessedPacket, MixProcessingError> {
|
||||
measure!({
|
||||
let packet_mode = received.packet_mode();
|
||||
let sphinx_packet = received.into_inner();
|
||||
let packet = received.into_inner();
|
||||
|
||||
if packet_mode.is_old_vpn() {
|
||||
return Err(MixProcessingError::ReceivedOldTypeVpnPacket);
|
||||
}
|
||||
|
||||
self.perform_initial_sphinx_packet_processing(sphinx_packet)
|
||||
self.perform_initial_packet_processing(packet)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -90,14 +85,14 @@ impl SphinxPacketProcessor {
|
||||
/// and packs all the data in a way that can be easily sent to the next hop.
|
||||
fn process_forward_hop(
|
||||
&self,
|
||||
packet: SphinxPacket,
|
||||
packet: NymPacket,
|
||||
forward_address: NodeAddressBytes,
|
||||
delay: SphinxDelay,
|
||||
packet_mode: PacketMode,
|
||||
packet_type: PacketType,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
let next_hop_address = NymNodeRoutingAddress::try_from(forward_address)?;
|
||||
|
||||
let mix_packet = MixPacket::new(next_hop_address, packet, packet_mode);
|
||||
let mix_packet = MixPacket::new(next_hop_address, packet, packet_type);
|
||||
Ok(MixProcessingResult::ForwardHop(mix_packet, Some(delay)))
|
||||
}
|
||||
|
||||
@@ -124,21 +119,25 @@ impl SphinxPacketProcessor {
|
||||
&self,
|
||||
data: Vec<u8>,
|
||||
packet_size: PacketSize,
|
||||
packet_mode: PacketMode,
|
||||
packet_type: PacketType,
|
||||
) -> Result<(Option<MixPacket>, Vec<u8>), MixProcessingError> {
|
||||
match packet_size {
|
||||
PacketSize::AckPacket => {
|
||||
PacketSize::AckPacket | PacketSize::OutfoxAckPacket => {
|
||||
trace!("received an ack packet!");
|
||||
Ok((None, data))
|
||||
}
|
||||
PacketSize::RegularPacket
|
||||
| PacketSize::ExtendedPacket8
|
||||
| PacketSize::ExtendedPacket16
|
||||
| PacketSize::ExtendedPacket32 => {
|
||||
| PacketSize::ExtendedPacket32
|
||||
| PacketSize::OutfoxRegularPacket
|
||||
| PacketSize::OutfoxExtendedPacket8
|
||||
| PacketSize::OutfoxExtendedPacket16
|
||||
| PacketSize::OutfoxExtendedPacket32 => {
|
||||
trace!("received a normal packet!");
|
||||
let (ack_data, message) = self.split_hop_data_into_ack_and_message(data)?;
|
||||
let (ack_first_hop, ack_packet) = SurbAck::try_recover_first_hop_packet(&ack_data)?;
|
||||
let forward_ack = MixPacket::new(ack_first_hop, ack_packet, packet_mode);
|
||||
let forward_ack = MixPacket::new(ack_first_hop, ack_packet, packet_type);
|
||||
Ok((Some(forward_ack), message))
|
||||
}
|
||||
}
|
||||
@@ -152,12 +151,12 @@ impl SphinxPacketProcessor {
|
||||
destination: DestinationAddressBytes,
|
||||
payload: Payload,
|
||||
packet_size: PacketSize,
|
||||
packet_mode: PacketMode,
|
||||
packet_type: PacketType,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
let packet_message = payload.recover_plaintext()?;
|
||||
|
||||
let (forward_ack, message) =
|
||||
self.split_into_ack_and_message(packet_message, packet_size, packet_mode)?;
|
||||
self.split_into_ack_and_message(packet_message, packet_size, packet_type)?;
|
||||
|
||||
Ok(MixProcessingResult::FinalHop(ProcessedFinalHop {
|
||||
destination,
|
||||
@@ -172,16 +171,16 @@ impl SphinxPacketProcessor {
|
||||
&self,
|
||||
packet: ProcessedPacket,
|
||||
packet_size: PacketSize,
|
||||
packet_mode: PacketMode,
|
||||
packet_type: PacketType,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
match packet {
|
||||
ProcessedPacket::ForwardHop(packet, address, delay) => {
|
||||
self.process_forward_hop(*packet, address, delay, packet_mode)
|
||||
self.process_forward_hop(NymPacket::Sphinx(*packet), address, delay, packet_type)
|
||||
}
|
||||
// right now there's no use for the surb_id included in the header - probably it should get removed from the
|
||||
// sphinx all together?
|
||||
ProcessedPacket::FinalHop(destination, _, payload) => {
|
||||
self.process_final_hop(destination, payload, packet_size, packet_mode)
|
||||
self.process_final_hop(destination, payload, packet_size, packet_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,19 +191,19 @@ impl SphinxPacketProcessor {
|
||||
)]
|
||||
pub fn process_received(
|
||||
&self,
|
||||
received: FramedSphinxPacket,
|
||||
received: FramedNymPacket,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
// explicit packet size will help to correctly parse final hop
|
||||
measure!({
|
||||
let packet_size = received.packet_size();
|
||||
let packet_mode = received.packet_mode();
|
||||
let packet_type = received.packet_type();
|
||||
|
||||
// unwrap the sphinx packet and if possible and appropriate, cache keys
|
||||
let processed_packet = self.perform_initial_unwrapping(received)?;
|
||||
|
||||
// for forward packets, extract next hop and set delay (but do NOT delay here)
|
||||
// for final packets, extract SURBAck
|
||||
self.perform_final_processing(processed_packet, packet_size, packet_mode)
|
||||
self.perform_final_processing(processed_packet, packet_size, packet_type)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,8 @@ use nym_sphinx_addressing::nodes::{
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::DEFAULT_NUM_MIX_HOPS;
|
||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||
use nym_sphinx_types::Error as SphinxError;
|
||||
use nym_sphinx_types::{
|
||||
delays::{self, Delay},
|
||||
SphinxPacket,
|
||||
};
|
||||
use nym_sphinx_types::delays::{self, Delay};
|
||||
use nym_sphinx_types::{NymPacket, NymPacketError};
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::convert::TryFrom;
|
||||
@@ -22,7 +19,7 @@ use std::time;
|
||||
use thiserror::Error;
|
||||
|
||||
pub struct SurbAck {
|
||||
surb_ack_packet: SphinxPacket,
|
||||
surb_ack_packet: NymPacket,
|
||||
first_hop_address: NymNodeRoutingAddress,
|
||||
expected_total_delay: Delay,
|
||||
}
|
||||
@@ -35,8 +32,8 @@ pub enum SurbAckRecoveryError {
|
||||
#[error("could not extract first hop address information - {0}")]
|
||||
InvalidAddress(#[from] NymNodeRoutingAddressError),
|
||||
|
||||
#[error("the contained sphinx packet was not correctly formed - {0}")]
|
||||
InvalidSphinxPacket(#[from] SphinxError),
|
||||
#[error("packet: {0}")]
|
||||
NymPacket(#[from] NymPacketError),
|
||||
}
|
||||
|
||||
impl SurbAck {
|
||||
@@ -58,10 +55,12 @@ impl SurbAck {
|
||||
|
||||
let surb_ack_payload = prepare_identifier(rng, ack_key, marshaled_fragment_id);
|
||||
|
||||
let surb_ack_packet = SphinxPacketBuilder::new()
|
||||
.with_payload_size(PacketSize::AckPacket.payload_size())
|
||||
.build_packet(surb_ack_payload, &route, &destination, &delays)
|
||||
.unwrap();
|
||||
let surb_ack_packet = NymPacket::Sphinx(
|
||||
SphinxPacketBuilder::new()
|
||||
.with_payload_size(PacketSize::AckPacket.payload_size())
|
||||
.build_packet(surb_ack_payload, &route, &destination, &delays)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// in our case, the last hop is a gateway that does NOT do any delays
|
||||
let expected_total_delay = delays.iter().take(delays.len() - 1).sum();
|
||||
@@ -85,21 +84,21 @@ impl SurbAck {
|
||||
self.expected_total_delay
|
||||
}
|
||||
|
||||
pub fn prepare_for_sending(self) -> (Delay, Vec<u8>) {
|
||||
pub fn prepare_for_sending(self) -> Result<(Delay, Vec<u8>), SurbAckRecoveryError> {
|
||||
// SURB_FIRST_HOP || SURB_ACK
|
||||
let surb_bytes: Vec<_> = self
|
||||
.first_hop_address
|
||||
.as_zero_padded_bytes(MAX_NODE_ADDRESS_UNPADDED_LEN)
|
||||
.into_iter()
|
||||
.chain(self.surb_ack_packet.to_bytes().into_iter())
|
||||
.chain(self.surb_ack_packet.to_bytes()?.into_iter())
|
||||
.collect();
|
||||
(self.expected_total_delay, surb_bytes)
|
||||
Ok((self.expected_total_delay, surb_bytes))
|
||||
}
|
||||
|
||||
// partial reciprocal of `prepare_for_sending` performed by the gateway
|
||||
pub fn try_recover_first_hop_packet(
|
||||
b: &[u8],
|
||||
) -> Result<(NymNodeRoutingAddress, SphinxPacket), SurbAckRecoveryError> {
|
||||
) -> Result<(NymNodeRoutingAddress, NymPacket), SurbAckRecoveryError> {
|
||||
if b.len() != Self::len() {
|
||||
Err(SurbAckRecoveryError::InvalidPacketSize {
|
||||
received: b.len(),
|
||||
@@ -111,7 +110,7 @@ impl SurbAck {
|
||||
// TODO: this will be variable once/if we decide to introduce optimization described
|
||||
// in common/nymsphinx/chunking/src/lib.rs:available_plaintext_size()
|
||||
let address_offset = MAX_NODE_ADDRESS_UNPADDED_LEN;
|
||||
let packet = SphinxPacket::from_bytes(&b[address_offset..])?;
|
||||
let packet = NymPacket::sphinx_from_bytes(&b[address_offset..])?;
|
||||
|
||||
Ok((address, packet))
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use nym_sphinx_addressing::clients::Recipient;
|
||||
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN};
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::{ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx_types::{delays, Error as SphinxError, SURBMaterial, SphinxPacket, SURB};
|
||||
use nym_sphinx_types::{delays, NymPacket, SURBMaterial, SphinxError, SURB};
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use serde::de::{Error as SerdeError, Visitor};
|
||||
@@ -173,7 +173,7 @@ impl ReplySurb {
|
||||
self,
|
||||
message: M,
|
||||
packet_size: PacketSize,
|
||||
) -> Result<(SphinxPacket, NymNodeRoutingAddress), ReplySurbError> {
|
||||
) -> Result<(NymPacket, NymNodeRoutingAddress), ReplySurbError> {
|
||||
let message_bytes = message.as_ref();
|
||||
if message_bytes.len() != packet_size.plaintext_size() {
|
||||
return Err(ReplySurbError::UnpaddedMessageError);
|
||||
@@ -187,6 +187,6 @@ impl ReplySurb {
|
||||
|
||||
let first_hop_address = NymNodeRoutingAddress::try_from(first_hop).unwrap();
|
||||
|
||||
Ok((packet, first_hop_address))
|
||||
Ok((NymPacket::Sphinx(packet), first_hop_address))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use nym_crypto::shared_key::new_ephemeral_shared_key;
|
||||
use nym_crypto::symmetric::stream_cipher;
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||
use nym_sphinx_acknowledgements::surb_ack::{SurbAck, SurbAckRecoveryError};
|
||||
use nym_sphinx_acknowledgements::AckKey;
|
||||
use nym_sphinx_addressing::clients::Recipient;
|
||||
use nym_sphinx_addressing::nodes::NymNodeRoutingAddress;
|
||||
@@ -11,10 +11,10 @@ use nym_sphinx_chunking::fragment::COVER_FRAG_ID;
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::{
|
||||
PacketEncryptionAlgorithm, PacketHkdfAlgorithm, PacketMode, DEFAULT_NUM_MIX_HOPS,
|
||||
PacketEncryptionAlgorithm, PacketHkdfAlgorithm, PacketType, DEFAULT_NUM_MIX_HOPS,
|
||||
};
|
||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||
use nym_sphinx_types::{delays, Error as SphinxError};
|
||||
use nym_sphinx_types::{delays, NymPacket};
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::convert::TryFrom;
|
||||
@@ -28,8 +28,8 @@ pub enum CoverMessageError {
|
||||
#[error("Could not construct cover message due to invalid topology - {0}")]
|
||||
InvalidTopologyError(#[from] NymTopologyError),
|
||||
|
||||
#[error("Could not construct a valid sphinx packet - {0}")]
|
||||
SphinxError(#[from] SphinxError),
|
||||
#[error("SurbAck: {0}")]
|
||||
SurbAck(#[from] SurbAckRecoveryError),
|
||||
}
|
||||
|
||||
pub fn generate_loop_cover_surb_ack<R>(
|
||||
@@ -67,7 +67,7 @@ where
|
||||
// we don't care about total ack delay - we will not be retransmitting it anyway
|
||||
let (_, ack_bytes) =
|
||||
generate_loop_cover_surb_ack(rng, topology, ack_key, full_address, average_ack_delay)?
|
||||
.prepare_for_sending();
|
||||
.prepare_for_sending()?;
|
||||
|
||||
// cover message can't be distinguishable from a normal traffic so we have to go through
|
||||
// all the effort of key generation, encryption, etc. Note here we are generating shared key
|
||||
@@ -111,15 +111,17 @@ where
|
||||
let destination = full_address.as_sphinx_destination();
|
||||
|
||||
// once merged, that's an easy rng injection point for sphinx packets : )
|
||||
let packet = SphinxPacketBuilder::new()
|
||||
.with_payload_size(packet_size.payload_size())
|
||||
.build_packet(packet_payload, &route, &destination, &delays)
|
||||
.unwrap();
|
||||
let packet = NymPacket::Sphinx(
|
||||
SphinxPacketBuilder::new()
|
||||
.with_payload_size(packet_size.payload_size())
|
||||
.build_packet(packet_payload, &route, &destination, &delays)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let first_hop_address =
|
||||
NymNodeRoutingAddress::try_from(route.first().unwrap().address).unwrap();
|
||||
|
||||
Ok(MixPacket::new(first_hop_address, packet, PacketMode::Mix))
|
||||
Ok(MixPacket::new(first_hop_address, packet, PacketType::Mix))
|
||||
}
|
||||
|
||||
/// Helper function used to determine if given message represents a loop cover message.
|
||||
|
||||
@@ -12,3 +12,4 @@ nym-sphinx-addressing = { path = "../addressing" }
|
||||
nym-sphinx-params = { path = "../params" }
|
||||
nym-sphinx-types = { path = "../types" }
|
||||
nym-outfox = { path = "../../../nym-outfox" }
|
||||
thiserror = "1"
|
||||
|
||||
@@ -2,42 +2,28 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError};
|
||||
use nym_sphinx_params::{PacketMode, PacketSize};
|
||||
use nym_sphinx_types::SphinxPacket;
|
||||
use nym_sphinx_params::{PacketSize, PacketType};
|
||||
use nym_sphinx_types::{NymPacket, NymPacketError};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MixPacketFormattingError {
|
||||
#[error("too few bytes provided to recover from bytes")]
|
||||
TooFewBytesProvided,
|
||||
InvalidPacketMode,
|
||||
#[error("provided packet mode is invalid")]
|
||||
InvalidPacketType,
|
||||
#[error("received request had invalid size - received {0}")]
|
||||
InvalidPacketSize(usize),
|
||||
#[error("address field was incorrectly encoded")]
|
||||
InvalidAddress,
|
||||
#[error("received sphinx packet was malformed")]
|
||||
MalformedSphinxPacket,
|
||||
#[error("Packet: {0}")]
|
||||
Packet(#[from] NymPacketError),
|
||||
}
|
||||
|
||||
impl Display for MixPacketFormattingError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
use MixPacketFormattingError::*;
|
||||
match self {
|
||||
TooFewBytesProvided => write!(f, "Too few bytes provided to recover from bytes"),
|
||||
InvalidAddress => write!(f, "address field was incorrectly encoded"),
|
||||
InvalidPacketSize(actual) =>
|
||||
write!(
|
||||
f,
|
||||
"received request had invalid size. (actual: {}, but expected one of: {} (ACK), {} (REGULAR), {}, {}, {} (EXTENDED))",
|
||||
actual, PacketSize::AckPacket.size(), PacketSize::RegularPacket.size(),
|
||||
PacketSize::ExtendedPacket8.size(), PacketSize::ExtendedPacket16.size(),
|
||||
PacketSize::ExtendedPacket32.size()
|
||||
),
|
||||
MalformedSphinxPacket => write!(f, "received sphinx packet was malformed"),
|
||||
InvalidPacketMode => write!(f, "provided packet mode is invalid")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for MixPacketFormattingError {}
|
||||
|
||||
impl From<NymNodeRoutingAddressError> for MixPacketFormattingError {
|
||||
fn from(_: NymNodeRoutingAddressError) -> Self {
|
||||
MixPacketFormattingError::InvalidAddress
|
||||
@@ -46,19 +32,16 @@ impl From<NymNodeRoutingAddressError> for MixPacketFormattingError {
|
||||
|
||||
pub struct MixPacket {
|
||||
next_hop: NymNodeRoutingAddress,
|
||||
sphinx_packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl Debug for MixPacket {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"MixPacket to {:?} with packet_mode {:?}. Sphinx header: {:?}, payload length: {}",
|
||||
self.next_hop,
|
||||
self.packet_mode,
|
||||
self.sphinx_packet.header,
|
||||
self.sphinx_packet.payload.len()
|
||||
"MixPacket to {:?} with packet_type {:?}. Packet {:?}",
|
||||
self.next_hop, self.packet_type, self.packet
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -66,13 +49,13 @@ impl Debug for MixPacket {
|
||||
impl MixPacket {
|
||||
pub fn new(
|
||||
next_hop: NymNodeRoutingAddress,
|
||||
sphinx_packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
) -> Self {
|
||||
MixPacket {
|
||||
next_hop,
|
||||
sphinx_packet,
|
||||
packet_mode,
|
||||
packet,
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,52 +63,52 @@ impl MixPacket {
|
||||
self.next_hop
|
||||
}
|
||||
|
||||
pub fn sphinx_packet(&self) -> &SphinxPacket {
|
||||
&self.sphinx_packet
|
||||
pub fn packet(&self) -> &NymPacket {
|
||||
&self.packet
|
||||
}
|
||||
|
||||
pub fn into_sphinx_packet(self) -> SphinxPacket {
|
||||
self.sphinx_packet
|
||||
pub fn into_packet(self) -> NymPacket {
|
||||
self.packet
|
||||
}
|
||||
|
||||
pub fn packet_mode(&self) -> PacketMode {
|
||||
self.packet_mode
|
||||
pub fn packet_type(&self) -> PacketType {
|
||||
self.packet_type
|
||||
}
|
||||
|
||||
// the message is formatted as follows:
|
||||
// PACKET_MODE || FIRST_HOP || SPHINX_PACKET
|
||||
// packet_type || FIRST_HOP || packet
|
||||
pub fn try_from_bytes(b: &[u8]) -> Result<Self, MixPacketFormattingError> {
|
||||
let packet_mode = match PacketMode::try_from(b[0]) {
|
||||
let packet_type = match PacketType::try_from(b[0]) {
|
||||
Ok(mode) => mode,
|
||||
Err(_) => return Err(MixPacketFormattingError::InvalidPacketMode),
|
||||
Err(_) => return Err(MixPacketFormattingError::InvalidPacketType),
|
||||
};
|
||||
|
||||
let next_hop = NymNodeRoutingAddress::try_from_bytes(&b[1..])?;
|
||||
let addr_offset = next_hop.bytes_min_len();
|
||||
|
||||
let sphinx_packet_data = &b[addr_offset + 1..];
|
||||
let packet_size = sphinx_packet_data.len();
|
||||
let packet_data = &b[addr_offset + 1..];
|
||||
let packet_size = packet_data.len();
|
||||
if PacketSize::get_type(packet_size).is_err() {
|
||||
Err(MixPacketFormattingError::InvalidPacketSize(packet_size))
|
||||
} else {
|
||||
let sphinx_packet = match SphinxPacket::from_bytes(sphinx_packet_data) {
|
||||
Ok(packet) => packet,
|
||||
Err(_) => return Err(MixPacketFormattingError::MalformedSphinxPacket),
|
||||
let packet = match packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_from_bytes(packet_data)?,
|
||||
_ => NymPacket::sphinx_from_bytes(packet_data)?,
|
||||
};
|
||||
|
||||
Ok(MixPacket {
|
||||
next_hop,
|
||||
sphinx_packet,
|
||||
packet_mode,
|
||||
packet,
|
||||
packet_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_bytes(self) -> Vec<u8> {
|
||||
std::iter::once(self.packet_mode as u8)
|
||||
pub fn into_bytes(self) -> Result<Vec<u8>, MixPacketFormattingError> {
|
||||
Ok(std::iter::once(self.packet_type as u8)
|
||||
.chain(self.next_hop.as_bytes().into_iter())
|
||||
.chain(self.sphinx_packet.to_bytes().into_iter())
|
||||
.collect()
|
||||
.chain(self.packet.to_bytes()?.into_iter())
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,65 +1,55 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::packet::{FramedSphinxPacket, Header};
|
||||
use crate::packet::{FramedNymPacket, Header};
|
||||
use bytes::{Buf, BufMut, BytesMut};
|
||||
use nym_sphinx_params::packet_modes::InvalidPacketMode;
|
||||
use nym_sphinx_params::packet_sizes::{InvalidPacketSize, PacketSize};
|
||||
use nym_sphinx_types::Error as SphinxError;
|
||||
use nym_sphinx_types::SphinxPacket;
|
||||
use nym_sphinx_params::packet_types::InvalidPacketType;
|
||||
use nym_sphinx_params::PacketType;
|
||||
use nym_sphinx_types::{NymPacket, NymPacketError};
|
||||
use std::io;
|
||||
use thiserror::Error;
|
||||
use tokio_util::codec::{Decoder, Encoder};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum SphinxCodecError {
|
||||
pub enum NymCodecError {
|
||||
#[error("the packet size information was malformed - {0}")]
|
||||
InvalidPacketSize(#[from] InvalidPacketSize),
|
||||
|
||||
#[error("the packet mode information was malformed - {0}")]
|
||||
InvalidPacketMode(#[from] InvalidPacketMode),
|
||||
|
||||
#[error("the actual sphinx packet was malformed - {0}")]
|
||||
MalformedSphinxPacket(#[from] SphinxError),
|
||||
InvalidPacketType(#[from] InvalidPacketType),
|
||||
|
||||
#[error("encountered an IO error - {0}")]
|
||||
IoError(#[from] io::Error),
|
||||
}
|
||||
|
||||
impl From<SphinxCodecError> for io::Error {
|
||||
fn from(err: SphinxCodecError) -> Self {
|
||||
match err {
|
||||
SphinxCodecError::InvalidPacketSize(source) => {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, source)
|
||||
}
|
||||
SphinxCodecError::InvalidPacketMode(source) => {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, source)
|
||||
}
|
||||
SphinxCodecError::MalformedSphinxPacket(source) => {
|
||||
io::Error::new(io::ErrorKind::InvalidData, source)
|
||||
}
|
||||
SphinxCodecError::IoError(err) => err,
|
||||
}
|
||||
}
|
||||
#[error("encountered a packet error - {0}")]
|
||||
NymPacket(#[from] NymPacketError),
|
||||
|
||||
#[error("could not convert to bytes")]
|
||||
ToBytes,
|
||||
|
||||
#[error("could not convert to bytes")]
|
||||
FromBytes,
|
||||
}
|
||||
|
||||
// TODO: in the future it could be extended to have state containing symmetric encryption key
|
||||
// so that all data could be encrypted easily (alternatively we could just slap TLS)
|
||||
pub struct SphinxCodec;
|
||||
pub struct NymCodec;
|
||||
|
||||
impl Encoder<FramedSphinxPacket> for SphinxCodec {
|
||||
type Error = SphinxCodecError;
|
||||
impl Encoder<FramedNymPacket> for NymCodec {
|
||||
type Error = NymCodecError;
|
||||
|
||||
fn encode(&mut self, item: FramedSphinxPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||
fn encode(&mut self, item: FramedNymPacket, dst: &mut BytesMut) -> Result<(), Self::Error> {
|
||||
item.header.encode(dst);
|
||||
dst.put(item.packet.to_bytes().as_ref());
|
||||
let packet_bytes = item.packet.to_bytes()?;
|
||||
dst.put(packet_bytes.as_slice());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Decoder for SphinxCodec {
|
||||
type Item = FramedSphinxPacket;
|
||||
type Error = SphinxCodecError;
|
||||
impl Decoder for NymCodec {
|
||||
type Item = FramedNymPacket;
|
||||
type Error = NymCodecError;
|
||||
|
||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
if src.is_empty() {
|
||||
@@ -76,23 +66,32 @@ impl Decoder for SphinxCodec {
|
||||
None => return Ok(None), // we have some data but not enough to get header back
|
||||
};
|
||||
|
||||
let sphinx_packet_size = header.packet_size.size();
|
||||
let frame_len = header.size() + sphinx_packet_size;
|
||||
let packet_size = header.packet_size.size();
|
||||
let frame_len = header.size() + packet_size;
|
||||
|
||||
if src.len() < frame_len {
|
||||
// we don't have enough bytes to read the rest of frame
|
||||
src.reserve(sphinx_packet_size);
|
||||
src.reserve(packet_size);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
// advance buffer past the header - at this point we have enough bytes
|
||||
src.advance(header.size());
|
||||
let sphinx_packet_bytes = src.split_to(sphinx_packet_size);
|
||||
let packet_bytes = src.split_to(packet_size);
|
||||
let packet = if let Some(slice) = packet_bytes.get(..) {
|
||||
// here it could be debatable whether stream is corrupt or not,
|
||||
// but let's go with the safer approach and assume it is.
|
||||
match header.packet_type {
|
||||
PacketType::Outfox => NymPacket::outfox_from_bytes(slice)?,
|
||||
PacketType::Mix => NymPacket::sphinx_from_bytes(slice)?,
|
||||
PacketType::Vpn => NymPacket::sphinx_from_bytes(slice)?,
|
||||
}
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
// here it could be debatable whether stream is corrupt or not,
|
||||
// but let's go with the safer approach and assume it is.
|
||||
let packet = SphinxPacket::from_bytes(&sphinx_packet_bytes)?;
|
||||
let nymsphinx_packet = FramedSphinxPacket { header, packet };
|
||||
// let packet = SphinxPacket::from_bytes(&sphinx_packet_bytes)?;
|
||||
let nymsphinx_packet = FramedNymPacket { header, packet };
|
||||
|
||||
// As per docs:
|
||||
// Before returning from the function, implementations should ensure that the buffer
|
||||
@@ -120,7 +119,6 @@ impl Decoder for SphinxCodec {
|
||||
};
|
||||
}
|
||||
src.reserve(allocate_for_next_packet);
|
||||
|
||||
Ok(Some(nymsphinx_packet))
|
||||
}
|
||||
}
|
||||
@@ -128,13 +126,36 @@ impl Decoder for SphinxCodec {
|
||||
#[cfg(test)]
|
||||
mod packet_encoding {
|
||||
use super::*;
|
||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||
use nym_sphinx_types::{
|
||||
crypto, Delay as SphinxDelay, Destination, DestinationAddressBytes, Node, NodeAddressBytes,
|
||||
DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, NODE_ADDRESS_LENGTH,
|
||||
};
|
||||
|
||||
fn make_valid_sphinx_packet(size: PacketSize) -> SphinxPacket {
|
||||
fn make_valid_outfox_packet(size: PacketSize) -> NymPacket {
|
||||
let (_, node1_pk) = crypto::keygen();
|
||||
let node1 = Node::new(
|
||||
NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
|
||||
node1_pk,
|
||||
);
|
||||
let (_, node2_pk) = crypto::keygen();
|
||||
let node2 = Node::new(
|
||||
NodeAddressBytes::from_bytes([4u8; NODE_ADDRESS_LENGTH]),
|
||||
node2_pk,
|
||||
);
|
||||
let (_, node3_pk) = crypto::keygen();
|
||||
let node3 = Node::new(
|
||||
NodeAddressBytes::from_bytes([2u8; NODE_ADDRESS_LENGTH]),
|
||||
node3_pk,
|
||||
);
|
||||
|
||||
let route = &[node1, node2, node3];
|
||||
|
||||
let payload = vec![1; 48];
|
||||
|
||||
NymPacket::outfox_build(payload, route, Some(size.plaintext_size())).unwrap()
|
||||
}
|
||||
|
||||
fn make_valid_sphinx_packet(size: PacketSize) -> NymPacket {
|
||||
let (_, node1_pk) = crypto::keygen();
|
||||
let node1 = Node::new(
|
||||
NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
|
||||
@@ -161,9 +182,7 @@ mod packet_encoding {
|
||||
SphinxDelay::new_from_nanos(42),
|
||||
SphinxDelay::new_from_nanos(42),
|
||||
];
|
||||
SphinxPacketBuilder::new()
|
||||
.with_payload_size(size.payload_size())
|
||||
.build_packet(b"foomp", &route, &destination, &delays)
|
||||
NymPacket::sphinx_build(size.payload_size(), b"foomp", &route, &destination, &delays)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -171,32 +190,50 @@ mod packet_encoding {
|
||||
fn whole_packet_can_be_decoded_from_a_valid_encoded_instance() {
|
||||
let header = Default::default();
|
||||
let sphinx_packet = make_valid_sphinx_packet(Default::default());
|
||||
let sphinx_bytes = sphinx_packet.to_bytes();
|
||||
let sphinx_bytes = sphinx_packet.to_bytes().unwrap();
|
||||
|
||||
let packet = FramedSphinxPacket {
|
||||
let packet = FramedNymPacket {
|
||||
header,
|
||||
packet: sphinx_packet,
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(packet, &mut bytes).unwrap();
|
||||
let decoded = SphinxCodec.decode(&mut bytes).unwrap().unwrap();
|
||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
||||
let decoded = NymCodec.decode(&mut bytes).unwrap().unwrap();
|
||||
|
||||
assert_eq!(decoded.header, header);
|
||||
assert_eq!(decoded.packet.to_bytes(), sphinx_bytes)
|
||||
assert_eq!(decoded.packet.to_bytes().unwrap(), sphinx_bytes)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whole_outfox_can_be_decoded_from_a_valid_encoded_instance() {
|
||||
let header = Header::outfox();
|
||||
let packet = make_valid_outfox_packet(PacketSize::OutfoxRegularPacket);
|
||||
let packet_bytes = packet.to_bytes().unwrap();
|
||||
|
||||
NymPacket::outfox_from_bytes(packet_bytes.as_slice()).unwrap();
|
||||
|
||||
let packet = FramedNymPacket { header, packet };
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
||||
let decoded = NymCodec.decode(&mut bytes).unwrap().unwrap();
|
||||
|
||||
assert_eq!(decoded.header, header);
|
||||
assert_eq!(decoded.packet.to_bytes().unwrap(), packet_bytes)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod decode_will_allocate_enough_bytes_for_next_call {
|
||||
use super::*;
|
||||
use nym_sphinx_params::packet_version::PacketVersion;
|
||||
use nym_sphinx_params::PacketMode;
|
||||
use nym_sphinx_params::PacketType;
|
||||
|
||||
#[test]
|
||||
fn for_empty_bytes() {
|
||||
// empty bytes should allocate for header + ack packet
|
||||
let mut empty_bytes = BytesMut::new();
|
||||
assert!(SphinxCodec.decode(&mut empty_bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut empty_bytes).unwrap().is_none());
|
||||
assert_eq!(
|
||||
empty_bytes.capacity(),
|
||||
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
|
||||
@@ -217,11 +254,11 @@ mod packet_encoding {
|
||||
let header = Header {
|
||||
packet_version: PacketVersion::Legacy,
|
||||
packet_size,
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut bytes = BytesMut::new();
|
||||
header.encode(&mut bytes);
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
|
||||
assert_eq!(bytes.capacity(), Header::LEGACY_SIZE + packet_size.size())
|
||||
}
|
||||
@@ -241,11 +278,11 @@ mod packet_encoding {
|
||||
let header = Header {
|
||||
packet_version: PacketVersion::Versioned(123),
|
||||
packet_size,
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut bytes = BytesMut::new();
|
||||
header.encode(&mut bytes);
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
|
||||
assert_eq!(
|
||||
bytes.capacity(),
|
||||
@@ -257,18 +294,17 @@ mod packet_encoding {
|
||||
#[test]
|
||||
fn for_full_frame_with_legacy_header() {
|
||||
// if full frame is used exactly, there should be enough space for header + ack packet
|
||||
let packet = FramedSphinxPacket {
|
||||
let packet = FramedNymPacket {
|
||||
header: Header {
|
||||
packet_version: PacketVersion::Legacy,
|
||||
packet_size: Default::default(),
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(packet, &mut bytes).unwrap();
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert_eq!(
|
||||
bytes.capacity(),
|
||||
Header::LEGACY_SIZE + PacketSize::AckPacket.size()
|
||||
@@ -278,14 +314,14 @@ mod packet_encoding {
|
||||
#[test]
|
||||
fn for_full_frame_with_versioned_header() {
|
||||
// if full frame is used exactly, there should be enough space for header + ack packet
|
||||
let packet = FramedSphinxPacket {
|
||||
let packet = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(packet, &mut bytes).unwrap();
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
NymCodec.encode(packet, &mut bytes).unwrap();
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert_eq!(
|
||||
bytes.capacity(),
|
||||
Header::VERSIONED_SIZE + PacketSize::AckPacket.size()
|
||||
@@ -304,20 +340,19 @@ mod packet_encoding {
|
||||
];
|
||||
|
||||
for packet_size in packet_sizes {
|
||||
let first_packet = FramedSphinxPacket {
|
||||
let first_packet = FramedNymPacket {
|
||||
header: Header {
|
||||
packet_version: PacketVersion::Legacy,
|
||||
packet_size: Default::default(),
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
},
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(first_packet, &mut bytes).unwrap();
|
||||
NymCodec.encode(first_packet, &mut bytes).unwrap();
|
||||
bytes.put_u8(packet_size as u8);
|
||||
bytes.put_u8(PacketMode::default() as u8);
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
bytes.put_u8(PacketType::default() as u8);
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
|
||||
assert!(bytes.capacity() >= Header::LEGACY_SIZE + packet_size.size())
|
||||
}
|
||||
@@ -335,53 +370,53 @@ mod packet_encoding {
|
||||
];
|
||||
|
||||
for packet_size in packet_sizes {
|
||||
let first_packet = FramedSphinxPacket {
|
||||
let first_packet = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
SphinxCodec.encode(first_packet, &mut bytes).unwrap();
|
||||
NymCodec.encode(first_packet, &mut bytes).unwrap();
|
||||
bytes.put_u8(PacketVersion::new_versioned(123).as_u8().unwrap());
|
||||
bytes.put_u8(packet_size as u8);
|
||||
bytes.put_u8(PacketMode::default() as u8);
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
bytes.put_u8(PacketType::default() as u8);
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
|
||||
assert!(bytes.capacity() >= Header::VERSIONED_SIZE + packet_size.size())
|
||||
// assert!(bytes.capacity() >= Header::VERSIONED_SIZE + packet_size.size())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_decode_two_packets_immediately() {
|
||||
let packet1 = FramedSphinxPacket {
|
||||
let packet1 = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let packet2 = FramedSphinxPacket {
|
||||
let packet2 = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let mut bytes = BytesMut::new();
|
||||
|
||||
SphinxCodec.encode(packet1, &mut bytes).unwrap();
|
||||
SphinxCodec.encode(packet2, &mut bytes).unwrap();
|
||||
NymCodec.encode(packet1, &mut bytes).unwrap();
|
||||
NymCodec.encode(packet2, &mut bytes).unwrap();
|
||||
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_decode_two_packets_in_separate_calls() {
|
||||
let packet1 = FramedSphinxPacket {
|
||||
let packet1 = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
|
||||
let packet2 = FramedSphinxPacket {
|
||||
let packet2 = FramedNymPacket {
|
||||
header: Header::default(),
|
||||
packet: make_valid_sphinx_packet(Default::default()),
|
||||
};
|
||||
@@ -389,18 +424,17 @@ mod packet_encoding {
|
||||
let mut bytes = BytesMut::new();
|
||||
let mut bytes_tmp = BytesMut::new();
|
||||
|
||||
SphinxCodec.encode(packet1, &mut bytes).unwrap();
|
||||
SphinxCodec.encode(packet2, &mut bytes_tmp).unwrap();
|
||||
NymCodec.encode(packet1, &mut bytes).unwrap();
|
||||
NymCodec.encode(packet2, &mut bytes_tmp).unwrap();
|
||||
|
||||
let tmp = bytes_tmp.split_off(100);
|
||||
bytes.put(bytes_tmp);
|
||||
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
|
||||
bytes.put(tmp);
|
||||
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(SphinxCodec.decode(&mut bytes).unwrap().is_none());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_some());
|
||||
assert!(NymCodec.decode(&mut bytes).unwrap().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,52 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::codec::SphinxCodecError;
|
||||
use crate::codec::NymCodecError;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::packet_version::PacketVersion;
|
||||
use nym_sphinx_params::PacketMode;
|
||||
use nym_sphinx_types::SphinxPacket;
|
||||
use nym_sphinx_params::PacketType;
|
||||
use nym_sphinx_types::NymPacket;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
pub struct FramedSphinxPacket {
|
||||
#[derive(Debug)]
|
||||
pub struct FramedNymPacket {
|
||||
/// Contains any metadata helping receiver to handle the underlying packet.
|
||||
pub(crate) header: Header,
|
||||
|
||||
/// The actual SphinxPacket being sent.
|
||||
pub(crate) packet: SphinxPacket,
|
||||
pub(crate) packet: NymPacket,
|
||||
}
|
||||
|
||||
impl FramedSphinxPacket {
|
||||
pub fn new(packet: SphinxPacket, packet_mode: PacketMode, use_legacy_version: bool) -> Self {
|
||||
impl FramedNymPacket {
|
||||
pub fn new(packet: NymPacket, packet_type: PacketType, use_legacy_version: bool) -> Self {
|
||||
// If this fails somebody is using the library in a super incorrect way, because they
|
||||
// already managed to somehow create a sphinx packet
|
||||
let packet_size = PacketSize::get_type(packet.len()).unwrap();
|
||||
|
||||
FramedSphinxPacket {
|
||||
FramedNymPacket {
|
||||
header: Header {
|
||||
packet_version: PacketVersion::new(use_legacy_version),
|
||||
packet_size,
|
||||
packet_mode,
|
||||
packet_type,
|
||||
},
|
||||
packet,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn header(&self) -> Header {
|
||||
self.header
|
||||
}
|
||||
|
||||
pub fn packet_size(&self) -> PacketSize {
|
||||
self.header.packet_size
|
||||
}
|
||||
|
||||
pub fn packet_mode(&self) -> PacketMode {
|
||||
self.header.packet_mode
|
||||
pub fn packet_type(&self) -> PacketType {
|
||||
self.header.packet_type
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> SphinxPacket {
|
||||
pub fn into_inner(self) -> NymPacket {
|
||||
self.packet
|
||||
}
|
||||
}
|
||||
@@ -64,15 +69,23 @@ pub struct Header {
|
||||
///
|
||||
/// TODO: ask @AP whether this can be sent like this - could it introduce some anonymity issues?
|
||||
/// (note: this will be behind some encryption, either something implemented by us or some SSL action)
|
||||
// Note: currently packet_mode is deprecated but is still left as a concept behind to not break
|
||||
// Note: currently packet_type is deprecated but is still left as a concept behind to not break
|
||||
// compatibility with existing network
|
||||
pub(crate) packet_mode: PacketMode,
|
||||
pub(crate) packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl Header {
|
||||
pub(crate) const LEGACY_SIZE: usize = 2;
|
||||
pub(crate) const VERSIONED_SIZE: usize = 3;
|
||||
|
||||
pub fn outfox() -> Header {
|
||||
Header {
|
||||
packet_version: PacketVersion::default(),
|
||||
packet_size: PacketSize::OutfoxRegularPacket,
|
||||
packet_type: PacketType::Outfox,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn size(&self) -> usize {
|
||||
if self.packet_version.is_legacy() {
|
||||
Self::LEGACY_SIZE
|
||||
@@ -90,12 +103,12 @@ impl Header {
|
||||
}
|
||||
|
||||
dst.put_u8(self.packet_size as u8);
|
||||
dst.put_u8(self.packet_mode as u8);
|
||||
dst.put_u8(self.packet_type as u8);
|
||||
// reserve bytes for the actual packet
|
||||
dst.reserve(self.packet_size.size());
|
||||
}
|
||||
|
||||
pub(crate) fn decode(src: &mut BytesMut) -> Result<Option<Self>, SphinxCodecError> {
|
||||
pub(crate) fn decode(src: &mut BytesMut) -> Result<Option<Self>, NymCodecError> {
|
||||
if src.len() < Self::LEGACY_SIZE {
|
||||
// can't do anything if we don't have enough bytes - but reserve enough for the next call
|
||||
src.reserve(Self::LEGACY_SIZE);
|
||||
@@ -107,7 +120,7 @@ impl Header {
|
||||
Ok(Some(Header {
|
||||
packet_version,
|
||||
packet_size: PacketSize::try_from(src[0])?,
|
||||
packet_mode: PacketMode::try_from(src[1])?,
|
||||
packet_type: PacketType::try_from(src[1])?,
|
||||
}))
|
||||
} else if src.len() < Self::VERSIONED_SIZE {
|
||||
// we're missing that 1 byte to read the full header...
|
||||
@@ -117,7 +130,7 @@ impl Header {
|
||||
Ok(Some(Header {
|
||||
packet_version,
|
||||
packet_size: PacketSize::try_from(src[1])?,
|
||||
packet_mode: PacketMode::try_from(src[2])?,
|
||||
packet_type: PacketType::try_from(src[2])?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -148,7 +161,7 @@ mod header_encoding {
|
||||
[
|
||||
PacketVersion::new_versioned(123).as_u8().unwrap(),
|
||||
unknown_packet_size,
|
||||
PacketMode::default() as u8,
|
||||
PacketType::default() as u8,
|
||||
]
|
||||
.as_ref(),
|
||||
);
|
||||
@@ -156,12 +169,12 @@ mod header_encoding {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoding_will_fail_for_unknown_packet_mode() {
|
||||
let unknown_packet_mode: u8 = 255;
|
||||
fn decoding_will_fail_for_unknown_packet_type() {
|
||||
let unknown_packet_type: u8 = 255;
|
||||
// make sure this is still 'unknown' for if we make changes in the future
|
||||
assert!(PacketMode::try_from(unknown_packet_mode).is_err());
|
||||
assert!(PacketType::try_from(unknown_packet_type).is_err());
|
||||
|
||||
let mut bytes = BytesMut::from([PacketSize::default() as u8, unknown_packet_mode].as_ref());
|
||||
let mut bytes = BytesMut::from([PacketSize::default() as u8, unknown_packet_type].as_ref());
|
||||
assert!(Header::decode(&mut bytes).is_err())
|
||||
}
|
||||
|
||||
@@ -191,7 +204,7 @@ mod header_encoding {
|
||||
let header = Header {
|
||||
packet_version: PacketVersion::Legacy,
|
||||
packet_size,
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut bytes = BytesMut::new();
|
||||
header.encode(&mut bytes);
|
||||
@@ -212,7 +225,7 @@ mod header_encoding {
|
||||
let header = Header {
|
||||
packet_version: PacketVersion::Versioned(123),
|
||||
packet_size,
|
||||
packet_mode: Default::default(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut bytes = BytesMut::new();
|
||||
header.encode(&mut bytes);
|
||||
|
||||
@@ -8,11 +8,11 @@ use nym_crypto::ctr;
|
||||
type Aes128Ctr = ctr::Ctr64BE<Aes128>;
|
||||
|
||||
// Re-export for ease of use
|
||||
pub use packet_modes::PacketMode;
|
||||
pub use packet_sizes::PacketSize;
|
||||
pub use packet_types::PacketType;
|
||||
|
||||
pub mod packet_modes;
|
||||
pub mod packet_sizes;
|
||||
pub mod packet_types;
|
||||
pub mod packet_version;
|
||||
|
||||
// If somebody can provide an argument why it might be reasonable to have more than 255 mix hops,
|
||||
@@ -29,7 +29,7 @@ pub type SerializedFragmentIdentifier = [u8; FRAG_ID_LEN];
|
||||
// when packet header gets serialized, the following bytes (in that order) are put onto the wire:
|
||||
// - packet_version (starting with v1.1.0)
|
||||
// - packet_size indicator
|
||||
// - packet_mode
|
||||
// - packet_type
|
||||
// it also just so happens that the only valid values for packet_size indicator include values 1-6
|
||||
// therefore if we receive byte `7` (or larger than that) we'll know we received a versioned packet,
|
||||
// otherwise we should treat it as legacy
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{received} is not a valid packet mode tag")]
|
||||
pub struct InvalidPacketMode {
|
||||
received: u8,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
pub enum PacketMode {
|
||||
/// Represents 'normal' packet sent through the network that should be delayed by an appropriate
|
||||
/// value at each hop.
|
||||
#[default]
|
||||
Mix = 0,
|
||||
|
||||
/// Represents a VPN packet that should not be delayed and ideally cached pre-computed keys
|
||||
/// should be used for unwrapping data. Note that it does not offer the same level of anonymity.
|
||||
Vpn = 1,
|
||||
}
|
||||
|
||||
impl PacketMode {
|
||||
pub fn is_mix(self) -> bool {
|
||||
self == PacketMode::Mix
|
||||
}
|
||||
|
||||
pub fn is_old_vpn(self) -> bool {
|
||||
self == PacketMode::Vpn
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for PacketMode {
|
||||
type Error = InvalidPacketMode;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
_ if value == (PacketMode::Mix as u8) => Ok(Self::Mix),
|
||||
_ if value == (PacketMode::Vpn as u8) => Ok(Self::Vpn),
|
||||
v => Err(InvalidPacketMode { received: v }),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::FRAG_ID_LEN;
|
||||
use nym_sphinx_types::header::HEADER_SIZE;
|
||||
use nym_sphinx_types::PAYLOAD_OVERHEAD_SIZE;
|
||||
use nym_sphinx_types::{MIX_PARAMS_LEN, OUTFOX_PACKET_OVERHEAD, PAYLOAD_OVERHEAD_SIZE};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryFrom;
|
||||
@@ -12,20 +12,27 @@ use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
// each sphinx packet contains mandatory header and payload padding + markers
|
||||
const PACKET_OVERHEAD: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE;
|
||||
const SPHINX_PACKET_OVERHEAD: usize = HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE;
|
||||
|
||||
// it's up to the smart people to figure those values out : )
|
||||
const REGULAR_PACKET_SIZE: usize = 2 * 1024 + PACKET_OVERHEAD;
|
||||
|
||||
// TODO: even though we have 16B IV, is having just 5B (FRAG_ID_LEN) of the ID possibly insecure?
|
||||
|
||||
// TODO: I'm not entirely sure if we can easily extract `<AckEncryptionAlgorithm as NewStreamCipher>::NonceSize`
|
||||
// into a const usize before relevant stuff is stabilised in rust...
|
||||
const ACK_IV_SIZE: usize = 16;
|
||||
|
||||
const ACK_PACKET_SIZE: usize = ACK_IV_SIZE + FRAG_ID_LEN + PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_8: usize = 8 * 1024 + PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_16: usize = 16 * 1024 + PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_32: usize = 32 * 1024 + PACKET_OVERHEAD;
|
||||
const ACK_PACKET_SIZE: usize = ACK_IV_SIZE + FRAG_ID_LEN + SPHINX_PACKET_OVERHEAD;
|
||||
const REGULAR_PACKET_SIZE: usize = 2 * 1024 + SPHINX_PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_8: usize = 8 * 1024 + SPHINX_PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_16: usize = 16 * 1024 + SPHINX_PACKET_OVERHEAD;
|
||||
const EXTENDED_PACKET_SIZE_32: usize = 32 * 1024 + SPHINX_PACKET_OVERHEAD;
|
||||
|
||||
const OUTFOX_ACK_PACKET_SIZE: usize = ACK_IV_SIZE + FRAG_ID_LEN + OUTFOX_PACKET_OVERHEAD;
|
||||
const OUTFOX_REGULAR_PACKET_SIZE: usize = 2 * 1024 + OUTFOX_PACKET_OVERHEAD;
|
||||
const OUTFOX_EXTENDED_PACKET_SIZE_8: usize = 8 * 1024 + OUTFOX_PACKET_OVERHEAD;
|
||||
const OUTFOX_EXTENDED_PACKET_SIZE_16: usize = 16 * 1024 + OUTFOX_PACKET_OVERHEAD;
|
||||
const OUTFOX_EXTENDED_PACKET_SIZE_32: usize = 32 * 1024 + OUTFOX_PACKET_OVERHEAD;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum InvalidPacketSize {
|
||||
@@ -62,6 +69,25 @@ pub enum PacketSize {
|
||||
// for example for streaming fast and furious in compressed XviD quality
|
||||
#[serde(rename = "extended16")]
|
||||
ExtendedPacket16 = 5,
|
||||
|
||||
#[serde(rename = "outfox_regular")]
|
||||
OutfoxRegularPacket = 6,
|
||||
|
||||
// for sending SURB-ACKs
|
||||
#[serde(rename = "outfox_ack")]
|
||||
OutfoxAckPacket = 7,
|
||||
|
||||
// for example for streaming fast and furious in uncompressed 10bit 4K HDR quality
|
||||
#[serde(rename = "outfox_extended32")]
|
||||
OutfoxExtendedPacket32 = 8,
|
||||
|
||||
// for example for streaming fast and furious in heavily compressed lossy RealPlayer quality
|
||||
#[serde(rename = "outfox_extended8")]
|
||||
OutfoxExtendedPacket8 = 9,
|
||||
|
||||
// for example for streaming fast and furious in compressed XviD quality
|
||||
#[serde(rename = "outfox_extended16")]
|
||||
OutfoxExtendedPacket16 = 10,
|
||||
}
|
||||
|
||||
impl PartialOrd for PacketSize {
|
||||
@@ -88,6 +114,11 @@ impl FromStr for PacketSize {
|
||||
"extended8" => Ok(Self::ExtendedPacket8),
|
||||
"extended16" => Ok(Self::ExtendedPacket16),
|
||||
"extended32" => Ok(Self::ExtendedPacket32),
|
||||
"outfox_regular" => Ok(Self::OutfoxRegularPacket),
|
||||
"outfox_ack" => Ok(Self::OutfoxAckPacket),
|
||||
"outfox_extended8" => Ok(Self::OutfoxExtendedPacket8),
|
||||
"outfox_extended16" => Ok(Self::OutfoxExtendedPacket16),
|
||||
"outfox_extended32" => Ok(Self::OutfoxExtendedPacket32),
|
||||
s => Err(InvalidPacketSize::UnknownExtendedPacketVariant {
|
||||
received: s.to_string(),
|
||||
}),
|
||||
@@ -103,6 +134,11 @@ impl Display for PacketSize {
|
||||
PacketSize::ExtendedPacket32 => write!(f, "extended32"),
|
||||
PacketSize::ExtendedPacket8 => write!(f, "extended8"),
|
||||
PacketSize::ExtendedPacket16 => write!(f, "extended16"),
|
||||
PacketSize::OutfoxRegularPacket => write!(f, "outfox_regular"),
|
||||
PacketSize::OutfoxAckPacket => write!(f, "outfox_ack"),
|
||||
PacketSize::OutfoxExtendedPacket32 => write!(f, "outfox_extended32"),
|
||||
PacketSize::OutfoxExtendedPacket8 => write!(f, "outfox_extended8"),
|
||||
PacketSize::OutfoxExtendedPacket16 => write!(f, "outfox_extended16"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,6 +163,17 @@ impl TryFrom<u8> for PacketSize {
|
||||
_ if value == (PacketSize::ExtendedPacket8 as u8) => Ok(Self::ExtendedPacket8),
|
||||
_ if value == (PacketSize::ExtendedPacket16 as u8) => Ok(Self::ExtendedPacket16),
|
||||
_ if value == (PacketSize::ExtendedPacket32 as u8) => Ok(Self::ExtendedPacket32),
|
||||
_ if value == (PacketSize::OutfoxRegularPacket as u8) => Ok(Self::OutfoxRegularPacket),
|
||||
_ if value == (PacketSize::OutfoxAckPacket as u8) => Ok(Self::OutfoxAckPacket),
|
||||
_ if value == (PacketSize::OutfoxExtendedPacket8 as u8) => {
|
||||
Ok(Self::OutfoxExtendedPacket8)
|
||||
}
|
||||
_ if value == (PacketSize::OutfoxExtendedPacket16 as u8) => {
|
||||
Ok(Self::OutfoxExtendedPacket16)
|
||||
}
|
||||
_ if value == (PacketSize::OutfoxExtendedPacket32 as u8) => {
|
||||
Ok(Self::OutfoxExtendedPacket32)
|
||||
}
|
||||
v => Err(InvalidPacketSize::UnknownPacketTag { received: v }),
|
||||
}
|
||||
}
|
||||
@@ -140,15 +187,50 @@ impl PacketSize {
|
||||
PacketSize::ExtendedPacket8 => EXTENDED_PACKET_SIZE_8,
|
||||
PacketSize::ExtendedPacket16 => EXTENDED_PACKET_SIZE_16,
|
||||
PacketSize::ExtendedPacket32 => EXTENDED_PACKET_SIZE_32,
|
||||
PacketSize::OutfoxRegularPacket => OUTFOX_REGULAR_PACKET_SIZE,
|
||||
PacketSize::OutfoxAckPacket => OUTFOX_ACK_PACKET_SIZE,
|
||||
PacketSize::OutfoxExtendedPacket8 => OUTFOX_EXTENDED_PACKET_SIZE_8,
|
||||
PacketSize::OutfoxExtendedPacket16 => OUTFOX_EXTENDED_PACKET_SIZE_16,
|
||||
PacketSize::OutfoxExtendedPacket32 => OUTFOX_EXTENDED_PACKET_SIZE_32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn header_size(&self) -> usize {
|
||||
match self {
|
||||
PacketSize::RegularPacket
|
||||
| PacketSize::AckPacket
|
||||
| PacketSize::ExtendedPacket8
|
||||
| PacketSize::ExtendedPacket16
|
||||
| PacketSize::ExtendedPacket32 => HEADER_SIZE,
|
||||
PacketSize::OutfoxRegularPacket
|
||||
| PacketSize::OutfoxAckPacket
|
||||
| PacketSize::OutfoxExtendedPacket8
|
||||
| PacketSize::OutfoxExtendedPacket16
|
||||
| PacketSize::OutfoxExtendedPacket32 => MIX_PARAMS_LEN,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn payload_overhead(&self) -> usize {
|
||||
match self {
|
||||
PacketSize::RegularPacket
|
||||
| PacketSize::AckPacket
|
||||
| PacketSize::ExtendedPacket8
|
||||
| PacketSize::ExtendedPacket16
|
||||
| PacketSize::ExtendedPacket32 => PAYLOAD_OVERHEAD_SIZE,
|
||||
PacketSize::OutfoxRegularPacket
|
||||
| PacketSize::OutfoxAckPacket
|
||||
| PacketSize::OutfoxExtendedPacket8
|
||||
| PacketSize::OutfoxExtendedPacket16
|
||||
| PacketSize::OutfoxExtendedPacket32 => OUTFOX_PACKET_OVERHEAD - MIX_PARAMS_LEN,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn plaintext_size(self) -> usize {
|
||||
self.size() - HEADER_SIZE - PAYLOAD_OVERHEAD_SIZE
|
||||
self.size() - self.header_size() - self.payload_overhead()
|
||||
}
|
||||
|
||||
pub const fn payload_size(self) -> usize {
|
||||
self.size() - HEADER_SIZE
|
||||
self.size() - self.header_size()
|
||||
}
|
||||
|
||||
pub fn get_type(size: usize) -> Result<Self, InvalidPacketSize> {
|
||||
@@ -162,6 +244,16 @@ impl PacketSize {
|
||||
Ok(PacketSize::ExtendedPacket16)
|
||||
} else if PacketSize::ExtendedPacket32.size() == size {
|
||||
Ok(PacketSize::ExtendedPacket32)
|
||||
} else if PacketSize::OutfoxRegularPacket.size() == size {
|
||||
Ok(PacketSize::OutfoxRegularPacket)
|
||||
} else if PacketSize::OutfoxAckPacket.size() == size {
|
||||
Ok(PacketSize::OutfoxAckPacket)
|
||||
} else if PacketSize::OutfoxExtendedPacket8.size() == size {
|
||||
Ok(PacketSize::OutfoxExtendedPacket8)
|
||||
} else if PacketSize::OutfoxExtendedPacket16.size() == size {
|
||||
Ok(PacketSize::OutfoxExtendedPacket16)
|
||||
} else if PacketSize::OutfoxExtendedPacket32.size() == size {
|
||||
Ok(PacketSize::OutfoxExtendedPacket32)
|
||||
} else {
|
||||
Err(InvalidPacketSize::UnknownPacketSize { received: size })
|
||||
}
|
||||
@@ -169,10 +261,16 @@ impl PacketSize {
|
||||
|
||||
pub fn is_extended_size(&self) -> bool {
|
||||
match self {
|
||||
PacketSize::RegularPacket | PacketSize::AckPacket => false,
|
||||
PacketSize::RegularPacket
|
||||
| PacketSize::AckPacket
|
||||
| PacketSize::OutfoxAckPacket
|
||||
| PacketSize::OutfoxRegularPacket => false,
|
||||
PacketSize::ExtendedPacket8
|
||||
| PacketSize::ExtendedPacket16
|
||||
| PacketSize::ExtendedPacket32 => true,
|
||||
| PacketSize::ExtendedPacket32
|
||||
| PacketSize::OutfoxExtendedPacket8
|
||||
| PacketSize::OutfoxExtendedPacket16
|
||||
| PacketSize::OutfoxExtendedPacket32 => true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,8 +283,12 @@ impl PacketSize {
|
||||
}
|
||||
|
||||
pub fn get_type_from_plaintext(plaintext_size: usize) -> Result<Self, InvalidPacketSize> {
|
||||
let packet_size = plaintext_size + PACKET_OVERHEAD;
|
||||
Self::get_type(packet_size)
|
||||
let sphinx_packet_size = plaintext_size + SPHINX_PACKET_OVERHEAD;
|
||||
let outfox_packet_size = plaintext_size + OUTFOX_PACKET_OVERHEAD;
|
||||
match Self::get_type(sphinx_packet_size) {
|
||||
Ok(t) => Ok(t),
|
||||
Err(_) => Self::get_type(outfox_packet_size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2021-2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
#[error("{received} is not a valid packet mode tag")]
|
||||
pub struct InvalidPacketType {
|
||||
received: u8,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
|
||||
pub enum PacketType {
|
||||
/// Represents 'normal' packet sent through the network that should be delayed by an appropriate
|
||||
/// value at each hop.
|
||||
#[default]
|
||||
Mix = 0,
|
||||
|
||||
/// Represents a packet that should be sent through the network as fast as possible.
|
||||
Vpn = 1,
|
||||
|
||||
/// Abusing this to add Outfox support
|
||||
Outfox = 2,
|
||||
}
|
||||
|
||||
impl PacketType {
|
||||
pub fn is_mix(self) -> bool {
|
||||
self == PacketType::Mix
|
||||
}
|
||||
|
||||
pub fn is_outfox(self) -> bool {
|
||||
self == PacketType::Outfox
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for PacketType {
|
||||
type Error = InvalidPacketType;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
_ if value == (PacketType::Mix as u8) => Ok(Self::Mix),
|
||||
_ if value == (PacketType::Outfox as u8) => Ok(Self::Outfox),
|
||||
v => Err(InvalidPacketType { received: v }),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{PacketSize, CURRENT_PACKET_VERSION_NUMBER};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum PacketVersion {
|
||||
// this will allow updated mixnodes to still understand packets from before the update
|
||||
Legacy,
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::message::{NymMessage, ACK_OVERHEAD};
|
||||
use crate::NymsphinxPayloadBuilder;
|
||||
use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::Digest;
|
||||
use nym_outfox::packet::OutfoxPacket;
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||
use nym_sphinx_acknowledgements::AckKey;
|
||||
use nym_sphinx_addressing::clients::Recipient;
|
||||
@@ -13,9 +14,9 @@ use nym_sphinx_anonymous_replies::reply_surb::ReplySurb;
|
||||
use nym_sphinx_chunking::fragment::{Fragment, FragmentIdentifier};
|
||||
use nym_sphinx_forwarding::packet::MixPacket;
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::{ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx_params::{PacketType, ReplySurbKeyDigestAlgorithm, DEFAULT_NUM_MIX_HOPS};
|
||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||
use nym_sphinx_types::{delays, Delay};
|
||||
use nym_sphinx_types::{delays, Delay, NymPacket};
|
||||
use nym_topology::{NymTopology, NymTopologyError};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::convert::TryFrom;
|
||||
@@ -149,8 +150,12 @@ where
|
||||
let surb_ack = self.generate_surb_ack(fragment_identifier, topology, ack_key)?;
|
||||
let ack_delay = surb_ack.expected_total_delay();
|
||||
|
||||
let packet_payload = NymsphinxPayloadBuilder::new(fragment, surb_ack)
|
||||
.build_reply(reply_surb.encryption_key());
|
||||
let packet_payload = match NymsphinxPayloadBuilder::new(fragment, surb_ack)
|
||||
.build_reply(reply_surb.encryption_key())
|
||||
{
|
||||
Ok(payload) => payload,
|
||||
Err(_e) => return Err(NymTopologyError::PayloadBuilder),
|
||||
};
|
||||
|
||||
// the unwrap here is fine as the failures can only originate from attempting to use invalid payload lengths
|
||||
// and we just very carefully constructed a (presumably) valid one
|
||||
@@ -190,6 +195,7 @@ where
|
||||
topology: &NymTopology,
|
||||
ack_key: &AckKey,
|
||||
packet_recipient: &Recipient,
|
||||
packet_type: PacketType,
|
||||
) -> Result<PreparedFragment, NymTopologyError> {
|
||||
// each plain or repliable packet (i.e. not a reply) attaches an ephemeral public key so that the recipient
|
||||
// could perform diffie-hellman with its own keys followed by a kdf to re-derive
|
||||
@@ -208,8 +214,12 @@ where
|
||||
let surb_ack = self.generate_surb_ack(fragment_identifier, topology, ack_key)?;
|
||||
let ack_delay = surb_ack.expected_total_delay();
|
||||
|
||||
let packet_payload = NymsphinxPayloadBuilder::new(fragment, surb_ack)
|
||||
.build_regular(&mut self.rng, packet_recipient.encryption_key());
|
||||
let packet_payload = match NymsphinxPayloadBuilder::new(fragment, surb_ack)
|
||||
.build_regular(&mut self.rng, packet_recipient.encryption_key())
|
||||
{
|
||||
Ok(payload) => payload,
|
||||
Err(_e) => return Err(NymTopologyError::PayloadBuilder),
|
||||
};
|
||||
|
||||
// generate pseudorandom route for the packet
|
||||
let route = topology.random_route_to_gateway(
|
||||
@@ -224,10 +234,26 @@ where
|
||||
|
||||
// create the actual sphinx packet here. With valid route and correct payload size,
|
||||
// there's absolutely no reason for this call to fail.
|
||||
let sphinx_packet = SphinxPacketBuilder::new()
|
||||
.with_payload_size(packet_size.payload_size())
|
||||
.build_packet(packet_payload, &route, &destination, &delays)
|
||||
.unwrap();
|
||||
|
||||
let sphinx_packet = match packet_type {
|
||||
PacketType::Outfox => NymPacket::Outfox(OutfoxPacket::build(
|
||||
packet_payload,
|
||||
route.as_slice().try_into()?,
|
||||
Some(packet_size.payload_size()),
|
||||
)?),
|
||||
PacketType::Mix => NymPacket::Sphinx(
|
||||
SphinxPacketBuilder::new()
|
||||
.with_payload_size(packet_size.payload_size())
|
||||
.build_packet(packet_payload, &route, &destination, &delays)
|
||||
.unwrap(),
|
||||
),
|
||||
PacketType::Vpn => NymPacket::Sphinx(
|
||||
SphinxPacketBuilder::new()
|
||||
.with_payload_size(packet_size.payload_size())
|
||||
.build_packet(packet_payload, &route, &destination, &delays)
|
||||
.unwrap(),
|
||||
),
|
||||
};
|
||||
|
||||
// from the previously constructed route extract the first hop
|
||||
let first_hop_address =
|
||||
|
||||
@@ -6,7 +6,7 @@ use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::shared_key::new_ephemeral_shared_key;
|
||||
use nym_crypto::symmetric::stream_cipher;
|
||||
use nym_crypto::symmetric::stream_cipher::CipherKey;
|
||||
use nym_sphinx_acknowledgements::surb_ack::SurbAck;
|
||||
use nym_sphinx_acknowledgements::surb_ack::{SurbAck, SurbAckRecoveryError};
|
||||
use nym_sphinx_anonymous_replies::SurbEncryptionKey;
|
||||
use nym_sphinx_chunking::fragment::Fragment;
|
||||
use nym_sphinx_params::{
|
||||
@@ -28,11 +28,11 @@ impl NymsphinxPayloadBuilder {
|
||||
self,
|
||||
packet_encryption_key: &CipherKey<C>,
|
||||
variant_data: impl IntoIterator<Item = u8>,
|
||||
) -> NymsphinxPayload
|
||||
) -> Result<NymsphinxPayload, SurbAckRecoveryError>
|
||||
where
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let (_, surb_ack_bytes) = self.surb_ack.prepare_for_sending();
|
||||
let (_, surb_ack_bytes) = self.surb_ack.prepare_for_sending()?;
|
||||
|
||||
let mut fragment_data = self.fragment.into_bytes();
|
||||
stream_cipher::encrypt_in_place::<C>(
|
||||
@@ -46,16 +46,19 @@ impl NymsphinxPayloadBuilder {
|
||||
// where variant-specific data is as follows:
|
||||
// for replies it would be the digest of the encryption key used
|
||||
// for 'regular' messages it would be the public component used in DH later used in the KDF
|
||||
NymsphinxPayload(
|
||||
Ok(NymsphinxPayload(
|
||||
surb_ack_bytes
|
||||
.into_iter()
|
||||
.chain(variant_data.into_iter())
|
||||
.chain(fragment_data.into_iter())
|
||||
.collect(),
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
pub fn build_reply(self, packet_encryption_key: &SurbEncryptionKey) -> NymsphinxPayload {
|
||||
pub fn build_reply(
|
||||
self,
|
||||
packet_encryption_key: &SurbEncryptionKey,
|
||||
) -> Result<NymsphinxPayload, SurbAckRecoveryError> {
|
||||
let key_digest = packet_encryption_key.compute_digest();
|
||||
self.build::<ReplySurbEncryptionAlgorithm>(
|
||||
packet_encryption_key.inner(),
|
||||
@@ -67,7 +70,7 @@ impl NymsphinxPayloadBuilder {
|
||||
self,
|
||||
rng: &mut R,
|
||||
recipient_encryption_key: &encryption::PublicKey,
|
||||
) -> NymsphinxPayload
|
||||
) -> Result<NymsphinxPayload, SurbAckRecoveryError>
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
|
||||
@@ -7,8 +7,6 @@ use nym_crypto::asymmetric::encryption;
|
||||
use nym_crypto::shared_key::recompute_shared_key;
|
||||
use nym_crypto::symmetric::stream_cipher;
|
||||
use nym_crypto::symmetric::stream_cipher::CipherKey;
|
||||
use nym_outfox::error::OutfoxError;
|
||||
use nym_outfox::lion::lion_transform_decrypt;
|
||||
use nym_sphinx_anonymous_replies::requests::AnonymousSenderTag;
|
||||
use nym_sphinx_anonymous_replies::SurbEncryptionKey;
|
||||
use nym_sphinx_chunking::fragment::Fragment;
|
||||
@@ -76,49 +74,6 @@ pub enum MessageRecoveryError {
|
||||
|
||||
#[error("Failed to recover message fragment - {0}")]
|
||||
FragmentRecoveryError(#[from] ChunkingError),
|
||||
|
||||
#[error("Outfox: {source}")]
|
||||
OutfoxRecoveryError {
|
||||
#[from]
|
||||
source: OutfoxError,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct OutfoxMessageReceiver {
|
||||
reconstructor: MessageReconstructor,
|
||||
}
|
||||
|
||||
impl OutfoxMessageReceiver {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl MessageReceiver for OutfoxMessageReceiver {
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn reconstructor(&mut self) -> &mut MessageReconstructor {
|
||||
&mut self.reconstructor
|
||||
}
|
||||
|
||||
fn num_mix_hops(&self) -> u8 {
|
||||
DEFAULT_NUM_MIX_HOPS
|
||||
}
|
||||
|
||||
fn decrypt_raw_message<C>(
|
||||
&self,
|
||||
message: &mut [u8],
|
||||
key: &CipherKey<C>,
|
||||
) -> Result<(), MessageRecoveryError>
|
||||
where
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
lion_transform_decrypt(message, key)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MessageReceiver {
|
||||
|
||||
@@ -9,6 +9,5 @@ repository = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
sphinx-packet = { version = "0.1.0" }
|
||||
|
||||
#[patch.crates-io]
|
||||
#sphinx-packet = { path = "../../../../sphinx" }
|
||||
nym-outfox = { path = "../../../nym-outfox" }
|
||||
thiserror = "1"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub use nym_outfox::{error::OutfoxError, format::MIX_PARAMS_LEN, packet::OUTFOX_PACKET_OVERHEAD};
|
||||
// re-exporting types and constants available in sphinx
|
||||
use nym_outfox::packet::OutfoxPacket;
|
||||
pub use sphinx_packet::{
|
||||
constants::{
|
||||
self, DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, MAX_PATH_LENGTH, NODE_ADDRESS_LENGTH,
|
||||
@@ -13,5 +15,101 @@ pub use sphinx_packet::{
|
||||
payload::{Payload, PAYLOAD_OVERHEAD_SIZE},
|
||||
route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier},
|
||||
surb::{SURBMaterial, SURB},
|
||||
Error, ProcessedPacket, Result, SphinxPacket,
|
||||
Error as SphinxError, ProcessedPacket,
|
||||
};
|
||||
use sphinx_packet::{SphinxPacket, SphinxPacketBuilder};
|
||||
use std::{array::TryFromSliceError, fmt};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum NymPacketError {
|
||||
#[error("Sphinx error: {0}")]
|
||||
Sphinx(#[from] sphinx_packet::Error),
|
||||
|
||||
#[error("Outfox error: {0}")]
|
||||
Outfox(#[from] nym_outfox::error::OutfoxError),
|
||||
|
||||
#[error("{0}")]
|
||||
FromSlice(#[from] TryFromSliceError),
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum NymPacket {
|
||||
Sphinx(SphinxPacket),
|
||||
Outfox(OutfoxPacket),
|
||||
}
|
||||
|
||||
impl fmt::Debug for NymPacket {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match &self {
|
||||
NymPacket::Sphinx(packet) => f
|
||||
.debug_struct("NymPacket::Sphinx")
|
||||
.field("len", &packet.len())
|
||||
.finish(),
|
||||
NymPacket::Outfox(packet) => f
|
||||
.debug_struct("NymPacket::Outfox")
|
||||
.field("len", &packet.len())
|
||||
.finish(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NymPacket {
|
||||
pub fn sphinx_build<M: AsRef<[u8]>>(
|
||||
size: usize,
|
||||
message: M,
|
||||
route: &[Node],
|
||||
destination: &Destination,
|
||||
delays: &[Delay],
|
||||
) -> Result<NymPacket, NymPacketError> {
|
||||
Ok(NymPacket::Sphinx(
|
||||
SphinxPacketBuilder::new()
|
||||
.with_payload_size(size)
|
||||
.build_packet(message, route, destination, delays)?,
|
||||
))
|
||||
}
|
||||
pub fn sphinx_from_bytes(bytes: &[u8]) -> Result<NymPacket, NymPacketError> {
|
||||
Ok(NymPacket::Sphinx(SphinxPacket::from_bytes(bytes)?))
|
||||
}
|
||||
|
||||
pub fn outfox_build<M: AsRef<[u8]>>(
|
||||
payload: M,
|
||||
route: &[Node],
|
||||
size: Option<usize>,
|
||||
) -> Result<NymPacket, NymPacketError> {
|
||||
Ok(NymPacket::Outfox(OutfoxPacket::build(
|
||||
payload,
|
||||
route.try_into()?,
|
||||
size,
|
||||
)?))
|
||||
}
|
||||
|
||||
pub fn outfox_from_bytes(bytes: &[u8]) -> Result<NymPacket, NymPacketError> {
|
||||
Ok(NymPacket::Outfox(OutfoxPacket::try_from(bytes)?))
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
NymPacket::Sphinx(packet) => packet.len(),
|
||||
NymPacket::Outfox(packet) => packet.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Result<Vec<u8>, NymPacketError> {
|
||||
match self {
|
||||
NymPacket::Sphinx(packet) => Ok(packet.to_bytes()),
|
||||
NymPacket::Outfox(packet) => Ok(packet.to_bytes()?),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process(self, node_secret_key: &PrivateKey) -> Result<ProcessedPacket, NymPacketError> {
|
||||
match self {
|
||||
NymPacket::Sphinx(packet) => Ok(packet.process(node_secret_key)?),
|
||||
NymPacket::Outfox(_packet) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use nym_socks5_requests::{
|
||||
ConnectionId, RemoteAddress, Socks5ProtocolVersion, Socks5ProviderRequest, Socks5Request,
|
||||
};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_task::connections::{LaneQueueLengths, TransmissionLane};
|
||||
use nym_task::TaskClient;
|
||||
use pin_project::pin_project;
|
||||
@@ -181,6 +182,7 @@ pub(crate) struct SocksClient {
|
||||
started_proxy: bool,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
shutdown_listener: TaskClient,
|
||||
packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl Drop for SocksClient {
|
||||
@@ -209,6 +211,7 @@ impl SocksClient {
|
||||
self_address: &Recipient,
|
||||
lane_queue_lengths: LaneQueueLengths,
|
||||
mut shutdown_listener: TaskClient,
|
||||
packet_type: Option<PacketType>,
|
||||
) -> Self {
|
||||
// If this task fails and exits, we don't want to send shutdown signal
|
||||
shutdown_listener.mark_as_success();
|
||||
@@ -229,6 +232,7 @@ impl SocksClient {
|
||||
started_proxy: false,
|
||||
lane_queue_lengths,
|
||||
shutdown_listener,
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,6 +349,7 @@ impl SocksClient {
|
||||
msg.into_bytes(),
|
||||
self.config.connection_start_surbs,
|
||||
TransmissionLane::ConnectionId(self.connection_id),
|
||||
self.packet_type,
|
||||
);
|
||||
self.input_sender
|
||||
.send(input_message)
|
||||
@@ -367,6 +372,7 @@ impl SocksClient {
|
||||
self.service_provider,
|
||||
msg.into_bytes(),
|
||||
TransmissionLane::ConnectionId(self.connection_id),
|
||||
self.packet_type,
|
||||
);
|
||||
self.input_sender
|
||||
.send(input_message)
|
||||
@@ -404,6 +410,7 @@ impl SocksClient {
|
||||
let request_version = self.config.request_version();
|
||||
|
||||
let recipient = self.service_provider;
|
||||
let packet_type = self.packet_type;
|
||||
let (stream, _) = ProxyRunner::new(
|
||||
stream,
|
||||
local_stream_remote,
|
||||
@@ -432,9 +439,15 @@ impl SocksClient {
|
||||
provider_message.into_bytes(),
|
||||
per_request_surbs,
|
||||
lane,
|
||||
packet_type,
|
||||
)
|
||||
} else {
|
||||
InputMessage::new_regular(recipient, provider_message.into_bytes(), lane)
|
||||
InputMessage::new_regular(
|
||||
recipient,
|
||||
provider_message.into_bytes(),
|
||||
lane,
|
||||
packet_type,
|
||||
)
|
||||
}
|
||||
})
|
||||
.await
|
||||
|
||||
@@ -104,6 +104,7 @@ impl SphinxSocksServer {
|
||||
&self.self_address,
|
||||
self.lane_queue_lengths.clone(),
|
||||
self.shutdown.clone(),
|
||||
None
|
||||
);
|
||||
|
||||
tokio::spawn(async move {
|
||||
|
||||
@@ -8,6 +8,7 @@ use nym_mixnet_contract_common::GatewayBond;
|
||||
use nym_sphinx_addressing::nodes::NodeIdentity;
|
||||
use nym_sphinx_types::Node as SphinxNode;
|
||||
use rand::{CryptoRng, Rng};
|
||||
use std::array::TryFromSliceError;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
@@ -52,6 +53,15 @@ pub enum NymTopologyError {
|
||||
total_nodes: usize,
|
||||
layer_distribution: Vec<(MixLayer, usize)>,
|
||||
},
|
||||
// We can't import SurbAckRecoveryError due to cyclic dependency, this is a bit dirty
|
||||
#[error("Could not build payload")]
|
||||
PayloadBuilder,
|
||||
|
||||
#[error("Outfox: {0}")]
|
||||
Outfox(#[from] nym_sphinx_types::OutfoxError),
|
||||
|
||||
#[error("{0}")]
|
||||
FromSlice(#[from] TryFromSliceError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
Generated
+261
-10
@@ -2,6 +2,16 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.7.5"
|
||||
@@ -9,7 +19,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cipher 0.3.0",
|
||||
"cpufeatures",
|
||||
"ctr",
|
||||
"opaque-debug 0.3.0",
|
||||
@@ -38,6 +48,12 @@ version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@@ -86,6 +102,20 @@ dependencies = [
|
||||
"opaque-debug 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"constant_time_eq",
|
||||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
@@ -95,6 +125,15 @@ dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bs58"
|
||||
version = "0.4.0"
|
||||
@@ -150,6 +189,30 @@ dependencies = [
|
||||
"keystream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher 0.4.4",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chacha20poly1305"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"chacha20",
|
||||
"cipher 0.4.4",
|
||||
"poly1305",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.3.0"
|
||||
@@ -159,6 +222,17 @@ dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coconut-test"
|
||||
version = "0.1.0"
|
||||
@@ -190,6 +264,12 @@ version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b"
|
||||
|
||||
[[package]]
|
||||
name = "cosmwasm-crypto"
|
||||
version = "1.0.0"
|
||||
@@ -258,6 +338,49 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
@@ -276,6 +399,17 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
"rand_core 0.6.4",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.7.0"
|
||||
@@ -302,14 +436,14 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
"cipher 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "3.2.1"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
|
||||
checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"digest 0.9.0",
|
||||
@@ -501,6 +635,17 @@ dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||
dependencies = [
|
||||
"block-buffer 0.10.4",
|
||||
"crypto-common",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.11"
|
||||
@@ -701,8 +846,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -750,6 +897,15 @@ dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
@@ -808,6 +964,15 @@ dependencies = [
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
@@ -823,7 +988,7 @@ version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09270fd4fa1111bc614ed2246c7ef56239a3063d5be0d1ec3b589c505d400aeb"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"hermit-abi 0.3.1",
|
||||
"libc",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
@@ -949,6 +1114,15 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
@@ -959,6 +1133,16 @@ dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||
dependencies = [
|
||||
"hermit-abi 0.2.6",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-coconut-bandwidth"
|
||||
version = "0.1.0"
|
||||
@@ -1105,6 +1289,22 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-outfox"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"chacha20",
|
||||
"chacha20poly1305",
|
||||
"curve25519-dalek",
|
||||
"getrandom 0.2.8",
|
||||
"rand",
|
||||
"rayon",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-pemstore"
|
||||
version = "0.2.0"
|
||||
@@ -1143,7 +1343,9 @@ dependencies = [
|
||||
name = "nym-sphinx-types"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"nym-outfox",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1232,6 +1434,17 @@ version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||
dependencies = [
|
||||
"cpufeatures",
|
||||
"opaque-debug 0.3.0",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
@@ -1379,6 +1592,28 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
@@ -1485,6 +1720,12 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "sec1"
|
||||
version = "0.2.1"
|
||||
@@ -1572,7 +1813,7 @@ version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
@@ -1804,6 +2045,16 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.3.1"
|
||||
@@ -2024,9 +2275,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "x25519-dalek"
|
||||
version = "1.2.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077"
|
||||
checksum = "5a0c105152107e3b96f6a00a65e86ce82d9b125230e1c4302940eca58ff71f4f"
|
||||
dependencies = [
|
||||
"curve25519-dalek",
|
||||
"rand_core 0.5.1",
|
||||
@@ -2035,9 +2286,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.3.0"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
|
||||
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
||||
dependencies = [
|
||||
"zeroize_derive",
|
||||
]
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::authentication::encrypted_address::EncryptedAddressBytes;
|
||||
use crate::iv::IV;
|
||||
use crate::registration::handshake::SharedKeys;
|
||||
use crate::{GatewayMacSize, PROTOCOL_VERSION};
|
||||
use log::error;
|
||||
use nym_coconut_interface::Credential;
|
||||
use nym_crypto::generic_array::typenum::Unsigned;
|
||||
use nym_crypto::hmac::recompute_keyed_hmac_and_verify_tag;
|
||||
@@ -290,7 +291,13 @@ impl BinaryRequest {
|
||||
pub fn into_encrypted_tagged_bytes(self, shared_key: &SharedKeys) -> Vec<u8> {
|
||||
match self {
|
||||
BinaryRequest::ForwardSphinx(mix_packet) => {
|
||||
let forwarding_data = mix_packet.into_bytes();
|
||||
let forwarding_data = match mix_packet.into_bytes() {
|
||||
Ok(mix_packet) => mix_packet,
|
||||
Err(e) => {
|
||||
error!("Could not convert packet to bytes: {e}");
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: it could be theoretically slightly more efficient if the data wasn't taken
|
||||
// by reference because then it makes a copy for encryption rather than do it in place
|
||||
|
||||
@@ -283,7 +283,7 @@ where
|
||||
&self,
|
||||
mix_packet: MixPacket,
|
||||
) -> Result<ServerResponse, RequestHandlingError> {
|
||||
let consumed_bandwidth = mix_packet.sphinx_packet().len() as i64;
|
||||
let consumed_bandwidth = mix_packet.packet().len() as i64;
|
||||
|
||||
let available_bandwidth = self.get_available_bandwidth().await?;
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ use log::*;
|
||||
use nym_mixnet_client::forwarder::MixForwardingSender;
|
||||
use nym_mixnode_common::packet_processor::processor::ProcessedFinalHop;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::framing::codec::SphinxCodec;
|
||||
use nym_sphinx::framing::packet::FramedSphinxPacket;
|
||||
use nym_sphinx::framing::codec::NymCodec;
|
||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
||||
use nym_sphinx::DestinationAddressBytes;
|
||||
use nym_task::TaskClient;
|
||||
use std::collections::HashMap;
|
||||
@@ -155,7 +155,7 @@ impl<St: Storage> ConnectionHandler<St> {
|
||||
self.forward_ack(forward_ack, client_address);
|
||||
}
|
||||
|
||||
async fn handle_received_packet(&mut self, framed_sphinx_packet: FramedSphinxPacket) {
|
||||
async fn handle_received_packet(&mut self, framed_sphinx_packet: FramedNymPacket) {
|
||||
//
|
||||
// TODO: here be replay attack detection - it will require similar key cache to the one in
|
||||
// packet processor for vpn packets,
|
||||
@@ -182,7 +182,7 @@ impl<St: Storage> ConnectionHandler<St> {
|
||||
) {
|
||||
debug!("Starting connection handler for {:?}", remote);
|
||||
shutdown.mark_as_success();
|
||||
let mut framed_conn = Framed::new(conn, SphinxCodec);
|
||||
let mut framed_conn = Framed::new(conn, NymCodec);
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
|
||||
@@ -5,7 +5,7 @@ use nym_crypto::asymmetric::encryption;
|
||||
use nym_mixnode_common::packet_processor::error::MixProcessingError;
|
||||
pub use nym_mixnode_common::packet_processor::processor::MixProcessingResult;
|
||||
use nym_mixnode_common::packet_processor::processor::{ProcessedFinalHop, SphinxPacketProcessor};
|
||||
use nym_sphinx::framing::packet::FramedSphinxPacket;
|
||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
@@ -32,7 +32,7 @@ impl PacketProcessor {
|
||||
|
||||
pub(crate) fn process_received(
|
||||
&self,
|
||||
received: FramedSphinxPacket,
|
||||
received: FramedNymPacket,
|
||||
) -> Result<ProcessedFinalHop, GatewayProcessingError> {
|
||||
match self.inner_processor.process_received(received)? {
|
||||
MixProcessingResult::ForwardHop(..) => {
|
||||
|
||||
+6
-1
@@ -51,9 +51,14 @@ fn test_function() {
|
||||
async fn main() {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "cpucycles")] {
|
||||
setup_tracing!("/tmp/tracing.log");
|
||||
let home_dir = dirs::home_dir().expect("Could not get $HOME");
|
||||
let logs_dir = home_dir.join(".nym").join("logs");
|
||||
let logs_dir_str = logs_dir.to_str().expect("Could not construct logs path");
|
||||
setup_tracing!(logs_dir_str);
|
||||
info!("CPU cycles measurement is ON")
|
||||
} else {
|
||||
setup_logging();
|
||||
info!("CPU cycles measurement is OFF")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ use crate::node::TaskClient;
|
||||
use futures::StreamExt;
|
||||
use nym_mixnode_common::measure;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::framing::codec::SphinxCodec;
|
||||
use nym_sphinx::framing::packet::FramedSphinxPacket;
|
||||
use nym_sphinx::framing::codec::NymCodec;
|
||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
||||
use nym_sphinx::Delay as SphinxDelay;
|
||||
use std::net::SocketAddr;
|
||||
use tokio::net::TcpStream;
|
||||
@@ -54,7 +54,7 @@ impl ConnectionHandler {
|
||||
feature = "cpucycles",
|
||||
instrument(skip(self, framed_sphinx_packet), fields(cpucycles))
|
||||
)]
|
||||
fn handle_received_packet(&self, framed_sphinx_packet: FramedSphinxPacket) {
|
||||
fn handle_received_packet(&self, framed_sphinx_packet: FramedNymPacket) {
|
||||
//
|
||||
// TODO: here be replay attack detection - it will require similar key cache to the one in
|
||||
// packet processor for vpn packets,
|
||||
@@ -86,7 +86,7 @@ impl ConnectionHandler {
|
||||
) {
|
||||
debug!("Starting connection handler for {:?}", remote);
|
||||
shutdown.mark_as_success();
|
||||
let mut framed_conn = Framed::new(conn, SphinxCodec);
|
||||
let mut framed_conn = Framed::new(conn, NymCodec);
|
||||
while !shutdown.is_shutdown() {
|
||||
tokio::select! {
|
||||
biased;
|
||||
|
||||
@@ -6,7 +6,7 @@ use nym_crypto::asymmetric::encryption;
|
||||
use nym_mixnode_common::packet_processor::error::MixProcessingError;
|
||||
pub use nym_mixnode_common::packet_processor::processor::MixProcessingResult;
|
||||
use nym_mixnode_common::packet_processor::processor::SphinxPacketProcessor;
|
||||
use nym_sphinx::framing::packet::FramedSphinxPacket;
|
||||
use nym_sphinx::framing::packet::FramedNymPacket;
|
||||
|
||||
// PacketProcessor contains all data required to correctly unwrap and forward sphinx packets
|
||||
#[derive(Clone)]
|
||||
@@ -31,7 +31,7 @@ impl PacketProcessor {
|
||||
|
||||
pub(crate) fn process_received(
|
||||
&self,
|
||||
received: FramedSphinxPacket,
|
||||
received: FramedNymPacket,
|
||||
) -> Result<MixProcessingResult, MixProcessingError> {
|
||||
self.node_stats_update_sender.report_received();
|
||||
self.inner_processor.process_received(received)
|
||||
|
||||
@@ -58,12 +58,12 @@ where
|
||||
|
||||
fn forward_packet(&mut self, packet: MixPacket) {
|
||||
let next_hop = packet.next_hop();
|
||||
let packet_mode = packet.packet_mode();
|
||||
let sphinx_packet = packet.into_sphinx_packet();
|
||||
let packet_type = packet.packet_type();
|
||||
let packet = packet.into_packet();
|
||||
|
||||
if let Err(err) =
|
||||
self.mixnet_client
|
||||
.send_without_response(next_hop, sphinx_packet, packet_mode)
|
||||
if let Err(err) = self
|
||||
.mixnet_client
|
||||
.send_without_response(next_hop, packet, packet_type)
|
||||
{
|
||||
if err.kind() == io::ErrorKind::WouldBlock {
|
||||
// we only know for sure if we dropped a packet if our sending queue was full
|
||||
@@ -134,38 +134,38 @@ mod tests {
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
|
||||
use nym_sphinx::NymPacket;
|
||||
use nym_task::TaskManager;
|
||||
|
||||
use nym_sphinx::addressing::nodes::NymNodeRoutingAddress;
|
||||
use nym_sphinx_params::packet_sizes::PacketSize;
|
||||
use nym_sphinx_params::PacketMode;
|
||||
use nym_sphinx_types::builder::SphinxPacketBuilder;
|
||||
use nym_sphinx_params::PacketType;
|
||||
use nym_sphinx_types::{
|
||||
crypto, Delay as SphinxDelay, Destination, DestinationAddressBytes, Node, NodeAddressBytes,
|
||||
SphinxPacket, DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, NODE_ADDRESS_LENGTH,
|
||||
DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, NODE_ADDRESS_LENGTH,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
struct TestClient {
|
||||
pub packets_sent: Arc<Mutex<Vec<(NymNodeRoutingAddress, SphinxPacket, PacketMode)>>>,
|
||||
pub packets_sent: Arc<Mutex<Vec<(NymNodeRoutingAddress, NymPacket, PacketType)>>>,
|
||||
}
|
||||
|
||||
impl nym_mixnet_client::SendWithoutResponse for TestClient {
|
||||
fn send_without_response(
|
||||
&mut self,
|
||||
address: NymNodeRoutingAddress,
|
||||
packet: SphinxPacket,
|
||||
packet_mode: PacketMode,
|
||||
packet: NymPacket,
|
||||
packet_type: PacketType,
|
||||
) -> io::Result<()> {
|
||||
self.packets_sent
|
||||
.lock()
|
||||
.unwrap()
|
||||
.push((address, packet, packet_mode));
|
||||
.push((address, packet, packet_type));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn make_valid_sphinx_packet(size: PacketSize) -> SphinxPacket {
|
||||
fn make_valid_sphinx_packet(size: PacketSize) -> NymPacket {
|
||||
let (_, node1_pk) = crypto::keygen();
|
||||
let node1 = Node::new(
|
||||
NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]),
|
||||
@@ -192,9 +192,7 @@ mod tests {
|
||||
SphinxDelay::new_from_nanos(42),
|
||||
SphinxDelay::new_from_nanos(42),
|
||||
];
|
||||
SphinxPacketBuilder::new()
|
||||
.with_payload_size(size.payload_size())
|
||||
.build_packet(b"foomp", &route, &destination, &delays)
|
||||
NymPacket::sphinx_build(size.payload_size(), b"foomp", &route, &destination, &delays)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
@@ -219,7 +217,7 @@ mod tests {
|
||||
let mix_packet = MixPacket::new(
|
||||
next_hop,
|
||||
make_valid_sphinx_packet(PacketSize::default()),
|
||||
PacketMode::default(),
|
||||
PacketType::default(),
|
||||
);
|
||||
let forward_instant = None;
|
||||
packet_sender
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::message::NymMessage;
|
||||
use nym_sphinx::params::PacketSize;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use nym_sphinx::{
|
||||
acknowledgements::AckKey, addressing::clients::Recipient, preparer::MessagePreparer,
|
||||
};
|
||||
@@ -43,12 +43,13 @@ impl Chunker {
|
||||
message: Vec<u8>,
|
||||
topology: &NymTopology,
|
||||
packet_sender: Recipient,
|
||||
packet_type: PacketType,
|
||||
) -> Vec<MixPacket> {
|
||||
// I really dislike how we have to overwrite the parameter of the `MessagePreparer` on each run
|
||||
// but without some significant API changes in the `MessagePreparer` this was the easiest
|
||||
// way to being able to have variable sender address.
|
||||
self.message_preparer.set_sender_address(packet_sender);
|
||||
self.prepare_packets(message, topology, packet_sender)
|
||||
self.prepare_packets(message, topology, packet_sender, packet_type)
|
||||
}
|
||||
|
||||
fn prepare_packets(
|
||||
@@ -56,6 +57,7 @@ impl Chunker {
|
||||
message: Vec<u8>,
|
||||
topology: &NymTopology,
|
||||
packet_sender: Recipient,
|
||||
packet_type: PacketType,
|
||||
) -> Vec<MixPacket> {
|
||||
let ack_key: AckKey = AckKey::new(&mut self.rng);
|
||||
|
||||
@@ -68,7 +70,13 @@ impl Chunker {
|
||||
// don't bother with acks etc. for time being
|
||||
let prepared_fragment = self
|
||||
.message_preparer
|
||||
.prepare_chunk_for_sending(message_chunk, topology, &ack_key, &packet_sender)
|
||||
.prepare_chunk_for_sending(
|
||||
message_chunk,
|
||||
topology,
|
||||
&ack_key,
|
||||
&packet_sender,
|
||||
packet_type,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
mix_packets.push(prepared_fragment.mix_packet);
|
||||
|
||||
@@ -20,6 +20,7 @@ use futures::channel::mpsc;
|
||||
use nym_bandwidth_controller::BandwidthController;
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage;
|
||||
use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::receiver::MessageReceiver;
|
||||
use nym_task::TaskManager;
|
||||
use std::sync::Arc;
|
||||
@@ -132,6 +133,7 @@ impl<'a> NetworkMonitorBuilder<'a> {
|
||||
received_processor,
|
||||
summary_producer,
|
||||
self.node_status_storage,
|
||||
PacketType::Mix,
|
||||
);
|
||||
|
||||
NetworkMonitorRunnables {
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::network_monitor::test_route::TestRoute;
|
||||
use crate::storage::NymApiStorage;
|
||||
use crate::support::config::Config;
|
||||
use log::{debug, error, info};
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::receiver::MessageReceiver;
|
||||
use nym_task::TaskClient;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
@@ -44,6 +45,8 @@ pub(super) struct Monitor<R: MessageReceiver + Send + 'static> {
|
||||
/// The minimum number of test routes that need to be constructed (and working) in order for
|
||||
/// a monitor test run to be valid.
|
||||
minimum_test_routes: usize,
|
||||
|
||||
packet_type: PacketType,
|
||||
}
|
||||
|
||||
impl<R: MessageReceiver + Send> Monitor<R> {
|
||||
@@ -54,6 +57,7 @@ impl<R: MessageReceiver + Send> Monitor<R> {
|
||||
received_processor: ReceivedProcessor<R>,
|
||||
summary_producer: SummaryProducer,
|
||||
node_status_storage: NymApiStorage,
|
||||
packet_type: PacketType,
|
||||
) -> Self {
|
||||
Monitor {
|
||||
test_nonce: 1,
|
||||
@@ -68,6 +72,7 @@ impl<R: MessageReceiver + Send> Monitor<R> {
|
||||
route_test_packets: config.get_route_test_packets(),
|
||||
test_routes: config.get_test_routes(),
|
||||
minimum_test_routes: config.get_minimum_test_routes(),
|
||||
packet_type,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,8 +127,11 @@ impl<R: MessageReceiver + Send> Monitor<R> {
|
||||
for route in routes {
|
||||
let mut packet_preparer = self.packet_preparer.clone();
|
||||
let route = route.clone();
|
||||
let gateway_packets = packet_preparer
|
||||
.prepare_test_route_viability_packets(&route, self.route_test_packets);
|
||||
let gateway_packets = packet_preparer.prepare_test_route_viability_packets(
|
||||
&route,
|
||||
self.route_test_packets,
|
||||
self.packet_type,
|
||||
);
|
||||
packets.push(gateway_packets);
|
||||
}
|
||||
|
||||
@@ -230,7 +238,7 @@ impl<R: MessageReceiver + Send> Monitor<R> {
|
||||
info!("Generating test mix packets for all the network nodes...");
|
||||
let prepared_packets = self
|
||||
.packet_preparer
|
||||
.prepare_test_packets(self.test_nonce, routes)
|
||||
.prepare_test_packets(self.test_nonce, routes, self.packet_type)
|
||||
.await;
|
||||
|
||||
let total_sent = prepared_packets
|
||||
|
||||
@@ -11,6 +11,7 @@ use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_mixnet_contract_common::{Addr, GatewayBond, Layer, MixId, MixNodeBond};
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::forwarding::packet::MixPacket;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_topology::{gateway, mix, NymTopology};
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::{thread_rng, Rng};
|
||||
@@ -170,6 +171,7 @@ impl PacketPreparer {
|
||||
packet: &TestPacket,
|
||||
topology: &NymTopology,
|
||||
packet_recipient: Recipient,
|
||||
packet_type: PacketType,
|
||||
) -> MixPacket {
|
||||
// this should be done only once. We can't really do it at construction time
|
||||
// as there's no sane Default for Recipient
|
||||
@@ -180,6 +182,7 @@ impl PacketPreparer {
|
||||
packet.to_bytes(),
|
||||
topology,
|
||||
packet_recipient,
|
||||
packet_type,
|
||||
);
|
||||
assert_eq!(
|
||||
mix_packets.len(),
|
||||
@@ -368,12 +371,14 @@ impl PacketPreparer {
|
||||
&mut self,
|
||||
route: &TestRoute,
|
||||
num: usize,
|
||||
packet_type: PacketType,
|
||||
) -> GatewayPackets {
|
||||
let mut mix_packets = Vec::with_capacity(num);
|
||||
let test_packet = route.self_test_packet();
|
||||
let recipient = self.create_packet_sender(route.gateway());
|
||||
for _ in 0..num {
|
||||
let mix_packet = self.wrap_test_packet(&test_packet, route.topology(), recipient);
|
||||
let mix_packet =
|
||||
self.wrap_test_packet(&test_packet, route.topology(), recipient, packet_type);
|
||||
mix_packets.push(mix_packet)
|
||||
}
|
||||
|
||||
@@ -428,6 +433,7 @@ impl PacketPreparer {
|
||||
&mut self,
|
||||
test_nonce: u64,
|
||||
test_routes: &[TestRoute],
|
||||
packet_type: PacketType,
|
||||
) -> PreparedPackets {
|
||||
// only test mixnodes that are rewarded, i.e. that will be rewarded in this interval.
|
||||
// (remember that "idle" nodes are still part of that set)
|
||||
@@ -462,7 +468,8 @@ impl PacketPreparer {
|
||||
let topology = test_route.substitute_mix(mixnode);
|
||||
// produce n mix packets
|
||||
for _ in 0..self.per_node_test_packets {
|
||||
let mix_packet = self.wrap_test_packet(&test_packet, &topology, recipient);
|
||||
let mix_packet =
|
||||
self.wrap_test_packet(&test_packet, &topology, recipient, packet_type);
|
||||
mix_packets.push(mix_packet);
|
||||
}
|
||||
}
|
||||
@@ -482,7 +489,8 @@ impl PacketPreparer {
|
||||
let topology = test_route.substitute_gateway(gateway);
|
||||
// produce n mix packets
|
||||
for _ in 0..self.per_node_test_packets {
|
||||
let mix_packet = self.wrap_test_packet(&test_packet, &topology, recipient);
|
||||
let mix_packet =
|
||||
self.wrap_test_packet(&test_packet, &topology, recipient, packet_type);
|
||||
gateway_mix_packets.push(mix_packet);
|
||||
}
|
||||
|
||||
|
||||
Generated
+9
-28
@@ -3191,7 +3191,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-bin-common"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"clap",
|
||||
@@ -3565,8 +3565,9 @@ dependencies = [
|
||||
"chacha20poly1305",
|
||||
"curve25519-dalek",
|
||||
"getrandom 0.2.8",
|
||||
"rand 0.7.3",
|
||||
"rayon",
|
||||
"sphinx-packet 0.1.0 (git+https://github.com/nymtech/sphinx.git)",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
@@ -3741,6 +3742,7 @@ dependencies = [
|
||||
"nym-sphinx-addressing",
|
||||
"nym-sphinx-params",
|
||||
"nym-sphinx-types",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3768,7 +3770,9 @@ dependencies = [
|
||||
name = "nym-sphinx-types"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"sphinx-packet 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nym-outfox",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3841,7 +3845,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-vesting-contract"
|
||||
version = "1.3.0"
|
||||
version = "1.3.1"
|
||||
dependencies = [
|
||||
"cosmwasm-derive",
|
||||
"cosmwasm-std",
|
||||
@@ -3859,7 +3863,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-vesting-contract-common"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"cosmwasm-std",
|
||||
"nym-contracts-common",
|
||||
@@ -5377,29 +5381,6 @@ dependencies = [
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sphinx-packet"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/nymtech/sphinx.git#ca107d94360cdf8bbfbdb12fe5320ed74f80e40c"
|
||||
dependencies = [
|
||||
"aes 0.7.5",
|
||||
"arrayref",
|
||||
"blake2",
|
||||
"bs58",
|
||||
"byteorder",
|
||||
"chacha",
|
||||
"curve25519-dalek",
|
||||
"digest 0.9.0",
|
||||
"hkdf 0.11.0",
|
||||
"hmac 0.11.0",
|
||||
"lioness",
|
||||
"log",
|
||||
"rand 0.7.3",
|
||||
"rand_distr",
|
||||
"sha2 0.9.9",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
|
||||
@@ -15,9 +15,8 @@ chacha20poly1305 = "0.10.1"
|
||||
# Need this star over here to pull in js into getrandom
|
||||
getrandom = { version = "*", features = ["js"] }
|
||||
thiserror = "1"
|
||||
|
||||
sphinx-packet = { git = "https://github.com/nymtech/sphinx.git" }
|
||||
|
||||
sphinx-packet = "0.1.0"
|
||||
rand = "0.7.3"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.4"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use std::array::TryFromSliceError;
|
||||
|
||||
use crate::format::MIX_PARAMS_LEN;
|
||||
use crate::lion::MIN_MESSAGE_LEN;
|
||||
use chacha20::cipher::InvalidLength;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[derive(Debug, Error, Clone)]
|
||||
pub enum OutfoxError {
|
||||
#[error("Lengths mismatch, expected: {expected}, got: {got}")]
|
||||
LenMismatch { expected: usize, got: usize },
|
||||
@@ -20,8 +21,10 @@ pub enum OutfoxError {
|
||||
#[error("Message length must be greater then {MIN_MESSAGE_LEN} bytes")]
|
||||
InvalidMessageLength,
|
||||
#[error("{source}")]
|
||||
TryFromSluce {
|
||||
TryFromSlice {
|
||||
#[from]
|
||||
source: TryFromSliceError,
|
||||
},
|
||||
#[error("Header length must be {MIX_PARAMS_LEN}, got {0}")]
|
||||
InvalidHeaderLength(usize),
|
||||
}
|
||||
|
||||
+105
-32
@@ -66,44 +66,83 @@ use sphinx_packet::route::Node;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
const GROUPELEMENTBYTES: usize = 32;
|
||||
const TAGBYTES: usize = 16;
|
||||
pub const GROUPELEMENTBYTES: u8 = 32;
|
||||
pub const TAGBYTES: u8 = 16;
|
||||
pub const MIX_PARAMS_LEN: usize = 5;
|
||||
|
||||
pub const fn groupelementbytes() -> usize {
|
||||
GROUPELEMENTBYTES as usize
|
||||
}
|
||||
|
||||
pub const fn tagbytes() -> usize {
|
||||
TAGBYTES as usize
|
||||
}
|
||||
|
||||
use std::ops::Range;
|
||||
use std::u8;
|
||||
|
||||
use crate::error::OutfoxError;
|
||||
use crate::lion::*;
|
||||
use crate::packet::DEFAULT_ROUTING_INFO_SIZE;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
/// A structure that holds mix packet construction parameters. These incluse the length
|
||||
/// of the routing information at each hop, the number of hops, and the payload length.
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub struct MixCreationParameters {
|
||||
/// The routing length is inner first, so \[0\] is the innermost routing length, etc (in bytes)
|
||||
pub routing_information_length_by_stage: Vec<usize>,
|
||||
/// In our stratified topology this will always be 3
|
||||
pub routing_information_length_by_stage: [u8; 3],
|
||||
/// The payload length (in bytes)
|
||||
pub payload_length_bytes: usize,
|
||||
pub payload_length_bytes: u16,
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for MixCreationParameters {
|
||||
type Error = OutfoxError;
|
||||
|
||||
fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
|
||||
if v.len() != MIX_PARAMS_LEN {
|
||||
return Err(OutfoxError::InvalidHeaderLength(v.len()));
|
||||
}
|
||||
let (routing, payload) = v.split_at(3);
|
||||
Ok(MixCreationParameters {
|
||||
routing_information_length_by_stage: routing.try_into()?,
|
||||
payload_length_bytes: u16::from_le_bytes(payload.try_into()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl MixCreationParameters {
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = Vec::with_capacity(5);
|
||||
bytes.extend_from_slice(self.routing_information_length_by_stage.as_slice());
|
||||
bytes.extend_from_slice(&self.payload_length_bytes.to_le_bytes());
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn payload_length_bytes(&self) -> usize {
|
||||
self.payload_length_bytes as usize
|
||||
}
|
||||
|
||||
/// Create a set of parameters for a mix packet format.
|
||||
pub fn new(payload_length_bytes: usize) -> MixCreationParameters {
|
||||
pub fn new(payload_length_bytes: u16) -> MixCreationParameters {
|
||||
MixCreationParameters {
|
||||
routing_information_length_by_stage: Vec::new(),
|
||||
routing_information_length_by_stage: [DEFAULT_ROUTING_INFO_SIZE; 3],
|
||||
payload_length_bytes,
|
||||
}
|
||||
}
|
||||
|
||||
/// Add another outer layer containing some byte length of routing data.
|
||||
pub fn add_outer_layer(&mut self, routing_information_length_bytes: usize) {
|
||||
self.routing_information_length_by_stage
|
||||
.push(routing_information_length_bytes);
|
||||
}
|
||||
// pub fn add_outer_layer(&mut self, routing_information_length_bytes: usize) {
|
||||
// self.routing_information_length_by_stage
|
||||
// .push(routing_information_length_bytes);
|
||||
// }
|
||||
|
||||
/// The length of the buffer needed to build a packet.
|
||||
pub fn total_packet_length(&self) -> usize {
|
||||
let mut len = self.payload_length_bytes;
|
||||
let mut len = self.payload_length_bytes();
|
||||
for stage_len in &self.routing_information_length_by_stage {
|
||||
len += stage_len + GROUPELEMENTBYTES + TAGBYTES
|
||||
len += *stage_len as usize + groupelementbytes() + tagbytes()
|
||||
}
|
||||
len
|
||||
}
|
||||
@@ -126,7 +165,7 @@ impl MixCreationParameters {
|
||||
|
||||
return (total_size - inner_size..total_size, params);
|
||||
} else {
|
||||
remaining_header_length_bytes += stage_len + GROUPELEMENTBYTES + TAGBYTES;
|
||||
remaining_header_length_bytes += (stage_len + GROUPELEMENTBYTES + TAGBYTES) as u16;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,47 +176,59 @@ impl MixCreationParameters {
|
||||
/// A structure representing the parameters of a single stage of mixing.
|
||||
pub struct MixStageParameters {
|
||||
/// The routing information length for this stage of mixing
|
||||
pub routing_information_length_bytes: usize,
|
||||
pub routing_information_length_bytes: u8,
|
||||
/// The reamining header length for this stage of mixing
|
||||
pub remaining_header_length_bytes: usize,
|
||||
pub remaining_header_length_bytes: u16,
|
||||
/// The payload length
|
||||
pub payload_length_bytes: usize,
|
||||
pub payload_length_bytes: u16,
|
||||
}
|
||||
|
||||
impl MixStageParameters {
|
||||
pub fn routing_information_length_bytes(&self) -> usize {
|
||||
self.routing_information_length_bytes as usize
|
||||
}
|
||||
|
||||
pub fn remaining_header_length_bytes(&self) -> usize {
|
||||
self.remaining_header_length_bytes as usize
|
||||
}
|
||||
|
||||
pub fn payload_length_bytes(&self) -> usize {
|
||||
self.payload_length_bytes as usize
|
||||
}
|
||||
|
||||
pub fn incoming_packet_length(&self) -> usize {
|
||||
GROUPELEMENTBYTES + TAGBYTES + self.outgoing_packet_length()
|
||||
groupelementbytes() + tagbytes() + self.outgoing_packet_length()
|
||||
}
|
||||
|
||||
pub fn outgoing_packet_length(&self) -> usize {
|
||||
self.routing_information_length_bytes
|
||||
+ self.remaining_header_length_bytes
|
||||
+ self.payload_length_bytes
|
||||
self.routing_information_length_bytes()
|
||||
+ self.remaining_header_length_bytes()
|
||||
+ self.payload_length_bytes()
|
||||
}
|
||||
|
||||
pub fn pub_element_range(&self) -> Range<usize> {
|
||||
0..GROUPELEMENTBYTES
|
||||
0..groupelementbytes()
|
||||
}
|
||||
|
||||
pub fn tag_range(&self) -> Range<usize> {
|
||||
GROUPELEMENTBYTES..GROUPELEMENTBYTES + TAGBYTES
|
||||
groupelementbytes()..groupelementbytes() + tagbytes()
|
||||
}
|
||||
|
||||
pub fn routing_data_range(&self) -> Range<usize> {
|
||||
GROUPELEMENTBYTES + TAGBYTES
|
||||
..GROUPELEMENTBYTES + TAGBYTES + self.routing_information_length_bytes
|
||||
groupelementbytes() + tagbytes()
|
||||
..groupelementbytes() + tagbytes() + self.routing_information_length_bytes()
|
||||
}
|
||||
|
||||
pub fn header_range(&self) -> Range<usize> {
|
||||
GROUPELEMENTBYTES + TAGBYTES
|
||||
..GROUPELEMENTBYTES
|
||||
+ TAGBYTES
|
||||
+ self.routing_information_length_bytes
|
||||
+ self.remaining_header_length_bytes
|
||||
groupelementbytes() + tagbytes()
|
||||
..groupelementbytes()
|
||||
+ tagbytes()
|
||||
+ self.routing_information_length_bytes()
|
||||
+ self.remaining_header_length_bytes()
|
||||
}
|
||||
|
||||
pub fn payload_range(&self) -> Range<usize> {
|
||||
self.incoming_packet_length() - self.payload_length_bytes..self.incoming_packet_length()
|
||||
self.incoming_packet_length() - self.payload_length_bytes()..self.incoming_packet_length()
|
||||
}
|
||||
|
||||
pub fn encode_mix_layer(
|
||||
@@ -197,10 +248,10 @@ impl MixStageParameters {
|
||||
});
|
||||
}
|
||||
|
||||
if routing_data.len() != self.routing_information_length_bytes {
|
||||
if routing_data.len() != self.routing_information_length_bytes() {
|
||||
return Err(OutfoxError::LenMismatch {
|
||||
expected: routing_data.len(),
|
||||
got: self.routing_information_length_bytes,
|
||||
got: self.routing_information_length_bytes(),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -272,3 +323,25 @@ impl MixStageParameters {
|
||||
Ok(shared_key)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::MixCreationParameters;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[test]
|
||||
fn test_to_bytes() {
|
||||
let mix_params = MixCreationParameters::new(1024);
|
||||
assert_eq!(mix_params.to_bytes(), vec![32, 32, 32, 0, 4])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_bytes() {
|
||||
let params_bytes = vec![32, 32, 32, 0, 4];
|
||||
let mix_params = MixCreationParameters::new(1024);
|
||||
assert_eq!(
|
||||
mix_params,
|
||||
MixCreationParameters::try_from(params_bytes.as_slice()).unwrap()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+47
-14
@@ -1,38 +1,71 @@
|
||||
use std::ops::Range;
|
||||
use std::{convert::TryFrom, ops::Range};
|
||||
|
||||
use crate::{
|
||||
error::OutfoxError,
|
||||
format::{MixCreationParameters, MixStageParameters},
|
||||
format::{
|
||||
groupelementbytes, tagbytes, MixCreationParameters, MixStageParameters, MIX_PARAMS_LEN,
|
||||
},
|
||||
};
|
||||
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
use sphinx_packet::{packet::builder::DEFAULT_PAYLOAD_SIZE, route::Node};
|
||||
|
||||
pub const OUTFOX_PACKET_OVERHEAD: usize =
|
||||
MIX_PARAMS_LEN + (groupelementbytes() + tagbytes() + DEFAULT_ROUTING_INFO_SIZE as usize) * 3;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OutfoxPacket {
|
||||
mix_params: MixCreationParameters,
|
||||
payload: Vec<u8>,
|
||||
}
|
||||
|
||||
pub const DEFAULT_ROUTING_INFO_SIZE: usize = 32;
|
||||
pub const DEFAULT_ROUTING_INFO_SIZE: u8 = 32;
|
||||
|
||||
impl TryFrom<&[u8]> for OutfoxPacket {
|
||||
type Error = OutfoxError;
|
||||
|
||||
fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
|
||||
let (header, payload) = v.split_at(MIX_PARAMS_LEN);
|
||||
Ok(OutfoxPacket {
|
||||
mix_params: MixCreationParameters::try_from(header)?,
|
||||
payload: payload.to_vec(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl OutfoxPacket {
|
||||
pub fn build(
|
||||
payload: &[u8],
|
||||
pub fn len(&self) -> usize {
|
||||
self.mix_params().total_packet_length()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Result<Vec<u8>, OutfoxError> {
|
||||
let mut bytes = vec![];
|
||||
bytes.extend(self.mix_params.to_bytes());
|
||||
bytes.extend(self.payload.as_slice());
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
pub fn build<M: AsRef<[u8]>>(
|
||||
payload: M,
|
||||
route: &[Node; 3],
|
||||
user_secret_key: &[u8],
|
||||
packet_size: Option<usize>,
|
||||
) -> Result<OutfoxPacket, OutfoxError> {
|
||||
let mut mix_params = MixCreationParameters::new(DEFAULT_PAYLOAD_SIZE);
|
||||
let mut secret_key = [0; 32];
|
||||
OsRng.fill_bytes(&mut secret_key);
|
||||
let packet_size = packet_size.unwrap_or(DEFAULT_PAYLOAD_SIZE);
|
||||
let mix_params = MixCreationParameters::new(packet_size as u16);
|
||||
|
||||
for node in route.iter() {
|
||||
mix_params.add_outer_layer(node.address.as_bytes_ref().len());
|
||||
}
|
||||
|
||||
let padding = mix_params.total_packet_length() - payload.len();
|
||||
let padding = mix_params.total_packet_length() - payload.as_ref().len();
|
||||
let mut buffer = vec![0; padding];
|
||||
buffer.extend_from_slice(payload);
|
||||
buffer.extend_from_slice(payload.as_ref());
|
||||
|
||||
for (idx, node) in route.iter().rev().enumerate() {
|
||||
let (range, stage_params) = mix_params.get_stage_params(idx);
|
||||
stage_params.encode_mix_layer(&mut buffer[range], user_secret_key, node)?;
|
||||
stage_params.encode_mix_layer(&mut buffer[range], &secret_key, node)?;
|
||||
}
|
||||
|
||||
Ok(OutfoxPacket {
|
||||
|
||||
@@ -3,25 +3,25 @@ extern crate nym_outfox;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
use nym_outfox::packet::OutfoxPacket;
|
||||
use sphinx_packet::constants::NODE_ADDRESS_LENGTH;
|
||||
use sphinx_packet::crypto::PublicKey;
|
||||
use sphinx_packet::packet::builder::DEFAULT_PAYLOAD_SIZE;
|
||||
use sphinx_packet::route::Node;
|
||||
use sphinx_packet::route::NodeAddressBytes;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use nym_outfox::format::*;
|
||||
use nym_outfox::lion::*;
|
||||
|
||||
use std::iter::repeat_with;
|
||||
|
||||
pub fn randombytes(n: usize) -> Vec<u8> {
|
||||
repeat_with(|| fastrand::u8(..)).take(n).collect()
|
||||
}
|
||||
|
||||
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
use nym_outfox::packet::OutfoxPacket;
|
||||
use sphinx_packet::constants::NODE_ADDRESS_LENGTH;
|
||||
use sphinx_packet::crypto::PublicKey;
|
||||
use sphinx_packet::route::Node;
|
||||
use sphinx_packet::route::NodeAddressBytes;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use nym_outfox::format::*;
|
||||
use nym_outfox::lion::*;
|
||||
|
||||
#[test]
|
||||
fn test_encode_decode() {
|
||||
let mix_params = MixStageParameters {
|
||||
@@ -81,8 +81,6 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_packet_params() {
|
||||
let user_secret = randombytes(32);
|
||||
|
||||
let (node1_pk, node1_pub) = sphinx_packet::crypto::keygen();
|
||||
let node1 = Node::new(
|
||||
NodeAddressBytes::from_bytes([0u8; NODE_ADDRESS_LENGTH]),
|
||||
@@ -101,9 +99,17 @@ mod tests {
|
||||
|
||||
let route = [node1, node2, node3];
|
||||
|
||||
let payload = randombytes(DEFAULT_PAYLOAD_SIZE);
|
||||
let payload = randombytes(2048);
|
||||
|
||||
let mut packet = OutfoxPacket::build(&payload, &route, &user_secret).unwrap();
|
||||
let packet = OutfoxPacket::build(&payload, &route, Some(2048)).unwrap();
|
||||
let packet_bytes = packet.to_bytes().unwrap();
|
||||
println!(
|
||||
"packet bytes length, {}, declared {}",
|
||||
packet_bytes.len(),
|
||||
packet.len()
|
||||
);
|
||||
|
||||
let mut packet = OutfoxPacket::try_from(packet_bytes.as_slice()).unwrap();
|
||||
|
||||
packet.decode_mix_layer(2, &node1_pk.to_bytes()).unwrap();
|
||||
packet.decode_mix_layer(1, &node2_pk.to_bytes()).unwrap();
|
||||
|
||||
Generated
+181
-6
@@ -23,6 +23,16 @@ dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.7.5"
|
||||
@@ -30,7 +40,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cipher 0.3.0",
|
||||
"cpufeatures",
|
||||
"ctr",
|
||||
"opaque-debug 0.3.0",
|
||||
@@ -42,9 +52,9 @@ version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"aead 0.4.3",
|
||||
"aes",
|
||||
"cipher",
|
||||
"cipher 0.3.0",
|
||||
"ctr",
|
||||
"ghash",
|
||||
"subtle 2.4.1",
|
||||
@@ -119,6 +129,12 @@ version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.64"
|
||||
@@ -288,6 +304,20 @@ dependencies = [
|
||||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"constant_time_eq",
|
||||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
@@ -496,6 +526,30 @@ dependencies = [
|
||||
"keystream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher 0.4.4",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chacha20poly1305"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
|
||||
dependencies = [
|
||||
"aead 0.5.2",
|
||||
"chacha20",
|
||||
"cipher 0.4.4",
|
||||
"poly1305",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.3.0"
|
||||
@@ -505,6 +559,17 @@ dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.4"
|
||||
@@ -636,6 +701,12 @@ version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b"
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
@@ -782,6 +853,30 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset 0.8.0",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.14"
|
||||
@@ -816,6 +911,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
"rand_core 0.6.4",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
@@ -891,7 +987,7 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
"cipher 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1342,7 +1438,7 @@ version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"memoffset 0.6.5",
|
||||
"rustc_version 0.3.3",
|
||||
]
|
||||
|
||||
@@ -2239,6 +2335,15 @@ dependencies = [
|
||||
"cfb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"generic-array 0.14.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
@@ -2573,6 +2678,15 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.16"
|
||||
@@ -2959,6 +3073,22 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-outfox"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"blake3",
|
||||
"chacha20",
|
||||
"chacha20poly1305",
|
||||
"curve25519-dalek",
|
||||
"getrandom 0.2.8",
|
||||
"rand 0.7.3",
|
||||
"rayon",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-pemstore"
|
||||
version = "0.2.0"
|
||||
@@ -2970,7 +3100,9 @@ dependencies = [
|
||||
name = "nym-sphinx-types"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"nym-outfox",
|
||||
"sphinx-packet",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3642,6 +3774,17 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "poly1305"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
|
||||
dependencies = [
|
||||
"cpufeatures",
|
||||
"opaque-debug 0.3.0",
|
||||
"universal-hash 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.5.3"
|
||||
@@ -3651,7 +3794,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"opaque-debug 0.3.0",
|
||||
"universal-hash",
|
||||
"universal-hash 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3894,6 +4037,28 @@ dependencies = [
|
||||
"cty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
@@ -5441,6 +5606,16 @@ dependencies = [
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d3160b73c9a19f7e2939a2fdad446c57c1bbbbf4d919d3213ff1267a580d8b5"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"subtle 2.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
|
||||
@@ -590,6 +590,7 @@ where
|
||||
client_state,
|
||||
reconstructed_receiver,
|
||||
task_manager: started_client.task_manager,
|
||||
packet_type: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use nym_client_core::client::{
|
||||
};
|
||||
use nym_sphinx::{
|
||||
addressing::clients::{ClientIdentity, Recipient},
|
||||
params::PacketType,
|
||||
receiver::ReconstructedMessage,
|
||||
};
|
||||
use nym_task::{
|
||||
@@ -45,6 +46,7 @@ pub struct MixnetClient {
|
||||
|
||||
/// The task manager that controlls all the spawned tasks that the clients uses to do it's job.
|
||||
pub(crate) task_manager: TaskManager,
|
||||
pub(crate) packet_type: Option<PacketType>,
|
||||
}
|
||||
|
||||
impl MixnetClient {
|
||||
@@ -163,9 +165,11 @@ impl MixnetClient {
|
||||
let lane = TransmissionLane::General;
|
||||
let input_msg = match surbs {
|
||||
IncludedSurbs::Amount(surbs) => {
|
||||
InputMessage::new_anonymous(address, message, surbs, lane)
|
||||
InputMessage::new_anonymous(address, message, surbs, lane, self.packet_type)
|
||||
}
|
||||
IncludedSurbs::ExposeSelfAddress => {
|
||||
InputMessage::new_regular(address, message, lane, self.packet_type)
|
||||
}
|
||||
IncludedSurbs::ExposeSelfAddress => InputMessage::new_regular(address, message, lane),
|
||||
};
|
||||
self.send(input_msg).await
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user