aboutsummaryrefslogtreecommitdiffstats
path: root/whisper/whisperv2/message.go
diff options
context:
space:
mode:
Diffstat (limited to 'whisper/whisperv2/message.go')
-rw-r--r--whisper/whisperv2/message.go156
1 files changed, 156 insertions, 0 deletions
diff --git a/whisper/whisperv2/message.go b/whisper/whisperv2/message.go
new file mode 100644
index 000000000..7ef9d0912
--- /dev/null
+++ b/whisper/whisperv2/message.go
@@ -0,0 +1,156 @@
+// Copyright 2014 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+
+// Contains the Whisper protocol Message element. For formal details please see
+// the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#messages.
+
+package whisperv2
+
+import (
+ "crypto/ecdsa"
+ "math/rand"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/logger/glog"
+)
+
+// Message represents an end-user data packet to transmit through the Whisper
+// protocol. These are wrapped into Envelopes that need not be understood by
+// intermediate nodes, just forwarded.
+type Message struct {
+ Flags byte // First bit is signature presence, rest reserved and should be random
+ Signature []byte
+ Payload []byte
+
+ Sent time.Time // Time when the message was posted into the network
+ TTL time.Duration // Maximum time to live allowed for the message
+
+ To *ecdsa.PublicKey // Message recipient (identity used to decode the message)
+ Hash common.Hash // Message envelope hash to act as a unique id
+}
+
+// Options specifies the exact way a message should be wrapped into an Envelope.
+type Options struct {
+ From *ecdsa.PrivateKey
+ To *ecdsa.PublicKey
+ TTL time.Duration
+ Topics []Topic
+}
+
+// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
+func NewMessage(payload []byte) *Message {
+ // Construct an initial flag set: no signature, rest random
+ flags := byte(rand.Intn(256))
+ flags &= ^signatureFlag
+
+ // Assemble and return the message
+ return &Message{
+ Flags: flags,
+ Payload: payload,
+ Sent: time.Now(),
+ }
+}
+
+// Wrap bundles the message into an Envelope to transmit over the network.
+//
+// pow (Proof Of Work) controls how much time to spend on hashing the message,
+// inherently controlling its priority through the network (smaller hash, bigger
+// priority).
+//
+// The user can control the amount of identity, privacy and encryption through
+// the options parameter as follows:
+// - options.From == nil && options.To == nil: anonymous broadcast
+// - options.From != nil && options.To == nil: signed broadcast (known sender)
+// - options.From == nil && options.To != nil: encrypted anonymous message
+// - options.From != nil && options.To != nil: encrypted signed message
+func (self *Message) Wrap(pow time.Duration, options Options) (*Envelope, error) {
+ // Use the default TTL if non was specified
+ if options.TTL == 0 {
+ options.TTL = DefaultTTL
+ }
+ self.TTL = options.TTL
+
+ // Sign and encrypt the message if requested
+ if options.From != nil {
+ if err := self.sign(options.From); err != nil {
+ return nil, err
+ }
+ }
+ if options.To != nil {
+ if err := self.encrypt(options.To); err != nil {
+ return nil, err
+ }
+ }
+ // Wrap the processed message, seal it and return
+ envelope := NewEnvelope(options.TTL, options.Topics, self)
+ envelope.Seal(pow)
+
+ return envelope, nil
+}
+
+// sign calculates and sets the cryptographic signature for the message , also
+// setting the sign flag.
+func (self *Message) sign(key *ecdsa.PrivateKey) (err error) {
+ self.Flags |= signatureFlag
+ self.Signature, err = crypto.Sign(self.hash(), key)
+ return
+}
+
+// Recover retrieves the public key of the message signer.
+func (self *Message) Recover() *ecdsa.PublicKey {
+ defer func() { recover() }() // in case of invalid signature
+
+ // Short circuit if no signature is present
+ if self.Signature == nil {
+ return nil
+ }
+ // Otherwise try and recover the signature
+ pub, err := crypto.SigToPub(self.hash(), self.Signature)
+ if err != nil {
+ glog.V(logger.Error).Infof("Could not get public key from signature: %v", err)
+ return nil
+ }
+ return pub
+}
+
+// encrypt encrypts a message payload with a public key.
+func (self *Message) encrypt(key *ecdsa.PublicKey) (err error) {
+ self.Payload, err = crypto.Encrypt(key, self.Payload)
+ return
+}
+
+// decrypt decrypts an encrypted payload with a private key.
+func (self *Message) decrypt(key *ecdsa.PrivateKey) error {
+ cleartext, err := crypto.Decrypt(key, self.Payload)
+ if err == nil {
+ self.Payload = cleartext
+ }
+ return err
+}
+
+// hash calculates the SHA3 checksum of the message flags and payload.
+func (self *Message) hash() []byte {
+ return crypto.Keccak256(append([]byte{self.Flags}, self.Payload...))
+}
+
+// bytes flattens the message contents (flags, signature and payload) into a
+// single binary blob.
+func (self *Message) bytes() []byte {
+ return append([]byte{self.Flags}, append(self.Signature, self.Payload...)...)
+}