@@ -105,6 +105,7 @@ pub(super) enum PendingHTLCRouting {
105
105
/// The SCID from the onion that we should forward to. This could be a real SCID or a fake one
106
106
/// generated using `get_fake_scid` from the scid_utils::fake_scid module.
107
107
short_channel_id: u64, // This should be NonZero<u64> eventually when we bump MSRV
108
+ blinded: Option<BlindedForward>,
108
109
},
109
110
Receive {
110
111
payment_data: msgs::FinalOnionHopData,
@@ -182,6 +183,12 @@ pub(super) enum HTLCForwardInfo {
182
183
},
183
184
}
184
185
186
+ #[derive(Clone, Copy, Hash, PartialEq, Eq)]
187
+ pub(super) struct BlindedForward {
188
+ inbound_blinding_point: PublicKey,
189
+ we_are_intro_node: bool,
190
+ }
191
+
185
192
/// Tracks the inbound corresponding to an outbound HTLC
186
193
#[derive(Clone, Hash, PartialEq, Eq)]
187
194
pub(crate) struct HTLCPreviousHopData {
@@ -2733,22 +2740,45 @@ where
2733
2740
hmac: hop_hmac,
2734
2741
};
2735
2742
2736
- let (short_channel_id, amt_to_forward, outgoing_cltv_value) = match hop_data {
2743
+ let (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_pt)
2744
+ = match hop_data
2745
+ {
2737
2746
msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } =>
2738
- (short_channel_id, amt_to_forward, outgoing_cltv_value),
2739
- msgs::InboundOnionPayload::Receive { .. } =>
2747
+ (short_channel_id, amt_to_forward, outgoing_cltv_value, None),
2748
+ msgs::InboundOnionPayload::BlindedForward {
2749
+ short_channel_id, payment_relay, intro_node_blinding_point, ..
2750
+ } => {
2751
+ // We checked these values in [`Self::decode_update_add_htlc_onion`].
2752
+ let amt_to_forward = msg.amount_msat - payment_relay.fee_base_msat as u64
2753
+ - (msg.amount_msat * payment_relay.fee_proportional_millionths as u64 / 1_000_000);
2754
+ let outgoing_cltv_value = msg.cltv_expiry - payment_relay.cltv_expiry_delta as u32;
2755
+ (short_channel_id, amt_to_forward, outgoing_cltv_value, intro_node_blinding_point)
2756
+ },
2757
+ msgs::InboundOnionPayload::Receive { .. } => {
2740
2758
return Err(InboundOnionErr {
2741
2759
msg: "Final Node OnionHopData provided for us as an intermediary node",
2742
2760
err_code: 0x4000 | 22,
2743
2761
err_data: Vec::new(),
2744
- }),
2745
- _ => todo!()
2762
+ })
2763
+ },
2764
+ msgs::InboundOnionPayload::BlindedReceive { .. } => {
2765
+ return Err(InboundOnionErr {
2766
+ msg: "Final Node OnionHopData provided for us as an intermediary node",
2767
+ err_code: INVALID_ONION_BLINDING,
2768
+ err_data: Sha256::hash(&msg.onion_routing_packet.hop_data).into_inner().to_vec(),
2769
+ })
2770
+ },
2746
2771
};
2747
2772
2748
2773
Ok(PendingHTLCInfo {
2749
2774
routing: PendingHTLCRouting::Forward {
2750
2775
onion_packet: outgoing_packet,
2751
2776
short_channel_id,
2777
+ blinded: intro_node_blinding_pt.or(msg.blinding_point)
2778
+ .map(|bp| BlindedForward {
2779
+ inbound_blinding_point: bp,
2780
+ we_are_intro_node: intro_node_blinding_pt.is_some(),
2781
+ }),
2752
2782
},
2753
2783
payment_hash: msg.payment_hash,
2754
2784
incoming_shared_secret: shared_secret,
@@ -2939,6 +2969,15 @@ where
2939
2969
}
2940
2970
}
2941
2971
}
2972
+ macro_rules! return_blinded_htlc_err {
2973
+ ($msg: expr) => {
2974
+ if msg.blinding_point.is_some() {
2975
+ return_malformed_err!($msg, INVALID_ONION_BLINDING);
2976
+ } else {
2977
+ return_err!($msg, INVALID_ONION_BLINDING, [0; 32]);
2978
+ }
2979
+ }
2980
+ }
2942
2981
2943
2982
let next_hop = match onion_utils::decode_next_payment_hop(shared_secret,
2944
2983
&msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac, msg.payment_hash,
@@ -2962,6 +3001,39 @@ where
2962
3001
msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
2963
3002
(short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk))
2964
3003
},
3004
+ onion_utils::Hop::Forward {
3005
+ next_hop_data: msgs::InboundOnionPayload::BlindedForward {
3006
+ short_channel_id, ref payment_relay, ref payment_constraints,
3007
+ ..
3008
+ }, ..
3009
+ } => {
3010
+ let amt_to_forward =
3011
+ match msg.amount_msat.checked_mul(payment_relay.fee_proportional_millionths as u64)
3012
+ .map(|prop_fee| prop_fee / 1_000_000)
3013
+ .and_then(|fee| msg.amount_msat.checked_sub(fee))
3014
+ .and_then(|amt| amt.checked_sub(payment_relay.fee_base_msat as u64))
3015
+ {
3016
+ Some(a) => a,
3017
+ None => {
3018
+ return_blinded_htlc_err!("Over or underflow computing amt_to_forward for blinded forward");
3019
+ }
3020
+ };
3021
+ let outgoing_cltv_value =
3022
+ match msg.cltv_expiry.checked_sub(payment_relay.cltv_expiry_delta as u32) {
3023
+ Some(v) => v,
3024
+ None => {
3025
+ return_blinded_htlc_err!("Underflow computing cltv value for blinded forward");
3026
+ }
3027
+ };
3028
+ if amt_to_forward < payment_constraints.htlc_minimum_msat ||
3029
+ outgoing_cltv_value > payment_constraints.max_cltv_expiry
3030
+ {
3031
+ return_blinded_htlc_err!("amt_to_forward did not meet htlc_minimum_msat or outgoing_cltv_value exceeded max_cltv_expiry");
3032
+ }
3033
+ let next_packet_pk = onion_utils::next_hop_pubkey(&self.secp_ctx,
3034
+ msg.onion_routing_packet.public_key.unwrap(), &shared_secret);
3035
+ (short_channel_id, amt_to_forward, outgoing_cltv_value, Some(next_packet_pk))
3036
+ },
2965
3037
// We'll do receive checks in [`Self::construct_pending_htlc_info`] so we have access to the
2966
3038
// inbound channel's state.
2967
3039
onion_utils::Hop::Receive { .. } => return Ok((next_hop, shared_secret, None)),
@@ -3808,8 +3880,8 @@ where
3808
3880
})?;
3809
3881
3810
3882
let routing = match payment.forward_info.routing {
3811
- PendingHTLCRouting::Forward { onion_packet, .. } => {
3812
- PendingHTLCRouting::Forward { onion_packet, short_channel_id: next_hop_scid }
3883
+ PendingHTLCRouting::Forward { onion_packet, blinded, .. } => {
3884
+ PendingHTLCRouting::Forward { short_channel_id: next_hop_scid, onion_packet, blinded, }
3813
3885
},
3814
3886
_ => unreachable!() // Only `PendingHTLCRouting::Forward`s are intercepted
3815
3887
};
@@ -4008,7 +4080,8 @@ where
4008
4080
prev_short_channel_id, prev_htlc_id, prev_funding_outpoint, prev_user_channel_id,
4009
4081
forward_info: PendingHTLCInfo {
4010
4082
incoming_shared_secret, payment_hash, outgoing_amt_msat, outgoing_cltv_value,
4011
- routing: PendingHTLCRouting::Forward { onion_packet, .. }, skimmed_fee_msat, ..
4083
+ routing: PendingHTLCRouting::Forward { onion_packet, blinded, .. },
4084
+ skimmed_fee_msat, ..
4012
4085
},
4013
4086
}) => {
4014
4087
log_trace!(self.logger, "Adding HTLC from short id {} with payment_hash {} to channel with short id {} after delay", prev_short_channel_id, &payment_hash, short_chan_id);
@@ -4021,9 +4094,24 @@ where
4021
4094
// Phantom payments are only PendingHTLCRouting::Receive.
4022
4095
phantom_shared_secret: None,
4023
4096
});
4024
- if let Err(e) = chan.get_mut().queue_add_htlc(outgoing_amt_msat,
4025
- payment_hash, outgoing_cltv_value, htlc_source.clone(),
4026
- onion_packet, skimmed_fee_msat, None, &self.fee_estimator,
4097
+ let next_blinding_point = if let Some(b) = blinded {
4098
+ let encrypted_tlvs_ss = self.node_signer.ecdh(
4099
+ Recipient::Node, &b.inbound_blinding_point, None
4100
+ ).unwrap().secret_bytes();
4101
+ match onion_utils::next_hop_pubkey(&self.secp_ctx, b.inbound_blinding_point, &encrypted_tlvs_ss) {
4102
+ Ok(pk) => Some(pk),
4103
+ Err(_) => {
4104
+ failed_forwards.push((htlc_source, payment_hash,
4105
+ HTLCFailReason::reason(INVALID_ONION_BLINDING, vec![0; 32]),
4106
+ HTLCDestination::FailedPayment { payment_hash }
4107
+ ));
4108
+ continue;
4109
+ }
4110
+ }
4111
+ } else { None };
4112
+ if let Err(e) = chan.get_mut().queue_add_htlc(outgoing_amt_msat, payment_hash,
4113
+ outgoing_cltv_value, htlc_source.clone(), onion_packet, skimmed_fee_msat,
4114
+ next_blinding_point, &self.fee_estimator,
4027
4115
&self.logger)
4028
4116
{
4029
4117
if let ChannelError::Ignore(msg) = e {
@@ -7946,6 +8034,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting,
7946
8034
(0, Forward) => {
7947
8035
(0, onion_packet, required),
7948
8036
(2, short_channel_id, required),
8037
+ (4, blinded, option),
7949
8038
},
7950
8039
(1, Receive) => {
7951
8040
(0, payment_data, required),
@@ -7965,6 +8054,11 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting,
7965
8054
},
7966
8055
;);
7967
8056
8057
+ impl_writeable_tlv_based!(BlindedForward, {
8058
+ (0, inbound_blinding_point, required),
8059
+ (2, we_are_intro_node, required),
8060
+ });
8061
+
7968
8062
impl_writeable_tlv_based!(PendingHTLCInfo, {
7969
8063
(0, routing, required),
7970
8064
(2, incoming_shared_secret, required),
0 commit comments