# MuWire network protocol The MuWire protocol operates over a TCP-like streaming layer offered by the I2P streaming library. ## Handshake A connection begins with the word "MuWire" followed by a space and one of the following words: "leaf", "peer" or "results", depending on whether Alice is in a leaf, ultrapeer or responder role. This allows Bob to immediately drop the connection without allocating any more resources. If Bob is an ultrapeer he responds to the handshake by either accepting it or rejecting it and optionally suggesting other ultrapeers to connect to. Accepting the handshake is done by responding with a single word "OK". Rejecting the handshake is done by responding with the word "REJECT", optionally followed JSON payload prefixed by two unsigned bytes indicating the length of the JSON document. In that document, Bob can suggest ultrapeers to connect to in b64 format: ``` { tryHosts: [b64.1, b64.2...] } ``` ## Compression All traffic after the handshake is compressed using the same compression algorithm in Gnutella. ## Blobs in JSON All protocol elements that are represented as blobs (personas, certificates, file names, seach terms) get Base64 encoded when transmitted as part of JSON documents. ## Internationalization support All protocol elements that may contain non-ascii characters (file names, search terms, persona nicknames) are represented as a binary blob with the following format: ``` byte 0: unsigned length of the official charset name bytes 1 to N: name of the charset in ASCII bytes N+1 and N+2: unsigned length of the binary representation of the string bytes N+3 to N+M: binary representation of the string ``` ## Persona wire format (See the "web-of-trust" document for the definition of a MuWire persona). A persona is represented as a blob with the following format: ``` byte 0: unsigned version number of the format. Currently fixed at 1. bytes 1 to N: nickname of the persona in internationalized format bytes N+1 and N+2: unsigned length of the I2P destination of the persona bytes N+3 to N+M: the I2P destination of the persona bytes N+M+1 to N+M+O: public key of the persona (length of public key TBD) bytes N+M+O+1 to N+M+O+P: signature of bytes 0 to N+M+O (length TBD) ``` ## Certificate wire format (See the "web-of-trust" document for the definition of a MuWire certificate) A certificate is represented as a blob with the following format: ``` byte 0: unsigned version number of the format. Currently fixed at 1. bytes 1 to 8: timestamp in milliseconds the certificate was created bytes 9 to N: Alice's persona bytes N+1 to M: Bob's persona bytes M+1 to O: signature of bytes 0 to M, signed by Alice (length TBD) ``` ## Messages After the handhsake follows a stream of messages. Messages can arrive in any order. Every 10 seconds a "Ping" message is sent on each connection which serves as a keep-alive. The response to that message is a "Pong" which carries b64 destinations of ultrapeers the remote side has been able to connect to. This keeps the host pool in each node fresh. Between ultrapeers, each message consists of 3 bytes - the most significant bit of the first byte indicates if the payload is binary or JSON. The remaining 23 bits indicate the length of the message. Between leaf and ultrapeer, each message consists of 2 bytes unsigned payload length followed by the JSON payload. The JSON structure has two mandatory top-level fields - type and version: ``` { type : "MessageType", version : 1, ... } ``` Binary messages can be two types: full bloom filter or a patch messageHTTP/1.1 200 OK Content-Disposition: inline; filename="wire-protocol.md"; filename*=UTF-8''wire-protocol.md Content-Type: text/plain; charset=utf-8 X-Content-Type-Options: nosniff Date: Wed, 23 Jul 2025 02:00:21 GMT Cache-Control: public, max-age=21600, no-transform Content-Length: 8791 Last-Modified: Mon, 29 Oct 2018 16:48:18 GMT X-Frame-Options: SAMEORIGIN Access-Control-Expose-Headers: Content-Disposition Etag: "b2ac1f85b82df0dec7accba276cf9cf8a11822fd" Connection: close X-Cache-Status: HIT X-Cache-Age: 0 # MuWire network protocol The MuWire protocol operates over a TCP-like streaming layer offered by the I2P streaming library. ## Handshake A connection begins with the word "MuWire" followed by a space and one of the following words: "leaf", "peer" or "results", depending on whether Alice is in a leaf, ultrapeer or responder role. This allows Bob to immediately drop the connection without allocating any more resources. If Bob is an ultrapeer he responds to the handshake by either accepting it or rejecting it and optionally suggesting other ultrapeers to connect to. Accepting the handshake is done by responding with a single word "OK". Rejecting the handshake is done by responding with the word "REJECT", optionally followed JSON payload prefixed by two unsigned bytes indicating the length of the JSON document. In that document, Bob can suggest ultrapeers to connect to in b64 format: ``` { tryHosts: [b64.1, b64.2...] } ``` ## Compression All traffic after the handshake is compressed using the same compression algorithm in Gnutella. ## Blobs in JSON All protocol elements that are represented as blobs (personas, certificates, file names, seach terms) get Base64 encoded when transmitted as part of JSON documents. ## Internationalization support All protocol elements that may contain non-ascii characters (file names, search terms, persona nicknames) are represented as a binary blob with the following format: ``` byte 0: unsigned length of the official charset name bytes 1 to N: name of the charset in ASCII bytes N+1 and N+2: unsigned length of the binary representation of the string bytes N+3 to N+M: binary representation of the string ``` ## Persona wire format (See the "web-of-trust" document for the definition of a MuWire persona). A persona is represented as a blob with the following format: ``` byte 0: unsigned version number of the format. Currently fixed at 1. bytes 1 to N: nickname of the persona in internationalized format bytes N+1 and N+2: unsigned length of the I2P destination of the persona bytes N+3 to N+M: the I2P destination of the persona bytes N+M+1 to N+M+O: public key of the persona (length of public key TBD) bytes N+M+O+1 to N+M+O+P: signature of bytes 0 to N+M+O (length TBD) ``` ## Certificate wire format (See the "web-of-trust" document for the definition of a MuWire certificate) A certificate is represented as a blob with the following format: ``` byte 0: unsigned version number of the format. Currently fixed at 1. bytes 1 to 8: timestamp in milliseconds the certificate was created bytes 9 to N: Alice's persona bytes N+1 to M: Bob's persona bytes M+1 to O: signature of bytes 0 to M, signed by Alice (length TBD) ``` ## Messages After the handhsake follows a stream of messages. Messages can arrive in any order. Every 10 seconds a "Ping" message is sent on each connection which serves as a keep-alive. The response to that message is a "Pong" which carries b64 destinations of ultrapeers the remote side has been able to connect to. This keeps the host pool in each node fresh. Between ultrapeers, each message consists of 3 bytes - the most significant bit of the first byte indicates if the payload is binary or JSON. The remaining 23 bits indicate the length of the message. Between leaf and ultrapeer, each message consists of 2 bytes unsigned payload length followed by the JSON payload. The JSON structure has two mandatory top-level fields - type and version: ``` { type : "MessageType", version : 1, ... } ``` Binary messages can be two types: full bloom filter or a patch message