Skip to content

Commit 05a6be0

Browse files
committed
Use impl Iterator rather than a callback when building onion keys
The onion keys building logic is rather ancient and predates the `-> impl Trait` syntax in Rust, and thus used a callback. Here we move it to an `impl Iterator` which is much Rustier and cleans up the code a bit.
1 parent d903f69 commit 05a6be0

File tree

1 file changed

+58
-72
lines changed

1 file changed

+58
-72
lines changed

lightning/src/ln/onion_utils.rs

Lines changed: 58 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -296,26 +296,25 @@ impl<'a, 'b> OnionPayload<'a, 'b> for msgs::OutboundTrampolinePayload<'a> {
296296
}
297297
}
298298

299-
#[inline]
300-
fn construct_onion_keys_generic_callback<'a, T, H, FType>(
301-
secp_ctx: &Secp256k1<T>, hops: &'a [H], blinded_tail: Option<&BlindedTail>,
302-
session_priv: &SecretKey, mut callback: FType,
303-
) where
299+
fn construct_onion_keys_generic<'a, T, H>(
300+
secp_ctx: &'a Secp256k1<T>, hops: &'a [H], blinded_tail: Option<&'a BlindedTail>,
301+
session_priv: &SecretKey,
302+
) -> impl Iterator<Item = (SharedSecret, [u8; 32], PublicKey, Option<&'a H>, usize)> + 'a
303+
where
304304
T: secp256k1::Signing,
305305
H: HopInfo,
306-
FType: FnMut(SharedSecret, [u8; 32], PublicKey, Option<&'a H>, usize),
307306
{
308307
let mut blinded_priv = session_priv.clone();
309308
let mut blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv);
310309

311-
let unblinded_hops_iter = hops.iter().map(|h| (h.node_pubkey(), Some(h)));
312-
let blinded_pks_iter = blinded_tail
310+
let unblinded_hops = hops.iter().map(|h| (h.node_pubkey(), Some(h)));
311+
let blinded_pks = blinded_tail
313312
.map(|t| t.hops.iter())
314313
.unwrap_or([].iter())
315314
.skip(1) // Skip the intro node because it's included in the unblinded hops
316315
.map(|h| (&h.blinded_node_id, None));
317316

318-
for (idx, (pubkey, route_hop_opt)) in unblinded_hops_iter.chain(blinded_pks_iter).enumerate() {
317+
unblinded_hops.chain(blinded_pks).enumerate().map(move |(idx, (pubkey, route_hop_opt))| {
319318
let shared_secret = SharedSecret::new(pubkey, &blinded_priv);
320319

321320
let mut sha = Sha256::engine();
@@ -330,8 +329,8 @@ fn construct_onion_keys_generic_callback<'a, T, H, FType>(
330329
.expect("Blinding are never invalid as we picked the starting private key randomly");
331330
blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv);
332331

333-
callback(shared_secret, blinding_factor, ephemeral_pubkey, route_hop_opt, idx);
334-
}
332+
(shared_secret, blinding_factor, ephemeral_pubkey, route_hop_opt, idx)
333+
})
335334
}
336335

337336
// can only fail if an intermediary hop has an invalid public key or session_priv is invalid
@@ -346,25 +345,20 @@ pub(super) fn construct_onion_keys<T: secp256k1::Signing>(
346345
}
347346
Some(t)
348347
});
349-
construct_onion_keys_generic_callback(
350-
secp_ctx,
351-
&path.hops,
352-
blinded_tail,
353-
session_priv,
354-
|shared_secret, _blinding_factor, ephemeral_pubkey, _, _| {
355-
let (rho, mu) = gen_rho_mu_from_shared_secret(shared_secret.as_ref());
356-
357-
res.push(OnionKeys {
358-
#[cfg(test)]
359-
shared_secret,
360-
#[cfg(test)]
361-
blinding_factor: _blinding_factor,
362-
ephemeral_pubkey,
363-
rho,
364-
mu,
365-
});
366-
},
367-
);
348+
let iter = construct_onion_keys_generic(secp_ctx, &path.hops, blinded_tail, session_priv);
349+
for (shared_secret, _blinding_factor, ephemeral_pubkey, _, _) in iter {
350+
let (rho, mu) = gen_rho_mu_from_shared_secret(shared_secret.as_ref());
351+
352+
res.push(OnionKeys {
353+
#[cfg(test)]
354+
shared_secret,
355+
#[cfg(test)]
356+
blinding_factor: _blinding_factor,
357+
ephemeral_pubkey,
358+
rho,
359+
mu,
360+
});
361+
}
368362

369363
res
370364
}
@@ -375,25 +369,21 @@ pub(super) fn construct_trampoline_onion_keys<T: secp256k1::Signing>(
375369
) -> Vec<OnionKeys> {
376370
let mut res = Vec::with_capacity(blinded_tail.trampoline_hops.len());
377371

378-
construct_onion_keys_generic_callback(
379-
secp_ctx,
380-
&blinded_tail.trampoline_hops,
381-
Some(blinded_tail),
382-
session_priv,
383-
|shared_secret, _blinding_factor, ephemeral_pubkey, _, _| {
384-
let (rho, mu) = gen_rho_mu_from_shared_secret(shared_secret.as_ref());
385-
386-
res.push(OnionKeys {
387-
#[cfg(test)]
388-
shared_secret,
389-
#[cfg(test)]
390-
blinding_factor: _blinding_factor,
391-
ephemeral_pubkey,
392-
rho,
393-
mu,
394-
});
395-
},
396-
);
372+
let hops = &blinded_tail.trampoline_hops;
373+
let iter = construct_onion_keys_generic(secp_ctx, &hops, Some(blinded_tail), session_priv);
374+
for (shared_secret, _blinding_factor, ephemeral_pubkey, _, _) in iter {
375+
let (rho, mu) = gen_rho_mu_from_shared_secret(shared_secret.as_ref());
376+
377+
res.push(OnionKeys {
378+
#[cfg(test)]
379+
shared_secret,
380+
#[cfg(test)]
381+
blinding_factor: _blinding_factor,
382+
ephemeral_pubkey,
383+
rho,
384+
mu,
385+
});
386+
}
397387

398388
res
399389
}
@@ -1059,31 +1049,27 @@ where
10591049
let mut onion_keys =
10601050
Vec::with_capacity(path.hops.len() + num_trampoline_hops + num_blinded_hops);
10611051

1062-
construct_onion_keys_generic_callback(
1063-
secp_ctx,
1064-
&path.hops,
1065-
// if we have Trampoline hops, the blinded hops are part of the inner Trampoline onion
1066-
if path.has_trampoline_hops() { None } else { path.blinded_tail.as_ref() },
1067-
outer_session_priv,
1068-
|shared_secret, _, _, route_hop_option: Option<&RouteHop>, _| {
1069-
onion_keys.push((route_hop_option.map(|rh| ErrorHop::RouteHop(rh)), shared_secret))
1070-
},
1071-
);
1052+
// if we have Trampoline hops, the blinded hops are part of the inner Trampoline onion
1053+
let nontrampoline_bp =
1054+
if path.has_trampoline_hops() { None } else { path.blinded_tail.as_ref() };
1055+
let nontrampoline_hops =
1056+
construct_onion_keys_generic(secp_ctx, &path.hops, nontrampoline_bp, outer_session_priv);
1057+
for (shared_secret, _, _, route_hop_option, _) in nontrampoline_hops {
1058+
onion_keys.push((route_hop_option.map(|rh| ErrorHop::RouteHop(rh)), shared_secret));
1059+
}
10721060

10731061
if path.has_trampoline_hops() {
1074-
construct_onion_keys_generic_callback(
1075-
secp_ctx,
1076-
// Trampoline hops are part of the blinded tail, so this can never panic
1077-
&path.blinded_tail.as_ref().unwrap().trampoline_hops,
1078-
path.blinded_tail.as_ref(),
1079-
inner_session_priv.expect("Trampoline hops always have an inner session priv"),
1080-
|shared_secret, _, _, trampoline_hop_option: Option<&TrampolineHop>, _| {
1081-
onion_keys.push((
1082-
trampoline_hop_option.map(|th| ErrorHop::TrampolineHop(th)),
1083-
shared_secret,
1084-
))
1085-
},
1086-
);
1062+
// Trampoline hops are part of the blinded tail, so this can never panic
1063+
let blinded_tail = path.blinded_tail.as_ref();
1064+
let hops = &blinded_tail.unwrap().trampoline_hops;
1065+
let inner_session_priv =
1066+
inner_session_priv.expect("Trampoline hops always have an inner session priv");
1067+
let trampoline_hops =
1068+
construct_onion_keys_generic(secp_ctx, hops, blinded_tail, inner_session_priv);
1069+
for (shared_secret, _, _, trampoline_hop_option, _) in trampoline_hops {
1070+
onion_keys
1071+
.push((trampoline_hop_option.map(|th| ErrorHop::TrampolineHop(th)), shared_secret));
1072+
}
10871073
}
10881074

10891075
// Handle packed channel/node updates for passing back for the route handler

0 commit comments

Comments
 (0)