@@ -68,7 +68,6 @@ impl BlindedMessagePath {
6868 /// pubkey in `node_pks` will be the destination node.
6969 ///
7070 /// Errors if no hops are provided or if `node_pk`(s) are invalid.
71- // TODO: make all payloads the same size with padding + add dummy hops
7271 pub fn new < ES : Deref , T : secp256k1:: Signing + secp256k1:: Verification > (
7372 intermediate_nodes : & [ MessageForwardNode ] , recipient_node_id : PublicKey ,
7473 context : MessageContext , entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
@@ -91,6 +90,45 @@ impl BlindedMessagePath {
9190 intermediate_nodes,
9291 recipient_node_id,
9392 context,
93+ 0 ,
94+ & blinding_secret,
95+ )
96+ . map_err ( |_| ( ) ) ?,
97+ } ) )
98+ }
99+
100+ /// Create a path for an onion message, to be forwarded along `node_pks`.
101+ ///
102+ /// Additionally allows appending a number of dummy hops before the final hop,
103+ /// increasing the total path length and enhancing privacy by obscuring the true
104+ /// distance between sender and recipient.
105+ ///
106+ /// The last node pubkey in `node_pks` will be the destination node.
107+ ///
108+ /// Errors if no hops are provided or if `node_pk`(s) are invalid.
109+ pub fn new_with_dummy_hops < ES : Deref , T : secp256k1:: Signing + secp256k1:: Verification > (
110+ intermediate_nodes : & [ MessageForwardNode ] , dummy_hops_count : u8 , recipient_node_id : PublicKey ,
111+ context : MessageContext , entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
112+ ) -> Result < Self , ( ) >
113+ where
114+ ES :: Target : EntropySource ,
115+ {
116+ let introduction_node = IntroductionNode :: NodeId (
117+ intermediate_nodes. first ( ) . map_or ( recipient_node_id, |n| n. node_id ) ,
118+ ) ;
119+ let blinding_secret_bytes = entropy_source. get_secure_random_bytes ( ) ;
120+ let blinding_secret =
121+ SecretKey :: from_slice ( & blinding_secret_bytes[ ..] ) . expect ( "RNG is busted" ) ;
122+
123+ Ok ( Self ( BlindedPath {
124+ introduction_node,
125+ blinding_point : PublicKey :: from_secret_key ( secp_ctx, & blinding_secret) ,
126+ blinded_hops : blinded_hops (
127+ secp_ctx,
128+ intermediate_nodes,
129+ recipient_node_id,
130+ context,
131+ dummy_hops_count,
94132 & blinding_secret,
95133 )
96134 . map_err ( |_| ( ) ) ?,
@@ -507,11 +545,12 @@ pub(crate) const MESSAGE_PADDING_ROUND_OFF: usize = 100;
507545/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
508546pub ( super ) fn blinded_hops < T : secp256k1:: Signing + secp256k1:: Verification > (
509547 secp_ctx : & Secp256k1 < T > , intermediate_nodes : & [ MessageForwardNode ] ,
510- recipient_node_id : PublicKey , context : MessageContext , session_priv : & SecretKey ,
548+ recipient_node_id : PublicKey , context : MessageContext , dummy_hops_count : u8 , session_priv : & SecretKey ,
511549) -> Result < Vec < BlindedHop > , secp256k1:: Error > {
512550 let pks = intermediate_nodes
513551 . iter ( )
514552 . map ( |node| node. node_id )
553+ . chain ( ( 0 ..dummy_hops_count) . map ( |_| recipient_node_id) )
515554 . chain ( core:: iter:: once ( recipient_node_id) ) ;
516555 let is_compact = intermediate_nodes. iter ( ) . any ( |node| node. short_channel_id . is_some ( ) ) ;
517556
@@ -526,6 +565,12 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
526565 . map ( |next_hop| {
527566 ControlTlvs :: Forward ( ForwardTlvs { next_hop, next_blinding_override : None } )
528567 } )
568+ . chain ( ( 0 ..dummy_hops_count) . map ( |_| {
569+ ControlTlvs :: Forward ( ForwardTlvs {
570+ next_hop : NextMessageHop :: NodeId ( recipient_node_id) ,
571+ next_blinding_override : None ,
572+ } )
573+ } ) )
529574 . chain ( core:: iter:: once ( ControlTlvs :: Receive ( ReceiveTlvs { context : Some ( context) } ) ) ) ;
530575
531576 if is_compact {
0 commit comments