Skip to content

Commit 4f5b367

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 224ef96 commit 4f5b367

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,
@@ -635,15 +659,24 @@ impl_writeable_tlv_based!(DNSResolverContext, {
635659
/// to pad message blinded path's [`BlindedHop`]
636660
pub(crate) const MESSAGE_PADDING_ROUND_OFF: usize = 100;
637661

662+
/// The maximum number of dummy hops that can be added to a blinded path.
663+
/// This is to prevent paths from becoming too long and potentially causing
664+
/// issues with message processing or routing.
665+
pub const MAX_DUMMY_HOPS_COUNT: usize = 10;
666+
638667
/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
639668
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
640669
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[MessageForwardNode],
641-
recipient_node_id: PublicKey, context: MessageContext, session_priv: &SecretKey,
642-
local_node_receive_key: ReceiveAuthKey,
670+
recipient_node_id: PublicKey, dummy_hop_count: usize, context: MessageContext,
671+
session_priv: &SecretKey, local_node_receive_key: ReceiveAuthKey,
643672
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
673+
let dummy_count = cmp::min(dummy_hop_count, MAX_DUMMY_HOPS_COUNT);
644674
let pks = intermediate_nodes
645675
.iter()
646676
.map(|node| (node.node_id, None))
677+
.chain(
678+
core::iter::repeat((recipient_node_id, Some(local_node_receive_key))).take(dummy_count),
679+
)
647680
.chain(core::iter::once((recipient_node_id, Some(local_node_receive_key))));
648681
let is_compact = intermediate_nodes.iter().any(|node| node.short_channel_id.is_some());
649682

@@ -658,6 +691,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
658691
.map(|next_hop| {
659692
ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None })
660693
})
694+
.chain((0..dummy_count).map(|_| ControlTlvs::Dummy))
661695
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { context: Some(context) })));
662696

663697
if is_compact {

0 commit comments

Comments
 (0)