Skip to content

Commit 9d35475

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 0f587ff commit 9d35475

File tree

7 files changed

+64
-21
lines changed

7 files changed

+64
-21
lines changed

lightning-background-processor/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ mod tests {
11741174
use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
11751175
use lightning::routing::router::{CandidateRouteHop, DefaultRouter, Path, RouteHop};
11761176
use lightning::routing::scoring::{ChannelUsage, LockableScore, ScoreLookUp, ScoreUpdate};
1177-
use lightning::sign::{ChangeDestinationSourceSync, InMemorySigner, KeysManager};
1177+
use lightning::sign::{ChangeDestinationSourceSync, InMemorySigner, KeysManager, NodeSigner};
11781178
use lightning::types::features::{ChannelFeatures, NodeFeatures};
11791179
use lightning::types::payment::PaymentHash;
11801180
use lightning::util::config::UserConfig;
@@ -1650,6 +1650,7 @@ mod tests {
16501650
let msg_router = Arc::new(DefaultMessageRouter::new(
16511651
network_graph.clone(),
16521652
Arc::clone(&keys_manager),
1653+
keys_manager.get_expanded_key(),
16531654
));
16541655
let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Bitcoin));
16551656
let kv_store =

lightning-liquidity/tests/common/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use lightning::onion_message::messenger::DefaultMessageRouter;
2424
use lightning::routing::gossip::{NetworkGraph, P2PGossipSync};
2525
use lightning::routing::router::{CandidateRouteHop, DefaultRouter, Path};
2626
use lightning::routing::scoring::{ChannelUsage, ScoreLookUp, ScoreUpdate};
27-
use lightning::sign::{InMemorySigner, KeysManager};
27+
use lightning::sign::{InMemorySigner, KeysManager, NodeSigner};
2828
use lightning::util::config::UserConfig;
2929
use lightning::util::persist::{
3030
KVStore, CHANNEL_MANAGER_PERSISTENCE_KEY, CHANNEL_MANAGER_PERSISTENCE_PRIMARY_NAMESPACE,
@@ -418,8 +418,11 @@ pub(crate) fn create_liquidity_node(
418418
scorer.clone(),
419419
Default::default(),
420420
));
421-
let msg_router =
422-
Arc::new(DefaultMessageRouter::new(Arc::clone(&network_graph), Arc::clone(&keys_manager)));
421+
let msg_router = Arc::new(DefaultMessageRouter::new(
422+
Arc::clone(&network_graph),
423+
Arc::clone(&keys_manager),
424+
keys_manager.get_expanded_key(),
425+
));
423426
let chain_source = Arc::new(test_utils::TestChainSource::new(Network::Bitcoin));
424427
let kv_store =
425428
Arc::new(FilesystemStore::new(format!("{}_persister_{}", &persist_dir, i).into()));

lightning/src/ln/functional_test_utils.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::onion_message::messenger::OnionMessenger;
2929
use crate::ln::onion_utils::LocalHTLCFailureReason;
3030
use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate};
3131
use crate::routing::router::{self, PaymentParameters, Route, RouteParameters};
32-
use crate::sign::{EntropySource, RandomBytes};
32+
use crate::sign::{EntropySource, NodeSigner, RandomBytes};
3333
use crate::util::config::{MaxDustHTLCExposure, UserConfig};
3434
use crate::util::logger::Logger;
3535
use crate::util::scid_utils;
@@ -725,7 +725,7 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
725725
signer_provider: self.keys_manager,
726726
fee_estimator: &test_utils::TestFeeEstimator::new(253),
727727
router: &test_utils::TestRouter::new(Arc::clone(&network_graph), &self.logger, &scorer),
728-
message_router: &test_utils::TestMessageRouter::new(network_graph, self.keys_manager),
728+
message_router: &test_utils::TestMessageRouter::new(network_graph, self.keys_manager, self.keys_manager.get_expanded_key()),
729729
chain_monitor: self.chain_monitor,
730730
tx_broadcaster: &broadcaster,
731731
logger: &self.logger,
@@ -3347,13 +3347,14 @@ pub fn create_node_cfgs_with_persisters<'a>(node_count: usize, chanmon_cfgs: &'a
33473347
let chain_monitor = test_utils::TestChainMonitor::new(Some(&chanmon_cfgs[i].chain_source), &chanmon_cfgs[i].tx_broadcaster, &chanmon_cfgs[i].logger, &chanmon_cfgs[i].fee_estimator, persisters[i], &chanmon_cfgs[i].keys_manager);
33483348
let network_graph = Arc::new(NetworkGraph::new(Network::Testnet, &chanmon_cfgs[i].logger));
33493349
let seed = [i as u8; 32];
3350+
let expanded_key = chanmon_cfgs[i].keys_manager.get_expanded_key();
33503351
nodes.push(NodeCfg {
33513352
chain_source: &chanmon_cfgs[i].chain_source,
33523353
logger: &chanmon_cfgs[i].logger,
33533354
tx_broadcaster: &chanmon_cfgs[i].tx_broadcaster,
33543355
fee_estimator: &chanmon_cfgs[i].fee_estimator,
33553356
router: test_utils::TestRouter::new(network_graph.clone(), &chanmon_cfgs[i].logger, &chanmon_cfgs[i].scorer),
3356-
message_router: test_utils::TestMessageRouter::new(network_graph.clone(), &chanmon_cfgs[i].keys_manager),
3357+
message_router: test_utils::TestMessageRouter::new(network_graph.clone(), &chanmon_cfgs[i].keys_manager, expanded_key),
33573358
chain_monitor,
33583359
keys_manager: &chanmon_cfgs[i].keys_manager,
33593360
node_seed: seed,

lightning/src/ln/functional_tests.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use crate::routing::gossip::{NetworkGraph, NetworkUpdate};
5050
use crate::routing::router::{
5151
get_route, Path, PaymentParameters, Route, RouteHop, RouteParameters,
5252
};
53-
use crate::sign::{EntropySource, OutputSpender, SignerProvider};
53+
use crate::sign::{EntropySource, NodeSigner, OutputSpender, SignerProvider};
5454
use crate::types::features::{ChannelFeatures, ChannelTypeFeatures, NodeFeatures};
5555
use crate::types::payment::{PaymentHash, PaymentSecret};
5656
use crate::util::config::{
@@ -5112,7 +5112,11 @@ pub fn test_key_derivation_params() {
51125112
let scorer = RwLock::new(test_utils::TestScorer::new());
51135113
let router =
51145114
test_utils::TestRouter::new(network_graph.clone(), &chanmon_cfgs[0].logger, &scorer);
5115-
let message_router = test_utils::TestMessageRouter::new(network_graph.clone(), &keys_manager);
5115+
let message_router = test_utils::TestMessageRouter::new(
5116+
network_graph.clone(),
5117+
&keys_manager,
5118+
keys_manager.get_expanded_key(),
5119+
);
51165120
let node = NodeCfg {
51175121
chain_source: &chanmon_cfgs[0].chain_source,
51185122
logger: &chanmon_cfgs[0].logger,

lightning/src/onion_message/functional_tests.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,11 @@ fn create_nodes_using_cfgs(cfgs: Vec<MessengerCfg>) -> Vec<MessengerNode> {
279279
let node_signer = Arc::new(TestNodeSigner::new(secret_key));
280280

281281
let node_id_lookup = Arc::new(EmptyNodeIdLookUp {});
282-
let message_router =
283-
Arc::new(DefaultMessageRouter::new(network_graph.clone(), entropy_source.clone()));
282+
let message_router = Arc::new(DefaultMessageRouter::new(
283+
network_graph.clone(),
284+
entropy_source.clone(),
285+
node_signer.get_expanded_key(),
286+
));
284287
let offers_message_handler = Arc::new(TestOffersMessageHandler {});
285288
let async_payments_message_handler = Arc::new(TestAsyncPaymentsMessageHandler {});
286289
let dns_resolver_message_handler = Arc::new(TestDNSResolverMessageHandler {});

lightning/src/onion_message/messenger.rs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use crate::ln::channelmanager::Verification;
4040
use crate::ln::msgs::{
4141
self, BaseMessageHandler, MessageSendEvent, OnionMessage, OnionMessageHandler, SocketAddress,
4242
};
43-
use crate::ln::onion_utils;
43+
use crate::ln::{inbound_payment, onion_utils};
4444
use crate::routing::gossip::{NetworkGraph, NodeId, ReadOnlyNetworkGraph};
4545
use crate::sign::{EntropySource, NodeSigner, Recipient};
4646
use crate::types::features::{InitFeatures, NodeFeatures};
@@ -541,6 +541,7 @@ where
541541
{
542542
network_graph: G,
543543
entropy_source: ES,
544+
expanded_key: inbound_payment::ExpandedKey,
544545
}
545546

546547
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, ES: Deref> DefaultMessageRouter<G, L, ES>
@@ -549,16 +550,19 @@ where
549550
ES::Target: EntropySource,
550551
{
551552
/// Creates a [`DefaultMessageRouter`] using the given [`NetworkGraph`].
552-
pub fn new(network_graph: G, entropy_source: ES) -> Self {
553-
Self { network_graph, entropy_source }
553+
pub fn new(
554+
network_graph: G, entropy_source: ES, expanded_key: inbound_payment::ExpandedKey,
555+
) -> Self {
556+
Self { network_graph, entropy_source, expanded_key }
554557
}
555558

556559
fn create_blinded_paths_from_iter<
557560
I: ExactSizeIterator<Item = MessageForwardNode>,
558561
T: secp256k1::Signing + secp256k1::Verification,
559562
>(
560563
network_graph: &G, recipient: PublicKey, context: MessageContext, peers: I,
561-
entropy_source: &ES, secp_ctx: &Secp256k1<T>, compact_paths: bool,
564+
entropy_source: &ES, expanded_key: &inbound_payment::ExpandedKey, secp_ctx: &Secp256k1<T>,
565+
compact_paths: bool,
562566
) -> Result<Vec<BlindedMessagePath>, ()> {
563567
// Limit the number of blinded paths that are computed.
564568
const MAX_PATHS: usize = 3;
@@ -567,6 +571,19 @@ where
567571
// recipient's node_id.
568572
const MIN_PEER_CHANNELS: usize = 3;
569573

574+
// Add a random number (0 to 5) of dummy hops to each non-compact blinded path
575+
// to make it harder to infer the recipient's position.
576+
//
577+
// # Note on compact paths:
578+
//
579+
// Compact paths are optimized for minimal size. Adding dummy hops to them
580+
// would increase their size and negate their primary advantage.
581+
// Therefore, we avoid adding dummy hops to compact paths.
582+
let dummy_hops_count = compact_paths.then_some(0).unwrap_or_else(|| {
583+
let random_byte = entropy_source.get_secure_random_bytes()[0];
584+
random_byte % 6
585+
});
586+
570587
let network_graph = network_graph.deref().read_only();
571588
let is_recipient_announced =
572589
network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient));
@@ -597,7 +614,15 @@ where
597614
let paths = peer_info
598615
.into_iter()
599616
.map(|(peer, _, _)| {
600-
BlindedMessagePath::new(&[peer], recipient, context.clone(), entropy, secp_ctx)
617+
BlindedMessagePath::new_with_dummy_hops(
618+
&[peer],
619+
dummy_hops_count,
620+
recipient,
621+
context.clone(),
622+
entropy,
623+
expanded_key,
624+
secp_ctx,
625+
)
601626
})
602627
.take(MAX_PATHS)
603628
.collect::<Result<Vec<_>, _>>();
@@ -666,7 +691,7 @@ where
666691

667692
pub(crate) fn create_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
668693
network_graph: &G, recipient: PublicKey, context: MessageContext, peers: Vec<PublicKey>,
669-
entropy_source: &ES, secp_ctx: &Secp256k1<T>,
694+
entropy_source: &ES, expanded_key: &inbound_payment::ExpandedKey, secp_ctx: &Secp256k1<T>,
670695
) -> Result<Vec<BlindedMessagePath>, ()> {
671696
let peers =
672697
peers.into_iter().map(|node_id| MessageForwardNode { node_id, short_channel_id: None });
@@ -676,21 +701,24 @@ where
676701
context,
677702
peers.into_iter(),
678703
entropy_source,
704+
expanded_key,
679705
secp_ctx,
680706
false,
681707
)
682708
}
683709

684710
pub(crate) fn create_compact_blinded_paths<T: secp256k1::Signing + secp256k1::Verification>(
685711
network_graph: &G, recipient: PublicKey, context: MessageContext,
686-
peers: Vec<MessageForwardNode>, entropy_source: &ES, secp_ctx: &Secp256k1<T>,
712+
peers: Vec<MessageForwardNode>, entropy_source: &ES,
713+
expanded_key: &inbound_payment::ExpandedKey, secp_ctx: &Secp256k1<T>,
687714
) -> Result<Vec<BlindedMessagePath>, ()> {
688715
Self::create_blinded_paths_from_iter(
689716
network_graph,
690717
recipient,
691718
context,
692719
peers.into_iter(),
693720
entropy_source,
721+
expanded_key,
694722
secp_ctx,
695723
true,
696724
)
@@ -719,6 +747,7 @@ where
719747
context,
720748
peers,
721749
&self.entropy_source,
750+
&self.expanded_key,
722751
secp_ctx,
723752
)
724753
}
@@ -733,6 +762,7 @@ where
733762
context,
734763
peers,
735764
&self.entropy_source,
765+
&self.expanded_key,
736766
secp_ctx,
737767
)
738768
}

lightning/src/util/test_utils.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ use crate::events::bump_transaction::{Utxo, WalletSource};
2525
#[cfg(any(test, feature = "_externalize_tests"))]
2626
use crate::ln::chan_utils::CommitmentTransaction;
2727
use crate::ln::channel_state::ChannelDetails;
28-
use crate::ln::channelmanager;
2928
use crate::ln::inbound_payment::ExpandedKey;
3029
use crate::ln::msgs::{BaseMessageHandler, MessageSendEvent};
3130
use crate::ln::script::ShutdownScript;
3231
use crate::ln::types::ChannelId;
32+
use crate::ln::{channelmanager, inbound_payment};
3333
use crate::ln::{msgs, wire};
3434
use crate::offers::invoice::UnsignedBolt12Invoice;
3535
use crate::onion_message::messenger::{
@@ -324,8 +324,9 @@ pub struct TestMessageRouter<'a> {
324324
impl<'a> TestMessageRouter<'a> {
325325
pub fn new(
326326
network_graph: Arc<NetworkGraph<&'a TestLogger>>, entropy_source: &'a TestKeysInterface,
327+
expanded_key: inbound_payment::ExpandedKey,
327328
) -> Self {
328-
Self { inner: DefaultMessageRouter::new(network_graph, entropy_source) }
329+
Self { inner: DefaultMessageRouter::new(network_graph, entropy_source, expanded_key) }
329330
}
330331
}
331332

@@ -1487,7 +1488,7 @@ impl TestNodeSigner {
14871488

14881489
impl NodeSigner for TestNodeSigner {
14891490
fn get_expanded_key(&self) -> ExpandedKey {
1490-
unreachable!()
1491+
ExpandedKey::new([42; 32])
14911492
}
14921493

14931494
fn get_node_id(&self, recipient: Recipient) -> Result<PublicKey, ()> {

0 commit comments

Comments
 (0)