Skip to content

Commit

Permalink
BOLT 8: use incremented numbers for numbering.
Browse files Browse the repository at this point in the history
Markdown doesn't care, but we have humans reading the text.

Reported-by: @Roasbeef
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell committed Jan 30, 2018
1 parent 0f50cc2 commit 58f6a70
Showing 1 changed file with 54 additions and 54 deletions.
108 changes: 54 additions & 54 deletions 08-transport.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,47 +226,47 @@ and 16 bytes for the `poly1305` tag.
**Sender Actions:**

1. `e = generateKey()`
1. `h = SHA-256(h || e.pub.serializeCompressed())`
2. `h = SHA-256(h || e.pub.serializeCompressed())`
* The newly generated ephemeral key is accumulated into the running
handshake digest.
1. `ss = ECDH(rs, e.priv)`
3. `ss = ECDH(rs, e.priv)`
* The initiator performs an ECDH between its newly generated ephemeral
key and the remote node's static public key.
1. `ck, temp_k1 = HKDF(ck, ss)`
4. `ck, temp_k1 = HKDF(ck, ss)`
* A new temporary encryption key is generated, which is
used to generate the authenticating MAC.
1. `c = encryptWithAD(temp_k1, 0, h, zero)`
5. `c = encryptWithAD(temp_k1, 0, h, zero)`
* where `zero` is a zero-length plaintext
1. `h = SHA-256(h || c)`
6. `h = SHA-256(h || c)`
* Finally, the generated ciphertext is accumulated into the authenticating
handshake digest.
1. Send `m = 0 || e.pub.serializeCompressed() || c` to the responder over the network buffer.
7. Send `m = 0 || e.pub.serializeCompressed() || c` to the responder over the network buffer.

**Receiver Actions:**

1. Read _exactly_ 50 bytes from the network buffer.
1. Parse out the read message (`m`) into `v = m[0]`, `re = m[1:33]`, and `c = m[34:]`.
2. Parse out the read message (`m`) into `v = m[0]`, `re = m[1:33]`, and `c = m[34:]`.
* where `m[0]` is the _first_ byte of `m`, `m[1:33]` is the next 33
bytes of `m`, and `m[34:]` is the last 16 bytes of `m`
* The raw bytes of the remote party's ephemeral public key (`e`) are to be
deserialized into a point on the curve using affine coordinates as encoded
by the key's serialized composed format.
1. If `v` is an unrecognized handshake version, then the responder MUST
3. If `v` is an unrecognized handshake version, then the responder MUST
abort the connection attempt.
1. `h = SHA-256(h || re.serializeCompressed())`
4. `h = SHA-256(h || re.serializeCompressed())`
* The responder accumulates the initiator's ephemeral key into the authenticating
handshake digest.
1. `ss = ECDH(re, s.priv)`
5. `ss = ECDH(re, s.priv)`
* The responder performs an ECDH between its static public key and the
initiator's ephemeral public key.
1. `ck, temp_k1 = HKDF(ck, ss)`
6. `ck, temp_k1 = HKDF(ck, ss)`
* A new temporary encryption key is generated, which will
shortly be used to check the authenticating MAC.
1. `p = decryptWithAD(temp_k1, 0, h, c)`
7. `p = decryptWithAD(temp_k1, 0, h, c)`
* If the MAC check in this operation fails, then the initiator does _not_
know the responder's static public key. If so, then the responder MUST terminate the
connection without any further messages.
1. `h = SHA-256(h || c)`
8. `h = SHA-256(h || c)`
* The received ciphertext is mixed into the handshake digest. This step serves
to ensure the payload wasn't modified by a MiTM.

Expand All @@ -288,44 +288,44 @@ for the `poly1305` tag.
**Sender Actions:**

1. `e = generateKey()`
1. `h = SHA-256(h || e.pub.serializeCompressed())`
2. `h = SHA-256(h || e.pub.serializeCompressed())`
* The newly generated ephemeral key is accumulated into the running
handshake digest.
1. `ss = ECDH(re, e.priv)`
3. `ss = ECDH(re, e.priv)`
* where `re` is the ephemeral key of the initiator, which was received
during Act One
1. `ck, temp_k2 = HKDF(ck, ss)`
4. `ck, temp_k2 = HKDF(ck, ss)`
* A new temporary encryption key is generated, which is
used to generate the authenticating MAC.
1. `c = encryptWithAD(temp_k2, 0, h, zero)`
5. `c = encryptWithAD(temp_k2, 0, h, zero)`
* where `zero` is a zero-length plaintext
1. `h = SHA-256(h || c)`
6. `h = SHA-256(h || c)`
* Finally, the generated ciphertext is accumulated into the authenticating
handshake digest.
1. Send `m = 0 || e.pub.serializeCompressed() || c` to the initiator over the network buffer.
7. Send `m = 0 || e.pub.serializeCompressed() || c` to the initiator over the network buffer.


**Receiver Actions:**

1. Read _exactly_ 50 bytes from the network buffer.
1. Parse out the read message (`m`) into `v = m[0]`, `re = m[1:33]`, and `c = m[34:]`.
2. Parse out the read message (`m`) into `v = m[0]`, `re = m[1:33]`, and `c = m[34:]`.
* where `m[0]` is the _first_ byte of `m`, `m[1:33]` is the next 33
bytes of `m`, and `m[34:]` is the last 16 bytes of `m`
1. If `v` is an unrecognized handshake version, then the responder MUST
3. If `v` is an unrecognized handshake version, then the responder MUST
abort the connection attempt.
1. `h = SHA-256(h || re.serializeCompressed())`
1. `ss = ECDH(re, e.priv)`
4. `h = SHA-256(h || re.serializeCompressed())`
5. `ss = ECDH(re, e.priv)`
* where `re` is the responder's ephemeral public key
* The raw bytes of the remote party's ephemeral public key (`re`) are to be
deserialized into a point on the curve using affine coordinates as encoded
by the key's serialized composed format.
1. `ck, temp_k2 = HKDF(ck, ss)`
6. `ck, temp_k2 = HKDF(ck, ss)`
* A new temporary encryption key is generated, which is
used to generate the authenticating MAC.
1. `p = decryptWithAD(temp_k2, 0, h, c)`
7. `p = decryptWithAD(temp_k2, 0, h, c)`
* If the MAC check in this operation fails, then the initiator MUST
terminate the connection without any further messages.
1. `h = SHA-256(h || c)`
8. `h = SHA-256(h || c)`
* The received ciphertext is mixed into the handshake digest. This step serves
to ensure the payload wasn't modified by a MiTM.

Expand All @@ -351,51 +351,51 @@ construction, and 16 bytes for a final authenticating tag.

1. `c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())`
* where `s` is the static public key of the initiator
1. `h = SHA-256(h || c)`
1. `ss = ECDH(re, s.priv)`
2. `h = SHA-256(h || c)`
3. `ss = ECDH(re, s.priv)`
* where `re` is the ephemeral public key of the responder.
1. `ck, temp_k3 = HKDF(ck, ss)`
4. `ck, temp_k3 = HKDF(ck, ss)`
* The final intermediate shared secret is mixed into the running chaining key.
1. `t = encryptWithAD(temp_k3, 0, h, zero)`
5. `t = encryptWithAD(temp_k3, 0, h, zero)`
* where `zero` is a zero-length plaintext
1. `sk, rk = HKDF(ck, zero)`
6. `sk, rk = HKDF(ck, zero)`
* where `zero` is a zero-length plaintext,
`sk` is the key to be used by the initiator to encrypt messages to the
responder,
and `rk` is the key to be used by the initiator to decrypt messages sent by
the responder
* The final encryption keys to be used for sending and
receiving messages for the duration of the session are generated.
1. `rn = 0, sn = 0`
7. `rn = 0, sn = 0`
* The sending and receiving nonces are initialized to zero.
1. Send `m = 0 || c || t` over the network buffer.
8. Send `m = 0 || c || t` over the network buffer.


**Receiver Actions:**

1. Read _exactly_ 66 bytes from the network buffer.
1. Parse out the read message (`m`) into `v = m[0]`, `c = m[1:49]` and `t = m[50:]`
1. If `v` is an unrecognized handshake version, then the responder MUST
2. Parse out the read message (`m`) into `v = m[0]`, `c = m[1:49]` and `t = m[50:]`
3. If `v` is an unrecognized handshake version, then the responder MUST
abort the connection attempt.
1. `rs = decryptWithAD(temp_k2, 1, h, c)`
4. `rs = decryptWithAD(temp_k2, 1, h, c)`
* At this point, the responder has recovered the static public key of the
initiator.
1. `h = SHA-256(h || c)`
1. `ss = ECDH(rs, e.priv)`
5. `h = SHA-256(h || c)`
6. `ss = ECDH(rs, e.priv)`
* where `e` is the responder's original ephemeral key
1. `ck, temp_k3 = HKDF(ck, ss)`
1. `p = decryptWithAD(temp_k3, 0, h, t)`
7. `ck, temp_k3 = HKDF(ck, ss)`
8. `p = decryptWithAD(temp_k3, 0, h, t)`
* If the MAC check in this operation fails, then the responder MUST
terminate the connection without any further messages.
1. `rk, sk = HKDF(ck, zero)`
9. `rk, sk = HKDF(ck, zero)`
* where `zero` is a zero-length plaintext,
`rk` is the key to be used by the responder to decrypt the messages sent
by the initiator,
and `sk` is the key to be used by the responder to encrypt messages to
the initiator
* The final encryption keys to be used for sending and
receiving messages for the duration of the session are generated.
1. `rn = 0, sn = 0`
10. `rn = 0, sn = 0`
* The sending and receiving nonces are initialized to zero.

## Lightning Message Specification
Expand Down Expand Up @@ -445,18 +445,18 @@ In order to encrypt a Lightning message (`m`), given a sending key (`sk`) and a

1. let `l = len(m)`
* where `len` obtains the length in bytes of the Lightning message
1. Serialize `l` into 2 bytes encoded as a big-endian integer.
1. Encrypt `l` (using `ChaChaPoly-1305`, `sn`, and `sk`), to obtain `lc`
2. Serialize `l` into 2 bytes encoded as a big-endian integer.
3. Encrypt `l` (using `ChaChaPoly-1305`, `sn`, and `sk`), to obtain `lc`
(18 bytes)
* The nonce `sn` is encoded as a 96-bit little-endian number. As the
decoded nonce is 64 bits, the 96-bit nonce is encoded as: 32 bits
of leading zeroes followed by a 64-bit value.
* The nonce `sn` MUST be incremented after this step.
* A zero-length byte slice is to be passed as the AD (associated data).
1. Finally, encrypt the message itself (`m`) using the same procedure used to
4. Finally, encrypt the message itself (`m`) using the same procedure used to
encrypt the length prefix. Let encrypted ciphertext be known as `c`.
* The nonce `sn` MUST be incremented after this step.
1. Send `lc || c` over the network buffer.
5. Send `lc || c` over the network buffer.


### Decrypting Messages
Expand All @@ -465,14 +465,14 @@ In order to decrypt the _next_ message in the network stream, the following is
done:

1. Read _exactly_ 18 bytes from the network buffer.
1. Let the encrypted length prefix be known as `lc`
1. Decrypt `lc` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to obtain the size of
2. Let the encrypted length prefix be known as `lc`
3. Decrypt `lc` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to obtain the size of
the encrypted packet `l`.
* A zero-length byte slice is to be passed as the AD (associated data).
* The nonce `rn` MUST be incremented after this step.
1. Read _exactly_ `l+16` bytes from the network buffer, let the bytes be known as
4. Read _exactly_ `l+16` bytes from the network buffer, let the bytes be known as
`c`.
1. Decrypt `c` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to obtain decrypted
5. Decrypt `c` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to obtain decrypted
plaintext packet `p`.
* The nonce `rn` MUST be incremented after this step.

Expand All @@ -491,10 +491,10 @@ to it exceeds 1000.
Key rotation for a key `k` is performed according to the following:

1. Let `ck` be the chaining key obtained at the end of Act Three.
1. `ck', k' = HKDF(ck, k)`
1. Reset the nonce for the key to `n = 0`.
1. `k = k'`
1. `ck = ck'`
2. `ck', k' = HKDF(ck, k)`
3. Reset the nonce for the key to `n = 0`.
4. `k = k'`
5. `ck = ck'`

# Security Considerations

Expand Down

0 comments on commit 58f6a70

Please sign in to comment.