nym_outfox/
packet.rs

1use crate::{
2    constants::{DEFAULT_HOPS, MAGIC_SLICE, MIN_PACKET_SIZE, MIX_PARAMS_LEN},
3    error::OutfoxError,
4    format::{MixCreationParameters, MixStageParameters},
5};
6use sphinx_packet::{
7    crypto::PrivateKey,
8    packet::builder::DEFAULT_PAYLOAD_SIZE,
9    route::{Destination, Node},
10};
11use std::{array::TryFromSliceError, collections::VecDeque, ops::Range};
12
13#[derive(Debug)]
14pub struct OutfoxPacket {
15    mix_params: MixCreationParameters,
16    payload: Vec<u8>,
17}
18
19pub struct OutfoxProcessedPacket {
20    packet: OutfoxPacket,
21    next_address: [u8; 32],
22}
23
24impl OutfoxProcessedPacket {
25    pub fn new(packet: OutfoxPacket, next_address: [u8; 32]) -> Self {
26        OutfoxProcessedPacket {
27            packet,
28            next_address,
29        }
30    }
31
32    pub fn into_packet(self) -> OutfoxPacket {
33        self.packet
34    }
35
36    pub fn next_address(&self) -> &[u8; 32] {
37        &self.next_address
38    }
39}
40
41impl TryFrom<&[u8]> for OutfoxPacket {
42    type Error = OutfoxError;
43
44    fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
45        let (header, payload) = v.split_at(MIX_PARAMS_LEN);
46        Ok(OutfoxPacket {
47            mix_params: MixCreationParameters::try_from(header)?,
48            payload: payload.to_vec(),
49        })
50    }
51}
52
53impl OutfoxPacket {
54    pub fn recover_plaintext(&self) -> Result<Vec<u8>, OutfoxError> {
55        let plaintext = self.payload()[self.payload_range()].to_vec();
56        let mut plaintext = VecDeque::from_iter(plaintext);
57        while let Some(0) = plaintext.front() {
58            plaintext.pop_front();
59        }
60        let mut plaintext = plaintext.make_contiguous().to_vec();
61        let payload = plaintext.split_off(MAGIC_SLICE.len());
62        if plaintext != MAGIC_SLICE {
63            Err(OutfoxError::InvalidMagicBytes(plaintext))
64        } else {
65            Ok(payload)
66        }
67    }
68
69    pub fn len(&self) -> usize {
70        self.mix_params().total_packet_length() + MIX_PARAMS_LEN
71    }
72
73    pub fn is_empty(&self) -> bool {
74        self.len() == 0
75    }
76
77    pub fn to_bytes(&self) -> Result<Vec<u8>, OutfoxError> {
78        let mut bytes = vec![];
79        bytes.extend(self.mix_params.to_bytes());
80        bytes.extend(self.payload.as_slice());
81        Ok(bytes)
82    }
83
84    pub fn build<M: AsRef<[u8]>>(
85        payload: M,
86        route: &[Node; 4],
87        destination: &Destination,
88        packet_size: Option<usize>,
89    ) -> Result<OutfoxPacket, OutfoxError> {
90        let secret_key = x25519_dalek::StaticSecret::random();
91        let packet_size = packet_size.unwrap_or(DEFAULT_PAYLOAD_SIZE);
92        let packet_size = if packet_size < MIN_PACKET_SIZE {
93            MIN_PACKET_SIZE
94        } else {
95            packet_size
96        } + MAGIC_SLICE.len();
97        let mix_params = MixCreationParameters::new(packet_size as u16);
98
99        let padding = mix_params.total_packet_length() - payload.as_ref().len() - MAGIC_SLICE.len();
100        let mut buffer = vec![0; padding];
101        buffer.extend_from_slice(MAGIC_SLICE);
102        buffer.extend_from_slice(payload.as_ref());
103
104        // Last node in the route is a gateway, it will decrypt last, and get the final destination address
105        let (range, stage_params) = mix_params.get_stage_params(0);
106        stage_params.encode_mix_layer(
107            &mut buffer[range],
108            &secret_key,
109            route.last().unwrap().pub_key,
110            destination.address.as_bytes_ref(),
111        )?;
112
113        let route = route.iter().rev().collect::<Vec<&Node>>();
114
115        // We've reversed the route, and we iterate pairs of node, first node in the pair is the destination, and the second(last) is the processing node
116        // Route: [N1, N2, N3, G]
117        // Reverse: [G, N3, N2, N1]
118        // Pairs: [(G, N3), (N3, N2), (N2, N1)]
119        // We iterate over pairs, and encode the mix layer for each pair
120        // For the first pair, we encode the mix layer for N3, and the destination is G
121        // For the second pair, we encode the mix layer for N2, and the destination is N3
122        // For the third pair, we encode the mix layer for N1, and the destination is N2
123        // Entry gateway will simply forward the packet to N1 and processing will continue from there
124        for (idx, nodes) in route.windows(2).enumerate() {
125            let (range, stage_params) = mix_params.get_stage_params(idx + 1);
126            // We know that we'll always get 4 nodes, so we can unwrap here
127            let processing_node = nodes.last().unwrap();
128            let destination_node = nodes.first().unwrap();
129            let secret_key = x25519_dalek::StaticSecret::random();
130            stage_params.encode_mix_layer(
131                &mut buffer[range],
132                &secret_key,
133                processing_node.pub_key,
134                destination_node.address.as_bytes(),
135            )?;
136        }
137
138        Ok(OutfoxPacket {
139            mix_params,
140            payload: buffer,
141        })
142    }
143
144    pub fn stage_params(&self, layer_number: usize) -> (Range<usize>, MixStageParameters) {
145        self.mix_params().get_stage_params(layer_number)
146    }
147
148    pub fn mix_params(&self) -> &MixCreationParameters {
149        &self.mix_params
150    }
151
152    pub fn payload(&self) -> &[u8] {
153        &self.payload
154    }
155
156    pub fn payload_range(&self) -> Range<usize> {
157        self.stage_params(DEFAULT_HOPS - 1).1.payload_range()
158    }
159
160    pub fn payload_mut(&mut self) -> &mut [u8] {
161        &mut self.payload
162    }
163
164    pub fn decode_mix_layer(
165        &mut self,
166        layer: usize,
167        mix_secret_key: &x25519_dalek::StaticSecret,
168    ) -> Result<Vec<u8>, OutfoxError> {
169        let (range, params) = self.stage_params(layer);
170        let routing_data =
171            params.decode_mix_layer(&mut self.payload_mut()[range], mix_secret_key)?;
172        Ok(routing_data)
173    }
174
175    pub fn update_routing_information(&mut self, layer: usize) -> Result<(), TryFromSliceError> {
176        let mut routing_info = self
177            .mix_params()
178            .routing_information_length_by_stage
179            .to_vec();
180        routing_info.push(0);
181        routing_info.swap_remove(layer);
182        self.mix_params.routing_information_length_by_stage = routing_info.as_slice().try_into()?;
183        Ok(())
184    }
185
186    pub fn is_final_hop(&self) -> bool {
187        self.mix_params()
188            .routing_information_length_by_stage
189            .iter()
190            .all(|x| x == &0)
191    }
192
193    pub fn decode_next_layer(
194        &mut self,
195        mix_secret_key: &PrivateKey,
196    ) -> Result<[u8; 32], OutfoxError> {
197        let routing_lenght_by_stage = self
198            .mix_params()
199            .routing_information_length_by_stage
200            .as_slice();
201        let mut layer = DEFAULT_HOPS - 1;
202        for (i, length) in routing_lenght_by_stage.iter().rev().enumerate() {
203            if length == &32 {
204                layer = DEFAULT_HOPS - 1 - i;
205                break;
206            }
207        }
208        self.decode_mix_layer(layer, mix_secret_key)?;
209        self.update_routing_information(layer)?;
210        let (range, stage_params) = self.mix_params().get_stage_params(layer);
211        let routing_bytes = &self.payload()[range][stage_params.routing_data_range()];
212        let routing_address: [u8; 32] = routing_bytes.try_into()?;
213        Ok(routing_address)
214    }
215}