github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/whisper/whisperv6/envelope.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:51</date> 10 //</624342690238042112> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 // 29 30 package whisperv6 31 32 import ( 33 "crypto/ecdsa" 34 "encoding/binary" 35 "fmt" 36 gmath "math" 37 "math/big" 38 "time" 39 40 "github.com/ethereum/go-ethereum/common" 41 "github.com/ethereum/go-ethereum/common/math" 42 "github.com/ethereum/go-ethereum/crypto" 43 "github.com/ethereum/go-ethereum/crypto/ecies" 44 "github.com/ethereum/go-ethereum/rlp" 45 ) 46 47 // 48 // 49 type Envelope struct { 50 Expiry uint32 51 TTL uint32 52 Topic TopicType 53 Data []byte 54 Nonce uint64 55 56 pow float64 // 57 58 // 59 hash common.Hash // 60 bloom []byte 61 } 62 63 // 64 func (e *Envelope) size() int { 65 return EnvelopeHeaderLength + len(e.Data) 66 } 67 68 // 69 func (e *Envelope) rlpWithoutNonce() []byte { 70 res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Data}) 71 return res 72 } 73 74 // 75 // 76 func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage) *Envelope { 77 env := Envelope{ 78 Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), 79 TTL: ttl, 80 Topic: topic, 81 Data: msg.Raw, 82 Nonce: 0, 83 } 84 85 return &env 86 } 87 88 // 89 // 90 func (e *Envelope) Seal(options *MessageParams) error { 91 if options.PoW == 0 { 92 // 93 return nil 94 } 95 96 var target, bestBit int 97 if options.PoW < 0 { 98 // 99 // 100 // 101 e.Expiry += options.WorkTime 102 } else { 103 target = e.powToFirstBit(options.PoW) 104 } 105 106 buf := make([]byte, 64) 107 h := crypto.Keccak256(e.rlpWithoutNonce()) 108 copy(buf[:32], h) 109 110 finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() 111 for nonce := uint64(0); time.Now().UnixNano() < finish; { 112 for i := 0; i < 1024; i++ { 113 binary.BigEndian.PutUint64(buf[56:], nonce) 114 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 115 firstBit := math.FirstBitSet(d) 116 if firstBit > bestBit { 117 e.Nonce, bestBit = nonce, firstBit 118 if target > 0 && bestBit >= target { 119 return nil 120 } 121 } 122 nonce++ 123 } 124 } 125 126 if target > 0 && bestBit < target { 127 return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) 128 } 129 130 return nil 131 } 132 133 // 134 // 135 func (e *Envelope) PoW() float64 { 136 if e.pow == 0 { 137 e.calculatePoW(0) 138 } 139 return e.pow 140 } 141 142 func (e *Envelope) calculatePoW(diff uint32) { 143 buf := make([]byte, 64) 144 h := crypto.Keccak256(e.rlpWithoutNonce()) 145 copy(buf[:32], h) 146 binary.BigEndian.PutUint64(buf[56:], e.Nonce) 147 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 148 firstBit := math.FirstBitSet(d) 149 x := gmath.Pow(2, float64(firstBit)) 150 x /= float64(e.size()) 151 x /= float64(e.TTL + diff) 152 e.pow = x 153 } 154 155 func (e *Envelope) powToFirstBit(pow float64) int { 156 x := pow 157 x *= float64(e.size()) 158 x *= float64(e.TTL) 159 bits := gmath.Log2(x) 160 bits = gmath.Ceil(bits) 161 res := int(bits) 162 if res < 1 { 163 res = 1 164 } 165 return res 166 } 167 168 // 169 func (e *Envelope) Hash() common.Hash { 170 if (e.hash == common.Hash{}) { 171 encoded, _ := rlp.EncodeToBytes(e) 172 e.hash = crypto.Keccak256Hash(encoded) 173 } 174 return e.hash 175 } 176 177 // 178 func (e *Envelope) DecodeRLP(s *rlp.Stream) error { 179 raw, err := s.Raw() 180 if err != nil { 181 return err 182 } 183 // 184 // 185 // 186 // 187 // 188 type rlpenv Envelope 189 if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { 190 return err 191 } 192 e.hash = crypto.Keccak256Hash(raw) 193 return nil 194 } 195 196 // 197 func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { 198 message := &ReceivedMessage{Raw: e.Data} 199 err := message.decryptAsymmetric(key) 200 switch err { 201 case nil: 202 return message, nil 203 case ecies.ErrInvalidPublicKey: // 204 return nil, err 205 default: 206 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 207 } 208 } 209 210 // 211 func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { 212 msg = &ReceivedMessage{Raw: e.Data} 213 err = msg.decryptSymmetric(key) 214 if err != nil { 215 msg = nil 216 } 217 return msg, err 218 } 219 220 // 221 func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { 222 if watcher == nil { 223 return nil 224 } 225 226 // 227 if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() { 228 return nil 229 } 230 231 if watcher.expectsAsymmetricEncryption() { 232 msg, _ = e.OpenAsymmetric(watcher.KeyAsym) 233 if msg != nil { 234 msg.Dst = &watcher.KeyAsym.PublicKey 235 } 236 } else if watcher.expectsSymmetricEncryption() { 237 msg, _ = e.OpenSymmetric(watcher.KeySym) 238 if msg != nil { 239 msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 240 } 241 } 242 243 if msg != nil { 244 ok := msg.ValidateAndParse() 245 if !ok { 246 return nil 247 } 248 msg.Topic = e.Topic 249 msg.PoW = e.PoW() 250 msg.TTL = e.TTL 251 msg.Sent = e.Expiry - e.TTL 252 msg.EnvelopeHash = e.Hash() 253 } 254 return msg 255 } 256 257 // 258 func (e *Envelope) Bloom() []byte { 259 if e.bloom == nil { 260 e.bloom = TopicToBloom(e.Topic) 261 } 262 return e.bloom 263 } 264 265 // 266 func TopicToBloom(topic TopicType) []byte { 267 b := make([]byte, BloomFilterSize) 268 var index [3]int 269 for j := 0; j < 3; j++ { 270 index[j] = int(topic[j]) 271 if (topic[3] & (1 << uint(j))) != 0 { 272 index[j] += 256 273 } 274 } 275 276 for j := 0; j < 3; j++ { 277 byteIndex := index[j] / 8 278 bitIndex := index[j] % 8 279 b[byteIndex] = (1 << uint(bitIndex)) 280 } 281 return b 282 } 283 284 // 285 // 286 func (w *Whisper) GetEnvelope(hash common.Hash) *Envelope { 287 w.poolMu.RLock() 288 defer w.poolMu.RUnlock() 289 return w.envelopes[hash] 290 } 291