10
10
//! LDK sends, receives, and forwards onion messages via the [`OnionMessenger`]. See its docs for
11
11
//! more information.
12
12
13
- use bitcoin:: secp256k1:: { self , PublicKey , Secp256k1 } ;
13
+ use bitcoin:: secp256k1:: { self , PublicKey , Secp256k1 , SecretKey } ;
14
14
15
15
use chain:: keysinterface:: { InMemorySigner , KeysInterface , KeysManager , Sign } ;
16
16
use ln:: msgs;
17
+ use ln:: onion_utils;
18
+ use super :: blinded_route:: { BlindedRoute , ForwardTlvs , ReceiveTlvs } ;
19
+ use super :: packet:: { BIG_PACKET_HOP_DATA_LEN , ForwardControlTlvs , Packet , Payload , ReceiveControlTlvs , SMALL_PACKET_HOP_DATA_LEN } ;
20
+ use super :: utils;
17
21
use util:: logger:: Logger ;
18
22
19
23
use core:: ops:: Deref ;
@@ -37,6 +41,23 @@ pub struct OnionMessenger<Signer: Sign, K: Deref, L: Deref>
37
41
// custom_handler: CustomHandler, // handles custom onion messages
38
42
}
39
43
44
+ /// The destination of an onion message.
45
+ pub enum Destination {
46
+ /// We're sending this onion message to a node.
47
+ Node ( PublicKey ) ,
48
+ /// We're sending this onion message to a blinded route.
49
+ BlindedRoute ( BlindedRoute ) ,
50
+ }
51
+
52
+ impl Destination {
53
+ pub ( super ) fn num_hops ( & self ) -> usize {
54
+ match self {
55
+ Destination :: Node ( _) => 1 ,
56
+ Destination :: BlindedRoute ( BlindedRoute { blinded_hops, .. } ) => blinded_hops. len ( ) ,
57
+ }
58
+ }
59
+ }
60
+
40
61
impl < Signer : Sign , K : Deref , L : Deref > OnionMessenger < Signer , K , L >
41
62
where K :: Target : KeysInterface < Signer = Signer > ,
42
63
L :: Target : Logger ,
@@ -53,6 +74,36 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
53
74
logger,
54
75
}
55
76
}
77
+
78
+ /// Send an empty onion message to `destination`, routing it through `intermediate_nodes`.
79
+ pub fn send_onion_message ( & self , intermediate_nodes : & [ PublicKey ] , destination : Destination ) -> Result < ( ) , secp256k1:: Error > {
80
+ let blinding_secret_bytes = self . keys_manager . get_secure_random_bytes ( ) ;
81
+ let blinding_secret = SecretKey :: from_slice ( & blinding_secret_bytes[ ..] ) . expect ( "RNG is busted" ) ;
82
+ let ( introduction_node_id, blinding_point) = if intermediate_nodes. len ( ) != 0 {
83
+ ( intermediate_nodes[ 0 ] , PublicKey :: from_secret_key ( & self . secp_ctx , & blinding_secret) )
84
+ } else {
85
+ match destination {
86
+ Destination :: Node ( pk) => ( pk, PublicKey :: from_secret_key ( & self . secp_ctx , & blinding_secret) ) ,
87
+ Destination :: BlindedRoute ( BlindedRoute { introduction_node_id, blinding_point, .. } ) =>
88
+ ( introduction_node_id, blinding_point) ,
89
+ }
90
+ } ;
91
+ let ( packet_payloads, packet_keys) = packet_payloads_and_keys (
92
+ & self . secp_ctx , intermediate_nodes, destination, & blinding_secret) ?;
93
+
94
+ let prng_seed = self . keys_manager . get_secure_random_bytes ( ) ;
95
+ let onion_packet = construct_onion_message_packet ( packet_payloads, packet_keys, prng_seed) ;
96
+
97
+ let mut pending_per_peer_msgs = self . pending_messages . lock ( ) . unwrap ( ) ;
98
+ let pending_msgs = pending_per_peer_msgs. entry ( introduction_node_id) . or_insert ( Vec :: new ( ) ) ;
99
+ pending_msgs. push (
100
+ msgs:: OnionMessage {
101
+ blinding_point,
102
+ onion_routing_packet : onion_packet,
103
+ }
104
+ ) ;
105
+ Ok ( ( ) )
106
+ }
56
107
}
57
108
58
109
// TODO: parameterize the below Simple* types with OnionMessenger and handle the messages it
@@ -69,3 +120,90 @@ pub type SimpleArcOnionMessenger<L> = OnionMessenger<InMemorySigner, Arc<KeysMan
69
120
///[`SimpleRefChannelManager`]: crate::ln::channelmanager::SimpleRefChannelManager
70
121
///[`SimpleRefPeerManager`]: crate::ln::peer_handler::SimpleRefPeerManager
71
122
pub type SimpleRefOnionMessenger < ' a , ' b , L > = OnionMessenger < InMemorySigner , & ' a KeysManager , & ' b L > ;
123
+
124
+ /// Construct onion packet payloads and keys for sending an onion message along the given
125
+ /// `unblinded_path` to the given `destination`.
126
+ fn packet_payloads_and_keys < T : secp256k1:: Signing + secp256k1:: Verification > (
127
+ secp_ctx : & Secp256k1 < T > , unblinded_path : & [ PublicKey ] , destination : Destination , session_priv : & SecretKey
128
+ ) -> Result < ( Vec < ( Payload , [ u8 ; 32 ] ) > , Vec < onion_utils:: OnionKeys > ) , secp256k1:: Error > {
129
+ let num_hops = unblinded_path. len ( ) + destination. num_hops ( ) ;
130
+ let mut payloads = Vec :: with_capacity ( num_hops) ;
131
+ let mut onion_packet_keys = Vec :: with_capacity ( num_hops) ;
132
+
133
+ let ( mut intro_node_id_blinding_pt, num_blinded_hops) = if let Destination :: BlindedRoute ( BlindedRoute {
134
+ introduction_node_id, blinding_point, blinded_hops } ) = & destination {
135
+ ( Some ( ( * introduction_node_id, * blinding_point) ) , blinded_hops. len ( ) ) } else { ( None , 0 ) } ;
136
+ let num_unblinded_hops = num_hops - num_blinded_hops;
137
+
138
+ let mut unblinded_path_idx = 0 ;
139
+ let mut blinded_path_idx = 0 ;
140
+ let mut prev_control_tlvs_ss = None ;
141
+ utils:: construct_keys_callback ( secp_ctx, unblinded_path, Some ( destination) , session_priv, |_, onion_packet_ss, ephemeral_pubkey, control_tlvs_ss, unblinded_pk_opt, enc_payload_opt| {
142
+ if num_unblinded_hops != 0 && unblinded_path_idx < num_unblinded_hops {
143
+ if let Some ( ss) = prev_control_tlvs_ss. take ( ) {
144
+ payloads. push ( ( Payload :: Forward ( ForwardControlTlvs :: Unblinded (
145
+ ForwardTlvs {
146
+ next_node_id : unblinded_pk_opt. unwrap ( ) ,
147
+ next_blinding_override : None ,
148
+ }
149
+ ) ) , ss) ) ;
150
+ }
151
+ prev_control_tlvs_ss = Some ( control_tlvs_ss) ;
152
+ unblinded_path_idx += 1 ;
153
+ } else if let Some ( ( intro_node_id, blinding_pt) ) = intro_node_id_blinding_pt. take ( ) {
154
+ if let Some ( control_tlvs_ss) = prev_control_tlvs_ss. take ( ) {
155
+ payloads. push ( ( Payload :: Forward ( ForwardControlTlvs :: Unblinded ( ForwardTlvs {
156
+ next_node_id : intro_node_id,
157
+ next_blinding_override : Some ( blinding_pt) ,
158
+ } ) ) , control_tlvs_ss) ) ;
159
+ }
160
+ if let Some ( encrypted_payload) = enc_payload_opt {
161
+ payloads. push ( ( Payload :: Forward ( ForwardControlTlvs :: Blinded ( encrypted_payload) ) ,
162
+ control_tlvs_ss) ) ;
163
+ } else { debug_assert ! ( false ) ; }
164
+ blinded_path_idx += 1 ;
165
+ } else if blinded_path_idx < num_blinded_hops - 1 && enc_payload_opt. is_some ( ) {
166
+ payloads. push ( ( Payload :: Forward ( ForwardControlTlvs :: Blinded ( enc_payload_opt. unwrap ( ) ) ) ,
167
+ control_tlvs_ss) ) ;
168
+ blinded_path_idx += 1 ;
169
+ } else if let Some ( encrypted_payload) = enc_payload_opt {
170
+ payloads. push ( ( Payload :: Receive {
171
+ control_tlvs : ReceiveControlTlvs :: Blinded ( encrypted_payload) ,
172
+ } , control_tlvs_ss) ) ;
173
+ }
174
+
175
+ let ( rho, mu) = onion_utils:: gen_rho_mu_from_shared_secret ( onion_packet_ss. as_ref ( ) ) ;
176
+ onion_packet_keys. push ( onion_utils:: OnionKeys {
177
+ #[ cfg( test) ]
178
+ shared_secret : onion_packet_ss,
179
+ #[ cfg( test) ]
180
+ blinding_factor : [ 0 ; 32 ] ,
181
+ ephemeral_pubkey,
182
+ rho,
183
+ mu,
184
+ } ) ;
185
+ } ) ?;
186
+
187
+ if let Some ( control_tlvs_ss) = prev_control_tlvs_ss {
188
+ payloads. push ( ( Payload :: Receive {
189
+ control_tlvs : ReceiveControlTlvs :: Unblinded ( ReceiveTlvs { path_id : None , } )
190
+ } , control_tlvs_ss) ) ;
191
+ }
192
+
193
+ Ok ( ( payloads, onion_packet_keys) )
194
+ }
195
+
196
+ fn construct_onion_message_packet ( payloads : Vec < ( Payload , [ u8 ; 32 ] ) > , onion_keys : Vec < onion_utils:: OnionKeys > , prng_seed : [ u8 ; 32 ] ) -> Packet {
197
+ // Spec rationale:
198
+ // "`len` allows larger messages to be sent than the standard 1300 bytes allowed for an HTLC
199
+ // onion, but this should be used sparingly as it is reduces anonymity set, hence the
200
+ // recommendation that it either look like an HTLC onion, or if larger, be a fixed size."
201
+ let payloads_ser_len = onion_utils:: payloads_serialized_length ( & payloads) ;
202
+ let hop_data_len = if payloads_ser_len <= SMALL_PACKET_HOP_DATA_LEN {
203
+ SMALL_PACKET_HOP_DATA_LEN
204
+ } else if payloads_ser_len <= BIG_PACKET_HOP_DATA_LEN {
205
+ BIG_PACKET_HOP_DATA_LEN
206
+ } else { payloads_ser_len } ;
207
+
208
+ onion_utils:: construct_onion_message_packet :: < _ , _ > ( payloads, onion_keys, prng_seed, hop_data_len)
209
+ }
0 commit comments