github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/whisper/whisperv5/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 //</624342688589680640> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 // 29 30 package whisperv5 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 Version []byte 51 Expiry uint32 52 TTL uint32 53 Topic TopicType 54 AESNonce []byte 55 Data []byte 56 EnvNonce uint64 57 58 pow float64 // 59 hash common.Hash // 60 // 61 } 62 63 // 64 func (e *Envelope) size() int { 65 return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data) 66 } 67 68 // 69 func (e *Envelope) rlpWithoutNonce() []byte { 70 res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data}) 71 return res 72 } 73 74 // 75 // 76 func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *sentMessage) *Envelope { 77 env := Envelope{ 78 Version: make([]byte, 1), 79 Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), 80 TTL: ttl, 81 Topic: topic, 82 AESNonce: aesNonce, 83 Data: msg.Raw, 84 EnvNonce: 0, 85 } 86 87 if EnvelopeVersion < 256 { 88 env.Version[0] = byte(EnvelopeVersion) 89 } else { 90 panic("please increase the size of Envelope.Version before releasing this version") 91 } 92 93 return &env 94 } 95 96 func (e *Envelope) IsSymmetric() bool { 97 return len(e.AESNonce) > 0 98 } 99 100 func (e *Envelope) isAsymmetric() bool { 101 return !e.IsSymmetric() 102 } 103 104 func (e *Envelope) Ver() uint64 { 105 return bytesToUintLittleEndian(e.Version) 106 } 107 108 // 109 // 110 func (e *Envelope) Seal(options *MessageParams) error { 111 var target, bestBit int 112 if options.PoW == 0 { 113 // 114 e.Expiry += options.WorkTime 115 } else { 116 target = e.powToFirstBit(options.PoW) 117 if target < 1 { 118 target = 1 119 } 120 } 121 122 buf := make([]byte, 64) 123 h := crypto.Keccak256(e.rlpWithoutNonce()) 124 copy(buf[:32], h) 125 126 finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() 127 for nonce := uint64(0); time.Now().UnixNano() < finish; { 128 for i := 0; i < 1024; i++ { 129 binary.BigEndian.PutUint64(buf[56:], nonce) 130 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 131 firstBit := math.FirstBitSet(d) 132 if firstBit > bestBit { 133 e.EnvNonce, bestBit = nonce, firstBit 134 if target > 0 && bestBit >= target { 135 return nil 136 } 137 } 138 nonce++ 139 } 140 } 141 142 if target > 0 && bestBit < target { 143 return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) 144 } 145 146 return nil 147 } 148 149 func (e *Envelope) PoW() float64 { 150 if e.pow == 0 { 151 e.calculatePoW(0) 152 } 153 return e.pow 154 } 155 156 func (e *Envelope) calculatePoW(diff uint32) { 157 buf := make([]byte, 64) 158 h := crypto.Keccak256(e.rlpWithoutNonce()) 159 copy(buf[:32], h) 160 binary.BigEndian.PutUint64(buf[56:], e.EnvNonce) 161 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 162 firstBit := math.FirstBitSet(d) 163 x := gmath.Pow(2, float64(firstBit)) 164 x /= float64(e.size()) 165 x /= float64(e.TTL + diff) 166 e.pow = x 167 } 168 169 func (e *Envelope) powToFirstBit(pow float64) int { 170 x := pow 171 x *= float64(e.size()) 172 x *= float64(e.TTL) 173 bits := gmath.Log2(x) 174 bits = gmath.Ceil(bits) 175 return int(bits) 176 } 177 178 // 179 func (e *Envelope) Hash() common.Hash { 180 if (e.hash == common.Hash{}) { 181 encoded, _ := rlp.EncodeToBytes(e) 182 e.hash = crypto.Keccak256Hash(encoded) 183 } 184 return e.hash 185 } 186 187 // 188 func (e *Envelope) DecodeRLP(s *rlp.Stream) error { 189 raw, err := s.Raw() 190 if err != nil { 191 return err 192 } 193 // 194 // 195 // 196 // 197 // 198 type rlpenv Envelope 199 if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { 200 return err 201 } 202 e.hash = crypto.Keccak256Hash(raw) 203 return nil 204 } 205 206 // 207 func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { 208 message := &ReceivedMessage{Raw: e.Data} 209 err := message.decryptAsymmetric(key) 210 switch err { 211 case nil: 212 return message, nil 213 case ecies.ErrInvalidPublicKey: // 214 return nil, err 215 default: 216 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 217 } 218 } 219 220 // 221 func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { 222 msg = &ReceivedMessage{Raw: e.Data} 223 err = msg.decryptSymmetric(key, e.AESNonce) 224 if err != nil { 225 msg = nil 226 } 227 return msg, err 228 } 229 230 // 231 func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { 232 if e.isAsymmetric() { 233 msg, _ = e.OpenAsymmetric(watcher.KeyAsym) 234 if msg != nil { 235 msg.Dst = &watcher.KeyAsym.PublicKey 236 } 237 } else if e.IsSymmetric() { 238 msg, _ = e.OpenSymmetric(watcher.KeySym) 239 if msg != nil { 240 msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 241 } 242 } 243 244 if msg != nil { 245 ok := msg.Validate() 246 if !ok { 247 return nil 248 } 249 msg.Topic = e.Topic 250 msg.PoW = e.PoW() 251 msg.TTL = e.TTL 252 msg.Sent = e.Expiry - e.TTL 253 msg.EnvelopeHash = e.Hash() 254 msg.EnvelopeVersion = e.Ver() 255 } 256 return msg 257 } 258