From b1e884b69c3e1de4b2798444f451d311a4ab0bad Mon Sep 17 00:00:00 2001 From: shaavan Date: Mon, 22 Sep 2025 15:54:01 +0530 Subject: [PATCH 1/2] Introduce ReceiveAuthKey-based verification in Blinded Payment Paths Extends the work started in [PR#3917](https://github.com/lightningdevkit/rust-lightning/pull/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. --- fuzz/src/chanmon_consistency.rs | 5 +-- fuzz/src/full_stack.rs | 5 +-- fuzz/src/invoice_request_deser.rs | 4 ++- fuzz/src/refund_deser.rs | 4 ++- lightning/src/blinded_path/payment.rs | 29 +++++++++++------ lightning/src/ln/blinded_payment_tests.rs | 31 ++++++++++++------ .../src/ln/max_payment_path_len_tests.rs | 2 ++ lightning/src/ln/msgs.rs | 32 +++++++++++++++---- lightning/src/offers/flow.rs | 2 ++ lightning/src/routing/router.rs | 22 +++++++------ lightning/src/util/test_utils.rs | 6 ++-- 11 files changed, 97 insertions(+), 45 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 9f03de47d23..17a46ff3ac8 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -128,8 +128,9 @@ impl Router for FuzzRouter { } fn create_blinded_payment_paths( - &self, _recipient: PublicKey, _first_hops: Vec, _tlvs: ReceiveTlvs, - _amount_msats: Option, _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey, + _first_hops: Vec, _tlvs: ReceiveTlvs, _amount_msats: Option, + _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 97a74871ea4..6ddcd782225 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -157,8 +157,9 @@ impl Router for FuzzRouter { } fn create_blinded_payment_paths( - &self, _recipient: PublicKey, _first_hops: Vec, _tlvs: ReceiveTlvs, - _amount_msats: Option, _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey, + _first_hops: Vec, _tlvs: ReceiveTlvs, _amount_msats: Option, + _secp_ctx: &Secp256k1, ) -> Result, ()> { unreachable!() } diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index 96d8515f0b5..93618d1c9dc 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -21,7 +21,7 @@ use lightning::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields}; use lightning::offers::nonce::Nonce; use lightning::offers::offer::OfferId; use lightning::offers::parse::Bolt12SemanticError; -use lightning::sign::EntropySource; +use lightning::sign::{EntropySource, ReceiveAuthKey}; use lightning::types::features::BlindedHopFeatures; use lightning::types::payment::{PaymentHash, PaymentSecret}; use lightning::types::string::UntrustedString; @@ -85,6 +85,7 @@ fn build_response( let expanded_key = ExpandedKey::new([42; 32]); let entropy_source = Randomness {}; let nonce = Nonce::from_entropy_source(&entropy_source); + let receive_auth_key = ReceiveAuthKey([41; 32]); let invoice_request_fields = if let Ok(ver) = invoice_request.clone().verify_using_metadata(&expanded_key, secp_ctx) { @@ -136,6 +137,7 @@ fn build_response( let payment_path = BlindedPaymentPath::new( &intermediate_nodes, pubkey(42), + receive_auth_key, payee_tlvs, u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index 6151d810344..2dea67ca087 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -20,7 +20,7 @@ use lightning::offers::invoice::UnsignedBolt12Invoice; use lightning::offers::nonce::Nonce; use lightning::offers::parse::Bolt12SemanticError; use lightning::offers::refund::Refund; -use lightning::sign::EntropySource; +use lightning::sign::{EntropySource, ReceiveAuthKey}; use lightning::types::features::BlindedHopFeatures; use lightning::types::payment::{PaymentHash, PaymentSecret}; use lightning::util::ser::Writeable; @@ -71,6 +71,7 @@ fn build_response( ) -> Result { let expanded_key = ExpandedKey::new([42; 32]); let entropy_source = Randomness {}; + let receive_auth_key = ReceiveAuthKey([41; 32]); let nonce = Nonce::from_entropy_source(&entropy_source); let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {}); let payee_tlvs = UnauthenticatedReceiveTlvs { @@ -103,6 +104,7 @@ fn build_response( let payment_path = BlindedPaymentPath::new( &intermediate_nodes, pubkey(42), + receive_auth_key, payee_tlvs, u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index 37d7a1dba7d..ae60aaa3be9 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -16,7 +16,7 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; use crate::blinded_path::utils::{self, BlindedPathWithPadding}; use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp}; -use crate::crypto::streams::ChaChaPolyReadAdapter; +use crate::crypto::streams::ChaChaDualPolyReadAdapter; use crate::io; use crate::io::Cursor; use crate::ln::channel_state::CounterpartyForwardingInfo; @@ -28,7 +28,7 @@ use crate::offers::invoice_request::InvoiceRequestFields; use crate::offers::nonce::Nonce; use crate::offers::offer::OfferId; use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph}; -use crate::sign::{EntropySource, NodeSigner, Recipient}; +use crate::sign::{EntropySource, NodeSigner, ReceiveAuthKey, Recipient}; use crate::types::features::BlindedHopFeatures; use crate::types::payment::PaymentSecret; use crate::types::routing::RoutingFees; @@ -93,8 +93,8 @@ pub struct BlindedPaymentPath { impl BlindedPaymentPath { /// Create a one-hop blinded path for a payment. pub fn one_hop( - payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, min_final_cltv_expiry_delta: u16, - entropy_source: ES, secp_ctx: &Secp256k1, + payee_node_id: PublicKey, local_node_receive_key: ReceiveAuthKey, payee_tlvs: ReceiveTlvs, + min_final_cltv_expiry_delta: u16, entropy_source: ES, secp_ctx: &Secp256k1, ) -> Result where ES::Target: EntropySource, @@ -105,6 +105,7 @@ impl BlindedPaymentPath { Self::new( &[], payee_node_id, + local_node_receive_key, payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta, @@ -121,8 +122,8 @@ impl BlindedPaymentPath { // TODO: make all payloads the same size with padding + add dummy hops pub fn new( intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey, - payee_tlvs: ReceiveTlvs, htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16, - entropy_source: ES, secp_ctx: &Secp256k1, + local_node_receive_key: ReceiveAuthKey, payee_tlvs: ReceiveTlvs, htlc_maximum_msat: u64, + min_final_cltv_expiry_delta: u16, entropy_source: ES, secp_ctx: &Secp256k1, ) -> Result where ES::Target: EntropySource, @@ -150,6 +151,7 @@ impl BlindedPaymentPath { payee_node_id, payee_tlvs, &blinding_secret, + local_node_receive_key, ), }, payinfo: blinded_payinfo, @@ -226,12 +228,19 @@ impl BlindedPaymentPath { let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &self.inner_path.blinding_point, None)?; let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes()); + let receive_auth_key = node_signer.get_receive_auth_key(); let encrypted_control_tlvs = &self.inner_path.blinded_hops.get(0).ok_or(())?.encrypted_payload; let mut s = Cursor::new(encrypted_control_tlvs); let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64); - match ChaChaPolyReadAdapter::read(&mut reader, rho) { - Ok(ChaChaPolyReadAdapter { readable, .. }) => Ok((readable, control_tlvs_ss)), + let ChaChaDualPolyReadAdapter { readable, used_aad } = + ChaChaDualPolyReadAdapter::read(&mut reader, (rho, receive_auth_key.0)) + .map_err(|_| ())?; + + match (&readable, used_aad) { + (BlindedPaymentTlvs::Forward(_), false) | (BlindedPaymentTlvs::Receive(_), true) => { + Ok((readable, control_tlvs_ss)) + }, _ => Err(()), } } @@ -660,12 +669,12 @@ pub(crate) const PAYMENT_PADDING_ROUND_OFF: usize = 30; /// Construct blinded payment hops for the given `intermediate_nodes` and payee info. pub(super) fn blinded_hops( secp_ctx: &Secp256k1, intermediate_nodes: &[PaymentForwardNode], payee_node_id: PublicKey, - payee_tlvs: ReceiveTlvs, session_priv: &SecretKey, + payee_tlvs: ReceiveTlvs, session_priv: &SecretKey, local_node_receive_key: ReceiveAuthKey, ) -> Vec { let pks = intermediate_nodes .iter() .map(|node| (node.node_id, None)) - .chain(core::iter::once((payee_node_id, None))); + .chain(core::iter::once((payee_node_id, Some(local_node_receive_key)))); let tlvs = intermediate_nodes .iter() .map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs)) diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 8959e347bf7..85be2799702 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -86,12 +86,13 @@ pub fn blinded_payment_path( let nonce = Nonce([42u8; 16]); let expanded_key = keys_manager.get_expanded_key(); + let receive_auth_key = keys_manager.get_receive_auth_key(); let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let mut secp_ctx = Secp256k1::new(); BlindedPaymentPath::new( - &intermediate_nodes[..], *node_ids.last().unwrap(), payee_tlvs, - intro_node_max_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_maximum_msat), + &intermediate_nodes[..], *node_ids.last().unwrap(), receive_auth_key, + payee_tlvs, intro_node_max_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_maximum_msat), TEST_FINAL_CLTV as u16, keys_manager, &secp_ctx ).unwrap() } @@ -171,11 +172,13 @@ fn do_one_hop_blinded_path(success: bool) { }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key(); + let receive_auth_key = chanmon_cfgs[1].keys_manager.get_receive_auth_key(); let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( - &[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, + &[], nodes[1].node.get_our_node_id(), receive_auth_key, + payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[1].keys_manager, &secp_ctx ).unwrap(); @@ -225,9 +228,11 @@ fn mpp_to_one_hop_blinded_path() { }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[3].keys_manager.get_expanded_key(); + let receive_auth_key = chanmon_cfgs[3].keys_manager.get_receive_auth_key(); let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let blinded_path = BlindedPaymentPath::new( - &[], nodes[3].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, + &[], nodes[3].node.get_our_node_id(), receive_auth_key, + payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[3].keys_manager, &secp_ctx ).unwrap(); @@ -1335,10 +1340,12 @@ fn custom_tlvs_to_blinded_path() { }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key(); + let receive_auth_key = chanmon_cfgs[1].keys_manager.get_receive_auth_key(); let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( - &[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, + &[], nodes[1].node.get_our_node_id(), receive_auth_key, + payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[1].keys_manager, &secp_ctx ).unwrap(); @@ -1389,11 +1396,13 @@ fn fails_receive_tlvs_authentication() { }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key(); + let receive_auth_key = chanmon_cfgs[1].keys_manager.get_receive_auth_key(); let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( - &[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, + &[], nodes[1].node.get_our_node_id(), receive_auth_key, + payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[1].keys_manager, &secp_ctx ).unwrap(); @@ -1424,7 +1433,8 @@ fn fails_receive_tlvs_authentication() { let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( - &[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, + &[], nodes[1].node.get_our_node_id(), receive_auth_key, + payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[1].keys_manager, &secp_ctx ).unwrap(); @@ -1627,7 +1637,7 @@ fn route_blinding_spec_test_vector() { &self, _invoice: &RawBolt11Invoice, _recipient: Recipient, ) -> Result { unreachable!() } fn get_peer_storage_key(&self) -> PeerStorageKey { unreachable!() } - fn get_receive_auth_key(&self) -> ReceiveAuthKey { unreachable!() } + fn get_receive_auth_key(&self) -> ReceiveAuthKey { ReceiveAuthKey([41; 32]) } fn sign_bolt12_invoice( &self, _invoice: &UnsignedBolt12Invoice, ) -> Result { unreachable!() } @@ -1940,7 +1950,7 @@ fn test_trampoline_inbound_payment_decoding() { &self, _invoice: &RawBolt11Invoice, _recipient: Recipient, ) -> Result { unreachable!() } fn get_peer_storage_key(&self) -> PeerStorageKey { unreachable!() } - fn get_receive_auth_key(&self) -> ReceiveAuthKey { unreachable!() } + fn get_receive_auth_key(&self) -> ReceiveAuthKey { ReceiveAuthKey([41; 32]) } fn sign_bolt12_invoice( &self, _invoice: &UnsignedBolt12Invoice, ) -> Result { unreachable!() } @@ -2207,8 +2217,9 @@ fn do_test_trampoline_single_hop_receive(success: bool) { }; let nonce = Nonce([42u8; 16]); let expanded_key = nodes[2].keys_manager.get_expanded_key(); + let receive_auth_key = nodes[2].keys_manager.get_receive_auth_key(); let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); - let blinded_path = BlindedPaymentPath::new(&[], carol_node_id, payee_tlvs, u64::MAX, 0, nodes[2].keys_manager, &secp_ctx).unwrap(); + let blinded_path = BlindedPaymentPath::new(&[], carol_node_id, receive_auth_key, payee_tlvs, u64::MAX, 0, nodes[2].keys_manager, &secp_ctx).unwrap(); let route = Route { paths: vec![Path { diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index 8425e1928ad..366f54b9c80 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -223,11 +223,13 @@ fn one_hop_blinded_path_with_custom_tlv() { }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[2].keys_manager.get_expanded_key(); + let receive_auth_key = chanmon_cfgs[2].keys_manager.get_receive_auth_key(); let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( &[], nodes[2].node.get_our_node_id(), + receive_auth_key, payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index c0c8239f621..4462f77cf24 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -59,7 +59,7 @@ use core::str::FromStr; #[cfg(feature = "std")] use std::net::SocketAddr; -use crate::crypto::streams::ChaChaPolyReadAdapter; +use crate::crypto::streams::ChaChaDualPolyReadAdapter; use crate::util::base32; use crate::util::logger; use crate::util::ser::{ @@ -3655,10 +3655,11 @@ where .ecdh(Recipient::Node, &blinding_point, None) .map_err(|_| DecodeError::InvalidValue)?; let rho = onion_utils::gen_rho_from_shared_secret(&enc_tlvs_ss.secret_bytes()); + let receive_auth_key = node_signer.get_receive_auth_key(); let mut s = Cursor::new(&enc_tlvs); let mut reader = FixedLengthReader::new(&mut s, enc_tlvs.len() as u64); - match ChaChaPolyReadAdapter::read(&mut reader, rho)? { - ChaChaPolyReadAdapter { + match ChaChaDualPolyReadAdapter::read(&mut reader, (rho, receive_auth_key.0))? { + ChaChaDualPolyReadAdapter { readable: BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, @@ -3667,11 +3668,13 @@ where features, next_blinding_override, }), + used_aad, } => { if amt.is_some() || cltv_value.is_some() || total_msat.is_some() || keysend_preimage.is_some() || invoice_request.is_some() + || used_aad { return Err(DecodeError::InvalidValue); } @@ -3684,7 +3687,14 @@ where next_blinding_override, })) }, - ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(receive_tlvs) } => { + ChaChaDualPolyReadAdapter { + readable: BlindedPaymentTlvs::Receive(receive_tlvs), + used_aad, + } => { + if !used_aad { + return Err(DecodeError::InvalidValue); + } + let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs; let expanded_key = node_signer.get_expanded_key(); if tlvs.verify_for_offer_payment(hmac, nonce, &expanded_key).is_err() { @@ -3754,6 +3764,7 @@ where { fn read(r: &mut R, args: (Option, NS)) -> Result { let (update_add_blinding_point, node_signer) = args; + let receive_auth_key = node_signer.get_receive_auth_key(); let mut amt = None; let mut cltv_value = None; @@ -3807,8 +3818,8 @@ where let rho = onion_utils::gen_rho_from_shared_secret(&enc_tlvs_ss.secret_bytes()); let mut s = Cursor::new(&enc_tlvs); let mut reader = FixedLengthReader::new(&mut s, enc_tlvs.len() as u64); - match ChaChaPolyReadAdapter::read(&mut reader, rho)? { - ChaChaPolyReadAdapter { + match ChaChaDualPolyReadAdapter::read(&mut reader, (rho, receive_auth_key.0))? { + ChaChaDualPolyReadAdapter { readable: BlindedTrampolineTlvs::Forward(TrampolineForwardTlvs { next_trampoline, @@ -3817,11 +3828,13 @@ where features, next_blinding_override, }), + used_aad, } => { if amt.is_some() || cltv_value.is_some() || total_msat.is_some() || keysend_preimage.is_some() || invoice_request.is_some() + || used_aad { return Err(DecodeError::InvalidValue); } @@ -3834,9 +3847,14 @@ where next_blinding_override, })) }, - ChaChaPolyReadAdapter { + ChaChaDualPolyReadAdapter { readable: BlindedTrampolineTlvs::Receive(receive_tlvs), + used_aad, } => { + if !used_aad { + return Err(DecodeError::InvalidValue); + } + let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs; let expanded_key = node_signer.get_expanded_key(); if tlvs.verify_for_offer_payment(hmac, nonce, &expanded_key).is_err() { diff --git a/lightning/src/offers/flow.rs b/lightning/src/offers/flow.rs index 88f0cc5079c..6415d4b37b0 100644 --- a/lightning/src/offers/flow.rs +++ b/lightning/src/offers/flow.rs @@ -329,6 +329,7 @@ where let expanded_key = &self.inbound_payment_key; let entropy = &*entropy_source; let secp_ctx = &self.secp_ctx; + let receive_auth_key = self.receive_auth_key; let payee_node_id = self.get_our_node_id(); @@ -349,6 +350,7 @@ where router.create_blinded_payment_paths( payee_node_id, + receive_auth_key, usable_channels, payee_tlvs, amount_msats, diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 8434b17698d..c032868b648 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -28,7 +28,7 @@ use crate::routing::gossip::{ DirectedChannelInfo, EffectiveCapacity, NetworkGraph, NodeId, ReadOnlyNetworkGraph, }; use crate::routing::scoring::{ChannelUsage, LockableScore, ScoreLookUp}; -use crate::sign::EntropySource; +use crate::sign::{EntropySource, ReceiveAuthKey}; use crate::sync::Mutex; use crate::types::features::{ BlindedHopFeatures, Bolt11InvoiceFeatures, Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures, @@ -129,8 +129,8 @@ where fn create_blinded_payment_paths< T: secp256k1::Signing + secp256k1::Verification > ( - &self, recipient: PublicKey, first_hops: Vec, tlvs: ReceiveTlvs, - amount_msats: Option, secp_ctx: &Secp256k1 + &self, recipient: PublicKey, local_node_receive_key: ReceiveAuthKey, first_hops: Vec, + tlvs: ReceiveTlvs, amount_msats: Option, secp_ctx: &Secp256k1 ) -> Result, ()> { // Limit the number of blinded paths that are computed. const MAX_PAYMENT_PATHS: usize = 3; @@ -197,7 +197,7 @@ where }) .map(|forward_node| { BlindedPaymentPath::new( - &[forward_node], recipient, tlvs.clone(), u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, + &[forward_node], recipient, local_node_receive_key, tlvs.clone(), u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, &*self.entropy_source, secp_ctx ) }) @@ -209,7 +209,7 @@ where _ => { if network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient)) { BlindedPaymentPath::new( - &[], recipient, tlvs, u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, &*self.entropy_source, + &[], recipient, local_node_receive_key, tlvs, u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, &*self.entropy_source, secp_ctx ).map(|path| vec![path]) } else { @@ -243,8 +243,9 @@ impl Router for FixedRouter { } fn create_blinded_payment_paths( - &self, _recipient: PublicKey, _first_hops: Vec, _tlvs: ReceiveTlvs, - _amount_msats: Option, _secp_ctx: &Secp256k1, + &self, _recipient: PublicKey, _local_node_receive_key: ReceiveAuthKey, + _first_hops: Vec, _tlvs: ReceiveTlvs, _amount_msats: Option, + _secp_ctx: &Secp256k1, ) -> Result, ()> { // Should be unreachable as this router is only intended to provide a one-time payment route. debug_assert!(false); @@ -281,10 +282,11 @@ pub trait Router { /// Creates [`BlindedPaymentPath`]s for payment to the `recipient` node. The channels in `first_hops` /// are assumed to be with the `recipient`'s peers. The payment secret and any constraints are - /// given in `tlvs`. + /// given in `tlvs`. The `local_node_receive_key` is required to authenticate the blinded payment paths. fn create_blinded_payment_paths( - &self, recipient: PublicKey, first_hops: Vec, tlvs: ReceiveTlvs, - amount_msats: Option, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, local_node_receive_key: ReceiveAuthKey, + first_hops: Vec, tlvs: ReceiveTlvs, amount_msats: Option, + secp_ctx: &Secp256k1, ) -> Result, ()>; } diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index ad8ea224205..c0023a2b74b 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -289,13 +289,15 @@ impl<'a> Router for TestRouter<'a> { } fn create_blinded_payment_paths( - &self, recipient: PublicKey, first_hops: Vec, tlvs: ReceiveTlvs, - amount_msats: Option, secp_ctx: &Secp256k1, + &self, recipient: PublicKey, local_node_receive_key: ReceiveAuthKey, + first_hops: Vec, tlvs: ReceiveTlvs, amount_msats: Option, + secp_ctx: &Secp256k1, ) -> Result, ()> { let mut expected_paths = self.next_blinded_payment_paths.lock().unwrap(); if expected_paths.is_empty() { self.router.create_blinded_payment_paths( recipient, + local_node_receive_key, first_hops, tlvs, amount_msats, From b18ccb35f9539f7d0d048a86be3e3ac1dbda217d Mon Sep 17 00:00:00 2001 From: shaavan Date: Thu, 25 Sep 2025 14:17:55 +0530 Subject: [PATCH 2/2] Cleanup: Remove redundant (hmac, nonce) from codebase Now that we have introduced an alternate mechanism for authentication in the codebase, we can safely remove the now redundant (hmac, nonce) fields from the Payment ReceiveTlvs's while maintaining the security of the onion messages. --- fuzz/src/invoice_request_deser.rs | 9 +- fuzz/src/refund_deser.rs | 11 +-- lightning/src/blinded_path/payment.rs | 89 +++++-------------- lightning/src/ln/async_payments_tests.rs | 5 +- lightning/src/ln/blinded_payment_tests.rs | 43 +++------ lightning/src/ln/channelmanager.rs | 40 +-------- .../src/ln/max_payment_path_len_tests.rs | 8 +- lightning/src/ln/msgs.rs | 29 ++---- lightning/src/offers/flow.rs | 75 +++++----------- lightning/src/offers/signer.rs | 31 +------ lightning/src/routing/router.rs | 4 +- 11 files changed, 76 insertions(+), 268 deletions(-) diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index 93618d1c9dc..a21303debd7 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -12,13 +12,12 @@ use bitcoin::secp256k1::{self, Keypair, Parity, PublicKey, Secp256k1, SecretKey} use core::convert::TryFrom; use lightning::blinded_path::payment::{ BlindedPaymentPath, Bolt12OfferContext, ForwardTlvs, PaymentConstraints, PaymentContext, - PaymentForwardNode, PaymentRelay, UnauthenticatedReceiveTlvs, + PaymentForwardNode, PaymentRelay, ReceiveTlvs, }; use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA; use lightning::ln::inbound_payment::ExpandedKey; use lightning::offers::invoice::UnsignedBolt12Invoice; use lightning::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields}; -use lightning::offers::nonce::Nonce; use lightning::offers::offer::OfferId; use lightning::offers::parse::Bolt12SemanticError; use lightning::sign::{EntropySource, ReceiveAuthKey}; @@ -84,7 +83,6 @@ fn build_response( ) -> Result { let expanded_key = ExpandedKey::new([42; 32]); let entropy_source = Randomness {}; - let nonce = Nonce::from_entropy_source(&entropy_source); let receive_auth_key = ReceiveAuthKey([41; 32]); let invoice_request_fields = @@ -107,7 +105,7 @@ fn build_response( offer_id: OfferId([42; 32]), invoice_request: invoice_request_fields, }); - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret: PaymentSecret([42; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 1_000_000, @@ -115,7 +113,6 @@ fn build_response( }, payment_context, }; - let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let intermediate_nodes = [PaymentForwardNode { tlvs: ForwardTlvs { short_channel_id: 43, @@ -125,7 +122,7 @@ fn build_response( fee_base_msat: 1, }, payment_constraints: PaymentConstraints { - max_cltv_expiry: payee_tlvs.tlvs().payment_constraints.max_cltv_expiry + 40, + max_cltv_expiry: payee_tlvs.payment_constraints.max_cltv_expiry + 40, htlc_minimum_msat: 100, }, features: BlindedHopFeatures::empty(), diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index 2dea67ca087..446ac704455 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -12,12 +12,10 @@ use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1, SecretKey}; use core::convert::TryFrom; use lightning::blinded_path::payment::{ BlindedPaymentPath, Bolt12RefundContext, ForwardTlvs, PaymentConstraints, PaymentContext, - PaymentForwardNode, PaymentRelay, UnauthenticatedReceiveTlvs, + PaymentForwardNode, PaymentRelay, ReceiveTlvs, }; use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA; -use lightning::ln::inbound_payment::ExpandedKey; use lightning::offers::invoice::UnsignedBolt12Invoice; -use lightning::offers::nonce::Nonce; use lightning::offers::parse::Bolt12SemanticError; use lightning::offers::refund::Refund; use lightning::sign::{EntropySource, ReceiveAuthKey}; @@ -69,12 +67,10 @@ fn privkey(byte: u8) -> SecretKey { fn build_response( refund: &Refund, signing_pubkey: PublicKey, secp_ctx: &Secp256k1, ) -> Result { - let expanded_key = ExpandedKey::new([42; 32]); let entropy_source = Randomness {}; let receive_auth_key = ReceiveAuthKey([41; 32]); - let nonce = Nonce::from_entropy_source(&entropy_source); let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {}); - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret: PaymentSecret([42; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 1_000_000, @@ -82,7 +78,6 @@ fn build_response( }, payment_context, }; - let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let intermediate_nodes = [PaymentForwardNode { tlvs: ForwardTlvs { short_channel_id: 43, @@ -92,7 +87,7 @@ fn build_response( fee_base_msat: 1, }, payment_constraints: PaymentConstraints { - max_cltv_expiry: payee_tlvs.tlvs().payment_constraints.max_cltv_expiry + 40, + max_cltv_expiry: payee_tlvs.payment_constraints.max_cltv_expiry + 40, htlc_minimum_msat: 100, }, features: BlindedHopFeatures::empty(), diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index ae60aaa3be9..13ade222f5b 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -9,8 +9,6 @@ //! Data structures and methods for constructing [`BlindedPaymentPath`]s to send a payment over. -use bitcoin::hashes::hmac::Hmac; -use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; @@ -20,8 +18,6 @@ use crate::crypto::streams::ChaChaDualPolyReadAdapter; use crate::io; use crate::io::Cursor; use crate::ln::channel_state::CounterpartyForwardingInfo; -use crate::ln::channelmanager::Verification; -use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs::DecodeError; use crate::ln::onion_utils; use crate::offers::invoice_request::InvoiceRequestFields; @@ -137,7 +133,7 @@ impl BlindedPaymentPath { let blinded_payinfo = compute_payinfo( intermediate_nodes, - &payee_tlvs.tlvs, + &payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta, )?; @@ -334,26 +330,8 @@ pub struct TrampolineForwardTlvs { /// Data to construct a [`BlindedHop`] for receiving a payment. This payload is custom to LDK and /// may not be valid if received by another lightning implementation. -/// -/// Can only be constructed by calling [`UnauthenticatedReceiveTlvs::authenticate`]. #[derive(Clone, Debug)] pub struct ReceiveTlvs { - /// The TLVs for which the HMAC in `authentication` is derived. - pub(crate) tlvs: UnauthenticatedReceiveTlvs, - /// An HMAC of `tlvs` along with a nonce used to construct it. - pub(crate) authentication: (Hmac, Nonce), -} - -impl ReceiveTlvs { - /// Returns the underlying TLVs. - pub fn tlvs(&self) -> &UnauthenticatedReceiveTlvs { - &self.tlvs - } -} - -/// An unauthenticated [`ReceiveTlvs`]. -#[derive(Clone, Debug)] -pub struct UnauthenticatedReceiveTlvs { /// Used to authenticate the sender of a payment to the receiver and tie MPP HTLCs together. pub payment_secret: PaymentSecret, /// Constraints for the receiver of this payment. @@ -362,17 +340,6 @@ pub struct UnauthenticatedReceiveTlvs { pub payment_context: PaymentContext, } -impl UnauthenticatedReceiveTlvs { - /// Creates an authenticated [`ReceiveTlvs`], which includes an HMAC and the provide [`Nonce`] - /// that can be use later to verify it authenticity. - pub fn authenticate(self, nonce: Nonce, expanded_key: &ExpandedKey) -> ReceiveTlvs { - ReceiveTlvs { - authentication: (self.hmac_for_offer_payment(nonce, expanded_key), nonce), - tlvs: self, - } - } -} - /// Data to construct a [`BlindedHop`] for sending a payment over. /// /// [`BlindedHop`]: crate::blinded_path::BlindedHop @@ -545,19 +512,12 @@ impl Writeable for TrampolineForwardTlvs { } } +// Note: The `authentication` TLV field was removed in LDK v0.3 following +// the introduction of `ReceiveAuthKey`-based authentication for inbound +// `BlindedPaymentPaths`s. Because we do not support receiving to those +// contexts anymore (they will fail the `ReceiveAuthKey`-based +// authentication checks), we can reuse that field here. impl Writeable for ReceiveTlvs { - fn write(&self, w: &mut W) -> Result<(), io::Error> { - encode_tlv_stream!(w, { - (12, self.tlvs.payment_constraints, required), - (65536, self.tlvs.payment_secret, required), - (65537, self.tlvs.payment_context, required), - (65539, self.authentication, required), - }); - Ok(()) - } -} - -impl Writeable for UnauthenticatedReceiveTlvs { fn write(&self, w: &mut W) -> Result<(), io::Error> { encode_tlv_stream!(w, { (12, self.payment_constraints, required), @@ -592,7 +552,6 @@ impl Readable for BlindedPaymentTlvs { (14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))), (65536, payment_secret, option), (65537, payment_context, option), - (65539, authentication, option), }); if let Some(short_channel_id) = scid { @@ -611,12 +570,9 @@ impl Readable for BlindedPaymentTlvs { return Err(DecodeError::InvalidValue); } Ok(BlindedPaymentTlvs::Receive(ReceiveTlvs { - tlvs: UnauthenticatedReceiveTlvs { - payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?, - payment_constraints: payment_constraints.0.unwrap(), - payment_context: payment_context.ok_or(DecodeError::InvalidValue)?, - }, - authentication: authentication.ok_or(DecodeError::InvalidValue)?, + payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?, + payment_constraints: payment_constraints.0.unwrap(), + payment_context: payment_context.ok_or(DecodeError::InvalidValue)?, })) } } @@ -632,7 +588,6 @@ impl Readable for BlindedTrampolineTlvs { (14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))), (65536, payment_secret, option), (65537, payment_context, option), - (65539, authentication, option), }); if let Some(next_trampoline) = next_trampoline { @@ -651,19 +606,15 @@ impl Readable for BlindedTrampolineTlvs { return Err(DecodeError::InvalidValue); } Ok(BlindedTrampolineTlvs::Receive(ReceiveTlvs { - tlvs: UnauthenticatedReceiveTlvs { - payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?, - payment_constraints: payment_constraints.0.unwrap(), - payment_context: payment_context.ok_or(DecodeError::InvalidValue)?, - }, - authentication: authentication.ok_or(DecodeError::InvalidValue)?, + payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?, + payment_constraints: payment_constraints.0.unwrap(), + payment_context: payment_context.ok_or(DecodeError::InvalidValue)?, })) } } } -/// Represents the padding round off size (in bytes) that -/// is used to pad payment bilnded path's [`BlindedHop`] +/// Represents the padding round-off size (in bytes) used to pad payment blinded path's [`BlindedHop`]. pub(crate) const PAYMENT_PADDING_ROUND_OFF: usize = 30; /// Construct blinded payment hops for the given `intermediate_nodes` and payee info. @@ -743,7 +694,7 @@ where } pub(super) fn compute_payinfo( - intermediate_nodes: &[PaymentForwardNode], payee_tlvs: &UnauthenticatedReceiveTlvs, + intermediate_nodes: &[PaymentForwardNode], payee_tlvs: &ReceiveTlvs, payee_htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16, ) -> Result { let (aggregated_base_fee, aggregated_prop_fee) = @@ -866,7 +817,7 @@ impl_writeable_tlv_based!(Bolt12RefundContext, {}); mod tests { use crate::blinded_path::payment::{ Bolt12RefundContext, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentForwardNode, - PaymentRelay, UnauthenticatedReceiveTlvs, + PaymentRelay, ReceiveTlvs, }; use crate::ln::functional_test_utils::TEST_FINAL_CLTV; use crate::types::features::BlindedHopFeatures; @@ -916,7 +867,7 @@ mod tests { htlc_maximum_msat: u64::max_value(), }, ]; - let recv_tlvs = UnauthenticatedReceiveTlvs { + let recv_tlvs = ReceiveTlvs { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), @@ -934,7 +885,7 @@ mod tests { #[test] fn compute_payinfo_1_hop() { - let recv_tlvs = UnauthenticatedReceiveTlvs { + let recv_tlvs = ReceiveTlvs { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), @@ -991,7 +942,7 @@ mod tests { htlc_maximum_msat: u64::max_value(), }, ]; - let recv_tlvs = UnauthenticatedReceiveTlvs { + let recv_tlvs = ReceiveTlvs { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 3 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), @@ -1050,7 +1001,7 @@ mod tests { htlc_maximum_msat: u64::max_value(), }, ]; - let recv_tlvs = UnauthenticatedReceiveTlvs { + let recv_tlvs = ReceiveTlvs { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), @@ -1119,7 +1070,7 @@ mod tests { htlc_maximum_msat: 10_000, }, ]; - let recv_tlvs = UnauthenticatedReceiveTlvs { + let recv_tlvs = ReceiveTlvs { payment_secret: PaymentSecret([0; 32]), payment_constraints: PaymentConstraints { max_cltv_expiry: 0, htlc_minimum_msat: 1 }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs index d56670f4d67..78250e69f83 100644 --- a/lightning/src/ln/async_payments_tests.rs +++ b/lightning/src/ln/async_payments_tests.rs @@ -272,7 +272,6 @@ fn pass_async_payments_oms( fn create_static_invoice_builder<'a>( recipient: &Node, offer: &'a Offer, offer_nonce: Nonce, relative_expiry: Option, ) -> StaticInvoiceBuilder<'a> { - let entropy = recipient.keys_manager; let amount_msat = offer.amount().and_then(|amount| match amount { Amount::Bitcoin { amount_msats } => Some(amount_msats), Amount::Currency { .. } => None, @@ -296,7 +295,6 @@ fn create_static_invoice_builder<'a>( .flow .create_static_invoice_builder( &recipient.router, - entropy, offer, offer_nonce, payment_secret, @@ -1860,7 +1858,7 @@ fn expired_static_invoice_payment_path() { .advance_path_by_one(&nodes[1].keys_manager, &nodes[1].node, &secp_ctx) .unwrap(); match blinded_path.decrypt_intro_payload(&nodes[2].keys_manager).unwrap().0 { - BlindedPaymentTlvs::Receive(tlvs) => tlvs.tlvs.payment_constraints.max_cltv_expiry, + BlindedPaymentTlvs::Receive(tlvs) => tlvs.payment_constraints.max_cltv_expiry, _ => panic!(), } }; @@ -3106,7 +3104,6 @@ fn intercepted_hold_htlc() { .flow .test_create_blinded_payment_paths( &recipient.router, - recipient.keys_manager, first_hops, None, payment_secret, diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 85be2799702..3f65b89821d 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -15,7 +15,7 @@ use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey, schnorr}; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature}; use crate::blinded_path; -use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12RefundContext, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentForwardNode, PaymentRelay, UnauthenticatedReceiveTlvs, PAYMENT_PADDING_ROUND_OFF}; +use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12RefundContext, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentForwardNode, PaymentRelay, ReceiveTlvs, PAYMENT_PADDING_ROUND_OFF}; use crate::blinded_path::utils::is_padded; use crate::events::{Event, HTLCHandlingFailureType, PaymentFailureReason}; use crate::ln::types::ChannelId; @@ -31,7 +31,6 @@ use crate::ln::onion_payment; use crate::ln::onion_utils::{self, LocalHTLCFailureReason}; use crate::ln::outbound_payment::{Retry, IDEMPOTENCY_TIMEOUT_TICKS}; use crate::offers::invoice::UnsignedBolt12Invoice; -use crate::offers::nonce::Nonce; use crate::prelude::*; use crate::routing::router::{BlindedTail, Path, Payee, PaymentParameters, RouteHop, RouteParameters, TrampolineHop}; use crate::sign::{NodeSigner, PeerStorageKey, ReceiveAuthKey, Recipient}; @@ -74,7 +73,7 @@ pub fn blinded_payment_path( }); } - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret, payment_constraints: PaymentConstraints { max_cltv_expiry: u32::max_value(), @@ -84,10 +83,7 @@ pub fn blinded_payment_path( payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; - let nonce = Nonce([42u8; 16]); - let expanded_key = keys_manager.get_expanded_key(); let receive_auth_key = keys_manager.get_receive_auth_key(); - let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let mut secp_ctx = Secp256k1::new(); BlindedPaymentPath::new( @@ -162,7 +158,7 @@ fn do_one_hop_blinded_path(success: bool) { let amt_msat = 5000; let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None); - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret, payment_constraints: PaymentConstraints { max_cltv_expiry: u32::max_value(), @@ -170,10 +166,7 @@ fn do_one_hop_blinded_path(success: bool) { }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; - let nonce = Nonce([42u8; 16]); - let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key(); let receive_auth_key = chanmon_cfgs[1].keys_manager.get_receive_auth_key(); - let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( @@ -218,7 +211,7 @@ fn mpp_to_one_hop_blinded_path() { let amt_msat = 15_000_000; let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None); - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret, payment_constraints: PaymentConstraints { max_cltv_expiry: u32::max_value(), @@ -226,10 +219,7 @@ fn mpp_to_one_hop_blinded_path() { }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; - let nonce = Nonce([42u8; 16]); - let expanded_key = chanmon_cfgs[3].keys_manager.get_expanded_key(); let receive_auth_key = chanmon_cfgs[3].keys_manager.get_receive_auth_key(); - let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let blinded_path = BlindedPaymentPath::new( &[], nodes[3].node.get_our_node_id(), receive_auth_key, payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, @@ -1330,7 +1320,7 @@ fn custom_tlvs_to_blinded_path() { let amt_msat = 5000; let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None); - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret, payment_constraints: PaymentConstraints { max_cltv_expiry: u32::max_value(), @@ -1338,10 +1328,8 @@ fn custom_tlvs_to_blinded_path() { }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; - let nonce = Nonce([42u8; 16]); - let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key(); let receive_auth_key = chanmon_cfgs[1].keys_manager.get_receive_auth_key(); - let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); + let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( &[], nodes[1].node.get_our_node_id(), receive_auth_key, @@ -1386,7 +1374,7 @@ fn fails_receive_tlvs_authentication() { let amt_msat = 5000; let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None); - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret, payment_constraints: PaymentConstraints { max_cltv_expiry: u32::max_value(), @@ -1394,10 +1382,7 @@ fn fails_receive_tlvs_authentication() { }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; - let nonce = Nonce([42u8; 16]); - let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key(); let receive_auth_key = chanmon_cfgs[1].keys_manager.get_receive_auth_key(); - let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( @@ -1419,7 +1404,7 @@ fn fails_receive_tlvs_authentication() { // Swap in a different nonce to force authentication to fail. let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None); - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret, payment_constraints: PaymentConstraints { max_cltv_expiry: u32::max_value(), @@ -1427,13 +1412,12 @@ fn fails_receive_tlvs_authentication() { }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; - let nonce = Nonce([43u8; 16]); - let mut payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); - payee_tlvs.authentication.1 = Nonce([0u8; 16]); + // Use a mismatched ReceiveAuthKey to force auth failure: + let mismatched_receive_auth_key = ReceiveAuthKey([0u8; 32]); let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( - &[], nodes[1].node.get_our_node_id(), receive_auth_key, + &[], nodes[1].node.get_our_node_id(), mismatched_receive_auth_key, payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16, &chanmon_cfgs[1].keys_manager, &secp_ctx ).unwrap(); @@ -2207,7 +2191,7 @@ fn do_test_trampoline_single_hop_receive(success: bool) { let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), None); // Create a 1-hop blinded path for Carol. - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret, payment_constraints: PaymentConstraints { max_cltv_expiry: u32::max_value(), @@ -2215,10 +2199,7 @@ fn do_test_trampoline_single_hop_receive(success: bool) { }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; - let nonce = Nonce([42u8; 16]); - let expanded_key = nodes[2].keys_manager.get_expanded_key(); let receive_auth_key = nodes[2].keys_manager.get_receive_auth_key(); - let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let blinded_path = BlindedPaymentPath::new(&[], carol_node_id, receive_auth_key, payee_tlvs, u64::MAX, 0, nodes[2].keys_manager, &secp_ctx).unwrap(); let route = Route { diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 644920557d2..271ecaa9b24 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -35,9 +35,7 @@ use bitcoin::{secp256k1, Sequence, SignedAmount}; use crate::blinded_path::message::{ AsyncPaymentsContext, BlindedMessagePath, MessageForwardNode, OffersContext, }; -use crate::blinded_path::payment::{ - AsyncBolt12OfferContext, Bolt12OfferContext, PaymentContext, UnauthenticatedReceiveTlvs, -}; +use crate::blinded_path::payment::{AsyncBolt12OfferContext, Bolt12OfferContext, PaymentContext}; use crate::blinded_path::NodeIdLookUp; use crate::chain; use crate::chain::chaininterface::{ @@ -100,7 +98,6 @@ use crate::offers::nonce::Nonce; use crate::offers::offer::{Offer, OfferFromHrn}; use crate::offers::parse::Bolt12SemanticError; use crate::offers::refund::Refund; -use crate::offers::signer; use crate::offers::static_invoice::StaticInvoice; use crate::onion_message::async_payments::{ AsyncPaymentsMessage, AsyncPaymentsMessageHandler, HeldHtlcAvailable, OfferPaths, @@ -574,34 +571,6 @@ impl Ord for ClaimableHTLC { } } -/// A trait defining behavior for creating and verifing the HMAC for authenticating a given data. -pub trait Verification { - /// Constructs an HMAC to include in [`OffersContext`] for the data along with the given - /// [`Nonce`]. - fn hmac_for_offer_payment( - &self, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, - ) -> Hmac; - - /// Authenticates the data using an HMAC and a [`Nonce`] taken from an [`OffersContext`]. - fn verify_for_offer_payment( - &self, hmac: Hmac, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, - ) -> Result<(), ()>; -} - -impl Verification for UnauthenticatedReceiveTlvs { - fn hmac_for_offer_payment( - &self, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, - ) -> Hmac { - signer::hmac_for_payment_tlvs(self, nonce, expanded_key) - } - - fn verify_for_offer_payment( - &self, hmac: Hmac, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, - ) -> Result<(), ()> { - signer::verify_payment_tlvs(self, hmac, nonce, expanded_key) - } -} - /// A user-provided identifier in [`ChannelManager::send_payment`] used to uniquely identify /// a payment and ensure idempotency in LDK. /// @@ -5642,12 +5611,10 @@ where fn check_refresh_async_receive_offer_cache(&self, timer_tick_occurred: bool) { let peers = self.get_peers_for_blinded_path(); let channels = self.list_usable_channels(); - let entropy = &*self.entropy_source; let router = &*self.router; let refresh_res = self.flow.check_refresh_async_receive_offer_cache( peers, channels, - entropy, router, timer_tick_occurred, ); @@ -13364,11 +13331,8 @@ where &self, amount_msats: Option, payment_secret: PaymentSecret, payment_context: PaymentContext, relative_expiry_seconds: u32, ) -> Result, ()> { - let entropy = &*self.entropy_source; - self.flow.test_create_blinded_payment_paths( &self.router, - entropy, self.list_usable_channels(), amount_msats, payment_secret, @@ -15272,7 +15236,6 @@ where InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => { let result = self.flow.create_invoice_builder_from_invoice_request_with_keys( &self.router, - &*self.entropy_source, &request, self.list_usable_channels(), get_payment_info, @@ -15297,7 +15260,6 @@ where InvoiceRequestVerifiedFromOffer::ExplicitKeys(request) => { let result = self.flow.create_invoice_builder_from_invoice_request_without_keys( &self.router, - &*self.entropy_source, &request, self.list_usable_channels(), get_payment_info, diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index 366f54b9c80..f67ad442c29 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -12,7 +12,7 @@ use crate::blinded_path::payment::{ BlindedPayInfo, BlindedPaymentPath, Bolt12RefundContext, PaymentConstraints, PaymentContext, - UnauthenticatedReceiveTlvs, + ReceiveTlvs, }; use crate::blinded_path::BlindedHop; use crate::events::Event; @@ -24,7 +24,6 @@ use crate::ln::msgs::{BaseMessageHandler, OnionMessageHandler}; use crate::ln::onion_utils; use crate::ln::onion_utils::MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY; use crate::ln::outbound_payment::{RecipientOnionFields, Retry, RetryableSendFailure}; -use crate::offers::nonce::Nonce; use crate::prelude::*; use crate::routing::router::{ PaymentParameters, RouteParameters, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, @@ -213,7 +212,7 @@ fn one_hop_blinded_path_with_custom_tlv() { let amt_msat = 100_000; let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), None); - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret, payment_constraints: PaymentConstraints { max_cltv_expiry: u32::max_value(), @@ -221,10 +220,7 @@ fn one_hop_blinded_path_with_custom_tlv() { }, payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; - let nonce = Nonce([42u8; 16]); - let expanded_key = chanmon_cfgs[2].keys_manager.get_expanded_key(); let receive_auth_key = chanmon_cfgs[2].keys_manager.get_receive_auth_key(); - let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); let mut secp_ctx = Secp256k1::new(); let blinded_path = BlindedPaymentPath::new( &[], diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 4462f77cf24..67bf764c397 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -32,11 +32,8 @@ use bitcoin::secp256k1::PublicKey; use bitcoin::{secp256k1, Transaction, Witness}; use crate::blinded_path::message::BlindedMessagePath; -use crate::blinded_path::payment::{ - BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs, UnauthenticatedReceiveTlvs, -}; +use crate::blinded_path::payment::{BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs}; use crate::blinded_path::payment::{BlindedTrampolineTlvs, TrampolineForwardTlvs}; -use crate::ln::channelmanager::Verification; use crate::ln::onion_utils; use crate::ln::types::ChannelId; use crate::offers::invoice_request::InvoiceRequest; @@ -3695,17 +3692,9 @@ where return Err(DecodeError::InvalidValue); } - let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs; - let expanded_key = node_signer.get_expanded_key(); - if tlvs.verify_for_offer_payment(hmac, nonce, &expanded_key).is_err() { - return Err(DecodeError::InvalidValue); - } + let ReceiveTlvs { payment_secret, payment_constraints, payment_context } = + receive_tlvs; - let UnauthenticatedReceiveTlvs { - payment_secret, - payment_constraints, - payment_context, - } = tlvs; if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue); } @@ -3855,17 +3844,9 @@ where return Err(DecodeError::InvalidValue); } - let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs; - let expanded_key = node_signer.get_expanded_key(); - if tlvs.verify_for_offer_payment(hmac, nonce, &expanded_key).is_err() { - return Err(DecodeError::InvalidValue); - } + let ReceiveTlvs { payment_secret, payment_constraints, payment_context } = + receive_tlvs; - let UnauthenticatedReceiveTlvs { - payment_secret, - payment_constraints, - payment_context, - } = tlvs; if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue); } diff --git a/lightning/src/offers/flow.rs b/lightning/src/offers/flow.rs index 6415d4b37b0..94a4534c61a 100644 --- a/lightning/src/offers/flow.rs +++ b/lightning/src/offers/flow.rs @@ -23,7 +23,7 @@ use crate::blinded_path::message::{ }; use crate::blinded_path::payment::{ AsyncBolt12OfferContext, BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, - PaymentConstraints, PaymentContext, UnauthenticatedReceiveTlvs, + PaymentConstraints, PaymentContext, ReceiveTlvs, }; use crate::chain::channelmonitor::LATENCY_GRACE_PERIOD_BLOCKS; @@ -317,17 +317,14 @@ where /// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to /// [`Router::create_blinded_payment_paths`]. - fn create_blinded_payment_paths( - &self, router: &R, entropy_source: ES, usable_channels: Vec, - amount_msats: Option, payment_secret: PaymentSecret, payment_context: PaymentContext, + fn create_blinded_payment_paths( + &self, router: &R, usable_channels: Vec, amount_msats: Option, + payment_secret: PaymentSecret, payment_context: PaymentContext, relative_expiry_seconds: u32, ) -> Result, ()> where - ES::Target: EntropySource, R::Target: Router, { - let expanded_key = &self.inbound_payment_key; - let entropy = &*entropy_source; let secp_ctx = &self.secp_ctx; let receive_auth_key = self.receive_auth_key; @@ -340,13 +337,11 @@ where .saturating_add(LATENCY_GRACE_PERIOD_BLOCKS) .saturating_add(self.best_block.read().unwrap().height); - let payee_tlvs = UnauthenticatedReceiveTlvs { + let payee_tlvs = ReceiveTlvs { payment_secret, payment_constraints: PaymentConstraints { max_cltv_expiry, htlc_minimum_msat: 1 }, payment_context, }; - let nonce = Nonce::from_entropy_source(entropy); - let payee_tlvs = payee_tlvs.authenticate(nonce, expanded_key); router.create_blinded_payment_paths( payee_node_id, @@ -361,18 +356,16 @@ where #[cfg(test)] /// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to /// [`Router::create_blinded_payment_paths`]. - pub(crate) fn test_create_blinded_payment_paths( - &self, router: &R, entropy_source: ES, usable_channels: Vec, - amount_msats: Option, payment_secret: PaymentSecret, payment_context: PaymentContext, + pub(crate) fn test_create_blinded_payment_paths( + &self, router: &R, usable_channels: Vec, amount_msats: Option, + payment_secret: PaymentSecret, payment_context: PaymentContext, relative_expiry_seconds: u32, ) -> Result, ()> where - ES::Target: EntropySource, R::Target: Router, { self.create_blinded_payment_paths( router, - entropy_source, usable_channels, amount_msats, payment_secret, @@ -828,17 +821,15 @@ where /// created via [`Self::create_async_receive_offer_builder`]. /// /// This is not exported to bindings users as builder patterns don't map outside of move semantics. - pub fn create_static_invoice_builder<'a, ES: Deref, R: Deref>( - &self, router: &R, entropy_source: ES, offer: &'a Offer, offer_nonce: Nonce, - payment_secret: PaymentSecret, relative_expiry_secs: u32, - usable_channels: Vec, peers: Vec, + pub fn create_static_invoice_builder<'a, R: Deref>( + &self, router: &R, offer: &'a Offer, offer_nonce: Nonce, payment_secret: PaymentSecret, + relative_expiry_secs: u32, usable_channels: Vec, + peers: Vec, ) -> Result, Bolt12SemanticError> where - ES::Target: EntropySource, R::Target: Router, { let expanded_key = &self.inbound_payment_key; - let entropy = &*entropy_source; let secp_ctx = &self.secp_ctx; let payment_context = @@ -854,7 +845,6 @@ where let payment_paths = self .create_blinded_payment_paths( router, - entropy, usable_channels, amount_msat, payment_secret, @@ -927,7 +917,6 @@ where let payment_paths = self .create_blinded_payment_paths( router, - entropy, usable_channels, Some(amount_msats), payment_secret, @@ -972,18 +961,14 @@ where /// Returns a [`Bolt12SemanticError`] if: /// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`]. /// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`]. - pub fn create_invoice_builder_from_invoice_request_with_keys<'a, ES: Deref, R: Deref, F>( - &self, router: &R, entropy_source: ES, - invoice_request: &'a VerifiedInvoiceRequest, + pub fn create_invoice_builder_from_invoice_request_with_keys<'a, R: Deref, F>( + &self, router: &R, invoice_request: &'a VerifiedInvoiceRequest, usable_channels: Vec, get_payment_info: F, ) -> Result<(InvoiceBuilder<'a, DerivedSigningPubkey>, MessageContext), Bolt12SemanticError> where - ES::Target: EntropySource, - R::Target: Router, F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>, { - let entropy = &*entropy_source; let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32; let amount_msats = @@ -999,7 +984,6 @@ where let payment_paths = self .create_blinded_payment_paths( router, - entropy, usable_channels, Some(amount_msats), payment_secret, @@ -1037,17 +1021,14 @@ where /// Returns a [`Bolt12SemanticError`] if: /// - Valid blinded payment paths could not be generated for the [`Bolt12Invoice`]. /// - The [`InvoiceBuilder`] could not be created from the [`InvoiceRequest`]. - pub fn create_invoice_builder_from_invoice_request_without_keys<'a, ES: Deref, R: Deref, F>( - &self, router: &R, entropy_source: ES, - invoice_request: &'a VerifiedInvoiceRequest, + pub fn create_invoice_builder_from_invoice_request_without_keys<'a, R: Deref, F>( + &self, router: &R, invoice_request: &'a VerifiedInvoiceRequest, usable_channels: Vec, get_payment_info: F, ) -> Result<(InvoiceBuilder<'a, ExplicitSigningPubkey>, MessageContext), Bolt12SemanticError> where - ES::Target: EntropySource, R::Target: Router, F: Fn(u64, u32) -> Result<(PaymentHash, PaymentSecret), Bolt12SemanticError>, { - let entropy = &*entropy_source; let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32; let amount_msats = @@ -1063,7 +1044,6 @@ where let payment_paths = self .create_blinded_payment_paths( router, - entropy, usable_channels, Some(amount_msats), payment_secret, @@ -1394,12 +1374,11 @@ where /// the cache can self-regulate the number of messages sent out. /// /// Errors if we failed to create blinded reply paths when sending an [`OfferPathsRequest`] message. - pub fn check_refresh_async_receive_offer_cache( - &self, peers: Vec, usable_channels: Vec, entropy: ES, - router: R, timer_tick_occurred: bool, + pub fn check_refresh_async_receive_offer_cache( + &self, peers: Vec, usable_channels: Vec, router: R, + timer_tick_occurred: bool, ) -> Result<(), ()> where - ES::Target: EntropySource, R::Target: Router, { // Terminate early if this node does not intend to receive async payments. @@ -1413,7 +1392,7 @@ where self.check_refresh_async_offers(peers.clone(), timer_tick_occurred)?; if timer_tick_occurred { - self.check_refresh_static_invoices(peers, usable_channels, entropy, router); + self.check_refresh_static_invoices(peers, usable_channels, router); } Ok(()) @@ -1470,11 +1449,9 @@ where /// Enqueue onion messages that will used to request invoice refresh from the static invoice /// server, based on the offers provided by the cache. - fn check_refresh_static_invoices( - &self, peers: Vec, usable_channels: Vec, entropy: ES, - router: R, + fn check_refresh_static_invoices( + &self, peers: Vec, usable_channels: Vec, router: R, ) where - ES::Target: EntropySource, R::Target: Router, { let mut serve_static_invoice_msgs = Vec::new(); @@ -1489,7 +1466,6 @@ where offer_nonce, peers.clone(), usable_channels.clone(), - &*entropy, &*router, ) { Ok((invoice, path)) => (invoice, path), @@ -1655,7 +1631,6 @@ where offer_nonce, peers, usable_channels, - &*entropy, router, ) { Ok(res) => res, @@ -1690,12 +1665,11 @@ where /// Creates a [`StaticInvoice`] and a blinded path for the server to forward invoice requests from /// payers to our node. - fn create_static_invoice_for_server( + fn create_static_invoice_for_server( &self, offer: &Offer, offer_nonce: Nonce, peers: Vec, - usable_channels: Vec, entropy: ES, router: R, + usable_channels: Vec, router: R, ) -> Result<(StaticInvoice, BlindedMessagePath), ()> where - ES::Target: EntropySource, R::Target: Router, { let expanded_key = &self.inbound_payment_key; @@ -1722,7 +1696,6 @@ where let invoice = self .create_static_invoice_builder( &router, - &*entropy, &offer, offer_nonce, payment_secret, diff --git a/lightning/src/offers/signer.rs b/lightning/src/offers/signer.rs index 645949ff866..e51a120b6d7 100644 --- a/lightning/src/offers/signer.rs +++ b/lightning/src/offers/signer.rs @@ -9,7 +9,6 @@ //! Utilities for signing offer messages and verifying metadata. -use crate::blinded_path::payment::UnauthenticatedReceiveTlvs; use crate::ln::channelmanager::PaymentId; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN}; use crate::offers::merkle::TlvRecord; @@ -41,16 +40,14 @@ const WITH_ENCRYPTED_PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[4; 16]; // The following `HMAC_INPUT` constants were previously used for authenticating fields in // `OffersContext`, but were removed in LDK v0.2 with the introduction of `ReceiveAuthKey`-based // authentication. -// Their corresponding values (`[5; 16]` and `[7; 16]`) are now reserved and must not +// Their corresponding values (`[5; 16]`, `[7; 16]` and `[8; 16]`) are now reserved and must not // be reused to ensure type confusion attacks are impossible. // // Reserved HMAC_INPUT values — do not reuse: // // const OFFER_PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[5; 16]; // const PAYMENT_HASH_HMAC_INPUT: &[u8; 16] = &[7; 16]; - -// HMAC input for `ReceiveTlvs`. The HMAC is used in `blinded_path::payment::PaymentContext`. -const PAYMENT_TLVS_HMAC_INPUT: &[u8; 16] = &[8; 16]; +// const PAYMENT_TLVS_HMAC_INPUT: &[u8; 16] = &[8; 16]; /// Message metadata which possibly is derived from [`MetadataMaterial`] such that it can be /// verified. @@ -449,27 +446,3 @@ fn hmac_for_message<'a>( Ok(hmac) } - -pub(crate) fn hmac_for_payment_tlvs( - receive_tlvs: &UnauthenticatedReceiveTlvs, nonce: Nonce, expanded_key: &ExpandedKey, -) -> Hmac { - const IV_BYTES: &[u8; IV_LEN] = b"LDK Payment TLVs"; - let mut hmac = expanded_key.hmac_for_offer(); - hmac.input(IV_BYTES); - hmac.input(&nonce.0); - hmac.input(PAYMENT_TLVS_HMAC_INPUT); - receive_tlvs.write(&mut hmac).unwrap(); - - Hmac::from_engine(hmac) -} - -pub(crate) fn verify_payment_tlvs( - receive_tlvs: &UnauthenticatedReceiveTlvs, hmac: Hmac, nonce: Nonce, - expanded_key: &ExpandedKey, -) -> Result<(), ()> { - if hmac_for_payment_tlvs(receive_tlvs, nonce, expanded_key) == hmac { - Ok(()) - } else { - Err(()) - } -} diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index c032868b648..e969237d10f 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -180,7 +180,9 @@ where let cltv_expiry_delta = payment_relay.cltv_expiry_delta as u32; let payment_constraints = PaymentConstraints { - max_cltv_expiry: tlvs.tlvs().payment_constraints.max_cltv_expiry + cltv_expiry_delta, + max_cltv_expiry: tlvs.payment_constraints + .max_cltv_expiry + .saturating_add(cltv_expiry_delta), htlc_minimum_msat: details.inbound_htlc_minimum_msat.unwrap_or(0), }; Some(PaymentForwardNode {