From 204dd42a7d6167d482cdb09f1fea5b12cd973c44 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Thu, 24 Mar 2022 15:43:40 -0400 Subject: [PATCH] Expose methods for ChannelManager-less phantom invoice generation --- lightning-invoice/src/utils.rs | 16 ++++++++++---- lightning/src/ln/inbound_payment.rs | 33 +++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/lightning-invoice/src/utils.rs b/lightning-invoice/src/utils.rs index 62820cfe..f6affc4d 100644 --- a/lightning-invoice/src/utils.rs +++ b/lightning-invoice/src/utils.rs @@ -38,9 +38,11 @@ use sync::Mutex; /// may be too long for QR code scanning. To fix this, `PhantomRouteHints::channels` may be pared /// down /// -/// `payment_hash` and `payment_secret` come from [`ChannelManager::create_inbound_payment`] or +/// `payment_hash` and `payment_secret` can come from [`ChannelManager::create_inbound_payment`] or /// [`ChannelManager::create_inbound_payment_for_hash`]. These values can be retrieved from any -/// participating node. +/// participating node. Alternatively, [`inbound_payment::create`] or +/// [`inbound_payment::create_from_hash`] may be used to retrieve these values without a +/// `ChannelManager`. /// /// Note that the provided `keys_manager`'s `KeysInterface` implementation must support phantom /// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this @@ -48,6 +50,8 @@ use sync::Mutex; /// /// [`PhantomKeysManager`]: lightning::chain::keysinterface::PhantomKeysManager /// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints +/// [`inbound_payment::create`]: lightning::ln::inbound_payment::create +/// [`inbound_payment::create_from_hash`]: lightning::ln::inbound_payment::create_from_hash /// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels pub fn create_phantom_invoice( amt_msat: Option, description: String, payment_hash: PaymentHash, payment_secret: PaymentSecret, @@ -76,9 +80,11 @@ pub fn create_phantom_invoice( /// /// `description_hash` is a SHA-256 hash of the description text /// -/// `payment_hash` and `payment_secret` come from [`ChannelManager::create_inbound_payment`] or +/// `payment_hash` and `payment_secret` can come from [`ChannelManager::create_inbound_payment`] or /// [`ChannelManager::create_inbound_payment_for_hash`]. These values can be retrieved from any -/// participating node. +/// participating node. Alternatively, [`inbound_payment::create`] or +/// [`inbound_payment::create_from_hash`] may be used to retrieve these values without a +/// `ChannelManager`. /// /// Note that the provided `keys_manager`'s `KeysInterface` implementation must support phantom /// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this @@ -86,6 +92,8 @@ pub fn create_phantom_invoice( /// /// [`PhantomKeysManager`]: lightning::chain::keysinterface::PhantomKeysManager /// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints +/// [`inbound_payment::create`]: lightning::ln::inbound_payment::create +/// [`inbound_payment::create_from_hash`]: lightning::ln::inbound_payment::create_from_hash /// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels pub fn create_phantom_invoice_with_description_hash( amt_msat: Option, description_hash: Sha256, payment_hash: PaymentHash, diff --git a/lightning/src/ln/inbound_payment.rs b/lightning/src/ln/inbound_payment.rs index f7fbb489..8ed77e5a 100644 --- a/lightning/src/ln/inbound_payment.rs +++ b/lightning/src/ln/inbound_payment.rs @@ -38,7 +38,7 @@ const METHOD_TYPE_OFFSET: usize = 5; /// [`KeysInterface::get_inbound_payment_key_material`]. /// /// [`KeysInterface::get_inbound_payment_key_material`]: crate::chain::keysinterface::KeysInterface::get_inbound_payment_key_material -pub(super) struct ExpandedKey { +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). metadata_key: [u8; 32], @@ -51,7 +51,10 @@ pub(super) struct ExpandedKey { } impl ExpandedKey { - pub(super) fn new(key_material: &KeyMaterial) -> 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 { let (metadata_key, ldk_pmt_hash_key, user_pmt_hash_key) = hkdf_extract_expand_thrice(b"LDK Inbound Payment Key Expansion", &key_material.0); Self { @@ -77,10 +80,21 @@ impl Method { } } -pub(super) fn create(keys: &ExpandedKey, min_value_msat: Option, invoice_expiry_delta_secs: u32, keys_manager: &K, highest_seen_timestamp: u64) -> Result<(PaymentHash, PaymentSecret), ()> +/// Equivalent to [`crate::ln::channelmanager::ChannelManager::create_inbound_payment`], but no +/// `ChannelManager` is required. Useful for generating invoices for [phantom node payments] without +/// a `ChannelManager`. +/// +/// `keys` is generated by calling [`KeysInterface::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. +/// +/// `current_time` is a Unix timestamp representing the current time. +/// +/// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager +pub fn create(keys: &ExpandedKey, min_value_msat: Option, invoice_expiry_delta_secs: u32, keys_manager: &K, current_time: u64) -> Result<(PaymentHash, PaymentSecret), ()> where K::Target: KeysInterface { - let metadata_bytes = construct_metadata_bytes(min_value_msat, Method::LdkPaymentHash, invoice_expiry_delta_secs, highest_seen_timestamp)?; + let metadata_bytes = construct_metadata_bytes(min_value_msat, Method::LdkPaymentHash, invoice_expiry_delta_secs, current_time)?; let mut iv_bytes = [0 as u8; IV_LEN]; let rand_bytes = keys_manager.get_secure_random_bytes(); @@ -96,8 +110,15 @@ pub(super) fn create(keys: &ExpandedKey, min_value_msat: Ok((ldk_pmt_hash, payment_secret)) } -pub(super) fn create_from_hash(keys: &ExpandedKey, min_value_msat: Option, payment_hash: PaymentHash, invoice_expiry_delta_secs: u32, highest_seen_timestamp: u64) -> Result { - let metadata_bytes = construct_metadata_bytes(min_value_msat, Method::UserPaymentHash, invoice_expiry_delta_secs, highest_seen_timestamp)?; +/// Equivalent to [`crate::ln::channelmanager::ChannelManager::create_inbound_payment_for_hash`], +/// but no `ChannelManager` is required. Useful for generating invoices for [phantom node payments] +/// without a `ChannelManager`. +/// +/// See [`create`] for information on the `keys` and `current_time` parameters. +/// +/// [phantom node payments]: crate::chain::keysinterface::PhantomKeysManager +pub fn create_from_hash(keys: &ExpandedKey, min_value_msat: Option, payment_hash: PaymentHash, invoice_expiry_delta_secs: u32, current_time: u64) -> Result { + let metadata_bytes = construct_metadata_bytes(min_value_msat, Method::UserPaymentHash, invoice_expiry_delta_secs, current_time)?; let mut hmac = HmacEngine::::new(&keys.user_pmt_hash_key); hmac.input(&metadata_bytes); -- 2.30.2