github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/whisper/whisperv6/envelope.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  // Contains the Whisper protocol Envelope element.
    13  
    14  package whisperv6
    15  
    16  import (
    17  	"crypto/ecdsa"
    18  	"encoding/binary"
    19  	"fmt"
    20  	gmath "math"
    21  	"math/big"
    22  	"time"
    23  
    24  	"github.com/Sberex/go-sberex/common"
    25  	"github.com/Sberex/go-sberex/common/math"
    26  	"github.com/Sberex/go-sberex/crypto"
    27  	"github.com/Sberex/go-sberex/crypto/ecies"
    28  	"github.com/Sberex/go-sberex/rlp"
    29  )
    30  
    31  // Envelope represents a clear-text data packet to transmit through the Whisper
    32  // network. Its contents may or may not be encrypted and signed.
    33  type Envelope struct {
    34  	Expiry uint32
    35  	TTL    uint32
    36  	Topic  TopicType
    37  	Data   []byte
    38  	Nonce  uint64
    39  
    40  	pow float64 // Message-specific PoW as described in the Whisper specification.
    41  
    42  	// the following variables should not be accessed directly, use the corresponding function instead: Hash(), Bloom()
    43  	hash  common.Hash // Cached hash of the envelope to avoid rehashing every time.
    44  	bloom []byte
    45  }
    46  
    47  // size returns the size of envelope as it is sent (i.e. public fields only)
    48  func (e *Envelope) size() int {
    49  	return EnvelopeHeaderLength + len(e.Data)
    50  }
    51  
    52  // rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
    53  func (e *Envelope) rlpWithoutNonce() []byte {
    54  	res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Data})
    55  	return res
    56  }
    57  
    58  // NewEnvelope wraps a Whisper message with expiration and destination data
    59  // included into an envelope for network forwarding.
    60  func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage) *Envelope {
    61  	env := Envelope{
    62  		Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
    63  		TTL:    ttl,
    64  		Topic:  topic,
    65  		Data:   msg.Raw,
    66  		Nonce:  0,
    67  	}
    68  
    69  	return &env
    70  }
    71  
    72  // Seal closes the envelope by spending the requested amount of time as a proof
    73  // of work on hashing the data.
    74  func (e *Envelope) Seal(options *MessageParams) error {
    75  	if options.PoW == 0 {
    76  		// PoW is not required
    77  		return nil
    78  	}
    79  
    80  	var target, bestBit int
    81  	if options.PoW < 0 {
    82  		// target is not set - the function should run for a period
    83  		// of time specified in WorkTime param. Since we can predict
    84  		// the execution time, we can also adjust Expiry.
    85  		e.Expiry += options.WorkTime
    86  	} else {
    87  		target = e.powToFirstBit(options.PoW)
    88  	}
    89  
    90  	buf := make([]byte, 64)
    91  	h := crypto.Keccak256(e.rlpWithoutNonce())
    92  	copy(buf[:32], h)
    93  
    94  	finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano()
    95  	for nonce := uint64(0); time.Now().UnixNano() < finish; {
    96  		for i := 0; i < 1024; i++ {
    97  			binary.BigEndian.PutUint64(buf[56:], nonce)
    98  			d := new(big.Int).SetBytes(crypto.Keccak256(buf))
    99  			firstBit := math.FirstBitSet(d)
   100  			if firstBit > bestBit {
   101  				e.Nonce, bestBit = nonce, firstBit
   102  				if target > 0 && bestBit >= target {
   103  					return nil
   104  				}
   105  			}
   106  			nonce++
   107  		}
   108  	}
   109  
   110  	if target > 0 && bestBit < target {
   111  		return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime)
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  // PoW computes (if necessary) and returns the proof of work target
   118  // of the envelope.
   119  func (e *Envelope) PoW() float64 {
   120  	if e.pow == 0 {
   121  		e.calculatePoW(0)
   122  	}
   123  	return e.pow
   124  }
   125  
   126  func (e *Envelope) calculatePoW(diff uint32) {
   127  	buf := make([]byte, 64)
   128  	h := crypto.Keccak256(e.rlpWithoutNonce())
   129  	copy(buf[:32], h)
   130  	binary.BigEndian.PutUint64(buf[56:], e.Nonce)
   131  	d := new(big.Int).SetBytes(crypto.Keccak256(buf))
   132  	firstBit := math.FirstBitSet(d)
   133  	x := gmath.Pow(2, float64(firstBit))
   134  	x /= float64(e.size())
   135  	x /= float64(e.TTL + diff)
   136  	e.pow = x
   137  }
   138  
   139  func (e *Envelope) powToFirstBit(pow float64) int {
   140  	x := pow
   141  	x *= float64(e.size())
   142  	x *= float64(e.TTL)
   143  	bits := gmath.Log2(x)
   144  	bits = gmath.Ceil(bits)
   145  	res := int(bits)
   146  	if res < 1 {
   147  		res = 1
   148  	}
   149  	return res
   150  }
   151  
   152  // Hash returns the SHA3 hash of the envelope, calculating it if not yet done.
   153  func (e *Envelope) Hash() common.Hash {
   154  	if (e.hash == common.Hash{}) {
   155  		encoded, _ := rlp.EncodeToBytes(e)
   156  		e.hash = crypto.Keccak256Hash(encoded)
   157  	}
   158  	return e.hash
   159  }
   160  
   161  // DecodeRLP decodes an Envelope from an RLP data stream.
   162  func (e *Envelope) DecodeRLP(s *rlp.Stream) error {
   163  	raw, err := s.Raw()
   164  	if err != nil {
   165  		return err
   166  	}
   167  	// The decoding of Envelope uses the struct fields but also needs
   168  	// to compute the hash of the whole RLP-encoded envelope. This
   169  	// type has the same structure as Envelope but is not an
   170  	// rlp.Decoder (does not implement DecodeRLP function).
   171  	// Only public members will be encoded.
   172  	type rlpenv Envelope
   173  	if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil {
   174  		return err
   175  	}
   176  	e.hash = crypto.Keccak256Hash(raw)
   177  	return nil
   178  }
   179  
   180  // OpenAsymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
   181  func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) {
   182  	message := &ReceivedMessage{Raw: e.Data}
   183  	err := message.decryptAsymmetric(key)
   184  	switch err {
   185  	case nil:
   186  		return message, nil
   187  	case ecies.ErrInvalidPublicKey: // addressed to somebody else
   188  		return nil, err
   189  	default:
   190  		return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err)
   191  	}
   192  }
   193  
   194  // OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
   195  func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
   196  	msg = &ReceivedMessage{Raw: e.Data}
   197  	err = msg.decryptSymmetric(key)
   198  	if err != nil {
   199  		msg = nil
   200  	}
   201  	return msg, err
   202  }
   203  
   204  // Open tries to decrypt an envelope, and populates the message fields in case of success.
   205  func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) {
   206  	// The API interface forbids filters doing both symmetric and asymmetric encryption.
   207  	if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() {
   208  		return nil
   209  	}
   210  
   211  	if watcher.expectsAsymmetricEncryption() {
   212  		msg, _ = e.OpenAsymmetric(watcher.KeyAsym)
   213  		if msg != nil {
   214  			msg.Dst = &watcher.KeyAsym.PublicKey
   215  		}
   216  	} else if watcher.expectsSymmetricEncryption() {
   217  		msg, _ = e.OpenSymmetric(watcher.KeySym)
   218  		if msg != nil {
   219  			msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym)
   220  		}
   221  	}
   222  
   223  	if msg != nil {
   224  		ok := msg.ValidateAndParse()
   225  		if !ok {
   226  			return nil
   227  		}
   228  		msg.Topic = e.Topic
   229  		msg.PoW = e.PoW()
   230  		msg.TTL = e.TTL
   231  		msg.Sent = e.Expiry - e.TTL
   232  		msg.EnvelopeHash = e.Hash()
   233  	}
   234  	return msg
   235  }
   236  
   237  // Bloom maps 4-bytes Topic into 64-byte bloom filter with 3 bits set (at most).
   238  func (e *Envelope) Bloom() []byte {
   239  	if e.bloom == nil {
   240  		e.bloom = TopicToBloom(e.Topic)
   241  	}
   242  	return e.bloom
   243  }
   244  
   245  // TopicToBloom converts the topic (4 bytes) to the bloom filter (64 bytes)
   246  func TopicToBloom(topic TopicType) []byte {
   247  	b := make([]byte, bloomFilterSize)
   248  	var index [3]int
   249  	for j := 0; j < 3; j++ {
   250  		index[j] = int(topic[j])
   251  		if (topic[3] & (1 << uint(j))) != 0 {
   252  			index[j] += 256
   253  		}
   254  	}
   255  
   256  	for j := 0; j < 3; j++ {
   257  		byteIndex := index[j] / 8
   258  		bitIndex := index[j] % 8
   259  		b[byteIndex] = (1 << uint(bitIndex))
   260  	}
   261  	return b
   262  }