Skip to content

Commit cf2fa9d

Browse files
authored
Merge pull request #3248 from jkczyz/2024-08-blinded-path-utils-refactor
Refactor `BlindedPath` construction utils
2 parents 9effe0a + 76c9fda commit cf2fa9d

File tree

5 files changed

+96
-58
lines changed

5 files changed

+96
-58
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,18 +374,20 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
374374
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[MessageForwardNode],
375375
recipient_node_id: PublicKey, context: MessageContext, session_priv: &SecretKey,
376376
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
377-
let pks = intermediate_nodes.iter().map(|node| &node.node_id)
378-
.chain(core::iter::once(&recipient_node_id));
377+
let pks = intermediate_nodes.iter().map(|node| node.node_id)
378+
.chain(core::iter::once(recipient_node_id));
379379
let tlvs = pks.clone()
380380
.skip(1) // The first node's TLVs contains the next node's pubkey
381381
.zip(intermediate_nodes.iter().map(|node| node.short_channel_id))
382382
.map(|(pubkey, scid)| match scid {
383383
Some(scid) => NextMessageHop::ShortChannelId(scid),
384-
None => NextMessageHop::NodeId(*pubkey),
384+
None => NextMessageHop::NodeId(pubkey),
385385
})
386386
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }))
387387
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs{ context: Some(context) })));
388388

389-
utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
389+
let path = pks.zip(tlvs);
390+
391+
utils::construct_blinded_hops(secp_ctx, path, session_priv)
390392
}
391393

lightning/src/blinded_path/payment.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -462,11 +462,14 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
462462
secp_ctx: &Secp256k1<T>, intermediate_nodes: &[PaymentForwardNode],
463463
payee_node_id: PublicKey, payee_tlvs: ReceiveTlvs, session_priv: &SecretKey,
464464
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
465-
let pks = intermediate_nodes.iter().map(|node| &node.node_id)
466-
.chain(core::iter::once(&payee_node_id));
465+
let pks = intermediate_nodes.iter().map(|node| node.node_id)
466+
.chain(core::iter::once(payee_node_id));
467467
let tlvs = intermediate_nodes.iter().map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))
468468
.chain(core::iter::once(BlindedPaymentTlvsRef::Receive(&payee_tlvs)));
469-
utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
469+
470+
let path = pks.zip(tlvs);
471+
472+
utils::construct_blinded_hops(secp_ctx, path, session_priv)
470473
}
471474

472475
/// `None` if underflow occurs.

lightning/src/blinded_path/utils.rs

Lines changed: 76 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -25,42 +25,38 @@ use crate::util::ser::{Readable, Writeable};
2525

2626
use crate::io;
2727

28+
use core::borrow::Borrow;
29+
2830
#[allow(unused_imports)]
2931
use crate::prelude::*;
3032

3133
// TODO: DRY with onion_utils::construct_onion_keys_callback
32-
#[inline]
33-
pub(crate) fn construct_keys_callback<'a, T, I, F>(
34-
secp_ctx: &Secp256k1<T>, unblinded_path: I, destination: Option<Destination>,
35-
session_priv: &SecretKey, mut callback: F
36-
) -> Result<(), secp256k1::Error>
37-
where
38-
T: secp256k1::Signing + secp256k1::Verification,
39-
I: Iterator<Item=&'a PublicKey>,
40-
F: FnMut(PublicKey, SharedSecret, PublicKey, [u8; 32], Option<PublicKey>, Option<Vec<u8>>),
34+
macro_rules! build_keys_helper {
35+
($session_priv: ident, $secp_ctx: ident, $callback: ident) =>
4136
{
42-
let mut msg_blinding_point_priv = session_priv.clone();
43-
let mut msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
37+
let mut msg_blinding_point_priv = $session_priv.clone();
38+
let mut msg_blinding_point = PublicKey::from_secret_key($secp_ctx, &msg_blinding_point_priv);
4439
let mut onion_packet_pubkey_priv = msg_blinding_point_priv.clone();
4540
let mut onion_packet_pubkey = msg_blinding_point.clone();
4641

4742
macro_rules! build_keys {
48-
($pk: expr, $blinded: expr, $encrypted_payload: expr) => {{
49-
let encrypted_data_ss = SharedSecret::new(&$pk, &msg_blinding_point_priv);
43+
($hop: expr, $blinded: expr, $encrypted_payload: expr) => {{
44+
let pk = *$hop.borrow();
45+
let encrypted_data_ss = SharedSecret::new(&pk, &msg_blinding_point_priv);
5046

51-
let blinded_hop_pk = if $blinded { $pk } else {
47+
let blinded_hop_pk = if $blinded { pk } else {
5248
let hop_pk_blinding_factor = {
5349
let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
5450
hmac.input(encrypted_data_ss.as_ref());
5551
Hmac::from_engine(hmac).to_byte_array()
5652
};
57-
$pk.mul_tweak(secp_ctx, &Scalar::from_be_bytes(hop_pk_blinding_factor).unwrap())?
53+
pk.mul_tweak($secp_ctx, &Scalar::from_be_bytes(hop_pk_blinding_factor).unwrap())?
5854
};
5955
let onion_packet_ss = SharedSecret::new(&blinded_hop_pk, &onion_packet_pubkey_priv);
6056

6157
let rho = onion_utils::gen_rho_from_shared_secret(encrypted_data_ss.as_ref());
62-
let unblinded_pk_opt = if $blinded { None } else { Some($pk) };
63-
callback(blinded_hop_pk, onion_packet_ss, onion_packet_pubkey, rho, unblinded_pk_opt, $encrypted_payload);
58+
let unblinded_hop_opt = if $blinded { None } else { Some($hop) };
59+
$callback(blinded_hop_pk, onion_packet_ss, onion_packet_pubkey, rho, unblinded_hop_opt, $encrypted_payload);
6460
(encrypted_data_ss, onion_packet_ss)
6561
}}
6662
}
@@ -77,7 +73,7 @@ where
7773
};
7874

7975
msg_blinding_point_priv = msg_blinding_point_priv.mul_tweak(&Scalar::from_be_bytes(msg_blinding_point_blinding_factor).unwrap())?;
80-
msg_blinding_point = PublicKey::from_secret_key(secp_ctx, &msg_blinding_point_priv);
76+
msg_blinding_point = PublicKey::from_secret_key($secp_ctx, &msg_blinding_point_priv);
8177

8278
let onion_packet_pubkey_blinding_factor = {
8379
let mut sha = Sha256::engine();
@@ -86,45 +82,83 @@ where
8682
Sha256::from_engine(sha).to_byte_array()
8783
};
8884
onion_packet_pubkey_priv = onion_packet_pubkey_priv.mul_tweak(&Scalar::from_be_bytes(onion_packet_pubkey_blinding_factor).unwrap())?;
89-
onion_packet_pubkey = PublicKey::from_secret_key(secp_ctx, &onion_packet_pubkey_priv);
85+
onion_packet_pubkey = PublicKey::from_secret_key($secp_ctx, &onion_packet_pubkey_priv);
9086
};
9187
}
88+
}}
89+
90+
#[inline]
91+
pub(crate) fn construct_keys_for_onion_message<'a, T, I, F>(
92+
secp_ctx: &Secp256k1<T>, unblinded_path: I, destination: Destination, session_priv: &SecretKey,
93+
mut callback: F,
94+
) -> Result<(), secp256k1::Error>
95+
where
96+
T: secp256k1::Signing + secp256k1::Verification,
97+
I: Iterator<Item=PublicKey>,
98+
F: FnMut(PublicKey, SharedSecret, PublicKey, [u8; 32], Option<PublicKey>, Option<Vec<u8>>),
99+
{
100+
build_keys_helper!(session_priv, secp_ctx, callback);
92101

93102
for pk in unblinded_path {
94-
build_keys_in_loop!(*pk, false, None);
103+
build_keys_in_loop!(pk, false, None);
95104
}
96-
if let Some(dest) = destination {
97-
match dest {
98-
Destination::Node(pk) => {
99-
build_keys!(pk, false, None);
100-
},
101-
Destination::BlindedPath(BlindedMessagePath(BlindedPath { blinded_hops, .. })) => {
102-
for hop in blinded_hops {
103-
build_keys_in_loop!(hop.blinded_node_id, true, Some(hop.encrypted_payload));
104-
}
105-
},
106-
}
105+
match destination {
106+
Destination::Node(pk) => {
107+
build_keys!(pk, false, None);
108+
},
109+
Destination::BlindedPath(BlindedMessagePath(BlindedPath { blinded_hops, .. })) => {
110+
for hop in blinded_hops {
111+
build_keys_in_loop!(hop.blinded_node_id, true, Some(hop.encrypted_payload));
112+
}
113+
},
114+
}
115+
Ok(())
116+
}
117+
118+
#[inline]
119+
pub(super) fn construct_keys_for_blinded_path<'a, T, I, F, H>(
120+
secp_ctx: &Secp256k1<T>, unblinded_path: I, session_priv: &SecretKey, mut callback: F,
121+
) -> Result<(), secp256k1::Error>
122+
where
123+
T: secp256k1::Signing + secp256k1::Verification,
124+
H: Borrow<PublicKey>,
125+
I: Iterator<Item=H>,
126+
F: FnMut(PublicKey, SharedSecret, PublicKey, [u8; 32], Option<H>, Option<Vec<u8>>),
127+
{
128+
build_keys_helper!(session_priv, secp_ctx, callback);
129+
130+
for pk in unblinded_path {
131+
build_keys_in_loop!(pk, false, None);
107132
}
108133
Ok(())
109134
}
110135

111-
// Panics if `unblinded_tlvs` length is less than `unblinded_pks` length
112-
pub(crate) fn construct_blinded_hops<'a, T, I1, I2>(
113-
secp_ctx: &Secp256k1<T>, unblinded_pks: I1, mut unblinded_tlvs: I2, session_priv: &SecretKey
136+
struct PublicKeyWithTlvs<W: Writeable> {
137+
pubkey: PublicKey,
138+
tlvs: W,
139+
}
140+
141+
impl<W: Writeable> Borrow<PublicKey> for PublicKeyWithTlvs<W> {
142+
fn borrow(&self) -> &PublicKey {
143+
&self.pubkey
144+
}
145+
}
146+
147+
pub(crate) fn construct_blinded_hops<'a, T, I, W>(
148+
secp_ctx: &Secp256k1<T>, unblinded_path: I, session_priv: &SecretKey,
114149
) -> Result<Vec<BlindedHop>, secp256k1::Error>
115150
where
116151
T: secp256k1::Signing + secp256k1::Verification,
117-
I1: Iterator<Item=&'a PublicKey>,
118-
I2: Iterator,
119-
I2::Item: Writeable
152+
I: Iterator<Item=(PublicKey, W)>,
153+
W: Writeable
120154
{
121-
let mut blinded_hops = Vec::with_capacity(unblinded_pks.size_hint().0);
122-
construct_keys_callback(
123-
secp_ctx, unblinded_pks, None, session_priv,
124-
|blinded_node_id, _, _, encrypted_payload_rho, _, _| {
155+
let mut blinded_hops = Vec::with_capacity(unblinded_path.size_hint().0);
156+
construct_keys_for_blinded_path(
157+
secp_ctx, unblinded_path.map(|(pubkey, tlvs)| PublicKeyWithTlvs { pubkey, tlvs }), session_priv,
158+
|blinded_node_id, _, _, encrypted_payload_rho, unblinded_hop_data, _| {
125159
blinded_hops.push(BlindedHop {
126160
blinded_node_id,
127-
encrypted_payload: encrypt_payload(unblinded_tlvs.next().unwrap(), encrypted_payload_rho),
161+
encrypted_payload: encrypt_payload(unblinded_hop_data.unwrap().tlvs, encrypted_payload_rho),
128162
});
129163
})?;
130164
Ok(blinded_hops)

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1392,19 +1392,17 @@ fn route_blinding_spec_test_vector() {
13921392
let blinding_override = PublicKey::from_secret_key(&secp_ctx, &dave_eve_session_priv);
13931393
assert_eq!(blinding_override, pubkey_from_hex("031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f"));
13941394
// Can't use the public API here as the encrypted payloads contain unknown TLVs.
1395+
let path = [(dave_node_id, WithoutLength(&dave_unblinded_tlvs)), (eve_node_id, WithoutLength(&eve_unblinded_tlvs))];
13951396
let mut dave_eve_blinded_hops = blinded_path::utils::construct_blinded_hops(
1396-
&secp_ctx, [dave_node_id, eve_node_id].iter(),
1397-
&mut [WithoutLength(&dave_unblinded_tlvs), WithoutLength(&eve_unblinded_tlvs)].iter(),
1398-
&dave_eve_session_priv
1397+
&secp_ctx, path.into_iter(), &dave_eve_session_priv
13991398
).unwrap();
14001399

14011400
// Concatenate an additional Bob -> Carol blinded path to the Eve -> Dave blinded path.
14021401
let bob_carol_session_priv = secret_from_hex("0202020202020202020202020202020202020202020202020202020202020202");
14031402
let bob_blinding_point = PublicKey::from_secret_key(&secp_ctx, &bob_carol_session_priv);
1403+
let path = [(bob_node_id, WithoutLength(&bob_unblinded_tlvs)), (carol_node_id, WithoutLength(&carol_unblinded_tlvs))];
14041404
let bob_carol_blinded_hops = blinded_path::utils::construct_blinded_hops(
1405-
&secp_ctx, [bob_node_id, carol_node_id].iter(),
1406-
&mut [WithoutLength(&bob_unblinded_tlvs), WithoutLength(&carol_unblinded_tlvs)].iter(),
1407-
&bob_carol_session_priv
1405+
&secp_ctx, path.into_iter(), &bob_carol_session_priv
14081406
).unwrap();
14091407

14101408
let mut blinded_hops = bob_carol_blinded_hops;

lightning/src/onion_message/messenger.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@ where
918918
}
919919
};
920920
let (packet_payloads, packet_keys) = packet_payloads_and_keys(
921-
&secp_ctx, &intermediate_nodes, destination, contents, reply_path, &blinding_secret
921+
&secp_ctx, intermediate_nodes, destination, contents, reply_path, &blinding_secret
922922
)?;
923923

924924
let prng_seed = entropy_source.get_secure_random_bytes();
@@ -1811,7 +1811,7 @@ pub type SimpleRefOnionMessenger<
18111811
/// Construct onion packet payloads and keys for sending an onion message along the given
18121812
/// `unblinded_path` to the given `destination`.
18131813
fn packet_payloads_and_keys<T: OnionMessageContents, S: secp256k1::Signing + secp256k1::Verification>(
1814-
secp_ctx: &Secp256k1<S>, unblinded_path: &[PublicKey], destination: Destination, message: T,
1814+
secp_ctx: &Secp256k1<S>, unblinded_path: Vec<PublicKey>, destination: Destination, message: T,
18151815
mut reply_path: Option<BlindedMessagePath>, session_priv: &SecretKey
18161816
) -> Result<(Vec<(Payload<T>, [u8; 32])>, Vec<onion_utils::OnionKeys>), SendError> {
18171817
let num_hops = unblinded_path.len() + destination.num_hops();
@@ -1836,7 +1836,8 @@ fn packet_payloads_and_keys<T: OnionMessageContents, S: secp256k1::Signing + sec
18361836
let mut blinded_path_idx = 0;
18371837
let mut prev_control_tlvs_ss = None;
18381838
let mut final_control_tlvs = None;
1839-
utils::construct_keys_callback(secp_ctx, unblinded_path.iter(), Some(destination), session_priv,
1839+
utils::construct_keys_for_onion_message(
1840+
secp_ctx, unblinded_path.into_iter(), destination, session_priv,
18401841
|_, onion_packet_ss, ephemeral_pubkey, control_tlvs_ss, unblinded_pk_opt, enc_payload_opt| {
18411842
if num_unblinded_hops != 0 && unblinded_path_idx < num_unblinded_hops {
18421843
if let Some(ss) = prev_control_tlvs_ss.take() {

0 commit comments

Comments
 (0)