|
| 1 | +# Route Blinding |
| 2 | + |
| 3 | +## Table of Contents |
| 4 | + |
| 5 | +* [Proposal](#proposal) |
| 6 | + * [Introduction](#introduction) |
| 7 | + * [Overview](#overview) |
| 8 | + * [Notations](#notations) |
| 9 | + * [Requirements](#requirements) |
| 10 | + * [Encrypted recipient data](#encrypted-recipient-data) |
| 11 | + * [Creating a blinded route](#creating-a-blinded-route) |
| 12 | + * [Sending to a blinded route](#sending-to-a-blinded-route) |
| 13 | + * [Receiving from a blinded route](#receiving-from-a-blinded-route) |
| 14 | + * [Sample flow](#sample-flow) |
| 15 | + * [Unblinding channels via fee probing](#unblinding-channels-via-fee-probing) |
| 16 | +* [Tips and Tricks](#tips-and-tricks) |
| 17 | + * [Recipient pays fees](#recipient-pays-fees) |
| 18 | + * [Dummy hops](#dummy-hops) |
| 19 | + * [Wallets and unannounced channels](#wallets-and-unannounced-channels) |
| 20 | + * [Blinded trampoline route](#blinded-trampoline-route) |
| 21 | +* [FAQ](#faq) |
| 22 | + * [Why not use rendezvous](#why-not-use-rendezvous) |
| 23 | + * [Why not use HORNET](#why-not-use-hornet) |
| 24 | + |
| 25 | +## Proposal |
| 26 | + |
| 27 | +### Introduction |
| 28 | + |
| 29 | +Route blinding is a lightweight technique to provide recipient anonymity by blinding an arbitrary |
| 30 | +amount of hops at the end of an onion path. It's more flexible than rendezvous because it lets |
| 31 | +senders arbitrarily update amounts and lock times, and reuse a blinded route multiple times (which |
| 32 | +is useful when retrying a failed route or using multi-part payments). |
| 33 | + |
| 34 | +The downside compared to rendezvous is that senders have more leeway to probe by changing various |
| 35 | +variables, so the scheme needs to explicitly defend against probing attacks and may be less private. |
| 36 | + |
| 37 | +Some use-cases where route blinding is useful include: |
| 38 | + |
| 39 | +* Recipient anonymity when receiving payments |
| 40 | +* Using unannounced channels in invoices without revealing them |
| 41 | +* Forcing a payment to go through a specific set of intermediaries that can witness the payment |
| 42 | +* Providing anonymous reply paths for onion messages (offers, stuckless payments, etc) |
| 43 | + |
| 44 | +### Overview |
| 45 | + |
| 46 | +At a high level, route blinding works by having the recipient choose an introduction point and a |
| 47 | +route to himself from that introduction point. The recipient then blinds each node and channel |
| 48 | +along that route with ECDH. The recipient includes the blinded route and a secret in the invoice, |
| 49 | +which allows each node in the blinded route to incrementally unblind the payloads. |
| 50 | + |
| 51 | +This scheme requires all the nodes in the blinded route and the sender to activate support for the |
| 52 | +feature. It only becomes effective once a big enough share of the network supports it. |
| 53 | + |
| 54 | +### Notations |
| 55 | + |
| 56 | +* A node `N(i)`'s `node_id` is defined as: `P(i) = k(i) * G`. |
| 57 | +* Blinded `node_id`s are defined as: `B(i) = b(i) * G`. |
| 58 | +* Ephemeral public keys are defined as: `E(i) = e(i) * G`. |
| 59 | + |
| 60 | +### Requirements |
| 61 | + |
| 62 | +A node `N(r)` wants to provide a blinded route `N(r) <- ... <- N(1) <- N(0)` that must be used |
| 63 | +to receive onion messages. |
| 64 | + |
| 65 | +* The channels used along that route may be either announced or unannounced. |
| 66 | +* When used for payments, intermediate nodes in the blinded route MUST NOT learn `payment_secret`. |
| 67 | +* Intermediate nodes in the blinded route MUST NOT learn the `node_id` or `scid` of other |
| 68 | + intermediate nodes except for their immediate predecessor or successor. |
| 69 | +* Intermediate nodes in the blinded route MUST NOT learn their distance to the recipient `N(r)`. |
| 70 | +* Senders MUST NOT learn the real `node_id`s and `scid`s of the blinded intermediate hops after the |
| 71 | + introduction point `N(0)`. |
| 72 | +* If `N(r)` creates multiple blinded routes to herself, senders MUST NOT be able to tell that these |
| 73 | + routes lead to the same recipient (unless this information is leaked by higher layers of the |
| 74 | + protocol, such as using the same `payment_hash`). |
| 75 | + |
| 76 | +### Encrypted recipient data |
| 77 | + |
| 78 | +Route blinding introduces a new TLV field to the onion `tlv_payload`: the `encrypted_recipient_data`. |
| 79 | + |
| 80 | +This field is used to carry data coming from the final recipient that cannot be modified by the |
| 81 | +sender. For route blinding it only needs to contain the `scid` to use when forwarding the message, |
| 82 | +but it may be extended with additional data in the future. It uses ChaCha20-Poly1305 as AEAD scheme. |
| 83 | + |
| 84 | +1. type: 10 (`encrypted_recipient_data`) |
| 85 | +2. data: |
| 86 | + * [`...*byte`:`encrypted_recipient_data`] |
| 87 | + |
| 88 | +Once decrypted, the content of this encrypted payload is a TLV stream that may contain any tlv |
| 89 | +record defined in Bolt 4 (onion TLV namespace). |
| 90 | + |
| 91 | +### Creating a blinded route |
| 92 | + |
| 93 | +`N(r)` performs the following steps to create a blinded route: |
| 94 | + |
| 95 | +```text |
| 96 | +Initialization: |
| 97 | +
|
| 98 | + e(0) <- {0;1}^256 |
| 99 | + E(0) = e(0) * G |
| 100 | +
|
| 101 | +Blinding: |
| 102 | +
|
| 103 | + For i = 0 to r-1: |
| 104 | + ss(i) = H(e(i) * P(i)) = H(k(i) * E(i)) // shared secret known only by N(r) and N(i) |
| 105 | + B(i) = HMAC256("blinded_node_id", ss(i)) * P(i) // Blinded node_id for N(i), private key known only by N(i) |
| 106 | + rho(i) = HMAC256("rho", ss(i)) // Key used to encrypt payload for N(i) by N(r) |
| 107 | + e(i+1) = H(E(i) || ss(i)) * e(i) // Ephemeral private key, only known by N(r) |
| 108 | + E(i+1) = H(E(i) || ss(i)) * E(i) // NB: N(i) must not learn e(i) |
| 109 | +
|
| 110 | +Blinded route: |
| 111 | + |
| 112 | + (P(0),fees(0),cltv(0),encrypted_recipient_data(0)) |
| 113 | + (B(1),fees(1),cltv(1),encrypted_recipient_data(1)) |
| 114 | + ... |
| 115 | + (B(r-1),fees(r-1),cltv(r-1),encrypted_recipient_data(r-1)) |
| 116 | +``` |
| 117 | + |
| 118 | +Note that this is exactly the same construction as Sphinx, but at each hop we use the shared secret |
| 119 | +to derive a blinded `node_id` for `N(i)` for which the private key will only be known by `N(i)`. |
| 120 | + |
| 121 | +The recipient needs to provide `E(0)` and the blinded route to potential senders. |
| 122 | +The `encrypted_recipient_data(i)` is encrypted with ChaCha20-Poly1305 using the `rho(i)` key, and |
| 123 | +contains the real `short_channel_id` to forward to (and potentially other fields). |
| 124 | +`E(i)` is included as additional authenticated data to detect probing attempts by the sender. |
| 125 | + |
| 126 | +Note that the introduction point uses the real `node_id`, not the blinded one, because the sender |
| 127 | +needs to be able to locate this introduction point and find a route to it. But the sender will send |
| 128 | +`E(0)`, which will allow the introduction point to compute the shared secret and correctly forward. |
| 129 | + |
| 130 | +Note that in the specific case of payments, the recipient can sign the invoice with `e(0)`. |
| 131 | +The sender will recover `E(0)` from the signature so no extra field needs to be added to Bolt 11. |
| 132 | +And this ensures the recipient doesn't reveal his real `node_id` through the invoice signature. |
| 133 | + |
| 134 | +However, if the recipient wants to be able to prove invoice ownership in the future, she should |
| 135 | +sign the invoice with a different key and provide `E(0)` via a dedicated Bolt 11 field. |
| 136 | + |
| 137 | +### Sending to a blinded route |
| 138 | + |
| 139 | +The sender finds a route to the introduction point `N(0)`, and extends it with the blinded route. |
| 140 | +It then creates an onion for that route, and includes `E(0)` and `encrypted_recipient_data(0)` in |
| 141 | +the onion payload for `N(0)`. |
| 142 | + |
| 143 | +When `N(0)` receives the onion and decrypts it, it finds `E(0)` in the payload and is able to |
| 144 | +compute the following: |
| 145 | + |
| 146 | +```text |
| 147 | + ss(0) = H(k(0) * E(0)) |
| 148 | + rho(0) = HMAC256("rho", ss(0)) |
| 149 | + E(1) = H(E(0) || ss(0)) * E(0) |
| 150 | +``` |
| 151 | + |
| 152 | +It uses `rho(0)` to decrypt the `encrypted_recipient_data(0)` and discover the `scid` to forward to. |
| 153 | +It forwards the onion to the next node and includes `E(1)` in a TLV field in the message extension. |
| 154 | + |
| 155 | +All the following intermediate nodes `N(i)` do the following steps: |
| 156 | + |
| 157 | +```text |
| 158 | + E(i) <- extracted from TLV extension |
| 159 | + ss(i) = H(k(i) * E(i)) |
| 160 | + b(i) = HMAC256("blinded_node_id", ss(i)) * k(i) |
| 161 | + Use b(i) to decrypt the incoming onion |
| 162 | + rho(i) = HMAC256("rho", ss(i)) |
| 163 | + Use rho(i) to decrypt the `encrypted_recipient_data` inside the onion and discover the next node |
| 164 | + E(i+1) = H(E(i) || ss(i)) * E(i) |
| 165 | + Forward the onion to the next node and include E(i+1) in a TLV field in the message extension |
| 166 | +``` |
| 167 | + |
| 168 | +### Receiving from a blinded route |
| 169 | + |
| 170 | +When `N(r)` receives the onion message and `E(r)` in the TLV extension, she does the same |
| 171 | +unwrapping as intermediate nodes. The difference is that the onion will be a final onion. |
| 172 | + |
| 173 | +### Sample flow |
| 174 | + |
| 175 | +Alice creates an invoice with the following blinded path: `Carol -> Bob -> Alice`. |
| 176 | +This invoice contains the following blinded path: |
| 177 | + |
| 178 | +```text |
| 179 | + (P(carol),fees(carol),cltv(carol),encrypted_recipient_data(carol)) |
| 180 | + (B(bob),fees(bob),cltv(bob),encrypted_recipient_data(bob)) |
| 181 | +``` |
| 182 | + |
| 183 | +Eve can reach Carol via Dave: `Eve -> Dave -> Carol`. |
| 184 | + |
| 185 | +```text |
| 186 | + Eve Dave Carol Bob Alice |
| 187 | + | | | | | |
| 188 | + | update_add_htlc | update_add_htlc | update_add_htlc | update_add_htlc | |
| 189 | + | +-------------------------------+ | +-------------------------------+ | +-------------------------------+ | +-------------------------------+ | |
| 190 | + | | amount: 10025 msat | | | amount: 10020 msat | | | amount: 10010 msat | | | amount: 10000 msat | | |
| 191 | + | | expiry: 125 | | | expiry: 120 | | | expiry: 110 | | | expiry: 100 | | |
| 192 | + | | onion_routing_packet: | | | onion_routing_packet: | | | onion_routing_packet: | | | onion_routing_packet: | | |
| 193 | + | | +---------------------------+ | | | +---------------------------+ | | | +---------------------------+ | | | +---------------------------+ | | |
| 194 | + | --> | | amount_fwd: 10020 msat | | --> | --> | | amount_fwd: 10010 msat | | --> | --> | | amount_fwd: 10000 msat | | --> | --> | | amount_fwd: 10000 msat | | --> | |
| 195 | + | | | expiry: 120 | | | | | expiry: 110 | | | | | expiry: 100 | | | | | expiry: 100 | | | |
| 196 | + | | | scid: scid_dc | | | | | encrd: encrypted(scid_cb) | | | | | encrd: encrypted(scid_ba) | | | | +---------------------------+ | | |
| 197 | + | | +---------------------------+ | | | | eph_key: E(carol) | | | | +---------------------------+ | | | tlv_extension | | |
| 198 | + | +-------------------------------+ | | +---------------------------+ | | | tlv_extension | | | +-------------------+ | | |
| 199 | + | | +-------------------------------+ | | +-------------------+ | | | | eph_key: E(alice) | | | |
| 200 | + | | | | | eph_key: E(bob) | | | | +-------------------+ | | |
| 201 | + | | | | +-------------------+ | | +-------------------------------+ | |
| 202 | + | | | +-------------------------------+ | | |
| 203 | +``` |
| 204 | + |
| 205 | +NB: the `encrypted_recipient_data` is annotated `encrd` for brevity. |
| 206 | + |
| 207 | +### Unblinding channels via fee probing |
| 208 | + |
| 209 | +The fees and cltv for the blinded route can be abused by the sender to try to unblind the real |
| 210 | +nodes and channels used. The sender can create onions with increased fees/cltv for the first |
| 211 | +blinded hop, starting with very low values. While the fee/cltv is below the real fee of the first |
| 212 | +hop, the sender will get an error from `N(0)`. Once the fee/cltv proposed actually satisfies the |
| 213 | +first hop's requirements, the error will come from another node `N(i)` inside the blinded path. |
| 214 | + |
| 215 | +The sender can then unblind channels one-by-one by discovering their real fees/cltv and matching |
| 216 | +those to existing channels in the graph. |
| 217 | + |
| 218 | +To mitigate this, when nodes along the blinded path are offered an invalid HTLC, they should: |
| 219 | + |
| 220 | +* return a dummy error encrypted with a throw-away key: the sender will receive an error she can't |
| 221 | + decrypt and doesn't know which node generated it |
| 222 | +* hold the HTLC for a random amount of time before sending the error (otherwise the sender can |
| 223 | + still use timing to guess which node errored out) |
| 224 | + |
| 225 | +Even with such mitigations the sender can discover the real fees/cltv of one of the blinded |
| 226 | +channels. To do so she uses the correct fees and cltv for all but one channel, and for that target |
| 227 | +channel she tries fees/cltv until the payment succeeds. Once the payment succeeds she knows the |
| 228 | +approximate fees/cltv of the target channel (but since the payment succeeded, she can't continue |
| 229 | +probing). |
| 230 | + |
| 231 | +Maybe nodes along the blinded path could use slightly different fees/cltv than what they publicly |
| 232 | +advertize? Or the recipient could add some fuzzing to it to blind them more? |
| 233 | + |
| 234 | +Are those mitigations enough? Or can a clever attacker still work around them? |
| 235 | + |
| 236 | +## Tips and Tricks |
| 237 | + |
| 238 | +### Recipient pays fees |
| 239 | + |
| 240 | +It may be unfair to make payers pay more fees to accomodate the recipient's wish for anonymity. |
| 241 | +It should instead be the recipient that pays the fees of the blinded hops (and the payer pays the |
| 242 | +fees to reach the introduction point). |
| 243 | + |
| 244 | +For example, if a merchant is selling an item for `N` satoshis, it should create an invoice for |
| 245 | +`N-f` satoshis, where `f` is the fee of the blinded part of the route. |
| 246 | + |
| 247 | +### Dummy hops |
| 248 | + |
| 249 | +The sender knows an upper bound on the distance between the recipient and `N(0)`. If the recipient |
| 250 | +is close to `N(0)`, this might not be ideal. In such cases, the recipient may add any number of |
| 251 | +dummy hops at the beginning of the blinded route by using `N(j) = N(r)`. The sender will not be |
| 252 | +able to distinguish those from normal blinded hops. |
| 253 | + |
| 254 | +Note that the recipient needs to fully validate each dummy hop to detect tampering. |
| 255 | + |
| 256 | +### Wallets and unannounced channels |
| 257 | + |
| 258 | +Route blinding is particularly useful for wallets that are connected to nodes via unannounced |
| 259 | +channels. Such wallets would use a single blinded hop, which effectively hides their `node_id` |
| 260 | +and `scid` from the sender. It obviously reveals to the blinded node that the next node is the |
| 261 | +final recipient, but a wallet that's not online all the time with a stable IP will never be able |
| 262 | +to hide that information from the nodes it connects to anyway (even with rendezvous). |
| 263 | + |
| 264 | +### Blinded trampoline route |
| 265 | + |
| 266 | +Route blinding can also be used with trampoline very easily. Instead of encrypting the |
| 267 | +`outgoing_channel_id`, we simply need to encrypt the `outgoing_node_id`. |
| 268 | + |
| 269 | +Each trampoline node can then decrypt the `node_id` of the next node and compute `E(i)` for the |
| 270 | +next trampoline node. That `E(i)` can then be sent in the outer onion payload instead of using the |
| 271 | +message's TLV extensions, which is even cleaner. |
| 272 | + |
| 273 | +## FAQ |
| 274 | + |
| 275 | +### Why not use rendezvous |
| 276 | + |
| 277 | +While rendezvous is more private, it's also less flexible: it doesn't support reusing the partial |
| 278 | +onion nor retrying with updated fees on intermediate node failure. Route blinding has different |
| 279 | +trade-offs, which makes it useful for slightly different use-cases than rendezvous. |
| 280 | + |
| 281 | +Route blinding lets senders choose the amounts and cltv sent through each blinded channel: it makes |
| 282 | +payment success more likely, but introduces a probing surface for attackers. |
| 283 | + |
| 284 | +### Why not use HORNET |
| 285 | + |
| 286 | +HORNET requires a slow session setup before it can provide useful speedups. In cases where you |
| 287 | +expect to send a single message per session (which is the case for most payments), HORNET actually |
| 288 | +performs worse than Sphinx in latency, bandwidth and privacy. |
| 289 | + |
| 290 | +## Open Questions |
| 291 | + |
| 292 | +* Should we include feature bits in `encrypted_recipient_data`? It's yet another probing vector so |
| 293 | + we'd need to "sanitize" them to avoid reducing the node's anonymity set... |
| 294 | +* Should we add the `payment_hash` to the additional data authenticated by `encrypted_recipient_data`? |
| 295 | +* Should we include cltv and feerates in the `encrypted_recipient_data`? And use uniform fees/cltv |
| 296 | + accross the blinded path to protect against attacks leveraging multiple blinded invoices? |
0 commit comments