@@ -98,11 +98,13 @@ impl ExpandedKey {
9898 }
9999}
100100
101+ /// We currently set aside 3 bits for the `Method` in the `PaymentSecret`.
101102enum Method {
102103 LdkPaymentHash = 0 ,
103104 UserPaymentHash = 1 ,
104105 LdkPaymentHashCustomFinalCltv = 2 ,
105106 UserPaymentHashCustomFinalCltv = 3 ,
107+ SpontaneousPayment = 4 ,
106108}
107109
108110impl Method {
@@ -112,6 +114,7 @@ impl Method {
112114 bits if bits == Method :: UserPaymentHash as u8 => Ok ( Method :: UserPaymentHash ) ,
113115 bits if bits == Method :: LdkPaymentHashCustomFinalCltv as u8 => Ok ( Method :: LdkPaymentHashCustomFinalCltv ) ,
114116 bits if bits == Method :: UserPaymentHashCustomFinalCltv as u8 => Ok ( Method :: UserPaymentHashCustomFinalCltv ) ,
117+ bits if bits == Method :: SpontaneousPayment as u8 => Ok ( Method :: SpontaneousPayment ) ,
115118 unknown => Err ( unknown) ,
116119 }
117120 }
@@ -191,6 +194,26 @@ pub fn create_from_hash(keys: &ExpandedKey, min_value_msat: Option<u64>, payment
191194 Ok ( construct_payment_secret ( & iv_bytes, & metadata_bytes, & keys. metadata_key ) )
192195}
193196
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+
194217fn construct_metadata_bytes ( min_value_msat : Option < u64 > , payment_type : Method ,
195218 invoice_expiry_delta_secs : u32 , highest_seen_timestamp : u64 , min_final_cltv_expiry_delta : Option < u16 > ) -> Result < [ u8 ; METADATA_LEN ] , ( ) > {
196219 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
320343 }
321344 }
322345 } ,
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+ } ,
323354 Err ( unknown_bits) => {
324355 log_trace ! ( logger, "Failing HTLC with payment hash {} due to unknown payment type {}" , & payment_hash, unknown_bits) ;
325356 return Err ( ( ) ) ;
@@ -365,6 +396,9 @@ pub(super) fn get_payment_preimage(payment_hash: PaymentHash, payment_secret: Pa
365396 Ok ( Method :: UserPaymentHash ) | Ok ( Method :: UserPaymentHashCustomFinalCltv ) => Err ( APIError :: APIMisuseError {
366397 err : "Expected payment type to be LdkPaymentHash, instead got UserPaymentHash" . to_string ( )
367398 } ) ,
399+ Ok ( Method :: SpontaneousPayment ) => Err ( APIError :: APIMisuseError {
400+ err : "Can't extract payment preimage for spontaneous payments" . to_string ( )
401+ } ) ,
368402 Err ( other) => Err ( APIError :: APIMisuseError { err : format ! ( "Unknown payment type: {}" , other) } ) ,
369403 }
370404}
0 commit comments