From bd0dd9b9a8cf21e77ad8aa5209ee3fbd0f43d0ce Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Sun, 1 Dec 2024 15:48:47 -0500 Subject: [PATCH 01/10] HMAC construction/verification for ReceiveTlvs When receiving a PaymentContext from a blinded payment, the context must be authenticated. Otherwise, the context can be forged and would appear within a PaymentPurpose. Add functions for constructing and verifying an HMAC for the ReceiveTlvs, which contains the PaymentContext. --- lightning/src/ln/channelmanager.rs | 14 ++++++++++++++ lightning/src/offers/signer.rs | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 53c190d36a0..bc63ef29404 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -480,6 +480,20 @@ impl Verification for PaymentHash { } } +impl Verification for ReceiveTlvs { + fn hmac_for_offer_payment( + &self, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, + ) -> Hmac { + signer::hmac_for_payment_tlvs(self, nonce, expanded_key) + } + + fn verify_for_offer_payment( + &self, hmac: Hmac, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, + ) -> Result<(), ()> { + signer::verify_payment_tlvs(self, hmac, nonce, expanded_key) + } +} + /// A user-provided identifier in [`ChannelManager::send_payment`] used to uniquely identify /// a payment and ensure idempotency in LDK. /// diff --git a/lightning/src/offers/signer.rs b/lightning/src/offers/signer.rs index d8caa2175fe..aee79175f5f 100644 --- a/lightning/src/offers/signer.rs +++ b/lightning/src/offers/signer.rs @@ -16,6 +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::ln::channelmanager::PaymentId; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN}; use crate::offers::merkle::TlvRecord; @@ -46,6 +47,9 @@ const ASYNC_PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[6; 16]; // HMAC input for a `PaymentHash`. The HMAC is used in `OffersContext::InboundPayment`. const PAYMENT_HASH_HMAC_INPUT: &[u8; 16] = &[7; 16]; +// HMAC input for `ReceiveTlvs`. The HMAC is used in `blinded_path::payment::PaymentContext`. +const PAYMENT_TLVS_HMAC_INPUT: &[u8; 16] = &[8; 16]; + /// Message metadata which possibly is derived from [`MetadataMaterial`] such that it can be /// verified. #[derive(Clone)] @@ -459,3 +463,22 @@ fn hmac_for_payment_id( Hmac::from_engine(hmac) } + +pub(crate) fn hmac_for_payment_tlvs( + receive_tlvs: &ReceiveTlvs, nonce: Nonce, expanded_key: &ExpandedKey, +) -> Hmac { + const IV_BYTES: &[u8; IV_LEN] = b"LDK Payment TLVs"; + let mut hmac = expanded_key.hmac_for_offer(); + hmac.input(IV_BYTES); + hmac.input(&nonce.0); + hmac.input(PAYMENT_TLVS_HMAC_INPUT); + receive_tlvs.write(&mut hmac).unwrap(); + + Hmac::from_engine(hmac) +} + +pub(crate) fn verify_payment_tlvs( + receive_tlvs: &ReceiveTlvs, hmac: Hmac, nonce: Nonce, expanded_key: &ExpandedKey, +) -> Result<(), ()> { + if hmac_for_payment_tlvs(receive_tlvs, nonce, expanded_key) == hmac { Ok(()) } else { Err(()) } +} From 09bec6eee98ddfd9472b5d31721e4256d8442db1 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 4 Dec 2024 15:55:30 -0600 Subject: [PATCH 02/10] Return ExpandedKey from NodeSigner NodeSinger::get_inbound_payment_key_material returns KeyMaterial, which is used for constructing an ExpandedKey. Change the trait to return an ExpandedKey directly instead. This allows for direct access to the ExpandedKey when a NodeSigner referenced is available. Otherwise, it would either need to be reconstructed or passed in separately. --- fuzz/src/chanmon_consistency.rs | 5 +++-- fuzz/src/full_stack.rs | 10 +++++----- fuzz/src/onion_message.rs | 5 +++-- lightning/src/ln/blinded_payment_tests.rs | 13 +++++-------- lightning/src/ln/channelmanager.rs | 8 +++----- lightning/src/ln/inbound_payment.rs | 17 ++++++++--------- lightning/src/ln/invoice_utils.rs | 5 ++--- lightning/src/ln/offers_tests.rs | 3 +-- lightning/src/sign/mod.rs | 17 +++++++++-------- lightning/src/util/test_utils.rs | 7 ++++--- 10 files changed, 43 insertions(+), 47 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 421a0d09a48..8859e5ce644 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -50,6 +50,7 @@ use lightning::ln::channelmanager::{ ChainParameters, ChannelManager, ChannelManagerReadArgs, PaymentId, RecipientOnionFields, Retry, }; use lightning::ln::functional_test_utils::*; +use lightning::ln::inbound_payment::ExpandedKey; use lightning::ln::msgs::{ self, ChannelMessageHandler, CommitmentUpdate, DecodeError, Init, UpdateAddHTLC, }; @@ -334,10 +335,10 @@ impl NodeSigner for KeyProvider { Ok(SharedSecret::new(other_key, &node_secret)) } - fn get_inbound_payment_key_material(&self) -> KeyMaterial { + fn get_inbound_payment_key(&self) -> ExpandedKey { #[rustfmt::skip] let random_bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, self.node_secret[31]]; - KeyMaterial(random_bytes) + ExpandedKey::new(&KeyMaterial(random_bytes)) } fn sign_invoice( diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index f9570841ab2..d48a7466e37 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -43,6 +43,7 @@ use lightning::ln::channelmanager::{ ChainParameters, ChannelManager, InterceptId, PaymentId, RecipientOnionFields, Retry, }; use lightning::ln::functional_test_utils::*; +use lightning::ln::inbound_payment::ExpandedKey; use lightning::ln::msgs::{self, DecodeError}; use lightning::ln::peer_handler::{ IgnoringMessageHandler, MessageHandler, PeerManager, SocketDescriptor, @@ -79,7 +80,6 @@ use bitcoin::secp256k1::{self, Message, PublicKey, Scalar, Secp256k1, SecretKey} use std::cell::RefCell; use std::cmp; -use std::convert::TryInto; use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; @@ -364,7 +364,7 @@ impl<'a> Drop for MoneyLossDetector<'a> { struct KeyProvider { node_secret: SecretKey, - inbound_payment_key: KeyMaterial, + inbound_payment_key: ExpandedKey, counter: AtomicU64, signer_state: RefCell>)>>, } @@ -402,8 +402,8 @@ impl NodeSigner for KeyProvider { Ok(SharedSecret::new(other_key, &node_secret)) } - fn get_inbound_payment_key_material(&self) -> KeyMaterial { - self.inbound_payment_key.clone() + fn get_inbound_payment_key(&self) -> ExpandedKey { + self.inbound_payment_key } fn sign_invoice( @@ -636,7 +636,7 @@ pub fn do_test(mut data: &[u8], logger: &Arc) { let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone(), - inbound_payment_key: KeyMaterial(inbound_payment_key.try_into().unwrap()), + inbound_payment_key: ExpandedKey::new(&KeyMaterial(inbound_payment_key)), counter: AtomicU64::new(0), signer_state: RefCell::new(new_hash_map()), }); diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs index 59255d0a0e9..94da4d09be5 100644 --- a/fuzz/src/onion_message.rs +++ b/fuzz/src/onion_message.rs @@ -9,6 +9,7 @@ use lightning::blinded_path::message::{ AsyncPaymentsContext, BlindedMessagePath, MessageContext, OffersContext, }; use lightning::blinded_path::EmptyNodeIdLookUp; +use lightning::ln::inbound_payment::ExpandedKey; use lightning::ln::msgs::{self, DecodeError, OnionMessageHandler}; use lightning::ln::peer_handler::IgnoringMessageHandler; use lightning::ln::script::ShutdownScript; @@ -22,7 +23,7 @@ use lightning::onion_message::messenger::{ }; use lightning::onion_message::offers::{OffersMessage, OffersMessageHandler}; use lightning::onion_message::packet::OnionMessageContents; -use lightning::sign::{EntropySource, KeyMaterial, NodeSigner, Recipient, SignerProvider}; +use lightning::sign::{EntropySource, NodeSigner, Recipient, SignerProvider}; use lightning::types::features::InitFeatures; use lightning::util::logger::Logger; use lightning::util::ser::{Readable, Writeable, Writer}; @@ -223,7 +224,7 @@ impl NodeSigner for KeyProvider { Ok(SharedSecret::new(other_key, &node_secret)) } - fn get_inbound_payment_key_material(&self) -> KeyMaterial { + fn get_inbound_payment_key(&self) -> ExpandedKey { unreachable!() } diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 5af098a68d9..f2548341b83 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -20,6 +20,7 @@ use crate::ln::channelmanager; use crate::ln::channelmanager::{HTLCFailureMsg, PaymentId, RecipientOnionFields}; use crate::types::features::{BlindedHopFeatures, ChannelFeatures, NodeFeatures}; use crate::ln::functional_test_utils::*; +use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs; use crate::ln::msgs::{ChannelMessageHandler, UnsignedGossipMessage}; use crate::ln::onion_payment; @@ -29,7 +30,7 @@ use crate::ln::outbound_payment::{Retry, IDEMPOTENCY_TIMEOUT_TICKS}; use crate::offers::invoice::UnsignedBolt12Invoice; use crate::prelude::*; use crate::routing::router::{BlindedTail, Path, Payee, PaymentParameters, RouteHop, RouteParameters}; -use crate::sign::{KeyMaterial, NodeSigner, Recipient}; +use crate::sign::{NodeSigner, Recipient}; use crate::util::config::UserConfig; use crate::util::ser::WithoutLength; use crate::util::test_utils; @@ -1221,9 +1222,7 @@ fn blinded_keysend() { create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0); let chan_upd_1_2 = create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0).0.contents; - let inbound_payment_key = inbound_payment::ExpandedKey::new( - &nodes[2].keys_manager.get_inbound_payment_key_material() - ); + let inbound_payment_key = nodes[2].keys_manager.get_inbound_payment_key(); let payment_secret = inbound_payment::create_for_spontaneous_payment( &inbound_payment_key, None, u32::MAX, nodes[2].node.duration_since_epoch().as_secs(), None ).unwrap(); @@ -1262,9 +1261,7 @@ fn blinded_mpp_keysend() { let chan_1_3 = create_announced_chan_between_nodes(&nodes, 1, 3); let chan_2_3 = create_announced_chan_between_nodes(&nodes, 2, 3); - let inbound_payment_key = inbound_payment::ExpandedKey::new( - &nodes[3].keys_manager.get_inbound_payment_key_material() - ); + let inbound_payment_key = nodes[3].keys_manager.get_inbound_payment_key(); let payment_secret = inbound_payment::create_for_spontaneous_payment( &inbound_payment_key, None, u32::MAX, nodes[3].node.duration_since_epoch().as_secs(), None ).unwrap(); @@ -1528,7 +1525,7 @@ fn route_blinding_spec_test_vector() { } Ok(SharedSecret::new(other_key, &node_secret)) } - fn get_inbound_payment_key_material(&self) -> KeyMaterial { unreachable!() } + fn get_inbound_payment_key(&self) -> ExpandedKey { unreachable!() } fn get_node_id(&self, _recipient: Recipient) -> Result { unreachable!() } fn sign_invoice( &self, _invoice: &RawBolt11Invoice, _recipient: Recipient, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index bc63ef29404..04275a708bf 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -233,7 +233,7 @@ pub enum PendingHTLCRouting { requires_blinded_error: bool, /// Set if we are receiving a keysend to a blinded path, meaning we created the /// [`PaymentSecret`] and should verify it using our - /// [`NodeSigner::get_inbound_payment_key_material`]. + /// [`NodeSigner::get_inbound_payment_key`]. has_recipient_created_payment_secret: bool, }, } @@ -3494,8 +3494,7 @@ where ) -> Self { let mut secp_ctx = Secp256k1::new(); secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes()); - let inbound_pmt_key_material = node_signer.get_inbound_payment_key_material(); - let expanded_inbound_key = inbound_payment::ExpandedKey::new(&inbound_pmt_key_material); + let expanded_inbound_key = node_signer.get_inbound_payment_key(); ChannelManager { default_configuration: config.clone(), chain_hash: ChainHash::using_genesis_block(params.network), @@ -13902,8 +13901,7 @@ where }, None)); } - let inbound_pmt_key_material = args.node_signer.get_inbound_payment_key_material(); - let expanded_inbound_key = inbound_payment::ExpandedKey::new(&inbound_pmt_key_material); + let expanded_inbound_key = args.node_signer.get_inbound_payment_key(); let mut claimable_payments = hash_map_with_capacity(claimable_htlcs_list.len()); if let Some(purposes) = claimable_htlc_purposes { diff --git a/lightning/src/ln/inbound_payment.rs b/lightning/src/ln/inbound_payment.rs index 5b8d48e1c74..7ecbf0c4435 100644 --- a/lightning/src/ln/inbound_payment.rs +++ b/lightning/src/ln/inbound_payment.rs @@ -37,10 +37,10 @@ const AMT_MSAT_LEN: usize = 8; // retrieve said payment type bits. const METHOD_TYPE_OFFSET: usize = 5; -/// A set of keys that were HKDF-expanded from an initial call to -/// [`NodeSigner::get_inbound_payment_key_material`]. +/// A set of keys that were HKDF-expanded. Returned by [`NodeSigner::get_inbound_payment_key`]. /// -/// [`NodeSigner::get_inbound_payment_key_material`]: crate::sign::NodeSigner::get_inbound_payment_key_material +/// [`NodeSigner::get_inbound_payment_key`]: crate::sign::NodeSigner::get_inbound_payment_key +#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] pub struct ExpandedKey { /// The key used to encrypt the bytes containing the payment metadata (i.e. the amount and /// expiry, included for payment verification on decryption). @@ -129,9 +129,8 @@ fn min_final_cltv_expiry_delta_from_metadata(bytes: [u8; METADATA_LEN]) -> u16 { /// `ChannelManager` is required. Useful for generating invoices for [phantom node payments] without /// a `ChannelManager`. /// -/// `keys` is generated by calling [`NodeSigner::get_inbound_payment_key_material`] and then -/// calling [`ExpandedKey::new`] with its result. It is recommended to cache this value and not -/// regenerate it for each new inbound payment. +/// `keys` is generated by calling [`NodeSigner::get_inbound_payment_key`]. It is recommended to +/// cache this value and not regenerate it for each new inbound payment. /// /// `current_time` is a Unix timestamp representing the current time. /// @@ -139,7 +138,7 @@ fn min_final_cltv_expiry_delta_from_metadata(bytes: [u8; METADATA_LEN]) -> u16 { /// on versions of LDK prior to 0.0.114. /// /// [phantom node payments]: crate::sign::PhantomKeysManager -/// [`NodeSigner::get_inbound_payment_key_material`]: crate::sign::NodeSigner::get_inbound_payment_key_material +/// [`NodeSigner::get_inbound_payment_key`]: crate::sign::NodeSigner::get_inbound_payment_key pub fn create(keys: &ExpandedKey, min_value_msat: Option, invoice_expiry_delta_secs: u32, entropy_source: &ES, current_time: u64, min_final_cltv_expiry_delta: Option) -> Result<(PaymentHash, PaymentSecret), ()> @@ -281,7 +280,7 @@ fn construct_payment_secret(iv_bytes: &[u8; IV_LEN], metadata_bytes: &[u8; METAD /// For payments including a custom `min_final_cltv_expiry_delta`, the metadata is constructed as: /// payment method (3 bits) || payment amount (8 bytes - 3 bits) || min_final_cltv_expiry_delta (2 bytes) || expiry (6 bytes) /// -/// In both cases the result is then encrypted using a key derived from [`NodeSigner::get_inbound_payment_key_material`]. +/// In both cases the result is then encrypted using a key derived from [`NodeSigner::get_inbound_payment_key`]. /// /// Then on payment receipt, we verify in this method that the payment preimage and payment secret /// match what was constructed. @@ -302,7 +301,7 @@ fn construct_payment_secret(iv_bytes: &[u8; IV_LEN], metadata_bytes: &[u8; METAD /// /// See [`ExpandedKey`] docs for more info on the individual keys used. /// -/// [`NodeSigner::get_inbound_payment_key_material`]: crate::sign::NodeSigner::get_inbound_payment_key_material +/// [`NodeSigner::get_inbound_payment_key`]: crate::sign::NodeSigner::get_inbound_payment_key /// [`create_inbound_payment`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment /// [`create_inbound_payment_for_hash`]: crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash pub(super) fn verify(payment_hash: PaymentHash, payment_data: &msgs::FinalOnionHopData, diff --git a/lightning/src/ln/invoice_utils.rs b/lightning/src/ln/invoice_utils.rs index 07e108dab06..5be0b3f4b97 100644 --- a/lightning/src/ln/invoice_utils.rs +++ b/lightning/src/ln/invoice_utils.rs @@ -12,7 +12,7 @@ use crate::sign::{Recipient, NodeSigner, SignerProvider, EntropySource}; use crate::types::payment::PaymentHash; use crate::ln::channel_state::ChannelDetails; use crate::ln::channelmanager::{Bolt11InvoiceParameters, ChannelManager, PhantomRouteHints, MIN_CLTV_EXPIRY_DELTA, MIN_FINAL_CLTV_EXPIRY_DELTA}; -use crate::ln::inbound_payment::{create, create_from_hash, ExpandedKey}; +use crate::ln::inbound_payment::{create, create_from_hash}; use crate::routing::gossip::RoutingFees; use crate::routing::router::{RouteHint, RouteHintHop, Router}; use crate::onion_message::messenger::MessageRouter; @@ -165,8 +165,7 @@ where Bolt11InvoiceDescription::Hash(hash) => InvoiceBuilder::new(network).description_hash(hash.0), }; - // If we ever see performance here being too slow then we should probably take this ExpandedKey as a parameter instead. - let keys = ExpandedKey::new(&node_signer.get_inbound_payment_key_material()); + let keys = node_signer.get_inbound_payment_key(); let (payment_hash, payment_secret) = if let Some(payment_hash) = payment_hash { let payment_secret = create_from_hash( &keys, diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs index a7eeebf9848..6455a60b139 100644 --- a/lightning/src/ln/offers_tests.rs +++ b/lightning/src/ln/offers_tests.rs @@ -51,7 +51,6 @@ use crate::events::{ClosureReason, Event, MessageSendEventsProvider, PaymentFail use crate::ln::channelmanager::{Bolt12PaymentError, MAX_SHORT_LIVED_RELATIVE_EXPIRY, PaymentId, RecentPaymentDetails, Retry, self}; use crate::types::features::Bolt12InvoiceFeatures; use crate::ln::functional_test_utils::*; -use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs::{ChannelMessageHandler, Init, NodeAnnouncement, OnionMessage, OnionMessageHandler, RoutingMessageHandler, SocketAddress, UnsignedGossipMessage, UnsignedNodeAnnouncement}; use crate::ln::outbound_payment::IDEMPOTENCY_TIMEOUT_TICKS; use crate::offers::invoice::Bolt12Invoice; @@ -2218,7 +2217,7 @@ fn fails_paying_invoice_with_unknown_required_features() { let payment_paths = invoice.payment_paths().to_vec(); let payment_hash = invoice.payment_hash(); - let expanded_key = ExpandedKey::new(&alice.keys_manager.get_inbound_payment_key_material()); + let expanded_key = alice.keys_manager.get_inbound_payment_key(); let secp_ctx = Secp256k1::new(); let created_at = alice.node.duration_since_epoch(); diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index ed4f296b783..8bed5aaf132 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -51,6 +51,7 @@ use crate::ln::channel_keys::{ add_public_key_tweak, DelayedPaymentBasepoint, DelayedPaymentKey, HtlcBasepoint, HtlcKey, RevocationBasepoint, RevocationKey, }; +use crate::ln::inbound_payment::ExpandedKey; #[cfg(taproot)] use crate::ln::msgs::PartialSignatureWithNonce; use crate::ln::msgs::{UnsignedChannelAnnouncement, UnsignedGossipMessage}; @@ -820,7 +821,7 @@ pub trait EntropySource { /// A trait that can handle cryptographic operations at the scope level of a node. pub trait NodeSigner { - /// Get secret key material as bytes for use in encrypting and decrypting inbound payment data. + /// Get the [`ExpandedKey`] for use in encrypting and decrypting inbound payment data. /// /// If the implementor of this trait supports [phantom node payments], then every node that is /// intended to be included in the phantom invoice route hints must return the same value from @@ -832,7 +833,7 @@ pub trait NodeSigner { /// This method must return the same value each time it is called. /// /// [phantom node payments]: PhantomKeysManager - fn get_inbound_payment_key_material(&self) -> KeyMaterial; + fn get_inbound_payment_key(&self) -> ExpandedKey; /// Get node id based on the provided [`Recipient`]. /// @@ -1852,7 +1853,7 @@ pub struct KeysManager { secp_ctx: Secp256k1, node_secret: SecretKey, node_id: PublicKey, - inbound_payment_key: KeyMaterial, + inbound_payment_key: ExpandedKey, destination_script: ScriptBuf, shutdown_pubkey: PublicKey, channel_master_key: Xpriv, @@ -1938,7 +1939,7 @@ impl KeysManager { secp_ctx, node_secret, node_id, - inbound_payment_key: KeyMaterial(inbound_pmt_key_bytes), + inbound_payment_key: ExpandedKey::new(&KeyMaterial(inbound_pmt_key_bytes)), destination_script, shutdown_pubkey, @@ -2175,7 +2176,7 @@ impl NodeSigner for KeysManager { Ok(SharedSecret::new(other_key, &node_secret)) } - fn get_inbound_payment_key_material(&self) -> KeyMaterial { + fn get_inbound_payment_key(&self) -> ExpandedKey { self.inbound_payment_key.clone() } @@ -2312,7 +2313,7 @@ pub struct PhantomKeysManager { pub(crate) inner: KeysManager, #[cfg(not(test))] inner: KeysManager, - inbound_payment_key: KeyMaterial, + inbound_payment_key: ExpandedKey, phantom_secret: SecretKey, phantom_node_id: PublicKey, } @@ -2344,7 +2345,7 @@ impl NodeSigner for PhantomKeysManager { Ok(SharedSecret::new(other_key, &node_secret)) } - fn get_inbound_payment_key_material(&self) -> KeyMaterial { + fn get_inbound_payment_key(&self) -> ExpandedKey { self.inbound_payment_key.clone() } @@ -2444,7 +2445,7 @@ impl PhantomKeysManager { let phantom_node_id = PublicKey::from_secret_key(&inner.secp_ctx, &phantom_secret); Self { inner, - inbound_payment_key: KeyMaterial(inbound_key), + inbound_payment_key: ExpandedKey::new(&KeyMaterial(inbound_key)), phantom_secret, phantom_node_id, } diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 813b481c9cf..442a709866c 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -30,6 +30,7 @@ use crate::ln::channelmanager; #[cfg(test)] use crate::ln::chan_utils::CommitmentTransaction; use crate::types::features::{ChannelFeatures, InitFeatures, NodeFeatures}; +use crate::ln::inbound_payment::ExpandedKey; use crate::ln::{msgs, wire}; use crate::ln::msgs::LightningError; use crate::ln::script::ShutdownScript; @@ -1188,7 +1189,7 @@ impl TestNodeSigner { } impl NodeSigner for TestNodeSigner { - fn get_inbound_payment_key_material(&self) -> crate::sign::KeyMaterial { + fn get_inbound_payment_key(&self) -> ExpandedKey { unreachable!() } @@ -1254,8 +1255,8 @@ impl NodeSigner for TestKeysInterface { self.backing.ecdh(recipient, other_key, tweak) } - fn get_inbound_payment_key_material(&self) -> sign::KeyMaterial { - self.backing.get_inbound_payment_key_material() + fn get_inbound_payment_key(&self) -> ExpandedKey { + self.backing.get_inbound_payment_key() } fn sign_invoice(&self, invoice: &RawBolt11Invoice, recipient: Recipient) -> Result { From a29153025f24766f48e2fee72b994baabe7283b9 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 5 Dec 2024 14:38:06 -0600 Subject: [PATCH 03/10] Remove KeyMaterial Now that NodeSigner::get_inbound_payment_key returns an ExpandedKey instead of KeyMaterial, the latter is no longer needed. Remove KeyMaterial and replace its uses with [u8; 32]. --- fuzz/src/chanmon_consistency.rs | 6 +-- fuzz/src/full_stack.rs | 6 +-- fuzz/src/offer_deser.rs | 4 +- lightning/src/ln/inbound_payment.rs | 6 +-- lightning/src/ln/outbound_payment.rs | 9 ++-- lightning/src/offers/invoice.rs | 55 ++++++++++++------------- lightning/src/offers/invoice_request.rs | 48 +++++++++++---------- lightning/src/offers/merkle.rs | 9 ++-- lightning/src/offers/offer.rs | 7 ++-- lightning/src/offers/refund.rs | 5 +-- lightning/src/offers/static_invoice.rs | 27 ++++++------ lightning/src/sign/mod.rs | 11 +---- 12 files changed, 87 insertions(+), 106 deletions(-) diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 8859e5ce644..ca3f0028f3a 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -61,9 +61,7 @@ use lightning::onion_message::messenger::{Destination, MessageRouter, OnionMessa use lightning::routing::router::{ InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters, Router, }; -use lightning::sign::{ - EntropySource, InMemorySigner, KeyMaterial, NodeSigner, Recipient, SignerProvider, -}; +use lightning::sign::{EntropySource, InMemorySigner, NodeSigner, Recipient, SignerProvider}; use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::util::config::UserConfig; use lightning::util::errors::APIError; @@ -338,7 +336,7 @@ impl NodeSigner for KeyProvider { fn get_inbound_payment_key(&self) -> ExpandedKey { #[rustfmt::skip] let random_bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, self.node_secret[31]]; - ExpandedKey::new(&KeyMaterial(random_bytes)) + ExpandedKey::new(random_bytes) } fn sign_invoice( diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index d48a7466e37..c1f2dd11b1e 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -57,9 +57,7 @@ use lightning::routing::router::{ InFlightHtlcs, PaymentParameters, Route, RouteParameters, Router, }; use lightning::routing::utxo::UtxoLookup; -use lightning::sign::{ - EntropySource, InMemorySigner, KeyMaterial, NodeSigner, Recipient, SignerProvider, -}; +use lightning::sign::{EntropySource, InMemorySigner, NodeSigner, Recipient, SignerProvider}; use lightning::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::util::config::{ChannelConfig, UserConfig}; use lightning::util::errors::APIError; @@ -636,7 +634,7 @@ pub fn do_test(mut data: &[u8], logger: &Arc) { let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone(), - inbound_payment_key: ExpandedKey::new(&KeyMaterial(inbound_payment_key)), + inbound_payment_key: ExpandedKey::new(inbound_payment_key), counter: AtomicU64::new(0), signer_state: RefCell::new(new_hash_map()), }); diff --git a/fuzz/src/offer_deser.rs b/fuzz/src/offer_deser.rs index f903e48851d..68902ab3150 100644 --- a/fuzz/src/offer_deser.rs +++ b/fuzz/src/offer_deser.rs @@ -16,7 +16,7 @@ use lightning::offers::invoice_request::InvoiceRequest; use lightning::offers::nonce::Nonce; use lightning::offers::offer::{Amount, Offer, Quantity}; use lightning::offers::parse::Bolt12SemanticError; -use lightning::sign::{EntropySource, KeyMaterial}; +use lightning::sign::EntropySource; use lightning::util::ser::Writeable; #[inline] @@ -43,7 +43,7 @@ impl EntropySource for FixedEntropy { } fn build_request(offer: &Offer) -> Result { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); diff --git a/lightning/src/ln/inbound_payment.rs b/lightning/src/ln/inbound_payment.rs index 7ecbf0c4435..72f877978fe 100644 --- a/lightning/src/ln/inbound_payment.rs +++ b/lightning/src/ln/inbound_payment.rs @@ -20,7 +20,7 @@ use crate::ln::msgs; use crate::ln::msgs::MAX_VALUE_MSAT; use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::offers::nonce::Nonce; -use crate::sign::{KeyMaterial, EntropySource}; +use crate::sign::EntropySource; use crate::util::errors::APIError; use crate::util::logger::Logger; @@ -64,7 +64,7 @@ impl ExpandedKey { /// Create a new [`ExpandedKey`] for generating an inbound payment hash and secret. /// /// It is recommended to cache this value and not regenerate it for each new inbound payment. - pub fn new(key_material: &KeyMaterial) -> ExpandedKey { + pub fn new(key_material: [u8; 32]) -> ExpandedKey { let ( metadata_key, ldk_pmt_hash_key, @@ -72,7 +72,7 @@ impl ExpandedKey { offers_base_key, offers_encryption_key, spontaneous_pmt_key, - ) = hkdf_extract_expand_6x(b"LDK Inbound Payment Key Expansion", &key_material.0); + ) = hkdf_extract_expand_6x(b"LDK Inbound Payment Key Expansion", &key_material); Self { metadata_key, ldk_pmt_hash_key, diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 2f3bb3378ed..7568e236b6e 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -2411,7 +2411,6 @@ mod tests { use crate::offers::test_utils::*; use crate::routing::gossip::NetworkGraph; use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters}; - use crate::sign::KeyMaterial; use crate::sync::{Arc, Mutex, RwLock}; use crate::util::errors::APIError; use crate::util::hash_tables::new_hash_map; @@ -2756,7 +2755,7 @@ mod tests { let router = test_utils::TestRouter::new(network_graph, &logger, &scorer); let secp_ctx = Secp256k1::new(); let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let nonce = Nonce([0; 16]); let pending_events = Mutex::new(VecDeque::new()); @@ -2813,7 +2812,7 @@ mod tests { let pending_events = Mutex::new(VecDeque::new()); let outbound_payments = OutboundPayments::new(new_hash_map()); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let nonce = Nonce([0; 16]); let payment_id = PaymentId([0; 32]); let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100)); @@ -2875,7 +2874,7 @@ mod tests { let pending_events = Mutex::new(VecDeque::new()); let outbound_payments = OutboundPayments::new(new_hash_map()); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let nonce = Nonce([0; 16]); let payment_id = PaymentId([0; 32]); let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100)); @@ -2960,7 +2959,7 @@ mod tests { } fn dummy_invoice_request() -> InvoiceRequest { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); diff --git a/lightning/src/offers/invoice.rs b/lightning/src/offers/invoice.rs index 3539d0f81d1..136ea2625de 100644 --- a/lightning/src/offers/invoice.rs +++ b/lightning/src/offers/invoice.rs @@ -1605,7 +1605,6 @@ mod tests { use crate::blinded_path::BlindedHop; use crate::blinded_path::message::BlindedMessagePath; - use crate::sign::KeyMaterial; use crate::types::features::{Bolt12InvoiceFeatures, InvoiceRequestFeatures, OfferFeatures}; use crate::ln::channelmanager::PaymentId; use crate::ln::inbound_payment::ExpandedKey; @@ -1649,7 +1648,7 @@ mod tests { #[test] fn builds_invoice_for_offer_with_defaults() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1913,7 +1912,7 @@ mod tests { #[cfg(feature = "std")] #[test] fn builds_invoice_from_offer_with_expiration() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1981,7 +1980,7 @@ mod tests { #[test] fn builds_invoice_from_offer_using_derived_keys() { let node_id = recipient_pubkey(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2014,7 +2013,7 @@ mod tests { panic!("error building invoice: {:?}", e); } - let expanded_key = ExpandedKey::new(&KeyMaterial([41; 32])); + let expanded_key = ExpandedKey::new([41; 32]); assert!( invoice_request.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).is_err() ); @@ -2039,7 +2038,7 @@ mod tests { #[test] fn builds_invoice_from_refund_using_derived_keys() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let secp_ctx = Secp256k1::new(); @@ -2061,7 +2060,7 @@ mod tests { #[test] fn builds_invoice_from_refund_with_path() { let node_id = payer_pubkey(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let secp_ctx = Secp256k1::new(); @@ -2090,7 +2089,7 @@ mod tests { #[test] fn builds_invoice_with_relative_expiry() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2132,7 +2131,7 @@ mod tests { #[test] fn builds_invoice_with_amount_from_request() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2154,7 +2153,7 @@ mod tests { #[test] fn builds_invoice_with_quantity_from_request() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2190,7 +2189,7 @@ mod tests { #[test] fn builds_invoice_with_fallback_address() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2242,7 +2241,7 @@ mod tests { #[test] fn builds_invoice_with_allow_mpp() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2267,7 +2266,7 @@ mod tests { #[test] fn fails_signing_invoice() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2302,7 +2301,7 @@ mod tests { #[test] fn parses_invoice_with_payment_paths() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2362,7 +2361,7 @@ mod tests { #[test] fn parses_invoice_with_created_at() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2397,7 +2396,7 @@ mod tests { #[test] fn parses_invoice_with_relative_expiry() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2424,7 +2423,7 @@ mod tests { #[test] fn parses_invoice_with_payment_hash() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2459,7 +2458,7 @@ mod tests { #[test] fn parses_invoice_with_amount() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2492,7 +2491,7 @@ mod tests { #[test] fn parses_invoice_with_allow_mpp() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2523,7 +2522,7 @@ mod tests { #[test] fn parses_invoice_with_fallback_address() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2587,7 +2586,7 @@ mod tests { #[test] fn parses_invoice_with_node_id() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2633,7 +2632,7 @@ mod tests { #[test] fn parses_invoice_with_node_id_from_blinded_path() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2710,7 +2709,7 @@ mod tests { #[test] fn fails_parsing_invoice_without_signature() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2735,7 +2734,7 @@ mod tests { #[test] fn fails_parsing_invoice_with_invalid_signature() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2765,7 +2764,7 @@ mod tests { #[test] fn parses_invoice_with_unknown_tlv_records() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let payment_id = PaymentId([1; 32]); @@ -2849,7 +2848,7 @@ mod tests { #[test] fn parses_invoice_with_experimental_tlv_records() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let payment_id = PaymentId([1; 32]); @@ -2979,7 +2978,7 @@ mod tests { #[test] fn fails_parsing_invoice_with_out_of_range_tlv_records() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -3008,7 +3007,7 @@ mod tests { #[test] fn fails_parsing_invoice_with_message_paths() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs index 2594c056f05..74bbdb8a0bf 100644 --- a/lightning/src/offers/invoice_request.rs +++ b/lightning/src/offers/invoice_request.rs @@ -32,7 +32,6 @@ //! # use lightning::offers::nonce::Nonce; //! use lightning::offers::offer::Offer; //! # use lightning::sign::EntropySource; -//! use lightning::sign::KeyMaterial; //! use lightning::util::ser::Writeable; //! //! # struct FixedEntropy; @@ -42,7 +41,7 @@ //! # } //! # } //! # fn parse() -> Result<(), lightning::offers::parse::Bolt12ParseError> { -//! let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); +//! let expanded_key = ExpandedKey::new([42; 32]); //! # let entropy = FixedEntropy {}; //! # let nonce = Nonce::from_entropy_source(&entropy); //! let secp_ctx = Secp256k1::new(); @@ -1329,7 +1328,6 @@ mod tests { use core::num::NonZeroU64; #[cfg(feature = "std")] use core::time::Duration; - use crate::sign::KeyMaterial; use crate::ln::channelmanager::PaymentId; use crate::types::features::{InvoiceRequestFeatures, OfferFeatures}; use crate::ln::inbound_payment::ExpandedKey; @@ -1354,7 +1352,7 @@ mod tests { #[test] fn builds_invoice_request_with_defaults() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1440,7 +1438,7 @@ mod tests { #[cfg(feature = "std")] #[test] fn builds_invoice_request_from_offer_with_expiration() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1473,7 +1471,7 @@ mod tests { #[test] fn builds_invoice_request_with_derived_payer_signing_pubkey() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1566,7 +1564,7 @@ mod tests { #[test] fn builds_invoice_request_with_chain() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1646,7 +1644,7 @@ mod tests { #[test] fn builds_invoice_request_with_amount() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1752,7 +1750,7 @@ mod tests { #[test] fn builds_invoice_request_with_features() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1782,7 +1780,7 @@ mod tests { #[test] fn builds_invoice_request_with_quantity() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1874,7 +1872,7 @@ mod tests { #[test] fn builds_invoice_request_with_payer_note() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1904,7 +1902,7 @@ mod tests { #[test] fn fails_responding_with_unknown_required_features() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1925,7 +1923,7 @@ mod tests { #[test] fn parses_invoice_request_with_metadata() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1947,7 +1945,7 @@ mod tests { #[test] fn parses_invoice_request_with_chain() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1985,7 +1983,7 @@ mod tests { #[test] fn parses_invoice_request_with_amount() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2081,7 +2079,7 @@ mod tests { #[test] fn parses_invoice_request_with_quantity() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2205,7 +2203,7 @@ mod tests { #[test] fn fails_parsing_invoice_request_without_metadata() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2232,7 +2230,7 @@ mod tests { #[test] fn fails_parsing_invoice_request_without_payer_signing_pubkey() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2257,7 +2255,7 @@ mod tests { #[test] fn fails_parsing_invoice_request_without_issuer_id() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2284,7 +2282,7 @@ mod tests { #[test] fn fails_parsing_invoice_request_without_signature() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2307,7 +2305,7 @@ mod tests { #[test] fn fails_parsing_invoice_request_with_invalid_signature() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2334,7 +2332,7 @@ mod tests { #[test] fn parses_invoice_request_with_unknown_tlv_records() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let payment_id = PaymentId([1; 32]); @@ -2420,7 +2418,7 @@ mod tests { #[test] fn parses_invoice_request_with_experimental_tlv_records() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let payment_id = PaymentId([1; 32]); @@ -2530,7 +2528,7 @@ mod tests { #[test] fn fails_parsing_invoice_request_with_out_of_range_tlv_records() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -2568,7 +2566,7 @@ mod tests { #[test] fn copies_verified_invoice_request_fields() { let node_id = recipient_pubkey(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); diff --git a/lightning/src/offers/merkle.rs b/lightning/src/offers/merkle.rs index 60b0353f1d0..8c3eaaed24d 100644 --- a/lightning/src/offers/merkle.rs +++ b/lightning/src/offers/merkle.rs @@ -309,7 +309,6 @@ mod tests { use crate::offers::parse::Bech32Encode; use crate::offers::signer::Metadata; use crate::offers::test_utils::recipient_pubkey; - use crate::sign::KeyMaterial; use crate::util::ser::Writeable; #[test] @@ -334,7 +333,7 @@ mod tests { #[test] fn calculates_merkle_root_hash_from_invoice_request() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let nonce = Nonce([0u8; 16]); let secp_ctx = Secp256k1::new(); let payment_id = PaymentId([1; 32]); @@ -378,7 +377,7 @@ mod tests { #[test] fn compute_tagged_hash() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let nonce = Nonce([0u8; 16]); let secp_ctx = Secp256k1::new(); let payment_id = PaymentId([1; 32]); @@ -401,7 +400,7 @@ mod tests { #[test] fn skips_encoding_signature_tlv_records() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let nonce = Nonce([0u8; 16]); let secp_ctx = Secp256k1::new(); let payment_id = PaymentId([1; 32]); @@ -433,7 +432,7 @@ mod tests { #[test] fn iterates_over_tlv_stream_range() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let nonce = Nonce([0u8; 16]); let secp_ctx = Secp256k1::new(); let payment_id = PaymentId([1; 32]); diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index 3843c10cb8d..613f9accd47 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -1220,7 +1220,6 @@ mod tests { use core::time::Duration; use crate::blinded_path::BlindedHop; use crate::blinded_path::message::BlindedMessagePath; - use crate::sign::KeyMaterial; use crate::types::features::OfferFeatures; use crate::ln::channelmanager::PaymentId; use crate::ln::inbound_payment::ExpandedKey; @@ -1343,7 +1342,7 @@ mod tests { #[test] fn builds_offer_with_metadata_derived() { let node_id = recipient_pubkey(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1403,7 +1402,7 @@ mod tests { #[test] fn builds_offer_with_derived_signing_pubkey() { let node_id = recipient_pubkey(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1692,7 +1691,7 @@ mod tests { #[test] fn fails_requesting_invoice_with_unknown_required_features() { - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); diff --git a/lightning/src/offers/refund.rs b/lightning/src/offers/refund.rs index 7a47ad99b3b..a68d0eb658e 100644 --- a/lightning/src/offers/refund.rs +++ b/lightning/src/offers/refund.rs @@ -999,7 +999,6 @@ mod tests { use crate::blinded_path::BlindedHop; use crate::blinded_path::message::BlindedMessagePath; - use crate::sign::KeyMaterial; use crate::ln::channelmanager::PaymentId; use crate::types::features::{InvoiceRequestFeatures, OfferFeatures}; use crate::ln::inbound_payment::ExpandedKey; @@ -1100,7 +1099,7 @@ mod tests { #[test] fn builds_refund_with_metadata_derived() { let node_id = payer_pubkey(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1161,7 +1160,7 @@ mod tests { #[test] fn builds_refund_with_derived_signing_pubkey() { let node_id = payer_pubkey(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); diff --git a/lightning/src/offers/static_invoice.rs b/lightning/src/offers/static_invoice.rs index 50655c392c8..39c17eb3bcc 100644 --- a/lightning/src/offers/static_invoice.rs +++ b/lightning/src/offers/static_invoice.rs @@ -720,7 +720,6 @@ mod tests { SIGNATURE_TAG, }; use crate::offers::test_utils::*; - use crate::sign::KeyMaterial; use crate::types::features::{Bolt12InvoiceFeatures, OfferFeatures}; use crate::util::ser::{BigSize, Iterable, Writeable}; use bitcoin::constants::ChainHash; @@ -776,7 +775,7 @@ mod tests { let node_id = recipient_pubkey(); let payment_paths = payment_paths(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -816,7 +815,7 @@ mod tests { let node_id = recipient_pubkey(); let payment_paths = payment_paths(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -913,7 +912,7 @@ mod tests { fn builds_invoice_from_offer_with_expiration() { let node_id = recipient_pubkey(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -971,7 +970,7 @@ mod tests { fn builds_invoice_from_offer_using_derived_key() { let node_id = recipient_pubkey(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -997,7 +996,7 @@ mod tests { panic!("error building invoice: {:?}", e); } - let expanded_key = ExpandedKey::new(&KeyMaterial([41; 32])); + let expanded_key = ExpandedKey::new([41; 32]); if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys( &offer, payment_paths(), @@ -1017,7 +1016,7 @@ mod tests { fn fails_build_with_missing_paths() { let node_id = recipient_pubkey(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1084,7 +1083,7 @@ mod tests { fn fails_building_with_missing_issuer_signing_pubkey() { let node_id = recipient_pubkey(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1120,7 +1119,7 @@ mod tests { #[test] fn fails_building_with_invalid_metadata() { let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1150,7 +1149,7 @@ mod tests { fn fails_building_with_extra_offer_chains() { let node_id = recipient_pubkey(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1183,7 +1182,7 @@ mod tests { let node_id = recipient_pubkey(); let payment_paths = payment_paths(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1225,7 +1224,7 @@ mod tests { let node_id = recipient_pubkey(); let payment_paths = payment_paths(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1362,7 +1361,7 @@ mod tests { let node_id = recipient_pubkey(); let payment_paths = payment_paths(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); @@ -1462,7 +1461,7 @@ mod tests { let node_id = recipient_pubkey(); let payment_paths = payment_paths(); let now = now(); - let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); + let expanded_key = ExpandedKey::new([42; 32]); let entropy = FixedEntropy {}; let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 8bed5aaf132..94d68288022 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -82,13 +82,6 @@ pub mod ecdsa; #[cfg(taproot)] pub mod taproot; -/// Used as initial key material, to be expanded into multiple secret keys (but not to be used -/// directly). This is used within LDK to encrypt/decrypt inbound payment data. -/// -/// This is not exported to bindings users as we just use `[u8; 32]` directly -#[derive(Hash, Copy, Clone, PartialEq, Eq, Debug)] -pub struct KeyMaterial(pub [u8; 32]); - /// Information about a spendable output to a P2WSH script. /// /// See [`SpendableOutputDescriptor::DelayedPaymentOutput`] for more details on how to spend this. @@ -1939,7 +1932,7 @@ impl KeysManager { secp_ctx, node_secret, node_id, - inbound_payment_key: ExpandedKey::new(&KeyMaterial(inbound_pmt_key_bytes)), + inbound_payment_key: ExpandedKey::new(inbound_pmt_key_bytes), destination_script, shutdown_pubkey, @@ -2445,7 +2438,7 @@ impl PhantomKeysManager { let phantom_node_id = PublicKey::from_secret_key(&inner.secp_ctx, &phantom_secret); Self { inner, - inbound_payment_key: ExpandedKey::new(&KeyMaterial(inbound_key)), + inbound_payment_key: ExpandedKey::new(inbound_key), phantom_secret, phantom_node_id, } From 55c02fdee15d68825f6d48bd365762bb0542aefd Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Sun, 1 Dec 2024 16:23:27 -0500 Subject: [PATCH 04/10] 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. --- fuzz/src/invoice_request_deser.rs | 11 ++- fuzz/src/refund_deser.rs | 11 ++- lightning/src/blinded_path/payment.rs | 74 ++++++++++++++++--- lightning/src/ln/blinded_payment_tests.rs | 29 ++++++-- lightning/src/ln/channelmanager.rs | 12 ++- .../src/ln/max_payment_path_len_tests.rs | 9 ++- lightning/src/ln/msgs.rs | 10 ++- lightning/src/offers/signer.rs | 7 +- lightning/src/routing/router.rs | 2 +- 9 files changed, 128 insertions(+), 37 deletions(-) diff --git a/fuzz/src/invoice_request_deser.rs b/fuzz/src/invoice_request_deser.rs index d5a43ae46ec..37668c1d801 100644 --- a/fuzz/src/invoice_request_deser.rs +++ b/fuzz/src/invoice_request_deser.rs @@ -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( invoice_request: &InvoiceRequest, secp_ctx: &Secp256k1, ) -> Result { + 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( 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( }, 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( 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(), diff --git a/fuzz/src/refund_deser.rs b/fuzz/src/refund_deser.rs index d8d9881ef97..6151d810344 100644 --- a/fuzz/src/refund_deser.rs +++ b/fuzz/src/refund_deser.rs @@ -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( refund: &Refund, signing_pubkey: PublicKey, secp_ctx: &Secp256k1, ) -> Result { + 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( }, 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( 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(), diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index 62ce7dec186..e1b8498957f 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -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, 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(&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(&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 = _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 { 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, diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index f2548341b83..d75c21b2ce9 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -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, diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 04275a708bf..f47b627cd10 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -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 { @@ -10490,13 +10490,16 @@ where fn create_blinded_payment_paths( &self, amount_msats: u64, payment_secret: PaymentSecret, payment_context: PaymentContext ) -> Result, ()> { + 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 ) diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index af30003ee5d..c5c48e0c671 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -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, diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index c20d2027209..84da5a9f2a6 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -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 ReadableArgs<(Option, 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)?, diff --git a/lightning/src/offers/signer.rs b/lightning/src/offers/signer.rs index aee79175f5f..fa9fdfa3467 100644 --- a/lightning/src/offers/signer.rs +++ b/lightning/src/offers/signer.rs @@ -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 { 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, nonce: Nonce, expanded_key: &ExpandedKey, + receive_tlvs: &UnauthenticatedReceiveTlvs, hmac: Hmac, nonce: Nonce, + expanded_key: &ExpandedKey, ) -> Result<(), ()> { if hmac_for_payment_tlvs(receive_tlvs, nonce, expanded_key) == hmac { Ok(()) } else { Err(()) } } diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index b91b1b47d6e..78a93aa0d39 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -145,7 +145,7 @@ impl>, 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 { From a041463c30c6e803c921ae57ac2e6e6b512d5d1f Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 4 Dec 2024 16:00:43 -0600 Subject: [PATCH 05/10] Fix lint warning in lightning-invoice when fuzzing --- lightning-invoice/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index 329ef4b04c8..07c8342b5ea 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -1086,6 +1086,7 @@ impl RawBolt11Invoice { /// Calculate the hash of the encoded `RawBolt11Invoice` which should be signed. pub fn signable_hash(&self) -> [u8; 32] { + #[cfg(not(fuzzing))] use crate::ser::Base32Iterable; Self::hash_from_parts(self.hrp.to_string().as_bytes(), self.data.fe_iter()) From 62cdf5d60b3d1c906710a5881c456aa332b85699 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 4 Dec 2024 14:32:24 -0600 Subject: [PATCH 06/10] Verify that an HTLC's ReceiveTlvs is authentic When receiving a payment over a BlindedPaymentPath, a PaymentContext is included but was not authenticated. The previous commit adds an HMAC of the payment::ReceiveTlvs (which contains the PaymentContext) and the nonce used to create the HMAC. This commit verifies the authenticity when parsing the InboundOnionPayload. This prevents a malicious actor from for forging it. --- lightning/src/ln/msgs.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 84da5a9f2a6..659ec65f6cf 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -32,6 +32,7 @@ use bitcoin::script::ScriptBuf; use bitcoin::hash_types::Txid; use crate::blinded_path::payment::{BlindedPaymentTlvs, ForwardTlvs, ReceiveTlvs, UnauthenticatedReceiveTlvs}; +use crate::ln::channelmanager::Verification; use crate::ln::types::ChannelId; use crate::types::payment::{PaymentPreimage, PaymentHash, PaymentSecret}; use crate::types::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; @@ -2908,7 +2909,12 @@ impl ReadableArgs<(Option, NS)> for InboundOnionPayload wh }) }, ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(receive_tlvs) } => { - let ReceiveTlvs { tlvs, authentication: _ } = receive_tlvs; + let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs; + let expanded_key = node_signer.get_inbound_payment_key(); + if tlvs.verify_for_offer_payment(hmac, nonce, &expanded_key).is_err() { + return Err(DecodeError::InvalidValue); + } + let UnauthenticatedReceiveTlvs { payment_secret, payment_constraints, payment_context, } = tlvs; From faf8367e9a6a17206fab6b9f24f0803b465c9b1e Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 5 Dec 2024 15:22:09 -0600 Subject: [PATCH 07/10] Require a PaymentContext in payment::ReceiveTlvs UnknownPaymentContext is used when payment::ReceiveTlvs doesn't contain a PaymentContext. This is only needed for a legacy BlindedPaymentPath. Since these paths a short-lived, UnknownPaymentContext is no longer needed. Remove it and require that payment::ReceiveTlvs always contains a PaymentContext. Any such path would fail authentication since the payment::ReceiveTlvs would be missing an HMAC and Nonce, so this is a good time to remove UnknownPaymentContext. --- lightning/src/blinded_path/payment.rs | 43 ++++--------------- lightning/src/events/mod.rs | 2 +- lightning/src/ln/blinded_payment_tests.rs | 10 ++--- .../src/ln/max_payment_path_len_tests.rs | 4 +- 4 files changed, 17 insertions(+), 42 deletions(-) diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index e1b8498957f..e3a81927146 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -344,9 +344,6 @@ pub struct PaymentConstraints { /// [`PaymentPurpose`]: crate::events::PaymentPurpose #[derive(Clone, Debug, Eq, PartialEq)] pub enum PaymentContext { - /// The payment context was unknown. - Unknown(UnknownPaymentContext), - /// The payment was made for an invoice requested from a BOLT 12 [`Offer`]. /// /// [`Offer`]: crate::offers::offer::Offer @@ -364,10 +361,6 @@ pub(crate) enum PaymentContextRef<'a> { Bolt12Refund(&'a Bolt12RefundContext), } -/// An unknown payment context. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct UnknownPaymentContext(()); - /// The context of a payment made for an invoice requested from a BOLT 12 [`Offer`]. /// /// [`Offer`]: crate::offers::offer::Offer @@ -391,12 +384,6 @@ pub struct Bolt12OfferContext { #[derive(Clone, Debug, Eq, PartialEq)] pub struct Bolt12RefundContext {} -impl PaymentContext { - pub(crate) fn unknown() -> Self { - PaymentContext::Unknown(UnknownPaymentContext(())) - } -} - impl TryFrom for PaymentRelay { type Error = (); @@ -477,7 +464,7 @@ impl Readable for BlindedPaymentTlvs { (12, payment_constraints, required), (14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))), (65536, payment_secret, option), - (65537, payment_context, (default_value, PaymentContext::unknown())), + (65537, payment_context, option), (65539, authentication, option), }); let _padding: Option = _padding; @@ -499,7 +486,7 @@ impl Readable for BlindedPaymentTlvs { tlvs: UnauthenticatedReceiveTlvs { payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?, payment_constraints: payment_constraints.0.unwrap(), - payment_context: payment_context.0.unwrap(), + payment_context: payment_context.ok_or(DecodeError::InvalidValue)?, }, authentication: authentication.ok_or(DecodeError::InvalidValue)?, })) @@ -637,7 +624,7 @@ impl Readable for PaymentConstraints { impl_writeable_tlv_based_enum_legacy!(PaymentContext, ; - (0, Unknown), + // 0 for Unknown removed in version 0.1. (1, Bolt12Offer), (2, Bolt12Refund), ); @@ -659,18 +646,6 @@ impl<'a> Writeable for PaymentContextRef<'a> { } } -impl Writeable for UnknownPaymentContext { - fn write(&self, _w: &mut W) -> Result<(), io::Error> { - Ok(()) - } -} - -impl Readable for UnknownPaymentContext { - fn read(_r: &mut R) -> Result { - Ok(UnknownPaymentContext(())) - } -} - impl_writeable_tlv_based!(Bolt12OfferContext, { (0, offer_id, required), (2, invoice_request, required), @@ -681,7 +656,7 @@ impl_writeable_tlv_based!(Bolt12RefundContext, {}); #[cfg(test)] mod tests { use bitcoin::secp256k1::PublicKey; - use crate::blinded_path::payment::{PaymentForwardNode, ForwardTlvs, PaymentConstraints, PaymentContext, PaymentRelay, UnauthenticatedReceiveTlvs}; + use crate::blinded_path::payment::{Bolt12RefundContext, 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; @@ -732,7 +707,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let htlc_maximum_msat = 100_000; let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, 12).unwrap(); @@ -751,7 +726,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let blinded_payinfo = super::compute_payinfo(&[], &recv_tlvs, 4242, TEST_FINAL_CLTV as u16).unwrap(); assert_eq!(blinded_payinfo.fee_base_msat, 0); @@ -807,7 +782,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 3, }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let htlc_maximum_msat = 100_000; let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, TEST_FINAL_CLTV as u16).unwrap(); @@ -860,7 +835,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let htlc_minimum_msat = 3798; assert!(super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_minimum_msat - 1, TEST_FINAL_CLTV as u16).is_err()); @@ -917,7 +892,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, 10_000, TEST_FINAL_CLTV as u16).unwrap(); diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs index 0319e54c3d3..5bc446f9724 100644 --- a/lightning/src/events/mod.rs +++ b/lightning/src/events/mod.rs @@ -183,7 +183,7 @@ impl PaymentPurpose { payment_context: Option, ) -> Self { match payment_context { - Some(PaymentContext::Unknown(_)) | None => { + None => { PaymentPurpose::Bolt11InvoicePayment { payment_preimage, payment_secret, diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index d75c21b2ce9..c940a7345e8 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -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, UnauthenticatedReceiveTlvs}; +use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12RefundContext, 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}; @@ -79,7 +79,7 @@ fn blinded_payment_path( htlc_minimum_msat: intro_node_min_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_minimum_msat), }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let nonce = Nonce([42u8; 16]); @@ -130,7 +130,7 @@ fn do_one_hop_blinded_path(success: bool) { max_cltv_expiry: u32::max_value(), htlc_minimum_msat: chan_upd.htlc_minimum_msat, }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_key(); @@ -178,7 +178,7 @@ fn mpp_to_one_hop_blinded_path() { max_cltv_expiry: u32::max_value(), htlc_minimum_msat: chan_upd_1_3.htlc_minimum_msat, }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[3].keys_manager.get_inbound_payment_key(); @@ -1386,7 +1386,7 @@ fn custom_tlvs_to_blinded_path() { max_cltv_expiry: u32::max_value(), htlc_minimum_msat: chan_upd.htlc_minimum_msat, }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_key(); diff --git a/lightning/src/ln/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs index c5c48e0c671..9db12491b49 100644 --- a/lightning/src/ln/max_payment_path_len_tests.rs +++ b/lightning/src/ln/max_payment_path_len_tests.rs @@ -12,7 +12,7 @@ use bitcoin::secp256k1::{Secp256k1, PublicKey}; use crate::blinded_path::BlindedHop; -use crate::blinded_path::payment::{BlindedPayInfo, BlindedPaymentPath, PaymentConstraints, PaymentContext, UnauthenticatedReceiveTlvs}; +use crate::blinded_path::payment::{BlindedPayInfo, BlindedPaymentPath, Bolt12RefundContext, PaymentConstraints, PaymentContext, UnauthenticatedReceiveTlvs}; use crate::events::{Event, MessageSendEventsProvider}; use crate::types::payment::PaymentSecret; use crate::ln::blinded_payment_tests::get_blinded_route_parameters; @@ -165,7 +165,7 @@ fn one_hop_blinded_path_with_custom_tlv() { max_cltv_expiry: u32::max_value(), htlc_minimum_msat: chan_upd_1_2.htlc_minimum_msat, }, - payment_context: PaymentContext::unknown(), + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), }; let nonce = Nonce([42u8; 16]); let expanded_key = chanmon_cfgs[2].keys_manager.get_inbound_payment_key(); From 4f0252fe75b67c8d491e822ae6468e02ff245ffa Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 5 Dec 2024 18:34:14 -0600 Subject: [PATCH 08/10] Test payment::ReceiveTlvs authentication failure --- lightning/src/ln/blinded_payment_tests.rs | 88 +++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index c940a7345e8..c1fad65c14f 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -1424,6 +1424,94 @@ fn custom_tlvs_to_blinded_path() { ); } +#[test] +fn fails_receive_tlvs_authentication() { + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + let chan_upd = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0).0.contents; + + let amt_msat = 5000; + let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None); + let payee_tlvs = UnauthenticatedReceiveTlvs { + payment_secret, + payment_constraints: PaymentConstraints { + max_cltv_expiry: u32::max_value(), + htlc_minimum_msat: chan_upd.htlc_minimum_msat, + }, + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + }; + 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, + &chanmon_cfgs[1].keys_manager, &secp_ctx + ).unwrap(); + + let route_params = RouteParameters::from_payment_params_and_value( + PaymentParameters::blinded(vec![blinded_path]), + amt_msat, + ); + + // Test authentication works normally. + nodes[0].node.send_payment(payment_hash, RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap(); + check_added_monitors(&nodes[0], 1); + pass_along_route(&nodes[0], &[&[&nodes[1]]], amt_msat, payment_hash, payment_secret); + claim_payment(&nodes[0], &[&nodes[1]], payment_preimage); + + // Swap in a different nonce to force authentication to fail. + let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None); + let payee_tlvs = UnauthenticatedReceiveTlvs { + payment_secret, + payment_constraints: PaymentConstraints { + max_cltv_expiry: u32::max_value(), + htlc_minimum_msat: chan_upd.htlc_minimum_msat, + }, + payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}), + }; + let nonce = Nonce([43u8; 16]); + let mut payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key); + payee_tlvs.authentication.1 = Nonce([0u8; 16]); + + 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, + &chanmon_cfgs[1].keys_manager, &secp_ctx + ).unwrap(); + + let route_params = RouteParameters::from_payment_params_and_value( + PaymentParameters::blinded(vec![blinded_path]), + amt_msat, + ); + + nodes[0].node.send_payment(payment_hash, RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0), route_params, Retry::Attempts(0)).unwrap(); + check_added_monitors(&nodes[0], 1); + + let mut events = nodes[0].node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + let ev = remove_first_msg_event_to_node(&nodes[1].node.get_our_node_id(), &mut events); + let mut payment_event = SendEvent::from_event(ev); + + nodes[1].node.handle_update_add_htlc(nodes[0].node.get_our_node_id(), &payment_event.msgs[0]); + check_added_monitors!(nodes[1], 0); + do_commitment_signed_dance(&nodes[1], &nodes[0], &payment_event.commitment_msg, true, true); + nodes[1].node.process_pending_htlc_forwards(); + + let mut update_fail = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); + assert!(update_fail.update_fail_htlcs.len() == 1); + let fail_msg = &update_fail.update_fail_htlcs[0]; + nodes[0].node.handle_update_fail_htlc(nodes[1].node.get_our_node_id(), fail_msg); + commitment_signed_dance!(nodes[0], nodes[1], update_fail.commitment_signed, false); + expect_payment_failed_conditions( + &nodes[0], payment_hash, true, + PaymentFailedConditions::new().expected_htlc_error_data(0x4000 | 22, &[]), + ); +} + fn secret_from_hex(hex: &str) -> SecretKey { SecretKey::from_slice(&>::from_hex(hex).unwrap()).unwrap() } From 09b134490aa30dacba3d7bb11eea706d36c57331 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 5 Dec 2024 18:50:44 -0600 Subject: [PATCH 09/10] Add pending changelog for PR 3435 --- .../3435-authenticate-payment-receive-tlvs.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 pending_changelog/3435-authenticate-payment-receive-tlvs.txt diff --git a/pending_changelog/3435-authenticate-payment-receive-tlvs.txt b/pending_changelog/3435-authenticate-payment-receive-tlvs.txt new file mode 100644 index 00000000000..714bd00d8ce --- /dev/null +++ b/pending_changelog/3435-authenticate-payment-receive-tlvs.txt @@ -0,0 +1,9 @@ +## API Updates + * Payment `ReceiveTlvs` now contains an `authentication` field. It should be + set to `None` and then filled in with a nonce and the HMAC produced by + `ReceiveTlvs::hmac_for_offer_payment` when passing in the nonce (#3435). + +## Backwards Compatibility + * `ReceiveTlvs` for payments over `BlindedPaymentPath`s are now authenticated. + Any inbound payments for a preexisting `Bolt12Invoice` will therefore fail + (#3435). From d287bf0d7d1c03e1ba1209026424e9871abc9b22 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 12 Dec 2024 13:28:19 -0600 Subject: [PATCH 10/10] Fix lint warning in lightning when fuzzing --- lightning/src/ln/channelmanager.rs | 2 +- lightning/src/ln/outbound_payment.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index f47b627cd10..b312e0055ee 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -54,7 +54,7 @@ use crate::types::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelType #[cfg(any(feature = "_test_utils", test))] use crate::types::features::Bolt11InvoiceFeatures; use crate::routing::router::{BlindedTail, InFlightHtlcs, Path, Payee, PaymentParameters, RouteParameters, Router}; -#[cfg(any(test, fuzzing))] +#[cfg(test)] use crate::routing::router::Route; use crate::ln::onion_payment::{check_incoming_htlc_cltv, create_recv_pending_htlc_info, create_fwd_pending_htlc_info, decode_incoming_update_add_htlc_onion, InboundHTLCErr, NextPacketDetails}; use crate::ln::msgs; diff --git a/lightning/src/ln/outbound_payment.rs b/lightning/src/ln/outbound_payment.rs index 7568e236b6e..80d93387ac3 100644 --- a/lightning/src/ln/outbound_payment.rs +++ b/lightning/src/ln/outbound_payment.rs @@ -790,7 +790,7 @@ impl OutboundPayments { best_block_height, logger, pending_events, &send_payment_along_path) } - #[cfg(any(test, fuzzing))] + #[cfg(test)] pub(super) fn send_payment_with_route( &self, route: &Route, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId, entropy_source: &ES, node_signer: &NS, best_block_height: u32,