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 <codeclass="language-plaintext highlighter-rouge">{IK}-contact-code</code>, where <codeclass="language-plaintext highlighter-rouge">IK</code> is the hex encoded public key of the user, prefixed with <codeclass="language-plaintext highlighter-rouge">0x</code>. The node encrypts the channel in the same way it encrypted public chats.</li></ul><h3id="contact-verification"><ahref="#contact-verification"class="anchor-heading"aria-labelledby="contact-verification"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Contact Verification </h3><p>To verify that contact key information is as it should be, use the following.</p><h4id="identicon"><ahref="#identicon"class="anchor-heading"aria-labelledby="identicon"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> 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 receiver’s public key is the one stored locally.</p><h4id="3-word-pseudonym--whisperwaku-key-fingerprint"><ahref="#3-word-pseudonym--whisperwaku-key-fingerprint"class="anchor-heading"aria-labelledby="3-word-pseudonym--whisperwaku-key-fingerprint"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> 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 contact’s public profile and in the chat UI.</p><ul><li>implementation: <ahref="https://github.com/status-im/status-react/tree/develop/src/status_im/utils/gfycat">gfycat</a></li></ul><h4id="ens-name"><ahref="#ens-name"class="anchor-heading"aria-labelledby="ens-name"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> ENS name </h4><p>Status offers the ability to register a mapping of a human readable subdomain of <codeclass="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 s
</code></pre></div></div><p>minor modification for compatibility and flexibility makes the key self-identifiable and easily parsable,</p><divclass="language-text highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>fe70104261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc3cd4e22200c68daf7493e1f8da6a190a68a671e2d3977809612424c7c3888bc6
</code></pre></div></div><p>EC serialization and compact encoding produces a much smaller string representation of the original key.</p><divclass="language-text highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>zQ3shPyZJnxZK4Bwyx9QsaksNKDYTPmpwPvGSjMYVHoXHeEgB
</code></pre></div></div><h3id="public-key-compression-rationale"><ahref="#public-key-compression-rationale"class="anchor-heading"aria-labelledby="public-key-compression-rationale"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> 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><codeclass="language-plaintext highlighter-rouge">0xe70104261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc3cd4e22200c68daf7493e1f8da6a190a68a671e2d3977809612424c7c3888bc6</code></li><li><codeclass="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 <codeclass="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><codeclass="language-plaintext highlighter-rouge">Onboarding</code>><codeclass="language-plaintext highlighter-rouge">Choose a chat name</code></li><li><codeclass="language-plaintext highlighter-rouge">Profile</code>><codeclass="language-plaintext highlighter-rouge">Header</code></li><li><codeclass="language-plaintext highlighter-rouge">Profile</code>><codeclass="language-plaintext highlighter-rouge">Share icon</code>><codeclass="language-plaintext highlighter-rouge">QR code popover</code></li><li><codeclass="language-plaintext highlighter-rouge">Invite friends</code> url from <codeclass="language-plaintext highlighter-rouge">Invite friends</code> button and <codeclass="language-plaintext highlighter-rouge">+ -button</code>><codeclass="language-plaintext highlighter-rouge">Invite friends</code></li><li>Other user <codeclass="language-plaintext highlighter-rouge">Profile details</code></li><li><codeclass="language-plaintext highlighter-rouge">Profile details</code>><codeclass="language-plaintext highlighter-rouge">Share icon</code>><codeclass="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><divclass="table-wrapper"><table><thead><tr><th>Uncompressed</th><th>Compressed</th></tr></thead><tbody><tr><td><imgsrc="https://user-images.githubusercontent.com/5702426/80531063-e98fcc80-8991-11ea-8c02-c354b5828d35.png"width="400"/></td><td><imgsrc="https://user-images.githubusercontent.com/5702426/80501933-f4356c00-8967-11ea-87d8-eae18becece9.png"width="400"/></td></tr></tbody></table></div><h3id="key-encoding"><ahref="#key-encoding"class="anchor-heading"aria-labelledby="key-encoding"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Key Encoding </h3><p>When implementing the pk de/serialization functionality, the node MUST use the <ahref="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 <codeclass="language-plaintext highlighter-rouge">multibase</code> encoding formats.</p><pre><codeclass="language-csv">encoding, code, description, status
identity, 0x00, 8-bit binary (encoder and decoder keeps data unmodified), default
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 <codeclass="language-plaintext highlighter-rouge">multibase</code> protocol to parse strings prepended with <codeclass="language-plaintext highlighter-rouge">0x</code> as <codeclass="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. <codeclass="language-plaintext highlighter-rouge">0x1337c0de</code>).</p><p><em>Example:</em></p><p><codeclass="language-plaintext highlighter-rouge">0xe70102261c55675e55ff25edb50b345cfb3a3f35f60712d251cbaaab97bd50054c6ebc</code></p><p>SHOULD be interpreted as</p><p><codeclass="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><h3id="public-key-types"><ahref="#public-key-types"class="anchor-heading"aria-labelledby="public-key-types"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Public Key Types </h3><p>When implementing the pk de/serialization functionality, The node MUST support the <ahref="https://github.com/multiformats/multicodec">multiformats/multicodec</a> key type identifiers for the following public key type.</p><divclass="table-wrapper"><table><thead><tr><th>Name</th><th>Tag</th><th>Code</th><th>Description</th></tr></thead><tbody><tr><td><codeclass="language-plaintext highlighter-rouge">secp256k1-pub</code></td><td>key</td><td><codeclass="language-plaintext highlighter-rouge">0xe7</code></td><td>Secp256k1 public key</td></tr></tbody></table></div><p>For a public key to be identifiable to the node the public key data MUST be prepended with the relevant <ahref="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><divclass="language-text highlighter-rouge"><divclass="highlight"><preclass="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 <codeclass="language-plaintext highlighter-rouge">multicodec</code> code for a secp256k1 public key is <codeclass="language-plaintext highlighter-rouge">0xe7</code>.</p><p>After parsing the code <codeclass="language-plaintext highlighter-rouge">0xe7</code> as a <codeclass="language-plaintext highlighter-rouge">multiformats/uvarint</code>, the byte value is <codeclass="language-plaintext highlighter-rouge">0xe7 0x01</code>, prepending this to the public key results in the below representation.</p><divclass="language-text highlighter-rouge"><divclass="highlight"><preclass="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><h3id="deserialization-process-flow"><ahref="#deserialization-process-flow"class="anchor-heading"aria-labelledby="deserialization-process-flow"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> De/Serialization Process Flow </h3><p>When implementing the pk de/serialization functionality, the node MUST be passed a <codeclass="language-plaintext highlighter-rouge">multicodec</code> identified public key, of the above supported types, encoded with a valid <codeclass="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><h4id="serialization-example"><ahref="#serialization-example"class="anchor-heading"aria-labelledby="serialization-example"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Serialization Example </h4><p>A hexadecimal encoded secp256k1 public chat key typically is represented as below:</p><divclass="language-text highlighter-rouge"><divclass="highlight"><preclass="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 <codeclass="language-plaintext highlighter-rouge">multicodec</code><codeclass="language-plaintext highlighter-rouge">uvarint</code> code <codeclass="language-plaintext highlighter-rouge">0xea 0x01</code> and encoded with a valid <codeclass="language-plaintext highlighter-rouge">multibase</code> encoding, therefore giving the following:</p><divclass="language-text highlighter-rouge"><divclass="highlight"><preclass="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 <codeclass="language-plaintext highlighter-rouge">multibase</code> encoding identifier.</p><p>In this example the output encoding is defined as <codeclass="language-plaintext highlighter-rouge">base58 bitcoin</code>.</p><divclass="language-text highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>z
</code></pre></div></div><p>The return value in this case would be</p><divclass="language-text highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>zQ3shPyZJnxZK4Bwyx9QsaksNKDYTPmpwPvGSjMYVHoXHeEgB
</code></pre></div></div><p>Which after <codeclass="language-plaintext highlighter-rouge">multibase</code> decoding can be represented in bytes as below:</p><divclass="language-text highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>e7 | 01 | 02
</code></pre></div></div><h4id="deserialization-example"><ahref="#deserialization-example"class="anchor-heading"aria-labelledby="deserialization-example"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> 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 <ahref="https://github.com/status-im/status-go/blob/c9772325f2dca76b3504191c53313663ca2efbe5/api/utils_test.go"><codeclass="language-plaintext highlighter-rouge">status-go</code> implementation and tests</a>.</p><h2id="security-considerations"><ahref="#security-considerations"class="anchor-heading"aria-labelledby="security-considerations"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Security Considerations </h2><p>-</p><h2id="changelog"><ahref="#changelog"class="anchor-heading"aria-labelledby="changelog"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Changelog </h2><h3id="version-04"><ahref="#version-04"class="anchor-heading"aria-labelledby="version-04"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Version 0.4 </h3><p>Released <ahref="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><h3id="version-03"><ahref="#version-03"class="anchor-heading"aria-labelledby="version-03"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Version 0.3 </h3><p>Released <ahref="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 <codeclass="language-plaintext highlighter-rouge">Mailserver</code> term consistent</li><li>Added clarification to Open Whisper Systems</li></ul><h2id="copyright"><ahref="#copyright"class="anchor-heading"aria-labelledby="copyright"><svgviewBox="0 0 16 16"aria-hidden="true"><usexlink:href="#svg-link"></use></svg></a> Copyright </h2><p>Copyright and related rights waived via <ahref="https://creativecommons.org/publicdomain/zero/1.0/">CC0</a>.</p></div></div><divclass="search-overlay"></div></div></body></html>