///
/// [`Bolt12Invoice::payment_hash`]: crate::offers::invoice::Bolt12Invoice::payment_hash
payment_hash: PaymentHash,
+
+ /// A nonce used for authenticating that a received [`InvoiceError`] is for a valid
+ /// sent [`Bolt12Invoice`].
+ ///
+ /// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
+ /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
+ nonce: Nonce,
+
+ /// Authentication code for the [`PaymentHash`], which should be checked when the context is
+ /// used to log the received [`InvoiceError`].
+ ///
+ /// [`InvoiceError`]: crate::offers::invoice_error::InvoiceError
+ hmac: Hmac<Sha256>,
},
}
},
(2, InboundPayment) => {
(0, payment_hash, required),
+ (1, nonce, required),
+ (2, hmac, required)
},
);
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
+ let nonce = Nonce::from_entropy_source(entropy);
+ let hmac = payment_hash.hmac_for_offer_payment(nonce, expanded_key);
let context = OffersContext::InboundPayment {
- payment_hash: invoice.payment_hash(),
+ payment_hash: invoice.payment_hash(), nonce, hmac
};
let reply_paths = self.create_blinded_paths(context)
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
},
OffersMessage::InvoiceError(invoice_error) => {
let payment_hash = match context {
- Some(OffersContext::InboundPayment { payment_hash }) => Some(payment_hash),
+ Some(OffersContext::InboundPayment { payment_hash, nonce, hmac }) => {
+ match payment_hash.verify(hmac, nonce, expanded_key) {
+ Ok(_) => Some(payment_hash),
+ Err(_) => None,
+ }
+ },
_ => None,
};