Skip to content

Commit f5b1b46

Browse files
committed
Add a random per-path CLTV offset for privacy.
1 parent 6259e7a commit f5b1b46

File tree

13 files changed

+459
-136
lines changed

13 files changed

+459
-136
lines changed

fuzz/src/full_stack.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,8 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
459459
final_value_msat,
460460
final_cltv_expiry_delta: 42,
461461
};
462-
let route = match find_route(&our_id, &params, &network_graph, None, Arc::clone(&logger), &scorer) {
462+
let random_seed_bytes: [u8; 32] = keys_manager.get_secure_random_bytes();
463+
let route = match find_route(&our_id, &params, &network_graph, None, Arc::clone(&logger), &scorer, &random_seed_bytes) {
463464
Ok(route) => route,
464465
Err(_) => return,
465466
};
@@ -482,7 +483,8 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
482483
final_value_msat,
483484
final_cltv_expiry_delta: 42,
484485
};
485-
let mut route = match find_route(&our_id, &params, &network_graph, None, Arc::clone(&logger), &scorer) {
486+
let random_seed_bytes: [u8; 32] = keys_manager.get_secure_random_bytes();
487+
let mut route = match find_route(&our_id, &params, &network_graph, None, Arc::clone(&logger), &scorer, &random_seed_bytes) {
486488
Ok(route) => route,
487489
Err(_) => return,
488490
};

fuzz/src/router.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
250250
}
251251
}
252252
let scorer = FixedPenaltyScorer::with_penalty(0);
253+
let random_seed_bytes: [u8; 32] = [get_slice!(1)[0]; 32];
253254
for target in node_pks.iter() {
254255
let route_params = RouteParameters {
255256
payment_params: PaymentParameters::from_node_id(*target).with_route_hints(last_hops.clone()),
@@ -258,7 +259,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
258259
};
259260
let _ = find_route(&our_pubkey, &route_params, &net_graph,
260261
first_hops.map(|c| c.iter().collect::<Vec<_>>()).as_ref().map(|a| a.as_slice()),
261-
Arc::clone(&logger), &scorer);
262+
Arc::clone(&logger), &scorer, &random_seed_bytes);
262263
}
263264
},
264265
}

lightning-background-processor/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -669,13 +669,15 @@ mod tests {
669669

670670
#[test]
671671
fn test_invoice_payer() {
672+
let keys_manager = test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
673+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
672674
let nodes = create_nodes(2, "test_invoice_payer".to_string());
673675

674676
// Initiate the background processors to watch each node.
675677
let data_dir = nodes[0].persister.get_data_dir();
676678
let persister = move |node: &ChannelManager<InMemorySigner, Arc<ChainMonitor>, Arc<test_utils::TestBroadcaster>, Arc<KeysManager>, Arc<test_utils::TestFeeEstimator>, Arc<test_utils::TestLogger>>| FilesystemPersister::persist_manager(data_dir.clone(), node);
677-
let router = DefaultRouter::new(Arc::clone(&nodes[0].network_graph), Arc::clone(&nodes[0].logger));
678679
let scorer = Arc::new(Mutex::new(test_utils::TestScorer::with_penalty(0)));
680+
let router = DefaultRouter::new(Arc::clone(&nodes[0].network_graph), Arc::clone(&nodes[0].logger), random_seed_bytes);
679681
let invoice_payer = Arc::new(InvoicePayer::new(Arc::clone(&nodes[0].node), router, scorer, Arc::clone(&nodes[0].logger), |_: &_| {}, RetryAttempts(2)));
680682
let event_handler = Arc::clone(&invoice_payer);
681683
let bg_processor = BackgroundProcessor::start(persister, event_handler, nodes[0].chain_monitor.clone(), nodes[0].node.clone(), nodes[0].net_graph_msg_handler.clone(), nodes[0].peer_manager.clone(), nodes[0].logger.clone());

lightning-invoice/src/utils.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use {CreationError, Currency, DEFAULT_EXPIRY_TIME, Invoice, InvoiceBuilder, Sign
44
use payment::{Payer, Router};
55

66
use bech32::ToBase32;
7-
use bitcoin_hashes::Hash;
7+
use bitcoin_hashes::{Hash, sha256};
88
use crate::prelude::*;
99
use lightning::chain;
1010
use lightning::chain::chaininterface::{BroadcasterInterface, FeeEstimator};
@@ -20,6 +20,7 @@ use secp256k1::key::PublicKey;
2020
use core::convert::TryInto;
2121
use core::ops::Deref;
2222
use core::time::Duration;
23+
use sync::Mutex;
2324

2425
#[cfg(feature = "std")]
2526
/// Utility to create an invoice that can be paid to one of multiple nodes, or a "phantom invoice."
@@ -222,12 +223,15 @@ where
222223
pub struct DefaultRouter<G: Deref<Target = NetworkGraph>, L: Deref> where L::Target: Logger {
223224
network_graph: G,
224225
logger: L,
226+
random_seed_bytes: Mutex<[u8; 32]>,
225227
}
226228

227229
impl<G: Deref<Target = NetworkGraph>, L: Deref> DefaultRouter<G, L> where L::Target: Logger {
228-
/// Creates a new router using the given [`NetworkGraph`] and [`Logger`].
229-
pub fn new(network_graph: G, logger: L) -> Self {
230-
Self { network_graph, logger }
230+
/// Creates a new router using the given [`NetworkGraph`], a [`Logger`], and a randomness source
231+
/// `random_seed_bytes`.
232+
pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32]) -> Self {
233+
let random_seed_bytes = Mutex::new(random_seed_bytes);
234+
Self { network_graph, logger, random_seed_bytes }
231235
}
232236
}
233237

@@ -237,7 +241,12 @@ where L::Target: Logger {
237241
&self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
238242
first_hops: Option<&[&ChannelDetails]>, scorer: &S
239243
) -> Result<Route, LightningError> {
240-
find_route(payer, params, &*self.network_graph, first_hops, &*self.logger, scorer)
244+
let random_seed_bytes = {
245+
let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap();
246+
*locked_random_seed_bytes = sha256::Hash::hash(&*locked_random_seed_bytes).into_inner();
247+
*locked_random_seed_bytes
248+
};
249+
find_route(payer, params, &*self.network_graph, first_hops, &*self.logger, scorer, &random_seed_bytes)
241250
}
242251
}
243252

@@ -297,6 +306,7 @@ mod test {
297306
use lightning::util::enforcing_trait_impls::EnforcingSigner;
298307
use lightning::util::events::{MessageSendEvent, MessageSendEventsProvider, Event};
299308
use lightning::util::test_utils;
309+
use lightning::chain::keysinterface::KeysInterface;
300310
use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
301311

302312
#[test]
@@ -325,9 +335,10 @@ mod test {
325335
let network_graph = node_cfgs[0].network_graph;
326336
let logger = test_utils::TestLogger::new();
327337
let scorer = test_utils::TestScorer::with_penalty(0);
338+
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
328339
let route = find_route(
329340
&nodes[0].node.get_our_node_id(), &route_params, network_graph,
330-
Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer,
341+
Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer, &random_seed_bytes
331342
).unwrap();
332343

333344
let payment_event = {
@@ -413,9 +424,10 @@ mod test {
413424
let network_graph = node_cfgs[0].network_graph;
414425
let logger = test_utils::TestLogger::new();
415426
let scorer = test_utils::TestScorer::with_penalty(0);
427+
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
416428
let route = find_route(
417429
&nodes[0].node.get_our_node_id(), &params, network_graph,
418-
Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer,
430+
Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer, &random_seed_bytes
419431
).unwrap();
420432
let (payment_event, fwd_idx) = {
421433
let mut payment_hash = PaymentHash([0; 32]);

lightning/src/ln/channelmanager.rs

+15-8
Original file line numberDiff line numberDiff line change
@@ -6843,6 +6843,7 @@ mod tests {
68436843
use util::errors::APIError;
68446844
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
68456845
use util::test_utils;
6846+
use chain::keysinterface::KeysInterface;
68466847

68476848
#[cfg(feature = "std")]
68486849
#[test]
@@ -7096,6 +7097,7 @@ mod tests {
70967097
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
70977098
create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
70987099
let scorer = test_utils::TestScorer::with_penalty(0);
7100+
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
70997101

71007102
// To start (1), send a regular payment but don't claim it.
71017103
let expected_route = [&nodes[1]];
@@ -7109,7 +7111,7 @@ mod tests {
71097111
};
71107112
let route = find_route(
71117113
&nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
7112-
nodes[0].logger, &scorer
7114+
nodes[0].logger, &scorer, &random_seed_bytes
71137115
).unwrap();
71147116
nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
71157117
check_added_monitors!(nodes[0], 1);
@@ -7140,7 +7142,7 @@ mod tests {
71407142
let payment_preimage = PaymentPreimage([42; 32]);
71417143
let route = find_route(
71427144
&nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
7143-
nodes[0].logger, &scorer
7145+
nodes[0].logger, &scorer, &random_seed_bytes
71447146
).unwrap();
71457147
let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
71467148
check_added_monitors!(nodes[0], 1);
@@ -7201,9 +7203,10 @@ mod tests {
72017203
let network_graph = nodes[0].network_graph;
72027204
let first_hops = nodes[0].node.list_usable_channels();
72037205
let scorer = test_utils::TestScorer::with_penalty(0);
7206+
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
72047207
let route = find_route(
72057208
&payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
7206-
nodes[0].logger, &scorer
7209+
nodes[0].logger, &scorer, &random_seed_bytes
72077210
).unwrap();
72087211

72097212
let test_preimage = PaymentPreimage([42; 32]);
@@ -7244,9 +7247,10 @@ mod tests {
72447247
let network_graph = nodes[0].network_graph;
72457248
let first_hops = nodes[0].node.list_usable_channels();
72467249
let scorer = test_utils::TestScorer::with_penalty(0);
7250+
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
72477251
let route = find_route(
72487252
&payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
7249-
nodes[0].logger, &scorer
7253+
nodes[0].logger, &scorer, &random_seed_bytes
72507254
).unwrap();
72517255

72527256
let test_preimage = PaymentPreimage([42; 32]);
@@ -7330,7 +7334,7 @@ mod tests {
73307334
pub mod bench {
73317335
use chain::Listen;
73327336
use chain::chainmonitor::{ChainMonitor, Persist};
7333-
use chain::keysinterface::{KeysManager, InMemorySigner};
7337+
use chain::keysinterface::{KeysManager, KeysInterface, InMemorySigner};
73347338
use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage};
73357339
use ln::features::{InitFeatures, InvoiceFeatures};
73367340
use ln::functional_test_utils::*;
@@ -7339,7 +7343,7 @@ pub mod bench {
73397343
use routing::router::{PaymentParameters, get_route};
73407344
use util::test_utils;
73417345
use util::config::UserConfig;
7342-
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};
7346+
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
73437347

73447348
use bitcoin::hashes::Hash;
73457349
use bitcoin::hashes::sha256::Hash as Sha256;
@@ -7447,8 +7451,11 @@ pub mod bench {
74477451
let payment_params = PaymentParameters::from_node_id($node_b.get_our_node_id())
74487452
.with_features(InvoiceFeatures::known());
74497453
let scorer = test_utils::TestScorer::with_penalty(0);
7450-
let route = get_route(&$node_a.get_our_node_id(), &payment_params, &dummy_graph,
7451-
Some(&usable_channels.iter().map(|r| r).collect::<Vec<_>>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer).unwrap();
7454+
let seed = [3u8; 32];
7455+
let keys_manager = KeysManager::new(&seed, 42, 42);
7456+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
7457+
let route = get_route(&$node_a.get_our_node_id(), &payment_params, &dummy_graph.read_only(),
7458+
Some(&usable_channels.iter().map(|r| r).collect::<Vec<_>>()), 10_000, TEST_FINAL_CLTV, &logger_a, &scorer, &random_seed_bytes).unwrap();
74527459

74537460
let mut payment_preimage = PaymentPreimage([0; 32]);
74547461
payment_preimage.0[0..8].copy_from_slice(&payment_count.to_le_bytes());

lightning/src/ln/functional_test_utils.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//! A bunch of useful utilities for building networks of nodes and exchanging messages between
1111
//! nodes for functional tests.
1212
13-
use chain::{BestBlock, Confirm, Listen, Watch};
13+
use chain::{BestBlock, Confirm, Listen, Watch, keysinterface::KeysInterface};
1414
use chain::channelmonitor::ChannelMonitor;
1515
use chain::transaction::OutPoint;
1616
use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
@@ -1094,15 +1094,18 @@ macro_rules! get_route_and_payment_hash {
10941094
$crate::get_route_and_payment_hash!($send_node, $recv_node, vec![], $recv_value, TEST_FINAL_CLTV)
10951095
}};
10961096
($send_node: expr, $recv_node: expr, $last_hops: expr, $recv_value: expr, $cltv: expr) => {{
1097+
use $crate::chain::keysinterface::KeysInterface;
10971098
let (payment_preimage, payment_hash, payment_secret) = $crate::get_payment_preimage_hash!($recv_node, Some($recv_value));
10981099
let payment_params = $crate::routing::router::PaymentParameters::from_node_id($recv_node.node.get_our_node_id())
10991100
.with_features($crate::ln::features::InvoiceFeatures::known())
11001101
.with_route_hints($last_hops);
11011102
let scorer = $crate::util::test_utils::TestScorer::with_penalty(0);
1103+
let keys_manager = $crate::util::test_utils::TestKeysInterface::new(&[0u8; 32], bitcoin::network::constants::Network::Testnet);
1104+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
11021105
let route = $crate::routing::router::get_route(
1103-
&$send_node.node.get_our_node_id(), &payment_params, $send_node.network_graph,
1106+
&$send_node.node.get_our_node_id(), &payment_params, &$send_node.network_graph.read_only(),
11041107
Some(&$send_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
1105-
$recv_value, $cltv, $send_node.logger, &scorer
1108+
$recv_value, $cltv, $send_node.logger, &scorer, &random_seed_bytes
11061109
).unwrap();
11071110
(route, payment_hash, payment_preimage, payment_secret)
11081111
}}
@@ -1557,11 +1560,15 @@ pub const TEST_FINAL_CLTV: u32 = 70;
15571560
pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) -> (PaymentPreimage, PaymentHash, PaymentSecret) {
15581561
let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id())
15591562
.with_features(InvoiceFeatures::known());
1563+
let network_graph = origin_node.network_graph.read_only();
15601564
let scorer = test_utils::TestScorer::with_penalty(0);
1565+
let seed = [0u8; 32];
1566+
let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
1567+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
15611568
let route = get_route(
1562-
&origin_node.node.get_our_node_id(), &payment_params, &origin_node.network_graph,
1569+
&origin_node.node.get_our_node_id(), &payment_params, &network_graph,
15631570
Some(&origin_node.node.list_usable_channels().iter().collect::<Vec<_>>()),
1564-
recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer).unwrap();
1571+
recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
15651572
assert_eq!(route.paths.len(), 1);
15661573
assert_eq!(route.paths[0].len(), expected_route.len());
15671574
for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {
@@ -1575,10 +1582,14 @@ pub fn route_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route:
15751582
pub fn route_over_limit<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], recv_value: u64) {
15761583
let payment_params = PaymentParameters::from_node_id(expected_route.last().unwrap().node.get_our_node_id())
15771584
.with_features(InvoiceFeatures::known());
1585+
let network_graph = origin_node.network_graph.read_only();
15781586
let scorer = test_utils::TestScorer::with_penalty(0);
1587+
let seed = [0u8; 32];
1588+
let keys_manager = test_utils::TestKeysInterface::new(&seed, Network::Testnet);
1589+
let random_seed_bytes = keys_manager.get_secure_random_bytes();
15791590
let route = get_route(
1580-
&origin_node.node.get_our_node_id(), &payment_params, origin_node.network_graph,
1581-
None, recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer).unwrap();
1591+
&origin_node.node.get_our_node_id(), &payment_params, &network_graph,
1592+
None, recv_value, TEST_FINAL_CLTV, origin_node.logger, &scorer, &random_seed_bytes).unwrap();
15821593
assert_eq!(route.paths.len(), 1);
15831594
assert_eq!(route.paths[0].len(), expected_route.len());
15841595
for (node, hop) in expected_route.iter().zip(route.paths[0].iter()) {

0 commit comments

Comments
 (0)