You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Commit to payment_metadata in inbound payment HMAC
When payment_metadata is set in a BOLT 11 invoice, users expect to
receive it back as-is in the payment onion. In order to ensure it
isn't tampered with, they presumably will add an HMAC, or worse, not
add one and forget that it can be tampered with.
Instead, here we include it in the HMAC computation for the payment
secret. This ensures that the sender must relay the correct
metadata for the payment to be accepted by the receiver, binding
the metadata to the payment cryptographically.
The metadata is only included in the HMAC when present, so existing
payments without metadata continue to verify correctly. However,
this does break receiving payments with metadata today. On an
upgrade this seems acceptable to me given we have seen almost no
use of payment metadata in practice.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
/// [`BlindedMessagePath`]s for an async recipient to communicate with this node and interactively
@@ -17113,7 +17141,8 @@ impl<
17113
17141
self.create_inbound_payment(
17114
17142
Some(amount_msats),
17115
17143
relative_expiry,
17116
-
None
17144
+
None,
17145
+
None,
17117
17146
).map_err(|_| Bolt12SemanticError::InvalidAmount)
17118
17147
};
17119
17148
@@ -21325,15 +21354,15 @@ mod tests {
21325
21354
// payment verification fails as expected.
21326
21355
let mut bad_payment_hash = payment_hash.clone();
21327
21356
bad_payment_hash.0[0] += 1;
21328
-
match inbound_payment::verify(bad_payment_hash, &payment_data, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger) {
21357
+
match inbound_payment::verify(bad_payment_hash, &payment_data, None, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger) {
21329
21358
Ok(_) => panic!("Unexpected ok"),
21330
21359
Err(()) => {
21331
21360
nodes[0].logger.assert_log_contains("lightning::ln::inbound_payment", "Failing HTLC with user-generated payment_hash", 1);
21332
21361
}
21333
21362
}
21334
21363
21335
21364
// Check that using the original payment hash succeeds.
21336
-
assert!(inbound_payment::verify(payment_hash, &payment_data, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger).is_ok());
21365
+
assert!(inbound_payment::verify(payment_hash, &payment_data, None, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger).is_ok());
0 commit comments