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.
This commit is contained in:
Jeffrey Czyz 2024-12-04 15:55:30 -06:00
parent bd0dd9b9a8
commit 09bec6eee9
No known key found for this signature in database
GPG Key ID: 912EF12EA67705F5
10 changed files with 43 additions and 47 deletions

View File

@ -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(

View File

@ -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<HashMap<u8, (bool, Arc<Mutex<EnforcementState>>)>>,
}
@ -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<dyn Logger>) {
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()),
});

View File

@ -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!()
}

View File

@ -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<PublicKey, ()> { unreachable!() }
fn sign_invoice(
&self, _invoice: &RawBolt11Invoice, _recipient: Recipient,

View File

@ -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 {

View File

@ -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<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>) -> 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<L: Deref>(payment_hash: PaymentHash, payment_data: &msgs::FinalOnionHopData,

View File

@ -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,

View File

@ -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();

View File

@ -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<secp256k1::All>,
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,
}

View File

@ -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<RecoverableSignature, ()> {