@@ -1434,8 +1434,8 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14341434 features, signing_pubkey,
14351435 } ;
14361436
1437- match offer_tlv_stream. node_id {
1438- Some ( expected_signing_pubkey) => {
1437+ match ( offer_tlv_stream. node_id , & offer_tlv_stream . paths ) {
1438+ ( Some ( expected_signing_pubkey) , _ ) => {
14391439 if fields. signing_pubkey != expected_signing_pubkey {
14401440 return Err ( Bolt12SemanticError :: InvalidSigningPubkey ) ;
14411441 }
@@ -1445,7 +1445,21 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
14451445 ) ?;
14461446 Ok ( InvoiceContents :: ForOffer { invoice_request, fields } )
14471447 } ,
1448- 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 ) => {
14491463 let refund = RefundContents :: try_from (
14501464 ( payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
14511465 ) ?;
@@ -1463,7 +1477,7 @@ mod tests {
14631477 use bitcoin:: blockdata:: script:: ScriptBuf ;
14641478 use bitcoin:: hashes:: Hash ;
14651479 use bitcoin:: network:: constants:: Network ;
1466- use bitcoin:: secp256k1:: { Message , Secp256k1 , XOnlyPublicKey , self } ;
1480+ use bitcoin:: secp256k1:: { KeyPair , Message , Secp256k1 , SecretKey , XOnlyPublicKey , self } ;
14671481 use bitcoin:: address:: { Address , Payload , WitnessProgram , WitnessVersion } ;
14681482 use bitcoin:: key:: TweakedPublicKey ;
14691483
@@ -2366,6 +2380,81 @@ mod tests {
23662380 }
23672381 }
23682382
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+
23692458 #[ test]
23702459 fn fails_parsing_invoice_without_signature ( ) {
23712460 let mut buffer = Vec :: new ( ) ;
0 commit comments