From 966b9d319c115605ff7a81ed95873f6e542c080b Mon Sep 17 00:00:00 2001 From: t-bast Date: Thu, 31 Mar 2022 16:10:03 +0200 Subject: [PATCH 1/3] Route Blinding Route blinding allows a recipient to provide a blinded route to potential payers. Each node_id in the route is tweaked, and dummy hops may be included. This is an alternative to rendezvous to preserve recipient anonymity. It has a different set of trade-offs: onions are re-usable, but the privacy guarantees are a bit weaker and require more work (e.g. when handling payment fees and errors). --- proposals/route-blinding.md | 504 ++++++++++++++++++++++++++++++++++++ 1 file changed, 504 insertions(+) create mode 100644 proposals/route-blinding.md diff --git a/proposals/route-blinding.md b/proposals/route-blinding.md new file mode 100644 index 000000000..987bae0b1 --- /dev/null +++ b/proposals/route-blinding.md @@ -0,0 +1,504 @@ +# Route Blinding + +## Table of Contents + +* [Proposal](#proposal) + * [Introduction](#introduction) + * [Overview](#overview) + * [Notations](#notations) + * [Requirements](#requirements) + * [Encrypted data](#encrypted-data) + * [Creating a blinded route](#creating-a-blinded-route) + * [Sending to a blinded route](#sending-to-a-blinded-route) + * [Receiving from a blinded route](#receiving-from-a-blinded-route) + * [Blinded payments](#blinded-payments) +* [Attacks](#attacks) + * [Unblinding channels with payment probing](#unblinding-channels-with-payment-probing) + * [Unblinding nodes after restart](#unblinding-nodes-after-restart) +* [Tips and Tricks](#tips-and-tricks) + * [Recipient pays fees](#recipient-pays-fees) + * [Dummy hops](#dummy-hops) + * [Wallets and unannounced channels](#wallets-and-unannounced-channels) + * [Blinded trampoline route](#blinded-trampoline-route) +* [FAQ](#faq) + * [Why not use rendezvous](#why-not-use-rendezvous) + * [Why not use HORNET](#why-not-use-hornet) + +## Proposal + +### Introduction + +Route blinding is a lightweight technique to provide recipient anonymity by blinding an arbitrary +amount of hops at the end of an onion path. It's more flexible than rendezvous routing because it +simply replaces the public keys of the nodes in the route with random public keys while letting +senders choose what data they put in the onion for each hop. Blinded routes are also reusable in +some cases (e.g. onion messages). + +The downside compared to rendezvous is that senders have more leeway to probe by changing various +variables, so the scheme needs to explicitly defend against probing attacks and may provide less +privacy against some classes of attacks. + +Some use-cases where route blinding is useful include: + +* Sender and recipient anonymity for onion messages +* Recipient anonymity for Bolt 12 offers +* Recipient anonymity when receiving payments +* Using unannounced channels in invoices without revealing them +* Forcing a payment to go through a specific set of intermediaries that can witness the payment + +### Overview + +At a high level, route blinding works by having the recipient choose an _introduction point_ and a +route to itself from that introduction point. The recipient then blinds each node and channel along +that route with ECDH. The recipient sends details about the blinded route and some cryptographic +material to the sender (via a Bolt 11 invoice or Bolt 12 offer), which lets the sender build an +onion with enough information to allow nodes in the blinded route to incrementally unblind the next +node in the route. + +This scheme requires all the nodes in the blinded route and the sender to activate support for the +feature. It needs a big enough share of the network to support it to provide meaningful privacy +guarantees. + +### Notations + +* A node `N(i)`'s `node_id` is defined as: `N(i) = k(i) * G` (`k(i)` is the node's private key). +* Blinded `node_id`s are defined as: `B(i) = b(i) * G` (`b(i)` is the blinding factor). +* Sphinx ephemeral public keys are defined as: `E(i) = e(i) * G`. + +### Requirements + +A node `N(r)` wants to provide a blinded route `N(0) -> N(1) -> ... -> N(r)` that must be used +to receive onions. + +* Intermediate nodes in the blinded route MUST NOT learn the `node_id` or `scid` of other + intermediate nodes except for their immediate predecessor or successor. +* Intermediate nodes in the blinded route MUST NOT learn their distance to the recipient `N(r)`. +* Senders MUST NOT learn the real `node_id` and `scid` of the blinded intermediate hops after the + introduction point `N(0)`. +* If `N(r)` creates multiple blinded routes to itself, senders MUST NOT be able to tell that these + routes lead to the same recipient (unless of course this information is leaked by higher layers + of the protocol, such as using the same `payment_hash` or being generated for the same offer). + +### Encrypted data + +Route blinding introduces a new TLV field to the onion `tlv_payload`: the `encrypted_data`. + +This field is used to carry data coming from the builder of the route that cannot be modified by +the sender. It needs to contain enough data to let intermediate nodes locate the next node in the +route (usually a `node_id` or `scid`), and may be extended with additional data in the future. It +uses ChaCha20-Poly1305 as AEAD scheme. + +1. type: 10 (`encrypted_data`) +2. data: + * [`...*byte`:`encrypted_data`] + +Once decrypted, the content of this encrypted payload is a TLV stream. + +### Creating a blinded route + +`N(r)` performs the following steps to create a blinded route: + +```text +Initialization: + + e(0) <- {0;1}^256 + E(0) = e(0) * G + +Blinding: + + For i = 0 to r: + ss(i) = H(e(i) * N(i)) = H(k(i) * E(i)) // shared secret known only by N(r) and N(i) + B(i) = HMAC256("blinded_node_id", ss(i)) * N(i) // Blinded node_id for N(i), private key known only by N(i) + rho(i) = HMAC256("rho", ss(i)) // Key used to encrypt payload for N(i) by N(r) + e(i+1) = H(E(i) || ss(i)) * e(i) // Ephemeral private key, only known by N(r) + E(i+1) = H(E(i) || ss(i)) * E(i) // NB: N(i) must not learn e(i) +``` + +Note that this is exactly the same construction as Sphinx, but at each hop we use the shared secret +to derive a blinded `node_id` for `N(i)` for which the private key will only be known by `N(i)`. + +The recipient then creates `encrypted_data(i)` by encrypting application-specific data with +ChaCha20-Poly1305 using the `rho(i)` key. + +To use the blinded route, senders need the following data: + +* The real `node_id` of the introduction point `N(0)` (to locate the beginning of the route) +* The list of blinded `node_id`s: `[B(1),...,B(r)]` +* The encrypted data for each node: `[encrypted_data(0),...,encrypted_data(r)]` +* The first blinding ephemeral key: `E(0)` + +### Sending to a blinded route + +The sender finds a route to the introduction point `N(0)`, and extends it with the blinded route. +It then creates an onion for that whole route, and includes `E(0)` and `encrypted_data(0)` in the +onion payload for `N(0)`. It includes `encrypted_data(i)` in the onion payload for `B(i)`. + +When `N(0)` receives the onion and decrypts it, it finds `E(0)` in the payload and is able to +compute the following: + +```text + ss(0) = H(k(0) * E(0)) + rho(0) = HMAC256("rho", ss(0)) + E(1) = H(E(0) || ss(0)) * E(0) +``` + +It uses `rho(0)` to decrypt the `encrypted_data(0)` and discovers that `B(1)` is actually `N(1)`. +It forwards the onion to `N(1)` and includes `E(1)` in a TLV field in the lightning message +(e.g. in the extension field of an `update_add_htlc` message). + +All the following intermediate nodes `N(i)` do the following steps: + +```text + E(i) <- extracted from the lightning message's fields + ss(i) = H(k(i) * E(i)) + b(i) = HMAC256("blinded_node_id", ss(i)) * k(i) + Use b(i) instead of k(i) to decrypt the incoming onion using sphinx + rho(i) = HMAC256("rho", ss(i)) + Use rho(i) to decrypt the `encrypted_data` inside the onion and discover the next node + E(i+1) = H(E(i) || ss(i)) * E(i) + Forward the onion to the next node and include E(i+1) in a TLV field in the message +``` + +### Receiving from a blinded route + +When `N(r)` receives the onion message and `E(r)`, they do the same unwrapping as intermediate +nodes. The difference is that the onion will be a final onion. + +`N(r)` must also validate that the blinded route was used in the context it was created for, and is +a route that they created. It's important to note than anyone can create valid blinded routes to +anyone else. Alice for example is able to create a blinded route `Bob -> Carol -> Dave`. In most +cases, Dave wants to ignore messages that come through routes that were created by someone else. + +The details of this validation step depends on the actual application using route blinding. For +example, when using a blinded route for payments, the recipient must verify that the route was +used in conjunction with the right `payment_hash`. It can do so by storing the `payment_preimage` +in the `encrypted_data` payload to itself and verifying it when receiving the payment: malicious +senders don't know the preimage beforehand, so they won't be able to create a satisfying route. + +Without this validation step, the recipient exposes itself to malicious probing, which could let +attackers deanonymize the route. + +### Blinded payments + +This section provides more details on how route blinding can be used for payments. + +In order to protect against malicious probing (detailed in the [Attacks](#attacks) section), it is +the recipient who chooses what payment relay parameters will be used inside the route (e.g. fees) +and encodes them in the `encrypted_data` payload for each blinded node. The sender will not set the +`amt_to_forward` and `outgoing_cltv_value` fields in the onion payloads for blinded intermediate +nodes: these nodes will instead follow the instructions found in their `encrypted_data`. + +The `encrypted_data` for each intermediate node will contain the following fields: + +* `short_channel_id`: outgoing channel that should be used to route the payment +* `fee_base_msat`: base fee that must be applied before relaying the payment +* `fee_proportional_millionths`: proportional fee that must be applied before relaying the payment +* `cltv_expiry_delta`: cltv expiry delta that must be applied before relaying the payment +* `max_cltv_expiry`: maximum expiry allowed for this payment +* `htlc_minimum_msat`: minimum htlc amount that should be accepted +* `allowed_features`: features related to payment relay that the sender is allowed to use + +The recipient must use values that exceed the ones found in each `channel_udpate`, otherwise it +would be easy for a malicious sender to figure out which channels are hidden inside the blinded +route. + +The recipient also includes the `payment_preimage` (or another private unique identifier for the +payment) in the `path_id` field of the `encrypted_data` payload for itself: this will let the +recipient verify that the route is only used for that specific payment and was generated by them. + +If a node inside the blinded route receives a payment that doesn't use the parameters provided in +the `encrypted_data`, it must reject the payment and respond with an unparsable error onion. That +ensures the payer won't know which node failed and for what reason (otherwise that would provide +data that the payer could use to probe nodes inside the route). + +Note that we are also providing a `max_cltv_expiry` field: this ensures that the blinded route +expires after some time, restricting future probing attempts. + +If we assume that all nodes support `var_onion_option`, we don't need to include the +`allowed_features` field for now as there are no other features that affect payment relay and +could be used as a probing vector. However, future updates may add such features (e.g. PTLC +support), in which case the `allowed_features` field must not be empty. + +Let's go through an example to clarify those requirements. + +Alice creates an invoice with the following blinded route: `Carol -> Bob -> Alice`. +The channels along that route have the following settings: + +* `Carol -> Bob` + * `fee_base_msat`: 10 + * `fee_proportional_millionths`: 250 + * `cltv_expiry_delta`: 144 + * `htlc_minimum_msat`: 1 +* `Bob -> Alice` + * `fee_base_msat`: 50 + * `fee_proportional_millionths`: 100 + * `cltv_expiry_delta`: 48 + * `htlc_minimum_msat`: 1000 + +Alice chooses the following parameters for the blinded route, that satisfy the requirements of the +channels described above and adds a safety margin in case nodes update their relay parameters: + +* `fee_base_msat`: 100 +* `fee_proportional_millionths`: 500 +* `htlc_minimum_msat`: 1000 +* `cltv_expiry_delta`: 144 + +Alice uses the same values for both channels for simplicity's sake. Alice can now compute aggregate +values for the complete route (iteratively starting from the end of the route): + +* `route_fee_base_msat`: ceil(100 + 100 * (1 + 500/1000000)) = 201 +* `route_fee_proportional_millionths`: ceil((500/1000000) + (500/1000000) + (500/1000000)^2) = 1001 +* `route_cltv_expiry_delta`: 288 +* NB: we need to round values up, otherwise the recipient will receive slightly less than expected + +Let's assume the current block height is 1000. Alice wants the route to be used in the next 200 +blocks, so she sets `max_cltv_expiry = 1200` and adds `cltv_expiry_delta` for each hop. Alice then +transmits the following information to the sender (most likely via an invoice): + +* Blinded route: `[N(carol), B(bob), B(alice)]` +* First blinding ephemeral key: `E(carol)` +* Aggregated route relay parameters and constraints: + * `fee_base_msat`: 201 + * `fee_proportional_millionths`: 1001 + * `htlc_minimum_msat`: 1000 + * `cltv_expiry_delta`: 288 + * `max_cltv_expiry`: 1200 + * `allowed_features`: empty +* Encrypted data for blinded nodes: + * `encrypted_payload(alice)`: + * `path_id`: `payment_preimage` + * `max_cltv_expiry`: 1200 + * `encrypted_payload(bob)`: + * `outgoing_channel_id`: `scid_bob_alice` + * `fee_base_msat`: 100 + * `fee_proportional_millionths`: 500 + * `htlc_minimum_msat`: 1000 + * `max_cltv_expiry`: 1344 + * `encrypted_payload(carol)`: + * `outgoing_channel_id`: `scid_carol_bob` + * `fee_base_msat`: 100 + * `fee_proportional_millionths`: 500 + * `htlc_minimum_msat`: 1000 + * `max_cltv_expiry`: 1488 + +Note that the introduction point (Carol) uses the real `node_id`, not the blinded one, because the +sender needs to be able to locate this introduction point and find a route to it. The sender will +send the first blinding ephemeral key `E(carol)` in the onion `hop_payload` for Carol, which will +allow Carol to compute the blinding shared secret and correctly forward. We put this blinding +ephemeral key in the onion instead of using a tlv in `update_add_htlc` because intermediate nodes +added before the blinded route may not support route blinding and wouldn't know how to relay it. + +Eve wants to send 100 000 msat to this blinded route. +She can reach Carol via Dave: `Eve -> Dave -> Carol`, where the channel between Dave and Carol uses +the following relay parameters: + +* `fee_base_msat`: 10 +* `fee_proportional_millionths`: 100 +* `cltv_expiry_delta`: 24 + +Eve uses the aggregated route relay parameters to compute how much should be sent to Carol: + +* `amount = ceil(100000 + 201 + 1001 * 100000 / 1000000) = 100302 msat` + +Eve chooses a final expiry of 1100, which is below Alice's `max_cltv_expiry`, and computes the +expiry that should be sent to Carol: + +* `expiry = 1100 + 288 = 1388` + +When a node in the blinded route receives an htlc, the onion will not contain the `amt_to_forward` +or `outgoing_cltv_value`. They will have to compute them based on the fields contained in their +`encrypted_data` (`fee_base_msat`, `fee_proportional_millionths` and `cltv_expiry_delta`). + +For example, here is how Carol will compute the values for the htlc she relays to Bob: + +* `amount = ceil((100302 - fee_base_msat) / (1 + fee_proportional_millionths)) = 100152 msat` +* `expiry = 1388 - cltv_expiry_delta = 1244` + +And here is how Bob computes the values for the htlc he relays to Alice: + +* `amount = ceil((100152 - fee_base_msat) / (1 + fee_proportional_millionths)) = 100002 msat` +* `expiry = 1244 - cltv_expiry_delta = 1100` + +Note that as the rounding errors aggregate, the recipient will receive slightly more than what was +expected. The sender includes `amt_to_forward` in the onion payload for the recipient to let them +verify that the received amount is (slightly) greater than what the sender intended to send (which +protects against intermediate nodes that would try to relay a lower amount). + +The messages exchanged will contain the following values: + +```text + Eve Dave Carol Bob Alice + | update_add_htlc | update_add_htlc | update_add_htlc | update_add_htlc | + | +--------------------------------+ | +------------------------------------------+ | +------------------------------------------+ | +--------------------------------+ | + | | amount: 100322 msat | | | amount: 100302 msat | | | amount: 100152 msat | | | amount: 100002 msat | | + | | expiry: 1412 | | | expiry: 1388 | | | expiry: 1244 | | | expiry: 1100 | | + | | onion_routing_packet: | | | onion_routing_packet: | | | onion_routing_packet: | | | onion_routing_packet: | | + | | +----------------------------+ | | | +--------------------------------------+ | | | +--------------------------------------+ | | | +----------------------------+ | | + | --> | | amount_fwd: 100302 msat | | --> | --> | | blinding_eph_key: E(carol) | | --> | --> | | encrypted_data: | | --> | --> | | amount_fwd: 100000 msat | | --> | + | | | outgoing_expiry: 1388 | | | | | encrypted_data: | | | | | +----------------------------------+ | | | | | outgoing_expiry: 1100 | | | + | | | scid: scid_dave_to_carol | | | | | +----------------------------------+ | | | | | | scid: scid_bob_to_alice | | | | | | encrypted_data: | | | + | | +----------------------------+ | | | | | scid: scid_carol_to_bob | | | | | | | fee_base_msat: 100 | | | | | | +-----------------------+ | | | + | | | blinding_eph_key: E(carol) | | | | | | fee_base_msat: 100 | | | | | | | fee_proportional_millionths: 500 | | | | | | | path_id: preimage | | | | + | | | encrypted_data(carol) | | | | | | fee_proportional_millionths: 500 | | | | | | | htlc_minimum_msat: 1000 | | | | | | | max_cltv_expiry: 1200 | | | | + | | +----------------------------+ | | | | | htlc_minimum_msat: 1000 | | | | | | | cltv_expiry_delta: 144 | | | | | | +-----------------------+ | | | + | | | encrypted_data(bob) | | | | | | cltv_expiry_delta: 144 | | | | | | | max_cltv_expiry: 1344 | | | | | +----------------------------+ | | + | | +----------------------------+ | | | | | max_cltv_expiry: 1488 | | | | | | +----------------------------------+ | | | | tlv_extension | | + | | | amount_fwd: 100000 msat | | | | | +----------------------------------+ | | | | +--------------------------------------+ | | | +----------------------------+ | | + | | | outgoing_expiry: 1100 | | | | +--------------------------------------+ | | | | amount_fwd: 100000 msat | | | | | blinding_eph_key: E(alice) | | | + | | | encrypted_data(alice) | | | | | encrypted_data(bob) | | | | | outgoing_expiry: 1100 | | | | +----------------------------+ | | + | | +----------------------------+ | | | +--------------------------------------+ | | | | encrypted_data(alice) | | | +--------------------------------+ | + | +--------------------------------+ | | | amount_fwd: 100000 msat | | | | +--------------------------------------+ | | | + | | | | outgoing_expiry: 1100 | | | | tlv_extension | | | + | | | | encrypted_data(alice) | | | | +--------------------------------------+ | | | + | | | +--------------------------------------+ | | | | blinding_eph_key: E(bob) | | | | + | | +------------------------------------------+ | | +--------------------------------------+ | | | + | | | +------------------------------------------+ | | + | | | | | +``` + +Note that all onion payloads are described in each `update_add_htlc` for clarity, but only the +first one can be decrypted by the intermediate node that receives the message (standard Bolt 4 +onion encryption). + +## Attacks + +### Unblinding channels with payment probing + +Recipients must be careful when using route blinding for payments to avoid letting attackers +guess which nodes are hidden inside of the route. Let's walk through an attack to understand +why. + +Let's assume that our routing graph looks like this: + +```text + +-------+ +-------+ + | X | | X | + +-------+ +-------+ + | | + | | ++-------+ +-------+ +-------+ +-------+ +| X |------| Carol |------| Bob |------| Alice | ++-------+ +-------+ +-------+ +-------+ + | | + | | + +-------+ +-------+ + | X | | X | + +-------+ +-------+ +``` + +Alice creates a blinded route `Carol -> Bob -> Alice`. +Alice has chosen what fee settings will be used inside the blinded route. +Let's assume she has chosen `fee_base_msat = 10` and `fee_proportional_millionths = 100`. + +The attacker knows that the recipient is at most two hops away from Carol. Instead of making the +payment, the attacker watches for new `channel_update`s for every channel in a two-hops radius +around Carol. At some point, the attacker sees a `channel_update` for the channel `Bob -> Alice` +that sets `fee_proportional_millionths = 150`, which exceeds what Alice has chosen for the blinded +route. The attacker then tries to make the payment. + +When Bob receives the payment, the fees are below its current settings, so it should reject it. +The attacker would then receive a failure, and be able to infer that it's very likely that Alice +is the final recipient. + +If the attackers are able to frequently request invoices from the recipient (e.g. from a Bolt 12 +offer), they don't even have to attempt the payment to detect this. They can simply periodically +request invoices from the recipient and detect when the recipient raises the fees or cltv of the +blinded route, and match that with recent `channel_update`s that they received. + +Similarly, feature bits that apply to payment relaying behavior can be used to fingerprint nodes +inside the blinded route: this is why `allowed_features` are committed inside the `encrypted_data`. + +If nodes across the network use different values for `htlc_minimum_msat`, it can also be used to +fingerprint nodes: that's why it is also committed inside the `encrypted_data`. + +This type of attack is the reason why all parameters that affect payment relaying behavior (fees, +cltv, features, etc) are chosen by the recipient. The recipient should add a large enough margin +to the current values actually used by nodes inside the route to protect against future raises. +This is also why blinded routes used for payments have a `max_cltv_expiry` set by the recipient, +even though that doesn't fully address the issue if the attackers are able to frequently request +new blinded routes. + +Altruistic relaying nodes inside a blinded route could choose to relay payments with fees below +their current settings, which would break this heuristic: however their economic incentive is to +reject them, so we cannot rely on them to protect recipient privacy. + +Similarly, we mandate relaying nodes to only accept payments using exactly the fees provided in +the `encrypted_data` payload. Otherwise, when observing a `channel_update` that raises a specific +channel's fees, the attackers could try to use these new fees in a payment attempt: if the payment +goes through, they would have even more confidence about the channel used in the blinded route. +The incentives for relaying nodes aren't great, because we're asking them to reject payments that +give them the right amount of fees to protect recipient privacy. + +### Unblinding nodes after restart + +The attacks described in the previous section only applied to scenarios that use route blinding +for payments. However, a variation of the same technique can be used for any scenario relying on +route blinding to relay messages. + +If attackers suspect that a given node `N` may be part of a blinded route, they can wait for that +node to go offline, and try using the blinded route while the node is offline. If the blinded +route fails, it's likely that this node was indeed part of the blinded route. By repeating this +sampling regularly, attackers can increase the confidence in their unblinding. + +To address this, recipients should choose nodes with high uptime for their blinded routes and +periodically refresh them. + +## Tips and Tricks + +### Recipient pays fees + +It may be unfair to make payers pay more fees to accomodate the recipient's wish for anonymity. +It should instead be the recipient that pays the fees of the blinded hops (and the payer pays the +fees to reach the introduction point). + +If a merchant is selling an item for `N` satoshis, it should create an invoice for `N-f` satoshis, +where `f` is the fee of the blinded part of the route. + +### Dummy hops + +The sender knows an upper bound on the distance between the recipient and `N(0)`. If the recipient +is close to `N(0)`, this might not be ideal. In such cases, the recipient may add any number of +dummy hops at the end of the blinded route by using `N(j) = N(r)`. The sender will not be able to +distinguish those from normal blinded hops. + +NB: + +* the recipient needs to fully validate each dummy hop's onion payload to detect tampering (and + must ensure that these hops have been used and not truncated) +* the recipient must use padding to ensure all `encrypted_data` payloads have the same length, + otherwise the payer will be able to guess which hop is actually the recipient + +### Wallets and unannounced channels + +Route blinding is particularly useful for wallets that are connected to nodes via unannounced +channels. Such wallets could use a single blinded hop, which effectively hides their `node_id` +and `scid` from the sender. It obviously reveals to the blinded node that the next node is the +final recipient, but a wallet that's not online all the time with a stable IP will never be able +to hide that information from the nodes it connects to anyway (even with rendezvous). + +### Blinded trampoline route + +Route blinding can also be used with trampoline very easily. Instead of providing the +`outgoing_channel_id` in `encrypted_data`, we simply need to provide the `outgoing_node_id`. + +Each trampoline node can then decrypt the `node_id` of the next node and compute `E(i)` for the +next trampoline node. That `E(i)` can then be sent in the outer onion payload instead of using the +lightning message's fields, which is even cleaner and doesn't require nodes between trampoline +nodes to understand route blinding. + +## FAQ + +### Why not use rendezvous + +While rendezvous is more private, it's also less flexible: senders cannot add data to the partial +onion nor reuse it. When used for payments, the amount must be fixed ahead of time in the partial +onion, which doesn't combine well with multi-part payments or temporary liquidity issues. + +Route blinding lets senders choose most of the data they put in the onion payloads, which makes +it much more flexible, at the expense of introducing more probing surface for attackers. + +### Why not use HORNET + +HORNET requires a slow session setup before it can provide useful speedups. In cases where you +expect to send a single message per session (which is the case for payments and onion messages), +HORNET actually performs worse than Sphinx in latency, bandwidth and privacy. From a1584179a7fba0b47bcc69d6f547ab4f50e86c91 Mon Sep 17 00:00:00 2001 From: t-bast Date: Thu, 31 Mar 2022 17:03:56 +0200 Subject: [PATCH 2/3] Bolt 4: add route blinding construction Add specification requirements for creating and using blinded routes. This commit contains the low-level details of the route blinding scheme, decoupled from how it can be used by high-level components such as onion messages or payments. --- 04-onion-routing.md | 148 ++++++++++++++++++++++++++++++++ bolt04/route-blinding-test.json | 139 ++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 bolt04/route-blinding-test.json diff --git a/04-onion-routing.md b/04-onion-routing.md index b2242e052..4642d8178 100644 --- a/04-onion-routing.md +++ b/04-onion-routing.md @@ -50,6 +50,7 @@ A node: * [Packet Structure](#packet-structure) * [Payload Format](#payload-format) * [Basic Multi-Part Payments](#basic-multi-part-payments) + * [Route Blinding](#route-blinding) * [Accepting and Forwarding a Payment](#accepting-and-forwarding-a-payment) * [Payload for the Last Node](#payload-for-the-last-node) * [Non-strict Forwarding](#non-strict-forwarding) @@ -352,6 +353,153 @@ otherwise meets the amount criterion (eg. some other failure, or invoice timeout), however if it were to fulfill only some of them, intermediary nodes could simply claim the remaining ones. +### Route Blinding + +Nodes receiving onion packets may hide their identity from senders by +"blinding" an arbitrary amount of hops at the end of an onion path. + +When using route blinding, nodes find a route to themselves from a given +"introduction node". They then use ECDH with each node in that route to create +a "blinded" node ID and an encrypted blob (`encrypted_data`) for each one of +the blinded nodes. + +They communicate this blinded route and the encrypted blobs to the sender. +The sender finds a route to the introduction node and extends it with the +blinded route provided by the recipient. The sender includes the encrypted +blobs in the corresponding onion payloads: they allow nodes in the blinded +part of the route to "unblind" the next node and correctly forward the packet. + +The `encrypted_data` is a TLV stream, encrypted for a given blinded node, that +may contain the following TLV fields: + +1. `tlv_stream`: `encrypted_data_tlv` +2. types: + 1. type: 1 (`padding`) + 2. data: + * [`...*byte`:`padding`] + 1. type: 2 (`short_channel_id`) + 2. data: + * [`short_channel_id`:`short_channel_id`] + 1. type: 4 (`next_node_id`) + 2. data: + * [`point`:`node_id`] + 1. type: 6 (`path_id`) + 2. data: + * [`...*byte`:`data`] + 1. type: 8 (`next_blinding_override`) + 2. data: + * [`point`:`blinding`] + +#### Requirements + +A recipient N(r) creating a blinded route `N(0) -> N(1) -> ... -> N(r)` to itself: + +- MUST create a blinded node ID `B(i)` for each node using the following algorithm: + - `e(0) <- {0;1}^256` + - `E(0) = e(0) * G` + - For every node in the route: + - let `N(i) = k(i) * G` be the `node_id` (`k(i)` is `N(i)`'s private key) + - `ss(i) = SHA256(e(i) * N(i)) = SHA256(k(i) * E(i))` (ECDH shared secret known only by `N(r)` and `N(i)`) + - `B(i) = HMAC256("blinded_node_id", ss(i)) * N(i)` (blinded `node_id` for `N(i)`, private key known only by `N(i)`) + - `rho(i) = HMAC256("rho", ss(i))` (key used to encrypt the payload for `N(i)` by `N(r)`) + - `e(i+1) = SHA256(E(i) || ss(i)) * e(i)` (blinding ephemeral private key, only known by `N(r)`) + - `E(i+1) = SHA256(E(i) || ss(i)) * E(i)` (NB: `N(i)` MUST NOT learn `e(i)`) +- If it creates `encrypted_data` payloads for blinded nodes: + - MUST encrypt them with ChaCha20-Poly1305 using the `rho(i)` key and an all-zero nonce + - MAY store private data in the `path_id` of the payload to itself to verify + that the route is used in the right context and was created by them + - SHOULD add padding data to ensure all `encrypted_data` have the same length +- MUST communicate the blinded node IDs `B(i)` and `encrypted_data(i)` to the sender +- MUST communicate the real node ID of the introduction point `N(0)` to the sender +- MUST communicate the first blinding ephemeral key `E(0)` to the sender + +The sender: + +- MUST provide the `encrypted_data` field for each node in the blinded route + in their respective onion payloads +- MUST communicate `E(0)` to the introduction point (e.g. in the onion payload + for that node or in a tlv field of the lightning message) + +The introduction point: + +- MUST compute: + - `ss(0) = SHA256(k(0) * E(0))` (standard ECDH) + - `rho(0) = HMAC256("rho", ss(0))` + - `E(1) = SHA256(E(0) || ss(0)) * E(0)` +- If an `encrypted_data` field is provided: + - MUST decrypt it using `rho(0)` + - MUST use the decrypted fields to locate the next node +- If `encrypted_data` contains a `next_blinding_override`: + - MUST use it as the next blinding point instead of `E(1)` +- Otherwise: + - MUST use `E(1)` as the next blinding point +- MUST forward the onion and include the next blinding point in the lightning + message for the next node + +An intermediate node in the blinded route: + +- MUST compute: + - `ss(i) = SHA256(k(i) * E(i))` (standard ECDH) + - `b(i) = HMAC256("blinded_node_id", ss(i)) * k(i)` + - `rho(i) = HMAC256("rho", ss(i))` + - `E(i+1) = SHA256(E(i) || ss(i)) * E(i)` +- MUST use `b(i)` instead of its private key `k(i)` to decrypt the onion. Note + that the node may instead tweak the onion ephemeral key with + `HMAC256("blinded_node_id", ss(i))` which achieves the same result. +- If an `encrypted_data` field is provided: + - MUST decrypt it using `rho(i)` + - MUST use the decrypted fields to locate the next node +- If `encrypted_data` contains a `next_blinding_override`: + - MUST use it as the next blinding point instead of `E(i+1)` +- Otherwise: + - MUST use `E(i+1)` as the next blinding point +- MUST forward the onion and include the next blinding point in the lightning + message for the next node + +The final recipient: + +- MUST compute: + - `ss(r) = SHA256(k(r) * E(r))` (standard ECDH) + - `b(r) = HMAC256("blinded_node_id", ss(r)) * k(r)` + - `rho(r) = HMAC256("rho", ss(r))` +- If an `encrypted_data` field is provided: + - MUST decrypt it using `rho(r)` +- MUST ignore the message if the `path_id` does not match the blinded route it + created + +#### Rationale + +Route blinding is a lightweight technique to provide recipient anonymity. +It's more flexible than rendezvous routing because it simply replaces the public +keys of the nodes in the route with random public keys while letting senders +choose what data they put in the onion for each hop. Blinded routes are also +reusable in some cases (e.g. onion messages). + +Each node in the blinded route needs to receive `E(i)` to be able to decrypt +the onion and the `encrypted_data` payload. Protocols that use route blinding +must specify how this value is propagated between nodes. + +When concatenating two blinded routes generated by different nodes, the +last node of the first route needs to know the first `blinding_point` of the +second route: the `next_blinding_override` field must be used to transmit this +information. + +The final recipient must verify that the blinded route is used in the right +context (e.g. for a specific payment) and was created by them. Otherwise a +malicious sender could create different blinded routes to all the nodes that +they suspect could be the real recipient and try them until one accepts the +message. The recipient can protect against that by storing `E(r)` and the +context (e.g. a `payment_hash`), and verifying that they match when receiving +the onion. Otherwise, to avoid additional storage cost, it can put some private +context information in the `path_id` field (e.g. the `payment_preimage`) and +verify that when receiving the onion. Note that it's important to use private +information in that case, that senders cannot have access to. + +The `padding` field can be used to ensure that all `encrypted_data` have the +same length. It's particularly useful when adding dummy hops at the end of a +blinded route, to prevent the sender from figuring out which node is the final +recipient. + # Accepting and Forwarding a Payment Once a node has decoded the payload it either accepts the payment locally, or forwards it to the peer indicated as the next hop in the payload. diff --git a/bolt04/route-blinding-test.json b/bolt04/route-blinding-test.json new file mode 100644 index 000000000..0be3d7faa --- /dev/null +++ b/bolt04/route-blinding-test.json @@ -0,0 +1,139 @@ +{ + "comment": "test vector for using blinded routes", + "generate": { + "comment": "This section contains test data for creating a blinded route. This route is the concatenation of two blinded routes: one from Dave to Eve and one from Bob to Carol.", + "hops": [ + { + "comment": "Bob creates a Bob -> Carol route with the following session_key and concatenates it with the Dave -> Eve route.", + "session_key": "0202020202020202020202020202020202020202020202020202020202020202", + "alias": "Bob", + "node_id": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c", + "tlvs": { + "padding": "00000000000000000000000000000000", + "short_channel_id": "0x0x42", + "next_node_id": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007", + "unknown_tag_65001": "123456" + }, + "encoded_tlvs": "0110000000000000000000000000000000000208000000000000002a0421027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007fdfde903123456", + "ephemeral_privkey": "0202020202020202020202020202020202020202020202020202020202020202", + "ephemeral_pubkey": "024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "shared_secret": "76771bab0cc3d0de6e6f60147fd7c9c7249a5ced3d0612bdfaeec3b15452229d", + "rho": "ba217b23c0978d84c4a19be8a9ff64bc1b40ed0d7ecf59521567a5b3a9a1dd48", + "encrypted_data": "cd4b00ff9c09ed28102b210ac73aa12d63e90a5acebc496c49f57c639e098acbaec5b5ffb8592b07bdb6665ccb56f1258ab1857383f6542c8371dcee568a0a35a218288814849db13ce6f84a464fa517d9e1684333e3", + "blinded_node_id": "03da173ad2aee2f701f17e59fbd16cb708906d69838a5f088e8123fb36e89a2c25" + }, + { + "comment": "Notice the next_blinding_override tlv in Carol's payload, indicating that Bob concatenated his route with another blinded route starting at Dave.", + "alias": "Carol", + "node_id": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007", + "tlvs": { + "next_node_id": "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991", + "next_blinding_override": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f" + }, + "encoded_tlvs": "0421032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910821031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "ephemeral_privkey": "0a2aa791ac81265c139237b2b84564f6000b1d4d0e68d4b9cc97c5536c9b61c1", + "ephemeral_pubkey": "034e09f450a80c3d252b258aba0a61215bf60dda3b0dc78ffb0736ea1259dfd8a0", + "shared_secret": "dc91516ec6b530a3d641c01f29b36ed4dc29a74e063258278c0eeed50313d9b8", + "rho": "d1e62bae1a8e169da08e6204997b60b1a7971e0f246814c648125c35660f5416", + "encrypted_data": "ca26157e44ab01e82becf86497e1d05ad3e70903d22721210af41d791bf406873024d95b7a1ad128b2526932febfeeab237000563c1f33c78530b3880f8407326eef8bc004932b22323d13343ef740019c08e538e5c5", + "blinded_node_id": "02e466727716f044290abf91a14a6d90e87487da160c2a3cbd0d465d7a78eb83a7" + }, + { + "comment": "Eve creates a Dave -> Eve blinded route using the following session_key.", + "session_key": "0101010101010101010101010101010101010101010101010101010101010101", + "alias": "Dave", + "node_id": "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991", + "tlvs": { + "padding": "0000000000000000000000000000000000000000000000", + "short_channel_id": "0x0x561", + "next_node_id": "02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145" + }, + "encoded_tlvs": "0117000000000000000000000000000000000000000000000002080000000000000231042102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145", + "ephemeral_privkey": "0101010101010101010101010101010101010101010101010101010101010101", + "ephemeral_pubkey": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "shared_secret": "dc46f3d1d99a536300f17bc0512376cc24b9502c5d30144674bfaa4b923d9057", + "rho": "393aa55d35c9e207a8f28180b81628a31dff558c84959cdc73130f8c321d6a06", + "encrypted_data": "0f94a72cff3b64a3d6e1e4903cf8c8b0a17144aeb249dcb86563a5ee1f679ee8db3c6719bd4364f469aa5fea76ffdc49543d568a707ab73a3e855b25ca585bf12c9d5c9cb6c5c10374a4a66d95aeeea4fe146d0c2754", + "blinded_node_id": "036861b366f284f0a11738ffbf7eda46241a8977592878fe3175ae1d1e4754eccf" + }, + { + "comment": "Eve is the final recipient, so she included a path_id in her own payload to verify that the route is used when she expects it.", + "alias": "Eve", + "node_id": "02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145", + "tlvs": { + "padding": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "path_id": "00112233445566778899aabbccddeeff", + "unknown_tag_65535": "06c1" + }, + "encoded_tlvs": "012c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061000112233445566778899aabbccddeefffdffff0206c1", + "ephemeral_privkey": "62e8bcd6b5f7affe29bec4f0515aab2eebd1ce848f4746a9638aa14e3024fb1b", + "ephemeral_pubkey": "03e09038ee76e50f444b19abf0a555e8697e035f62937168b80adf0931b31ce52a", + "shared_secret": "352a706b194c2b6d0a04ba1f617383fb816dc5f8f9ac0b60dd19c9ae3b517289", + "rho": "719d0307340b1c68b79865111f0de6e97b093a30bc603cebd1beb9eef116f2d8", + "encrypted_data": "da2c7e5f7881219884beae6ae68971de73bab4c3055d9865b1afb60722a63a7e4ea796de84fc9af674952e900ff518ed6b3640a7e47b5f3e4fbce5fab87e47a11d84c66d1234f1cec1da2f56b72b64896509aef9b754", + "blinded_node_id": "021982a48086cb8984427d3727fe35a03d396b234f0701f5249daa12e8105c8dae" + } + ] + }, + "route": { + "comment": "This section contains the resulting blinded route, which can then be used inside onion messages or payments.", + "introduction_node_id": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c", + "blinding": "024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "hops": [ + { + "blinded_node_id": "03da173ad2aee2f701f17e59fbd16cb708906d69838a5f088e8123fb36e89a2c25", + "encrypted_data": "cd4b00ff9c09ed28102b210ac73aa12d63e90a5acebc496c49f57c639e098acbaec5b5ffb8592b07bdb6665ccb56f1258ab1857383f6542c8371dcee568a0a35a218288814849db13ce6f84a464fa517d9e1684333e3" + }, + { + "blinded_node_id": "02e466727716f044290abf91a14a6d90e87487da160c2a3cbd0d465d7a78eb83a7", + "encrypted_data": "ca26157e44ab01e82becf86497e1d05ad3e70903d22721210af41d791bf406873024d95b7a1ad128b2526932febfeeab237000563c1f33c78530b3880f8407326eef8bc004932b22323d13343ef740019c08e538e5c5" + }, + { + "blinded_node_id": "036861b366f284f0a11738ffbf7eda46241a8977592878fe3175ae1d1e4754eccf", + "encrypted_data": "0f94a72cff3b64a3d6e1e4903cf8c8b0a17144aeb249dcb86563a5ee1f679ee8db3c6719bd4364f469aa5fea76ffdc49543d568a707ab73a3e855b25ca585bf12c9d5c9cb6c5c10374a4a66d95aeeea4fe146d0c2754" + }, + { + "blinded_node_id": "021982a48086cb8984427d3727fe35a03d396b234f0701f5249daa12e8105c8dae", + "encrypted_data": "da2c7e5f7881219884beae6ae68971de73bab4c3055d9865b1afb60722a63a7e4ea796de84fc9af674952e900ff518ed6b3640a7e47b5f3e4fbce5fab87e47a11d84c66d1234f1cec1da2f56b72b64896509aef9b754" + } + ] + }, + "unblind": { + "comment": "This section contains test data for unblinding the route at each intermediate hop.", + "hops": [ + { + "alias": "Bob", + "node_privkey": "4242424242424242424242424242424242424242424242424242424242424242", + "ephemeral_pubkey": "024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "blinded_privkey": "d12fec0332c3e9d224789a17ebd93595f37d37bd8ef8bd3d2e6ce50acb9e554f", + "decrypted_data": "0110000000000000000000000000000000000208000000000000002a0421027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007fdfde903123456", + "next_ephemeral_pubkey": "034e09f450a80c3d252b258aba0a61215bf60dda3b0dc78ffb0736ea1259dfd8a0" + }, + { + "alias": "Carol", + "node_privkey": "4343434343434343434343434343434343434343434343434343434343434343", + "ephemeral_pubkey": "034e09f450a80c3d252b258aba0a61215bf60dda3b0dc78ffb0736ea1259dfd8a0", + "blinded_privkey": "bfa697fbbc8bbc43ca076e6dd60d306038a32af216b9dc6fc4e59e5ae28823c1", + "decrypted_data": "0421032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910821031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "next_ephemeral_pubkey": "03af5ccc91851cb294e3a364ce63347709a08cdffa58c672e9a5c587ddd1bbca60", + "next_ephemeral_pubkey_override": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f" + }, + { + "alias": "Dave", + "node_privkey": "4444444444444444444444444444444444444444444444444444444444444444", + "ephemeral_pubkey": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "blinded_privkey": "cebc115c7fce4c295dc396dea6c79115b289b8ceeceea2ed61cf31428d88fc4e", + "decrypted_data": "0117000000000000000000000000000000000000000000000002080000000000000231042102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145", + "next_ephemeral_pubkey": "03e09038ee76e50f444b19abf0a555e8697e035f62937168b80adf0931b31ce52a" + }, + { + "alias": "Eve", + "node_privkey": "4545454545454545454545454545454545454545454545454545454545454545", + "ephemeral_pubkey": "03e09038ee76e50f444b19abf0a555e8697e035f62937168b80adf0931b31ce52a", + "blinded_privkey": "ff4e07da8d92838bedd019ce532eb990ed73b574e54a67862a1df81b40c0d2af", + "decrypted_data": "012c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061000112233445566778899aabbccddeefffdffff0206c1", + "next_ephemeral_pubkey": "038fc6859a402b96ce4998c537c823d6ab94d1598fca02c788ba5dd79fbae83589" + } + ] + } +} \ No newline at end of file From 3b814f0d031450a9cddd2718be7ed50c5444095b Mon Sep 17 00:00:00 2001 From: t-bast Date: Mon, 11 Apr 2022 18:37:01 +0200 Subject: [PATCH 3/3] Bolt 4: add blinded payments Add specification requirements for using route blinding to make payments while preserving recipient anonymity. Implementers must ensure they understand all those requirements, there are subtle attacks that could let malicious senders deanonymize the route if incompletely implemented. --- .aspell.en.pws | 2 + 02-peer-protocol.md | 24 +++ 04-onion-routing.md | 253 ++++++++++++++++++------- 09-features.md | 44 +++-- bolt04/blinded-payment-onion-test.json | 183 ++++++++++++++++++ bolt04/route-blinding-test.json | 92 ++++++--- proposals/route-blinding.md | 140 ++++++++++++-- 7 files changed, 608 insertions(+), 130 deletions(-) create mode 100644 bolt04/blinded-payment-onion-test.json diff --git a/.aspell.en.pws b/.aspell.en.pws index f1a1d35e1..c527a657d 100644 --- a/.aspell.en.pws +++ b/.aspell.en.pws @@ -391,3 +391,5 @@ griefing unspendable pkh kB +unblind +unblinded \ No newline at end of file diff --git a/02-peer-protocol.md b/02-peer-protocol.md index 8a5751c01..f43c68611 100644 --- a/02-peer-protocol.md +++ b/02-peer-protocol.md @@ -990,6 +990,12 @@ is destined, is described in [BOLT #4](04-onion-routing.md). * [`u32`:`cltv_expiry`] * [`1366*byte`:`onion_routing_packet`] +1. `tlv_stream`: `update_add_htlc_tlvs` +2. types: + 1. type: 0 (`blinding_point`) + 2. data: + * [`point`:`blinding`] + #### Requirements A sending node: @@ -1025,6 +1031,8 @@ A sending node: - for the first HTLC it offers: - MUST set `id` to 0. - MUST increase the value of `id` by 1 for each successive offer. + - if it is relaying a payment inside a blinded route: + - MUST set `blinding_point` (see [Route Blinding](04-onion-routing.md#route-blinding)) `id` MUST NOT be reset to 0 after the update is complete (i.e. after `revoke_and_ack` has been received). It MUST continue incrementing instead. @@ -1049,6 +1057,8 @@ A receiving node: - if other `id` violations occur: - MAY send a `warning` and close the connection, or send an `error` and fail the channel. + - if `blinding_point` is provided: + - MUST use the corresponding blinded private key to decrypt the `onion_routing_packet` (see [Route Blinding](04-onion-routing.md#route-blinding)) The `onion_routing_packet` contains an obfuscated list of hops and instructions for each hop along the path. It commits to the HTLC by setting the `payment_hash` as associated data, i.e. includes the `payment_hash` in the computation of HMACs. @@ -1131,6 +1141,17 @@ A node: commitment transactions: - MUST NOT send an `update_fulfill_htlc`, `update_fail_htlc`, or `update_fail_malformed_htlc`. + - When failing an incoming HTLC: + - If `current_blinding_point` is set in the onion payload and it is not the + final node: + - MUST send an `update_fail_htlc` error using the + `invalid_onion_blinding` failure code with the `sha256_of_onion` + of the onion it received, for any local or downstream errors. + - SHOULD add a random delay before sending `update_fail_htlc`. + - If `blinding_point` is set in the incoming `update_add_htlc`: + - MUST send an `update_fail_malformed_htlc` error using the + `invalid_onion_blinding` failure code with the `sha256_of_onion` + of the onion it received, for any local or downstream errors. A receiving node: - if the `id` does not correspond to an HTLC in its current commitment transaction: @@ -1170,6 +1191,9 @@ errors. However, without re-checking the actual encrypted packet sent, it won't know whether the error was its own or the remote's; so such detection is left as an option. +Nodes inside a blinded route must use `invalid_onion_blinding` to avoid +leaking information to senders trying to probe the blinded route. + ### Committing Updates So Far: `commitment_signed` When a node has changes for the remote commitment, it can apply them, diff --git a/04-onion-routing.md b/04-onion-routing.md index 4642d8178..ed8cf2f3e 100644 --- a/04-onion-routing.md +++ b/04-onion-routing.md @@ -199,9 +199,18 @@ This is formatted according to the Type-Length-Value format defined in [BOLT #1] 2. data: * [`32*byte`:`payment_secret`] * [`tu64`:`total_msat`] + 1. type: 10 (`encrypted_recipient_data`) + 2. data: + * [`...*byte`:`encrypted_data`] + 1. type: 12 (`current_blinding_point`) + 2. data: + * [`point`:`blinding`] 1. type: 16 (`payment_metadata`) 2. data: * [`...*byte`:`payment_metadata`] + 1. type: 18 (`total_amount_msat`) + 2. data: + * [`tu64`:`total_msat`] `short_channel_id` is the ID of the outgoing channel used to route the message; the receiving peer should operate the other end of this channel. @@ -230,39 +239,97 @@ leaking its position in the route. ### Requirements -The writer: - - For every node: +The creator of `encrypted_recipient_data` (usually, the recipient of payment): + + - MUST create `encrypted_data_tlv` for each node in the blinded route (including itself). + - MUST include `encrypted_data_tlv.short_channel_id` and `encrypted_data_tlv.payment_relay` for each non-final node. + - MUST set `encrypted_data_tlv.payment_constraints` for each non-final node: + - `max_cltv_expiry` to the largest block height at which the route is allowed to be used, starting + from the final node and adding `encrypted_data_tlv.payment_relay.cltv_expiry_delta` at each hop. + - `htlc_minimum_msat` to the largest minimum HTLC value the nodes will allow. + - If it sets `encrypted_data_tlv.allowed_features`: + - MUST set it to an empty array. + - MUST compute the total fees and cltv delta of the route as follows and communicate them to the sender: + - `total_fee_base_msat(n+1) = (fee_base_msat(n+1) * 1000000 + total_fee_base_msat(n) * (1000000 + fee_proportional_millionths(n+1)) + 1000000 - 1) / 1000000` + - `total_fee_proportional_millionths(n+1) = ((total_fee_proportional_millionths(n) + fee_proportional_millionths(n+1)) * 1000000 + total_fee_proportional_millionths(n) * fee_proportional_millionths(n+1) + 1000000 - 1) / 1000000` + - MUST create the `encrypted_recipient_data` from the `encrypted_data_tlv` as required in [Route Blinding](#route-blinding). + +The writer of `tlv_payload`: + + - For every node inside a blinded route: + - MUST include the `encrypted_recipient_data` provided by the recipient + - For the first node in the blinded route: + - MUST include the `blinding_point` provided by the recipient in `current_blinding_point` + - If it is the final node: + - MUST include `amt_to_forward`, `outgoing_cltv_value` and `total_amount_msat`. + - MUST NOT include any other tlv field. + - For every node outside of a blinded route: - MUST include `amt_to_forward` and `outgoing_cltv_value`. - - For every non-final node: - - MUST include `short_channel_id` - - MUST NOT include `payment_data` - - For the final node: - - MUST NOT include `short_channel_id` - - if the recipient provided `payment_secret`: - - MUST include `payment_data` - - MUST set `payment_secret` to the one provided - - MUST set `total_msat` to the total amount it will send - - if the recipient provided `payment_metadata`: - - MUST include `payment_metadata` with every HTLC - - MUST not apply any limits to the size of payment_metadata except the limits implied by the fixed onion size + - For every non-final node: + - MUST include `short_channel_id` + - MUST NOT include `payment_data` + - For the final node: + - MUST NOT include `short_channel_id` + - if the recipient provided `payment_secret`: + - MUST include `payment_data` + - MUST set `payment_secret` to the one provided + - MUST set `total_msat` to the total amount it will send + - if the recipient provided `payment_metadata`: + - MUST include `payment_metadata` with every HTLC + - MUST not apply any limits to the size of `payment_metadata` except the limits implied by the fixed onion size The reader: - - MUST return an error if `amt_to_forward` or `outgoing_cltv_value` are not present. - - if it is not the final node: + + - If `encrypted_recipient_data` is present: + - If `blinding_point` is set in the incoming `update_add_htlc`: + - MUST return an error if `current_blinding_point` is present. + - MUST use that `blinding_point` as the blinding point for decryption. + - Otherwise: + - MUST return an error if `current_blinding_point` is not present. + - MUST use that `current_blinding_point` as the blinding point for decryption. + - SHOULD add a random delay before returning errors. + - MUST return an error if `encrypted_recipient_data` does not decrypt using the + blinding point as described in [Route Blinding](#route-blinding). + - If `payment_constraints` is present: + - MUST return an error if: + - the expiry is greater than `encrypted_recipient_data.payment_constraints.max_cltv_expiry`. + - the amount is below `encrypted_recipient_data.payment_constraints.htlc_minimum_msat`. + - If `allowed_features` is missing: + - MUST process the message as if it were present and contained an empty array. - MUST return an error if: - - `short_channel_id` is not present, - - it cannot forward the HTLC to the peer indicated by the channel `short_channel_id`. - - incoming `amount_msat` - `fee` < `amt_to_forward` (where `fee` is the advertised fee as described in [BOLT #7](07-routing-gossip.md#htlc-fees)) - - `cltv_expiry` - `cltv_expiry_delta` < `outgoing_cltv_value` - - if it is the final node: - - MUST treat `total_msat` as if it were equal to `amt_to_forward` if it - is not present. + - `encrypted_recipient_data.allowed_features.features` contains an unknown feature bit (even if it is odd). + - the payment uses a feature not included in `encrypted_recipient_data.allowed_features.features`. + - If it is not the final node: + - MUST return an error if the payload contains other tlv fields than `encrypted_recipient_data` and `current_blinding_point`. + - MUST return an error if `encrypted_recipient_data` does not contain either `short_channel_id` or `next_node_id`. + - MUST return an error if `encrypted_recipient_data` does not contain `payment_relay`. + - MUST use values from `encrypted_recipient_data.payment_relay` to calculate `amt_to_forward` and `outgoing_cltv_value` as follows: + - `amt_to_forward = ((amount_msat - fee_base_msat) * 1000000 + 1000000 + fee_proportional_millionths - 1) / (1000000 + fee_proportional_millionths)` + - `outgoing_cltv_value = cltv_expiry - payment_relay.cltv_expiry_delta` + - If it is the final node: + - MUST return an error if the payload contains other tlv fields than `encrypted_recipient_data`, `current_blinding_point`, `amt_to_forward`, `outgoing_cltv_value` and `total_amount_msat`. + - MUST return an error if `amt_to_forward`, `outgoing_cltv_value` or `total_amount_msat` are not present. + - MUST return an error if `amt_to_forward` is below what it expects for the payment. + - MUST return an error if incoming `cltv_expiry` < `outgoing_cltv_value`. + - MUST return an error if incoming `cltv_expiry` < `current_block_height` + `min_final_cltv_expiry_delta`. + - Otherwise (it is not part of a blinded route): + - MUST return an error if `blinding_point` is set in the incoming `update_add_htlc` or `current_blinding_point` is present. + - MUST return an error if `amt_to_forward` or `outgoing_cltv_value` are not present. + - if it is not the final node: + - MUST return an error if: + - `short_channel_id` is not present, + - it cannot forward the HTLC to the peer indicated by the channel `short_channel_id`. + - incoming `amount_msat` - `fee` < `amt_to_forward` (where `fee` is the advertised fee as described in [BOLT #7](07-routing-gossip.md#htlc-fees)) + - `cltv_expiry` - `cltv_expiry_delta` < `outgoing_cltv_value` + - If it is the final node: + - MUST treat `total_msat` as if it were equal to `amt_to_forward` if it is not present. - MUST return an error if: - incoming `amount_msat` < `amt_to_forward`. - incoming `cltv_expiry` < `outgoing_cltv_value`. - incoming `cltv_expiry` < `current_block_height` + `min_final_cltv_expiry_delta`. -Additional requirements are specified [below](#basic-multi-part-payments). +Additional requirements are specified [here](#basic-multi-part-payments) for +multi-part payments, and [here](#route-blinding) for blinded payments. ### Basic Multi-Part Payments @@ -276,6 +343,10 @@ ultimate sender that the rest of the payment will follow in succeeding HTLCs; we call these outstanding HTLCs which have the same preimage, an "HTLC set". +Note that there are two distinct tlv fields that can be used to transmit +`total_msat`. The last one, `total_amount_msat`, was introduced with +blinded paths for which the `payment_secret` doesn't make sense. + `payment_metadata` is to be included in every payment part, so that invalid payment details can be detected as early as possible. @@ -359,9 +430,9 @@ Nodes receiving onion packets may hide their identity from senders by "blinding" an arbitrary amount of hops at the end of an onion path. When using route blinding, nodes find a route to themselves from a given -"introduction node". They then use ECDH with each node in that route to create -a "blinded" node ID and an encrypted blob (`encrypted_data`) for each one of -the blinded nodes. +"introduction node" and initial "blinding point". They then use ECDH with +each node in that route to create a "blinded" node ID and an encrypted blob +(`encrypted_data`) for each one of the blinded nodes. They communicate this blinded route and the encrypted blobs to the sender. The sender finds a route to the introduction node and extends it with the @@ -369,6 +440,15 @@ blinded route provided by the recipient. The sender includes the encrypted blobs in the corresponding onion payloads: they allow nodes in the blinded part of the route to "unblind" the next node and correctly forward the packet. +Note that there are two ways for the sender to reach the introduction +point: one is to create a normal (unblinded) payment, and place the +initial blinding point in `current_blinding_point` along with the +`encrypted_data` in the onion payload for the introduction point to +start the blinded path. The second way is to create a blinded path to +the introduction point, set `next_blinding_override` inside the +`encrypted_data_tlv` on the hop prior to the introduction point to the +initial blinding point, and have it sent to the introduction node. + The `encrypted_data` is a TLV stream, encrypted for a given blinded node, that may contain the following TLV fields: @@ -389,6 +469,18 @@ may contain the following TLV fields: 1. type: 8 (`next_blinding_override`) 2. data: * [`point`:`blinding`] + 1. type: 10 (`payment_relay`) + 2. data: + * [`u16`:`cltv_expiry_delta`] + * [`u32`:`fee_proportional_millionths`] + * [`tu32`:`fee_base_msat`] + 1. type: 12 (`payment_constraints`) + 2. data: + * [`u32`:`max_cltv_expiry`] + * [`tu64`:`htlc_minimum_msat`] + 1. type: 14 (`allowed_features`) + 2. data: + * [`...*byte`:`features`] #### Requirements @@ -404,51 +496,32 @@ A recipient N(r) creating a blinded route `N(0) -> N(1) -> ... -> N(r)` to itsel - `rho(i) = HMAC256("rho", ss(i))` (key used to encrypt the payload for `N(i)` by `N(r)`) - `e(i+1) = SHA256(E(i) || ss(i)) * e(i)` (blinding ephemeral private key, only known by `N(r)`) - `E(i+1) = SHA256(E(i) || ss(i)) * E(i)` (NB: `N(i)` MUST NOT learn `e(i)`) -- If it creates `encrypted_data` payloads for blinded nodes: - - MUST encrypt them with ChaCha20-Poly1305 using the `rho(i)` key and an all-zero nonce - - MAY store private data in the `path_id` of the payload to itself to verify - that the route is used in the right context and was created by them - - SHOULD add padding data to ensure all `encrypted_data` have the same length -- MUST communicate the blinded node IDs `B(i)` and `encrypted_data(i)` to the sender +- MAY replace `E(i+1)` with a different value, but if it does: + - MUST set `encrypted_data_tlv(i).next_blinding_override` to `E(i+1)` +- MAY store private data in `encrypted_data_tlv(r).path_id` to verify that the route is used in the right context and was created by them +- SHOULD add padding data to ensure all `encrypted_data_tlv(i)` have the same length +- MUST encrypt each `encrypted_data_tlv(i)` with ChaCha20-Poly1305 using the corresponding `rho(i)` key and an all-zero nonce to produce `encrypted_recipient_data(i)` +- MUST communicate the blinded node IDs `B(i)` and `encrypted_recipient_data(i)` to the sender - MUST communicate the real node ID of the introduction point `N(0)` to the sender - MUST communicate the first blinding ephemeral key `E(0)` to the sender -The sender: +A reader: -- MUST provide the `encrypted_data` field for each node in the blinded route - in their respective onion payloads -- MUST communicate `E(0)` to the introduction point (e.g. in the onion payload - for that node or in a tlv field of the lightning message) - -The introduction point: - -- MUST compute: - - `ss(0) = SHA256(k(0) * E(0))` (standard ECDH) - - `rho(0) = HMAC256("rho", ss(0))` - - `E(1) = SHA256(E(0) || ss(0)) * E(0)` -- If an `encrypted_data` field is provided: - - MUST decrypt it using `rho(0)` - - MUST use the decrypted fields to locate the next node -- If `encrypted_data` contains a `next_blinding_override`: - - MUST use it as the next blinding point instead of `E(1)` +- If it receives `blinding_point` (`E(i)`) from the prior peer: + - MUST use `b(i)` instead of its private key `k(i)` to decrypt the onion. + Note that the node may instead tweak the onion ephemeral key with + `HMAC256("blinded_node_id", ss(i))` which achieves the same result. - Otherwise: - - MUST use `E(1)` as the next blinding point -- MUST forward the onion and include the next blinding point in the lightning - message for the next node - -An intermediate node in the blinded route: - + - MUST use `k(i)` to decrypt the onion, to extract `current_blinding_point` (`E(i)`). - MUST compute: - `ss(i) = SHA256(k(i) * E(i))` (standard ECDH) - `b(i) = HMAC256("blinded_node_id", ss(i)) * k(i)` - `rho(i) = HMAC256("rho", ss(i))` - `E(i+1) = SHA256(E(i) || ss(i)) * E(i)` -- MUST use `b(i)` instead of its private key `k(i)` to decrypt the onion. Note - that the node may instead tweak the onion ephemeral key with - `HMAC256("blinded_node_id", ss(i))` which achieves the same result. -- If an `encrypted_data` field is provided: - - MUST decrypt it using `rho(i)` - - MUST use the decrypted fields to locate the next node +- MUST decrypt the `encrypted_data` field using `rho(i)` and use the + decrypted fields to locate the next node +- If the `encrypted_data` field is missing or cannot be decrypted: + - MUST return an error - If `encrypted_data` contains a `next_blinding_override`: - MUST use it as the next blinding point instead of `E(i+1)` - Otherwise: @@ -462,8 +535,9 @@ The final recipient: - `ss(r) = SHA256(k(r) * E(r))` (standard ECDH) - `b(r) = HMAC256("blinded_node_id", ss(r)) * k(r)` - `rho(r) = HMAC256("rho", ss(r))` -- If an `encrypted_data` field is provided: - - MUST decrypt it using `rho(r)` +- MUST decrypt the `encrypted_data` field using `rho(r)` +- If the `encrypted_data` field is missing or cannot be decrypted: + - MUST return an error - MUST ignore the message if the `path_id` does not match the blinded route it created @@ -495,11 +569,25 @@ context information in the `path_id` field (e.g. the `payment_preimage`) and verify that when receiving the onion. Note that it's important to use private information in that case, that senders cannot have access to. +Whenever the introduction point receives a failure from the blinded route, it +should add a random delay before forwarding the error. Failures are likely to +be probing attempts and message timing may help the attacker infer its distance +to the final recipient. + The `padding` field can be used to ensure that all `encrypted_data` have the same length. It's particularly useful when adding dummy hops at the end of a blinded route, to prevent the sender from figuring out which node is the final recipient. +When route blinding is used for payments, the recipient specifies the fees and +expiry that blinded nodes should apply to the payment instead of letting the +sender configure them. The recipient also adds additional constraints to the +payments that can go through that route to protect against probing attacks that +would let malicious nodes unblind the identity of the blinded nodes. It should +set `payment_constraints.max_cltv_expiry` to restrict the lifetime of a blinded +route and reduce the risk that an intermediate node updates its fees and rejects +payments (which could be used to unblind nodes inside the route). + # Accepting and Forwarding a Payment Once a node has decoded the payload it either accepts the payment locally, or forwards it to the peer indicated as the next hop in the payload. @@ -944,6 +1032,12 @@ The association between the forward and return packets is handled outside of this onion routing protocol, e.g. via association with an HTLC in a payment channel. +Error handling for HTLCs with `blinding_point` is particularly fraught, +since differences in implementations (or versions) may be leveraged to +de-anonymize elements of the blinded path. Thus the decision turn every +error into `invalid_onion_blinding` which will be converted to a normal +onion error by the introduction point. + ### Requirements The _erring node_: @@ -1155,15 +1249,27 @@ the decrypted byte stream. The complete amount of the multi-part payment was not received within a reasonable time. +1. type: BADONION|PERM|24 (`invalid_onion_blinding`) +2. data: + * [`sha256`:`sha256_of_onion`] + +An error occurred within the blinded path. + ### Requirements An _erring node_: - - MUST select one of the above error codes when creating an error message. - - MUST include the appropriate data for that particular error type. - - if there is more than one error: - - SHOULD select the first error it encounters from the list above. + - if `blinding_point` is set in the incoming `update_add_htlc`: + - MUST return an `invalid_onion_blinding` error. + - if `current_blinding_point` is set in the onion payload and it is not the + final node: + - MUST return an `invalid_onion_blinding` error. + - otherwise: + - MUST select one of the above error codes when creating an error message. + - MUST include the appropriate data for that particular error type. + - if there is more than one error: + - SHOULD select the first error it encounters from the list above. -Any _erring node_ MAY: +An _erring node_ MAY: - if the `realm` byte is unknown: - return an `invalid_realm` error. - if the per-hop payload in the onion is invalid (e.g. it is not a valid tlv stream) @@ -1177,6 +1283,15 @@ Any _erring node_ MAY: which were NOT included in the onion: - return a `required_node_feature_missing` error. +A _forwarding node_ MUST: + - if `blinding_point` is set in the incoming `update_add_htlc`: + - return an `invalid_onion_blinding` error. + - if `current_blinding_point` is set in the onion payload and it is not the + final node: + - return an `invalid_onion_blinding` error. + - otherwise: + - select one of the above error codes when creating an error message. + A _forwarding node_ MAY, but a _final node_ MUST NOT: - if the onion `version` byte is unknown: - return an `invalid_onion_version` error. diff --git a/09-features.md b/09-features.md index 21fdf09a9..ba0a0c5bf 100644 --- a/09-features.md +++ b/09-features.md @@ -19,32 +19,35 @@ for use of the channel, so the presentation of those features depends on the feature itself. The Context column decodes as follows: + * `I`: presented in the `init` message. * `N`: presented in the `node_announcement` messages * `C`: presented in the `channel_announcement` message. * `C-`: presented in the `channel_announcement` message, but always odd (optional). * `C+`: presented in the `channel_announcement` message, but always even (required). * `9`: presented in [BOLT 11](11-payment-encoding.md) invoices. - -| Bits | Name | Description | Context | Dependencies | Link | -|-------|----------------------------------|-----------------------------------------------------------|----------|-------------------|---------------------------------------| -| 0/1 | `option_data_loss_protect` | Requires or supports extra `channel_reestablish` fields | IN | | [BOLT #2][bolt02-retransmit] | -| 3 | `initial_routing_sync` | Sending node needs a complete routing information dump | I | | [BOLT #7][bolt07-sync] | -| 4/5 | `option_upfront_shutdown_script` | Commits to a shutdown scriptpubkey when opening channel | IN | | [BOLT #2][bolt02-open] | -| 6/7 | `gossip_queries` | More sophisticated gossip control | IN | | [BOLT #7][bolt07-query] | -| 8/9 | `var_onion_optin` | Requires/supports variable-length routing onion payloads | IN9 | | [Routing Onion Specification][bolt04] | -| 10/11 | `gossip_queries_ex` | Gossip queries can include additional information | IN | `gossip_queries` | [BOLT #7][bolt07-query] | -| 12/13 | `option_static_remotekey` | Static key for remote output | IN | | [BOLT #3](03-transactions.md) | -| 14/15 | `payment_secret` | Node supports `payment_secret` field | IN9 | `var_onion_optin` | [Routing Onion Specification][bolt04] | -| 16/17 | `basic_mpp` | Node can receive basic multi-part payments | IN9 | `payment_secret` | [BOLT #4][bolt04-mpp] | -| 18/19 | `option_support_large_channel` | Can create large channels | IN | | [BOLT #2](02-peer-protocol.md#the-open_channel-message) | -| 20/21 | `option_anchor_outputs` | Anchor outputs | IN | `option_static_remotekey` | [BOLT #3](03-transactions.md) | -| 22/23 | `option_anchors_zero_fee_htlc_tx` | Anchor commitment type with zero fee HTLC transactions | IN | `option_static_remotekey` | [BOLT #3][bolt03-htlc-tx], [lightning-dev][ml-sighash-single-harmful]| -| 26/27 | `option_shutdown_anysegwit` | Future segwit versions allowed in `shutdown` | IN | | [BOLT #2][bolt02-shutdown] | -| 44/45 | `option_channel_type` | Node supports the `channel_type` field in open/accept | IN | | [BOLT #2](02-peer-protocol.md#the-open_channel-message) | -| 46/47 | `option_scid_alias` | Supply channel aliases for routing | IN | | [BOLT #2][bolt02-channel-ready] | -| 48/49 | `option_payment_metadata` | Payment metadata in tlv record | 9 | | [BOLT #11](11-payment-encoding.md#tagged-fields) -| 50/51 | `option_zeroconf` | Understands zeroconf channel types | IN | `option_scid_alias` | [BOLT #2][bolt02-channel-ready] | +* `B`: presented in the `allowed_features` field of a blinded path. + +| Bits | Name | Description | Context | Dependencies | Link | +|-------|-----------------------------------|-----------------------------------------------------------|----------|---------------------------|-----------------------------------------------------------------------| +| 0/1 | `option_data_loss_protect` | Requires or supports extra `channel_reestablish` fields | IN | | [BOLT #2][bolt02-retransmit] | +| 3 | `initial_routing_sync` | Sending node needs a complete routing information dump | I | | [BOLT #7][bolt07-sync] | +| 4/5 | `option_upfront_shutdown_script` | Commits to a shutdown scriptpubkey when opening channel | IN | | [BOLT #2][bolt02-open] | +| 6/7 | `gossip_queries` | More sophisticated gossip control | IN | | [BOLT #7][bolt07-query] | +| 8/9 | `var_onion_optin` | Requires/supports variable-length routing onion payloads | IN9 | | [Routing Onion Specification][bolt04] | +| 10/11 | `gossip_queries_ex` | Gossip queries can include additional information | IN | `gossip_queries` | [BOLT #7][bolt07-query] | +| 12/13 | `option_static_remotekey` | Static key for remote output | IN | | [BOLT #3](03-transactions.md) | +| 14/15 | `payment_secret` | Node supports `payment_secret` field | IN9 | `var_onion_optin` | [Routing Onion Specification][bolt04] | +| 16/17 | `basic_mpp` | Node can receive basic multi-part payments | IN9 | `payment_secret` | [BOLT #4][bolt04-mpp] | +| 18/19 | `option_support_large_channel` | Can create large channels | IN | | [BOLT #2](02-peer-protocol.md#the-open_channel-message) | +| 20/21 | `option_anchor_outputs` | Anchor outputs | IN | `option_static_remotekey` | [BOLT #3](03-transactions.md) | +| 22/23 | `option_anchors_zero_fee_htlc_tx` | Anchor commitment type with zero fee HTLC transactions | IN | `option_static_remotekey` | [BOLT #3][bolt03-htlc-tx], [lightning-dev][ml-sighash-single-harmful] | +| 24/25 | `option_route_blinding` | Node supports blinded paths | IN9 | `var_onion_optin` | [BOLT #4](bolt04-route-blinding) | +| 26/27 | `option_shutdown_anysegwit` | Future segwit versions allowed in `shutdown` | IN | | [BOLT #2][bolt02-shutdown] | +| 44/45 | `option_channel_type` | Node supports the `channel_type` field in open/accept | IN | | [BOLT #2](02-peer-protocol.md#the-open_channel-message) | +| 46/47 | `option_scid_alias` | Supply channel aliases for routing | IN | | [BOLT #2][bolt02-channel-ready] | +| 48/49 | `option_payment_metadata` | Payment metadata in tlv record | 9 | | [BOLT #11](11-payment-encoding.md#tagged-fields) | +| 50/51 | `option_zeroconf` | Understands zeroconf channel types | IN | `option_scid_alias` | [BOLT #2][bolt02-channel-ready] | ## Definitions @@ -100,4 +103,5 @@ This work is licensed under a [Creative Commons Attribution 4.0 International Li [bolt07-sync]: 07-routing-gossip.md#initial-sync [bolt07-query]: 07-routing-gossip.md#query-messages [bolt04-mpp]: 04-onion-routing.md#basic-multi-part-payments +[bolt04-route-blinding]: 04-onion-routing.md#route-blinding [ml-sighash-single-harmful]: https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-September/002796.html diff --git a/bolt04/blinded-payment-onion-test.json b/bolt04/blinded-payment-onion-test.json new file mode 100644 index 000000000..97406fb1f --- /dev/null +++ b/bolt04/blinded-payment-onion-test.json @@ -0,0 +1,183 @@ +{ + "comment": "test vector for a payment onion sent to a partially blinded route", + "generate": { + "comment": "This section contains test data for creating a payment onion that sends to the provided blinded route.", + "session_key": "0303030303030303030303030303030303030303030303030303030303030303", + "associated_data": "4242424242424242424242424242424242424242424242424242424242424242", + "final_amount_msat": 100000, + "final_cltv": 749000, + "blinded_payinfo": { + "comment": "total costs for using the blinded path", + "fee_base_msat": 10100, + "fee_proportional_millionths": 251, + "cltv_expiry_delta": 150 + }, + "blinded_route": { + "comment": "This section contains a blinded route that the sender will use for his payment, usually obtained from a Bolt 12 invoice.", + "introduction_node_id": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c", + "blinding": "024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "hops": [ + { + "alias": "Bob", + "blinded_node_id": "03da173ad2aee2f701f17e59fbd16cb708906d69838a5f088e8123fb36e89a2c25", + "encrypted_data": "cd7b00ff9c09ed28102b210ac73aa12d63e90852cebc496c49f57c499a2888b49f2e72b19446f7e60a818aa2938d8c625415b992b8928a7321edb8f7cea40de362bed082ad51acc6156dca5532fb68" + }, + { + "alias": "Carol", + "blinded_node_id": "02e466727716f044290abf91a14a6d90e87487da160c2a3cbd0d465d7a78eb83a7", + "encrypted_data": "cc0f16524fd7f8bb0f4e8d40ad71709ef140174c76faa574cac401bb8992fef76c4d004aa485dd599ed1cf2715f570f656a5aaecaf1ee8dc9d0fa1d424759be1932a8f29fac08bc2d2a1ed7159f28b" + }, + { + "alias": "Dave", + "blinded_node_id": "036861b366f284f0a11738ffbf7eda46241a8977592878fe3175ae1d1e4754eccf", + "encrypted_data": "0fa1a72cff3b64a3d6e1e4903cf8c8b0a17144aeb249dcb86561adee1f679ee8db3e561d9e49895fd4bcebf6f58d6f61a6d41a9bf5aa4b0453437856632e8255c351873143ddf2bb2b0832b091e1b4" + }, + { + "alias": "Eve", + "blinded_node_id": "021982a48086cb8984427d3727fe35a03d396b234f0701f5249daa12e8105c8dae", + "encrypted_data": "da1c7e5f7881219884beae6ae68971de73bab4c3055d9865b1afb60722a63c688768042ade22f2c22f5724767d171fd221d3e579e43b354cc72e3ef146ada91a892d95fc48662f5b158add0af457da" + } + ] + }, + "full_route": { + "comment": "The sender adds one normal hop through Alice, who doesn't support blinded payments (and doesn't charge a fee). The sender provides the initial blinding point in Bob's onion payload, and encrypted_data for each node in the blinded route.", + "hops": [ + { + "alias": "Alice", + "pubkey": "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619", + "payload": "14020301ae2d04030b6e5e0608000000000000000a", + "tlvs": { + "outgoing_channel_id": "0x0x10", + "amt_to_forward": 110125, + "outgoing_cltv_value": 749150 + } + }, + { + "alias": "Bob", + "pubkey": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c", + "payload": "740a4fcd7b00ff9c09ed28102b210ac73aa12d63e90852cebc496c49f57c499a2888b49f2e72b19446f7e60a818aa2938d8c625415b992b8928a7321edb8f7cea40de362bed082ad51acc6156dca5532fb680c21024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "tlvs": { + "current_blinding_point": "024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", + "encrypted_recipient_data": { + "padding": "0000000000000000000000000000000000000000000000000000000000000000", + "short_channel_id": "0x0x1", + "payment_relay": { + "cltv_expiry_delta": 50, + "fee_proportional_millionths": 0, + "fee_base_msat": 10000 + }, + "payment_constraints": { + "max_cltv_expiry": 750150, + "htlc_minimum_msat": 50 + }, + "allowed_features": { + "features": [] + } + } + } + }, + { + "alias": "Carol", + "pubkey": "02e466727716f044290abf91a14a6d90e87487da160c2a3cbd0d465d7a78eb83a7", + "payload": "510a4fcc0f16524fd7f8bb0f4e8d40ad71709ef140174c76faa574cac401bb8992fef76c4d004aa485dd599ed1cf2715f570f656a5aaecaf1ee8dc9d0fa1d424759be1932a8f29fac08bc2d2a1ed7159f28b", + "tlvs": { + "encrypted_recipient_data": { + "short_channel_id": "0x0x2", + "next_blinding_override": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "payment_relay": { + "cltv_expiry_delta": 75, + "fee_proportional_millionths": 150, + "fee_base_msat": 100 + }, + "payment_constraints": { + "max_cltv_expiry": 750100, + "htlc_minimum_msat": 50 + }, + "allowed_features": { + "features": [] + } + } + } + }, + { + "alias": "Dave", + "pubkey": "036861b366f284f0a11738ffbf7eda46241a8977592878fe3175ae1d1e4754eccf", + "payload": "510a4f0fa1a72cff3b64a3d6e1e4903cf8c8b0a17144aeb249dcb86561adee1f679ee8db3e561d9e49895fd4bcebf6f58d6f61a6d41a9bf5aa4b0453437856632e8255c351873143ddf2bb2b0832b091e1b4", + "tlvs": { + "encrypted_recipient_data": { + "padding": "00000000000000000000000000000000000000000000000000000000000000000000", + "short_channel_id": "0x0x3", + "payment_relay": { + "cltv_expiry_delta": 25, + "fee_proportional_millionths": 100 + }, + "payment_constraints": { + "max_cltv_expiry": 750025, + "htlc_minimum_msat": 50 + }, + "allowed_features": { + "features": [] + } + } + } + }, + { + "alias": "Eve", + "pubkey": "021982a48086cb8984427d3727fe35a03d396b234f0701f5249daa12e8105c8dae", + "payload": "6002030186a004030b6dc80a4fda1c7e5f7881219884beae6ae68971de73bab4c3055d9865b1afb60722a63c688768042ade22f2c22f5724767d171fd221d3e579e43b354cc72e3ef146ada91a892d95fc48662f5b158add0af457da12030249f0", + "tlvs": { + "amt_to_forward": 100000, + "total_amount_msat": 150000, + "outgoing_cltv_value": 749000, + "encrypted_recipient_data": { + "padding": "00000000000000000000000000000000000000000000000000000000", + "path_id": "c9cf92f45ade68345bc20ae672e2012f4af487ed4415", + "payment_constraints": { + "max_cltv_expiry": 750000, + "htlc_minimum_msat": 50 + }, + "allowed_features": { + "features": [] + } + } + } + } + ] + }, + "onion": "0002531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337dadf610256c6ab518495dce9cdedf9391e21a71dada75be905267ba82f326c0513dda706908cfee834996700f881b2aed106585d61a2690de4ebe5d56ad2013b520af2a3c49316bc590ee83e8c31b1eb11ff766dad27ca993326b1ed582fb451a2ad87fbf6601134c6341c4a2deb6850e25a355be68dbb6923dc89444fdd74a0f700433b667bda345926099f5547b07e97ad903e8a01566a78ae177366239e793dac719de805565b6d0a1d290e273f705cfc56873f8b5e28225f7ded7a1d4ceffae63f91e477be8c917c786435976102a924ba4ba3de6150c829ce01c25428f2f5d05ef023be7d590ecdf6603730db3948f80ca1ed3d85227e64ef77200b9b557f427b6e1073cfa0e63e4485441768b98ab11ba8104a6cee1d7af7bb5ee9c05cf9cf4718901e92e09dfe5cb3af336a953072391c1e91fc2f4b92e124b38e0c6d17ef6ba7bbe93f02046975bb01b7f766fcfc5a755af11a90cc7eb3505986b56e07a7855534d03b79f0dfbfe645b0d6d4185c038771fd25b800aa26b2ed2e30b1e713659468618a2fea04fcd0473284598f76b11b0d159d343bc9711d3bea8d561547bcc8fff12317c0e7b1ee75bcb8082d762b6417f99d0f71ff7c060f6b564ad6827edaffa72eefcc4ce633a8da8d41c19d8f6aebd8878869eb518ccc16dccae6a94c690957598ce0295c1c46af5d7a2f0955b5400526bfd1430f554562614b5d00feff3946427be520dee629b76b6a9c2b1da6701c8ca628a69d6d40e20dd69d6e879d7a052d9c16f544b49738c7ff3cdd0613e9ed00ead7707702d1a6a0b88de1927a50c36beb78f4ff81e3dd97b706307596eebb363d418a891e1cb4589ce86ce81cdc0e1473d7a7dd5f6bb6e147c1f7c46fa879b4512c25704da6cdbb3c123a72e3585dc07b3e5cbe7fecf3a08426eee8c70ddc46ebf98b0bcb14a08c469cb5cfb6702acc0befd17640fa60244eca491280a95fbbc5833d26e4be70fcf798b55e06eb9fcb156942dcf108236f32a5a6c605687ba4f037eddbb1834dcbcd5293a0b66c621346ca5d893d239c26619b24c71f25cecc275e1ab24436ac01c80c0006fab2d95e82e3a0c3ea02d08ec5b24eb39205c49f4b549dcab7a88962336c4624716902f4e08f2b23cfd324f18405d66e9da3627ac34a6873ba2238386313af20d5a13bbd507fdc73015a17e3bd38fae1145f7f70d7cb8c5e1cdf9cf06d1246592a25d56ec2ae44cd7f75aa7f5f4a2b2ee49a41a26be4fab3f3f2ceb7b08510c5e2b7255326e4c417325b333cafe96dde1314a15dd6779a7d5a8a40622260041e936247eec8ec39ca29a1e18161db37497bdd4447a7d5ef3b8d22a2acd7f486b152bb66d3a15afc41dc9245a8d75e1d33704d4471e417ccc8d31645fdd647a2c191692675cf97664951d6ce98237d78b0962ad1433b5a3e49ddddbf57a391b14dcce00b4d7efe5cbb1e78f30d5ef53d66c381a45e275d2dcf6be559acb3c42494a9a2156eb8dcf03dd92b2ebaa697ea628fa0f75f125e4a7daa10f8dcf56ebaf7814557708c75580fad2bbb33e66ad7a4788a7aaac792aaae76138d7ff09df6a1a1920ddcf22e5e7007b15171b51ff81799355232ce39f7d5ceeaf704255d790041d6390a69f42816cba641ec81faa3d7c0fdec59dfe4ca41f31a692eaffc66b083995d86c575aea4514a3e09e8b3a1fa4d1591a2505f253ad0b6bfd9d87f063d2be414d3a427c0506a88ac5bdbef9b50d73bce876f85c196dca435e210e1d6713695b529ddda3350fb5065a6a8288abd265380917bac8ebbc7d5ced564587471dddf90c22ce6dbadea7e7a6723438d4cf6ac6dae27d033a8cadd77ab262e8defb33445ddb2056ec364c7629c33745e2338" + }, + "decrypt": { + "comment": "This section contains the internal values generated by intermediate nodes when decrypting their payload.", + "hops": [ + { + "alias": "Alice", + "onion": "0002531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe337dadf610256c6ab518495dce9cdedf9391e21a71dada75be905267ba82f326c0513dda706908cfee834996700f881b2aed106585d61a2690de4ebe5d56ad2013b520af2a3c49316bc590ee83e8c31b1eb11ff766dad27ca993326b1ed582fb451a2ad87fbf6601134c6341c4a2deb6850e25a355be68dbb6923dc89444fdd74a0f700433b667bda345926099f5547b07e97ad903e8a01566a78ae177366239e793dac719de805565b6d0a1d290e273f705cfc56873f8b5e28225f7ded7a1d4ceffae63f91e477be8c917c786435976102a924ba4ba3de6150c829ce01c25428f2f5d05ef023be7d590ecdf6603730db3948f80ca1ed3d85227e64ef77200b9b557f427b6e1073cfa0e63e4485441768b98ab11ba8104a6cee1d7af7bb5ee9c05cf9cf4718901e92e09dfe5cb3af336a953072391c1e91fc2f4b92e124b38e0c6d17ef6ba7bbe93f02046975bb01b7f766fcfc5a755af11a90cc7eb3505986b56e07a7855534d03b79f0dfbfe645b0d6d4185c038771fd25b800aa26b2ed2e30b1e713659468618a2fea04fcd0473284598f76b11b0d159d343bc9711d3bea8d561547bcc8fff12317c0e7b1ee75bcb8082d762b6417f99d0f71ff7c060f6b564ad6827edaffa72eefcc4ce633a8da8d41c19d8f6aebd8878869eb518ccc16dccae6a94c690957598ce0295c1c46af5d7a2f0955b5400526bfd1430f554562614b5d00feff3946427be520dee629b76b6a9c2b1da6701c8ca628a69d6d40e20dd69d6e879d7a052d9c16f544b49738c7ff3cdd0613e9ed00ead7707702d1a6a0b88de1927a50c36beb78f4ff81e3dd97b706307596eebb363d418a891e1cb4589ce86ce81cdc0e1473d7a7dd5f6bb6e147c1f7c46fa879b4512c25704da6cdbb3c123a72e3585dc07b3e5cbe7fecf3a08426eee8c70ddc46ebf98b0bcb14a08c469cb5cfb6702acc0befd17640fa60244eca491280a95fbbc5833d26e4be70fcf798b55e06eb9fcb156942dcf108236f32a5a6c605687ba4f037eddbb1834dcbcd5293a0b66c621346ca5d893d239c26619b24c71f25cecc275e1ab24436ac01c80c0006fab2d95e82e3a0c3ea02d08ec5b24eb39205c49f4b549dcab7a88962336c4624716902f4e08f2b23cfd324f18405d66e9da3627ac34a6873ba2238386313af20d5a13bbd507fdc73015a17e3bd38fae1145f7f70d7cb8c5e1cdf9cf06d1246592a25d56ec2ae44cd7f75aa7f5f4a2b2ee49a41a26be4fab3f3f2ceb7b08510c5e2b7255326e4c417325b333cafe96dde1314a15dd6779a7d5a8a40622260041e936247eec8ec39ca29a1e18161db37497bdd4447a7d5ef3b8d22a2acd7f486b152bb66d3a15afc41dc9245a8d75e1d33704d4471e417ccc8d31645fdd647a2c191692675cf97664951d6ce98237d78b0962ad1433b5a3e49ddddbf57a391b14dcce00b4d7efe5cbb1e78f30d5ef53d66c381a45e275d2dcf6be559acb3c42494a9a2156eb8dcf03dd92b2ebaa697ea628fa0f75f125e4a7daa10f8dcf56ebaf7814557708c75580fad2bbb33e66ad7a4788a7aaac792aaae76138d7ff09df6a1a1920ddcf22e5e7007b15171b51ff81799355232ce39f7d5ceeaf704255d790041d6390a69f42816cba641ec81faa3d7c0fdec59dfe4ca41f31a692eaffc66b083995d86c575aea4514a3e09e8b3a1fa4d1591a2505f253ad0b6bfd9d87f063d2be414d3a427c0506a88ac5bdbef9b50d73bce876f85c196dca435e210e1d6713695b529ddda3350fb5065a6a8288abd265380917bac8ebbc7d5ced564587471dddf90c22ce6dbadea7e7a6723438d4cf6ac6dae27d033a8cadd77ab262e8defb33445ddb2056ec364c7629c33745e2338", + "node_privkey": "4141414141414141414141414141414141414141414141414141414141414141" + }, + { + "alias": "Bob", + "onion": "000280caa47c2a0ea677f6a77529e46caa04212153a8d5f829bee1e7339b17e2e2a9a3461d10472364a4ff12344beb6df96fb0c38ec47d1e956ddff5a665190fcca5ed02c3a3903fd8bbd4a4b95b197867c378b67b08f0624cfe80734ba512869c0fa22099beb1f6f1ea325b07ce7449736d7ffad79178b428d8ea2d7bc6578f12dbd788ef933f3b5ba352797c41f6786c3820c96726acf8bddf2cfa5d9c617d2b0bd5ab7b93f7964c98f44cf47db8422f47d11100236a29579f1cafcd38bd979814e1d2bf6d625edf50e1e21bfaf6268e3180dd7aafd3892da281c6dd53c1c366d0fdaf670b6ad84a38d6e8a3f4a80d132d686fd3b7443bc2250023bdb9303190f74c9220481cf99da30b5ec2bdb5a49028f5014e3eaeaa48429a0c78ebd3bb7c7d582c22b7d547cd269f0c4490373a81bf92687e73dac2075b4bda189ce0be225f5f510655e37a6e724a1415bede0a076b92a882cc2a82878ba67aaedf71454eb42b7f8638df8e21d5f708006e5112e2dc0a4afbcfed9f2c7959be812853ca8e313fbc99a0f38f1ee4479c96ccb836632b0808401db159bd2637f7a664013241e4664e994a0a9a3940115a702c60381e66d291e1ade1be2802e1226e311e3201a7c9682b6bc4354caff3d439adb1dfee53ad3fb3dd5e169d64796853bb323129f41213b166a7cac00f728c3e33bd7e59aa2ac0d1341cdb1532b507a0f446e51022a882ac16405442347b70f78c9b6e122f8e70096a4fae4c0405db5b869e0b7b59b09519c4dbf4d4980483906e837da0bee93f668ffaad37d6a4764211a02f95ad2dc2d942c198796741c20a3baf8efb5a53bd9c1a0148318d60a97d0013ab63269097ea295d62c1426d064f0b31c02e74a348ee0509998e701069f5a1e0c1086aed38d2ec87da69fb57a992d88ace3b4a16b0960f5a94936e2e684a9926cf4f911969a2a5d31fed0c7616d30197848253170e51274278873b11f3f5cc1b04b14aa5812524e4d86cbf08306c2aa671288324d7a009b2be533b1d7d0ce6defeeb630b86a9655f1e6424fcb559ed67457c115fba0d0719374802ea68fab299fd3f273be86fa3d2e7456020db2f47c6ec16c21ce6ec65de495e20af1941a5dcd65d910c1cb93f22e1318c173c645c81aed681c9704a8a541ac3d6ff604f46d0260468acbfec1b771b9eb8cd49a2124468dae786571895a569aae18438eaee6343ab2634823119fa2439634645d12e3b4a748b9cc0398b8416a834eb5d9e5cf619bbfaba4894d1c574c738caf530d0862f4cc75eb52bd3921d2d9edb09940edb1e3776423b0046d870ccdcc5d61f72e0440b97a93eeef21fb246a779d339be301a5971400749d6cc9911dfbf9de8ae86fac83c860fdd0e2bfa40af37c99d50e50fd6e5ae86597a201112ed404042b55e132f243dec481a2adc1d5e4b71e1efdea806ea900b2907ce877742d5ecf700ff3640f737863d0dd7207e462ee8d0e17d52047a88ae7446f419560d23968bf64957949e36953155b0ac2511c66be2890b4036329a21e132efb635297a64431899e0c351e50c6682c9b4d79b5d122466d02cd84f206369417d9c194a9349d3c631d72eb7857a9cd542906fc02ad6cdcf9bcf25ace3d826b6623fa5164351e14d3f0de5c8445a2ba3aae26595d0e31c3e307c1d56d4274f61f056145c1b8d6880872b9b10a8bfa4a923cad2edbcf5c50eba48936ed2bcc0be60eb721a74b46704aaae5ad24e2797852195dfacbb30a777d33b63d4dc4f35cfbe5e88fd1944c55a54fd53581446ea061ad29f4671da819ad7488c5dfc700f5f7a1b2af0d6a6e9d9ffc570a6d3209614ab4dc43728f3f0cd7eb4ce36ccd98936bbcbd32627384434bd01e9c0f93b2a5173fba184685e19b9af78afe876aa4e4b4242382b293133771d95a2bd83fa9c62", + "node_privkey": "4242424242424242424242424242424242424242424242424242424242424242", + "next_blinding": "034e09f450a80c3d252b258aba0a61215bf60dda3b0dc78ffb0736ea1259dfd8a0" + }, + { + "alias": "Carol", + "onion": "000288b48876fb0dc0d7375233ccaf2910dc0dc81ba52e5a7906f00d75e0d58dbd4bb7c2714870529410735f0951e72cbe981e2e167c0d8f3de33a36e39e78465aea2acad1e23c78b6fd342d63e37d214c912b4a0be344618f779138edc1b42a5ca3218ca2fea4be427f6cd0d387160db2bf6c2ba8e82941c8cf3626bd6bed7187f633012ef49df38f6b12963cb639e9eed1b9d269dcebcbd0b25287aa536ec85e7320b02e193122199a745ccbaaebd37f5d4b71f52f9b50feeb793eeef56924a046bc5e7003f6253e0284a8d3fe2e42c3564050f1e753cd32cc258ac0ffa6e05eecad5ba1286f78252e60dd884a65405ab673a85ba52adfa65c1086d4bb37ba2e0848adb2b04379775ad798492b14e8997f30ffa9cf5d432bdf5b246fce008fd876399beed827db58195f4f6192f6ff4ec63cb17fdcb497cb7aec26846a71dd8dca02fc3bb14dd7231a4d62a981bec54b71eb20331096dfa214a0ff4489ee96db663826ae8c850e9f06baa52a47b8eb576363f97e742aab2dc616acc6e74588e1d2ac16694febc90abaf5b1c684163c0e615a68d32633f01934adc8c6bf91fa3fd7aad033b7596d60402494e45e2c1632c40f7bfbd88a81a896a1d28ed6338c83e1eeaa467945d59998eb456c95f94bf1892e8f326ec2d5e0196b7073f106febc6ab8ca5bcc23f77ffc819bc1b5debce418ccc7d8391bbf33bceee6110beba170121bd99f54c956e64970bdab31227b03ee0ea3f01fbd9bd74015f6f82d04fab072e8f85f4370d09f41ee3e48eb959767bd989abb4eea42c4daa0437a7f747d7f9b70eb87b9f9b0b6f283b8205912601a432999b8869fd9fe5bad3572edac24da7184f9298f21ff60923db277264d29c846dd2f228f6fc53b6b60364237de64773f803f174ed10229c374f603ccc5fd3a62cb413ffe6f5630dc646bb33f231b2350537ec39e5d3f2fe1a1cb019ed0b18ad14019cad27afcca8ad70387ca110394c0432774f1aa1fa404b2e086c84a55388d3bd102501c78ef925cce89d76fa04c3f20f2d1f0ce507ac8b37b7913e3949ba12bbc5a4f6bac37c2415622d365bc8b83709a28e3d46f3850c89a3ff4d027fef6e3e4ce5c6c85f663c7eaec3c9730106fb82f53249a905533cfabee812aae51965b24b42f7ab471967bc8e73354e69141ee26a1f03684d5fb9c256a34de8257210e0390dd3962db521ae0a3bdab28300610ab2a634b699e5f092da5a061609ef6414bd805c8171f54ad6f285fb64ce0becca0b61188badcf8ef21190dad629e3fb3e89f55ebba829919540ebf5f8ae4283836d3c9133c1ca3365f6b9394916730411650686e0c2ab9c53b6cda9efdd5cfcb53ba9b6962bb6aa49d0a83a87460b60a9c7d2643ee99afe652883795f14014ec5df61b1e30c041c1fa6487f3c82f1ded5f83ffbef5017e197b7fb77be3b36e284a15e57d45bf9316dcaf97eb78ee4642b731ba05c5063bce1333fab4af6da97c80a96ee599b4df823efbedc250c0abba9783da7ddf2414b2a4774ff2880a7dc6791103e18b8631e39743cf9e87aed71700daa5dc72fdae520324741f92ea3d510ff555dea5e45f15cda87272d4559a12d4777680acb06993840e3c748da82c16cae556015fb2acd0335da11a3388575394048ab71199793ab706abc9d68add2075d79a5cc0f779845ee8b98951be61fd293d6c15b9d4653935bf17cf50bd31f8b79e60dba0e7fd6864754fd94262485a4f65e7eb3e1922f51b1a4dd2b4fd2c20d94d1213fbe90bd603dfc7e15176382e3ce0f43f980d44d23bf3c57f54a15f42c171a8f2511e28ac178c6f01396e50397a57ffb09c5e6c315bd3ae7983577c1a0386c6d5d9a2223438e321b0fedfdee58fa452d57dc11a256834bb49ac9deeec88e4bf563c7340f44a240caec941c7e50f09cf", + "node_privkey": "4343434343434343434343434343434343434343434343434343434343434343", + "next_blinding": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f" + }, + { + "alias": "Dave", + "onion": "0003f25471c0f2ff549a7fd7859100306bb6c294c209f34c77f782897f184b967c498efc246bdb8e060a6d1cf8dd0d4d732e33311fb96c9e9f1274005fa3d08b41704a1b7224c6300a7caead7baa0a8263eba2e0de6956ee8e4a1958264f47e4cf20d194eb576f5bd249ee4fece563f80fd76dc3eaca8f956188406d83195752b5c90c4b2a5e7ac3a8d5c62b17b551aff48ef6842a7e9326832c9a4a2fd415011150a9e71beb901fd9747bac8add1c694b612730dc86b5b19a0bbbc675947a953316e3303d7b30c182f94def9206671edac9a3ec3e52d28fc28247a1c73ab751bf61c82c3950f617e758f79bd0ba294defb20466eaf1e801462046baad3aec3e5b8868a7b037f23d73a47a7e74c77107334f37388cff863e452820c61d89728fa75c84bc7cdfc06dcdd1911f5f803353926d073efd65251380e174913aae03318ea5b6f0ec83998c55ab99bef62803ea2da9f6d1ea892b90efc4f8ffb685a5201a781da2e6ac5923645638c9709ae32171a00c0cd3d8c7eedfb06b4eedc7d3e566987e2e3805a038f21d78ded5d6c7137a5e8e592f3180ee4d5f4e1289176f67fc38690d0958bc82e240b72b10577f340f1e14b8633f0b6d9729ff4618be2a972400a015a871ba33be70335f652a8d70f2bd32421d6ac2af781d667dad787d6aef4505a15d046579e46eebe757444cffca6d0610f0dd36a7ce57af969bd0c3f7006298ef406a25f689daf58f875d44d2423ebf195b503f11c37c506ea6abe50a463f7bb5e9b964604d832724de768513f6b38bf71715e1feea8a6e86797788d487146891564919da1372016ed8f08c7fcbff66a4a65a3d0fcd8e3daac6eba41f5d65ef2d8075364a9e78b3a273549f6eac4abb72e912e237990367e0d43e89945f8ac3907be5a6c662139485a50cb5ce3f0ba08586c39f6c515368ec3f91b72295f1b7a73a9df322ae9a45d363d6c616be3300083764cbdee31221f25a318f095feacb09f957c96db30fccca47a0215b576c3ed925a0bad05d6400abe318c11f36628c387a4ee38832182cd44b3cd48e5422c1f1e3b57218dfe72c611f5415127720e60f6e2400607e61841b76de1704bcbeb0daf1377ccb2253916de2b6d490bb71ba0a44fea2e94f2423d723934557d5905e01b2b80232a884e258d46dc92ea11e0818d0ece5b914f02049866e151801ab8c9aea155479b354dc91151fb9ba43277458f9760dd859faaa139e3b9ab36a1dbc36a93ef2c90598b20cb30ef3c4f23a2d6178b4d1da668fb328a25d84d30a132d9f2a6a988cbe2e5c2be01cb6db4b4725a50d6cdacf5fb083e7d650a25bec1407fbc047d26076c7596429a29606ad527e97ef0824ad6c1b05831a3e5b71c63a528918a3301cdd4061fc1fcce3da601961f2602a2b002ac8404125c2d52666263858a923e197efcda873c32d86897352e4f2264ad6a1b48acc0fe78ff55cb442cb2bb5fa2880810e1d00aa0247057fb80b7ed36cf9647af41b44ee4a63ee2d6f652526404572520a7d2d9dcde4e62df0c3be89f8471550594cdd16a51a9cacc58729c092c68506162fe65edc2314055d389f724ced189d826a546b5c4d08a43d977b3cf033de5760b71a7cc38ee5851592031aafb467a89b3b6c7ed67b15d44c48d6baedce3e95e08ec7c55038f3eba90ccb900895734f0fb7efe54961ce493369cc56416898a9bed7c2482871c15a7f1eb5ed17c33657fc31333539c2dfb59461af09e7049228113b5c9feea5a6e9959c18c51b19c90995afb9c76f2c0c820964cd7989c993a73925818a656c6a18dcd1a1e3782b2eae06dd5a41250ec2d1c203626ab9920c1673339eff04b1eb0cab85ef5909f571f9b83cdf21697c9f5cfa1c76e7bca955510e2126b3bb989a4ac21cf948f965e48bc363d2997437797b4f770e8b65", + "node_privkey": "4444444444444444444444444444444444444444444444444444444444444444", + "next_blinding": "03e09038ee76e50f444b19abf0a555e8697e035f62937168b80adf0931b31ce52a" + }, + { + "alias": "Eve", + "onion": "0002ef43c4dfe9aee14248c445406ac7980474ce106c504d9025f57963739130adfd06eb26201baee8866af2d1b7a7ab26595349dad002af0590193aaa8f400ab394f5994ec831aeeecb64421c566e3556cbdd7e7e50deb1fc49fd5e007308ab6494415514abff978899623f9b6065ca1e243bb78170118e8b8c8b53b750b59cc1ec017d167adbb3aabab7c2d84fbf94f5d827239f4c2b9d2c3cfe68fe5641f25e386202a4b6edff2a71e700229df7230c8ca31bd5588f04799e9640c9c20a47cba713f3cc5ad3202e14bb520880f2a8409d8e7835cae21b48a651c2d47fe6af785889ab98f1416f6e4ad67a66ae681e9a8828bad3f9b6890221c4a7ec80531d6b63eb30843f613ce644795bc8bcee60e8f7b36f3fd04de762f103c52efaf36a2f3bbbaac482d6271dc4180c10bcc076c04d06ea7fd8fb6a647e0e10523b05da2d89e4139fb55c2315cd01bdcbd57587fef8442d7ff5620630fd2d2e79739d90be811bf2cba60415d6cba2cea14ba1859f3122cd905c4e12e3e2a1ab6fab54b2ec40e434626e2d3c3195c02c82a8bd64d226c2328ac72ca12197d9908eaf54333717448ce6ed73adc0ac05e2ee1d735131d87918beb8995993dc8f63fe10f2c8eba2be7ab8bb44d9f78f59ef3e4c180bd75e4eef2381450c6f0480d543997305f1d07815993b5aca8d88d474966d9abec93bb069a16aa2da75b87f94576e01d08a17d3e0e3d0370f010733a7d7affb12cdf94c259a62607fce71003535c4727305de5ff7bba3840922844b3a45f62c29715fccf440517ef121450f6962396fba9b07036d085582405dcae6ee95964b66bc7c85b8d02d90091500db3cebf6de584f86b7b55335a8c9aa26381b00747f055cc458a2cadfccf9c29702bf941447beaca6583cca09492a57d4b03b2ca00dbaf41dfd6a9b249381626a7debe475735a7e39e77a363eccf14669046f656cc09ad448da8d8b545e6a604f46dc481786d09a94c63cf23f49ba367d2929466364dbce2a8ffce3dadf8f4cef8a56e1fefa1a3304a953fe83018e57d8a95694b02d994fea2630a9a3d5f1e2f6d6142d503ec4152871f7122d7e566a03261f554639e7a759e0e73846f71d5cace37d91336fc9ca9396bf64ca2cf45fa2db779b3b5c63b04f1c0c1fb79fdfcf5a82b0202df934ae1720a7ce1e047cbec3f82737b50168c974f4623cacce87e3f5bd5232caca7956d28ffedcf11ac5998662c5f6b13c6126584ca2e894d3fcbad4d130bbe22e88a135e0020cdd43853e0b3af3800e9544854d211e873cf68ab683578d501d69ec5dc7fce42ac436d58243880c1b88227b0681c6c9dd8a8ad0793202b15ab63b787b748e258da3e68d0e649fc4ac081a71de8adbc891c113d5f722686b6ac4ed9e3cc247bc4a4643416f480627e9de20f7307f434a499f5c6951c2e8b3ff51d455bf65ceb5ee3dee47b968ac2642e13d8a68f903b73627c2e75788fecca5836371a908eea4f1ea44db2315bc185f77e478efeaaa4da2da13fe7aeaa79ed1d04876a8b2b7b333c5de8c4c9a50274c2eb7b9bd2a3630c57173174781fc9785235f830cefa1c82080eaffdef257f18eedc9ddfd25a696a11a3dc56cd836be72f5f4a2cbb6316d5d3b1ad91a7ec7d877f28d2c29a5525b0b24362699281b0e3b48f38caf1085045fe9089f9e6fb29e4b47aa4cecf68c9bf72073469bd9beeea5e88bfe554cb6a81231149ba7fe7784c154fd8b0f9179ecdf1e9fd5c2939ec1ab16df9cbe9359101ebce933d4f65d3f66f87afaecfe9c046b52f4878b6c430329df7bd879fba8864fcbd9b782bf545734699b9b5a66b466dcedc0c9368803b5b0f1232950cef398ad3e057a5db964bd3e5c8a5717b30b41601a4f11ad63afe404cb6f1e8ea5fd7a8e085b65ca5136146febf4d47928dcc9a9e0", + "node_privkey": "4545454545454545454545454545454545454545454545454545454545454545", + "next_blinding": "038fc6859a402b96ce4998c537c823d6ab94d1598fca02c788ba5dd79fbae83589" + } + ] + } +} \ No newline at end of file diff --git a/bolt04/route-blinding-test.json b/bolt04/route-blinding-test.json index 0be3d7faa..c69cc72be 100644 --- a/bolt04/route-blinding-test.json +++ b/bolt04/route-blinding-test.json @@ -9,17 +9,28 @@ "alias": "Bob", "node_id": "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c", "tlvs": { - "padding": "00000000000000000000000000000000", - "short_channel_id": "0x0x42", - "next_node_id": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007", - "unknown_tag_65001": "123456" + "padding": "0000000000000000000000000000000000000000000000000000", + "short_channel_id": "0x0x1729", + "payment_relay": { + "cltv_expiry_delta": 36, + "fee_proportional_millionths": 150, + "fee_base_msat": 10000 + }, + "payment_constraints": { + "max_cltv_expiry": 748005, + "htlc_minimum_msat": 1500 + }, + "allowed_features": { + "features": [] + }, + "unknown_tag_561": "123456" }, - "encoded_tlvs": "0110000000000000000000000000000000000208000000000000002a0421027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007fdfde903123456", + "encoded_tlvs": "011a0000000000000000000000000000000000000000000000000000020800000000000006c10a0800240000009627100c06000b69e505dc0e00fd023103123456", "ephemeral_privkey": "0202020202020202020202020202020202020202020202020202020202020202", "ephemeral_pubkey": "024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", "shared_secret": "76771bab0cc3d0de6e6f60147fd7c9c7249a5ced3d0612bdfaeec3b15452229d", "rho": "ba217b23c0978d84c4a19be8a9ff64bc1b40ed0d7ecf59521567a5b3a9a1dd48", - "encrypted_data": "cd4b00ff9c09ed28102b210ac73aa12d63e90a5acebc496c49f57c639e098acbaec5b5ffb8592b07bdb6665ccb56f1258ab1857383f6542c8371dcee568a0a35a218288814849db13ce6f84a464fa517d9e1684333e3", + "encrypted_data": "cd4100ff9c09ed28102b210ac73aa12d63e90852cebc496c49f57c49982088b49f2e70b99287fdee0aa58aa39913ab405813b999f66783aa2fe637b3cda91ffc0913c30324e2c6ce327e045183e4bffecb", "blinded_node_id": "03da173ad2aee2f701f17e59fbd16cb708906d69838a5f088e8123fb36e89a2c25" }, { @@ -27,15 +38,27 @@ "alias": "Carol", "node_id": "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007", "tlvs": { - "next_node_id": "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991", - "next_blinding_override": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f" + "short_channel_id": "0x0x1105", + "next_blinding_override": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "payment_relay": { + "cltv_expiry_delta": 48, + "fee_proportional_millionths": 100, + "fee_base_msat": 500 + }, + "payment_constraints": { + "max_cltv_expiry": 747969, + "htlc_minimum_msat": 1500 + }, + "allowed_features": { + "features": [] + } }, - "encoded_tlvs": "0421032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910821031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "encoded_tlvs": "020800000000000004510821031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0a0800300000006401f40c06000b69c105dc0e00", "ephemeral_privkey": "0a2aa791ac81265c139237b2b84564f6000b1d4d0e68d4b9cc97c5536c9b61c1", "ephemeral_pubkey": "034e09f450a80c3d252b258aba0a61215bf60dda3b0dc78ffb0736ea1259dfd8a0", "shared_secret": "dc91516ec6b530a3d641c01f29b36ed4dc29a74e063258278c0eeed50313d9b8", "rho": "d1e62bae1a8e169da08e6204997b60b1a7971e0f246814c648125c35660f5416", - "encrypted_data": "ca26157e44ab01e82becf86497e1d05ad3e70903d22721210af41d791bf406873024d95b7a1ad128b2526932febfeeab237000563c1f33c78530b3880f8407326eef8bc004932b22323d13343ef740019c08e538e5c5", + "encrypted_data": "cc0f16524fd7f8bb0b1d8d40ad71709ef140174c76faa574cac401bb8992fef76c4d004aa485dd599ed1cf2715f57ff62da5aaec5d7b10d59b04d8a9d77e472b9b3ecc2179334e411be22fa4c02b467c7e", "blinded_node_id": "02e466727716f044290abf91a14a6d90e87487da160c2a3cbd0d465d7a78eb83a7" }, { @@ -44,16 +67,26 @@ "alias": "Dave", "node_id": "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991", "tlvs": { - "padding": "0000000000000000000000000000000000000000000000", + "padding": "0000000000000000000000000000000000000000000000000000000000000000000000", "short_channel_id": "0x0x561", - "next_node_id": "02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145" + "payment_relay": { + "cltv_expiry_delta": 144, + "fee_proportional_millionths": 250 + }, + "payment_constraints": { + "max_cltv_expiry": 747921, + "htlc_minimum_msat": 1500 + }, + "allowed_features": { + "features": [] + } }, - "encoded_tlvs": "0117000000000000000000000000000000000000000000000002080000000000000231042102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145", + "encoded_tlvs": "01230000000000000000000000000000000000000000000000000000000000000000000000020800000000000002310a060090000000fa0c06000b699105dc0e00", "ephemeral_privkey": "0101010101010101010101010101010101010101010101010101010101010101", "ephemeral_pubkey": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", "shared_secret": "dc46f3d1d99a536300f17bc0512376cc24b9502c5d30144674bfaa4b923d9057", "rho": "393aa55d35c9e207a8f28180b81628a31dff558c84959cdc73130f8c321d6a06", - "encrypted_data": "0f94a72cff3b64a3d6e1e4903cf8c8b0a17144aeb249dcb86563a5ee1f679ee8db3c6719bd4364f469aa5fea76ffdc49543d568a707ab73a3e855b25ca585bf12c9d5c9cb6c5c10374a4a66d95aeeea4fe146d0c2754", + "encrypted_data": "0fa0a72cff3b64a3d6e1e4903cf8c8b0a17144aeb249dcb86561adee1f679ee8db3e561d9c43815fd4bcebf6f58c546da0cd8a9bf5cebd0d554802f6c0255e28e4a27343f761fe518cd897463187991105", "blinded_node_id": "036861b366f284f0a11738ffbf7eda46241a8977592878fe3175ae1d1e4754eccf" }, { @@ -61,16 +94,23 @@ "alias": "Eve", "node_id": "02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145", "tlvs": { - "padding": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "path_id": "00112233445566778899aabbccddeeff", + "padding": "0000000000000000000000000000000000000000000000000000", + "path_id": "deadbeef", + "payment_constraints": { + "max_cltv_expiry": 747777, + "htlc_minimum_msat": 1500 + }, + "allowed_features": { + "features": [113] + }, "unknown_tag_65535": "06c1" }, - "encoded_tlvs": "012c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061000112233445566778899aabbccddeefffdffff0206c1", + "encoded_tlvs": "011a00000000000000000000000000000000000000000000000000000604deadbeef0c06000b690105dc0e0f020000000000000000000000000000fdffff0206c1", "ephemeral_privkey": "62e8bcd6b5f7affe29bec4f0515aab2eebd1ce848f4746a9638aa14e3024fb1b", "ephemeral_pubkey": "03e09038ee76e50f444b19abf0a555e8697e035f62937168b80adf0931b31ce52a", "shared_secret": "352a706b194c2b6d0a04ba1f617383fb816dc5f8f9ac0b60dd19c9ae3b517289", "rho": "719d0307340b1c68b79865111f0de6e97b093a30bc603cebd1beb9eef116f2d8", - "encrypted_data": "da2c7e5f7881219884beae6ae68971de73bab4c3055d9865b1afb60722a63a7e4ea796de84fc9af674952e900ff518ed6b3640a7e47b5f3e4fbce5fab87e47a11d84c66d1234f1cec1da2f56b72b64896509aef9b754", + "encrypted_data": "da1a7e5f7881219884beae6ae68971de73bab4c3055d9865b1afb60724a2e4d3f0489ad884f7f3f77149209f0df51efd6b276294a02e3949c7254fbc8b5cab58212d9a78983e1cf86fe218b30c4ca8f6d8", "blinded_node_id": "021982a48086cb8984427d3727fe35a03d396b234f0701f5249daa12e8105c8dae" } ] @@ -82,19 +122,19 @@ "hops": [ { "blinded_node_id": "03da173ad2aee2f701f17e59fbd16cb708906d69838a5f088e8123fb36e89a2c25", - "encrypted_data": "cd4b00ff9c09ed28102b210ac73aa12d63e90a5acebc496c49f57c639e098acbaec5b5ffb8592b07bdb6665ccb56f1258ab1857383f6542c8371dcee568a0a35a218288814849db13ce6f84a464fa517d9e1684333e3" + "encrypted_data": "cd4100ff9c09ed28102b210ac73aa12d63e90852cebc496c49f57c49982088b49f2e70b99287fdee0aa58aa39913ab405813b999f66783aa2fe637b3cda91ffc0913c30324e2c6ce327e045183e4bffecb" }, { "blinded_node_id": "02e466727716f044290abf91a14a6d90e87487da160c2a3cbd0d465d7a78eb83a7", - "encrypted_data": "ca26157e44ab01e82becf86497e1d05ad3e70903d22721210af41d791bf406873024d95b7a1ad128b2526932febfeeab237000563c1f33c78530b3880f8407326eef8bc004932b22323d13343ef740019c08e538e5c5" + "encrypted_data": "cc0f16524fd7f8bb0b1d8d40ad71709ef140174c76faa574cac401bb8992fef76c4d004aa485dd599ed1cf2715f57ff62da5aaec5d7b10d59b04d8a9d77e472b9b3ecc2179334e411be22fa4c02b467c7e" }, { "blinded_node_id": "036861b366f284f0a11738ffbf7eda46241a8977592878fe3175ae1d1e4754eccf", - "encrypted_data": "0f94a72cff3b64a3d6e1e4903cf8c8b0a17144aeb249dcb86563a5ee1f679ee8db3c6719bd4364f469aa5fea76ffdc49543d568a707ab73a3e855b25ca585bf12c9d5c9cb6c5c10374a4a66d95aeeea4fe146d0c2754" + "encrypted_data": "0fa0a72cff3b64a3d6e1e4903cf8c8b0a17144aeb249dcb86561adee1f679ee8db3e561d9c43815fd4bcebf6f58c546da0cd8a9bf5cebd0d554802f6c0255e28e4a27343f761fe518cd897463187991105" }, { "blinded_node_id": "021982a48086cb8984427d3727fe35a03d396b234f0701f5249daa12e8105c8dae", - "encrypted_data": "da2c7e5f7881219884beae6ae68971de73bab4c3055d9865b1afb60722a63a7e4ea796de84fc9af674952e900ff518ed6b3640a7e47b5f3e4fbce5fab87e47a11d84c66d1234f1cec1da2f56b72b64896509aef9b754" + "encrypted_data": "da1a7e5f7881219884beae6ae68971de73bab4c3055d9865b1afb60724a2e4d3f0489ad884f7f3f77149209f0df51efd6b276294a02e3949c7254fbc8b5cab58212d9a78983e1cf86fe218b30c4ca8f6d8" } ] }, @@ -106,7 +146,7 @@ "node_privkey": "4242424242424242424242424242424242424242424242424242424242424242", "ephemeral_pubkey": "024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766", "blinded_privkey": "d12fec0332c3e9d224789a17ebd93595f37d37bd8ef8bd3d2e6ce50acb9e554f", - "decrypted_data": "0110000000000000000000000000000000000208000000000000002a0421027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007fdfde903123456", + "decrypted_data": "011a0000000000000000000000000000000000000000000000000000020800000000000006c10a0800240000009627100c06000b69e505dc0e00fd023103123456", "next_ephemeral_pubkey": "034e09f450a80c3d252b258aba0a61215bf60dda3b0dc78ffb0736ea1259dfd8a0" }, { @@ -114,7 +154,7 @@ "node_privkey": "4343434343434343434343434343434343434343434343434343434343434343", "ephemeral_pubkey": "034e09f450a80c3d252b258aba0a61215bf60dda3b0dc78ffb0736ea1259dfd8a0", "blinded_privkey": "bfa697fbbc8bbc43ca076e6dd60d306038a32af216b9dc6fc4e59e5ae28823c1", - "decrypted_data": "0421032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e6686809910821031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", + "decrypted_data": "020800000000000004510821031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f0a0800300000006401f40c06000b69c105dc0e00", "next_ephemeral_pubkey": "03af5ccc91851cb294e3a364ce63347709a08cdffa58c672e9a5c587ddd1bbca60", "next_ephemeral_pubkey_override": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f" }, @@ -123,7 +163,7 @@ "node_privkey": "4444444444444444444444444444444444444444444444444444444444444444", "ephemeral_pubkey": "031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f", "blinded_privkey": "cebc115c7fce4c295dc396dea6c79115b289b8ceeceea2ed61cf31428d88fc4e", - "decrypted_data": "0117000000000000000000000000000000000000000000000002080000000000000231042102edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145", + "decrypted_data": "01230000000000000000000000000000000000000000000000000000000000000000000000020800000000000002310a060090000000fa0c06000b699105dc0e00", "next_ephemeral_pubkey": "03e09038ee76e50f444b19abf0a555e8697e035f62937168b80adf0931b31ce52a" }, { @@ -131,7 +171,7 @@ "node_privkey": "4545454545454545454545454545454545454545454545454545454545454545", "ephemeral_pubkey": "03e09038ee76e50f444b19abf0a555e8697e035f62937168b80adf0931b31ce52a", "blinded_privkey": "ff4e07da8d92838bedd019ce532eb990ed73b574e54a67862a1df81b40c0d2af", - "decrypted_data": "012c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000061000112233445566778899aabbccddeefffdffff0206c1", + "decrypted_data": "011a00000000000000000000000000000000000000000000000000000604deadbeef0c06000b690105dc0e0f020000000000000000000000000000fdffff0206c1", "next_ephemeral_pubkey": "038fc6859a402b96ce4998c537c823d6ab94d1598fca02c788ba5dd79fbae83589" } ] diff --git a/proposals/route-blinding.md b/proposals/route-blinding.md index 987bae0b1..86a82d4c1 100644 --- a/proposals/route-blinding.md +++ b/proposals/route-blinding.md @@ -19,6 +19,7 @@ * [Recipient pays fees](#recipient-pays-fees) * [Dummy hops](#dummy-hops) * [Wallets and unannounced channels](#wallets-and-unannounced-channels) + * [Blinded route selection](#blinded-route-selection) * [Blinded trampoline route](#blinded-trampoline-route) * [FAQ](#faq) * [Why not use rendezvous](#why-not-use-rendezvous) @@ -198,9 +199,10 @@ The `encrypted_data` for each intermediate node will contain the following field * `htlc_minimum_msat`: minimum htlc amount that should be accepted * `allowed_features`: features related to payment relay that the sender is allowed to use -The recipient must use values that exceed the ones found in each `channel_udpate`, otherwise it -would be easy for a malicious sender to figure out which channels are hidden inside the blinded -route. +The recipient must use values that provide a good enough anonymity set, by looking at nearby +channels and selecting values that would work for a large enough number of those channels. +Otherwise it could be easy for a malicious sender to figure out which channels are hidden inside +the blinded route if for example the selected fees are lower than most other candidates. The recipient also includes the `payment_preimage` (or another private unique identifier for the payment) in the `path_id` field of the `encrypted_data` payload for itself: this will let the @@ -244,12 +246,18 @@ channels described above and adds a safety margin in case nodes update their rel * `cltv_expiry_delta`: 144 Alice uses the same values for both channels for simplicity's sake. Alice can now compute aggregate -values for the complete route (iteratively starting from the end of the route): +values for the complete route (iteratively starting from the end of the route), using integer +arithmetric to compute `ceil(a/b)` as `(a+b-1)/b` (we round values up, otherwise the sender may +receive slightly less than intended): -* `route_fee_base_msat`: ceil(100 + 100 * (1 + 500/1000000)) = 201 -* `route_fee_proportional_millionths`: ceil((500/1000000) + (500/1000000) + (500/1000000)^2) = 1001 +* `route_fee_base_msat(n+1) = (fee_base_msat(n+1) * 1000000 + route_fee_base_msat(n) * (1000000 + fee_proportional_millionths(n+1)) + 1000000 - 1) / 1000000` +* `route_fee_proportional_millionths(n+1) = ((route_fee_proportional_millionths(n) + fee_proportional_millionths(n+1)) * 1000000 + route_fee_proportional_millionths(n) * fee_proportional_millionths(n+1) + 1000000 - 1) / 1000000` + +This yields the following values: + +* `route_fee_base_msat`: 201 +* `route_fee_proportional_millionths`: 1001 * `route_cltv_expiry_delta`: 288 -* NB: we need to round values up, otherwise the recipient will receive slightly less than expected Let's assume the current block height is 1000. Alice wants the route to be used in the next 200 blocks, so she sets `max_cltv_expiry = 1200` and adds `cltv_expiry_delta` for each hop. Alice then @@ -288,19 +296,19 @@ allow Carol to compute the blinding shared secret and correctly forward. We put ephemeral key in the onion instead of using a tlv in `update_add_htlc` because intermediate nodes added before the blinded route may not support route blinding and wouldn't know how to relay it. -Eve wants to send 100 000 msat to this blinded route. -She can reach Carol via Dave: `Eve -> Dave -> Carol`, where the channel between Dave and Carol uses +Erin wants to send 100 000 msat to this blinded route. +She can reach Carol via Dave: `Erin -> Dave -> Carol`, where the channel between Dave and Carol uses the following relay parameters: * `fee_base_msat`: 10 * `fee_proportional_millionths`: 100 * `cltv_expiry_delta`: 24 -Eve uses the aggregated route relay parameters to compute how much should be sent to Carol: +Erin uses the aggregated route relay parameters to compute how much should be sent to Carol: -* `amount = ceil(100000 + 201 + 1001 * 100000 / 1000000) = 100302 msat` +* `amount = 100000 + 201 + (1001 * 100000 + 1000000 - 1) / 1000000 = 100302 msat` -Eve chooses a final expiry of 1100, which is below Alice's `max_cltv_expiry`, and computes the +Erin chooses a final expiry of 1100, which is below Alice's `max_cltv_expiry`, and computes the expiry that should be sent to Carol: * `expiry = 1100 + 288 = 1388` @@ -311,12 +319,12 @@ or `outgoing_cltv_value`. They will have to compute them based on the fields con For example, here is how Carol will compute the values for the htlc she relays to Bob: -* `amount = ceil((100302 - fee_base_msat) / (1 + fee_proportional_millionths)) = 100152 msat` +* `amount = ((100302 - fee_base_msat) * 1000000 + 1000000 + fee_proportional_millionths - 1) / (1000000 + fee_proportional_millionths) = 100152 msat` * `expiry = 1388 - cltv_expiry_delta = 1244` And here is how Bob computes the values for the htlc he relays to Alice: -* `amount = ceil((100152 - fee_base_msat) / (1 + fee_proportional_millionths)) = 100002 msat` +* `amount = ((100152 - fee_base_msat) * 1000000 + 1000000 + fee_proportional_millionths - 1) / (1000000 + fee_proportional_millionths) = 100002 msat` * `expiry = 1244 - cltv_expiry_delta = 1100` Note that as the rounding errors aggregate, the recipient will receive slightly more than what was @@ -327,7 +335,7 @@ protects against intermediate nodes that would try to relay a lower amount). The messages exchanged will contain the following values: ```text - Eve Dave Carol Bob Alice + Erin Dave Carol Bob Alice | update_add_htlc | update_add_htlc | update_add_htlc | update_add_htlc | | +--------------------------------+ | +------------------------------------------+ | +------------------------------------------+ | +--------------------------------+ | | | amount: 100322 msat | | | amount: 100302 msat | | | amount: 100152 msat | | | amount: 100002 msat | | @@ -476,6 +484,80 @@ and `scid` from the sender. It obviously reveals to the blinded node that the ne final recipient, but a wallet that's not online all the time with a stable IP will never be able to hide that information from the nodes it connects to anyway (even with rendezvous). +### Blinded route selection + +There is a wide array of strategies that a recipient may use when creating a blinded route to +ensure good privacy while maintaining good payment reliability. We will walk through some of +these strategies below. Note that these are only examples, implementations should find strategies +that suit their users' needs. + +If the recipient is not a public node and has a small number of peers, then it's very simple: +they can include one path per peer. A mobile wallet's topology for example will typically look +like this: + +```text + +-------+ +-------+ + +----------| Carol | | X | + | +-------+ +-------+ + | | | + | | | ++-------+ +-------+ +-------+ +-------+ +| Alice |------| Bob |------| X |------| X | ++-------+ +-------+ +-------+ +-------+ + | | + | | + | +-------+ + +-------------------------| Dave | + +-------+ +``` + +Alice could provide a blinded route containing one blinded path per peer and dummy hops: + +* Bob -> Blinded(Alice) -> Blinded(Alice) -> Blinded(Alice) +* Carol -> Blinded(Alice) -> Blinded(Alice) -> Blinded(Alice) +* Dave -> Blinded(Alice) -> Blinded(Alice) -> Blinded(Alice) + +Alice is able to use all of her inbound liquidity while benefiting from a large anonymity set: she +could be any node at most three hops away from Bob, Carol and Dave. + +If the recipient is a public node, its strategy will be different. It should use introduction nodes +that have many peers to obtain a good anonymity set. Let's assume that Alice's neighbourhood has +the following topology: + +```text ++-------+ +-------+ +| X | | X | ++-------+ +-------+ + | | + | | ++-------+ +-------+ +-------+ +| N1 |------| N2 |------| X | ++-------+ +-------+ +-------+ + | | | + | | | ++-------+ +-------+ +-------+ +-------+ +| Alice |------| N3 |------| N4 |------| X | ++-------+ +-------+ +-------+ +-------+ +``` + +Alice can run a BFS of depth 2 to identify that N2 and N4 are good introduction nodes that provide +a large anonymity set. She can then provide the following blinded paths: + +* N2 -> Blinded(N1) -> Blinded(Alice) -> Blinded(Alice) +* N4 -> Blinded(N3) -> Blinded(Alice) -> Blinded(Alice) + +Alice should analyze the payment relay parameters of all channels in her anonymity set and choose +fees/cltv that would work for a large enough subset of them. + +Note that Alice chose non-overlapping paths: otherwise these paths may not have enough liquidity +to relay the payment she expects to receive, unless the path capacity is much larger than the +expected payment. + +When the receiver expects to receive large payments, liquidity may become an issue if it is +scattered among too many peers. The receiver may be forced to use introduction nodes that are +direct peers to ensure that enough liquidity is available (in which case it's particularly useful +to include dummy hops in the blinded paths). + ### Blinded trampoline route Route blinding can also be used with trampoline very easily. Instead of providing the @@ -486,6 +568,34 @@ next trampoline node. That `E(i)` can then be sent in the outer onion payload in lightning message's fields, which is even cleaner and doesn't require nodes between trampoline nodes to understand route blinding. +Using a blinded trampoline route is a good solution for public nodes that have many peers and +run into liquidity issues affecting payment reliability. Such recipients can choose trampoline +nodes that will be able to find many paths towards them: + +```text + +-------+ +-------+ + +----------| X |--------+ +--------| X |----------+ + | +-------+ | | +-------+ | + | | | | + | | | | ++-------+ +-------+ +-------+ +-------+ +-------+ +| T1 |------| X |------| Alice |------| X |------| T2 | ++-------+ +-------+ +-------+ +-------+ +-------+ + | | | | + | | | | + | +-------+ | | +-------+ | + +----------| X |--------+ +--------| X |----------+ + +-------+ +-------+ +``` + +Alice can provide the following blinded trampoline paths: + +* T1 -> Blinded(Alice) +* T2 -> Blinded(Alice) + +T1 and T2 will be able to find many paths towards Alice and retry whenever some paths fail, +working around the potential liquidity constraints. + ## FAQ ### Why not use rendezvous