1
0
Fork 0
mirror of https://github.com/lightning/bolts.git synced 2025-03-10 17:18:44 +01:00

BOLT 8: use incremented numbers for numbering.

Markdown doesn't care, but we have humans reading the text.

Reported-by: @roasbeef
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2018-01-30 14:10:05 +10:30
parent 0f50cc220d
commit 58f6a70889

View file

@ -226,47 +226,47 @@ and 16 bytes for the `poly1305` tag.
**Sender Actions:** **Sender Actions:**
1. `e = generateKey()` 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 * The newly generated ephemeral key is accumulated into the running
handshake digest. handshake digest.
1. `ss = ECDH(rs, e.priv)` 3. `ss = ECDH(rs, e.priv)`
* The initiator performs an ECDH between its newly generated ephemeral * The initiator performs an ECDH between its newly generated ephemeral
key and the remote node's static public key. 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 * A new temporary encryption key is generated, which is
used to generate the authenticating MAC. 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 * 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 * Finally, the generated ciphertext is accumulated into the authenticating
handshake digest. 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:** **Receiver Actions:**
1. Read _exactly_ 50 bytes from the network buffer. 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 * 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` 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 * 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 deserialized into a point on the curve using affine coordinates as encoded
by the key's serialized composed format. 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. 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 * The responder accumulates the initiator's ephemeral key into the authenticating
handshake digest. 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 * The responder performs an ECDH between its static public key and the
initiator's ephemeral public key. 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 * A new temporary encryption key is generated, which will
shortly be used to check the authenticating MAC. 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_ * 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 know the responder's static public key. If so, then the responder MUST terminate the
connection without any further messages. 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 * The received ciphertext is mixed into the handshake digest. This step serves
to ensure the payload wasn't modified by a MiTM. to ensure the payload wasn't modified by a MiTM.
@ -288,44 +288,44 @@ for the `poly1305` tag.
**Sender Actions:** **Sender Actions:**
1. `e = generateKey()` 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 * The newly generated ephemeral key is accumulated into the running
handshake digest. 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 * where `re` is the ephemeral key of the initiator, which was received
during Act One 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 * A new temporary encryption key is generated, which is
used to generate the authenticating MAC. 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 * 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 * Finally, the generated ciphertext is accumulated into the authenticating
handshake digest. 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:** **Receiver Actions:**
1. Read _exactly_ 50 bytes from the network buffer. 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 * 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` 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. abort the connection attempt.
1. `h = SHA-256(h || re.serializeCompressed())` 4. `h = SHA-256(h || re.serializeCompressed())`
1. `ss = ECDH(re, e.priv)` 5. `ss = ECDH(re, e.priv)`
* where `re` is the responder's ephemeral public key * where `re` is the responder's ephemeral public key
* The raw bytes of the remote party's ephemeral public key (`re`) are to be * 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 deserialized into a point on the curve using affine coordinates as encoded
by the key's serialized composed format. 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 * A new temporary encryption key is generated, which is
used to generate the authenticating MAC. 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 * If the MAC check in this operation fails, then the initiator MUST
terminate the connection without any further messages. 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 * The received ciphertext is mixed into the handshake digest. This step serves
to ensure the payload wasn't modified by a MiTM. to ensure the payload wasn't modified by a MiTM.
@ -351,14 +351,14 @@ construction, and 16 bytes for a final authenticating tag.
1. `c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())` 1. `c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())`
* where `s` is the static public key of the initiator * where `s` is the static public key of the initiator
1. `h = SHA-256(h || c)` 2. `h = SHA-256(h || c)`
1. `ss = ECDH(re, s.priv)` 3. `ss = ECDH(re, s.priv)`
* where `re` is the ephemeral public key of the responder. * 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. * 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 * 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, * where `zero` is a zero-length plaintext,
`sk` is the key to be used by the initiator to encrypt messages to the `sk` is the key to be used by the initiator to encrypt messages to the
responder, responder,
@ -366,28 +366,28 @@ construction, and 16 bytes for a final authenticating tag.
the responder the responder
* The final encryption keys to be used for sending and * The final encryption keys to be used for sending and
receiving messages for the duration of the session are generated. 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. * 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:** **Receiver Actions:**
1. Read _exactly_ 66 bytes from the network buffer. 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:]` 2. 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 3. If `v` is an unrecognized handshake version, then the responder MUST
abort the connection attempt. 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 * At this point, the responder has recovered the static public key of the
initiator. initiator.
1. `h = SHA-256(h || c)` 5. `h = SHA-256(h || c)`
1. `ss = ECDH(rs, e.priv)` 6. `ss = ECDH(rs, e.priv)`
* where `e` is the responder's original ephemeral key * where `e` is the responder's original ephemeral key
1. `ck, temp_k3 = HKDF(ck, ss)` 7. `ck, temp_k3 = HKDF(ck, ss)`
1. `p = decryptWithAD(temp_k3, 0, h, t)` 8. `p = decryptWithAD(temp_k3, 0, h, t)`
* If the MAC check in this operation fails, then the responder MUST * If the MAC check in this operation fails, then the responder MUST
terminate the connection without any further messages. 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, * where `zero` is a zero-length plaintext,
`rk` is the key to be used by the responder to decrypt the messages sent `rk` is the key to be used by the responder to decrypt the messages sent
by the initiator, by the initiator,
@ -395,7 +395,7 @@ construction, and 16 bytes for a final authenticating tag.
the initiator the initiator
* The final encryption keys to be used for sending and * The final encryption keys to be used for sending and
receiving messages for the duration of the session are generated. 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. * The sending and receiving nonces are initialized to zero.
## Lightning Message Specification ## Lightning Message Specification
@ -445,18 +445,18 @@ In order to encrypt a Lightning message (`m`), given a sending key (`sk`) and a
1. let `l = len(m)` 1. let `l = len(m)`
* where `len` obtains the length in bytes of the Lightning message * where `len` obtains the length in bytes of the Lightning message
1. Serialize `l` into 2 bytes encoded as a big-endian integer. 2. Serialize `l` into 2 bytes encoded as a big-endian integer.
1. Encrypt `l` (using `ChaChaPoly-1305`, `sn`, and `sk`), to obtain `lc` 3. Encrypt `l` (using `ChaChaPoly-1305`, `sn`, and `sk`), to obtain `lc`
(18 bytes) (18 bytes)
* The nonce `sn` is encoded as a 96-bit little-endian number. As the * 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 decoded nonce is 64 bits, the 96-bit nonce is encoded as: 32 bits
of leading zeroes followed by a 64-bit value. of leading zeroes followed by a 64-bit value.
* The nonce `sn` MUST be incremented after this step. * The nonce `sn` MUST be incremented after this step.
* A zero-length byte slice is to be passed as the AD (associated data). * 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`. encrypt the length prefix. Let encrypted ciphertext be known as `c`.
* The nonce `sn` MUST be incremented after this step. * 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 ### Decrypting Messages
@ -465,14 +465,14 @@ In order to decrypt the _next_ message in the network stream, the following is
done: done:
1. Read _exactly_ 18 bytes from the network buffer. 1. Read _exactly_ 18 bytes from the network buffer.
1. Let the encrypted length prefix be known as `lc` 2. Let the encrypted length prefix be known as `lc`
1. Decrypt `lc` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to obtain the size of 3. Decrypt `lc` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to obtain the size of
the encrypted packet `l`. the encrypted packet `l`.
* A zero-length byte slice is to be passed as the AD (associated data). * A zero-length byte slice is to be passed as the AD (associated data).
* The nonce `rn` MUST be incremented after this step. * 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`. `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`. plaintext packet `p`.
* The nonce `rn` MUST be incremented after this step. * The nonce `rn` MUST be incremented after this step.
@ -491,10 +491,10 @@ to it exceeds 1000.
Key rotation for a key `k` is performed according to the following: 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. Let `ck` be the chaining key obtained at the end of Act Three.
1. `ck', k' = HKDF(ck, k)` 2. `ck', k' = HKDF(ck, k)`
1. Reset the nonce for the key to `n = 0`. 3. Reset the nonce for the key to `n = 0`.
1. `k = k'` 4. `k = k'`
1. `ck = ck'` 5. `ck = ck'`
# Security Considerations # Security Considerations