This commit is contained in:
status-im-auto 2021-11-16 14:54:10 +00:00 committed by Jenkins
parent 3539483f73
commit 590672e462
50 changed files with 1980 additions and 6054 deletions

View File

@ -1,38 +0,0 @@
# Description
This file explains the process of local development for this repository.
# Dependencies
This repository is built using [Jekyll](https://jekyllrb.com/) along with some plugins and a theme.
To install the necessary dependencies on Ubuntu use:
```
sudo apt-get install ruby-full build-essential zlib1g-dev
gem install jekyll bundler
```
It might be necessary to specify installation destination for your Gems:
```
export GEM_HOME="$HOME/.gems"
export PATH="$HOME/gems/bin:$PATH"
```
For instructions on other systems use [these docs](https://jekyllrb.com/docs/installation/).
Then you can install other Gems like the `just-the-docs` theme:
```
bundle install
```
# Building
To simply build the site use:
```
bundle exec jekyll build --config _config_local.yml
```
This will generate the site files and put them under `_site`.
But if you want Jekyll to continuously build and also serve the site use:
```
bundle exec jekyll serve --config _config_local.yml --incremental
```
This should make it available under http://127.0.0.1:4000/.

File diff suppressed because one or more lines are too long

8
development.html Normal file

File diff suppressed because one or more lines are too long

7
draft/12.html Normal file

File diff suppressed because one or more lines are too long

1
draft/13.html Normal file

File diff suppressed because one or more lines are too long

1
draft/14.html Normal file

File diff suppressed because one or more lines are too long

111
draft/16.html Normal file

File diff suppressed because one or more lines are too long

66
draft/3.html Normal file

File diff suppressed because one or more lines are too long

130
draft/6.html Normal file

File diff suppressed because one or more lines are too long

34
draft/7.html Normal file

File diff suppressed because one or more lines are too long

1
draft/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

118
raw/16.html Normal file

File diff suppressed because one or more lines are too long

1
raw/index.html Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,58 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://specs.status.im/spec/1</loc>
<loc>https://specs.status.im/stable/1</loc>
</url>
<url>
<loc>https://specs.status.im/spec/10</loc>
<loc>https://specs.status.im/stable/10</loc>
</url>
<url>
<loc>https://specs.status.im/spec/11</loc>
<loc>https://specs.status.im/stable/11</loc>
</url>
<url>
<loc>https://specs.status.im/spec/12</loc>
<loc>https://specs.status.im/draft/12</loc>
</url>
<url>
<loc>https://specs.status.im/spec/13</loc>
<loc>https://specs.status.im/draft/13</loc>
</url>
<url>
<loc>https://specs.status.im/spec/14</loc>
<loc>https://specs.status.im/draft/14</loc>
</url>
<url>
<loc>https://specs.status.im/spec/15</loc>
<loc>https://specs.status.im/stable/15</loc>
</url>
<url>
<loc>https://specs.status.im/specs/16</loc>
<loc>https://specs.status.im/draft/16</loc>
</url>
<url>
<loc>https://specs.status.im/spec/2</loc>
<loc>https://specs.status.im/stable/2</loc>
</url>
<url>
<loc>https://specs.status.im/spec/3</loc>
<loc>https://specs.status.im/stable/3</loc>
</url>
<url>
<loc>https://specs.status.im/spec/3</loc>
<loc>https://specs.status.im/draft/3</loc>
</url>
<url>
<loc>https://specs.status.im/spec/4</loc>
<loc>https://specs.status.im/stable/4</loc>
</url>
<url>
<loc>https://specs.status.im/spec/5</loc>
<loc>https://specs.status.im/stable/5</loc>
</url>
<url>
<loc>https://specs.status.im/spec/6</loc>
<loc>https://specs.status.im/stable/6</loc>
</url>
<url>
<loc>https://specs.status.im/spec/6</loc>
<loc>https://specs.status.im/draft/6</loc>
</url>
<url>
<loc>https://specs.status.im/spec/7</loc>
<loc>https://specs.status.im/draft/7</loc>
</url>
<url>
<loc>https://specs.status.im/spec/8</loc>
<loc>https://specs.status.im/stable/8</loc>
</url>
<url>
<loc>https://specs.status.im/spec/9</loc>
<loc>https://specs.status.im/stable/9</loc>
</url>
<url>
<loc>https://specs.status.im/development</loc>
</url>
<url>
<loc>https://specs.status.im/</loc>
@ -61,7 +64,7 @@
<loc>https://specs.status.im/style-guideline</loc>
</url>
<url>
<loc>https://specs.status.im/specs/draft</loc>
<loc>https://specs.status.im/draft/</loc>
</url>
<url>
<loc>https://specs.status.im/home.html</loc>
@ -70,13 +73,13 @@
<loc>https://specs.status.im/post.html</loc>
</url>
<url>
<loc>https://specs.status.im/spec/16</loc>
<loc>https://specs.status.im/raw/16</loc>
</url>
<url>
<loc>https://specs.status.im/specs/raw</loc>
<loc>https://specs.status.im/raw/</loc>
</url>
<url>
<loc>https://specs.status.im/specs/stable</loc>
<loc>https://specs.status.im/stable/</loc>
</url>
<url>
<loc>https://specs.status.im/default.html</loc>

View File

@ -1,482 +0,0 @@
<h1 id="1client">1/CLIENT</h1>
<blockquote>
<p>Version: 0.3</p>
<p>Status: Stable</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>, Dean Eigenmann <a href="mailto:dean@status.im">dean@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>, Samuel Hawksby-Robinson <a href="mailto:samuel@status.im">samuel@status.im</a> (alphabetical order)</p>
</blockquote>
<h2 id="abstract">Abstract</h2>
<p>This specification describes how to write a Status client for
communicating with other Status clients.</p>
<p>This specification presents a reference implementation of the protocol <sup><a href="#footnotes">1</a></sup> that is used
in a command line client <sup><a href="#footnotes">2</a></sup> and a mobile app <sup><a href="#footnotes">3</a></sup>.</p>
<p>This document consists of two parts. The first outlines the specifications that
have to be implemented in order to be a full Status client. The second gives a design rationale and answers some common questions.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#table-of-contents">Table of Contents</a></li>
<li><a href="#introduction">Introduction</a>
<ul>
<li><a href="#protocol-layers">Protocol layers</a></li>
<li><a href="#protobuf">Protobuf</a></li>
</ul>
</li>
<li><a href="#components">Components</a>
<ul>
<li><a href="#p2p-overlay">P2P Overlay</a>
<ul>
<li><a href="#node-discovery-and-roles">Node discovery and roles</a></li>
<li><a href="#bootstrapping">Bootstrapping</a></li>
<li><a href="#discovery">Discovery</a></li>
<li><a href="#mobile-nodes">Mobile nodes</a></li>
</ul>
</li>
<li><a href="#transport-privacy-and-whisper--waku-usage">Transport privacy and Whisper/Waku usage</a></li>
<li><a href="#secure-transport">Secure Transport</a></li>
<li><a href="#data-sync">Data Sync</a></li>
<li><a href="#payloads-and-clients">Payloads and clients</a></li>
<li><a href="#bips-and-eips-standards-support">BIPs and EIPs Standards support</a></li>
</ul>
</li>
<li><a href="#security-considerations">Security Considerations</a></li>
<li><a href="#design-rationale">Design Rationale</a>
<ul>
<li><a href="#p2p-overlay-1">P2P Overlay</a>
<ul>
<li><a href="#why-devp2p-why-not-use-libp2p">Why devp2p? Why not use libp2p?</a></li>
<li><a href="#what-about-other-rlpx-subprotocols-like-les-and-swarm">What about other RLPx subprotocols like LES, and Swarm?</a></li>
<li><a href="#why-do-you-use-whisper">Why do you use Whisper?</a></li>
<li><a href="#why-do-you-use-waku">Why do you use Waku?</a></li>
<li><a href="#why-is-pow-for-waku-set-so-low">Why is PoW for Waku set so low?</a></li>
<li><a href="#why-do-you-not-use-discovery-v5-for-node-discovery">Why do you not use Discovery v5 for node discovery?</a></li>
<li><a href="#i-heard-something-about-mailservers-being-trusted-somehow">I heard something about <code class="language-plaintext highlighter-rouge">Mailservers</code> being trusted somehow?</a></li>
</ul>
</li>
<li><a href="#data-sync-1">Data sync</a>
<ul>
<li><a href="#why-is-mvds-not-used-for-public-chats">Why is MVDS not used for public chats?</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#footnotes">Footnotes</a></li>
<li><a href="#appendix-a-security-considerations">Appendix A: Security considerations</a>
<ul>
<li><a href="#scalability-and-ux">Scalability and UX</a></li>
<li><a href="#privacy">Privacy</a></li>
<li><a href="#spam-resistance">Spam resistance</a></li>
<li><a href="#censorship-resistance">Censorship resistance</a></li>
</ul>
</li>
<li><a href="#acknowledgments">Acknowledgments</a></li>
<li><a href="#changelog">Changelog</a>
<ul>
<li><a href="#version-03">Version 0.3</a></li>
</ul>
</li>
</ul>
<h2 id="introduction">Introduction</h2>
<h3 id="protocol-layers">Protocol layers</h3>
<p>Implementing a Status clients largely means implementing the following layers. Additionally, there are separate specifications for things like key management and account lifecycle.</p>
<p>Other aspects, such as how a node uses IPFS for stickers or how the browser works, are currently underspecified. These specifications facilitate the implementation of a Status client for basic private communication.</p>
<table>
<thead>
<tr>
<th>Layer</th>
<th>Purpose</th>
<th>Technology</th>
</tr>
</thead>
<tbody>
<tr>
<td>Data and payloads</td>
<td>End user functionality</td>
<td>1:1, group chat, public chat</td>
</tr>
<tr>
<td>Data sync</td>
<td>Data consistency</td>
<td>MVDS.</td>
</tr>
<tr>
<td>Secure transport</td>
<td>Confidentiality, PFS, etc</td>
<td>Double Ratchet</td>
</tr>
<tr>
<td>Transport privacy</td>
<td>Routing, Metadata protection</td>
<td>Waku / Whisper</td>
</tr>
<tr>
<td>P2P Overlay</td>
<td>Overlay routing, NAT traversal</td>
<td>devp2p</td>
</tr>
</tbody>
</table>
<h3 id="protobuf">Protobuf</h3>
<p><a href="https://developers.google.com/protocol-buffers/"><code class="language-plaintext highlighter-rouge">protobuf</code></a> is used in different layers, version <code class="language-plaintext highlighter-rouge">proto3</code> used is unless stated otherwise.</p>
<h2 id="components">Components</h2>
<h3 id="p2p-overlay">P2P Overlay</h3>
<p>Status clients run on a public, permissionless peer-to-peer network, as specified by the devP2P
network protocols. devP2P provides a protocol for node discovery which is in
draft mode
<a href="https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md">here</a>. See
more on node discovery and management in the next section.</p>
<p>To communicate between Status nodes, the <a href="https://github.com/ethereum/devp2p/blob/master/rlpx.md">RLPx Transport
Protocol, v5</a> is used, which
allows for TCP-based communication between nodes.</p>
<p>On top of this RLPx-based subprotocols are ran, the client
SHOULD NOT use <a href="https://eips.ethereum.org/EIPS/eip-627">Whisper V6</a>, the client
SHOULD use <a href="https://rfc.vac.dev/spec/6/">Waku V1</a>
for privacy-preserving messaging and efficient usage of a nodes bandwidth.</p>
<h4 id="node-discovery-and-roles">Node discovery and roles</h4>
<p>There are four types of node roles:</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">Bootstrap node</code></li>
<li><code class="language-plaintext highlighter-rouge">Whisper/Waku relayer</code></li>
<li><code class="language-plaintext highlighter-rouge">Mailserver</code> (servers and clients)</li>
<li><code class="language-plaintext highlighter-rouge">Mobile node</code> (Status Clients)</li>
</ol>
<p>A standard Status client MUST implement both <code class="language-plaintext highlighter-rouge">Whisper/Waku relayer</code> and <code class="language-plaintext highlighter-rouge">Mobile node</code> node types. The
other node types are optional, but it is RECOMMEND to implement a <code class="language-plaintext highlighter-rouge">Mailserver</code>
client mode, otherwise the user experience is likely to be poor.</p>
<h4 id="bootstrapping">Bootstrapping</h4>
<p>Bootstrap nodes allow Status nodes to discover and connect to other Status nodes
in the network.</p>
<p>Currently, Status Gmbh provides the main bootstrap nodes, but anyone can
run these provided they are connected to the rest of the Whisper/Waku network.</p>
<p>Status maintains a list of production fleet bootstrap nodes in the following locations:</p>
<p><strong>Hong Kong:</strong></p>
<ul>
<li><code class="language-plaintext highlighter-rouge">enode://6e6554fb3034b211398fcd0f0082cbb6bd13619e1a7e76ba66e1809aaa0c5f1ac53c9ae79cf2fd4a7bacb10d12010899b370c75fed19b991d9c0cdd02891abad@47.75.99.169:443</code></li>
<li><code class="language-plaintext highlighter-rouge">enode://23d0740b11919358625d79d4cac7d50a34d79e9c69e16831c5c70573757a1f5d7d884510bc595d7ee4da3c1508adf87bbc9e9260d804ef03f8c1e37f2fb2fc69@47.52.106.107:443</code></li>
</ul>
<p><strong>Amsterdam:</strong></p>
<ul>
<li><code class="language-plaintext highlighter-rouge">enode://436cc6f674928fdc9a9f7990f2944002b685d1c37f025c1be425185b5b1f0900feaf1ccc2a6130268f9901be4a7d252f37302c8335a2c1a62736e9232691cc3a@178.128.138.128:443</code></li>
<li><code class="language-plaintext highlighter-rouge">enode://5395aab7833f1ecb671b59bf0521cf20224fe8162fc3d2675de4ee4d5636a75ec32d13268fc184df8d1ddfa803943906882da62a4df42d4fccf6d17808156a87@178.128.140.188:443</code></li>
</ul>
<p><strong>Central US:</strong></p>
<ul>
<li><code class="language-plaintext highlighter-rouge">enode://32ff6d88760b0947a3dee54ceff4d8d7f0b4c023c6dad34568615fcae89e26cc2753f28f12485a4116c977be937a72665116596265aa0736b53d46b27446296a@34.70.75.208:443</code></li>
<li><code class="language-plaintext highlighter-rouge">enode://5405c509df683c962e7c9470b251bb679dd6978f82d5b469f1f6c64d11d50fbd5dd9f7801c6ad51f3b20a5f6c7ffe248cc9ab223f8bcbaeaf14bb1c0ef295fd0@35.223.215.156:443</code></li>
</ul>
<p>These bootstrap nodes MAY change and are not guaranteed to stay this way forever
and at some point circumstances might force them to change.</p>
<h4 id="discovery">Discovery</h4>
<p>A Status client MUST discover or have a list of peers to connect to. Status uses a
light discovery mechanism based on a combination of <a href="https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md">Discovery
v5</a> and
<a href="https://github.com/libp2p/specs/tree/master/rendezvous">Rendezvous Protocol</a>,
(with some
<a href="https://github.com/status-im/rendezvous#differences-with-original-rendezvous">modifications</a>).
Additionally, some static nodes MAY also be used.</p>
<p>A Status client MUST use at least one discovery method or use static nodes
to communicate with other clients.</p>
<p>Discovery V5 uses bootstrap nodes to discover other peers. Bootstrap nodes MUST support
Discovery V5 protocol as well in order to provide peers. It is kademlia-based discovery mechanism
and it might consume significant (at least on mobile) amount of network traffic to operate.</p>
<p>In order to take advantage from simpler and more mobile-friendly peers discovery mechanism,
i.e. Rendezvous protocol, one MUST provide a list of Rendezvous nodes which speak
Rendezvous protocol. Rendezvous protocol is request-response discovery mechanism.
It uses Ethereum Node Records (ENR) to report discovered peers.</p>
<p>Both peers discovery mechanisms use topics to provide peers with certain capabilities.
There is no point in returning peers that do not support a particular protocol.
Status nodes that want to be discovered MUST register to Discovery V5 and/or Rendezvous
with the <code class="language-plaintext highlighter-rouge">whisper</code> topic. Status nodes that are <code class="language-plaintext highlighter-rouge">Mailservers</code> and want to
be discoverable MUST additionally register with the <code class="language-plaintext highlighter-rouge">whispermail</code> topic.</p>
<p>It is RECOMMENDED to use both mechanisms but at the same time implement a structure
called <code class="language-plaintext highlighter-rouge">PeerPool</code>. <code class="language-plaintext highlighter-rouge">PeerPool</code> is responsible for maintaining an optimal number of peers.
For mobile nodes, there is no significant advantage to have more than 2-3 peers and one <code class="language-plaintext highlighter-rouge">Mailserver</code>.
<code class="language-plaintext highlighter-rouge">PeerPool</code> can notify peers discovery protocol implementations that they should suspend
their execution because the optimal number of peers is found. They should resume
if the number of connected peers drops or a <code class="language-plaintext highlighter-rouge">Mailserver</code> disconnects.</p>
<p>It is worth noticing that an efficient caching strategy MAY be of great use, especially,
on mobile devices. Discovered peers can be cached as they rarely change and used
when the client starts again. In such a case, there might be no need to even start
peers discovery protocols because cached peers will satisfy the optimal number of peers.</p>
<p>Alternatively, a client MAY rely exclusively on a list of static peers. This is the most efficient
way because there are no peers discovery algorithm overhead introduced. The disadvantage
is that these peers might be gone and without peers discovery mechanism, it wont be possible to find
new ones.</p>
<p>The current list of static peers is published on <a href="https://fleets.status.im/">https://fleets.status.im/</a>. <code class="language-plaintext highlighter-rouge">eth.prod</code> is the current
group of peers the official Status client uses. The others are test networks.</p>
<p>Finally, Waku node addresses can be retrieved by traversing
the merkle tree found at <a href="https://fleets.status.im"><code class="language-plaintext highlighter-rouge">fleets.status.im</code></a>, as described in <a href="https://eips.ethereum.org/EIPS/eip-1459#client-protocol">EIP-1459</a>.</p>
<h4 id="mobile-nodes">Mobile nodes</h4>
<p>A <code class="language-plaintext highlighter-rouge">Mobile node</code> is a Whisper and/or Waku node which connects to part of the respective Whisper
and/or Waku network(s). A <code class="language-plaintext highlighter-rouge">Mobile node</code> MAY relay messages. See next section for more details on how
to use Whisper and/or Waku to communicate with other Status nodes.</p>
<h3 id="transport-privacy-and-whisper--waku-usage">Transport privacy and Whisper / Waku usage</h3>
<p>Once a Whisper and/or Waku node is up and running there are some specific settings required
to communicate with other Status nodes.</p>
<p>See <a href="https://specs.status.im/spec/3">3/WHISPER-USAGE</a> and <a href="https://specs.status.im/spec/10">10/WAKU-USAGE</a> for more details.</p>
<p>For providing an offline inbox, see the complementary <a href="https://specs.status.im/spec/4">4/WHISPER-MAILSERVER</a> and <a href="https://specs.status.im/spec/11">11/WAKU-MAILSERVER</a>.</p>
<h3 id="secure-transport">Secure Transport</h3>
<p>In order to provide confidentiality, integrity, authentication and forward
secrecy of messages the node implements a secure transport on top of Whisper and Waku. This is
used in 1:1 chats and group chats, but not for public chats. See <a href="https://specs.status.im/spec/5">5/SECURE-TRANSPORT</a> for more.</p>
<h3 id="data-sync">Data Sync</h3>
<p><a href="https://specs.vac.dev/mvds.html">MVDS</a> is used for 1:1 and group chats, however it is currently not in use for public chats.
<a href="#payloads-and-clients">Status payloads</a> are serialized and then wrapped inside an
MVDS message which is added to an <a href="https://specs.vac.dev/mvds.html#payloads">MVDS payload</a>,
the node encrypts this payload (if necessary for 1-to-1 / group-chats) and sends it using
Whisper or Waku which also encrypts it.</p>
<h3 id="payloads-and-clients">Payloads and clients</h3>
<p>On top of secure transport, various types of data sync clients and
the node uses payload formats for things like 1:1 chat, group chat and public chat. These have
various degrees of standardization. Please refer to <a href="https://specs.status.im/spec/6">6/PAYLOADS</a> for more details.</p>
<h3 id="bips-and-eips-standards-support">BIPs and EIPs Standards support</h3>
<p>For a list of EIPs and BIPs that SHOULD be supported by Status client, please
see <a href="https://specs.status.im/spec/8">8/EIPS</a>.</p>
<h2 id="security-considerations">Security Considerations</h2>
<p>See <a href="#appendix-a-security-considerations">Appendix A</a></p>
<h2 id="design-rationale">Design Rationale</h2>
<h3 id="p2p-overlay-1">P2P Overlay</h3>
<h4 id="why-devp2p-why-not-use-libp2p">Why devp2p? Why not use libp2p?</h4>
<p>At the time Status developed the main Status clients, devp2p was the most
mature. However, in the future libp2p is likely to be used, as itll
provide us with multiple transports, better protocol negotiation, NAT traversal,
etc.</p>
<p>For very experimental bridge support, see the bridge between libp2p and devp2p
in <a href="https://github.com/status-im/murmur">Murmur</a>.</p>
<h4 id="what-about-other-rlpx-subprotocols-like-les-and-swarm">What about other RLPx subprotocols like LES, and Swarm?</h4>
<p>Status is primarily optimized for resource restricted devices, and at present
time light client support for these protocols are suboptimal. This is a work in
progress.</p>
<p>For better Ethereum light client support, see <a href="https://github.com/status-im/status-go/issues/1025">Re-enable LES as
option</a>. For better Swarm
support, see <a href="https://github.com/ethersphere/SWIPs/pull/12">Swarm adaptive
nodes</a>.</p>
<p>For transaction support, Status clients currently have to rely on Infura.</p>
<p>Status clients currently do not offer native support for file storage.</p>
<h4 id="why-do-you-use-whisper">Why do you use Whisper?</h4>
<p>Whisper is one of the <a href="http://gavwood.com/dappsweb3.html">three parts</a> of the
vision of Ethereum as the world computer, Ethereum and Swarm being the other
two. Status was started as an encapsulation of and a clear window to this world
computer.</p>
<h4 id="why-do-you-use-waku">Why do you use Waku?</h4>
<p>Waku is a direct upgrade and replacement for Whisper, the main motivation for
developing and implementing Waku can be found in the <a href="https://rfc.vac.dev/spec/6/#motivation">Waku specs</a>.</p>
<blockquote>
<p>Waku was created to incrementally improve in areas that Whisper is lacking in,
with special attention to resource restricted devices. We specify the standard for
Waku messages in order to ensure forward compatibility of different Waku clients,
backwards compatibility with Whisper clients, as well as to allow multiple
implementations of Waku and its capabilities. We also modify the language to be more
unambiguous, concise and consistent.</p>
</blockquote>
<p>Considerable work has gone into the active development of Ethereum, in contrast Whisper
is not currently under active development, and it has several drawbacks. Among others:</p>
<ul>
<li>Whisper is very wasteful bandwidth-wise and doesnt appear to be scalable</li>
<li>Proof of work is a poor spam protection mechanism for heterogeneous devices</li>
<li>The privacy guarantees provided are not rigorous</li>
<li>There are no incentives to run a node</li>
</ul>
<p>Finding a more suitable transport privacy is an ongoing research effort,
together with <a href="https://vac.dev/vac-overview">Vac</a> and other teams in the space.</p>
<h4 id="why-is-pow-for-waku-set-so-low">Why is PoW for Waku set so low?</h4>
<p>A higher PoW would be desirable, but this kills the battery on mobile phones,
which is a prime target for Status clients.</p>
<p>This means the network is currently vulnerable to DDoS attacks. Alternative
methods of spam protection are currently being researched.</p>
<h4 id="why-do-you-not-use-discovery-v5-for-node-discovery">Why do you not use Discovery v5 for node discovery?</h4>
<p>At the time of implementing dynamic node discovery, Discovery v5 wasnt completed
yet. Additionally, running a DHT on a mobile leads to slow node discovery, bad
battery and poor bandwidth usage. Instead, each client can choose to turn on
Discovery v5 for a short period until the node populates their peer list.</p>
<p>For some further investigation, see
<a href="https://github.com/status-im/swarms/blob/master/ideas/092-disc-v5-research.md">here</a>.</p>
<h4 id="i-heard-something-about-mailservers-being-trusted-somehow">I heard something about <code class="language-plaintext highlighter-rouge">Mailservers</code> being trusted somehow?</h4>
<p>In order to use a <code class="language-plaintext highlighter-rouge">Mailserver</code>, a given node needs to connect to it directly, i.e. add the <code class="language-plaintext highlighter-rouge">Mailserver</code> as its peer and mark it as trusted. This means that the <code class="language-plaintext highlighter-rouge">Mailserver</code> is able to send direct p2p messages to the node instead of broadcasting them. Effectively, it knows the bloom filter of the topics the node is interested in, when it is online as well as many metadata like IP address.</p>
<h3 id="data-sync-1">Data sync</h3>
<h4 id="why-is-mvds-not-used-for-public-chats">Why is MVDS not used for public chats?</h4>
<p>Currently, public chats are broadcast-based, and theres no direct way of finding
out who is receiving messages. Hence theres no clear group sync state context
whereby participants can sync. Additionally, MVDS is currently not optimized for
large group contexts, which means bandwidth usage will be a lot higher than
reasonable. See <a href="https://vac.dev/p2p-data-sync-for-mobile">P2P Data Sync for
Mobile</a> for more. This is an active
area of research.</p>
<h2 id="footnotes">Footnotes</h2>
<ol>
<li><a href="https://github.com/status-im/status-protocol-go/">https://github.com/status-im/status-protocol-go/</a></li>
<li><a href="https://github.com/status-im/status-console-client/">https://github.com/status-im/status-console-client/</a></li>
<li><a href="https://github.com/status-im/status-react/">https://github.com/status-im/status-react/</a></li>
</ol>
<h2 id="appendix-a-security-considerations">Appendix A: Security considerations</h2>
<p>There are several security considerations to take into account when running Status. Chief among them are: scalability, DDoS-resistance and privacy. These also vary depending on what capabilities are used, such as <code class="language-plaintext highlighter-rouge">Mailserver</code>, light node, and so on.</p>
<h3 id="scalability-and-ux">Scalability and UX</h3>
<p><strong>Bandwidth usage:</strong></p>
<p>In version 1 of Status, bandwidth usage is likely to be an issue. In Status version 1.1 this is partially addressed with Waku usage, see <a href="https://github.com/vacp2p/research/tree/dcc71f4779be832d3b5ece9c4e11f1f7ec24aac2/whisper_scalability">the theoretical scaling model</a>.</p>
<p><strong><code class="language-plaintext highlighter-rouge">Mailserver</code> High Availability requirement:</strong></p>
<p>A <code class="language-plaintext highlighter-rouge">Mailserver</code> has to be online to receive messages for other nodes, this puts a high availability requirement on it.</p>
<p><strong>Gossip-based routing:</strong></p>
<p>Use of gossip-based routing doesnt necessarily scale. It means each node can see a message multiple times, and having too many light nodes can cause propagation probability that is too low. See <a href="https://our.status.im/whisper-pss-comparison/">Whisper vs PSS</a> for more and a possible Kademlia based alternative.</p>
<p><strong>Lack of incentives:</strong></p>
<p>Status currently lacks incentives to run nodes, which means node operators are more likely to create centralized choke points.</p>
<h3 id="privacy">Privacy</h3>
<p><strong>Light node privacy:</strong></p>
<p>The main privacy concern with light nodes is that directly connected peers will know that a message originates from them (as it are the only ones it sends). This means nodes can make assumptions about what messages (topics) their peers are interested in.</p>
<p><strong>Bloom filter privacy:</strong></p>
<p>A user reveals which messages they are interested in, by setting only the topics they are interested in on the bloom filter. This is a fundamental trade-off between bandwidth usage and privacy, though the trade-off space is likely suboptimal in terms of the <a href="https://eprint.iacr.org/2017/954.pdf">Anonymity</a> <a href="https://petsymposium.org/2019/files/hotpets/slides/coordination-helps-anonymity-slides.pdf">trilemma</a>.</p>
<p><strong><code class="language-plaintext highlighter-rouge">Mailserver client</code> privacy:</strong></p>
<p>A <code class="language-plaintext highlighter-rouge">Mailserver client</code> has to trust a <code class="language-plaintext highlighter-rouge">Mailserver</code>, which means they can send direct traffic. This reveals what topics / bloom filter a node is interested in, along with its peerID (with IP).</p>
<p><strong>Privacy guarantees not rigorous:</strong></p>
<p>Privacy for Whisper or Waku hasnt been studied rigorously for various threat models like global passive adversary, local active attacker, etc. This is unlike e.g. Tor and mixnets.</p>
<p><strong>Topic hygiene:</strong></p>
<p>Similar to bloom filter privacy, using a very specific topic reveals more information. See scalability model linked above.</p>
<h3 id="spam-resistance">Spam resistance</h3>
<p><strong>PoW bad for heterogeneous devices:</strong></p>
<p>Proof of work is a poor spam prevention mechanism. A mobile device can only have a very low PoW in order not to use too much CPU / burn up its phone battery. This means someone can spin up a powerful node and overwhelm the network.</p>
<p><strong><code class="language-plaintext highlighter-rouge">Mailserver</code> trusted connection:</strong></p>
<p>A <code class="language-plaintext highlighter-rouge">Mailserver</code> has a direct TCP connection, which means they are trusted to send traffic. This means a malicious or malfunctioning <code class="language-plaintext highlighter-rouge">Mailserver</code> can overwhelm an individual node.</p>
<h3 id="censorship-resistance">Censorship resistance</h3>
<p><strong>Devp2p TCP port blockable:</strong></p>
<p>By default Devp2p runs on port <code class="language-plaintext highlighter-rouge">30303</code>, which is not commonly used for any other service. This means it is easy to censor, e.g. airport WiFi. This can be mitigated somewhat by running on e.g. port <code class="language-plaintext highlighter-rouge">80</code> or <code class="language-plaintext highlighter-rouge">443</code>, but there are still outstanding issues. See libp2p and Tors Pluggable Transport for how this can be improved.</p>
<p>See <a href="https://github.com/status-im/status-react/issues/6351">https://github.com/status-im/status-react/issues/6351</a> for some discussion.</p>
<h2 id="acknowledgments">Acknowledgments</h2>
<p>Jacek Sieka</p>
<h2 id="changelog">Changelog</h2>
<h3 id="version-03">Version 0.3</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/664dd1c9df6ad409e4c007fefc8c8945b8d324e8">May 22, 2020</a></p>
<ul>
<li>Added that Waku SHOULD be used</li>
<li>Added that Whisper SHOULD NOT be used</li>
<li>Added language to include Waku in all relevant places</li>
<li>Change to keep <code class="language-plaintext highlighter-rouge">Mailserver</code> term consistent</li>
</ul>

View File

@ -1,480 +0,0 @@
<h1 id="10waku-usage">10/WAKU-USAGE</h1>
<blockquote>
<p>Version: 0.1</p>
<p>Status: Stable</p>
<p>Authors: Adam Babik <a href="mailto:adam@status.im">adam@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>, Samuel Hawksby-Robinson <a href="mailto:samuel@status.im">samuel@status.im</a> (alphabetical order)</p>
</blockquote>
<ul>
<li><a href="#10waku-usage">Status Waku Usage Specification</a>
<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="#waku-packets">Waku packets</a></li>
<li><a href="#waku-node-configuration">Waku node configuration</a></li>
<li><a href="#status">Status</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>
<li><a href="#negotiated-topic">Negotiated 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="#waku-v1-extensions">Waku V1 extensions</a>
<ul>
<li><a href="#request-historic-messages">Request historic messages</a>
<ul>
<li><a href="#wakuext_requestmessages">wakuext_requestMessages</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#changelog">Changelog</a>
<ul>
<li><a href="#version-01">Version 0.1</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="abstract">Abstract</h2>
<p>Status uses <a href="https://rfc.vac.dev/spec/6/">Waku</a> to provide
privacy-preserving routing and messaging on top of devP2P. Waku 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 Waku topic.
This allows anyone to listen on a single channel.</p>
<p>Additionally, since anyone can receive Waku 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>
<h2 id="reason">Reason</h2>
<p>Provide routing, metadata protection, topic-based multicasting and basic
encryption properties to support asynchronous chat.</p>
<h2 id="terminology">Terminology</h2>
<ul>
<li><em>Waku node</em>: an Ethereum node with Waku V1 enabled</li>
<li><em>Waku network</em>: a group of Waku nodes connected together through the internet connection and forming a graph</li>
<li><em>Message</em>: a decrypted Waku 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="waku-packets">Waku packets</h2>
<table>
<thead>
<tr>
<th>Packet Name</th>
<th style="text-align: right">Code</th>
<th>References</th>
</tr>
</thead>
<tbody>
<tr>
<td>Status</td>
<td style="text-align: right">0</td>
<td><a href="#status">Status</a>, <a href="https://rfc.vac.dev/spec/6/#status">WAKU-1</a></td>
</tr>
<tr>
<td>Messages</td>
<td style="text-align: right">1</td>
<td><a href="https://rfc.vac.dev/spec/6/#messages">WAKU-1</a></td>
</tr>
<tr>
<td>Batch Ack</td>
<td style="text-align: right">11</td>
<td>Undocumented. Marked for Deprecation</td>
</tr>
<tr>
<td>Message Response</td>
<td style="text-align: right">12</td>
<td><a href="https://rfc.vac.dev/spec/6/#batch-ack-and-message-response">WAKU-1</a></td>
</tr>
<tr>
<td>Status Update</td>
<td style="text-align: right">22</td>
<td><a href="https://rfc.vac.dev/spec/6/#status-update">WAKU-1</a></td>
</tr>
<tr>
<td>P2P Request Complete</td>
<td style="text-align: right">125</td>
<td><a href="https://specs.status.im/spec/4">4/WAKU-MAILSERVER</a></td>
</tr>
<tr>
<td>P2P Request</td>
<td style="text-align: right">126</td>
<td><a href="https://specs.status.im/spec/4">4/WAKU-MAILSERVER</a>, <a href="https://rfc.vac.dev/spec/6/#p2p-request">WAKU-1</a></td>
</tr>
<tr>
<td>P2P Messages</td>
<td style="text-align: right">127</td>
<td><a href="https://specs.status.im/spec/4">4/WAKU-MAILSERVER</a>, <a href="https://rfc.vac.dev/spec/6/#p2p-request-complete">WAKU-1</a></td>
</tr>
</tbody>
</table>
<h2 id="waku-node-configuration">Waku node configuration</h2>
<p>A Waku node must be properly configured to receive messages from Status clients.</p>
<p>Nodes use Wakus Proof Of Work algorithm 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.002</code> for payloads less than 50,000 bytes</li>
<li>proof-of-work requirement not larger than <code class="language-plaintext highlighter-rouge">0.000002</code> for payloads greater than or equal to 50,000 bytes</li>
<li>time-to-live not lower than <code class="language-plaintext highlighter-rouge">10</code> (in seconds)</li>
</ul>
<h2 id="status">Status</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>[
[ pow-requirement-key pow-requirement ]
[ bloom-filter-key bloom-filter ]
[ light-node-key light-node ]
[ confirmations-enabled-key confirmations-enabled ]
[ rate-limits-key rate-limits ]
[ topic-interest-key topic-interest ]
]
</code></pre></div></div>
<table>
<thead>
<tr>
<th>Option Name</th>
<th>Key</th>
<th>Type</th>
<th>Description</th>
<th>References</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="language-plaintext highlighter-rouge">pow-requirement</code></td>
<td><code class="language-plaintext highlighter-rouge">0x00</code></td>
<td><code class="language-plaintext highlighter-rouge">uint64</code></td>
<td>minimum PoW accepted by the peer</td>
<td><a href="https://rfc.vac.dev/spec/6/#pow-requirement-field">WAKU-1#pow-requirement</a></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">bloom-filter</code></td>
<td><code class="language-plaintext highlighter-rouge">0x01</code></td>
<td><code class="language-plaintext highlighter-rouge">[]byte</code></td>
<td>bloom filter of Waku topic accepted by the peer</td>
<td><a href="https://rfc.vac.dev/spec/6/#bloom-filter-field">WAKU-1#bloom-filter</a></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">light-node</code></td>
<td><code class="language-plaintext highlighter-rouge">0x02</code></td>
<td><code class="language-plaintext highlighter-rouge">bool</code></td>
<td>when true, the peer wont forward envelopes through the Messages packet.</td>
<td><a href="https://rfc.vac.dev/spec/6/#light-node">WAKU-1#light-node</a></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">confirmations-enabled</code></td>
<td><code class="language-plaintext highlighter-rouge">0x03</code></td>
<td><code class="language-plaintext highlighter-rouge">bool</code></td>
<td>when true, the peer will send message confirmations</td>
<td><a href="https://rfc.vac.dev/spec/6/#confirmations-enabled-field">WAKU-1#confirmations-enabled-field</a></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">rate-limits</code></td>
<td><code class="language-plaintext highlighter-rouge">0x04</code></td>
<td> </td>
<td>See <a href="#rate-limiting">Rate limiting</a></td>
<td><a href="https://rfc.vac.dev/spec/6/#rate-limits-field">WAKU-1#rate-limits</a></td>
</tr>
<tr>
<td><code class="language-plaintext highlighter-rouge">topic-interest</code></td>
<td><code class="language-plaintext highlighter-rouge">0x05</code></td>
<td><code class="language-plaintext highlighter-rouge">[10000][4]byte</code></td>
<td>Topic interest is used to share a nodes interest in envelopes with specific topics. It does this in a more bandwidth considerate way, at the expense of some metadata protection. Peers MUST only send envelopes with specified topics.</td>
<td><a href="https://rfc.vac.dev/spec/6/#topic-interest-field">WAKU-1#topic-interest</a>, <a href="https://github.com/vacp2p/research/tree/dcc71f4779be832d3b5ece9c4e11f1f7ec24aac2/whisper_scalability">the theoretical scaling model</a></td>
</tr>
</tbody>
</table>
<!-- TODO Add `light-node` and `confirmations-enabled` links when https://github.com/vacp2p/specs/pull/128 is merged -->
<h2 id="rate-limiting">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 nodes rate limits, the connection between them MAY be dropped.</p>
<p>Each node SHOULD broadcast its rate limits to its peers using <code class="language-plaintext highlighter-rouge">rate limits</code> in <code class="language-plaintext highlighter-rouge">status-options</code> via packet code <code class="language-plaintext highlighter-rouge">0x00</code> or <code class="language-plaintext highlighter-rouge">0x22</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 peers rate limits. If the limit gets exceeded, the connection MAY be dropped by the peer.</p>
<h2 id="keys-management">Keys management</h2>
<p>The protocol requires a key (symmetric or asymmetric) for the following actions:</p>
<ul>
<li>signing &amp; verifying messages (asymmetric key)</li>
<li>encrypting &amp; 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 Waku topics to achieve its goals.</p>
<h3 id="contact-code-topic">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">contactCode</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">&lt;</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">&lt;</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">Partitioned topic</h3>
<p>Waku 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>. They 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">&lt;</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">&lt;</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">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">&lt;</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">&lt;</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 ??? -->
<h3 id="group-chat-topic">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">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">&lt;</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">&lt;</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">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 clients <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 clients <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> &amp; <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">Message encryption</h2>
<p>Even though, the protocol specifies an encryption layer that encrypts messages before passing them to the transport layer, Waku protocol requires each Waku 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">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 <code class="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 <code class="language-plaintext highlighter-rouge">Mailserver</code>. If additionally, sending a message is limited to non-<code class="language-plaintext highlighter-rouge">Mailserver</code> peers, it also guarantees that the message got broadcast through the network and it reached the selected <code class="language-plaintext highlighter-rouge">Mailserver</code>.</p>
<h2 id="waku-v1-extensions">Waku V1 extensions</h2>
<h3 id="request-historic-messages">Request historic messages</h3>
<p>Sends a request for historic messages to a <code class="language-plaintext highlighter-rouge">Mailserver</code>. The <code class="language-plaintext highlighter-rouge">Mailserver</code> node MUST be a direct peer and MUST be marked as trusted (using <code class="language-plaintext highlighter-rouge">waku_markTrustedPeer</code>).</p>
<p>The request does not wait for the response. It merely sends a peer-to-peer message to the <code class="language-plaintext highlighter-rouge">Mailserver</code> and its up to <code class="language-plaintext highlighter-rouge">Mailserver</code> 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>Its 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="wakuext_requestmessages">wakuext_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>: <code class="language-plaintext highlighter-rouge">Mailserver</code>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 used to authenticate with the <code class="language-plaintext highlighter-rouge">Mailserver</code>, derived from the <code class="language-plaintext highlighter-rouge">Mailserver</code> 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 <code class="language-plaintext highlighter-rouge">Mailserver</code>.</p>
<!-- TODO: Clarify actual request with bloom filter to mailserver -->
<h2 id="changelog">Changelog</h2>
<h3 id="version-01">Version 0.1</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/664dd1c9df6ad409e4c007fefc8c8945b8d324e8">May 22, 2020</a></p>
<ul>
<li>Created document</li>
<li>Forked from <a href="3-whisper-usage.md">3-whisper-usage</a></li>
<li>Change to keep <code class="language-plaintext highlighter-rouge">Mailserver</code> term consistent</li>
<li>Replaced Whisper references with Waku</li>
<li>Added <a href="#status">Status options</a> section</li>
<li>Updated <a href="#waku-packets">Waku packets</a> section to match Waku</li>
<li>Added that <code class="language-plaintext highlighter-rouge">Batch Ack</code> is marked for deprecation</li>
<li>Changed <code class="language-plaintext highlighter-rouge">shh_generateSymKeyFromPassword</code> to <code class="language-plaintext highlighter-rouge">waku_generateSymKeyFromPassword</code>
<ul>
<li><a href="https://github.com/status-im/status-go/blob/2d13ccf5ec3db7e48d7a96a7954be57edb96f12f/waku/api.go#L172-L175">Exists here</a></li>
<li><a href="https://github.com/status-im/status-go/blob/2d13ccf5ec3db7e48d7a96a7954be57edb96f12f/eth-node/bridge/geth/public_waku_api.go#L33-L36">Exists here</a></li>
</ul>
</li>
<li>Changed <code class="language-plaintext highlighter-rouge">shh_markTrustedPeer</code> to <code class="language-plaintext highlighter-rouge">waku_markTrustedPeer</code>
<ul>
<li><a href="https://github.com/status-im/status-go/blob/2d13ccf5ec3db7e48d7a96a7954be57edb96f12f/waku/api.go#L100-L108">Exists here</a></li>
</ul>
</li>
<li>Changed <code class="language-plaintext highlighter-rouge">shhext_requestMessages</code> to <code class="language-plaintext highlighter-rouge">wakuext_requestMessages</code>
<ul>
<li><a href="https://github.com/status-im/status-go/blob/2d13ccf5ec3db7e48d7a96a7954be57edb96f12f/services/wakuext/api.go#L76-L139">Exists here</a></li>
</ul>
</li>
</ul>

View File

@ -1,141 +0,0 @@
<h1 id="11waku-mailserver">11/WAKU-MAILSERVER</h1>
<blockquote>
<p>Version: 0.1</p>
<p>Status: Stable</p>
<p>Authors: Adam Babik <a href="mailto:adam@status.im">adam@status.im</a>, Oskar Thorén <a href="mailto:oskar@status.im">oskar@status.im</a>, Samuel Hawksby-Robinson <a href="mailto:samuel@status.im">samuel@status.im</a> (alphabetical order)</p>
</blockquote>
<ul>
<li><a href="#11waku-mailserver">Status Waku Mailserver Specification</a>
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#mailserver"><code class="language-plaintext highlighter-rouge">Mailserver</code></a>
<ul>
<li><a href="#archiving-messages">Archiving messages</a></li>
<li><a href="#requesting-messages">Requesting messages</a></li>
<li><a href="#receiving-historic-messages">Receiving historic messages</a></li>
</ul>
</li>
<li><a href="#security-considerations">Security considerations</a>
<ul>
<li><a href="#confidentiality">Confidentiality</a></li>
<li><a href="#altruistic-and-centralized-operator-risk">Altruistic and centralized operator risk</a></li>
<li><a href="#privacy-concerns">Privacy concerns</a></li>
<li><a href="#denial-of-service">Denial-of-service</a></li>
</ul>
</li>
<li><a href="#changelog">Changelog</a>
<ul>
<li><a href="#version-01">Version 0.1</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="abstract">Abstract</h2>
<p>Being mostly offline is an intrinsic property of mobile clients. They need to save network transfer and battery consumption to avoid spending too much money or constant charging. Waku protocol, on the other hand, is an online protocol. Messages are available in the Waku network only for short period of time calculate in seconds.</p>
<p>Waku Mailserver is a specification that allows messages to be stored permanently and to allows the stored messages to be delivered to requesting client nodes, regardless if the messages are not available in the network due to the message TTL expiring.</p>
<h2 id="mailserver"><code class="language-plaintext highlighter-rouge">Mailserver</code></h2>
<p>From the network perspective, a <code class="language-plaintext highlighter-rouge">Mailserver</code> is just like any other Waku node. The only difference is that a <code class="language-plaintext highlighter-rouge">Mailserver</code> has the capability of archiving messages and delivering them to its peers on-demand.</p>
<p>It is important to notice that a <code class="language-plaintext highlighter-rouge">Mailserver</code> will only handle requests from its direct peers and exchanged packets between a <code class="language-plaintext highlighter-rouge">Mailserver</code> and a peer are p2p messages.</p>
<h3 id="archiving-messages">Archiving messages</h3>
<p>A node which wants to provide <code class="language-plaintext highlighter-rouge">Mailserver</code> functionality MUST store envelopes from
incoming message packets (Waku packet-code <code class="language-plaintext highlighter-rouge">0x01</code>). The envelopes can be stored in any
format, however they MUST be serialized and deserialized to the Waku envelope format.</p>
<p>A <code class="language-plaintext highlighter-rouge">Mailserver</code> SHOULD store envelopes for all topics to be generally useful for any peer, however for specific use cases it MAY store envelopes for a subset of topics.</p>
<h3 id="requesting-messages">Requesting messages</h3>
<p>In order to request historic messages, a node MUST send a packet P2P Request (<code class="language-plaintext highlighter-rouge">0x7e</code>) to a peer providing <code class="language-plaintext highlighter-rouge">Mailserver</code> functionality. This packet requires one argument which MUST be a Waku envelope.</p>
<p>In the Waku envelopes payload section, there MUST be RLP-encoded information about the details of the request:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ Lower, Upper, Bloom, Limit, Cursor ]
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">Lower</code>: 4-byte wide unsigned integer (UNIX time in seconds; oldest requested envelopes creation time)<br />
<code class="language-plaintext highlighter-rouge">Upper</code>: 4-byte wide unsigned integer (UNIX time in seconds; newest requested envelopes creation time)<br />
<code class="language-plaintext highlighter-rouge">Bloom</code>: 64-byte wide array of Waku topics encoded in a bloom filter to filter envelopes<br />
<code class="language-plaintext highlighter-rouge">Limit</code>: 4-byte wide unsigned integer limiting the number of returned envelopes<br />
<code class="language-plaintext highlighter-rouge">Cursor</code>: an array of a cursor returned from the previous request (optional)</p>
<p>The <code class="language-plaintext highlighter-rouge">Cursor</code> field SHOULD be filled in if a number of envelopes between <code class="language-plaintext highlighter-rouge">Lower</code> and <code class="language-plaintext highlighter-rouge">Upper</code> is greater than <code class="language-plaintext highlighter-rouge">Limit</code> so that the requester can send another request using the obtained <code class="language-plaintext highlighter-rouge">Cursor</code> value. What exactly is in the <code class="language-plaintext highlighter-rouge">Cursor</code> is up to the implementation. The requester SHOULD NOT use a <code class="language-plaintext highlighter-rouge">Cursor</code> obtained from one <code class="language-plaintext highlighter-rouge">Mailserver</code> in a request to another <code class="language-plaintext highlighter-rouge">Mailserver</code> because the format or the result MAY be different.</p>
<p>The envelope MUST be encrypted with a symmetric key agreed between the requester and the <code class="language-plaintext highlighter-rouge">Mailserver</code>.</p>
<h3 id="receiving-historic-messages">Receiving historic messages</h3>
<p>Historic messages MUST be sent to a peer as a packet with a P2P Message code (<code class="language-plaintext highlighter-rouge">0x7f</code>) followed by an array of Waku envelopes.</p>
<p>In order to receive historic messages from a <code class="language-plaintext highlighter-rouge">Mailserver</code>, a node MUST trust the selected <code class="language-plaintext highlighter-rouge">Mailserver</code>, that is allowed to send packets with the P2P Message code. By default, the node discards such packets.</p>
<p>Received envelopes MUST be passed through the Waku envelope pipelines so that they are picked up by registered filters and passed to subscribers.</p>
<p>For a requester, to know that all messages have been sent by a <code class="language-plaintext highlighter-rouge">Mailserver</code>, it SHOULD handle P2P Request Complete code (<code class="language-plaintext highlighter-rouge">0x7d</code>). This code is followed by the following parameters:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ RequestID, LastEnvelopeHash, Cursor ]
</code></pre></div></div>
<ul>
<li><code class="language-plaintext highlighter-rouge">RequestID</code>: 32-byte wide array with a Keccak-256 hash of the envelope containing the original request</li>
<li><code class="language-plaintext highlighter-rouge">LastEnvelopeHash</code>: 32-byte wide array with a Keccak-256 hash of the last sent envelope for the request</li>
<li><code class="language-plaintext highlighter-rouge">Cursor</code>: an array of a cursor returned from the previous request (optional)</li>
</ul>
<p>If <code class="language-plaintext highlighter-rouge">Cursor</code> is not empty, it means that not all messages were sent due to the set <code class="language-plaintext highlighter-rouge">Limit</code> in the request. One or more consecutive requests MAY be sent with <code class="language-plaintext highlighter-rouge">Cursor</code> field filled in order to receive the rest of the messages.</p>
<h2 id="security-considerations">Security considerations</h2>
<h3 id="confidentiality">Confidentiality</h3>
<p>The node encrypts all Waku envelopes. A <code class="language-plaintext highlighter-rouge">Mailserver</code> node can not inspect their contents.</p>
<h3 id="altruistic-and-centralized-operator-risk">Altruistic and centralized operator risk</h3>
<p>In order to be useful, a <code class="language-plaintext highlighter-rouge">Mailserver</code> SHOULD be online most of time. That means
users either have to be a bit tech-savvy to run their own node, or rely on someone
else to run it for them.</p>
<p>Currently, one of Statuss legal entities provides <code class="language-plaintext highlighter-rouge">Mailservers</code> in an altruistic manner, but this is
suboptimal from a decentralization, continuance and risk point of view. Coming
up with a better system for this is ongoing research.</p>
<p>A Status client SHOULD allow the <code class="language-plaintext highlighter-rouge">Mailserver</code> selection to be customizable.</p>
<h3 id="privacy-concerns">Privacy concerns</h3>
<p>In order to use a <code class="language-plaintext highlighter-rouge">Mailserver</code>, a given node needs to connect to it directly,
i.e. add the <code class="language-plaintext highlighter-rouge">Mailserver</code> as its peer and mark it as trusted. This means that the
<code class="language-plaintext highlighter-rouge">Mailserver</code> is able to send direct p2p messages to the node instead of
broadcasting them. Effectively, it will have access to the bloom filter of
topics that the user is interested in, when it is online as well as many
metadata like IP address.</p>
<h3 id="denial-of-service">Denial-of-service</h3>
<p>Since a <code class="language-plaintext highlighter-rouge">Mailserver</code> is delivering expired envelopes and has a direct TCP connection with the recipient, the recipient is vulnerable to DoS attacks from a malicious <code class="language-plaintext highlighter-rouge">Mailserver</code> node.</p>
<h2 id="changelog">Changelog</h2>
<h3 id="version-01">Version 0.1</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/664dd1c9df6ad409e4c007fefc8c8945b8d324e8">May 22, 2020</a></p>
<ul>
<li>Created document</li>
<li>Forked from <a href="4-whisper-mailserver.md">4-whisper-mailserver</a></li>
<li>Change to keep <code class="language-plaintext highlighter-rouge">Mailserver</code> term consistent</li>
<li>Replaced Whisper references with Waku</li>
</ul>

View File

@ -1,114 +0,0 @@
<h1 id="12ipfs-gateway-for-sticker-pack">12/IPFS gateway for Sticker Pack</h1>
<blockquote>
<p>Version: 0.1.0</p>
<p>Status: Draft</p>
<p>Authors: Gheorghe Pinzaru <a href="mailto:gheorghe@status.im">gheorghe@status.im</a></p>
</blockquote>
<h2 id="table-of-contents">Table of Contents</h2>
<ol>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#specification">Specification</a></li>
<li><a href="#copyright">Copyright</a></li>
</ol>
<h2 id="abstract">Abstract</h2>
<p>This specification describes how Status uses the IPFS gateway to store stickers.
The specification explores image format, how a user uploads stickers and how an end user can see them inside the Status app.</p>
<h2 id="definition">Definition</h2>
<table>
<thead>
<tr>
<th>Term</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Stickers</strong></td>
<td>A set of images which can be used to express emotions</td>
</tr>
<tr>
<td><strong>Sticker Pack</strong></td>
<td>ERC721 token which includes the set of stickers</td>
</tr>
<tr>
<td><strong>IPFS</strong></td>
<td>P2P network used to store and share data, in this case, the images for the stickerpack</td>
</tr>
</tbody>
</table>
<h2 id="specification">Specification</h2>
<h3 id="image-format">Image format</h3>
<p>Accepted image file types are <code class="language-plaintext highlighter-rouge">PNG</code>, <code class="language-plaintext highlighter-rouge">JPG/JPEG</code> and <code class="language-plaintext highlighter-rouge">GIF</code>, with a maximum allowed size of 300kb.
The minimum sticker image resolution is 512x512, and its background SHOULD be transparent.</p>
<h3 id="distribution">Distribution</h3>
<p>The node implements sticker packs as <a href="https://eips.ethereum.org/EIPS/eip-721">ERC721 token</a> and contain a set of stickers. The node stores these stickers
inside the sticker pack as a set of hyperlinks pointing to IPFS storage. These hyperlinks are publicly available and can be accessed by any user inside the status chat.
Stickers can be sent in chat only by accounts that own the sticker pack.</p>
<h3 id="ipfs-gateway">IPFS gateway</h3>
<p>At the moment of writing, the current main Status app uses the <a href="https://infura.io/">Infura</a> gateway. However, clients could choose a different gateway or to run own IPFS node.
Infura gateway is an HTTPS gateway, which based on an HTTP GET request with the multihash block will return the stored content at that block address.</p>
<p>The node requires the use of a gateway to enable easy access to the resources over HTTP.
The node stores each image of a sticker inside IPFS using a unique address that is
derived from the hash of the file. This ensures that a file cant be overridden, and an end-user of the IPFS will receive the same file at a given address.</p>
<h3 id="security">Security</h3>
<p>The IPFS gateway acts as an end-user of the IPFS and allows users of the gateway to access IPFS without connection to the P2P network.
Usage of a gateway introduces potential risk for the users of that gateway provider. In case of a compromise in the security of the provider, meta information such as IP address, User-Agent and other of its users can be leaked.
If the provider servers are unavailable the node loses access through the gateway to the IPFS network.</p>
<h3 id="status-sticker-usage">Status sticker usage</h3>
<p>When the app shows a sticker, the Status app makes an HTTP GET request to IPFS gateway using the hyperlink.</p>
<p>To send a sticker in chat, a user of Status should buy or install a sticker pack.</p>
<p>To be available for installation a Sticker Pack should be submitted to Sticker market by an author.</p>
<h4 id="submit-a-sticker">Submit a sticker</h4>
<p>To submit a sticker pack, the author should upload all assets to IPFS. Then generate a payload including name, author, thumbnail, preview and a list of stickers in the <a href="https://github.com/edn-format/edn">EDN format</a>. Following this structure:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{meta {:name "Sticker pack name"
:author "Author Name"
:thumbnail "e30101701220602163b4f56c747333f43775fdcbe4e62d6a3e147b22aaf6097ce0143a6b2373"
:preview "e30101701220ef54a5354b78ef82e542bd468f58804de71c8ec268da7968a1422909357f2456"
:stickers [{:hash "e301017012207737b75367b8068e5bdd027d7b71a25138c83e155d1f0c9bc5c48ff158724495"}
{:hash "e301017012201a9cdea03f27cda1aede7315f79579e160c7b2b6a2eb51a66e47a96f47fe5284"}]}}
</code></pre></div></div>
<p>All asset fields, are contenthash fields as per <a href="https://eips.ethereum.org/EIPS/eip-1577">EIP 1577</a>.
The node also uploads this payload to IPFS, and the node uses the IPFS address in the content field of the Sticker Market contract. See <a href="https://github.com/status-im/sticker-market/blob/651e88e5f38c690e57ecaad47f46b9641b8b1e27/docs/specification.md">Sticker Market spec</a> for a detailed description of the contract.</p>
<h4 id="install-a-sticker-pack">Install a sticker pack</h4>
<p>To install a sticker pack, the node fetches all sticker packs available in Sticker Market. The node needs the following steps to fetch all sticker packs:</p>
<h4 id="1-get-total-number-of-sticker-packs">1. Get total number of sticker packs</h4>
<p>Call <code class="language-plaintext highlighter-rouge">packCount()</code> on the sticker market contract, will return number of sticker pack registered as <code class="language-plaintext highlighter-rouge">uint256</code>.</p>
<h4 id="2-get-sticker-pack-by-id">2. Get sticker pack by id</h4>
<p>IDs are represented as <code class="language-plaintext highlighter-rouge">uint256</code> and are incremental from <code class="language-plaintext highlighter-rouge">0</code> to total number of sticker packs in the contract, received in the previous step. To get a sticker pack call <code class="language-plaintext highlighter-rouge">getPackData(sticker-pack-id)</code>, the return type is <code class="language-plaintext highlighter-rouge">["bytes4[]" "address" "bool" "uint256" "uint256" "bytes"]</code> which represents the following fields: <code class="language-plaintext highlighter-rouge">[category owner mintable timestamp price contenthash]</code>. Price is the SNT value in wei set by sticker pack owner. The contenthash is the IPFS address described in the <a href="#submit-a-sticker">submit description</a> above. Other fields specification could be found in <a href="https://github.com/status-im/sticker-market/blob/651e88e5f38c690e57ecaad47f46b9641b8b1e27/docs/specification.md">Sticker Market spec</a></p>
<h5 id="3-get-owned-sticker-packs">3. Get owned sticker packs</h5>
<p>The current Status app fetches owned sticker packs during the open of any sticker view (a screen which shows a sticker pack, or the list of sticker packs).
To get owned packs, get all owned tokens for the current account address, by calling <code class="language-plaintext highlighter-rouge">balanceOf(address)</code> where address is the address for the current account. This method returns a <code class="language-plaintext highlighter-rouge">uint256</code> representing the count of available tokens. Using <code class="language-plaintext highlighter-rouge">tokenOfOwnerByIndex(address,uint256)</code> method, with the address of the user and ID in form of a <code class="language-plaintext highlighter-rouge">uint256</code> which is an incremented int from 0 to the total number of tokens, gives the token id. To get the sticker pack id from a token call<code class="language-plaintext highlighter-rouge">tokenPackId(uint256)</code> where <code class="language-plaintext highlighter-rouge">uint256</code> is the token id. This method will return an <code class="language-plaintext highlighter-rouge">uint256</code> which is the id of the owned sticker pack.</p>
<h5 id="4-buy-a-sticker-pack">4. Buy a sticker pack</h5>
<p>To buy a sticker pack call <code class="language-plaintext highlighter-rouge">approveAndCall(address,uint256,bytes)</code> where <code class="language-plaintext highlighter-rouge">address</code> is the address of buyer,<code class="language-plaintext highlighter-rouge">uint256</code> is the price and third parameters <code class="language-plaintext highlighter-rouge">bytes</code> is the callback called if approved. In the callback, call <code class="language-plaintext highlighter-rouge">buyToken(uint256,address,uint256)</code>, first parameter is sticker pack id, second buyers address, and the last is the price.</p>
<h2 id="copyright">Copyright</h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>

View File

@ -1,151 +0,0 @@
<h1 id="133rd-party">13/3RD-PARTY</h1>
<blockquote>
<p>Version: 0.1</p>
<p>Status: Draft</p>
<p>Authors: Volodymyr Kozieiev <a href="mailto:volodymyr@status.im">volodymyr@status.im</a></p>
</blockquote>
<h1 id="third-party-apis-used-for-core-functionality">Third party APIs used for core functionality</h1>
<h2 id="table-of-contents">Table of Contents</h2>
<ol>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#definitions">Definitions</a></li>
<li><a href="#why-3rd-party-api-can-be-a-problem">Why 3rd party API can be a problem?</a></li>
<li><a href="#3rd-party-apis-used-by-current-status-app">3rd party APIs used by Status</a>
<ul>
<li><a href="#infura">Infura</a></li>
<li><a href="#etherscan">Etherscan</a></li>
<li><a href="#cryptocompare">CryptoCompare</a></li>
<li><a href="#collectibles">Collectibles</a></li>
<li><a href="#iubenda">Iubenda</a></li>
</ul>
</li>
<li><a href="#changelog">Changelog</a></li>
<li><a href="#copyright">Copyright</a></li>
</ol>
<h2 id="abstract">Abstract</h2>
<p>This specification discusses 3rd party APIs that Status relies on. These APIs provide various capabilities such as:</p>
<ul>
<li>communicate with the Ethereum network</li>
<li>allow users to see address and transaction details on external website</li>
<li>get fiat/crypto exchange rates</li>
<li>get information about collectibles</li>
<li>hosts privacy policy</li>
</ul>
<h2 id="definitions">Definitions</h2>
<table>
<thead>
<tr>
<th>Term</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fiat money</td>
<td>Currency which established as money, often by government regulation, but that has no intrinsic value</td>
</tr>
<tr>
<td>Full node</td>
<td>Any computer, connected to the Ethereum network, which fully enforces all the consensus rules of Ethereum.</td>
</tr>
<tr>
<td>Crypto-collectible</td>
<td>A cryptographically unique, non-fungible digital asset . Unlike cryptocurrencies, which require all tokens to be identical, each crypto-collectible token is unique or limited in quantity.</td>
</tr>
</tbody>
</table>
<h2 id="why-3rd-party-api-can-be-a-problem">Why 3rd party API can be a problem?</h2>
<p>Relying on 3rd party APIs interferes with <code class="language-plaintext highlighter-rouge">censorship resistance</code> Status principle. Since Status aims to avoid suppression of information it is important to reduce amount of 3rd parties crucial for app functionality.</p>
<h2 id="3rd-party-apis-used-by-current-status-app">3rd party APIs used by current Status app</h2>
<h3 id="infura">Infura</h3>
<h5 id="what-is-it">What is it?</h5>
<p>Infura hosts a collection of full nodes for the Ethereum network and provides an API to access both the Ethereum and IPFS networks without having to run a full node.</p>
<h5 id="how-status-use-it">How Status use it?</h5>
<p>Status works on mobile devices and therefore cant rely on local node. So all communication to Ethereum network happens via Infura.</p>
<h5 id="concerns">Concerns</h5>
<p>Making a HTTP request means that a user leaks metadata, which can be used in various attacks if an attacker hacks the service.
Infura hosts on centralized providers. If these fail or the provider cuts off service, then Status features requiring Ethereum calls will.</p>
<h3 id="etherscan">Etherscan</h3>
<h5 id="what-is-it-1">What is it?</h5>
<p>Etherscan is a service that allows user to explore and search the Ethereum blockchain for transactions, addresses, tokens, prices and other activities taking place on Ethereum.</p>
<h5 id="how-status-use-it-1">How Status use it?</h5>
<p>Status Wallet allows users to view details of addresses and transactions on Etherscan.</p>
<h5 id="concerns-1">Concerns</h5>
<p>If Etherscan fails user wont be able to view address or transaction details with it. But inside the app this info will still be available.</p>
<h3 id="cryptocompare">CryptoCompare</h3>
<h5 id="what-is-it-2">What is it?</h5>
<p>CryptoCompare is a service that shows live streaming prices, charts and analysis from top crypto exchanges.</p>
<h5 id="how-status-use-it-2">How Status use it?</h5>
<p>Status regularly fetches crypto prices from CryptoCompare. Using that info Status calculates fiat value for transaction or wallet assets.</p>
<h5 id="concerns-2">Concerns</h5>
<p>Making a HTTP request means that a user leaks metadata, which can be used in various attacks if an attacker hacks the service.
If CryptoCompare fails Status wont be able to show fiat equivalent of crypto in wallet.</p>
<h3 id="collectibles">Collectibles</h3>
<p>There is a set of services that used for getting information about collectibles:</p>
<ul>
<li>https://api.pixura.io/graphql</li>
<li>https://www.etheremon.com/api</li>
<li>https://us-central1-cryptostrikers-prod.cloudfunctions.net/cards/</li>
<li>https://api.cryptokitties.co/</li>
</ul>
<h5 id="concerns-3">Concerns</h5>
<p>Making a HTTP request means that a user leaks metadata, which can be used in various attacks if an attacker hacks the service.</p>
<h3 id="iubenda">Iubenda</h3>
<h5 id="what-is-it-3">What is it?</h5>
<p>Service that helps in creating documents that make websites and apps compliant with the law across multiple countries and legislations.</p>
<h5 id="how-status-use-it-3">How Status use it?</h5>
<p>Privacy policy of Status hosted on Iubenda.</p>
<h5 id="concerns-4">Concerns</h5>
<p>If Iubenda fails Status users wont be able to navigate to apps privacy policy.</p>
<h2 id="changelog">Changelog</h2>
<table>
<thead>
<tr>
<th style="text-align: center">Version</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><a href="https://github.com/status-im/specs/blob/master/docs/draft/9-3rd-party.md">0.1.0</a></td>
<td>Initial Release</td>
</tr>
</tbody>
</table>
<h2 id="copyright">Copyright</h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>

View File

@ -1,186 +0,0 @@
<h1 id="dapp-browser-api-usage">Dapp browser API usage</h1>
<h2 id="table-of-contents">Table of Contents</h2>
<ol>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#definitions">Definitions</a></li>
<li><a href="#overview">Overview</a></li>
<li><a href="#usage">Usage</a>
<ul>
<li><a href="#properties">Properties</a>
<ul>
<li><a href="#isStatus"><code class="language-plaintext highlighter-rouge">isStatus</code></a></li>
<li><a href="#status"><code class="language-plaintext highlighter-rouge">status</code></a></li>
</ul>
</li>
<li><a href="#methods">Methods</a>
<ul>
<li><a href="#isConnected"><code class="language-plaintext highlighter-rouge">isConnected</code></a></li>
<li><a href="#request"><code class="language-plaintext highlighter-rouge">request</code></a></li>
<li><a href="#scanQRCode"><code class="language-plaintext highlighter-rouge">scanQRCode</code></a></li>
</ul>
</li>
<li><a href="#unused">Unused</a>
<ul>
<li><a href="#enable"><code class="language-plaintext highlighter-rouge">enable</code></a></li>
<li><a href="#send"><code class="language-plaintext highlighter-rouge">send</code></a></li>
<li><a href="#sendAsync"><code class="language-plaintext highlighter-rouge">sendAsync</code></a></li>
<li><a href="#sendSync"><code class="language-plaintext highlighter-rouge">sendSync</code></a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#implementation">Implementation</a></li>
<li><a href="#compatibility">Compatibility</a></li>
<li><a href="#changelog">Changelog</a></li>
<li><a href="#copyright">Copyright</a></li>
</ol>
<h2 id="abstract">Abstract</h2>
<p>This document describes requirements that an application must fulfill in order to provide a proper environment for Dapps running inside a browser. A description of the Status Dapp API is provided, along with an overview of bidirectional communication underlying the API implementation. The document also includes a list of EIPs that this API implements.</p>
<h2 id="definitions">Definitions</h2>
<table>
<thead>
<tr>
<th>Term</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Webview</strong></td>
<td>Platform-specific browser core implementation.</td>
</tr>
<tr>
<td><strong>Ethereum Provider</strong></td>
<td>A JS object (<code class="language-plaintext highlighter-rouge">window.ethereum</code>) injected into each web page opened in the browser providing web3 compatible provider.</td>
</tr>
<tr>
<td><strong>Bridge</strong></td>
<td>A set of facilities allow bidirectional communication between JS code and the application.</td>
</tr>
</tbody>
</table>
<h2 id="overview">Overview</h2>
<p>The application should expose an Ethereum Provider object (<code class="language-plaintext highlighter-rouge">window.ethereum</code>) to JS code running inside the browser. It is important to have the <code class="language-plaintext highlighter-rouge">window.ethereum</code> object available before the page loads, otherwise Dapps might not work correctly.</p>
<p>Additionally, the browser component should also provide bidirectional communication between JS code and the application.</p>
<h2 id="usage-in-dapps">Usage in Dapps</h2>
<p>Dapps can use the below properties and methods of <code class="language-plaintext highlighter-rouge">window.ethereum</code> object.</p>
<h3 id="properties">Properties</h3>
<h4 id="isstatus"><code class="language-plaintext highlighter-rouge">isStatus</code></h4>
<p>Returns true. Can be used by the Dapp to find out whether its running inside Status.</p>
<h4 id="status"><code class="language-plaintext highlighter-rouge">status</code></h4>
<p>Returns a <code class="language-plaintext highlighter-rouge">StatusAPI</code> object. For now it supports one method: <code class="language-plaintext highlighter-rouge">getContactCode</code> that sends a <code class="language-plaintext highlighter-rouge">contact-code</code> request to Status.</p>
<h3 id="methods">Methods</h3>
<h4 id="isconnected"><code class="language-plaintext highlighter-rouge">isConnected</code></h4>
<p>Similarly to Ethereum JS API <a href="https://github.com/ethereum/wiki/wiki/JavaScript-API#web3isconnected">docs</a>, it should be called to check if connection to a node exists. On Status, this fn always returns true, as once Status is up and running, node is automatically started.</p>
<h4 id="scanqrcode"><code class="language-plaintext highlighter-rouge">scanQRCode</code></h4>
<p>Sends a <code class="language-plaintext highlighter-rouge">qr-code</code> Status API request.</p>
<h4 id="request"><code class="language-plaintext highlighter-rouge">request</code></h4>
<p><code class="language-plaintext highlighter-rouge">request</code> method as defined by EIP-1193.</p>
<h3 id="unused">Unused</h3>
<p>Below are some legacy methods that some Dapps might still use.</p>
<h4 id="enable-deprecated"><code class="language-plaintext highlighter-rouge">enable</code> (DEPRECATED)</h4>
<p>Sends a <code class="language-plaintext highlighter-rouge">web3</code> Status API request. It returns a first entry in the list of available accounts.</p>
<p>Legacy <code class="language-plaintext highlighter-rouge">enable</code> method as defined by <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1102.md">EIP1102</a>.</p>
<h4 id="send-deprecated"><code class="language-plaintext highlighter-rouge">send</code> (DEPRECATED)</h4>
<p>Legacy <code class="language-plaintext highlighter-rouge">send</code> method as defined by <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md">EIP1193</a>.</p>
<h4 id="sendasync-deprecated"><code class="language-plaintext highlighter-rouge">sendAsync</code> (DEPRECATED)</h4>
<p>Legacy <code class="language-plaintext highlighter-rouge">sendAsync</code> method as defined by <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md">EIP1193</a>.</p>
<h4 id="sendsync-deprecated"><code class="language-plaintext highlighter-rouge">sendSync</code> (DEPRECATED)</h4>
<p>Legacy <code class="language-plaintext highlighter-rouge">send</code> method.</p>
<h2 id="implementation">Implementation</h2>
<p>Status uses a <a href="https://github.com/status-im/react-native-webview">forked version</a> of <a href="https://github.com/react-native-community/react-native-webview">react-native-webview</a> to display web or dapps content. The fork provides an Android implementation of JS injection before page load. It is required in order to properly inject Ethereum Provider object.</p>
<p>Status injects two JS scripts:</p>
<ul>
<li><a href="https://github.com/status-im/status-react/blob/develop/resources/js/provider.js">provider.js</a>: <code class="language-plaintext highlighter-rouge">window.ethereum</code> object</li>
<li><a href="https://github.com/status-im/status-react/blob/develop/resources/js/webview.js">webview.js</a>: override for <code class="language-plaintext highlighter-rouge">history.pushState</code> used internally</li>
</ul>
<p>Dapps running inside a browser communicate with Status Ethereum node by means of a <em>bridge</em> provided by react-native-webview library. The bridge allows for bidirectional communication between browser and Status. In order to do so, it injects a special <code class="language-plaintext highlighter-rouge">ReactNativeWebview</code> object into each page it loads.</p>
<p>On Status (React Native) end, <code class="language-plaintext highlighter-rouge">react-native-webview</code> library provides <code class="language-plaintext highlighter-rouge">WebView.injectJavascript</code> function on a webview component that allows to execute arbitrary code inside the webview. Thus it is possible to inject a function call passing Status node response back to the Dapp.</p>
<p>Below is the table briefly describing what functions/properties are used. More details available in package <a href="https://github.com/react-native-community/react-native-webview/blob/master/docs/Guide.md#communicating-between-js-and-native">docs</a>.</p>
<table>
<thead>
<tr>
<th>Direction</th>
<th>Side</th>
<th>Method</th>
</tr>
</thead>
<tbody>
<tr>
<td>Browser-&gt;Status</td>
<td>JS</td>
<td><code class="language-plaintext highlighter-rouge">ReactNativeWebView.postMessage()</code></td>
</tr>
<tr>
<td>Browser-&gt;Status</td>
<td>RN</td>
<td><code class="language-plaintext highlighter-rouge">WebView.onMessage()</code></td>
</tr>
<tr>
<td>Status-&gt;Browser</td>
<td>JS</td>
<td><code class="language-plaintext highlighter-rouge">ReactNativeWebView.onMessage()</code></td>
</tr>
<tr>
<td>Status-&gt;Browser</td>
<td>RN</td>
<td><code class="language-plaintext highlighter-rouge">WebView.injectJavascript()</code></td>
</tr>
</tbody>
</table>
<h2 id="compatibility">Compatibility</h2>
<p>Status browser supports the following EIPs:</p>
<ul>
<li><a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1102.md">EIP1102</a>: <code class="language-plaintext highlighter-rouge">eth_requestAccounts</code> support</li>
<li><a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md">EIP1193</a>: <code class="language-plaintext highlighter-rouge">connect</code>, <code class="language-plaintext highlighter-rouge">disconnect</code>, <code class="language-plaintext highlighter-rouge">chainChanged</code>, and <code class="language-plaintext highlighter-rouge">accountsChanged</code> event support is not implemented</li>
</ul>
<h2 id="changelog">Changelog</h2>
<table>
<thead>
<tr>
<th style="text-align: center">Version</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><a href="https://github.com/specs/...">0.1.0</a></td>
<td>Initial Release</td>
</tr>
</tbody>
</table>
<h2 id="copyright">Copyright</h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>

View File

@ -1,28 +0,0 @@
<h1 id="15notifications">15/NOTIFICATIONS</h1>
<h2 id="local-notifications">Local Notifications</h2>
<p>A client should implement local notifications to offer notifications for any event in the app without the privacy cost and dependency on third party services. This means that the client should run a background service to continuously or periodically check for updates.</p>
<h3 id="android">Android</h3>
<p>Android allows running services on the device. When the user enables notifications, the client may start a ``Foreground Service`, and display a permanent notification indicating that the service is running, as required by Android guidelines.
The service will simply keep the app from being killed by the system when it is in the background.
The client will then be able to run in the background and display local notifications on events such as receiving a message in a one to one chat.</p>
<p>To facilitate the implementation of local notifications, a node implementation such as <code class="language-plaintext highlighter-rouge">status-go</code> may provide a specific <code class="language-plaintext highlighter-rouge">notification</code> signal.</p>
<p>Notifications are a separate process in Android, and interaction with a notification generates an <code class="language-plaintext highlighter-rouge">Intent</code>. To handle intents, the <code class="language-plaintext highlighter-rouge">NewMessageSignalHandler</code> may use a <code class="language-plaintext highlighter-rouge">BroadcastReceiver</code>, in order to update the state of local notifications when the user dismisses or tap a notification. If the user taps on a notification, the <code class="language-plaintext highlighter-rouge">BroadcastReceiver</code> generates a new intent to open the app should use universal links to get the user to the right place.</p>
<h3 id="ios">iOS</h3>
<p>We are not able to offer local notifications on iOS because there is no concept of services in iOS. It offers background updates but theyre not consistently triggered, and cannot be relied upon. The system decides when the background updates are triggered and the heuristics arent known.</p>
<h2 id="why-is-there-no-push-notifications">Why is there no Push Notifications?</h2>
<p>Push Notifications, as offered by Apple and Google are a privacy concern, they require a centralized service that is aware of who the notification needs to be delivered to.</p>
<h2 id="copyright">Copyright</h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>

View File

@ -1,808 +0,0 @@
<h1 id="16push-notification-server">16/PUSH-NOTIFICATION-SERVER</h1>
<blockquote>
<p>Version: 0.1</p>
<p>Status: Raw</p>
<p>Authors: Andrea Maria Piana <a href="mailto:andreap@status.im">andreap@status.im</a></p>
</blockquote>
<ul>
<li><a href="#16push-notification-server">Push Notification Server</a>
<ul>
<li><a href="#reason">Reason</a></li>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#components">Components</a></li>
<li><a href="#registering-with-the-push-notification-service">Registering with the push notification service</a></li>
<li><a href="#re-registering-with-the-push-notification-server">Re-registering with the push notification service</a></li>
<li><a href="#changing-options">Changing options</a></li>
<li><a href="#unregistering-from-push-notifications">Unregistering from push notifications</a></li>
<li><a href="#advertising-a-push-notification-server">Advertising a push notification server</a></li>
<li><a href="#discovering-a-push-notification-server">Discovering a push notification server</a></li>
<li><a href="#querying-the-push-notification-server">Querying the push notification service</a></li>
<li><a href="#sending-a-push-notification">Sending a push notification</a></li>
<li><a href="#flow">Flow</a>
<ul>
<li><a href="#registration-process">Registration process</a></li>
<li><a href="#sending-a-notification">Sending a notification</a></li>
<li><a href="#receiving-a-push-notification">Receiving a push notification</a></li>
</ul>
</li>
<li><a href="#protobuf-description">Protobuf description</a>
<ul>
<li><a href="#pushnotificationregistration">PushNotificationRegistration</a></li>
<li><a href="#pushnotificationregistrationresponse">PushNotificationRegistrationResponse</a></li>
<li><a href="#contactcodeadvertisement">ContactCodeAdvertisement</a></li>
<li><a href="#pushnotificationquery">PushNotificationQuery</a></li>
<li><a href="#pushnotificationqueryinfo">PushNotificationQueryInfo</a></li>
<li><a href="#pushnotificationqueryresponse">PushNotificationQueryResponse</a></li>
<li><a href="#pushnotification">PushNotification</a></li>
<li><a href="#pushnotificationrequest">PushNotificationRequest</a></li>
<li><a href="#pushnotificationacknowledgement">PushNotificationResponse</a></li>
<li><a href="#pushnotificationreport">PushNotificationReport</a></li>
</ul>
</li>
<li><a href="#anonymous-mode-of-operations">Anonymous mode of operations</a></li>
<li><a href="#security-considerations">Security considerations</a></li>
<li><a href="#faq">FAQ</a></li>
<li><a href="#changelog">Changelog</a>
<ul>
<li><a href="#version-01">Version 0.1</a></li>
</ul>
</li>
<li><a href="#copyright">Copyright</a></li>
</ul>
</li>
</ul>
<h2 id="reason">Reason</h2>
<p>Push notifications for iOS devices and some Android devices can only be
implemented by relying on <a href="https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1">APN service</a> for iOS or <a href="https://firebase.google.com/">Firebase</a>.</p>
<p>This is useful for Android devices that do not support foreground services or that often kill the
foreground service.</p>
<p>iOS only allows certain kind of applications to keep a connection open when in the
background, VoIP for example, which current status client does not qualify for.</p>
<p>Applications on iOS can also request execution time when they are in the <a href="https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_background/updating_your_app_with_background_app_refresh">background</a>
but it has a limited set of use cases, for example it wont schedule any time
if the application was force quit, and generally is not responsive enough to implement
a push notification system.</p>
<p>Therefore Status provides a set of Push notification services that can be used
to achieve this functionality.</p>
<p>Because this cant be safely implemented in a privacy preserving manner, clients
MUST be given an option to opt-in to receiving and sending push notifications. They are disabled by default.</p>
<h2 id="requirements">Requirements</h2>
<p>The party releasing the app MUST possess a certificate for the Apple Push Notification service and its has to run a <a href="https://github.com/appleboy/gorush">gorush</a> publicly accessible server for sending the actual notification.
The party releasing the app, Status in this case, needs to run its own <a href="https://github.com/appleboy/gorush">gorush</a></p>
<h2 id="components">Components</h2>
<h3 id="gorush-instance">Gorush instance</h3>
<p>A <a href="https://github.com/appleboy/gorush">gorush</a> instance MUST be publicly
available, this will be used only by push notification servers.</p>
<h3 id="push-notification-server">Push notification server</h3>
<p>A push notification server used by clients to register for receiving and sending push notifications.</p>
<h3 id="registering-client">Registering client</h3>
<p>A Status client that wants to receive push notifications</p>
<h3 id="sending-client">Sending client</h3>
<p>A Status client that wants to send push notifications</p>
<h2 id="registering-with-the-push-notification-service">Registering with the push notification service</h2>
<p>A client MAY register with one or more Push Notification services of their choice.</p>
<p>A <code class="language-plaintext highlighter-rouge">PNR message</code> (Push Notification Registration) MUST be sent to the <a href="../stable/10-waku-usage.md#partitioned-topic">partitioned topic</a> for the
public key of the node, encrypted with this key.</p>
<p>The message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_REGISTRATION</code>.</p>
<p>The marshaled protobuf payload MUST also be encrypted with AES-GCM using the DiffieHellman key
generated from the client and server identity.</p>
<p>This is done in order to ensure that the extracted key from the signature will be
considered invalid if it cant decrypt the payload.</p>
<p>The content of the message MUST contain the following <a href="https://developers.google.com/protocol-buffers/">protobuf record</a>:</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationRegistration</span> <span class="p">{</span>
<span class="kd">enum</span> <span class="n">TokenType</span> <span class="p">{</span>
<span class="na">UNKNOWN_TOKEN_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">APN_TOKEN</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="na">FIREBASE_TOKEN</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">TokenType</span> <span class="na">token_type</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">device_token</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">access_token</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kt">bool</span> <span class="na">enabled</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="kt">uint64</span> <span class="na">version</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">allowed_key_list</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">blocked_chat_list</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="kt">bool</span> <span class="na">unregister</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">grant</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="kt">bool</span> <span class="na">allow_from_contacts_only</span> <span class="o">=</span> <span class="mi">11</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">apn_topic</span> <span class="o">=</span> <span class="mi">12</span><span class="p">;</span>
<span class="kt">bool</span> <span class="na">block_mentions</span> <span class="o">=</span> <span class="mi">13</span><span class="p">;</span>
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">allowed_mentions_chat_list</span> <span class="o">=</span> <span class="mi">14</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>A push notification server will handle the message according to the following rules:</p>
<ul>
<li>it MUST extract the public key of the sender from the signature and verify that
the payload can be decrypted successfully.</li>
<li>it MUST verify that <code class="language-plaintext highlighter-rouge">token_type</code> is supported</li>
<li>it MUST verify that <code class="language-plaintext highlighter-rouge">device_token</code> is non empty</li>
<li>it MUST verify that <code class="language-plaintext highlighter-rouge">installation_id</code> is non empty</li>
<li>it MUST verify that <code class="language-plaintext highlighter-rouge">version</code> is non-zero and greater than the currently stored version for the public key and installation id of the sender, if any</li>
<li>it MUST verify that <code class="language-plaintext highlighter-rouge">grant</code> is non empty and according to the <a href="#server-grant">specs</a></li>
<li>it MUST verify that <code class="language-plaintext highlighter-rouge">access_token</code> is a valid <a href="https://tools.ietf.org/html/rfc4122"><code class="language-plaintext highlighter-rouge">uuid</code></a></li>
<li>it MUST verify that <code class="language-plaintext highlighter-rouge">apn_topic</code> is set if <code class="language-plaintext highlighter-rouge">token_type</code> is <code class="language-plaintext highlighter-rouge">APN_TOKEN</code></li>
</ul>
<p>If the message cant be decrypted, the message MUST be discarded.</p>
<p>If <code class="language-plaintext highlighter-rouge">token_type</code> is not supported, a response MUST be sent with <code class="language-plaintext highlighter-rouge">error</code> set to
<code class="language-plaintext highlighter-rouge">UNSUPPORTED_TOKEN_TYPE</code>.</p>
<p>If <code class="language-plaintext highlighter-rouge">token</code>,<code class="language-plaintext highlighter-rouge">installation_id</code>,<code class="language-plaintext highlighter-rouge">device_tokens</code>,<code class="language-plaintext highlighter-rouge">version</code> are empty, a response MUST
be sent with <code class="language-plaintext highlighter-rouge">error</code> set to <code class="language-plaintext highlighter-rouge">MALFORMED_MESSAGE</code>.</p>
<p>If the <code class="language-plaintext highlighter-rouge">version</code> is equal or less than the currently stored version, a response MUST
be sent with <code class="language-plaintext highlighter-rouge">error</code> set to <code class="language-plaintext highlighter-rouge">VERSION_MISMATCH</code>.</p>
<p>If any other error occurs the <code class="language-plaintext highlighter-rouge">error</code> should be set to <code class="language-plaintext highlighter-rouge">INTERNAL_ERROR</code>.</p>
<p>If the response is successful <code class="language-plaintext highlighter-rouge">success</code> MUST be set to <code class="language-plaintext highlighter-rouge">true</code> otherwise a response MUST be sent with <code class="language-plaintext highlighter-rouge">success</code> set to <code class="language-plaintext highlighter-rouge">false</code>.</p>
<p><code class="language-plaintext highlighter-rouge">request_id</code> should be set to the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the encrypted payload.</p>
<p>The response MUST be sent on the [partitioned topic][./10-waku-usage.md#partitioned-topic] of the sender
and MUST not be encrypted using the <a href="../docs/stable/5-secure-transport.md">secure transport</a> to facilitate
the usage of ephemeral keys.</p>
<p>The payload of the response is:</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationRegistrationResponse</span> <span class="p">{</span>
<span class="kt">bool</span> <span class="na">success</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">ErrorType</span> <span class="na">error</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">request_id</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kd">enum</span> <span class="n">ErrorType</span> <span class="p">{</span>
<span class="na">UNKNOWN_ERROR_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">MALFORMED_MESSAGE</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="na">VERSION_MISMATCH</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="na">UNSUPPORTED_TOKEN_TYPE</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="na">INTERNAL_ERROR</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_REGISTRATION_RESPONSE</code>.</p>
<p>A client SHOULD listen for a response sent on the [partitioned topic][./10-waku-usage.md#partitioned-topic]
that the key used to register.</p>
<p>If <code class="language-plaintext highlighter-rouge">success</code> is <code class="language-plaintext highlighter-rouge">true</code> the client has registered successfully.</p>
<p>If <code class="language-plaintext highlighter-rouge">success</code> is <code class="language-plaintext highlighter-rouge">false</code>:</p>
<ul>
<li>If <code class="language-plaintext highlighter-rouge">MALFORMED_MESSAGE</code> is returned, the request SHOULD NOT be retried without ensuring
that it is correctly formed.</li>
<li>If <code class="language-plaintext highlighter-rouge">INTERNAL_ERROR</code> is returned, the request MAY be retried, but the client MUST
backoff exponentially</li>
</ul>
<p>A client MAY register with multiple Push Notification Servers in order to increase availability.</p>
<p>A client SHOULD make sure that all the notification services they registered with have the same information about their tokens.</p>
<p>If no response is returned the request SHOULD be considered failed and MAY be retried with the same server or a different one, but clients MUST exponentially backoff after each trial.</p>
<p>If the request is successful the token SHOULD be <a href="#advertising-a-push-notification-server">advertised</a> as described below</p>
<h3 id="query-topic">Query topic</h3>
<p>On successful registration the server MUST be listening to the topic derived from:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> 0XHexEncode(Shake256(CompressedClientPublicKey))
</code></pre></div></div>
<p>Using the topic derivation algorithm described <a href="../stable/10-waku-usage.md#public-chats">here</a>
and listen for client queries.</p>
<h3 id="server-grant">Server grant</h3>
<p>A push notification server needs to demonstrate to a client that it was authorized
by the client to send them push notifications. This is done by building
a grant which is specific to a given client-server pair.
The grant is built as follow:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Signature(Keccak256(CompressedPublicKeyOfClient . CompressedPublicKeyOfServer . AccessToken), PrivateKeyOfClient)
</code></pre></div></div>
<p>When receiving a grant the server MUST be validate that the signature matches the registering client.</p>
<h2 id="re-registering-with-the-push-notification-server">Re-registering with the push notification server</h2>
<p>A client SHOULD re-register with the node if the APN or FIREBASE token changes.</p>
<p>When re-registering a client SHOULD ensure that it has the most up-to-date
<code class="language-plaintext highlighter-rouge">PushNotificationRegistration</code> and increment <code class="language-plaintext highlighter-rouge">version</code> if necessary.</p>
<p>Once re-registered, a client SHOULD advertise the changes.</p>
<h2 id="changing-options">Changing options</h2>
<p>This is handled in exactly the same way as re-registering above.</p>
<h2 id="unregistering-from-push-notifications">Unregistering from push notifications</h2>
<p>To unregister a client MUST send a <code class="language-plaintext highlighter-rouge">PushNotificationRegistration</code> request as described
above with <code class="language-plaintext highlighter-rouge">unregister</code> set to <code class="language-plaintext highlighter-rouge">true</code>, or removing
their device information.</p>
<p>The server MUST remove all data about this user if <code class="language-plaintext highlighter-rouge">unregistering</code> is <code class="language-plaintext highlighter-rouge">true</code>,
apart from the <code class="language-plaintext highlighter-rouge">hash</code> of the public key and the <code class="language-plaintext highlighter-rouge">version</code> of the last options,
in order to make sure that old messages are not processed.</p>
<p>A client MAY unregister from a server on explicit logout if multiple chat keys
are used on a single device.</p>
<h2 id="advertising-a-push-notification-server">Advertising a push notification server</h2>
<p>Each user registered with one or more push notification servers SHOULD
advertise periodically the push notification services that they have registered with for each device they own.</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationQueryInfo</span> <span class="p">{</span>
<span class="kt">string</span> <span class="na">access_token</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">public_key</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">allowed_user_list</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">grant</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="kt">uint64</span> <span class="na">version</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">server_public_key</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">message</span> <span class="nc">ContactCodeAdvertisement</span> <span class="p">{</span>
<span class="k">repeated</span> <span class="n">PushNotificationQueryInfo</span> <span class="na">push_notification_info</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_QUERY_INFO</code>.</p>
<p>If no filtering is done based on public keys,
the access token SHOULD be included in the advertisement.
Otherwise it SHOULD be left empty.</p>
<p>This SHOULD be advertised on the <a href="./10-waku-usage.md#contact-code-topic">contact code topic</a>
and SHOULD be coupled with normal contact-code advertisement.</p>
<p>Every time a user register or re-register with a push notification service, their
contact-code SHOULD be re-advertised.</p>
<p>Multiple servers MAY be advertised for the same <code class="language-plaintext highlighter-rouge">installation_id</code> for redundancy reasons.</p>
<h2 id="discovering-a-push-notification-server">Discovering a push notification server</h2>
<p>To discover a push notification service for a given user, their <a href="./10-waku-usage.md#contact-code-topic">contact code topic</a>
SHOULD be listened to.
A mailserver can be queried for the specific topic to retrieve the most up-to-date
contact code.</p>
<h2 id="querying-the-push-notification-server">Querying the push notification server</h2>
<p>If a token is not present in the latest advertisement for a user, the server
SHOULD be queried directly.</p>
<p>To query a server a message:</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationQuery</span> <span class="p">{</span>
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">public_keys</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_QUERY</code>.</p>
<p>MUST be sent to the server on the topic derived from the hashed public key of the
key we are querying, as <a href="#query-topic">described above</a>.</p>
<p>An ephemeral key SHOULD be used and SHOULD NOT be encrypted using the <a href="../docs/stable/5-secure-transport.md">secure transport</a>.</p>
<p>If the server has information about the client a response MUST be sent:</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationQueryInfo</span> <span class="p">{</span>
<span class="kt">string</span> <span class="na">access_token</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">public_key</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">allowed_user_list</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">grant</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="kt">uint64</span> <span class="na">version</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">server_public_key</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">message</span> <span class="nc">PushNotificationQueryResponse</span> <span class="p">{</span>
<span class="k">repeated</span> <span class="n">PushNotificationQueryInfo</span> <span class="na">info</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">message_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">bool</span> <span class="na">success</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>A <code class="language-plaintext highlighter-rouge">PushNotificationQueryResponse</code> message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_QUERY_RESPONSE</code>.</p>
<p>Otherwise a response MUST NOT be sent.</p>
<p>If <code class="language-plaintext highlighter-rouge">allowed_key_list</code> is not set <code class="language-plaintext highlighter-rouge">access_token</code> MUST be set and <code class="language-plaintext highlighter-rouge">allowed_key_list</code> MUST NOT
be set.</p>
<p>If <code class="language-plaintext highlighter-rouge">allowed_key_list</code> is set <code class="language-plaintext highlighter-rouge">allowed_key_list</code> MUST be set and <code class="language-plaintext highlighter-rouge">access_token</code> MUST NOT be set.</p>
<p>If <code class="language-plaintext highlighter-rouge">access_token</code> is returned, the <code class="language-plaintext highlighter-rouge">access_token</code> SHOULD be used to send push notifications.</p>
<p>If <code class="language-plaintext highlighter-rouge">allowed_key_list</code> are returned, the client SHOULD decrypt each
token by generating an <code class="language-plaintext highlighter-rouge">AES-GCM</code> symmetric key from the DiffieHellman between the
target client and itself
If AES decryption succeeds it will return a valid <a href="https://tools.ietf.org/html/rfc4122"><code class="language-plaintext highlighter-rouge">uuid</code></a> which is what is used for access_token.
The token SHOULD be used to send push notifications.</p>
<p>The response MUST be sent on the [partitioned topic][./10-waku-usage.md#partitioned-topic] of the sender
and MUST not be encrypted using the <a href="../docs/stable/5-secure-transport.md">secure transport</a> to facilitate
the usage of ephemeral keys.</p>
<p>On receiving a response a client MUST verify <code class="language-plaintext highlighter-rouge">grant</code> to ensure that the server
has been authorized to send push notification to a given client.</p>
<h2 id="sending-a-push-notification">Sending a push notification</h2>
<p>When sending a push notification, only the <code class="language-plaintext highlighter-rouge">installation_id</code> for the devices targeted
by the message SHOULD be used.</p>
<p>If a message is for all the user devices, all the <code class="language-plaintext highlighter-rouge">installation_id</code> known to the client MAY be used.</p>
<p>The number of devices MAY be capped in order to reduce resource consumption.</p>
<p>At least 3 devices SHOULD be targeted, ordered by last activity.</p>
<p>For any device that a token is available, or that a token is successfully queried,
a push notification message SHOULD be sent to the corresponding push notification server.</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotification</span> <span class="p">{</span>
<span class="kt">string</span> <span class="na">access_token</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">chat_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">public_key</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="kd">message</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="n">PushNotificationType</span> <span class="na">type</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="kd">enum</span> <span class="n">PushNotificationType</span> <span class="p">{</span>
<span class="na">UNKNOWN_PUSH_NOTIFICATION_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">MESSAGE</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="na">MENTION</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">bytes</span> <span class="na">author</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">message</span> <span class="nc">PushNotificationRequest</span> <span class="p">{</span>
<span class="k">repeated</span> <span class="n">PushNotification</span> <span class="na">requests</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">message_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>A <code class="language-plaintext highlighter-rouge">PushNotificationRequest</code> message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_REQUEST</code>.</p>
<p>Where <code class="language-plaintext highlighter-rouge">message</code> is the encrypted payload of the message and <code class="language-plaintext highlighter-rouge">chat_id</code> is the
<code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the <code class="language-plaintext highlighter-rouge">chat_id</code>.
<code class="language-plaintext highlighter-rouge">message_id</code> is the id of the message
<code class="language-plaintext highlighter-rouge">author</code> is the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the public key of the sender.</p>
<p>If multiple server are available for a given push notification, only one notification
MUST be sent.</p>
<p>If no response is received
a client SHOULD wait at least 3 seconds, after which the request MAY be retried against a different server</p>
<p>This message SHOULD be sent using an ephemeral key.</p>
<p>On receiving the message, the push notification server MUST validate the access token.
If the access token is valid, a notification MUST be sent to the gorush instance with the
following data:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
"notifications": [
{
"tokens": ["token_a", "token_b"],
"platform": 1,
"message": "You have a new message",
"data": {
"chat_id": chat_id,
"message": message,
"installation_ids": [installation_id_1, installation_id_2]
}
}
]
}
</code></pre></div></div>
<p>Where platform is <code class="language-plaintext highlighter-rouge">1</code> for IOS and <code class="language-plaintext highlighter-rouge">2</code> for Firebase, according to the <a href="https://github.com/appleboy/gorush">gorush
documentation</a></p>
<p>A server MUST return a response message:</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PushNotificationReport</span> <span class="p">{</span>
<span class="kt">bool</span> <span class="na">success</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">ErrorType</span> <span class="na">error</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kd">enum</span> <span class="n">ErrorType</span> <span class="p">{</span>
<span class="na">UNKNOWN_ERROR_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">WRONG_TOKEN</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="na">INTERNAL_ERROR</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="na">NOT_REGISTERED</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">bytes</span> <span class="na">public_key</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">message</span> <span class="nc">PushNotificationResponse</span> <span class="p">{</span>
<span class="kt">bytes</span> <span class="na">message_id</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">repeated</span> <span class="n">PushNotificationReport</span> <span class="na">reports</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>A <code class="language-plaintext highlighter-rouge">PushNotificationResponse</code> message MUST be wrapped in a <a href="../stable/6-payloads.6#payload-wrapper"><code class="language-plaintext highlighter-rouge">ApplicationMetadataMessage</code></a> with type set to <code class="language-plaintext highlighter-rouge">PUSH_NOTIFICATION_RESPONSE</code>.</p>
<p>Where <code class="language-plaintext highlighter-rouge">message_id</code> is the <code class="language-plaintext highlighter-rouge">message_id</code> sent by the client.</p>
<p>The response MUST be sent on the [partitioned topic][./10-waku-usage.md#partitioned-topic] of the sender
and MUST not be encrypted using the <a href="../docs/stable/5-secure-transport.md">secure transport</a> to facilitate
the usage of ephemeral keys.</p>
<p>If the request is accepted <code class="language-plaintext highlighter-rouge">success</code> MUST be set to <code class="language-plaintext highlighter-rouge">true</code>.
Otherwise <code class="language-plaintext highlighter-rouge">success</code> MUST be set to <code class="language-plaintext highlighter-rouge">false</code>.</p>
<p>If <code class="language-plaintext highlighter-rouge">error</code> is <code class="language-plaintext highlighter-rouge">BAD_TOKEN</code> the client MAY query again the server for the token and
retry the request.</p>
<p>If <code class="language-plaintext highlighter-rouge">error</code> is <code class="language-plaintext highlighter-rouge">INTERNAL_ERROR</code> the client MAY retry the request.</p>
<h2 id="flow">Flow</h2>
<h3 id="registration-process">Registration process</h3>
<ul>
<li>A client will generate a notification token through <code class="language-plaintext highlighter-rouge">APN</code> or <code class="language-plaintext highlighter-rouge">Firebase</code>.</li>
<li>The client will <a href="#registering-with-the-push-notification-service">register</a> with one or more push notification server of their choosing.</li>
<li>The server should process the response and respond according to the success of the operation</li>
<li>If the request is not successful it might be retried, and adjusted according to the response. A different server can be also used.</li>
<li>Once the request is successful the client should <a href="#advertising-a-push-notification-server">advertise</a> the new coordinates</li>
</ul>
<h3 id="sending-a-notification">Sending a notification</h3>
<ul>
<li>A client should prepare a message and extract the targeted installation-ids</li>
<li>It should retrieve the most up to date information for a given user, either by
querying a push notification server, a mailserver if not listening already to the given topic, or checking
the database locally</li>
<li>It should then <a href="#sending-a-push-notification">send</a> a push notification according
to the rules described</li>
<li>The server should then send a request to the gorush server including all the required
information</li>
</ul>
<h3 id="receiving-a-push-notification">Receiving a push notification</h3>
<ul>
<li>On receiving the notification, a client can open the right account by checking the
<code class="language-plaintext highlighter-rouge">installation_id</code> included. The <code class="language-plaintext highlighter-rouge">chat_id</code> MAY be used to open the chat if present.</li>
<li><code class="language-plaintext highlighter-rouge">message</code> can be decrypted and presented to the user. Otherwise messages can be pulled from the mailserver if the <code class="language-plaintext highlighter-rouge">message_id</code> is no already present.</li>
</ul>
<h2 id="protobuf-description">Protobuf description</h2>
<h3 id="pushnotificationregistration">PushNotificationRegistration</h3>
<p><code class="language-plaintext highlighter-rouge">token_type</code>: the type of token. Currently supported is <code class="language-plaintext highlighter-rouge">APN_TOKEN</code> for Apple Push
<code class="language-plaintext highlighter-rouge">device_token</code>: the actual push notification token sent by <code class="language-plaintext highlighter-rouge">Firebase</code> or <code class="language-plaintext highlighter-rouge">APN</code>
and <code class="language-plaintext highlighter-rouge">FIREBASE_TOKEN</code> for firebase.
<code class="language-plaintext highlighter-rouge">installation_id</code>: the <a href="./2-account.md"><code class="language-plaintext highlighter-rouge">installation_id</code></a> of the device
<code class="language-plaintext highlighter-rouge">access_token</code>: the access token that will be given to clients to send push notifications
<code class="language-plaintext highlighter-rouge">enabled</code>: whether the device wants to be sent push notifications
<code class="language-plaintext highlighter-rouge">version</code>: a monotonically increasing number identifying the current <code class="language-plaintext highlighter-rouge">PushNotificationRegistration</code>. Any time anything is changed in the record it MUST be increased by the client, otherwise the request will not be accepted.
<code class="language-plaintext highlighter-rouge">allowed_key_list</code>: a list of <code class="language-plaintext highlighter-rouge">access_token</code> encrypted with the AES key generated
by DiffieHellman between the publisher and the allowed
contact.
<code class="language-plaintext highlighter-rouge">blocked_chat_list</code>: a list of <code class="language-plaintext highlighter-rouge">SHA2-256</code> hashes of chat ids.
Any chat id in this list will not trigger a notification.
<code class="language-plaintext highlighter-rouge">unregister</code>: whether the account should be unregistered
<code class="language-plaintext highlighter-rouge">grant</code>: the grant for this specific server
<code class="language-plaintext highlighter-rouge">allow_from_contacts_only</code>: whether the client only wants push notifications from contacts
<code class="language-plaintext highlighter-rouge">apn_topic</code>: the APN topic for the push notification
<code class="language-plaintext highlighter-rouge">block_mentions</code>: whether the client does not want to be notified on mentions
<code class="language-plaintext highlighter-rouge">allowed_mentions_chat_list</code>: a list of <code class="language-plaintext highlighter-rouge">SHA2-256</code> hashes of chat ids where we want to receive mentions</p>
<h4 id="data-disclosed">Data disclosed</h4>
<ul>
<li>Type of device owned by a given user</li>
<li>The <code class="language-plaintext highlighter-rouge">FIREBASE</code> or <code class="language-plaintext highlighter-rouge">APN</code> push notification token</li>
<li>Hash of the chat_id a user is not interested in for notifications</li>
<li>The times a push notification record has been modified by the user</li>
<li>The number of contacts a client has, in case <code class="language-plaintext highlighter-rouge">allowed_key_list</code> is set</li>
</ul>
<h3 id="pushnotificationregistrationresponse">PushNotificationRegistrationResponse</h3>
<p><code class="language-plaintext highlighter-rouge">success</code>: whether the registration was successful
<code class="language-plaintext highlighter-rouge">error</code>: the error type, if any
<code class="language-plaintext highlighter-rouge">request_id</code>: the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> hash of the <code class="language-plaintext highlighter-rouge">signature</code> of the request
<code class="language-plaintext highlighter-rouge">preferences</code>: the server stored preferences in case of an error</p>
<h3 id="contactcodeadvertisement">ContactCodeAdvertisement</h3>
<p><code class="language-plaintext highlighter-rouge">push_notification_info</code>: the information for each device advertised</p>
<h4 id="data-disclosed-1">Data disclosed</h4>
<ul>
<li>The chat key of the sender</li>
</ul>
<h3 id="pushnotificationquery">PushNotificationQuery</h3>
<p><code class="language-plaintext highlighter-rouge">public_keys</code>: the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the public keys the client is interested in</p>
<h4 id="data-disclosed-2">Data disclosed</h4>
<ul>
<li>The hash of the public keys the client is interested in</li>
</ul>
<h3 id="pushnotificationqueryinfo">PushNotificationQueryInfo</h3>
<p><code class="language-plaintext highlighter-rouge">access_token</code>: the access token used to send a push notification
<code class="language-plaintext highlighter-rouge">installation_id</code>: the <code class="language-plaintext highlighter-rouge">installation_id</code> of the device associated with the <code class="language-plaintext highlighter-rouge">access_token</code>
<code class="language-plaintext highlighter-rouge">public_key</code>: the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the public key associated with this <code class="language-plaintext highlighter-rouge">access_token</code> and <code class="language-plaintext highlighter-rouge">installation_id</code>
<code class="language-plaintext highlighter-rouge">allowed_key_list</code>: a list of encrypted access tokens to be returned
to the client in case theres any filtering on public keys in place.
<code class="language-plaintext highlighter-rouge">grant</code>: the grant used to register with this server.
<code class="language-plaintext highlighter-rouge">version</code>: the version of the registration on the server.
<code class="language-plaintext highlighter-rouge">server_public_key</code>: the compressed public key of the server.</p>
<h3 id="pushnotificationqueryresponse">PushNotificationQueryResponse</h3>
<p><code class="language-plaintext highlighter-rouge">info</code>: a list of <code class="language-plaintext highlighter-rouge">PushNotificationQueryInfo</code>.
<code class="language-plaintext highlighter-rouge">message_id</code>: the message id of the <code class="language-plaintext highlighter-rouge">PushNotificationQueryInfo</code> the server is replying to.
<code class="language-plaintext highlighter-rouge">success</code>: whether the query was successful.</p>
<h3 id="pushnotification">PushNotification</h3>
<p><code class="language-plaintext highlighter-rouge">access_token</code>: the access token used to send a push notification.
<code class="language-plaintext highlighter-rouge">chat_id</code>: the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the <code class="language-plaintext highlighter-rouge">chat_id</code>.
<code class="language-plaintext highlighter-rouge">public_key</code>: the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the compressed public key of the receiving client.
<code class="language-plaintext highlighter-rouge">installation_id</code>: the installation id of the receiving client.
<code class="language-plaintext highlighter-rouge">message</code>: the encrypted message that is being notified on.
<code class="language-plaintext highlighter-rouge">type</code>: the type of the push notification, either <code class="language-plaintext highlighter-rouge">MESSAGE</code> or <code class="language-plaintext highlighter-rouge">MENTION</code>
<code class="language-plaintext highlighter-rouge">author</code>: the <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the public key of the sender</p>
<h3 id="data-disclosed-3">Data disclosed</h3>
<ul>
<li>The <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the <code class="language-plaintext highlighter-rouge">chat_id</code> the notification is to be sent for</li>
<li>The cypher text of the message</li>
<li>The <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the public key of the sender</li>
<li>The type of notification</li>
</ul>
<h3 id="pushnotificationrequest">PushNotificationRequest</h3>
<p><code class="language-plaintext highlighter-rouge">requests</code>: a list of <code class="language-plaintext highlighter-rouge">PushNotification</code>
<code class="language-plaintext highlighter-rouge">message_id</code>: the <a href="./6-payloads.md">status message id</a></p>
<h3 id="data-disclosed-4">Data disclosed</h3>
<ul>
<li>The status message id for which the notification is for</li>
</ul>
<h3 id="pushnotificationresponse">PushNotificationResponse</h3>
<p><code class="language-plaintext highlighter-rouge">message_id</code>: the <code class="language-plaintext highlighter-rouge">message_id</code> being notified on.
<code class="language-plaintext highlighter-rouge">reports</code>: a list of <code class="language-plaintext highlighter-rouge">PushNotificationReport</code></p>
<h3 id="pushnotificationreport">PushNotificationReport</h3>
<p><code class="language-plaintext highlighter-rouge">success</code>: whether the push notification was successful.
<code class="language-plaintext highlighter-rouge">error</code>: the type of the error in case of failure.
<code class="language-plaintext highlighter-rouge">public_key</code>: the public key of the user being notified.
<code class="language-plaintext highlighter-rouge">installation_id</code>: the installation id of the user being notified.</p>
<h2 id="anonymous-mode-of-operations">Anonymous mode of operations</h2>
<p>An anonymous mode of operations MAY be provided by the client, where the
responsibility of propagating information about the user is left to the client,
in order to preserve privacy.</p>
<p>A client in anonymous mode can register with the server using a key different
from their chat key.
This will hide their real chat key.</p>
<p>This public key is effectively a secret and SHOULD only be disclosed to clients that you the user wants to be notified by.</p>
<p>A client MAY advertise the access token on the contact-code topic of the key generated.
A client MAY share their public key through <a href="./6-payloads.md#contact-update">contact updates</a></p>
<p>A client receiving a push notification public key SHOULD listen to the contact code
topic of the push notification public key for updates.</p>
<p>The method described above effectively does not share the identity of the sender
nor the receiver to the server, but MAY result in missing push notifications as
the propagation of the secret is left to the client.</p>
<p>This can be mitigated by <a href="./6-payloads.md">device syncing</a>, but not completely
addressed.</p>
<h2 id="security-considerations">Security considerations</h2>
<p>If no anonymous mode is used, when registering with a push notification service a client discloses:</p>
<ul>
<li>The chat key</li>
<li>The devices that will receive notifications</li>
</ul>
<p>A client MAY disclose:</p>
<ul>
<li>The hash of the chat_ids they want to filter out</li>
</ul>
<p>When running in anonymous mode, the clients chat key is not disclosed.</p>
<p>When querying a push notification server a client will disclose:</p>
<ul>
<li>That it is interested in sending push notification to another client,
but the querying clients chat key is not disclosed</li>
</ul>
<p>When sending a push notification a client discloses:</p>
<ul>
<li>The <code class="language-plaintext highlighter-rouge">SHAKE-256</code> of the chat id</li>
</ul>
<p>review process. Point can be integrated, suggestion welcome.</p>
<h2 id="faq">FAQ</h2>
<h3 id="why-having-acl-done-at-the-server-side-and-not-the-client">Why having ACL done at the server side and not the client?</h3>
<p>We looked into silent notification for
<a href="https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app">IOS</a> (android has no equivalent)
but cant be used as its expected to receive maximum 2/3 per hour, so not our use case. There
are also issue when the user force quit the app.</p>
<h3 id="why-using-an-access-token">Why using an access token?</h3>
<p>The access token is used to decouple the requesting information from the user from
actually sending the push notification.</p>
<p>Some ACL is necessary otherwise it would be too easy to spam users (its still fairly
trivial, but with this method you could allow only contacts to send you push notifications).</p>
<p>Therefore your identity must be revealed to the server either when sending or querying.</p>
<p>By using an access token we increase deniability, as the server would know
who requested the token but not necessarily who sent a push notification.
Correlation between the two can be trivial in some cases.</p>
<p>This also allows a mode of use as we had before, where the server does not propagate
info at all, and its left to the user to propagate the token, through contact requests
for example.</p>
<h3 id="why-advertise-with-the-bundle">Why advertise with the bundle?</h3>
<p>Advertising with the bundle allows us to piggy-back on an already implemented behavior
and save some bandwidth in cases where is not filtering by public keys</p>
<h3 id="whats-the--bandwidth-impact-for-this">Whats the bandwidth impact for this?</h3>
<p>Generally speaking, for each 1-to-1 message and group chat message you will sending
1 and <code class="language-plaintext highlighter-rouge">number of participants</code> push notifications. This can be optimized if
multiple users are using the same push notification server. Queries have also
a bandwidth impact but they are made only when actually needed</p>
<h3 id="whats-the-information-disclosed">Whats the information disclosed?</h3>
<p>The data disclosed with each message sent by the client is above, but for a summary:</p>
<p>When you register with a push notification service you may disclose:</p>
<p>1) Your chat key
2) Which devices you have
3) The hash of the chat_ids you want to filter out
4) The hash of the public keys you are interested/not interested in</p>
<p>When you query a notification service you may disclose:</p>
<p>1) Your chat key
2) The fact that you are interested in sending push notification to a given user</p>
<p>Effectively this is fairly revealing if the user has a whitelist implemented.
Therefore sending notification should be optional.</p>
<h3 id="what-prevents-a-user-from-generating-a-random-key-and-getting-an-access-token-and-spamming">What prevents a user from generating a random key and getting an access token and spamming?</h3>
<p>Nothing really, thats the same as the status app as a whole. the only mechanism that prevents
this is using a white-list as described above, but that implies disclosing your true identity to the push notification server.</p>
<h3 id="why-not-0-knowledge-proofsquantum-computing">Why not 0-knowledge proofs/quantum computing</h3>
<p>We start simple, we can iterate</p>
<h3 id="how-to-handle-backwardforward-compatibility">How to handle backward/forward compatibility</h3>
<p>Most of the request have a target, so protocol negotiation can happen. We cannot negotiated
the advertisement as thats effectively a broadcast, but those info should not change and we can
always accrete the message.</p>
<h3 id="why-ack_key">Why ack_key?</h3>
<p>Thats necessary to avoid duplicated push notifications and allow for the retry
in case the notification is not successful.</p>
<p>Deduplication of the push notification is done on the client side, to reduce a bit
of centralization and also in order not to have to modify gorush.</p>
<h3 id="can-i-run-my-own-node">Can I run my own node?</h3>
<p>Sure, the methods allow that</p>
<h3 id="can-i-register-with-multiple-nodes-for-redundancy">Can I register with multiple nodes for redundancy</h3>
<p>Yep</p>
<h3 id="what-does-my-node-disclose">What does my node disclose?</h3>
<p>Your node will disclose the IP address is running from, as it makes an HTTP post to
gorush. A waku adapter could be used, but please not now.</p>
<h3 id="does-this-have-high-reliability-requirements">Does this have high-reliability requirements?</h3>
<p>The gorush server yes, no way around it.</p>
<p>The rest, kind of, at least one node having your token needs to be up for you to receive notifications.
But you can register with multiple servers (desktop, status, etc) if thats a concern.</p>
<h3 id="can-someone-else-ie-not-status-run-this">Can someone else (i.e not status) run this?</h3>
<p>Push notification servers can be run by anyone. Gorush can be run by anyone I take,
but we are in charge of the certificate, so they would not be able to notify status-clients.</p>
<h2 id="changelog">Changelog</h2>
<h3 id="version-01">Version 0.1</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/"></a></p>
<ul>
<li>Initial version</li>
</ul>
<h2 id="copyright">Copyright</h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>

View File

@ -1,547 +0,0 @@
<h1 id="2account">2/ACCOUNT</h1>
<blockquote>
<p>Version: 0.4</p>
<p>Status: Stable</p>
<p>Authors: 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>, Samuel Hawksby-Robinson <a href="mailto:samuel@status.im">samuel@status.im</a> (alphabetical order)</p>
</blockquote>
<h2 id="abstract">Abstract</h2>
<p>This specification explains what Status account is, and how a node establishes trust.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#table-of-contents">Table of Contents</a></li>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#initial-key-generation">Initial Key Generation</a>
<ul>
<li><a href="#publicprivate-keypairs">Public/Private Keypairs</a></li>
<li><a href="#x3dh-prekey-bundle-creation">X3DH Prekey bundle creation</a></li>
</ul>
</li>
<li><a href="#account-broadcasting">Account Broadcasting</a>
<ul>
<li><a href="#x3dh-prekey-bundles">X3DH Prekey bundles</a></li>
</ul>
</li>
<li><a href="#optional-account-additions">Optional Account additions</a>
<ul>
<li><a href="#ens-username">ENS Username</a></li>
</ul>
</li>
<li><a href="#trust-establishment">Trust establishment</a>
<ul>
<li><a href="#terms-glossary">Terms Glossary</a></li>
<li><a href="#contact-discovery">Contact Discovery</a>
<ul>
<li><a href="#public-channels">Public channels</a></li>
<li><a href="#private-11-messages">Private 1:1 messages</a></li>
</ul>
</li>
<li><a href="#initial-key-exchange">Initial Key Exchange</a>
<ul>
<li><a href="#bundles">Bundles</a></li>
</ul>
</li>
<li><a href="#contact-verification">Contact Verification</a>
<ul>
<li><a href="#identicon">Identicon</a></li>
<li><a href="#3-word-pseudonym--whisperwaku-key-fingerprint">3 word pseudonym / Whisper/Waku key fingerprint</a></li>
<li><a href="#ens-name">ENS name</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#public-key-serialization">Public Key Serialization</a>
<ul>
<li><a href="#basic-serialization-example">Basic Serialization Example</a></li>
<li><a href="#public-key-compression-rationale">Public Key “Compression” Rationale</a></li>
<li><a href="#key-encoding">Key Encoding</a></li>
<li><a href="#public-key-types">Public Key Types</a></li>
<li><a href="#deserialization-process-flow">De/Serialization Process Flow</a>
<ul>
<li><a href="#serialization-example">Serialization Example</a></li>
<li><a href="#deserialization-example">Deserialization Example</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#security-considerations">Security Considerations</a></li>
<li><a href="#changelog">Changelog</a>
<ul>
<li><a href="#version-03">Version 0.3</a></li>
</ul>
</li>
</ul>
<!-- markdown-toc end -->
<h2 id="introduction">Introduction</h2>
<p>The core concept of an account in Status is a set of cryptographic keypairs. Namely, the combination of the following:</p>
<ol>
<li>a Whisper/Waku chat identity keypair</li>
<li>a set of cryptocurrency wallet keypairs</li>
</ol>
<p>The node verifies or derives everything else associated with the contact from the above items, including:</p>
<ul>
<li>Ethereum address (future verification, currently the same base keypair)</li>
<li>3 word mnemonic name</li>
<li>identicon</li>
<li>message signatures</li>
</ul>
<h2 id="initial-key-generation">Initial Key Generation</h2>
<h3 id="publicprivate-keypairs">Public/Private Keypairs</h3>
<ul>
<li>An ECDSA (secp256k1 curve) public/private keypair MUST be generated via a <a href="https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki">BIP43</a> derived path from a <a href="https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki">BIP39</a> mnemonic seed phrase.</li>
<li>The default paths are defined as such:
<ul>
<li>Whisper/Waku Chat Key (<code class="language-plaintext highlighter-rouge">IK</code>): <code class="language-plaintext highlighter-rouge">m/43'/60'/1581'/0'/0</code> (post Multiaccount integration)
<ul>
<li>following <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md">EIP1581</a>
<!-- WE CURRENTLY DO NOT IMPLEMENT ENCRYPTION KEY, FOR FUTURE - C.P. -->
<!-- - DB encryption Key (`DBK`): `m/43'/60'/1581'/1'/0` (post Multiaccount integration) -->
<!-- - following [EIP1581](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1581.md) --></li>
</ul>
</li>
<li>Status Wallet paths: <code class="language-plaintext highlighter-rouge">m/44'/60'/0'/0/i</code> starting at <code class="language-plaintext highlighter-rouge">i=0</code>
<ul>
<li>following <a href="https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki">BIP44</a></li>
<li>NOTE: this (<code class="language-plaintext highlighter-rouge">i=0</code>) is also the current (and only) path for Whisper/Waku key before Multiaccount integration</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="x3dh-prekey-bundle-creation">X3DH Prekey bundle creation</h3>
<ul>
<li>Status follows the X3DH prekey bundle scheme that <a href="https://en.wikipedia.org/wiki/Signal_Messenger#2013%E2%80%932018:_Open_Whisper_Systems">Open Whisper Systems</a> (not to be confused with the Whisper sub-protocol) outlines <a href="https://signal.org/docs/specifications/x3dh/#the-x3dh-protocol">in their documentation</a> with the following exceptions:
<ul>
<li>Status does not publish one-time keys <code class="language-plaintext highlighter-rouge">OPK</code> or perform DH including them, because there are no central servers in the Status implementation.</li>
</ul>
</li>
<li>A client MUST create X3DH prekey bundles, each defined by the following items:
<ul>
<li>Identity Key: <code class="language-plaintext highlighter-rouge">IK</code></li>
<li>Signed prekey: <code class="language-plaintext highlighter-rouge">SPK</code></li>
<li>Prekey signature: <code class="language-plaintext highlighter-rouge">Sig(IK, Encode(SPK))</code></li>
<li>Timestamp</li>
</ul>
</li>
<li>These bundles are made available in a variety of ways, as defined in section 2.1.</li>
</ul>
<h2 id="account-broadcasting">Account Broadcasting</h2>
<ul>
<li>A user is responsible for broadcasting certain information publicly so that others may contact them.</li>
</ul>
<h3 id="x3dh-prekey-bundles">X3DH Prekey bundles</h3>
<ul>
<li>A client SHOULD regenerate a new X3DH prekey bundle every 24 hours. This MAY be done in a lazy way, such that a client that does not come online past this time period does not regenerate or broadcast bundles.</li>
<li>The current bundle SHOULD be broadcast on a Whisper/Waku topic specific to his Identity Key, <code class="language-plaintext highlighter-rouge">{IK}-contact-code</code>, intermittently. This MAY be done every 6 hours.</li>
<li>A bundle SHOULD accompany every message sent.</li>
<li>TODO: retrieval of long-time offline users bundle via <code class="language-plaintext highlighter-rouge">{IK}-contact-code</code></li>
</ul>
<h2 id="optional-account-additions">Optional Account additions</h2>
<h3 id="ens-username">ENS Username</h3>
<ul>
<li>A user MAY register a public username on the Ethereum Name System (ENS). This username is a user-chosen subdomain of the <code class="language-plaintext highlighter-rouge">stateofus.eth</code> ENS registration that maps to their Whisper/Waku identity key (<code class="language-plaintext highlighter-rouge">IK</code>).</li>
</ul>
<!-- ### User Profile Picture
- An account MAY edit the `IK` generated identicon with a chosen picture. This picture will become part of the publicly broadcast profile of the account. -->
<!-- TODO: Elaborate on wallet account and multiaccount -->
<!-- TODO: Elaborate on security implications -->
<h2 id="trust-establishment">Trust establishment</h2>
<p><strong>Trust establishment deals with users verifying they are communicating with who they think they are.</strong></p>
<h3 id="terms-glossary">Terms Glossary</h3>
<table>
<thead>
<tr>
<th>term</th>
<th>description</th>
</tr>
</thead>
<tbody>
<tr>
<td>privkey</td>
<td>ECDSA secp256k1 private key</td>
</tr>
<tr>
<td>pubkey</td>
<td>ECDSA secp256k1 public key</td>
</tr>
<tr>
<td>Whisper/Waku key</td>
<td>pubkey for chat with HD derivation path m/43/60/1581/0/0</td>
</tr>
</tbody>
</table>
<h3 id="contact-discovery">Contact Discovery</h3>
<h4 id="public-channels">Public channels</h4>
<ul>
<li>Public group channels in Status are a broadcast/subscription system. All public messages are encrypted with a symmetric key derived from the channel name, <code class="language-plaintext highlighter-rouge">K_{pub,sym}</code>, which is publicly known.</li>
<li>A public group channels symmetric key MUST creation must follow the <a href="https://web3js.readthedocs.io/en/1.0/web3-shh.html#generatesymkeyfrompassword">web3 API</a>s <code class="language-plaintext highlighter-rouge">web3.ssh.generateSymKeyFromPassword</code> function</li>
<li>In order to post to a public group channel, a client MUST have a valid account created.</li>
<li>In order to listen to a public group channel, a client must subscribe to the channel name. The sender of a message is derived from the messages signature.</li>
<li>Discovery of channel names is not currently part of the protocol, and is typically done out of band. If a channel name is used that has not been used, it will be created.</li>
<li>A client MUST sign the message otherwise it will be discarded by the recipients.</li>
<li>channel name specification:
<ul>
<li>matches <code class="language-plaintext highlighter-rouge">[a-z0-9\-]</code></li>
<li>is not a public key</li>
</ul>
</li>
</ul>
<h4 id="private-11-messages">Private 1:1 messages</h4>
<p>This can be done in the following ways:</p>
<ol>
<li>scanning a user generated QR code</li>
<li>discovery through the Status app</li>
<li>asynchronous X3DH key exchange</li>
<li>public key via public channel listening
<ul>
<li><code class="language-plaintext highlighter-rouge">status-react/src/status_im/contact_code/core.cljs</code></li>
</ul>
</li>
<li>contact codes</li>
<li>decentralized storage (not implemented)</li>
<li>Whisper/Waku</li>
</ol>
<h3 id="initial-key-exchange">Initial Key Exchange</h3>
<h4 id="bundles">Bundles</h4>
<ul>
<li>An X3DH prekey bundle is defined as (<a href="https://github.com/status-im/status-go/messaging/chat/protobuf/encryption.pb.go">code</a>):
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Identity // Identity key
SignedPreKeys // a map of installation id to array of signed prekeys by that installation id
Signature // Prekey signature
Timestamp // When the bundle was lasted created locally
</code></pre></div> </div>
<ul>
<li>include BundleContainer</li>
</ul>
</li>
<li>a new bundle SHOULD be created at least every 12 hours</li>
<li>a node only generates a bundle when it is used</li>
<li>a bundle SHOULD be distributed on the contact code channel. This is the Whisper and Waku topic <code class="language-plaintext highlighter-rouge">{IK}-contact-code</code>, where <code class="language-plaintext highlighter-rouge">IK</code> is the hex encoded public key of the user, prefixed with <code class="language-plaintext highlighter-rouge">0x</code>. The node encrypts the channel in the same way it encrypted public chats.</li>
</ul>
<h3 id="contact-verification">Contact Verification</h3>
<p>To verify that contact key information is as it should be, use the following.</p>
<h4 id="identicon">Identicon</h4>
<p>A low-poly identicon is deterministically generated from the Whisper/Waku chat public key. This can be compared out of band to ensure the receivers public key is the one stored locally.</p>
<h4 id="3-word-pseudonym--whisperwaku-key-fingerprint">3 word pseudonym / Whisper/Waku key fingerprint</h4>
<p>Status generates a deterministic 3-word random pseudonym from the Whisper/Waku chat public key. This pseudonym acts as a human readable fingerprint to the Whisper/Waku chat public key. This name also shows when viewing a contacts public profile and in the chat UI.</p>
<ul>
<li>implementation: <a href="https://github.com/status-im/status-react/tree/develop/src/status_im/utils/gfycat">gfycat</a></li>
</ul>
<h4 id="ens-name">ENS name</h4>
<p>Status offers the ability to register a mapping of a human readable subdomain of <code class="language-plaintext highlighter-rouge">stateofus.eth</code> to their Whisper/Waku chat public key. The user purchases this registration (currently by staking 10 SNT) and the node stores it on the Ethereum mainnet blockchain for public lookup.</p>
<!-- TODO: Elaborate on security implications -->
<!-- TODO: Incorporate or cut below into proper spec
### Possible Connection Breakdown
possible connections
- client - client (not really ever, this is facilitated through all other connections)
- personal chat
- ratcheted with X3DH
- private group chat
- pairwise ratcheted with X3DH
- public chat
- client - mailserver (statusd + ???)
- a mailserver identifies itself by an [enode address](https://github.com/ethereum/wiki/wiki/enode-url-format)
- client - Whisper/Waku node (statusd)
- a node identifies itself by an enode address
- client - bootnode (go-ethereum)
- a bootnode identifies itself by
- an enode address
- `NOTE: redezvous information here`
- client - ENS registry (ethereum blockchain -> default to infura)
- client - Ethereum RPC (custom go-ethereum RPC API -> default to infura API)
- client - IPFS (Status hosted IPFS gateway -> defaults to ???)
- we have a status hosted IPFS gateway for pinning but it currently isn't used much.
### Notes
A user in the system is a public-private key pair using the Elliptic-Curve Cryptography secp256k1 that Ethereum uses.
- A 3-word random name is derived from the public key using the following package
- `NOTE: need to find package`
- This provides an associated human-readble fingerprint to the user's public key
- A user can optionally add additional layers on top of this keypair
- Chosen username
- ENS username
All messages sent are encrypted with the public key of the destination and signed by the private key of the given user using the following scheme:
- private chat
- X3DH is used to define shared secrets which is then double ratcheted
- private group chat
- considered pairwise private chats
- public group chat
- the message is encrypted with a symmetric key derived from the chat name
-->
<h2 id="public-key-serialization">Public Key Serialization</h2>
<p>Idiomatically known as “public key compression” and “public key decompression”.</p>
<p>The node SHOULD provide functionality for the serialization and deserialization of public / chat keys.</p>
<p>For maximum flexibility, when implementing this functionality, the node MUST support public keys encoded in a range of encoding formats, detailed below.</p>
<h3 id="basic-serialization-example">Basic Serialization Example</h3>
<p>In the example of a typical hexadecimal encoded elliptical curve (EC) public key (such as a secp256k1 pk),</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x04261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc3cd4e22200c68daf7493e1f8da6a190a68a671e2d3977809612424c7c3888bc6
</code></pre></div></div>
<p>minor modification for compatibility and flexibility makes the key self-identifiable and easily parsable,</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fe70104261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc3cd4e22200c68daf7493e1f8da6a190a68a671e2d3977809612424c7c3888bc6
</code></pre></div></div>
<p>EC serialization and compact encoding produces a much smaller string representation of the original key.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zQ3shPyZJnxZK4Bwyx9QsaksNKDYTPmpwPvGSjMYVHoXHeEgB
</code></pre></div></div>
<h3 id="public-key-compression-rationale">Public Key “Compression” Rationale</h3>
<p>Serialized and compactly encoded (“compressed”) public keys have a number of UI / UX advantages over non-serialized less densely encoded public keys.</p>
<p>Compressed public keys are smaller, and users may perceive them as less intimidating and less unnecessarily large. Compare the “compressed” and “uncompressed” version of the same public key from above example:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">0xe70104261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc3cd4e22200c68daf7493e1f8da6a190a68a671e2d3977809612424c7c3888bc6</code></li>
<li><code class="language-plaintext highlighter-rouge">zQ3shPyZJnxZK4Bwyx9QsaksNKDYTPmpwPvGSjMYVHoXHeEgB</code></li>
</ul>
<p>The user can transmit and share the same data, but at one third of the original size. 136 characters uncompressed vs 49 characters compressed, giving a significant character length reduction of 64%.</p>
<p>The user client app MAY use the compressed public keys throughout the user interface. For example in the <code class="language-plaintext highlighter-rouge">status-react</code> implementation of the user interface the following places could take advantage of a significantly smaller public key:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Onboarding</code> &gt; <code class="language-plaintext highlighter-rouge">Choose a chat name</code></li>
<li><code class="language-plaintext highlighter-rouge">Profile</code> &gt; <code class="language-plaintext highlighter-rouge">Header</code></li>
<li><code class="language-plaintext highlighter-rouge">Profile</code> &gt; <code class="language-plaintext highlighter-rouge">Share icon</code> &gt; <code class="language-plaintext highlighter-rouge">QR code popover</code></li>
<li><code class="language-plaintext highlighter-rouge">Invite friends</code> url from <code class="language-plaintext highlighter-rouge">Invite friends</code> button and <code class="language-plaintext highlighter-rouge">+ -button</code> &gt; <code class="language-plaintext highlighter-rouge">Invite friends</code></li>
<li>Other user <code class="language-plaintext highlighter-rouge">Profile details</code></li>
<li><code class="language-plaintext highlighter-rouge">Profile details</code> &gt; <code class="language-plaintext highlighter-rouge">Share icon</code> &gt; <code class="language-plaintext highlighter-rouge">QR code popover</code></li>
</ul>
<p>In the case of QR codes a compressed public key can reduce the complexity of the derived codes:</p>
<table>
<thead>
<tr>
<th>Uncompressed</th>
<th>Compressed</th>
</tr>
</thead>
<tbody>
<tr>
<td><img src="https://user-images.githubusercontent.com/5702426/80531063-e98fcc80-8991-11ea-8c02-c354b5828d35.png" width="400" /></td>
<td><img src="https://user-images.githubusercontent.com/5702426/80501933-f4356c00-8967-11ea-87d8-eae18becece9.png" width="400" /></td>
</tr>
</tbody>
</table>
<h3 id="key-encoding">Key Encoding</h3>
<p>When implementing the pk de/serialization functionality, the node MUST use the <a href="https://github.com/multiformats/multibase">multiformats/multibase</a> encoding protocol to interpret incoming key data and to return key data in a desired encoding.</p>
<p>The node SHOULD support the following <code class="language-plaintext highlighter-rouge">multibase</code> encoding formats.</p>
<pre><code class="language-csv">encoding, code, description, status
identity, 0x00, 8-bit binary (encoder and decoder keeps data unmodified), default
base2, 0, binary (01010101), candidate
base8, 7, octal, draft
base10, 9, decimal, draft
base16, f, hexadecimal, default
base16upper, F, hexadecimal, default
base32hex, v, rfc4648 case-insensitive - no padding - highest char, candidate
base32hexupper, V, rfc4648 case-insensitive - no padding - highest char, candidate
base32hexpad, t, rfc4648 case-insensitive - with padding, candidate
base32hexpadupper, T, rfc4648 case-insensitive - with padding, candidate
base32, b, rfc4648 case-insensitive - no padding, default
base32upper, B, rfc4648 case-insensitive - no padding, default
base32pad, c, rfc4648 case-insensitive - with padding, candidate
base32padupper, C, rfc4648 case-insensitive - with padding, candidate
base32z, h, z-base-32 (used by Tahoe-LAFS), draft
base36, k, base36 [0-9a-z] case-insensitive - no padding, draft
base36upper, K, base36 [0-9a-z] case-insensitive - no padding, draft
base58btc, z, base58 bitcoin, default
base58flickr, Z, base58 flicker, candidate
base64, m, rfc4648 no padding, default
base64pad, M, rfc4648 with padding - MIME encoding, candidate
base64url, u, rfc4648 no padding, default
base64urlpad, U, rfc4648 with padding, default
</code></pre>
<p><strong>Note</strong> this specification RECOMMENDs that implementations extend the standard <code class="language-plaintext highlighter-rouge">multibase</code> protocol to parse strings prepended with <code class="language-plaintext highlighter-rouge">0x</code> as <code class="language-plaintext highlighter-rouge">f</code> hexadecimal encoded bytes.</p>
<p>Implementing this recommendation will allow the node to correctly interpret traditionally identified hexadecimal strings (e.g. <code class="language-plaintext highlighter-rouge">0x1337c0de</code>).</p>
<p><em>Example:</em></p>
<p><code class="language-plaintext highlighter-rouge">0xe70102261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc</code></p>
<p>SHOULD be interpreted as</p>
<p><code class="language-plaintext highlighter-rouge">fe70102261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc</code></p>
<p>This specification RECOMMENDs that the consuming service of the node uses a compact encoding type, such as base64 or base58 to allow for as short representations of the key as possible.</p>
<h3 id="public-key-types">Public Key Types</h3>
<p>When implementing the pk de/serialization functionality, The node MUST support the <a href="https://github.com/multiformats/multicodec">multiformats/multicodec</a> key type identifiers for the following public key type.</p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Tag</th>
<th>Code</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code class="language-plaintext highlighter-rouge">secp256k1-pub</code></td>
<td>key</td>
<td><code class="language-plaintext highlighter-rouge">0xe7</code></td>
<td>Secp256k1 public key</td>
</tr>
</tbody>
</table>
<p>For a public key to be identifiable to the node the public key data MUST be prepended with the relevant <a href="https://github.com/multiformats/unsigned-varint">multiformats/unsigned-varint</a> formatted code.</p>
<p><em>Example:</em></p>
<p>Below is a representation of an deserialized secp256k1 public key.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>04
26 | 1c | 55 | 67 | 5e | 55 | ff | 25
ed | b5 | 0b | 34 | 5c | fb | 3a | 3f
35 | f6 | 07 | 12 | d2 | 51 | cb | aa
ab | 97 | bd | 50 | 05 | 4c | 6e | bc
3c | d4 | e2 | 22 | 00 | c6 | 8d | af
74 | 93 | e1 | f8 | da | 6a | 19 | 0a
68 | a6 | 71 | e2 | d3 | 97 | 78 | 09
61 | 24 | 24 | c7 | c3 | 88 | 8b | c6
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">multicodec</code> code for a secp256k1 public key is <code class="language-plaintext highlighter-rouge">0xe7</code>.</p>
<p>After parsing the code <code class="language-plaintext highlighter-rouge">0xe7</code> as a <code class="language-plaintext highlighter-rouge">multiformats/uvarint</code>, the byte value is <code class="language-plaintext highlighter-rouge">0xe7 0x01</code>, prepending this to the public key results in the below representation.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>e7 | 01 | 04
26 | 1c | 55 | 67 | 5e | 55 | ff | 25
ed | b5 | 0b | 34 | 5c | fb | 3a | 3f
35 | f6 | 07 | 12 | d2 | 51 | cb | aa
ab | 97 | bd | 50 | 05 | 4c | 6e | bc
3c | d4 | e2 | 22 | 00 | c6 | 8d | af
74 | 93 | e1 | f8 | da | 6a | 19 | 0a
68 | a6 | 71 | e2 | d3 | 97 | 78 | 09
61 | 24 | 24 | c7 | c3 | 88 | 8b | c6
</code></pre></div></div>
<h3 id="deserialization-process-flow">De/Serialization Process Flow</h3>
<p>When implementing the pk de/serialization functionality, the node MUST be passed a <code class="language-plaintext highlighter-rouge">multicodec</code> identified public key, of the above supported types, encoded with a valid <code class="language-plaintext highlighter-rouge">multibase</code> identifier.</p>
<p>This specification RECOMMENDs that the node also accept an encoding type parameter to encode the output data. This provides for the case where the user requires the de/serialization key to be in a different encoding to the encoding of the given key.</p>
<h4 id="serialization-example">Serialization Example</h4>
<p>A hexadecimal encoded secp256k1 public chat key typically is represented as below:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x04261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc3cd4e22200c68daf7493e1f8da6a190a68a671e2d3977809612424c7c3888bc6
</code></pre></div></div>
<p>To be properly interpreted by the node for serialization the public key MUST be prepended with the <code class="language-plaintext highlighter-rouge">multicodec</code> <code class="language-plaintext highlighter-rouge">uvarint</code> code <code class="language-plaintext highlighter-rouge">0xea 0x01</code> and encoded with a valid <code class="language-plaintext highlighter-rouge">multibase</code> encoding, therefore giving the following:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>fea0104261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc3cd4e22200c68daf7493e1f8da6a190a68a671e2d3977809612424c7c3888bc6
</code></pre></div></div>
<p>If adhering to the specification recommendation to provide the user with an output encoding parameter, the above string would be passed to the node with the following <code class="language-plaintext highlighter-rouge">multibase</code> encoding identifier.</p>
<p>In this example the output encoding is defined as <code class="language-plaintext highlighter-rouge">base58 bitcoin</code>.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>z
</code></pre></div></div>
<p>The return value in this case would be</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zQ3shPyZJnxZK4Bwyx9QsaksNKDYTPmpwPvGSjMYVHoXHeEgB
</code></pre></div></div>
<p>Which after <code class="language-plaintext highlighter-rouge">multibase</code> decoding can be represented in bytes as below:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>e7 | 01 | 02
26 | 1c | 55 | 67 | 5e | 55 | ff | 25
ed | b5 | 0b | 34 | 5c | fb | 3a | 3f
35 | f6 | 07 | 12 | d2 | 51 | cb | aa
ab | 97 | bd | 50 | 05 | 4c | 6e | bc
</code></pre></div></div>
<h4 id="deserialization-example">Deserialization Example</h4>
<p>For the user, the deserialization process is exactly the same as serialization with the exception that the user MUST provide a serialized public key for deserialization. Else the deserialization algorithm will fail.</p>
<p>For further guidance on the implementation of public key de/serialization consult the <a href="https://github.com/status-im/status-go/blob/c9772325f2dca76b3504191c53313663ca2efbe5/api/utils_test.go"><code class="language-plaintext highlighter-rouge">status-go</code> implementation and tests</a>.</p>
<h2 id="security-considerations">Security Considerations</h2>
<p>-</p>
<h2 id="changelog">Changelog</h2>
<h3 id="version-04">Version 0.4</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/e98a9b76b7d4e1ce93e0b692e1521c2d54f72c59">June 24, 2020</a></p>
<ul>
<li>Added details of public key serialization and deserialization</li>
</ul>
<h3 id="version-03">Version 0.3</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/664dd1c9df6ad409e4c007fefc8c8945b8d324e8">May 22, 2020</a></p>
<ul>
<li>Added language to include Waku in all relevant places</li>
<li>Change to keep <code class="language-plaintext highlighter-rouge">Mailserver</code> term consistent</li>
<li>Added clarification to Open Whisper Systems</li>
</ul>

View File

@ -1,433 +0,0 @@
<h1 id="3whisper-usage">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">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">Reason</h2>
<p>Provide routing, metadata protection, topic-based multicasting and basic
encryption properties to support asynchronous chat.</p>
<h2 id="terminology">Terminology</h2>
<ul>
<li><em>Whisper node</em>: an Ethereum node with Whisper V6 enabled (in the case of geth, its <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">Whisper packets</h2>
<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>
<h2 id="whisper-node-configuration">Whisper node configuration</h2>
<p>A Whisper node must be properly configured to receive messages from Status clients.</p>
<p>Whispers 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-react/releases/tag/untagged-079a6d98babfeaa3f8c0">Status app version <code class="language-plaintext highlighter-rouge">1.3</code></a> and below</li>
</ul>
<h2 id="handshake">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 wont 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">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 nodes 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 peers rate limits. If the limit gets exceeded, the connection MAY be dropped by the peer.</p>
<h2 id="keys-management">Keys management</h2>
<p>The protocol requires a key (symmetric or asymmetric) for the following actions:</p>
<ul>
<li>signing &amp; verifying messages (asymmetric key)</li>
<li>encrypting &amp; 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">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">&lt;</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">&lt;</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">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">&lt;</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">&lt;</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">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">&lt;</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">&lt;</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">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">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">&lt;</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">&lt;</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">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 clients <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 clients <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> &amp; <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">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">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">Whisper V6 extensions</h2>
<h3 id="request-historic-messages">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 its 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>Its 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">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>: Mailservers 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">Changelog</h2>
<h3 id="03">0.3</h3>
<ul>
<li>Updated minimum PoW to <code class="language-plaintext highlighter-rouge">0.00001</code>
<h3 id="02">0.2</h3>
</li>
<li>Document created</li>
</ul>
<h2 id="copyright">Copyright</h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>

View File

@ -1,130 +0,0 @@
<h1 id="4whisper-mailserver">4/WHISPER-MAILSERVER</h1>
<blockquote>
<p>Version: 0.3</p>
<p>Status: Stable</p>
<p>Authors: Adam Babik <a href="mailto:adam@status.im">adam@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="#mailserver"><code class="language-plaintext highlighter-rouge">Mailserver</code></a>
<ul>
<li><a href="#archiving-messages">Archiving messages</a></li>
<li><a href="#requesting-messages">Requesting messages</a></li>
<li><a href="#receiving-historic-messages">Receiving historic messages</a></li>
</ul>
</li>
<li><a href="#security-considerations">Security considerations</a>
<ul>
<li><a href="#confidentiality">Confidentiality</a></li>
<li><a href="#altruistic-and-centralized-operator-risk">Altruistic and centralized operator risk</a></li>
<li><a href="#privacy-concerns">Privacy concerns</a></li>
<li><a href="#denial-of-service">Denial-of-service</a></li>
</ul>
</li>
<li><a href="#changelog">Changelog</a>
<ul>
<li><a href="#version-03">Version 0.3</a></li>
</ul>
</li>
</ul>
<h2 id="abstract">Abstract</h2>
<p>Being mostly offline is an intrinsic property of mobile clients. They need to save network transfer and battery consumption to avoid spending too much money or constant charging. Whisper protocol, on the other hand, is an online protocol. Messages are available in the Whisper network only for short period of time calculate in seconds.</p>
<p>Whisper <code class="language-plaintext highlighter-rouge">Mailserver</code> is a Whisper extension that allows to store messages permanently and deliver them to the clients even though they are already not available in the network and expired.</p>
<h2 id="mailserver"><code class="language-plaintext highlighter-rouge">Mailserver</code></h2>
<p>From the network perspective, <code class="language-plaintext highlighter-rouge">Mailserver</code> is just like any other Whisper node. The only difference is that it has a capability of archiving messages and delivering them to its peers on-demand.</p>
<p>It is important to notice that <code class="language-plaintext highlighter-rouge">Mailserver</code> will only handle requests from its direct peers and exchanged packets between <code class="language-plaintext highlighter-rouge">Mailserver</code> and a peer are p2p messages.</p>
<h3 id="archiving-messages">Archiving messages</h3>
<p>A node which wants to provide <code class="language-plaintext highlighter-rouge">Mailserver</code> functionality MUST store envelopes from incoming message packets (Whisper packet-code <code class="language-plaintext highlighter-rouge">0x01</code>). The envelopes can be stored in any format, however they MUST be serialized and deserialized to the Whisper envelope format.</p>
<p>A <code class="language-plaintext highlighter-rouge">Mailserver</code> SHOULD store envelopes for all topics to be generally useful for any peer, however for specific use cases it MAY store envelopes for a subset of topics.</p>
<h3 id="requesting-messages">Requesting messages</h3>
<p>In order to request historic messages, a node MUST send a packet P2P Request (<code class="language-plaintext highlighter-rouge">0x7e</code>) to a peer providing <code class="language-plaintext highlighter-rouge">Mailserver</code> functionality. This packet requires one argument which MUST be a Whisper envelope.</p>
<p>In the Whisper envelopes payload section, there MUST be RLP-encoded information about the details of the request:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ Lower, Upper, Bloom, Limit, Cursor ]
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">Lower</code>: 4-byte wide unsigned integer (UNIX time in seconds; oldest requested envelopes creation time)<br />
<code class="language-plaintext highlighter-rouge">Upper</code>: 4-byte wide unsigned integer (UNIX time in seconds; newest requested envelopes creation time)<br />
<code class="language-plaintext highlighter-rouge">Bloom</code>: 64-byte wide array of Whisper topics encoded in a bloom filter to filter envelopes<br />
<code class="language-plaintext highlighter-rouge">Limit</code>: 4-byte wide unsigned integer limiting the number of returned envelopes<br />
<code class="language-plaintext highlighter-rouge">Cursor</code>: an array of a cursor returned from the previous request (optional)</p>
<p>The <code class="language-plaintext highlighter-rouge">Cursor</code> field SHOULD be filled in if a number of envelopes between <code class="language-plaintext highlighter-rouge">Lower</code> and <code class="language-plaintext highlighter-rouge">Upper</code> is greater than <code class="language-plaintext highlighter-rouge">Limit</code> so that the requester can send another request using the obtained <code class="language-plaintext highlighter-rouge">Cursor</code> value. What exactly is in the <code class="language-plaintext highlighter-rouge">Cursor</code> is up to the implementation. The requester SHOULD NOT use a <code class="language-plaintext highlighter-rouge">Cursor</code> obtained from one <code class="language-plaintext highlighter-rouge">Mailserver</code> in a request to another <code class="language-plaintext highlighter-rouge">Mailserver</code> because the format or the result MAY be different.</p>
<p>The envelope MUST be encrypted with a symmetric key agreed between the requester and <code class="language-plaintext highlighter-rouge">Mailserver</code>.</p>
<h3 id="receiving-historic-messages">Receiving historic messages</h3>
<p>Historic messages MUST be sent to a peer as a packet with a P2P Message code (<code class="language-plaintext highlighter-rouge">0x7f</code>) followed by an array of Whisper envelopes. It is incompatible with the original Whisper spec (EIP-627) because it allows only a single envelope, however, an array of envelopes is much more performant. In order to stay compatible with EIP-627, a peer receiving historic message MUST handle both cases.</p>
<p>In order to receive historic messages from a <code class="language-plaintext highlighter-rouge">Mailserver</code>, a node MUST trust the selected <code class="language-plaintext highlighter-rouge">Mailserver</code>, that is allowed to send packets with the P2P Message code. By default, the node discards such packets.</p>
<p>Received envelopes MUST be passed through the Whisper envelope pipelines so that they are picked up by registered filters and passed to subscribers.</p>
<p>For a requester, to know that all messages have been sent by <code class="language-plaintext highlighter-rouge">Mailserver</code>, it SHOULD handle P2P Request Complete code (<code class="language-plaintext highlighter-rouge">0x7d</code>). This code is followed by the following parameters:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[ RequestID, LastEnvelopeHash, Cursor ]
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">RequestID</code>: 32-byte wide array with a Keccak-256 hash of the envelope containing the original request<br />
<code class="language-plaintext highlighter-rouge">LastEnvelopeHash</code>: 32-byte wide array with a Keccak-256 hash of the last sent envelope for the request<br />
<code class="language-plaintext highlighter-rouge">Cursor</code>: an array of a cursor returned from the previous request (optional)</p>
<p>If <code class="language-plaintext highlighter-rouge">Cursor</code> is not empty, it means that not all messages were sent due to the set <code class="language-plaintext highlighter-rouge">Limit</code> in the request. One or more consecutive requests MAY be sent with <code class="language-plaintext highlighter-rouge">Cursor</code> field filled in order to receive the rest of the messages.</p>
<h2 id="security-considerations">Security considerations</h2>
<h3 id="confidentiality">Confidentiality</h3>
<p>The node encrypts all Whisper envelopes. A <code class="language-plaintext highlighter-rouge">Mailserver</code> node can not inspect their contents.</p>
<h3 id="altruistic-and-centralized-operator-risk">Altruistic and centralized operator risk</h3>
<p>In order to be useful, a <code class="language-plaintext highlighter-rouge">Mailserver</code> SHOULD be online most of the time. That means
users either have to be a bit tech-savvy to run their own node, or rely on someone
else to run it for them.</p>
<p>Currently, one of Statuss legal entities provides <code class="language-plaintext highlighter-rouge">Mailservers</code> in an altruistic manner, but this is
suboptimal from a decentralization, continuance and risk point of view. Coming
up with a better system for this is ongoing research.</p>
<p>A Status client SHOULD allow the <code class="language-plaintext highlighter-rouge">Mailserver</code> selection to be customizable.</p>
<h3 id="privacy-concerns">Privacy concerns</h3>
<p>In order to use a <code class="language-plaintext highlighter-rouge">Mailserver</code>, a given node needs to connect to it directly,
i.e. add the <code class="language-plaintext highlighter-rouge">Mailserver</code> as its peer and mark it as trusted. This means that the
<code class="language-plaintext highlighter-rouge">Mailserver</code> is able to send direct p2p messages to the node instead of
broadcasting them. Effectively, it will have access to the bloom filter of
topics that the user is interested in, when it is online as well as many
metadata like IP address.</p>
<h3 id="denial-of-service">Denial-of-service</h3>
<p>Since a <code class="language-plaintext highlighter-rouge">Mailserver</code> is delivering expired envelopes and has a direct TCP connection with the recipient, the recipient is vulnerable to DoS attacks from a malicious <code class="language-plaintext highlighter-rouge">Mailserver</code> node.</p>
<h2 id="changelog">Changelog</h2>
<h3 id="version-03">Version 0.3</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/664dd1c9df6ad409e4c007fefc8c8945b8d324e8">May 22, 2020</a></p>
<ul>
<li>Change to keep <code class="language-plaintext highlighter-rouge">Mailserver</code> term consistent</li>
</ul>

View File

@ -1,599 +0,0 @@
<h1 id="5secure-transport">5/SECURE-TRANSPORT</h1>
<blockquote>
<p>Version: 0.3</p>
<p>Status: Stable</p>
<p>Authors: Andrea Piana <a href="mailto:andreap@status.im">andreap@status.im</a>, Pedro Pombeiro <a href="mailto:pedro@status.im">pedro@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>, Dean Eigenmann <a href="mailto:dean@status.im">dean@status.im</a></p>
</blockquote>
<h2 id="abstract">Abstract</h2>
<p>This document describes how Status provides a secure channel between two peers, and thus provide confidentiality, integrity, authenticity and forward secrecy. It is transport-agnostic and works over asynchronous networks.</p>
<p>It builds on the <a href="https://signal.org/docs/specifications/x3dh/">X3DH</a> and <a href="https://signal.org/docs/specifications/doubleratchet/">Double Ratchet</a> specifications, with some adaptations to operate in a decentralized environment.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#table-of-contents">Table of Contents</a></li>
<li><a href="#introduction">Introduction</a>
<ul>
<li><a href="#definitions">Definitions</a></li>
<li><a href="#design-requirements">Design Requirements</a></li>
<li><a href="#conventions">Conventions</a></li>
<li><a href="#transport-layer">Transport Layer</a></li>
<li><a href="#user-flow-for-1-to-1-communications">User flow for 1-to-1 communications</a>
<ul>
<li><a href="#account-generation">Account generation</a></li>
<li><a href="#account-recovery">Account recovery</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#messaging">Messaging</a>
<ul>
<li><a href="#end-to-end-encryption">End-to-end encryption</a></li>
<li><a href="#prekeys">Prekeys</a></li>
<li><a href="#bundle-retrieval">Bundle retrieval</a></li>
<li><a href="#11-chat-contact-request">1:1 chat contact request</a>
<ul>
<li><a href="#initial-key-exchange-flow-x3dh">Initial key exchange flow (X3DH)</a></li>
<li><a href="#double-ratchet">Double Ratchet</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#security-considerations">Security Considerations</a></li>
<li><a href="#session-management">Session management</a>
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#initialization">Initialization</a></li>
<li><a href="#concurrent-sessions">Concurrent sessions</a></li>
<li><a href="#re-keying">Re-keying</a></li>
<li><a href="#multi-device-support">Multi-device support</a></li>
<li><a href="#pairing">Pairing</a></li>
<li><a href="#sending-messages-to-a-paired-group">Sending messages to a paired group</a></li>
<li><a href="#account-recovery">Account recovery</a></li>
<li><a href="#partitioned-devices">Partitioned devices</a></li>
</ul>
</li>
<li><a href="#changelog">Changelog</a>
<ul>
<li><a href="#version-03">Version 0.3</a></li>
</ul>
</li>
</ul>
<h2 id="introduction">Introduction</h2>
<p>This document describes how nodes establish a secure channel, and how various conversational security properties are achieved.</p>
<h3 id="definitions">Definitions</h3>
<ul>
<li>
<p><strong>Perfect Forward Secrecy</strong> is a feature of specific key-agreement protocols which provide assurances that session keys will not be compromised even if the private keys of the participants are compromised. Specifically, past messages cannot be decrypted by a third-party who manages to get a hold of a private key.</p>
</li>
<li>
<p><strong>Secret channel</strong> describes a communication channel where Double Ratchet algorithm is in use.</p>
</li>
</ul>
<h3 id="design-requirements">Design Requirements</h3>
<ul>
<li><strong>Confidentiality</strong>: The adversary should not be able to learn what data is being exchanged between two Status clients.</li>
<li><strong>Authenticity</strong>: The adversary should not be able to cause either endpoint of a Status 1:1 chat to accept data from any third party as though it came from the other endpoint.</li>
<li><strong>Forward Secrecy</strong>: The adversary should not be able to learn what data was exchanged between two Status clients if, at some later time, the adversary compromises one or both of the endpoint devices.</li>
<li><strong>Integrity</strong>: The adversary should not be able to cause either endpoint of a Status 1:1 chat to accept data that has been tampered with.</li>
</ul>
<p>All of these properties are ensured by the use of <a href="https://signal.org/docs/specifications/doubleratchet/">Signals Double Ratchet</a></p>
<h3 id="conventions">Conventions</h3>
<p>Types used in this specification are defined using <a href="https://developers.google.com/protocol-buffers/">Protobuf</a>.</p>
<h3 id="transport-layer">Transport Layer</h3>
<p><a href="3-whisper-usage.md">Whisper</a> and <a href="10-waku-usage.md">Waku</a> serves as the transport layers for the Status chat protocol.</p>
<h3 id="user-flow-for-1-to-1-communications">User flow for 1-to-1 communications</h3>
<h4 id="account-generation">Account generation</h4>
<p>See <a href="./2-account.md">Account specification</a></p>
<h4 id="account-recovery">Account recovery</h4>
<p>If Alice later recovers her account, the Double Ratchet state information will not be available, so she is no longer able to decrypt any messages received from existing contacts.</p>
<p>If an incoming message (on the same Whisper/Waku topic) fails to decrypt, the node replies a message with the current bundle, so that the node notifies the other end of the new device. Subsequent communications will use this new bundle.</p>
<h2 id="messaging">Messaging</h2>
<p>All 1:1 and group chat messaging in Status is subject to end-to-end encryption to provide users with a strong degree of privacy and security. Public chat messages are publicly readable by anyone since theres no permission model for who is participating in a public chat.</p>
<p>The rest of this document is purely about 1:1 and private group chat. Private group chat largely reduces to 1:1 chat, since theres a secure channel between each pair-wise participant.</p>
<h3 id="end-to-end-encryption">End-to-end encryption</h3>
<p>End-to-end encryption (E2EE) takes place between two clients. The main cryptographic protocol is a <a href="https://github.com/status-im/doubleratchet/">Status implementation</a> of the Double Ratchet protocol, which is in turn derived from the <a href="https://otr.cypherpunks.ca/Protocol-v3-4.1.1.html">Off-the-Record protocol</a>, using a different ratchet. The transport protocol subsequently encrypt the message payload - Whisper/Waku (see section <a href="#transport-layer">Transport Layer</a>) -, using symmetric key encryption.
Furthermore, Status uses the concept of prekeys (through the use of <a href="https://signal.org/docs/specifications/x3dh/">X3DH</a>) to allow the protocol to operate in an asynchronous environment. It is not necessary for two parties to be online at the same time to initiate an encrypted conversation.</p>
<p>Status uses the following cryptographic primitives:</p>
<ul>
<li>Whisper/Waku
<ul>
<li>AES-256-GCM</li>
<li>ECIES</li>
<li>ECDSA</li>
<li>KECCAK-256</li>
</ul>
</li>
<li>X3DH
<ul>
<li>Elliptic curve Diffie-Hellman key exchange (secp256k1)</li>
<li>KECCAK-256</li>
<li>ECDSA</li>
<li>ECIES</li>
</ul>
</li>
<li>Double Ratchet
<ul>
<li>HMAC-SHA-256 as MAC</li>
<li>Elliptic curve Diffie-Hellman key exchange (Curve25519)</li>
<li>AES-256-CTR with HMAC-SHA-256 and IV derived alongside an encryption key</li>
</ul>
<p>The node achieves key derivation using HKDF.</p>
</li>
</ul>
<h3 id="prekeys">Prekeys</h3>
<p>Every client initially generates some key material which is stored locally:</p>
<ul>
<li>Identity keypair based on secp256k1 - <code class="language-plaintext highlighter-rouge">IK</code></li>
<li>A signed prekey based on secp256k1 - <code class="language-plaintext highlighter-rouge">SPK</code></li>
<li>A prekey signature - <code class="language-plaintext highlighter-rouge">Sig(IK, Encode(SPK))</code></li>
</ul>
<p>More details can be found in the <code class="language-plaintext highlighter-rouge">X3DH Prekey bundle creation</code> section of <a href="https://specs.status.im/spec/2#x3dh-prekey-bundles">2/ACCOUNT</a>.</p>
<p>Prekey bundles can be extracted from any users messages, or found via searching for their specific topic, <code class="language-plaintext highlighter-rouge">{IK}-contact-code</code>.</p>
<p>TODO: See below on bundle retrieval, this seems like enhancement and parameter for recommendation</p>
<h3 id="bundle-retrieval">Bundle retrieval</h3>
<!-- TODO: Potentially move this completely over to [Trust Establishment](./status-account-spec.md) -->
<p>X3DH works by having client apps create and make available a bundle of prekeys (the X3DH bundle) that can later be requested by other interlocutors when they wish to start a conversation with a given user.</p>
<p>In the X3DH specification, nodes typically use a shared server to store bundles and allow other users to download them upon request. Given Status goal of decentralization, Status chat clients cannot rely on the same type of infrastructure and must achieve the same result using other means. By growing order of convenience and security, the considered approaches are:</p>
<ul>
<li>contact codes;</li>
<li>public and one-to-one chats;</li>
<li>QR codes;</li>
<li>ENS record;</li>
<li>Decentralized permanent storage (e.g. Swarm, IPFS).</li>
<li>Whisper/Waku</li>
</ul>
<!-- TODO: Comment, it isn't clear what we actually _do_. It seems as if this is exploring the problem space. From a protocol point of view, it might make sense to describe the interface, and then have a recommendation section later on that specifies what we do. See e.g. Signal's specs where they specify specifics later on. -->
<p>Currently, only public and one-to-one message exchanges and Whisper/Waku is used to exchange bundles.</p>
<p>Since bundles stored in QR codes or ENS records cannot be updated to delete already used keys, the approach taken is to rotate more frequently the bundle (once every 24 hours), which will be propagated by the app through the channel available.</p>
<h3 id="11-chat-contact-request">1:1 chat contact request</h3>
<p>There are two phases in the initial negotiation of a 1:1 chat:</p>
<ol>
<li><strong>Identity verification</strong> (e.g., face-to-face contact exchange through QR code, Identicon matching). A QR code serves two purposes simultaneously - identity verification and initial bundle retrieval;</li>
<li><strong>Asynchronous initial key exchange</strong>, using X3DH.</li>
</ol>
<p>For more information on account generation and trust establishment, see <a href="https://specs.status.im/spec/2">2/ACCOUNT</a></p>
<h4 id="initial-key-exchange-flow-x3dh">Initial key exchange flow (X3DH)</h4>
<p><a href="https://signal.org/docs/specifications/x3dh/#sending-the-initial-message">Section 3 of the X3DH protocol</a> describes the initial key exchange flow, with some additional context:</p>
<ul>
<li>The users identity keys <code class="language-plaintext highlighter-rouge">IK_A</code> and <code class="language-plaintext highlighter-rouge">IK_B</code> correspond to their respective Status chat public keys;</li>
<li>Since it is not possible to guarantee that a prekey will be used only once in a decentralized world, the one-time prekey <code class="language-plaintext highlighter-rouge">OPK_B</code> is not used in this scenario;</li>
<li>Nodes do not send Bundles to a centralized server, but instead served in a decentralized way as described in <a href="#bundle-retrieval">bundle retrieval</a>.</li>
</ul>
<p>Alice retrieves Bobs prekey bundle, however it is not specific to Alice. It contains:</p>
<p>(<a href="https://github.com/status-im/status-go/blob/a904d9325e76f18f54d59efc099b63293d3dcad3/services/shhext/chat/encryption.proto#L12">protobuf</a>)</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// X3DH prekey bundle</span>
<span class="kd">message</span> <span class="nc">Bundle</span> <span class="p">{</span>
<span class="kt">bytes</span> <span class="na">identity</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">map</span><span class="o">&lt;</span><span class="kt">string</span><span class="p">,</span><span class="n">SignedPreKey</span><span class="err">&gt;</span> <span class="na">signed_pre_keys</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">signature</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kt">int64</span> <span class="na">timestamp</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li><code class="language-plaintext highlighter-rouge">identity</code>: Identity key <code class="language-plaintext highlighter-rouge">IK_B</code></li>
<li><code class="language-plaintext highlighter-rouge">signed_pre_keys</code>: Signed prekey <code class="language-plaintext highlighter-rouge">SPK_B</code> for each device, indexed by <code class="language-plaintext highlighter-rouge">installation-id</code></li>
<li><code class="language-plaintext highlighter-rouge">signature</code>: Prekey signature <i>Sig(<code class="language-plaintext highlighter-rouge">IK_B</code>, Encode(<code class="language-plaintext highlighter-rouge">SPK_B</code>))</i></li>
<li><code class="language-plaintext highlighter-rouge">timestamp</code>: When the bundle was created locally</li>
</ul>
<p>(<a href="https://github.com/status-im/status-go/blob/a904d9325e76f18f54d59efc099b63293d3dcad3/services/shhext/chat/encryption.proto#L5">protobuf</a>)</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">SignedPreKey</span> <span class="p">{</span>
<span class="kt">bytes</span> <span class="na">signed_pre_key</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">uint32</span> <span class="na">version</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">signature</code> is generated by sorting <code class="language-plaintext highlighter-rouge">installation-id</code> in lexicographical order, and concatenating the <code class="language-plaintext highlighter-rouge">signed-pre-key</code> and <code class="language-plaintext highlighter-rouge">version</code>:</p>
<p><code class="language-plaintext highlighter-rouge">installation-id-1signed-pre-key1version1installation-id2signed-pre-key2-version-2</code></p>
<h4 id="double-ratchet">Double Ratchet</h4>
<p>Having established the initial shared secret <code class="language-plaintext highlighter-rouge">SK</code> through X3DH, it can be used to seed a Double Ratchet exchange between Alice and Bob.</p>
<p>Please refer to the <a href="https://signal.org/docs/specifications/doubleratchet/">Double Ratchet spec</a> for more details.</p>
<p>The initial message sent by Alice to Bob is sent as a top-level <code class="language-plaintext highlighter-rouge">ProtocolMessage</code> (<a href="https://github.com/status-im/status-go/blob/a904d9325e76f18f54d59efc099b63293d3dcad3/services/shhext/chat/encryption.proto#L65">protobuf</a>) containing a map of <code class="language-plaintext highlighter-rouge">DirectMessageProtocol</code> indexed by <code class="language-plaintext highlighter-rouge">installation-id</code> (<a href="https://github.com/status-im/status-go/blob/1ac9dd974415c3f6dee95145b6644aeadf02f02c/services/shhext/chat/encryption.proto#L56">protobuf</a>):</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">ProtocolMessage</span> <span class="p">{</span>
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="k">repeated</span> <span class="n">Bundle</span> <span class="na">bundles</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="c1">// One to one message, encrypted, indexed by installation_id</span>
<span class="n">map</span><span class="o">&lt;</span><span class="kt">string</span><span class="p">,</span><span class="n">DirectMessageProtocol</span><span class="err">&gt;</span> <span class="na">direct_message</span> <span class="o">=</span> <span class="mi">101</span><span class="p">;</span>
<span class="c1">// Public chats, not encrypted</span>
<span class="kt">bytes</span> <span class="na">public_message</span> <span class="o">=</span> <span class="mi">102</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li><code class="language-plaintext highlighter-rouge">bundles</code>: a sequence of bundles</li>
<li><code class="language-plaintext highlighter-rouge">installation_id</code>: the installation id of the sender</li>
<li><code class="language-plaintext highlighter-rouge">direct_message</code> is a map of <code class="language-plaintext highlighter-rouge">DirectMessageProtocol</code> indexed by <code class="language-plaintext highlighter-rouge">installation-id</code></li>
<li><code class="language-plaintext highlighter-rouge">public_message</code>: unencrypted public chat message.</li>
</ul>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">DirectMessageProtocol</span> <span class="p">{</span>
<span class="n">X3DHHeader</span> <span class="na">X3DH_header</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">DRHeader</span> <span class="na">DR_header</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="n">DHHeader</span> <span class="na">DH_header</span> <span class="o">=</span> <span class="mi">101</span><span class="p">;</span>
<span class="c1">// Encrypted payload</span>
<span class="kt">bytes</span> <span class="na">payload</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>
<p><code class="language-plaintext highlighter-rouge">X3DH_header</code>: the <code class="language-plaintext highlighter-rouge">X3DHHeader</code> field in <code class="language-plaintext highlighter-rouge">DirectMessageProtocol</code> contains:</p>
<p>(<a href="https://github.com/status-im/status-go/blob/a904d9325e76f18f54d59efc099b63293d3dcad3/services/shhext/chat/encryption.proto#L47">protobuf</a>)</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">message</span> <span class="nc">X3DHHeader</span> <span class="p">{</span>
<span class="kt">bytes</span> <span class="na">key</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">id</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div> </div>
<ul>
<li><code class="language-plaintext highlighter-rouge">key</code>: Alices ephemeral key <code class="language-plaintext highlighter-rouge">EK_A</code>;</li>
<li><code class="language-plaintext highlighter-rouge">id</code>: Identifier stating which of Bobs prekeys Alice used, in this case Bobs bundle signed prekey.</li>
</ul>
<p>Alices identity key <code class="language-plaintext highlighter-rouge">IK_A</code> is sent at the transport layer level (Whisper/Waku);</p>
</li>
<li><code class="language-plaintext highlighter-rouge">DR_header</code>: Double ratchet header (<a href="https://github.com/status-im/status-go/blob/a904d9325e76f18f54d59efc099b63293d3dcad3/services/shhext/chat/encryption.proto#L31">protobuf</a>). Used when Bobs public bundle is available:
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">message</span> <span class="nc">DRHeader</span> <span class="p">{</span>
<span class="kt">bytes</span> <span class="na">key</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">uint32</span> <span class="na">n</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">uint32</span> <span class="na">pn</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">id</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div> </div>
<ul>
<li><code class="language-plaintext highlighter-rouge">key</code>: Alices current ratchet public key (as mentioned in <a href="https://signal.org/docs/specifications/doubleratchet/#symmetric-key-ratchet">DR spec section 2.2</a>);</li>
<li><code class="language-plaintext highlighter-rouge">n</code>: number of the message in the sending chain;</li>
<li><code class="language-plaintext highlighter-rouge">pn</code>: length of the previous sending chain;</li>
<li><code class="language-plaintext highlighter-rouge">id</code>: Bobs bundle ID.</li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">DH_header</code>: Diffie-Helman header (used when Bobs bundle is not available):
(<a href="https://github.com/status-im/status-go/blob/a904d9325e76f18f54d59efc099b63293d3dcad3/services/shhext/chat/encryption.proto#L42">protobuf</a>)
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">message</span> <span class="nc">DHHeader</span> <span class="p">{</span>
<span class="kt">bytes</span> <span class="na">key</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div> </div>
<ul>
<li><code class="language-plaintext highlighter-rouge">key</code>: Alices compressed ephemeral public key.</li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">payload</code>:
<ul>
<li>if a bundle is available, contains payload encrypted with the Double Ratchet algorithm;</li>
<li>otherwise, payload encrypted with output key of DH exchange (no Perfect Forward Secrecy).</li>
</ul>
</li>
</ul>
<!-- TODO: A lot of links to status-go, seems likely these should be updated to status-protocol-go -->
<h2 id="security-considerations">Security Considerations</h2>
<p>The same considerations apply as in <a href="https://signal.org/docs/specifications/x3dh/#security-considerations">section 4 of the X3DH spec</a> and <a href="https://signal.org/docs/specifications/doubleratchet/#security-considerations">section 6 of the Double Ratchet spec</a>, with some additions detailed below.</p>
<!-- TODO: Add any additional context here not covered in the X3DH and DR specs -->
<!--
TODO: description here
### --- Security and Privacy Features
#### Confidentiality (YES)
> Only the intended recipients are able to read a message. Specifically, the message must not be readable by a server operator that is not a conversation participant
- Yes.
- There's a layer of encryption at Whisper as well as above with Double Ratchet
- Relay nodes and Mailservers can only read a topic of a Whisper message, and nothing within the payload.
#### Integrity (YES)
> No honest party will accept a message that has been modified in transit.
- Yes.
- Assuming a user validates (TODO: Check this assumption) every message they are able to decrypt and validate its signature from the sender, then it is not able to be altered in transit.
* [igorm] i'm really not sure about it, Whisper provides a signature, but I'm not sure we check it anywhere (simple grepping didn't give anything)
* [andrea] Whisper checks the signature and a public key is derived from it, we check the public key is a meaningful public key. The pk itself is not in the content of the message for public chats/1-to-1 so potentially you could send a message from a random account without having access to the private key, but that would not be much of a deal, as you might just as easily create a random account)
#### Authentication (YES)
> Each participant in the conversation receives proof of possession of a known long-term secret from all other participants that they believe to be participating in the conversation. In addition, each participant is able to verify that a message was sent from the claimed source
- 1:1 --- one-to-one messages are encrypted with the recipient's public key, and digitally signed by the sender's. In order to provide Perfect Forward Secrecy, we build on the X3DH and Double Ratchet specifications from Open Whisper Systems, with some adaptations to operate in a decentralized environment.
- group --- group chat is pairwise
- public --- A user subscribes to a public channel topic and the decryption key is derived from the topic name
**TODO:** Need to verify that this is actually the case
**TODO:** Fill in explicit details here
#### Participant Consistency (YES?)
> At any point when a message is accepted by an honest party, all honest parties are guaranteed to have the same view of the participant list
- **TODO:** Need details here
#### Destination Validation (YES?)
> When a message is accepted by an honest party, they can verify that they were included in the set of intended recipients for the message.
- Users are aware of the topic that a message was sent to, and that they have the ability to decrypt it.
-
#### Forward Secrecy (PARTIAL)
> Compromising all key material does not enable decryption of previously encrypted data
- After first back and forth between two contacts with PFS enabled, yes.
#### Backward Secrecy (YES)
> Compromising all key material does not enable decryption of succeeding encrypted data
- PFS requires both backward and forwards secrecy
[Andrea: This is not true, (Perfect) Forward Secrecy does not imply backward secrecy (which is also called post-compromise security, as signal calls it, or future secrecy, it's not well defined). Technically this is a NO , double ratchet offers good Backward secrecy, but not perfect. Effectively if all the key material is compromised, any future message received will be also compromised (due to the hash ratchet), until a DH ratchet step is completed (i.e. the compromised party generate a new random key and ratchet)]
#### Anonymity Preserving (PARTIAL)
> Any anonymity features provided by the underlying transport privacy architecture are not undermined (e.g., if the transport privacy system provides anonymity, the conversation security level does not de-anonymize users by linking key identifiers).
- by default, yes
- ENS Naming system attaches an identifier to a given public key
#### Speaker Consistency (PARTIAL)
> All participants agree on the sequence of messages sent by each participant. A protocol might perform consistency checks on blocks of messages during the protocol, or after every message is sent.
- We use Lamport timestamps for ordering of events.
- In addition to this, we use local timestamps to attempt a more intuitive ordering. [Andrea: currently this was introduced as a regression during performance optimization and might result in out-of-order messages if sent across day boundaries, so I consider it a bug and not part of the specs (it does not make the order more intuitive, quite the opposite as it might result in causally related messages being out-of-order, but helps dividing the messages in days)]
- Fundamentally, there's no single source of truth, nor consensus process for global ordering [Andrea: Global ordering does not need a consensus process i.e. if you order messages alphabetically, and you break ties consistently, you have global ordering, as all the participants will see the same ordering (as opposed to say order by the time the message was received locally), of course is not useful, you want to have causal + global to be meaningful]
TODO: Understand how this is different from Global Transcript
[Andrea: This is basically Global transcript for a single participants, we offer global transcript]
#### Causality Preserving (PARTIAL)
> Implementations can avoid displaying a message before messages that causally precede it
- Not yet, but in pipeline (data sync layer)
[Andrea: Messages are already causally ordered, we don't display messages that are causally related out-of-order, that's already granted by lamport timestamps]
TODO: Verify if this can be done already by looking at Lamport clock difference
#### Global Transcript (PARTIAL)
> All participants see all messages in the same order
- See directly above
[Andrea: messages are globally (total) ordered, so all participants see the same ordering]
#### Message Unlinkability (NO)
> If a judge is convinced that a participant authored one message in the conversation, this does not provide evidence that they authored other messages
- Currently, the Status software signs every messages sent with the user's public key, thus making it unable to provide unlinkability.
- This is not necessary though, and could be built in to have an option to not sign.
- Side note: moot account allows for this but is a function of the anonymity set that uses it. The more people that use this account the stronger the unlinkability.
#### Message Repudiation (NO)
> Given a conversation transcript and all cryptographic keys, there is no evidence that a given message was authored by any particular user
- All messages are digitally signed by their sender.
- The underlying transport, Whisper/Waku, does allow for unsigned messages, but we don't use it.
#### Participant Repudiation (NO)
> Given a conversation transcript and all cryptographic key material for all but one accused (honest) participant, there is no evidence that the honest participant was in a conversation with any of the other participants.
### --- Group related features
#### Computational Equality (YES)
> All chat participants share an equal computational load
- One a message is sent, all participants in a group chat perform the same steps to retrieve and decrypt it.
- If proof of work is actually used at the Whisper layer (basically turned off in Status) then the sender would have to do additional computational work to send messages.
#### Trust Equality (PARTIAL)
> No participant is more trusted or takes on more responsibility than any other
- 1:1 chats and public chats are equal
- group chats have admins (on purpose)
- Private Group chats have Administrators and Members. Upon construction, the creator is made an admin. These groups have the following privileges:
- Admins:
- Add group members
- Promote group members to admin
- Change group name
- Members:
- Accept invitation to group
- Leave group
- Non-Members:
- Invited by admins show up as "invited" in group; this leaks contact information
- Invited people don't opt-in to being invited
TODO: Group chat dynamics should have a documented state diagram
TODO: create issues for identity leak of invited members as well as current members of a group showing up who have not accepted yet [Andrea: that's an interesting point, didn't think of that. Currently we have this behavior for 2 reasons, backward compatibility with previous releases, which had no concept of joining, and also because we rely on other peers to propagate group info, so we don't have a single-message point of failure (the invitation), the first can be addressed easily, the second is trickier, without giving up the propagation mechanism (if we choose to give this up, then it's trivial)]
#### Subgroup Messaging (NO)
> Messages can be sent to a subset of participants without forming a new conversation
- This would require a new topic and either a new public chat or a new group chat
[Andrea: This is a YES, as messages are pairwise encrypted, and client-side fanout, so anyone could potentially send a message only to a subset of the group]
#### Contractible Membership (PARTIAL)
> After the conversation begins, participants can leave without restarting the protocol
- For 1:1, there is no way to ignore or block a user from sending you a message. This is currently in the pipeline.
- For public chats, Yes. A member simply stops subscribing to a specific topic and will no longer receive messages.
- For group chats: this assumes pairwise encryption OR key is renegotiated
- This only currently works on the identity level, and not the device level. A ghost device will have access to anything other devices have.
[Andrea: For group chats, that's possible as using pairwise encryption, also with group chats (which use device-to-device encryption), ghost devices is a bit more complicated, in general, they don't have access to the messages you send, i.e. If I send a message from device A1 to the group chat and there is a ghost device A2, it will not be able to decrypt the content, but will see that a message has been sent (as only paired devices are kept in sync, and those are explicitly approved by the user). Messages that you receive are different, so a ghost device (A2) will potentially be able to decrypt the message, but A1 can detect the ghost device (in most cases, it's complicated :), the pfs docs describe multi-device support), for one-to-one ghost devices are undetectable]
#### Expandable Membership (PARTIAL)
> After the conversation begins, participants can join without restarting the protocol.
- 1:1: no, only 1:1
- private group: yes, since it is pair-wise, each person in the group just creates a pair with the new member
- public: yes, as members of a public chat are only subscribing to a topic and receiving anyone sending messages to it.
### --- Usability and Adoption
#### Out-of-Order Resilient (PARTIAL)
> If a message is delayed in transit, but eventually arrives, its contents are accessible upon arrival
- Due to asynchronous forward secrecy and no additional services, private keys might be rotated
[Andrea: That's correct, in some cases if the message is delayed for too long, or really out-of-order, the specific message key might have been deleted, as we only keep the last 3000 message keys]
[Igor: TTL of a Whisper message can expire, so any node-in-transit will drop it. Also, I believe we ignore messages with skewed timestamps]
#### Dropped Message Resilient (PARTIAL)
> Messages can be decrypted without receipt of all previous messages. This is desirable for asynchronous and unreliable network services
- Public chats: yes, users are able to decrypt any message received at any time.
- 1-to-1/group chat also, this is a YES in my opinion
#### Asynchronous (PARTIAL)
> Messages can be sent securely to disconnected recipients and received upon their next connection
- The semantics around message reliability are currently poor
* [Igor: messages are stored on mailservers for way longer than TTL (30 days), but that requires Status infrastructure]
- There's a TTL in Whisper and mailserver can deliver messages after the fact
TODO: this requires more detail
#### Multi-Device Support (YES)
> A user can participate in the conversation using multiple devices at once. Each device must be able to send and receive messages. Ideally, all devices have identical views of the conversation. The devices might use a synchronized long-term key or distinct keys.
- Yes
- There is currently work being done to improve the syncing process between a user's devices.
#### No Additional Service (NO)
> The protocol does not require any infrastructure other than the protocol participants. Specifically, the protocol must not require additional servers for relaying messages or storing any kind of key material.
- The protocol requires Whisper/Waku relay servers and mailservers currently.
- The larger the number of Whisper/Waku relay servers, the better the transport security but there might be potential scaling problems.
- Mailservers act to provide asynchronicity so users can retrieve messages after coming back from an offline period.
-->
<h2 id="session-management">Session management</h2>
<p>A node identifies a peer by two pieces of data:</p>
<p>1) An <code class="language-plaintext highlighter-rouge">installation-id</code> which is generated upon creating a new account in the <code class="language-plaintext highlighter-rouge">Status</code> application
2) Their identity Whisper/Waku key</p>
<h3 id="initialization">Initialization</h3>
<p>A node initializes a new session once a successful X3DH exchange has taken place. Subsequent messages will use the established session until re-keying is necessary.</p>
<h3 id="concurrent-sessions">Concurrent sessions</h3>
<p>If a node creates two sessions concurrently between two peers, the one with the symmetric key first in byte order SHOULD be used, this marks that the other has expired.</p>
<h3 id="re-keying">Re-keying</h3>
<p>On receiving a bundle from a given peer with a higher version, the old bundle SHOULD be marked as expired and a new session SHOULD be established on the next message sent.</p>
<h3 id="multi-device-support">Multi-device support</h3>
<p>Multi-device support is quite challenging as there is not a central place where information on which and how many devices (identified by their respective <code class="language-plaintext highlighter-rouge">installation-id</code>) belongs to a whisper-identity / waku-identity.</p>
<p>Furthermore, account recovery always needs to be taken into consideration, where a user wipes clean the whole device and the nodes loses all the information about any previous sessions.</p>
<p>Taking these considerations into account, the way the network propagates multi-device information using x3dh bundles, which will contain information about paired devices as well as information about the sending device.</p>
<p>This means that every time a new device is paired, the bundle needs to be updated and propagated with the new information, the user has the responsibility to make sure the pairing is successful.</p>
<p>The method is loosely based on https://signal.org/docs/specifications/sesame/ .</p>
<h3 id="pairing">Pairing</h3>
<p>When a user adds a new account in the <code class="language-plaintext highlighter-rouge">Status</code> application, a new <code class="language-plaintext highlighter-rouge">installation-id</code> will be generated. The device should be paired as soon as possible if other devices are present. Once paired the contacts will be notified of the new device and it will be included in further communications.</p>
<p>If a bundle received from the <code class="language-plaintext highlighter-rouge">IK</code> is different to the <code class="language-plaintext highlighter-rouge">installation-id</code>, the device will be shown to the user and will have to be manually approved, to a maximum of 3. Once that is done any message sent by one device will also be sent to any other enabled device.</p>
<p>Once a user enables a new device, a new bundle will be generated which will include pairing information.</p>
<p>The bundle will be propagated to contacts through the usual channels.</p>
<p>Removal of paired devices is a manual step that needs to be applied on each device, and consist simply in disabling the device, at which point pairing information will not be propagated anymore.</p>
<h3 id="sending-messages-to-a-paired-group">Sending messages to a paired group</h3>
<p>When sending a message, the peer will send a message to other <code class="language-plaintext highlighter-rouge">installation-id</code> that they have seen.
The node caps the number of devices to 3, ordered by last activity.
The node sends messages using pairwise encryption, including their own devices.</p>
<h3 id="account-recovery-1">Account recovery</h3>
<p>Account recovery is no different from adding a new device, and it is handled in exactly the same way.</p>
<h3 id="partitioned-devices">Partitioned devices</h3>
<p>In some cases (i.e. account recovery when no other pairing device is available, device not paired), it is possible that a device will receive a message that is not targeted to its own <code class="language-plaintext highlighter-rouge">installation-id</code>.
In this case an empty message containing bundle information is sent back, which will notify the receiving end of including this device in any further communication.</p>
<h2 id="changelog">Changelog</h2>
<h3 id="version-03">Version 0.3</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/664dd1c9df6ad409e4c007fefc8c8945b8d324e8">May 22, 2020</a></p>
<ul>
<li>Added language to include Waku in all relevant places</li>
</ul>

View File

@ -1,693 +0,0 @@
<h1 id="6payloads">6/PAYLOADS</h1>
<blockquote>
<p>Version: 0.5</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>, Oskar Thorén <a href="mailto:oskar@status.im">oskar@status.im</a>, Samuel Hawksby-Robinson <a href="mailto:samuel@status.im">samuel@status.im</a> (alphabetical order)</p>
</blockquote>
<h2 id="abstract">Abstract</h2>
<p>This specification describes how the payload of each message in Status looks
like. It is primarily centered around chat and chat-related use cases.</p>
<p>The payloads aims to be flexible enough to support messaging but also cases
described in the <a href="https://status.im/whitepaper.pdf">Status Whitepaper</a> as well
as various clients created using different technologies.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#table-of-contents">Table of Contents</a></li>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#payload-wrapper">Payload wrapper</a></li>
<li><a href="#encoding">Encoding</a></li>
<li><a href="#types-of-messages">Types of messages</a>
<ul>
<li><a href="#message">Message</a>
<ul>
<li><a href="#payload">Payload</a></li>
<li><a href="#payload-1">Payload</a></li>
<li><a href="#content-types">Content types</a>
<ul>
<li><a href="#sticker-content-type">Sticker content type</a></li>
<li><a href="#image-content-type">Image content type</a></li>
<li><a href="#audio-content-type">Audio content type</a></li>
</ul>
</li>
<li><a href="#message-types">Message types</a></li>
<li><a href="#clock-vs-timestamp-and-message-ordering">Clock vs Timestamp and message ordering</a></li>
<li><a href="#chats">Chats</a></li>
</ul>
</li>
<li><a href="#contact-update">Contact Update</a>
<ul>
<li><a href="#payload-2">Payload</a></li>
<li><a href="#contact-update-1">Contact update</a></li>
</ul>
</li>
<li><a href="#emojireaction">EmojiReaction</a></li>
<li><a href="#syncinstallationcontact">SyncInstallationContact</a>
<ul>
<li><a href="#payload-3">Payload</a></li>
</ul>
</li>
<li><a href="#syncinstallationpublicchat">SyncInstallationPublicChat</a>
<ul>
<li><a href="#payload-4">Payload</a></li>
</ul>
</li>
<li><a href="#pairinstallation">PairInstallation</a>
<ul>
<li><a href="#payload-5">Payload</a></li>
</ul>
</li>
<li><a href="#membershipupdatemessage-and-membershipupdateevent">MembershipUpdateMessage and MembershipUpdateEvent</a></li>
</ul>
</li>
<li><a href="#upgradability">Upgradability</a></li>
<li><a href="#security-considerations">Security Considerations</a></li>
<li><a href="#changelog">Changelog</a></li>
<li><a href="#copyright">Copyright</a></li>
</ul>
<h2 id="introduction">Introduction</h2>
<p>This document describes the payload format and some special considerations.</p>
<h2 id="payload-wrapper">Payload wrapper</h2>
<p>The node wraps all payloads in a <a href="https://developers.google.com/protocol-buffers/">protobuf record</a>
record:</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">StatusProtocolMessage</span> <span class="p">{</span>
<span class="kt">bytes</span> <span class="na">signature</span> <span class="o">=</span> <span class="mi">4001</span><span class="p">;</span>
<span class="kt">bytes</span> <span class="na">payload</span> <span class="o">=</span> <span class="mi">4002</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">signature</code> is the bytes of the signed <code class="language-plaintext highlighter-rouge">SHA3-256</code> of the payload, signed with the key of the author of the message.
The node needs the signature to validate authorship of the message, so that the message can be relayed to third parties.
If a signature is not present, but an author is provided by a layer below, the message is not to be relayed to third parties, and it is considered plausibly deniable.</p>
<h2 id="encoding">Encoding</h2>
<p>The node encodes the payload using <a href="https://developers.google.com/protocol-buffers">Protobuf</a></p>
<h2 id="types-of-messages">Types of messages</h2>
<h3 id="message">Message</h3>
<p>The type <code class="language-plaintext highlighter-rouge">ChatMessage</code> represents a chat message exchanged between clients.</p>
<h4 id="payload">Payload</h4>
<p>The protobuf description is:</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">ChatMessage</span> <span class="p">{</span>
<span class="c1">// Lamport timestamp of the chat message</span>
<span class="kt">uint64</span> <span class="na">clock</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="c1">// Unix timestamps in milliseconds, currently not used as we use Whisper/Waku as more reliable, but here</span>
<span class="c1">// so that we don't rely on it</span>
<span class="kt">uint64</span> <span class="na">timestamp</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="c1">// Text of the message</span>
<span class="kt">string</span> <span class="na">text</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="c1">// Id of the message that we are replying to</span>
<span class="kt">string</span> <span class="na">response_to</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="c1">// Ens name of the sender</span>
<span class="kt">string</span> <span class="na">ens_name</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="c1">// Chat id, this field is symmetric for public-chats and private group chats,</span>
<span class="c1">// but asymmetric in case of one-to-ones, as the sender will use the chat-id</span>
<span class="c1">// of the received, while the receiver will use the chat-id of the sender.</span>
<span class="kt">string</span> <span class="na">chat_id</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="c1">// The type of message (public/one-to-one/private-group-chat)</span>
<span class="n">MessageType</span> <span class="na">message_type</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="c1">// The type of the content of the message</span>
<span class="n">ContentType</span> <span class="na">content_type</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="k">oneof</span> <span class="n">payload</span> <span class="p">{</span>
<span class="n">StickerMessage</span> <span class="na">sticker</span> <span class="o">=</span> <span class="mi">9</span><span class="p">;</span>
<span class="n">ImageMessage</span> <span class="na">image</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="n">AudioMessage</span> <span class="na">audio</span> <span class="o">=</span> <span class="mi">11</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">enum</span> <span class="n">ContentType</span> <span class="p">{</span>
<span class="na">UNKNOWN_CONTENT_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">TEXT_PLAIN</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="na">STICKER</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="na">STATUS</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="na">EMOJI</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="na">TRANSACTION_COMMAND</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="c1">// Only local</span>
<span class="na">SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="na">IMAGE</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span>
<span class="na">AUDIO</span> <span class="o">=</span> <span class="mi">8</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="payload-1">Payload</h4>
<table>
<thead>
<tr>
<th>Field</th>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>clock</td>
<td><code class="language-plaintext highlighter-rouge">uint64</code></td>
<td>The clock of the chat</td>
</tr>
<tr>
<td>2</td>
<td>timestamp</td>
<td><code class="language-plaintext highlighter-rouge">uint64</code></td>
<td>The sender timestamp at message creation</td>
</tr>
<tr>
<td>3</td>
<td>text</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>The content of the message</td>
</tr>
<tr>
<td>4</td>
<td>response_to</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>The ID of the message replied to</td>
</tr>
<tr>
<td>5</td>
<td>ens_name</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>The ENS name of the user sending the message</td>
</tr>
<tr>
<td>6</td>
<td>chat_id</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>The local ID of the chat the message is sent to</td>
</tr>
<tr>
<td>7</td>
<td>message_type</td>
<td><code class="language-plaintext highlighter-rouge">MessageType</code></td>
<td>The type of message, different for one-to-one, public or group chats</td>
</tr>
<tr>
<td>8</td>
<td>content_type</td>
<td><code class="language-plaintext highlighter-rouge">ContentType</code></td>
<td>The type of the content of the message</td>
</tr>
<tr>
<td>9</td>
<td>payload</td>
<td><code class="language-plaintext highlighter-rouge">Sticker</code> I <code class="language-plaintext highlighter-rouge">Image</code> I <code class="language-plaintext highlighter-rouge">Audio</code> I <code class="language-plaintext highlighter-rouge">nil</code></td>
<td>The payload of the message based on the content type</td>
</tr>
</tbody>
</table>
<h4 id="content-types">Content types</h4>
<p>A node requires content types for a proper interpretation of incoming messages. Not each message is plain text but may carry different information.</p>
<p>The following content types MUST be supported:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">TEXT_PLAIN</code> identifies a message which content is a plaintext.</li>
</ul>
<p>There are other content types that MAY be implemented by the client:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">STICKER</code></li>
<li><code class="language-plaintext highlighter-rouge">STATUS</code></li>
<li><code class="language-plaintext highlighter-rouge">EMOJI</code></li>
<li><code class="language-plaintext highlighter-rouge">TRANSACTION_COMMAND</code></li>
<li><code class="language-plaintext highlighter-rouge">IMAGE</code></li>
<li><code class="language-plaintext highlighter-rouge">AUDIO</code></li>
</ul>
<h5 id="mentions">Mentions</h5>
<p>A mention MUST be represented as a string with the <code class="language-plaintext highlighter-rouge">@0xpk</code> format, where <code class="language-plaintext highlighter-rouge">pk</code> is the public key of the <a href="https://specs.status.im/spec/2">user account</a> to be mentioned, within the <code class="language-plaintext highlighter-rouge">text</code> field of a message with content_type <code class="language-plaintext highlighter-rouge">TEXT_PLAIN</code>.
A message MAY contain more than one mention.
This specification RECOMMENDs that the application does not require the user to enter the entire pk.
This specification RECOMMENDs that the application allows the user to create a mention by typing @ followed by the related ENS or 3-word pseudonym.
This specification RECOMMENDs that the application provides the user auto-completion functionality to create a mention.
For better user experience, the client SHOULD display a known <a href="https://specs.status.im/spec/2#contact-verification">ens name or the 3-word pseudonym corresponding to the key</a> instead of the <code class="language-plaintext highlighter-rouge">pk</code>.</p>
<h5 id="sticker-content-type">Sticker content type</h5>
<p>A <code class="language-plaintext highlighter-rouge">ChatMessage</code> with <code class="language-plaintext highlighter-rouge">STICKER</code> <code class="language-plaintext highlighter-rouge">Content/Type</code> MUST also specify the ID of the <code class="language-plaintext highlighter-rouge">Pack</code> and
the <code class="language-plaintext highlighter-rouge">Hash</code> of the pack, in the <code class="language-plaintext highlighter-rouge">Sticker</code> field of <code class="language-plaintext highlighter-rouge">ChatMessage</code></p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">StickerMessage</span> <span class="p">{</span>
<span class="kt">string</span> <span class="na">hash</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">int32</span> <span class="na">pack</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h5 id="image-content-type">Image content type</h5>
<p>A <code class="language-plaintext highlighter-rouge">ChatMessage</code> with <code class="language-plaintext highlighter-rouge">IMAGE</code> <code class="language-plaintext highlighter-rouge">Content/Type</code> MUST also specify the <code class="language-plaintext highlighter-rouge">payload</code> of the image
and the <code class="language-plaintext highlighter-rouge">type</code>.</p>
<p>Clients MUST sanitize the payload before accessing its content, in particular:</p>
<ul>
<li>Clients MUST choose a secure decoder</li>
<li>Clients SHOULD strip metadata if present without parsing/decoding it</li>
<li>Clients SHOULD NOT add metadata/exif when sending an image file for privacy and security reasons</li>
<li>Clients MUST make sure that the transport layer constraints the size of the payload to limit they are able to handle securely</li>
</ul>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">ImageMessage</span> <span class="p">{</span>
<span class="kt">bytes</span> <span class="na">payload</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">ImageType</span> <span class="na">type</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kd">enum</span> <span class="n">ImageType</span> <span class="p">{</span>
<span class="na">UNKNOWN_IMAGE_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">PNG</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="na">JPEG</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="na">WEBP</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="na">GIF</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h5 id="audio-content-type">Audio content type</h5>
<p>A <code class="language-plaintext highlighter-rouge">ChatMessage</code> with <code class="language-plaintext highlighter-rouge">AUDIO</code> <code class="language-plaintext highlighter-rouge">Content/Type</code> MUST also specify the <code class="language-plaintext highlighter-rouge">payload</code> of the audio,
the <code class="language-plaintext highlighter-rouge">type</code> and the duration in milliseconds (<code class="language-plaintext highlighter-rouge">duration_ms</code>).</p>
<p>Clients MUST sanitize the payload before accessing its content, in particular:</p>
<ul>
<li>Clients MUST choose a secure decoder</li>
<li>Clients SHOULD strip metadata if present without parsing/decoding it</li>
<li>Clients SHOULD NOT add metadata/exif when sending an audio file for privacy and security reasons</li>
<li>Clients MUST make sure that the transport layer constraints the size of the payload to limit they are able to handle securely</li>
</ul>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">AudioMessage</span> <span class="p">{</span>
<span class="kt">bytes</span> <span class="na">payload</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">AudioType</span> <span class="na">type</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">uint64</span> <span class="na">duration_ms</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kd">enum</span> <span class="n">AudioType</span> <span class="p">{</span>
<span class="na">UNKNOWN_AUDIO_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">AAC</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="na">AMR</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
</code></pre></div></div>
<h4 id="message-types">Message types</h4>
<p>A node requires message types to decide how to encrypt a particular message and what metadata needs to be attached when passing a message to the transport layer. For more on this, see <a href="./../stable/3-whisper-usage.md">3/WHISPER-USAGE</a> and <a href="./../stable/10-waku-usage.md">10/WAKU-USAGE</a>.</p>
<!-- TODO: This reference is a bit odd, considering the layer payloads should interact with is Secure Transport, and not Whisper/Waku. This requires more detail -->
<p>The following messages types MUST be supported:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">ONE_TO_ONE</code> is a message to the public group</li>
<li><code class="language-plaintext highlighter-rouge">PUBLIC_GROUP</code> is a private message</li>
<li><code class="language-plaintext highlighter-rouge">PRIVATE_GROUP</code> is a message to the private group.</li>
</ul>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">enum</span> <span class="n">MessageType</span> <span class="p">{</span>
<span class="na">UNKNOWN_MESSAGE_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">ONE_TO_ONE</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="na">PUBLIC_GROUP</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="na">PRIVATE_GROUP</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="c1">// Only local</span>
<span class="na">SYSTEM_MESSAGE_PRIVATE_GROUP</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="clock-vs-timestamp-and-message-ordering">Clock vs Timestamp and message ordering</h4>
<p>If a user sends a new message before the messages sent while the user was offline are received, the new
message is supposed to be displayed last in a chat. This is where the basic algorithm of Lamport timestamp would fall short
as its only meant to order causally related events.</p>
<p>The status client therefore makes a “bid”, speculating that it will beat the current chat-timestamp, s.t. the status clients
Lamport timestamp format is: <code class="language-plaintext highlighter-rouge">clock = </code>max({timestamp}, chat_clock + 1)`</p>
<p>This will satisfy the Lamport requirement, namely: a -&gt; b then T(a) &lt; T(b)</p>
<p><code class="language-plaintext highlighter-rouge">timestamp</code> MUST be Unix time calculated, when the node creates the message, in milliseconds. This field SHOULD not be relied upon for message ordering.</p>
<p><code class="language-plaintext highlighter-rouge">clock</code> SHOULD be calculated using the algorithm of <a href="https://en.wikipedia.org/wiki/Lamport_timestamps">Lamport timestamps</a>. When there are messages available in a chat, the node calculates <code class="language-plaintext highlighter-rouge">clock</code>s value based on the last received message in a particular chat: <code class="language-plaintext highlighter-rouge">max(timeNowInMs, last-message-clock-value + 1)</code>. If there are no messages, <code class="language-plaintext highlighter-rouge">clock</code> is initialized with <code class="language-plaintext highlighter-rouge">timestamp</code>s value.</p>
<p>Messages with a <code class="language-plaintext highlighter-rouge">clock</code> greater than <code class="language-plaintext highlighter-rouge">120</code> seconds over the Whisper/Waku timestamp SHOULD be discarded, in order to avoid malicious users to increase the <code class="language-plaintext highlighter-rouge">clock</code> of a chat arbitrarily.</p>
<p>Messages with a <code class="language-plaintext highlighter-rouge">clock</code> less than <code class="language-plaintext highlighter-rouge">120</code> seconds under the Whisper/Waku timestamp might indicate an attempt to insert messages in the chat history which is not distinguishable from a <code class="language-plaintext highlighter-rouge">datasync</code> layer re-transit event. A client MAY mark this messages with a warning to the user, or discard them.</p>
<p>The node uses <code class="language-plaintext highlighter-rouge">clock</code> value for the message ordering. The algorithm used, and the distributed nature of the system produces casual ordering, which might produce counter-intuitive results in some edge cases. For example, when a user joins a public chat and sends a message before receiving the exist messages, their message <code class="language-plaintext highlighter-rouge">clock</code> value might be lower and the message will end up in the past when the historical messages are fetched.</p>
<h4 id="chats">Chats</h4>
<p>Chat is a structure that helps organize messages. Its usually desired to display messages only from a single recipient, or a group of recipients at a time and chats help to achieve that.</p>
<p>All incoming messages can be matched against a chat. The below table describes how to calculate a chat ID for each message type.</p>
<table>
<thead>
<tr>
<th>Message Type</th>
<th>Chat ID Calculation</th>
<th>Direction</th>
<th>Comment</th>
</tr>
</thead>
<tbody>
<tr>
<td>PUBLIC_GROUP</td>
<td>chat ID is equal to a public channel name; it should equal <code class="language-plaintext highlighter-rouge">chatId</code> from the message</td>
<td>Incoming/Outgoing</td>
<td> </td>
</tr>
<tr>
<td>ONE_TO_ONE</td>
<td>let <code class="language-plaintext highlighter-rouge">P</code> be a public key of the recipient; <code class="language-plaintext highlighter-rouge">hex-encode(P)</code> is a chat ID; use it as <code class="language-plaintext highlighter-rouge">chatId</code> value in the message</td>
<td>Outgoing</td>
<td> </td>
</tr>
<tr>
<td>user-message</td>
<td>let <code class="language-plaintext highlighter-rouge">P</code> be a public key of messages signature; <code class="language-plaintext highlighter-rouge">hex-encode(P)</code> is a chat ID; discard <code class="language-plaintext highlighter-rouge">chat-id</code> from message</td>
<td>Incoming</td>
<td>if there is no matched chat, it might be the first message from public key <code class="language-plaintext highlighter-rouge">P</code>; the node MAY discard the message or MAY create a new chat; Status official clients create a new chat</td>
</tr>
<tr>
<td>PRIVATE_GROUP</td>
<td>use <code class="language-plaintext highlighter-rouge">chatId</code> from the message</td>
<td>Incoming/Outgoing</td>
<td>find an existing chat by <code class="language-plaintext highlighter-rouge">chatId</code>; if none is found, the user is not a member of that chat or the user hasnt joined that chat, the message MUST be discarded</td>
</tr>
</tbody>
</table>
<h3 id="contact-update">Contact Update</h3>
<p><code class="language-plaintext highlighter-rouge">ContactUpdate</code> is a message exchange to notify peers that either the
user has been added as a contact, or that information about the sending user have
changed.</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">ContactUpdate</span> <span class="p">{</span>
<span class="kt">uint64</span> <span class="na">clock</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">ens_name</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">profile_image</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="payload-2">Payload</h4>
<table>
<thead>
<tr>
<th>Field</th>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>clock</td>
<td><code class="language-plaintext highlighter-rouge">uint64</code></td>
<td>The clock of the chat with the user</td>
</tr>
<tr>
<td>2</td>
<td>ens_name</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>The ENS name if set</td>
</tr>
<tr>
<td>3</td>
<td>profile_image</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>The base64 encoded profile picture of the user</td>
</tr>
</tbody>
</table>
<h4 id="contact-update-1">Contact update</h4>
<p>A client SHOULD send a <code class="language-plaintext highlighter-rouge">ContactUpdate</code> to all the contacts each time:</p>
<ul>
<li>The ens_name has changed</li>
<li>A user edits the profile image</li>
</ul>
<p>A client SHOULD also periodically send a <code class="language-plaintext highlighter-rouge">ContactUpdate</code> to all the contacts, the interval is up to the client, the Status official client sends these updates every 48 hours.</p>
<h3 id="emojireaction">EmojiReaction</h3>
<p><code class="language-plaintext highlighter-rouge">EmojiReaction</code>s represents a users “reaction” to a specific chat message. For more information about the concept of
emoji reactions see <a href="https://en.wikipedia.org/wiki/Facebook_like_button#Use_on_Facebook">Facebook Reactions</a>.</p>
<p>This specification RECOMMENDS that the UI/UX implementation of sending <code class="language-plaintext highlighter-rouge">EmojiReactions</code> requires only a single click
operation, as users have an expectation that emoji reactions are effortless and simple to perform.</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">EmojiReaction</span> <span class="p">{</span>
<span class="c1">// clock Lamport timestamp of the chat message</span>
<span class="kt">uint64</span> <span class="na">clock</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="c1">// chat_id the ID of the chat the message belongs to, for query efficiency the chat_id is stored in the db even though the</span>
<span class="c1">// target message also stores the chat_id</span>
<span class="kt">string</span> <span class="na">chat_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="c1">// message_id the ID of the target message that the user wishes to react to</span>
<span class="kt">string</span> <span class="na">message_id</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="c1">// message_type is (somewhat confusingly) the ID of the type of chat the message belongs to</span>
<span class="n">MessageType</span> <span class="na">message_type</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="c1">// type the ID of the emoji the user wishes to react with</span>
<span class="n">Type</span> <span class="na">type</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="kd">enum</span> <span class="n">Type</span> <span class="p">{</span>
<span class="na">UNKNOWN_EMOJI_REACTION_TYPE</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">LOVE</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="na">THUMBS_UP</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="na">THUMBS_DOWN</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="na">LAUGH</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="na">SAD</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="na">ANGRY</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// whether this is a retraction of a previously sent emoji</span>
<span class="kt">bool</span> <span class="na">retracted</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Clients MUST specify <code class="language-plaintext highlighter-rouge">clock</code>, <code class="language-plaintext highlighter-rouge">chat_id</code>, <code class="language-plaintext highlighter-rouge">message_id</code>, <code class="language-plaintext highlighter-rouge">type</code> and <code class="language-plaintext highlighter-rouge">message_type</code>.</p>
<p>This specification RECOMMENDS that the UI/UX implementation of retracting an <code class="language-plaintext highlighter-rouge">EmojiReaction</code>s requires only a single
click operation, as users have an expectation that emoji reaction removals are effortless and simple to perform.</p>
<h3 id="syncinstallationcontact">SyncInstallationContact</h3>
<p>The node uses <code class="language-plaintext highlighter-rouge">SyncInstallationContact</code> messages to synchronize in a best-effort the contacts to other devices.</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">SyncInstallationContact</span> <span class="p">{</span>
<span class="kt">uint64</span> <span class="na">clock</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">profile_image</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">ens_name</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kt">uint64</span> <span class="na">last_updated</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span>
<span class="k">repeated</span> <span class="kt">string</span> <span class="na">system_tags</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="payload-3">Payload</h4>
<table>
<thead>
<tr>
<th>Field</th>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>clock</td>
<td><code class="language-plaintext highlighter-rouge">uint64</code></td>
<td>clock value of the chat</td>
</tr>
<tr>
<td>2</td>
<td>id</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>id of the contact synced</td>
</tr>
<tr>
<td>3</td>
<td>profile_image</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td><code class="language-plaintext highlighter-rouge">base64</code> encoded profile picture of the user</td>
</tr>
<tr>
<td>4</td>
<td>ens_name</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>ENS name of the contact</td>
</tr>
<tr>
<td>5</td>
<td><code class="language-plaintext highlighter-rouge">array[string]</code></td>
<td>Array of <code class="language-plaintext highlighter-rouge">system_tags</code> for the user, this can currently be: <code class="language-plaintext highlighter-rouge">":contact/added", ":contact/blocked", ":contact/request-received"</code></td>
<td> </td>
</tr>
</tbody>
</table>
<h3 id="syncinstallationpublicchat">SyncInstallationPublicChat</h3>
<p>The node uses <code class="language-plaintext highlighter-rouge">SyncInstallationPublicChat</code> message to synchronize in a best-effort the public chats to other devices.</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">SyncInstallationPublicChat</span> <span class="p">{</span>
<span class="kt">uint64</span> <span class="na">clock</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="payload-4">Payload</h4>
<table>
<thead>
<tr>
<th>Field</th>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>clock</td>
<td><code class="language-plaintext highlighter-rouge">uint64</code></td>
<td>clock value of the chat</td>
</tr>
<tr>
<td>2</td>
<td>id</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>id of the chat synced</td>
</tr>
</tbody>
</table>
<h3 id="pairinstallation">PairInstallation</h3>
<p>The node uses <code class="language-plaintext highlighter-rouge">PairInstallation</code> messages to propagate information about a device to its paired devices.</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">message</span> <span class="nc">PairInstallation</span> <span class="p">{</span>
<span class="kt">uint64</span> <span class="na">clock</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">installation_id</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">device_type</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="kt">string</span> <span class="na">name</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h4 id="payload-5">Payload</h4>
<table>
<thead>
<tr>
<th>Field</th>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>clock</td>
<td><code class="language-plaintext highlighter-rouge">uint64</code></td>
<td>clock value of the chat</td>
</tr>
<tr>
<td>2</td>
<td>installation_id</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>A randomly generated id that identifies this device</td>
</tr>
<tr>
<td>3</td>
<td>device_type</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>The OS of the device <code class="language-plaintext highlighter-rouge">ios</code>,<code class="language-plaintext highlighter-rouge">android</code> or <code class="language-plaintext highlighter-rouge">desktop</code></td>
</tr>
<tr>
<td>4</td>
<td>name</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>The self-assigned name of the device</td>
</tr>
</tbody>
</table>
<h3 id="membershipupdatemessage-and-membershipupdateevent">MembershipUpdateMessage and MembershipUpdateEvent</h3>
<p><code class="language-plaintext highlighter-rouge">MembershipUpdateEvent</code> is a message used to propagate information about group membership changes in a group chat.
The details are in the <a href="./7-group-chat.md">Group chats specs</a>.</p>
<h2 id="upgradability">Upgradability</h2>
<p>There are two ways to upgrade the protocol without breaking compatibility:</p>
<ul>
<li>A node always supports accretion</li>
<li>A node does not support deletion of existing fields or messages, which might break compatibility</li>
</ul>
<h2 id="security-considerations">Security Considerations</h2>
<p>-</p>
<h2 id="changelog">Changelog</h2>
<h3 id="version-05">Version 0.5</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/968fafff23cdfc67589b34dd64015de29aaf41f0">August 25, 2020</a></p>
<ul>
<li>Added support for emoji reactions</li>
</ul>
<h3 id="version-04">Version 0.4</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/ad45cd5fed3c0f79dfa472253a404f670dd47396">July 16, 2020</a></p>
<ul>
<li>Added support for images</li>
<li>Added support for audio</li>
</ul>
<h3 id="version-03">Version 0.3</h3>
<p>Released <a href="https://github.com/status-im/specs/commit/664dd1c9df6ad409e4c007fefc8c8945b8d324e8">May 22, 2020</a></p>
<ul>
<li>Added language to include Waku in all relevant places</li>
</ul>
<h2 id="copyright">Copyright</h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>

View File

@ -1,216 +0,0 @@
<h1 id="7group-chat">7/GROUP-CHAT</h1>
<blockquote>
<p>Version: 0.1</p>
<p>Status: Draft</p>
<p>Authors: Andrea Maria Piana <a href="mailto:andreap@status.im">andreap@status.im</a></p>
</blockquote>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#membership-updates">Membership updates</a>
<ul>
<li><a href="#chat-id">Chat ID</a></li>
<li><a href="#signature">Signature</a></li>
<li><a href="#group-membership-event">Group membership event</a>
<ul>
<li><a href="#chat_created">chat-created</a></li>
<li><a href="#name_changed">name-changed</a></li>
<li><a href="#members_added">members-added</a></li>
<li><a href="#member_joined">members-joined</a></li>
<li><a href="#admins_added">admins-added</a></li>
<li><a href="#member_removed">members-removed</a></li>
<li><a href="#admin_removed">admin-removed</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="abstract">Abstract</h2>
<p>This document describes the group chat protocol used by the status application. The node uses pairwise encryption among member so a message is exchanged between each participant, similarly to a one-to-one message.</p>
<h2 id="membership-updates">Membership updates</h2>
<p>The node uses membership updates messages to propagate group chat membership changes. The protobuf format is described in the <a href="https://specs.status.im/spec/6">6/PAYLOADS</a>. Below describes each specific field.</p>
<p>The protobuf messages are:</p>
<div class="language-protobuf highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// MembershipUpdateMessage is a message used to propagate information</span>
<span class="c1">// about group membership changes.</span>
<span class="kd">message</span> <span class="nc">MembershipUpdateMessage</span> <span class="p">{</span>
<span class="c1">// The chat id of the private group chat</span>
<span class="kt">string</span> <span class="na">chat_id</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="c1">// A list of events for this group chat, first 65 bytes are the signature, then is a </span>
<span class="c1">// protobuf encoded MembershipUpdateEvent</span>
<span class="k">repeated</span> <span class="kt">bytes</span> <span class="na">events</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="c1">// An optional chat message</span>
<span class="n">ChatMessage</span> <span class="kd">message</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">message</span> <span class="nc">MembershipUpdateEvent</span> <span class="p">{</span>
<span class="c1">// Lamport timestamp of the event as described in [Status Payload Specs](status-payload-specs.md#clock-vs-timestamp-and-message-ordering)</span>
<span class="kt">uint64</span> <span class="na">clock</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="c1">// List of public keys of the targets of the action</span>
<span class="k">repeated</span> <span class="kt">string</span> <span class="na">members</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="c1">// Name of the chat for the CHAT_CREATED/NAME_CHANGED event types</span>
<span class="kt">string</span> <span class="na">name</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="c1">// The type of the event</span>
<span class="n">EventType</span> <span class="na">type</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kd">enum</span> <span class="n">EventType</span> <span class="p">{</span>
<span class="na">UNKNOWN</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="na">CHAT_CREATED</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// See [CHAT_CREATED](#chat-created)</span>
<span class="na">NAME_CHANGED</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="c1">// See [NAME_CHANGED](#name-changed)</span>
<span class="na">MEMBERS_ADDED</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">// See [MEMBERS_ADDED](#members-added)</span>
<span class="na">MEMBER_JOINED</span> <span class="o">=</span> <span class="mi">4</span><span class="p">;</span> <span class="c1">// See [MEMBER_JOINED](#member-joined)</span>
<span class="na">MEMBER_REMOVED</span> <span class="o">=</span> <span class="mi">5</span><span class="p">;</span> <span class="c1">// See [MEMBER_REMOVED](#member-removed)</span>
<span class="na">ADMINS_ADDED</span> <span class="o">=</span> <span class="mi">6</span><span class="p">;</span> <span class="c1">// See [ADMINS_ADDED](#admins-added)</span>
<span class="na">ADMIN_REMOVED</span> <span class="o">=</span> <span class="mi">7</span><span class="p">;</span> <span class="c1">// See [ADMIN_REMOVED](#admin-removed)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="payload">Payload</h3>
<p><code class="language-plaintext highlighter-rouge">MembershipUpdateMessage</code>:</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>chat-id</td>
<td><code class="language-plaintext highlighter-rouge">string</code></td>
<td>The chat id of the chat where the change is to take place</td>
</tr>
<tr>
<td>2</td>
<td>events</td>
<td>See details</td>
<td>A list of events that describe the membership changes, in their encoded protobuf form</td>
</tr>
<tr>
<td>3</td>
<td>message</td>
<td><code class="language-plaintext highlighter-rouge">ChatMessage</code></td>
<td>An optional message, described in <a href="./6-payloads.md#message">Message</a></td>
</tr>
</tbody>
</table>
<p><code class="language-plaintext highlighter-rouge">MembershipUpdateEvent</code>:</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Name</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>clock</td>
<td><code class="language-plaintext highlighter-rouge">uint64</code></td>
<td>The clock value of the event</td>
</tr>
<tr>
<td>2</td>
<td>members</td>
<td><code class="language-plaintext highlighter-rouge">[]string</code></td>
<td>An optional list of hex encoded (prefixed with <code class="language-plaintext highlighter-rouge">0x</code>) public keys, the targets of the action</td>
</tr>
<tr>
<td>3</td>
<td>name</td>
<td><code class="language-plaintext highlighter-rouge">name</code></td>
<td>An optional name, for those events that make use of it</td>
</tr>
<tr>
<td>4</td>
<td>type</td>
<td><code class="language-plaintext highlighter-rouge">EventType</code></td>
<td>The type of event sent, described below</td>
</tr>
</tbody>
</table>
<h3 id="chat-id">Chat ID</h3>
<p>Each membership update MUST be sent with a corresponding <code class="language-plaintext highlighter-rouge">chatId</code>.
The format of this chat ID MUST be a string of <a href="https://tools.ietf.org/html/rfc4122">UUID</a>, concatenated with the hex-encoded public key of the creator of the chat, joined by <code class="language-plaintext highlighter-rouge">-</code>. This chatId MUST be validated by all clients, and MUST be discarded if it does not follow these rules.</p>
<h3 id="signature">Signature</h3>
<p>The node calculates the signature for each event by encoding each <code class="language-plaintext highlighter-rouge">MembershipUpdateEvent</code> in its protobuf representation and prepending the bytes of the chatID, lastly the node signs the <code class="language-plaintext highlighter-rouge">Keccak256</code> of the bytes using the private key by the author and added to the <code class="language-plaintext highlighter-rouge">events</code> field of MembershipUpdateMessage.</p>
<h3 id="group-membership-event">Group membership event</h3>
<p>Any <code class="language-plaintext highlighter-rouge">group membership</code> event received MUST be verified by calculating the signature as per the method described above.
The author MUST be extracted from it, if the verification fails the event MUST be discarded.</p>
<h4 id="chat_created">CHAT_CREATED</h4>
<p>Chat <code class="language-plaintext highlighter-rouge">created event</code> is the first event that needs to be sent. Any event with a clock value lower than this MUST be discarded.
Upon receiving this event a client MUST validate the <code class="language-plaintext highlighter-rouge">chatId</code> provided with the updates and create a chat with identified by <code class="language-plaintext highlighter-rouge">chatId</code> and named <code class="language-plaintext highlighter-rouge">name</code>.</p>
<h4 id="name_changed">NAME_CHANGED</h4>
<p><code class="language-plaintext highlighter-rouge">admins</code> use a <code class="language-plaintext highlighter-rouge">name changed</code> event to change the name of the group chat.
Upon receiving this event a client MUST validate the <code class="language-plaintext highlighter-rouge">chatId</code> provided with the updates and MUST ensure the author of the event is an admin of the chat, otherwise the event MUST be ignored.
If the event is valid the chat name SHOULD be changed to <code class="language-plaintext highlighter-rouge">name</code>.</p>
<h4 id="members_added">MEMBERS_ADDED</h4>
<p><code class="language-plaintext highlighter-rouge">admins</code> use a <code class="language-plaintext highlighter-rouge">members added</code> event to add members to the chat.
Upon receiving this event a client MUST validate the <code class="language-plaintext highlighter-rouge">chatId</code> provided with the updates and MUST ensure the author of the event is an admin of the chat, otherwise the event MUST be ignored.
If the event is valid a client MUST update the list of members of the chat who have not joined, adding the <code class="language-plaintext highlighter-rouge">members</code> received.
<code class="language-plaintext highlighter-rouge">members</code> is an array of hex encoded public keys.</p>
<h4 id="member_joined">MEMBER_JOINED</h4>
<p><code class="language-plaintext highlighter-rouge">members</code> use a <code class="language-plaintext highlighter-rouge">members joined</code> event to signal that they want to start receiving messages from this chat.
Upon receiving this event a client MUST validate the <code class="language-plaintext highlighter-rouge">chatId</code> provided with the updates.
If the event is valid a client MUST update the list of members of the chat who joined, adding the signer. Any <code class="language-plaintext highlighter-rouge">message</code> sent to the group chat should now include the newly joined member.</p>
<h4 id="admins_added">ADMINS_ADDED</h4>
<p><code class="language-plaintext highlighter-rouge">admins</code> use an <code class="language-plaintext highlighter-rouge">admins added</code> event to add make other admins in the chat.
Upon receiving this event a client MUST validate the <code class="language-plaintext highlighter-rouge">chatId</code> provided with the updates, MUST ensure the author of the event is an admin of the chat and MUST ensure all <code class="language-plaintext highlighter-rouge">members</code> are already <code class="language-plaintext highlighter-rouge">members</code> of the chat, otherwise the event MUST be ignored.
If the event is valid a client MUST update the list of admins of the chat, adding the <code class="language-plaintext highlighter-rouge">members</code> received.
<code class="language-plaintext highlighter-rouge">members</code> is an array of hex encoded public keys.</p>
<h4 id="member_removed">MEMBER_REMOVED</h4>
<p><code class="language-plaintext highlighter-rouge">members</code> and/or <code class="language-plaintext highlighter-rouge">admins</code> use a <code class="language-plaintext highlighter-rouge">member-removed</code> event to leave or kick members of the chat.
Upon receiving this event a client MUST validate the <code class="language-plaintext highlighter-rouge">chatId</code> provided with the updates, MUST ensure that:</p>
<ul>
<li>If the author of the event is an admin, target can only be themselves or a non-admin member.</li>
<li>
<h2 id="if-the-author-of-the-event-is-not-an-admin-the-target-of-the-event-can-only-be-themselves">If the author of the event is not an admin, the target of the event can only be themselves.</h2>
<p>If the event is valid a client MUST remove the member from the list of <code class="language-plaintext highlighter-rouge">members</code>/<code class="language-plaintext highlighter-rouge">admins</code> of the chat, and no further message should be sent to them.</p>
</li>
</ul>
<h4 id="admin_removed">ADMIN_REMOVED</h4>
<p><code class="language-plaintext highlighter-rouge">Admins</code> use an <code class="language-plaintext highlighter-rouge">admin-removed</code> event to drop admin privileges.
Upon receiving this event a client MUST validate the <code class="language-plaintext highlighter-rouge">chatId</code> provided with the updates, MUST ensure that the author of the event is also the target of the event.</p>
<p>If the event is valid a client MUST remove the member from the list of <code class="language-plaintext highlighter-rouge">admins</code> of the chat.</p>

View File

@ -1,381 +0,0 @@
<h1 id="8eips">8/EIPS</h1>
<blockquote>
<p>Version: 0.2</p>
<p>Status: Stable</p>
<p>Authors: Ricardo Guilherme Schmidt <a href="mailto:ricardo3@status.im">ricardo3@status.im</a></p>
</blockquote>
<h2 id="abstract">Abstract</h2>
<p>This specification describes how Status relates with EIPs.</p>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#table-of-contents">Table of Contents</a></li>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#components">Components</a></li>
</ul>
<h2 id="introduction">Introduction</h2>
<p>Status should follow all standards as possible. Whenever the Status app needs a feature, it should be first checked if there is a standard for that, if not, Status should propose a standard.</p>
<h3 id="support-table">Support table</h3>
<table>
<thead>
<tr>
<th> </th>
<th>Status v0</th>
<th>Status v1</th>
<th>Other</th>
<th>State</th>
</tr>
</thead>
<tbody>
<tr>
<td>BIP32</td>
<td>N</td>
<td>Y</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>BIP39</td>
<td>Y</td>
<td>Y</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>BIP43</td>
<td>N</td>
<td>Y</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>BIP44</td>
<td>N</td>
<td>Y</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP20</td>
<td>Y</td>
<td>Y</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP55</td>
<td>Y</td>
<td>Y</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP67</td>
<td>P</td>
<td>P</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP137</td>
<td>P</td>
<td>P</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP155</td>
<td>Y</td>
<td>Y</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP165</td>
<td>P</td>
<td>N</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP181</td>
<td>P</td>
<td>N</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP191</td>
<td>Y?</td>
<td>N</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP627</td>
<td>Y</td>
<td>Y</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP681</td>
<td>Y</td>
<td>N</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP712</td>
<td>P</td>
<td>P</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP721</td>
<td>P</td>
<td>P</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP831</td>
<td>N</td>
<td>Y</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP945</td>
<td>Y</td>
<td>Y</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP1102</td>
<td>Y</td>
<td>Y</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP1193</td>
<td>Y</td>
<td>Y</td>
<td>Y</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP1577</td>
<td>Y</td>
<td>P</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP1581</td>
<td>N</td>
<td>Y</td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">stable</code></td>
</tr>
<tr>
<td>EIP1459</td>
<td>N</td>
<td> </td>
<td>N</td>
<td><code class="language-plaintext highlighter-rouge">raw</code></td>
</tr>
</tbody>
</table>
<h2 id="components">Components</h2>
<h3 id="bip32---hierarchical-deterministic-wallets">BIP32 - Hierarchical Deterministic Wallets</h3>
<p>Support: Dependency.<br />
Reference: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki<br />
Description: Enable wallets to derive multiple private keys from the same seed.<br />
Used for: Dependency of BIP39 and BIP43.</p>
<h3 id="bip39---mnemonic-code-for-generating-deterministic-keys">BIP39 - Mnemonic code for generating deterministic keys</h3>
<p>Support: Dependency.<br />
Reference: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki<br />
Description: Enable wallet to create private key based on a safe seed phrase.
Used for: Security and user experience.</p>
<h3 id="bip43---purpose-field-for-deterministic-wallets">BIP43 - Purpose Field for Deterministic Wallets</h3>
<p>Support: Dependency.<br />
Reference: https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki<br />
Description: Enable wallet to create private keys branched for a specific purpose.<br />
Used for: Dependency of BIP44, uses “ethereum” coin.</p>
<h3 id="bip44---multi-account-hierarchy-for-deterministic-wallets">BIP44 - Multi-Account Hierarchy for Deterministic Wallets</h3>
<p>Support: Dependency.<br />
Reference: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki<br />
Description: Enable wallet to derive multiple accounts in top of BIP39.<br />
Used for: Privacy.<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/constants.cljs#L240 <br />
Observation: BIP44 dont solve privacy issues regarding the transparency of transactions, therefore directly connected addresses through a transactions can be identifiable by a “network reconnaissance attack” over transaction history, this attack together with leakage of information from centralized services, such as exchanges, would be fatal against the whole privacy of users, regardless of BIP44.</p>
<h3 id="eip20---fungible-token">EIP20 - Fungible Token</h3>
<p>Support: Full.<br />
Reference: https://eips.ethereum.org/EIPS/eip-20<br />
Description: Enable wallets to use tokens based on smart contracts compliant with this standard.<br />
Used for: Wallet feature.<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/tokens.cljs</p>
<h3 id="eip55---mixed-case-checksum-address-encoding">EIP55 - Mixed-case checksum address encoding</h3>
<p>Support: Full.<br />
Reference: https://eips.ethereum.org/EIPS/eip-55<br />
Description: Checksum standard that uses lowercase and uppercase inside address hex value.<br />
Used for: Sanity check of forms using ethereum address.<br />
Related: https://github.com/status-im/status-react/issues/4959 https://github.com/status-im/status-react/issues/8707<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/eip55.cljs</p>
<h3 id="eip67---standard-uri-scheme-with-metadata-value-and-byte-code">EIP67 - Standard URI scheme with metadata, value and byte code</h3>
<p>Support: Partial.<br />
Reference: https://github.com/ethereum/EIPs/issues/67<br />
Description: A standard way of creating Ethereum URIs for various use-cases.<br />
Used for: Legacy support.<br />
https://github.com/status-im/status-react/issues/875</p>
<h3 id="eip137---ethereum-domain-name-service---specification">EIP137 - Ethereum Domain Name Service - Specification</h3>
<p>Support: Partial.<br />
Reference: https://eips.ethereum.org/EIPS/eip-137<br />
Description: Enable wallets to lookup ENS names.<br />
Used for: User experience, as a wallet and identity feature, usernames.<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/ens.cljs#L86</p>
<h3 id="eip155---simple-replay-attack-protection">EIP155 - Simple replay attack protection</h3>
<p>Support: Full.<br />
Reference: https://eips.ethereum.org/EIPS/eip-155<br />
Description: Defined chainId parameter in the singed ethereum transaction payload.<br />
Used for: Signing transactions, crucial to safety of users against replay attacks.<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/core.cljs</p>
<h3 id="eip165---standard-interface-detection">EIP165 - Standard Interface Detection</h3>
<p>Support: Dependency/Partial.<br />
Reference: https://eips.ethereum.org/EIPS/eip-165<br />
Description: Standard interface for contract to answer if it supports other interfaces.<br />
Used for: Dependency of ENS and EIP721.<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/eip165.cljs</p>
<h3 id="eip181---ens-support-for-reverse-resolution-of-ethereum-addresses">EIP181 - ENS support for reverse resolution of Ethereum addresses</h3>
<p>Support: Partial.<br />
Reference: https://eips.ethereum.org/EIPS/eip-181<br />
Description: Enable wallets to render reverse resolution of Ethereum addresses.<br />
Used for: Wallet feature.<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/ens.cljs#L86</p>
<h3 id="eip191---signed-message">EIP191 - Signed Message</h3>
<p>Support: Full.<br />
Reference: https://eips.ethereum.org/EIPS/eip-191<br />
Description: Contract signature standard, adds an obligatory padding to signed message to differentiate from Ethereum Transaction messages.<br />
Used for: Dapp support, security, dependency of ERC712.</p>
<h3 id="eip627---whisper-specification">EIP627 - Whisper Specification</h3>
<p>Support: Full.<br />
Reference: https://eips.ethereum.org/EIPS/eip-627<br />
Description: format of Whisper messages within the ÐΞVp2p Wire Protocol.<br />
Used for: Chat protocol.</p>
<h3 id="eip681---url-format-for-transaction-requests">EIP681 - URL Format for Transaction Requests</h3>
<p>Support: Partial.<br />
Reference: https://eips.ethereum.org/EIPS/eip-681
Description: A link that pop up a transaction in the wallet.<br />
Used for: Useful as QR code data for transaction requests, chat transaction requests and for dapp links to transaction requests.<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/eip681.cljs<br />
Related: <a href="https://github.com/status-im/status-react/issues/9183">Issue #9183: URL Format for Transaction Requests (EIP681) is poorly supported</a> https://github.com/status-im/status-react/pull/9240 https://github.com/status-im/status-react/issues/9238 https://github.com/status-im/status-react/issues/7214 https://github.com/status-im/status-react/issues/7325 https://github.com/status-im/status-react/issues/8150</p>
<h3 id="eip712---typed-signed-message">EIP712 - Typed Signed Message</h3>
<p>Support: Partial.<br />
Reference: https://eips.ethereum.org/EIPS/eip-712<br />
Description: Standardize types for contract signature, allowing users to easily inspect whats being signed.<br />
Used for: User experience, security.<br />
Related: https://github.com/status-im/status-react/issues/5461 https://github.com/status-im/status-react/commit/ba37f7b8d029d3358c7b284f6a2383b9ef9526c9</p>
<h3 id="eip721---non-fungible-token">EIP721 - Non Fungible Token</h3>
<p>Support: Partial.<br />
Reference: https://eips.ethereum.org/EIPS/eip-721<br />
Description: Enable wallets to use tokens based on smart contracts compliant with this standard.<br />
Used for: Wallet feature.<br />
Related: https://github.com/status-im/status-react/issues/8909<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/erc721.cljs https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/tokens.cljs</p>
<h3 id="eip945---web-3-qr-code-scanning-api">EIP945 - Web 3 QR Code Scanning API</h3>
<p>Support: Full.<br />
Reference: https://github.com/ethereum/EIPs/issues/945<br />
Used for: Sharing contactcode, reading transaction requests.<br />
Related: https://github.com/status-im/status-react/issues/5870</p>
<h3 id="eip1102---opt-in-account-exposure">EIP1102 - Opt-in account exposure</h3>
<p>Support: Full.<br />
Reference: https://eips.ethereum.org/EIPS/eip-1102<br />
Description: Allow users to opt-in the exposure of their ethereum address to dapps they browse.<br />
Used for: Privacy, DApp support.<br />
Related: https://github.com/status-im/status-react/issues/7985</p>
<h3 id="eip1193---ethereum-provider-javascript-api">EIP1193 - Ethereum Provider JavaScript API</h3>
<p>Support: Full.<br />
Reference: https://eips.ethereum.org/EIPS/eip-1193<br />
Description: Allows dapps to recognize event changes on wallet.<br />
Used for: DApp support.<br />
Related: https://github.com/status-im/status-react/pull/7246</p>
<h3 id="eip1577---contenthash-field-for-ens">EIP1577 - contenthash field for ENS</h3>
<p>Support: Partial.<br />
Reference: https://eips.ethereum.org/EIPS/eip-1577<br />
Description: Allows users browse ENS domains using contenthash standard.<br />
Used for: Browser, DApp support.<br />
Related: https://github.com/status-im/status-react/issues/6688<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/utils/contenthash.cljs https://github.com/status-im/status-react/blob/develop/test/cljs/status_im/test/utils/contenthash.cljs#L5</p>
<h3 id="eip1581---non-wallet-usage-of-keys-derived-from-bip-32-trees">EIP1581 - Non-wallet usage of keys derived from BIP-32 trees</h3>
<p>Support: Partial.<br />
Reference: https://eips.ethereum.org/EIPS/eip-1581<br />
Description: Allow wallet to derive keys that are less sensible (non wallet).<br />
Used for: Security (dont reuse wallet key) and user experience (dont request keycard every login).<br />
Related: https://github.com/status-im/status-react/issues/9088 https://github.com/status-im/status-react/pull/9096<br />
Sourcecode: https://github.com/status-im/status-react/blob/develop/src/status_im/constants.cljs#L242</p>
<h3 id="eip1459---node-discovery-via-dns">EIP1459 - Node Discovery via DNS</h3>
<p>Support: -
Reference: https://eips.ethereum.org/EIPS/eip-1459
Description: Allows the storing and retrieving of nodes through merkle trees stored in TXT records of a domain.
Used for: Finding Waku nodes.
Related: -
Sourcecode: -</p>

View File

@ -1,222 +0,0 @@
<h1 id="9ethereum-usage">9/ETHEREUM-USAGE</h1>
<blockquote>
<p>Version: 0.1</p>
<p>Status: Stable</p>
<p>Authors: Andrea Maria Piana <a href="mailto:andreap@status.im">andreap@status.im</a></p>
</blockquote>
<h1 id="status-interactions-with-the-ethereum-blockchain">Status interactions with the Ethereum blockchain</h1>
<p>This specification documents all the interactions that the Status client has
with the <a href="https://ethereum.org/developers/">Ethereum</a> blockchain.</p>
<p>All the interactions are made through <a href="https://github.com/ethereum/wiki/wiki/JSON-RPC">JSON-RPC</a>.
Currently <a href="https://infura.io/">Infura</a> is used. The client assumes high-availability, otherwise
it will not be able to interact with the Ethereum blockchain.
Status nodes rely on these Infura nodes to validate the integrity of the transaction and report a
consistent history.</p>
<p>Key handling is described <a href="./2-account.md">here</a></p>
<ol>
<li><a href="#Wallet">Wallet</a></li>
<li><a href="#ENS">ENS</a></li>
</ol>
<h2 id="wallet">Wallet</h2>
<p>The wallet in Status has two main components:</p>
<p>1) Sending transactions
2) Fetching balance</p>
<p>In the section below are described the <code class="language-plaintext highlighter-rouge">RPC</code> calls made the nodes, with a brief
description of their functionality and how it is used by Status.</p>
<ol>
<li><a href="#Sending-transactions">Sending transactions</a>
<ul>
<li><a href="#EstimateGas">EstimateGas</a></li>
<li><a href="#PendingNonceAt">PendingNonceAt</a></li>
<li><a href="#SuggestGasPrice">SuggestGasPrice</a></li>
<li><a href="#SendTransaction">SendTransaction</a></li>
</ul>
</li>
<li><a href="#Fetching-balance">Fetching balance</a>
<ul>
<li><a href="#BlockByHash">BlockByHash</a></li>
<li><a href="#BlockByNumber">BlockByNumber</a></li>
<li><a href="#FilterLogs">FilterLogs</a></li>
<li><a href="#HeaderByNumber">HeaderByNumber</a></li>
<li><a href="#NonceAt">NonceAt</a></li>
<li><a href="#TransactionByHash">TransactionByHash</a></li>
<li><a href="#TransactionReceipt">TransactionReceipt</a></li>
</ul>
</li>
</ol>
<h3 id="sending-transactions">Sending transactions</h3>
<h4 id="estimategas">EstimateGas</h4>
<p>EstimateGas tries to estimate the gas needed to execute a specific transaction based on
the current pending state of the backend blockchain. There is no guarantee that this is
the true gas limit requirement as other transactions may be added or removed by miners,
but it should provide a basis for setting a reasonable default.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L499</p>
<h4 id="pendingnonceat">PendingNonceAt</h4>
<p><code class="language-plaintext highlighter-rouge">PendingNonceAt</code> returns the account nonce of the given account in the pending state.
This is the nonce that should be used for the next transaction.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L440</p>
<h4 id="suggestgasprice">SuggestGasPrice</h4>
<p><code class="language-plaintext highlighter-rouge">SuggestGasPrice</code> retrieves the currently suggested gas price to allow a timely
execution of a transaction.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L487</p>
<h4 id="sendtransaction">SendTransaction</h4>
<p><code class="language-plaintext highlighter-rouge">SendTransaction</code> injects a signed transaction into the pending pool for execution.</p>
<p>If the transaction was a contract creation use the TransactionReceipt method to get the
contract address after the transaction has been mined.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L512</p>
<h3 id="fetching-balance">Fetching balance</h3>
<p>A Status node fetches the current and historical [ECR20] (https://eips.ethereum.org/EIPS/eip-20) and ETH balance for the user wallet address.
Collectibles following the <a href="https://eips.ethereum.org/EIPS/eip-721">ECR-721</a> are also fetched if enabled.</p>
<p>A Status node supports by default the following <a href="https://github.com/status-im/status-react/blob/develop/src/status_im/ethereum/tokens.cljs">tokens</a>. Custom tokens can be added by specifying the <code class="language-plaintext highlighter-rouge">address</code>, <code class="language-plaintext highlighter-rouge">symbol</code> and <code class="language-plaintext highlighter-rouge">decimals</code>.</p>
<h4 id="blockbyhash">BlockByHash</h4>
<p><code class="language-plaintext highlighter-rouge">BlockByHash</code> returns the given full block.</p>
<p>It is used by status to fetch a given block which will then be inspected for
transfers to the user address, both tokens and ETH.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L78</p>
<h4 id="blockbynumber">BlockByNumber</h4>
<p><code class="language-plaintext highlighter-rouge">BlockByNumber</code> returns a block from the current canonical chain. If number is nil, the
latest known block is returned.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L82</p>
<h4 id="filterlogs">FilterLogs</h4>
<p><code class="language-plaintext highlighter-rouge">FilterLogs</code> executes a filter query.</p>
<p>Status uses this function to filter out logs, using the hash of the block
and the address of interest, both inbound and outbound.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L377</p>
<h4 id="nonceat">NonceAt</h4>
<p><code class="language-plaintext highlighter-rouge">NonceAt</code> returns the account nonce of the given account.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L366</p>
<h4 id="transactionbyhash">TransactionByHash</h4>
<p><code class="language-plaintext highlighter-rouge">TransactionByHash</code> returns the transaction with the given hash, used to inspect those
transactions made/received by the user.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L202</p>
<h4 id="headerbynumber">HeaderByNumber</h4>
<p><code class="language-plaintext highlighter-rouge">HeaderByNumber</code> returns a block header from the current canonical chain.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L172</p>
<h4 id="transactionreceipt">TransactionReceipt</h4>
<p><code class="language-plaintext highlighter-rouge">TransactionReceipt</code> returns the receipt of a transaction by transaction hash.
It is used in status to check if a token transfer was made to the user address.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
</code></pre></div></div>
<p>https://github.com/ethereum/go-ethereum/blob/26d271dfbba1367326dec38068f9df828d462c61/ethclient/ethclient.go#L270</p>
<h2 id="ens">ENS</h2>
<p>All the interactions with <code class="language-plaintext highlighter-rouge">ENS</code> are made through the <a href="https://github.com/ensdomains/ens">ENS contract</a></p>
<p>For the <code class="language-plaintext highlighter-rouge">stateofus.eth</code> username, one can be registered through these <a href="https://github.com/status-im/ens-usernames">contracts</a></p>
<h3 id="registering-releasing-and-updating">Registering, releasing and updating</h3>
<ul>
<li><a href="https://github.com/status-im/ens-usernames/blob/77d9394d21a5b6213902473b7a16d62a41d9cd09/contracts/registry/UsernameRegistrar.sol#L113">Registering a username</a></li>
<li><a href="https://github.com/status-im/ens-usernames/blob/77d9394d21a5b6213902473b7a16d62a41d9cd09/contracts/registry/UsernameRegistrar.sol#L131">Releasing a username</a></li>
<li><a href="https://github.com/status-im/ens-usernames/blob/77d9394d21a5b6213902473b7a16d62a41d9cd09/contracts/registry/UsernameRegistrar.sol#L174">Updating a username</a></li>
</ul>
<h3 id="slashing">Slashing</h3>
<p>Usernames MUST be in a specific format, otherwise they MAY be slashed:</p>
<ul>
<li>They MUST only contain alphanumeric characters</li>
<li>They MUST NOT be in the form <code class="language-plaintext highlighter-rouge">0x[0-9a-f]{5}.*</code> and have more than 12 characters</li>
<li>They MUST NOT be in the <a href="https://github.com/status-im/ens-usernames/blob/47c4c6c2058be0d80b7d678e611e166659414a3b/config/ens-usernames/reservedNames.js">reserved list</a></li>
<li>
<p>They MUST NOT be too short, this is dynamically set in the contract and can be checked against the <a href="https://github.com/status-im/ens-usernames/blob/master/contracts/registry/UsernameRegistrar.sol#L26">contract</a></p>
</li>
<li><a href="https://github.com/status-im/ens-usernames/blob/77d9394d21a5b6213902473b7a16d62a41d9cd09/contracts/registry/UsernameRegistrar.sol#L237">Slash a reserved username</a></li>
<li><a href="https://github.com/status-im/ens-usernames/blob/77d9394d21a5b6213902473b7a16d62a41d9cd09/contracts/registry/UsernameRegistrar.sol#L261">Slash an invalid username</a></li>
<li><a href="https://github.com/status-im/ens-usernames/blob/77d9394d21a5b6213902473b7a16d62a41d9cd09/contracts/registry/UsernameRegistrar.sol#L215">Slash a username too similar to an address</a></li>
<li><a href="https://github.com/status-im/ens-usernames/blob/77d9394d21a5b6213902473b7a16d62a41d9cd09/contracts/registry/UsernameRegistrar.sol#L200">Slash a username that is too short</a></li>
</ul>
<p>ENS names are propagated through <code class="language-plaintext highlighter-rouge">ChatMessage</code> and <code class="language-plaintext highlighter-rouge">ContactUpdate</code> <a href="./6-payloads.md">payload</a>.
A client SHOULD verify ens names against the public key of the sender on receiving the message against the <a href="https://github.com/ensdomains/ens">ENS contract</a></p>
<h2 id="copyright">Copyright</h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>

View File

@ -1,290 +0,0 @@
<h2 id="table-of-contents">Table of Contents</h2>
<ol>
<li><a href="#abstract">Abstract</a></li>
<li><a href="#definitions">Definitions</a></li>
<li><a href="#Multiaccount-creationrestoring">Multiaccount creation</a></li>
<li><a href="#Multiaccount-restoring-via-pairing">Multiaccount restoring via pairing</a></li>
<li><a href="#Multiaccount-unlocking">Multiaccount unlocking</a></li>
<li><a href="#Transaction-signing">Transaction signing</a></li>
<li><a href="#Account-derivation">Account derivation</a></li>
<li><a href="#Reset-pin">Reset pin</a></li>
<li><a href="#Unblock-pin">Unblock pin</a></li>
<li><a href="#Status-go-calls">Status go calls</a></li>
<li><a href="#Where-are-the-keys-stored">Where are the keys stored?</a></li>
<li><a href="#Copyright">Copyright</a></li>
</ol>
<h2 id="abstract">Abstract</h2>
<p>In this specification, we describe how Status communicates with Keycard to create, store and use multiaccount.</p>
<h2 id="definitions">Definitions</h2>
<table>
<thead>
<tr>
<th>Term</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>Keycard Hardwallet</td>
<td><a href="https://keycard.tech/docs/">https://keycard.tech/docs/</a></td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
<h2 id="multiaccount-creationrestoring">Multiaccount creation/restoring</h2>
<h3 id="creation-and-restoring-via-mnemonic">Creation and restoring via mnemonic</h3>
<ol>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/get-application-info</code>
request: <code class="language-plaintext highlighter-rouge">nil</code>
response: <code class="language-plaintext highlighter-rouge">{"initialized?" false}</code></li>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/init-card</code>
request: <code class="language-plaintext highlighter-rouge">{:pin 123123}</code>
response:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="s">"password"</span><span class="w"> </span><span class="s">"nEJXqf6VWbqeC5oN"</span><span class="n">,</span><span class="w">
</span><span class="s">"puk"</span><span class="w"> </span><span class="s">"411810112887"</span><span class="n">,</span><span class="w">
</span><span class="s">"pin"</span><span class="w"> </span><span class="s">"123123"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
</li>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/get-application-info</code>
request: <code class="language-plaintext highlighter-rouge">nil</code>
response:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="s">"free-pairing-slots"</span><span class="w"> </span><span class="mi">5</span><span class="n">,</span><span class="w">
</span><span class="s">"app-version"</span><span class="w"> </span><span class="s">"2.2"</span><span class="n">,</span><span class="w">
</span><span class="s">"secure-channel-pub-key"</span><span class="w"> </span><span class="s">"04e70d7af7d91b8cd23adbefdfc242c096adee6c1b5ad27a4013a8f926864c1a4f816b338238dc4a04226ab42f23672585c6dca03627885530643f1656ee69b025"</span><span class="n">,</span><span class="w">
</span><span class="s">"key-uid"</span><span class="w"> </span><span class="s">""</span><span class="n">,</span><span class="w">
</span><span class="s">"instance-uid"</span><span class="w"> </span><span class="s">"9f149d438988a7af5e1a186f650c9328"</span><span class="n">,</span><span class="w">
</span><span class="s">"paired?"</span><span class="w"> </span><span class="n">false,</span><span class="w">
</span><span class="s">"has-master-key?"</span><span class="w"> </span><span class="n">false,</span><span class="w">
</span><span class="s">"initialized?"</span><span class="w"> </span><span class="n">true</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/pair</code>
params: <code class="language-plaintext highlighter-rouge">{:password "nEJXqf6VWbqeC5oN"}</code>
response: <code class="language-plaintext highlighter-rouge">AAVefVX0kPGsxnvQV5OXRbRTLGI3k8/S27rpsq/lZrVR</code> (<code class="language-plaintext highlighter-rouge">pairing</code>)</p>
</li>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/generate-and-load-keys</code>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="no">:mnemonic</span><span class="w"> </span><span class="s">"lift mansion moment version card type uncle sunny lock gather nerve math"</span><span class="n">,</span><span class="w">
</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"AAVefVX0kPGsxnvQV5OXRbRTLGI3k8/S27rpsq/lZrVR"</span><span class="n">,</span><span class="w">
</span><span class="no">:pin</span><span class="w"> </span><span class="s">"123123"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response:</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="s">"whisper-address"</span><span class="w"> </span><span class="s">"1f29a1a60c8a12f80c397a91c6ae0323f420e609"</span><span class="n">,</span><span class="w">
</span><span class="s">"whisper-private-key"</span><span class="w"> </span><span class="s">"123123123123123"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-root-public-key"</span><span class="w"> </span><span class="s">"04eb9d01990a106a65a6dfaa48300f72aecfeabe502d9f4f7aeaccb146dc2f16e2dec81dcec0a1a52c1df4450f441a48c210e1a73777c0161030378df22e4ae015"</span><span class="n">,</span><span class="w">
</span><span class="s">"encryption-public-key"</span><span class="w"> </span><span class="s">"045ee42f012d72be74b31a28ce320df617e0cd5b9b343fad34fcd61e2f5dfa89ab23d880473ba4e95401a191764c7f872b7af92ea0d8c39462147df6f3f05c2a11"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-root-address"</span><span class="w"> </span><span class="s">"132dd67ff47cc1c376879c474fd2afd0f1eee6de"</span><span class="n">,</span><span class="w">
</span><span class="s">"whisper-public-key"</span><span class="w"> </span><span class="s">"0450ad84bb95f32c64f4e5027cc11d1b363a0566a0cfc475c5653e8af9964c5c9b0661129b75e6e1bc6e96ba2443238e53e7f49f2c5f2d16fcf04aca4826765d46"</span><span class="n">,</span><span class="w">
</span><span class="s">"address"</span><span class="w"> </span><span class="s">"bf93eb43fea2ce94bf3a6463c16680b56aa4a08a"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-address"</span><span class="w"> </span><span class="s">"7eee1060d8e4722d36c99f30ff8291caa3cfc40c"</span><span class="n">,</span><span class="w">
</span><span class="s">"key-uid"</span><span class="w"> </span><span class="s">"472d8436ccedb64bcbd897bed5895ec3458b306352e1bcee377df87db32ef2c2"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-public-key"</span><span class="w"> </span><span class="s">"0495ab02978ea1f8b059140e0be5a87aad9b64bb7d9706735c47dda6e182fd5ca41744ca37583b9a10c316b01d4321d6c85760c61301874089acab041037246294"</span><span class="n">,</span><span class="w">
</span><span class="s">"public-key"</span><span class="w"> </span><span class="s">"0465d452d12171711f32bb931f9ea26fe1b88fe2511a7909a042b914fde10a99719136365d506e2d1694fc14627f9d557da33865efc6001da3942fc1d4d2469ca1"</span><span class="n">,</span><span class="w">
</span><span class="s">"instance-uid"</span><span class="w"> </span><span class="s">"9f149d438988a7af5e1a186f650c9328"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
</li>
</ol>
<h3 id="multiaccount-restoring-via-pairing">Multiaccount restoring via pairing</h3>
<p>This flow is required in case if a user want to pair a card with an existing multiaccount on it.</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/get-application-info</code>
request: <code class="language-plaintext highlighter-rouge">nil</code>
response:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="s">"free-pairing-slots"</span><span class="w"> </span><span class="mi">4</span><span class="n">,</span><span class="w">
</span><span class="s">"app-version"</span><span class="w"> </span><span class="s">"2.2"</span><span class="n">,</span><span class="w">
</span><span class="s">"secure-channel-pub-key"</span><span class="w"> </span><span class="s">"04e70d7af7d91b8cd23adbefdfc242c096adee6c1b5ad27a4013a8f926864c1a4f816b338238dc4a04226ab42f23672585c6dca03627885530643f1656ee69b025"</span><span class="n">,</span><span class="w">
</span><span class="s">"key-uid"</span><span class="w"> </span><span class="s">""</span><span class="n">,</span><span class="w">
</span><span class="s">"instance-uid"</span><span class="w"> </span><span class="s">"9f149d438988a7af5e1a186f650c9328"</span><span class="n">,</span><span class="w">
</span><span class="s">"paired?"</span><span class="w"> </span><span class="n">false,</span><span class="w">
</span><span class="s">"has-master-key?"</span><span class="w"> </span><span class="n">false,</span><span class="w">
</span><span class="s">"initialized?"</span><span class="w"> </span><span class="n">true</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/pair</code>
params: <code class="language-plaintext highlighter-rouge">{:password "nEJXqf6VWbqeC5oN"}</code>
response: <code class="language-plaintext highlighter-rouge">AAVefVX0kPGsxnvQV5OXRbRTLGI3k8/S27rpsq/lZrVR</code> (<code class="language-plaintext highlighter-rouge">pairing</code>)</p>
</li>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/generate-and-load-keys</code>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="no">:mnemonic</span><span class="w"> </span><span class="s">"lift mansion moment version card type uncle sunny lock gather nerve math"</span><span class="n">,</span><span class="w">
</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"AAVefVX0kPGsxnvQV5OXRbRTLGI3k8/S27rpsq/lZrVR"</span><span class="n">,</span><span class="w">
</span><span class="no">:pin</span><span class="w"> </span><span class="s">"123123"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response:</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="s">"whisper-address"</span><span class="w"> </span><span class="s">"1f29a1a60c8a12f80c397a91c6ae0323f420e609"</span><span class="n">,</span><span class="w">
</span><span class="s">"whisper-private-key"</span><span class="w"> </span><span class="s">"123123123123123123123"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-root-public-key"</span><span class="w"> </span><span class="s">"04eb9d01990a106a65a6dfaa48300f72aecfeabe502d9f4f7aeaccb146dc2f16e2dec81dcec0a1a52c1df4450f441a48c210e1a73777c0161030378df22e4ae015"</span><span class="n">,</span><span class="w">
</span><span class="s">"encryption-public-key"</span><span class="w"> </span><span class="s">"045ee42f012d72be74b31a28ce320df617e0cd5b9b343fad34fcd61e2f5dfa89ab23d880473ba4e95401a191764c7f872b7af92ea0d8c39462147df6f3f05c2a11"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-root-address"</span><span class="w"> </span><span class="s">"132dd67ff47cc1c376879c474fd2afd0f1eee6de"</span><span class="n">,</span><span class="w">
</span><span class="s">"whisper-public-key"</span><span class="w"> </span><span class="s">"0450ad84bb95f32c64f4e5027cc11d1b363a0566a0cfc475c5653e8af9964c5c9b0661129b75e6e1bc6e96ba2443238e53e7f49f2c5f2d16fcf04aca4826765d46"</span><span class="n">,</span><span class="w">
</span><span class="s">"address"</span><span class="w"> </span><span class="s">"bf93eb43fea2ce94bf3a6463c16680b56aa4a08a"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-address"</span><span class="w"> </span><span class="s">"7eee1060d8e4722d36c99f30ff8291caa3cfc40c"</span><span class="n">,</span><span class="w">
</span><span class="s">"key-uid"</span><span class="w"> </span><span class="s">"472d8436ccedb64bcbd897bed5895ec3458b306352e1bcee377df87db32ef2c2"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-public-key"</span><span class="w"> </span><span class="s">"0495ab02978ea1f8b059140e0be5a87aad9b64bb7d9706735c47dda6e182fd5ca41744ca37583b9a10c316b01d4321d6c85760c61301874089acab041037246294"</span><span class="n">,</span><span class="w">
</span><span class="s">"public-key"</span><span class="w"> </span><span class="s">"0465d452d12171711f32bb931f9ea26fe1b88fe2511a7909a042b914fde10a99719136365d506e2d1694fc14627f9d557da33865efc6001da3942fc1d4d2469ca1"</span><span class="n">,</span><span class="w">
</span><span class="s">"instance-uid"</span><span class="w"> </span><span class="s">"9f149d438988a7af5e1a186f650c9328"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
</li>
</ol>
<h2 id="multiaccount-unlocking">Multiaccount unlocking</h2>
<ol>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/get-application-info</code>
params:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="no">:pairing</span><span class="w"> </span><span class="n">nil,</span><span class="w"> </span><span class="no">:on-success</span><span class="w"> </span><span class="n">nil</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response:</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="s">"free-pairing-slots"</span><span class="w"> </span><span class="mi">4</span><span class="n">,</span><span class="w">
</span><span class="s">"app-version"</span><span class="w"> </span><span class="s">"2.2"</span><span class="n">,</span><span class="w">
</span><span class="s">"secure-channel-pub-key"</span><span class="w"> </span><span class="s">"04b079ac513d5e0ebbe9becbae1618503419f5cb59edddc7d7bb09ce0db069a8e6dec1fb40c6b8e5454f7e1fcd0bb4a0b9750256afb4e4390e169109f3ea3ba91d"</span><span class="n">,</span><span class="w">
</span><span class="s">"key-uid"</span><span class="w"> </span><span class="s">"a5424fb033f5cc66dce9cbbe464426b6feff70ca40aa952c56247aaeaf4764a9"</span><span class="n">,</span><span class="w">
</span><span class="s">"instance-uid"</span><span class="w"> </span><span class="s">"2268254e3ed7898839abe0b40e1b4200"</span><span class="n">,</span><span class="w">
</span><span class="s">"paired?"</span><span class="w"> </span><span class="n">false,</span><span class="w">
</span><span class="s">"has-master-key?"</span><span class="w"> </span><span class="n">true,</span><span class="w">
</span><span class="s">"initialized?"</span><span class="w"> </span><span class="n">true</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
</li>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/get-keys</code>
params:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"ACEWbvUlordYWOE6M1Narn/AXICRltjyuKIAn4kkPXQG"</span><span class="n">,</span><span class="w">
</span><span class="no">:pin</span><span class="w"> </span><span class="s">"123123"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response:</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="s">"whisper-address"</span><span class="w"> </span><span class="s">"ec83f7354ca112203d2ce3e0b77b47e6e33258aa"</span><span class="n">,</span><span class="w">
</span><span class="s">"whisper-private-key"</span><span class="w"> </span><span class="s">"123123123123123123123123"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-root-public-key"</span><span class="w"> </span><span class="s">"0424a93fe62a271ad230eb2957bf221b4644670589f5c0d69bd11f3371034674bf7875495816095006c2c0d5f834d628b87691a8bbe3bcc2225269020febd65a19"</span><span class="n">,</span><span class="w">
</span><span class="s">"encryption-public-key"</span><span class="w"> </span><span class="s">"0437eef85e669f800570f444e64baa2d0580e61cf60c0e9236b4108455ec1943f385043f759fcb5bd8348e32d6d6550a844cf24e57f68e9397a0f7c824a8caee2d"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-root-address"</span><span class="w"> </span><span class="s">"6ff915f9f31f365511b1b8c1e40ce7f266caa5ce"</span><span class="n">,</span><span class="w">
</span><span class="s">"whisper-public-key"</span><span class="w"> </span><span class="s">"04b195df4336c596cca1b89555dc55dd6bb4c5c4491f352f6fdfae140a2349213423042023410f73a862aa188f6faa05c80b0344a1e39c253756cb30d8753f9f8324"</span><span class="n">,</span><span class="w">
</span><span class="s">"address"</span><span class="w"> </span><span class="s">"73509a1bb5f3b74d0dba143705cd9b4b55b8bba1"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-address"</span><span class="w"> </span><span class="s">"2f0cc0e0859e7a05f319d902624649c7e0f48955"</span><span class="n">,</span><span class="w">
</span><span class="s">"key-uid"</span><span class="w"> </span><span class="s">"a5424fb033f5cc66dce9cbbe464426b6feff70ca40aa952c56247aaeaf4764a9"</span><span class="n">,</span><span class="w">
</span><span class="s">"wallet-public-key"</span><span class="w"> </span><span class="s">"04d6fab73772933215872c239787b2281f3b10907d099d04b88c861e713bd2b95883e0b1710a266830da29e76bbf6b87ed034ab139e36cc235a1b2a5b5ddfd4e91"</span><span class="n">,</span><span class="w">
</span><span class="s">"public-key"</span><span class="w"> </span><span class="s">"0437eef85e669f800570f444e64baa2d0580e61cf60c0e9236b4108455ec1943f385043f759fcb5bd8348e32d6d6550a844cf24e57f68e9397a0f7c824a8caee2d"</span><span class="n">,</span><span class="w">
</span><span class="s">"instance-uid"</span><span class="w"> </span><span class="s">"2268254e3ed7898839abe0b40e1b4200"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
</li>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/get-application-info</code>
params:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"ACEWbvUlordYWOE6M1Narn/AXICRltjyuKIAn4kkPXQG"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response:</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="s">"paired?"</span><span class="w"> </span><span class="n">true,</span><span class="w">
</span><span class="s">"has-master-key?"</span><span class="w"> </span><span class="n">true,</span><span class="w">
</span><span class="s">"app-version"</span><span class="w"> </span><span class="s">"2.2"</span><span class="n">,</span><span class="w">
</span><span class="s">"free-pairing-slots"</span><span class="w"> </span><span class="mi">4</span><span class="n">,</span><span class="w">
</span><span class="s">"pin-retry-counter"</span><span class="w"> </span><span class="mi">3</span><span class="n">,</span><span class="w">
</span><span class="s">"puk-retry-counter"</span><span class="w"> </span><span class="mi">5</span><span class="n">,</span><span class="w">
</span><span class="s">"initialized?"</span><span class="w"> </span><span class="n">true,</span><span class="w">
</span><span class="s">"secure-channel-pub-key"</span><span class="w"> </span><span class="s">"04b079ac513d5e0ebbe9becbae1618503419f5cb59edddc7d7bb09ce0db069a8e6dec1fb40c6b8e5454f7e1fcd0bb4a0b9750256afb4e4390e169109f3ea3ba91d"</span><span class="n">,</span><span class="w">
</span><span class="s">"key-uid"</span><span class="w"> </span><span class="s">"a5424fb033f5cc66dce9cbbe464426b6feff70ca40aa952c56247aaeaf4764a9"</span><span class="n">,</span><span class="w">
</span><span class="s">"instance-uid"</span><span class="w"> </span><span class="s">"2268254e3ed7898839abe0b40e1b4200"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
</li>
</ol>
<h2 id="transaction-signing">Transaction signing</h2>
<ol>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/get-application-info</code>
params:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"ALecvegKyOW4szknl01yYWx60GLDK5gDhxMgJECRZ+7h"</span><span class="n">,</span><span class="w">
</span><span class="no">:on-success</span><span class="w"> </span><span class="no">:hardwallet/sign</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response:</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="s">"paired?"</span><span class="w"> </span><span class="n">true,</span><span class="w">
</span><span class="s">"has-master-key?"</span><span class="w"> </span><span class="n">true,</span><span class="w">
</span><span class="s">"app-version"</span><span class="w"> </span><span class="s">"2.2"</span><span class="n">,</span><span class="w">
</span><span class="s">"free-pairing-slots"</span><span class="w"> </span><span class="mi">4</span><span class="n">,</span><span class="w">
</span><span class="s">"pin-retry-counter"</span><span class="w"> </span><span class="mi">3</span><span class="n">,</span><span class="w">
</span><span class="s">"puk-retry-counter"</span><span class="w"> </span><span class="mi">5</span><span class="n">,</span><span class="w">
</span><span class="s">"initialized?"</span><span class="w"> </span><span class="n">true,</span><span class="w">
</span><span class="s">"secure-channel-pub-key"</span><span class="w"> </span><span class="s">"0476d11f2ccdad4e7779b95a1ce063d7280cb6c09afe2c0e48ca0c64ab9cf2b3c901d12029d6c266bfbe227c73a802561302b2330ac07a3270fc638ad258fced4a"</span><span class="n">,</span><span class="w">
</span><span class="s">"key-uid"</span><span class="w"> </span><span class="s">"d5c8cde8085e7a3fcf95aafbcbd7b3cfe32f61b85c2a8f662f60e76bdc100718"</span><span class="n">,</span><span class="w">
</span><span class="s">"instance-uid"</span><span class="w"> </span><span class="s">"e20e27bfee115b431e6e81b8e9dcf04c"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
</li>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/sign</code>
params:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="no">:hash</span><span class="w"> </span><span class="s">"92fc7ef54c3e0c42de256b93fbf2c49dc6948ee089406e204dec943b7a0142a9"</span><span class="n">,</span><span class="w">
</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"ALecvegKyOW4szknl01yYWx60GLDK5gDhxMgJECRZ+7h"</span><span class="n">,</span><span class="w">
</span><span class="no">:pin</span><span class="w"> </span><span class="s">"123123"</span><span class="n">,</span><span class="w">
</span><span class="no">:path</span><span class="w"> </span><span class="s">"m/44'/60'/0'/0/0"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response: <code class="language-plaintext highlighter-rouge">5d2ca075593cf50aa34007a0a1df7df14a369534450fce4a2ae8d023a9d9c0e216b5e5e3f64f81bee91613318d01601573fdb15c11887a3b8371e3291e894de600</code></p>
</li>
</ol>
<h2 id="account-derivation">Account derivation</h2>
<ol>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/verify-pin</code>
params:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="no">:pin</span><span class="w"> </span><span class="s">"123123"</span><span class="n">,</span><span class="w">
</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"ALecvegKyOW4szknl01yYWx60GLDK5gDhxMgJECRZ+7h"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response: <code class="language-plaintext highlighter-rouge">3</code></p>
</li>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/export-key</code>
params:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="p">{</span><span class="no">:pin</span><span class="w"> </span><span class="s">"123123"</span><span class="n">,</span><span class="w">
</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"ALecvegKyOW4szknl01yYWx60GLDK5gDhxMgJECRZ+7h"</span><span class="n">,</span><span class="w">
</span><span class="no">:path</span><span class="w"> </span><span class="s">"m/44'/60'/0'/0/1"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response: <code class="language-plaintext highlighter-rouge">046d1bcd2310a5e0094bc515b0ec995a8cb59e23d564094443af10011b6c00bdde44d160cdd32b4b6341ddd7dc83a4f31fdf60ec2276455649ccd7a22fa4ea01d8</code> (accounts <code class="language-plaintext highlighter-rouge">public-key</code>)</p>
</li>
</ol>
<h2 id="reset-pin">Reset pin</h2>
<ol>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/change-pin</code>
params:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="no">:new-pin</span><span class="w"> </span><span class="s">"111111"</span><span class="n">,</span><span class="w">
</span><span class="no">:current-pin</span><span class="w"> </span><span class="s">"222222"</span><span class="n">,</span><span class="w">
</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"AA0sKxPkN+jMHXZZeI8Rgz04AaY5Fg0CzVbm9189Khob"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response:
<code class="language-plaintext highlighter-rouge">true</code></p>
</li>
</ol>
<h2 id="unblock-pin">Unblock pin</h2>
<p>If user enters a wrong pin three times in a row a card gets blocked. The user can use puk code then to unblock the card and set a new pin.</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/unblock-pin</code>
params:
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="no">:puk</span><span class="w"> </span><span class="s">"120702722103"</span><span class="n">,</span><span class="w">
</span><span class="no">:new-pin</span><span class="w"> </span><span class="s">"111111"</span><span class="n">,</span><span class="w">
</span><span class="no">:pairing</span><span class="w"> </span><span class="s">"AIoQl0OtCL0/uSN7Ct1/FHRMEk/eM2Lrhn0bw7f8sgOe"</span><span class="p">}</span><span class="w">
</span></code></pre></div> </div>
<p>response
<code class="language-plaintext highlighter-rouge">true</code></p>
</li>
</ol>
<h2 id="status-go-calls">Status go calls</h2>
<p>In order to use the card in the app we need to use some parts of status-go API, specifically:</p>
<ol>
<li><a href="https://github.com/status-im/status-go/blob/b33ad8147d23a932064f241e575511d70a601dcc/mobile/status.go#L337"><code class="language-plaintext highlighter-rouge">SaveAccountAndLoginWithKeycard</code></a> after multiaccount creation/restoring to store multiaccount and login into it</li>
<li><a href="https://github.com/status-im/status-go/blob/b33ad8147d23a932064f241e575511d70a601dcc/mobile/status.go#L373"><code class="language-plaintext highlighter-rouge">LoginWithKeycard</code></a> to log into already existing account</li>
<li><a href="https://github.com/status-im/status-go/blob/b33ad8147d23a932064f241e575511d70a601dcc/mobile/status.go#L492"><code class="language-plaintext highlighter-rouge">HashTransaction</code></a> and <a href="https://github.com/status-im/status-go/blob/b33ad8147d23a932064f241e575511d70a601dcc/mobile/status.go#L520"><code class="language-plaintext highlighter-rouge">HashMessage</code></a> for hashing transaction/message before signing</li>
<li><a href="https://github.com/status-im/status-go/blob/b33ad8147d23a932064f241e575511d70a601dcc/mobile/status.go#L471"><code class="language-plaintext highlighter-rouge">SendTransactionWithSignature</code></a> to send transaction</li>
</ol>
<h2 id="where-are-the-keys-stored">Where are the keys stored?</h2>
<ol>
<li>When we create a regular multiaccount all its keys are stored on device and are encrypted via key which is derived from users password. In case if account was created using keycard all keys are stored on the card and are retrieved from it during signing into multiaccount.</li>
<li>When we create a regular multiaccount we also create a separate database for it and this database is encrypted using key which is derived from users password. For a keycard account we use <code class="language-plaintext highlighter-rouge">encryption-public-key</code> (returned by <code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/get-keys</code>/<code class="language-plaintext highlighter-rouge">status-im.hardwallet.card/generate-and-load-keys</code>) as a password.</li>
</ol>
<h2 id="copyright">Copyright</h2>
<p>Copyright and related rights waived via <a href="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
stable/1.html Normal file

File diff suppressed because one or more lines are too long

73
stable/10.html Normal file

File diff suppressed because one or more lines are too long

3
stable/11.html Normal file

File diff suppressed because one or more lines are too long

1
stable/15.html Normal file

File diff suppressed because one or more lines are too long

59
stable/2.html Normal file

File diff suppressed because one or more lines are too long

66
stable/3.html Normal file

File diff suppressed because one or more lines are too long

3
stable/4.html Normal file

File diff suppressed because one or more lines are too long

49
stable/5.html Normal file

File diff suppressed because one or more lines are too long

104
stable/6.html Normal file

File diff suppressed because one or more lines are too long

1
stable/8.html Normal file

File diff suppressed because one or more lines are too long

12
stable/9.html Normal file

File diff suppressed because one or more lines are too long

1
stable/index.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long