5555//! .allow_mpp()
5656//! .fallback_v0_p2wpkh(&wpubkey_hash)
5757//! .build()?
58- //! .sign::<_, Infallible>(|digest| Ok(secp_ctx.sign_schnorr_no_aux_rand(digest, &keys)))
58+ //! .sign::<_, Infallible>(
59+ //! |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
60+ //! )
5961//! .expect("failed verifying signature")
6062//! .write(&mut buffer)
6163//! .unwrap();
8486//! .allow_mpp()
8587//! .fallback_v0_p2wpkh(&wpubkey_hash)
8688//! .build()?
87- //! .sign::<_, Infallible>(|digest| Ok(secp_ctx.sign_schnorr_no_aux_rand(digest, &keys)))
89+ //! .sign::<_, Infallible>(
90+ //! |message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
91+ //! )
8892//! .expect("failed verifying signature")
8993//! .write(&mut buffer)
9094//! .unwrap();
@@ -97,11 +101,11 @@ use bitcoin::blockdata::constants::ChainHash;
97101use bitcoin:: hash_types:: { WPubkeyHash , WScriptHash } ;
98102use bitcoin:: hashes:: Hash ;
99103use bitcoin:: network:: constants:: Network ;
100- use bitcoin:: secp256k1:: { KeyPair , Message , PublicKey , Secp256k1 , self } ;
104+ use bitcoin:: secp256k1:: { KeyPair , PublicKey , Secp256k1 , self } ;
101105use bitcoin:: secp256k1:: schnorr:: Signature ;
102106use bitcoin:: util:: address:: { Address , Payload , WitnessVersion } ;
103107use bitcoin:: util:: schnorr:: TweakedPublicKey ;
104- use core:: convert:: { Infallible , TryFrom } ;
108+ use core:: convert:: { AsRef , Infallible , TryFrom } ;
105109use core:: time:: Duration ;
106110use crate :: io;
107111use crate :: blinded_path:: BlindedPath ;
@@ -110,7 +114,7 @@ use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures};
110114use crate :: ln:: inbound_payment:: ExpandedKey ;
111115use crate :: ln:: msgs:: DecodeError ;
112116use crate :: offers:: invoice_request:: { INVOICE_REQUEST_PAYER_ID_TYPE , INVOICE_REQUEST_TYPES , IV_BYTES as INVOICE_REQUEST_IV_BYTES , InvoiceRequest , InvoiceRequestContents , InvoiceRequestTlvStream , InvoiceRequestTlvStreamRef } ;
113- use crate :: offers:: merkle:: { SignError , SignatureTlvStream , SignatureTlvStreamRef , TlvStream , WithoutSignatures , self } ;
117+ use crate :: offers:: merkle:: { SignError , SignatureTlvStream , SignatureTlvStreamRef , TaggedHash , TlvStream , WithoutSignatures , self } ;
114118use crate :: offers:: offer:: { Amount , OFFER_TYPES , OfferTlvStream , OfferTlvStreamRef } ;
115119use crate :: offers:: parse:: { Bolt12ParseError , Bolt12SemanticError , ParsedMessage } ;
116120use crate :: offers:: payer:: { PAYER_METADATA_TYPE , PayerTlvStream , PayerTlvStreamRef } ;
@@ -126,7 +130,8 @@ use std::time::SystemTime;
126130
127131const DEFAULT_RELATIVE_EXPIRY : Duration = Duration :: from_secs ( 7200 ) ;
128132
129- pub ( super ) const SIGNATURE_TAG : & ' static str = concat ! ( "lightning" , "invoice" , "signature" ) ;
133+ /// Tag for the hash function used when signing a [`Bolt12Invoice`]'s merkle root.
134+ pub const SIGNATURE_TAG : & ' static str = concat ! ( "lightning" , "invoice" , "signature" ) ;
130135
131136/// Builds a [`Bolt12Invoice`] from either:
132137/// - an [`InvoiceRequest`] for the "offer to be paid" flow or
@@ -331,15 +336,15 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
331336impl < ' a > InvoiceBuilder < ' a , ExplicitSigningPubkey > {
332337 /// Builds an unsigned [`Bolt12Invoice`] after checking for valid semantics. It can be signed by
333338 /// [`UnsignedBolt12Invoice::sign`].
334- pub fn build ( self ) -> Result < UnsignedBolt12Invoice < ' a > , Bolt12SemanticError > {
339+ pub fn build ( self ) -> Result < UnsignedBolt12Invoice , Bolt12SemanticError > {
335340 #[ cfg( feature = "std" ) ] {
336341 if self . invoice . is_offer_or_refund_expired ( ) {
337342 return Err ( Bolt12SemanticError :: AlreadyExpired ) ;
338343 }
339344 }
340345
341346 let InvoiceBuilder { invreq_bytes, invoice, .. } = self ;
342- Ok ( UnsignedBolt12Invoice { invreq_bytes, invoice } )
347+ Ok ( UnsignedBolt12Invoice :: new ( invreq_bytes, invoice) )
343348 }
344349}
345350
@@ -355,23 +360,42 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
355360 }
356361
357362 let InvoiceBuilder { invreq_bytes, invoice, keys, .. } = self ;
358- let unsigned_invoice = UnsignedBolt12Invoice { invreq_bytes, invoice } ;
363+ let unsigned_invoice = UnsignedBolt12Invoice :: new ( invreq_bytes, invoice) ;
359364
360365 let keys = keys. unwrap ( ) ;
361366 let invoice = unsigned_invoice
362- . sign :: < _ , Infallible > ( |digest| Ok ( secp_ctx. sign_schnorr_no_aux_rand ( digest, & keys) ) )
367+ . sign :: < _ , Infallible > (
368+ |message| Ok ( secp_ctx. sign_schnorr_no_aux_rand ( message. as_ref ( ) . as_digest ( ) , & keys) )
369+ )
363370 . unwrap ( ) ;
364371 Ok ( invoice)
365372 }
366373}
367374
368375/// A semantically valid [`Bolt12Invoice`] that hasn't been signed.
369- pub struct UnsignedBolt12Invoice < ' a > {
370- invreq_bytes : & ' a Vec < u8 > ,
376+ pub struct UnsignedBolt12Invoice {
377+ bytes : Vec < u8 > ,
371378 invoice : InvoiceContents ,
379+ tagged_hash : TaggedHash ,
372380}
373381
374- impl < ' a > UnsignedBolt12Invoice < ' a > {
382+ impl UnsignedBolt12Invoice {
383+ fn new ( invreq_bytes : & [ u8 ] , invoice : InvoiceContents ) -> Self {
384+ // Use the invoice_request bytes instead of the invoice_request TLV stream as the latter may
385+ // have contained unknown TLV records, which are not stored in `InvoiceRequestContents` or
386+ // `RefundContents`.
387+ let ( _, _, _, invoice_tlv_stream) = invoice. as_tlv_stream ( ) ;
388+ let invoice_request_bytes = WithoutSignatures ( invreq_bytes) ;
389+ let unsigned_tlv_stream = ( invoice_request_bytes, invoice_tlv_stream) ;
390+
391+ let mut bytes = Vec :: new ( ) ;
392+ unsigned_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
393+
394+ let tagged_hash = TaggedHash :: new ( SIGNATURE_TAG , & bytes) ;
395+
396+ Self { bytes, invoice, tagged_hash }
397+ }
398+
375399 /// The public key corresponding to the key needed to sign the invoice.
376400 pub fn signing_pubkey ( & self ) -> PublicKey {
377401 self . invoice . fields ( ) . signing_pubkey
@@ -380,37 +404,33 @@ impl<'a> UnsignedBolt12Invoice<'a> {
380404 /// Signs the invoice using the given function.
381405 ///
382406 /// This is not exported to bindings users as functions aren't currently mapped.
383- pub fn sign < F , E > ( self , sign : F ) -> Result < Bolt12Invoice , SignError < E > >
407+ pub fn sign < F , E > ( mut self , sign : F ) -> Result < Bolt12Invoice , SignError < E > >
384408 where
385- F : FnOnce ( & Message ) -> Result < Signature , E >
409+ F : FnOnce ( & Self ) -> Result < Signature , E >
386410 {
387- // Use the invoice_request bytes instead of the invoice_request TLV stream as the latter may
388- // have contained unknown TLV records, which are not stored in `InvoiceRequestContents` or
389- // `RefundContents`.
390- let ( _, _, _, invoice_tlv_stream) = self . invoice . as_tlv_stream ( ) ;
391- let invoice_request_bytes = WithoutSignatures ( self . invreq_bytes ) ;
392- let unsigned_tlv_stream = ( invoice_request_bytes, invoice_tlv_stream) ;
393-
394- let mut bytes = Vec :: new ( ) ;
395- unsigned_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
396-
397411 let pubkey = self . invoice . fields ( ) . signing_pubkey ;
398- let signature = merkle:: sign_message ( sign, SIGNATURE_TAG , & bytes , pubkey) ?;
412+ let signature = merkle:: sign_message ( sign, & self , pubkey) ?;
399413
400414 // Append the signature TLV record to the bytes.
401415 let signature_tlv_stream = SignatureTlvStreamRef {
402416 signature : Some ( & signature) ,
403417 } ;
404- signature_tlv_stream. write ( & mut bytes) . unwrap ( ) ;
418+ signature_tlv_stream. write ( & mut self . bytes ) . unwrap ( ) ;
405419
406420 Ok ( Bolt12Invoice {
407- bytes,
421+ bytes : self . bytes ,
408422 contents : self . invoice ,
409423 signature,
410424 } )
411425 }
412426}
413427
428+ impl AsRef < TaggedHash > for UnsignedBolt12Invoice {
429+ fn as_ref ( & self ) -> & TaggedHash {
430+ & self . tagged_hash
431+ }
432+ }
433+
414434/// A `Bolt12Invoice` is a payment request, typically corresponding to an [`Offer`] or a [`Refund`].
415435///
416436/// An invoice may be sent in response to an [`InvoiceRequest`] in the case of an offer or sent
@@ -1686,15 +1706,14 @@ mod tests {
16861706 . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
16871707 . build ( ) . unwrap ( )
16881708 . sign ( payer_sign) . unwrap ( ) ;
1689- let mut unsigned_invoice = invoice_request
1709+ let mut invoice_builder = invoice_request
16901710 . respond_with_no_std ( payment_paths ( ) , payment_hash ( ) , now ( ) ) . unwrap ( )
16911711 . fallback_v0_p2wsh ( & script. wscript_hash ( ) )
16921712 . fallback_v0_p2wpkh ( & pubkey. wpubkey_hash ( ) . unwrap ( ) )
1693- . fallback_v1_p2tr_tweaked ( & tweaked_pubkey)
1694- . build ( ) . unwrap ( ) ;
1713+ . fallback_v1_p2tr_tweaked ( & tweaked_pubkey) ;
16951714
16961715 // Only standard addresses will be included.
1697- let fallbacks = unsigned_invoice . invoice . fields_mut ( ) . fallbacks . as_mut ( ) . unwrap ( ) ;
1716+ let fallbacks = invoice_builder . invoice . fields_mut ( ) . fallbacks . as_mut ( ) . unwrap ( ) ;
16981717 // Non-standard addresses
16991718 fallbacks. push ( FallbackAddress { version : 1 , program : vec ! [ 0u8 ; 41 ] } ) ;
17001719 fallbacks. push ( FallbackAddress { version : 2 , program : vec ! [ 0u8 ; 1 ] } ) ;
@@ -1703,7 +1722,7 @@ mod tests {
17031722 fallbacks. push ( FallbackAddress { version : 1 , program : vec ! [ 0u8 ; 33 ] } ) ;
17041723 fallbacks. push ( FallbackAddress { version : 2 , program : vec ! [ 0u8 ; 40 ] } ) ;
17051724
1706- let invoice = unsigned_invoice . sign ( recipient_sign) . unwrap ( ) ;
1725+ let invoice = invoice_builder . build ( ) . unwrap ( ) . sign ( recipient_sign) . unwrap ( ) ;
17071726 let mut buffer = Vec :: new ( ) ;
17081727 invoice. write ( & mut buffer) . unwrap ( ) ;
17091728
0 commit comments