Include a one-hop blinded path in Offer and Refund
authorJeffrey Czyz <jkczyz@gmail.com>
Fri, 3 Mar 2023 15:38:45 +0000 (09:38 -0600)
committerJeffrey Czyz <jkczyz@gmail.com>
Wed, 18 Oct 2023 23:33:14 +0000 (18:33 -0500)
While this doesn't add much privacy over not including any blinded
paths, it allows us to exercise code for receiving on blinded paths.

lightning/src/blinded_path/mod.rs
lightning/src/ln/channelmanager.rs
lightning/src/routing/router.rs

index 896999799fbebed4456f8c53768881698d4e581f..1415836c01fee6cacaa8d2808f28d6d9ecfba37a 100644 (file)
@@ -57,7 +57,7 @@ pub struct BlindedHop {
 
 impl BlindedPath {
        /// Create a one-hop blinded path for a message.
-       pub fn one_hop_for_message<ES: EntropySource, T: secp256k1::Signing + secp256k1::Verification>(
+       pub fn one_hop_for_message<ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification>(
                recipient_node_id: PublicKey, entropy_source: &ES, secp_ctx: &Secp256k1<T>
        ) -> Result<Self, ()> {
                Self::new_for_message(&[recipient_node_id], entropy_source, secp_ctx)
@@ -68,7 +68,7 @@ impl BlindedPath {
        ///
        /// Errors if no hops are provided or if `node_pk`(s) are invalid.
        //  TODO: make all payloads the same size with padding + add dummy hops
-       pub fn new_for_message<ES: EntropySource, T: secp256k1::Signing + secp256k1::Verification>(
+       pub fn new_for_message<ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification>(
                node_pks: &[PublicKey], entropy_source: &ES, secp_ctx: &Secp256k1<T>
        ) -> Result<Self, ()> {
                if node_pks.is_empty() { return Err(()) }
index 3810cfb8171eeca169e29eb5b36f68ca5b23fdfe..113d690215599d87618b535ab6259bab89635a69 100644 (file)
@@ -30,6 +30,7 @@ use bitcoin::secp256k1::{SecretKey,PublicKey};
 use bitcoin::secp256k1::Secp256k1;
 use bitcoin::{LockTime, secp256k1, Sequence};
 
+use crate::blinded_path::BlindedPath;
 use crate::chain;
 use crate::chain::{Confirm, ChannelMonitorUpdateStatus, Watch, BestBlock};
 use crate::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator, LowerBoundedFeeEstimator};
@@ -7130,6 +7131,11 @@ where
        /// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer. The offer will
        /// not have an expiration unless otherwise set on the builder.
        ///
+       /// Uses a one-hop [`BlindedPath`] for the offer with [`ChannelManager::get_our_node_id`] as the
+       /// introduction node and a derived signing pubkey for recipient privacy. As such, currently,
+       /// the node must be announced. Otherwise, there is no way to find a path to the introduction
+       /// node in order to send the [`InvoiceRequest`].
+       ///
        /// [`Offer`]: crate::offers::offer::Offer
        /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
        pub fn create_offer_builder(
@@ -7139,10 +7145,11 @@ where
                let expanded_key = &self.inbound_payment_key;
                let entropy = &*self.entropy_source;
                let secp_ctx = &self.secp_ctx;
+               let path = self.create_one_hop_blinded_path();
 
-               // TODO: Set blinded paths
                OfferBuilder::deriving_signing_pubkey(description, node_id, expanded_key, entropy, secp_ctx)
                        .chain_hash(self.chain_hash)
+                       .path(path)
        }
 
        /// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
@@ -7152,6 +7159,11 @@ where
        ///
        /// The provided `payment_id` is used to ensure that only one invoice is paid for the refund.
        ///
+       /// Uses a one-hop [`BlindedPath`] for the refund with [`ChannelManager::get_our_node_id`] as
+       /// the introduction node and a derived payer id for sender privacy. As such, currently, the
+       /// node must be announced. Otherwise, there is no way to find a path to the introduction node
+       /// in order to send the [`Bolt12Invoice`].
+       ///
        /// [`Refund`]: crate::offers::refund::Refund
        /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
        pub fn create_refund_builder(
@@ -7162,13 +7174,14 @@ where
                let expanded_key = &self.inbound_payment_key;
                let entropy = &*self.entropy_source;
                let secp_ctx = &self.secp_ctx;
+               let path = self.create_one_hop_blinded_path();
 
-               // TODO: Set blinded paths
                let builder = RefundBuilder::deriving_payer_id(
                        description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
                )?
                        .chain_hash(self.chain_hash)
-                       .absolute_expiry(absolute_expiry);
+                       .absolute_expiry(absolute_expiry)
+                       .path(path);
 
                self.pending_outbound_payments
                        .add_new_awaiting_invoice(
@@ -7279,6 +7292,14 @@ where
                inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
        }
 
+       /// Creates a one-hop blinded path with [`ChannelManager::get_our_node_id`] as the introduction
+       /// node.
+       fn create_one_hop_blinded_path(&self) -> BlindedPath {
+               let entropy_source = self.entropy_source.deref();
+               let secp_ctx = &self.secp_ctx;
+               BlindedPath::one_hop_for_message(self.get_our_node_id(), entropy_source, secp_ctx).unwrap()
+       }
+
        /// Gets a fake short channel id for use in receiving [phantom node payments]. These fake scids
        /// are used when constructing the phantom invoice's route hints.
        ///
index 4c8a31bd73533fdf3ca4d19b869c8339edcc2167..104f4c93c3871aca1f0e6f3af73a959e9c13001f 100644 (file)
@@ -90,6 +90,7 @@ pub trait Router {
                &self, payer: &PublicKey, route_params: &RouteParameters,
                first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs
        ) -> Result<Route, LightningError>;
+
        /// Finds a [`Route`] for a payment between the given `payer` and a payee.
        ///
        /// The `payee` and the payment's value are given in [`RouteParameters::payment_params`]