github.com/needkane/go-ethereum@v1.7.4-0.20180131070256-c212876ea2b7/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/common/math" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/crypto/ecies" 33 "github.com/ethereum/go-ethereum/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 var target, bestBit int 81 if options.PoW == 0 { 82 // adjust for the duration of Seal() execution only if execution time is predefined unconditionally 83 e.Expiry += options.WorkTime 84 } else { 85 target = e.powToFirstBit(options.PoW) 86 if target < 1 { 87 target = 1 88 } 89 } 90 91 buf := make([]byte, 64) 92 h := crypto.Keccak256(e.rlpWithoutNonce()) 93 copy(buf[:32], h) 94 95 finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() 96 for nonce := uint64(0); time.Now().UnixNano() < finish; { 97 for i := 0; i < 1024; i++ { 98 binary.BigEndian.PutUint64(buf[56:], nonce) 99 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 100 firstBit := math.FirstBitSet(d) 101 if firstBit > bestBit { 102 e.Nonce, bestBit = nonce, firstBit 103 if target > 0 && bestBit >= target { 104 return nil 105 } 106 } 107 nonce++ 108 } 109 } 110 111 if target > 0 && bestBit < target { 112 return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) 113 } 114 115 return nil 116 } 117 118 // PoW computes (if necessary) and returns the proof of work target 119 // of the envelope. 120 func (e *Envelope) PoW() float64 { 121 if e.pow == 0 { 122 e.calculatePoW(0) 123 } 124 return e.pow 125 } 126 127 func (e *Envelope) calculatePoW(diff uint32) { 128 buf := make([]byte, 64) 129 h := crypto.Keccak256(e.rlpWithoutNonce()) 130 copy(buf[:32], h) 131 binary.BigEndian.PutUint64(buf[56:], e.Nonce) 132 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 133 firstBit := math.FirstBitSet(d) 134 x := gmath.Pow(2, float64(firstBit)) 135 x /= float64(e.size()) 136 x /= float64(e.TTL + diff) 137 e.pow = x 138 } 139 140 func (e *Envelope) powToFirstBit(pow float64) int { 141 x := pow 142 x *= float64(e.size()) 143 x *= float64(e.TTL) 144 bits := gmath.Log2(x) 145 bits = gmath.Ceil(bits) 146 return int(bits) 147 } 148 149 // Hash returns the SHA3 hash of the envelope, calculating it if not yet done. 150 func (e *Envelope) Hash() common.Hash { 151 if (e.hash == common.Hash{}) { 152 encoded, _ := rlp.EncodeToBytes(e) 153 e.hash = crypto.Keccak256Hash(encoded) 154 } 155 return e.hash 156 } 157 158 // DecodeRLP decodes an Envelope from an RLP data stream. 159 func (e *Envelope) DecodeRLP(s *rlp.Stream) error { 160 raw, err := s.Raw() 161 if err != nil { 162 return err 163 } 164 // The decoding of Envelope uses the struct fields but also needs 165 // to compute the hash of the whole RLP-encoded envelope. This 166 // type has the same structure as Envelope but is not an 167 // rlp.Decoder (does not implement DecodeRLP function). 168 // Only public members will be encoded. 169 type rlpenv Envelope 170 if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { 171 return err 172 } 173 e.hash = crypto.Keccak256Hash(raw) 174 return nil 175 } 176 177 // OpenAsymmetric tries to decrypt an envelope, potentially encrypted with a particular key. 178 func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { 179 message := &ReceivedMessage{Raw: e.Data} 180 err := message.decryptAsymmetric(key) 181 switch err { 182 case nil: 183 return message, nil 184 case ecies.ErrInvalidPublicKey: // addressed to somebody else 185 return nil, err 186 default: 187 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 188 } 189 } 190 191 // OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key. 192 func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { 193 msg = &ReceivedMessage{Raw: e.Data} 194 err = msg.decryptSymmetric(key) 195 if err != nil { 196 msg = nil 197 } 198 return msg, err 199 } 200 201 // Open tries to decrypt an envelope, and populates the message fields in case of success. 202 func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { 203 // The API interface forbids filters doing both symmetric and asymmetric encryption. 204 if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() { 205 return nil 206 } 207 208 if watcher.expectsAsymmetricEncryption() { 209 msg, _ = e.OpenAsymmetric(watcher.KeyAsym) 210 if msg != nil { 211 msg.Dst = &watcher.KeyAsym.PublicKey 212 } 213 } else if watcher.expectsSymmetricEncryption() { 214 msg, _ = e.OpenSymmetric(watcher.KeySym) 215 if msg != nil { 216 msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 217 } 218 } 219 220 if msg != nil { 221 ok := msg.ValidateAndParse() 222 if !ok { 223 return nil 224 } 225 msg.Topic = e.Topic 226 msg.PoW = e.PoW() 227 msg.TTL = e.TTL 228 msg.Sent = e.Expiry - e.TTL 229 msg.EnvelopeHash = e.Hash() 230 } 231 return msg 232 } 233 234 // Bloom maps 4-bytes Topic into 64-byte bloom filter with 3 bits set (at most). 235 func (e *Envelope) Bloom() []byte { 236 if e.bloom == nil { 237 e.bloom = TopicToBloom(e.Topic) 238 } 239 return e.bloom 240 } 241 242 // TopicToBloom converts the topic (4 bytes) to the bloom filter (64 bytes) 243 func TopicToBloom(topic TopicType) []byte { 244 b := make([]byte, bloomFilterSize) 245 var index [3]int 246 for j := 0; j < 3; j++ { 247 index[j] = int(topic[j]) 248 if (topic[3] & (1 << uint(j))) != 0 { 249 index[j] += 256 250 } 251 } 252 253 for j := 0; j < 3; j++ { 254 byteIndex := index[j] / 8 255 bitIndex := index[j] % 8 256 b[byteIndex] = (1 << uint(bitIndex)) 257 } 258 return b 259 }