+The SPTPS protocol is designed to address the weaknesses in the legacy protocol.
+SPTPS is based on TLS 1.2, but has been simplified: there is no support for exchanging public keys, and there is no cipher suite negotiation.
+Instead, SPTPS always uses a very strong cipher suite:
+peers authenticate each other using 521 bits ECC keys,
+Diffie-Hellman using ephemeral 521 bits ECC keys is used to provide perfect forward secrecy (PFS),
+AES-256-CTR is used for encryption, and HMAC-SHA-256 for message authentication.
+
+Similar to TLS, messages are split up in records.
+A complete logical record contains the following information:
+
+@itemize
+@item uint32_t seqno (network byte order)
+@item uint16_t length (network byte order)
+@item uint8_t type
+@item opaque data[length]
+@item opaque hmac[HMAC_SIZE] (HMAC over all preceding fields)
+@end itemize
+
+Depending on whether SPTPS records are sent via TCP or UDP, either the seqno or the length field is omitted on the wire
+(but they are still included in the calculation of the HMAC);
+for TCP packets are guaranteed to arrive in-order so we can infer the seqno, but packets can be split or merged, so we still need the length field to determine the boundaries between records;
+for UDP packets we know that there is exactly one record per packet, and we know the length of a packet, but packets can be dropped, duplicated and/or reordered, so we need to include the seqno.
+
+The type field is used to distinguish between application records or handshake records.
+Types 0 to 127 are application records, type 128 is a handshake record, and types 129 to 255 are reserved.
+
+Before the initial handshake, no fields are encrypted, and the HMAC field is not present.
+After the authentication handshake, the length (if present), type and data fields are encrypted, and the HMAC field is present.
+For UDP packets, the seqno field is not encrypted, as it is used to determine the value of the counter used for encryption.
+
+The authentication consists of an exchange of Key EXchange, SIGnature and ACKnowledge messages, transmitted using type 128 records.
+
+Overview:
+
+@example
+Initiator Responder
+---------------------
+KEX ->
+ <- KEX
+SIG ->
+ <- SIG
+
+...encrypt and HMAC using session keys from now on...
+
+App ->
+ <- App
+...
+ ...
+
+...key renegotiation starts here...
+
+KEX ->
+ <- KEX
+SIG ->
+ <- SIG
+ACK ->
+ <- ACK
+
+...encrypt and HMAC using new session keys from now on...
+
+App ->
+ <- App
+...
+ ...
+---------------------
+@end example
+
+Note that the responder does not need to wait before it receives the first KEX message,
+it can immediately send its own once it has accepted an incoming connection.
+
+Key EXchange message:
+
+@itemize
+@item uint8_t kex_version (always 0 in this version of SPTPS)
+@item opaque nonce[32] (random number)
+@item opaque ecdh_key[ECDH_SIZE]
+@end itemize
+
+SIGnature message:
+
+@itemize
+@item opaque ecdsa_signature[ECDSA_SIZE]
+@end itemize
+
+ACKnowledge message:
+
+@itemize
+@item empty (only sent after key renegotiation)
+@end itemize
+
+Remarks:
+
+@itemize
+@item At the start, both peers generate a random nonce and an Elliptic Curve public key and send it to the other in the KEX message.
+@item After receiving the other's KEX message, both KEX messages are concatenated (see below),
+ and the result is signed using ECDSA.
+ The result is sent to the other.
+@item After receiving the other's SIG message, the signature is verified.
+ If it is correct, the shared secret is calculated from the public keys exchanged in the KEX message using the Elliptic Curve Diffie-Helman algorithm.
+@item The shared secret key is expanded using a PRF.
+ Both nonces and the application specific label are also used as input for the PRF.
+@item An ACK message is sent only when doing key renegotiation, and is sent using the old encryption keys.
+@item The expanded key is used to key the encryption and HMAC algorithms.
+@end itemize
+
+The signature is calculated over this string:
+
+@itemize
+@item uint8_t initiator (0 = local peer, 1 = remote peer is initiator)
+@item opaque remote_kex_message[1 + 32 + ECDH_SIZE]
+@item opaque local_kex_message[1 + 32 + ECDH_SIZE]
+@item opaque label[label_length]
+@end itemize
+
+The PRF is calculated as follows:
+
+@itemize
+@item A HMAC using SHA512 is used, the shared secret is used as the key.
+@item For each block of 64 bytes, a HMAC is calculated. For block n: hmac[n] =
+ HMAC_SHA512(hmac[n - 1] + seed)
+@item For the first block (n = 1), hmac[0] is given by HMAC_SHA512(zeroes + seed),
+ where zeroes is a block of 64 zero bytes.
+@end itemize
+
+The seed is as follows:
+
+@itemize
+@item const char[13] "key expansion"
+@item opaque responder_nonce[32]
+@item opaque initiator_nonce[32]
+@item opaque label[label_length]
+@end itemize
+
+The expanded key is used as follows:
+
+@itemize
+@item opaque responder_cipher_key[CIPHER_KEYSIZE]
+@item opaque responder_digest_key[DIGEST_KEYSIZE]
+@item opaque initiator_cipher_key[CIPHER_KEYSIZE]
+@item opaque initiator_digest_key[DIGEST_KEYSIZE]
+@end itemize
+
+Where initiator_cipher_key is the key used by session initiator to encrypt
+messages sent to the responder.
+
+When using 521 bits EC keys, the AES-256-CTR cipher and HMAC-SHA-256 digest algorithm,
+the sizes are as follows:
+
+@example
+ECDH_SIZE: 67 (= ceil(521/8) + 1)
+ECDSA_SIZE: 141 (= 2 * ceil(521/8) + 9)
+CIPHER_KEYSIZE: 48 (= 256/8 + 128/8)
+DIGEST_KEYSIZE: 32 (= 256/8)
+@end example
+
+Note that the cipher key also includes the initial value for the counter.