@@ -98,11 +98,13 @@ impl ExpandedKey {
98
98
}
99
99
}
100
100
101
+ /// We currently set aside 3 bits for the `Method` in the `PaymentSecret`.
101
102
enum Method {
102
103
LdkPaymentHash = 0 ,
103
104
UserPaymentHash = 1 ,
104
105
LdkPaymentHashCustomFinalCltv = 2 ,
105
106
UserPaymentHashCustomFinalCltv = 3 ,
107
+ SpontaneousPayment = 4 ,
106
108
}
107
109
108
110
impl Method {
@@ -112,6 +114,7 @@ impl Method {
112
114
bits if bits == Method :: UserPaymentHash as u8 => Ok ( Method :: UserPaymentHash ) ,
113
115
bits if bits == Method :: LdkPaymentHashCustomFinalCltv as u8 => Ok ( Method :: LdkPaymentHashCustomFinalCltv ) ,
114
116
bits if bits == Method :: UserPaymentHashCustomFinalCltv as u8 => Ok ( Method :: UserPaymentHashCustomFinalCltv ) ,
117
+ bits if bits == Method :: SpontaneousPayment as u8 => Ok ( Method :: SpontaneousPayment ) ,
115
118
unknown => Err ( unknown) ,
116
119
}
117
120
}
@@ -191,6 +194,26 @@ pub fn create_from_hash(keys: &ExpandedKey, min_value_msat: Option<u64>, payment
191
194
Ok ( construct_payment_secret ( & iv_bytes, & metadata_bytes, & keys. metadata_key ) )
192
195
}
193
196
197
+ #[ cfg( async_payments) ]
198
+ pub ( super ) fn create_for_spontaneous_payment (
199
+ keys : & ExpandedKey , min_value_msat : Option < u64 > , invoice_expiry_delta_secs : u32 ,
200
+ current_time : u64 , min_final_cltv_expiry_delta : Option < u16 >
201
+ ) -> Result < PaymentSecret , ( ) > {
202
+ let metadata_bytes = construct_metadata_bytes (
203
+ min_value_msat, Method :: SpontaneousPayment , invoice_expiry_delta_secs, current_time,
204
+ min_final_cltv_expiry_delta
205
+ ) ?;
206
+
207
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & keys. spontaneous_pmt_key ) ;
208
+ hmac. input ( & metadata_bytes) ;
209
+ let hmac_bytes = Hmac :: from_engine ( hmac) . to_byte_array ( ) ;
210
+
211
+ let mut iv_bytes = [ 0 as u8 ; IV_LEN ] ;
212
+ iv_bytes. copy_from_slice ( & hmac_bytes[ ..IV_LEN ] ) ;
213
+
214
+ Ok ( construct_payment_secret ( & iv_bytes, & metadata_bytes, & keys. metadata_key ) )
215
+ }
216
+
194
217
fn construct_metadata_bytes ( min_value_msat : Option < u64 > , payment_type : Method ,
195
218
invoice_expiry_delta_secs : u32 , highest_seen_timestamp : u64 , min_final_cltv_expiry_delta : Option < u16 > ) -> Result < [ u8 ; METADATA_LEN ] , ( ) > {
196
219
if min_value_msat. is_some ( ) && min_value_msat. unwrap ( ) > MAX_VALUE_MSAT {
@@ -320,6 +343,14 @@ pub(super) fn verify<L: Deref>(payment_hash: PaymentHash, payment_data: &msgs::F
320
343
}
321
344
}
322
345
} ,
346
+ Ok ( Method :: SpontaneousPayment ) => {
347
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & keys. spontaneous_pmt_key ) ;
348
+ hmac. input ( & metadata_bytes[ ..] ) ;
349
+ if !fixed_time_eq ( & iv_bytes, & Hmac :: from_engine ( hmac) . to_byte_array ( ) . split_at_mut ( IV_LEN ) . 0 ) {
350
+ log_trace ! ( logger, "Failing async payment HTLC with sender-generated payment_hash {}: unexpected payment_secret" , & payment_hash) ;
351
+ return Err ( ( ) )
352
+ }
353
+ } ,
323
354
Err ( unknown_bits) => {
324
355
log_trace ! ( logger, "Failing HTLC with payment hash {} due to unknown payment type {}" , & payment_hash, unknown_bits) ;
325
356
return Err ( ( ) ) ;
@@ -365,6 +396,9 @@ pub(super) fn get_payment_preimage(payment_hash: PaymentHash, payment_secret: Pa
365
396
Ok ( Method :: UserPaymentHash ) | Ok ( Method :: UserPaymentHashCustomFinalCltv ) => Err ( APIError :: APIMisuseError {
366
397
err : "Expected payment type to be LdkPaymentHash, instead got UserPaymentHash" . to_string ( )
367
398
} ) ,
399
+ Ok ( Method :: SpontaneousPayment ) => Err ( APIError :: APIMisuseError {
400
+ err : "Can't extract payment preimage for spontaneous payments" . to_string ( )
401
+ } ) ,
368
402
Err ( other) => Err ( APIError :: APIMisuseError { err : format ! ( "Unknown payment type: {}" , other) } ) ,
369
403
}
370
404
}
0 commit comments