mirror of https://github.com/status-im/specs.git
67 lines
41 KiB
HTML
67 lines
41 KiB
HTML
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <title>3/WHISPER-USAGE - Status Specification</title> <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"> <link rel="stylesheet" href="/assets/css/just-the-docs-default.css"> <script type="text/javascript" src="/assets/js/vendor/lunr.min.js"></script> <script type="text/javascript" src="/assets/js/just-the-docs.js"></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Begin Jekyll SEO tag v2.7.1 --> <title>3/WHISPER-USAGE | Status Specification</title> <meta name="generator" content="Jekyll v4.2.1" /> <meta property="og:title" content="3/WHISPER-USAGE" /> <meta property="og:locale" content="en_US" /> <link rel="canonical" href="https://specs.status.im/draft/3" /> <meta property="og:url" content="https://specs.status.im/draft/3" /> <meta property="og:site_name" content="Status Specification" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="3/WHISPER-USAGE" /> <script type="application/ld+json"> {"@type":"WebPage","url":"https://specs.status.im/draft/3","headline":"3/WHISPER-USAGE","@context":"https://schema.org"}</script> <!-- End Jekyll SEO tag --> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-link" viewBox="0 0 24 24"> <title>Link</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"> <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path> </svg> </symbol> <symbol id="svg-search" viewBox="0 0 24 24"> <title>Search</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"> <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line> </svg> </symbol> <symbol id="svg-menu" viewBox="0 0 24 24"> <title>Menu</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"> <line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line> </svg> </symbol> <symbol id="svg-arrow-right" viewBox="0 0 24 24"> <title>Expand</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"> <polyline points="9 18 15 12 9 6"></polyline> </svg> </symbol> <symbol id="svg-doc" viewBox="0 0 24 24"> <title>Document</title> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file"> <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline> </svg> </symbol> </svg> <div class="side-bar"> <div class="site-header"> <a href="https://specs.status.im/" class="site-title lh-tight"> Status Specification </a> <a href="#" id="menu-button" class="site-button"> <svg viewBox="0 0 24 24" class="icon"><use xlink:href="#svg-menu"></use></svg> </a> </div> <nav role="navigation" aria-label="Main" id="site-nav" class="site-nav"> <ul class="nav-list"><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="https://specs.status.im/spec/" class="nav-list-link">Stable specs</a><ul class="nav-list "><li class="nav-list-item "><a href="https://specs.status.im/spec/1" class="nav-list-link">1/CLIENT</a></li><li class="nav-list-item "><a href="https://specs.status.im/spec/10" class="nav-list-link">10/WAKU-USAGE</a></li><li class="nav-list-item "><a href="https://specs.status.im/spec/11" class="nav-list-link">11/WAKU-MAILSERVER</a></li><li class="nav-list-item "><a href="https://specs.status.im/draft/15" class="nav-list-link">15/NOTIFICATIONS</a></li><li class="nav-list-item "><a href="https://specs.status.im/spec/2" class="nav-list-link">2/ACCOUNT</a></li><li class="nav-list-item "><a href="https://specs.status.im/spec/3" class="nav-list-link">3/WHISPER-USAGE</a></li><li class="nav-list-item "><a href="https://specs.status.im/spec/4" class="nav-list-link">4/WHISPER-MAILSERVER</a></li><li class="nav-list-item "><a href="https://specs.status.im/spec/5" class="nav-list-link">5/SECURE-TRANSPORT</a></li><li class="nav-list-item "><a href="https://specs.status.im/spec/6" class="nav-list-link">6/PAYLOADS</a></li><li class="nav-list-item "><a href="https://specs.status.im/spec/8" class="nav-list-link">8/EIPS</a></li><li class="nav-list-item "><a href="https://specs.status.im/spec/9" class="nav-list-link">9/ETHEREUM-USAGE</a></li></ul></li><li class="nav-list-item active"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="https://specs.status.im/draft/" class="nav-list-link">Draft specs</a><ul class="nav-list "><li class="nav-list-item "><a href="https://specs.status.im/draft/12" class="nav-list-link">12/IPFS gateway for Sticker Pack</a></li><li class="nav-list-item "><a href="https://specs.status.im/draft/13" class="nav-list-link">13/3RD-PARTY-USAGE</a></li><li class="nav-list-item "><a href="https://specs.status.im/draft/14" class="nav-list-link">14/Dapp browser API usage</a></li><li class="nav-list-item "><a href="https://specs.status.im/draft/16" class="nav-list-link">16/Keycard Usage for Wallet and Chat Keys</a></li><li class="nav-list-item active"><a href="https://specs.status.im/draft/3" class="nav-list-link active">3/WHISPER-USAGE</a></li><li class="nav-list-item "><a href="https://specs.status.im/draft/6" class="nav-list-link">6/PAYLOADS</a></li><li class="nav-list-item "><a href="https://specs.status.im/draft/7" class="nav-list-link">7/GROUP-CHAT</a></li></ul></li><li class="nav-list-item"><a href="#" class="nav-list-expander"><svg viewBox="0 0 24 24"><use xlink:href="#svg-arrow-right"></use></svg></a><a href="https://specs.status.im/raw/" class="nav-list-link">Raw specs</a><ul class="nav-list "><li class="nav-list-item "><a href="https://specs.status.im/raw/16" class="nav-list-link">16/PUSH-NOTIFICATION-SERVER</a></li></ul></li><li class="nav-list-item"><a href="https://specs.status.im/development" class="nav-list-link">DEVELOPMENT</a></li><li class="nav-list-item"><a href="https://specs.status.im/style-guideline" class="nav-list-link">STYLE-GUIDELINE</a></li></ul> </nav> <footer class="site-footer"> This site uses <a href="https://github.com/pmarsceill/just-the-docs">Just the Docs</a>, a documentation theme for Jekyll. </footer> </div> <div class="main" id="top"> <div id="main-header" class="main-header"> <div class="search"> <div class="search-input-wrap"> <input type="text" id="search-input" class="search-input" tabindex="0" placeholder="Search Status Specification" aria-label="Search Status Specification" autocomplete="off"> <label for="search-input" class="search-label"><svg viewBox="0 0 24 24" class="search-icon"><use xlink:href="#svg-search"></use></svg></label> </div> <div id="search-results" class="search-results"></div> </div> </div> <div id="main-content-wrap" class="main-content-wrap"> <nav aria-label="Breadcrumb" class="breadcrumb-nav"> <ol class="breadcrumb-nav-list"> <li class="breadcrumb-nav-list-item"><a href="https://specs.status.im/draft/">Draft specs</a></li> <li class="breadcrumb-nav-list-item"><span>3/WHISPER-USAGE</span></li> </ol> </nav> <div id="main-content" class="main-content" role="main"> <h1 id="3whisper-usage"> <a href="#3whisper-usage" class="anchor-heading" aria-labelledby="3whisper-usage"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> 3/WHISPER-USAGE </h1> <blockquote> <p>Version: 0.3</p> <p>Status: Draft</p> <p>Authors: Adam Babik <a href="mailto:adam@status.im">adam@status.im</a>, Andrea Maria Piana <a href="mailto:andreap@status.im">andreap@status.im</a>, Corey Petty <a href="mailto:corey@status.im">corey@status.im</a>, Oskar Thorén <a href="mailto:oskar@status.im">oskar@status.im</a> (alphabetical order)</p> </blockquote> <ul> <li><a href="#abstract">Abstract</a></li> <li><a href="#reason">Reason</a></li> <li><a href="#terminology">Terminology</a></li> <li><a href="#whisper-packets">Whisper packets</a></li> <li><a href="#whisper-node-configuration">Whisper node configuration</a></li> <li><a href="#handshake">Handshake</a></li> <li><a href="#rate-limiting">Rate limiting</a></li> <li><a href="#keys-management">Keys management</a> <ul> <li><a href="#contact-code-topic">Contact code topic</a></li> <li><a href="#partitioned-topic">Partitioned topic</a></li> <li><a href="#public-chats">Public chats</a></li> <li><a href="#group-chat-topic">Group chat topic</a></li> </ul> </li> <li><a href="#message-encryption">Message encryption</a></li> <li><a href="#message-confirmations">Message confirmations</a></li> <li><a href="#whisper-v6-extensions">Whisper V6 extensions</a> <ul> <li><a href="#request-historic-messages">Request historic messages</a> <ul> <li><a href="#shhext_requestmessages">shhext_requestMessages</a></li> </ul> </li> </ul> </li> <li><a href="#changelog">Changelog</a></li> </ul> <h2 id="abstract"> <a href="#abstract" class="anchor-heading" aria-labelledby="abstract"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Abstract </h2> <p>Status uses <a href="https://eips.ethereum.org/EIPS/eip-627">Whisper</a> to provide privacy-preserving routing and messaging on top of devP2P. Whisper uses topics to partition its messages, and these are leveraged for all chat capabilities. In the case of public chats, the channel name maps directly to its Whisper topic. This allows anyone to listen on a single channel.</p> <p>Additionally, since anyone can receive Whisper envelopes, it relies on the ability to decrypt messages to decide who is the correct recipient. Status nodes do not rely upon this property, and implement another secure transport layer on top of Whisper.</p> <p>Finally, using an extension of Whisper provides the ability to do offline messaging.</p> <h2 id="reason"> <a href="#reason" class="anchor-heading" aria-labelledby="reason"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Reason </h2> <p>Provide routing, metadata protection, topic-based multicasting and basic encryption properties to support asynchronous chat.</p> <h2 id="terminology"> <a href="#terminology" class="anchor-heading" aria-labelledby="terminology"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Terminology </h2> <ul> <li><em>Whisper node</em>: an Ethereum node with Whisper V6 enabled (in the case of geth, it’s <code class="language-plaintext highlighter-rouge">--shh</code> option)</li> <li><em>Whisper network</em>: a group of Whisper nodes connected together through the internet connection and forming a graph</li> <li><em>Message</em>: a decrypted Whisper message</li> <li><em>Offline message</em>: an archived envelope</li> <li><em>Envelope</em>: an encrypted message with metadata like topic and Time-To-Live</li> </ul> <h2 id="whisper-packets"> <a href="#whisper-packets" class="anchor-heading" aria-labelledby="whisper-packets"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Whisper packets </h2> <div class="table-wrapper"><table> <thead> <tr> <th>Packet Name</th> <th style="text-align: right">Code</th> <th>EIP-627</th> <th>References</th> </tr> </thead> <tbody> <tr> <td>Status</td> <td style="text-align: right">0</td> <td>✔</td> <td><a href="#handshake">Handshake</a></td> </tr> <tr> <td>Messages</td> <td style="text-align: right">1</td> <td>✔</td> <td><a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-627.md">EIP-627</a></td> </tr> <tr> <td>PoW Requirement</td> <td style="text-align: right">2</td> <td>✔</td> <td><a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-627.md">EIP-627</a></td> </tr> <tr> <td>Bloom Filter</td> <td style="text-align: right">3</td> <td>✔</td> <td><a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-627.md">EIP-627</a></td> </tr> <tr> <td>Batch Ack</td> <td style="text-align: right">11</td> <td>𝘅</td> <td>Undocumented</td> </tr> <tr> <td>Message Response</td> <td style="text-align: right">12</td> <td>𝘅</td> <td>Undocumented</td> </tr> <tr> <td>P2P Sync Request</td> <td style="text-align: right">123</td> <td>𝘅</td> <td>Undocumented</td> </tr> <tr> <td>P2P Sync Response</td> <td style="text-align: right">124</td> <td>𝘅</td> <td>Undocumented</td> </tr> <tr> <td>P2P Request Complete</td> <td style="text-align: right">125</td> <td>𝘅</td> <td><a href="https://specs.status.im/spec/4">4/WHISPER-MAILSERVER</a></td> </tr> <tr> <td>P2P Request</td> <td style="text-align: right">126</td> <td>✔</td> <td><a href="https://specs.status.im/spec/4">4/WHISPER-MAILSERVER</a></td> </tr> <tr> <td>P2P Messages</td> <td style="text-align: right">127</td> <td>✔/𝘅 (EIP-627 supports only single envelope in a packet)</td> <td><a href="https://specs.status.im/spec/4">4/WHISPER-MAILSERVER</a></td> </tr> </tbody> </table></div> <h2 id="whisper-node-configuration"> <a href="#whisper-node-configuration" class="anchor-heading" aria-labelledby="whisper-node-configuration"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Whisper node configuration </h2> <p>A Whisper node must be properly configured to receive messages from Status clients.</p> <p>Whisper’s Proof Of Work algorithm is used to deter denial of service and various spam/flood attacks against the Whisper network. The sender of a message must perform some work which in this case means processing time. Because Status’ main client is a mobile client, this easily leads to battery draining and poor performance of the app itself. Hence, all clients MUST use the following Whisper node settings:</p> <ul> <li>proof-of-work requirement not larger than <code class="language-plaintext highlighter-rouge">0.00001</code></li> <li>time-to-live not lower than <code class="language-plaintext highlighter-rouge">10</code> (in seconds)</li> <li>any payload below <code class="language-plaintext highlighter-rouge">50000</code> bytes MUST be sent with a PoW Target of at least <code class="language-plaintext highlighter-rouge">0.002</code>, in order to maintain backward compatibility with version <code class="language-plaintext highlighter-rouge">0.2</code> and <a href="https://github.com/status-im/status-mobile/releases/tag/untagged-079a6d98babfeaa3f8c0">Status app version <code class="language-plaintext highlighter-rouge">1.3</code></a> and below</li> </ul> <h2 id="handshake"> <a href="#handshake" class="anchor-heading" aria-labelledby="handshake"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Handshake </h2> <p>Handshake is a RLP-encoded packet sent to a newly connected peer. It MUST start with a Status Code (<code class="language-plaintext highlighter-rouge">0x00</code>) and follow up with items:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ protocolVersion, PoW, bloom, isLightNode, confirmationsEnabled, rateLimits ]
|
||
</code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">protocolVersion</code>: version of the Whisper protocol <code class="language-plaintext highlighter-rouge">PoW</code>: minimum PoW accepted by the peer <code class="language-plaintext highlighter-rouge">bloom</code>: bloom filter of Whisper topic accepted by the peer <code class="language-plaintext highlighter-rouge">isLightNode</code>: when true, the peer won’t forward messages <code class="language-plaintext highlighter-rouge">confirmationsEnabled</code>: when true, the peer will send message confirmations <code class="language-plaintext highlighter-rouge">rateLimits</code>: is <code class="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><code class="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> <h2 id="rate-limiting"> <a href="#rate-limiting" class="anchor-heading" aria-labelledby="rate-limiting"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink: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 (<code class="language-plaintext highlighter-rouge">0x14</code>). The rate limits is RLP-encoded information:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ IP limits, PeerID limits, Topic limits ]
|
||
</code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">IP limits</code>: 4-byte wide unsigned integer <code class="language-plaintext highlighter-rouge">PeerID limits</code>: 4-byte wide unsigned integer <code class="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> <h2 id="keys-management"> <a href="#keys-management" class="anchor-heading" aria-labelledby="keys-management"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink: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 <a href="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> <h3 id="contact-code-topic"> <a href="#contact-code-topic" class="anchor-heading" aria-labelledby="contact-code-topic"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink: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> <div class="language-golang highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">contactCode</span> <span class="o">:=</span> <span class="s">"0x"</span> <span class="o">+</span> <span class="n">hexEncode</span><span class="p">(</span><span class="n">activePublicKey</span><span class="p">)</span> <span class="o">+</span> <span class="s">"-contact-code"</span>
|
||
|
||
<span class="k">var</span> <span class="n">hash</span> <span class="p">[]</span><span class="kt">byte</span> <span class="o">=</span> <span class="n">keccak256</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
|
||
<span class="k">var</span> <span class="n">topicLen</span> <span class="kt">int</span> <span class="o">=</span> <span class="m">4</span>
|
||
|
||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">hash</span><span class="p">)</span> <span class="o"><</span> <span class="n">topicLen</span> <span class="p">{</span>
|
||
<span class="n">topicLen</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">hash</span><span class="p">)</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="k">var</span> <span class="n">topic</span> <span class="p">[</span><span class="m">4</span><span class="p">]</span><span class="kt">byte</span>
|
||
<span class="k">for</span> <span class="n">i</span> <span class="o">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">topicLen</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
|
||
<span class="n">topic</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">hash</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
|
||
<span class="p">}</span>
|
||
</code></pre></div></div> <h3 id="partitioned-topic"> <a href="#partitioned-topic" class="anchor-heading" aria-labelledby="partitioned-topic"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink: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 <code class="language-plaintext highlighter-rouge">5000</code>. Partitioned topics MUST be generated following the algorithm below:</p> <div class="language-golang highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="n">partitionsNum</span> <span class="o">*</span><span class="n">big</span><span class="o">.</span><span class="n">Int</span> <span class="o">=</span> <span class="n">big</span><span class="o">.</span><span class="n">NewInt</span><span class="p">(</span><span class="m">5000</span><span class="p">)</span>
|
||
<span class="k">var</span> <span class="n">partition</span> <span class="o">*</span><span class="n">big</span><span class="o">.</span><span class="n">Int</span> <span class="o">=</span> <span class="n">big</span><span class="o">.</span><span class="n">NewInt</span><span class="p">(</span><span class="m">0</span><span class="p">)</span><span class="o">.</span><span class="n">Mod</span><span class="p">(</span><span class="n">publicKey</span><span class="o">.</span><span class="n">X</span><span class="p">,</span> <span class="n">partitionsNum</span><span class="p">)</span>
|
||
|
||
<span class="n">partitionTopic</span> <span class="o">:=</span> <span class="s">"contact-discovery-"</span> <span class="o">+</span> <span class="n">strconv</span><span class="o">.</span><span class="n">FormatInt</span><span class="p">(</span><span class="n">partition</span><span class="o">.</span><span class="n">Int64</span><span class="p">(),</span> <span class="m">10</span><span class="p">)</span>
|
||
|
||
<span class="k">var</span> <span class="n">hash</span> <span class="p">[]</span><span class="kt">byte</span> <span class="o">=</span> <span class="n">keccak256</span><span class="p">(</span><span class="n">partitionTopic</span><span class="p">)</span>
|
||
<span class="k">var</span> <span class="n">topicLen</span> <span class="kt">int</span> <span class="o">=</span> <span class="m">4</span>
|
||
|
||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">hash</span><span class="p">)</span> <span class="o"><</span> <span class="n">topicLen</span> <span class="p">{</span>
|
||
<span class="n">topicLen</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">hash</span><span class="p">)</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="k">var</span> <span class="n">topic</span> <span class="p">[</span><span class="m">4</span><span class="p">]</span><span class="kt">byte</span>
|
||
<span class="k">for</span> <span class="n">i</span> <span class="o">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">topicLen</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
|
||
<span class="n">topic</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">hash</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
|
||
<span class="p">}</span>
|
||
</code></pre></div></div> <h3 id="public-chats"> <a href="#public-chats" class="anchor-heading" aria-labelledby="public-chats"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink: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> <div class="language-golang highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">var</span> <span class="n">hash</span> <span class="p">[]</span><span class="kt">byte</span>
|
||
<span class="n">hash</span> <span class="o">=</span> <span class="n">keccak256</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
|
||
|
||
<span class="n">topicLen</span> <span class="o">=</span> <span class="m">4</span>
|
||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">hash</span><span class="p">)</span> <span class="o"><</span> <span class="n">topicLen</span> <span class="p">{</span>
|
||
<span class="n">topicLen</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">hash</span><span class="p">)</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="k">var</span> <span class="n">topic</span> <span class="p">[</span><span class="m">4</span><span class="p">]</span><span class="kt">byte</span>
|
||
<span class="k">for</span> <span class="n">i</span> <span class="o">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">topicLen</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
|
||
<span class="n">topic</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">hash</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
|
||
<span class="p">}</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. --> <h3 id="group-chat-topic"> <a href="#group-chat-topic" class="anchor-heading" aria-labelledby="group-chat-topic"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink: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> <h3 id="negotiated-topic"> <a href="#negotiated-topic" class="anchor-heading" aria-labelledby="negotiated-topic"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink: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 <code class="language-plaintext highlighter-rouge">SHA3-256</code> of the key generated.</p> <div class="language-golang highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
|
||
<span class="n">sharedKey</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">ecies</span><span class="o">.</span><span class="n">ImportECDSA</span><span class="p">(</span><span class="n">myPrivateKey</span><span class="p">)</span><span class="o">.</span><span class="n">GenerateShared</span><span class="p">(</span>
|
||
<span class="n">ecies</span><span class="o">.</span><span class="n">ImportECDSAPublic</span><span class="p">(</span><span class="n">theirPublicKey</span><span class="p">),</span>
|
||
<span class="m">16</span><span class="p">,</span>
|
||
<span class="m">16</span><span class="p">,</span>
|
||
<span class="p">)</span>
|
||
|
||
|
||
<span class="n">hexEncodedKey</span> <span class="o">:=</span> <span class="n">hex</span><span class="o">.</span><span class="n">EncodeToString</span><span class="p">(</span><span class="n">sharedKey</span><span class="p">)</span>
|
||
|
||
<span class="k">var</span> <span class="n">hash</span> <span class="p">[]</span><span class="kt">byte</span> <span class="o">=</span> <span class="n">keccak256</span><span class="p">(</span><span class="n">hexEncodedKey</span><span class="p">)</span>
|
||
<span class="k">var</span> <span class="n">topicLen</span> <span class="kt">int</span> <span class="o">=</span> <span class="m">4</span>
|
||
|
||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">hash</span><span class="p">)</span> <span class="o"><</span> <span class="n">topicLen</span> <span class="p">{</span>
|
||
<span class="n">topicLen</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">hash</span><span class="p">)</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="k">var</span> <span class="n">topic</span> <span class="p">[</span><span class="m">4</span><span class="p">]</span><span class="kt">byte</span>
|
||
<span class="k">for</span> <span class="n">i</span> <span class="o">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">topicLen</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span> <span class="p">{</span>
|
||
<span class="n">topic</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">hash</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
|
||
<span class="p">}</span>
|
||
</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> <h3 id="flow"> <a href="#flow" class="anchor-heading" aria-labelledby="flow"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Flow </h3> <p>To exchange messages with client <code class="language-plaintext highlighter-rouge">B</code>, a client <code class="language-plaintext highlighter-rouge">A</code> SHOULD:</p> <ul> <li>Listen to client’s <code class="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 <code class="language-plaintext highlighter-rouge">B</code> partitioned topic</li> <li>Listen to the Negotiated Topic between <code class="language-plaintext highlighter-rouge">A</code> & <code class="language-plaintext highlighter-rouge">B</code></li> <li>Once client <code class="language-plaintext highlighter-rouge">A</code> receives a message from <code class="language-plaintext highlighter-rouge">B</code>, the Negotiated Topic SHOULD be used</li> </ul> <h2 id="message-encryption"> <a href="#message-encryption" class="anchor-heading" aria-labelledby="message-encryption"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink: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 <a href="https://github.com/ethereum/go-ethereum/wiki/Whisper-v6-RPC-API#shh_generatesymkeyfrompassword"><code class="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> <h2 id="message-confirmations"> <a href="#message-confirmations" class="anchor-heading" aria-labelledby="message-confirmations"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink: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 (<code class="language-plaintext highlighter-rouge">0x01</code>).</p> <p>A node sends a message confirmation using Batch Acknowledge packet (<code class="language-plaintext highlighter-rouge">0x0b</code>) or Message Response packet (<code class="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> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ Version, Response]
|
||
</code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">Version</code>: a version of the Message Response, equal to <code class="language-plaintext highlighter-rouge">1</code>, <code class="language-plaintext highlighter-rouge">Response</code>: <code class="language-plaintext highlighter-rouge">[ Hash, Errors ]</code> where <code class="language-plaintext highlighter-rouge">Hash</code> is a keccak256 hash of the envelopes batch data (raw bytes) for which the confirmation is sent and <code class="language-plaintext highlighter-rouge">Errors</code> is a list of envelope errors when processing the batch. A single error contains <code class="language-plaintext highlighter-rouge">[ Hash, Code, Description ]</code> where <code class="language-plaintext highlighter-rouge">Hash</code> is a hash of the processed envelope, <code class="language-plaintext highlighter-rouge">Code</code> is an error code and <code class="language-plaintext highlighter-rouge">Description</code> is a descriptive error message.</p> <p>The supported codes: <code class="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 (<code class="language-plaintext highlighter-rouge">0x0b</code>) and Message Response packet (<code class="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 Mailservers 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 Mailserver. If additionally, sending a message is limited to non-Mailserver peers, it also guarantees that the message got broadcast through the network and it reached the selected Mailserver.</p> <h2 id="whisper-v6-extensions"> <a href="#whisper-v6-extensions" class="anchor-heading" aria-labelledby="whisper-v6-extensions"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Whisper V6 extensions </h2> <h3 id="request-historic-messages"> <a href="#request-historic-messages" class="anchor-heading" aria-labelledby="request-historic-messages"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Request historic messages </h3> <p>Sends a request for historic messages to a Mailserver. The Mailserver node MUST be a direct peer and MUST be marked as trusted (using <code class="language-plaintext highlighter-rouge">shh_markTrustedPeer</code>).</p> <p>The request does not wait for the response. It merely sends a peer-to-peer message to the Mailserver and it’s up to Mailserver to process it and start sending historic messages.</p> <p>The drawback of this approach is that it is impossible to tell which historic messages are the result of which request.</p> <p>It’s recommended to return messages from newest to oldest. To move further back in time, use <code class="language-plaintext highlighter-rouge">cursor</code> and <code class="language-plaintext highlighter-rouge">limit</code>.</p> <h4 id="shhext_requestmessages"> <a href="#shhext_requestmessages" class="anchor-heading" aria-labelledby="shhext_requestmessages"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> shhext_requestMessages </h4> <p><strong>Parameters</strong>:</p> <ol> <li>Object - The message request object: <ul> <li><code class="language-plaintext highlighter-rouge">mailServerPeer</code> - <code class="language-plaintext highlighter-rouge">String</code>: Mailserver’s enode address.</li> <li><code class="language-plaintext highlighter-rouge">from</code> - <code class="language-plaintext highlighter-rouge">Number</code> (optional): Lower bound of time range as unix timestamp, default is 24 hours back from now.</li> <li><code class="language-plaintext highlighter-rouge">to</code> - <code class="language-plaintext highlighter-rouge">Number</code> (optional): Upper bound of time range as unix timestamp, default is now.</li> <li><code class="language-plaintext highlighter-rouge">limit</code> - <code class="language-plaintext highlighter-rouge">Number</code> (optional): Limit the number of messages sent back, default is no limit.</li> <li><code class="language-plaintext highlighter-rouge">cursor</code> - <code class="language-plaintext highlighter-rouge">String</code> (optional): Used for paginated requests.</li> <li><code class="language-plaintext highlighter-rouge">topics</code> - <code class="language-plaintext highlighter-rouge">Array</code>: hex-encoded message topics.</li> <li><code class="language-plaintext highlighter-rouge">symKeyID</code> - <code class="language-plaintext highlighter-rouge">String</code>: an ID of a symmetric key to authenticate to Mailserver, derived from Mailserver password.</li> </ul> </li> </ol> <p><strong>Returns</strong>: <code class="language-plaintext highlighter-rouge">Boolean</code> - returns <code class="language-plaintext highlighter-rouge">true</code> if the request was sent.</p> <p>The above <code class="language-plaintext highlighter-rouge">topics</code> is then converted into a bloom filter and then and sent to the Mailserver.</p> <!-- TODO: Clarify actual request with bloom filter to mailserver --> <h2 id="changelog"> <a href="#changelog" class="anchor-heading" aria-labelledby="changelog"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Changelog </h2> <h3 id="03"> <a href="#03" class="anchor-heading" aria-labelledby="03"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> 0.3 </h3> <ul> <li>Updated minimum PoW to <code class="language-plaintext highlighter-rouge">0.00001</code> <h3 id="02"> <a href="#02" class="anchor-heading" aria-labelledby="02"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> 0.2 </h3> </li> <li>Document created</li> </ul> <h2 id="copyright"> <a href="#copyright" class="anchor-heading" aria-labelledby="copyright"><svg viewBox="0 0 16 16" aria-hidden="true"><use xlink:href="#svg-link"></use></svg></a> Copyright </h2> <p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p> </div> </div> <div class="search-overlay"></div> </div> </body> </html>
|