99
1010//! Creating blinded paths and related utilities live here.
1111
12+ pub mod payment;
13+ pub ( crate ) mod message;
1214pub ( crate ) mod utils;
1315
1416use bitcoin:: secp256k1:: { self , PublicKey , Secp256k1 , SecretKey } ;
1517
16- use crate :: sign:: { EntropySource , NodeSigner , Recipient } ;
17- use crate :: onion_message:: ControlTlvs ;
18+ use crate :: sign:: EntropySource ;
1819use 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 } ;
2221
23- use core:: mem;
24- use core:: ops:: Deref ;
25- use crate :: io:: { self , Cursor } ;
22+ use crate :: io;
2623use crate :: prelude:: * ;
2724
2825/// Onion messages and payments can be sent and received to blinded paths, which serve to hide the
@@ -44,13 +41,14 @@ pub struct BlindedPath {
4441 pub blinded_hops : Vec < BlindedHop > ,
4542}
4643
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.
4947#[ derive( Clone , Debug , Hash , PartialEq , Eq ) ]
5048pub 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`] .
5250 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`] .
5452 // The node sending to this blinded path will later encode this payload into the onion packet for
5553 // this hop.
5654 pub encrypted_payload : Vec < u8 > ,
@@ -73,81 +71,30 @@ impl BlindedPath {
7371 Ok ( BlindedPath {
7472 introduction_node_id,
7573 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 ( |_| ( ) ) ?,
7775 } )
7876 }
7977
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" ) ;
14489
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+ }
15198}
15299
153100impl Writeable for BlindedPath {
@@ -185,41 +132,3 @@ impl_writeable!(BlindedHop, {
185132 encrypted_payload
186133} ) ;
187134
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