From 219691f9ef7b709fbb128cd39e9559ee02b50e18 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Wed, 19 Jun 2024 12:42:16 -0500 Subject: [PATCH] Pass Nonce directly to OfferBuilder When using OfferBuilder::deriving_signing_pubkey, the nonce generated needs to be the same one included in any OfferBuilder::paths. This is because the nonce is used along with the offer TLVs to derive a signing pubkey and will soon be elided from the metadata entirely. --- lightning/src/ln/channelmanager.rs | 7 ++-- lightning/src/offers/invoice.rs | 8 ++-- lightning/src/offers/invoice_request.rs | 5 ++- lightning/src/offers/offer.rs | 22 +++++----- lightning/src/offers/static_invoice.rs | 55 ++++++++++++++----------- 5 files changed, 51 insertions(+), 46 deletions(-) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 9bceb5816..34267aded 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -64,6 +64,7 @@ use crate::ln::wire::Encode; use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice}; use crate::offers::invoice_error::InvoiceError; use crate::offers::invoice_request::{DerivedPayerId, InvoiceRequestBuilder}; +use crate::offers::nonce::Nonce; use crate::offers::offer::{Offer, OfferBuilder}; use crate::offers::parse::Bolt12SemanticError; use crate::offers::refund::{Refund, RefundBuilder}; @@ -8784,13 +8785,11 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => { let entropy = &*$self.entropy_source; let secp_ctx = &$self.secp_ctx; + let nonce = Nonce::from_entropy_source(entropy); let path = $self.create_blinded_paths_using_absolute_expiry(OffersContext::Unknown {}, absolute_expiry) .and_then(|paths| paths.into_iter().next().ok_or(())) .map_err(|_| Bolt12SemanticError::MissingPaths)?; - - let builder = OfferBuilder::deriving_signing_pubkey( - node_id, expanded_key, entropy, secp_ctx - ) + let builder = OfferBuilder::deriving_signing_pubkey(node_id, expanded_key, nonce, secp_ctx) .chain_hash($self.chain_hash) .path(path); diff --git a/lightning/src/offers/invoice.rs b/lightning/src/offers/invoice.rs index 3f96e703b..cfe97afd1 100644 --- a/lightning/src/offers/invoice.rs +++ b/lightning/src/offers/invoice.rs @@ -1416,6 +1416,7 @@ mod tests { use crate::ln::msgs::DecodeError; use crate::offers::invoice_request::InvoiceRequestTlvStreamRef; use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self}; + use crate::offers::nonce::Nonce; use crate::offers::offer::{Amount, OfferTlvStreamRef, Quantity}; use crate::prelude::*; #[cfg(not(c_bindings))] @@ -1752,6 +1753,7 @@ mod tests { let node_id = recipient_pubkey(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath { @@ -1765,8 +1767,7 @@ mod tests { #[cfg(c_bindings)] use crate::offers::offer::OfferWithDerivedMetadataBuilder as OfferBuilder; - let offer = OfferBuilder - ::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .amount_msats(1000) .path(blinded_path) .build().unwrap(); @@ -1785,8 +1786,7 @@ mod tests { let expanded_key = ExpandedKey::new(&KeyMaterial([41; 32])); assert!(invoice_request.verify(&expanded_key, &secp_ctx).is_err()); - let offer = OfferBuilder - ::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .amount_msats(1000) // Omit the path so that node_id is used for the signing pubkey instead of deriving .build().unwrap(); diff --git a/lightning/src/offers/invoice_request.rs b/lightning/src/offers/invoice_request.rs index b9ccc5f4d..3b45f9511 100644 --- a/lightning/src/offers/invoice_request.rs +++ b/lightning/src/offers/invoice_request.rs @@ -1217,6 +1217,7 @@ mod tests { use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; use crate::offers::invoice::{Bolt12Invoice, SIGNATURE_TAG as INVOICE_SIGNATURE_TAG}; use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self}; + use crate::offers::nonce::Nonce; use crate::offers::offer::{Amount, OfferTlvStreamRef, Quantity}; #[cfg(not(c_bindings))] use { @@ -2274,12 +2275,12 @@ mod tests { let node_id = recipient_pubkey(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); #[cfg(c_bindings)] use crate::offers::offer::OfferWithDerivedMetadataBuilder as OfferBuilder; - let offer = OfferBuilder - ::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .chain(Network::Testnet) .amount_msats(1000) .supported_quantity(Quantity::Unbounded) diff --git a/lightning/src/offers/offer.rs b/lightning/src/offers/offer.rs index 03e1e92a4..674cfeaa1 100644 --- a/lightning/src/offers/offer.rs +++ b/lightning/src/offers/offer.rs @@ -243,9 +243,9 @@ macro_rules! offer_explicit_metadata_builder_methods { ( macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => { /// Similar to [`OfferBuilder::new`] except, if [`OfferBuilder::path`] is called, the signing - /// pubkey is derived from the given [`ExpandedKey`] and [`EntropySource`]. This provides - /// recipient privacy by using a different signing pubkey for each offer. Otherwise, the - /// provided `node_id` is used for the signing pubkey. + /// pubkey is derived from the given [`ExpandedKey`] and [`Nonce`]. This provides recipient + /// privacy by using a different signing pubkey for each offer. Otherwise, the provided + /// `node_id` is used for the signing pubkey. /// /// Also, sets the metadata when [`OfferBuilder::build`] is called such that it can be used by /// [`InvoiceRequest::verify`] to determine if the request was produced for the offer given an @@ -253,11 +253,10 @@ macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => { /// /// [`InvoiceRequest::verify`]: crate::offers::invoice_request::InvoiceRequest::verify /// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey - pub fn deriving_signing_pubkey( - node_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES, + pub fn deriving_signing_pubkey( + node_id: PublicKey, expanded_key: &ExpandedKey, nonce: Nonce, secp_ctx: &'a Secp256k1<$secp_context> - ) -> Self where ES::Target: EntropySource { - let nonce = Nonce::from_entropy_source(entropy_source); + ) -> Self { let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, None); let metadata = Metadata::DerivedSigningPubkey(derivation_material); Self { @@ -1164,6 +1163,7 @@ mod tests { use crate::ln::features::OfferFeatures; use crate::ln::inbound_payment::ExpandedKey; use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; + use crate::offers::nonce::Nonce; use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError}; use crate::offers::test_utils::*; use crate::util::ser::{BigSize, Writeable}; @@ -1278,12 +1278,12 @@ mod tests { let node_id = recipient_pubkey(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); #[cfg(c_bindings)] use super::OfferWithDerivedMetadataBuilder as OfferBuilder; - let offer = OfferBuilder - ::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .amount_msats(1000) .build().unwrap(); assert_eq!(offer.signing_pubkey(), Some(node_id)); @@ -1329,6 +1329,7 @@ mod tests { let node_id = recipient_pubkey(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); let blinded_path = BlindedPath { @@ -1342,8 +1343,7 @@ mod tests { #[cfg(c_bindings)] use super::OfferWithDerivedMetadataBuilder as OfferBuilder; - let offer = OfferBuilder - ::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .amount_msats(1000) .path(blinded_path) .build().unwrap(); diff --git a/lightning/src/offers/static_invoice.rs b/lightning/src/offers/static_invoice.rs index 69f4073e6..7c084ba3e 100644 --- a/lightning/src/offers/static_invoice.rs +++ b/lightning/src/offers/static_invoice.rs @@ -565,6 +565,7 @@ mod tests { use crate::offers::invoice::InvoiceTlvStreamRef; use crate::offers::merkle; use crate::offers::merkle::{SignatureTlvStreamRef, TaggedHash}; + use crate::offers::nonce::Nonce; use crate::offers::offer::{Offer, OfferBuilder, OfferTlvStreamRef, Quantity}; use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError}; use crate::offers::static_invoice::{ @@ -608,13 +609,13 @@ mod tests { let now = now(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); - let offer = - OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) - .path(blinded_path()) - .build() - .unwrap(); + let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) + .path(blinded_path()) + .build() + .unwrap(); StaticInvoiceBuilder::for_offer_using_derived_keys( &offer, @@ -647,13 +648,13 @@ mod tests { let now = now(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); - let offer = - OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) - .path(blinded_path()) - .build() - .unwrap(); + let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) + .path(blinded_path()) + .build() + .unwrap(); let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys( &offer, @@ -742,13 +743,14 @@ mod tests { let now = now(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); let future_expiry = Duration::from_secs(u64::max_value()); let past_expiry = Duration::from_secs(0); let valid_offer = - OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .path(blinded_path()) .absolute_expiry(future_expiry) .build() @@ -769,7 +771,7 @@ mod tests { assert_eq!(invoice.absolute_expiry(), Some(future_expiry)); let expired_offer = - OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .path(blinded_path()) .absolute_expiry(past_expiry) .build() @@ -797,10 +799,11 @@ mod tests { let now = now(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); let valid_offer = - OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .path(blinded_path()) .build() .unwrap(); @@ -860,10 +863,11 @@ mod tests { let now = now(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); let valid_offer = - OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .path(blinded_path()) .build() .unwrap(); @@ -916,10 +920,11 @@ mod tests { let now = now(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); let offer_with_extra_chain = - OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) + OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) .path(blinded_path()) .chain(Network::Bitcoin) .chain(Network::Testnet) @@ -947,13 +952,13 @@ mod tests { let now = now(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); - let offer = - OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) - .path(blinded_path()) - .build() - .unwrap(); + let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) + .path(blinded_path()) + .build() + .unwrap(); const TEST_RELATIVE_EXPIRY: u32 = 3600; let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys( @@ -988,13 +993,13 @@ mod tests { let now = now(); let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32])); let entropy = FixedEntropy {}; + let nonce = Nonce::from_entropy_source(&entropy); let secp_ctx = Secp256k1::new(); - let offer = - OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, &entropy, &secp_ctx) - .path(blinded_path()) - .build() - .unwrap(); + let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx) + .path(blinded_path()) + .build() + .unwrap(); let invoice = StaticInvoiceBuilder::for_offer_using_derived_keys( &offer, -- 2.39.5