9
9
10
10
//! Creating blinded paths and related utilities live here.
11
11
12
+ pub mod payment;
13
+ pub ( crate ) mod message;
12
14
pub ( crate ) mod utils;
13
15
14
16
use bitcoin:: secp256k1:: { self , PublicKey , Secp256k1 , SecretKey } ;
15
17
16
- use crate :: sign:: { EntropySource , NodeSigner , Recipient } ;
17
- use crate :: onion_message:: ControlTlvs ;
18
+ use crate :: sign:: EntropySource ;
18
19
use crate :: ln:: msgs:: DecodeError ;
19
- use crate :: ln:: onion_utils;
20
- use crate :: util:: chacha20poly1305rfc:: { ChaChaPolyReadAdapter , ChaChaPolyWriteAdapter } ;
21
- use crate :: util:: ser:: { FixedLengthReader , LengthReadableArgs , Readable , VecWriter , Writeable , Writer } ;
20
+ use crate :: util:: ser:: { Readable , Writeable , Writer } ;
22
21
23
- use core:: mem;
24
- use core:: ops:: Deref ;
25
- use crate :: io:: { self , Cursor } ;
22
+ use crate :: io;
26
23
use crate :: prelude:: * ;
27
24
28
25
/// Onion messages and payments can be sent and received to blinded paths, which serve to hide the
@@ -44,13 +41,14 @@ pub struct BlindedPath {
44
41
pub blinded_hops : Vec < BlindedHop > ,
45
42
}
46
43
47
- /// Used to construct the blinded hops portion of a blinded path. These hops cannot be identified
48
- /// by outside observers and thus can be used to hide the identity of the recipient.
44
+ /// An encrypted payload and node id corresponding to a hop in a payment or onion message path, to
45
+ /// be encoded in the sender's onion packet. These hops cannot be identified by outside observers
46
+ /// and thus can be used to hide the identity of the recipient.
49
47
#[ derive( Clone , Debug , Hash , PartialEq , Eq ) ]
50
48
pub struct BlindedHop {
51
- /// The blinded node id of this hop in a blinded path .
49
+ /// The blinded node id of this hop in a [`BlindedPath`] .
52
50
pub blinded_node_id : PublicKey ,
53
- /// The encrypted payload intended for this hop in a blinded path .
51
+ /// The encrypted payload intended for this hop in a [`BlindedPath`] .
54
52
// The node sending to this blinded path will later encode this payload into the onion packet for
55
53
// this hop.
56
54
pub encrypted_payload : Vec < u8 > ,
@@ -73,81 +71,30 @@ impl BlindedPath {
73
71
Ok ( BlindedPath {
74
72
introduction_node_id,
75
73
blinding_point : PublicKey :: from_secret_key ( secp_ctx, & blinding_secret) ,
76
- blinded_hops : blinded_message_hops ( secp_ctx, node_pks, & blinding_secret) . map_err ( |_| ( ) ) ?,
74
+ blinded_hops : message :: blinded_hops ( secp_ctx, node_pks, & blinding_secret) . map_err ( |_| ( ) ) ?,
77
75
} )
78
76
}
79
77
80
- // Advance the blinded onion message path by one hop, so make the second hop into the new
81
- // introduction node.
82
- pub ( super ) fn advance_message_path_by_one < NS : Deref , T : secp256k1:: Signing + secp256k1:: Verification >
83
- ( & mut self , node_signer : & NS , secp_ctx : & Secp256k1 < T > ) -> Result < ( ) , ( ) >
84
- where NS :: Target : NodeSigner
85
- {
86
- let control_tlvs_ss = node_signer. ecdh ( Recipient :: Node , & self . blinding_point , None ) ?;
87
- let rho = onion_utils:: gen_rho_from_shared_secret ( & control_tlvs_ss. secret_bytes ( ) ) ;
88
- let encrypted_control_tlvs = self . blinded_hops . remove ( 0 ) . encrypted_payload ;
89
- let mut s = Cursor :: new ( & encrypted_control_tlvs) ;
90
- let mut reader = FixedLengthReader :: new ( & mut s, encrypted_control_tlvs. len ( ) as u64 ) ;
91
- match ChaChaPolyReadAdapter :: read ( & mut reader, rho) {
92
- Ok ( ChaChaPolyReadAdapter { readable : ControlTlvs :: Forward ( ForwardTlvs {
93
- mut next_node_id, next_blinding_override,
94
- } ) } ) => {
95
- let mut new_blinding_point = match next_blinding_override {
96
- Some ( blinding_point) => blinding_point,
97
- None => {
98
- onion_utils:: next_hop_pubkey ( secp_ctx, self . blinding_point ,
99
- control_tlvs_ss. as_ref ( ) ) . map_err ( |_| ( ) ) ?
100
- }
101
- } ;
102
- mem:: swap ( & mut self . blinding_point , & mut new_blinding_point) ;
103
- mem:: swap ( & mut self . introduction_node_id , & mut next_node_id) ;
104
- Ok ( ( ) )
105
- } ,
106
- _ => Err ( ( ) )
107
- }
108
- }
109
- }
110
-
111
- /// Construct blinded onion message hops for the given `unblinded_path`.
112
- fn blinded_message_hops < T : secp256k1:: Signing + secp256k1:: Verification > (
113
- secp_ctx : & Secp256k1 < T > , unblinded_path : & [ PublicKey ] , session_priv : & SecretKey
114
- ) -> Result < Vec < BlindedHop > , secp256k1:: Error > {
115
- let mut blinded_hops = Vec :: with_capacity ( unblinded_path. len ( ) ) ;
116
-
117
- let mut prev_ss_and_blinded_node_id = None ;
118
- utils:: construct_keys_callback ( secp_ctx, unblinded_path, None , session_priv, |blinded_node_id, _, _, encrypted_payload_ss, unblinded_pk, _| {
119
- if let Some ( ( prev_ss, prev_blinded_node_id) ) = prev_ss_and_blinded_node_id {
120
- if let Some ( pk) = unblinded_pk {
121
- let payload = ForwardTlvs {
122
- next_node_id : pk,
123
- next_blinding_override : None ,
124
- } ;
125
- blinded_hops. push ( BlindedHop {
126
- blinded_node_id : prev_blinded_node_id,
127
- encrypted_payload : encrypt_payload ( payload, prev_ss) ,
128
- } ) ;
129
- } else { debug_assert ! ( false ) ; }
130
- }
131
- prev_ss_and_blinded_node_id = Some ( ( encrypted_payload_ss, blinded_node_id) ) ;
132
- } ) ?;
133
-
134
- if let Some ( ( final_ss, final_blinded_node_id) ) = prev_ss_and_blinded_node_id {
135
- let final_payload = ReceiveTlvs { path_id : None } ;
136
- blinded_hops. push ( BlindedHop {
137
- blinded_node_id : final_blinded_node_id,
138
- encrypted_payload : encrypt_payload ( final_payload, final_ss) ,
139
- } ) ;
140
- } else { debug_assert ! ( false ) }
141
-
142
- Ok ( blinded_hops)
143
- }
78
+ /// Create a blinded path for a payment, to be forwarded along `path`. The last node
79
+ /// in `path` will be the destination node.
80
+ ///
81
+ /// Errors if `path` is empty or a node id in `path` is invalid.
82
+ // TODO: make all payloads the same size with padding + add dummy hops
83
+ pub fn new_for_payment < ES : EntropySource , T : secp256k1:: Signing + secp256k1:: Verification > (
84
+ intermediate_nodes : & [ ( PublicKey , payment:: ForwardTlvs ) ] , payee_node_id : PublicKey ,
85
+ payee_tlvs : payment:: ReceiveTlvs , entropy_source : & ES , secp_ctx : & Secp256k1 < T >
86
+ ) -> Result < Self , ( ) > {
87
+ let blinding_secret_bytes = entropy_source. get_secure_random_bytes ( ) ;
88
+ let blinding_secret = SecretKey :: from_slice ( & blinding_secret_bytes[ ..] ) . expect ( "RNG is busted" ) ;
144
89
145
- /// Encrypt TLV payload to be used as a [`BlindedHop::encrypted_payload`].
146
- fn encrypt_payload < P : Writeable > ( payload : P , encrypted_tlvs_ss : [ u8 ; 32 ] ) -> Vec < u8 > {
147
- let mut writer = VecWriter ( Vec :: new ( ) ) ;
148
- let write_adapter = ChaChaPolyWriteAdapter :: new ( encrypted_tlvs_ss, & payload) ;
149
- write_adapter. write ( & mut writer) . expect ( "In-memory writes cannot fail" ) ;
150
- writer. 0
90
+ Ok ( BlindedPath {
91
+ introduction_node_id : intermediate_nodes. first ( ) . map_or ( payee_node_id, |n| n. 0 ) ,
92
+ blinding_point : PublicKey :: from_secret_key ( secp_ctx, & blinding_secret) ,
93
+ blinded_hops : payment:: blinded_hops (
94
+ secp_ctx, intermediate_nodes, payee_node_id, payee_tlvs, & blinding_secret
95
+ ) . map_err ( |_| ( ) ) ?,
96
+ } )
97
+ }
151
98
}
152
99
153
100
impl Writeable for BlindedPath {
@@ -185,41 +132,3 @@ impl_writeable!(BlindedHop, {
185
132
encrypted_payload
186
133
} ) ;
187
134
188
- /// TLVs to encode in an intermediate onion message packet's hop data. When provided in a blinded
189
- /// route, they are encoded into [`BlindedHop::encrypted_payload`].
190
- pub ( crate ) struct ForwardTlvs {
191
- /// The node id of the next hop in the onion message's path.
192
- pub ( super ) next_node_id : PublicKey ,
193
- /// Senders to a blinded path use this value to concatenate the route they find to the
194
- /// introduction node with the blinded path.
195
- pub ( super ) next_blinding_override : Option < PublicKey > ,
196
- }
197
-
198
- /// Similar to [`ForwardTlvs`], but these TLVs are for the final node.
199
- pub ( crate ) struct ReceiveTlvs {
200
- /// If `path_id` is `Some`, it is used to identify the blinded path that this onion message is
201
- /// sending to. This is useful for receivers to check that said blinded path is being used in
202
- /// the right context.
203
- pub ( super ) path_id : Option < [ u8 ; 32 ] > ,
204
- }
205
-
206
- impl Writeable for ForwardTlvs {
207
- fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
208
- // TODO: write padding
209
- encode_tlv_stream ! ( writer, {
210
- ( 4 , self . next_node_id, required) ,
211
- ( 8 , self . next_blinding_override, option)
212
- } ) ;
213
- Ok ( ( ) )
214
- }
215
- }
216
-
217
- impl Writeable for ReceiveTlvs {
218
- fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io:: Error > {
219
- // TODO: write padding
220
- encode_tlv_stream ! ( writer, {
221
- ( 6 , self . path_id, option) ,
222
- } ) ;
223
- Ok ( ( ) )
224
- }
225
- }
0 commit comments