X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fonion_payment.rs;h=5ea07cfab30db4325bc71415f1b3f331ca1a37dc;hb=a2b4813c1f9421e3074145bf0ffd67e8636692a6;hp=ca15a37c072d89625a0a235fb226d170f758cdb4;hpb=37150b4d697f723f278b6cf3f63892df272b9aa5;p=rust-lightning diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs index ca15a37c..5ea07cfa 100644 --- a/lightning/src/ln/onion_payment.rs +++ b/lightning/src/ln/onion_payment.rs @@ -1,10 +1,12 @@ -//! Utilities for channelmanager.rs +//! Utilities to decode payment onions and do contextless validation of incoming payments. //! -//! Includes a public [`peel_payment_onion`] function for use by external projects or libraries. +//! 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}; @@ -110,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, current_height: u32, accept_mpp_keysend: bool, ) -> Result { - 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 { @@ -206,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 { @@ -225,7 +233,9 @@ pub(super) fn create_recv_pending_htlc_info( }) } -/// Peel one layer off an incoming onion, returning [`PendingHTLCInfo`] (either Forward or Receive). +/// Peel one layer off an incoming onion, returning a [`PendingHTLCInfo`] that contains information +/// about the intended next-hop for the HTLC. +/// /// This does all the relevant context-free checks that LDK requires for payment relay or /// acceptance. If the payment is to be received, and the amount matches the expected amount for /// a given invoice, this indicates the [`msgs::UpdateAddHTLC`], once fully committed in the @@ -234,7 +244,7 @@ pub(super) fn create_recv_pending_htlc_info( /// [`Event::PaymentClaimable`]: crate::events::Event::PaymentClaimable pub fn peel_payment_onion( msg: &msgs::UpdateAddHTLC, node_signer: &NS, logger: &L, secp_ctx: &Secp256k1, - cur_height: u32, accept_mpp_keysend: bool, + cur_height: u32, accept_mpp_keysend: bool, allow_skimmed_fees: bool, ) -> Result where NS::Target: NodeSigner, @@ -273,6 +283,10 @@ where err_data: Vec::new(), }); } + + // TODO: If this is potentially a phantom payment we should decode the phantom payment + // onion here and check it. + create_fwd_pending_htlc_info( msg, next_hop_data, next_hop_hmac, new_packet_bytes, shared_secret, Some(next_packet_pubkey) @@ -281,7 +295,7 @@ where onion_utils::Hop::Receive(received_data) => { create_recv_pending_htlc_info( received_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry, - None, false, msg.skimmed_fee_msat, cur_height, accept_mpp_keysend, + None, allow_skimmed_fees, msg.skimmed_fee_msat, cur_height, accept_mpp_keysend, )? } }) @@ -319,8 +333,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::::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 { @@ -348,7 +368,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 }) => { @@ -477,7 +497,7 @@ mod tests { let msg = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, onion); let logger = test_utils::TestLogger::with_id("bob".to_string()); - let peeled = peel_payment_onion(&msg, &&bob, &&logger, &secp_ctx, cur_height, true) + let peeled = peel_payment_onion(&msg, &&bob, &&logger, &secp_ctx, cur_height, true, false) .map_err(|e| e.msg).unwrap(); let next_onion = match peeled.routing { @@ -488,7 +508,7 @@ mod tests { }; let msg2 = make_update_add_msg(amount_msat, cltv_expiry, payment_hash, next_onion); - let peeled2 = peel_payment_onion(&msg2, &&charlie, &&logger, &secp_ctx, cur_height, true) + let peeled2 = peel_payment_onion(&msg2, &&charlie, &&logger, &secp_ctx, cur_height, true, false) .map_err(|e| e.msg).unwrap(); match peeled2.routing {