From ed012edc15998ed378ede999fad9b181297a0f28 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 27 Mar 2024 18:03:35 -0700 Subject: [PATCH] BOLT-04: convert blinded paths syntax to use LaTeX rendering Github now supports inline LaTeX rendering: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/writing-mathematical-expressions In this commit, we use this new feature to improve the rendering of the routines for blinded paths. --- 04-onion-routing.md | 60 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/04-onion-routing.md b/04-onion-routing.md index e4cd40a..30a6352 100644 --- a/04-onion-routing.md +++ b/04-onion-routing.md @@ -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