Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BOLT-04: use underscores in place of parens for blinded paths notation #1151

Merged
merged 2 commits into from
Apr 22, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 30 additions & 30 deletions 04-onion-routing.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of like the LaTeX rendering. However, generally I would prefer to have changes to notation/style made globally rather locally, which could lead to confusion when similar/the same things are rendered differently in different parts of the specs. So, IMO it would be better to stick to ASCII/markdown rendering if we're not planning to change all BOLTs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm down to do it all. Main tradeoff I think is that it looks great when viewed on Github, but if you view the raw markdown then there's a lot of extra markup that just gets in the way.

We can also just include this first commit, then do the second one more broadly in another PR.

Original file line number Diff line number Diff line change
Expand Up @@ -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` SHOULD be obtained via CSPRG)
- `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}`
- 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
- 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
Expand Down