Skip to content

Drop ChannelManager::pending_inbound_payment and replace payment_secret with HMAC(payment data) #1171

Closed
@TheBlueMatt

Description

@TheBlueMatt

Currently we require the user register all inbound payments before we receive them so that we can authenticate them using the payment secret. This is kinda annoying, we have to store a bunch of payment state and time that out appropriately based on user-provided timeout data (via block timestamps...).

This is maybe all fine except its a good bit of complexity and we'd like to avoid it if possible. In lightning/bolts#912, Joost suggested lightning nodes just take their local payment metadata and encrypt it to themselves (with an HMAC), then have the sender send us that data in the HTLC onion. This way, we make the sender (via the invoice) deal with tracking our payment metadata and we don't actually have to store it at all.

For most lightning clients this is probably annoying cause they have material payment metadata, but, we don't - we (currently, see PendingInboundPayment) only care about the payment hash/preimage, payment secret, amount, expiry, and user_payment_id. If we drop the last one, I believe we can trivially just start doing this today, except via the payment secret and not a new field.

There is a bit of complexity here, however, because we have effectively two different payment types - those from create_inbound_payment where we constructed the payment preimage, and create_inbound_payment_for_hash where the user gave us the payment hash. This is rectifiable, however.

To shove all the needed info in the payment secret, we'd replace the payment secret with an encrypted blob. That encrypted blob would be different based on the type of payment:

For create_inbound_payment payments, we'd set it to contain:

 * the minimum amount field - 8 bytes
 * the high bit of the minimum amount field is 0
 * the payment expiry timestamp - 8 bytes
 * 16 bytes of random data

Then, we'd take an HMAC of the above and set the payment preimage to the HMAC of the above. We'd (of course) hash the payment preimage as the payment hash. Thus, when we receive a payment, we take the payment secret, we HMAC it, we hash the HMAC and we check that the payment hash matches - if it does, we've effectively HMAC'd the data and know its ours and process using the encrypted metadata, otherwise we fail the payment.

For create_inbound_payment_for_hash we do something similar, but:

  • instead of the high bit of the minimum amount field being 0, we set it to 1, which allows us to identify the type of payment
  • instead of 16 bytes of random data we set it to HMAC(payment_hash || minimum amount field || expiry field)
    Thus, upon receipt, we re-generate the now-explicit HMAC and check that it matches the metadata and payment hash.

All of this requires that we drop the user_payment_id, but @valentinewallace's understanding from asking our users is none of them use it, and they can always store local payment metadata against the payment hash itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions