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