1
0
mirror of https://github.com/lightning/bolts.git synced 2024-11-19 01:50:03 +01:00

Merge pull request #1151 from Roasbeef/blinded-paths-notation

BOLT-04: use underscores in place of parens for blinded paths notation
This commit is contained in:
Olaoluwa Osuntokun 2024-04-22 13:21:55 -07:00 committed by GitHub
commit db278ab9b2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -492,58 +492,58 @@ may contain the following TLV fields:
#### Requirements
A recipient N(r) creating a blinded route `N(0) -> N(1) -> ... -> N(r)` to itself:
A recipient $`N_r`$ creating a blinded route $`N_0 \rightarrow N_1 \rightarrow ... \rightarrow 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`
- MUST create a blinded node ID $`B_i`$ for each node using the following algorithm:
- $`e_0 /leftarrow {0;1}^256`$ ($`e_0`$ SHOULD be obtained via CSPRG)
- $`E_0 = e_0 \cdot 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)`)
- 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
- 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(\text{"blinded\_node\_id"}, ss_i) * N_i`$ (blinded `node_id` for $`N_i`$, private key known only by $`N_i`$)
- $`rho_i = HMAC256(\text{"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`$)
- 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
A reader:
- 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.
- 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.
$`HMAC256(\text{"blinded\_node\_id}", ss_i)`$ which achieves the same result.
- Otherwise:
- MUST use `k(i)` to decrypt the onion, to extract `current_blinding_point` (`E(i)`).
- 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 decrypt the `encrypted_data` field using `rho(i)` and use the
- $`ss_i = SHA256(k_i * E_i)`$ (standard ECDH)
- $`b_i = HMAC256(\text{"blinded\_node\_id"}, ss_i) * k_i`$
- $`rho_i = HMAC256(\text{"rho"}, ss_i)`$
- $`E_{i+1} = SHA256(E_i || ss_i) * E_i`$
- 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)`
- 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 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))`
- MUST decrypt the `encrypted_data` field using `rho(r)`
- $`ss_r = SHA256(k_r * E_r)`$ (standard ECDH)
- $`b_r = HMAC256(\text{"blinded\_node\_id"}, ss_r) * k_r`$
- $`rho_r = HMAC256(\text{"rho"}, ss_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
@ -557,7 +557,7 @@ 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
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.
@ -570,7 +570,7 @@ 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
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