@@ -249,9 +249,12 @@ macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => {
249249 ///
250250 /// Also, sets the metadata when [`OfferBuilder::build`] is called such that it can be used by
251251 /// [`InvoiceRequest::verify`] to determine if the request was produced for the offer given an
252- /// [`ExpandedKey`].
252+ /// [`ExpandedKey`]. However, if [`OfferBuilder::path`] is called, then the metadata will not be
253+ /// set and must be included in each [`BlindedPath`] instead. In this case, use
254+ /// [`InvoiceRequest::verify_using_recipient_data`].
253255 ///
254256 /// [`InvoiceRequest::verify`]: crate::offers::invoice_request::InvoiceRequest::verify
257+ /// [`InvoiceRequest::verify_using_recipient_data`]: crate::offers::invoice_request::InvoiceRequest::verify_using_recipient_data
255258 /// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
256259 pub fn deriving_signing_pubkey(
257260 node_id: PublicKey , expanded_key: & ExpandedKey , nonce: Nonce ,
@@ -384,9 +387,12 @@ macro_rules! offer_builder_methods { (
384387 }
385388
386389 fn build_without_checks( $( $self_mut) * $self: $self_type) -> Offer {
387- // Create the metadata for stateless verification of an InvoiceRequest.
388390 if let Some ( mut metadata) = $self. offer. metadata. take( ) {
391+ // Create the metadata for stateless verification of an InvoiceRequest.
389392 if metadata. has_derivation_material( ) {
393+
394+ // Don't derive keys if no blinded paths were given since this means the signing
395+ // pubkey must be the node id of an announced node.
390396 if $self. offer. paths. is_none( ) {
391397 metadata = metadata. without_keys( ) ;
392398 }
@@ -398,14 +404,17 @@ macro_rules! offer_builder_methods { (
398404 tlv_stream. node_id = None ;
399405 }
400406
407+ // Either replace the signing pubkey with the derived pubkey or include the metadata
408+ // for verification. In the former case, the blinded paths must include
409+ // `OffersContext::InvoiceRequest` instead.
401410 let ( derived_metadata, keys) = metadata. derive_from( tlv_stream, $self. secp_ctx) ;
402- metadata = derived_metadata ;
403- if let Some ( keys) = keys {
404- $self. offer. signing_pubkey = Some ( keys . public_key ( ) ) ;
411+ match keys {
412+ Some ( keys) => $self . offer . signing_pubkey = Some ( keys . public_key ( ) ) ,
413+ None => $self. offer. metadata = Some ( derived_metadata ) ,
405414 }
415+ } else {
416+ $self. offer. metadata = Some ( metadata) ;
406417 }
407-
408- $self. offer. metadata = Some ( metadata) ;
409418 }
410419
411420 let mut bytes = Vec :: new( ) ;
@@ -667,9 +676,9 @@ impl Offer {
667676
668677 #[ cfg( async_payments) ]
669678 pub ( super ) fn verify < T : secp256k1:: Signing > (
670- & self , key : & ExpandedKey , secp_ctx : & Secp256k1 < T >
679+ & self , nonce : Nonce , key : & ExpandedKey , secp_ctx : & Secp256k1 < T >
671680 ) -> Result < ( OfferId , Option < Keypair > ) , ( ) > {
672- self . contents . verify ( & self . bytes , key, secp_ctx)
681+ self . contents . verify_using_recipient_data ( & self . bytes , nonce , key, secp_ctx)
673682 }
674683}
675684
@@ -1296,6 +1305,7 @@ mod tests {
12961305 let offer = OfferBuilder :: deriving_signing_pubkey ( node_id, & expanded_key, nonce, & secp_ctx)
12971306 . amount_msats ( 1000 )
12981307 . build ( ) . unwrap ( ) ;
1308+ assert ! ( offer. metadata( ) . is_some( ) ) ;
12991309 assert_eq ! ( offer. signing_pubkey( ) , Some ( node_id) ) ;
13001310
13011311 let invoice_request = offer. request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
@@ -1365,23 +1375,22 @@ mod tests {
13651375 . amount_msats ( 1000 )
13661376 . path ( blinded_path)
13671377 . build ( ) . unwrap ( ) ;
1378+ assert ! ( offer. metadata( ) . is_none( ) ) ;
13681379 assert_ne ! ( offer. signing_pubkey( ) , Some ( node_id) ) ;
13691380
13701381 let invoice_request = offer. request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
13711382 . build ( ) . unwrap ( )
13721383 . sign ( payer_sign) . unwrap ( ) ;
1373- match invoice_request. verify ( & expanded_key, & secp_ctx) {
1384+ match invoice_request. verify_using_recipient_data ( nonce , & expanded_key, & secp_ctx) {
13741385 Ok ( invoice_request) => assert_eq ! ( invoice_request. offer_id, offer. id( ) ) ,
13751386 Err ( _) => panic ! ( "unexpected error" ) ,
13761387 }
13771388
1389+ // Fails verification when using the wrong method
13781390 let invoice_request = offer. request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
13791391 . build ( ) . unwrap ( )
13801392 . sign ( payer_sign) . unwrap ( ) ;
1381- match invoice_request. verify_using_recipient_data ( nonce, & expanded_key, & secp_ctx) {
1382- Ok ( invoice_request) => assert_eq ! ( invoice_request. offer_id, offer. id( ) ) ,
1383- Err ( _) => panic ! ( "unexpected error" ) ,
1384- }
1393+ assert ! ( invoice_request. verify( & expanded_key, & secp_ctx) . is_err( ) ) ;
13851394
13861395 // Fails verification with altered offer field
13871396 let mut tlv_stream = offer. as_tlv_stream ( ) ;
@@ -1394,7 +1403,9 @@ mod tests {
13941403 . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
13951404 . build ( ) . unwrap ( )
13961405 . sign ( payer_sign) . unwrap ( ) ;
1397- assert ! ( invoice_request. verify( & expanded_key, & secp_ctx) . is_err( ) ) ;
1406+ assert ! (
1407+ invoice_request. verify_using_recipient_data( nonce, & expanded_key, & secp_ctx) . is_err( )
1408+ ) ;
13981409
13991410 // Fails verification with altered signing pubkey
14001411 let mut tlv_stream = offer. as_tlv_stream ( ) ;
@@ -1408,7 +1419,9 @@ mod tests {
14081419 . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
14091420 . build ( ) . unwrap ( )
14101421 . sign ( payer_sign) . unwrap ( ) ;
1411- assert ! ( invoice_request. verify( & expanded_key, & secp_ctx) . is_err( ) ) ;
1422+ assert ! (
1423+ invoice_request. verify_using_recipient_data( nonce, & expanded_key, & secp_ctx) . is_err( )
1424+ ) ;
14121425 }
14131426
14141427 #[ test]
0 commit comments