Include HMAC and Nonce in payment::ReceiveTlvs

In order to authenticate a PaymentContext, an HMAC and Nonce must be
included along with it in payment::ReceiveTlvs. Compute the HMAC when
constructing a BlindedPaymentPath and include it in the recipient's
BlindedPaymentTlvs. Authentication will be added in an upcoming commit.
This commit is contained in:
Jeffrey Czyz 2024-12-01 16:23:27 -05:00
parent a29153025f
commit 55c02fdee1
No known key found for this signature in database
GPG key ID: 912EF12EA67705F5
9 changed files with 128 additions and 37 deletions

View file

@ -12,11 +12,13 @@ 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, ReceiveTlvs,
PaymentForwardNode, PaymentRelay, UnauthenticatedReceiveTlvs,
};
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;
@ -80,7 +82,9 @@ fn privkey(byte: u8) -> SecretKey {
fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
invoice_request: &InvoiceRequest, secp_ctx: &Secp256k1<T>,
) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> {
let expanded_key = ExpandedKey::new([42; 32]);
let entropy_source = Randomness {};
let nonce = Nonce::from_entropy_source(&entropy_source);
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: OfferId([42; 32]),
invoice_request: InvoiceRequestFields {
@ -92,7 +96,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
human_readable_name: None,
},
});
let payee_tlvs = ReceiveTlvs {
let payee_tlvs = UnauthenticatedReceiveTlvs {
payment_secret: PaymentSecret([42; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 1_000_000,
@ -100,6 +104,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
},
payment_context,
};
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
let intermediate_nodes = [PaymentForwardNode {
tlvs: ForwardTlvs {
short_channel_id: 43,
@ -109,7 +114,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
fee_base_msat: 1,
},
payment_constraints: PaymentConstraints {
max_cltv_expiry: payee_tlvs.payment_constraints.max_cltv_expiry + 40,
max_cltv_expiry: payee_tlvs.tlvs().payment_constraints.max_cltv_expiry + 40,
htlc_minimum_msat: 100,
},
features: BlindedHopFeatures::empty(),

View file

@ -12,10 +12,12 @@ use bitcoin::secp256k1::{self, Keypair, PublicKey, Secp256k1, SecretKey};
use core::convert::TryFrom;
use lightning::blinded_path::payment::{
BlindedPaymentPath, Bolt12RefundContext, ForwardTlvs, PaymentConstraints, PaymentContext,
PaymentForwardNode, PaymentRelay, ReceiveTlvs,
PaymentForwardNode, PaymentRelay, UnauthenticatedReceiveTlvs,
};
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;
@ -67,9 +69,11 @@ fn privkey(byte: u8) -> SecretKey {
fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
refund: &Refund, signing_pubkey: PublicKey, secp_ctx: &Secp256k1<T>,
) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> {
let expanded_key = ExpandedKey::new([42; 32]);
let entropy_source = Randomness {};
let nonce = Nonce::from_entropy_source(&entropy_source);
let payment_context = PaymentContext::Bolt12Refund(Bolt12RefundContext {});
let payee_tlvs = ReceiveTlvs {
let payee_tlvs = UnauthenticatedReceiveTlvs {
payment_secret: PaymentSecret([42; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 1_000_000,
@ -77,6 +81,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
},
payment_context,
};
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
let intermediate_nodes = [PaymentForwardNode {
tlvs: ForwardTlvs {
short_channel_id: 43,
@ -86,7 +91,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
fee_base_msat: 1,
},
payment_constraints: PaymentConstraints {
max_cltv_expiry: payee_tlvs.payment_constraints.max_cltv_expiry + 40,
max_cltv_expiry: payee_tlvs.tlvs().payment_constraints.max_cltv_expiry + 40,
htlc_minimum_msat: 100,
},
features: BlindedHopFeatures::empty(),

View file

@ -9,6 +9,8 @@
//! 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::{self, PublicKey, Secp256k1, SecretKey};
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp};
@ -18,10 +20,13 @@ use crate::io;
use crate::io::Cursor;
use crate::types::payment::PaymentSecret;
use crate::ln::channel_state::CounterpartyForwardingInfo;
use crate::ln::channelmanager::Verification;
use crate::types::features::BlindedHopFeatures;
use crate::ln::inbound_payment::ExpandedKey;
use crate::ln::msgs::DecodeError;
use crate::ln::onion_utils;
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};
@ -114,7 +119,7 @@ impl BlindedPaymentPath {
let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
let blinded_payinfo = compute_payinfo(
intermediate_nodes, &payee_tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta
intermediate_nodes, &payee_tlvs.tlvs, htlc_maximum_msat, min_final_cltv_expiry_delta
)?;
Ok(Self {
inner_path: BlindedPath {
@ -252,8 +257,26 @@ pub struct ForwardTlvs {
/// 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<Sha256>, 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.
@ -262,6 +285,17 @@ pub struct ReceiveTlvs {
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
@ -400,11 +434,23 @@ impl Writeable for ForwardTlvs {
}
impl Writeable for ReceiveTlvs {
fn write<W: Writer>(&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<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
encode_tlv_stream!(w, {
(12, self.payment_constraints, required),
(65536, self.payment_secret, required),
(65537, self.payment_context, required)
(65537, self.payment_context, required),
});
Ok(())
}
@ -432,6 +478,7 @@ impl Readable for BlindedPaymentTlvs {
(14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))),
(65536, payment_secret, option),
(65537, payment_context, (default_value, PaymentContext::unknown())),
(65539, authentication, option),
});
let _padding: Option<utils::Padding> = _padding;
@ -449,9 +496,12 @@ impl Readable for BlindedPaymentTlvs {
} else {
if payment_relay.is_some() || features.is_some() { return Err(DecodeError::InvalidValue) }
Ok(BlindedPaymentTlvs::Receive(ReceiveTlvs {
payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
payment_constraints: payment_constraints.0.unwrap(),
payment_context: payment_context.0.unwrap(),
tlvs: UnauthenticatedReceiveTlvs {
payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
payment_constraints: payment_constraints.0.unwrap(),
payment_context: payment_context.0.unwrap(),
},
authentication: authentication.ok_or(DecodeError::InvalidValue)?,
}))
}
}
@ -494,7 +544,7 @@ pub(crate) fn amt_to_forward_msat(inbound_amt_msat: u64, payment_relay: &Payment
}
pub(super) fn compute_payinfo(
intermediate_nodes: &[PaymentForwardNode], payee_tlvs: &ReceiveTlvs,
intermediate_nodes: &[PaymentForwardNode], payee_tlvs: &UnauthenticatedReceiveTlvs,
payee_htlc_maximum_msat: u64, min_final_cltv_expiry_delta: u16,
) -> Result<BlindedPayInfo, ()> {
let mut curr_base_fee: u64 = 0;
@ -631,7 +681,7 @@ impl_writeable_tlv_based!(Bolt12RefundContext, {});
#[cfg(test)]
mod tests {
use bitcoin::secp256k1::PublicKey;
use crate::blinded_path::payment::{PaymentForwardNode, ForwardTlvs, ReceiveTlvs, PaymentConstraints, PaymentContext, PaymentRelay};
use crate::blinded_path::payment::{PaymentForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, UnauthenticatedReceiveTlvs};
use crate::types::payment::PaymentSecret;
use crate::types::features::BlindedHopFeatures;
use crate::ln::functional_test_utils::TEST_FINAL_CLTV;
@ -676,7 +726,7 @@ mod tests {
},
htlc_maximum_msat: u64::max_value(),
}];
let recv_tlvs = ReceiveTlvs {
let recv_tlvs = UnauthenticatedReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,
@ -695,7 +745,7 @@ mod tests {
#[test]
fn compute_payinfo_1_hop() {
let recv_tlvs = ReceiveTlvs {
let recv_tlvs = UnauthenticatedReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,
@ -751,7 +801,7 @@ mod tests {
},
htlc_maximum_msat: u64::max_value()
}];
let recv_tlvs = ReceiveTlvs {
let recv_tlvs = UnauthenticatedReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,
@ -804,7 +854,7 @@ mod tests {
},
htlc_maximum_msat: u64::max_value()
}];
let recv_tlvs = ReceiveTlvs {
let recv_tlvs = UnauthenticatedReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,
@ -861,7 +911,7 @@ mod tests {
},
htlc_maximum_msat: 10_000
}];
let recv_tlvs = ReceiveTlvs {
let recv_tlvs = UnauthenticatedReceiveTlvs {
payment_secret: PaymentSecret([0; 32]),
payment_constraints: PaymentConstraints {
max_cltv_expiry: 0,

View file

@ -12,7 +12,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, PaymentForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, ReceiveTlvs};
use crate::blinded_path::payment::{BlindedPaymentPath, PaymentForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, UnauthenticatedReceiveTlvs};
use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PaymentFailureReason};
use crate::ln::types::ChannelId;
use crate::types::payment::{PaymentHash, PaymentSecret};
@ -28,6 +28,7 @@ use crate::ln::onion_utils;
use crate::ln::onion_utils::INVALID_ONION_BLINDING;
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};
use crate::sign::{NodeSigner, Recipient};
@ -70,7 +71,8 @@ fn blinded_payment_path(
.unwrap_or_else(|| channel_upds[idx - 1].htlc_maximum_msat),
});
}
let payee_tlvs = ReceiveTlvs {
let payee_tlvs = UnauthenticatedReceiveTlvs {
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
@ -79,6 +81,11 @@ fn blinded_payment_path(
},
payment_context: PaymentContext::unknown(),
};
let nonce = Nonce([42u8; 16]);
let expanded_key = keys_manager.get_inbound_payment_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,
@ -117,7 +124,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 = ReceiveTlvs {
let payee_tlvs = UnauthenticatedReceiveTlvs {
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
@ -125,6 +132,10 @@ fn do_one_hop_blinded_path(success: bool) {
},
payment_context: PaymentContext::unknown(),
};
let nonce = Nonce([42u8; 16]);
let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_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,
@ -161,7 +172,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 = ReceiveTlvs {
let payee_tlvs = UnauthenticatedReceiveTlvs {
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
@ -169,6 +180,9 @@ fn mpp_to_one_hop_blinded_path() {
},
payment_context: PaymentContext::unknown(),
};
let nonce = Nonce([42u8; 16]);
let expanded_key = chanmon_cfgs[3].keys_manager.get_inbound_payment_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,
&chanmon_cfgs[3].keys_manager, &secp_ctx
@ -303,7 +317,7 @@ fn do_forward_checks_failure(check: ForwardCheckFail, intro_fails: bool) {
let mut route_params = get_blinded_route_parameters(amt_msat, payment_secret, 1, 1_0000_0000,
nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(),
&[&chan_upd_1_2, &chan_upd_2_3], &chanmon_cfgs[3].keys_manager);
route_params.payment_params.max_path_length = 18;
route_params.payment_params.max_path_length = 17;
let route = get_route(&nodes[0], &route_params).unwrap();
node_cfgs[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
@ -1366,7 +1380,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 = ReceiveTlvs {
let payee_tlvs = UnauthenticatedReceiveTlvs {
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
@ -1374,6 +1388,9 @@ fn custom_tlvs_to_blinded_path() {
},
payment_context: PaymentContext::unknown(),
};
let nonce = Nonce([42u8; 16]);
let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_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,

View file

@ -36,7 +36,7 @@ use crate::events::FundingInfo;
use crate::blinded_path::message::{AsyncPaymentsContext, MessageContext, OffersContext};
use crate::blinded_path::NodeIdLookUp;
use crate::blinded_path::message::{BlindedMessagePath, MessageForwardNode};
use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, ReceiveTlvs};
use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, UnauthenticatedReceiveTlvs};
use crate::chain;
use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
@ -480,7 +480,7 @@ impl Verification for PaymentHash {
}
}
impl Verification for ReceiveTlvs {
impl Verification for UnauthenticatedReceiveTlvs {
fn hmac_for_offer_payment(
&self, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey,
) -> Hmac<Sha256> {
@ -10490,13 +10490,16 @@ where
fn create_blinded_payment_paths(
&self, amount_msats: u64, payment_secret: PaymentSecret, payment_context: PaymentContext
) -> Result<Vec<BlindedPaymentPath>, ()> {
let expanded_key = &self.inbound_payment_key;
let entropy = &*self.entropy_source;
let secp_ctx = &self.secp_ctx;
let first_hops = self.list_usable_channels();
let payee_node_id = self.get_our_node_id();
let max_cltv_expiry = self.best_block.read().unwrap().height + CLTV_FAR_FAR_AWAY
+ LATENCY_GRACE_PERIOD_BLOCKS;
let payee_tlvs = ReceiveTlvs {
let payee_tlvs = UnauthenticatedReceiveTlvs {
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry,
@ -10504,6 +10507,9 @@ where
},
payment_context,
};
let nonce = Nonce::from_entropy_source(entropy);
let payee_tlvs = payee_tlvs.authenticate(nonce, expanded_key);
self.router.create_blinded_payment_paths(
payee_node_id, first_hops, payee_tlvs, amount_msats, secp_ctx
)

View file

@ -12,7 +12,7 @@
use bitcoin::secp256k1::{Secp256k1, PublicKey};
use crate::blinded_path::BlindedHop;
use crate::blinded_path::payment::{BlindedPayInfo, BlindedPaymentPath, PaymentConstraints, PaymentContext, ReceiveTlvs};
use crate::blinded_path::payment::{BlindedPayInfo, BlindedPaymentPath, PaymentConstraints, PaymentContext, UnauthenticatedReceiveTlvs};
use crate::events::{Event, MessageSendEventsProvider};
use crate::types::payment::PaymentSecret;
use crate::ln::blinded_payment_tests::get_blinded_route_parameters;
@ -24,8 +24,10 @@ use crate::ln::msgs::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::{DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, PaymentParameters, RouteParameters};
use crate::sign::NodeSigner;
use crate::util::errors::APIError;
use crate::util::ser::Writeable;
use crate::util::test_utils;
@ -157,7 +159,7 @@ fn one_hop_blinded_path_with_custom_tlv() {
// Construct the route parameters for sending to nodes[2]'s 1-hop blinded path.
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 = ReceiveTlvs {
let payee_tlvs = UnauthenticatedReceiveTlvs {
payment_secret,
payment_constraints: PaymentConstraints {
max_cltv_expiry: u32::max_value(),
@ -165,6 +167,9 @@ fn one_hop_blinded_path_with_custom_tlv() {
},
payment_context: PaymentContext::unknown(),
};
let nonce = Nonce([42u8; 16]);
let expanded_key = chanmon_cfgs[2].keys_manager.get_inbound_payment_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(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,

View file

@ -31,7 +31,7 @@ use bitcoin::{secp256k1, Witness};
use bitcoin::script::ScriptBuf;
use bitcoin::hash_types::Txid;
use crate::blinded_path::payment::{BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs};
use crate::blinded_path::payment::{BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs, UnauthenticatedReceiveTlvs};
use crate::ln::types::ChannelId;
use crate::types::payment::{PaymentPreimage, PaymentHash, PaymentSecret};
use crate::types::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
@ -2907,9 +2907,11 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
next_blinding_override,
})
},
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs {
payment_secret, payment_constraints, payment_context
})} => {
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(receive_tlvs) } => {
let ReceiveTlvs { tlvs, authentication: _ } = receive_tlvs;
let UnauthenticatedReceiveTlvs {
payment_secret, payment_constraints, payment_context,
} = tlvs;
if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
Ok(Self::BlindedReceive {
sender_intended_htlc_amt_msat: amt.ok_or(DecodeError::InvalidValue)?,

View file

@ -16,7 +16,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey, self};
use types::payment::PaymentHash;
use core::fmt;
use crate::blinded_path::payment::ReceiveTlvs;
use crate::blinded_path::payment::UnauthenticatedReceiveTlvs;
use crate::ln::channelmanager::PaymentId;
use crate::ln::inbound_payment::{ExpandedKey, IV_LEN};
use crate::offers::merkle::TlvRecord;
@ -465,7 +465,7 @@ fn hmac_for_payment_id(
}
pub(crate) fn hmac_for_payment_tlvs(
receive_tlvs: &ReceiveTlvs, nonce: Nonce, expanded_key: &ExpandedKey,
receive_tlvs: &UnauthenticatedReceiveTlvs, nonce: Nonce, expanded_key: &ExpandedKey,
) -> Hmac<Sha256> {
const IV_BYTES: &[u8; IV_LEN] = b"LDK Payment TLVs";
let mut hmac = expanded_key.hmac_for_offer();
@ -478,7 +478,8 @@ pub(crate) fn hmac_for_payment_tlvs(
}
pub(crate) fn verify_payment_tlvs(
receive_tlvs: &ReceiveTlvs, hmac: Hmac<Sha256>, nonce: Nonce, expanded_key: &ExpandedKey,
receive_tlvs: &UnauthenticatedReceiveTlvs, hmac: Hmac<Sha256>, nonce: Nonce,
expanded_key: &ExpandedKey,
) -> Result<(), ()> {
if hmac_for_payment_tlvs(receive_tlvs, nonce, expanded_key) == hmac { Ok(()) } else { Err(()) }
}

View file

@ -145,7 +145,7 @@ impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, ES: Deref, S: Deref, SP: Size
let cltv_expiry_delta = payment_relay.cltv_expiry_delta as u32;
let payment_constraints = PaymentConstraints {
max_cltv_expiry: tlvs.payment_constraints.max_cltv_expiry + cltv_expiry_delta,
max_cltv_expiry: tlvs.tlvs().payment_constraints.max_cltv_expiry + cltv_expiry_delta,
htlc_minimum_msat: details.inbound_htlc_minimum_msat.unwrap_or(0),
};
Some(PaymentForwardNode {