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