@@ -176,6 +176,72 @@ pub(super) fn construct_onion_keys<T: secp256k1::Signing>(
176
176
Ok ( res)
177
177
}
178
178
179
+ #[ inline]
180
+ pub ( super ) fn construct_trampoline_onion_keys_callback < T , FType > (
181
+ secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey , mut callback : FType ,
182
+ ) -> Result < ( ) , secp256k1:: Error >
183
+ where
184
+ T : secp256k1:: Signing ,
185
+ FType : FnMut ( SharedSecret , [ u8 ; 32 ] , PublicKey , Option < & TrampolineHop > , usize ) ,
186
+ {
187
+ let mut blinded_priv = session_priv. clone ( ) ;
188
+ let mut blinded_pub = PublicKey :: from_secret_key ( secp_ctx, & blinded_priv) ;
189
+
190
+ let unblinded_hops_iter = path. trampoline_hops . iter ( ) . map ( |h| ( & h. pubkey , Some ( h) ) ) ;
191
+ let blinded_pks_iter = path
192
+ . blinded_tail
193
+ . as_ref ( )
194
+ . map ( |t| t. hops . iter ( ) )
195
+ . unwrap_or ( [ ] . iter ( ) )
196
+ . skip ( 1 ) // Skip the intro node because it's included in the unblinded hops
197
+ . map ( |h| ( & h. blinded_node_id , None ) ) ;
198
+ for ( idx, ( pubkey, route_hop_opt) ) in unblinded_hops_iter. chain ( blinded_pks_iter) . enumerate ( ) {
199
+ let shared_secret = SharedSecret :: new ( pubkey, & blinded_priv) ;
200
+
201
+ let mut sha = Sha256 :: engine ( ) ;
202
+ sha. input ( & blinded_pub. serialize ( ) [ ..] ) ;
203
+ sha. input ( shared_secret. as_ref ( ) ) ;
204
+ let blinding_factor = Sha256 :: from_engine ( sha) . to_byte_array ( ) ;
205
+
206
+ let ephemeral_pubkey = blinded_pub;
207
+
208
+ blinded_priv = blinded_priv. mul_tweak ( & Scalar :: from_be_bytes ( blinding_factor) . unwrap ( ) ) ?;
209
+ blinded_pub = PublicKey :: from_secret_key ( secp_ctx, & blinded_priv) ;
210
+
211
+ callback ( shared_secret, blinding_factor, ephemeral_pubkey, route_hop_opt, idx) ;
212
+ }
213
+
214
+ Ok ( ( ) )
215
+ }
216
+
217
+ // can only fail if an intermediary hop has an invalid public key or session_priv is invalid
218
+ pub ( super ) fn construct_trampoline_onion_keys < T : secp256k1:: Signing > (
219
+ secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey ,
220
+ ) -> Result < Vec < OnionKeys > , secp256k1:: Error > {
221
+ let mut res = Vec :: with_capacity ( path. trampoline_hops . len ( ) ) ;
222
+
223
+ construct_trampoline_onion_keys_callback (
224
+ secp_ctx,
225
+ & path,
226
+ session_priv,
227
+ |shared_secret, _blinding_factor, ephemeral_pubkey, _, _| {
228
+ let ( rho, mu) = gen_rho_mu_from_shared_secret ( shared_secret. as_ref ( ) ) ;
229
+
230
+ res. push ( OnionKeys {
231
+ #[ cfg( test) ]
232
+ shared_secret,
233
+ #[ cfg( test) ]
234
+ blinding_factor : _blinding_factor,
235
+ ephemeral_pubkey,
236
+ rho,
237
+ mu,
238
+ } ) ;
239
+ } ,
240
+ ) ?;
241
+
242
+ Ok ( res)
243
+ }
244
+
179
245
fn build_trampoline_onion_payloads < ' a > (
180
246
path : & ' a Path , total_msat : u64 , recipient_onion : & ' a RecipientOnionFields ,
181
247
starting_htlc_offset : u32 , keysend_preimage : & Option < PaymentPreimage > ,
0 commit comments