@@ -68,7 +68,6 @@ impl BlindedMessagePath {
68
68
/// pubkey in `node_pks` will be the destination node.
69
69
///
70
70
/// 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
72
71
pub fn new < ES : Deref , T : secp256k1:: Signing + secp256k1:: Verification > (
73
72
intermediate_nodes : & [ MessageForwardNode ] , recipient_node_id : PublicKey ,
74
73
context : MessageContext , entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
@@ -91,6 +90,45 @@ impl BlindedMessagePath {
91
90
intermediate_nodes,
92
91
recipient_node_id,
93
92
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,
94
132
& blinding_secret,
95
133
)
96
134
. map_err ( |_| ( ) ) ?,
@@ -507,11 +545,12 @@ pub(crate) const MESSAGE_PADDING_ROUND_OFF: usize = 100;
507
545
/// Construct blinded onion message hops for the given `intermediate_nodes` and `recipient_node_id`.
508
546
pub ( super ) fn blinded_hops < T : secp256k1:: Signing + secp256k1:: Verification > (
509
547
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 ,
511
549
) -> Result < Vec < BlindedHop > , secp256k1:: Error > {
512
550
let pks = intermediate_nodes
513
551
. iter ( )
514
552
. map ( |node| node. node_id )
553
+ . chain ( ( 0 ..dummy_hops_count) . map ( |_| recipient_node_id) )
515
554
. chain ( core:: iter:: once ( recipient_node_id) ) ;
516
555
let is_compact = intermediate_nodes. iter ( ) . any ( |node| node. short_channel_id . is_some ( ) ) ;
517
556
@@ -526,6 +565,12 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
526
565
. map ( |next_hop| {
527
566
ControlTlvs :: Forward ( ForwardTlvs { next_hop, next_blinding_override : None } )
528
567
} )
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
+ } ) )
529
574
. chain ( core:: iter:: once ( ControlTlvs :: Receive ( ReceiveTlvs { context : Some ( context) } ) ) ) ;
530
575
531
576
if is_compact {
0 commit comments