Fix blinded recipient fail on receive reqs violation
[rust-lightning] / lightning / src / ln / onion_payment.rs
index 06a9ae07e1e0024c075082711d9064278227cf5a..c92c8fd24cd670c1fa5e82c73ca130568b5a1542 100644 (file)
@@ -3,9 +3,10 @@
 //! Primarily features [`peel_payment_onion`], which allows the decoding of an onion statelessly
 //! and can be used to predict whether we'd accept a payment.
 
-use bitcoin::hashes::Hash;
+use bitcoin::hashes::{Hash, HashEngine};
+use bitcoin::hashes::hmac::{Hmac, HmacEngine};
 use bitcoin::hashes::sha256::Hash as Sha256;
-use bitcoin::secp256k1::{self, Secp256k1, PublicKey};
+use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1};
 
 use crate::blinded_path;
 use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay};
@@ -111,16 +112,21 @@ pub(super) fn create_recv_pending_htlc_info(
        amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>, allow_underpay: bool,
        counterparty_skimmed_fee_msat: Option<u64>, current_height: u32, accept_mpp_keysend: bool,
 ) -> Result<PendingHTLCInfo, InboundOnionErr> {
-       let (payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, outgoing_cltv_value, payment_metadata) = match hop_data {
+       let (
+               payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, outgoing_cltv_value,
+               payment_metadata, requires_blinded_error
+       ) = match hop_data {
                msgs::InboundOnionPayload::Receive {
                        payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata, ..
                } =>
-                       (payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata),
+                       (payment_data, keysend_preimage, custom_tlvs, amt_msat, outgoing_cltv_value, payment_metadata,
+                        false),
                msgs::InboundOnionPayload::BlindedReceive {
-                       amt_msat, total_msat, outgoing_cltv_value, payment_secret, ..
+                       amt_msat, total_msat, outgoing_cltv_value, payment_secret, intro_node_blinding_point, ..
                } => {
                        let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
-                       (Some(payment_data), None, Vec::new(), amt_msat, outgoing_cltv_value, None)
+                       (Some(payment_data), None, Vec::new(), amt_msat, outgoing_cltv_value, None,
+                        intro_node_blinding_point.is_none())
                }
                msgs::InboundOnionPayload::Forward { .. } => {
                        return Err(InboundOnionErr {
@@ -207,6 +213,7 @@ pub(super) fn create_recv_pending_htlc_info(
                        incoming_cltv_expiry: outgoing_cltv_value,
                        phantom_shared_secret,
                        custom_tlvs,
+                       requires_blinded_error,
                }
        } else {
                return Err(InboundOnionErr {
@@ -312,11 +319,16 @@ where
                ($msg: expr, $err_code: expr) => {
                        {
                                log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
+                               let (sha256_of_onion, failure_code) = if msg.blinding_point.is_some() {
+                                       ([0; 32], INVALID_ONION_BLINDING)
+                               } else {
+                                       (Sha256::hash(&msg.onion_routing_packet.hop_data).to_byte_array(), $err_code)
+                               };
                                return Err(HTLCFailureMsg::Malformed(msgs::UpdateFailMalformedHTLC {
                                        channel_id: msg.channel_id,
                                        htlc_id: msg.htlc_id,
-                                       sha256_of_onion: Sha256::hash(&msg.onion_routing_packet.hop_data).to_byte_array(),
-                                       failure_code: $err_code,
+                                       sha256_of_onion,
+                                       failure_code,
                                }));
                        }
                }
@@ -326,8 +338,14 @@ where
                return_malformed_err!("invalid ephemeral pubkey", 0x8000 | 0x4000 | 6);
        }
 
+       let blinded_node_id_tweak = msg.blinding_point.map(|bp| {
+               let blinded_tlvs_ss = node_signer.ecdh(Recipient::Node, &bp, None).unwrap().secret_bytes();
+               let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
+               hmac.input(blinded_tlvs_ss.as_ref());
+               Scalar::from_be_bytes(Hmac::from_engine(hmac).to_byte_array()).unwrap()
+       });
        let shared_secret = node_signer.ecdh(
-               Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), None
+               Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), blinded_node_id_tweak.as_ref()
        ).unwrap().secret_bytes();
 
        if msg.onion_routing_packet.version != 0 {
@@ -342,6 +360,10 @@ where
        macro_rules! return_err {
                ($msg: expr, $err_code: expr, $data: expr) => {
                        {
+                               if msg.blinding_point.is_some() {
+                                       return_malformed_err!($msg, INVALID_ONION_BLINDING)
+                               }
+
                                log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg);
                                return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC {
                                        channel_id: msg.channel_id,
@@ -355,7 +377,7 @@ where
 
        let next_hop = match onion_utils::decode_next_payment_hop(
                shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
-               msg.payment_hash, node_signer
+               msg.payment_hash, msg.blinding_point, node_signer
        ) {
                Ok(res) => res,
                Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {