@@ -322,6 +322,15 @@ pub struct TrampolineForwardTlvs {
322322 pub next_blinding_override : Option < PublicKey > ,
323323}
324324
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+
325334/// Data to construct a [`BlindedHop`] for receiving a payment. This payload is custom to LDK and
326335/// may not be valid if received by another lightning implementation.
327336#[ derive( Clone , Debug ) ]
@@ -340,6 +349,8 @@ pub struct ReceiveTlvs {
340349pub ( crate ) enum BlindedPaymentTlvs {
341350 /// This blinded payment data is for a forwarding node.
342351 Forward ( ForwardTlvs ) ,
352+ /// This blinded payment data is dummy and is to be peeled by receiving node.
353+ Dummy ( PaymentDummyTlv ) ,
343354 /// This blinded payment data is for the receiving node.
344355 Receive ( ReceiveTlvs ) ,
345356}
@@ -357,6 +368,7 @@ pub(crate) enum BlindedTrampolineTlvs {
357368// Used to include forward and receive TLVs in the same iterator for encoding.
358369enum BlindedPaymentTlvsRef < ' a > {
359370 Forward ( & ' a ForwardTlvs ) ,
371+ Dummy ( & ' a PaymentDummyTlv ) ,
360372 Receive ( & ' a ReceiveTlvs ) ,
361373}
362374
@@ -506,6 +518,15 @@ impl Writeable for TrampolineForwardTlvs {
506518 }
507519}
508520
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+
509530// Note: Authentication TLV field was removed in LDK v0.2 following the
510531// introduction of `ReceiveAuthKey`-based authentication for inbound
511532// `BlindedPaymentPaths`s. Because we do not support receiving to those
@@ -526,6 +547,7 @@ impl<'a> Writeable for BlindedPaymentTlvsRef<'a> {
526547 fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
527548 match self {
528549 Self :: Forward ( tlvs) => tlvs. write ( w) ?,
550+ Self :: Dummy ( tlv) => tlv. write ( w) ?,
529551 Self :: Receive ( tlvs) => tlvs. write ( w) ?,
530552 }
531553 Ok ( ( ) )
@@ -542,32 +564,50 @@ impl Readable for BlindedPaymentTlvs {
542564 ( 2 , scid, option) ,
543565 ( 8 , next_blinding_override, option) ,
544566 ( 10 , payment_relay, option) ,
545- ( 12 , payment_constraints, required ) ,
567+ ( 12 , payment_constraints, option ) ,
546568 ( 14 , features, ( option, encoding: ( BlindedHopFeatures , WithoutLength ) ) ) ,
547569 ( 65536 , payment_secret, option) ,
548570 ( 65537 , payment_context, option) ,
571+ ( 65539 , is_dummy, option)
549572 } ) ;
550573
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 {
556594 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 ,
560598 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 ) ,
571611 }
572612 }
573613}
0 commit comments