diff --git a/brontide.asciidoc b/brontide.asciidoc new file mode 100644 index 0000000..de0bb79 --- /dev/null +++ b/brontide.asciidoc @@ -0,0 +1,603 @@ += Brontide: Lightning's Encrypted Message Transport + +== Intro + +Unlike the vanilla Bitcoin P2P network, every node in the Lightning Network is +identified by a unique public key which serves as it identity. By default, this +public key is used to end-to-end encrypt _all_ communication within the +network. Encryption by default at the lowest level of the protocol ensures that +all messages are authenticated, are immune to man-in-the-middle attacks, +snooping by 3rd parties, and ensures privacy at the fundamental transport +level. In this chapter, we'll learn about the encryption protocol used by the +Lightning network in detail. Upon completion of this chapter, the reader will +be familiar with the state of the art in encrypted messaging protocols, as well +as the various properties such a protocol provides to the network. It's worth +mentioning that the core of the encrypted message transport is _agonstic_ to +its usage within the context of the Lightning Network. As a result, the +custom encrypted message transport Lightning uses, commonly referred to as +"Brontide" (more on that later) can be dropped into any context that requires +encrypted communication between two parties. + +== The Channel Graph as Decentralized Public Key Infrastructure + +As we learned in the chapter on multi-hop forwarding, very node has a long-term +identity that is used as the identifier for a vertex during path finding and +also used in the asymmetric cryptographic operations related to the creation of +onion encrypted routing packets. This public key, which serves as a node's +long-term identity is included in the DNS bootstrapping response, as well as +embedded within the Channel Graph. As a result, before a node attempts to +connect out to another node on the P2P network, it already knows the public key +of the node it wishes to connect to. + +Additionally, if the node being connected to already h a series of public +channels within the graph, then the connecting node is able to further verify +the sanctity of the identity of the node. As the entire channel graph is fully +authenticated, one can view it as a sort of decentralized public key +infrastructure: in order to register a key, a public channel in the Bitcoin +blockchain must be opened, once a node no longer has any public channels, then +they've effectively been removed from the PKI. + +As Lightning is a decentralized network, it's imperative that no one central +party is designated the power to provision a public key identity within the +network. In place of a central party, the Lightning Network uses the Bitcoin +blockchain as a sybil mitigation mechanism, as gaining an identity on the +network has a tangible cost: the fee needed to create a channel in the +blockchain, as well as the opportunity cost of the capital allocated to their +channels. In the process of essentially rolling a domain specific PKI, the +Lightning network is able to significantly simply its encrypted transport +protocol as it doesn't need to deal with all the complexities that come along +with TLS, the Transport Layer Security protocol. + +== Why Not TLS? + +Readers familiar with the TLS system may be wondering at this point: why wasn't +TLS used in spite of the drawbacks of the existing PKI system? It is indeed a +fact that "self signed certificates" can be used to effectively sidestep the +existing global PKI system by simply asserting to the identity of a given +public key amongst a set of peers. However, even with the existing PKI system +out of the way, TLS has several drawbacks that prompted the creators of the LN +to instead opt for a more compact custom encryption protocol. + +To start with, TLS is a protocol that has been around for several decades and +as a result has evolved over time as new advances have been made in the space +of transport encryption. However, overtime this evolution has caused the +protocol to balloon in size and complexity. Over the past few decades several +vulnerabilities in TLS has been discovered, and patched with each evolution +further increasing the complexity of the protocol. As a result of the age of +the protocol several versions and iterations exist, meaning a client needs to +understand many of the prior iterations of the protocol in order to communicate +with a large portion of the public internet further increasing implementation +complexity. + +In the past several memory safety vulnerabilities have been discovered in +widely used implementations of SSL/TLS. Packaging such a protocol within every +Lightning node would serve to increase the attack surface of nodes exposed to +to the public peer to peer network. In order to increase the security of the +network as a whole, and minimize exploitable attack surface, the creators of +the LN instead opted to adopt the Noise Protocol Framework. Noise as a protocol +internalizes several of the security and privacy lessons learned over time due +to continual scrutiny of the TLS protocol over decades. In a way, the existence +of Noise allows the community to effective "start over", with a more compact, +simplified protocol that retains all the added benefits of TLS. + +== The Noise Protocol Framework + +The Noise Protocol Framework is a modern, extensible, and flexible message +encryption protocol designed by the creators of the Signal protocol. The Signal +protocol is one of the most widely used message encryption protocols in the +world. It's used by both Signal and Whatsapp, which cumulatively are used by +over a billion people around the world. The Noise framework is the result of +decades of evolution both within academia as well as industry of message +encryption protocols. Lightning uses the Noise protocol framework to implement +a _message oriented_ encryption protocol used by all nodes to communicate with +each other. + +A communication session using Noise has two distinct phases: the handshake +phase, and the messaging phase. Before two parties can communicate with each +other, they first need to arrive at a shared secret known only to them which +will be used to encrypt and authenticate messages sent to each other. A flavor +of an authenticated key agreement is used to arrive at a final shared key +between the tow parties. In the context of the Noise protocol, this +authenticated key agreement is referred to as a "handshake". Once that +handshake has been completed, both nodes can now being to send each other +encrypted messages. Each time peers need to connect, or reconnect to each +other, a fresh iteration of the handshake protocol is executed ensuring that +forward secrecy (leaking the key of a prior transcript doesn't compromise any +future transcripts) is achieved. + +As the Noise protocol allows a protocol designer to drop choose from several +cryptographic primitives such as symmetric encryption and public key +cryptography, its customary that each flavor of the Noise protocol is referred +to by a unique name. In the spirit of "Noise", each flavor of the protocol +selects a name derived from some sort of "noise". In the context of the +Lightning Network, the flavor of Noise use will be referred to from here on as +"Brontide". A brontide is a low billowing noise, similar to what one would hear +during a thunderstorm when very far away. + +=== Noise Protocol Handshakes + +The Noise protocol is extremely flexible in that it advertises several +handshakes, each with different security and privacy properties for a would be +protocol implementer to select from. A deep exploration of each of the +handshakes, and their various trade-offs is out of the scope of this chapter. +With that said, the Lighting Network uses a specific handshake referred to as +`Noise_XK`. The unique property provided by this handshake is "identity +hiding": in order for a node to initiate a connection with another node, it +must first know it's public key. Mechanically, this means that the public key +of the responder is actually never transmitted during the context of the +handshake. Instead, a clever series of Elliptic-Curve Diffie-Hellman (ECDH) and +Message Authentication Code (MAC) checks are used to authenticate the +responder. + +=== Handshake Notation & Protocol Flow + +Each handshakes typically consist of several steps. At each step some +(possibly) encrypted material is sent to the opposite party, an ECDH (or +several) are performed, with the result of the handshake being "mixed" into a +protocol "transcript". This transcript serves to authenticate each step of the +protocol and helps thwart a flavor of main-man-in-the-middle attacks. At the +end of the handshake, two keys `ck` and `k` are produced which are used to +encrypt messages (`k`) as well as rotate keys (`ck`) throughout the lifetime of +the session. + +In the context of a handshake, `s` is usually a long-term static public key. +Within Brontide, the public key crypto system used is an elliptic curve one, +instantiated with the `secp256k1` curve which is used elsewhere in Bitcoin. +Several ephemeral keys are generated throughout the handshake. We use `e` to +refer to a new ephemeral key. ECDH operations between two keys are notated as +the concatenation of two keys. As an example, `ee` represents an ECDH operation +between two ephemeral keys. + +== Brontide: Lightning's P2P Encryption + +=== High-Level Overview + +Using the notation laid out earlier, we can succinctly describe the `Noise_XK` +as follows: +``` + Noise_XK(s, rs): + <- rs + ... + -> e, e(rs) + <- e, ee + -> s, se +``` + +The protocol begins with the "pre-transmission" of the responder's static key +(`rs)` to the initiator. Before executing the handshake, the initiator is to +generate its own static key (`s`). During each step of the handshake, all +material sent across the wire, as well as the keys sent/used are incrementally +hashed into a "handshake digest", `h`. This digest is never sent across the +wire during the handshake, and is instead used as the "Associated Data" when an +AEAD (authenticated encryption w/ associated data) is sent across the wire. +Associated data allows an encryption protocol to authenticate additional +information along side a cipher text packet. In other domains, the AD may be a +domain name, or plaintext portion of the packet. + +The existence of `h` ensures that if a portion of a transmitted handshake +message is replaced, then the other side will notice. At each step, a MAC +digest is checked. If the MAC check succeeds, then the receiving party knows +that the handshake has been successful up until that point. Otherwise if a MAC +check ever fails, then the handshake process has failed, and the connection +should be terminated. + +Brontide also adds a new piece of data to each handshake message: a protocol +version. The initial protocol version is `0`. At the time of writing, no new +protocol versions has been created. As a result, if a peer receives a version +other than `0`, then they should reject the handshake initiation attempt. + +As far as cryptographic primitives, `SHA-256` is used as the hash function of +choice, `secp256k1` as the elliptic curve, and `ChaChaPoly-130` as the AEAD +(symmetric encryption) construction. + +Each variant of the Noise protocol has a unique ASCII string used to uniquely +refer to it. In order to ensure that two parties are using the same protocol +variant, the ASCII string is hashed into a digest, which is used to initialize +the starting handshake state. In the context of Brontide, the ASCII string +describing the protocol is: `Noise_XK_secp256k1_ChaChaPoly_SHA256`. + +=== Brontide: A Handshake in Three Acts + +The handshake portion of Brontide can be see prated into three distinct "acts". +The entire handshake takes 1.5 round trips between the initiator and responder. +At each act, a single message is sent between both parties. The handshake +message is a _fixed_ sized payload prefixed by the protocol version. + +The Noise protocol uses an object oriented inspired notation to describe the +protocol at each step. During set up of the handshake state, each side will +initialize the following "variables": + + * `ck`: the **chaining key**. This value is the accumulated hash of all + previous ECDH outputs. At the end of the handshake, `ck` is used to derive + the encryption keys for Lightning messages. + + * `h`: the **handshake hash**. This value is the accumulated hash of _all_ + handshake data that has been sent and received so far during the handshake + process. + + * `temp_k1`, `temp_k2`, `temp_k3`: the **intermediate keys**. These are used to + encrypt and decrypt the zero-length AEAD payloads at the end of each handshake + message. + + * `e`: a party's **ephemeral keypair**. For each session, a node MUST generate a + new ephemeral key with strong cryptographic randomness. + + * `s`: a party's **static keypair** (`ls` for local, `rs` for remote) + +Given this handshake+messaging session state, we'll then define a series of +functions that will operate on the handshake and messaging state. When +describing the handshake protocol, we'll use these variables in a manner +similar to pseudo-code in order to reduce the verbosity of the explanation of +each step in the protocol. We'll define the _functional_ primitives of the +handshake as: + + * `ECDH(k, rk)`: performs an Elliptic-Curve Diffie-Hellman operation using + `k`, which is a valid `secp256k1` private key, and `rk`, which is a valid public key + * The returned value is the SHA256 of the compressed format of the + generated point. + + * `HKDF(salt,ikm)`: a function defined in `RFC 5869`[3](#reference-3), + evaluated with a zero-length `info` field + * All invocations of `HKDF` implicitly return 64 bytes of + cryptographic randomness using the extract-and-expand component of the + `HKDF`. + + * `encryptWithAD(k, n, ad, plaintext)`: outputs `encrypt(k, n, ad, plaintext)` + * Where `encrypt` is an evaluation of `ChaCha20-Poly1305` (IETF variant) + with the passed arguments, with nonce `n` encoded as 32 zero bits, + followed by a *little-endian* 64-bit value. Note: this follows the Noise + Protocol convention, rather than our normal endian. + + * `decryptWithAD(k, n, ad, ciphertext)`: outputs `decrypt(k, n, ad, ciphertext)` + * Where `decrypt` is an evaluation of `ChaCha20-Poly1305` (IETF variant) + with the passed arguments, with nonce `n` encoded as 32 zero bits, + followed by a *little-endian* 64-bit value. + + * `generateKey()`: generates and returns a fresh `secp256k1` keypair + * Where the object returned by `generateKey` has two attributes: + * `.pub`, which returns an abstract object representing the public key + * `.priv`, which represents the private key used to generate the + public key + * Where the object also has a single method: + * `.serializeCompressed()` + + * `a || b` denotes the concatenation of two byte strings `a` and `b` + +==== Handshake Session State Initialization + +Before starting the handshake process, both sides need to initialize the +starting state that they'll use to advance the handshake process. To start, +both sides need to construct the initial handshake digest `h` which will be +used as the initial handshake digest. + + 1. `h = SHA-256(protocolName)` + * where `protocolName = "Noise_XK_secp256k1_ChaChaPoly_SHA256"` encoded as + an ASCII string + + 2. `ck = h` + + 3. `h = SHA-256(h || prologue)` + * where `prologue` is the ASCII string: `lightning` + +In addition to the protocol name, we also add in an extra "prologue" that is +used to further bind the protocol context to the Lightning network. + +To conclude the initialization step, both sides mix the responder's public key +into the handshake digest. As this digest is used as the associated data with a +zero-length ciphertext (only the MAC) is sent, this ensures that the initiator +does indeed know the public key of the responder. + + * The initiating node mixes in the responding node's static public key + serialized in Bitcoin's compressed format: + * `h = SHA-256(h || rs.pub.serializeCompressed())` + + * The responding node mixes in their local static public key serialized in + Bitcoin's compressed format: + * `h = SHA-256(h || ls.pub.serializeCompressed())` + +==== Handshake Acts + +After the initial handshake initialization, we can begin the actual execution +of the handshake process. The Brontide handshake is compromised of a series of +three messages sent between the initiator and responder, hence referred to as +"acts". As each act is a single message sent between the parties, a handshake +is completed in a total of 1.5 round trips (0.5 for each act). + +The first act completes the initial portion of the incremental Triple Diffie +Hellman key exchange (using a new ephemeral key generated by the initiator), +and also ensures that the initiator actually knows the long-term public key of +the responder. During the second act, the responder transmits the thermal key +they wish to use for the session to the initiator, and one again incrementally +mixes this new key into the Triple DH handshake. During the third and final +act, the initiator transmits their long-term static public key to the +responder, and executes the final DH operation to mix that into the final +resulting shared secret. + +===== Act One + +``` + -> e, es +``` + +Act One is sent from initiator to responder. During Act One, the initiator +attempts to satisfy an implicit challenge by the responder. To complete this +challenge, the initiator must know the static public key of the responder. + +The handshake message is _exactly_ 50 bytes: 1 byte for the handshake +version, 33 bytes for the compressed ephemeral public key of the initiator, +and 16 bytes for the `poly1305` tag. + +**Sender Actions:** + +1. `e = generateKey()` +2. `h = SHA-256(h || e.pub.serializeCompressed())` + * The newly generated ephemeral key is accumulated into the running + handshake digest. +3. `es = ECDH(e.priv, rs)` + * The initiator performs an ECDH between its newly generated ephemeral + key and the remote node's static public key. +4. `ck, temp_k1 = HKDF(ck, es)` + * A new temporary encryption key is generated, which is + used to generate the authenticating MAC. +5. `c = encryptWithAD(temp_k1, 0, h, zero)` + * where `zero` is a zero-length plaintext +6. `h = SHA-256(h || c)` + * Finally, the generated ciphertext is accumulated into the authenticating + handshake digest. +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. +2. Parse the read message (`m`) into `v`, `re`, and `c`: + * where `v` is the _first_ byte of `m`, `re` is the next 33 + bytes of `m`, and `c` is the last 16 bytes of `m` + * 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. +3. If `v` is an unrecognized handshake version, then the responder MUST + abort the connection attempt. +4. `h = SHA-256(h || re.serializeCompressed())` + * The responder accumulates the initiator's ephemeral key into the authenticating + handshake digest. +5. `es = ECDH(s.priv, re)` + * The responder performs an ECDH between its static private key and the + initiator's ephemeral public key. +6. `ck, temp_k1 = HKDF(ck, es)` + * A new temporary encryption key is generated, which will + shortly be used to check the authenticating MAC. +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 this is the case, then the + responder MUST terminate the connection without any further messages. +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. + +===== Act Two + +``` + <- e, ee +``` + +Act Two is sent from the responder to the initiator. Act Two will _only_ +take place if Act One was successful. Act One was successful if the +responder was able to properly decrypt and check the MAC of the tag sent at +the end of Act One. + +The handshake is _exactly_ 50 bytes: 1 byte for the handshake version, 33 +bytes for the compressed ephemeral public key of the responder, and 16 bytes +for the `poly1305` tag. + +**Sender Actions:** + +1. `e = generateKey()` +2. `h = SHA-256(h || e.pub.serializeCompressed())` + * The newly generated ephemeral key is accumulated into the running + handshake digest. +3. `ee = ECDH(e.priv, re)` + * where `re` is the ephemeral key of the initiator, which was received + during Act One +4. `ck, temp_k2 = HKDF(ck, ee)` + * A new temporary encryption key is generated, which is + used to generate the authenticating MAC. +5. `c = encryptWithAD(temp_k2, 0, h, zero)` + * where `zero` is a zero-length plaintext +6. `h = SHA-256(h || c)` + * Finally, the generated ciphertext is accumulated into the authenticating + handshake digest. +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. +2. Parse the read message (`m`) into `v`, `re`, and `c`: + * where `v` is the _first_ byte of `m`, `re` is the next 33 + bytes of `m`, and `c` is the last 16 bytes of `m`. +3. If `v` is an unrecognized handshake version, then the responder MUST + abort the connection attempt. +4. `h = SHA-256(h || re.serializeCompressed())` +5. `ee = ECDH(e.priv, re)` + * 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. +6. `ck, temp_k2 = HKDF(ck, ee)` + * A new temporary encryption key is generated, which is + used to generate the authenticating MAC. +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. +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. + +===== Act Three + +``` + -> s, se +``` + +Act Three is the final phase in the authenticated key agreement described in +this section. This act is sent from the initiator to the responder as a +concluding step. Act Three is executed _if and only if_ Act Two was successful. +During Act Three, the initiator transports its static public key to the +responder encrypted with _strong_ forward secrecy, using the accumulated `HKDF` +derived secret key at this point of the handshake. + +The handshake is _exactly_ 66 bytes: 1 byte for the handshake version, 33 +bytes for the static public key encrypted with the `ChaCha20` stream +cipher, 16 bytes for the encrypted public key's tag generated via the AEAD +construction, and 16 bytes for a final authenticating tag. + +**Sender Actions:** + +1. `c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())` + * where `s` is the static public key of the initiator +2. `h = SHA-256(h || c)` +3. `se = ECDH(s.priv, re)` + * where `re` is the ephemeral public key of the responder +4. `ck, temp_k3 = HKDF(ck, se)` + * The final intermediate shared secret is mixed into the running chaining key. +5. `t = encryptWithAD(temp_k3, 0, h, zero)` + * where `zero` is a zero-length plaintext +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. +7. `rn = 0, sn = 0` + * The sending and receiving nonces are initialized to 0. +8. Send `m = 0 || c || t` over the network buffer. + +**Receiver Actions:** + +1. Read _exactly_ 66 bytes from the network buffer. +2. Parse the read message (`m`) into `v`, `c`, and `t`: + * where `v` is the _first_ byte of `m`, `c` is the next 49 + bytes of `m`, and `t` is the last 16 bytes of `m` +3. If `v` is an unrecognized handshake version, then the responder MUST + abort the connection attempt. +4. `rs = decryptWithAD(temp_k2, 1, h, c)` + * At this point, the responder has recovered the static public key of the + initiator. +5. `h = SHA-256(h || c)` +6. `se = ECDH(e.priv, rs)` + * where `e` is the responder's original ephemeral key +7. `ck, temp_k3 = HKDF(ck, se)` +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. +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. +10. `rn = 0, sn = 0` + * The sending and receiving nonces are initialized to 0. + +==== Transport Message Encryption + +At the conclusion of Act Three, both sides have derived the encryption keys, which +will be used to encrypt and decrypt messages for the remainder of the +session. + +The actual Lightning protocol messages are encapsulated within AEAD ciphertexts. +Each message is prefixed with another AEAD ciphertext, which encodes the total +length of the following Lightning message (not including its MAC). + +The *maximum* size of _any_ Lightning message MUST NOT exceed `65535` bytes. A +maximum size of `65535` simplifies testing, makes memory management easier, and +helps mitigate memory-exhaustion attacks. + +In order to make traffic analysis more difficult, the length prefix for all +encrypted Lightning messages is also encrypted. Additionally a 16-byte +`Poly-1305` tag is added to the encrypted length prefix in order to ensure that +the packet length hasn't been modified when in-flight and also to avoid +creating a decryption oracle. + +The structure of packets on the wire resembles the following: + +``` ++------------------------------- +|2-byte encrypted message length| ++------------------------------- +| 16-byte MAC of the encrypted | +| message length | ++------------------------------- +| | +| | +| encrypted Lightning | +| message | +| | ++------------------------------- +| 16-byte MAC of the | +| Lightning message | ++------------------------------- +``` + +The prefixed message length is encoded as a 2-byte big-endian integer, for a +total maximum packet length of `2 + 16 + 65535 + 16` = `65569` bytes. + +===== Encrypting and Sending Messages + +In order to encrypt and send a Lightning message (`m`) to the network stream, +given a sending key (`sk`) and a nonce (`sn`), the following steps are +completed: + +1. Let `l = len(m)`. + * where `len` obtains the length in bytes of the Lightning message +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 0s 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). +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. +5. Send `lc || c` over the network buffer. + +===== Receiving and Decrypting Messages + +In order to decrypt the _next_ message in the network stream, the following +steps are completed: + +1. Read _exactly_ 18 bytes from the network buffer. +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. +4. Read _exactly_ `l+16` bytes from the network buffer, and let the bytes be + known as `c`. +5. Decrypt `c` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to obtain decrypted + plaintext packet `p`. + * The nonce `rn` MUST be incremented after this step. + +==== Lightning Message Key Rotation + +Changing keys regularly and forgetting previous keys is useful to prevent the +decryption of old messages, in the case of later key leakage (i.e. backwards +secrecy). + +Key rotation is performed for _each_ key (`sk` and `rk`) _individually_. A key +is to be rotated after a party encrypts or decrypts 1000 times with it (i.e. +every 500 messages). This can be properly accounted for by rotating the key +once the nonce dedicated to it exceeds 1000. + +Key rotation for a key `k` is performed according to the following steps: + +1. Let `ck` be the chaining key obtained at the end of Act Three. +2. `ck', k' = HKDF(ck, k)` +3. Reset the nonce for the key to `n = 0`. +4. `k = k'` +5. `ck = ck'`