github.com/aitimate-0/go-ethereum@v1.9.7/whisper/whisperv6/envelope.go (about) 1 // Copyright 2016 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. 18 19 package whisperv6 20 21 import ( 22 "crypto/ecdsa" 23 "encoding/binary" 24 "fmt" 25 gmath "math" 26 "math/big" 27 "time" 28 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/crypto/ecies" 32 "github.com/ethereum/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 39 TTL uint32 40 Topic TopicType 41 Data []byte 42 Nonce uint64 43 44 pow float64 // Message-specific PoW as described in the Whisper specification. 45 46 // the following variables should not be accessed directly, use the corresponding function instead: Hash(), Bloom() 47 hash common.Hash // Cached hash of the envelope to avoid rehashing every time. 48 bloom []byte 49 } 50 51 // size returns the size of envelope as it is sent (i.e. public fields only) 52 func (e *Envelope) size() int { 53 return EnvelopeHeaderLength + len(e.Data) 54 } 55 56 // rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce. 57 func (e *Envelope) rlpWithoutNonce() []byte { 58 res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Data}) 59 return res 60 } 61 62 // NewEnvelope wraps a Whisper message with expiration and destination data 63 // included into an envelope for network forwarding. 64 func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage) *Envelope { 65 env := Envelope{ 66 Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), 67 TTL: ttl, 68 Topic: topic, 69 Data: msg.Raw, 70 Nonce: 0, 71 } 72 73 return &env 74 } 75 76 // Seal closes the envelope by spending the requested amount of time as a proof 77 // of work on hashing the data. 78 func (e *Envelope) Seal(options *MessageParams) error { 79 if options.PoW == 0 { 80 // PoW is not required 81 return nil 82 } 83 84 var target, bestLeadingZeros int 85 if options.PoW < 0 { 86 // target is not set - the function should run for a period 87 // of time specified in WorkTime param. Since we can predict 88 // the execution time, we can also adjust Expiry. 89 e.Expiry += options.WorkTime 90 } else { 91 target = e.powToFirstBit(options.PoW) 92 } 93 94 rlp := e.rlpWithoutNonce() 95 buf := make([]byte, len(rlp)+8) 96 copy(buf, rlp) 97 asAnInt := new(big.Int) 98 99 finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() 100 for nonce := uint64(0); time.Now().UnixNano() < finish; { 101 for i := 0; i < 1024; i++ { 102 binary.BigEndian.PutUint64(buf[len(rlp):], nonce) 103 h := crypto.Keccak256(buf) 104 asAnInt.SetBytes(h) 105 leadingZeros := 256 - asAnInt.BitLen() 106 if leadingZeros > bestLeadingZeros { 107 e.Nonce, bestLeadingZeros = nonce, leadingZeros 108 if target > 0 && bestLeadingZeros >= target { 109 return nil 110 } 111 } 112 nonce++ 113 } 114 } 115 116 if target > 0 && bestLeadingZeros < target { 117 return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) 118 } 119 120 return nil 121 } 122 123 // PoW computes (if necessary) and returns the proof of work target 124 // of the envelope. 125 func (e *Envelope) PoW() float64 { 126 if e.pow == 0 { 127 e.calculatePoW(0) 128 } 129 return e.pow 130 } 131 132 func (e *Envelope) calculatePoW(diff uint32) { 133 rlp := e.rlpWithoutNonce() 134 buf := make([]byte, len(rlp)+8) 135 copy(buf, rlp) 136 binary.BigEndian.PutUint64(buf[len(rlp):], e.Nonce) 137 powHash := new(big.Int).SetBytes(crypto.Keccak256(buf)) 138 leadingZeroes := 256 - powHash.BitLen() 139 x := gmath.Pow(2, float64(leadingZeroes)) 140 x /= float64(len(rlp)) 141 x /= float64(e.TTL + diff) 142 e.pow = x 143 } 144 145 func (e *Envelope) powToFirstBit(pow float64) int { 146 x := pow 147 x *= float64(e.size()) 148 x *= float64(e.TTL) 149 bits := gmath.Log2(x) 150 bits = gmath.Ceil(bits) 151 res := int(bits) 152 if res < 1 { 153 res = 1 154 } 155 return res 156 } 157 158 // Hash returns the SHA3 hash of the envelope, calculating it if not yet done. 159 func (e *Envelope) Hash() common.Hash { 160 if (e.hash == common.Hash{}) { 161 encoded, _ := rlp.EncodeToBytes(e) 162 e.hash = crypto.Keccak256Hash(encoded) 163 } 164 return e.hash 165 } 166 167 // DecodeRLP decodes an Envelope from an RLP data stream. 168 func (e *Envelope) DecodeRLP(s *rlp.Stream) error { 169 raw, err := s.Raw() 170 if err != nil { 171 return err 172 } 173 // The decoding of Envelope uses the struct fields but also needs 174 // to compute the hash of the whole RLP-encoded envelope. This 175 // type has the same structure as Envelope but is not an 176 // rlp.Decoder (does not implement DecodeRLP function). 177 // Only public members will be encoded. 178 type rlpenv Envelope 179 if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { 180 return err 181 } 182 e.hash = crypto.Keccak256Hash(raw) 183 return nil 184 } 185 186 // OpenAsymmetric tries to decrypt an envelope, potentially encrypted with a particular key. 187 func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { 188 message := &ReceivedMessage{Raw: e.Data} 189 err := message.decryptAsymmetric(key) 190 switch err { 191 case nil: 192 return message, nil 193 case ecies.ErrInvalidPublicKey: // addressed to somebody else 194 return nil, err 195 default: 196 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 197 } 198 } 199 200 // OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key. 201 func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { 202 msg = &ReceivedMessage{Raw: e.Data} 203 err = msg.decryptSymmetric(key) 204 if err != nil { 205 msg = nil 206 } 207 return msg, err 208 } 209 210 // Open tries to decrypt an envelope, and populates the message fields in case of success. 211 func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { 212 if watcher == nil { 213 return nil 214 } 215 216 // The API interface forbids filters doing both symmetric and asymmetric encryption. 217 if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() { 218 return nil 219 } 220 221 if watcher.expectsAsymmetricEncryption() { 222 msg, _ = e.OpenAsymmetric(watcher.KeyAsym) 223 if msg != nil { 224 msg.Dst = &watcher.KeyAsym.PublicKey 225 } 226 } else if watcher.expectsSymmetricEncryption() { 227 msg, _ = e.OpenSymmetric(watcher.KeySym) 228 if msg != nil { 229 msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 230 } 231 } 232 233 if msg != nil { 234 ok := msg.ValidateAndParse() 235 if !ok { 236 return nil 237 } 238 msg.Topic = e.Topic 239 msg.PoW = e.PoW() 240 msg.TTL = e.TTL 241 msg.Sent = e.Expiry - e.TTL 242 msg.EnvelopeHash = e.Hash() 243 } 244 return msg 245 } 246 247 // Bloom maps 4-bytes Topic into 64-byte bloom filter with 3 bits set (at most). 248 func (e *Envelope) Bloom() []byte { 249 if e.bloom == nil { 250 e.bloom = TopicToBloom(e.Topic) 251 } 252 return e.bloom 253 } 254 255 // TopicToBloom converts the topic (4 bytes) to the bloom filter (64 bytes) 256 func TopicToBloom(topic TopicType) []byte { 257 b := make([]byte, BloomFilterSize) 258 var index [3]int 259 for j := 0; j < 3; j++ { 260 index[j] = int(topic[j]) 261 if (topic[3] & (1 << uint(j))) != 0 { 262 index[j] += 256 263 } 264 } 265 266 for j := 0; j < 3; j++ { 267 byteIndex := index[j] / 8 268 bitIndex := index[j] % 8 269 b[byteIndex] = (1 << uint(bitIndex)) 270 } 271 return b 272 } 273 274 // GetEnvelope retrieves an envelope from the message queue by its hash. 275 // It returns nil if the envelope can not be found. 276 func (w *Whisper) GetEnvelope(hash common.Hash) *Envelope { 277 w.poolMu.RLock() 278 defer w.poolMu.RUnlock() 279 return w.envelopes[hash] 280 }