Skip to content

Commit e92b5a7

Browse files
committed
Add a random per-path CLTV offset for privacy.
1 parent 1a73449 commit e92b5a7

File tree

13 files changed

+460
-136
lines changed

13 files changed

+460
-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};
@@ -22,6 +22,7 @@ use secp256k1::key::PublicKey;
2222
use core::convert::TryInto;
2323
use core::ops::Deref;
2424
use core::time::Duration;
25+
use sync::Mutex;
2526

2627
#[cfg(feature = "std")]
2728
/// Utility to create an invoice that can be paid to one of multiple nodes, or a "phantom invoice."
@@ -224,12 +225,15 @@ where
224225
pub struct DefaultRouter<G: Deref<Target = NetworkGraph>, L: Deref> where L::Target: Logger {
225226
network_graph: G,
226227
logger: L,
228+
random_seed_bytes: Mutex<[u8; 32]>,
227229
}
228230

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

@@ -239,7 +243,12 @@ where L::Target: Logger {
239243
&self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
240244
first_hops: Option<&[&ChannelDetails]>, scorer: &S
241245
) -> Result<Route, LightningError> {
242-
find_route(payer, params, &*self.network_graph, first_hops, &*self.logger, scorer)
246+
let random_seed_bytes = {
247+
let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap();
248+
*locked_random_seed_bytes = sha256::Hash::hash(&*locked_random_seed_bytes).into_inner();
249+
*locked_random_seed_bytes
250+
};
251+
find_route(payer, params, &*self.network_graph, first_hops, &*self.logger, scorer, &random_seed_bytes)
243252
}
244253
}
245254

@@ -299,6 +308,7 @@ mod test {
299308
use lightning::util::enforcing_trait_impls::EnforcingSigner;
300309
use lightning::util::events::{MessageSendEvent, MessageSendEventsProvider, Event};
301310
use lightning::util::test_utils;
311+
use lightning::chain::keysinterface::KeysInterface;
302312
use utils::create_invoice_from_channelmanager_and_duration_since_epoch;
303313

304314
#[test]
@@ -327,9 +337,10 @@ mod test {
327337
let network_graph = node_cfgs[0].network_graph;
328338
let logger = test_utils::TestLogger::new();
329339
let scorer = test_utils::TestScorer::with_penalty(0);
340+
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
330341
let route = find_route(
331342
&nodes[0].node.get_our_node_id(), &route_params, network_graph,
332-
Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer,
343+
Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer, &random_seed_bytes
333344
).unwrap();
334345

335346
let payment_event = {
@@ -415,9 +426,10 @@ mod test {
415426
let network_graph = node_cfgs[0].network_graph;
416427
let logger = test_utils::TestLogger::new();
417428
let scorer = test_utils::TestScorer::with_penalty(0);
429+
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
418430
let route = find_route(
419431
&nodes[0].node.get_our_node_id(), &params, network_graph,
420-
Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer,
432+
Some(&first_hops.iter().collect::<Vec<_>>()), &logger, &scorer, &random_seed_bytes
421433
).unwrap();
422434
let (payment_event, fwd_idx) = {
423435
let mut payment_hash = PaymentHash([0; 32]);

lightning/src/ln/channelmanager.rs

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

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

71017103
// To start (1), send a regular payment but don't claim it.
71027104
let expected_route = [&nodes[1]];
@@ -7110,7 +7112,7 @@ mod tests {
71107112
};
71117113
let route = find_route(
71127114
&nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
7113-
nodes[0].logger, &scorer
7115+
nodes[0].logger, &scorer, &random_seed_bytes
71147116
).unwrap();
71157117
nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
71167118
check_added_monitors!(nodes[0], 1);
@@ -7141,7 +7143,7 @@ mod tests {
71417143
let payment_preimage = PaymentPreimage([42; 32]);
71427144
let route = find_route(
71437145
&nodes[0].node.get_our_node_id(), &route_params, nodes[0].network_graph, None,
7144-
nodes[0].logger, &scorer
7146+
nodes[0].logger, &scorer, &random_seed_bytes
71457147
).unwrap();
71467148
let (payment_hash, _) = nodes[0].node.send_spontaneous_payment(&route, Some(payment_preimage)).unwrap();
71477149
check_added_monitors!(nodes[0], 1);
@@ -7202,9 +7204,10 @@ mod tests {
72027204
let network_graph = nodes[0].network_graph;
72037205
let first_hops = nodes[0].node.list_usable_channels();
72047206
let scorer = test_utils::TestScorer::with_penalty(0);
7207+
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
72057208
let route = find_route(
72067209
&payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
7207-
nodes[0].logger, &scorer
7210+
nodes[0].logger, &scorer, &random_seed_bytes
72087211
).unwrap();
72097212

72107213
let test_preimage = PaymentPreimage([42; 32]);
@@ -7245,9 +7248,10 @@ mod tests {
72457248
let network_graph = nodes[0].network_graph;
72467249
let first_hops = nodes[0].node.list_usable_channels();
72477250
let scorer = test_utils::TestScorer::with_penalty(0);
7251+
let random_seed_bytes = chanmon_cfgs[1].keys_manager.get_secure_random_bytes();
72487252
let route = find_route(
72497253
&payer_pubkey, &route_params, network_graph, Some(&first_hops.iter().collect::<Vec<_>>()),
7250-
nodes[0].logger, &scorer
7254+
nodes[0].logger, &scorer, &random_seed_bytes
72517255
).unwrap();
72527256

72537257
let test_preimage = PaymentPreimage([42; 32]);
@@ -7331,7 +7335,7 @@ mod tests {
73317335
pub mod bench {
73327336
use chain::Listen;
73337337
use chain::chainmonitor::{ChainMonitor, Persist};
7334-
use chain::keysinterface::{KeysManager, InMemorySigner};
7338+
use chain::keysinterface::{KeysManager, KeysInterface, InMemorySigner};
73357339
use ln::channelmanager::{BestBlock, ChainParameters, ChannelManager, PaymentHash, PaymentPreimage};
73367340
use ln::features::{InitFeatures, InvoiceFeatures};
73377341
use ln::functional_test_utils::*;
@@ -7340,7 +7344,7 @@ pub mod bench {
73407344
use routing::router::{PaymentParameters, get_route};
73417345
use util::test_utils;
73427346
use util::config::UserConfig;
7343-
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};
7347+
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider};
73447348

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

74547461
let mut payment_preimage = PaymentPreimage([0; 32]);
74557462
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)