Skip to content

Commit 5afa023

Browse files
shaavanjkczyz
andcommitted
f: Alternate approach. Introduce padding as a 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 5afa023

File tree

10 files changed

+106
-37
lines changed

10 files changed

+106
-37
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 13 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;
2121
use crate::io;
2222
use crate::io::Cursor;
2323
use crate::ln::channelmanager::PaymentId;
@@ -31,6 +31,8 @@ use crate::util::ser::{FixedLengthReader, LengthReadableArgs, Writeable, Writer}
3131
use core::mem;
3232
use core::ops::Deref;
3333

34+
use super::utils::Padding;
35+
3436
/// An intermediate node, and possibly a short channel id leading to the next node.
3537
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
3638
pub struct ForwardNode {
@@ -46,6 +48,8 @@ pub struct ForwardNode {
4648
/// route, they are encoded into [`BlindedHop::encrypted_payload`].
4749
#[derive(Clone)]
4850
pub(crate) struct ForwardTlvs {
51+
/// The padding data used to make all packets of a Blinded Path of same size
52+
pub(crate) padding: Option<Padding>,
4953
/// The next hop in the onion message's path.
5054
pub(crate) next_hop: NextMessageHop,
5155
/// Senders to a blinded path use this value to concatenate the route they find to the
@@ -56,6 +60,8 @@ pub(crate) struct ForwardTlvs {
5660
/// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
5761
#[derive(Clone)]
5862
pub(crate) struct ReceiveTlvs {
63+
/// The padding data used to make all packets of a Blinded Path of same size
64+
pub(crate) padding: Option<Padding>,
5965
/// If `context` is `Some`, it is used to identify the blinded path that this onion message is
6066
/// sending to. This is useful for receivers to check that said blinded path is being used in
6167
/// the right context.
@@ -69,6 +75,7 @@ impl Writeable for ForwardTlvs {
6975
NextMessageHop::ShortChannelId(scid) => (None, Some(scid)),
7076
};
7177
encode_tlv_stream!(writer, {
78+
(1, self.padding, option),
7279
(2, short_channel_id, option),
7380
(4, next_node_id, option),
7481
(8, self.next_blinding_override, option)
@@ -80,6 +87,7 @@ impl Writeable for ForwardTlvs {
8087
impl Writeable for ReceiveTlvs {
8188
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
8289
encode_tlv_stream!(writer, {
90+
(1, self.padding, option),
8391
(65537, self.context, option),
8492
});
8593
Ok(())
@@ -184,15 +192,15 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
184192
Some(scid) => NextMessageHop::ShortChannelId(scid),
185193
None => NextMessageHop::NodeId(*pubkey),
186194
})
187-
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override: None }))
188-
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs{ context: Some(context) })));
195+
.map(|next_hop| ControlTlvs::Forward(ForwardTlvs { padding: None, next_hop, next_blinding_override: None }))
196+
.chain(core::iter::once(ControlTlvs::Receive(ReceiveTlvs{ padding: None, context: Some(context) })));
189197

190198
let max_length = tlvs.clone()
191199
.map(|tlv| tlv.serialized_length())
192200
.max()
193201
.unwrap_or(0);
194202

195-
let length_tlvs = tlvs.map(|tlvs| WithPadding { max_length, tlvs });
203+
let length_tlvs = tlvs.map(|tlv| tlv.pad_tlvs(max_length));
196204

197205
utils::construct_blinded_hops(secp_ctx, pks, length_tlvs, session_priv)
198206
}
@@ -216,7 +224,7 @@ where
216224
let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
217225
match ChaChaPolyReadAdapter::read(&mut reader, rho) {
218226
Ok(ChaChaPolyReadAdapter {
219-
readable: ControlTlvs::Forward(ForwardTlvs { next_hop, next_blinding_override })
227+
readable: ControlTlvs::Forward(ForwardTlvs {padding: _, next_hop, next_blinding_override })
220228
}) => {
221229
let next_node_id = match next_hop {
222230
NextMessageHop::NodeId(pubkey) => pubkey,

lightning/src/blinded_path/payment.rs

Lines changed: 57 additions & 2 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;
@@ -35,6 +35,8 @@ use core::ops::Deref;
3535
#[allow(unused_imports)]
3636
use crate::prelude::*;
3737

38+
use super::utils::Padding;
39+
3840
/// An intermediate node, its outbound channel, and relay parameters.
3941
#[derive(Clone, Debug)]
4042
pub struct ForwardNode {
@@ -50,6 +52,8 @@ pub struct ForwardNode {
5052
/// Data to construct a [`BlindedHop`] for forwarding a payment.
5153
#[derive(Clone, Debug)]
5254
pub struct ForwardTlvs {
55+
/// The padding data used to make all packets of a Blinded Path of same size
56+
pub padding: Option<Padding>,
5357
/// The short channel id this payment should be forwarded out over.
5458
pub short_channel_id: u64,
5559
/// Payment parameters for relaying over [`Self::short_channel_id`].
@@ -67,6 +71,8 @@ pub struct ForwardTlvs {
6771
/// may not be valid if received by another lightning implementation.
6872
#[derive(Clone, Debug)]
6973
pub struct ReceiveTlvs {
74+
/// The padding data used to make all packets of a Blinded Path of same size
75+
pub padding: Option<Padding>,
7076
/// Used to authenticate the sender of a payment to the receiver and tie MPP HTLCs together.
7177
pub payment_secret: PaymentSecret,
7278
/// Constraints for the receiver of this payment.
@@ -78,6 +84,7 @@ pub struct ReceiveTlvs {
7884
/// Data to construct a [`BlindedHop`] for sending a payment over.
7985
///
8086
/// [`BlindedHop`]: crate::blinded_path::BlindedHop
87+
#[derive(Clone)]
8188
pub(crate) enum BlindedPaymentTlvs {
8289
/// This blinded payment data is for a forwarding node.
8390
Forward(ForwardTlvs),
@@ -92,6 +99,27 @@ enum BlindedPaymentTlvsRef<'a> {
9299
Receive(&'a ReceiveTlvs),
93100
}
94101

102+
impl<'a> BlindedPaymentTlvsRef<'a> {
103+
pub(crate) fn pad_tlvs(self, max_length: usize) -> BlindedPaymentTlvs {
104+
let length = max_length.checked_sub(self.serialized_length());
105+
debug_assert!(length.is_some(), "Size of this packet should not be larger than the size of the largest packet.");
106+
let padding = Some(Padding::new(length.unwrap()));
107+
108+
match self {
109+
BlindedPaymentTlvsRef::Forward(tlvs) => {
110+
let mut new_tlvs = tlvs.clone();
111+
new_tlvs.padding = padding;
112+
BlindedPaymentTlvs::Forward(new_tlvs)
113+
}
114+
BlindedPaymentTlvsRef::Receive(tlvs) => {
115+
let mut new_tlvs = tlvs.clone();
116+
new_tlvs.padding = padding;
117+
BlindedPaymentTlvs::Receive(new_tlvs)
118+
}
119+
}
120+
}
121+
}
122+
95123
/// Parameters for relaying over a given [`BlindedHop`].
96124
///
97125
/// [`BlindedHop`]: crate::blinded_path::BlindedHop
@@ -205,6 +233,7 @@ impl Writeable for ForwardTlvs {
205233
if self.features == BlindedHopFeatures::empty() { None }
206234
else { Some(&self.features) };
207235
encode_tlv_stream!(w, {
236+
(1, self.padding, option),
208237
(2, self.short_channel_id, required),
209238
(10, self.payment_relay, required),
210239
(12, self.payment_constraints, required),
@@ -217,6 +246,7 @@ impl Writeable for ForwardTlvs {
217246
impl Writeable for ReceiveTlvs {
218247
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
219248
encode_tlv_stream!(w, {
249+
(1, self.padding, option),
220250
(12, self.payment_constraints, required),
221251
(65536, self.payment_secret, required),
222252
(65537, self.payment_context, required)
@@ -225,6 +255,16 @@ impl Writeable for ReceiveTlvs {
225255
}
226256
}
227257

258+
impl Writeable for BlindedPaymentTlvs {
259+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
260+
match self {
261+
Self::Forward(tlvs) => tlvs.write(w)?,
262+
Self::Receive(tlvs) => tlvs.write(w)?,
263+
}
264+
Ok(())
265+
}
266+
}
267+
228268
impl<'a> Writeable for BlindedPaymentTlvsRef<'a> {
229269
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
230270
match self {
@@ -253,6 +293,7 @@ impl Readable for BlindedPaymentTlvs {
253293
return Err(DecodeError::InvalidValue)
254294
}
255295
Ok(BlindedPaymentTlvs::Forward(ForwardTlvs {
296+
padding: None,
256297
short_channel_id,
257298
payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?,
258299
payment_constraints: payment_constraints.0.unwrap(),
@@ -261,6 +302,7 @@ impl Readable for BlindedPaymentTlvs {
261302
} else {
262303
if payment_relay.is_some() || features.is_some() { return Err(DecodeError::InvalidValue) }
263304
Ok(BlindedPaymentTlvs::Receive(ReceiveTlvs {
305+
padding: None,
264306
payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
265307
payment_constraints: payment_constraints.0.unwrap(),
266308
payment_context: payment_context.0.unwrap(),
@@ -284,7 +326,7 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
284326
.max()
285327
.unwrap_or(0);
286328

287-
let length_tlvs = tlvs.map(|tlvs| WithPadding { max_length, tlvs });
329+
let length_tlvs = tlvs.map(|tlv| tlv.pad_tlvs(max_length));
288330

289331
utils::construct_blinded_hops(secp_ctx, pks, length_tlvs, session_priv)
290332
}
@@ -498,6 +540,7 @@ mod tests {
498540
let intermediate_nodes = vec![ForwardNode {
499541
node_id: dummy_pk,
500542
tlvs: ForwardTlvs {
543+
padding: None,
501544
short_channel_id: 0,
502545
payment_relay: PaymentRelay {
503546
cltv_expiry_delta: 144,
@@ -514,6 +557,7 @@ mod tests {
514557
}, ForwardNode {
515558
node_id: dummy_pk,
516559
tlvs: ForwardTlvs {
560+
padding: None,
517561
short_channel_id: 0,
518562
payment_relay: PaymentRelay {
519563
cltv_expiry_delta: 144,
@@ -529,6 +573,7 @@ mod tests {
529573
htlc_maximum_msat: u64::max_value(),
530574
}];
531575
let recv_tlvs = ReceiveTlvs {
576+
padding: None,
532577
payment_secret: PaymentSecret([0; 32]),
533578
payment_constraints: PaymentConstraints {
534579
max_cltv_expiry: 0,
@@ -548,6 +593,7 @@ mod tests {
548593
#[test]
549594
fn compute_payinfo_1_hop() {
550595
let recv_tlvs = ReceiveTlvs {
596+
padding: None,
551597
payment_secret: PaymentSecret([0; 32]),
552598
payment_constraints: PaymentConstraints {
553599
max_cltv_expiry: 0,
@@ -571,6 +617,7 @@ mod tests {
571617
let intermediate_nodes = vec![ForwardNode {
572618
node_id: dummy_pk,
573619
tlvs: ForwardTlvs {
620+
padding: None,
574621
short_channel_id: 0,
575622
payment_relay: PaymentRelay {
576623
cltv_expiry_delta: 0,
@@ -587,6 +634,7 @@ mod tests {
587634
}, ForwardNode {
588635
node_id: dummy_pk,
589636
tlvs: ForwardTlvs {
637+
padding: None,
590638
short_channel_id: 0,
591639
payment_relay: PaymentRelay {
592640
cltv_expiry_delta: 0,
@@ -602,6 +650,7 @@ mod tests {
602650
htlc_maximum_msat: u64::max_value()
603651
}];
604652
let recv_tlvs = ReceiveTlvs {
653+
padding: None,
605654
payment_secret: PaymentSecret([0; 32]),
606655
payment_constraints: PaymentConstraints {
607656
max_cltv_expiry: 0,
@@ -622,6 +671,7 @@ mod tests {
622671
let intermediate_nodes = vec![ForwardNode {
623672
node_id: dummy_pk,
624673
tlvs: ForwardTlvs {
674+
padding: None,
625675
short_channel_id: 0,
626676
payment_relay: PaymentRelay {
627677
cltv_expiry_delta: 0,
@@ -638,6 +688,7 @@ mod tests {
638688
}, ForwardNode {
639689
node_id: dummy_pk,
640690
tlvs: ForwardTlvs {
691+
padding: None,
641692
short_channel_id: 0,
642693
payment_relay: PaymentRelay {
643694
cltv_expiry_delta: 0,
@@ -653,6 +704,7 @@ mod tests {
653704
htlc_maximum_msat: u64::max_value()
654705
}];
655706
let recv_tlvs = ReceiveTlvs {
707+
padding: None,
656708
payment_secret: PaymentSecret([0; 32]),
657709
payment_constraints: PaymentConstraints {
658710
max_cltv_expiry: 0,
@@ -677,6 +729,7 @@ mod tests {
677729
let intermediate_nodes = vec![ForwardNode {
678730
node_id: dummy_pk,
679731
tlvs: ForwardTlvs {
732+
padding: None,
680733
short_channel_id: 0,
681734
payment_relay: PaymentRelay {
682735
cltv_expiry_delta: 0,
@@ -693,6 +746,7 @@ mod tests {
693746
}, ForwardNode {
694747
node_id: dummy_pk,
695748
tlvs: ForwardTlvs {
749+
padding: None,
696750
short_channel_id: 0,
697751
payment_relay: PaymentRelay {
698752
cltv_expiry_delta: 0,
@@ -708,6 +762,7 @@ mod tests {
708762
htlc_maximum_msat: 10_000
709763
}];
710764
let recv_tlvs = ReceiveTlvs {
765+
padding: None,
711766
payment_secret: PaymentSecret([0; 32]),
712767
payment_constraints: PaymentConstraints {
713768
max_cltv_expiry: 0,

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/ln/blinded_payment_tests.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ fn blinded_payment_path(
3939
intermediate_nodes.push(ForwardNode {
4040
node_id: *node_id,
4141
tlvs: ForwardTlvs {
42+
padding: None,
4243
short_channel_id: chan_upd.short_channel_id,
4344
payment_relay: PaymentRelay {
4445
cltv_expiry_delta: chan_upd.cltv_expiry_delta,
@@ -57,6 +58,7 @@ fn blinded_payment_path(
5758
});
5859
}
5960
let payee_tlvs = ReceiveTlvs {
61+
padding: None,
6062
payment_secret,
6163
payment_constraints: PaymentConstraints {
6264
max_cltv_expiry: u32::max_value(),
@@ -104,6 +106,7 @@ fn do_one_hop_blinded_path(success: bool) {
104106
let amt_msat = 5000;
105107
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None);
106108
let payee_tlvs = ReceiveTlvs {
109+
padding: None,
107110
payment_secret,
108111
payment_constraints: PaymentConstraints {
109112
max_cltv_expiry: u32::max_value(),
@@ -148,6 +151,7 @@ fn mpp_to_one_hop_blinded_path() {
148151
let amt_msat = 15_000_000;
149152
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None);
150153
let payee_tlvs = ReceiveTlvs {
154+
padding: None,
151155
payment_secret,
152156
payment_constraints: PaymentConstraints {
153157
max_cltv_expiry: u32::max_value(),
@@ -1293,6 +1297,7 @@ fn custom_tlvs_to_blinded_path() {
12931297
let amt_msat = 5000;
12941298
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None);
12951299
let payee_tlvs = ReceiveTlvs {
1300+
padding: None,
12961301
payment_secret,
12971302
payment_constraints: PaymentConstraints {
12981303
max_cltv_expiry: u32::max_value(),

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9345,6 +9345,7 @@ where
93459345
let max_cltv_expiry = self.best_block.read().unwrap().height + CLTV_FAR_FAR_AWAY
93469346
+ LATENCY_GRACE_PERIOD_BLOCKS;
93479347
let payee_tlvs = ReceiveTlvs {
9348+
padding: None,
93489349
payment_secret,
93499350
payment_constraints: PaymentConstraints {
93509351
max_cltv_expiry,

0 commit comments

Comments
 (0)