Moved relevant parts of old mix-client to nymsphinx (#221)

This commit is contained in:
Jędrzej Stuczyński
2020-05-06 16:18:27 +01:00
committed by GitHub
parent c3e18cedd5
commit f9d3ee7fc4
16 changed files with 105 additions and 257 deletions
Generated
+1 -15
View File
@@ -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",
]
-1
View File
@@ -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",
-1
View File
@@ -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"}
@@ -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<T: NymTopology> Stream for LoopCoverTrafficStream<T> {
// 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<T: 'static + NymTopology> LoopCoverTrafficStream<T> {
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<T: 'static + NymTopology> LoopCoverTrafficStream<T> {
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;
@@ -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<T: NymTopology> Stream for OutQueueControl<T> {
// 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<T: 'static + NymTopology> OutQueueControl<T> {
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<T: 'static + NymTopology> OutQueueControl<T> {
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<T: 'static + NymTopology> OutQueueControl<T> {
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 {
@@ -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;
-18
View File
@@ -1,18 +0,0 @@
[package]
name = "mix-client"
version = "0.1.0"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
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"}
-69
View File
@@ -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<dyn std::error::Error>> {
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?
}
}
-129
View File
@@ -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<topology::NymTopologyError> for SphinxPacketEncapsulationError {
fn from(_: NymTopologyError) -> Self {
use SphinxPacketEncapsulationError::*;
InvalidTopologyError
}
}
impl From<nymsphinx::Error> for SphinxPacketEncapsulationError {
fn from(err: nymsphinx::Error) -> Self {
SphinxPacketEncapsulationError::SphinxError(err)
}
}
impl From<NymNodeRoutingAddressError> for SphinxPacketEncapsulationError {
fn from(_: NymNodeRoutingAddressError) -> Self {
use SphinxPacketEncapsulationError::*;
InvalidFirstMixAddress
}
}
#[deprecated(note = "please use loop_cover_message_route instead")]
pub fn loop_cover_message<T: NymTopology>(
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<nymsphinx::Node>,
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<T: NymTopology>(
recipient: Destination,
message: Vec<u8>,
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<u8>,
route: Vec<nymsphinx::Node>,
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))
}
+1
View File
@@ -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" }
+1
View File
@@ -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
@@ -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<SphinxError> for SphinxPacketEncapsulationError {
fn from(err: SphinxError) -> Self {
SphinxPacketEncapsulationError::SphinxError(err)
}
}
impl From<NymNodeRoutingAddressError> for SphinxPacketEncapsulationError {
fn from(_: NymNodeRoutingAddressError) -> Self {
use SphinxPacketEncapsulationError::*;
InvalidFirstMixAddress
}
}
pub fn loop_cover_message_route(
our_address: DestinationAddressBytes,
surb_id: SURBIdentifier,
route: Vec<SphinxNode>,
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<u8>,
route: Vec<SphinxNode>,
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))
}
+2
View File
@@ -0,0 +1,2 @@
pub mod encapsulation;
pub mod poisson;
-6
View File
@@ -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
@@ -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;