\chapter{DHT Group Chats Packet Protocols} All packet fields are considered mandatory unless flagged as \textbf{\verb'[optional]'}. The minimum size of an encrypted packet is 83 bytes for lossless and 75 bytes for lossy. The maximum size of an encrypted packet is 1400 bytes. \section{Full Packet Structure} \subsection{Plaintext header} \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & Packet Kind \\ \texttt{32} & Sender's Public Encryption Key \\ \texttt{32} & Receiver's Public Encryption Key \textbf{\verb'[optional]'} \\ \texttt{24} & Nonce \\ \end{tabular} \subsection{Encrypted header} \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{0-8} & Padding \\ \texttt{1} & Group Packet Identifier \\ \texttt{8} & Message Id \textbf{\verb'[optional]'} \\ \end{tabular} \subsection{Encrypted payload} \begin{tabular}{l|l} Length & Contents \\ \hline Variable & Payload \\ \end{tabular} The plaintext header contains a \textbf{\verb'Toxcore Network Packet Kind'} which identifies the toxcore networking level packet type. These types are: \begin{tabular}{l|l} Type & Net Packet ID \\ \hline \textbf{\verb'NET_PACKET_GC_HANDSHAKE'} & 0x5a \\ \textbf{\verb'NET_PACKET_GC_LOSSLESS'} & 0x5b \\ \textbf{\verb'NET_PACKET_GC_LOSSY'} & 0x5c \\ \end{tabular} The sender's public encryption key is used to identify the peer who sent the packet, as well as to identify the group instance for which the packet is intended for all \textbf{\verb'NET_PACKET_GC_LOSSLESS'} and \textbf{\verb'NET_PACKET_GC_LOSSY'} packets. It is also used to establish a secure connection with the sender during the handshake protocol. The receiver's public encryption key is only sent in \textbf{\verb'NET_PACKET_GC_HANDSHAKE'} packets, and is used to identify the group instance for which the packet is intended. The encrypted header for lossless and lossy packets contains between 0 and 8 bytes of empty padding. The \textbf{\verb'Group Packet Identifier'} is used to identify the type of group packet, and the \textbf{\verb'Message ID'} is a unique packet identifier which must be included in the lossless packet header. The message ID must begin at 1, and increment by 1 after each new lossless packet is successfully sent. The encrypted payload contains arbitrary data specific to the respective group packet identifier. The length may range from zero to the maximum packet size (minus the headers). These payloads will be the focus of the remainder of this document. \section{Handshake packet payloads} Handshake packet payloads are structured as follows: \subsection{HANDSHAKE\_REQUEST (0x00) and HANDSHAKE\_RESPONSE (0x01)} \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{32} & Public Session Key \\ \texttt{32} & Public Signature Key \\ \texttt{1} & Request Type \\ \texttt{1} & Join Type \\ variable & 1 Packed TCP Relay \\ \end{tabular} \hline This packet type is used to initiate a secure connection with a peer. The \textbf{\verb'Public Session Key'} is a temporary key unique to this peer which, along with its secret counterpart, will be used to create a shared session encryption key. This keypair is used for all further communication for the current session. It must only be used for a single peer, and must be discarded of once the connection with the peer is severed. The \textbf{\verb'Public Signature Key'} is our own permanent signature key for this group chat. The \textbf{\verb'Request Type'} is an identifier for the type of handshake being initiated, defined as an enumerator starting at zero as follows: \begin{tabular}{l|l} Type & ID \\ \hline \textbf{\verb'HANDSHAKE_INVITE_REQUEST'} & 0x00 \\ \textbf{\verb'HANDSHAKE_PEER_INFO_EXCHANGE'} & 0x01 \\ \end{tabular} If the request type is an invite request, the receiving peer must respond with a \textbf{\verb'INVITE_REQUEST'} packet. If the request type is a peer info exchange, the receiving peer must respond with a \textbf{\verb'PEER_INFO_RESPONSE'} packet followed immediately by a \textbf{\verb'PEER_INFO_REQUEST'} packet. The \textbf{\verb'Join Type'} indicates whether the initiator of a handshake is joining via the public DHT or a private friend invite. This field is ignored in handshake response packets. It is defined as an enumerator beginning at zero as follows: \begin{tabular}{l|l} Type & ID \\ \hline \textbf{\verb'PUBLIC'} & 0x00 \\ \textbf{\verb'PRIVATE'} & 0x01 \\ \end{tabular} The packed TCP relay contains a TCP relay that the sender may be connected through by the receiver. \section{Lossy Packet Payloads} \subsection{PING (0x01)} A ping packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{2} & Peerlist Checksum \\ \texttt{2} & Confirmed Peer Count \\ \texttt{4} & Shared State Version \\ \texttt{4} & Sanctions Credentials Version \\ \texttt{2} & Peer Roles Checksum \\ \texttt{4} & Topic Version \\ \texttt{2} & Topic Checksum \\ Variable & Packed IP Address and Port \\ \end{tabular} Ping packets are sent every 12 seconds to every confirmed peer in order to maintain peer connections, and to ensure the group state between peers are in sync. A peer is considered to be disconnected from the group after a ping packet has not been receieved over a period of time. \subsection{MESSAGE\_ACK (0x02)} Message ack packets are structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{8} & Message ID \\ \texttt{1} & Type \\ \end{tabular} This packet ensures that all lossless packets are successfully received and processed in sequential order as they were sent. Message ack types are defined by an enumerator beginning at zero as follows: \begin{tabular}{l|l} Type & ID \\ \hline \textbf{\verb'GR_ACK_RECV'} & 0x00 \\ \textbf{\verb'GR_ACK_REQ'} & 0x01 \\ \end{tabular} If the type is \textbf{\verb'GR_ACK_RECV'}, this indicates that the packet with the given id has been received and successfully processed. If the type is \textbf{\verb'GR_ACK_REQ'}, this indicates that the message with the given id should be sent again. \subsection{INVITE\_RESPONSE\_REJECT (0x03)} An invite response reject payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & Type \\ \end{tabular} This packet alerts a peer that their invite request has been rejected. The reason for the rejection is specified by the \textbf{\verb'type'} field. Rejection types are defined by an enumerator beginning at zero as follows: \begin{tabular}{l|l} Type & ID \\ \hline \textbf{\verb'GROUP_FULL'} & 0x00 \\ \textbf{\verb'INVALID_PASSWORD'} & 0x01 \\ \textbf{\verb'INVITE_FAILED'} & 0x02 \\ \end{tabular} \section{Lossless Packet Payloads} \subsection{CUSTOM\_PRIVATE\_PACKET (0xee)} A custom private packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline Variable & Arbitrary Data \\ \end{tabular} This packet is used to to send arbitrary data to a specific peer. It may be used for client-side features. A custom private packet must be greater than 0 bytes, and may not exceed \textbf{\verb'TOX_MAX_CUSTOM_PACKET'} bytes. \subsection{FRAGMENT (0xef)} Fragment packets are structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & Lossless Packet Type \textbf{\verb'[First chunk only]'} \\ Variable & Arbitrary data \\ \end{tabular} Represents a segment in a sequence of packet fragments that comprise one full lossless packet payload which exceeds the maximum allowed packet chunk size (500 bytes). The first byte in the first chunk must be a lossless packet type. Each chunk in the sequence must be sent in succession. The end of the sequence is signaled by a fragment packet with a length of zero. A fully assembled packet must be no greater than 50,000 bytes. \subsection{KEY\_ROTATIONS (0xf0)} Key rotation packets are structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & \textbf{\verb'is_response'} \\ \texttt{32} & Public Encryption Key \\ \end{tabular} Key rotation packets are used to rotate session encryption keys with a peer. If \textbf{\verb'is_response'} is zero, the packet initiates a public key exchange. Otherwise, a non-zero value indicates that the packet is a response to a previously initiated exchange. The public encryption key must be a newly generated key which takes the place of the previously used session key. The resulting shared session key is generated using the same protocol as the initial handshake, and must be kept secret. Request packets should be sent at least once every 10 minutes, and only by the peer whose permanent public encryption key for the given group is closer to the group \textbf{\verb'Chat ID'} according to the \href{#distance}{\texttt{Distance}} metric. If the receiving peer does not receive a key rotation request packet after more than 10 minutes plus 12 seconds since the last successful rotation, the connection with the peer should be severed. \subsection{TCP\_RELAYS (0xf1)} A TCP relay packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline Variable & Packed TCP Relays \\ \end{tabular} The purpose of this packet is to share a list of TCP relays with a confirmed peer. Used to maintain a list of mutual TCP relays with other peers, which are used to maintain TCP connections when direct connections cannot be established. This packet is sent to every confirmed peer whenever a new TCP relay is added to our list, or periodically when we presently have no shared TCP relays with a given peer. \subsection{CUSTOM\_PACKETS (0xf2)} A custom packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline Variable & Arbitrary Data \\ \end{tabular} This packet is used to send arbitrary data to the group. It may be used for client-side features. A custom packet must be greater than 0 bytes, and may not exceed \textbf{\verb'TOX_MAX_CUSTOM_PACKET'} bytes. \subsection{BROADCAST (0xf3)} A broadcast packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & Type \\ Variable & Payload \\ \end{tabular} This packet broadcasts a message to all confirmed peers in a group (with the exception of \textbf{\verb'PRIVATE_MESSAGE'}). The type of broadcast is specificed by the \textbf{\verb'type'} field. Broadcast types are defined and structured as follows: \paragraph{STATUS (0x00)} \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & User status \\ \end{tabular} Indicates that a peer has changed their status. Statuses must be of type \textbf{\verb'USERSTATUS'}. \paragraph{NICK (0x01)} \begin{tabular}{l|l} Length & Contents \\ \hline Variable & Name \\ \end{tabular} Indicates that a peer has changed their nickname. A nick must be greater than 0 bytes, and may not exceed \textbf{\verb'TOX_MAX_NAME_LENGTH'} bytes in length. \paragraph{PLAIN\_MESSAGE (0x02)} \begin{tabular}{l|l} Length & Contents \\ \hline Variable & Arbitrary data \\ \end{tabular} Contains an arbitrary message. A plain message must be greater than 0 bytes, and may not exceed \textbf{\verb'TOX_MAX_MESSAGE_LENGTH'} bytes. \paragraph{ACTION\_MESSAGE (0x03)} \begin{tabular}{l|l} Length & Contents \\ \hline Variable & Arbitrary data \\ \end{tabular} Contains an arbitrary message. An action message must be greater than 0 bytes, and may not exceed \textbf{\verb'TOX_MAX_MESSAGE_LENGTH'} bytes. \paragraph{PRIVATE\_MESSAGE (0x04)} \begin{tabular}{l|l} Length & Contents \\ \hline Variable & Arbitrary data \\ \end{tabular} Contains an arbitrary message which is only sent to the intended peer. A private message must be greater than 0 bytes, and may not exceed \textbf{\verb'TOX_MAX_MESSAGE_LENGTH'} bytes. \paragraph{PEER\_EXIT (0x05)} \begin{tabular}{l|l} Length & Contents \\ \hline Variable & Arbitrary data \textbf{\verb'[optional]'} \\ \end{tabular} Indicates that a peer is leaving the group. Contains an optional parting message which may not exceed \textbf{\verb'TOX_GROUP_MAX_PART_LENGTH'}. \paragraph{PEER\_KICK (0x06)} \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{32} & Public Encryption Key \\ \end{tabular} Indicates that the peer associated with the public encryption key has been kicked from the group by a moderator or the founder. This peer must be removed from the peer list. \paragraph{SET\_MOD (0x07)} \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & is_promoted \\ \texttt{32} & Public Signature Key \\ \end{tabular} Indicates that the peer associated with the public signature key has either been promoted to or demoted from the \textbf{\verb'Moderator'} role by the group founder. If \textbf{\verb'is_promoted'} is non-zero, the peer should be promoted and added to the moderator list. Otherwise they should be demoted to the \textbf{\verb'User'} role and removed from the moderator list. \paragraph{SET\_OBSERVER (0x08)} \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & is_demoted \\ \texttt{32} & Public Encryption Key \\ \texttt{32} & Public Signature Key \\ \texttt{137} & Sanctions List Entry \textbf{\verb'[optional]'} \\ \texttt{132} & Packed Sanctions List Credentials \\ \end{tabular} Indicates that the peer associated with the given public keys has either been demoted to or promoted from the \textbf{\verb'Observer'} role by the group founder or a moderator. If \textbf{\verb'is_demoted'} is non-zero, the peer should be demoted and added to the sanctions list. Otherwise they should be promoted to the \textbf{\verb'User'} role and removed from the sanctions list. \subsection{PEER\_INFO\_REQUEST (0xf4)} A peer info request packet contains an empty payload. Its purpose is to request a peer to send us information about themselves. \subsection{PEER\_INFO\_RESPONSE (0xf5)} A peer info response packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{2} & Group Password Length \textbf{\verb'[optional]'} \\ \texttt{32} & Group Password \textbf{\verb'[optional]'} \\ \texttt{2} & Name Length \\ \texttt{128} & Name \\ \texttt{1} & Status \\ \end{tabular} This packet supplies information about ourselves to a peer. It is sent as a response to a \textbf{\verb'PEER_INFO_REQUEST'} or \textbf{\verb'HS_PEER_INFO_EXCHANGE'} packet as part of the handshake protocol. A password and length of password must be included in the packet if the group is password protected. \subsection{INVITE\_REQUEST (0xf6)} An invite request packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{2} & Group Password Length \textbf{\verb'[optional]'} \\ \texttt{32} & Group Password \textbf{\verb'[optional]'} \\ \end{tabular} This packet requests an invite to the group. A password and length of password must be included in the packet if the group is password protected. \subsection{INVITE\_RESPONSE (0xf7)} An invite response packet has an empty payload. This packet alerts a peer who sent us an \textbf{\verb'INVITE_REQUEST'} packet that their request has been validated, which informs them that they may continue to the next step in the handshake protocol. Before sending this packet we first attempt to validate the invite request. If validation fails, we instead send a packet of type \textbf{\verb'INVITE_RESPONSE_REJECT'} in response, and remove the peer from our peer list. \subsection{SYNC\_REQUEST (0xf8)} A sync request packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{2} & \textbf{\verb'Sync_Flags'} \\ \texttt{2} & Group Password Length \textbf{\verb'[optional]'} \\ \texttt{32} & Group Password \textbf{\verb'[optional]'} \\ \end{tabular} This packet asks a peer to send us state information about the group chat. The specific information being requested is specified via the \textbf{\verb'Sync_Flags'} field. A password and length of password must be included in the packet if the group is password protected. \textbf{\verb'Sync_Flags'} is a bitfield defined as a 16-bit unsigned integer which may have the bits set for the respective values depending on what information is being requested: \begin{tabular}{l|l} Type & Set Bits \\ \hline \textbf{\verb'PEER_LIST'} & 0x01 \\ \textbf{\verb'TOPIC'} & 0x02 \\ \textbf{\verb'STATE'} & 0x04 \\ \end{tabular} When the \textbf{\verb'STATE'} flag is set, the group's state data must be sent first, and in the following order: \textbf{\verb'Shared State'}, \textbf{\verb'Moderation List'}, \textbf{\verb'Sanctions List'}. \subsection{SYNC\_RESPONSE (0xf9)} A sync response packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{32} & Public Encryption Key \\ \texttt{1} & \textbf{\verb'IP_Port_Is_Set'} \\ \texttt{1} & TCP Relays Count \\ Variable & Packed IP\_Port \textbf{\verb'[optional]'} \\ Variable & Packed TCP Relays \textbf{\verb'[optional]'} \\ \end{tabular} This packet is sent as a response to a peer who made a sync request via the \textbf{\verb'SYNC_REQUEST'} packet. It contains a single packed peer announce, which is a data structure that contains all of the information about a peer needed to initiate the handshake protocol via TCP relays, a direct connection, or both. If the \textbf{\verb'IP_Port_Is_Set'} flag is non-zero, the packet will contain a packed \textbf{\verb'IP_Port'} of the peer associated with the given public key. If \textbf{\verb'TCP Relays Count'} is greater than 0, the packet will contain a list of tcp relays that the peer associated with the given public key is connected to. When responding to a sync request, one separate sync response will be sent for each peer in the peer list. All other requested group information is sent via its respective packet. \subsection{TOPIC (0xfa)} A topic packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{64} & Topic Signature \\ \texttt{4} & Topic Version \\ \texttt{2} & Topic Checksum \\ \texttt{2} & Topic Length \\ Topic Length & Topic \\ \texttt{32} & Public Signature Key \\ \end{tabular} This packet contains a topic as well as information used to validate the topic. Sent when the topic changes, or in response to a \textbf{\verb'SYNC_REQUEST'} in which the \textbf{\verb'TOPIC'} flag is set. A topic may not exceed \textbf{\verb'TOX_GROUP_MAX_TOPIC_LENGTH'} bytes in length. \subsection{SHARED\_STATE (0xfb)} A shared state packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{64} & Shared State Signature \\ \texttt{4} & Shared State Version \\ \texttt{64} & Founder Extended Public Key \\ \texttt{2} & Peer Limit \\ \texttt{2} & Group Name Length \\ \texttt{48} & Group Name \\ \texttt{1} & Privacy State \\ \texttt{2} & Group Password Length \\ \texttt{32} & Group Password \\ \texttt{32} & Moderator List Hash (Sha256) \\ \texttt{4} & Topic Lock State \\ \texttt{1} & Voice State \\ \end{tabular} This packet contains information about the group shared state. Sent to all peers by the group founder whenever the shared state has changed. Also sent in response to a \textbf{\verb'SYNC_REQUEST'} in which the \textbf{\verb'STATE'} flag is set. \subsection{MOD\_LIST (0xfc)} A moderation list packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{2} & Moderator Count \\ Variable & Moderator List \\ \end{tabular} This packet contains information about the moderator list, including the number of moderators, and a list of public signature keys of all current moderators. Sent to all peers by the group founder after the moderator list has been modified. Also sent in response to a \textbf{\verb'SYNC_REQUEST'} in which the \textbf{\verb'STATE'} flag is set. The moderator list is comprised of one or more 32 byte public signature keys. This packet must always be sent after a \textbf{\verb'SHARED_STATE'} packet, as the moderator list is validated using data contained within the shared state. \subsection{SANCTIONS\_LIST (0xfd)} A sanctions list packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{2} & Sanctions List Count \\ Variable & Sanctions List \\ \texttt{132} & Packed Sanctions List Credentials \\ \end{tabular} \paragraph{Sanctions List Entry} \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & Type \\ \texttt{32} & Public Signature Key \\ \texttt{8} & Unix Timestamp \\ \texttt{32} & Public Encryption Key \\ \texttt{64} & Signature \\ \end{tabular} \paragraph{Sanctions Credentials} \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{4} & Version \\ \texttt{32} & Hash (Sha256) \\ \texttt{2} & Checksum \\ \texttt{32} & Public Signature Key \\ \texttt{64} & Signature \\ \end{tabular} This packet contains information about the sanctions list, including the number of entries, the sanctions list, and the credentials needed to validate the sanctions list. Sanctions types are defined as an enumerator beginning at zero as follows: \begin{tabular}{l|l} Type & ID \\ \hline \textbf{\verb'OBSERVER'} & 0x00 \\ \end{tabular} During a sync response, this packet must be sent after a \textbf{\verb'MOD_LIST'} packet, as the sanctions list is validated using the moderator list. \subsection{FRIEND\_INVITE (0xfe)} A friend invite packet payload is structured as follows: \begin{tabular}{l|l} Length & Contents \\ \hline \texttt{1} & Type \\ \end{tabular} Used to initiate or respond to a group invite to or from an existing friend. The invite action is specified by the \textbf{\verb'type'} field. Invite types are defined as an enumerator beginning at zero as follows: \begin{tabular}{l|l} Type & ID \\ \hline \textbf{\verb'GROUP_INVITE'} & 0x00 \\ \textbf{\verb'GROUP_INVITE_ACCEPTED'} & 0x01 \\ \textbf{\verb'GROUP_INVITE_CONFIRM'} & 0x02 \\ \end{tabular} \subsection{HS\_RESPONSE\_ACK (0xff)} A handshake response ack packet has an empty payload. This packet is used to send acknowledgement that a lower level toxcore \textbf{\verb'NET_PACKET_GC_HANDSHAKE'} packet has been received, which is the first step in the group handshake protocol. This packet will initiate an invite request via the \textbf{\verb'INVITE_REQUEST'} packet. \begin{code} module Tox.Application.GroupChatPackets where \end{code}