@@ -210,10 +210,9 @@ macro_rules! invoice_explicit_signing_pubkey_builder_methods { ($self: ident, $s
210210 #[ cfg_attr( c_bindings, allow( dead_code) ) ]
211211 pub ( super ) fn for_offer(
212212 invoice_request: & ' a InvoiceRequest , payment_paths: Vec <( BlindedPayInfo , BlindedPath ) >,
213- created_at: Duration , payment_hash: PaymentHash
213+ created_at: Duration , payment_hash: PaymentHash , signing_pubkey : PublicKey
214214 ) -> Result <Self , Bolt12SemanticError > {
215215 let amount_msats = Self :: amount_msats( invoice_request) ?;
216- let signing_pubkey = invoice_request. contents. inner. offer. signing_pubkey( ) ;
217216 let contents = InvoiceContents :: ForOffer {
218217 invoice_request: invoice_request. contents. clone( ) ,
219218 fields: Self :: fields(
@@ -272,7 +271,7 @@ macro_rules! invoice_derived_signing_pubkey_builder_methods { ($self: ident, $se
272271 created_at: Duration , payment_hash: PaymentHash , keys: KeyPair
273272 ) -> Result <Self , Bolt12SemanticError > {
274273 let amount_msats = Self :: amount_msats( invoice_request) ?;
275- let signing_pubkey = invoice_request . contents . inner . offer . signing_pubkey ( ) ;
274+ let signing_pubkey = keys . public_key ( ) ;
276275 let contents = InvoiceContents :: ForOffer {
277276 invoice_request: invoice_request. contents. clone( ) ,
278277 fields: Self :: fields(
@@ -1435,8 +1434,8 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14351434 features, signing_pubkey,
14361435 } ;
14371436
1438- match offer_tlv_stream. node_id {
1439- Some ( expected_signing_pubkey) => {
1437+ match ( offer_tlv_stream. node_id , & offer_tlv_stream . paths ) {
1438+ ( Some ( expected_signing_pubkey) , _ ) => {
14401439 if fields. signing_pubkey != expected_signing_pubkey {
14411440 return Err ( Bolt12SemanticError :: InvalidSigningPubkey ) ;
14421441 }
@@ -1446,7 +1445,21 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14461445 ) ?;
14471446 Ok ( InvoiceContents :: ForOffer { invoice_request, fields } )
14481447 } ,
1449- None => {
1448+ ( None , Some ( paths) ) => {
1449+ if !paths
1450+ . iter ( )
1451+ . filter_map ( |path| path. blinded_hops . last ( ) )
1452+ . any ( |last_hop| fields. signing_pubkey == last_hop. blinded_node_id )
1453+ {
1454+ return Err ( Bolt12SemanticError :: InvalidSigningPubkey ) ;
1455+ }
1456+
1457+ let invoice_request = InvoiceRequestContents :: try_from (
1458+ ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
1459+ ) ?;
1460+ Ok ( InvoiceContents :: ForOffer { invoice_request, fields } )
1461+ } ,
1462+ ( None , None ) => {
14501463 let refund = RefundContents :: try_from (
14511464 ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
14521465 ) ?;
@@ -1464,7 +1477,7 @@ mod tests {
14641477 use bitcoin:: blockdata:: script:: ScriptBuf ;
14651478 use bitcoin:: hashes:: Hash ;
14661479 use bitcoin:: network:: constants:: Network ;
1467- use bitcoin:: secp256k1:: { Message , Secp256k1 , XOnlyPublicKey , self } ;
1480+ use bitcoin:: secp256k1:: { KeyPair , Message , Secp256k1 , SecretKey , XOnlyPublicKey , self } ;
14681481 use bitcoin:: address:: { Address , Payload , WitnessProgram , WitnessVersion } ;
14691482 use bitcoin:: key:: TweakedPublicKey ;
14701483
@@ -1633,6 +1646,7 @@ mod tests {
16331646 quantity: None ,
16341647 payer_id: Some ( & payer_pubkey( ) ) ,
16351648 payer_note: None ,
1649+ paths: None ,
16361650 } ,
16371651 InvoiceTlvStreamRef {
16381652 paths: Some ( Iterable ( payment_paths. iter( ) . map( |( _, path) | path) ) ) ,
@@ -1725,6 +1739,7 @@ mod tests {
17251739 quantity: None ,
17261740 payer_id: Some ( & payer_pubkey( ) ) ,
17271741 payer_note: None ,
1742+ paths: None ,
17281743 } ,
17291744 InvoiceTlvStreamRef {
17301745 paths: Some ( Iterable ( payment_paths. iter( ) . map( |( _, path) | path) ) ) ,
@@ -2365,6 +2380,81 @@ mod tests {
23652380 }
23662381 }
23672382
2383+ #[ test]
2384+ fn parses_invoice_with_node_id_from_blinded_path ( ) {
2385+ let paths = vec ! [
2386+ BlindedPath {
2387+ introduction_node: IntroductionNode :: NodeId ( pubkey( 40 ) ) ,
2388+ blinding_point: pubkey( 41 ) ,
2389+ blinded_hops: vec![
2390+ BlindedHop { blinded_node_id: pubkey( 43 ) , encrypted_payload: vec![ 0 ; 43 ] } ,
2391+ BlindedHop { blinded_node_id: pubkey( 44 ) , encrypted_payload: vec![ 0 ; 44 ] } ,
2392+ ] ,
2393+ } ,
2394+ BlindedPath {
2395+ introduction_node: IntroductionNode :: NodeId ( pubkey( 40 ) ) ,
2396+ blinding_point: pubkey( 41 ) ,
2397+ blinded_hops: vec![
2398+ BlindedHop { blinded_node_id: pubkey( 45 ) , encrypted_payload: vec![ 0 ; 45 ] } ,
2399+ BlindedHop { blinded_node_id: pubkey( 46 ) , encrypted_payload: vec![ 0 ; 46 ] } ,
2400+ ] ,
2401+ } ,
2402+ ] ;
2403+
2404+ let blinded_node_id_sign = |message : & UnsignedBolt12Invoice | {
2405+ let secp_ctx = Secp256k1 :: new ( ) ;
2406+ let keys = KeyPair :: from_secret_key ( & secp_ctx, & SecretKey :: from_slice ( & [ 46 ; 32 ] ) . unwrap ( ) ) ;
2407+ Ok ( secp_ctx. sign_schnorr_no_aux_rand ( message. as_ref ( ) . as_digest ( ) , & keys) )
2408+ } ;
2409+
2410+ let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
2411+ . clear_signing_pubkey ( )
2412+ . amount_msats ( 1000 )
2413+ . path ( paths[ 0 ] . clone ( ) )
2414+ . path ( paths[ 1 ] . clone ( ) )
2415+ . build ( ) . unwrap ( )
2416+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
2417+ . build ( ) . unwrap ( )
2418+ . sign ( payer_sign) . unwrap ( )
2419+ . respond_with_no_std_using_signing_pubkey (
2420+ payment_paths ( ) , payment_hash ( ) , now ( ) , pubkey ( 46 )
2421+ ) . unwrap ( )
2422+ . build ( ) . unwrap ( )
2423+ . sign ( blinded_node_id_sign) . unwrap ( ) ;
2424+
2425+ let mut buffer = Vec :: new ( ) ;
2426+ invoice. write ( & mut buffer) . unwrap ( ) ;
2427+
2428+ if let Err ( e) = Bolt12Invoice :: try_from ( buffer) {
2429+ panic ! ( "error parsing invoice: {:?}" , e) ;
2430+ }
2431+
2432+ let invoice = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
2433+ . clear_signing_pubkey ( )
2434+ . amount_msats ( 1000 )
2435+ . path ( paths[ 0 ] . clone ( ) )
2436+ . path ( paths[ 1 ] . clone ( ) )
2437+ . build ( ) . unwrap ( )
2438+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
2439+ . build ( ) . unwrap ( )
2440+ . sign ( payer_sign) . unwrap ( )
2441+ . respond_with_no_std_using_signing_pubkey (
2442+ payment_paths ( ) , payment_hash ( ) , now ( ) , recipient_pubkey ( )
2443+ ) . unwrap ( )
2444+ . build ( ) . unwrap ( )
2445+ . sign ( recipient_sign) . unwrap ( ) ;
2446+
2447+ let mut buffer = Vec :: new ( ) ;
2448+ invoice. write ( & mut buffer) . unwrap ( ) ;
2449+
2450+ match Bolt12Invoice :: try_from ( buffer) {
2451+ Ok ( _) => panic ! ( "expected error" ) ,
2452+ Err ( e) => {
2453+ assert_eq ! ( e, Bolt12ParseError :: InvalidSemantics ( Bolt12SemanticError :: InvalidSigningPubkey ) ) ;
2454+ } ,
2455+ }
2456+ }
2457+
23682458 #[ test]
23692459 fn fails_parsing_invoice_without_signature ( ) {
23702460 let mut buffer = Vec :: new ( ) ;
0 commit comments