@@ -73,12 +73,14 @@ use core::ops::Deref;
73
73
use std:: time:: Instant ;
74
74
75
75
mod inbound_payment {
76
+ use alloc:: string:: ToString ;
76
77
use bitcoin:: hashes:: { Hash , HashEngine } ;
77
78
use bitcoin:: hashes:: cmp:: fixed_time_eq;
78
79
use bitcoin:: hashes:: hmac:: { Hmac , HmacEngine } ;
79
80
use bitcoin:: hashes:: sha256:: Hash as Sha256 ;
80
81
use chain:: keysinterface:: { KeyMaterial , KeysInterface , Sign } ;
81
82
use ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
83
+ use ln:: channelmanager:: APIError ;
82
84
use ln:: msgs;
83
85
use ln:: msgs:: MAX_VALUE_MSAT ;
84
86
use util:: chacha20:: ChaCha20 ;
@@ -113,7 +115,7 @@ mod inbound_payment {
113
115
114
116
impl ExpandedKey {
115
117
pub ( super ) fn new ( key_material : & KeyMaterial ) -> ExpandedKey {
116
- hkdf_extract_expand ( & vec ! [ 0 ] , & key_material)
118
+ hkdf_extract_expand ( b"LDK Inbound Payment Key Expansion" , & key_material)
117
119
}
118
120
}
119
121
@@ -237,15 +239,7 @@ mod inbound_payment {
237
239
pub ( super ) fn verify < L : Deref > ( payment_hash : PaymentHash , payment_data : msgs:: FinalOnionHopData , highest_seen_timestamp : u64 , keys : & ExpandedKey , logger : & L ) -> Result < Option < PaymentPreimage > , ( ) >
238
240
where L :: Target : Logger
239
241
{
240
- let mut iv_bytes = [ 0 ; IV_LEN ] ;
241
- let ( iv_slice, encrypted_metadata_bytes) = payment_data. payment_secret . 0 . split_at ( IV_LEN ) ;
242
- iv_bytes. copy_from_slice ( iv_slice) ;
243
-
244
- let chacha_block = ChaCha20 :: get_single_block ( & keys. metadata_key , & iv_bytes) ;
245
- let mut metadata_bytes: [ u8 ; METADATA_LEN ] = [ 0 ; METADATA_LEN ] ;
246
- for i in 0 ..METADATA_LEN {
247
- metadata_bytes[ i] = chacha_block[ i] ^ encrypted_metadata_bytes[ i] ;
248
- }
242
+ let ( iv_bytes, metadata_bytes) = decrypt_metadata ( payment_data. payment_secret , keys) ;
249
243
250
244
let payment_type_res = Method :: from_bits ( ( metadata_bytes[ 0 ] & 0b1110_0000 ) >> METHOD_TYPE_OFFSET ) ;
251
245
let mut amt_msat_bytes = [ 0 ; AMT_MSAT_LEN ] ;
@@ -269,15 +263,13 @@ mod inbound_payment {
269
263
}
270
264
} ,
271
265
Ok ( Method :: LdkPaymentHash ) => {
272
- let mut hmac = HmacEngine :: < Sha256 > :: new ( & keys. ldk_pmt_hash_key ) ;
273
- hmac. input ( & iv_bytes) ;
274
- hmac. input ( & metadata_bytes) ;
275
- let decoded_payment_preimage = Hmac :: from_engine ( hmac) . into_inner ( ) ;
276
- if !fixed_time_eq ( & payment_hash. 0 , & Sha256 :: hash ( & decoded_payment_preimage) . into_inner ( ) ) {
277
- log_trace ! ( logger, "Failing HTLC with payment_hash {}: payment preimage {} did not match" , log_bytes!( payment_hash. 0 ) , log_bytes!( decoded_payment_preimage) ) ;
278
- return Err ( ( ) )
266
+ match derive_ldk_payment_preimage ( payment_hash, & iv_bytes, & metadata_bytes, keys) {
267
+ Ok ( preimage) => payment_preimage = Some ( preimage) ,
268
+ Err ( bad_preimage_bytes) => {
269
+ log_trace ! ( logger, "Failing HTLC with payment_hash {} due to mismatching preimage {}" , log_bytes!( payment_hash. 0 ) , log_bytes!( bad_preimage_bytes) ) ;
270
+ return Err ( ( ) )
271
+ }
279
272
}
280
- payment_preimage = Some ( PaymentPreimage ( decoded_payment_preimage) ) ;
281
273
} ,
282
274
Err ( unknown_bits) => {
283
275
log_trace ! ( logger, "Failing HTLC with payment hash {} due to unknown payment type {}" , log_bytes!( payment_hash. 0 ) , unknown_bits) ;
@@ -298,6 +290,50 @@ mod inbound_payment {
298
290
Ok ( payment_preimage)
299
291
}
300
292
293
+ pub ( super ) fn get_payment_preimage ( payment_hash : PaymentHash , payment_secret : PaymentSecret , keys : & ExpandedKey ) -> Result < PaymentPreimage , APIError > {
294
+ let ( iv_bytes, metadata_bytes) = decrypt_metadata ( payment_secret, keys) ;
295
+
296
+ match Method :: from_bits ( ( metadata_bytes[ 0 ] & 0b1110_0000 ) >> METHOD_TYPE_OFFSET ) {
297
+ Ok ( Method :: LdkPaymentHash ) => {
298
+ derive_ldk_payment_preimage ( payment_hash, & iv_bytes, & metadata_bytes, keys)
299
+ . map_err ( |bad_preimage_bytes| APIError :: APIMisuseError {
300
+ err : format ! ( "Payment hash {} did not match decoded preimage {}" , log_bytes!( payment_hash. 0 ) , log_bytes!( bad_preimage_bytes) )
301
+ } )
302
+ } ,
303
+ Ok ( Method :: UserPaymentHash ) => Err ( APIError :: APIMisuseError {
304
+ err : "Expected payment type to be LdkPaymentHash, instead got UserPaymentHash" . to_string ( )
305
+ } ) ,
306
+ Err ( other) => Err ( APIError :: APIMisuseError { err : format ! ( "Unknown payment type: {}" , other) } ) ,
307
+ }
308
+ }
309
+
310
+ fn decrypt_metadata ( payment_secret : PaymentSecret , keys : & ExpandedKey ) -> ( [ u8 ; IV_LEN ] , [ u8 ; METADATA_LEN ] ) {
311
+ let mut iv_bytes = [ 0 ; IV_LEN ] ;
312
+ let ( iv_slice, encrypted_metadata_bytes) = payment_secret. 0 . split_at ( IV_LEN ) ;
313
+ iv_bytes. copy_from_slice ( iv_slice) ;
314
+
315
+ let chacha_block = ChaCha20 :: get_single_block ( & keys. metadata_key , & iv_bytes) ;
316
+ let mut metadata_bytes: [ u8 ; METADATA_LEN ] = [ 0 ; METADATA_LEN ] ;
317
+ for i in 0 ..METADATA_LEN {
318
+ metadata_bytes[ i] = chacha_block[ i] ^ encrypted_metadata_bytes[ i] ;
319
+ }
320
+
321
+ ( iv_bytes, metadata_bytes)
322
+ }
323
+
324
+ // Errors if the payment preimage doesn't match `payment_hash`. Returns the bad preimage bytes in
325
+ // this case.
326
+ fn derive_ldk_payment_preimage ( payment_hash : PaymentHash , iv_bytes : & [ u8 ; IV_LEN ] , metadata_bytes : & [ u8 ; METADATA_LEN ] , keys : & ExpandedKey ) -> Result < PaymentPreimage , [ u8 ; 32 ] > {
327
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & keys. ldk_pmt_hash_key ) ;
328
+ hmac. input ( iv_bytes) ;
329
+ hmac. input ( metadata_bytes) ;
330
+ let decoded_payment_preimage = Hmac :: from_engine ( hmac) . into_inner ( ) ;
331
+ if !fixed_time_eq ( & payment_hash. 0 , & Sha256 :: hash ( & decoded_payment_preimage) . into_inner ( ) ) {
332
+ return Err ( decoded_payment_preimage) ;
333
+ }
334
+ return Ok ( PaymentPreimage ( decoded_payment_preimage) )
335
+ }
336
+
301
337
fn hkdf_extract_expand ( salt : & [ u8 ] , ikm : & KeyMaterial ) -> ExpandedKey {
302
338
let mut hmac = HmacEngine :: < Sha256 > :: new ( salt) ;
303
339
hmac. input ( & ikm. 0 ) ;
@@ -5026,8 +5062,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
5026
5062
/// payment secret fetched via this method or [`create_inbound_payment`], and which is at least
5027
5063
/// the `min_value_msat` provided here, if one is provided.
5028
5064
///
5029
- /// The [`PaymentHash`] (and corresponding [`PaymentPreimage`]) must be globally unique. This
5030
- /// method may return an Err if another payment with the same payment_hash is still pending.
5065
+ /// The [`PaymentHash`] (and corresponding [`PaymentPreimage`]) should be globally unique, though
5066
+ /// note that LDK will not stop you from registering duplicate payment hashes for inbound
5067
+ /// payments.
5031
5068
///
5032
5069
/// `min_value_msat` should be set if the invoice being generated contains a value. Any payment
5033
5070
/// received for the returned [`PaymentHash`] will be required to be at least `min_value_msat`
@@ -5079,6 +5116,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
5079
5116
self . set_payment_hash_secret_map ( payment_hash, None , min_value_msat, invoice_expiry_delta_secs)
5080
5117
}
5081
5118
5119
+ /// Gets an LDK-generated payment preimage from a payment hash and payment secret that were
5120
+ /// previously returned from [`create_inbound_payment`].
5121
+ ///
5122
+ /// [`create_inbound_payment`]: Self::create_inbound_payment
5123
+ pub fn get_payment_preimage ( & self , payment_hash : PaymentHash , payment_secret : PaymentSecret ) -> Result < PaymentPreimage , APIError > {
5124
+ inbound_payment:: get_payment_preimage ( payment_hash, payment_secret, & self . inbound_payment_key )
5125
+ }
5126
+
5082
5127
#[ cfg( any( test, feature = "fuzztarget" , feature = "_test_utils" ) ) ]
5083
5128
pub fn get_and_clear_pending_events ( & self ) -> Vec < events:: Event > {
5084
5129
let events = core:: cell:: RefCell :: new ( Vec :: new ( ) ) ;
0 commit comments