From cbd654d6fdfb05f7b1cb8d66bf81aebda76f7586 Mon Sep 17 00:00:00 2001 From: Drazen Urch Date: Thu, 20 Apr 2023 23:59:40 +0200 Subject: [PATCH] Outfox rest compat (#3333) * Outfox forwarding compat * Tidy up interface * PacketSize compat --- Cargo.lock | 1 + .../real_traffic_stream.rs | 2 +- .../client-libs/gateway-client/src/client.rs | 6 +- .../mixnet-client/src/forwarder.rs | 5 +- .../src/packet_processor/processor.rs | 6 +- .../acknowledgements/src/surb_ack.rs | 33 ++++---- .../anonymous-replies/src/reply_surb.rs | 6 +- common/nymsphinx/cover/src/lib.rs | 20 ++--- common/nymsphinx/forwarding/Cargo.toml | 1 + common/nymsphinx/forwarding/src/packet.rs | 79 ++++++++----------- common/nymsphinx/framing/src/codec.rs | 55 +++++-------- common/nymsphinx/params/src/packet_sizes.rs | 54 +++++++++++-- common/nymsphinx/src/preparer/mod.rs | 28 ++++--- common/nymsphinx/src/preparer/payload.rs | 17 ++-- common/nymsphinx/src/receiver.rs | 45 ----------- common/nymsphinx/types/src/lib.rs | 44 ++++++++++- common/topology/src/lib.rs | 3 + gateway/gateway-requests/src/types.rs | 9 ++- .../connection_handler/authenticated.rs | 2 +- mixnode/src/node/packet_delayforwarder.rs | 23 +++--- nym-connect/desktop/Cargo.lock | 1 + nym-outfox/Cargo.toml | 5 -- nym-outfox/src/packet.rs | 8 +- 23 files changed, 239 insertions(+), 214 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7024761e7a..f3e12de6b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4061,6 +4061,7 @@ dependencies = [ "nym-sphinx-addressing", "nym-sphinx-params", "nym-sphinx-types", + "thiserror", ] [[package]] diff --git a/common/client-core/src/client/real_messages_control/real_traffic_stream.rs b/common/client-core/src/client/real_messages_control/real_traffic_stream.rs index dfced77063..3aea9611cd 100644 --- a/common/client-core/src/client/real_messages_control/real_traffic_stream.rs +++ b/common/client-core/src/client/real_messages_control/real_traffic_stream.rs @@ -136,7 +136,7 @@ impl From 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 { diff --git a/common/client-libs/gateway-client/src/client.rs b/common/client-libs/gateway-client/src/client.rs index 5efb5a8119..c226c59959 100644 --- a/common/client-libs/gateway-client/src/client.rs +++ b/common/client-libs/gateway-client/src/client.rs @@ -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::() 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, )); } diff --git a/common/client-libs/mixnet-client/src/forwarder.rs b/common/client-libs/mixnet-client/src/forwarder.rs index 4defb056d7..ceef3e35e8 100644 --- a/common/client-libs/mixnet-client/src/forwarder.rs +++ b/common/client-libs/mixnet-client/src/forwarder.rs @@ -6,7 +6,6 @@ use futures::channel::mpsc; use futures::StreamExt; use log::*; use nym_sphinx::forwarding::packet::MixPacket; -use nym_sphinx::NymPacket; use std::time::Duration; pub type MixForwardingSender = mpsc::UnboundedSender; @@ -61,13 +60,13 @@ impl PacketForwarder { let next_hop = mix_packet.next_hop(); let packet_mode = mix_packet.packet_mode(); - let sphinx_packet = mix_packet.into_sphinx_packet(); + 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, NymPacket::Sphinx(sphinx_packet), packet_mode) + .send_without_response(next_hop, packet, packet_mode) { debug!("failed to forward the packet - {err}") } diff --git a/common/mixnode-common/src/packet_processor/processor.rs b/common/mixnode-common/src/packet_processor/processor.rs index c0295e2894..307d74a77a 100644 --- a/common/mixnode-common/src/packet_processor/processor.rs +++ b/common/mixnode-common/src/packet_processor/processor.rs @@ -11,7 +11,7 @@ use nym_sphinx_framing::packet::FramedNymPacket; use nym_sphinx_params::{PacketMode, PacketSize}; use nym_sphinx_types::{ Delay as SphinxDelay, DestinationAddressBytes, NodeAddressBytes, NymPacket, Payload, - PrivateKey, ProcessedPacket, SphinxPacket, + PrivateKey, ProcessedPacket, }; use std::convert::TryFrom; use std::sync::Arc; @@ -90,7 +90,7 @@ 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, @@ -180,7 +180,7 @@ impl SphinxPacketProcessor { ) -> Result { 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_mode) } // right now there's no use for the surb_id included in the header - probably it should get removed from the // sphinx all together? diff --git a/common/nymsphinx/acknowledgements/src/surb_ack.rs b/common/nymsphinx/acknowledgements/src/surb_ack.rs index 9331fbb26f..39d4fc47dd 100644 --- a/common/nymsphinx/acknowledgements/src/surb_ack.rs +++ b/common/nymsphinx/acknowledgements/src/surb_ack.rs @@ -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::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) { + pub fn prepare_for_sending(self) -> Result<(Delay, Vec), 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)) } diff --git a/common/nymsphinx/anonymous-replies/src/reply_surb.rs b/common/nymsphinx/anonymous-replies/src/reply_surb.rs index e501623a81..e9b1f4ca14 100644 --- a/common/nymsphinx/anonymous-replies/src/reply_surb.rs +++ b/common/nymsphinx/anonymous-replies/src/reply_surb.rs @@ -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, SURBMaterial, SphinxError, 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)) } } diff --git a/common/nymsphinx/cover/src/lib.rs b/common/nymsphinx/cover/src/lib.rs index 608ef1a1ae..c81d083fae 100644 --- a/common/nymsphinx/cover/src/lib.rs +++ b/common/nymsphinx/cover/src/lib.rs @@ -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; @@ -14,7 +14,7 @@ use nym_sphinx_params::{ PacketEncryptionAlgorithm, PacketHkdfAlgorithm, PacketMode, DEFAULT_NUM_MIX_HOPS, }; use nym_sphinx_types::builder::SphinxPacketBuilder; -use nym_sphinx_types::{delays, 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( @@ -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,10 +111,12 @@ 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(); diff --git a/common/nymsphinx/forwarding/Cargo.toml b/common/nymsphinx/forwarding/Cargo.toml index df071403a6..6509098398 100644 --- a/common/nymsphinx/forwarding/Cargo.toml +++ b/common/nymsphinx/forwarding/Cargo.toml @@ -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" diff --git a/common/nymsphinx/forwarding/src/packet.rs b/common/nymsphinx/forwarding/src/packet.rs index 024b80b005..484c26c752 100644 --- a/common/nymsphinx/forwarding/src/packet.rs +++ b/common/nymsphinx/forwarding/src/packet.rs @@ -3,41 +3,27 @@ use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError}; use nym_sphinx_params::{PacketMode, PacketSize}; -use nym_sphinx_types::SphinxPacket; +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, + #[error("provided packet mode is invalid")] InvalidPacketMode, + #[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 for MixPacketFormattingError { fn from(_: NymNodeRoutingAddressError) -> Self { MixPacketFormattingError::InvalidAddress @@ -46,7 +32,7 @@ impl From for MixPacketFormattingError { pub struct MixPacket { next_hop: NymNodeRoutingAddress, - sphinx_packet: SphinxPacket, + packet: NymPacket, packet_mode: PacketMode, } @@ -54,11 +40,8 @@ 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_mode {:?}. Packet {:?}", + self.next_hop, self.packet_mode, self.packet ) } } @@ -66,12 +49,12 @@ impl Debug for MixPacket { impl MixPacket { pub fn new( next_hop: NymNodeRoutingAddress, - sphinx_packet: SphinxPacket, + packet: NymPacket, packet_mode: PacketMode, ) -> Self { MixPacket { next_hop, - sphinx_packet, + packet, packet_mode, } } @@ -80,12 +63,12 @@ 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 { @@ -93,7 +76,7 @@ impl MixPacket { } // the message is formatted as follows: - // PACKET_MODE || FIRST_HOP || SPHINX_PACKET + // PACKET_MODE || FIRST_HOP || packet pub fn try_from_bytes(b: &[u8]) -> Result { let packet_mode = match PacketMode::try_from(b[0]) { Ok(mode) => mode, @@ -103,29 +86,29 @@ impl MixPacket { 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_mode { + PacketMode::Outfox => NymPacket::outfox_from_bytes(packet_data)?, + _ => NymPacket::sphinx_from_bytes(packet_data)?, }; Ok(MixPacket { next_hop, - sphinx_packet, + packet, packet_mode, }) } } - pub fn into_bytes(self) -> Vec { - std::iter::once(self.packet_mode as u8) + pub fn into_bytes(self) -> Result, MixPacketFormattingError> { + Ok(std::iter::once(self.packet_mode 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()) } } diff --git a/common/nymsphinx/framing/src/codec.rs b/common/nymsphinx/framing/src/codec.rs index d29f9c43f3..a7989d4250 100644 --- a/common/nymsphinx/framing/src/codec.rs +++ b/common/nymsphinx/framing/src/codec.rs @@ -6,8 +6,7 @@ use bytes::{Buf, BufMut, BytesMut}; use nym_sphinx_params::packet_modes::InvalidPacketMode; use nym_sphinx_params::packet_sizes::{InvalidPacketSize, PacketSize}; use nym_sphinx_params::PacketMode; -use nym_sphinx_types::{NymPacket, NymPacketError, SphinxError}; -use nym_sphinx_types::{OutfoxError, OutfoxPacket, SphinxPacket}; +use nym_sphinx_types::{NymPacket, NymPacketError}; use std::io; use thiserror::Error; use tokio_util::codec::{Decoder, Encoder}; @@ -20,12 +19,6 @@ pub enum NymCodecError { #[error("the packet mode information was malformed - {0}")] InvalidPacketMode(#[from] InvalidPacketMode), - #[error("the actual sphinx packet was malformed - {0}")] - MalformedSphinxPacket(#[from] SphinxError), - - #[error("the actual outfox packet was malformed - {0}")] - MalformedOutfoxPacket(#[from] OutfoxError), - #[error("encountered an IO error - {0}")] IoError(#[from] io::Error), @@ -133,8 +126,8 @@ impl Decoder for NymCodec { // 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_mode { - PacketMode::Outfox => NymPacket::Outfox(OutfoxPacket::try_from(slice)?), - _ => NymPacket::Sphinx(SphinxPacket::from_bytes(slice)?), + PacketMode::Outfox => NymPacket::outfox_from_bytes(slice)?, + _ => NymPacket::sphinx_from_bytes(slice)?, } } else { return Ok(None); @@ -176,13 +169,12 @@ impl Decoder for NymCodec { #[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, OUTFOX_PACKET_OVERHEAD, + DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, NODE_ADDRESS_LENGTH, }; - fn make_valid_outfox_packet(size: PacketSize) -> OutfoxPacket { + fn make_valid_outfox_packet(size: PacketSize) -> NymPacket { let (_, node1_pk) = crypto::keygen(); let node1 = Node::new( NodeAddressBytes::from_bytes([5u8; NODE_ADDRESS_LENGTH]), @@ -199,14 +191,14 @@ mod packet_encoding { node3_pk, ); - let route = [node1, node2, node3]; + let route = &[node1, node2, node3]; let payload = vec![1; 48]; - OutfoxPacket::build(&payload, &route, Some(size.size() - OUTFOX_PACKET_OVERHEAD)).unwrap() + NymPacket::outfox_build(payload, route, Some(size.plaintext_size())).unwrap() } - 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]), @@ -233,9 +225,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() } @@ -243,11 +233,11 @@ 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 = FramedNymPacket { header, - packet: NymPacket::Sphinx(sphinx_packet), + packet: sphinx_packet, }; let mut bytes = BytesMut::new(); @@ -264,12 +254,9 @@ mod packet_encoding { let packet = make_valid_outfox_packet(PacketSize::OutfoxRegularPacket); let packet_bytes = packet.to_bytes().unwrap(); - OutfoxPacket::try_from(packet_bytes.as_slice()).unwrap(); + NymPacket::outfox_from_bytes(packet_bytes.as_slice()).unwrap(); - let packet = FramedNymPacket { - header, - packet: NymPacket::Outfox(packet), - }; + let packet = FramedNymPacket { header, packet }; let mut bytes = BytesMut::new(); NymCodec.encode(packet, &mut bytes).unwrap(); @@ -355,7 +342,7 @@ mod packet_encoding { packet_version: PacketVersion::Legacy, ..Default::default() }, - packet: NymPacket::Sphinx(make_valid_sphinx_packet(Default::default())), + packet: make_valid_sphinx_packet(Default::default()), }; let mut bytes = BytesMut::new(); @@ -372,7 +359,7 @@ mod packet_encoding { // if full frame is used exactly, there should be enough space for header + ack packet let packet = FramedNymPacket { header: Header::default(), - packet: NymPacket::Sphinx(make_valid_sphinx_packet(Default::default())), + packet: make_valid_sphinx_packet(Default::default()), }; let mut bytes = BytesMut::new(); @@ -401,7 +388,7 @@ mod packet_encoding { packet_version: PacketVersion::Legacy, ..Default::default() }, - packet: NymPacket::Sphinx(make_valid_sphinx_packet(Default::default())), + packet: make_valid_sphinx_packet(Default::default()), }; let mut bytes = BytesMut::new(); @@ -428,7 +415,7 @@ mod packet_encoding { for packet_size in packet_sizes { let first_packet = FramedNymPacket { header: Header::default(), - packet: NymPacket::Sphinx(make_valid_sphinx_packet(Default::default())), + packet: make_valid_sphinx_packet(Default::default()), }; let mut bytes = BytesMut::new(); @@ -447,12 +434,12 @@ mod packet_encoding { fn can_decode_two_packets_immediately() { let packet1 = FramedNymPacket { header: Header::default(), - packet: NymPacket::Sphinx(make_valid_sphinx_packet(Default::default())), + packet: make_valid_sphinx_packet(Default::default()), }; let packet2 = FramedNymPacket { header: Header::default(), - packet: NymPacket::Sphinx(make_valid_sphinx_packet(Default::default())), + packet: make_valid_sphinx_packet(Default::default()), }; let mut bytes = BytesMut::new(); @@ -469,12 +456,12 @@ mod packet_encoding { fn can_decode_two_packets_in_separate_calls() { let packet1 = FramedNymPacket { header: Header::default(), - packet: NymPacket::Sphinx(make_valid_sphinx_packet(Default::default())), + packet: make_valid_sphinx_packet(Default::default()), }; let packet2 = FramedNymPacket { header: Header::default(), - packet: NymPacket::Sphinx(make_valid_sphinx_packet(Default::default())), + packet: make_valid_sphinx_packet(Default::default()), }; let mut bytes = BytesMut::new(); diff --git a/common/nymsphinx/params/src/packet_sizes.rs b/common/nymsphinx/params/src/packet_sizes.rs index 7c468dba63..a55532301b 100644 --- a/common/nymsphinx/params/src/packet_sizes.rs +++ b/common/nymsphinx/params/src/packet_sizes.rs @@ -3,7 +3,7 @@ use crate::FRAG_ID_LEN; use nym_sphinx_types::header::HEADER_SIZE; -use nym_sphinx_types::{OUTFOX_PACKET_OVERHEAD, 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; @@ -195,12 +195,42 @@ impl PacketSize { } } + 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 { @@ -214,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 }) } @@ -243,8 +283,12 @@ impl PacketSize { } pub fn get_type_from_plaintext(plaintext_size: usize) -> Result { - let packet_size = plaintext_size + SPHINX_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), + } } } diff --git a/common/nymsphinx/src/preparer/mod.rs b/common/nymsphinx/src/preparer/mod.rs index e31b56a6f5..be72ded710 100644 --- a/common/nymsphinx/src/preparer/mod.rs +++ b/common/nymsphinx/src/preparer/mod.rs @@ -15,7 +15,7 @@ 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_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 +149,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 @@ -208,8 +212,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 +232,12 @@ 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 = 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 = diff --git a/common/nymsphinx/src/preparer/payload.rs b/common/nymsphinx/src/preparer/payload.rs index 60786d3f11..73f0c4889c 100644 --- a/common/nymsphinx/src/preparer/payload.rs +++ b/common/nymsphinx/src/preparer/payload.rs @@ -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, variant_data: impl IntoIterator, - ) -> NymsphinxPayload + ) -> Result 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::( @@ -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 { let key_digest = packet_encryption_key.compute_digest(); self.build::( packet_encryption_key.inner(), @@ -67,7 +70,7 @@ impl NymsphinxPayloadBuilder { self, rng: &mut R, recipient_encryption_key: &encryption::PublicKey, - ) -> NymsphinxPayload + ) -> Result where R: RngCore + CryptoRng, { diff --git a/common/nymsphinx/src/receiver.rs b/common/nymsphinx/src/receiver.rs index ddfd1c9ad9..5a7491a1da 100644 --- a/common/nymsphinx/src/receiver.rs +++ b/common/nymsphinx/src/receiver.rs @@ -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( - &self, - message: &mut [u8], - key: &CipherKey, - ) -> Result<(), MessageRecoveryError> - where - C: StreamCipher + KeyIvInit, - { - lion_transform_decrypt(message, key)?; - Ok(()) - } } pub trait MessageReceiver { diff --git a/common/nymsphinx/types/src/lib.rs b/common/nymsphinx/types/src/lib.rs index 38ca61a6ce..b9f15693a8 100644 --- a/common/nymsphinx/types/src/lib.rs +++ b/common/nymsphinx/types/src/lib.rs @@ -1,8 +1,9 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -pub use nym_outfox::{error::OutfoxError, packet::OutfoxPacket, packet::OUTFOX_PACKET_OVERHEAD}; +pub use nym_outfox::{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, @@ -14,9 +15,10 @@ pub use sphinx_packet::{ payload::{Payload, PAYLOAD_OVERHEAD_SIZE}, route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier}, surb::{SURBMaterial, SURB}, - Error as SphinxError, ProcessedPacket, SphinxPacket, + Error as SphinxError, ProcessedPacket, }; -use std::fmt; +use sphinx_packet::{SphinxPacket, SphinxPacketBuilder}; +use std::{array::TryFromSliceError, fmt}; use thiserror::Error; #[derive(Error, Debug)] @@ -26,6 +28,9 @@ pub enum NymPacketError { #[error("Outfox error: {0}")] Outfox(#[from] nym_outfox::error::OutfoxError), + + #[error("{0}")] + FromSlice(#[from] TryFromSliceError), } #[allow(clippy::large_enum_variant)] @@ -50,6 +55,39 @@ impl fmt::Debug for NymPacket { } impl NymPacket { + pub fn sphinx_build>( + size: usize, + message: M, + route: &[Node], + destination: &Destination, + delays: &[Delay], + ) -> Result { + Ok(NymPacket::Sphinx( + SphinxPacketBuilder::new() + .with_payload_size(size) + .build_packet(message, route, destination, delays)?, + )) + } + pub fn sphinx_from_bytes(bytes: &[u8]) -> Result { + Ok(NymPacket::Sphinx(SphinxPacket::from_bytes(bytes)?)) + } + + pub fn outfox_build>( + payload: M, + route: &[Node], + size: Option, + ) -> Result { + Ok(NymPacket::Outfox(OutfoxPacket::build( + payload, + route.try_into()?, + size, + )?)) + } + + pub fn outfox_from_bytes(bytes: &[u8]) -> Result { + Ok(NymPacket::Outfox(OutfoxPacket::try_from(bytes)?)) + } + pub fn len(&self) -> usize { match self { NymPacket::Sphinx(packet) => packet.len(), diff --git a/common/topology/src/lib.rs b/common/topology/src/lib.rs index 4eab444605..ec964b486d 100644 --- a/common/topology/src/lib.rs +++ b/common/topology/src/lib.rs @@ -52,6 +52,9 @@ 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, } #[derive(Debug, Clone)] diff --git a/gateway/gateway-requests/src/types.rs b/gateway/gateway-requests/src/types.rs index 0685c0d473..3683144980 100644 --- a/gateway/gateway-requests/src/types.rs +++ b/gateway/gateway-requests/src/types.rs @@ -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 { 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 diff --git a/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs b/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs index 66c0c3f4f6..5ed12a30b3 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs @@ -283,7 +283,7 @@ where &self, mix_packet: MixPacket, ) -> Result { - 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?; diff --git a/mixnode/src/node/packet_delayforwarder.rs b/mixnode/src/node/packet_delayforwarder.rs index bcf2a6b669..9dc2ab92d0 100644 --- a/mixnode/src/node/packet_delayforwarder.rs +++ b/mixnode/src/node/packet_delayforwarder.rs @@ -5,7 +5,7 @@ use crate::node::node_statistics::UpdateSender; use futures::channel::mpsc; use futures::StreamExt; use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue}; -use nym_sphinx::{forwarding::packet::MixPacket, NymPacket}; +use nym_sphinx::forwarding::packet::MixPacket; use std::io; use tokio::time::Instant; @@ -59,13 +59,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 = packet.into_packet(); - if let Err(err) = self.mixnet_client.send_without_response( - next_hop, - NymPacket::Sphinx(sphinx_packet), - packet_mode, - ) { + if let Err(err) = self + .mixnet_client + .send_without_response(next_hop, packet, packet_mode) + { if err.kind() == io::ErrorKind::WouldBlock { // we only know for sure if we dropped a packet if our sending queue was full // in any other case the connection might still be re-established (or created for the first time) @@ -135,15 +134,15 @@ 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_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)] @@ -166,7 +165,7 @@ mod tests { } } - 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]), @@ -193,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() } diff --git a/nym-connect/desktop/Cargo.lock b/nym-connect/desktop/Cargo.lock index 6dd6ad7428..ec8fa94b4b 100644 --- a/nym-connect/desktop/Cargo.lock +++ b/nym-connect/desktop/Cargo.lock @@ -3742,6 +3742,7 @@ dependencies = [ "nym-sphinx-addressing", "nym-sphinx-params", "nym-sphinx-types", + "thiserror", ] [[package]] diff --git a/nym-outfox/Cargo.toml b/nym-outfox/Cargo.toml index 44df9b3487..36714d1eab 100644 --- a/nym-outfox/Cargo.toml +++ b/nym-outfox/Cargo.toml @@ -16,12 +16,7 @@ chacha20poly1305 = "0.10.1" getrandom = { version = "*", features = ["js"] } thiserror = "1" fastrand = "1.8" - sphinx-packet = "0.1.0" -[patch.crates-io] -sphinx-packet = { path = "../../../../sphinx" } - - [dev-dependencies] criterion = "0.4" diff --git a/nym-outfox/src/packet.rs b/nym-outfox/src/packet.rs index c5296ce850..cdb92fd6f3 100644 --- a/nym-outfox/src/packet.rs +++ b/nym-outfox/src/packet.rs @@ -49,8 +49,8 @@ impl OutfoxPacket { Ok(bytes) } - pub fn build( - payload: &[u8], + pub fn build>( + payload: M, route: &[Node; 3], packet_size: Option, ) -> Result { @@ -58,9 +58,9 @@ impl OutfoxPacket { let packet_size = packet_size.unwrap_or(DEFAULT_PAYLOAD_SIZE); let mix_params = MixCreationParameters::new(packet_size as u16); - 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);