From 4a11100c69b93a37c445aa565dd27e3bb13e2521 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Mon, 13 Feb 2023 21:54:37 -0600 Subject: [PATCH] Stateless offer and refund builder utilities Add utility functions to ChannelManager for creating OfferBuilder and RefundBuilder such that derived keys are used for the signing pubkey and payer id, respectively. This allows for stateless verification of any InvoiceRequest and Invoice messages. Later, blinded paths can be included in the returned builders. --- lightning/src/ln/channelmanager.rs | 34 +++++++++++++++++++++++++++++ lightning/src/ln/inbound_payment.rs | 5 ++++- lightning/src/offers/mod.rs | 1 - lightning/src/offers/offer.rs | 19 +++++++++++++++- lightning/src/offers/refund.rs | 19 +++++++++++++++- 5 files changed, 74 insertions(+), 4 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index d9e690a851c..84b53732849 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -56,6 +56,10 @@ use crate::ln::outbound_payment; use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment}; use crate::ln::wire::Encode; use crate::chain::keysinterface::{EntropySource, KeysManager, NodeSigner, Recipient, SignerProvider, ChannelSigner}; +use crate::offers::offer::OfferBuilder; +use crate::offers::parse::SemanticError; +use crate::offers::refund::RefundBuilder; +use crate::offers::signer::DerivedPubkey; use crate::util::config::{UserConfig, ChannelConfig}; use crate::util::events::{Event, EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination}; use crate::util::events; @@ -5377,6 +5381,36 @@ where Ok(payment_secret) } + /// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the + /// [`OnionMessenger`] when handling [`InvoiceRequest`] messages for the offer. + /// + /// [`Offer`]: crate::offers::offer::Offer + /// [`OnionMessenger`]: crate::onion_message::OnionMessenger + /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest + pub fn create_offer_builder(&self, description: String) -> OfferBuilder { + let nonce = inbound_payment::Nonce::from_entropy_source(&*self.entropy_source); + let signing_pubkey = DerivedPubkey::new(&self.inbound_payment_key, nonce); + + // TODO: Set blinded paths + OfferBuilder::deriving_signing_pubkey(description, signing_pubkey) + } + + /// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the + /// [`OnionMessenger`] when handling [`Invoice`] messages for the refund. + /// + /// [`Refund`]: crate::offers::refund::Refund + /// [`OnionMessenger`]: crate::onion_message::OnionMessenger + /// [`Invoice`]: crate::offers::invoice::Invoice + pub fn create_refund_builder( + &self, description: String, amount_msats: u64 + ) -> Result { + let nonce = inbound_payment::Nonce::from_entropy_source(&*self.entropy_source); + let payer_id = DerivedPubkey::new(&self.inbound_payment_key, nonce); + + // TODO: Set blinded paths + RefundBuilder::deriving_payer_id(description, payer_id, amount_msats) + } + /// Gets a payment secret and payment hash for use in an invoice given to a third party wishing /// to pay us. /// diff --git a/lightning/src/ln/inbound_payment.rs b/lightning/src/ln/inbound_payment.rs index b9a865e7c31..23ed31873ee 100644 --- a/lightning/src/ln/inbound_payment.rs +++ b/lightning/src/ln/inbound_payment.rs @@ -109,7 +109,10 @@ impl Nonce { pub const LENGTH: usize = 16; /// Creates a `Nonce` from the given [`EntropySource`]. - pub fn from_entropy_source(entropy_source: &ES) -> Self { + pub fn from_entropy_source(entropy_source: ES) -> Self + where + ES::Target: EntropySource, + { let mut bytes = [0u8; Self::LENGTH]; let rand_bytes = entropy_source.get_secure_random_bytes(); bytes.copy_from_slice(&rand_bytes[..Self::LENGTH]); diff --git a/lightning/src/offers/mod.rs b/lightning/src/offers/mod.rs index 0fb20f42d79..4762f271d00 100644 --- a/lightning/src/offers/mod.rs +++ b/lightning/src/offers/mod.rs @@ -19,7 +19,6 @@ pub mod offer; pub mod parse; mod payer; pub mod refund; -#[allow(unused)] pub(crate) mod signer; #[cfg(test)] mod test_utils; diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index d5f703b5dd0..5a7e4ff4c9b 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -13,6 +13,8 @@ //! published as a QR code to be scanned by a customer. The customer uses the offer to request an //! invoice from the merchant to be paid. //! +//! # Example +//! //! ``` //! extern crate bitcoin; //! extern crate core; @@ -65,6 +67,14 @@ //! # Ok(()) //! # } //! ``` +//! +//! # Note +//! +//! If constructing an [`Offer`] for use with a [`ChannelManager`], use +//! [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`]. +//! +//! [`ChannelManager`]: crate::ln::channelmanager::ChannelManager +//! [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder use bitcoin::blockdata::constants::ChainHash; use bitcoin::network::constants::Network; @@ -106,6 +116,14 @@ impl OfferBuilder { /// while the offer is valid. /// /// Use a different pubkey per offer to avoid correlating offers. + /// + /// # Note + /// + /// If constructing an [`Offer`] for use with a [`ChannelManager`], use + /// [`ChannelManager::create_offer_builder`] instead of [`OfferBuilder::new`]. + /// + /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager + /// [`ChannelManager::create_offer_builder`]: crate::ln::channelmanager::ChannelManager::create_offer_builder pub fn new(description: String, signing_pubkey: PublicKey) -> Self { let offer = OfferContents { chains: None, metadata: None, amount: None, description, @@ -123,7 +141,6 @@ impl OfferBuilder { /// /// [`InvoiceRequest::verify`]: crate::offers::invoice_request::InvoiceRequest::verify /// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey - #[allow(unused)] pub(crate) fn deriving_signing_pubkey( description: String, signing_pubkey: DerivedPubkey ) -> Self { diff --git a/lightning/src/offers/refund.rs b/lightning/src/offers/refund.rs index d09528b79b9..1c28333b469 100644 --- a/lightning/src/offers/refund.rs +++ b/lightning/src/offers/refund.rs @@ -18,6 +18,8 @@ //! [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest //! [`Offer`]: crate::offers::offer::Offer //! +//! # Example +//! //! ``` //! extern crate bitcoin; //! extern crate core; @@ -70,6 +72,14 @@ //! # Ok(()) //! # } //! ``` +//! +//! # Note +//! +//! If constructing a [`Refund`] for use with a [`ChannelManager`], use +//! [`ChannelManager::create_refund_builder`] instead of [`RefundBuilder::new`]. +//! +//! [`ChannelManager`]: crate::ln::channelmanager::ChannelManager +//! [`ChannelManager::create_refund_builder`]: crate::ln::channelmanager::ChannelManager::create_refund_builder use bitcoin::blockdata::constants::ChainHash; use bitcoin::network::constants::Network; @@ -114,6 +124,14 @@ impl RefundBuilder { /// /// Additionally, sets the required [`Refund::description`], [`Refund::metadata`], and /// [`Refund::amount_msats`]. + /// + /// # Note + /// + /// If constructing a [`Refund`] for use with a [`ChannelManager`], use + /// [`ChannelManager::create_refund_builder`] instead of [`RefundBuilder::new`]. + /// + /// [`ChannelManager`]: crate::ln::channelmanager::ChannelManager + /// [`ChannelManager::create_refund_builder`]: crate::ln::channelmanager::ChannelManager::create_refund_builder pub fn new( description: String, metadata: Vec, payer_id: PublicKey, amount_msats: u64 ) -> Result { @@ -138,7 +156,6 @@ impl RefundBuilder { /// /// [`Invoice::verify`]: crate::offers::invoice::Invoice::verify /// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey - #[allow(unused)] pub(crate) fn deriving_payer_id( description: String, payer_id: DerivedPubkey, amount_msats: u64 ) -> Result {