Skip to content

Commit 0b95789

Browse files
committed
Introduce ReceiveAuthKey-based verification in Blinded Payment Paths
Extends the work started in [PR#3917](#3917) by adding ReceiveAuthKey-based verification for Blinded Payment Paths. This reduces space previously taken by individual ReceiveTlvs and aligns the verification logic with that used for Blinded Message Paths.
1 parent 9514637 commit 0b95789

14 files changed

+125
-58
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,9 @@ impl Router for FuzzRouter {
128128
}
129129

130130
fn create_blinded_payment_paths<T: secp256k1::Signing + secp256k1::Verification>(
131-
&self, _recipient: PublicKey, _first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs,
132-
_amount_msats: Option<u64>, _secp_ctx: &Secp256k1<T>,
131+
&self, _recipient: PublicKey, _receive_auth_key: ReceiveAuthKey,
132+
_first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs, _amount_msats: Option<u64>,
133+
_secp_ctx: &Secp256k1<T>,
133134
) -> Result<Vec<BlindedPaymentPath>, ()> {
134135
unreachable!()
135136
}

fuzz/src/full_stack.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ use lightning::sign::{
6262
};
6363
use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
6464
use lightning::util::config::{ChannelConfig, UserConfig};
65-
use lightning::util::errors::APIError;
6665
use lightning::util::hash_tables::*;
6766
use lightning::util::logger::Logger;
6867
use lightning::util::ser::{Readable, Writeable};
@@ -157,8 +156,9 @@ impl Router for FuzzRouter {
157156
}
158157

159158
fn create_blinded_payment_paths<T: secp256k1::Signing + secp256k1::Verification>(
160-
&self, _recipient: PublicKey, _first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs,
161-
_amount_msats: Option<u64>, _secp_ctx: &Secp256k1<T>,
159+
&self, _recipient: PublicKey, _receive_auth_key: ReceiveAuthKey,
160+
_first_hops: Vec<ChannelDetails>, _tlvs: ReceiveTlvs, _amount_msats: Option<u64>,
161+
_secp_ctx: &Secp256k1<T>,
162162
) -> Result<Vec<BlindedPaymentPath>, ()> {
163163
unreachable!()
164164
}

fuzz/src/invoice_request_deser.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use lightning::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields};
2121
use lightning::offers::nonce::Nonce;
2222
use lightning::offers::offer::OfferId;
2323
use lightning::offers::parse::Bolt12SemanticError;
24-
use lightning::sign::EntropySource;
24+
use lightning::sign::{EntropySource, ReceiveAuthKey};
2525
use lightning::types::features::BlindedHopFeatures;
2626
use lightning::types::payment::{PaymentHash, PaymentSecret};
2727
use lightning::types::string::UntrustedString;
@@ -85,6 +85,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
8585
let expanded_key = ExpandedKey::new([42; 32]);
8686
let entropy_source = Randomness {};
8787
let nonce = Nonce::from_entropy_source(&entropy_source);
88+
let receive_auth_key = ReceiveAuthKey([41; 32]);
8889

8990
let invoice_request_fields =
9091
if let Ok(ver) = invoice_request.clone().verify_using_metadata(&expanded_key, secp_ctx) {
@@ -136,6 +137,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
136137
let payment_path = BlindedPaymentPath::new(
137138
&intermediate_nodes,
138139
pubkey(42),
140+
receive_auth_key,
139141
payee_tlvs,
140142
u64::MAX,
141143
MIN_FINAL_CLTV_EXPIRY_DELTA,

fuzz/src/refund_deser.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use lightning::offers::invoice::UnsignedBolt12Invoice;
2020
use lightning::offers::nonce::Nonce;
2121
use lightning::offers::parse::Bolt12SemanticError;
2222
use lightning::offers::refund::Refund;
23-
use lightning::sign::EntropySource;
23+
use lightning::sign::{EntropySource, ReceiveAuthKey};
2424
use lightning::types::features::BlindedHopFeatures;
2525
use lightning::types::payment::{PaymentHash, PaymentSecret};
2626
use lightning::util::ser::Writeable;
@@ -71,6 +71,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
7171
) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> {
7272
let expanded_key = ExpandedKey::new([42; 32]);
7373
let entropy_source = Randomness {};
74+
let receive_auth_key = ReceiveAuthKey([41; 32]);
7475
let nonce = Nonce::from_entropy_source(&entropy_source);
7576
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
7677
let payee_tlvs = UnauthenticatedReceiveTlvs {
@@ -103,6 +104,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
103104
let payment_path = BlindedPaymentPath::new(
104105
&intermediate_nodes,
105106
pubkey(42),
107+
receive_auth_key,
106108
payee_tlvs,
107109
u64::MAX,
108110
MIN_FINAL_CLTV_EXPIRY_DELTA,

lightning/src/blinded_path/payment.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
1616

1717
use crate::blinded_path::utils::{self, BlindedPathWithPadding};
1818
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp};
19-
use crate::crypto::streams::ChaChaPolyReadAdapter;
19+
use crate::crypto::streams::ChaChaDualPolyReadAdapter;
2020
use crate::io;
2121
use crate::io::Cursor;
2222
use crate::ln::channel_state::CounterpartyForwardingInfo;
@@ -28,7 +28,7 @@ use crate::offers::invoice_request::InvoiceRequestFields;
2828
use crate::offers::nonce::Nonce;
2929
use crate::offers::offer::OfferId;
3030
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
31-
use crate::sign::{EntropySource, NodeSigner, Recipient};
31+
use crate::sign::{EntropySource, NodeSigner, ReceiveAuthKey, Recipient};
3232
use crate::types::features::BlindedHopFeatures;
3333
use crate::types::payment::PaymentSecret;
3434
use crate::types::routing::RoutingFees;
@@ -93,8 +93,8 @@ pub struct BlindedPaymentPath {
9393
impl BlindedPaymentPath {
9494
/// Create a one-hop blinded path for a payment.
9595
pub fn one_hop<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
96-
payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, min_final_cltv_expiry_delta: u16,
97-
entropy_source: ES, secp_ctx: &Secp256k1<T>,
96+
payee_node_id: PublicKey, receive_auth_key: ReceiveAuthKey, payee_tlvs: ReceiveTlvs,
97+
min_final_cltv_expiry_delta: u16, entropy_source: ES, secp_ctx: &Secp256k1<T>,
9898
) -> Result<Self, ()>
9999
where
100100
ES::Target: EntropySource,
@@ -105,6 +105,7 @@ impl BlindedPaymentPath {
105105
Self::new(
106106
&[],
107107
payee_node_id,
108+
receive_auth_key,
108109
payee_tlvs,
109110
htlc_maximum_msat,
110111
min_final_cltv_expiry_delta,
@@ -121,8 +122,8 @@ impl BlindedPaymentPath {
121122
// TODO: make all payloads the same size with padding + add dummy hops
122123
pub fn new<ES: Deref, T: secp256k1::Signing + secp256k1::Verification>(
123124
intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey,
124-
payee_tlvs: ReceiveTlvs, htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16,
125-
entropy_source: ES, secp_ctx: &Secp256k1<T>,
125+
receive_auth_key: ReceiveAuthKey, payee_tlvs: ReceiveTlvs, htlc_maximum_msat: u64,
126+
min_final_cltv_expiry_delta: u16, entropy_source: ES, secp_ctx: &Secp256k1<T>,
126127
) -> Result<Self, ()>
127128
where
128129
ES::Target: EntropySource,
@@ -150,6 +151,7 @@ impl BlindedPaymentPath {
150151
payee_node_id,
151152
payee_tlvs,
152153
&blinding_secret,
154+
receive_auth_key,
153155
),
154156
},
155157
payinfo: blinded_payinfo,
@@ -226,12 +228,13 @@ impl BlindedPaymentPath {
226228
let control_tlvs_ss =
227229
node_signer.ecdh(Recipient::Node, &self.inner_path.blinding_point, None)?;
228230
let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
231+
let receive_auth_key = node_signer.get_receive_auth_key();
229232
let encrypted_control_tlvs =
230233
&self.inner_path.blinded_hops.get(0).ok_or(())?.encrypted_payload;
231234
let mut s = Cursor::new(encrypted_control_tlvs);
232235
let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
233-
match ChaChaPolyReadAdapter::read(&mut reader, rho) {
234-
Ok(ChaChaPolyReadAdapter { readable, .. }) => Ok((readable, control_tlvs_ss)),
236+
match ChaChaDualPolyReadAdapter::read(&mut reader, (rho, receive_auth_key.0)) {
237+
Ok(ChaChaDualPolyReadAdapter { readable, .. }) => Ok((readable, control_tlvs_ss)),
235238
_ => Err(()),
236239
}
237240
}
@@ -660,12 +663,12 @@ pub(crate) const PAYMENT_PADDING_ROUND_OFF: usize = 30;
660663
/// Construct blinded payment hops for the given `intermediate_nodes` and payee info.
661664
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
662665
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey,
663-
payee_tlvs: ReceiveTlvs, session_priv: &SecretKey,
666+
payee_tlvs: ReceiveTlvs, session_priv: &SecretKey, local_node_receive_key: ReceiveAuthKey,
664667
) -> Vec<BlindedHop> {
665668
let pks = intermediate_nodes
666669
.iter()
667670
.map(|node| (node.node_id, None))
668-
.chain(core::iter::once((payee_node_id, None)));
671+
.chain(core::iter::once((payee_node_id, Some(local_node_receive_key))));
669672
let tlvs = intermediate_nodes
670673
.iter()
671674
.map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,13 @@ pub fn blinded_payment_path(
8888

8989
let nonce = Nonce([42u8; 16]);
9090
let expanded_key = keys_manager.get_expanded_key();
91+
let receive_auth_key = keys_manager.get_receive_auth_key();
9192
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
9293

9394
let mut secp_ctx = Secp256k1::new();
9495
BlindedPaymentPath::new(
95-
&intermediate_nodes[..], *node_ids.last().unwrap(), payee_tlvs,
96-
intro_node_max_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_maximum_msat),
96+
&intermediate_nodes[..], *node_ids.last().unwrap(), receive_auth_key,
97+
payee_tlvs, intro_node_max_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_maximum_msat),
9798
TEST_FINAL_CLTV as u16, keys_manager, &secp_ctx
9899
).unwrap()
99100
}
@@ -173,11 +174,13 @@ fn do_one_hop_blinded_path(success: bool) {
173174
};
174175
let nonce = Nonce([42u8; 16]);
175176
let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key();
177+
let receive_auth_key = chanmon_cfgs[1].keys_manager.get_receive_auth_key();
176178
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
177179

178180
let mut secp_ctx = Secp256k1::new();
179181
let blinded_path = BlindedPaymentPath::new(
180-
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
182+
&[], nodes[1].node.get_our_node_id(), receive_auth_key,
183+
payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
181184
&chanmon_cfgs[1].keys_manager, &secp_ctx
182185
).unwrap();
183186

@@ -227,9 +230,11 @@ fn mpp_to_one_hop_blinded_path() {
227230
};
228231
let nonce = Nonce([42u8; 16]);
229232
let expanded_key = chanmon_cfgs[3].keys_manager.get_expanded_key();
233+
let receive_auth_key = chanmon_cfgs[3].keys_manager.get_receive_auth_key();
230234
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
231235
let blinded_path = BlindedPaymentPath::new(
232-
&[], nodes[3].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
236+
&[], nodes[3].node.get_our_node_id(), receive_auth_key,
237+
payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
233238
&chanmon_cfgs[3].keys_manager, &secp_ctx
234239
).unwrap();
235240

@@ -1337,10 +1342,12 @@ fn custom_tlvs_to_blinded_path() {
13371342
};
13381343
let nonce = Nonce([42u8; 16]);
13391344
let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key();
1345+
let receive_auth_key = chanmon_cfgs[1].keys_manager.get_receive_auth_key();
13401346
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
13411347
let mut secp_ctx = Secp256k1::new();
13421348
let blinded_path = BlindedPaymentPath::new(
1343-
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
1349+
&[], nodes[1].node.get_our_node_id(), receive_auth_key,
1350+
payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
13441351
&chanmon_cfgs[1].keys_manager, &secp_ctx
13451352
).unwrap();
13461353

@@ -1391,11 +1398,13 @@ fn fails_receive_tlvs_authentication() {
13911398
};
13921399
let nonce = Nonce([42u8; 16]);
13931400
let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key();
1401+
let receive_auth_key = chanmon_cfgs[1].keys_manager.get_receive_auth_key();
13941402
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
13951403

13961404
let mut secp_ctx = Secp256k1::new();
13971405
let blinded_path = BlindedPaymentPath::new(
1398-
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
1406+
&[], nodes[1].node.get_our_node_id(), receive_auth_key,
1407+
payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
13991408
&chanmon_cfgs[1].keys_manager, &secp_ctx
14001409
).unwrap();
14011410

@@ -1426,7 +1435,8 @@ fn fails_receive_tlvs_authentication() {
14261435

14271436
let mut secp_ctx = Secp256k1::new();
14281437
let blinded_path = BlindedPaymentPath::new(
1429-
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
1438+
&[], nodes[1].node.get_our_node_id(), receive_auth_key,
1439+
payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
14301440
&chanmon_cfgs[1].keys_manager, &secp_ctx
14311441
).unwrap();
14321442

@@ -1629,7 +1639,7 @@ fn route_blinding_spec_test_vector() {
16291639
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,
16301640
) -> Result<RecoverableSignature, ()> { unreachable!() }
16311641
fn get_peer_storage_key(&self) -> PeerStorageKey { unreachable!() }
1632-
fn get_receive_auth_key(&self) -> ReceiveAuthKey { unreachable!() }
1642+
fn get_receive_auth_key(&self) -> ReceiveAuthKey { ReceiveAuthKey([41; 32]) }
16331643
fn sign_bolt12_invoice(
16341644
&self, _invoice: &UnsignedBolt12Invoice,
16351645
) -> Result<schnorr::Signature, ()> { unreachable!() }
@@ -1942,7 +1952,7 @@ fn test_trampoline_inbound_payment_decoding() {
19421952
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,
19431953
) -> Result<RecoverableSignature, ()> { unreachable!() }
19441954
fn get_peer_storage_key(&self) -> PeerStorageKey { unreachable!() }
1945-
fn get_receive_auth_key(&self) -> ReceiveAuthKey { unreachable!() }
1955+
fn get_receive_auth_key(&self) -> ReceiveAuthKey { ReceiveAuthKey([41; 32]) }
19461956
fn sign_bolt12_invoice(
19471957
&self, _invoice: &UnsignedBolt12Invoice,
19481958
) -> Result<schnorr::Signature, ()> { unreachable!() }
@@ -2027,8 +2037,9 @@ fn do_test_trampoline_single_hop_receive(success: bool) {
20272037
let expanded_key = nodes[2].keys_manager.get_expanded_key();
20282038
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
20292039
let carol_unblinded_tlvs = payee_tlvs.encode();
2040+
let receive_auth_key = nodes[2].keys_manager.get_receive_auth_key();
20302041

2031-
let path = [((carol_node_id, None), WithoutLength(&carol_unblinded_tlvs))];
2042+
let path = [((carol_node_id, Some(receive_auth_key)), WithoutLength(&carol_unblinded_tlvs))];
20322043
blinded_path::utils::construct_blinded_hops(
20332044
&secp_ctx, path.into_iter(), &carol_alice_trampoline_session_priv,
20342045
)

lightning/src/ln/channelmanager.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4912,7 +4912,7 @@ where
49124912
let current_height: u32 = self.best_block.read().unwrap().height;
49134913
create_recv_pending_htlc_info(decoded_hop, shared_secret, msg.payment_hash,
49144914
msg.amount_msat, msg.cltv_expiry, None, allow_underpay, msg.skimmed_fee_msat,
4915-
current_height)
4915+
current_height, &*self.logger)
49164916
},
49174917
onion_utils::Hop::Forward { .. } | onion_utils::Hop::BlindedForward { .. } => {
49184918
create_fwd_pending_htlc_info(msg, decoded_hop, shared_secret, next_packet_pubkey_opt)
@@ -7025,6 +7025,7 @@ where
70257025
false,
70267026
None,
70277027
current_height,
7028+
&*self.logger,
70287029
);
70297030
match create_res {
70307031
Ok(info) => phantom_receives.push((
@@ -17912,7 +17913,7 @@ mod tests {
1791217913
use crate::util::config::{ChannelConfig, ChannelConfigUpdate};
1791317914
use crate::util::errors::APIError;
1791417915
use crate::util::ser::Writeable;
17915-
use crate::util::test_utils;
17916+
use crate::util::test_utils::{self, TestLogger};
1791617917
use bitcoin::secp256k1::ecdh::SharedSecret;
1791717918
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
1791817919
use core::sync::atomic::Ordering;
@@ -18737,6 +18738,7 @@ mod tests {
1873718738
let node_chanmgr = create_node_chanmgrs(1, &node_cfg, &[None]);
1873818739
let node = create_network(1, &node_cfg, &node_chanmgr);
1873918740
let sender_intended_amt_msat = 100;
18741+
let logger = TestLogger::new();
1874018742
let extra_fee_msat = 10;
1874118743
let hop_data = onion_utils::Hop::Receive {
1874218744
hop_data: msgs::InboundOnionReceivePayload {
@@ -18758,7 +18760,7 @@ mod tests {
1875818760
if let Err(crate::ln::channelmanager::InboundHTLCErr { reason, .. }) =
1875918761
create_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
1876018762
sender_intended_amt_msat - extra_fee_msat - 1, 42, None, true, Some(extra_fee_msat),
18761-
current_height)
18763+
current_height, &logger)
1876218764
{
1876318765
assert_eq!(reason, LocalHTLCFailureReason::FinalIncorrectHTLCAmount);
1876418766
} else { panic!(); }
@@ -18781,7 +18783,7 @@ mod tests {
1878118783
let current_height: u32 = node[0].node.best_block.read().unwrap().height;
1878218784
assert!(create_recv_pending_htlc_info(hop_data, [0; 32], PaymentHash([0; 32]),
1878318785
sender_intended_amt_msat - extra_fee_msat, 42, None, true, Some(extra_fee_msat),
18784-
current_height).is_ok());
18786+
current_height, &logger).is_ok());
1878518787
}
1878618788

1878718789
#[test]
@@ -18806,7 +18808,7 @@ mod tests {
1880618808
custom_tlvs: Vec::new(),
1880718809
},
1880818810
shared_secret: SharedSecret::from_bytes([0; 32]),
18809-
}, [0; 32], PaymentHash([0; 32]), 100, TEST_FINAL_CLTV + 1, None, true, None, current_height);
18811+
}, [0; 32], PaymentHash([0; 32]), 100, TEST_FINAL_CLTV + 1, None, true, None, current_height, &TestLogger::new());
1881018812

1881118813
// Should not return an error as this condition:
1881218814
// https://github.com/lightning/bolts/blob/4dcc377209509b13cf89a4b91fde7d478f5b46d8/04-onion-routing.md?plain=1#L334

lightning/src/ln/max_payment_path_len_tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,13 @@ fn one_hop_blinded_path_with_custom_tlv() {
223223
};
224224
let nonce = Nonce([42u8; 16]);
225225
let expanded_key = chanmon_cfgs[2].keys_manager.get_expanded_key();
226+
let receive_auth_key = chanmon_cfgs[2].keys_manager.get_receive_auth_key();
226227
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
227228
let mut secp_ctx = Secp256k1::new();
228229
let blinded_path = BlindedPaymentPath::new(
229230
&[],
230231
nodes[2].node.get_our_node_id(),
232+
receive_auth_key,
231233
payee_tlvs,
232234
u64::MAX,
233235
TEST_FINAL_CLTV as u16,

0 commit comments

Comments
 (0)