Skip to content

Commit e3885f0

Browse files
shaavanjkczyz
andcommitted
Introduce Option<Padding> for ControlTlvs variants.
- Introduce padding as a field in the `ForwardTlvs` and `ReceiveTlvs` structs to ensure the above condition is met. - Calculate the padding length prior to padding the TLVs and use that data to update the padding field later. Co-authored-by: Jeffrey Czyz <[email protected]>
1 parent 23aa06f commit e3885f0

File tree

6 files changed

+48
-13
lines changed

6 files changed

+48
-13
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
1717
use crate::prelude::*;
1818

1919
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NextMessageHop, NodeIdLookUp};
20-
use crate::blinded_path::utils;
20+
use crate::blinded_path::utils::{self, Padding};
2121
use crate::io;
2222
use crate::io::Cursor;
2323
use crate::ln::channelmanager::PaymentId;
@@ -44,7 +44,10 @@ pub struct ForwardNode {
4444

4545
/// TLVs to encode in an intermediate onion message packet's hop data. When provided in a blinded
4646
/// route, they are encoded into [`BlindedHop::encrypted_payload`].
47+
#[derive(Clone)]
4748
pub(crate) struct ForwardTlvs {
49+
/// The padding data used to make all packets of a Blinded Path of same size
50+
pub(crate) padding: Option<Padding>,
4851
/// The next hop in the onion message's path.
4952
pub(crate) next_hop: NextMessageHop,
5053
/// Senders to a blinded path use this value to concatenate the route they find to the
@@ -53,7 +56,10 @@ pub(crate) struct ForwardTlvs {
5356
}
5457

5558
/// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
59+
#[derive(Clone)]
5660
pub(crate) struct ReceiveTlvs {
61+
/// The padding data used to make all packets of a Blinded Path of same size
62+
pub(crate) padding: Option<Padding>,
5763
/// If `context` is `Some`, it is used to identify the blinded path that this onion message is
5864
/// sending to. This is useful for receivers to check that said blinded path is being used in
5965
/// the right context.
@@ -66,8 +72,8 @@ impl Writeable for ForwardTlvs {
6672
NextMessageHop::NodeId(pubkey) => (Some(pubkey), None),
6773
NextMessageHop::ShortChannelId(scid) => (None, Some(scid)),
6874
};
69-
// TODO: write padding
7075
encode_tlv_stream!(writer, {
76+
(1, self.padding, option),
7177
(2, short_channel_id, option),
7278
(4, next_node_id, option),
7379
(8, self.next_blinding_override, option)
@@ -78,8 +84,8 @@ impl Writeable for ForwardTlvs {
7884

7985
impl Writeable for ReceiveTlvs {
8086
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
81-
// TODO: write padding
8287
encode_tlv_stream!(writer, {
88+
(1, self.padding, option),
8389
(65537, self.context, option),
8490
});
8591
Ok(())
@@ -184,10 +190,17 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
184190
Some(scid) => NextMessageHop::ShortChannelId(scid),
185191
None => NextMessageHop::NodeId(*pubkey),
186192
})
187-
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }))
188-
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs{ context: Some(context) })));
193+
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { padding: None, next_hop, next_blinding_override: None }))
194+
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs{ padding: None, context: Some(context) })));
189195

190-
utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
196+
let max_length = tlvs.clone()
197+
.map(|tlv| tlv.serialized_length())
198+
.max()
199+
.unwrap_or(0);
200+
201+
let length_tlvs = tlvs.map(|tlv| tlv.pad_to_length(max_length));
202+
203+
utils::construct_blinded_hops(secp_ctx, pks, length_tlvs, session_priv)
191204
}
192205

193206
// Advance the blinded onion message path by one hop, so make the second hop into the new
@@ -209,7 +222,7 @@ where
209222
let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
210223
match ChaChaPolyReadAdapter::read(&mut reader, rho) {
211224
Ok(ChaChaPolyReadAdapter {
212-
readable: ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override })
225+
readable: ControlTlvs::Forward(ForwardTlvs {padding: _, next_hop, next_blinding_override })
213226
}) => {
214227
let next_node_id = match next_hop {
215228
NextMessageHop::NodeId(pubkey) => pubkey,

lightning/src/blinded_path/payment.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ pub(crate) enum BlindedPaymentTlvs {
8686
}
8787

8888
// Used to include forward and receive TLVs in the same iterator for encoding.
89+
#[derive(Clone)]
8990
enum BlindedPaymentTlvsRef<'a> {
9091
Forward(&'a ForwardTlvs),
9192
Receive(&'a ReceiveTlvs),
@@ -226,7 +227,6 @@ impl Writeable for ReceiveTlvs {
226227

227228
impl<'a> Writeable for BlindedPaymentTlvsRef<'a> {
228229
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
229-
// TODO: write padding
230230
match self {
231231
Self::Forward(tlvs) => tlvs.write(w)?,
232232
Self::Receive(tlvs) => tlvs.write(w)?,
@@ -278,6 +278,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
278278
.chain(core::iter::once(&payee_node_id));
279279
let tlvs = intermediate_nodes.iter().map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))
280280
.chain(core::iter::once(BlindedPaymentTlvsRef::Receive(&payee_tlvs)));
281+
281282
utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
282283
}
283284

lightning/src/blinded_path/utils.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ fn encrypt_payload<P: Writeable>(payload: P, encrypted_tlvs_rho: [u8; 32]) -> Ve
137137

138138
/// Represents optional padding for encrypted payloads.
139139
/// Padding is used to ensure payloads have a consistent length.
140-
pub(crate) struct Padding {
140+
#[derive(Clone, Debug)]
141+
pub struct Padding {
141142
length: usize,
142143
}
143144

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ fn do_forward_checks_failure(check: ForwardCheckFail, intro_fails: bool) {
289289
let mut route_params = get_blinded_route_parameters(amt_msat, payment_secret, 1, 1_0000_0000,
290290
nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(),
291291
&[&chan_upd_1_2, &chan_upd_2_3], &chanmon_cfgs[3].keys_manager);
292-
route_params.payment_params.max_path_length = 18;
292+
route_params.payment_params.max_path_length = 17;
293293

294294
let route = get_route(&nodes[0], &route_params).unwrap();
295295
node_cfgs[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));

lightning/src/onion_message/messenger.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ where
950950
(control_tlvs_ss, custom_handler.deref(), logger.deref())
951951
) {
952952
Ok((Payload::Receive::<ParsedOnionMessageContents<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage>> {
953-
message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context }), reply_path,
953+
message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { padding: _, context }), reply_path,
954954
}, None)) => {
955955
match (&message, &context) {
956956
(_, None) => {
@@ -969,7 +969,7 @@ where
969969
}
970970
},
971971
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
972-
next_hop, next_blinding_override
972+
padding: _, next_hop, next_blinding_override
973973
})), Some((next_hop_hmac, new_packet_bytes)))) => {
974974
// TODO: we need to check whether `next_hop` is our node, in which case this is a dummy
975975
// blinded hop and this onion message is destined for us. In this situation, we should keep
@@ -1772,6 +1772,7 @@ fn packet_payloads_and_keys<T: OnionMessageContents, S: secp256k1::Signing + sec
17721772
if let Some(ss) = prev_control_tlvs_ss.take() {
17731773
payloads.push((Payload::Forward(ForwardControlTlvs::Unblinded(
17741774
ForwardTlvs {
1775+
padding: None,
17751776
next_hop: NextMessageHop::NodeId(unblinded_pk_opt.unwrap()),
17761777
next_blinding_override: None,
17771778
}
@@ -1782,6 +1783,7 @@ fn packet_payloads_and_keys<T: OnionMessageContents, S: secp256k1::Signing + sec
17821783
} else if let Some((intro_node_id, blinding_pt)) = intro_node_id_blinding_pt.take() {
17831784
if let Some(control_tlvs_ss) = prev_control_tlvs_ss.take() {
17841785
payloads.push((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
1786+
padding: None,
17851787
next_hop: NextMessageHop::NodeId(intro_node_id),
17861788
next_blinding_override: Some(blinding_pt),
17871789
})), control_tlvs_ss));
@@ -1817,7 +1819,7 @@ fn packet_payloads_and_keys<T: OnionMessageContents, S: secp256k1::Signing + sec
18171819
}, prev_control_tlvs_ss.unwrap()));
18181820
} else {
18191821
payloads.push((Payload::Receive {
1820-
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { context: None }),
1822+
control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { padding: None, context: None }),
18211823
reply_path: reply_path.take(),
18221824
message,
18231825
}, prev_control_tlvs_ss.unwrap()));

lightning/src/onion_message/packet.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,29 @@ for Payload<ParsedOnionMessageContents<<H as CustomOnionMessageHandler>::CustomM
306306
/// or received. Thus we read a `ControlTlvs` rather than reading a [`ForwardTlvs`] or
307307
/// [`ReceiveTlvs`] directly. Also useful on the encoding side to keep forward and receive TLVs in
308308
/// the same iterator.
309+
#[derive(Clone)]
309310
pub(crate) enum ControlTlvs {
310311
/// This onion message is intended to be forwarded.
311312
Forward(ForwardTlvs),
312313
/// This onion message is intended to be received.
313314
Receive(ReceiveTlvs),
314315
}
315316

317+
impl ControlTlvs {
318+
pub(crate) fn pad_to_length(mut self, length: usize) -> Self {
319+
let pad_length = length.checked_sub(self.serialized_length());
320+
debug_assert!(pad_length.is_some(), "Size of this packet should not be larger than the size of largest packet.");
321+
let padding = Some(Padding::new(pad_length.unwrap()));
322+
323+
match &mut self {
324+
ControlTlvs::Forward(tlvs) => tlvs.padding = padding,
325+
ControlTlvs::Receive(tlvs) => tlvs.padding = padding,
326+
}
327+
328+
self
329+
}
330+
}
331+
316332
impl Readable for ControlTlvs {
317333
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
318334
_init_and_read_tlv_stream!(r, {
@@ -336,11 +352,13 @@ impl Readable for ControlTlvs {
336352

337353
let payload_fmt = if valid_fwd_fmt {
338354
ControlTlvs::Forward(ForwardTlvs {
355+
padding: None,
339356
next_hop: next_hop.unwrap(),
340357
next_blinding_override,
341358
})
342359
} else if valid_recv_fmt {
343360
ControlTlvs::Receive(ReceiveTlvs {
361+
padding: None,
344362
context,
345363
})
346364
} else {

0 commit comments

Comments
 (0)