Pass Nonce directly to InvoiceRequestBuilder

When using InvoiceRequestBuilder::deriving_payer_id, the nonce generated
needs to be the same one included in any reply path. This is because the
nonce is used along with the invoice request TLVs to derive a payer id.
While this data is also included in the payer_metadata, including it in
the blinded path would allow reducing the amount of data needed there to
just enough to provide entropy (i.e., 16 bytes). This is more important
for Refund because it can be transmitted via a QR code. But using the
same payer_metadata structure for both InvoiceRequest and Refund would
be beneficial to avoid more code.
This commit is contained in:
Jeffrey Czyz 2024-07-12 11:14:18 -05:00
parent bdf333045c
commit fd596c31b5
No known key found for this signature in database
GPG key ID: 912EF12EA67705F5
3 changed files with 20 additions and 29 deletions

View file

@ -8976,8 +8976,9 @@ where
let entropy = &*self.entropy_source;
let secp_ctx = &self.secp_ctx;
let nonce = Nonce::from_entropy_source(entropy);
let builder: InvoiceRequestBuilder<DerivedPayerId, secp256k1::All> = offer
.request_invoice_deriving_payer_id(expanded_key, entropy, secp_ctx, payment_id)?
.request_invoice_deriving_payer_id(expanded_key, nonce, secp_ctx, payment_id)?
.into();
let builder = builder.chain_hash(self.chain_hash)?;

View file

@ -61,8 +61,6 @@ use bitcoin::blockdata::constants::ChainHash;
use bitcoin::network::Network;
use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, self};
use bitcoin::secp256k1::schnorr::Signature;
use core::ops::Deref;
use crate::sign::EntropySource;
use crate::io;
use crate::blinded_path::BlindedPath;
use crate::ln::types::PaymentHash;
@ -171,11 +169,10 @@ macro_rules! invoice_request_explicit_payer_id_builder_methods { ($self: ident,
}
#[cfg_attr(c_bindings, allow(dead_code))]
pub(super) fn deriving_metadata<ES: Deref>(
offer: &'a Offer, payer_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES,
pub(super) fn deriving_metadata(
offer: &'a Offer, payer_id: PublicKey, expanded_key: &ExpandedKey, nonce: Nonce,
payment_id: PaymentId,
) -> Self where ES::Target: EntropySource {
let nonce = Nonce::from_entropy_source(entropy_source);
) -> Self {
let payment_id = Some(payment_id);
let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, payment_id);
let metadata = Metadata::Derived(derivation_material);
@ -201,11 +198,10 @@ macro_rules! invoice_request_derived_payer_id_builder_methods { (
$self: ident, $self_type: ty, $secp_context: ty
) => {
#[cfg_attr(c_bindings, allow(dead_code))]
pub(super) fn deriving_payer_id<ES: Deref>(
offer: &'a Offer, expanded_key: &ExpandedKey, entropy_source: ES,
pub(super) fn deriving_payer_id(
offer: &'a Offer, expanded_key: &ExpandedKey, nonce: Nonce,
secp_ctx: &'b Secp256k1<$secp_context>, payment_id: PaymentId
) -> Self where ES::Target: EntropySource {
let nonce = Nonce::from_entropy_source(entropy_source);
) -> Self {
let payment_id = Some(payment_id);
let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, payment_id);
let metadata = Metadata::DerivedSigningPubkey(derivation_material);
@ -1403,6 +1399,7 @@ mod tests {
let payer_id = payer_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 payment_id = PaymentId([1; 32]);
@ -1410,7 +1407,7 @@ mod tests {
.amount_msats(1000)
.build().unwrap();
let invoice_request = offer
.request_invoice_deriving_metadata(payer_id, &expanded_key, &entropy, payment_id)
.request_invoice_deriving_metadata(payer_id, &expanded_key, nonce, payment_id)
.unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
@ -1476,6 +1473,7 @@ mod tests {
fn builds_invoice_request_with_derived_payer_id() {
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
let entropy = FixedEntropy {};
let nonce = Nonce::from_entropy_source(&entropy);
let secp_ctx = Secp256k1::new();
let payment_id = PaymentId([1; 32]);
@ -1483,7 +1481,7 @@ mod tests {
.amount_msats(1000)
.build().unwrap();
let invoice_request = offer
.request_invoice_deriving_payer_id(&expanded_key, &entropy, &secp_ctx, payment_id)
.request_invoice_deriving_payer_id(&expanded_key, nonce, &secp_ctx, payment_id)
.unwrap()
.build_and_sign()
.unwrap();

View file

@ -82,10 +82,8 @@ use bitcoin::network::Network;
use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, self};
use core::hash::{Hash, Hasher};
use core::num::NonZeroU64;
use core::ops::Deref;
use core::str::FromStr;
use core::time::Duration;
use crate::sign::EntropySource;
use crate::io;
use crate::blinded_path::BlindedPath;
use crate::ln::channelmanager::PaymentId;
@ -699,25 +697,22 @@ macro_rules! request_invoice_derived_payer_id { ($self: ident, $builder: ty) =>
/// [`Bolt12Invoice::verify`]: crate::offers::invoice::Bolt12Invoice::verify
/// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
pub fn request_invoice_deriving_payer_id<
'a, 'b, ES: Deref,
'a, 'b,
#[cfg(not(c_bindings))]
T: secp256k1::Signing
>(
&'a $self, expanded_key: &ExpandedKey, entropy_source: ES,
&'a $self, expanded_key: &ExpandedKey, nonce: Nonce,
#[cfg(not(c_bindings))]
secp_ctx: &'b Secp256k1<T>,
#[cfg(c_bindings)]
secp_ctx: &'b Secp256k1<secp256k1::All>,
payment_id: PaymentId
) -> Result<$builder, Bolt12SemanticError>
where
ES::Target: EntropySource,
{
) -> Result<$builder, Bolt12SemanticError> {
if $self.offer_features().requires_unknown_bits() {
return Err(Bolt12SemanticError::UnknownRequiredFeatures);
}
Ok(<$builder>::deriving_payer_id($self, expanded_key, entropy_source, secp_ctx, payment_id))
Ok(<$builder>::deriving_payer_id($self, expanded_key, nonce, secp_ctx, payment_id))
}
} }
@ -728,18 +723,15 @@ macro_rules! request_invoice_explicit_payer_id { ($self: ident, $builder: ty) =>
/// Useful for recurring payments using the same `payer_id` with different invoices.
///
/// [`InvoiceRequest::payer_id`]: crate::offers::invoice_request::InvoiceRequest::payer_id
pub fn request_invoice_deriving_metadata<ES: Deref>(
&$self, payer_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES,
pub fn request_invoice_deriving_metadata(
&$self, payer_id: PublicKey, expanded_key: &ExpandedKey, nonce: Nonce,
payment_id: PaymentId
) -> Result<$builder, Bolt12SemanticError>
where
ES::Target: EntropySource,
{
) -> Result<$builder, Bolt12SemanticError> {
if $self.offer_features().requires_unknown_bits() {
return Err(Bolt12SemanticError::UnknownRequiredFeatures);
}
Ok(<$builder>::deriving_metadata($self, payer_id, expanded_key, entropy_source, payment_id))
Ok(<$builder>::deriving_metadata($self, payer_id, expanded_key, nonce, payment_id))
}
/// Creates an [`InvoiceRequestBuilder`] for the offer with the given `metadata` and `payer_id`,