Skip to content

Commit 439d245

Browse files
Simplify onion message blinded hop construction
Also adds a util for general blinded hop creation to be reused for blinded payment paths.
1 parent 70754e1 commit 439d245

File tree

3 files changed

+44
-31
lines changed

3 files changed

+44
-31
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -59,35 +59,14 @@ impl Writeable for ReceiveTlvs {
5959
pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
6060
secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], session_priv: &SecretKey
6161
) -> Result<Vec<BlindedHop>, secp256k1::Error> {
62-
let mut blinded_hops = Vec::with_capacity(unblinded_path.len());
62+
let blinded_tlvs = unblinded_path.iter()
63+
.skip(1) // The first node's TLVs contains the next node's pubkey
64+
.map(|pk| {
65+
ControlTlvs::Forward(ForwardTlvs { next_node_id: *pk, next_blinding_override: None })
66+
})
67+
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs { path_id: None })));
6368

64-
let mut prev_ss_and_blinded_node_id = None;
65-
utils::construct_keys_callback(secp_ctx, unblinded_path.iter(), None, session_priv,
66-
|blinded_node_id, _, _, encrypted_payload_ss, unblinded_pk, _| {
67-
if let Some((prev_ss, prev_blinded_node_id)) = prev_ss_and_blinded_node_id {
68-
if let Some(pk) = unblinded_pk {
69-
let payload = ForwardTlvs {
70-
next_node_id: pk,
71-
next_blinding_override: None,
72-
};
73-
blinded_hops.push(BlindedHop {
74-
blinded_node_id: prev_blinded_node_id,
75-
encrypted_payload: utils::encrypt_payload(payload, prev_ss),
76-
});
77-
} else { debug_assert!(false); }
78-
}
79-
prev_ss_and_blinded_node_id = Some((encrypted_payload_ss, blinded_node_id));
80-
})?;
81-
82-
if let Some((final_ss, final_blinded_node_id)) = prev_ss_and_blinded_node_id {
83-
let final_payload = ReceiveTlvs { path_id: None };
84-
blinded_hops.push(BlindedHop {
85-
blinded_node_id: final_blinded_node_id,
86-
encrypted_payload: utils::encrypt_payload(final_payload, final_ss),
87-
});
88-
} else { debug_assert!(false) }
89-
90-
Ok(blinded_hops)
69+
utils::construct_blinded_hops(secp_ctx, unblinded_path.iter(), blinded_tlvs, session_priv)
9170
}
9271

9372
// Advance the blinded onion message path by one hop, so make the second hop into the new

lightning/src/blinded_path/utils.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
1515
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey, Scalar};
1616
use bitcoin::secp256k1::ecdh::SharedSecret;
1717

18-
use super::BlindedPath;
18+
use super::{BlindedHop, BlindedPath};
1919
use crate::ln::msgs::DecodeError;
2020
use crate::ln::onion_utils;
2121
use crate::onion_message::Destination;
@@ -105,8 +105,32 @@ where
105105
Ok(())
106106
}
107107

108+
// Panics if `unblinded_tlvs` length is less than `unblinded_pks` length
109+
pub(super) fn construct_blinded_hops<'a, T, I1, I2>(
110+
secp_ctx: &Secp256k1<T>, unblinded_pks: I1, mut unblinded_tlvs: I2, session_priv: &SecretKey
111+
) -> Result<Vec<BlindedHop>, secp256k1::Error>
112+
where
113+
T: secp256k1::Signing + secp256k1::Verification,
114+
I1: Iterator<Item=&'a PublicKey>,
115+
I2: Iterator,
116+
I2::Item: Writeable
117+
{
118+
let mut blinded_hops = Vec::with_capacity(2); // We can't get the length of an Iterator without consuming it
119+
let mut curr_hop_idx = 0;
120+
construct_keys_callback(
121+
secp_ctx, unblinded_pks, None, session_priv,
122+
|blinded_node_id, _, _, encrypted_payload_rho, _, _| {
123+
blinded_hops.push(BlindedHop {
124+
blinded_node_id,
125+
encrypted_payload: encrypt_payload(unblinded_tlvs.next().unwrap(), encrypted_payload_rho),
126+
});
127+
curr_hop_idx += 1;
128+
})?;
129+
Ok(blinded_hops)
130+
}
131+
108132
/// Encrypt TLV payload to be used as a [`crate::blinded_path::BlindedHop::encrypted_payload`].
109-
pub(super) fn encrypt_payload<P: Writeable>(payload: P, encrypted_tlvs_ss: [u8; 32]) -> Vec<u8> {
133+
fn encrypt_payload<P: Writeable>(payload: P, encrypted_tlvs_ss: [u8; 32]) -> Vec<u8> {
110134
let mut writer = VecWriter(Vec::new());
111135
let write_adapter = ChaChaPolyWriteAdapter::new(encrypted_tlvs_ss, &payload);
112136
write_adapter.write(&mut writer).expect("In-memory writes cannot fail");

lightning/src/onion_message/packet.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ ReadableArgs<(SharedSecret, &H, &L)> for Payload<<H as CustomOnionMessageHandler
264264

265265
/// When reading a packet off the wire, we don't know a priori whether the packet is to be forwarded
266266
/// or received. Thus we read a ControlTlvs rather than reading a ForwardControlTlvs or
267-
/// ReceiveControlTlvs directly.
267+
/// ReceiveControlTlvs directly. Also useful on the encoding side to keep forward and receive TLVs
268+
/// in the same iterator.
268269
pub(crate) enum ControlTlvs {
269270
/// This onion message is intended to be forwarded.
270271
Forward(ForwardTlvs),
@@ -301,3 +302,12 @@ impl Readable for ControlTlvs {
301302
Ok(payload_fmt)
302303
}
303304
}
305+
306+
impl Writeable for ControlTlvs {
307+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
308+
match self {
309+
Self::Forward(tlvs) => tlvs.write(w),
310+
Self::Receive(tlvs) => tlvs.write(w),
311+
}
312+
}
313+
}

0 commit comments

Comments
 (0)