@@ -103,6 +103,7 @@ enum Method {
103103 UserPaymentHash = 1 ,
104104 LdkPaymentHashCustomFinalCltv = 2 ,
105105 UserPaymentHashCustomFinalCltv = 3 ,
106+ SpontaneousPayment = 4 ,
106107}
107108
108109impl Method {
@@ -112,6 +113,7 @@ impl Method {
112113 bits if bits == Method :: UserPaymentHash as u8 => Ok ( Method :: UserPaymentHash ) ,
113114 bits if bits == Method :: LdkPaymentHashCustomFinalCltv as u8 => Ok ( Method :: LdkPaymentHashCustomFinalCltv ) ,
114115 bits if bits == Method :: UserPaymentHashCustomFinalCltv as u8 => Ok ( Method :: UserPaymentHashCustomFinalCltv ) ,
116+ bits if bits == Method :: SpontaneousPayment as u8 => Ok ( Method :: SpontaneousPayment ) ,
115117 unknown => Err ( unknown) ,
116118 }
117119 }
@@ -191,6 +193,26 @@ pub fn create_from_hash(keys: &ExpandedKey, min_value_msat: Option<u64>, payment
191193 Ok ( construct_payment_secret ( & iv_bytes, & metadata_bytes, & keys. metadata_key ) )
192194}
193195
196+ #[ cfg( async_payments) ]
197+ pub ( super ) fn create_for_spontaneous_payment (
198+ keys : & ExpandedKey , min_value_msat : Option < u64 > , invoice_expiry_delta_secs : u32 ,
199+ current_time : u64 , min_final_cltv_expiry_delta : Option < u16 >
200+ ) -> Result < PaymentSecret , ( ) > {
201+ let metadata_bytes = construct_metadata_bytes (
202+ min_value_msat, Method :: SpontaneousPayment , invoice_expiry_delta_secs, current_time,
203+ min_final_cltv_expiry_delta
204+ ) ?;
205+
206+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & keys. offers_base_key ) ;
207+ hmac. input ( & metadata_bytes) ;
208+ let hmac_bytes = Hmac :: from_engine ( hmac) . to_byte_array ( ) ;
209+
210+ let mut iv_bytes = [ 0 as u8 ; IV_LEN ] ;
211+ iv_bytes. copy_from_slice ( & hmac_bytes[ ..IV_LEN ] ) ;
212+
213+ Ok ( construct_payment_secret ( & iv_bytes, & metadata_bytes, & keys. metadata_key ) )
214+ }
215+
194216fn construct_metadata_bytes ( min_value_msat : Option < u64 > , payment_type : Method ,
195217 invoice_expiry_delta_secs : u32 , highest_seen_timestamp : u64 , min_final_cltv_expiry_delta : Option < u16 > ) -> Result < [ u8 ; METADATA_LEN ] , ( ) > {
196218 if min_value_msat. is_some ( ) && min_value_msat. unwrap ( ) > MAX_VALUE_MSAT {
@@ -320,6 +342,14 @@ pub(super) fn verify<L: Deref>(payment_hash: PaymentHash, payment_data: &msgs::F
320342 }
321343 }
322344 } ,
345+ Ok ( Method :: SpontaneousPayment ) => {
346+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & keys. offers_base_key ) ;
347+ hmac. input ( & metadata_bytes[ ..] ) ;
348+ if !fixed_time_eq ( & iv_bytes, & Hmac :: from_engine ( hmac) . to_byte_array ( ) . split_at_mut ( IV_LEN ) . 0 ) {
349+ log_trace ! ( logger, "Failing async payment HTLC with sender-generated payment_hash {}: unexpected payment_secret" , & payment_hash) ;
350+ return Err ( ( ) )
351+ }
352+ } ,
323353 Err ( unknown_bits) => {
324354 log_trace ! ( logger, "Failing HTLC with payment hash {} due to unknown payment type {}" , & payment_hash, unknown_bits) ;
325355 return Err ( ( ) ) ;
@@ -365,6 +395,9 @@ pub(super) fn get_payment_preimage(payment_hash: PaymentHash, payment_secret: Pa
365395 Ok ( Method :: UserPaymentHash ) | Ok ( Method :: UserPaymentHashCustomFinalCltv ) => Err ( APIError :: APIMisuseError {
366396 err : "Expected payment type to be LdkPaymentHash, instead got UserPaymentHash" . to_string ( )
367397 } ) ,
398+ Ok ( Method :: SpontaneousPayment ) => Err ( APIError :: APIMisuseError {
399+ err : "Can't extract payment preimage for spontaneous payments" . to_string ( )
400+ } ) ,
368401 Err ( other) => Err ( APIError :: APIMisuseError { err : format ! ( "Unknown payment type: {}" , other) } ) ,
369402 }
370403}
0 commit comments