Skip to content

Commit 27a6edd

Browse files
shaavanjkczyz
andcommitted
f: Introduce Padding a message tlvs field instead of WithPadding
- WithPadding approach has a crucial flaw: it doesn't enforce that the tlv of the tlvs struct is not already utilizing the `(1,...)` position, which should be used for padding. - 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 fad1d97 commit 27a6edd

File tree

5 files changed

+37
-42
lines changed

5 files changed

+37
-42
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 11 additions & 5 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::{self, WithPadding};
20+
use crate::blinded_path::utils::{self, Padding};
2121
use crate::io;
2222
use crate::io::Cursor;
2323
use crate::ln::channelmanager::PaymentId;
@@ -46,6 +46,8 @@ pub struct ForwardNode {
4646
/// route, they are encoded into [`BlindedHop::encrypted_payload`].
4747
#[derive(Clone)]
4848
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>,
4951
/// The next hop in the onion message's path.
5052
pub(crate) next_hop: NextMessageHop,
5153
/// Senders to a blinded path use this value to concatenate the route they find to the
@@ -56,6 +58,8 @@ pub(crate) struct ForwardTlvs {
5658
/// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
5759
#[derive(Clone)]
5860
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>,
5963
/// If `context` is `Some`, it is used to identify the blinded path that this onion message is
6064
/// sending to. This is useful for receivers to check that said blinded path is being used in
6165
/// the right context.
@@ -69,6 +73,7 @@ impl Writeable for ForwardTlvs {
6973
NextMessageHop::ShortChannelId(scid) => (None, Some(scid)),
7074
};
7175
encode_tlv_stream!(writer, {
76+
(1, self.padding, option),
7277
(2, short_channel_id, option),
7378
(4, next_node_id, option),
7479
(8, self.next_blinding_override, option)
@@ -80,6 +85,7 @@ impl Writeable for ForwardTlvs {
8085
impl Writeable for ReceiveTlvs {
8186
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
8287
encode_tlv_stream!(writer, {
88+
(1, self.padding, option),
8389
(65537, self.context, option),
8490
});
8591
Ok(())
@@ -184,15 +190,15 @@ 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

190196
let max_length = tlvs.clone()
191197
.map(|tlv| tlv.serialized_length())
192198
.max()
193199
.unwrap_or(0);
194200

195-
let length_tlvs = tlvs.map(|tlvs| WithPadding { max_length, tlvs });
201+
let length_tlvs = tlvs.map(|tlv| tlv.pad_to_length(max_length));
196202

197203
utils::construct_blinded_hops(secp_ctx, pks, length_tlvs, session_priv)
198204
}
@@ -216,7 +222,7 @@ where
216222
let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
217223
match ChaChaPolyReadAdapter::read(&mut reader, rho) {
218224
Ok(ChaChaPolyReadAdapter {
219-
readable: ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override })
225+
readable: ControlTlvs::Forward(ForwardTlvs {padding: _, next_hop, next_blinding_override })
220226
}) => {
221227
let next_node_id = match next_hop {
222228
NextMessageHop::NodeId(pubkey) => pubkey,

lightning/src/blinded_path/payment.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
1515

1616
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp};
17-
use crate::blinded_path::utils::{self, WithPadding};
17+
use crate::blinded_path::utils;
1818
use crate::crypto::streams::ChaChaPolyReadAdapter;
1919
use crate::io;
2020
use crate::io::Cursor;
@@ -279,14 +279,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
279279
let tlvs = intermediate_nodes.iter().map(|node| BlindedPaymentTlvsRef::Forward(&node.tlvs))
280280
.chain(core::iter::once(BlindedPaymentTlvsRef::Receive(&payee_tlvs)));
281281

282-
let max_length = tlvs.clone()
283-
.map(|tlv| tlv.serialized_length())
284-
.max()
285-
.unwrap_or(0);
286-
287-
let length_tlvs = tlvs.map(|tlvs| WithPadding { max_length, tlvs });
288-
289-
utils::construct_blinded_hops(secp_ctx, pks, length_tlvs, session_priv)
282+
utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv)
290283
}
291284

292285
// Advance the blinded onion payment path by one hop, so make the second hop into the new

lightning/src/blinded_path/utils.rs

Lines changed: 2 additions & 25 deletions
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

@@ -177,27 +178,3 @@ impl Writeable for Padding {
177178
Ok(())
178179
}
179180
}
180-
181-
182-
/// A wrapper struct that stores the largest packet size for a [`BlindedPath`].
183-
/// This helps us calculate the appropriate padding size for the tlvs when writing them.
184-
pub(super) struct WithPadding<T: Writeable> {
185-
/// Length of the packet with the largest size in the [`BlindedPath`].
186-
pub(super) max_length: usize,
187-
/// The current packet's TLVs.
188-
pub(super) tlvs: T,
189-
}
190-
191-
impl<T: Writeable> Writeable for WithPadding<T> {
192-
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
193-
let length = self.max_length.checked_sub(self.tlvs.serialized_length());
194-
debug_assert!(length.is_some(), "Size of this packet should not be larger than the size of largest packet.");
195-
let padding = Some(Padding::new(length.unwrap()));
196-
197-
encode_tlv_stream!(writer, {
198-
(1, padding, option)
199-
});
200-
201-
self.tlvs.write(writer)
202-
}
203-
}

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: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,21 @@ pub(crate) enum ControlTlvs {
314314
Receive(ReceiveTlvs),
315315
}
316316

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+
317332
impl Readable for ControlTlvs {
318333
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
319334
_init_and_read_tlv_stream!(r, {
@@ -337,11 +352,13 @@ impl Readable for ControlTlvs {
337352

338353
let payload_fmt = if valid_fwd_fmt {
339354
ControlTlvs::Forward(ForwardTlvs {
355+
padding: None,
340356
next_hop: next_hop.unwrap(),
341357
next_blinding_override,
342358
})
343359
} else if valid_recv_fmt {
344360
ControlTlvs::Receive(ReceiveTlvs {
361+
padding: None,
345362
context,
346363
})
347364
} else {

0 commit comments

Comments
 (0)