@@ -54,21 +54,37 @@ 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 , secp_ctx : & Secp256k1 < T > ,
6064 ) -> Self
6165 where
6266 ES :: Target : EntropySource ,
6367 {
64- Self :: new ( & [ ] , recipient_node_id, local_node_receive_key, context, entropy_source, secp_ctx)
68+ Self :: new (
69+ & [ ] ,
70+ recipient_node_id,
71+ local_node_receive_key,
72+ context,
73+ compact_padding,
74+ entropy_source,
75+ secp_ctx,
76+ )
6577 }
6678
6779 /// Create a path for an onion message, to be forwarded along `node_pks`.
80+ ///
81+ /// `compact_padding` selects between space-inefficient padding that better hides contents and
82+ /// a space-constrained padding that does very little to hide the contents, especially for the
83+ /// last hop. It should only be set when the blinded path needs to be as compact as possible.
6884 pub fn new < ES : Deref , T : secp256k1:: Signing + secp256k1:: Verification > (
6985 intermediate_nodes : & [ MessageForwardNode ] , recipient_node_id : PublicKey ,
70- local_node_receive_key : ReceiveAuthKey , context : MessageContext , entropy_source : ES ,
71- secp_ctx : & Secp256k1 < T > ,
86+ local_node_receive_key : ReceiveAuthKey , context : MessageContext , compact_padding : bool ,
87+ entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
7288 ) -> Self
7389 where
7490 ES :: Target : EntropySource ,
@@ -79,19 +95,24 @@ impl BlindedMessagePath {
7995 0 ,
8096 local_node_receive_key,
8197 context,
98+ compact_padding,
8299 entropy_source,
83100 secp_ctx,
84101 )
85102 }
86103
87104 /// Same as [`BlindedMessagePath::new`], but allows specifying a number of dummy hops.
88105 ///
89- /// Note:
90- /// At most [`MAX_DUMMY_HOPS_COUNT`] dummy hops can be added to the blinded path.
106+ ///
107+ /// `compact_padding` selects between space-inefficient padding that better hides contents and
108+ /// a space-constrained padding that does very little to hide the contents, especially for the
109+ /// last hop. It should only be set when the blinded path needs to be as compact as possible.
110+ ///
111+ /// Note: At most [`MAX_DUMMY_HOPS_COUNT`] dummy hops can be added to the blinded path.
91112 pub fn new_with_dummy_hops < ES : Deref , T : secp256k1:: Signing + secp256k1:: Verification > (
92113 intermediate_nodes : & [ MessageForwardNode ] , recipient_node_id : PublicKey ,
93114 dummy_hop_count : usize , local_node_receive_key : ReceiveAuthKey , context : MessageContext ,
94- entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
115+ compact_padding : bool , entropy_source : ES , secp_ctx : & Secp256k1 < T > ,
95116 ) -> Self
96117 where
97118 ES :: Target : EntropySource ,
@@ -114,6 +135,7 @@ impl BlindedMessagePath {
114135 context,
115136 & blinding_secret,
116137 local_node_receive_key,
138+ compact_padding,
117139 ) ,
118140 } )
119141 }
@@ -714,7 +736,7 @@ pub const MAX_DUMMY_HOPS_COUNT: usize = 10;
714736pub ( super ) fn blinded_hops < T : secp256k1:: Signing + secp256k1:: Verification > (
715737 secp_ctx : & Secp256k1 < T > , intermediate_nodes : & [ MessageForwardNode ] ,
716738 recipient_node_id : PublicKey , dummy_hop_count : usize , context : MessageContext ,
717- session_priv : & SecretKey , local_node_receive_key : ReceiveAuthKey ,
739+ session_priv : & SecretKey , local_node_receive_key : ReceiveAuthKey , compact_padding : bool ,
718740) -> Vec < BlindedHop > {
719741 let dummy_count = cmp:: min ( dummy_hop_count, MAX_DUMMY_HOPS_COUNT ) ;
720742 let pks = intermediate_nodes
@@ -724,9 +746,8 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
724746 core:: iter:: repeat ( ( recipient_node_id, Some ( local_node_receive_key) ) ) . take ( dummy_count) ,
725747 )
726748 . 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 ( ) ) ;
728749
729- let tlvs = pks
750+ let intermediate_tlvs = pks
730751 . clone ( )
731752 . skip ( 1 ) // The first node's TLVs contains the next node's pubkey
732753 . zip ( intermediate_nodes. iter ( ) . map ( |node| node. short_channel_id ) )
@@ -737,18 +758,44 @@ pub(super) fn blinded_hops<T: secp256k1::Signing + secp256k1::Verification>(
737758 . map ( |next_hop| {
738759 ControlTlvs :: Forward ( ForwardTlvs { next_hop, next_blinding_override : None } )
739760 } )
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)
761+ . chain ( ( 0 ..dummy_count) . map ( |_| ControlTlvs :: Dummy ) ) ;
762+
763+ let max_intermediate_len =
764+ intermediate_tlvs. clone ( ) . map ( |tlvs| tlvs. serialized_length ( ) ) . max ( ) . unwrap_or ( 0 ) ;
765+ let have_intermediate_one_byte_smaller =
766+ intermediate_tlvs. clone ( ) . any ( |tlvs| tlvs. serialized_length ( ) == max_intermediate_len - 1 ) ;
767+
768+ let round_off = if compact_padding {
769+ // We can only pad by a minimum of two bytes. Thus, if there are any intermediate hops that
770+ // need to be padded by exactly one byte, we have to instead pad everything by two.
771+ if have_intermediate_one_byte_smaller {
772+ max_intermediate_len + 2
773+ } else {
774+ max_intermediate_len
775+ }
746776 } 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- }
777+ MESSAGE_PADDING_ROUND_OFF
778+ } ;
779+
780+ let tlvs = intermediate_tlvs. map ( |tlvs| {
781+ let res = BlindedPathWithPadding {
782+ tlvs,
783+ round_off,
784+ } ;
785+ if compact_padding {
786+ debug_assert_eq ! ( res. serialized_length( ) , max_intermediate_len) ;
787+ } else {
788+ // We don't currently ever push extra stuff to intermediate hops, so simply assert that
789+ // the fully-padded hops are always `MESSAGE_PADDING_ROUND_OFF` long.
790+ debug_assert_eq ! ( res. serialized_length( ) , MESSAGE_PADDING_ROUND_OFF ) ;
791+ }
792+ res
793+ } )
794+ . chain ( core:: iter:: once ( BlindedPathWithPadding {
795+ tlvs : ControlTlvs :: Receive ( ReceiveTlvs { context : Some ( context) } ) ,
796+ round_off : if compact_padding { 0 } else { MESSAGE_PADDING_ROUND_OFF } ,
797+ } ) ) ;
798+
799+ let path = pks. zip ( tlvs) ;
800+ utils:: construct_blinded_hops ( secp_ctx, path, session_priv)
754801}
0 commit comments