1use bitcoin::secp256k1::ecdh::SharedSecret;
13use bitcoin::secp256k1::PublicKey;
14
15use super::async_payments::AsyncPaymentsMessage;
16use super::dns_resolution::DNSResolverMessage;
17use super::messenger::CustomOnionMessageHandler;
18use super::offers::OffersMessage;
19use crate::blinded_path::message::{
20 BlindedMessagePath, DummyTlv, ForwardTlvs, NextMessageHop, ReceiveTlvs,
21};
22use crate::crypto::streams::{ChaChaDualPolyReadAdapter, ChaChaPolyWriteAdapter};
23use crate::ln::msgs::DecodeError;
24use crate::ln::onion_utils;
25use crate::sign::ReceiveAuthKey;
26use crate::util::logger::Logger;
27use crate::util::ser::{
28 BigSize, FixedLengthReader, LengthLimitedRead, LengthReadable, LengthReadableArgs, Readable,
29 ReadableArgs, Writeable, Writer,
30};
31
32use crate::io::{self, Read};
33use crate::prelude::*;
34use core::cmp;
35use core::fmt;
36
37pub(super) const SMALL_PACKET_HOP_DATA_LEN: usize = 1300;
40pub(super) const BIG_PACKET_HOP_DATA_LEN: usize = 32768;
41
42#[derive(Clone, Hash, PartialEq, Eq)]
44pub struct Packet {
45 pub version: u8,
47 pub public_key: PublicKey,
49 pub hop_data: Vec<u8>,
56 pub hmac: [u8; 32],
58}
59
60impl onion_utils::Packet for Packet {
61 type Data = Vec<u8>;
62 fn new(public_key: PublicKey, hop_data: Vec<u8>, hmac: [u8; 32]) -> Packet {
63 Self { version: 0, public_key, hop_data, hmac }
64 }
65}
66
67impl fmt::Debug for Packet {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 f.write_fmt(format_args!(
70 "Onion message packet version {} with hmac {:?}",
71 self.version,
72 &self.hmac[..]
73 ))
74 }
75}
76
77impl Writeable for Packet {
78 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
79 self.version.write(w)?;
80 self.public_key.write(w)?;
81 w.write_all(&self.hop_data)?;
82 self.hmac.write(w)?;
83 Ok(())
84 }
85}
86
87impl LengthReadable for Packet {
88 fn read_from_fixed_length_buffer<R: LengthLimitedRead>(r: &mut R) -> Result<Self, DecodeError> {
89 const READ_BUFFER_SIZE: usize = 4096;
90 let hop_data_len = r.remaining_bytes().saturating_sub(66) as usize; let version = Readable::read(r)?;
93 let public_key = Readable::read(r)?;
94
95 let mut hop_data = Vec::new();
96 let mut read_idx = 0;
97 while read_idx < hop_data_len {
98 let mut read_buffer = [0; READ_BUFFER_SIZE];
99 let read_amt = cmp::min(hop_data_len - read_idx, READ_BUFFER_SIZE);
100 r.read_exact(&mut read_buffer[..read_amt])?;
101 hop_data.extend_from_slice(&read_buffer[..read_amt]);
102 read_idx += read_amt;
103 }
104
105 let hmac = Readable::read(r)?;
106 Ok(Packet { version, public_key, hop_data, hmac })
107 }
108}
109
110pub(super) enum Payload<T: OnionMessageContents> {
114 Forward(ForwardControlTlvs),
116 Dummy {
118 control_tlvs_authenticated: bool,
121 },
122 Receive {
124 control_tlvs_authenticated: bool,
127 control_tlvs: ReceiveControlTlvs,
128 reply_path: Option<BlindedMessagePath>,
129 message: T,
130 },
131}
132
133#[derive(Clone, Debug)]
137pub enum ParsedOnionMessageContents<T: OnionMessageContents> {
138 Offers(OffersMessage),
140 AsyncPayments(AsyncPaymentsMessage),
142 DNSResolver(DNSResolverMessage),
144 Custom(T),
146}
147
148impl<T: OnionMessageContents> OnionMessageContents for ParsedOnionMessageContents<T> {
149 fn tlv_type(&self) -> u64 {
153 match self {
154 &ParsedOnionMessageContents::Offers(ref msg) => msg.tlv_type(),
155 &ParsedOnionMessageContents::AsyncPayments(ref msg) => msg.tlv_type(),
156 &ParsedOnionMessageContents::DNSResolver(ref msg) => msg.tlv_type(),
157 &ParsedOnionMessageContents::Custom(ref msg) => msg.tlv_type(),
158 }
159 }
160 #[cfg(c_bindings)]
161 fn msg_type(&self) -> String {
162 match self {
163 ParsedOnionMessageContents::Offers(ref msg) => msg.msg_type(),
164 ParsedOnionMessageContents::AsyncPayments(ref msg) => msg.msg_type(),
165 ParsedOnionMessageContents::DNSResolver(ref msg) => msg.msg_type(),
166 ParsedOnionMessageContents::Custom(ref msg) => msg.msg_type(),
167 }
168 }
169 #[cfg(not(c_bindings))]
170 fn msg_type(&self) -> &'static str {
171 match self {
172 ParsedOnionMessageContents::Offers(ref msg) => msg.msg_type(),
173 ParsedOnionMessageContents::AsyncPayments(ref msg) => msg.msg_type(),
174 ParsedOnionMessageContents::DNSResolver(ref msg) => msg.msg_type(),
175 ParsedOnionMessageContents::Custom(ref msg) => msg.msg_type(),
176 }
177 }
178}
179
180impl<T: OnionMessageContents> Writeable for ParsedOnionMessageContents<T> {
181 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
182 match self {
183 ParsedOnionMessageContents::Offers(msg) => msg.write(w),
184 ParsedOnionMessageContents::AsyncPayments(msg) => msg.write(w),
185 ParsedOnionMessageContents::DNSResolver(msg) => msg.write(w),
186 ParsedOnionMessageContents::Custom(msg) => msg.write(w),
187 }
188 }
189}
190
191pub trait OnionMessageContents: Writeable + core::fmt::Debug {
193 fn tlv_type(&self) -> u64;
195
196 #[cfg(c_bindings)]
197 fn msg_type(&self) -> String;
199
200 #[cfg(not(c_bindings))]
201 fn msg_type(&self) -> &'static str;
203}
204
205pub(super) enum ForwardControlTlvs {
207 Blinded(Vec<u8>),
210 Unblinded(ForwardTlvs),
215}
216
217pub(super) enum ReceiveControlTlvs {
219 Blinded(Vec<u8>),
221 Unblinded(ReceiveTlvs),
223}
224
225impl<T: OnionMessageContents> Writeable for (Payload<T>, [u8; 32]) {
227 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
228 match &self.0 {
229 Payload::Forward(ForwardControlTlvs::Blinded(encrypted_bytes)) => {
230 _encode_varint_length_prefixed_tlv!(w, { (4, encrypted_bytes, required_vec) })
231 },
232 Payload::Receive {
233 control_tlvs: ReceiveControlTlvs::Blinded(encrypted_bytes),
234 reply_path,
235 message,
236 control_tlvs_authenticated: _,
237 } => {
238 _encode_varint_length_prefixed_tlv!(w, {
239 (2, reply_path, option),
240 (4, encrypted_bytes, required_vec),
241 (message.tlv_type(), message, required)
242 })
243 },
244 Payload::Forward(ForwardControlTlvs::Unblinded(control_tlvs)) => {
245 let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
246 _encode_varint_length_prefixed_tlv!(w, { (4, write_adapter, required) })
247 },
248 Payload::Dummy { control_tlvs_authenticated: _ } => {
249 let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &DummyTlv);
250 _encode_varint_length_prefixed_tlv!(w, { (4, write_adapter, required) })
251 },
252 Payload::Receive {
253 control_tlvs: ReceiveControlTlvs::Unblinded(control_tlvs),
254 reply_path,
255 message,
256 control_tlvs_authenticated: _,
257 } => {
258 let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
259 _encode_varint_length_prefixed_tlv!(w, {
260 (2, reply_path, option),
261 (4, write_adapter, required),
262 (message.tlv_type(), message, required)
263 })
264 },
265 }
266 Ok(())
267 }
268}
269
270impl<H: CustomOnionMessageHandler + ?Sized, L: Logger + ?Sized>
272 ReadableArgs<(SharedSecret, &H, ReceiveAuthKey, &L)>
273 for Payload<ParsedOnionMessageContents<<H as CustomOnionMessageHandler>::CustomMessage>>
274{
275 fn read<R: Read>(
276 r: &mut R, args: (SharedSecret, &H, ReceiveAuthKey, &L),
277 ) -> Result<Self, DecodeError> {
278 let (encrypted_tlvs_ss, handler, receive_tlvs_key, logger) = args;
279
280 let v: BigSize = Readable::read(r)?;
281 let mut rd = FixedLengthReader::new(r, v.0);
282 let mut reply_path: Option<BlindedMessagePath> = None;
283 let mut read_adapter: Option<ChaChaDualPolyReadAdapter<ControlTlvs>> = None;
284 let rho = onion_utils::gen_rho_from_shared_secret(&encrypted_tlvs_ss.secret_bytes());
285 let mut message_type: Option<u64> = None;
286 let mut message = None;
287 decode_tlv_stream_with_custom_tlv_decode!(&mut rd, {
288 (2, reply_path, option),
289 (4, read_adapter, (option: LengthReadableArgs, (rho, receive_tlvs_key.0))),
290 }, |msg_type, msg_reader| {
291 if msg_type < 64 { return Ok(false) }
292 if message_type.is_some() { return Err(DecodeError::InvalidValue) }
294
295 message_type = Some(msg_type);
296 match msg_type {
297 tlv_type if OffersMessage::is_known_type(tlv_type) => {
298 let msg = OffersMessage::read(msg_reader, (tlv_type, logger))?;
299 message = Some(ParsedOnionMessageContents::Offers(msg));
300 Ok(true)
301 },
302 tlv_type if AsyncPaymentsMessage::is_known_type(tlv_type) => {
303 let msg = AsyncPaymentsMessage::read(msg_reader, tlv_type)?;
304 message = Some(ParsedOnionMessageContents::AsyncPayments(msg));
305 Ok(true)
306 },
307 tlv_type if DNSResolverMessage::is_known_type(tlv_type) => {
308 let msg = DNSResolverMessage::read(msg_reader, tlv_type)?;
309 message = Some(ParsedOnionMessageContents::DNSResolver(msg));
310 Ok(true)
311 },
312 _ => match handler.read_custom_message(msg_type, msg_reader)? {
313 Some(msg) => {
314 message = Some(ParsedOnionMessageContents::Custom(msg));
315 Ok(true)
316 },
317 None => Ok(false),
318 },
319 }
320 });
321 rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?;
322
323 match read_adapter {
324 None => return Err(DecodeError::InvalidValue),
325 Some(ChaChaDualPolyReadAdapter { readable: ControlTlvs::Forward(tlvs), used_aad }) => {
326 if used_aad || message_type.is_some() {
327 return Err(DecodeError::InvalidValue);
328 }
329 Ok(Payload::Forward(ForwardControlTlvs::Unblinded(tlvs)))
330 },
331 Some(ChaChaDualPolyReadAdapter { readable: ControlTlvs::Dummy, used_aad }) => {
332 Ok(Payload::Dummy { control_tlvs_authenticated: used_aad })
333 },
334 Some(ChaChaDualPolyReadAdapter { readable: ControlTlvs::Receive(tlvs), used_aad }) => {
335 Ok(Payload::Receive {
336 control_tlvs: ReceiveControlTlvs::Unblinded(tlvs),
337 reply_path,
338 message: message.ok_or(DecodeError::InvalidValue)?,
339 control_tlvs_authenticated: used_aad,
340 })
341 },
342 }
343 }
344}
345
346pub(crate) enum ControlTlvs {
351 Forward(ForwardTlvs),
353 Dummy,
355 Receive(ReceiveTlvs),
357}
358
359impl Readable for ControlTlvs {
360 fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
361 _init_and_read_tlv_stream!(r, {
362 (2, short_channel_id, option),
367 (4, next_node_id, option),
368 (8, next_blinding_override, option),
369 (65537, context, option),
370 (65539, is_dummy, option),
371 });
372
373 let next_hop = match (short_channel_id, next_node_id) {
374 (Some(_), Some(_)) => return Err(DecodeError::InvalidValue),
375 (Some(scid), None) => Some(NextMessageHop::ShortChannelId(scid)),
376 (None, Some(pubkey)) => Some(NextMessageHop::NodeId(pubkey)),
377 (None, None) => None,
378 };
379
380 let payload_fmt = match (next_hop, next_blinding_override, is_dummy) {
381 (Some(hop), _, None) => {
382 ControlTlvs::Forward(ForwardTlvs { next_hop: hop, next_blinding_override })
383 },
384 (None, None, Some(())) => ControlTlvs::Dummy,
385 (None, None, None) => ControlTlvs::Receive(ReceiveTlvs { context }),
386 _ => return Err(DecodeError::InvalidValue),
387 };
388
389 Ok(payload_fmt)
390 }
391}
392
393impl Writeable for ControlTlvs {
394 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
395 match self {
396 Self::Forward(tlvs) => tlvs.write(w),
397 Self::Dummy => DummyTlv.write(w),
398 Self::Receive(tlvs) => tlvs.write(w),
399 }
400 }
401}