sphinx_packet/header/routing/
mod.rs

1// Copyright 2020 Nym Technologies SA
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::constants::{HEADER_INTEGRITY_MAC_SIZE, MAX_PATH_LENGTH, NODE_META_INFO_SIZE};
16use crate::header::delays::Delay;
17use crate::header::filler::Filler;
18use crate::header::mac::HeaderIntegrityMac;
19use crate::header::routing::destination::FinalRoutingInformation;
20use crate::header::routing::nodes::{EncryptedRoutingInformation, RoutingInformation};
21use crate::header::shared_secret::ExpandedSharedSecret;
22use crate::route::{Destination, Node, NodeAddressBytes};
23use crate::version::Version;
24use crate::{Error, ErrorKind, Result};
25
26pub const TRUNCATED_ROUTING_INFO_SIZE: usize =
27    ENCRYPTED_ROUTING_INFO_SIZE - (NODE_META_INFO_SIZE + HEADER_INTEGRITY_MAC_SIZE);
28pub const ENCRYPTED_ROUTING_INFO_SIZE: usize =
29    (NODE_META_INFO_SIZE + HEADER_INTEGRITY_MAC_SIZE) * MAX_PATH_LENGTH;
30
31pub mod destination;
32pub mod nodes;
33
34pub const FORWARD_HOP: RoutingFlag = 1;
35pub const FINAL_HOP: RoutingFlag = 2;
36
37pub type RoutingFlag = u8;
38
39#[derive(Clone, Debug)]
40pub struct EncapsulatedRoutingInformation {
41    pub(crate) enc_routing_information: EncryptedRoutingInformation,
42    pub(crate) integrity_mac: HeaderIntegrityMac,
43}
44
45impl EncapsulatedRoutingInformation {
46    pub(crate) fn encapsulate(
47        enc_routing_information: EncryptedRoutingInformation,
48        integrity_mac: HeaderIntegrityMac,
49    ) -> Self {
50        Self {
51            enc_routing_information,
52            integrity_mac,
53        }
54    }
55
56    pub(crate) fn new(
57        route: &[Node],
58        destination: &Destination,
59        delays: &[Delay],
60        expanded_shared_secrets: &[ExpandedSharedSecret],
61        filler: Filler,
62        version: Version,
63    ) -> Self {
64        assert_eq!(route.len(), expanded_shared_secrets.len());
65        assert_eq!(delays.len(), route.len());
66
67        let final_keys = match expanded_shared_secrets.last() {
68            Some(k) => k,
69            None => panic!("empty keys"),
70        };
71
72        let encapsulated_destination_routing_info =
73            Self::for_final_hop(destination, final_keys, filler, route.len(), version);
74
75        Self::for_forward_hops(
76            encapsulated_destination_routing_info,
77            delays,
78            route,
79            expanded_shared_secrets,
80            version,
81        )
82    }
83
84    fn for_final_hop(
85        dest: &Destination,
86        expanded_shared_secret: &ExpandedSharedSecret,
87        filler: Filler,
88        route_len: usize,
89        version: Version,
90    ) -> Self {
91        FinalRoutingInformation::new(dest, route_len, version)
92            .add_padding(route_len) // add padding to obtain correct destination length
93            .encrypt(expanded_shared_secret.stream_cipher_key(), route_len) // encrypt with the key of final node (in our case service provider)
94            .combine_with_filler(filler, route_len) // add filler to get header of correct length
95            .encapsulate_with_mac(expanded_shared_secret.header_integrity_hmac_key())
96        // combine the previous data with a MAC on the header (also calculated with the SPs key)
97    }
98
99    fn for_forward_hops(
100        encapsulated_destination_routing_info: Self,
101        delays: &[Delay],
102        route: &[Node], // [Mix0, Mix1, Mix2, ..., Mix_{v-1}, Mix_v]
103        expanded_shared_secrets: &[ExpandedSharedSecret], // [Keys0, Keys1, Keys2, ..., Keys_{v-1}, Keys_v]
104        version: Version,
105    ) -> Self {
106        route
107            .iter()
108            .skip(1) // we don't want the first element as person creating the packet knows the address of the first hop
109            .map(|node| node.address.to_bytes()) // we only care about the address field
110            .zip(
111                // we need both route (i.e. address field) and corresponding keys of the PREVIOUS hop
112                expanded_shared_secrets
113                    .iter()
114                    .take(expanded_shared_secrets.len() - 1), // we don't want last element - it was already used to encrypt the destination
115            )
116            .zip(delays.iter().take(delays.len() - 1)) // no need for the delay for the final node
117            .rev() // we are working from the 'inside'
118            // we should be getting here
119            // [(Mix_v, Keys_{v-1}, Delay_{v-1}), (Mix_{v-1}, Keys_{v-2}, Delay_{v-2}), ..., (Mix2, Keys1, Delay1), (Mix1, Keys0, Delay0)]
120            .fold(
121                // we start from the already created encrypted final routing info and mac for the destination
122                // (encrypted with Keys_v)
123                encapsulated_destination_routing_info,
124                |next_hop_encapsulated_routing_information,
125                 ((current_node_address, previous_node), delay)| {
126                    RoutingInformation::new(
127                        NodeAddressBytes::from_bytes(current_node_address),
128                        delay.to_owned(),
129                        next_hop_encapsulated_routing_information,
130                        version,
131                    )
132                    .encrypt(previous_node.stream_cipher_key())
133                    .encapsulate_with_mac(previous_node.header_integrity_hmac_key())
134                },
135            )
136    }
137
138    pub fn to_bytes(&self) -> Vec<u8> {
139        self.integrity_mac
140            .as_bytes()
141            .iter()
142            .copied()
143            .chain(self.enc_routing_information.as_ref().iter().copied())
144            .collect()
145    }
146
147    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
148        if bytes.len() != HEADER_INTEGRITY_MAC_SIZE + ENCRYPTED_ROUTING_INFO_SIZE {
149            return Err(Error::new(
150                ErrorKind::InvalidRouting,
151                format!(
152                    "tried to recover routing information using {} bytes, expected {}",
153                    bytes.len(),
154                    HEADER_INTEGRITY_MAC_SIZE + ENCRYPTED_ROUTING_INFO_SIZE
155                ),
156            ));
157        }
158
159        let mut integrity_mac_bytes = [0u8; HEADER_INTEGRITY_MAC_SIZE];
160        let mut enc_routing_info_bytes = [0u8; ENCRYPTED_ROUTING_INFO_SIZE];
161
162        // first bytes represent the mac
163        integrity_mac_bytes.copy_from_slice(&bytes[..HEADER_INTEGRITY_MAC_SIZE]);
164        // the rest are for the routing info
165        enc_routing_info_bytes.copy_from_slice(
166            &bytes[HEADER_INTEGRITY_MAC_SIZE
167                ..HEADER_INTEGRITY_MAC_SIZE + ENCRYPTED_ROUTING_INFO_SIZE],
168        );
169
170        let integrity_mac = HeaderIntegrityMac::from_bytes(integrity_mac_bytes);
171        let enc_routing_information =
172            EncryptedRoutingInformation::from_bytes(enc_routing_info_bytes);
173
174        Ok(EncapsulatedRoutingInformation {
175            enc_routing_information,
176            integrity_mac,
177        })
178    }
179}
180
181#[cfg(test)]
182mod encapsulating_all_routing_information {
183    use super::*;
184    use crate::test_utils::{
185        fixtures::{destination_fixture, expanded_shared_secret_fixture, filler_fixture},
186        random_node,
187    };
188
189    #[test]
190    #[should_panic]
191    fn it_panics_if_route_is_longer_than_keys() {
192        let route = [random_node(), random_node(), random_node()];
193        let destination = destination_fixture();
194        let delays = [
195            Delay::new_from_nanos(10),
196            Delay::new_from_nanos(20),
197            Delay::new_from_nanos(30),
198        ];
199        let keys = [
200            expanded_shared_secret_fixture(),
201            expanded_shared_secret_fixture(),
202        ];
203        let filler = filler_fixture(route.len() - 1);
204
205        EncapsulatedRoutingInformation::new(
206            &route,
207            &destination,
208            &delays,
209            &keys,
210            filler,
211            Version::default(),
212        );
213    }
214
215    #[test]
216    #[should_panic]
217    fn it_panics_if_keys_are_longer_than_route() {
218        let route = [random_node(), random_node()];
219        let destination = destination_fixture();
220        let delays = [
221            Delay::new_from_nanos(10),
222            Delay::new_from_nanos(20),
223            Delay::new_from_nanos(30),
224        ];
225        let keys = [
226            expanded_shared_secret_fixture(),
227            expanded_shared_secret_fixture(),
228            expanded_shared_secret_fixture(),
229        ];
230        let filler = filler_fixture(route.len() - 1);
231
232        EncapsulatedRoutingInformation::new(
233            &route,
234            &destination,
235            &delays,
236            &keys,
237            filler,
238            Version::default(),
239        );
240    }
241
242    #[test]
243    #[should_panic]
244    fn it_panics_if_empty_route_is_provided() {
245        let route = vec![];
246        let destination = destination_fixture();
247        let delays = [
248            Delay::new_from_nanos(10),
249            Delay::new_from_nanos(20),
250            Delay::new_from_nanos(30),
251        ];
252        let keys = [
253            expanded_shared_secret_fixture(),
254            expanded_shared_secret_fixture(),
255            expanded_shared_secret_fixture(),
256        ];
257        let filler = filler_fixture(route.len() - 1);
258
259        EncapsulatedRoutingInformation::new(
260            &route,
261            &destination,
262            &delays,
263            &keys,
264            filler,
265            Version::default(),
266        );
267    }
268
269    #[test]
270    #[should_panic]
271    fn it_panic_if_empty_keys_are_provided() {
272        let route = [random_node(), random_node()];
273        let destination = destination_fixture();
274        let delays = [
275            Delay::new_from_nanos(10),
276            Delay::new_from_nanos(20),
277            Delay::new_from_nanos(30),
278        ];
279        let keys = vec![];
280        let filler = filler_fixture(route.len() - 1);
281
282        EncapsulatedRoutingInformation::new(
283            &route,
284            &destination,
285            &delays,
286            &keys,
287            filler,
288            Version::default(),
289        );
290    }
291}
292
293#[cfg(test)]
294mod encapsulating_forward_routing_information {
295    use super::*;
296    use crate::test_utils::{
297        fixtures::{destination_fixture, expanded_shared_secret_fixture, filler_fixture},
298        random_node,
299    };
300
301    #[test]
302    fn it_correctly_generates_sphinx_routing_information_for_route_of_length_3() {
303        // this is basically loop unwrapping, but considering the complex logic behind it, it's warranted
304        let route = [random_node(), random_node(), random_node()];
305        let destination = destination_fixture();
306        let delay0 = Delay::new_from_nanos(10);
307        let delay1 = Delay::new_from_nanos(20);
308        let delay2 = Delay::new_from_nanos(30);
309        let delays = [delay0, delay1, delay2].to_vec();
310        let routing_keys = [
311            expanded_shared_secret_fixture(),
312            expanded_shared_secret_fixture(),
313            expanded_shared_secret_fixture(),
314        ];
315        let filler = filler_fixture(route.len() - 1);
316        let filler_copy = filler_fixture(route.len() - 1);
317        assert_eq!(filler, filler_copy);
318
319        let destination_routing_info = EncapsulatedRoutingInformation::for_final_hop(
320            &destination,
321            routing_keys.last().unwrap(),
322            filler,
323            route.len(),
324            Version::default(),
325        );
326
327        let destination_routing_info_copy = destination_routing_info.clone();
328
329        // sanity check to make sure our 'copy' worked
330        assert_eq!(
331            destination_routing_info
332                .enc_routing_information
333                .as_ref()
334                .to_vec(),
335            destination_routing_info_copy
336                .enc_routing_information
337                .as_ref()
338                .to_vec()
339        );
340        assert_eq!(
341            destination_routing_info.integrity_mac.as_bytes().to_vec(),
342            destination_routing_info_copy
343                .integrity_mac
344                .as_bytes()
345                .to_vec()
346        );
347
348        let routing_info = EncapsulatedRoutingInformation::for_forward_hops(
349            destination_routing_info,
350            &delays,
351            &route,
352            &routing_keys,
353            Version::default(),
354        );
355
356        let layer_1_routing = RoutingInformation::new(
357            route[2].address,
358            delay1,
359            destination_routing_info_copy,
360            Version::default(),
361        )
362        .encrypt(routing_keys[1].stream_cipher_key())
363        .encapsulate_with_mac(routing_keys[1].header_integrity_hmac_key());
364
365        // this is what first mix should receive
366        let layer_0_routing = RoutingInformation::new(
367            route[1].address,
368            delay0,
369            layer_1_routing,
370            Version::default(),
371        )
372        .encrypt(routing_keys[0].stream_cipher_key())
373        .encapsulate_with_mac(routing_keys[0].header_integrity_hmac_key());
374
375        assert_eq!(
376            routing_info.enc_routing_information.as_ref().to_vec(),
377            layer_0_routing.enc_routing_information.as_ref().to_vec()
378        );
379        assert_eq!(
380            routing_info.integrity_mac.into_inner(),
381            layer_0_routing.integrity_mac.into_inner()
382        );
383    }
384    #[test]
385    fn it_correctly_generates_sphinx_routing_information_for_route_of_max_length() {
386        // this is basically loop unwrapping, but considering the complex iterator, it's warranted
387        assert_eq!(5, MAX_PATH_LENGTH); // make sure we catch it if we decided to change the constant
388
389        /* since we're using max path length we expect literally:
390        n4 || m4 || n3 || m3 || n2 || m2 || n1 || m1 || d || i || p
391        // so literally no filler!
392        where:
393        {n1, n2, ...} are node addresses
394        {m1, m2, ...} are macs on previous layers
395        d is destination address
396        i is destination identifier
397        p is destination padding
398        */
399        // TODO: IMPLEMENT SPHINX HEADER LAYER UNWRAPPING
400        // HOWEVER! to test it, we need to first wrap function to unwrap header layer because each consecutive (ni, mi) pair is encrypted
401    }
402}
403
404#[cfg(test)]
405mod converting_encapsulated_routing_info_to_bytes {
406    use super::*;
407    use crate::test_utils::fixtures::encapsulated_routing_information_fixture;
408
409    #[test]
410    fn it_is_possible_to_convert_back_and_forth() {
411        let encapsulated_routing_info = encapsulated_routing_information_fixture();
412        let encapsulated_routing_info_bytes = encapsulated_routing_info.to_bytes();
413
414        let recovered_routing_info =
415            EncapsulatedRoutingInformation::from_bytes(&encapsulated_routing_info_bytes).unwrap();
416        assert_eq!(
417            encapsulated_routing_info
418                .enc_routing_information
419                .as_ref()
420                .to_vec(),
421            recovered_routing_info
422                .enc_routing_information
423                .as_ref()
424                .to_vec()
425        );
426
427        assert_eq!(
428            encapsulated_routing_info.integrity_mac.into_inner(),
429            recovered_routing_info.integrity_mac.into_inner()
430        );
431    }
432}