bolt8

Encrypted and authenticated transport, per BOLT #8 (docs.ppad.tech/bolt8).
git clone git://git.ppad.tech/bolt8.git
Log | Files | Refs | README | LICENSE

08-transport.md (43682B)


      1 # BOLT #8: Encrypted and Authenticated Transport
      2 
      3 All communications between Lightning nodes is encrypted in order to
      4 provide confidentiality for all transcripts between nodes and is authenticated in order to
      5 avoid malicious interference. Each node has a known long-term identifier that
      6 is a public key on Bitcoin's `secp256k1` curve. This long-term public key is
      7 used within the protocol to establish an encrypted and authenticated connection
      8 with peers, and also to authenticate any information advertised on behalf
      9 of a node.
     10 
     11 # Table of Contents
     12 
     13   * [Cryptographic Messaging Overview](#cryptographic-messaging-overview)
     14     * [Authenticated Key Agreement Handshake](#authenticated-key-agreement-handshake)
     15     * [Handshake Versioning](#handshake-versioning)
     16     * [Noise Protocol Instantiation](#noise-protocol-instantiation)
     17   * [Authenticated Key Exchange Handshake Specification](#authenticated-key-exchange-handshake-specification)
     18     * [Handshake State](#handshake-state)
     19     * [Handshake State Initialization](#handshake-state-initialization)
     20     * [Handshake Exchange](#handshake-exchange)
     21   * [Lightning Message Specification](#lightning-message-specification)
     22     * [Encrypting and Sending Messages](#encrypting-and-sending-messages)
     23     * [Receiving and Decrypting Messages](#receiving-and-decrypting-messages)
     24   * [Lightning Message Key Rotation](#lightning-message-key-rotation)
     25   * [Security Considerations](#security-considerations)
     26   * [Appendix A: Transport Test Vectors](#appendix-a-transport-test-vectors)
     27     * [Initiator Tests](#initiator-tests)
     28     * [Responder Tests](#responder-tests)
     29     * [Message Encryption Tests](#message-encryption-tests)
     30   * [Acknowledgments](#acknowledgments)
     31   * [References](#references)
     32   * [Authors](#authors)
     33 
     34 ## Cryptographic Messaging Overview
     35 
     36 Prior to sending any Lightning messages, nodes MUST first initiate the
     37 cryptographic session state that is used to encrypt and authenticate all
     38 messages sent between nodes. The initialization of this cryptographic session
     39 state is completely distinct from any inner protocol message header or
     40 conventions.
     41 
     42 The transcript between two nodes is separated into two distinct segments:
     43 
     44 1. Before any actual data transfer, both nodes participate in an
     45    authenticated key agreement handshake, which is based on the Noise
     46    Protocol Framework<sup>[2](#reference-2)</sup>.
     47 2. If the initial handshake is successful, then nodes enter the Lightning
     48    message exchange phase. In the Lightning message exchange phase, all
     49    messages are Authenticated Encryption with Associated Data (AEAD) ciphertexts.
     50 
     51 ### Authenticated Key Agreement Handshake
     52 
     53 The handshake chosen for the authenticated key exchange is `Noise_XK`. As a
     54 pre-message, the initiator must know the identity public key of
     55 the responder. This provides a degree of identity hiding for the
     56 responder, as its static public key is _never_ transmitted during the handshake. Instead,
     57 authentication is achieved implicitly via a series of Elliptic-Curve
     58 Diffie-Hellman (ECDH) operations followed by a MAC check.
     59 
     60 The authenticated key agreement (`Noise_XK`) is performed in three distinct
     61 steps (acts). During each act of the handshake the following occurs: some (possibly encrypted) keying
     62 material is sent to the other party; an ECDH is performed, based on exactly
     63 which act is being executed, with the result mixed into the current set of
     64 encryption keys (`ck` the chaining key and `k` the encryption key); and
     65 an AEAD payload with a zero-length cipher text is sent. As this payload has no
     66 length, only a MAC is sent across. The mixing of ECDH outputs into
     67 a hash digest forms an incremental TripleDH handshake.
     68 
     69 Using the language of the Noise Protocol, `e` and `s` (both public keys with `e` being 
     70 the ephemeral key and `s` being the static key which in our case is usually the `nodeid`)
     71 indicate possibly encrypted keying material, and `es`, `ee`, and `se` each indicate an
     72 ECDH operation between two keys. The handshake is laid out as follows:
     73 ```
     74     Noise_XK(s, rs):
     75        <- s
     76        ...
     77        -> e, es
     78        <- e, ee
     79        -> s, se
     80 ```
     81 All of the handshake data sent across the wire, including the keying material, is
     82 incrementally hashed into a session-wide "handshake digest", `h`. Note that the
     83 handshake state `h` is never transmitted during the handshake; instead, digest
     84 is used as the Associated Data within the zero-length AEAD messages.
     85 
     86 Authenticating each message sent ensures that a man-in-the-middle (MITM) hasn't modified
     87 or replaced any of the data sent as part of a handshake, as the MAC
     88 check would fail on the other side if so.
     89 
     90 A successful check of the MAC by the receiver indicates implicitly that all
     91 authentication has been successful up to that point. If a MAC check ever fails
     92 during the handshake process, then the connection is to be immediately
     93 terminated.
     94 
     95 ### Handshake Versioning
     96 
     97 Each message sent during the initial handshake starts with a single leading
     98 byte, which indicates the version used for the current handshake. A version of 0
     99 indicates that no change is necessary, while a non-zero version indicate that the
    100 client has deviated from the protocol originally specified within this
    101 document.
    102 
    103 Clients MUST reject handshake attempts initiated with an unknown version.
    104 
    105 ### Noise Protocol Instantiation
    106 
    107 Concrete instantiations of the Noise Protocol require the definition of
    108 three abstract cryptographic objects: the hash function, the elliptic curve,
    109 and the AEAD cipher scheme. For Lightning, `SHA-256` is
    110 chosen as the hash function, `secp256k1` as the elliptic curve, and
    111 `ChaChaPoly-1305` as the AEAD construction.
    112 
    113 The composition of `ChaCha20` and `Poly1305` that are used MUST conform to
    114 `RFC 8439`<sup>[1](#reference-1)</sup>.
    115 
    116 The official protocol name for the Lightning variant of Noise is
    117 `Noise_XK_secp256k1_ChaChaPoly_SHA256`. The ASCII string representation of
    118 this value is hashed into a digest used to initialize the starting handshake
    119 state. If the protocol names of two endpoints differ, then the handshake
    120 process fails immediately.
    121 
    122 ## Authenticated Key Exchange Handshake Specification
    123 
    124 The handshake proceeds in three acts, taking 1.5 round trips. Each handshake is
    125 a _fixed_ sized payload without any header or additional meta-data attached.
    126 The exact size of each act is as follows:
    127 
    128    * **Act One**: 50 bytes
    129    * **Act Two**: 50 bytes
    130    * **Act Three**: 66 bytes
    131 
    132 ### Handshake State
    133 
    134 Throughout the handshake process, each side maintains these variables:
    135 
    136  * `ck`: the **chaining key**. This value is the accumulated hash of all
    137    previous ECDH outputs. At the end of the handshake, `ck` is used to derive
    138    the encryption keys for Lightning messages.
    139 
    140  * `h`: the **handshake hash**. This value is the accumulated hash of _all_
    141    handshake data that has been sent and received so far during the handshake
    142    process.
    143 
    144  * `temp_k1`, `temp_k2`, `temp_k3`: the **intermediate keys**. These are used to
    145    encrypt and decrypt the zero-length AEAD payloads at the end of each handshake
    146    message.
    147 
    148  * `e`: a party's **ephemeral keypair**. For each session, a node MUST generate a
    149    new ephemeral key with strong cryptographic randomness.
    150 
    151  * `s`: a party's **static keypair** (`ls` for local, `rs` for remote)
    152 
    153 The following functions will also be referenced:
    154 
    155   * `ECDH(k, rk)`: performs an Elliptic-Curve Diffie-Hellman operation using
    156     `k`, which is a valid `secp256k1` private key, and `rk`, which is a valid public key
    157       * The returned value is the SHA256 of the compressed format of the
    158 	    generated point.
    159 
    160   * `HKDF(salt,ikm)`: a function defined in `RFC 5869`<sup>[3](#reference-3)</sup>,
    161     evaluated with a zero-length `info` field
    162      * All invocations of `HKDF` implicitly return 64 bytes of
    163        cryptographic randomness using the extract-and-expand component of the
    164        `HKDF`.
    165 
    166   * `encryptWithAD(k, n, ad, plaintext)`: outputs `encrypt(k, n, ad, plaintext)`
    167      * Where `encrypt` is an evaluation of `ChaCha20-Poly1305` (IETF variant)
    168        with the passed arguments, with nonce `n` encoded as 32 zero bits,
    169        followed by a *little-endian* 64-bit value. Note: this follows the Noise
    170        Protocol convention, rather than our normal endian.
    171 
    172   * `decryptWithAD(k, n, ad, ciphertext)`: outputs `decrypt(k, n, ad, ciphertext)`
    173      * Where `decrypt` is an evaluation of `ChaCha20-Poly1305` (IETF variant)
    174        with the passed arguments, with nonce `n` encoded as 32 zero bits,
    175        followed by a *little-endian* 64-bit value.
    176 
    177   * `generateKey()`: generates and returns a fresh `secp256k1` keypair
    178      * Where the object returned by `generateKey` has two attributes:
    179          * `.pub`, which returns an abstract object representing the public key
    180          * `.priv`, which represents the private key used to generate the
    181            public key
    182      * Where the object also has a single method:
    183          * `.serializeCompressed()`
    184 
    185   * `a || b` denotes the concatenation of two byte strings `a` and `b`
    186 
    187 ### Handshake State Initialization
    188 
    189 Before the start of Act One, both sides initialize their per-sessions
    190 state as follows:
    191 
    192  1. `h = SHA-256(protocolName)`
    193     * where `protocolName = "Noise_XK_secp256k1_ChaChaPoly_SHA256"` encoded as
    194       an ASCII string
    195 
    196  2. `ck = h`
    197 
    198  3. `h = SHA-256(h || prologue)`
    199     * where `prologue` is the ASCII string: `lightning`
    200 
    201 As a concluding step, both sides mix the responder's public key into the
    202 handshake digest:
    203 
    204  * The initiating node mixes in the responding node's static public key
    205    serialized in Bitcoin's compressed format:
    206    * `h = SHA-256(h || rs.pub.serializeCompressed())`
    207 
    208  * The responding node mixes in their local static public key serialized in
    209    Bitcoin's compressed format:
    210    * `h = SHA-256(h || ls.pub.serializeCompressed())`
    211 
    212 ### Handshake Exchange
    213 
    214 #### Act One
    215 
    216 ```
    217     -> e, es
    218 ```
    219 
    220 Act One is sent from initiator to responder. During Act One, the initiator
    221 attempts to satisfy an implicit challenge by the responder. To complete this
    222 challenge, the initiator must know the static public key of the responder.
    223 
    224 The handshake message is _exactly_ 50 bytes: 1 byte for the handshake
    225 version, 33 bytes for the compressed ephemeral public key of the initiator,
    226 and 16 bytes for the `poly1305` tag.
    227 
    228 **Sender Actions:**
    229 
    230 1. `e = generateKey()`
    231 2. `h = SHA-256(h || e.pub.serializeCompressed())`
    232      * The newly generated ephemeral key is accumulated into the running
    233        handshake digest.
    234 3. `es = ECDH(e.priv, rs)`
    235      * The initiator performs an ECDH between its newly generated ephemeral
    236        key and the remote node's static public key.
    237 4. `ck, temp_k1 = HKDF(ck, es)`
    238      * A new temporary encryption key is generated, which is
    239        used to generate the authenticating MAC.
    240 5. `c = encryptWithAD(temp_k1, 0, h, zero)`
    241      * where `zero` is a zero-length plaintext
    242 6. `h = SHA-256(h || c)`
    243      * Finally, the generated ciphertext is accumulated into the authenticating
    244        handshake digest.
    245 7. Send `m = 0 || e.pub.serializeCompressed() || c` to the responder over the network buffer.
    246 
    247 **Receiver Actions:**
    248 
    249 1. Read _exactly_ 50 bytes from the network buffer.
    250 2. Parse the read message (`m`) into `v`, `re`, and `c`:
    251     * where `v` is the _first_ byte of `m`, `re` is the next 33
    252       bytes of `m`, and `c` is the last 16 bytes of `m`
    253     * The raw bytes of the remote party's ephemeral public key (`re`) are to be
    254       deserialized into a point on the curve using affine coordinates as encoded
    255       by the key's serialized composed format.
    256 3. If `v` is an unrecognized handshake version, then the responder MUST
    257     abort the connection attempt.
    258 4. `h = SHA-256(h || re.serializeCompressed())`
    259     * The responder accumulates the initiator's ephemeral key into the authenticating
    260       handshake digest.
    261 5. `es = ECDH(s.priv, re)`
    262     * The responder performs an ECDH between its static private key and the
    263       initiator's ephemeral public key.
    264 6. `ck, temp_k1 = HKDF(ck, es)`
    265     * A new temporary encryption key is generated, which will
    266       shortly be used to check the authenticating MAC.
    267 7. `p = decryptWithAD(temp_k1, 0, h, c)`
    268     * If the MAC check in this operation fails, then the initiator does _not_
    269       know the responder's static public key. If this is the case, then the
    270       responder MUST terminate the connection without any further messages.
    271 8. `h = SHA-256(h || c)`
    272      * The received ciphertext is mixed into the handshake digest. This step serves
    273        to ensure the payload wasn't modified by a MITM.
    274 
    275 #### Act Two
    276 
    277 ```
    278    <- e, ee
    279 ```
    280 
    281 Act Two is sent from the responder to the initiator. Act Two will _only_
    282 take place if Act One was successful. Act One was successful if the
    283 responder was able to properly decrypt and check the MAC of the tag sent at
    284 the end of Act One.
    285 
    286 The handshake is _exactly_ 50 bytes: 1 byte for the handshake version, 33
    287 bytes for the compressed ephemeral public key of the responder, and 16 bytes
    288 for the `poly1305` tag.
    289 
    290 **Sender Actions:**
    291 
    292 1. `e = generateKey()`
    293 2. `h = SHA-256(h || e.pub.serializeCompressed())`
    294      * The newly generated ephemeral key is accumulated into the running
    295        handshake digest.
    296 3. `ee = ECDH(e.priv, re)`
    297      * where `re` is the ephemeral key of the initiator, which was received
    298        during Act One
    299 4. `ck, temp_k2 = HKDF(ck, ee)`
    300      * A new temporary encryption key is generated, which is
    301        used to generate the authenticating MAC.
    302 5. `c = encryptWithAD(temp_k2, 0, h, zero)`
    303      * where `zero` is a zero-length plaintext
    304 6. `h = SHA-256(h || c)`
    305      * Finally, the generated ciphertext is accumulated into the authenticating
    306        handshake digest.
    307 7. Send `m = 0 || e.pub.serializeCompressed() || c` to the initiator over the network buffer.
    308 
    309 **Receiver Actions:**
    310 
    311 1. Read _exactly_ 50 bytes from the network buffer.
    312 2. Parse the read message (`m`) into `v`, `re`, and `c`:
    313     * where `v` is the _first_ byte of `m`, `re` is the next 33
    314       bytes of `m`, and `c` is the last 16 bytes of `m`.
    315 3. If `v` is an unrecognized handshake version, then the responder MUST
    316     abort the connection attempt.
    317 4. `h = SHA-256(h || re.serializeCompressed())`
    318 5. `ee = ECDH(e.priv, re)`
    319     * where `re` is the responder's ephemeral public key
    320     * The raw bytes of the remote party's ephemeral public key (`re`) are to be
    321       deserialized into a point on the curve using affine coordinates as encoded
    322       by the key's serialized composed format.
    323 6. `ck, temp_k2 = HKDF(ck, ee)`
    324      * A new temporary encryption key is generated, which is
    325        used to generate the authenticating MAC.
    326 7. `p = decryptWithAD(temp_k2, 0, h, c)`
    327     * If the MAC check in this operation fails, then the initiator MUST
    328       terminate the connection without any further messages.
    329 8. `h = SHA-256(h || c)`
    330      * The received ciphertext is mixed into the handshake digest. This step serves
    331        to ensure the payload wasn't modified by a MITM.
    332 
    333 #### Act Three
    334 
    335 ```
    336    -> s, se
    337 ```
    338 
    339 Act Three is the final phase in the authenticated key agreement described in
    340 this section. This act is sent from the initiator to the responder as a
    341 concluding step. Act Three is executed _if and only if_ Act Two was successful.
    342 During Act Three, the initiator transports its static public key to the
    343 responder encrypted with _strong_ forward secrecy, using the accumulated `HKDF`
    344 derived secret key at this point of the handshake.
    345 
    346 The handshake is _exactly_ 66 bytes: 1 byte for the handshake version, 33
    347 bytes for the static public key encrypted with the `ChaCha20` stream
    348 cipher, 16 bytes for the encrypted public key's tag generated via the AEAD
    349 construction, and 16 bytes for a final authenticating tag.
    350 
    351 **Sender Actions:**
    352 
    353 1. `c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())`
    354     * where `s` is the static public key of the initiator
    355 2. `h = SHA-256(h || c)`
    356 3. `se = ECDH(s.priv, re)`
    357     * where `re` is the ephemeral public key of the responder
    358 4. `ck, temp_k3 = HKDF(ck, se)`
    359     * The final intermediate shared secret is mixed into the running chaining key.
    360 5. `t = encryptWithAD(temp_k3, 0, h, zero)`
    361      * where `zero` is a zero-length plaintext
    362 6. `sk, rk = HKDF(ck, zero)`
    363      * where `zero` is a zero-length plaintext,
    364        `sk` is the key to be used by the initiator to encrypt messages to the
    365        responder,
    366        and `rk` is the key to be used by the initiator to decrypt messages sent by
    367        the responder
    368      * The final encryption keys, to be used for sending and
    369        receiving messages for the duration of the session, are generated.
    370 7. `rn = 0, sn = 0`
    371      * The sending and receiving nonces are initialized to 0.
    372 8. `rck = sck = ck`
    373      * The sending and receiving chaining keys are initialized the same.
    374 9. Send `m = 0 || c || t` over the network buffer.
    375 
    376 **Receiver Actions:**
    377 
    378 1. Read _exactly_ 66 bytes from the network buffer.
    379 2. Parse the read message (`m`) into `v`, `c`, and `t`:
    380     * where `v` is the _first_ byte of `m`, `c` is the next 49
    381       bytes of `m`, and `t` is the last 16 bytes of `m`
    382 3. If `v` is an unrecognized handshake version, then the responder MUST
    383     abort the connection attempt.
    384 4. `rs = decryptWithAD(temp_k2, 1, h, c)`
    385      * At this point, the responder has recovered the static public key of the
    386        initiator.
    387      * If the MAC check in this operation fails, then the responder MUST
    388        terminate the connection without any further messages.
    389 5. `h = SHA-256(h || c)`
    390 6. `se = ECDH(e.priv, rs)`
    391      * where `e` is the responder's original ephemeral key
    392 7. `ck, temp_k3 = HKDF(ck, se)`
    393 8. `p = decryptWithAD(temp_k3, 0, h, t)`
    394      * If the MAC check in this operation fails, then the responder MUST
    395        terminate the connection without any further messages.
    396 9. `rk, sk = HKDF(ck, zero)`
    397      * where `zero` is a zero-length plaintext,
    398        `rk` is the key to be used by the responder to decrypt the messages sent
    399        by the initiator,
    400        and `sk` is the key to be used by the responder to encrypt messages to
    401        the initiator
    402      * The final encryption keys, to be used for sending and
    403        receiving messages for the duration of the session, are generated.
    404 10. `rn = 0, sn = 0`
    405      * The sending and receiving nonces are initialized to 0.
    406 11. `rck = sck = ck`
    407      * The sending and receiving chaining keys are initialized the same.
    408 
    409 ## Lightning Message Specification
    410 
    411 At the conclusion of Act Three, both sides have derived the encryption keys, which
    412 will be used to encrypt and decrypt messages for the remainder of the
    413 session.
    414 
    415 The actual Lightning protocol messages are encapsulated within AEAD ciphertexts.
    416 Each message is prefixed with another AEAD ciphertext, which encodes the total
    417 length of the following Lightning message (not including its MAC).
    418 
    419 The *maximum* size of _any_ Lightning message MUST NOT exceed `65535` bytes. A
    420 maximum size of `65535` simplifies testing, makes memory management
    421 easier, and helps mitigate memory-exhaustion attacks.
    422 
    423 In order to make traffic analysis more difficult, the length prefix for
    424 all encrypted Lightning messages is also encrypted. Additionally a
    425 16-byte `Poly-1305` tag is added to the encrypted length prefix in order to ensure
    426 that the packet length hasn't been modified when in-flight and also to avoid
    427 creating a decryption oracle.
    428 
    429 The structure of packets on the wire resembles the following:
    430 
    431 ```
    432 +-------------------------------
    433 |2-byte encrypted message length|
    434 +-------------------------------
    435 |  16-byte MAC of the encrypted |
    436 |        message length         |
    437 +-------------------------------
    438 |                               |
    439 |                               |
    440 |     encrypted Lightning       |
    441 |            message            |
    442 |                               |
    443 +-------------------------------
    444 |     16-byte MAC of the        |
    445 |      Lightning message        |
    446 +-------------------------------
    447 ```
    448 
    449 The prefixed message length is encoded as a 2-byte big-endian integer,
    450 for a total maximum packet length of `2 + 16 + 65535 + 16` = `65569` bytes.
    451 
    452 ### Encrypting and Sending Messages
    453 
    454 In order to encrypt and send a Lightning message (`m`) to the network stream,
    455 given a sending key (`sk`) and a nonce (`sn`), the following steps are completed:
    456 
    457 1. Let `l = len(m)`.
    458     * where `len` obtains the length in bytes of the Lightning message
    459 2. Serialize `l` into 2 bytes encoded as a big-endian integer.
    460 3. Encrypt `l` (using `ChaChaPoly-1305`, `sn`, and `sk`), to obtain `lc`
    461     (18 bytes)
    462     * The nonce `sn` is encoded as a 96-bit little-endian number. As the
    463       decoded nonce is 64 bits, the 96-bit nonce is encoded as: 32 bits
    464       of leading 0s followed by a 64-bit value.
    465         * The nonce `sn` MUST be incremented after this step.
    466     * A zero-length byte slice is to be passed as the AD (associated data).
    467 4. Finally, encrypt the message itself (`m`) using the same procedure used to
    468     encrypt the length prefix. Let encrypted ciphertext be known as `c`.
    469     * The nonce `sn` MUST be incremented after this step.
    470 5. Send `lc || c` over the network buffer.
    471 
    472 ### Receiving and Decrypting Messages
    473 
    474 In order to decrypt the _next_ message in the network stream, the following
    475 steps are completed:
    476 
    477 1. Read _exactly_ 18 bytes from the network buffer.
    478 2. Let the encrypted length prefix be known as `lc`.
    479 3. Decrypt `lc` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to obtain the size of
    480     the encrypted packet `l`.
    481     * A zero-length byte slice is to be passed as the AD (associated data).
    482     * The nonce `rn` MUST be incremented after this step.
    483 4. Read _exactly_ `l+16` bytes from the network buffer, and let the bytes be
    484     known as `c`.
    485 5. Decrypt `c` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to obtain decrypted
    486     plaintext packet `p`.
    487     * The nonce `rn` MUST be incremented after this step.
    488 
    489 ## Lightning Message Key Rotation
    490 
    491 Changing keys regularly and forgetting previous keys is useful to
    492 prevent the decryption of old messages, in the case of later key leakage (i.e.
    493 backwards secrecy).
    494 
    495 Key rotation is performed for _each_ key (`sk` and `rk`) _individually_,
    496 using `sck` and `rck` respectively.  A key
    497 is to be rotated after a party encrypts or decrypts 1000 times with it (i.e. every 500 messages).
    498 This can be properly accounted for by rotating the key once the nonce dedicated
    499 to it reaches 1000.
    500 
    501 Key rotation for a key `k` is performed according to the following steps:
    502 
    503 1. Let `ck` be the chaining key (i.e. `rck` for `rk` or `sck` for `sk`)
    504 2. `ck', k' = HKDF(ck, k)`
    505 3. Reset the nonce for the key to `n = 0`.
    506 4. `k = k'`
    507 5. `ck = ck'`
    508 
    509 # Security Considerations
    510 
    511 It is strongly recommended that existing, commonly-used, validated
    512 libraries be used for encryption and decryption, to avoid the many possible
    513 implementation pitfalls.
    514 
    515 # Appendix A: Transport Test Vectors
    516 
    517 To make a repeatable test handshake, the following specifies what `generateKey()` will
    518 return (i.e. the value for `e.priv`) for each side. Note that this
    519 is a violation of the spec, which requires randomness.
    520 
    521 ## Initiator Tests
    522 
    523 The initiator SHOULD produce the given output when fed this input.
    524 The comments reflect internal states, for debugging purposes.
    525 
    526 ```
    527     name: transport-initiator successful handshake
    528     rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    529     ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    530     ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    531     e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    532     e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    533     # Act One
    534     # h=0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c
    535     # ss=0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3
    536     # HKDF(0x2640f52eebcd9e882958951c794250eedb28002c05d7dc2ea0f195406042caf1,0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3)
    537     # ck,temp_k1=0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f
    538     # encryptWithAD(0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f, 0x000000000000000000000000, 0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c, <empty>)
    539     # c=0df6086551151f58b8afe6c195782c6a
    540     # h=0x9d1ffbb639e7e20021d9259491dc7b160aab270fb1339ef135053f6f2cebe9ce
    541     output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    542     # Act Two
    543     input: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    544     # re=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    545     # h=0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf
    546     # ss=0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47
    547     # HKDF(0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47)
    548     # ck,temp_k2=0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc
    549     # decryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000000000000000000, 0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf, 0x6e2470b93aac583c9ef6eafca3f730ae)
    550     # h=0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72
    551     # Act Three
    552     # encryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000100000000000000, 0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72, 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa)
    553     # c=0xb9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c3822
    554     # h=0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660
    555     # ss=0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766
    556     # HKDF(0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766)
    557     # ck,temp_k3=0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520
    558     # encryptWithAD(0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520, 0x000000000000000000000000, 0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660, <empty>)
    559     # t=0x8dc68b1c466263b47fdf31e560e139ba
    560     output: 0x00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba
    561     # HKDF(0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,zero)
    562     output: sk,rk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9,0xbb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442
    563 
    564     name: transport-initiator act2 short read test
    565     rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    566     ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    567     ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    568     e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    569     e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    570     output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    571     # Act Two
    572     input: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730
    573     output: ERROR (ACT2_READ_FAILED)
    574 
    575     name: transport-initiator act2 bad version test
    576     rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    577     ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    578     ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    579     e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    580     e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    581     output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    582     # Act Two
    583     input: 0x0102466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    584     output: ERROR (ACT2_BAD_VERSION 1)
    585 
    586     name: transport-initiator act2 bad key serialization test
    587     rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    588     ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    589     ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    590     e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    591     e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    592     output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    593     # Act Two
    594     input: 0x0004466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    595     output: ERROR (ACT2_BAD_PUBKEY)
    596 
    597     name: transport-initiator act2 bad MAC test
    598     rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    599     ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
    600     ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    601     e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
    602     e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    603     output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    604     # Act Two
    605     input: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730af
    606     output: ERROR (ACT2_BAD_TAG)
    607 ```
    608 
    609 ## Responder Tests
    610 
    611 The responder SHOULD produce the given output when fed this input.
    612 
    613 ```
    614     name: transport-responder successful handshake
    615     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    616     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    617     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    618     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    619     # Act One
    620     input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    621     # re=0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
    622     # h=0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c
    623     # ss=0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3
    624     # HKDF(0x2640f52eebcd9e882958951c794250eedb28002c05d7dc2ea0f195406042caf1,0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3)
    625     # ck,temp_k1=0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f
    626     # decryptWithAD(0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f, 0x000000000000000000000000, 0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c, 0x0df6086551151f58b8afe6c195782c6a)
    627     # h=0x9d1ffbb639e7e20021d9259491dc7b160aab270fb1339ef135053f6f2cebe9ce
    628     # Act Two
    629     # e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27 e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    630     # h=0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf
    631     # ss=0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47
    632     # HKDF(0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47)
    633     # ck,temp_k2=0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc
    634     # encryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000000000000000000, 0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf, <empty>)
    635     # c=0x6e2470b93aac583c9ef6eafca3f730ae
    636     # h=0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72
    637     output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    638     # Act Three
    639     input: 0x00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba
    640     # decryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000100000000000000, 0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72, 0xb9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c3822)
    641     # rs=0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    642     # h=0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660
    643     # ss=0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766
    644     # HKDF(0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766)
    645     # ck,temp_k3=0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520
    646     # decryptWithAD(0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520, 0x000000000000000000000000, 0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660, 0x8dc68b1c466263b47fdf31e560e139ba)
    647     # HKDF(0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,zero)
    648     output: rk,sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9,0xbb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442
    649 
    650     name: transport-responder act1 short read test
    651     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    652     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    653     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    654     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    655     # Act One
    656     input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c
    657     output: ERROR (ACT1_READ_FAILED)
    658 
    659     name: transport-responder act1 bad version test
    660     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    661     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    662     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    663     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    664     # Act One
    665     input: 0x01036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    666     output: ERROR (ACT1_BAD_VERSION)
    667 
    668     name: transport-responder act1 bad key serialization test
    669     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    670     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    671     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    672     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    673     # Act One
    674     input: 0x00046360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    675     output: ERROR (ACT1_BAD_PUBKEY)
    676 
    677     name: transport-responder act1 bad MAC test
    678     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    679     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    680     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    681     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    682     # Act One
    683     input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6b
    684     output: ERROR (ACT1_BAD_TAG)
    685 
    686     name: transport-responder act3 bad version test
    687     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    688     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    689     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    690     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    691     # Act One
    692     input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    693     # Act Two
    694     output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    695     # Act Three
    696     input: 0x01b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba
    697     output: ERROR (ACT3_BAD_VERSION 1)
    698 
    699     name: transport-responder act3 short read test
    700     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    701     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    702     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    703     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    704     # Act One
    705     input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    706     # Act Two
    707     output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    708     # Act Three
    709     input: 0x00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139
    710     output: ERROR (ACT3_READ_FAILED)
    711 
    712     name: transport-responder act3 bad MAC for ciphertext test
    713     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    714     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    715     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    716     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    717     # Act One
    718     input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    719     # Act Two
    720     output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    721     # Act Three
    722     input: 0x00c9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba
    723     output: ERROR (ACT3_BAD_CIPHERTEXT)
    724 
    725     name: transport-responder act3 bad rs test
    726     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    727     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    728     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    729     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    730     # Act One
    731     input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    732     # Act Two
    733     output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    734     # Act Three
    735     input: 0x00bfe3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa2235536ad09a8ee351870c2bb7f78b754a26c6cef79a98d25139c856d7efd252c2ae73c
    736     # decryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000000000000000001, 0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72, 0xd7fedc211450dd9602b41081c9bd05328b8bf8c0238880f7b7cb8a34bb6d8354081e8d4b81887fae47a74fe8aab3008653)
    737     # rs=0x044f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
    738     output: ERROR (ACT3_BAD_PUBKEY)
    739 
    740     name: transport-responder act3 bad MAC test
    741     ls.priv=2121212121212121212121212121212121212121212121212121212121212121
    742     ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
    743     e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
    744     e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
    745     # Act One
    746     input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
    747     # Act Two
    748     output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
    749     # Act Three
    750     input: 0x00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139bb
    751     output: ERROR (ACT3_BAD_TAG)
    752 ```
    753 
    754 ## Message Encryption Tests
    755 
    756 In this test, the initiator sends length 5 messages containing "hello"
    757 1001 times. Only six example outputs are shown, for brevity and to test
    758 two key rotations:
    759 
    760 	name: transport-message test
    761     ck=0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01
    762 	sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9
    763 	rk=0xbb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442
    764     # encrypt l: cleartext=0x0005, AD=NULL, sn=0x000000000000000000000000, sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9 => 0xcf2b30ddf0cf3f80e7c35a6e6730b59fe802
    765     # encrypt m: cleartext=0x68656c6c6f, AD=NULL, sn=0x000000000100000000000000, sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9 => 0x473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95
    766 	output 0: 0xcf2b30ddf0cf3f80e7c35a6e6730b59fe802473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95
    767     # encrypt l: cleartext=0x0005, AD=NULL, sn=0x000000000200000000000000, sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9 => 0x72887022101f0b6753e0c7de21657d35a4cb
    768     # encrypt m: cleartext=0x68656c6c6f, AD=NULL, sn=0x000000000300000000000000, sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9 => 0x2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1
    769 	output 1: 0x72887022101f0b6753e0c7de21657d35a4cb2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1
    770     # 0xcc2c6e467efc8067720c2d09c139d1f77731893aad1defa14f9bf3c48d3f1d31, 0x3fbdc101abd1132ca3a0ae34a669d8d9ba69a587e0bb4ddd59524541cf4813d8 = HKDF(0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01, 0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9)
    771     # 0xcc2c6e467efc8067720c2d09c139d1f77731893aad1defa14f9bf3c48d3f1d31, 0x3fbdc101abd1132ca3a0ae34a669d8d9ba69a587e0bb4ddd59524541cf4813d8 = HKDF(0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01, 0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9)
    772     output 500: 0x178cb9d7387190fa34db9c2d50027d21793c9bc2d40b1e14dcf30ebeeeb220f48364f7a4c68bf8
    773     output 501: 0x1b186c57d44eb6de4c057c49940d79bb838a145cb528d6e8fd26dbe50a60ca2c104b56b60e45bd
    774     # 0x728366ed68565dc17cf6dd97330a859a6a56e87e2beef3bd828a4c4a54d8df06, 0x9e0477f9850dca41e42db0e4d154e3a098e5a000d995e421849fcd5df27882bd = HKDF(0xcc2c6e467efc8067720c2d09c139d1f77731893aad1defa14f9bf3c48d3f1d31, 0x3fbdc101abd1132ca3a0ae34a669d8d9ba69a587e0bb4ddd59524541cf4813d8)
    775     # 0x728366ed68565dc17cf6dd97330a859a6a56e87e2beef3bd828a4c4a54d8df06, 0x9e0477f9850dca41e42db0e4d154e3a098e5a000d995e421849fcd5df27882bd = HKDF(0xcc2c6e467efc8067720c2d09c139d1f77731893aad1defa14f9bf3c48d3f1d31, 0x3fbdc101abd1132ca3a0ae34a669d8d9ba69a587e0bb4ddd59524541cf4813d8)
    776     output 1000: 0x4a2f3cc3b5e78ddb83dcb426d9863d9d9a723b0337c89dd0b005d89f8d3c05c52b76b29b740f09
    777     output 1001: 0x2ecd8c8a5629d0d02ab457a0fdd0f7b90a192cd46be5ecb6ca570bfc5e268338b1a16cf4ef2d36
    778 
    779 # Acknowledgments
    780 
    781 TODO(roasbeef); fin
    782 
    783 # References
    784 1. <a id="reference-1">https://tools.ietf.org/html/rfc8439</a>
    785 2. <a id="reference-2">http://noiseprotocol.org/noise.html</a>
    786 3. <a id="reference-3">https://tools.ietf.org/html/rfc5869</a>
    787 
    788 # Authors
    789 
    790 FIXME
    791 
    792 ![Creative Commons License](https://i.creativecommons.org/l/by/4.0/88x31.png "License CC-BY")
    793 <br>
    794 This work is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/).