</code></pre></div></div><p><codeclass="language-plaintext highlighter-rouge">protocolVersion</code>: version of the Whisper protocol <codeclass="language-plaintext highlighter-rouge">PoW</code>: minimum PoW accepted by the peer <codeclass="language-plaintext highlighter-rouge">bloom</code>: bloom filter of Whisper topic accepted by the peer <codeclass="language-plaintext highlighter-rouge">isLightNode</code>: when true, the peer won’t forward messages <codeclass="language-plaintext highlighter-rouge">confirmationsEnabled</code>: when true, the peer will send message confirmations <codeclass="language-plaintext highlighter-rouge">rateLimits</code>: is <codeclass="language-plaintext highlighter-rouge">[ RateLimitIP, RateLimitPeerID, RateLimitTopic ]</code> where each values is an integer with a number of accepted packets per second per IP, Peer ID, and Topic respectively</p><p><codeclass="language-plaintext highlighter-rouge">bloom, isLightNode, confirmationsEnabled, and rateLimits</code> are all optional arguments in the handshake. However, if an optional field is specified, all optional fields preceding it MUST also be specified in order to be unambiguous.</p><h2id="rate-limiting"><ahref="#rate-limiting"class="anchor-heading"aria-labelledby="rate-limiting"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Rate limiting </h2><p>In order to provide an optional very basic Denial-of-Service attack protection, each node SHOULD define its own rate limits. The rate limits SHOULD be applied on IPs, peer IDs, and envelope topics.</p><p>Each node MAY decide to whitelist, i.e. do not rate limit, selected IPs or peer IDs.</p><p>If a peer exceeds node’s rate limits, the connection between them MAY be dropped.</p><p>Each node SHOULD broadcast its rate limits to its peers using rate limits packet code (<codeclass="language-plaintext highlighter-rouge">0x14</code>). The rate limits is RLP-encoded information:</p><divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>[ IP limits, PeerID limits, Topic limits ]
</code></pre></div></div><p><codeclass="language-plaintext highlighter-rouge">IP limits</code>: 4-byte wide unsigned integer <codeclass="language-plaintext highlighter-rouge">PeerID limits</code>: 4-byte wide unsigned integer <codeclass="language-plaintext highlighter-rouge">Topic limits</code>: 4-byte wide unsigned integer</p><p>The rate limits MAY also be sent as an optional parameter in the handshake.</p><p>Each node SHOULD respect rate limits advertised by its peers. The number of packets SHOULD be throttled in order not to exceed peer’s rate limits. If the limit gets exceeded, the connection MAY be dropped by the peer.</p><h2id="keys-management"><ahref="#keys-management"class="anchor-heading"aria-labelledby="keys-management"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Keys management </h2><p>The protocol requires a key (symmetric or asymmetric) for the following actions:</p><ul><li>signing & verifying messages (asymmetric key)</li><li>encrypting & decrypting messages (asymmetric or symmetric key).</li></ul><p>As nodes require asymmetric keys and symmetric keys to process incoming messages, they must be available all the time and are stored in memory.</p><p>Keys management for PFS is described in <ahref="https://specs.status.im/spec/5">5/SECURE-TRANSPORT</a>.</p><p>The Status protocols uses a few particular Whisper topics to achieve its goals.</p><h3id="contact-code-topic"><ahref="#contact-code-topic"class="anchor-heading"aria-labelledby="contact-code-topic"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Contact code topic </h3><p>Nodes use the contact code topic to facilitate the discovery of X3DH bundles so that the first message can be PFS-encrypted.</p><p>Each user publishes periodically to this topic. If user A wants to contact user B, she SHOULD look for their bundle on this contact code topic.</p><p>Contact code topic MUST be created following the algorithm below:</p><divclass="language-golang highlighter-rouge"><divclass="highlight"><preclass="highlight"><code><spanclass="n">contactCode</span><spanclass="o">:=</span><spanclass="s">"0x"</span><spanclass="o">+</span><spanclass="n">hexEncode</span><spanclass="p">(</span><spanclass="n">activePublicKey</span><spanclass="p">)</span><spanclass="o">+</span><spanclass="s">"-contact-code"</span>
</code></pre></div></div><h3id="partitioned-topic"><ahref="#partitioned-topic"class="anchor-heading"aria-labelledby="partitioned-topic"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Partitioned topic </h3><p>Whisper is broadcast-based protocol. In theory, everyone could communicate using a single topic but that would be extremely inefficient. Opposite would be using a unique topic for each conversation, however, this brings privacy concerns because it would be much easier to detect whether and when two parties have an active conversation.</p><p>Nodes use partitioned topics to broadcast private messages efficiently. By selecting a number of topic, it is possible to balance efficiency and privacy.</p><p>Currently, nodes set the number of partitioned topics to <codeclass="language-plaintext highlighter-rouge">5000</code>. They MUST be generated following the algorithm below:</p><divclass="language-golang highlighter-rouge"><divclass="highlight"><preclass="highlight"><code><spanclass="k">var</span><spanclass="n">partitionsNum</span><spanclass="o">*</span><spanclass="n">big</span><spanclass="o">.</span><spanclass="n">Int</span><spanclass="o">=</span><spanclass="n">big</span><spanclass="o">.</span><spanclass="n">NewInt</span><spanclass="p">(</span><spanclass="m">5000</span><spanclass="p">)</span>
</code></pre></div></div><h3id="public-chats"><ahref="#public-chats"class="anchor-heading"aria-labelledby="public-chats"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Public chats </h3><p>A public chat MUST use a topic derived from a public chat name following the algorithm below:</p><divclass="language-golang highlighter-rouge"><divclass="highlight"><preclass="highlight"><code><spanclass="k">var</span><spanclass="n">hash</span><spanclass="p">[]</span><spanclass="kt">byte</span>
</code></pre></div></div><!-- NOTE: commented out as it is currently not used. In code for potential future use. - C.P. Oct 8, 2019 ### Personal discovery topic Personal discovery topic is used to ??? A client MUST implement it following the algorithm below: ```golang personalDiscoveryTopic := "contact-discovery-" + hexEncode(publicKey) var hash []byte = keccak256(personalDiscoveryTopic) var topicLen int = 4 if len(hash) < topicLen { topicLen = len(hash) } var topic [4]byte for i = 0; i < topicLen; i++ { topic[i] = hash[i] } ``` Each Status Client SHOULD listen to this topic in order to receive ??? --><!-- NOTE: commented out as it is no longer valid as of V1. - C.P. Oct 8, 2019 ### Generic discovery topic Generic discovery topic is a legacy topic used to handle all one-to-one chats. The newer implementation should rely on [Partitioned Topic](#partitioned-topic) and [Personal discovery topic](#personal-discovery-topic). Generic discovery topic MUST be created following [Public chats](#public-chats) topic algorithm using string `contact-discovery` as a name. --><h3id="group-chat-topic"><ahref="#group-chat-topic"class="anchor-heading"aria-labelledby="group-chat-topic"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Group chat topic </h3><p>Group chats does not have a dedicated topic. All group chat messages (including membership updates) are sent as one-to-one messages to multiple recipients.</p><h3id="negotiated-topic"><ahref="#negotiated-topic"class="anchor-heading"aria-labelledby="negotiated-topic"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Negotiated topic </h3><p>When a client sends a one to one message to another client, it MUST listen to their negotiated topic. This is computed by generating a diffie-hellman key exchange between two members and taking the first four bytes of the <codeclass="language-plaintext highlighter-rouge">SHA3-256</code> of the key generated.</p><divclass="language-golang highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>
</code></pre></div></div><p>A client SHOULD send to the negotiated topic only if it has received a message from all the devices included in the conversation.</p><h3id="flow"><ahref="#flow"class="anchor-heading"aria-labelledby="flow"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Flow </h3><p>To exchange messages with client <codeclass="language-plaintext highlighter-rouge">B</code>, a client <codeclass="language-plaintext highlighter-rouge">A</code> SHOULD:</p><ul><li>Listen to client’s <codeclass="language-plaintext highlighter-rouge">B</code> Contact Code Topic to retrieve their bundle information, including a list of active devices</li><li>Send a message on client’s <codeclass="language-plaintext highlighter-rouge">B</code> partitioned topic</li><li>Listen to the Negotiated Topic between <codeclass="language-plaintext highlighter-rouge">A</code>&<codeclass="language-plaintext highlighter-rouge">B</code></li><li>Once client <codeclass="language-plaintext highlighter-rouge">A</code> receives a message from <codeclass="language-plaintext highlighter-rouge">B</code>, the Negotiated Topic SHOULD be used</li></ul><h2id="message-encryption"><ahref="#message-encryption"class="anchor-heading"aria-labelledby="message-encryption"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Message encryption </h2><p>Even though, the protocol specifies an encryption layer that encrypts messages before passing them to the transport layer, Whisper protocol requires each Whisper message to be encrypted anyway.</p><p>The node encrypts public and group messages using symmetric encryption, and creates the key from a channel name string. The implementation is available in <ahref="https://github.com/ethereum/go-ethereum/wiki/Whisper-v6-RPC-API#shh_generatesymkeyfrompassword"><codeclass="language-plaintext highlighter-rouge">shh_generateSymKeyFromPassword</code></a> JSON-RPC method of go-ethereum Whisper implementation.</p><p>The node encrypts one-to-one messages using asymmetric encryption.</p><h2id="message-confirmations"><ahref="#message-confirmations"class="anchor-heading"aria-labelledby="message-confirmations"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Message confirmations </h2><p>Sending a message is a complex process where many things can go wrong. Message confirmations tell a node that a message originating from it has been seen by its direct peers.</p><p>A node MAY send a message confirmation for any batch of messages received in a packet Messages Code (<codeclass="language-plaintext highlighter-rouge">0x01</code>).</p><p>A node sends a message confirmation using Batch Acknowledge packet (<codeclass="language-plaintext highlighter-rouge">0x0b</code>) or Message Response packet (<codeclass="language-plaintext highlighter-rouge">0x0c</code>).</p><p>The Batch Acknowledge packet is followed by a keccak256 hash of the envelopes batch data (raw bytes).</p><p>The Message Response packet is more complex and is followed by a Versioned Message Response:</p><divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>[ Version, Response]
</code></pre></div></div><p><codeclass="language-plaintext highlighter-rouge">Version</code>: a version of the Message Response, equal to <codeclass="language-plaintext highlighter-rouge">1</code>, <codeclass="language-plaintext highlighter-rouge">Response</code>: <codeclass="language-plaintext highlighter-rouge">[ Hash, Errors ]</code> where <codeclass="language-plaintext highlighter-rouge">Hash</code> is a keccak256 hash of the envelopes batch data (raw bytes) for which the confirmation is sent and <codeclass="language-plaintext highlighter-rouge">Errors</code> is a list of envelope errors when processing the batch. A single error contains <codeclass="language-plaintext highlighter-rouge">[ Hash, Code, Description ]</code> where <codeclass="language-plaintext highlighter-rouge">Hash</code> is a hash of the processed envelope, <codeclass="language-plaintext highlighter-rouge">Code</code> is an error code and <codeclass="language-plaintext highlighter-rouge">Description</code> is a descriptive error message.</p><p>The supported codes: <codeclass="language-plaintext highlighter-rouge">1</code>: means time sync error which happens when an envelope is too old or created in the future (the root cause is no time sync between nodes).</p><p>The drawback of sending message confirmations is that it increases the noise in the network because for each sent message, one or more peers broadcast a corresponding confirmation. To limit that, both Batch Acknowledge packet (<codeclass="language-plaintext highlighter-rouge">0x0b</code>) and Message Response packet (<codeclass="language-plaintext highlighter-rouge">0x0c</code>) are not broadcast to peers of the peers, i.e. they do not follow epidemic spread.</p><p>In the current Status network setup, only <codeclass="language-plaintext highlighter-rouge">Mailservers</code> support message confirmations. A client posting a message to the network and after receiving a confirmation can be sure that the message got processed by the <codeclass="language-plaintext highlighter-rouge">Mailserver</code>. If additionally, sending a message is limited to non-<codeclass="language-plaintext highlighter-rouge">Mailserver</code> peers, it also guarantees that the message got broadcast through the network and it reached the selected <codeclass="language-plaintext highlighter-rouge">Mailserver</code>.</p><h2id="whisper--waku-bridging"><ahref="#whisper--waku-bridging"class="anchor-heading"aria-labelledby="whisper--waku-bridging"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Whisper / Waku bridging </h2><p>In order to maintain compatibility between Whisper and Waku nodes, a Status network that implements both Whisper and Waku messaging protocols MUST have at least one node that is capable of discovering peers and implements <ahref="https://eips.ethereum.org/EIPS/eip-627">Whisper v6</a>, <ahref="https://rfc.vac.dev/spec/5/">Waku V0</a> and <ahref="https://rfc.vac.dev/spec/6/">Waku V1</a> specifications.</p><p>Additionally, any Status network that implements both Whisper and Waku messaging protocols MUST implement bridging capabilities as detailed in <ahref="https://rfc.vac.dev/spec/6/#waku-whisper-bridging">Waku V1#Bridging</a>.</p><h2id="whisper-v6-extensions"><ahref="#whisper-v6-extensions"class="anchor-heading"aria-labelledby="whisper-v6-extensions"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Whisper V6 extensions </h2><h3id="request-historic-messages"><ahref="#request-historic-messages"class="anchor-heading"aria-labelledby="request-historic-messages"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Request historic messages </h3><p>Sends a request for historic messages to a <codeclass="language-plaintext highlighter-rouge">Mailserver</code>. The <codeclass="language-plaintext highlighter-rouge">Mailserver</code> node MUST be a direct peer and MUST be marked as trusted (using <codeclass="language-plaintext highlighter-rouge">shh_mar