Skip to content

Commit

Permalink
Stateless offer and refund builder utilities
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jkczyz committed Feb 19, 2023
1 parent de41541 commit d68484f
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 4 deletions.
34 changes: 34 additions & 0 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ use crate::ln::outbound_payment;
use crate::ln::outbound_payment::{OutboundPayments, PaymentAttempts, PendingOutboundPayment, Retry};
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;
Expand Down Expand Up @@ -5318,6 +5322,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<RefundBuilder, SemanticError> {
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.
///
Expand Down
5 changes: 4 additions & 1 deletion lightning/src/ln/inbound_payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ impl Nonce {
pub const LENGTH: usize = 16;

/// Creates a `Nonce` from the given [`EntropySource`].
pub fn from_entropy_source<ES: EntropySource>(entropy_source: &ES) -> Self {
pub fn from_entropy_source<ES: Deref>(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]);
Expand Down
1 change: 0 additions & 1 deletion lightning/src/offers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
19 changes: 18 additions & 1 deletion lightning/src/offers/offer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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 {
Expand Down
19 changes: 18 additions & 1 deletion lightning/src/offers/refund.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
//! [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
//! [`Offer`]: crate::offers::offer::Offer
//!
//! # Example
//!
//! ```
//! extern crate bitcoin;
//! extern crate core;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<u8>, payer_id: PublicKey, amount_msats: u64
) -> Result<Self, SemanticError> {
Expand All @@ -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<Self, SemanticError> {
Expand Down

0 comments on commit d68484f

Please sign in to comment.