t-bast
4 years ago
1 changed files with 322 additions and 0 deletions
@ -0,0 +1,322 @@ |
|||
# Sphinx onion encryption: from Zero to Hero |
|||
|
|||
Lightning uses an onion encryption scheme called [Sphinx](http://www.cypherpunks.ca/~iang/pubs/Sphinx_Oakland09.pdf) |
|||
to guarantee privacy along a payment path. |
|||
|
|||
This article describes the Sphinx construction. |
|||
It can be particularly helpful for future implementers, curious users or people who want to tinker |
|||
with the crypto to provide new functionalities (such as rendezvous routing). |
|||
|
|||
## Table of Contents |
|||
|
|||
* [Notations](#notations) |
|||
* [Computing shared secrets](#computing-shared-secrets) |
|||
* [Generating a filler](#generating-a-filler) |
|||
* [Creating the payload](#creating-the-payload) |
|||
* [Decrypting the hop payload](#decrypting-the-hop-payload) |
|||
* [Full diagram](#full-diagram) |
|||
|
|||
## Notations |
|||
|
|||
```text |
|||
Alice -> N(1) -> N(2) -> ... -> N(r) |
|||
``` |
|||
|
|||
N(i)'s `node_id` is P(i) = k(i) * G. |
|||
The length of the encrypted payload sent to N(i) is l(i) (this includes the inner mac). |
|||
The total payload length is 1300 bytes. |
|||
|
|||
## Computing shared secrets |
|||
|
|||
* session_key <- {0;1}^256 |
|||
* ek(1) = session_key |
|||
* Shared with N(1): |
|||
* E(1) = ek(1) * G (sent unencrypted in the onion header) |
|||
* ss(1) = H(ek(1) * P(1)) = H(k(1) * E(1)) |
|||
* rho(1) = HMAC(0x72686F, ss(1)) |
|||
* b(1) = H(E(1) || ss(1)) |
|||
* ... |
|||
* ek(i) = b(i-1) * ek(i-1) |
|||
* Shared with N(i): |
|||
* E(i) = ek(i) * G (sent unencrypted in the onion header) |
|||
* ss(i) = H(ek(i) * P(i)) = H(k(i) * E(i)) |
|||
* rho(i) = HMAC(0x72686F, ss(i)) |
|||
* b(i) = H(E(i) || ss(i)) |
|||
|
|||
Every N(i) is able to compute E(i+1) = b(i) * E(i). |
|||
|
|||
## Generating a filler |
|||
|
|||
* Generate filler for payloads 1 to (r-1) |
|||
* Total of `l(1) + l(2) + ... + l(r-1)` bytes |
|||
* filler = [] |
|||
* For i <- 1..(r-1): |
|||
* filler <- (filler + [0; l(i)]) xor stream(rho(i))[1300-l(i-1)-...-l(1):1300+l(i)] |
|||
|
|||
Example filler for 3 nodes: |
|||
|
|||
```text |
|||
<---l(1)---> |
|||
+----------+ |
|||
| 00000000 | |
|||
+----------+ |
|||
(+) |
|||
<-----------------1300-----------------><---l(1)---> |
|||
+--------------------------------------------------+ |
|||
| stream(rho(1)) | |
|||
+--------------------------------------------------+ |
|||
= |
|||
<---l(1)---><-----l(2)-----> |
|||
+----------++--------------+ |
|||
| xxxxxxxx || 000000000000 | |
|||
+----------++--------------+ |
|||
(+) |
|||
<-----------------1300-------------><-----l(2)-----> |
|||
+--------------------------------------------------+ |
|||
| stream(rho(2)) | |
|||
+--------------------------------------------------+ |
|||
= |
|||
<---l(1) + l(2)------------><----l(3)----> |
|||
+--------------------------++------------+ |
|||
| xxxxxxxxxxxxxxxxxxxxxxxx || 0000000000 | |
|||
+--------------------------++------------+ |
|||
(+) |
|||
<-----------------1300---------------><----l(3)----> |
|||
+--------------------------------------------------+ |
|||
| stream(rho(3)) | |
|||
+--------------------------------------------------+ |
|||
= |
|||
<---l(1) + l(2) + l(3)-------------------> |
|||
+----------------------------------------+ |
|||
| xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
|||
+----------------------------------------+ |
|||
``` |
|||
|
|||
## Creating the payload |
|||
|
|||
The payload is encrypted hop by hop, starting from the recipient. |
|||
Every hop is authenticated. |
|||
I'm ignoring the mac handling for simplicity, but there's nothing complicated with it. |
|||
|
|||
* Special case for the recipient: |
|||
* payload(r) = ((p(r) + random bytes) xor stream(rho(r))[0:1300-l(r-1)-...-l(1)]) + filler |
|||
* For i <- (r-1)..1: |
|||
* payload(i) = (p(i) + payload(i-1)[0:1300-l(i)]) xor stream(rho(i)) |
|||
|
|||
```text |
|||
<--------1300-------------------------------------------------------------------> |
|||
<---l(r)---><-------------------------><----l(1) + l(2) + l(3)------------------> |
|||
+----------++-------------------------++----------------------------------------+ |
|||
| p(r) || random initial bytes || xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
|||
+----------++-------------------------++----------------------------------------+ |
|||
(+) |
|||
<-------1300 - l(1) - l(2) - l(3)-----> |
|||
+-------------------------------------+ |
|||
| stream(rho(r)) | |
|||
+-------------------------------------+ |
|||
= |
|||
<--------1300-------------------------------------------------------------------> |
|||
+-------------------------------------------------------------------------------+ |
|||
| encrypted payload for N(r) | |
|||
+-------------------------------------------------------------------------------+ |
|||
<----l(3)----><-------1300 - l(3)-----------------------------------------------> |
|||
+------------++-----------------------------------------------------------------+ |
|||
| p(3) || encrypted payload for N(r) (truncated) | |
|||
+------------++-----------------------------------------------------------------+ |
|||
(+) |
|||
+-------------------------------------------------------------------------------+ |
|||
| stream(rho(3)) | |
|||
+-------------------------------------------------------------------------------+ |
|||
= |
|||
<--------1300-------------------------------------------------------------------> |
|||
+-------------------------------------------------------------------------------+ |
|||
| encrypted payload for N(3) | |
|||
+-------------------------------------------------------------------------------+ |
|||
<-----l(2)-----><-------1300 - l(2)---------------------------------------------> |
|||
+--------------++---------------------------------------------------------------+ |
|||
| p(2) || encrypted payload for N(3) (truncated) | |
|||
+--------------++---------------------------------------------------------------+ |
|||
(+) |
|||
+-------------------------------------------------------------------------------+ |
|||
| stream(rho(2)) | |
|||
+-------------------------------------------------------------------------------+ |
|||
= |
|||
<--------1300-------------------------------------------------------------------> |
|||
+-------------------------------------------------------------------------------+ |
|||
| encrypted payload for N(2) | |
|||
+-------------------------------------------------------------------------------+ |
|||
<---l(1)---><--------1300 - l(1)------------------------------------------------> |
|||
+----------++-------------------------------------------------------------------+ |
|||
| p(1) || encrypted payload for N(2) (truncated) | |
|||
+----------++-------------------------------------------------------------------+ |
|||
(+) |
|||
+-------------------------------------------------------------------------------+ |
|||
| stream(rho(1)) | |
|||
+-------------------------------------------------------------------------------+ |
|||
= |
|||
<--------1300-------------------------------------------------------------------> |
|||
+-------------------------------------------------------------------------------+ |
|||
| encrypted payload for N(1) | |
|||
+-------------------------------------------------------------------------------+ |
|||
``` |
|||
|
|||
## Decrypting the hop payload |
|||
|
|||
This is where the filler matters: because it's generated with the same stream |
|||
cipher, decrypting re-creates it on-the-fly (and thus ensures macs are valid). |
|||
|
|||
```text |
|||
<--------1300-------------------------------------------------------------------> |
|||
+-------------------------------------------------------------------------------+ |
|||
| encrypted payload for N(1) | |
|||
+-------------------------------------------------------------------------------+ |
|||
(+) <---l(1)---> |
|||
+-------------------------------------------------------------------------------------------+ |
|||
| stream(rho(1)) | |
|||
+-------------------------------------------------------------------------------------------+ |
|||
= |
|||
<---l(1)---><--------1300-------------------------------------------------------------------> |
|||
+----------++-------------------------------------------------------------------------------+ |
|||
| p(1) || encrypted payload for N(2) | |
|||
+----------++-------------------------------------------------------------------------------+ |
|||
(+) <-----l(2)-----> |
|||
+-----------------------------------------------------------------------------------------------+ |
|||
| stream(rho(2)) | |
|||
+-----------------------------------------------------------------------------------------------+ |
|||
<-----l(2)-----> = |
|||
+--------------++-------------------------------------------------------------------------------+ |
|||
| p(2) || encrypted payload for N(3) | |
|||
+--------------++-------------------------------------------------------------------------------+ |
|||
(+) <----l(3)----> |
|||
+---------------------------------------------------------------------------------------------+ |
|||
| stream(rho(3)) | |
|||
+---------------------------------------------------------------------------------------------+ |
|||
<----l(3)----> = |
|||
+------------++-------------------------------------------------------------------------------+ |
|||
| p(3) || encrypted payload for N(r) | |
|||
+------------++-------------------------------------------------------------------------------+ |
|||
(+) |
|||
+-------------------------------------------------------------------------------+ |
|||
| stream(rho(r)) | |
|||
+-------------------------------------------------------------------------------+ |
|||
= |
|||
<--------1300-------------------------------------------------------------------> |
|||
<---l(r)---><-------------------------><--- l(1) + l(2) + l(3) -----------------> |
|||
+----------++-------------------------++----------------------------------------+ |
|||
| p(r) || random initial bytes || xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx | |
|||
+----------++-------------------------++----------------------------------------+ |
|||
``` |
|||
|
|||
## Full diagram |
|||
|
|||
```text |
|||
Alice -> Bob -> Carol -> Dave |
|||
``` |
|||
|
|||
```text |
|||
1. Filler Generation |
|||
|
|||
<-----l(B)-----> |
|||
+--------------+ |
|||
| 000000000000 | |
|||
+--------------+ |
|||
(+) |
|||
<-----------------1300------------------------------------------><-----l(B)-----> |
|||
+-------------------------------------------------------------------------------+ |
|||
| stream(ss(Bob)) | |
|||
+-------------------------------------------------------------------------------+ |
|||
= |
|||
<-----l(B)-----><-l(C)-> |
|||
+--------------++------+ |
|||
| xxxxxxxxxxxx || 0000 | |
|||
+--------------++------+ |
|||
(+) |
|||
<-----------------1300------------------------------------------><-l(C)-> |
|||
+-----------------------------------------------------------------------+ |
|||
| stream(ss(C)) | |
|||
+-----------------------------------------------------------------------+ |
|||
= |
|||
<-----l(B) + l(C)------> |
|||
+----------------------+ |
|||
| xxxxxxxxxxxxxxxxxxxx | |
|||
+----------------------+ |
|||
|
|||
2. Onion Encryption |
|||
|
|||
<-----------------1300------------------------------------------> |
|||
<----l(D)----><-------------------------><------l(B) + l(C)-----> |
|||
+------------++-------------------------++----------------------+ |
|||
| p(D) || random init bytes || xxxxxxxxxxxxxxxxxxxx | |
|||
+------------++-------------------------++----------------------+ |
|||
(+) |
|||
<---------1300 - l(B) - l(C)------------> |
|||
+---------------------------------------+ |
|||
| stream(ss(D)) | |
|||
+---------------------------------------+ |
|||
= |
|||
<---------1300 - l(B) - l(C)------------><------l(B) + l(C)-----> |
|||
+---------------------------------------++----------------------+ |
|||
| encrypted payload for Dave || xxxxxxxxxxxxxxxxxxxx | |
|||
+---------------------------------------++----------------------+ |
|||
<-l(C)-><--------1300 - l(C)------------------------------------> |
|||
+------++-------------------------------------------------------+ |
|||
| p(C) || encrypted payload for Dave (truncated) | |
|||
+------++-------------------------------------------------------+ |
|||
(+) |
|||
+---------------------------------------------------------------+ |
|||
| stream(ss(C)) | |
|||
+---------------------------------------------------------------+ |
|||
= |
|||
<--------1300---------------------------------------------------> |
|||
+---------------------------------------------------------------+ |
|||
| encrypted payload for Carol | |
|||
+---------------------------------------------------------------+ |
|||
<-----l(B)-----><----------1300 - l(B)--------------------------> |
|||
+--------------++-----------------------------------------------+ |
|||
| p(B) || encrypted payload for Carol (truncated) | |
|||
+--------------++-----------------------------------------------+ |
|||
(+) |
|||
+---------------------------------------------------------------+ |
|||
| stream(ss(B)) | |
|||
+---------------------------------------------------------------+ |
|||
= |
|||
<--------1300---------------------------------------------------> |
|||
+---------------------------------------------------------------+ |
|||
| encrypted payload for Bob | |
|||
+---------------------------------------------------------------+ |
|||
|
|||
3. Onion Decryption |
|||
|
|||
<--------1300---------------------------------------------------> |
|||
+---------------------------------------------------------------+ |
|||
| encrypted payload for Bob | |
|||
+---------------------------------------------------------------+ |
|||
(+) <-----l(B)-----> |
|||
+-------------------------------------------------------------------------------+ |
|||
| stream(ss(B)) | |
|||
+-------------------------------------------------------------------------------+ |
|||
= |
|||
<-----l(B)-----><------- 1300 --------------------------------------------------> |
|||
+--------------++---------------------------------------------------------------+ |
|||
| p(B) || encrypted payload for Carol | |
|||
+--------------++---------------------------------------------------------------+ |
|||
(+) <-l(C)-> |
|||
+-----------------------------------------------------------------------+ |
|||
| stream(ss(C)) | |
|||
+-----------------------------------------------------------------------+ |
|||
= |
|||
<-l(C)-><------- 1300 --------------------------------------------------> |
|||
+------++---------------------------------------------------------------+ |
|||
| p(C) || encrypted payload for Dave | |
|||
+------++---------------------------------------------------------------+ |
|||
(+) |
|||
+---------------------------------------------------------------+ |
|||
| stream(ss(D)) | |
|||
+---------------------------------------------------------------+ |
|||
= |
|||
<-----------------1300------------------------------------------> |
|||
<----l(D)----><-------------------------><------l(B) + l(C)-----> |
|||
+------------++-------------------------++----------------------+ |
|||
| p(D) || random init bytes || xxxxxxxxxxxxxxxxxxxx | |
|||
+------------++-------------------------++----------------------+ |
|||
``` |
Loading…
Reference in new issue