@@ -54,21 +54,38 @@ impl Readable for BlindedMessagePath {
5454
5555impl BlindedMessagePath {
5656 /// Create a one-hop blinded path for a message.
57+ ///
58+ /// `compact_padding` selects between space-inefficient padding that better hides contents and
59+ /// a space-constrained padding that does very little to hide the contents, especially for the
60+ /// last hop. It should only be set when the blinded path needs to be as compact as possible.
5761 pub fn one_hop < ES : Deref , T : secp256k1:: Signing + secp256k1:: Verification > (
5862 recipient_node_id : PublicKey , local_node_receive_key : ReceiveAuthKey ,
59- context : MessageContext , entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
63+ context : MessageContext , compact_padding : bool , entropy_source : ES ,
64+ secp_ctx : & Secp256k1 < T > ,
6065 ) -> Self
6166 where
6267 ES :: Target : EntropySource ,
6368 {
64- Self :: new ( & [ ] , recipient_node_id, local_node_receive_key, context, entropy_source, secp_ctx)
69+ Self :: new (
70+ & [ ] ,
71+ recipient_node_id,
72+ local_node_receive_key,
73+ context,
74+ compact_padding,
75+ entropy_source,
76+ secp_ctx,
77+ )
6578 }
6679
6780 /// Create a path for an onion message, to be forwarded along `node_pks`.
81+ ///
82+ /// `compact_padding` selects between space-inefficient padding that better hides contents and
83+ /// a space-constrained padding that does very little to hide the contents, especially for the
84+ /// last hop. It should only be set when the blinded path needs to be as compact as possible.
6885 pub fn new < ES : Deref , T : secp256k1:: Signing + secp256k1:: Verification > (
6986 intermediate_nodes : & [ MessageForwardNode ] , recipient_node_id : PublicKey ,
70- local_node_receive_key : ReceiveAuthKey , context : MessageContext , entropy_source : ES ,
71- secp_ctx : & Secp256k1 < T > ,
87+ local_node_receive_key : ReceiveAuthKey , context : MessageContext , compact_padding : bool ,
88+ entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
7289 ) -> Self
7390 where
7491 ES :: Target : EntropySource ,
@@ -79,19 +96,24 @@ impl BlindedMessagePath {
7996 0 ,
8097 local_node_receive_key,
8198 context,
99+ compact_padding,
82100 entropy_source,
83101 secp_ctx,
84102 )
85103 }
86104
87105 /// Same as [`BlindedMessagePath::new`], but allows specifying a number of dummy hops.
88106 ///
89- /// Note:
90- /// At most [`MAX_DUMMY_HOPS_COUNT`] dummy hops can be added to the blinded path.
107+ ///
108+ /// `compact_padding` selects between space-inefficient padding that better hides contents and
109+ /// a space-constrained padding that does very little to hide the contents, especially for the
110+ /// last hop. It should only be set when the blinded path needs to be as compact as possible.
111+ ///
112+ /// Note: At most [`MAX_DUMMY_HOPS_COUNT`] dummy hops can be added to the blinded path.
91113 pub fn new_with_dummy_hops < ES : Deref , T : secp256k1:: Signing + secp256k1:: Verification > (
92114 intermediate_nodes : & [ MessageForwardNode ] , recipient_node_id : PublicKey ,
93115 dummy_hop_count : usize , local_node_receive_key : ReceiveAuthKey , context : MessageContext ,
94- entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
116+ compact_padding : bool , entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
95117 ) -> Self
96118 where
97119 ES :: Target : EntropySource ,
@@ -114,6 +136,7 @@ impl BlindedMessagePath {
114136 context,
115137 & blinding_secret,
116138 local_node_receive_key,
139+ compact_padding,
117140 ) ,
118141 } )
119142 }
@@ -714,7 +737,7 @@ pub const MAX_DUMMY_HOPS_COUNT: usize = 10;
714737pub ( super ) fn blinded_hops < T : secp256k1:: Signing + secp256k1:: Verification > (
715738 secp_ctx : & Secp256k1 < T > , intermediate_nodes : & [ MessageForwardNode ] ,
716739 recipient_node_id : PublicKey , dummy_hop_count : usize , context : MessageContext ,
717- session_priv : & SecretKey , local_node_receive_key : ReceiveAuthKey ,
740+ session_priv : & SecretKey , local_node_receive_key : ReceiveAuthKey , compact_padding : bool ,
718741) -> Vec < BlindedHop > {
719742 let dummy_count = cmp:: min ( dummy_hop_count, MAX_DUMMY_HOPS_COUNT ) ;
720743 let pks = intermediate_nodes
@@ -724,9 +747,8 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
724747 core:: iter:: repeat ( ( recipient_node_id, Some ( local_node_receive_key) ) ) . take ( dummy_count) ,
725748 )
726749 . chain ( core:: iter:: once ( ( recipient_node_id, Some ( local_node_receive_key) ) ) ) ;
727- let is_compact = intermediate_nodes. iter ( ) . any ( |node| node. short_channel_id . is_some ( ) ) ;
728750
729- let tlvs = pks
751+ let intermediate_tlvs = pks
730752 . clone ( )
731753 . skip ( 1 ) // The first node's TLVs contains the next node's pubkey
732754 . zip ( intermediate_nodes. iter ( ) . map ( |node| node. short_channel_id ) )
@@ -737,18 +759,42 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
737759 . map ( |next_hop| {
738760 ControlTlvs :: Forward ( ForwardTlvs { next_hop, next_blinding_override : None } )
739761 } )
740- . chain ( ( 0 ..dummy_count) . map ( |_| ControlTlvs :: Dummy ) )
741- . chain ( core:: iter:: once ( ControlTlvs :: Receive ( ReceiveTlvs { context : Some ( context) } ) ) ) ;
742-
743- if is_compact {
744- let path = pks. zip ( tlvs) ;
745- utils:: construct_blinded_hops ( secp_ctx, path, session_priv)
762+ . chain ( ( 0 ..dummy_count) . map ( |_| ControlTlvs :: Dummy ) ) ;
763+
764+ let max_intermediate_len =
765+ intermediate_tlvs. clone ( ) . map ( |tlvs| tlvs. serialized_length ( ) ) . max ( ) . unwrap_or ( 0 ) ;
766+ let have_intermediate_one_byte_smaller =
767+ intermediate_tlvs. clone ( ) . any ( |tlvs| tlvs. serialized_length ( ) == max_intermediate_len - 1 ) ;
768+
769+ let round_off = if compact_padding {
770+ // We can only pad by a minimum of two bytes. Thus, if there are any intermediate hops that
771+ // need to be padded by exactly one byte, we have to instead pad everything by two.
772+ if have_intermediate_one_byte_smaller {
773+ max_intermediate_len + 2
774+ } else {
775+ max_intermediate_len
776+ }
746777 } else {
747- let path =
748- pks. zip ( tlvs. map ( |tlv| BlindedPathWithPadding {
749- tlvs : tlv,
750- round_off : MESSAGE_PADDING_ROUND_OFF ,
751- } ) ) ;
752- utils:: construct_blinded_hops ( secp_ctx, path, session_priv)
753- }
778+ MESSAGE_PADDING_ROUND_OFF
779+ } ;
780+
781+ let tlvs = intermediate_tlvs
782+ . map ( |tlvs| {
783+ let res = BlindedPathWithPadding { tlvs, round_off } ;
784+ if compact_padding {
785+ debug_assert_eq ! ( res. serialized_length( ) , max_intermediate_len) ;
786+ } else {
787+ // We don't currently ever push extra stuff to intermediate hops, so simply assert that
788+ // the fully-padded hops are always `MESSAGE_PADDING_ROUND_OFF` long.
789+ debug_assert_eq ! ( res. serialized_length( ) , MESSAGE_PADDING_ROUND_OFF ) ;
790+ }
791+ res
792+ } )
793+ . chain ( core:: iter:: once ( BlindedPathWithPadding {
794+ tlvs : ControlTlvs :: Receive ( ReceiveTlvs { context : Some ( context) } ) ,
795+ round_off : if compact_padding { 0 } else { MESSAGE_PADDING_ROUND_OFF } ,
796+ } ) ) ;
797+
798+ let path = pks. zip ( tlvs) ;
799+ utils:: construct_blinded_hops ( secp_ctx, path, session_priv)
754800}
0 commit comments