Skip to content

Commit

Permalink
Add onion message AsyncPaymentsContext for inbound payments
Browse files Browse the repository at this point in the history
This context is included in static invoice's blinded message paths, provided
back to us in HeldHtlcAvailable onion messages for blinded path authentication.
In future work, we will check if this context is valid and respond with a
ReleaseHeldHtlc message to release the upstream payment if so.

We also add creation methods for the hmac used for authenticating the blinded path
using the static invoice's corresponding offer id.
  • Loading branch information
valentinewallace committed Dec 6, 2024
1 parent 8d8436b commit 6cc741f
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
28 changes: 28 additions & 0 deletions lightning/src/blinded_path/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::ln::msgs::DecodeError;
use crate::ln::onion_utils;
use crate::types::payment::PaymentHash;
use crate::offers::nonce::Nonce;
use crate::offers::offer::OfferId;
use crate::onion_message::packet::ControlTlvs;
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
use crate::sign::{EntropySource, NodeSigner, Recipient};
Expand Down Expand Up @@ -402,6 +403,28 @@ pub enum AsyncPaymentsContext {
/// containing the expected [`PaymentId`].
hmac: Hmac<Sha256>,
},
/// Context contained within the [`BlindedMessagePath`]s we put in static invoices, provided back
/// to us in corresponding [`HeldHtlcAvailable`] messages.
///
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
InboundPayment {
/// The ID of the [`Offer`] that this [`BlindedMessagePath`]'s static invoice corresponds to.
/// Useful to authenticate that this blinded path was created by us for asynchronously paying
/// one of our offers.
///
/// [`Offer`]: crate::offers::offer::Offer
offer_id: OfferId,
/// A nonce used for authenticating that a [`HeldHtlcAvailable`] message is valid for a
/// preceding static invoice.
///
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
nonce: Nonce,
/// Authentication code for the [`OfferId`].
///
/// Prevents the recipient from being able to deanonymize us by creating a blinded path to us
/// containing the expected [`OfferId`].
hmac: Hmac<Sha256>,
},
}

impl_writeable_tlv_based_enum!(MessageContext,
Expand Down Expand Up @@ -433,6 +456,11 @@ impl_writeable_tlv_based_enum!(AsyncPaymentsContext,
(2, nonce, required),
(4, hmac, required),
},
(1, InboundPayment) => {
(0, offer_id, required),
(2, nonce, required),
(4, hmac, required),
},
);

/// Contains a simple nonce for use in a blinded path's context.
Expand Down
7 changes: 6 additions & 1 deletion lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11747,7 +11747,12 @@ where

fn handle_release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {
#[cfg(async_payments)] {
let AsyncPaymentsContext::OutboundPayment { payment_id, hmac, nonce } = _context;
let (payment_id, nonce, hmac) = match _context {
AsyncPaymentsContext::OutboundPayment { payment_id, hmac, nonce } => {
(payment_id, nonce, hmac)
},
_ => return
};
if payment_id.verify_for_async_payment(hmac, nonce, &self.inbound_payment_key).is_err() { return }
if let Err(e) = self.send_payment_for_static_invoice(payment_id) {
log_trace!(
Expand Down
16 changes: 16 additions & 0 deletions lightning/src/offers/offer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ use crate::offers::signer::{Metadata, MetadataMaterial, self};
use crate::util::ser::{CursorReadable, HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};
use crate::util::string::PrintableString;

#[cfg(async_payments)]
use {
bitcoin::hashes::hmac::Hmac,
bitcoin::hashes::sha256::Hash as Sha256,
crate::ln::inbound_payment,
};

#[cfg(not(c_bindings))]
use {
crate::offers::invoice_request::InvoiceRequestBuilder,
Expand Down Expand Up @@ -134,6 +141,15 @@ impl OfferId {
let tagged_hash = TaggedHash::from_tlv_stream(Self::ID_TAG, tlv_stream);
Self(tagged_hash.to_bytes())
}

/// Constructs an HMAC to include in [`AsyncPaymentsContext::InboundPayment`] for the offer id
/// along with the given [`Nonce`].
#[cfg(async_payments)]
pub fn hmac_for_static_invoice(
&self, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey,
) -> Hmac<Sha256> {
signer::hmac_for_static_invoice_offer_id(*self, nonce, expanded_key)
}
}

impl Borrow<[u8]> for OfferId {
Expand Down
20 changes: 20 additions & 0 deletions lightning/src/offers/signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ use crate::ln::channelmanager::PaymentId;
use crate::ln::inbound_payment::{ExpandedKey, IV_LEN};
use crate::offers::merkle::TlvRecord;
use crate::offers::nonce::Nonce;
#[cfg(async_payments)]
use crate::offers::offer::OfferId;
use crate::util::ser::Writeable;

use crate::prelude::*;
Expand All @@ -46,6 +48,10 @@ const ASYNC_PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[6; 16];
// HMAC input for a `PaymentHash`. The HMAC is used in `OffersContext::InboundPayment`.
const PAYMENT_HASH_HMAC_INPUT: &[u8; 16] = &[7; 16];

// HMAC input for an `OfferId`. The HMAC is used in `AsyncPaymentsContext::InboundPayment`.
#[cfg(async_payments)]
const ASYNC_PAYMENT_OFFER_ID_HMAC_INPUT: &[u8; 16] = &[8; 16];

/// Message metadata which possibly is derived from [`MetadataMaterial`] such that it can be
/// verified.
#[derive(Clone)]
Expand Down Expand Up @@ -459,3 +465,17 @@ fn hmac_for_payment_id(

Hmac::from_engine(hmac)
}

#[cfg(async_payments)]
pub(crate) fn hmac_for_static_invoice_offer_id(
offer_id: OfferId, nonce: Nonce, expanded_key: &ExpandedKey,
) -> Hmac<Sha256> {
const IV_BYTES: &[u8; IV_LEN] = b"LDK Offer ID ~~~";
let mut hmac = expanded_key.hmac_for_offer();
hmac.input(IV_BYTES);
hmac.input(&nonce.0);
hmac.input(ASYNC_PAYMENT_OFFER_ID_HMAC_INPUT);
hmac.input(&offer_id.0);

Hmac::from_engine(hmac)
}

0 comments on commit 6cc741f

Please sign in to comment.