@@ -98,6 +98,7 @@ enum Method {
9898 UserPaymentHash = 1 ,
9999 LdkPaymentHashCustomFinalCltv = 2 ,
100100 UserPaymentHashCustomFinalCltv = 3 ,
101+ SpontaneousPayment = 4 ,
101102}
102103
103104impl Method {
@@ -107,6 +108,7 @@ impl Method {
107108 bits if bits == Method :: UserPaymentHash as u8 => Ok ( Method :: UserPaymentHash ) ,
108109 bits if bits == Method :: LdkPaymentHashCustomFinalCltv as u8 => Ok ( Method :: LdkPaymentHashCustomFinalCltv ) ,
109110 bits if bits == Method :: UserPaymentHashCustomFinalCltv as u8 => Ok ( Method :: UserPaymentHashCustomFinalCltv ) ,
111+ bits if bits == Method :: SpontaneousPayment as u8 => Ok ( Method :: SpontaneousPayment ) ,
110112 unknown => Err ( unknown) ,
111113 }
112114 }
@@ -186,6 +188,26 @@ pub fn create_from_hash(keys: &ExpandedKey, min_value_msat: Option<u64>, payment
186188 Ok ( construct_payment_secret ( & iv_bytes, & metadata_bytes, & keys. metadata_key ) )
187189}
188190
191+ #[ cfg( async_payments) ]
192+ pub ( super ) fn create_for_spontaneous_payment (
193+ keys : & ExpandedKey , min_value_msat : Option < u64 > , invoice_expiry_delta_secs : u32 ,
194+ current_time : u64 , min_final_cltv_expiry_delta : Option < u16 >
195+ ) -> Result < PaymentSecret , ( ) > {
196+ let metadata_bytes = construct_metadata_bytes (
197+ min_value_msat, Method :: SpontaneousPayment , invoice_expiry_delta_secs, current_time,
198+ min_final_cltv_expiry_delta
199+ ) ?;
200+
201+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & keys. offers_base_key ) ;
202+ hmac. input ( & metadata_bytes) ;
203+ let hmac_bytes = Hmac :: from_engine ( hmac) . to_byte_array ( ) ;
204+
205+ let mut iv_bytes = [ 0 as u8 ; IV_LEN ] ;
206+ iv_bytes. copy_from_slice ( & hmac_bytes[ ..IV_LEN ] ) ;
207+
208+ Ok ( construct_payment_secret ( & iv_bytes, & metadata_bytes, & keys. metadata_key ) )
209+ }
210+
189211fn construct_metadata_bytes ( min_value_msat : Option < u64 > , payment_type : Method ,
190212 invoice_expiry_delta_secs : u32 , highest_seen_timestamp : u64 , min_final_cltv_expiry_delta : Option < u16 > ) -> Result < [ u8 ; METADATA_LEN ] , ( ) > {
191213 if min_value_msat. is_some ( ) && min_value_msat. unwrap ( ) > MAX_VALUE_MSAT {
@@ -315,6 +337,14 @@ pub(super) fn verify<L: Deref>(payment_hash: PaymentHash, payment_data: &msgs::F
315337 }
316338 }
317339 } ,
340+ Ok ( Method :: SpontaneousPayment ) => {
341+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & keys. offers_base_key ) ;
342+ hmac. input ( & metadata_bytes[ ..] ) ;
343+ if !fixed_time_eq ( & iv_bytes, & Hmac :: from_engine ( hmac) . to_byte_array ( ) . split_at_mut ( IV_LEN ) . 0 ) {
344+ log_trace ! ( logger, "Failing async payment HTLC with sender-generated payment_hash {}: unexpected payment_secret" , & payment_hash) ;
345+ return Err ( ( ) )
346+ }
347+ } ,
318348 Err ( unknown_bits) => {
319349 log_trace ! ( logger, "Failing HTLC with payment hash {} due to unknown payment type {}" , & payment_hash, unknown_bits) ;
320350 return Err ( ( ) ) ;
@@ -360,6 +390,9 @@ pub(super) fn get_payment_preimage(payment_hash: PaymentHash, payment_secret: Pa
360390 Ok ( Method :: UserPaymentHash ) | Ok ( Method :: UserPaymentHashCustomFinalCltv ) => Err ( APIError :: APIMisuseError {
361391 err : "Expected payment type to be LdkPaymentHash, instead got UserPaymentHash" . to_string ( )
362392 } ) ,
393+ Ok ( Method :: SpontaneousPayment ) => Err ( APIError :: APIMisuseError {
394+ err : "Can't extract payment preimage for spontaneous payments" . to_string ( )
395+ } ) ,
363396 Err ( other) => Err ( APIError :: APIMisuseError { err : format ! ( "Unknown payment type: {}" , other) } ) ,
364397 }
365398}
0 commit comments