inbound_payment: Add utility to get payment preimage given hash/secret
[rust-lightning] / lightning / src / ln / channelmanager.rs
index b727f7874d7636181c6b354226d7499e1e205e07..c51d17f67b9df16701321b687e23d533e191cd68 100644 (file)
@@ -73,12 +73,14 @@ use core::ops::Deref;
 use std::time::Instant;
 
 mod inbound_payment {
+       use alloc::string::ToString;
        use bitcoin::hashes::{Hash, HashEngine};
        use bitcoin::hashes::cmp::fixed_time_eq;
        use bitcoin::hashes::hmac::{Hmac, HmacEngine};
        use bitcoin::hashes::sha256::Hash as Sha256;
        use chain::keysinterface::{KeyMaterial, KeysInterface, Sign};
        use ln::{PaymentHash, PaymentPreimage, PaymentSecret};
+       use ln::channelmanager::APIError;
        use ln::msgs;
        use ln::msgs::MAX_VALUE_MSAT;
        use util::chacha20::ChaCha20;
@@ -288,6 +290,23 @@ mod inbound_payment {
                Ok(payment_preimage)
        }
 
+       pub(super) fn get_payment_preimage(payment_hash: PaymentHash, payment_secret: PaymentSecret, keys: &ExpandedKey) -> Result<PaymentPreimage, APIError> {
+               let (iv_bytes, metadata_bytes) = decrypt_metadata(payment_secret, keys);
+
+               match Method::from_bits((metadata_bytes[0] & 0b1110_0000) >> METHOD_TYPE_OFFSET) {
+                       Ok(Method::LdkPaymentHash) => {
+                               derive_ldk_payment_preimage(payment_hash, &iv_bytes, &metadata_bytes, keys)
+                                       .map_err(|bad_preimage_bytes| APIError::APIMisuseError {
+                                               err: format!("Payment hash {} did not match decoded preimage {}", log_bytes!(payment_hash.0), log_bytes!(bad_preimage_bytes))
+                                       })
+                       },
+                       Ok(Method::UserPaymentHash) => Err(APIError::APIMisuseError {
+                               err: "Expected payment type to be LdkPaymentHash, instead got UserPaymentHash".to_string()
+                       }),
+                       Err(other) => Err(APIError::APIMisuseError { err: format!("Unknown payment type: {}", other) }),
+               }
+       }
+
        fn decrypt_metadata(payment_secret: PaymentSecret, keys: &ExpandedKey) -> ([u8; IV_LEN], [u8; METADATA_LEN]) {
                let mut iv_bytes = [0; IV_LEN];
                let (iv_slice, encrypted_metadata_bytes) = payment_secret.0.split_at(IV_LEN);
@@ -5097,6 +5116,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                self.set_payment_hash_secret_map(payment_hash, None, min_value_msat, invoice_expiry_delta_secs)
        }
 
+       /// Gets an LDK-generated payment preimage from a payment hash and payment secret that were
+       /// previously returned from [`create_inbound_payment`].
+       ///
+       /// [`create_inbound_payment`]: Self::create_inbound_payment
+       pub fn get_payment_preimage(&self, payment_hash: PaymentHash, payment_secret: PaymentSecret) -> Result<PaymentPreimage, APIError> {
+               inbound_payment::get_payment_preimage(payment_hash, payment_secret, &self.inbound_payment_key)
+       }
+
        #[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))]
        pub fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
                let events = core::cell::RefCell::new(Vec::new());