@@ -424,6 +424,24 @@ pub struct InvoiceRequest {
424424 signature : Signature ,
425425}
426426
427+ /// An [`InvoiceRequest`] that has been verified by [`InvoiceRequest::verify`] and exposes different
428+ /// ways to respond depending on whether the signing keys were derived.
429+ #[ derive( Clone , Debug ) ]
430+ pub struct VerifiedInvoiceRequest {
431+ /// The verified request.
432+ inner : InvoiceRequest ,
433+
434+ /// Keys used for signing a [`Bolt12Invoice`] if they can be derived.
435+ ///
436+ /// If `Some`, must call [`respond_using_derived_keys`] when responding. Otherwise, call
437+ /// [`respond_with`].
438+ ///
439+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
440+ /// [`respond_using_derived_keys`]: Self::respond_using_derived_keys
441+ /// [`respond_with`]: Self::respond_with
442+ pub keys : Option < KeyPair > ,
443+ }
444+
427445/// The contents of an [`InvoiceRequest`], which may be shared with an [`Bolt12Invoice`].
428446///
429447/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
@@ -556,6 +574,63 @@ impl InvoiceRequest {
556574 InvoiceBuilder :: for_offer ( self , payment_paths, created_at, payment_hash)
557575 }
558576
577+ /// Verifies that the request was for an offer created using the given key. Returns the verified
578+ /// request along with the derived keys needed to sign a [`Bolt12Invoice`] for the request if
579+ /// they could be extracted from the metadata.
580+ ///
581+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
582+ pub fn verify < T : secp256k1:: Signing > (
583+ self , key : & ExpandedKey , secp_ctx : & Secp256k1 < T >
584+ ) -> Result < VerifiedInvoiceRequest , ( ) > {
585+ let keys = self . contents . inner . offer . verify ( & self . bytes , key, secp_ctx) ?;
586+ Ok ( VerifiedInvoiceRequest {
587+ inner : self ,
588+ keys,
589+ } )
590+ }
591+
592+ #[ cfg( test) ]
593+ fn as_tlv_stream ( & self ) -> FullInvoiceRequestTlvStreamRef {
594+ let ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream) =
595+ self . contents . as_tlv_stream ( ) ;
596+ let signature_tlv_stream = SignatureTlvStreamRef {
597+ signature : Some ( & self . signature ) ,
598+ } ;
599+ ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, signature_tlv_stream)
600+ }
601+ }
602+
603+ impl VerifiedInvoiceRequest {
604+ offer_accessors ! ( self , self . inner. contents. inner. offer) ;
605+ invoice_request_accessors ! ( self , self . inner. contents) ;
606+
607+ /// Creates an [`InvoiceBuilder`] for the request with the given required fields and using the
608+ /// [`Duration`] since [`std::time::SystemTime::UNIX_EPOCH`] as the creation time.
609+ ///
610+ /// See [`InvoiceRequest::respond_with_no_std`] for further details.
611+ ///
612+ /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
613+ ///
614+ /// [`Duration`]: core::time::Duration
615+ #[ cfg( feature = "std" ) ]
616+ pub fn respond_with (
617+ & self , payment_paths : Vec < ( BlindedPayInfo , BlindedPath ) > , payment_hash : PaymentHash
618+ ) -> Result < InvoiceBuilder < ExplicitSigningPubkey > , Bolt12SemanticError > {
619+ self . inner . respond_with ( payment_paths, payment_hash)
620+ }
621+
622+ /// Creates an [`InvoiceBuilder`] for the request with the given required fields.
623+ ///
624+ /// See [`InvoiceRequest::respond_with_no_std`] for further details.
625+ ///
626+ /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
627+ pub fn respond_with_no_std (
628+ & self , payment_paths : Vec < ( BlindedPayInfo , BlindedPath ) > , payment_hash : PaymentHash ,
629+ created_at : core:: time:: Duration
630+ ) -> Result < InvoiceBuilder < ExplicitSigningPubkey > , Bolt12SemanticError > {
631+ self . inner . respond_with_no_std ( payment_paths, payment_hash, created_at)
632+ }
633+
559634 /// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses
560635 /// derived signing keys from the originating [`Offer`] to sign the [`Bolt12Invoice`]. Must use
561636 /// the same [`ExpandedKey`] as the one used to create the offer.
@@ -566,17 +641,14 @@ impl InvoiceRequest {
566641 ///
567642 /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
568643 #[ cfg( feature = "std" ) ]
569- pub fn verify_and_respond_using_derived_keys < T : secp256k1:: Signing > (
570- & self , payment_paths : Vec < ( BlindedPayInfo , BlindedPath ) > , payment_hash : PaymentHash ,
571- expanded_key : & ExpandedKey , secp_ctx : & Secp256k1 < T >
644+ pub fn respond_using_derived_keys (
645+ & self , payment_paths : Vec < ( BlindedPayInfo , BlindedPath ) > , payment_hash : PaymentHash
572646 ) -> Result < InvoiceBuilder < DerivedSigningPubkey > , Bolt12SemanticError > {
573647 let created_at = std:: time:: SystemTime :: now ( )
574648 . duration_since ( std:: time:: SystemTime :: UNIX_EPOCH )
575649 . expect ( "SystemTime::now() should come after SystemTime::UNIX_EPOCH" ) ;
576650
577- self . verify_and_respond_using_derived_keys_no_std (
578- payment_paths, payment_hash, created_at, expanded_key, secp_ctx
579- )
651+ self . respond_using_derived_keys_no_std ( payment_paths, payment_hash, created_at)
580652 }
581653
582654 /// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses
@@ -588,42 +660,22 @@ impl InvoiceRequest {
588660 /// This is not exported to bindings users as builder patterns don't map outside of move semantics.
589661 ///
590662 /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
591- pub fn verify_and_respond_using_derived_keys_no_std < T : secp256k1 :: Signing > (
663+ pub fn respond_using_derived_keys_no_std (
592664 & self , payment_paths : Vec < ( BlindedPayInfo , BlindedPath ) > , payment_hash : PaymentHash ,
593- created_at : core:: time:: Duration , expanded_key : & ExpandedKey , secp_ctx : & Secp256k1 < T >
665+ created_at : core:: time:: Duration
594666 ) -> Result < InvoiceBuilder < DerivedSigningPubkey > , Bolt12SemanticError > {
595- if self . invoice_request_features ( ) . requires_unknown_bits ( ) {
667+ if self . inner . invoice_request_features ( ) . requires_unknown_bits ( ) {
596668 return Err ( Bolt12SemanticError :: UnknownRequiredFeatures ) ;
597669 }
598670
599- let keys = match self . verify ( expanded_key, secp_ctx) {
600- Err ( ( ) ) => return Err ( Bolt12SemanticError :: InvalidMetadata ) ,
601- Ok ( None ) => return Err ( Bolt12SemanticError :: InvalidMetadata ) ,
602- Ok ( Some ( keys) ) => keys,
671+ let keys = match self . keys {
672+ None => return Err ( Bolt12SemanticError :: InvalidMetadata ) ,
673+ Some ( keys) => keys,
603674 } ;
604675
605- InvoiceBuilder :: for_offer_using_keys ( self , payment_paths, created_at, payment_hash, keys)
606- }
607-
608- /// Verifies that the request was for an offer created using the given key. Returns the derived
609- /// keys need to sign an [`Bolt12Invoice`] for the request if they could be extracted from the
610- /// metadata.
611- ///
612- /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
613- pub fn verify < T : secp256k1:: Signing > (
614- & self , key : & ExpandedKey , secp_ctx : & Secp256k1 < T >
615- ) -> Result < Option < KeyPair > , ( ) > {
616- self . contents . inner . offer . verify ( & self . bytes , key, secp_ctx)
617- }
618-
619- #[ cfg( test) ]
620- fn as_tlv_stream ( & self ) -> FullInvoiceRequestTlvStreamRef {
621- let ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream) =
622- self . contents . as_tlv_stream ( ) ;
623- let signature_tlv_stream = SignatureTlvStreamRef {
624- signature : Some ( & self . signature ) ,
625- } ;
626- ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, signature_tlv_stream)
676+ InvoiceBuilder :: for_offer_using_keys (
677+ & self . inner , payment_paths, created_at, payment_hash, keys
678+ )
627679 }
628680}
629681
0 commit comments