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:
commit
db278ab9b2
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user