Skip to content

Commit 7f22871

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 81c3db0 commit 7f22871

File tree

1 file changed

+61
-77
lines changed

1 file changed

+61
-77
lines changed

lightning/src/ln/onion_utils.rs

Lines changed: 61 additions & 77 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
}
@@ -1043,31 +1033,27 @@ where
10431033
let mut onion_keys =
10441034
Vec::with_capacity(path.hops.len() + num_trampoline_hops + num_blinded_hops);
10451035

1046-
construct_onion_keys_generic_callback(
1047-
secp_ctx,
1048-
&path.hops,
1049-
// if we have Trampoline hops, the blinded hops are part of the inner Trampoline onion
1050-
if path.has_trampoline_hops() { None } else { path.blinded_tail.as_ref() },
1051-
outer_session_priv,
1052-
|shared_secret, _, _, route_hop_option: Option<&RouteHop>, _| {
1053-
onion_keys.push((route_hop_option.map(|rh| ErrorHop::RouteHop(rh)), shared_secret))
1054-
},
1055-
);
1036+
// if we have Trampoline hops, the blinded hops are part of the inner Trampoline onion
1037+
let nontrampoline_bp =
1038+
if path.has_trampoline_hops() { None } else { path.blinded_tail.as_ref() };
1039+
let nontrampoline_hops =
1040+
construct_onion_keys_generic(secp_ctx, &path.hops, nontrampoline_bp, outer_session_priv);
1041+
for (shared_secret, _, _, route_hop_option, _) in nontrampoline_hops {
1042+
onion_keys.push((route_hop_option.map(|rh| ErrorHop::RouteHop(rh)), shared_secret));
1043+
}
10561044

10571045
if path.has_trampoline_hops() {
1058-
construct_onion_keys_generic_callback(
1059-
secp_ctx,
1060-
// Trampoline hops are part of the blinded tail, so this can never panic
1061-
&path.blinded_tail.as_ref().unwrap().trampoline_hops,
1062-
path.blinded_tail.as_ref(),
1063-
inner_session_priv.expect("Trampoline hops always have an inner session priv"),
1064-
|shared_secret, _, _, trampoline_hop_option: Option<&TrampolineHop>, _| {
1065-
onion_keys.push((
1066-
trampoline_hop_option.map(|th| ErrorHop::TrampolineHop(th)),
1067-
shared_secret,
1068-
))
1069-
},
1070-
);
1046+
// Trampoline hops are part of the blinded tail, so this can never panic
1047+
let blinded_tail = path.blinded_tail.as_ref();
1048+
let hops = &blinded_tail.unwrap().trampoline_hops;
1049+
let inner_session_priv =
1050+
inner_session_priv.expect("Trampoline hops always have an inner session priv");
1051+
let trampoline_hops =
1052+
construct_onion_keys_generic(secp_ctx, hops, blinded_tail, inner_session_priv);
1053+
for (shared_secret, _, _, trampoline_hop_option, _) in trampoline_hops {
1054+
onion_keys
1055+
.push((trampoline_hop_option.map(|th| ErrorHop::TrampolineHop(th)), shared_secret));
1056+
}
10711057
}
10721058

10731059
// Handle packed channel/node updates for passing back for the route handler
@@ -2163,8 +2149,7 @@ mod tests {
21632149
let route = Route { paths: vec![path], route_params: None };
21642150

21652151
let onion_keys =
2166-
super::construct_onion_keys(&secp_ctx, &route.paths[0], &get_test_session_key())
2167-
.unwrap();
2152+
super::construct_onion_keys(&secp_ctx, &route.paths[0], &get_test_session_key());
21682153
assert_eq!(onion_keys.len(), route.paths[0].hops.len());
21692154
onion_keys
21702155
}
@@ -2536,13 +2521,12 @@ mod tests {
25362521
&secp_ctx,
25372522
&path.blinded_tail.as_ref().unwrap(),
25382523
&session_priv,
2539-
)
2540-
.unwrap();
2524+
);
25412525

25422526
let outer_onion_keys = {
25432527
let session_priv_hash = Sha256::hash(&session_priv.secret_bytes()).to_byte_array();
25442528
let outer_session_priv = SecretKey::from_slice(&session_priv_hash[..]).unwrap();
2545-
construct_onion_keys(&Secp256k1::new(), &path, &outer_session_priv).unwrap()
2529+
construct_onion_keys(&Secp256k1::new(), &path, &outer_session_priv)
25462530
};
25472531

25482532
let htlc_source = HTLCSource::OutboundRoute {

0 commit comments

Comments
 (0)