sphinx_packet/packet/
mod.rs1use crate::header::shared_secret::ExpandedSharedSecret;
2use crate::version::Version;
3use crate::{
4 header::{self, delays::Delay, HEADER_SIZE},
5 payload::{Payload, PAYLOAD_OVERHEAD_SIZE},
6 route::{Destination, DestinationAddressBytes, Node, NodeAddressBytes, SURBIdentifier},
7 Error, ErrorKind, Result,
8};
9use builder::SphinxPacketBuilder;
10use header::SphinxHeader;
11use x25519_dalek::{PublicKey, StaticSecret};
12
13pub mod builder;
14
15pub struct ProcessedPacket {
16 pub version: Version,
17 pub data: ProcessedPacketData,
18}
19
20pub enum ProcessedPacketData {
21 ForwardHop {
22 next_hop_packet: SphinxPacket,
23 next_hop_address: NodeAddressBytes,
24 delay: Delay,
25 },
26 FinalHop {
27 destination: DestinationAddressBytes,
28 identifier: SURBIdentifier,
29 payload: Payload,
30 },
31}
32
33impl ProcessedPacket {
34 pub fn shared_secret(&self) -> Option<PublicKey> {
35 match &self.data {
36 ProcessedPacketData::ForwardHop {
37 next_hop_packet, ..
38 } => Some(next_hop_packet.shared_secret()),
39 ProcessedPacketData::FinalHop { .. } => None,
40 }
41 }
42}
43
44pub struct SphinxPacket {
45 pub header: SphinxHeader,
46 pub payload: Payload,
47}
48
49#[allow(clippy::len_without_is_empty)]
50impl SphinxPacket {
51 pub fn new(
53 message: Vec<u8>,
54 route: &[Node],
55 destination: &Destination,
56 delays: &[Delay],
57 ) -> Result<SphinxPacket> {
58 SphinxPacketBuilder::default().build_packet(message, route, destination, delays)
59 }
60
61 pub fn shared_secret(&self) -> PublicKey {
62 self.header.shared_secret
63 }
64
65 pub fn len(&self) -> usize {
66 HEADER_SIZE + self.payload.len()
68 }
69
70 pub fn process_with_expanded_secret(
74 self,
75 expanded_shared_secret: &ExpandedSharedSecret,
76 ) -> Result<ProcessedPacket> {
77 let unwrapped_header = self
78 .header
79 .process_with_expanded_secret(expanded_shared_secret)?;
80 let unwrapped_payload = self.payload.unwrap(unwrapped_header.payload_key())?;
81
82 Ok(unwrapped_header.attach_payload(unwrapped_payload))
83 }
84
85 pub fn process(self, node_secret_key: &StaticSecret) -> Result<ProcessedPacket> {
87 let unwrapped_header = self.header.process(node_secret_key)?;
88 let unwrapped_payload = self.payload.unwrap(unwrapped_header.payload_key())?;
89
90 Ok(unwrapped_header.attach_payload(unwrapped_payload))
91 }
92
93 pub fn to_bytes(&self) -> Vec<u8> {
94 self.header
95 .to_bytes()
96 .iter()
97 .copied()
98 .chain(self.payload.as_bytes().iter().copied())
99 .collect()
100 }
101
102 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
103 if bytes.len() < HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE {
106 return Err(Error::new(
107 ErrorKind::InvalidPacket,
108 format!(
109 "tried to recover sphinx packet using {} bytes, expected at least {}",
110 bytes.len(),
111 HEADER_SIZE + PAYLOAD_OVERHEAD_SIZE
112 ),
113 ));
114 }
115
116 let header_bytes = &bytes[..HEADER_SIZE];
117 let payload_bytes = &bytes[HEADER_SIZE..];
118 let header = SphinxHeader::from_bytes(header_bytes)?;
119 let payload = Payload::from_bytes(payload_bytes)?;
120
121 Ok(SphinxPacket { header, payload })
122 }
123}
124
125#[cfg(test)]
126mod test_building_packet_from_bytes {
127 use super::*;
128
129 #[test]
130 fn from_bytes_returns_error_if_bytes_are_too_short() {
131 let bytes = [0u8; 1];
132 let expected = ErrorKind::InvalidPacket;
133 match SphinxPacket::from_bytes(&bytes) {
134 Err(err) => assert_eq!(expected, err.kind()),
135 _ => panic!("Should have returned an error when packet bytes too short"),
136 };
137 }
138}