1212use bitcoin:: secp256k1:: ecdh:: SharedSecret ;
1313use bitcoin:: secp256k1:: { self , PublicKey , Secp256k1 , SecretKey } ;
1414
15+ use crate :: blinded_path:: message:: MAX_DUMMY_HOPS_COUNT ;
1516use crate :: blinded_path:: utils:: { self , BlindedPathWithPadding } ;
1617use crate :: blinded_path:: { BlindedHop , BlindedPath , IntroductionNode , NodeIdLookUp } ;
1718use crate :: crypto:: streams:: ChaChaDualPolyReadAdapter ;
@@ -121,6 +122,32 @@ impl BlindedPaymentPath {
121122 local_node_receive_key : ReceiveAuthKey , payee_tlvs : ReceiveTlvs , htlc_maximum_msat : u64 ,
122123 min_final_cltv_expiry_delta : u16 , entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
123124 ) -> Result < Self , ( ) >
125+ where
126+ ES :: Target : EntropySource ,
127+ {
128+ BlindedPaymentPath :: new_with_dummy_hops (
129+ intermediate_nodes,
130+ payee_node_id,
131+ 0 ,
132+ local_node_receive_key,
133+ payee_tlvs,
134+ htlc_maximum_msat,
135+ min_final_cltv_expiry_delta,
136+ entropy_source,
137+ secp_ctx,
138+ )
139+ }
140+
141+ /// Same as [`BlindedPaymentPath::new`], but allows specifying a number of dummy hops.
142+ ///
143+ /// Note:
144+ /// At most [`MAX_DUMMY_HOPS_COUNT`] dummy hops can be added to the blinded path.
145+ pub fn new_with_dummy_hops < ES : Deref , T : secp256k1:: Signing + secp256k1:: Verification > (
146+ intermediate_nodes : & [ PaymentForwardNode ] , payee_node_id : PublicKey ,
147+ dummy_hop_count : usize , local_node_receive_key : ReceiveAuthKey , payee_tlvs : ReceiveTlvs ,
148+ htlc_maximum_msat : u64 , min_final_cltv_expiry_delta : u16 , entropy_source : ES ,
149+ secp_ctx : & Secp256k1 < T > ,
150+ ) -> Result < Self , ( ) >
124151 where
125152 ES :: Target : EntropySource ,
126153 {
@@ -145,6 +172,7 @@ impl BlindedPaymentPath {
145172 secp_ctx,
146173 intermediate_nodes,
147174 payee_node_id,
175+ dummy_hop_count,
148176 payee_tlvs,
149177 & blinding_secret,
150178 local_node_receive_key,
@@ -644,22 +672,46 @@ pub(crate) const PAYMENT_PADDING_ROUND_OFF: usize = 30;
644672/// Construct blinded payment hops for the given `intermediate_nodes` and payee info.
645673pub ( super ) fn blinded_hops < T : secp256k1:: Signing + secp256k1:: Verification > (
646674 secp_ctx : & Secp256k1 < T > , intermediate_nodes : & [ PaymentForwardNode ] , payee_node_id : PublicKey ,
647- payee_tlvs : ReceiveTlvs , session_priv : & SecretKey , local_node_receive_key : ReceiveAuthKey ,
675+ dummy_hop_count : usize , payee_tlvs : ReceiveTlvs , session_priv : & SecretKey ,
676+ local_node_receive_key : ReceiveAuthKey ,
648677) -> Vec < BlindedHop > {
678+ let dummy_count = core:: cmp:: min ( dummy_hop_count, MAX_DUMMY_HOPS_COUNT ) ;
649679 let pks = intermediate_nodes
650680 . iter ( )
651681 . map ( |node| ( node. node_id , None ) )
682+ . chain ( core:: iter:: repeat ( ( payee_node_id, Some ( local_node_receive_key) ) ) . take ( dummy_count) )
652683 . chain ( core:: iter:: once ( ( payee_node_id, Some ( local_node_receive_key) ) ) ) ;
653684 let tlvs = intermediate_nodes
654685 . iter ( )
655686 . map ( |node| BlindedPaymentTlvsRef :: Forward ( & node. tlvs ) )
687+ . chain ( ( 0 ..dummy_count) . map ( |_| BlindedPaymentTlvsRef :: Dummy ) )
656688 . chain ( core:: iter:: once ( BlindedPaymentTlvsRef :: Receive ( & payee_tlvs) ) ) ;
657689
658- let path = pks. zip (
659- tlvs. map ( |tlv| BlindedPathWithPadding { tlvs : tlv, round_off : PAYMENT_PADDING_ROUND_OFF } ) ,
660- ) ;
690+ let path: Vec < _ > = pks
691+ . zip (
692+ tlvs. map ( |tlv| BlindedPathWithPadding {
693+ tlvs : tlv,
694+ round_off : PAYMENT_PADDING_ROUND_OFF ,
695+ } ) ,
696+ )
697+ . collect ( ) ;
698+
699+ // Debug invariant: all non-final hops must have identical serialized size.
700+ #[ cfg( debug_assertions) ]
701+ if let Some ( ( _, first) ) = path. first ( ) {
702+ if path. len ( ) > 2 {
703+ let expected = first. serialized_length ( ) ;
704+
705+ for ( _, hop) in path. iter ( ) . skip ( 1 ) . take ( path. len ( ) - 2 ) {
706+ debug_assert ! (
707+ hop. serialized_length( ) == expected,
708+ "All intermediate blinded hops must have identical serialized size"
709+ ) ;
710+ }
711+ }
712+ }
661713
662- utils:: construct_blinded_hops ( secp_ctx, path, session_priv)
714+ utils:: construct_blinded_hops ( secp_ctx, path. into_iter ( ) , session_priv)
663715}
664716
665717/// `None` if underflow occurs.
0 commit comments