You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
653 lines
42 KiB
653 lines
42 KiB
3 years ago
|
# Lightning privacy: from Zero to Hero
|
||
|
|
||
|
This article contains many privacy pitfalls of lightning, how you can avoid them, and how we plan
|
||
|
on addressing them in the future.
|
||
|
|
||
|
## Table of Contents
|
||
|
|
||
|
* [On-Chain to Off-Chain privacy](#on-chain-to-off-chain-privacy)
|
||
|
* [Identifying lightning channel funding scripts](#identifying-lightning-channel-funding-scripts)
|
||
|
* [Public Channels](#public-channels)
|
||
|
* [Unannounced Channels](#unannounced-channels)
|
||
|
* [Off-Chain to Off-Chain privacy](#off-chain-to-off-chain-privacy)
|
||
|
* [Payment correlation](#payment-correlation)
|
||
|
* [Identifying mobile wallets](#identifying-mobile-wallets)
|
||
|
* [Path-finding tricks](#path-finding-tricks)
|
||
|
* [Trampoline](#trampoline)
|
||
|
* [Resources](#resources)
|
||
|
|
||
|
## On-Chain to Off-Chain privacy
|
||
|
|
||
|
Whenever you use lightning, there will be an on-chain footprint: you will be opening and closing
|
||
|
channels. It is important to ensure that this on-chain footprint doesn't leak too much information.
|
||
|
|
||
|
### Identifying lightning channel funding scripts
|
||
|
|
||
|
As we saw in the [lightning transactions](./lightning-txs.md) article, the channel funding
|
||
|
transaction uses a p2wsh 2-of-2 multisig.
|
||
|
While the channel is open, this is fine: an attacker looking at the blockchain only sees a p2wsh
|
||
|
output, which could contain anything.
|
||
|
However, when the channel is closed, we have to reveal that it is using a 2-of-2 multisig, which
|
||
|
is a strong indication that this may be a lightning channel.
|
||
|
|
||
|
Fortunately, this is very easy to fix with Taproot. Instead of using a p2wsh output, we will use
|
||
|
[Musig2](./schnorr.md) with a key path spend, which will be indistiguishable from a normal single
|
||
|
signature output.
|
||
|
|
||
|
However, there are two ways that a lightning channel can be closed: either cooperatively, where
|
||
|
both participants create a transaction that sends each one of them their final balance, or
|
||
|
unilaterally when one of the participants isn't collaborating.
|
||
|
|
||
|
In the second case, the transaction that is broadcast is the commitment transaction that we
|
||
|
described in the [lightning transactions](./lightning-txs.md) article. This transaction relies on
|
||
|
specialized scripts that are unique to lightning to allow participants to recover their funds.
|
||
|
These scripts will be visible on-chain and make it obvious that this was a lightning channel.
|
||
|
Unfortunately, there is probably no way to work around this issue while guaranteeing funds safety.
|
||
|
Node operators should avoid unilaterally closing as much as possible: this should only happen when
|
||
|
a peer is malicious or has disappeared.
|
||
|
|
||
|
### Public Channels
|
||
|
|
||
|
Lightning nodes currently advertize their channels in the lightning network by sending a
|
||
|
`channel_announcement` message to their peers, who will relay this announcement to the rest of the
|
||
|
network. This message contains the details of the funding transaction, which lets anyone running a
|
||
|
lightning node know which utxos are actually lightning channels.
|
||
|
|
||
|
The reason channels are advertized publicly inside the network is because we are using source
|
||
|
routing to ensure payment privacy: when Alice wants to send a payment to Bob, Alice must find a
|
||
|
route through existing channels to reach Bob. If Alice has access to the complete topology of the
|
||
|
graph, she can find the route herself, without revealing to anyone that she intends to send a
|
||
|
payment to Bob.
|
||
|
|
||
|
```text
|
||
|
+------+ +-----+
|
||
|
| Node | | Bob |
|
||
|
+------+ +-----+
|
||
|
| |
|
||
|
| |
|
||
|
+-------+ +------+ +------+
|
||
|
| Alice |---------| Node |---------| Node |
|
||
|
+-------+ +------+ +------+
|
||
|
| |
|
||
|
| +------+ |
|
||
|
+-------------| Node |-------------+
|
||
|
+------+
|
||
|
```
|
||
|
|
||
|
We can't get rid of this mechanism entirely if we want to preserve payment anonymity, but we can
|
||
|
make it better. Instead of disclosing all the details of our channel, we only need to let the
|
||
|
network know that there exists an on-chain transaction of at least a given amount that created a
|
||
|
channel between two nodes. The details of how we'll do that are not completely fleshed out yet,
|
||
|
but it should be possible with some cryptographic wizardry (e.g. ring signatures or zkps).
|
||
|
|
||
|
### Unannounced Channels
|
||
|
|
||
|
Fortunately, nodes that don't want to route payments (e.g. mobile wallets and merchants) have the
|
||
|
option of not announcing their channels to the network.
|
||
|
|
||
|
```text
|
||
|
+------+ +------+
|
||
|
| Node |---------| Node |
|
||
|
+------+ +------+
|
||
|
| |
|
||
|
| |
|
||
|
+-------+ +------+ +------+ +------+ +-----+
|
||
|
| Alice |ooooooooo| Node |---------| Node |---------| Node |ooooooooo| Bob |
|
||
|
+-------+ +------+ +------+ +------+ +-----+
|
||
|
o |
|
||
|
o +------+ |
|
||
|
oooooooooooooo| Node |-------------+
|
||
|
+------+
|
||
|
|
||
|
NB: unannounced channels are represented with "ooooo"
|
||
|
```
|
||
|
|
||
|
However, whenever nodes want to receive a payment, the sender needs to know how to find them in the
|
||
|
graph, so they have to disclose some information about their unannounced channels.
|
||
|
This is currently done using Bolt 11 invoices, where all the details of some of their unannounced
|
||
|
channels are included. This is bad because invoices are sometimes shared publicly (e.g. on Twitter)
|
||
|
which reveals these unannounced channels to everyone.
|
||
|
|
||
|
We have two upcoming features that will fix this:
|
||
|
|
||
|
* [Offers](https://github.com/lightning/bolts/pull/798) provide a static "address" that can be
|
||
|
shared publicly without revealing channel details.
|
||
|
* [Route Blinding](https://github.com/lightning/bolts/pull/765) lets recipients completely hide
|
||
|
their `node_id` and channels from payers.
|
||
|
|
||
|
Note that routing nodes can also partially leverage unannounced channels to preserve some utxo
|
||
|
privacy. Whenever two nodes have more than one channel open between them, they can choose to only
|
||
|
announce one of them to the network and keep the others private. When they receive a payment to
|
||
|
relay, they can use the unannounced channels, and nobody can know that they didn't use the public
|
||
|
channel. See the following example where unannounced channels are represented with `oooo`:
|
||
|
|
||
|
```text
|
||
|
0.4 btc 1.2 btc
|
||
|
oooooooooooooooooooo oooooooooooooooooooooo
|
||
|
o o o o
|
||
|
+------+ 1 btc +------+ 1.5 btc +------+ 0.8 btc +------+
|
||
|
| Node |-----------| Node |-------------| Node |-------------| Node |
|
||
|
+------+ +------+ +------+ +------+
|
||
|
o 0.6 btc o
|
||
|
oooooooooooooooooooo
|
||
|
```
|
||
|
|
||
|
There is a small drawback though: path-finding heuristics use the capacity between nodes to rank
|
||
|
which channels to use. Since routing nodes will be hiding some of their capacity, they may rank a
|
||
|
bit lower in path-finding scores.
|
||
|
|
||
|
## Off-Chain to Off-Chain privacy
|
||
|
|
||
|
Once you have opened channels, lightning should offer greater anonymity for your payments, as they
|
||
|
don't have any on-chain footprint. We explore some subtleties and pitfalls in the following
|
||
|
sections.
|
||
|
|
||
|
### Payment correlation
|
||
|
|
||
|
Lightning payments use an onion routing scheme called [Sphinx](./sphinx.md), which guarantees that
|
||
|
intermediate nodes only know the previous and the next node in the route, but cannot know whether
|
||
|
there are other hops before or after these nodes.
|
||
|
|
||
|
For example, if Alice uses the following payment route to pay Dave:
|
||
|
|
||
|
```text
|
||
|
+-------+ +-----+ +-------+ +------+
|
||
|
| Alice |---------->| Bob |---------->| Carol |---------->| Dave |
|
||
|
+-------+ +-----+ +-------+ +------+
|
||
|
```
|
||
|
|
||
|
When Bob receives the request to forward the payment to Carol, Bob only learns that:
|
||
|
|
||
|
* the payment could come from Alice or another unknown node before Alice
|
||
|
* the payment goes to Carol or another unknown node after Carol
|
||
|
|
||
|
Similarly, Carol only learns the following facts:
|
||
|
|
||
|
* the payment could come from Bob or another unknown node before Bob
|
||
|
* the payment goes to Dave or another unknown node after Dave
|
||
|
|
||
|
This mechanism provides great privacy for payments. However, we are unfortunately leaking some
|
||
|
data: because of how HTLCs work, all nodes in the route are given the same payment identifier,
|
||
|
the `payment_hash`. If two nodes in the route are controlled by the same entity, they can see
|
||
|
that this is the same payment.
|
||
|
|
||
|
```text
|
||
|
+---------------------------+
|
||
|
| Well well well... |
|
||
|
| I know that payment hash! |
|
||
|
+---------------------------+
|
||
|
|
|
||
|
|
|
||
|
+-------+ +-----+ +-------+ +------+ +------+
|
||
|
| Alice |---------->| Bob |---------->| Carol |---------->| Bob2 |---------->| Dave |
|
||
|
+-------+ | +-----+ | +-------+ | +------+ | +------+
|
||
|
| | | |
|
||
|
+--------------+ +--------------+ +--------------+ +--------------+
|
||
|
| payment_hash | | payment_hash | | payment_hash | | payment_hash |
|
||
|
| 0x123456 | | 0x123456 | | 0x123456 | | 0x123456 |
|
||
|
+--------------+ +--------------+ +--------------+ +--------------+
|
||
|
```
|
||
|
|
||
|
We will see in the following section how this kind of payment correlation can hurt the privacy
|
||
|
of mobile wallet payments.
|
||
|
|
||
|
The good news is that Taproot lets us switch from HTLCs to PTLCs, and one of the benefits of that
|
||
|
change is that it fixes this payment correlation attack entirely: with PTLCs, every node in the
|
||
|
route sees a different, random payment identifier.
|
||
|
|
||
|
```text
|
||
|
+-------------------------+
|
||
|
| Never seen that payment |
|
||
|
| point before... |
|
||
|
+-------------------------+
|
||
|
|
|
||
|
|
|
||
|
+-------+ +-----+ +-------+ +------+ +------+
|
||
|
| Alice |---------->| Bob |---------->| Carol |---------->| Bob2 |---------->| Dave |
|
||
|
+-------+ | +-----+ | +-------+ | +------+ | +------+
|
||
|
| | | |
|
||
|
+---------------+ +---------------+ +---------------+ +---------------+
|
||
|
| payment_point | | payment_point | | payment_point | | payment_point |
|
||
|
| 0x02123456 | | 0x03ff0123 | | 0x03abcdef | | 0x026bcad3 |
|
||
|
+---------------+ +---------------+ +---------------+ +---------------+
|
||
|
```
|
||
|
|
||
|
### Identifying mobile wallets
|
||
|
|
||
|
Most users will make their lightning payments from mobile wallets.
|
||
|
Mobile wallets are fundamentally different from server nodes: it is impossible for a mobile wallet
|
||
|
to hide the fact that it is a mobile wallet to its direct peers.
|
||
|
They do not have a stable IP address, they are offline most of the time, and they are not relaying
|
||
|
payments, which is easy to detect.
|
||
|
|
||
|
One of the consequences of that is that when a mobile wallet asks one of its peers to forward a
|
||
|
payment, that peers learns that the mobile wallet is the sender. Similarly, when a node forwards
|
||
|
a payment to a mobile wallet, it learns that this mobile wallet is the recipient.
|
||
|
|
||
|
Combined with the payment correlation issue described in the previous section, it can let attackers
|
||
|
discover who is paying who:
|
||
|
|
||
|
```text
|
||
|
+-----------------------+
|
||
|
| Well well well... |
|
||
|
| Alice is paying Dave! |
|
||
|
+-----------------------+
|
||
|
|
|
||
|
mobile | mobile
|
||
|
+-------+ +-----+ +-------+ +------+ +------+
|
||
|
| Alice |---------->| Bob |---------->| Carol |---------->| Bob2 |---------->| Dave |
|
||
|
+-------+ | +-----+ | +-------+ | +------+ | +------+
|
||
|
| | | |
|
||
|
+--------------+ +--------------+ +--------------+ +--------------+
|
||
|
| payment_hash | | payment_hash | | payment_hash | | payment_hash |
|
||
|
| 0x123456 | | 0x123456 | | 0x123456 | | 0x123456 |
|
||
|
+--------------+ +--------------+ +--------------+ +--------------+
|
||
|
```
|
||
|
|
||
|
Once lightning moves to PTLCs though, intermediate nodes will only be able to learn who the payer
|
||
|
or the recipient is, but not both. As we've seen, mobile wallets cannot expect to hide this
|
||
|
information anyway. However this isn't too bad, because:
|
||
|
|
||
|
* mobile wallets can use Tor or VPNs to hide their real IP address: the only identity that they
|
||
|
have on lightning is their `node_id`, which they can change regularly (at the cost of opening
|
||
|
new channels)
|
||
|
* peers only learn that mobile wallets are making payments or receiving them, but cannot know to
|
||
|
or from whom
|
||
|
* mobile wallets can make payments to themselves to create synthetic traffic and thwart off-chain
|
||
|
analysis heuristics
|
||
|
* mobile wallets can have multiple peers so that each of their peers only see a subset of their
|
||
|
payments
|
||
|
|
||
|
Note that this section only applies to mobile wallets that connect to nodes that are run by other
|
||
|
people. If you run a lightning node yourself, and your mobile wallet only connects to that node,
|
||
|
these issues don't apply: the network will not even see that your mobile wallet exists, since
|
||
|
everything will go through your lightning node.
|
||
|
|
||
|
### Path-finding tricks
|
||
|
|
||
|
More advanced attacks against payment privacy are possible by exploiting path-finding subtleties.
|
||
|
Let's explore two of them:
|
||
|
|
||
|
1. multi-part payment path intersection
|
||
|
2. graph filtering
|
||
|
|
||
|
Let's explore multi-part payment path intersection first.
|
||
|
Multi-part payments improve payment privacy against intermediate nodes (because they only see a
|
||
|
fraction of the total payment amount) but gives more data to the recipient node (because it sees
|
||
|
multiple parts arriving through different channels). Let's consider the following multi-part
|
||
|
payment:
|
||
|
|
||
|
```text
|
||
|
+-------+ +------+ +------+
|
||
|
| Alice |----------| Node |----------| Node |------------------+
|
||
|
+-------+ +------+ +------+ |
|
||
|
| | MPP part #1
|
||
|
+------------------+ |
|
||
|
| |
|
||
|
+-----+ +------+ +------+ MPP part #2 +------+
|
||
|
| Bob |------------| Node |----------| Node |---------------| Dave |
|
||
|
+-----+ +------+ +------+ +------+
|
||
|
| |
|
||
|
| |
|
||
|
| | MPP part #3
|
||
|
+-------+ +------+ +------+ |
|
||
|
| Carol |----------| Node |----------| Node |------------------+
|
||
|
+-------+ +------+ +------+
|
||
|
```
|
||
|
|
||
|
Dave can walk back all possible paths to find where they intersect. A simple analysis of the graph
|
||
|
makes it obvious that the most likely sender is thus Bob. With this kind of analysis, sender
|
||
|
anonymity cannot be guaranteed.
|
||
|
|
||
|
Note however that this is a toy theoretical example, exploiting this on the public graph for real
|
||
|
payments may not be feasible, but I believe it's worth mentioning.
|
||
|
|
||
|
The graph filtering attack is even more complex, and requires more resources, but the general idea
|
||
|
is interesting to explore.
|
||
|
|
||
|
Let's consider an end user (Alice) that is connected to a single node (Eve):
|
||
|
|
||
|
```text
|
||
|
+-------+ +-----+
|
||
|
| Alice |----------| Eve |
|
||
|
+-------+ +-----+
|
||
|
```
|
||
|
|
||
|
Alice thinks her payments are private because she computes the routes herself. However, since her
|
||
|
only peer is Eve, Alice gets updates about the public graph only through Eve. Eve can use this fact
|
||
|
to filter out some channels, and provide Alice with a pruned version of the graph that forces Alice
|
||
|
to go through nodes Eve controls to reach most parts of the network.
|
||
|
|
||
|
```text
|
||
|
+------+ +------+ +------+
|
||
|
+-------------| Node |----------| Node |----------| Eve2 |-------------+
|
||
|
| +------+ +------+ +------+ |
|
||
|
| | |
|
||
|
| +-----------------+ |
|
||
|
| | |
|
||
|
+-------+ +-----+ +------+ +------+ +------+ +------+
|
||
|
| Alice |----------| Eve |----------| Node |xxxxxxxxxx| Node |----------| Node |----------| Dave |
|
||
|
+-------+ +-----+ +------+ +------+ +------+ +------+
|
||
|
| | |
|
||
|
| | |
|
||
|
| | |
|
||
|
| +------+ +------+ +------+ |
|
||
|
+-------------| Node |xxxxxxxxxx| Node |----------| Node |-------------+
|
||
|
+------+ +------+ +------+
|
||
|
```
|
||
|
|
||
|
In the sample graph above, Eve filters out the channels marked with `xxxxx`. If Alice wants to pay
|
||
|
Dave, the only routes that she will find will go through Eve's second node, which allows Eve to
|
||
|
deanonymize the payment.
|
||
|
|
||
|
Again, it's important to emphasize that this kind of attacks only works in very specific cases,
|
||
|
and is probably only of theoretical interest.
|
||
|
|
||
|
### Trampoline
|
||
|
|
||
|
[Trampoline routing](https://github.com/lightning/bolts/pull/829) is a mechanism that lets mobile
|
||
|
wallets partially defer calculation of a payment route to intermediate nodes. It is important to
|
||
|
highlight that wallets don't defer the complete route calculation to intermediate nodes, only a
|
||
|
part of it, which is why it can preserve payment privacy.
|
||
|
|
||
|
Let's consider the following graph:
|
||
|
|
||
|
```text
|
||
|
Alice's local neighborhood Dave's local neighorhood
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
| | | |
|
||
|
| +------+ | +------+ +------+ +------+ | +------+ |
|
||
|
| +--------------| Node |-----------------------------| N2 |----------| N3 |----------| N4 |-------------+ +------------| Node | |
|
||
|
| | +------+ | +------+ +------+ +------+ | | | +------+ |
|
||
|
| | | | | | | | | |
|
||
|
| | +------------------+ | | | | | | |
|
||
|
| | | | | | | | | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | Alice |----------| Bob |-----------| Terry |----------| N1 |----------| Node |----------| Node |----------| Ted |----------| Carol |----------| Dave | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | | | | |
|
||
|
| | +------------------+ | | |
|
||
|
| | | | | |
|
||
|
| | +------+ | | |
|
||
|
| +--------------| Node | | | |
|
||
|
| +------+ | | |
|
||
|
| | | |
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
```
|
||
|
|
||
|
Alice and Dave don't need to sync the whole graph, just their local neighborhood, which saves them
|
||
|
a lot of bandwidth and ensures that whenever they run path-finding algorithms, it's on a very small
|
||
|
graph so it's very fast.
|
||
|
|
||
|
Let's walk through a typical trampoline payment.
|
||
|
|
||
|
The first step is for the recipient (Dave) to create an invoice, that will include some trampoline
|
||
|
nodes that are in his neighborhood, and which will be able to route the payment to Dave. Dave finds
|
||
|
these trampoline nodes by doing a simple graph search in his local neighborhood.
|
||
|
To keep the example simple, Dave includes a single trampoline node (Ted) in his invoice.
|
||
|
|
||
|
Alice scans Dave's invoice, which indicates that she must reach Ted. Alice selects a trampoline
|
||
|
node in her own neighborhood (Terry). Alice then builds a trampoline route:
|
||
|
|
||
|
```text
|
||
|
Alice -----> Terry -----> Ted -----> Dave
|
||
|
```
|
||
|
|
||
|
Alice encrypts this trampoline route in a payment onion, using exactly the same construction as
|
||
|
normal payments, but with a smaller size.
|
||
|
|
||
|
Alice then finds a route to Terry in her local neighborhood:
|
||
|
|
||
|
```text
|
||
|
Alice -----> Bob -----> Terry
|
||
|
```
|
||
|
|
||
|
Alice creates a normal payment onion for that route, and includes the trampoline onion in the
|
||
|
payload for Terry. At a high-level, the onion looks like this:
|
||
|
|
||
|
```text
|
||
|
+---------------------------------+
|
||
|
| encrypted payload for Bob |
|
||
|
+---------------------------------+
|
||
|
| encrypted payload for Terry |
|
||
|
| +-----------------------------+ |
|
||
|
| | encrypted payload for Terry | |
|
||
|
| +-----------------------------+ |
|
||
|
| | encrypted payload for Ted | |
|
||
|
| +-----------------------------+ |
|
||
|
| | encrypted payload for Dave | |
|
||
|
| +-----------------------------+ |
|
||
|
| | padding | |
|
||
|
| +-----------------------------+ |
|
||
|
+---------------------------------+
|
||
|
| padding |
|
||
|
+---------------------------------+
|
||
|
```
|
||
|
|
||
|
Alice sends the payment onwards:
|
||
|
|
||
|
```text
|
||
|
Alice's local neighborhood Dave's local neighorhood
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
| | | |
|
||
|
| +------+ | +------+ +------+ +------+ | +------+ |
|
||
|
| +--------------| Node |-----------------------------| N2 |----------| N3 |----------| N4 |-------------+ +------------| Node | |
|
||
|
| | +------+ | +------+ +------+ +------+ | | | +------+ |
|
||
|
| | | | | | | | | |
|
||
|
| | +------------------+ | | | | | | |
|
||
|
| | | | | | | | | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | Alice |>>>>>>>>>>| Bob |>>>>>>>>>>>| Terry |----------| N1 |----------| Node |----------| Node |----------| Ted |----------| Carol |----------| Dave | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | | | | |
|
||
|
| | +------------------+ | | |
|
||
|
| | | | | |
|
||
|
| | +------+ | | |
|
||
|
| +--------------| Node | | | |
|
||
|
| +------+ | | |
|
||
|
| | | |
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
```
|
||
|
|
||
|
Bob is an intermediate node in what looks to him like a normal payment. He only learns that:
|
||
|
|
||
|
* the payment could come from Alice or another unknown node before Alice
|
||
|
* the payment goes to Terry or another unknown node after Terry
|
||
|
* Bob does not know that trampoline is being used
|
||
|
|
||
|
When Terry receives the payment, he discovers that he must find a route to Terry and forward the
|
||
|
payment to him. He only learns that:
|
||
|
|
||
|
* the payment could come from Bob or another unknown node before Bob
|
||
|
* the payment goes to Ted or another unknown node after Ted
|
||
|
|
||
|
Terry finds a route to Ted and creates a normal onion for that route, including the trampoline
|
||
|
onion in the payload for Ted (with the topmost layer of this onion unwrapped).
|
||
|
At a high-level, the onion looks like this:
|
||
|
|
||
|
```text
|
||
|
+--------------------------------+
|
||
|
| encrypted payload for N1 |
|
||
|
+--------------------------------+
|
||
|
| encrypted payload for N2 |
|
||
|
+--------------------------------+
|
||
|
| encrypted payload for N3 |
|
||
|
+--------------------------------+
|
||
|
| encrypted payload for N4 |
|
||
|
+--------------------------------+
|
||
|
| encrypted payload for Ted |
|
||
|
| +----------------------------+ |
|
||
|
| | encrypted payload for Ted | |
|
||
|
| +----------------------------+ |
|
||
|
| | encrypted payload for Dave | |
|
||
|
| +----------------------------+ |
|
||
|
| | padding | |
|
||
|
| +----------------------------+ |
|
||
|
+--------------------------------+
|
||
|
| padding |
|
||
|
+--------------------------------+
|
||
|
```
|
||
|
|
||
|
Terry sends the payment onwards:
|
||
|
|
||
|
```text
|
||
|
Alice's local neighborhood Dave's local neighorhood
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
| | | |
|
||
|
| +------+ | +------+ +------+ +------+ | +------+ |
|
||
|
| +--------------| Node |-----------------------------| N2 |>>>>>>>>>>| N3 |>>>>>>>>>>| N4 |>>>>>>>>>>>>>> +------------| Node | |
|
||
|
| | +------+ | +------+ +------+ +------+ | v | +------+ |
|
||
|
| | | | ^ | | v | |
|
||
|
| | +------------------+ | ^ | | v | |
|
||
|
| | | | ^ | | v | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | Alice |>>>>>>>>>>| Bob |>>>>>>>>>>>| Terry |>>>>>>>>>>| N1 |----------| Node |----------| Node |----------| Ted |----------| Carol |----------| Dave | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | | | | |
|
||
|
| | +------------------+ | | |
|
||
|
| | | | | |
|
||
|
| | +------+ | | |
|
||
|
| +--------------| Node | | | |
|
||
|
| +------+ | | |
|
||
|
| | | |
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
```
|
||
|
|
||
|
N1, N2, N3 and N4 are intermediate nodes in what looks like a normal payment. They only learn that:
|
||
|
|
||
|
* the payment could come from the previous node or another unknown node before the previous node
|
||
|
* the payment goes to the next node or another unknown node after the next node
|
||
|
* they do not know that trampoline is being used
|
||
|
|
||
|
When Ted receives the payment, he discovers that he must find a route to Dave and forward the
|
||
|
payment to him. He only learns that:
|
||
|
|
||
|
* the payment could come from N4 or another unknown node before N4
|
||
|
* the payment goes to Dave or another unknown node after Dave
|
||
|
* if Dave is a mobile wallet though, Ted learns that Dave is the final recipient
|
||
|
* but Dave can use route blinding between him and Ted to hide its identity from Ted!
|
||
|
|
||
|
Ted finds a route to Dave and creates a normal onion for that route, including the trampoline
|
||
|
onion in the payload for Dave (with the topmost layer of this onion unwrapped).
|
||
|
At a high-level, the onion looks like this:
|
||
|
|
||
|
```text
|
||
|
+--------------------------------+
|
||
|
| encrypted payload for Carol |
|
||
|
+--------------------------------+
|
||
|
| encrypted payload for Dave |
|
||
|
| +----------------------------+ |
|
||
|
| | encrypted payload for Dave | |
|
||
|
| +----------------------------+ |
|
||
|
| | padding | |
|
||
|
| +----------------------------+ |
|
||
|
+--------------------------------+
|
||
|
| padding |
|
||
|
+--------------------------------+
|
||
|
```
|
||
|
|
||
|
Ted sends the payment onwards:
|
||
|
|
||
|
```text
|
||
|
Alice's local neighborhood Dave's local neighorhood
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
| | | |
|
||
|
| +------+ | +------+ +------+ +------+ | +------+ |
|
||
|
| +--------------| Node |-----------------------------| N2 |>>>>>>>>>>| N3 |>>>>>>>>>>| N4 |>>>>>>>>>>>>>> +------------| Node | |
|
||
|
| | +------+ | +------+ +------+ +------+ | v | +------+ |
|
||
|
| | | | ^ | | v | |
|
||
|
| | +------------------+ | ^ | | v | |
|
||
|
| | | | ^ | | v | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | Alice |>>>>>>>>>>| Bob |>>>>>>>>>>>| Terry |>>>>>>>>>>| N1 |----------| Node |----------| Node |----------| Ted |>>>>>>>>>>| Carol |>>>>>>>>>>| Dave | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | | | | |
|
||
|
| | +------------------+ | | |
|
||
|
| | | | | |
|
||
|
| | +------+ | | |
|
||
|
| +--------------| Node | | | |
|
||
|
| +------+ | | |
|
||
|
| | | |
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
```
|
||
|
|
||
|
Carol is an intermediate node in what looks to him like a normal payment. She only learns that:
|
||
|
|
||
|
* the payment could come from Ted or another unknown node before Ted
|
||
|
* the payment goes to Dave or another unknown node after Dave
|
||
|
* if Dave is a mobile wallet though, Carol learns that Dave is the final recipient (but it would
|
||
|
be the same with a non-trampoline payment)
|
||
|
* Carol does not know that trampoline is being used
|
||
|
|
||
|
Since Alice and Dave are blind to most of the graph, there is a strong chance that the complete
|
||
|
route used will be non-optimal. For example, the network could actually look like this:
|
||
|
|
||
|
```text
|
||
|
Alice's local neighborhood Dave's local neighorhood
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
| | | |
|
||
|
| +------+ | +------+ +------+ +------+ | +------+ |
|
||
|
| +--------------| Node |-----------------------------| N2 |----------| N3 |----------| N4 |-------------+ +------------| Node | |
|
||
|
| | +------+ | +------+ +------+ +------+ | | | +------+ |
|
||
|
| | | | | | | | | |
|
||
|
| | +------------------+ | | | | | | |
|
||
|
| | | | | | | | | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | Alice |----------| Bob |-----------| Terry |----------| N1 |----------| Node |----------| Node |----------| Ted |----------| Carol |----------| Dave | |
|
||
|
| +-------+ +-----+ +-------+ | +------+ +------+ +------+ | +------+ +-------+ +------+ |
|
||
|
| | | | | | |
|
||
|
| | +------------------+ | | | |
|
||
|
| | | | | | |
|
||
|
| | +------+ | | | |
|
||
|
| +--------------| Node |----------------------|-------------------------------------------------------|--------------------------+ |
|
||
|
| +------+ | | |
|
||
|
| | | |
|
||
|
+--------------------------------------------------+ +--------------------------------------------------+
|
||
|
```
|
||
|
|
||
|
Where a very efficient route exists, but Alice and Dave don't know about it.
|
||
|
This is actually a good thing for privacy, because it adds unpredictable randomness to the route
|
||
|
which cannot be reverse-engineered by attackers' heuristics.
|
||
|
|
||
|
In this example, we only used two intermediate trampoline nodes, as it is the most efficient way of
|
||
|
using trampoline, but privacy-aware users may also randomly add another trampoline node in the
|
||
|
middle of the route, which ensures that the final route will be very different from the optimal
|
||
|
route.
|
||
|
|
||
|
On top of that, trampoline combines very well with multi-part payments and makes them more reliable
|
||
|
and private. Each trampoline node can aggregate the incoming multi-part payment and then split the
|
||
|
outgoing payment differently:
|
||
|
|
||
|
```text
|
||
|
150k sat +------+ 250k sat 300k sat +------+ 200k sat
|
||
|
+-------------| Node |-------------+ +-------------| Node |--------------+
|
||
|
| +------+ | | +------+ |
|
||
|
| | | |
|
||
|
| | | |
|
||
|
| | | |
|
||
|
+-------+ 250k sat +------+ 400k sat +-------+ 500k sat +------+
|
||
|
| Alice |---------------------------| Bob |-----------------------------| Carol |-------------------------| Dave |
|
||
|
+-------+ +------+ +-------+ +------+
|
||
|
| |
|
||
|
| |
|
||
|
| |
|
||
|
| +------+ |
|
||
|
+-------------| Node |-------------+
|
||
|
150k sat +------+ 300k sat
|
||
|
```
|
||
|
|
||
|
Since each trampoline node has knowledge of its local balances that remote nodes don't have, they
|
||
|
are able to more efficiently decide how to split outgoing payments.
|
||
|
|
||
|
Moreover, this also fixes the multi-part payment path intersection we've discussed earlier.
|
||
|
Every trampoline node in the route (including the final recipient) is able to do some path
|
||
|
intersection analysis, but the only thing that they would learn is who the previous trampoline
|
||
|
node may be, which doesn't reveal who the actual payer is.
|
||
|
|
||
|
## Resources
|
||
|
|
||
|
* [SLP 319: Lightning Protocol Privacy Exploration](https://stephanlivera.com/episode/319/)
|
||
|
* [Offers specification](https://github.com/lightning/bolts/pull/798)
|
||
|
* [Route Blinding specification](https://github.com/lightning/bolts/pull/765)
|
||
|
* [Trampoline specification](https://github.com/lightning/bolts/pull/829)
|