github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/whisper/whisperv5/envelope.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 // 10 // 11 // 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 25 // 26 27 package whisperv5 28 29 import ( 30 "crypto/ecdsa" 31 "encoding/binary" 32 "fmt" 33 gmath "math" 34 "math/big" 35 "time" 36 37 "github.com/ethereum/go-ethereum/common" 38 "github.com/ethereum/go-ethereum/common/math" 39 "github.com/ethereum/go-ethereum/crypto" 40 "github.com/ethereum/go-ethereum/crypto/ecies" 41 "github.com/ethereum/go-ethereum/rlp" 42 ) 43 44 // 45 // 46 type Envelope struct { 47 Version []byte 48 Expiry uint32 49 TTL uint32 50 Topic TopicType 51 AESNonce []byte 52 Data []byte 53 EnvNonce uint64 54 55 pow float64 // 56 hash common.Hash // 57 // 58 } 59 60 // 61 func (e *Envelope) size() int { 62 return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data) 63 } 64 65 // 66 func (e *Envelope) rlpWithoutNonce() []byte { 67 res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data}) 68 return res 69 } 70 71 // 72 // 73 func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *sentMessage) *Envelope { 74 env := Envelope{ 75 Version: make([]byte, 1), 76 Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), 77 TTL: ttl, 78 Topic: topic, 79 AESNonce: aesNonce, 80 Data: msg.Raw, 81 EnvNonce: 0, 82 } 83 84 if EnvelopeVersion < 256 { 85 env.Version[0] = byte(EnvelopeVersion) 86 } else { 87 panic("please increase the size of Envelope.Version before releasing this version") 88 } 89 90 return &env 91 } 92 93 func (e *Envelope) IsSymmetric() bool { 94 return len(e.AESNonce) > 0 95 } 96 97 func (e *Envelope) isAsymmetric() bool { 98 return !e.IsSymmetric() 99 } 100 101 func (e *Envelope) Ver() uint64 { 102 return bytesToUintLittleEndian(e.Version) 103 } 104 105 // 106 // 107 func (e *Envelope) Seal(options *MessageParams) error { 108 var target, bestBit int 109 if options.PoW == 0 { 110 // 111 e.Expiry += options.WorkTime 112 } else { 113 target = e.powToFirstBit(options.PoW) 114 if target < 1 { 115 target = 1 116 } 117 } 118 119 buf := make([]byte, 64) 120 h := crypto.Keccak256(e.rlpWithoutNonce()) 121 copy(buf[:32], h) 122 123 finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() 124 for nonce := uint64(0); time.Now().UnixNano() < finish; { 125 for i := 0; i < 1024; i++ { 126 binary.BigEndian.PutUint64(buf[56:], nonce) 127 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 128 firstBit := math.FirstBitSet(d) 129 if firstBit > bestBit { 130 e.EnvNonce, bestBit = nonce, firstBit 131 if target > 0 && bestBit >= target { 132 return nil 133 } 134 } 135 nonce++ 136 } 137 } 138 139 if target > 0 && bestBit < target { 140 return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) 141 } 142 143 return nil 144 } 145 146 func (e *Envelope) PoW() float64 { 147 if e.pow == 0 { 148 e.calculatePoW(0) 149 } 150 return e.pow 151 } 152 153 func (e *Envelope) calculatePoW(diff uint32) { 154 buf := make([]byte, 64) 155 h := crypto.Keccak256(e.rlpWithoutNonce()) 156 copy(buf[:32], h) 157 binary.BigEndian.PutUint64(buf[56:], e.EnvNonce) 158 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 159 firstBit := math.FirstBitSet(d) 160 x := gmath.Pow(2, float64(firstBit)) 161 x /= float64(e.size()) 162 x /= float64(e.TTL + diff) 163 e.pow = x 164 } 165 166 func (e *Envelope) powToFirstBit(pow float64) int { 167 x := pow 168 x *= float64(e.size()) 169 x *= float64(e.TTL) 170 bits := gmath.Log2(x) 171 bits = gmath.Ceil(bits) 172 return int(bits) 173 } 174 175 // 176 func (e *Envelope) Hash() common.Hash { 177 if (e.hash == common.Hash{}) { 178 encoded, _ := rlp.EncodeToBytes(e) 179 e.hash = crypto.Keccak256Hash(encoded) 180 } 181 return e.hash 182 } 183 184 // 185 func (e *Envelope) DecodeRLP(s *rlp.Stream) error { 186 raw, err := s.Raw() 187 if err != nil { 188 return err 189 } 190 // 191 // 192 // 193 // 194 // 195 type rlpenv Envelope 196 if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { 197 return err 198 } 199 e.hash = crypto.Keccak256Hash(raw) 200 return nil 201 } 202 203 // 204 func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { 205 message := &ReceivedMessage{Raw: e.Data} 206 err := message.decryptAsymmetric(key) 207 switch err { 208 case nil: 209 return message, nil 210 case ecies.ErrInvalidPublicKey: // 211 return nil, err 212 default: 213 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 214 } 215 } 216 217 // 218 func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { 219 msg = &ReceivedMessage{Raw: e.Data} 220 err = msg.decryptSymmetric(key, e.AESNonce) 221 if err != nil { 222 msg = nil 223 } 224 return msg, err 225 } 226 227 // 228 func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { 229 if e.isAsymmetric() { 230 msg, _ = e.OpenAsymmetric(watcher.KeyAsym) 231 if msg != nil { 232 msg.Dst = &watcher.KeyAsym.PublicKey 233 } 234 } else if e.IsSymmetric() { 235 msg, _ = e.OpenSymmetric(watcher.KeySym) 236 if msg != nil { 237 msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 238 } 239 } 240 241 if msg != nil { 242 ok := msg.Validate() 243 if !ok { 244 return nil 245 } 246 msg.Topic = e.Topic 247 msg.PoW = e.PoW() 248 msg.TTL = e.TTL 249 msg.Sent = e.Expiry - e.TTL 250 msg.EnvelopeHash = e.Hash() 251 msg.EnvelopeVersion = e.Ver() 252 } 253 return msg 254 }