Skip to content

Commit d19827e

Browse files
committed
Add anti-probing penalty to ProbabilisticScorer
Currently, channel balances may be rather easily discovered through probing. This however poses a privacy risk, since the analysis of balance changes over adjacent channels could in the worst case empower an adversary to mount an end-to-end deanonymization attack, i.e., track who payed whom. The penalty added here is applied so we prefer nodes with a smaller `htlc_maximum_msat`, which makes balance discovery attacks harder to execute. As this improves privacy network-wide, we treat such nodes preferentially and hence create an incentive to restrict `htlc_maximum_msat`.
1 parent 16115cd commit d19827e

File tree

2 files changed

+60
-36
lines changed

2 files changed

+60
-36
lines changed

lightning/src/routing/gossip.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -745,13 +745,13 @@ impl<'a> DirectedChannelInfo<'a> {
745745
let (htlc_maximum_msat, effective_capacity) = match (htlc_maximum_msat, capacity_msat) {
746746
(Some(amount_msat), Some(capacity_msat)) => {
747747
let htlc_maximum_msat = cmp::min(amount_msat, capacity_msat);
748-
(htlc_maximum_msat, EffectiveCapacity::Total { capacity_msat })
748+
(htlc_maximum_msat, EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: Some(htlc_maximum_msat) })
749749
},
750750
(Some(amount_msat), None) => {
751751
(amount_msat, EffectiveCapacity::MaximumHTLC { amount_msat })
752752
},
753753
(None, Some(capacity_msat)) => {
754-
(capacity_msat, EffectiveCapacity::Total { capacity_msat })
754+
(capacity_msat, EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: None })
755755
},
756756
(None, None) => (EffectiveCapacity::Unknown.as_msat(), EffectiveCapacity::Unknown),
757757
};
@@ -850,6 +850,8 @@ pub enum EffectiveCapacity {
850850
Total {
851851
/// The funding amount denominated in millisatoshi.
852852
capacity_msat: u64,
853+
/// The maximum HTLC amount denominated in millisatoshi.
854+
htlc_maximum_msat: Option<u64>
853855
},
854856
/// A capacity sufficient to route any payment, typically used for private channels provided by
855857
/// an invoice.
@@ -869,7 +871,7 @@ impl EffectiveCapacity {
869871
match self {
870872
EffectiveCapacity::ExactLiquidity { liquidity_msat } => *liquidity_msat,
871873
EffectiveCapacity::MaximumHTLC { amount_msat } => *amount_msat,
872-
EffectiveCapacity::Total { capacity_msat } => *capacity_msat,
874+
EffectiveCapacity::Total { capacity_msat, .. } => *capacity_msat,
873875
EffectiveCapacity::Infinite => u64::max_value(),
874876
EffectiveCapacity::Unknown => UNKNOWN_CHANNEL_CAPACITY_MSAT,
875877
}

lightning/src/routing/scoring.rs

+55-33
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,14 @@ pub struct ProbabilisticScoringParameters {
361361
///
362362
/// Default value: 256 msat
363363
pub amount_penalty_multiplier_msat: u64,
364+
365+
/// This penalty is applied so we prefer nodes with a smaller `htlc_maximum_msat`, which makes
366+
/// balance discovery attacks harder to execute. As this improves privacy network-wide, we
367+
/// treat such nodes preferentially and hence create an incentive to restrict
368+
/// `htlc_maximum_msat`.
369+
///
370+
/// Default value: 10000 msat
371+
pub anti_probing_penalty_msat: u64,
364372
}
365373

366374
/// Accounting for channel liquidity balance uncertainty.
@@ -461,6 +469,7 @@ impl ProbabilisticScoringParameters {
461469
liquidity_penalty_multiplier_msat: 0,
462470
liquidity_offset_half_life: Duration::from_secs(3600),
463471
amount_penalty_multiplier_msat: 0,
472+
anti_probing_penalty_msat: 0,
464473
}
465474
}
466475
}
@@ -472,6 +481,7 @@ impl Default for ProbabilisticScoringParameters {
472481
liquidity_penalty_multiplier_msat: 40_000,
473482
liquidity_offset_half_life: Duration::from_secs(3600),
474483
amount_penalty_multiplier_msat: 256,
484+
anti_probing_penalty_msat: 10_000,
475485
}
476486
}
477487
}
@@ -672,12 +682,22 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
672682
fn channel_penalty_msat(
673683
&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
674684
) -> u64 {
675-
if let EffectiveCapacity::ExactLiquidity { liquidity_msat } = usage.effective_capacity {
676-
if usage.amount_msat > liquidity_msat {
677-
return u64::max_value();
678-
} else {
679-
return self.params.base_penalty_msat;
680-
};
685+
686+
let mut anti_probing_penalty_msat = 0;
687+
match usage.effective_capacity {
688+
EffectiveCapacity::ExactLiquidity { liquidity_msat } => {
689+
if usage.amount_msat > liquidity_msat {
690+
return u64::max_value();
691+
} else {
692+
return self.params.base_penalty_msat;
693+
}
694+
},
695+
EffectiveCapacity::Total{ capacity_msat, htlc_maximum_msat: Some(htlc_maximum_msat) } => {
696+
if htlc_maximum_msat*2 >= capacity_msat {
697+
anti_probing_penalty_msat = self.params.anti_probing_penalty_msat;
698+
}
699+
},
700+
_ => {},
681701
}
682702

683703
let liquidity_offset_half_life = self.params.liquidity_offset_half_life;
@@ -689,6 +709,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for Probabilis
689709
.unwrap_or(&ChannelLiquidity::new())
690710
.as_directed(source, target, capacity_msat, liquidity_offset_half_life)
691711
.penalty_msat(amount_msat, self.params)
712+
.saturating_add(anti_probing_penalty_msat)
692713
}
693714

694715
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
@@ -1512,7 +1533,7 @@ mod tests {
15121533
let usage = ChannelUsage {
15131534
amount_msat: 1_024,
15141535
inflight_htlc_msat: 0,
1515-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000 },
1536+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: Some(1_000) },
15161537
};
15171538
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
15181539
let usage = ChannelUsage { amount_msat: 10_240, ..usage };
@@ -1525,7 +1546,7 @@ mod tests {
15251546
let usage = ChannelUsage {
15261547
amount_msat: 128,
15271548
inflight_htlc_msat: 0,
1528-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
1549+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_000) },
15291550
};
15301551
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 58);
15311552
let usage = ChannelUsage { amount_msat: 256, ..usage };
@@ -1562,7 +1583,7 @@ mod tests {
15621583
let usage = ChannelUsage {
15631584
amount_msat: 39,
15641585
inflight_htlc_msat: 0,
1565-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 100 },
1586+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 100, htlc_maximum_msat: Some(1_000) },
15661587
};
15671588
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
15681589
let usage = ChannelUsage { amount_msat: 50, ..usage };
@@ -1586,7 +1607,7 @@ mod tests {
15861607
let usage = ChannelUsage {
15871608
amount_msat: 500,
15881609
inflight_htlc_msat: 0,
1589-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
1610+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: Some(1_000) },
15901611
};
15911612
let failed_path = payment_path_for_amount(500);
15921613
let successful_path = payment_path_for_amount(200);
@@ -1616,7 +1637,7 @@ mod tests {
16161637
let usage = ChannelUsage {
16171638
amount_msat: 250,
16181639
inflight_htlc_msat: 0,
1619-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
1640+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: Some(1_000) },
16201641
};
16211642
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
16221643
let usage = ChannelUsage { amount_msat: 500, ..usage };
@@ -1650,7 +1671,7 @@ mod tests {
16501671
let usage = ChannelUsage {
16511672
amount_msat: 250,
16521673
inflight_htlc_msat: 0,
1653-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
1674+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: Some(1_000) },
16541675
};
16551676
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
16561677
let usage = ChannelUsage { amount_msat: 500, ..usage };
@@ -1684,7 +1705,7 @@ mod tests {
16841705
let usage = ChannelUsage {
16851706
amount_msat: 250,
16861707
inflight_htlc_msat: 0,
1687-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
1708+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: Some(1_000) },
16881709
};
16891710
let path = payment_path_for_amount(500);
16901711

@@ -1715,7 +1736,7 @@ mod tests {
17151736
let usage = ChannelUsage {
17161737
amount_msat: 0,
17171738
inflight_htlc_msat: 0,
1718-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
1739+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_000) },
17191740
};
17201741
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
17211742
let usage = ChannelUsage { amount_msat: 1_024, ..usage };
@@ -1793,7 +1814,7 @@ mod tests {
17931814
let usage = ChannelUsage {
17941815
amount_msat: 256,
17951816
inflight_htlc_msat: 0,
1796-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
1817+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_000) },
17971818
};
17981819
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
17991820

@@ -1824,7 +1845,7 @@ mod tests {
18241845
let usage = ChannelUsage {
18251846
amount_msat: 512,
18261847
inflight_htlc_msat: 0,
1827-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
1848+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_000) },
18281849
};
18291850

18301851
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
@@ -1868,7 +1889,7 @@ mod tests {
18681889
let usage = ChannelUsage {
18691890
amount_msat: 500,
18701891
inflight_htlc_msat: 0,
1871-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
1892+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: Some(1_000) },
18721893
};
18731894

18741895
scorer.payment_path_failed(&payment_path_for_amount(500).iter().collect::<Vec<_>>(), 42);
@@ -1904,7 +1925,7 @@ mod tests {
19041925
let usage = ChannelUsage {
19051926
amount_msat: 500,
19061927
inflight_htlc_msat: 0,
1907-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
1928+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: Some(1_000) },
19081929
};
19091930

19101931
scorer.payment_path_failed(&payment_path_for_amount(500).iter().collect::<Vec<_>>(), 42);
@@ -1941,47 +1962,47 @@ mod tests {
19411962
let usage = ChannelUsage {
19421963
amount_msat: 100_000_000,
19431964
inflight_htlc_msat: 0,
1944-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 950_000_000 },
1965+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 950_000_000, htlc_maximum_msat: Some(1_000) },
19451966
};
19461967
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 3613);
19471968
let usage = ChannelUsage {
1948-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_950_000_000 }, ..usage
1969+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19491970
};
19501971
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1977);
19511972
let usage = ChannelUsage {
1952-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 2_950_000_000 }, ..usage
1973+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 2_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19531974
};
19541975
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1474);
19551976
let usage = ChannelUsage {
1956-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000 }, ..usage
1977+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19571978
};
19581979
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1223);
19591980
let usage = ChannelUsage {
1960-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000 }, ..usage
1981+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19611982
};
19621983
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 877);
19631984
let usage = ChannelUsage {
1964-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000 }, ..usage
1985+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19651986
};
19661987
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 845);
19671988
let usage = ChannelUsage {
1968-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000 }, ..usage
1989+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19691990
};
19701991
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
19711992
let usage = ChannelUsage {
1972-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000 }, ..usage
1993+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19731994
};
19741995
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
19751996
let usage = ChannelUsage {
1976-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000 }, ..usage
1997+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19771998
};
19781999
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
19792000
let usage = ChannelUsage {
1980-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000 }, ..usage
2001+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19812002
};
19822003
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
19832004
let usage = ChannelUsage {
1984-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000 }, ..usage
2005+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000, htlc_maximum_msat: Some(1_000) }, ..usage
19852006
};
19862007
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
19872008
}
@@ -1995,7 +2016,7 @@ mod tests {
19952016
let usage = ChannelUsage {
19962017
amount_msat: 128,
19972018
inflight_htlc_msat: 0,
1998-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024 },
2019+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_000) },
19992020
};
20002021

20012022
let params = ProbabilisticScoringParameters {
@@ -2006,7 +2027,8 @@ mod tests {
20062027
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 58);
20072028

20082029
let params = ProbabilisticScoringParameters {
2009-
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000, ..Default::default()
2030+
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
2031+
anti_probing_penalty_msat: 0, ..Default::default()
20102032
};
20112033
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
20122034
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558);
@@ -2021,7 +2043,7 @@ mod tests {
20212043
let usage = ChannelUsage {
20222044
amount_msat: 512_000,
20232045
inflight_htlc_msat: 0,
2024-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000 },
2046+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: Some(1_000) },
20252047
};
20262048

20272049
let params = ProbabilisticScoringParameters {
@@ -2073,7 +2095,7 @@ mod tests {
20732095
let usage = ChannelUsage {
20742096
amount_msat: 750,
20752097
inflight_htlc_msat: 0,
2076-
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000 },
2098+
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: Some(1_000) },
20772099
};
20782100
assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
20792101

0 commit comments

Comments
 (0)