@@ -322,6 +322,15 @@ pub struct TrampolineForwardTlvs {
322
322
pub next_blinding_override : Option < PublicKey > ,
323
323
}
324
324
325
+ /// Represents the dummy TLV encoded immediately before the actual [`ReceiveTlvs`] in a blinded path.
326
+ /// These TLVs are intended for the final node and are recursively authenticated until the real
327
+ /// [`ReceiveTlvs`] is reached.
328
+ ///
329
+ /// Their purpose is to arbitrarily extend the path length, obscuring the receiver's position in the
330
+ /// route and thereby enhancing privacy.
331
+ #[ derive( Debug ) ]
332
+ pub ( crate ) struct PaymentDummyTlv ;
333
+
325
334
/// Data to construct a [`BlindedHop`] for receiving a payment. This payload is custom to LDK and
326
335
/// may not be valid if received by another lightning implementation.
327
336
#[ derive( Clone , Debug ) ]
@@ -340,6 +349,8 @@ pub struct ReceiveTlvs {
340
349
pub ( crate ) enum BlindedPaymentTlvs {
341
350
/// This blinded payment data is for a forwarding node.
342
351
Forward ( ForwardTlvs ) ,
352
+ /// This blinded payment data is dummy and is to be peeled by receiving node.
353
+ Dummy ( PaymentDummyTlv ) ,
343
354
/// This blinded payment data is for the receiving node.
344
355
Receive ( ReceiveTlvs ) ,
345
356
}
@@ -357,6 +368,7 @@ pub(crate) enum BlindedTrampolineTlvs {
357
368
// Used to include forward and receive TLVs in the same iterator for encoding.
358
369
enum BlindedPaymentTlvsRef < ' a > {
359
370
Forward ( & ' a ForwardTlvs ) ,
371
+ Dummy ( & ' a PaymentDummyTlv ) ,
360
372
Receive ( & ' a ReceiveTlvs ) ,
361
373
}
362
374
@@ -506,6 +518,15 @@ impl Writeable for TrampolineForwardTlvs {
506
518
}
507
519
}
508
520
521
+ impl Writeable for PaymentDummyTlv {
522
+ fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
523
+ encode_tlv_stream ! ( writer, {
524
+ ( 65539 , ( ) , required) ,
525
+ } ) ;
526
+ Ok ( ( ) )
527
+ }
528
+ }
529
+
509
530
// Note: Authentication TLV field was removed in LDK v0.2 following the
510
531
// introduction of `ReceiveAuthKey`-based authentication for inbound
511
532
// `BlindedPaymentPaths`s. Because we do not support receiving to those
@@ -526,6 +547,7 @@ impl<'a> Writeable for BlindedPaymentTlvsRef<'a> {
526
547
fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
527
548
match self {
528
549
Self :: Forward ( tlvs) => tlvs. write ( w) ?,
550
+ Self :: Dummy ( tlv) => tlv. write ( w) ?,
529
551
Self :: Receive ( tlvs) => tlvs. write ( w) ?,
530
552
}
531
553
Ok ( ( ) )
@@ -542,32 +564,50 @@ impl Readable for BlindedPaymentTlvs {
542
564
( 2 , scid, option) ,
543
565
( 8 , next_blinding_override, option) ,
544
566
( 10 , payment_relay, option) ,
545
- ( 12 , payment_constraints, required ) ,
567
+ ( 12 , payment_constraints, option ) ,
546
568
( 14 , features, ( option, encoding: ( BlindedHopFeatures , WithoutLength ) ) ) ,
547
569
( 65536 , payment_secret, option) ,
548
570
( 65537 , payment_context, option) ,
571
+ ( 65539 , is_dummy, option)
549
572
} ) ;
550
573
551
- if let Some ( short_channel_id) = scid {
552
- if payment_secret. is_some ( ) {
553
- return Err ( DecodeError :: InvalidValue ) ;
554
- }
555
- Ok ( BlindedPaymentTlvs :: Forward ( ForwardTlvs {
574
+ match (
575
+ scid,
576
+ next_blinding_override,
577
+ payment_relay,
578
+ payment_constraints,
579
+ features,
580
+ payment_secret,
581
+ payment_context,
582
+ is_dummy,
583
+ ) {
584
+ (
585
+ Some ( short_channel_id) ,
586
+ next_override,
587
+ Some ( relay) ,
588
+ Some ( constraints) ,
589
+ features,
590
+ None ,
591
+ None ,
592
+ None ,
593
+ ) => Ok ( BlindedPaymentTlvs :: Forward ( ForwardTlvs {
556
594
short_channel_id,
557
- payment_relay : payment_relay . ok_or ( DecodeError :: InvalidValue ) ? ,
558
- payment_constraints : payment_constraints . 0 . unwrap ( ) ,
559
- next_blinding_override,
595
+ payment_relay : relay ,
596
+ payment_constraints : constraints ,
597
+ next_blinding_override : next_override ,
560
598
features : features. unwrap_or_else ( BlindedHopFeatures :: empty) ,
561
- } ) )
562
- } else {
563
- if payment_relay. is_some ( ) || features. is_some ( ) {
564
- return Err ( DecodeError :: InvalidValue ) ;
565
- }
566
- Ok ( BlindedPaymentTlvs :: Receive ( ReceiveTlvs {
567
- payment_secret : payment_secret. ok_or ( DecodeError :: InvalidValue ) ?,
568
- payment_constraints : payment_constraints. 0 . unwrap ( ) ,
569
- payment_context : payment_context. ok_or ( DecodeError :: InvalidValue ) ?,
570
- } ) )
599
+ } ) ) ,
600
+ ( None , None , None , Some ( constraints) , None , Some ( secret) , Some ( context) , None ) => {
601
+ Ok ( BlindedPaymentTlvs :: Receive ( ReceiveTlvs {
602
+ payment_secret : secret,
603
+ payment_constraints : constraints,
604
+ payment_context : context,
605
+ } ) )
606
+ } ,
607
+ ( None , None , None , None , None , None , None , Some ( ( ) ) ) => {
608
+ Ok ( BlindedPaymentTlvs :: Dummy ( PaymentDummyTlv ) )
609
+ } ,
610
+ _ => return Err ( DecodeError :: InvalidValue ) ,
571
611
}
572
612
}
573
613
}
0 commit comments