From f52bd0b8e3a0750f5a5fd2d2732b483b60c5eac7 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 18 Jul 2024 11:38:44 -0500 Subject: [PATCH] HMAC construction and verification for PaymentID When receiving an InvoiceError in response to an InvoiceRequest, the corresponding payment should be abandoned. Add functions for constructing and verifying an HMAC over a Payment ID to allow for this. --- lightning/src/offers/signer.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lightning/src/offers/signer.rs b/lightning/src/offers/signer.rs index c15b94d49..0aa51cd33 100644 --- a/lightning/src/offers/signer.rs +++ b/lightning/src/offers/signer.rs @@ -36,6 +36,9 @@ const DERIVED_METADATA_AND_KEYS_HMAC_INPUT: &[u8; 16] = &[2; 16]; const WITHOUT_ENCRYPTED_PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[3; 16]; const WITH_ENCRYPTED_PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[4; 16]; +// HMAC input for a `PaymentId`. The HMAC is used in `OffersContext::OutboundPayment`. +const PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[5; 16]; + /// Message metadata which possibly is derived from [`MetadataMaterial`] such that it can be /// verified. #[derive(Clone)] @@ -391,3 +394,22 @@ fn hmac_for_message<'a>( Ok(hmac) } + +pub(crate) fn hmac_for_payment_id( + payment_id: PaymentId, nonce: Nonce, expanded_key: &ExpandedKey, +) -> Hmac { + const IV_BYTES: &[u8; IV_LEN] = b"LDK Payment ID ~"; + let mut hmac = expanded_key.hmac_for_offer(); + hmac.input(IV_BYTES); + hmac.input(&nonce.0); + hmac.input(PAYMENT_ID_HMAC_INPUT); + hmac.input(&payment_id.0); + + Hmac::from_engine(hmac) +} + +pub(crate) fn verify_payment_id( + payment_id: PaymentId, hmac: Hmac, nonce: Nonce, expanded_key: &ExpandedKey, +) -> bool { + hmac_for_payment_id(payment_id, nonce, expanded_key) == hmac +} -- 2.39.5