diff --git a/Cargo.lock b/Cargo.lock index 625bd264d6..5bab68628e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1504,19 +1504,6 @@ dependencies = [ "winapi 0.3.8", ] -[[package]] -name = "mix-client" -version = "0.1.0" -dependencies = [ - "log 0.4.8", - "nymsphinx", - "pretty_env_logger", - "rand 0.7.3", - "rand_distr", - "tokio 0.2.16", - "topology", -] - [[package]] name = "mockito" version = "0.23.3" @@ -1625,7 +1612,6 @@ dependencies = [ "gateway-client", "gateway-requests", "log 0.4.8", - "mix-client", "multi-tcp-client", "nymsphinx", "pem", @@ -1656,7 +1642,6 @@ dependencies = [ "gateway-requests", "hmac", "log 0.4.8", - "mix-client", "multi-tcp-client", "nymsphinx", "pemstore", @@ -1730,6 +1715,7 @@ version = "0.1.0" dependencies = [ "log 0.4.8", "rand 0.7.3", + "rand_distr", "sphinx", ] diff --git a/Cargo.toml b/Cargo.toml index 50cc1f2452..121ba955fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ members = [ "clients/webassembly", "common/client-libs/directory-client", "common/client-libs/gateway-client", - "common/client-libs/mix-client", "common/client-libs/multi-tcp-client", "common/client-libs/validator-client", "common/config", diff --git a/clients/desktop/Cargo.toml b/clients/desktop/Cargo.toml index 8c0be25b71..63d64c4ad8 100644 --- a/clients/desktop/Cargo.toml +++ b/clients/desktop/Cargo.toml @@ -34,7 +34,6 @@ crypto = {path = "../../common/crypto"} directory-client = { path = "../../common/client-libs/directory-client" } gateway-client = { path = "../../common/client-libs/gateway-client" } gateway-requests = { path = "../../gateway/gateway-requests" } -mix-client = { path = "../../common/client-libs/mix-client" } multi-tcp-client = { path = "../../common/client-libs/multi-tcp-client" } nymsphinx = { path = "../../common/nymsphinx" } pemstore = {path = "../../common/pemstore"} diff --git a/clients/desktop/src/client/cover_traffic_stream.rs b/clients/desktop/src/client/cover_traffic_stream.rs index fc1edf59d8..9167e263e9 100644 --- a/clients/desktop/src/client/cover_traffic_stream.rs +++ b/clients/desktop/src/client/cover_traffic_stream.rs @@ -17,7 +17,10 @@ use crate::client::topology_control::TopologyAccessor; use futures::task::{Context, Poll}; use futures::{Future, Stream, StreamExt}; use log::*; -use nymsphinx::Destination; +use nymsphinx::{ + utils::{encapsulation, poisson}, + Destination, +}; use std::pin::Pin; use std::time::Duration; use tokio::runtime::Handle; @@ -50,8 +53,7 @@ impl Stream for LoopCoverTrafficStream { // we know it's time to send a message, so let's prepare delay for the next one // Get the `now` by looking at the current `delay` deadline let now = self.next_delay.deadline(); - let next_poisson_delay = - mix_client::poisson::sample(self.average_cover_message_sending_delay); + let next_poisson_delay = poisson::sample(self.average_cover_message_sending_delay); // The next interval value is `next_poisson_delay` after the one that just // yielded. @@ -90,7 +92,7 @@ impl LoopCoverTrafficStream { Some(route) => route, }; - let cover_message = match mix_client::packet::loop_cover_message_route( + let cover_message = match encapsulation::loop_cover_message_route( self.our_info.address.clone(), self.our_info.identifier, route, @@ -120,9 +122,8 @@ impl LoopCoverTrafficStream { async fn run(&mut self) { // we should set initial delay only when we actually start the stream - self.next_delay = time::delay_for(mix_client::poisson::sample( - self.average_cover_message_sending_delay, - )); + self.next_delay = + time::delay_for(poisson::sample(self.average_cover_message_sending_delay)); while let Some(_) = self.next().await { self.on_new_message().await; diff --git a/clients/desktop/src/client/real_traffic_stream.rs b/clients/desktop/src/client/real_traffic_stream.rs index 31a6822ce5..dade3651ad 100644 --- a/clients/desktop/src/client/real_traffic_stream.rs +++ b/clients/desktop/src/client/real_traffic_stream.rs @@ -19,7 +19,10 @@ use futures::channel::mpsc; use futures::task::{Context, Poll}; use futures::{Future, Stream, StreamExt}; use log::{error, info, trace, warn}; -use nymsphinx::{Destination, DestinationAddressBytes}; +use nymsphinx::{ + utils::{encapsulation, poisson}, + Destination, DestinationAddressBytes, +}; use std::pin::Pin; use std::time::Duration; use tokio::runtime::Handle; @@ -54,7 +57,7 @@ impl Stream for OutQueueControl { // we know it's time to send a message, so let's prepare delay for the next one // Get the `now` by looking at the current `delay` deadline let now = self.next_delay.deadline(); - let next_poisson_delay = mix_client::poisson::sample(self.average_message_sending_delay); + let next_poisson_delay = poisson::sample(self.average_message_sending_delay); // The next interval value is `next_poisson_delay` after the one that just // yielded. @@ -118,7 +121,7 @@ impl OutQueueControl { warn!("No valid topology detected - won't send any real or loop message this time"); } let route = route.unwrap(); - mix_client::packet::loop_cover_message_route( + encapsulation::loop_cover_message_route( self.our_info.address.clone(), self.our_info.identifier, route, @@ -131,7 +134,7 @@ impl OutQueueControl { warn!("No valid topology detected - won't send any real or loop message this time"); } let route = route.unwrap(); - mix_client::packet::encapsulate_message_route( + encapsulation::encapsulate_message_route( real_message.0, real_message.1, route, @@ -168,9 +171,7 @@ impl OutQueueControl { pub(crate) async fn run_out_queue_control(mut self) { // we should set initial delay only when we actually start the stream - self.next_delay = time::delay_for(mix_client::poisson::sample( - self.average_message_sending_delay, - )); + self.next_delay = time::delay_for(poisson::sample(self.average_message_sending_delay)); info!("starting out queue controller"); while let Some(next_message) = self.next().await { diff --git a/clients/desktop/src/client/received_buffer.rs b/clients/desktop/src/client/received_buffer.rs index 3e11edd530..af8eebd0e6 100644 --- a/clients/desktop/src/client/received_buffer.rs +++ b/clients/desktop/src/client/received_buffer.rs @@ -17,8 +17,10 @@ use futures::lock::Mutex; use futures::StreamExt; use gateway_client::SphinxPacketReceiver; use log::*; -use mix_client::packet::LOOP_COVER_MESSAGE_PAYLOAD; -use nymsphinx::chunking::reconstruction::MessageReconstructor; +use nymsphinx::{ + chunking::reconstruction::MessageReconstructor, + utils::encapsulation::LOOP_COVER_MESSAGE_PAYLOAD, +}; use std::sync::Arc; use tokio::runtime::Handle; use tokio::task::JoinHandle; diff --git a/common/client-libs/mix-client/Cargo.toml b/common/client-libs/mix-client/Cargo.toml deleted file mode 100644 index 6aebe3db33..0000000000 --- a/common/client-libs/mix-client/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "mix-client" -version = "0.1.0" -authors = ["Dave Hrycyszyn ", "Jędrzej Stuczyński "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -log = "0.4.8" -pretty_env_logger = "0.3" -rand = "0.7.2" -rand_distr = "0.2.2" -tokio = { version = "0.2", features = ["full"] } - -## internal -nymsphinx = {path = "../../nymsphinx"} -topology = {path = "../../topology"} diff --git a/common/client-libs/mix-client/src/lib.rs b/common/client-libs/mix-client/src/lib.rs deleted file mode 100644 index 1cca656b5b..0000000000 --- a/common/client-libs/mix-client/src/lib.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2020 Nym Technologies SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use log::*; -use nymsphinx::SphinxPacket; -use std::net::SocketAddr; -use tokio::prelude::*; - -pub mod packet; -pub mod poisson; - -pub struct MixClient {} - -impl MixClient { - #[allow(clippy::new_without_default)] - pub fn new() -> MixClient { - MixClient {} - } - - // Sends a Sphinx packet to a mixnode. - pub async fn send( - &self, - packet: SphinxPacket, - mix_addr: SocketAddr, - ) -> Result<(), Box> { - let bytes = packet.to_bytes(); - debug!("Sending to the following address: {:?}", mix_addr); - - let mut stream = tokio::net::TcpStream::connect(mix_addr).await?; - stream.write_all(&bytes[..]).await?; - Ok(()) - } -} - -#[cfg(test)] -mod sending_a_sphinx_packet { - // use super::*; - // use sphinx::SphinxPacket; - - #[test] - fn works() { - // arrange - // let directory = Client::new(); - // let message = "Hello, Sphinx!".as_bytes().to_vec(); - // let mixes = directory.get_mixes(); - // let destination = directory.get_destination(); - // let delays = sphinx::header::delays::generate(2); - // let packet = SphinxPacket::new(message, &mixes, &destination, &delays).unwrap(); - // let mix_client = MixClient::new(); - // let first_hop = mixes.first().unwrap(); - // - // // act - // mix_client.send(packet, first_hop); - - // assert - // wtf are we supposed to assert here? - } -} diff --git a/common/client-libs/mix-client/src/packet.rs b/common/client-libs/mix-client/src/packet.rs deleted file mode 100644 index 31bca84973..0000000000 --- a/common/client-libs/mix-client/src/packet.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2020 Nym Technologies SA -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use nymsphinx::addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError}; -use nymsphinx::{delays, Destination, DestinationAddressBytes, SURBIdentifier, SphinxPacket}; -use std::convert::TryFrom; -use std::net::SocketAddr; -use std::time; -use topology::{NymTopology, NymTopologyError}; - -pub const LOOP_COVER_MESSAGE_PAYLOAD: &[u8] = b"The cake is a lie!"; - -#[derive(Debug)] -pub enum SphinxPacketEncapsulationError { - NoValidProvidersError, - InvalidTopologyError, - SphinxError(nymsphinx::Error), - InvalidFirstMixAddress, -} - -impl From for SphinxPacketEncapsulationError { - fn from(_: NymTopologyError) -> Self { - use SphinxPacketEncapsulationError::*; - InvalidTopologyError - } -} - -impl From for SphinxPacketEncapsulationError { - fn from(err: nymsphinx::Error) -> Self { - SphinxPacketEncapsulationError::SphinxError(err) - } -} - -impl From for SphinxPacketEncapsulationError { - fn from(_: NymNodeRoutingAddressError) -> Self { - use SphinxPacketEncapsulationError::*; - InvalidFirstMixAddress - } -} - -#[deprecated(note = "please use loop_cover_message_route instead")] -pub fn loop_cover_message( - our_address: DestinationAddressBytes, - surb_id: SURBIdentifier, - topology: &T, - average_delay: time::Duration, -) -> Result<(SocketAddr, SphinxPacket), SphinxPacketEncapsulationError> { - let destination = Destination::new(our_address, surb_id); - - #[allow(deprecated)] - encapsulate_message( - destination, - LOOP_COVER_MESSAGE_PAYLOAD.to_vec(), - topology, - average_delay, - ) -} - -pub fn loop_cover_message_route( - our_address: DestinationAddressBytes, - surb_id: SURBIdentifier, - route: Vec, - average_delay: time::Duration, -) -> Result<(SocketAddr, SphinxPacket), SphinxPacketEncapsulationError> { - let destination = Destination::new(our_address, surb_id); - - encapsulate_message_route( - destination, - LOOP_COVER_MESSAGE_PAYLOAD.to_vec(), - route, - average_delay, - ) -} - -#[deprecated(note = "please use encapsulate_message_route instead")] -pub fn encapsulate_message( - recipient: Destination, - message: Vec, - topology: &T, - average_delay: time::Duration, -) -> Result<(SocketAddr, SphinxPacket), SphinxPacketEncapsulationError> { - let mut providers = topology.providers(); - if providers.is_empty() { - return Err(SphinxPacketEncapsulationError::NoValidProvidersError); - } - // unwrap is fine here as we asserted there is at least single provider - let provider = providers.pop().unwrap().into(); - - let route = topology.random_route_to(provider)?; - - let delays = delays::generate_from_average_duration(route.len(), average_delay); - - // build the packet - let packet = SphinxPacket::new(message, &route[..], &recipient, &delays, None)?; - - // we know the mix route must be valid otherwise we would have already returned an error - let first_node_address = - NymNodeRoutingAddress::try_from(route.first().unwrap().address.clone())?; - - Ok((first_node_address.into(), packet)) -} - -pub fn encapsulate_message_route( - recipient: Destination, - message: Vec, - route: Vec, - average_delay: time::Duration, -) -> Result<(SocketAddr, SphinxPacket), SphinxPacketEncapsulationError> { - let delays = delays::generate_from_average_duration(route.len(), average_delay); - - // build the packet - let packet = SphinxPacket::new(message, &route[..], &recipient, &delays, None)?; - - let first_node_address = - NymNodeRoutingAddress::try_from(route.first().unwrap().address.clone())?; - - Ok((first_node_address.into(), packet)) -} diff --git a/common/nymsphinx/Cargo.toml b/common/nymsphinx/Cargo.toml index fb3be3da06..f9596490dc 100644 --- a/common/nymsphinx/Cargo.toml +++ b/common/nymsphinx/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] log = "0.4.8" rand = {version = "0.7.3", features = ["wasm-bindgen"]} +rand_distr = "0.2.2" ## will be moved to proper dependencies once released sphinx = { git = "https://github.com/nymtech/sphinx", rev="72368ea048472823f7f9e78eed77a2c3d30a471f" } diff --git a/common/nymsphinx/src/lib.rs b/common/nymsphinx/src/lib.rs index 5488c2b08d..747a255baf 100644 --- a/common/nymsphinx/src/lib.rs +++ b/common/nymsphinx/src/lib.rs @@ -14,6 +14,7 @@ pub mod addressing; pub mod chunking; +pub mod utils; // Future consideration: currently in a lot of places, the payloads have randomised content // which is not a perfect testing strategy as it might not detect some edge cases I never would diff --git a/common/nymsphinx/src/utils/encapsulation.rs b/common/nymsphinx/src/utils/encapsulation.rs new file mode 100644 index 0000000000..7c3ada3153 --- /dev/null +++ b/common/nymsphinx/src/utils/encapsulation.rs @@ -0,0 +1,76 @@ +// Copyright 2020 Nym Technologies SA +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use crate::addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError}; +use crate::{delays, Destination, DestinationAddressBytes, SURBIdentifier, SphinxPacket}; +use crate::{Error as SphinxError, Node as SphinxNode}; +use std::convert::TryFrom; +use std::net::SocketAddr; +use std::time; + +pub const LOOP_COVER_MESSAGE_PAYLOAD: &[u8] = b"The cake is a lie!"; + +#[derive(Debug)] +pub enum SphinxPacketEncapsulationError { + NoValidProvidersError, + InvalidTopologyError, + SphinxError(SphinxError), + InvalidFirstMixAddress, +} + +impl From for SphinxPacketEncapsulationError { + fn from(err: SphinxError) -> Self { + SphinxPacketEncapsulationError::SphinxError(err) + } +} + +impl From for SphinxPacketEncapsulationError { + fn from(_: NymNodeRoutingAddressError) -> Self { + use SphinxPacketEncapsulationError::*; + InvalidFirstMixAddress + } +} + +pub fn loop_cover_message_route( + our_address: DestinationAddressBytes, + surb_id: SURBIdentifier, + route: Vec, + average_delay: time::Duration, +) -> Result<(SocketAddr, SphinxPacket), SphinxPacketEncapsulationError> { + let destination = Destination::new(our_address, surb_id); + + encapsulate_message_route( + destination, + LOOP_COVER_MESSAGE_PAYLOAD.to_vec(), + route, + average_delay, + ) +} + +pub fn encapsulate_message_route( + recipient: Destination, + message: Vec, + route: Vec, + average_delay: time::Duration, +) -> Result<(SocketAddr, SphinxPacket), SphinxPacketEncapsulationError> { + let delays = delays::generate_from_average_duration(route.len(), average_delay); + + // build the packet + let packet = SphinxPacket::new(message, &route[..], &recipient, &delays, None)?; + + let first_node_address = + NymNodeRoutingAddress::try_from(route.first().unwrap().address.clone())?; + + Ok((first_node_address.into(), packet)) +} diff --git a/common/nymsphinx/src/utils/mod.rs b/common/nymsphinx/src/utils/mod.rs new file mode 100644 index 0000000000..3235d6d540 --- /dev/null +++ b/common/nymsphinx/src/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod encapsulation; +pub mod poisson; diff --git a/common/client-libs/mix-client/src/poisson.rs b/common/nymsphinx/src/utils/poisson.rs similarity index 100% rename from common/client-libs/mix-client/src/poisson.rs rename to common/nymsphinx/src/utils/poisson.rs diff --git a/gateway/Cargo.toml b/gateway/Cargo.toml index 27fed8288c..0c7df9c53c 100644 --- a/gateway/Cargo.toml +++ b/gateway/Cargo.toml @@ -31,12 +31,6 @@ multi-tcp-client = { path = "../common/client-libs/multi-tcp-client" } nymsphinx = { path = "../common/nymsphinx" } pemstore = { path = "../common/pemstore" } -# this dependency is due to requiring to know content of loop message. however, mix-client module itself -# is going to be removed or renamed at some point as it no longer servers its purpose of sending traffic to mix network -# and only provides utility functions -mix-client = { path = "../common/client-libs/mix-client" } - - [dependencies.tungstenite] version = "0.10.0" default-features = false diff --git a/gateway/src/node/mixnet_handling/receiver/packet_processing.rs b/gateway/src/node/mixnet_handling/receiver/packet_processing.rs index 33e7cce31b..a62f6a77ea 100644 --- a/gateway/src/node/mixnet_handling/receiver/packet_processing.rs +++ b/gateway/src/node/mixnet_handling/receiver/packet_processing.rs @@ -21,8 +21,10 @@ use crypto::encryption; use futures::channel::oneshot; use futures::lock::Mutex; use log::*; -use mix_client::packet::LOOP_COVER_MESSAGE_PAYLOAD; -use nymsphinx::{DestinationAddressBytes, Error as SphinxError, ProcessedPacket, SphinxPacket}; +use nymsphinx::{ + utils::encapsulation::LOOP_COVER_MESSAGE_PAYLOAD, DestinationAddressBytes, + Error as SphinxError, ProcessedPacket, SphinxPacket, +}; use std::collections::HashMap; use std::io; use std::ops::Deref;