Skip to content

Commit 89cc8da

Browse files
committed
Introduce DummyTlv
1 parent 41ef815 commit 89cc8da

File tree

2 files changed

+54
-13
lines changed

2 files changed

+54
-13
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,23 @@ pub(crate) struct ForwardTlvs {
266266
pub(crate) next_blinding_override: Option<PublicKey>,
267267
}
268268

269+
/// Represents the dummy TLV encoded immediately before the actual [`ReceiveTlvs`] in a blinded path.
270+
/// These TLVs are intended for the final node and are recursively authenticated until the real
271+
/// [`ReceiveTlvs`] is reached.
272+
///
273+
/// Their purpose is to arbitrarily extend the path length, obscuring the receiver's position in the
274+
/// route and thereby enhancing privacy.
275+
pub(crate) struct DummyTlv {}
276+
277+
impl Writeable for DummyTlv {
278+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
279+
encode_tlv_stream!(writer, {
280+
(65539, (), required),
281+
});
282+
Ok(())
283+
}
284+
}
285+
269286
/// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
270287
pub(crate) struct ReceiveTlvs {
271288
/// If `context` is `Some`, it is used to identify the blinded path that this onion message is

lightning/src/onion_message/packet.rs

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use super::async_payments::AsyncPaymentsMessage;
1717
use super::dns_resolution::DNSResolverMessage;
1818
use super::messenger::CustomOnionMessageHandler;
1919
use super::offers::OffersMessage;
20-
use crate::blinded_path::message::{BlindedMessagePath, ForwardTlvs, NextMessageHop, ReceiveTlvs};
20+
use crate::blinded_path::message::{
21+
BlindedMessagePath, DummyTlv, ForwardTlvs, NextMessageHop, ReceiveTlvs,
22+
};
2123
use crate::crypto::streams::{ChaChaDualPolyReadAdapter, ChaChaPolyWriteAdapter};
2224
use crate::ln::msgs::DecodeError;
2325
use crate::ln::onion_utils;
@@ -112,6 +114,13 @@ impl LengthReadable for Packet {
112114
pub(super) enum Payload<T: OnionMessageContents> {
113115
/// This payload is for an intermediate hop.
114116
Forward(ForwardControlTlvs),
117+
/// This payload is a dummy hop, and is intended to be peeled.
118+
Dummy {
119+
/// The [`DummyControlTlvs`] were authenticated with the additional key that was
120+
/// provided to [`ReadableArgs::read`].
121+
control_tlvs_authenticated: bool,
122+
control_tlvs: DummyControlTlvs,
123+
},
115124
/// This payload is for the final hop.
116125
Receive {
117126
/// The [`ReceiveControlTlvs`] were authenticated with the additional key which was
@@ -212,6 +221,9 @@ pub(super) enum ForwardControlTlvs {
212221
Unblinded(ForwardTlvs),
213222
}
214223

224+
/// Dummy control TLVs, used for dummy hops.
225+
pub(super) struct DummyControlTlvs(pub(super) DummyTlv);
226+
215227
/// Receive control TLVs in their blinded and unblinded form.
216228
pub(super) enum ReceiveControlTlvs {
217229
/// See [`ForwardControlTlvs::Blinded`].
@@ -243,6 +255,13 @@ impl<T: OnionMessageContents> Writeable for (Payload<T>, [u8; 32]) {
243255
let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
244256
_encode_varint_length_prefixed_tlv!(w, { (4, write_adapter, required) })
245257
},
258+
Payload::Dummy {
259+
control_tlvs: DummyControlTlvs(control_tlvs),
260+
control_tlvs_authenticated: _,
261+
} => {
262+
let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
263+
_encode_varint_length_prefixed_tlv!(w, { (4, write_adapter, required) })
264+
},
246265
Payload::Receive {
247266
control_tlvs: ReceiveControlTlvs::Unblinded(control_tlvs),
248267
reply_path,
@@ -323,6 +342,12 @@ impl<H: CustomOnionMessageHandler + ?Sized, L: Logger + ?Sized>
323342
}
324343
Ok(Payload::Forward(ForwardControlTlvs::Unblinded(tlvs)))
325344
},
345+
Some(ChaChaDualPolyReadAdapter { readable: ControlTlvs::Dummy(tlvs), used_aad }) => {
346+
Ok(Payload::Dummy {
347+
control_tlvs_authenticated: used_aad,
348+
control_tlvs: DummyControlTlvs(tlvs),
349+
})
350+
},
326351
Some(ChaChaDualPolyReadAdapter { readable: ControlTlvs::Receive(tlvs), used_aad }) => {
327352
Ok(Payload::Receive {
328353
control_tlvs: ReceiveControlTlvs::Unblinded(tlvs),
@@ -342,6 +367,8 @@ impl<H: CustomOnionMessageHandler + ?Sized, L: Logger + ?Sized>
342367
pub(crate) enum ControlTlvs {
343368
/// This onion message is intended to be forwarded.
344369
Forward(ForwardTlvs),
370+
/// This onion message is a dummy, and is intended to be peeled.
371+
Dummy(DummyTlv),
345372
/// This onion message is intended to be received.
346373
Receive(ReceiveTlvs),
347374
}
@@ -357,6 +384,7 @@ impl Readable for ControlTlvs {
357384
(4, next_node_id, option),
358385
(8, next_blinding_override, option),
359386
(65537, context, option),
387+
(65539, is_dummy, option),
360388
});
361389

362390
let next_hop = match (short_channel_id, next_node_id) {
@@ -366,18 +394,13 @@ impl Readable for ControlTlvs {
366394
(None, None) => None,
367395
};
368396

369-
let valid_fwd_fmt = next_hop.is_some();
370-
let valid_recv_fmt = next_hop.is_none() && next_blinding_override.is_none();
371-
372-
let payload_fmt = if valid_fwd_fmt {
373-
ControlTlvs::Forward(ForwardTlvs {
374-
next_hop: next_hop.unwrap(),
375-
next_blinding_override,
376-
})
377-
} else if valid_recv_fmt {
378-
ControlTlvs::Receive(ReceiveTlvs { context })
379-
} else {
380-
return Err(DecodeError::InvalidValue);
397+
let payload_fmt = match (next_hop, next_blinding_override, is_dummy) {
398+
(Some(hop), _, None) => {
399+
ControlTlvs::Forward(ForwardTlvs { next_hop: hop, next_blinding_override })
400+
},
401+
(None, None, Some(())) => ControlTlvs::Dummy(DummyTlv {}),
402+
(None, None, None) => ControlTlvs::Receive(ReceiveTlvs { context }),
403+
_ => return Err(DecodeError::InvalidValue),
381404
};
382405

383406
Ok(payload_fmt)
@@ -388,6 +411,7 @@ impl Writeable for ControlTlvs {
388411
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
389412
match self {
390413
Self::Forward(tlvs) => tlvs.write(w),
414+
Self::Dummy(tlvs) => tlvs.write(w),
391415
Self::Receive(tlvs) => tlvs.write(w),
392416
}
393417
}

0 commit comments

Comments
 (0)