mirror of https://github.com/ethereum/go-ethereum
Merge pull request #21949 from MariusVanDerWijden/rem_whisper
doc: removed whisper documentationpull/23166/head
commit
19b89ebe84
@ -1,54 +0,0 @@ |
|||||||
--- |
|
||||||
title: Achieving Darkness |
|
||||||
sort_key: B |
|
||||||
--- |
|
||||||
|
|
||||||
Whisper is designed to be a building block in the next generation of unstoppable ÐApps. It was designed to provide resilience and privacy at considerable expense. At its most secure mode of operation Whisper can theoretically deliver complete darkness. Whisper should also allow the users to configure the level of privacy (how much information it leaks concerning the ÐApp content and ultimately, user activities) as a trade-off for performance. In this article we will discuss the strategy of achieving complete darkness. |
|
||||||
|
|
||||||
### Adversary |
|
||||||
|
|
||||||
In the worst case, you are playing against a very powerful adversary, which has a capacity to run a lot of Whisper nodes. In addition to that, it might generate Whisper identities in order to target a specific node. For example, it might generate IDs that will be very close to the ID of the target node, which then fit into Kademlia topology in such a way that will allow a traffic analysis from this node. As a result, it will be possible to see which messages originate from the target node. |
|
||||||
|
|
||||||
### Recipient vs. Sender |
|
||||||
|
|
||||||
Even if most nodes of the network belong to adversary, it will be still impossible to identify the recipient of particular message by the means of simple traffic analysis. But the sender might be identified. In order to prevent that, the node might maintain a certain noise level. For example, if the node sends on average several messages per hour, it might still send random messages every minute. Those extra messages should resemble the meaningful messages, but should contain randomly generated bytes and be encrypted with random key, so that adversary will not be able to distinguish the meaningful messages from the noise. It is necessary to encrypt (not only generate) random data because encrypted messages might have some common traits, which distinguish them from noise. E.g. in case of asymmetric encryption some bytes are allowed to have only certain values. |
|
||||||
|
|
||||||
In some cases recipient might also be probabilistically identified if two nodes send each other messages with common traits, e.g. same Topic or same size. That's why it is important to use different Topics for sending and receiving the messages within the session. |
|
||||||
|
|
||||||
### Topics |
|
||||||
|
|
||||||
It is possible to send asymmetrically encrypted messages without any Topic. However, in case of huge traffic it might be not practical to try decrypting all the incoming messages, since decrypt operation is quite expensive. Some filtering might be necessary. Whisper allows to subscribe for messages with particular Topic or specify several possible Topics. It is also possible to subscribe for partial Topic(s), e.g. first one, two, or three bytes of the Topic. |
|
||||||
|
|
||||||
Topic collisions are part of the plausible deniability strategy. Some messages from different nodes (and encrypted with different keys) should have the same Topic (or partial Topic). Therefore it is recommended to set the Topics dynamically, so that collisions will regulary occur on your node. |
|
||||||
|
|
||||||
For example, if there are 6000 nodes in the network and each of them on average sends ten messages per minute, it would make sense to set only first byte of the Topic (leaving the other three bytes random). In this case each node will receive on average 1000 messages per second. The node will try to decrypt approximately four messages (those matching the Topic), and one of them will be successfully decrypted. The rest of the messages will be ignored and just forwarded to the other peers. |
|
||||||
|
|
||||||
### Message Size and Padding |
|
||||||
|
|
||||||
When sending the messages, another important metric which could potentially leak metainformation is the size. Therefore, depending on the circumstances, it might be useful to send messages only of certain size or always generate random size (not exceeding certain limit). The API allows easy setting of padding. The default implementation of Whisper also uses the padding to align the messages along the 256-byte boundaries. |
|
||||||
|
|
||||||
### Symmetric vs. Asymmetric |
|
||||||
|
|
||||||
In case of symmetric encryption, the nodes must have already exchanged the encryption key via some secure channel. So, they should use the same channel to exchange the Topics (or partial Topics), and maybe PoW requirement for individual messages. In case of asymmetric encryption, the public key is exchanged via open channels, and it might be impossible to exchange any other information before they engage in secure communication. In this case different strategies might be employed. |
|
||||||
|
|
||||||
For example, the first message might be sent without any Topic. This message may contain all the information necessary to start a symmetrically encrypted session, complete with (partial) Topics, PoW requirement and symmetric keys. Because it requires trying to decrypt all the incoming asymmetric messages, the PoW requirement for such messages might be set very high, which might be acceptable since such messages are only sent once per session. |
|
||||||
|
|
||||||
Alternatively, a partial Topic should be published along with the public key and PoW requirement. E.g., if we use two or three bytes for the partial Topic of symmetrically encrypted messages, we might only use one byte for the asymmetric encryption. |
|
||||||
|
|
||||||
### Example of Session |
|
||||||
|
|
||||||
Suppose two nodes want to engage in secure communication. One of them sends an asymmetrically encrypted message of certain (pre-defined) format, which contains two symmetric keys and corresponding partial Topics, all randomly generated. The sender of this message subscribes for the messages with the first Topic (encrypted with the first key), and always encrypts outgoing messages with the second key. The recipient subscribes for the messages with the second Topic (encrypted with the second key), and always encrypts outgoing messages with the first key. They also include the message number in each outgoing message, in order to ensure the correct order of the messages, and detect if some of them did not arrive. After the session is over, the keys are deleted and never used again. |
|
||||||
|
|
||||||
In case of several participants (e.g. a group chat) they just need one additional key and one additional subscription for any additional participant. |
|
||||||
|
|
||||||
### Plausible Deniability |
|
||||||
|
|
||||||
Suppose a user has lost control of his key. It might happen due to hacker attack on his computer, or becuase a hostile entity forces him to reveal the key. In case he signed any message with his private key, it might be used as evidence against him. So, the user might prefer to use his key only to establish the session, and then engage in symmetrically encrypted communication without signing the messages. His peer may be sure about his identity, since the symmetric key was signed with his private key. But these messages can not be used as evidence, since this message could have been sent by anyone in possession of the symmetric key, especially if this key was used in a group chat session. |
|
||||||
|
|
||||||
### Steganography |
|
||||||
|
|
||||||
However, in some extreme cases even plausible deniability might not be enough. In those cases users might utilize the padding mechanism for steganographic purposes. It is possible to set arbitrary data as padding. The Whisper API allows easy access to padding for both writing and reading. Since vast majority of the messages will contain some kind of padding (either default or customized), it will be impossible to distinguish between randomly generated and encrypted padding bytes. The users should only use such encryption which does not reveal any metainformation (preferably symmetric stream ciphers), and then add the resulting data as padding to a message with some irrelevant payload. |
|
||||||
|
|
||||||
### Private Networks |
|
||||||
|
|
||||||
It is very easy to set up a private Whisper network, since Whisper does not contain any genesis block or indeed any state at all. You just start a bootstrap node to which everybody should connect. It might be useful for organizations with restricted access. Private network may have several advantages. For example, it might be very difficult for any adversary to join the network, which will make the traffic analysis almost impossible. Also, PoW requirement might be dropped, thus allowing instant messaging with very little overhead. |
|
@ -1,267 +0,0 @@ |
|||||||
--- |
|
||||||
title: Diagnostic tool wnode |
|
||||||
sort_key: B |
|
||||||
--- |
|
||||||
|
|
||||||
Wnode (whisper node) is a command-line diagnostic tool. It does not have a nice user interface, because its main purpose is diagnostic, and it's meant to be very light-weight rather than beautiful. Wnode might be used for different purposes, including: |
|
||||||
|
|
||||||
- running a standalone bootstrap node, in order to set up a private whisper network |
|
||||||
- connecting to particular node for debugging or other purposes |
|
||||||
- engaging in command-line chat with another peer in order to test its functionality |
|
||||||
- sending and receiving text messages |
|
||||||
- sending and receiving files |
|
||||||
- running fully functional mail server |
|
||||||
- testing functionality of mail client |
|
||||||
|
|
||||||
## Usage |
|
||||||
|
|
||||||
``` |
|
||||||
> wnode [flags/arguments] |
|
||||||
``` |
|
||||||
|
|
||||||
## Flags & Switches |
|
||||||
|
|
||||||
In case an argument is missing, `wnode` will either use the default value or prompt the user at startup. For security reasons, it is not possible to provide passwords in command-line arguments. In `test` mode, a hardcoded password ("test") is used. |
|
||||||
|
|
||||||
`-asym`: use asymmetric encryption in the chat |
|
||||||
|
|
||||||
`-boot`: A string representing the bootstrap node to connect to. For example: |
|
||||||
|
|
||||||
``` |
|
||||||
-boot=enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379 |
|
||||||
``` |
|
||||||
|
|
||||||
`-dbpath`: The path to the server's DB directory, for incoming messages to be stored |
|
||||||
|
|
||||||
`-echo`: prints some arguments for diagnostics |
|
||||||
|
|
||||||
`-fileexchange`: file exchange mode (send and receive files instead of text messages) |
|
||||||
|
|
||||||
`-filereader`: load and decrypt messages saved as files, display as plain text |
|
||||||
|
|
||||||
`-forwarder`: forwarder mode (only forward; neither send nor decrypt messages) |
|
||||||
|
|
||||||
`-generatekey`: generate and show the private key, and exit |
|
||||||
|
|
||||||
`-idfile`: file name containing a node ID (private key) in hexadecimal format |
|
||||||
|
|
||||||
`-ip`: IP address and port of this node (e.g. 127.0.0.1:30303) |
|
||||||
|
|
||||||
`-mailclient`: request expired messages from the mail server |
|
||||||
|
|
||||||
`-mailserver`: mail server mode (delivers expired messages on demand) |
|
||||||
|
|
||||||
`maxsize`: max size of message (default 1048576) |
|
||||||
|
|
||||||
`-mspow`: PoW requirement for Mail Server request (default 0.2) |
|
||||||
|
|
||||||
`-pow`: PoW for normal messages in float format (e.g. 2.7) (default 0.2) |
|
||||||
|
|
||||||
`-pub`: public key for asymmetric encryption. For example: |
|
||||||
|
|
||||||
``` |
|
||||||
-pub=0x07af49cbe6353b8732a8b9eb20dd1472f3d4512cd1a11382ee2817cc6de9453bc07c32c730b93bc83877b11e4f47d718751297f4edcbf35015df2b34ff5fc6a75d |
|
||||||
``` |
|
||||||
|
|
||||||
`-savedir`: directory where all incoming messages will be saved as files. Only big messages are stored there, except in `fileexchange` mode where all files are stored there. |
|
||||||
|
|
||||||
`-standalone`: don't actively connect to any peers, wait for incoming connections instead |
|
||||||
|
|
||||||
`-test`: use of predefined parameters for diagnostics, including passwords |
|
||||||
|
|
||||||
`-topic`: topic in hexadecimal format (e.g. 70a4beef) |
|
||||||
|
|
||||||
`-ttl`: time-to-live for messages in seconds (default 30) |
|
||||||
|
|
||||||
`-verbosity`: log verbosity level (default 1) |
|
||||||
|
|
||||||
`-work`: work time in seconds (default 5) |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Scenarios & Examples |
|
||||||
|
|
||||||
For simplicity, in these examples we assume that we only use `wnode` to communicate with another wnode. |
|
||||||
|
|
||||||
|
|
||||||
### Start a bootstrap node for test network |
|
||||||
|
|
||||||
``` |
|
||||||
$ wnode -standalone -forwarder -ip=127.0.0.1:30379 |
|
||||||
my public key: 0x040ef7acd60781c336c52056b3782f7eae45be2063e591ac6b78472dc27ba770010bde445ffd2f3623ad656f3859e00d11ef518df4916c4d4e258c60b15f34c682 enode://15454fc65bbf0031155f4eee83fa732f1454c314e9f78ade9cba4d4a098d29edbf5431764ee65b200169025c3f900cacc3348a000dda7a8a0d9643d0b7618712@127.0.0.1:30379 |
|
||||||
Bootstrap Whisper node started |
|
||||||
``` |
|
||||||
|
|
||||||
### Connecting to a bootstrap node |
|
||||||
|
|
||||||
After the bootstrap node has started, another local node can connect to it, using the resulting enode: |
|
||||||
|
|
||||||
``` |
|
||||||
$ wnode -test -boot=enode://15454fc65bbf0031155f4eee83fa732f1454c314e9f78ade9cba4d4a098d29edbf5431764ee65b200169025c3f900cacc3348a000dda7a8a0d9643d0b7618712@127.0.0.1:30379 |
|
||||||
............................ |
|
||||||
Whisper node started |
|
||||||
Connected to peer. |
|
||||||
............................ |
|
||||||
``` |
|
||||||
|
|
||||||
### Persistent ID |
|
||||||
|
|
||||||
Upon restarting the bootstrap node, its enode will be different, because the ID is randomly generated. For persistence accross restarts, it is possible to specify an ID stored in a file using the 'idfile' argument. |
|
||||||
|
|
||||||
Generating ID: |
|
||||||
|
|
||||||
``` |
|
||||||
$ wnode -generatekey > pk1.txt |
|
||||||
$ cat pk1.txt |
|
||||||
b3651aff593ef395ee7c16f3ca681830f7d8d0b2729cf472b14f2c4ebe833aa0 |
|
||||||
``` |
|
||||||
|
|
||||||
`pk1.txt` now contains the key used to generate the ID. |
|
||||||
|
|
||||||
Starting the bootstrap node with a persistent ID: |
|
||||||
|
|
||||||
``` |
|
||||||
bootnode $ wnode -forwarder -standalone -ip=127.0.0.1:30379 -idfile=pk1.txt |
|
||||||
my public key: 0x04be81a00a90f5c21ead8887eaa254b3f7a37e06f8f2d776dcc46954a228bc50c6fb6dfd155f7e44e6fef9b62fdf6dad041759b864d2cbe4089b6f5c16a817ff46 enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30379 |
|
||||||
Filter is configured for the topic: 5a4ea131 |
|
||||||
Bootstrap Whisper node started |
|
||||||
``` |
|
||||||
|
|
||||||
Now you can always use the same command to connect to your bootstrap node: |
|
||||||
|
|
||||||
``` |
|
||||||
othernode $ wnode -test -boot=enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30379 |
|
||||||
``` |
|
||||||
|
|
||||||
Be aware that the ID is stored unencrypted. This feature should only be used for test purposes. |
|
||||||
|
|
||||||
In order to set up a bootstrap node on a server with a dedicated IP address, its IP and port need to be specified explicitly: |
|
||||||
|
|
||||||
``` |
|
||||||
bootnode $ wnode -forwarder -standalone -ip=52.178.211.103:30379 |
|
||||||
``` |
|
||||||
|
|
||||||
### Using a mail server |
|
||||||
|
|
||||||
The mailserver is only provided as an example for people interested in building their own solution. It is not supported. |
|
||||||
|
|
||||||
``` |
|
||||||
$ wnode -forwarder -standalone -ip=127.0.0.1:30381 -idfile=config.txt -mailserver -dbpath=tmp/db |
|
||||||
``` |
|
||||||
|
|
||||||
|
|
||||||
### Chat with symmetric encryption |
|
||||||
|
|
||||||
For two nodes to communicate using symmetric encryption, one of them must assume the role of a bootstrap node, and the second one that of the client. The bootstrap node is started with the `standalone` flag, and the client must connect to it. It is easy to do on the same machine or on a dedicated server. But what if two peers are behind distinct NAT? In that case, you need a third bootstrap node on a dedicated server, which both peers can connect to. At the time of writing we have out test node with the following enode: |
|
||||||
`enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379`, |
|
||||||
to which both peers can connect with the following command: |
|
||||||
|
|
||||||
``` |
|
||||||
bootnode $ wnode -boot=enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379 |
|
||||||
``` |
|
||||||
|
|
||||||
The user is prompted for the symmetric encryption password. The symmetric key is derived from this password. The topic will be derived from the password as well, unless it's provided by the user on the command line (which is strongly encouraged for any meaningful communication): |
|
||||||
|
|
||||||
``` |
|
||||||
othernode $ wnode -topic=a6fcb30d -boot=enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379 |
|
||||||
``` |
|
||||||
|
|
||||||
The communication is therefore established. Typing message in one console will echo: |
|
||||||
|
|
||||||
``` |
|
||||||
hello world! |
|
||||||
|
|
||||||
1493061848 <031792461900245c6919c4b23447ef8ba43f79a2>: hello world! |
|
||||||
``` |
|
||||||
|
|
||||||
The first number (1493061848) is UNIX timestamp. This format is useful for Mail Client/Server tests. The number in brackets is the ID with which the message is signed. Seeing an ID with only zeros means the message is not signed, although encrypted with the right key. Another `wnode` peer will show the same output: |
|
||||||
|
|
||||||
``` |
|
||||||
1493061848 [031792461900245c6919c4b23447ef8ba43f79a2]: hello world! |
|
||||||
``` |
|
||||||
|
|
||||||
Only the brackets are different, indicating that this message originated from another identity. |
|
||||||
|
|
||||||
### Chat with Asymmetric Encryption |
|
||||||
|
|
||||||
Using asymmetric encryption is as simple as using the `-asym` flag: |
|
||||||
|
|
||||||
``` |
|
||||||
othernode $ wnode -topic=a6fcb30d -asym -boot=enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379 |
|
||||||
|
|
||||||
my public key: 0x0405007821171295a716c9d091371e836e98a5206d5b9ce9177df90c83fc308ebae2786a9c7bff999ad83d12be08e597d4b5a5240f3bb0bc366f008b7d0908df8a |
|
||||||
enode://efe233263c78482111ba6c058ccc69b7a2ea3372774733def4fd5a357dfbaa67657e665078d573f11876fd2b7d75d41926976f41e257f91b486e9d36f4143c8a@[::]:42562 |
|
||||||
Whisper node started |
|
||||||
Connected to peer. |
|
||||||
Please enter the peer's public key: |
|
||||||
``` |
|
||||||
|
|
||||||
First line of the output contains the key which should be passed to another peer, and vice versa. Once both clients have entered their peer's public key, the chat session is active. |
|
||||||
|
|
||||||
### Sending and receiving files |
|
||||||
|
|
||||||
File exchange is activated with the `fileexchange` flags. Examples here use the `-test` flag for simplicity. Assuming that the incoming messages are to be stored in `/home/tester/tmp/msg`, the resulting command line is: |
|
||||||
|
|
||||||
``` |
|
||||||
bootnode $ wnode -standalone -ip=127.0.0.1:30379 -idfile=pk1.txt -fileexchange -savedir=/home/tester/tmp/msg |
|
||||||
enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30379 |
|
||||||
``` |
|
||||||
|
|
||||||
To send a file to this first `wnode`, type: |
|
||||||
|
|
||||||
``` |
|
||||||
othernode $ wnode -test -boot=enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30379 |
|
||||||
``` |
|
||||||
|
|
||||||
Typing messages in the console of the second node, will cause the first one to display something like this: |
|
||||||
|
|
||||||
``` |
|
||||||
1493124416 {624fdf6983940c7ffa8a4742f76dc78ae9775c47}: message received and saved as 'aa6f339e830c86718ddf4254038dd9fa8da6494e3f3c856af500a5aeaf0df62d' (4 bytes) |
|
||||||
``` |
|
||||||
|
|
||||||
Messages are not displayed, but saved instead. Examine the contents of `/home/tester/tmp/msg/aa6f339e830c86718ddf4254038dd9fa8da6494e3f3c856af500a5aeaf0df62d` to confirm that the message is saved there. |
|
||||||
|
|
||||||
It is possible to send a file directly by typing its path. For example: |
|
||||||
|
|
||||||
``` |
|
||||||
> /home/tester/tmp/msg/aa6f339e830c86718ddf4254038dd9fa8da6494e3f3c856af500a5aeaf0df62d |
|
||||||
``` |
|
||||||
|
|
||||||
Asymmetric encryption is also available in file exchange mode by providing the `asym` flag. |
|
||||||
|
|
||||||
### Mail Server & Client |
|
||||||
|
|
||||||
Whisper protocol allows you to exchange messages with other peers only if you are online. But what if you go offline? Will important messages be lost forever? The golang implementation of Whisper v6 has a built-in support for Mail Client/Server functionality, which allows to create very secure (and even dark) anonymous email-like system. Wnode is designed to demonstrate the viability of such project. |
|
||||||
|
|
||||||
Mail Server and Client must have direct connection, since they exchange special kind of messages, which are not propagated any further. The reason for that is simple: if you receive the old (expired) message from the Server, and try to send it to other peers, they will recognise the message as expired, and drop connection with you. |
|
||||||
|
|
||||||
Starting Mail Server: |
|
||||||
|
|
||||||
|
|
||||||
``` |
|
||||||
bootnode $ wnode -mailserver -forwarder -standalone -test -ip=127.0.0.1:30381 -idfile=pk1.txt -dbpath=/home/tester/tmp/arj |
|
||||||
``` |
|
||||||
|
|
||||||
Now start another node, connect to the Server, and send some test messages to fill the database: |
|
||||||
|
|
||||||
``` |
|
||||||
othernode $ wnode -test -boot=enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30381 |
|
||||||
``` |
|
||||||
|
|
||||||
Note the UNIX time of the messages. For example: `1493127055`. |
|
||||||
Now start the Mail Client and connect to the Server: |
|
||||||
|
|
||||||
``` |
|
||||||
othernode $ wnode -mailclient -test -boot=enode://7d13360f5b1ddcf6947f244639113597a863abba0589d2fa5fffb2816ead0acea6211d5778a8be648e45e81ed881f4c1f5c9bbbf0e79065dfb54bcd97de3beab@127.0.0.1:30381 |
|
||||||
``` |
|
||||||
|
|
||||||
You will be prompted to enter the time range of the archived messages you want to receive: |
|
||||||
|
|
||||||
``` |
|
||||||
Please enter the lower limit of the time range (unix timestamp): 1493127000 |
|
||||||
Please enter the upper limit of the time range (unix timestamp): 1493127099 |
|
||||||
Please enter the topic (hexadecimal): |
|
||||||
``` |
|
||||||
|
|
||||||
You can leave the topic empty for now, in which case all the messages will be delivered, regardless of the topic. |
|
||||||
The message should be delivered by the the Server, decrypted by the Client and displayed on the screen. |
|
@ -1,102 +0,0 @@ |
|||||||
--- |
|
||||||
title: How to Whisper |
|
||||||
sort_key: B |
|
||||||
--- |
|
||||||
|
|
||||||
Whisper is a pure identity-based messaging system. Whisper provides a low-level (non-application-specific) but easily-accessible API without being based upon or prejudiced by the low-level hardware attributes and characteristics, particularly the notion of singular endpoints. |
|
||||||
|
|
||||||
This tutorial will guide you to setting up a full p2p server with whisper capabilities. |
|
||||||
|
|
||||||
Let's quickly cover some of whisper's basic functionality and discuss it in greater detail later. |
|
||||||
|
|
||||||
```go |
|
||||||
whisper.Send(myEnvelope) |
|
||||||
``` |
|
||||||
|
|
||||||
The notion of envelopes and messages in whisper is somewhat blurred. An application shouldn't ever need to know the difference between the two and should only care about the information it's interested in. Therefor whisper comes with a subscribing mechanism which allows you watch/listen for specific whisper messages (e.g., to you, with a specific topic, etc). |
|
||||||
|
|
||||||
```go |
|
||||||
whisper.Watch(Filter{ |
|
||||||
From: myFriendsPubKey, |
|
||||||
Fn: func(msg *whisper.Message) { /* ... */ }, |
|
||||||
}) |
|
||||||
``` |
|
||||||
|
|
||||||
## Envelopes & Messages |
|
||||||
|
|
||||||
Whenever you want to send message over the whisper network you need to prove to network you've done some significant work for sealing the message (such is the cost for sending messages) and thus the more work you put in to sealing the message the higher the priority the message will have when propagating it over the network. |
|
||||||
|
|
||||||
Whisper's *P*roof *o*f *W*ork consists of a simple SHA3 algorithm in which we try to find the smallest number within a given time frame. Giving the algorithm more time will result in a smaller number which means the message has a higher priority in the network. |
|
||||||
|
|
||||||
Messages are also sealed with a *T*ime *T*o *L*ive. Whisper peers will automatically flush out messages which have exceeded their time to live (with a maximum up to 2 days). |
|
||||||
|
|
||||||
Additionally messages may also contain a recipient (public key) and a set of topics. Topics will allow us to specify messages their subject (e.g., "shoes", "laptop", "marketplace", "chat"). Topics are automatically hashed and only the first 4 bytes are used during transmission and as such, topics are not 100% reliable, they should be treated as a probabilistic message filter. |
|
||||||
|
|
||||||
Sending a whisper message requires you to: |
|
||||||
|
|
||||||
1. create a new `whisper.Message` |
|
||||||
2. `Seal` it (optionally encrypt, sign and supply with topics) |
|
||||||
3. `Send` it to your peers |
|
||||||
|
|
||||||
```go |
|
||||||
topics := TopicsFromString("my", "message") |
|
||||||
msg := whisper.NewMessage([]byte("hello world")) // 1 |
|
||||||
envelope := msg.Seal(whisper.Opts{ // 2 |
|
||||||
From: myPrivateKey, // Sign it |
|
||||||
Topics: topics, |
|
||||||
}) |
|
||||||
whisper.Send(envelope) // 3 |
|
||||||
``` |
|
||||||
|
|
||||||
Whenever a message needs to be encrypted for a specific recipient supply the `Opts` struct with an additional `To` parameter which accepts the recipients public key (`ecdsa.PublicKey`). |
|
||||||
|
|
||||||
## Watching & Listening |
|
||||||
|
|
||||||
Watching for specific messages on the whisper network can be done using the `Watch` method. You have the option to watch for messages from a specific recipient, with specific topics or messages directly directed to you. |
|
||||||
|
|
||||||
```go |
|
||||||
topics := TopicsFromString("my", "message") |
|
||||||
whisper.Watch(Filter{ |
|
||||||
Topics: topics |
|
||||||
Fn: func(msg *Message) { |
|
||||||
fmt.Println(msg) |
|
||||||
}, |
|
||||||
}) |
|
||||||
``` |
|
||||||
|
|
||||||
## Connecting it all together |
|
||||||
|
|
||||||
Now if we tie it all together and supply whisper as a sub-protocol to the DEV's P2P service we have whisper including peer handling and message propagation. |
|
||||||
|
|
||||||
```go |
|
||||||
package main |
|
||||||
|
|
||||||
import ( |
|
||||||
"fmt" |
|
||||||
"log" |
|
||||||
"os" |
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/p2p" |
|
||||||
"github.com/ethereum/go-ethereum/whisper" |
|
||||||
"github.com/obscuren/secp256k1-go" |
|
||||||
) |
|
||||||
|
|
||||||
func main() { |
|
||||||
pub, _ := secp256k1.GenerateKeyPair() |
|
||||||
|
|
||||||
whisper := whisper.New() |
|
||||||
|
|
||||||
srv := p2p.Server{ |
|
||||||
MaxPeers: 10, |
|
||||||
Identity: p2p.NewSimpleClientIdentity("my-whisper-app", "1.0", "", string(pub)), |
|
||||||
ListenAddr: ":8000", |
|
||||||
Protocols: []p2p.Protocol{whisper.Protocol()}, |
|
||||||
} |
|
||||||
if err := srv.Start(); err != nil { |
|
||||||
fmt.Println("could not start server:", err) |
|
||||||
os.Exit(1) |
|
||||||
} |
|
||||||
|
|
||||||
select {} |
|
||||||
} |
|
||||||
``` |
|
@ -1,172 +0,0 @@ |
|||||||
--- |
|
||||||
title: Overview |
|
||||||
sort_key: A |
|
||||||
--- |
|
||||||
|
|
||||||
Whisper is a pure identity-based messaging system. Whisper provides a simple low-level API without being based upon or influenced by the low-level hardware attributes and characteristics. Peer-to-peer communication between the nodes of Whisper network uses the underlying [ÐΞVp2p Wire Protocol](https://github.com/ethereum/wiki/wiki/%C3%90%CE%9EVp2p-Wire-Protocol). Whisper was not designed to provide a connection-oriented system, nor for simply delivering data between a pair of particular network endpoints. However, this might be necessary in some very specific cases (e.g. delivering the expired messages in case they were missed), and Whisper protocol will accommodate for that. Whisper is designed for easy and efficient broadcasting, and also for low-level asynchronous communications. It is designed to be a building block in next generation of unstoppable ÐApps. It was designed to provide resilience and privacy at considerable expense. At its most secure mode of operation, Whisper can theoretically deliver 100% darkness. Whisper should also allow the users to configure the level of privacy (how much information it leaks concerning the ÐApp content and ultimately, user activities) as a trade-off for performance. |
|
||||||
|
|
||||||
Basically, all Whisper messages are supposed to be sent to every Whisper node. In order to prevent a DDoS attack, proof-of-work (PoW) algorithm is used. Messages will be processed (and forwarded further) only if their PoW exceeds a certain threshold, otherwise they will be dropped. |
|
||||||
|
|
||||||
### Encryption in version 6 |
|
||||||
|
|
||||||
All Whisper messages are encrypted and then sent via underlying ÐΞVp2p Protocol, which in turn uses its own encryption, on top of Whisper encryption. Every Whisper message must be encrypted either symmetrically or asymmetrically. Messages could be decrypted by anyone who possesses the corresponding key. |
|
||||||
|
|
||||||
In previous versions unencrypted messages were allowed, but since it was necessary to exchange the topic (more on that below), the nodes might as well use the same communication channel to exchange encryption key. |
|
||||||
|
|
||||||
Every node may possess multiple symmetric and asymmetric keys. Upon Envelope receipt, the node should try to decrypt it with each of the keys, depending on Envelope's encryption mode -- symmetric or asymmetric. In case of success, decrypted message is passed to the corresponding Ðapp. In any case, every Envelope should be forwarded to each of the node's peers. |
|
||||||
|
|
||||||
Asymmetric encryption uses the standard Elliptic Curve Integrated Encryption Scheme with SECP-256k1 public key. Symmetric encryption uses AES GCM algorithm with random 96-bit nonce. If the same nonce will be used twice, then all the previous messages encrypted with the same key will be compromised. Therefore no more than 2^48 messages should be encrypted with the same symmetric key (for detailed explanation please see the Birthday Paradox). However, since Whisper uses proof-of-work, this number could possibly be reached only under very special circumstances (e.g. private network with extremely high performance and reduced PoW). Still, usage of one-time session keys is strongly encouraged for all Ðapps. |
|
||||||
|
|
||||||
Although we assume these standard encryption algorithms to be reasonably secure, users are encouraged to use their own custom encryption on top of the default Whisper encryption. |
|
||||||
|
|
||||||
#### Envelopes |
|
||||||
|
|
||||||
Envelopes are the packets sent and received by Whisper nodes. Envelopes contain the encrypted payload and some metadata in plain format, because these data is essential for decryption. Envelopes are transmitted as RLP-encoded structures of the following format: |
|
||||||
|
|
||||||
[ Version, Expiry, TTL, Topic, AESNonce, Data, EnvNonce ] |
|
||||||
|
|
||||||
Version: up to 4 bytes (currently one byte containing zero). Version indicates encryption method. If Version is higher than current, envelope could not be decrypted, and therefore only forwarded to the peers. |
|
||||||
|
|
||||||
Expiry time: 4 bytes (UNIX time in seconds). |
|
||||||
|
|
||||||
TTL: 4 bytes (time-to-live in seconds). |
|
||||||
|
|
||||||
Topic: 4 bytes of arbitrary data. |
|
||||||
|
|
||||||
AESNonce: 12 bytes of random data (only present in case of symmetric encryption). |
|
||||||
|
|
||||||
Data: byte array of arbitrary size (contains encrypted message). |
|
||||||
|
|
||||||
EnvNonce: 8 bytes of arbitrary data (used for PoW calculation). |
|
||||||
|
|
||||||
Whisper nodes know nothing about content of envelopes which they can not decrypt. The nodes pass envelopes around regardless of their ability to decrypt the message, or their interest in it at all. This is an important component in Whisper's dark communications strategy. |
|
||||||
|
|
||||||
#### Messages |
|
||||||
|
|
||||||
Message is the content of Envelope's payload in plain format (unencrypted). |
|
||||||
|
|
||||||
Plaintext (unencrypted) message is formed as a concatenation of a single byte for flags, additional metadata (as stipulated by the flags) and the actual payload. The message has the following structure: |
|
||||||
|
|
||||||
flags: 1 byte |
|
||||||
optional padding: byte array of arbitrary size |
|
||||||
payload: byte array of arbitrary size |
|
||||||
optional signature: 65 bytes |
|
||||||
|
|
||||||
Those unable to decrypt the message data are also unable to access the signature. The signature, if provided, is the ECDSA signature of the Keccak-256 hash of the unencrypted data using the secret key of the originator identity. The signature is serialised as the concatenation of the `R`, `S` and `V` parameters of the SECP-256k1 ECDSA signature, in that order. `R` and `S` are both big-endian encoded, fixed-width 256-bit unsigned. `V` is an 8-bit big-endian encoded, non-normalised and should be either 27 or 28. |
|
||||||
|
|
||||||
The padding is introduced in order to align the message size, since message size alone might reveal important metainformation. The padding is supposed to contain random data (at least this is the default behaviour in version 6). However, it is possible to set arbitrary padding data, which might even be used for steganographic purposes. The API allows easy access to the padding data. |
|
||||||
|
|
||||||
Default version 6 implementation ensures the size of the message to be multiple of 256. However, it is possible to set arbitrary padding through Whisper API. It might be useful for private Whisper networks, e.g. in order to ensure that all Whisper messages have the same (arbitrary) size. Incoming Whisper messages might have arbitrary padding size, and still be compatible with version 6. |
|
||||||
|
|
||||||
The first several bytes of padding (up to four bytes) indicate the total size of padding. E.g. if padding is less than 256 bytes, then one byte is enough; if padding is less than 65536 bytes, then 2 bytes; and so on. |
|
||||||
|
|
||||||
Flags byte uses only three bits in v.6. First two bits indicate, how many bytes indicate the padding size. The third byte indicates if signature is present. Other bits must be set to zero for backwards compatibility of future versions. |
|
||||||
|
|
||||||
#### Topics |
|
||||||
|
|
||||||
It might not be feasible to try to decrypt ALL incoming envelopes, because decryption is quite expensive. In order to facilitate the filtering, Topics were introduced to the Whisper protocol. Topic gives a probabilistic hint about encryption key. Single Topic corresponds to a single key (symmetric or asymmetric). |
|
||||||
|
|
||||||
Upon receipt of a message, if the node detects a known Topic, it tries to decrypt the message with the corresponding key. In case of failure, the node assumes that Topic collision occurs, e.g. the message was encrypted with another key, and should be just forwarded further. Collisions are not only expected, they are necessary for plausible deniability. |
|
||||||
|
|
||||||
Any Envelope could be encrypted only with one key, and therefore it contains only one Topic. |
|
||||||
|
|
||||||
Topic field contains 4 bytes of arbitrary data. It might be generated from the key (e.g. first 4 bytes of the key hash), but we strongly discourage it. In order to avoid any compromise on security, Topics should be completely unrelated to the keys. |
|
||||||
|
|
||||||
In order to use symmetric encryption, the nodes must exchange symmetric keys via some secure channel anyway. They might use the same channel in order to exchange the corresponding Topics as well. |
|
||||||
|
|
||||||
In case of asymmetric encryption, it might be more complicated since public keys are meant to be exchanged via the open channels. So, the Ðapp has a choice of either publishing its Topic along with the public key (thus compromising on privacy), or trying to decrypt all asymmetrically encrypted Envelopes (at considerable expense). Alternatively, PoW requirement for asymmetric Envelopes might be set much higher than for symmetric ones, in order to limit the number of futile attempts. |
|
||||||
|
|
||||||
It is also possible to publish a partial Topic (first bytes), and then filter the incoming messages correspondingly. In this case the sender should set the first bytes as required, and rest should be randomly generated. |
|
||||||
|
|
||||||
Examples: |
|
||||||
|
|
||||||
Partial Topic: 0x12 (first byte must be 0x12, the last three bytes - random) |
|
||||||
Partial Topic: 0x1234 (first two bytes must be {0x12, 0x34}, the last two bytes - random) |
|
||||||
Partial Topic: 0x123456 (first three bytes must be {0x12, 0x34, 0x56}, the last byte - random) |
|
||||||
|
|
||||||
#### Filters |
|
||||||
|
|
||||||
Any Ðapp can install multiple Filters utilising the Whisper API. Filters contain the secret key (symmetric or asymmetric), and some conditions, according to which the Filter should try to decrypt the incoming Envelopes. If Envelope does not satisfy those conditions, it should be ignored. Those are: |
|
||||||
- array of possible Topics (or partial Topics) |
|
||||||
- Sender address |
|
||||||
- Recipient address |
|
||||||
- PoW requirement |
|
||||||
- AcceptP2P: boolean value, indicating whether the node accepts direct messages from trusted peers (reserved for some specific purposes, like Client/MailServer implementation) |
|
||||||
|
|
||||||
All incoming messages, that have satisfied the Filter conditions AND have been successfully decrypted, will be saved by the corresponding Filter until the Ðapp requests them. Ðapps are expected to poll for incoming messages at regular time intervals. All installed Filters are independent of each other, and their conditions might overlap. If a message satisfies the conditions of multiple Filters, it will be stored in each of the Filters. |
|
||||||
|
|
||||||
In future versions subscription will be used instead of polling. |
|
||||||
|
|
||||||
In case of partial Topic, the message will match the Filter if first X bytes of the message Topic are equal to the corresponding bytes of partial Topic in Filter (where X can be 1, 2 or 3). The last bytes of the message Topic are ignored in this case. |
|
||||||
|
|
||||||
#### Proof of Work |
|
||||||
|
|
||||||
The purpose of PoW is spam prevention, and also reducing the burden on the network. The cost of computing PoW can be regarded as the price you pay for allocated resources if you want the network to store your message for a specific time (TTL). In terms of resources, it does not matter if the network stores X equal messages for Y seconds, or Y messages for X seconds. Or N messages of Z bytes each versus Z messages of N bytes. So, required PoW should be proportional to both message size and TTL. |
|
||||||
|
|
||||||
After creating the Envelope, its Nonce should be repeatedly incremented, and then its hash should be calculated. This procedure could be run for a specific predefined time, looking for the lowest hash. Alternatively, the node might run the loop until certain predefined PoW is achieved. |
|
||||||
|
|
||||||
In version 6, PoW is defined as average number of iterations, required to find the current BestBit (the number of leading zero bits in the hash), divided by message size and TTL: |
|
||||||
|
|
||||||
<code>PoW = (2^BestBit) / (size * TTL)</code> |
|
||||||
|
|
||||||
Thus, we can use PoW as a single aggregated parameter for the message rating. In the future versions every node will be able to set its own PoW requirement dynamically and communicate this change to the other nodes via the Whisper protocol. Now it is only possible to set PoW requirement at the Ðapp startup. |
|
||||||
|
|
||||||
### Packet Codes (ÐΞVp2p level) |
|
||||||
|
|
||||||
As a sub-protocol of [ÐΞVp2p](https://github.com/ethereum/wiki/wiki/%C3%90%CE%9EVp2p-Wire-Protocol), Whisper sends and receives its messages within ÐΞVp2p packets. |
|
||||||
Whisper v6 supports the following packet codes: |
|
||||||
|
|
||||||
<code>Status (0x0)</code> |
|
||||||
|
|
||||||
<code>Messages (0x1)</code> |
|
||||||
|
|
||||||
<code>P2PMessage (0x2)</code> |
|
||||||
|
|
||||||
<code>P2PRequest (0x3)</code> |
|
||||||
|
|
||||||
Also, the following codes might be supported in the future: |
|
||||||
|
|
||||||
<code>PoWRequirement (0x4)</code> |
|
||||||
|
|
||||||
<code>BloomFilterExchange (0x5)</code> |
|
||||||
|
|
||||||
### Basic Operation |
|
||||||
|
|
||||||
Nodes are expected to receive and send envelopes continuously. They should maintain a map of envelopes, indexed by expiry time, and prune accordingly. They should also efficiently deliver messages to the front-end API through maintaining mappings between Ðapps, their filters and envelopes. |
|
||||||
|
|
||||||
When a node's envelope memory becomes exhausted, a node may drop envelopes it considers unimportant or unlikely to please its peers. Nodes should rate peers higher if they pass them envelopes with higher PoW. Nodes should blacklist peers if they pass invalid envelopes, i.e., expired envelopes or envelopes with an implied insertion time in the future. |
|
||||||
|
|
||||||
Nodes should always treat messages that its ÐApps have created no different than incoming messages. |
|
||||||
|
|
||||||
#### Creating and Sending Messages |
|
||||||
|
|
||||||
To send a message, the node should place the envelope its envelope pool. Then this envelope will be forwarded to the peers in due course along with the other envelopes. Composing an envelope from a basic payload, is done in a few steps: |
|
||||||
|
|
||||||
- Compose the Envelope data by concatenating the relevant flag byte, padding, payload (randomly generated or provided by user), and an optional signature. |
|
||||||
- Encrypt the data symmetrically or asymmetrically. |
|
||||||
- Add a Topic. |
|
||||||
- Set the TTL attribute. |
|
||||||
- Set the expiry as the present Unix time plus TTL. |
|
||||||
- Set the nonce which provides the best PoW. |
|
||||||
|
|
||||||
### Mail Server |
|
||||||
|
|
||||||
Suppose, a Ðapp waits for messages with certain Topic and suffers an unexpected network failure for certain period of time. As a result, a number of important messages will be lost. Since those messages are expired, there is no way to resend them via the normal Whisper channels, because they will be rejected and the peer punished. |
|
||||||
|
|
||||||
One possible way to solve this problem is to run a Mail Server, which would store all the messages, and resend them at the request of the known nodes. Even though the server might repack the old messages and provide sufficient PoW, it's not feasible to resend all of them at whim, because it would tantamount to DDoS attack on the entire network. Instead, the Mail Server should engage in peer-to-peer communication with the node, and resend the expired messages directly. The recipient will consume the messages and will not forward them any further. |
|
||||||
|
|
||||||
In order to facilitate this task, protocol-level support is provided in version 6. New message types are introduced to Whisper v.6: mailRequestCode and p2pCode. |
|
||||||
|
|
||||||
- mailRequestCode is used by the node to request historic (expired) messages from the Mail Server. The payload of this message should be understood by the Server. The Whisper protocol is entirely agnostic about it. It might contain a time frame, the node's authorization details, filtering information, payment details, etc. |
|
||||||
|
|
||||||
- p2pCode is a peer-to-peer message, that is not supposed to be forwarded to other peers. It will also bypass the protocol-level checks for expiry and PoW threshold. |
|
||||||
|
|
||||||
There is MailServer interface defined in the codebase for easy Mail Server implementation. One only needs to implement two functions: |
|
||||||
|
|
||||||
type MailServer interface { |
|
||||||
Archive(env *Envelope) |
|
||||||
DeliverMail(whisperPeer *Peer, data []byte) |
|
||||||
} |
|
||||||
|
|
||||||
Archive should just save all incoming messages. |
|
||||||
DeliverMail should be able to process the request and send the historic messages to the corresponding peer (with p2pCode), according to additional information in the data parameter. This function will be invoked upon receipt of protocol-level mailRequestCode. |
|
@ -1,110 +0,0 @@ |
|||||||
--- |
|
||||||
title: Whisper JavaScript example |
|
||||||
sort_key: B |
|
||||||
--- |
|
||||||
|
|
||||||
[This link](https://github.com/gballet/whisper-chat-example) contains a full-fledged example of how to use Whisper in a small chat application. |
|
||||||
|
|
||||||
The app is a simple Vue single page application that works in several steps. In the first step, the user configures the RPC service that they wish to connect to. Typically, this would be a `geth` client with the `--shh` option enabled. |
|
||||||
|
|
||||||
Then one can install the application locally by typing: |
|
||||||
|
|
||||||
``` |
|
||||||
$ git clone https://github.com/gballet/whisper-chat-example |
|
||||||
$ cd whisper-chat-example |
|
||||||
$ npm install |
|
||||||
``` |
|
||||||
|
|
||||||
The application is then started by typing: |
|
||||||
|
|
||||||
``` |
|
||||||
$ npm run dev |
|
||||||
``` |
|
||||||
|
|
||||||
The application will then be available at `http://localhost:8080` (Note the http here, which is because it's a **demo application** and should not be used in production) |
|
||||||
|
|
||||||
## User workflow |
|
||||||
|
|
||||||
The app starts by asking the user for their user name and whether they want a symmetric or asymmetric connection. If it's asymmetric, the geth server will propose a public key. If it's symmetric, a key has to be provided. |
|
||||||
|
|
||||||
Then the user presses "Start" and the conversation begins. |
|
||||||
|
|
||||||
## The app's state |
|
||||||
|
|
||||||
```javascript |
|
||||||
let data = { |
|
||||||
msgs: [], |
|
||||||
text: "", |
|
||||||
symKeyId: null, |
|
||||||
name: "", |
|
||||||
asymKeyId: null, |
|
||||||
sympw: "", |
|
||||||
asym: true, |
|
||||||
configured: false, |
|
||||||
topic: defaultTopic, |
|
||||||
recipientPubKey: defaultRecipientPubKey, |
|
||||||
asymPubKey: "" |
|
||||||
}; |
|
||||||
``` |
|
||||||
|
|
||||||
This is how the current, transient, state of the application is represented: |
|
||||||
|
|
||||||
* `msgs` is the list of messages in the current conversation |
|
||||||
* `text` contains the text that the current user is typing |
|
||||||
* `name` is the name of the current user, which is used to identify them in conversations |
|
||||||
* `asymKeyId` and `symKeyId` represent handles to the corresponding keys in `geth`'s memory |
|
||||||
* `recipientPubKey` is a hex string representing the public key that an asymmetric message is sent to |
|
||||||
* `topic` is a hex string representing the message's topic |
|
||||||
* `asymPubKey` is a hex string representing the user's own public key |
|
||||||
* `configured` is a flag that is set to true when the user has choosen either a public key or a symmetric key, and a user name |
|
||||||
* `sympw` contains the symmetric password |
|
||||||
|
|
||||||
## The `sendMessage` callback |
|
||||||
|
|
||||||
The `sendMessage` callback is called every time the user clicks on "Send" or presses the return key. It is responsible for creating the RPC request that instructs the `geth` node to encrypt and send the message. |
|
||||||
|
|
||||||
```javascript |
|
||||||
sendMessage() { |
|
||||||
// Start by declaring the message, we picked a JSON format with |
|
||||||
// `text` as the content and `name` as the name of the user who |
|
||||||
// is sending the message. |
|
||||||
let msg = { |
|
||||||
text: this.text, |
|
||||||
name: this.name |
|
||||||
}; |
|
||||||
|
|
||||||
// (code elided for clarity) |
|
||||||
// ... |
|
||||||
|
|
||||||
// Create the data object that will be sent to the RPC endpoint. |
|
||||||
let postData = { |
|
||||||
ttl: 7, |
|
||||||
topic: '0x07678231', |
|
||||||
powTarget: 2.01, |
|
||||||
powTime: 100, |
|
||||||
payload: encodeToHex(JSON.stringify(msg)), |
|
||||||
}; |
|
||||||
|
|
||||||
// Set the appropriate key id. |
|
||||||
if (this.asym) { |
|
||||||
postData.pubKey = this.recipientPubKey; |
|
||||||
postData.sig = this.asymKeyId; |
|
||||||
} else |
|
||||||
postData.symKeyID = this.symKeyId; |
|
||||||
|
|
||||||
// Perform the RPC call that will tell the node to forward |
|
||||||
// that message to all its neighboring nodes. |
|
||||||
this.shh.post(postData); |
|
||||||
|
|
||||||
// (code elided for clarity) |
|
||||||
// ... |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
The `msg` object is created. The format chosen for the object is specific to this demo application. It just contains a text and the name of the sender. This is obviously not secure enough for a real-world application. |
|
||||||
|
|
||||||
That object is converted to a string and then encoded as a hexadecimal string, in the `payload` member of the request's `POST` data object. Other fields include the `topic` of the message, how much work the sending server should do and other parameters. |
|
||||||
|
|
||||||
Next, depending whether the "asymmetric" checkbox has been ticked, the value of `this.asym` will be true or false. Based on this, the system will update the request object with the relevant information. |
|
||||||
|
|
||||||
Finally, the request is being sent with `this.shh.post(postData)`, which calls Web3's `shh.post` function to send the message. |
|
@ -1,786 +0,0 @@ |
|||||||
--- |
|
||||||
title: Whisper RPC API 6.0 |
|
||||||
sort_key: C |
|
||||||
--- |
|
||||||
|
|
||||||
This is the proposed API for whisper v6. |
|
||||||
|
|
||||||
### Specs |
|
||||||
|
|
||||||
- [shh_version](#shh_version) |
|
||||||
- [shh_info](#shh_info) |
|
||||||
- [shh_setMaxMessageSize](#shh_setmaxmessagesize) |
|
||||||
- [shh_setMinPoW](#shh_setminpow) |
|
||||||
- [shh_markTrustedPeer](#shh_marktrustedpeer) |
|
||||||
- [shh_newKeyPair](#shh_newkeypair) |
|
||||||
- [shh_addPrivateKey](#shh_addprivatekey) |
|
||||||
- [shh_deleteKeyPair](#shh_deletekeypair) |
|
||||||
- [shh_hasKeyPair](#shh_haskeypair) |
|
||||||
- [shh_getPublicKey](#shh_getpublickey) |
|
||||||
- [shh_getPrivateKey](#shh_getprivatekey) |
|
||||||
- [shh_newSymKey](#shh_newsymkey) |
|
||||||
- [shh_addSymKey](#shh_addsymkey) |
|
||||||
- [shh_generateSymKeyFromPassword](#shh_generatesymkeyfrompassword) |
|
||||||
- [shh_hasSymKey](#shh_hassymkey) |
|
||||||
- [shh_getSymKey](#shh_getsymkey) |
|
||||||
- [shh_deleteSymKey](#shh_deletesymkey) |
|
||||||
- [shh_subscribe](#shh_subscribe) |
|
||||||
- [shh_unsubscribe](#shh_unsubscribe) |
|
||||||
- [shh_newMessageFilter](#shh_newmessagefilter) |
|
||||||
- [shh_deleteMessageFilter](#shh_deletemessagefilter) |
|
||||||
- [shh_getFilterMessages](#shh_getfiltermessages) |
|
||||||
- [shh_post](#shh_post) |
|
||||||
|
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_version |
|
||||||
|
|
||||||
Returns the current semver version number. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
none |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String` - The version number. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_version","params":[],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "6.0" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_info |
|
||||||
|
|
||||||
Returns diagnostic information about the whisper node. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
none |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Object` - diagnostic information with the following properties: |
|
||||||
- `minPow` - `Number`: current minimum PoW requirement. |
|
||||||
- `maxMessageSize` - `Float`: current messgae size limit in bytes. |
|
||||||
- `memory` - `Number`: Memory size of the floating messages in bytes. |
|
||||||
- `messages` - `Number`: Number of floating messages. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_info","params":[],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": { |
|
||||||
"minPow": 12.5, |
|
||||||
"maxMessageSize": 20000, |
|
||||||
"memory": 10000, |
|
||||||
"messages": 20, |
|
||||||
} |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_setMaxMessageSize |
|
||||||
|
|
||||||
Sets the maximal message size allowed by this node. |
|
||||||
Incoming and outgoing messages with a larger size will be rejected. |
|
||||||
Whisper message size can never exceed the limit imposed by the underlying P2P protocol (10 Mb). |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `Number`: Message size in bytes. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean`: (`true`) on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_setMaxMessageSize","params":[234567],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": true |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_setMinPoW |
|
||||||
|
|
||||||
Sets the minimal PoW required by this node. |
|
||||||
|
|
||||||
This experimental function was introduced for the future dynamic adjustment of PoW requirement. If the node is overwhelmed with messages, it should raise the PoW requirement and notify the peers. The new value should be set relative to the old value (e.g. double). The old value could be obtained via shh_info call. |
|
||||||
|
|
||||||
**Note** This function is currently experimental. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `Number`: The new PoW requirement. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean`: `true` on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_setMinPoW","params":[12.3],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": true |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_markTrustedPeer |
|
||||||
|
|
||||||
Marks specific peer trusted, which will allow it to send historic (expired) messages. |
|
||||||
|
|
||||||
**Note** This function is not adding new nodes, the node needs to exists as a peer. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: Enode of the trusted peer. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean` (`true`) on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_markTrustedPeer","params":["enode://d25474361659861e9e651bc728a17e807a3359ca0d344afd544ed0f11a31faecaf4d74b55db53c6670fd624f08d5c79adfc8da5dd4a11b9213db49a3b750845e@52.178.209.125:30379"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": true |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
|
|
||||||
#### shh_newKeyPair |
|
||||||
|
|
||||||
Generates a new public and private key pair for message decryption and encryption. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
none |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newKeyPair","id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
|
|
||||||
#### shh_addPrivateKey |
|
||||||
|
|
||||||
Stores the key pair, and returns its ID. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: private key as HEX bytes. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_addPrivateKey","params":["0x8bda3abeb454847b515fa9b404cede50b1cc63cfdeddd4999d074284b4c21e15"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "3e22b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_deleteKeyPair |
|
||||||
|
|
||||||
Deletes the specifies key if it exists. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: ID of key pair. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean`: `true` on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_deleteKeyPair","params":["5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": true |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
|
|
||||||
#### shh_hasKeyPair |
|
||||||
|
|
||||||
Checks if the whisper node has a private key of a key pair matching the given ID. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: ID of key pair. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean`: (`true` or `false`) and error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_hasKeyPair","params":["5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": false |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_getPublicKey |
|
||||||
|
|
||||||
Returns the public key for identity ID. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: ID of key pair. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String`: Public key on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getPublicKey","params":["86e658cbc6da63120b79b5eec0c67d5dcfb6865a8f983eff08932477282b77bb"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "0x04d1574d4eab8f3dde4d2dc7ed2c4d699d77cbbdd09167b8fffa099652ce4df00c4c6e0263eafe05007a46fdf0c8d32b11aeabcd3abbc7b2bc2bb967368a68e9c6" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_getPrivateKey |
|
||||||
|
|
||||||
Returns the private key for identity ID. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: ID of the key pair. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String`: Private key on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getPrivateKey","params":["0xc862bf3cf4565d46abcbadaf4712a8940bfea729a91b9b0e338eab5166341ab5"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "0x234234e22b9ffc2387e18636e0534534a3d0c56b0243567432453264c16e78a2adc" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_newSymKey |
|
||||||
|
|
||||||
Generates a random symmetric key and stores it under an ID, which is then returned. |
|
||||||
Can be used encrypting and decrypting messages where the key is known to both parties. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
none |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newSymKey", "params": [], "id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "cec94d139ff51d7df1d228812b90c23ec1f909afa0840ed80f1e04030bb681e4" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_addSymKey |
|
||||||
|
|
||||||
Stores the key, and returns its ID. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: The raw key for symmetric encryption as HEX bytes. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_addSymKey","params":["0xf6dcf21ed6a17bd78d8c4c63195ab997b3b65ea683705501eae82d32667adc92"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_generateSymKeyFromPassword |
|
||||||
|
|
||||||
Generates the key from password, stores it, and returns its ID. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: password. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String`: Key ID on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_generateSymKeyFromPassword","params":["test"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "2e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_hasSymKey |
|
||||||
|
|
||||||
Returns true if there is a key associated with the name string. Otherwise, returns false. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: key ID. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean` (`true` or `false`) on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_hasSymKey","params":["f6dcf21ed6a17bd78d8c4c63195ab997b3b65ea683705501eae82d32667adc92"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": true |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_getSymKey |
|
||||||
|
|
||||||
Returns the symmetric key associated with the given ID. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: key ID. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String`: Raw key on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getSymKey","params":["f6dcf21ed6a17bd78d8c4c63195ab997b3b65ea683705501eae82d32667adc92"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "0xa82a520aff70f7a989098376e48ec128f25f767085e84d7fb995a9815eebff0a" |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_deleteSymKey |
|
||||||
|
|
||||||
Deletes the key associated with the name string if it exists. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: key ID. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean` (`true` or `false`) on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_deleteSymKey","params":["5e57b9ffc2387e18636e0a3d0c56b023264c16e78a2adcba1303cefc685e610f"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": true |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_subscribe |
|
||||||
|
|
||||||
Creates and registers a new subscription to receive notifications for inbound whisper messages. Returns the ID of the newly created subscription. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `id` - `String`: identifier of function call. In case of Whisper must contain the value "messages". |
|
||||||
|
|
||||||
2. `Object`. Options object with the following properties: |
|
||||||
- `symKeyID` - `String`: ID of symmetric key for message decryption. |
|
||||||
- `privateKeyID` - `String`: ID of private (asymmetric) key for message decryption. |
|
||||||
- `sig` - `String` (optional): Public key of the signature. |
|
||||||
- `minPow` - `Number` (optional): Minimal PoW requirement for incoming messages. |
|
||||||
- `topics` - `Array` (optional when asym key): Array of possible topics (or partial topics). |
|
||||||
- `allowP2P` - `Boolean` (optional): Indicates if this filter allows processing of direct peer-to-peer messages (which are not to be forwarded any further, because they might be expired). This might be the case in some very rare cases, e.g. if you intend to communicate to MailServers, etc. |
|
||||||
|
|
||||||
Either `symKeyID` or `privateKeyID` must be present. Can not be both. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String` - The subscription ID on success, the error on failure. |
|
||||||
|
|
||||||
|
|
||||||
##### Notification Return |
|
||||||
|
|
||||||
`Object`: The whisper message matching the subscription options, with the following parameters: |
|
||||||
- `sig` - `String`: Public key who signed this message. |
|
||||||
- `recipientPublicKey` - `String`: The recipients public key. |
|
||||||
- `ttl` - `Number`: Time-to-live in seconds. |
|
||||||
- `timestamp` - `Number`: Unix timestamp of the message genertion. |
|
||||||
- `topic` - `String` 4 Bytes: Message topic. |
|
||||||
- `payload` - `String`: Decrypted payload. |
|
||||||
- `padding` - `String`: Optional padding (byte array of arbitrary length). |
|
||||||
- `pow` - `Number`: Proof of work value. |
|
||||||
- `hash` - `String`: Hash of the enveloved message. |
|
||||||
|
|
||||||
|
|
||||||
##### Example |
|
||||||
``` |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_subscribe","params":["messages", { |
|
||||||
topics: ['0x5a4ea131', '0x11223344'], |
|
||||||
symKeyID: 'b874f3bbaf031214a567485b703a025cec27d26b2c4457d6b139e56ad8734cea', |
|
||||||
sig: '0x048229fb947363cf13bb9f9532e124f08840cd6287ecae6b537cda2947ec2b23dbdc3a07bdf7cd2bfb288c25c4d0d0461d91c719da736a22b7bebbcf912298d1e6', |
|
||||||
pow: 12.3(?) |
|
||||||
}],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": "02c1f5c953804acee3b68eda6c0afe3f1b4e0bec73c7445e10d45da333616412" |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Notification Result |
|
||||||
{ |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"method": "shh_subscription", |
|
||||||
"params": { |
|
||||||
subscription: "02c1f5c953804acee3b68eda6c0afe3f1b4e0bec73c7445e10d45da333616412", |
|
||||||
result: { |
|
||||||
sig: '0x0498ac1951b9078a0549c93c3f6088ec7c790032b17580dc3c0c9e900899a48d89eaa27471e3071d2de6a1f48716ecad8b88ee022f4321a7c29b6ffcbee65624ff', |
|
||||||
recipientPublicKey: null, |
|
||||||
ttl: 10, |
|
||||||
timestamp: 1498577270, |
|
||||||
topic: '0xffaadd11', |
|
||||||
payload: '0xffffffdddddd1122', |
|
||||||
padding: '0x35d017b66b124dd4c67623ed0e3f23ba68e3428aa500f77aceb0dbf4b63f69ccfc7ae11e39671d7c94f1ed170193aa3e327158dffdd7abb888b3a3cc48f718773dc0a9dcf1a3680d00fe17ecd4e8d5db31eb9a3c8e6e329d181ecb6ab29eb7a2d9889b49201d9923e6fd99f03807b730780a58924870f541a8a97c87533b1362646e5f573dc48382ef1e70fa19788613c9d2334df3b613f6e024cd7aadc67f681fda6b7a84efdea40cb907371cd3735f9326d02854', |
|
||||||
pow: 0.6714754098360656, |
|
||||||
hash: '0x17f8066f0540210cf67ef400a8a55bcb32a494a47f91a0d26611c5c1d66f8c57' |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_unsubscribe |
|
||||||
|
|
||||||
Cancels and removes an existing subscription. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `String`: subscription ID. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean`: `true` or `false`. |
|
||||||
|
|
||||||
##### Example |
|
||||||
```js |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_unsubscribe","params":["02c1f5c953804acee3b68eda6c0afe3f1b4e0bec73c7445e10d45da333616412"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": true |
|
||||||
} |
|
||||||
``` |
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_newMessageFilter |
|
||||||
|
|
||||||
Create a new filter within the node. This filter can be used to poll for new messages that match the set of criteria. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `criteria` - `Object`: see [shh_subscribe](#shh_subscribe) |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`String`: filter identifier |
|
||||||
|
|
||||||
##### Example |
|
||||||
``` |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_newMessageFilter","params":[{"symKeyID": "3742c75e4232325d54143707e4b73d17c2f86a5e4abe3359021be5653f5b2c81"}],"id":1}' localhost:8545 |
|
||||||
|
|
||||||
// Result |
|
||||||
{"jsonrpc":"2.0","id":1,"result":"2b47fbafb3cce24570812a82e6e93cd9e2551bbc4823f6548ff0d82d2206b326"} |
|
||||||
|
|
||||||
``` |
|
||||||
|
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_deleteMessageFilter |
|
||||||
|
|
||||||
Uninstall a message filter in the node |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `id` - `String`: filter identifier as returned when the filter was created |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean`: `true` on success, error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
``` |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_deleteMessageFilter","params":[{"symKeyID": "3742c75e4232325d54143707e4b73d17c2f86a5e4abe3359021be5653f5b2c81"}],"id":1}' localhost:8545 |
|
||||||
|
|
||||||
// Result |
|
||||||
{"jsonrpc":"2.0","id":1,"result": true} |
|
||||||
|
|
||||||
``` |
|
||||||
|
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_getFilterMessages |
|
||||||
|
|
||||||
Retrieve messages that match the filter criteria and are received between the last time this |
|
||||||
function was called and now. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `id` - `String`: ID of filter that was created with `shh_newMessageFilter` |
|
||||||
|
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Array of messages`: `true` on success and an error on failure. |
|
||||||
|
|
||||||
`Object`: whisper message: |
|
||||||
- `sig` - `String`: Public key who signed this message. |
|
||||||
- `ttl` - `Number`: Time-to-live in seconds. |
|
||||||
- `timestamp` - `Number`: Unix timestamp of the message generation. |
|
||||||
- `topic` - `String` 4 Bytes: Message topic. |
|
||||||
- `payload` - `String`: Decrypted payload. |
|
||||||
- `padding` - `String`: Optional padding (byte array of arbitrary length). |
|
||||||
- `pow` - `Number`: Proof of work value. |
|
||||||
- `hash` - `String`: Hash of the enveloped message. |
|
||||||
- `recipientPublicKey` - `String`: recipient public key |
|
||||||
|
|
||||||
##### Example |
|
||||||
``` |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_getFilterMessages","params":["2b47fbafb3cce24570812a82e6e93cd9e2551bbc4823f6548ff0d82d2206b326"],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id": 1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": [ |
|
||||||
{ |
|
||||||
"hash": "0xe05c4be74d667bd4c57dba2a8dbfb097d6fc2719d5c0d699d2f84a2442a4d8c2", |
|
||||||
"padding": "0x6e3e82571c7aa91f2a9e82e20344ede0d1112205555843d9dafffeb1536741a1fca758ff30cc01320bb0775aa5b82b9c9f48deb10bff8b5c61354bf8f95f2ab7289c7894c52e285b1d750ea2ffa78edd374bc7386a901d36a59022d73208c852dedaca8709087693ef6831b861139f42a89263af5931cb2b9253216dc42edc1393afd03940f91c561d20080f7a258aa52d30dcf4b1b921b7c910ad429f73ed9308cb6218537f0444d915e993ba8c9bb00af311aab3574bf1722b5640632bf5bb6b12406e1b89d0c98628117b1d8f55ea6b974e251b34969d4c49dfb6036d40e0d90414c65a8b036ae985396d6a4bf28332676e85dc0a0d352a58680200cc", |
|
||||||
"payload": "0xabcd", |
|
||||||
"pow": 0.5371803278688525, |
|
||||||
"recipientPublicKey": null, |
|
||||||
"sig": null, |
|
||||||
"timestamp": 1496991875, |
|
||||||
"topic": "0x01020304", |
|
||||||
"ttl": 50 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"hash": "0x4158eb81ad8e30cfcee67f20b1372983d388f1243a96e39f94fd2797b1e9c78e", |
|
||||||
"padding": "0xc15f786f34e5cef0fef6ce7c1185d799ecdb5ebca72b3310648c5588db2e99a0d73301c7a8d90115a91213f0bc9c72295fbaf584bf14dc97800550ea53577c9fb57c0249caeb081733b4e605cdb1a6011cee8b6d8fddb972c2b90157e23ba3baae6c68d4f0b5822242bb2c4cd821b9568d3033f10ec1114f641668fc1083bf79ebb9f5c15457b538249a97b22a4bcc4f02f06dec7318c16758f7c008001c2e14eba67d26218ec7502ad6ba81b2402159d7c29b068b8937892e3d4f0d4ad1fb9be5e66fb61d3d21a1c3163bce74c0a9d16891e2573146aa92ecd7b91ea96a6987ece052edc5ffb620a8987a83ac5b8b6140d8df6e92e64251bf3a2cec0cca", |
|
||||||
"payload": "0xdeadbeaf", |
|
||||||
"pow": 0.5371803278688525, |
|
||||||
"recipientPublicKey": null, |
|
||||||
"sig": null, |
|
||||||
"timestamp": 1496991876, |
|
||||||
"topic": "0x01020304", |
|
||||||
"ttl": 50 |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
|
|
||||||
``` |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*** |
|
||||||
|
|
||||||
#### shh_post |
|
||||||
|
|
||||||
Creates a whisper message and injects it into the network for distribution. |
|
||||||
|
|
||||||
##### Parameters |
|
||||||
|
|
||||||
1. `Object`. Post options object with the following properties: |
|
||||||
- `symKeyID` - `String`: ID of symmetric key for message encryption. |
|
||||||
- `pubKey` - `String`: public key for message encryption. |
|
||||||
- `sig` - `String` (optional): ID of the signing key. |
|
||||||
- `ttl` - `Number`: Time-to-live in seconds. |
|
||||||
- `topic` - `String` 4 Bytes (mandatory when key is symmetric): Message topic. |
|
||||||
- `payload` - `String`: Payload to be encrypted. |
|
||||||
- `padding` - `String` (optional): Optional padding (byte array of arbitrary length). |
|
||||||
- `powTime` - `Number`: Maximal time in seconds to be spent on proof of work. |
|
||||||
- `powTarget` - `Number`: Minimal PoW target required for this message. |
|
||||||
- `targetPeer` - `String` (optional): Optional peer ID (for peer-to-peer message only). |
|
||||||
|
|
||||||
Either `symKeyID` or `pubKey` must be present. Can not be both. |
|
||||||
|
|
||||||
##### Returns |
|
||||||
|
|
||||||
`Boolean`: `true` on success and an error on failure. |
|
||||||
|
|
||||||
##### Example |
|
||||||
``` |
|
||||||
// Request |
|
||||||
curl -X POST --data '{"jsonrpc":"2.0","method":"shh_post","params":[{ |
|
||||||
pubKey: 'b874f3bbaf031214a567485b703a025cec27d26b2c4457d6b139e56ad8734cea', |
|
||||||
ttl: 7, |
|
||||||
topic: '0x07678231', |
|
||||||
powTarget: 2.01, |
|
||||||
powTime: 2, |
|
||||||
payload: '0x68656c6c6f' |
|
||||||
}],"id":1}' |
|
||||||
|
|
||||||
// Result |
|
||||||
{ |
|
||||||
"id":1, |
|
||||||
"jsonrpc": "2.0", |
|
||||||
"result": true |
|
||||||
} |
|
||||||
``` |
|
Loading…
Reference in new issue