Offline BOLT 11 Invoices on Lightning with ECDH
If you’ve played around with the Lightning Network, you’ve most definitely come across a BOLT 11 invoice. It’s usually encoded as a QR code for conveniently scanning with your phone’s camera. It includes things like the receiving node’s public key, an amount with a unit suffix, a payment hash, a note, an expiry, maybe some routing hints, etc. These invoices are generated on-the-fly by the receiving node that generates a payment preimage which it keeps secret until the HTLCs have made their way across the route.
If we wanted to enable Lightning payments on a vending machine, for example, you might think that you’d need integrate an always-online node within the vending machine, or have it connected to some remote node to generate the invoices, or even duplicate the private key of the receiving node. However, with the help of ECDH, described in a message in the Lightning dev mailing list, we don’t need the vending machine to be online at all!
There are a few key elements to making this work.
Elliptic-Curve Diffie-Hellman (ECDH)
ECDH allows us to use elliptic-curve public–private key pairs to establish a shared secret.
Suppose Alice has an ECDSA secp256k1 public key A and private key a, and Bob has public key B and private key b. Alice can compute the point aB, and Bob can compute the point bA.
Note that if G is the generator point for the elliptic curve, then:
aB = a(bG) = (ab)G = (ba)G = b(aG) = bA
(By the corresponding associativity and commutativity rules of the associated groups)
So aB
(or equivalently, bA
) is the shared secret that could be used for symmetric encryption if desired (taking the x-coordinate for example).
This provides an opportunity for us to do something interesting.
Let’s say that the vending machine is an “offline” node that generates an ephemeral private key k
and corresponding public key K
(node ID). Suppose there is also an “online” node with public key N
that is owned by the vending machine company. The vending machine then generates an invoice with some routing hints that the payment should go through node N
.
So we declare N
as an intermediary routing node for K
, which is actually impossible to route to since it is offline / disconnnected from the Lightning Network.
This is where the trick comes in. The preimage is specifically constructed as hmac-sha256(x, amount)
, where x
is the shared secret between N
and K
(x-coordinate of kN
. The amount is stored in the 8 byte short channel ID between N
and K
. A channel that does not really exist.
Routing to a non-existent node
Now a customer walks up to the vending machine, and being a forward-thinking #LaserRaysUntil100k human, decides to pay with their non-custodial mobile Lightning wallet. They scan the BOLT 11 invoice generated by the vending machine and their wallet (node) picks up the routing hints. It then attempts to route the payment to K
along some route via N
.
Now when N
is asked to route a payment to an unknown node, it calculates the ECDH shared secret x
. It then uses this, along with the amount encoded in the short channel ID to reconstruct a preimage with hmac-sha256(x, amount)
. The payment hash is derived from that and if it matches the payment hash in the accepted HTLC, then it can claim the amount.
I plan to make a little Web simulation that demonstrates this a bit better at some stage! Until then, ride the Lightning!