[Lightning-dev] Stateless invoices with proof-of-payment

Joost Jager joost.jager at gmail.com
Tue Sep 21 10:08:06 UTC 2021


One of the qualities of lightning is that it can provide light-weight,
no-login payments with minimal friction. Games, paywalls, podcasts, etc can
immediately present a QR code that is ready for scan and pay.

Optimistically presenting payment requests does lead to many of those
payment requests going unused. A user visits a news site and decides not to
buy the article. The conventional approach is to create a lightning invoice
on a node and store the invoice together with order details in a database.
If the order then goes unfulfilled, cleaning processes remove the data from
the node and database again.

The problem with this setup is that it needs protection against unbounded
generation of payment requests. There are solutions for that such as rate
limiting, but wouldn't it be nice if invoices can be generated without the
need to keep any state at all?

Stateless invoices

What would happen if a lightning invoice is only generated and stored
nowhere on the recipient side? To the user, it won't make a difference.
They would still scan and pay the invoice. When the payment arrives at the
recipient though, two problems arise:

1. Recipient doesn't know whom or what the payment is for.

This can be solved by attaching additional custom tlv records to the htlc.
On the wire, this is all arranged for. The only missing piece is the
ability to specify additional data for that custom tlv record in a bolt11
invoice. One way would be to define a new tagged field for this in which
the recipient can encode the order details.

An alternative is to use the existing invoice description field and simply
always pass that along with the htlc as a custom tlv record.

A second alternative that already works today is to use part (for example
16 out of 32 bytes) of the payment_secret (aka payment address) to encode
the order details in. This assumes that the secret is still secret enough
with reduced entropy. Also there may not be enough space for every

2. Recipient doesn't know the preimage that is needed to settle the htlc(s).

One option is to use a keysend payment or AMP payment. In that case, the
sender includes the preimage with the htlc. Unfortunately this doesn't
provide the sender with a proof of payment that they'd get with a regular
lightning payment.

An alternative solution is to use a deterministic preimage based on a
(recipient node key-derived) secret, the payment secret and other relevant
properties. This allows the recipient to derive the same preimage twice:
Once when the lightning invoice is generated and again when a payment

It could be something like this:

payment_secret = random
preimage = H(node_secret | payment_secret | payment_amount |
invoice_hash = H(preimage)

The sender sends an htlc locked to invoice_hash for payment_amount and
passes along payment_secret and encoded_order_details in a custom tlv

When the recipient receives the htlc, they reconstruct the preimage
according to the formula above. At this point, all data is available to do
so. When H(preimage) indeed matches the htlc hash, they can settle the
payment knowing that this is an order that they committed to earlier.
Settling could be implemented as a just-in-time inserted invoice to keep
the diff small.

The preimage is returned to the sender and serves as a proof of payment.


To me it seems that stateless invoices can be a relatively simple way to
improve the resiliency of systems that deal with lightning invoices.
Unlimited amounts of invoices can be generated without worrying about
storage or memory, no matter if the requests are due to popularity of a
service or a deliberate dos attack.

Interested to hear your thoughts.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linuxfoundation.org/pipermail/lightning-dev/attachments/20210921/788f449b/attachment-0001.html>

More information about the Lightning-dev mailing list