github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/whisper/envelope.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Contains the Whisper protocol Envelope element. For formal details please see 18 // the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#envelopes. 19 20 package whisper 21 22 import ( 23 "crypto/ecdsa" 24 "encoding/binary" 25 "fmt" 26 "math/big" 27 "time" 28 29 "github.com/ethereumproject/go-ethereum/common" 30 "github.com/ethereumproject/go-ethereum/crypto" 31 "github.com/ethereumproject/go-ethereum/crypto/ecies" 32 "github.com/ethereumproject/go-ethereum/rlp" 33 ) 34 35 // Envelope represents a clear-text data packet to transmit through the Whisper 36 // network. Its contents may or may not be encrypted and signed. 37 type Envelope struct { 38 Expiry uint32 // Whisper protocol specifies int32, really should be int64 39 TTL uint32 // ^^^^^^ 40 Topics []Topic 41 Data []byte 42 Nonce uint32 43 44 hash common.Hash // Cached hash of the envelope to avoid rehashing every time 45 } 46 47 // NewEnvelope wraps a Whisper message with expiration and destination data 48 // included into an envelope for network forwarding. 49 func NewEnvelope(ttl time.Duration, topics []Topic, msg *Message) *Envelope { 50 return &Envelope{ 51 Expiry: uint32(time.Now().Add(ttl).Unix()), 52 TTL: uint32(ttl.Seconds()), 53 Topics: topics, 54 Data: msg.bytes(), 55 Nonce: 0, 56 } 57 } 58 59 // Seal closes the envelope by spending the requested amount of time as a proof 60 // of work on hashing the data. 61 func (self *Envelope) Seal(pow time.Duration) { 62 d := make([]byte, 64) 63 copy(d[:32], self.rlpWithoutNonce()) 64 65 finish, bestBit := time.Now().Add(pow).UnixNano(), 0 66 for nonce := uint32(0); time.Now().UnixNano() < finish; { 67 for i := 0; i < 1024; i++ { 68 binary.BigEndian.PutUint32(d[60:], nonce) 69 70 firstBit := common.FirstBitSet(new(big.Int).SetBytes(crypto.Keccak256(d))) 71 if firstBit > bestBit { 72 self.Nonce, bestBit = nonce, firstBit 73 } 74 nonce++ 75 } 76 } 77 } 78 79 // rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce. 80 func (self *Envelope) rlpWithoutNonce() []byte { 81 enc, _ := rlp.EncodeToBytes([]interface{}{self.Expiry, self.TTL, self.Topics, self.Data}) 82 return enc 83 } 84 85 // Open extracts the message contained within a potentially encrypted envelope. 86 func (self *Envelope) Open(key *ecdsa.PrivateKey) (msg *Message, err error) { 87 // Split open the payload into a message construct 88 data := self.Data 89 90 message := &Message{ 91 Flags: data[0], 92 Sent: time.Unix(int64(self.Expiry-self.TTL), 0), 93 TTL: time.Duration(self.TTL) * time.Second, 94 Hash: self.Hash(), 95 } 96 data = data[1:] 97 98 if message.Flags&signatureFlag == signatureFlag { 99 if len(data) < signatureLength { 100 return nil, fmt.Errorf("unable to open envelope. First bit set but len(data) < len(signature)") 101 } 102 message.Signature, data = data[:signatureLength], data[signatureLength:] 103 } 104 message.Payload = data 105 106 // Decrypt the message, if requested 107 if key == nil { 108 return message, nil 109 } 110 err = message.decrypt(key) 111 switch err { 112 case nil: 113 return message, nil 114 115 case ecies.ErrInvalidPublicKey: // Payload isn't encrypted 116 return message, err 117 118 default: 119 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 120 } 121 } 122 123 // Hash returns the SHA3 hash of the envelope, calculating it if not yet done. 124 func (self *Envelope) Hash() common.Hash { 125 if (self.hash == common.Hash{}) { 126 enc, _ := rlp.EncodeToBytes(self) 127 self.hash = crypto.Keccak256Hash(enc) 128 } 129 return self.hash 130 } 131 132 // DecodeRLP decodes an Envelope from an RLP data stream. 133 func (self *Envelope) DecodeRLP(s *rlp.Stream) error { 134 raw, err := s.Raw() 135 if err != nil { 136 return err 137 } 138 // The decoding of Envelope uses the struct fields but also needs 139 // to compute the hash of the whole RLP-encoded envelope. This 140 // type has the same structure as Envelope but is not an 141 // rlp.Decoder so we can reuse the Envelope struct definition. 142 type rlpenv Envelope 143 if err := rlp.DecodeBytes(raw, (*rlpenv)(self)); err != nil { 144 return err 145 } 146 self.hash = crypto.Keccak256Hash(raw) 147 return nil 148 }