diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index a5db1c4be..3abb0974e 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -113,6 +113,7 @@ fn build_response( htlc_minimum_msat: 100, }, features: BlindedHopFeatures::empty(), + next_blinding_override: None, }, node_id: pubkey(43), htlc_maximum_msat: 1_000_000_000_000, diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index 58dc68eed..17f255081 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -91,6 +91,7 @@ fn build_response( htlc_minimum_msat: 100, }, features: BlindedHopFeatures::empty(), + next_blinding_override: None, }, node_id: pubkey(43), htlc_maximum_msat: 1_000_000_000_000, diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index 765e0b91f..ca937c57d 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -201,6 +201,9 @@ pub struct ForwardTlvs { /// /// [`BlindedHop::encrypted_payload`]: crate::blinded_path::BlindedHop::encrypted_payload pub features: BlindedHopFeatures, + /// Set if this [`BlindedPaymentPath`] is concatenated to another, to indicate the + /// [`BlindedPaymentPath::blinding_point`] of the appended blinded path. + pub next_blinding_override: Option, } /// Data to construct a [`BlindedHop`] for receiving a payment. This payload is custom to LDK and @@ -379,6 +382,7 @@ impl Readable for BlindedPaymentTlvs { _init_and_read_tlv_stream!(r, { (1, _padding, option), (2, scid, option), + (8, next_blinding_override, option), (10, payment_relay, option), (12, payment_constraints, required), (14, features, option), @@ -395,6 +399,7 @@ impl Readable for BlindedPaymentTlvs { short_channel_id, payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?, payment_constraints: payment_constraints.0.unwrap(), + next_blinding_override, features: features.unwrap_or_else(BlindedHopFeatures::empty), })) } else { @@ -602,6 +607,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 100, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value(), @@ -618,6 +624,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1_000, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value(), @@ -675,6 +682,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value() @@ -691,6 +699,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 2_000, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value() @@ -726,6 +735,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 5_000, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value() @@ -742,6 +752,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 2_000, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: u64::max_value() @@ -781,6 +792,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: 5_000, @@ -797,6 +809,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: 10_000 diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index b13b1e04d..e959000d3 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -49,6 +49,7 @@ fn blinded_payment_path( htlc_minimum_msat: intro_node_min_htlc_opt.take() .unwrap_or_else(|| channel_upds[idx - 1].htlc_minimum_msat), }, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, htlc_maximum_msat: intro_node_max_htlc_opt.take() diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 641810f2f..e08b45558 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -226,6 +226,10 @@ pub struct BlindedForward { /// If needed, this determines how this HTLC should be failed backwards, based on whether we are /// the introduction node. pub failure: BlindedFailure, + /// Overrides the next hop's [`msgs::UpdateAddHTLC::blinding_point`]. Set if this HTLC is being + /// forwarded within a [`BlindedPaymentPath`] that was concatenated to another blinded path that + /// starts at the next hop. + pub next_blinding_override: Option, } impl PendingHTLCRouting { @@ -5313,12 +5317,14 @@ where blinded_failure: blinded.map(|b| b.failure), }); let next_blinding_point = blinded.and_then(|b| { - let encrypted_tlvs_ss = self.node_signer.ecdh( - Recipient::Node, &b.inbound_blinding_point, None - ).unwrap().secret_bytes(); - onion_utils::next_hop_pubkey( - &self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss - ).ok() + b.next_blinding_override.or_else(|| { + let encrypted_tlvs_ss = self.node_signer.ecdh( + Recipient::Node, &b.inbound_blinding_point, None + ).unwrap().secret_bytes(); + onion_utils::next_hop_pubkey( + &self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss + ).ok() + }) }); // Forward the HTLC over the most appropriate channel with the corresponding peer, @@ -11034,6 +11040,7 @@ impl_writeable_tlv_based!(PhantomRouteHints, { impl_writeable_tlv_based!(BlindedForward, { (0, inbound_blinding_point, required), (1, failure, (default_value, BlindedFailure::FromIntroductionNode)), + (3, next_blinding_override, option), }); impl_writeable_tlv_based_enum!(PendingHTLCRouting, diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 85f1ae0aa..83ce4f914 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -1764,6 +1764,7 @@ mod fuzzy_internal_msgs { payment_constraints: PaymentConstraints, features: BlindedHopFeatures, intro_node_blinding_point: Option, + next_blinding_override: Option, }, BlindedReceive { sender_intended_htlc_amt_msat: u64, @@ -2808,7 +2809,7 @@ impl ReadableArgs<(Option, &NS)> for InboundOnionPayload w let mut reader = FixedLengthReader::new(&mut s, enc_tlvs.len() as u64); match ChaChaPolyReadAdapter::read(&mut reader, rho)? { ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Forward(ForwardTlvs { - short_channel_id, payment_relay, payment_constraints, features + short_channel_id, payment_relay, payment_constraints, features, next_blinding_override })} => { if amt.is_some() || cltv_value.is_some() || total_msat.is_some() || keysend_preimage.is_some() @@ -2821,6 +2822,7 @@ impl ReadableArgs<(Option, &NS)> for InboundOnionPayload w payment_constraints, features, intro_node_blinding_point, + next_blinding_override, }) }, ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs { diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs index f62ca5d84..1163a5e63 100644 --- a/lightning/src/ln/onion_payment.rs +++ b/lightning/src/ln/onion_payment.rs @@ -75,12 +75,14 @@ pub(super) fn create_fwd_pending_htlc_info( }; let ( - short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point + short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point, + next_blinding_override ) = match hop_data { msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } => - (short_channel_id, amt_to_forward, outgoing_cltv_value, None), + (short_channel_id, amt_to_forward, outgoing_cltv_value, None, None), msgs::InboundOnionPayload::BlindedForward { short_channel_id, payment_relay, payment_constraints, intro_node_blinding_point, features, + next_blinding_override, } => { let (amt_to_forward, outgoing_cltv_value) = check_blinded_forward( msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features @@ -93,7 +95,8 @@ pub(super) fn create_fwd_pending_htlc_info( err_data: vec![0; 32], } })?; - (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point) + (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point, + next_blinding_override) }, msgs::InboundOnionPayload::Receive { .. } | msgs::InboundOnionPayload::BlindedReceive { .. } => return Err(InboundHTLCErr { @@ -110,6 +113,7 @@ pub(super) fn create_fwd_pending_htlc_info( blinded: intro_node_blinding_point.or(msg.blinding_point) .map(|bp| BlindedForward { inbound_blinding_point: bp, + next_blinding_override, failure: intro_node_blinding_point .map(|_| BlindedFailure::FromIntroductionNode) .unwrap_or(BlindedFailure::FromBlindedNode), diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 2d7450b91..43c4b7343 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -151,6 +151,7 @@ impl>, L: Deref, ES: Deref, S: Deref, SP: Size short_channel_id, payment_relay, payment_constraints, + next_blinding_override: None, features: BlindedHopFeatures::empty(), }, node_id: details.counterparty.node_id,