nym_sphinx_forwarding/
packet.rs

1// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use nym_sphinx_addressing::nodes::{NymNodeRoutingAddress, NymNodeRoutingAddressError};
5use nym_sphinx_params::{PacketSize, PacketType, SphinxKeyRotation};
6use nym_sphinx_types::{NymPacket, NymPacketError};
7
8use nym_sphinx_anonymous_replies::reply_surb::AppliedReplySurb;
9use nym_sphinx_params::key_rotation::InvalidSphinxKeyRotation;
10use nym_sphinx_params::packet_sizes::InvalidPacketSize;
11use nym_sphinx_params::packet_types::InvalidPacketType;
12use std::net::SocketAddr;
13use thiserror::Error;
14
15#[derive(Debug, Error)]
16pub enum MixPacketFormattingError {
17    #[error("too few bytes provided to recover from bytes")]
18    TooFewBytesProvided,
19
20    #[error("provided packet mode is invalid: {0}")]
21    InvalidPacketType(#[from] InvalidPacketType),
22
23    #[error("received request had an invalid packet size: {0}")]
24    InvalidPacketSize(#[from] InvalidPacketSize),
25
26    #[error("provided key rotation is invalid: {0}")]
27    InvalidKeyRotation(#[from] InvalidSphinxKeyRotation),
28
29    #[error("address field was incorrectly encoded")]
30    InvalidAddress,
31
32    #[error("received sphinx packet was malformed")]
33    MalformedSphinxPacket,
34
35    #[error("Packet: {0}")]
36    Packet(#[from] NymPacketError),
37}
38
39impl From<NymNodeRoutingAddressError> for MixPacketFormattingError {
40    fn from(_: NymNodeRoutingAddressError) -> Self {
41        MixPacketFormattingError::InvalidAddress
42    }
43}
44
45#[derive(Debug)]
46pub struct MixPacket {
47    next_hop: NymNodeRoutingAddress,
48    packet: NymPacket,
49    packet_type: PacketType,
50    key_rotation: SphinxKeyRotation,
51}
52
53impl MixPacket {
54    pub fn new(
55        next_hop: NymNodeRoutingAddress,
56        packet: NymPacket,
57        packet_type: PacketType,
58        key_rotation: SphinxKeyRotation,
59    ) -> Self {
60        MixPacket {
61            next_hop,
62            packet,
63            packet_type,
64            key_rotation,
65        }
66    }
67
68    pub fn from_applied_surb(
69        applied_reply_surb: AppliedReplySurb,
70        packet_type: PacketType,
71    ) -> Self {
72        MixPacket {
73            next_hop: applied_reply_surb.first_hop_address(),
74            key_rotation: applied_reply_surb.key_rotation(),
75            packet: applied_reply_surb.into_packet(),
76            packet_type,
77        }
78    }
79
80    pub fn next_hop(&self) -> NymNodeRoutingAddress {
81        self.next_hop
82    }
83
84    pub fn next_hop_address(&self) -> SocketAddr {
85        self.next_hop.into()
86    }
87
88    pub fn packet(&self) -> &NymPacket {
89        &self.packet
90    }
91
92    pub fn into_packet(self) -> NymPacket {
93        self.packet
94    }
95
96    pub fn key_rotation(&self) -> SphinxKeyRotation {
97        self.key_rotation
98    }
99
100    pub fn packet_type(&self) -> PacketType {
101        self.packet_type
102    }
103
104    // the message is formatted as follows:
105    // packet_type || FIRST_HOP || packet
106    pub fn try_from_v1_bytes(b: &[u8]) -> Result<Self, MixPacketFormattingError> {
107        // we need at least 1 byte to read packet type and another one to read type of the encoded first hop address
108        if b.len() < 2 {
109            return Err(MixPacketFormattingError::TooFewBytesProvided);
110        }
111
112        let packet_type = PacketType::try_from(b[0])?;
113
114        let next_hop = NymNodeRoutingAddress::try_from_bytes(&b[1..])?;
115        let addr_offset = next_hop.bytes_min_len();
116
117        let packet_data = &b[addr_offset + 1..];
118        let packet_size = packet_data.len();
119
120        // make sure the received data length corresponds to a valid packet
121        let _ = PacketSize::get_type(packet_size)?;
122
123        let packet = match packet_type {
124            PacketType::Mix => NymPacket::sphinx_from_bytes(packet_data)?,
125            PacketType::Outfox => NymPacket::outfox_from_bytes(packet_data)?,
126        };
127
128        Ok(MixPacket {
129            next_hop,
130            packet,
131            packet_type,
132            key_rotation: SphinxKeyRotation::Unknown,
133        })
134    }
135
136    pub fn into_v1_bytes(self) -> Result<Vec<u8>, MixPacketFormattingError> {
137        Ok(std::iter::once(self.packet_type as u8)
138            .chain(self.next_hop.as_bytes())
139            .chain(self.packet.to_bytes()?)
140            .collect())
141    }
142
143    // the message is formatted as follows:
144    // packet_type || KEY_ROTATION || FIRST_HOP || packet
145    pub fn try_from_v2_bytes(b: &[u8]) -> Result<Self, MixPacketFormattingError> {
146        // we need at least 1 byte to read packet type, 1 byte to read key rotation
147        // and finally another one to read type of the encoded first hop address
148        if b.len() < 3 {
149            return Err(MixPacketFormattingError::TooFewBytesProvided);
150        }
151
152        let packet_type = PacketType::try_from(b[0])?;
153        let key_rotation = SphinxKeyRotation::try_from(b[1])?;
154
155        let next_hop = NymNodeRoutingAddress::try_from_bytes(&b[2..])?;
156        let addr_offset = next_hop.bytes_min_len();
157
158        let packet_data = &b[addr_offset + 2..];
159        let packet_size = packet_data.len();
160
161        // make sure the received data length corresponds to a valid packet
162        let _ = PacketSize::get_type(packet_size)?;
163
164        let packet = match packet_type {
165            PacketType::Mix => NymPacket::sphinx_from_bytes(packet_data)?,
166            PacketType::Outfox => NymPacket::outfox_from_bytes(packet_data)?,
167        };
168
169        Ok(MixPacket {
170            next_hop,
171            packet,
172            packet_type,
173            key_rotation,
174        })
175    }
176
177    pub fn into_v2_bytes(self) -> Result<Vec<u8>, MixPacketFormattingError> {
178        Ok(std::iter::once(self.packet_type as u8)
179            .chain(std::iter::once(self.key_rotation as u8))
180            .chain(self.next_hop.as_bytes())
181            .chain(self.packet.to_bytes()?)
182            .collect())
183    }
184}
185
186// TODO: test for serialization and errors!