Rename get_inbound_payment_key to get_expanded_key
What changed, and why it matters
This commit is a simple rename of a function from get_inbound_payment_key to get_expanded_key, plus updated documentation. It does not change any behavior, logic, or security properties of the code. The change reflects that the same cryptographic key material is now used for more purposes than just inbound payments, such as BOLT 12 Offers and spontaneous payments.
No security action needed. Treat as a normal API/documentation refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit performs a pure refactor across 14 files, renaming the NodeSigner trait method get_inbound_payment_key to get_expanded_key and updating all call sites and doc links. The ExpandedKey type and its usage remain unchanged. Documentation is updated to list the broader use cases: inbound payment metadata encryption, payment hash authentication, BOLT 12 Offers key derivation/authentication, and spontaneous payment metadata authentication. No algorithmic, cryptographic, or API semantic changes are present.
Changed components
NodeSigner traitKeysManagerPhantomKeysManagerDynSignerinbound_payment modulechannelmanagerinvoice_utilsmsgstest and fuzz harnessesInspect captured patch +49 / −43
diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs
index ff5189f..3d7ca37 100644
--- a/fuzz/src/chanmon_consistency.rs
+++ b/fuzz/src/chanmon_consistency.rs
@@ -332,7 +332,7 @@ impl NodeSigner for KeyProvider {
Ok(SharedSecret::new(other_key, &node_secret))
}
- fn get_inbound_payment_key(&self) -> ExpandedKey {
+ fn get_expanded_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(random_bytes)
diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs
index 88e68e5..2e4e6bd 100644
--- a/fuzz/src/full_stack.rs
+++ b/fuzz/src/full_stack.rs
@@ -80,9 +80,9 @@ use bitcoin::secp256k1::{self, Message, PublicKey, Scalar, Secp256k1, SecretKey}
use lightning::util::dyn_signer::DynSigner;
-use std::collections::VecDeque;
use std::cell::RefCell;
use std::cmp;
+use std::collections::VecDeque;
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
@@ -406,7 +406,7 @@ impl NodeSigner for KeyProvider {
Ok(SharedSecret::new(other_key, &node_secret))
}
- fn get_inbound_payment_key(&self) -> ExpandedKey {
+ fn get_expanded_key(&self) -> ExpandedKey {
self.inbound_payment_key
}
diff --git a/fuzz/src/onion_message.rs b/fuzz/src/onion_message.rs
index 85ba626..d58b44f 100644
--- a/fuzz/src/onion_message.rs
+++ b/fuzz/src/onion_message.rs
@@ -255,7 +255,7 @@ impl NodeSigner for KeyProvider {
Ok(SharedSecret::new(other_key, &node_secret))
}
- fn get_inbound_payment_key(&self) -> ExpandedKey {
+ fn get_expanded_key(&self) -> ExpandedKey {
unreachable!()
}
diff --git a/lightning/src/ln/async_payments_tests.rs b/lightning/src/ln/async_payments_tests.rs
index 2fa5dee..e617f6f 100644
--- a/lightning/src/ln/async_payments_tests.rs
+++ b/lightning/src/ln/async_payments_tests.rs
@@ -255,7 +255,7 @@ fn create_static_invoice_builder<'a>(
let created_at = recipient.node.duration_since_epoch();
let payment_secret = inbound_payment::create_for_spontaneous_payment(
- &recipient.keys_manager.get_inbound_payment_key(),
+ &recipient.keys_manager.get_expanded_key(),
amount_msat,
relative_expiry_secs,
created_at.as_secs(),
@@ -982,7 +982,7 @@ fn amount_doesnt_match_invreq() {
valid_invreq = Some(invoice_request.clone());
*invoice_request = offer
.request_invoice(
- &nodes[0].keys_manager.get_inbound_payment_key(),
+ &nodes[0].keys_manager.get_expanded_key(),
Nonce::from_entropy_source(nodes[0].keys_manager),
&secp_ctx,
payment_id,
diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs
index 0631db3..8db7930 100644
--- a/lightning/src/ln/blinded_payment_tests.rs
+++ b/lightning/src/ln/blinded_payment_tests.rs
@@ -87,7 +87,7 @@ pub fn blinded_payment_path(
};
let nonce = Nonce([42u8; 16]);
- let expanded_key = keys_manager.get_inbound_payment_key();
+ let expanded_key = keys_manager.get_expanded_key();
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
let mut secp_ctx = Secp256k1::new();
@@ -172,7 +172,7 @@ fn do_one_hop_blinded_path(success: bool) {
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
};
let nonce = Nonce([42u8; 16]);
- let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_key();
+ let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key();
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
let mut secp_ctx = Secp256k1::new();
@@ -226,7 +226,7 @@ fn mpp_to_one_hop_blinded_path() {
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
};
let nonce = Nonce([42u8; 16]);
- let expanded_key = chanmon_cfgs[3].keys_manager.get_inbound_payment_key();
+ let expanded_key = chanmon_cfgs[3].keys_manager.get_expanded_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,
@@ -1336,7 +1336,7 @@ fn custom_tlvs_to_blinded_path() {
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
};
let nonce = Nonce([42u8; 16]);
- let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_key();
+ let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key();
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
let mut secp_ctx = Secp256k1::new();
let blinded_path = BlindedPaymentPath::new(
@@ -1390,7 +1390,7 @@ fn fails_receive_tlvs_authentication() {
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
};
let nonce = Nonce([42u8; 16]);
- let expanded_key = chanmon_cfgs[1].keys_manager.get_inbound_payment_key();
+ let expanded_key = chanmon_cfgs[1].keys_manager.get_expanded_key();
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
let mut secp_ctx = Secp256k1::new();
@@ -1622,7 +1622,7 @@ fn route_blinding_spec_test_vector() {
}
Ok(SharedSecret::new(other_key, &node_secret))
}
- fn get_inbound_payment_key(&self) -> ExpandedKey { unreachable!() }
+ fn get_expanded_key(&self) -> ExpandedKey { unreachable!() }
fn get_node_id(&self, _recipient: Recipient) -> Result<PublicKey, ()> { unreachable!() }
fn sign_invoice(
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,
@@ -1935,7 +1935,7 @@ fn test_trampoline_inbound_payment_decoding() {
}
Ok(SharedSecret::new(other_key, &node_secret))
}
- fn get_inbound_payment_key(&self) -> ExpandedKey { unreachable!() }
+ fn get_expanded_key(&self) -> ExpandedKey { unreachable!() }
fn get_node_id(&self, _recipient: Recipient) -> Result<PublicKey, ()> { unreachable!() }
fn sign_invoice(
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,
@@ -2023,7 +2023,7 @@ fn do_test_trampoline_single_hop_receive(success: bool) {
};
let nonce = Nonce([42u8; 16]);
- let expanded_key = nodes[2].keys_manager.get_inbound_payment_key();
+ let expanded_key = nodes[2].keys_manager.get_expanded_key();
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
let carol_unblinded_tlvs = payee_tlvs.encode();
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index c953e39..fa12f1e 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -315,7 +315,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`].
+ /// [`NodeSigner::get_expanded_key`].
has_recipient_created_payment_secret: bool,
/// The [`InvoiceRequest`] associated with the [`Offer`] corresponding to this payment.
invoice_request: Option<InvoiceRequest>,
@@ -3732,7 +3732,7 @@ where
let mut secp_ctx = Secp256k1::new();
secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
- let expanded_inbound_key = node_signer.get_inbound_payment_key();
+ let expanded_inbound_key = node_signer.get_expanded_key();
let our_network_pubkey = node_signer.get_node_id(Recipient::Node).unwrap();
let flow = OffersMessageFlow::new(
@@ -16697,7 +16697,7 @@ where
}
}
- let expanded_inbound_key = args.node_signer.get_inbound_payment_key();
+ let expanded_inbound_key = args.node_signer.get_expanded_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 f7b2a4a..17c2526 100644
--- a/lightning/src/ln/inbound_payment.rs
+++ b/lightning/src/ln/inbound_payment.rs
@@ -37,9 +37,9 @@ 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. Returned by [`NodeSigner::get_inbound_payment_key`].
+/// A set of keys that were HKDF-expanded. Returned by [`NodeSigner::get_expanded_key`].
///
-/// [`NodeSigner::get_inbound_payment_key`]: crate::sign::NodeSigner::get_inbound_payment_key
+/// [`NodeSigner::get_expanded_key`]: crate::sign::NodeSigner::get_expanded_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
@@ -133,7 +133,7 @@ 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`]. It is recommended to
+/// `keys` is generated by calling [`NodeSigner::get_expanded_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.
@@ -142,7 +142,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`]: crate::sign::NodeSigner::get_inbound_payment_key
+/// [`NodeSigner::get_expanded_key`]: crate::sign::NodeSigner::get_expanded_key
pub fn create<ES: Deref>(
keys: &ExpandedKey, min_value_msat: Option<u64>, invoice_expiry_delta_secs: u32,
entropy_source: &ES, current_time: u64, min_final_cltv_expiry_delta: Option<u16>,
@@ -321,7 +321,7 @@ fn construct_payment_secret(
/// 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`].
+/// In both cases the result is then encrypted using a key derived from [`NodeSigner::get_expanded_key`].
///
/// Then on payment receipt, we verify in this method that the payment preimage and payment secret
/// match what was constructed.
@@ -342,7 +342,7 @@ fn construct_payment_secret(
///
/// See [`ExpandedKey`] docs for more info on the individual keys used.
///
-/// [`NodeSigner::get_inbound_payment_key`]: crate::sign::NodeSigner::get_inbound_payment_key
+/// [`NodeSigner::get_expanded_key`]: crate::sign::NodeSigner::get_expanded_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<L: Deref>(
diff --git a/lightning/src/ln/invoice_utils.rs b/lightning/src/ln/invoice_utils.rs
index 509cb2e..c08d4fa 100644
--- a/lightning/src/ln/invoice_utils.rs
+++ b/lightning/src/ln/invoice_utils.rs
@@ -195,7 +195,7 @@ where
},
};
- let keys = node_signer.get_inbound_payment_key();
+ let keys = node_signer.get_expanded_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/max_payment_path_len_tests.rs b/lightning/src/ln/max_payment_path_len_tests.rs
index 4efa105..177050b 100644
--- a/lightning/src/ln/max_payment_path_len_tests.rs
+++ b/lightning/src/ln/max_payment_path_len_tests.rs
@@ -222,7 +222,7 @@ fn one_hop_blinded_path_with_custom_tlv() {
payment_context: PaymentContext::Bolt12Refund(Bolt12RefundContext {}),
};
let nonce = Nonce([42u8; 16]);
- let expanded_key = chanmon_cfgs[2].keys_manager.get_inbound_payment_key();
+ let expanded_key = chanmon_cfgs[2].keys_manager.get_expanded_key();
let payee_tlvs = payee_tlvs.authenticate(nonce, &expanded_key);
let mut secp_ctx = Secp256k1::new();
let blinded_path = BlindedPaymentPath::new(
diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs
index 71f73e0..6d02529 100644
--- a/lightning/src/ln/msgs.rs
+++ b/lightning/src/ln/msgs.rs
@@ -3589,7 +3589,7 @@ where
},
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(receive_tlvs) } => {
let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs;
- let expanded_key = node_signer.get_inbound_payment_key();
+ let expanded_key = node_signer.get_expanded_key();
if tlvs.verify_for_offer_payment(hmac, nonce, &expanded_key).is_err() {
return Err(DecodeError::InvalidValue);
}
@@ -3741,7 +3741,7 @@ where
readable: BlindedTrampolineTlvs::Receive(receive_tlvs),
} => {
let ReceiveTlvs { tlvs, authentication: (hmac, nonce) } = receive_tlvs;
- let expanded_key = node_signer.get_inbound_payment_key();
+ let expanded_key = node_signer.get_expanded_key();
if tlvs.verify_for_offer_payment(hmac, nonce, &expanded_key).is_err() {
return Err(DecodeError::InvalidValue);
}
diff --git a/lightning/src/ln/offers_tests.rs b/lightning/src/ln/offers_tests.rs
index 6c56ecc..c2971b3 100644
--- a/lightning/src/ln/offers_tests.rs
+++ b/lightning/src/ln/offers_tests.rs
@@ -2272,7 +2272,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 = alice.keys_manager.get_inbound_payment_key();
+ let expanded_key = alice.keys_manager.get_expanded_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 057a740..4a3383c 100644
--- a/lightning/src/sign/mod.rs
+++ b/lightning/src/sign/mod.rs
@@ -837,19 +837,25 @@ pub trait EntropySource {
/// A trait that can handle cryptographic operations at the scope level of a node.
pub trait NodeSigner {
- /// Get the [`ExpandedKey`] for use in encrypting and decrypting inbound payment data.
+ /// Get the [`ExpandedKey`] which provides cryptographic material for various Lightning Network operations.
///
- /// 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
- /// this method.
- // This is because LDK avoids storing inbound payment data by encrypting payment data in the
- // payment hash and/or payment secret, therefore for a payment to be receivable by multiple
- // nodes, they must share the key that encrypts this payment data.
+ /// This key set is used for:
+ /// - Encrypting and decrypting inbound payment metadata
+ /// - Authenticating payment hashes (both LDK-provided and user-provided)
+ /// - Supporting BOLT 12 Offers functionality (key derivation and authentication)
+ /// - Authenticating spontaneous payments' metadata
///
/// This method must return the same value each time it is called.
///
+ /// 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
+ /// this method. This is because LDK avoids storing inbound payment data. Instead, this key
+ /// is used to construct a payment secret which is received in the payment onion and used to
+ /// reconstruct the payment preimage. Therefore, for a payment to be receivable by multiple
+ /// nodes, they must share the same key.
+ ///
/// [phantom node payments]: PhantomKeysManager
- fn get_inbound_payment_key(&self) -> ExpandedKey;
+ fn get_expanded_key(&self) -> ExpandedKey;
/// Defines a method to derive a 32-byte encryption key for peer storage.
///
@@ -2184,7 +2190,7 @@ impl NodeSigner for KeysManager {
Ok(SharedSecret::new(other_key, &node_secret))
}
- fn get_inbound_payment_key(&self) -> ExpandedKey {
+ fn get_expanded_key(&self) -> ExpandedKey {
self.inbound_payment_key.clone()
}
@@ -2357,7 +2363,7 @@ impl NodeSigner for PhantomKeysManager {
Ok(SharedSecret::new(other_key, &node_secret))
}
- fn get_inbound_payment_key(&self) -> ExpandedKey {
+ fn get_expanded_key(&self) -> ExpandedKey {
self.inbound_payment_key.clone()
}
diff --git a/lightning/src/util/dyn_signer.rs b/lightning/src/util/dyn_signer.rs
index fc2f632..b040eca 100644
--- a/lightning/src/util/dyn_signer.rs
+++ b/lightning/src/util/dyn_signer.rs
@@ -217,7 +217,7 @@ inner,
fn sign_bolt12_invoice(,
invoice: &crate::offers::invoice::UnsignedBolt12Invoice
) -> Result<secp256k1::schnorr::Signature, ()>,
- fn get_inbound_payment_key(,) -> ExpandedKey,
+ fn get_expanded_key(,) -> ExpandedKey,
fn get_peer_storage_key(,) -> PeerStorageKey,
fn get_receive_auth_key(,) -> ReceiveAuthKey
);
@@ -284,7 +284,7 @@ delegate!(DynPhantomKeysInterface, NodeSigner,
fn sign_invoice(, invoice: &RawBolt11Invoice, recipient: Recipient) -> Result<RecoverableSignature, ()>,
fn sign_bolt12_invoice(, invoice: &crate::offers::invoice::UnsignedBolt12Invoice
) -> Result<secp256k1::schnorr::Signature, ()>,
- fn get_inbound_payment_key(,) -> ExpandedKey,
+ fn get_expanded_key(,) -> ExpandedKey,
fn get_peer_storage_key(,) -> PeerStorageKey,
fn get_receive_auth_key(,) -> ReceiveAuthKey
);
diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs
index e5388b7..22334b1 100644
--- a/lightning/src/util/test_utils.rs
+++ b/lightning/src/util/test_utils.rs
@@ -1550,7 +1550,7 @@ impl TestNodeSigner {
}
impl NodeSigner for TestNodeSigner {
- fn get_inbound_payment_key(&self) -> ExpandedKey {
+ fn get_expanded_key(&self) -> ExpandedKey {
unreachable!()
}
@@ -1636,8 +1636,8 @@ impl NodeSigner for TestKeysInterface {
self.backing.ecdh(recipient, other_key, tweak)
}
- fn get_inbound_payment_key(&self) -> ExpandedKey {
- self.backing.get_inbound_payment_key()
+ fn get_expanded_key(&self) -> ExpandedKey {
+ self.backing.get_expanded_key()
}
fn sign_invoice(
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.