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