nym_sphinx_types/
lib.rs

1// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{array::TryFromSliceError, fmt};
5use thiserror::Error;
6
7#[cfg(feature = "outfox")]
8pub use nym_outfox::packet::{OutfoxPacket, OutfoxProcessedPacket};
9
10#[cfg(feature = "sphinx")]
11pub use sphinx_packet::{SphinxPacket, SphinxPacketBuilder};
12
13#[cfg(feature = "outfox")]
14pub use nym_outfox::{
15    constants::MIN_PACKET_SIZE, constants::MIX_PARAMS_LEN, constants::OUTFOX_PACKET_OVERHEAD,
16    error::OutfoxError,
17};
18// re-exporting types and constants available in sphinx
19
20#[cfg(feature = "sphinx")]
21pub use sphinx_packet::{
22    Error as SphinxError, ProcessedPacket, ProcessedPacketData,
23    constants::{
24        self, DESTINATION_ADDRESS_LENGTH, IDENTIFIER_LENGTH, MAX_PATH_LENGTH, NODE_ADDRESS_LENGTH,
25        PAYLOAD_KEY_SIZE, REPLAY_TAG_SIZE,
26    },
27    crypto::{self, PrivateKey, PublicKey},
28    header::{self, HEADER_SIZE, ProcessedHeader, SphinxHeader, delays, delays::Delay},
29    packet::builder::DEFAULT_PAYLOAD_SIZE,
30    payload::{
31        PAYLOAD_OVERHEAD_SIZE, Payload,
32        key::{PayloadKey, PayloadKeySeed},
33    },
34    route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier},
35    surb::{SURB, SURBMaterial},
36    version::*,
37};
38
39#[derive(Error, Debug)]
40pub enum NymPacketError {
41    #[error("Sphinx error: {0}")]
42    #[cfg(feature = "sphinx")]
43    Sphinx(#[from] sphinx_packet::Error),
44
45    #[error("Outfox error: {0}")]
46    #[cfg(feature = "outfox")]
47    Outfox(#[from] nym_outfox::error::OutfoxError),
48
49    #[error("{0}")]
50    FromSlice(#[from] TryFromSliceError),
51}
52
53// TODO: wrap that guy and add extra metadata to indicate key rotation?
54#[allow(clippy::large_enum_variant)]
55pub enum NymPacket {
56    #[cfg(feature = "sphinx")]
57    Sphinx(SphinxPacket),
58    #[cfg(feature = "outfox")]
59    Outfox(OutfoxPacket),
60}
61
62pub enum NymProcessedPacket {
63    #[cfg(feature = "sphinx")]
64    Sphinx(ProcessedPacket),
65    #[cfg(feature = "outfox")]
66    Outfox(OutfoxProcessedPacket),
67}
68
69impl fmt::Debug for NymPacket {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        #[allow(unreachable_patterns)]
72        match &self {
73            #[cfg(feature = "sphinx")]
74            NymPacket::Sphinx(packet) => f
75                .debug_struct("NymPacket::Sphinx")
76                .field("len", &packet.len())
77                .finish(),
78            #[cfg(feature = "outfox")]
79            NymPacket::Outfox(packet) => f
80                .debug_struct("NymPacket::Outfox")
81                .field("len", &packet.len())
82                .finish(),
83            _ => write!(f, ""),
84        }
85    }
86}
87
88impl NymPacket {
89    #[cfg(feature = "sphinx")]
90    pub fn sphinx_build<M: AsRef<[u8]>>(
91        use_legacy_sphinx_format: bool,
92        size: usize,
93        message: M,
94        route: &[Node],
95        destination: &Destination,
96        delays: &[Delay],
97    ) -> Result<NymPacket, NymPacketError> {
98        let mut builder = SphinxPacketBuilder::new().with_payload_size(size);
99
100        if use_legacy_sphinx_format {
101            builder = builder.with_version(X25519_WITH_EXPLICIT_PAYLOAD_KEYS_VERSION)
102        };
103
104        Ok(NymPacket::Sphinx(builder.build_packet(
105            message,
106            route,
107            destination,
108            delays,
109        )?))
110    }
111    #[cfg(feature = "sphinx")]
112    pub fn sphinx_from_bytes(bytes: &[u8]) -> Result<NymPacket, NymPacketError> {
113        Ok(NymPacket::Sphinx(SphinxPacket::from_bytes(bytes)?))
114    }
115
116    #[cfg(feature = "outfox")]
117    pub fn outfox_build<M: AsRef<[u8]>>(
118        payload: M,
119        route: &[Node],
120        destination: &Destination,
121        size: Option<usize>,
122    ) -> Result<NymPacket, NymPacketError> {
123        Ok(NymPacket::Outfox(OutfoxPacket::build(
124            payload,
125            route.try_into()?,
126            destination,
127            size,
128        )?))
129    }
130
131    #[cfg(feature = "outfox")]
132    pub fn outfox_from_bytes(bytes: &[u8]) -> Result<NymPacket, NymPacketError> {
133        Ok(NymPacket::Outfox(OutfoxPacket::try_from(bytes)?))
134    }
135
136    pub fn len(&self) -> usize {
137        #[allow(unreachable_patterns)]
138        match self {
139            #[cfg(feature = "sphinx")]
140            NymPacket::Sphinx(packet) => packet.len(),
141            #[cfg(feature = "outfox")]
142            NymPacket::Outfox(packet) => packet.len(),
143            _ => 0,
144        }
145    }
146
147    pub fn is_empty(&self) -> bool {
148        self.len() == 0
149    }
150
151    pub fn to_bytes(&self) -> Result<Vec<u8>, NymPacketError> {
152        #[allow(unreachable_patterns)]
153        match self {
154            #[cfg(feature = "sphinx")]
155            NymPacket::Sphinx(packet) => Ok(packet.to_bytes()),
156            #[cfg(feature = "outfox")]
157            NymPacket::Outfox(packet) => Ok(packet.to_bytes()?),
158            _ => Ok(vec![]),
159        }
160    }
161
162    #[cfg(feature = "sphinx")]
163    pub fn process(
164        self,
165        node_secret_key: &PrivateKey,
166    ) -> Result<NymProcessedPacket, NymPacketError> {
167        match self {
168            NymPacket::Sphinx(packet) => {
169                Ok(NymProcessedPacket::Sphinx(packet.process(node_secret_key)?))
170            }
171            #[cfg(feature = "outfox")]
172            NymPacket::Outfox(mut packet) => {
173                let next_address = packet.decode_next_layer(node_secret_key)?;
174                Ok(NymProcessedPacket::Outfox(OutfoxProcessedPacket::new(
175                    packet,
176                    next_address,
177                )))
178            }
179        }
180    }
181
182    #[cfg(feature = "sphinx")]
183    #[allow(unreachable_patterns)]
184    pub fn sphinx_packet_ref(&self) -> Option<&SphinxPacket> {
185        match self {
186            NymPacket::Sphinx(packet) => Some(packet),
187            _ => None,
188        }
189    }
190
191    #[cfg(feature = "sphinx")]
192    #[allow(unreachable_patterns)]
193    pub fn to_sphinx_packet(self) -> Option<SphinxPacket> {
194        match self {
195            NymPacket::Sphinx(packet) => Some(packet),
196            _ => None,
197        }
198    }
199
200    #[cfg(feature = "sphinx")]
201    pub fn is_sphinx(&self) -> bool {
202        matches!(self, NymPacket::Sphinx(_))
203    }
204}