Skip to content

Commit 5badf75

Browse files
committed
Introduce Dummy Hop support in Blinded Path Constructor
Adds a new constructor for blinded paths that allows specifying the number of dummy hops. This enables users to insert arbitrary hops before the real destination, enhancing privacy by making it harder to infer the sender–receiver distance or identify the final destination. Lays the groundwork for future use of dummy hops in blinded path construction.
1 parent 89cc8da commit 5badf75

File tree

1 file changed

+37
-3
lines changed

1 file changed

+37
-3
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ use crate::types::payment::PaymentHash;
3131
use crate::util::scid_utils;
3232
use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Readable, Writeable, Writer};
3333

34-
use core::mem;
3534
use core::ops::Deref;
3635
use core::time::Duration;
36+
use core::{cmp, mem};
3737

3838
/// A blinded path to be used for sending or receiving a message, hiding the identity of the
3939
/// recipient.
@@ -74,6 +74,29 @@ impl BlindedMessagePath {
7474
local_node_receive_key: ReceiveAuthKey, context: MessageContext, entropy_source: ES,
7575
secp_ctx: &Secp256k1<T>,
7676
) -> Result<Self, ()>
77+
where
78+
ES::Target: EntropySource,
79+
{
80+
BlindedMessagePath::new_with_dummy_hops(
81+
intermediate_nodes,
82+
recipient_node_id,
83+
0,
84+
local_node_receive_key,
85+
context,
86+
entropy_source,
87+
secp_ctx,
88+
)
89+
}
90+
91+
/// Same as [`BlindedMessagePath::new`], but allows specifying a number of dummy hops.
92+
///
93+
/// Note:
94+
/// At most [`MAX_DUMMY_HOPS_COUNT`] dummy hops can be added to the blinded path.
95+
pub fn new_with_dummy_hops<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
96+
intermediate_nodes: &[MessageForwardNode], recipient_node_id: PublicKey,
97+
dummy_hop_count: usize, local_node_receive_key: ReceiveAuthKey, context: MessageContext,
98+
entropy_source: ES, secp_ctx: &Secp256k1<T>,
99+
) -> Result<Self, ()>
77100
where
78101
ES::Target: EntropySource,
79102
{
@@ -91,6 +114,7 @@ impl BlindedMessagePath {
91114
secp_ctx,
92115
intermediate_nodes,
93116
recipient_node_id,
117+
dummy_hop_count,
94118
context,
95119
&blinding_secret,
96120
local_node_receive_key,
@@ -638,15 +662,24 @@ impl_writeable_tlv_based!(DNSResolverContext, {
638662
/// to pad message blinded path's [`BlindedHop`]
639663
pub(crate) const MESSAGE_PADDING_ROUND_OFF: usize = 100;
640664

665+
/// The maximum number of dummy hops that can be added to a blinded path.
666+
/// This is to prevent paths from becoming too long and potentially causing
667+
/// issues with message processing or routing.
668+
pub const MAX_DUMMY_HOPS_COUNT: usize = 10;
669+
641670
/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
642671
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
643672
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[MessageForwardNode],
644-
recipient_node_id: PublicKey, context: MessageContext, session_priv: &SecretKey,
645-
local_node_receive_key: ReceiveAuthKey,
673+
recipient_node_id: PublicKey, dummy_hop_count: usize, context: MessageContext,
674+
session_priv: &SecretKey, local_node_receive_key: ReceiveAuthKey,
646675
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
676+
let dummy_count = cmp::min(dummy_hop_count, MAX_DUMMY_HOPS_COUNT);
647677
let pks = intermediate_nodes
648678
.iter()
649679
.map(|node| (node.node_id, None))
680+
.chain(
681+
core::iter::repeat((recipient_node_id, Some(local_node_receive_key))).take(dummy_count),
682+
)
650683
.chain(core::iter::once((recipient_node_id, Some(local_node_receive_key))));
651684
let is_compact = intermediate_nodes.iter().any(|node| node.short_channel_id.is_some());
652685

@@ -661,6 +694,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
661694
.map(|next_hop| {
662695
ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None })
663696
})
697+
.chain((0..dummy_count).map(|_| ControlTlvs::Dummy(DummyTlv {})))
664698
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { context: Some(context) })));
665699

666700
if is_compact {

0 commit comments

Comments
 (0)