Skip to content

Commit 988defb

Browse files
committed
Update Default Blinded Path constructor to use Dummy Hops
Applies dummy hops by default when constructing blinded paths via `DefaultMessageRouter`, enhancing privacy by obscuring the true path length. Uses a predefined `DUMMY_HOPS_COUNT` to apply dummy hops consistently without requiring explicit user input.
1 parent b8d62fc commit 988defb

File tree

1 file changed

+45
-31
lines changed

1 file changed

+45
-31
lines changed

lightning/src/onion_message/messenger.rs

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,14 @@ where
540540
entropy_source: ES,
541541
}
542542

543+
// Target total length (in hops) for non-compact blinded paths.
544+
// We pad with dummy hops until the path reaches this length,
545+
// obscuring the recipient's true position.
546+
//
547+
// Compact paths are optimized for minimal size, so we avoid
548+
// adding dummy hops to them.
549+
pub(crate) const PADDED_PATH_LENGTH: usize = 4;
550+
543551
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, ES: Deref> DefaultMessageRouter<G, L, ES>
544552
where
545553
L::Target: Logger,
@@ -595,40 +603,46 @@ where
595603
a_tor_only.cmp(b_tor_only).then(a_channels.cmp(b_channels).reverse())
596604
});
597605

598-
let entropy = &**entropy_source;
599-
let paths = peer_info
606+
let build_path = |intermediate_hops: &[MessageForwardNode]| {
607+
let dummy_hops_count = if compact_paths {
608+
0
609+
} else {
610+
// Add one for the final recipient TLV
611+
PADDED_PATH_LENGTH.saturating_sub(intermediate_hops.len() + 1)
612+
};
613+
614+
BlindedMessagePath::new_with_dummy_hops(
615+
intermediate_hops,
616+
recipient,
617+
dummy_hops_count,
618+
local_node_receive_key,
619+
context.clone(),
620+
&**entropy_source,
621+
secp_ctx,
622+
)
623+
};
624+
625+
// Try to create paths from peer info, fall back to direct path if needed
626+
let mut paths = peer_info
600627
.into_iter()
601-
.map(|(peer, _, _)| {
602-
BlindedMessagePath::new(
603-
&[peer],
604-
recipient,
605-
local_node_receive_key,
606-
context.clone(),
607-
entropy,
608-
secp_ctx,
609-
)
610-
})
628+
.map(|(peer, _, _)| build_path(&[peer]))
611629
.take(MAX_PATHS)
612-
.collect::<Result<Vec<_>, _>>();
613-
614-
let mut paths = match paths {
615-
Ok(paths) if !paths.is_empty() => Ok(paths),
616-
_ => {
617-
if is_recipient_announced {
618-
BlindedMessagePath::new(
619-
&[],
620-
recipient,
621-
local_node_receive_key,
622-
context,
623-
&**entropy_source,
624-
secp_ctx,
625-
)
630+
.collect::<Result<Vec<_>, _>>()
631+
.ok()
632+
.filter(|paths| !paths.is_empty())
633+
.or_else(|| {
634+
is_recipient_announced
635+
.then(|| build_path(&[]))
636+
.and_then(|result| result.ok())
626637
.map(|path| vec![path])
627-
} else {
628-
Err(())
629-
}
630-
},
631-
}?;
638+
})
639+
.ok_or(())?;
640+
641+
// Sanity check: Ones the paths are created for the non-compact case, ensure
642+
// each of them are of the length `PADDED_PATH_LENGTH`.
643+
if !compact_paths {
644+
debug_assert!(paths.iter().all(|path| path.blinded_hops().len() == PADDED_PATH_LENGTH));
645+
}
632646

633647
if compact_paths {
634648
for path in &mut paths {

0 commit comments

Comments
 (0)