github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:46</date> 10 //</624450125246238720> 11 12 13 //包含Whisper协议信封元素。 14 15 package whisperv6 16 17 import ( 18 "crypto/ecdsa" 19 "encoding/binary" 20 "fmt" 21 gmath "math" 22 "math/big" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/common/math" 27 "github.com/ethereum/go-ethereum/crypto" 28 "github.com/ethereum/go-ethereum/crypto/ecies" 29 "github.com/ethereum/go-ethereum/rlp" 30 ) 31 32 //信封表示一个明文数据包,通过耳语进行传输。 33 //网络。其内容可以加密或不加密和签名。 34 type Envelope struct { 35 Expiry uint32 36 TTL uint32 37 Topic TopicType 38 Data []byte 39 Nonce uint64 40 41 pow float64 //消息特定的POW,如Whisper规范中所述。 42 43 //不应直接访问以下变量,请改用相应的函数:hash()、bloom()。 44 hash common.Hash //信封的缓存哈希,以避免每次重新刷新。 45 bloom []byte 46 } 47 48 //大小返回信封发送时的大小(即仅公共字段) 49 func (e *Envelope) size() int { 50 return EnvelopeHeaderLength + len(e.Data) 51 } 52 53 //rlpwithoutnonce返回rlp编码的信封内容,nonce除外。 54 func (e *Envelope) rlpWithoutNonce() []byte { 55 res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Data}) 56 return res 57 } 58 59 //newenvelope用过期和目标数据包装了一条私语消息 60 //包含在信封中,用于网络转发。 61 func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage) *Envelope { 62 env := Envelope{ 63 Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), 64 TTL: ttl, 65 Topic: topic, 66 Data: msg.Raw, 67 Nonce: 0, 68 } 69 70 return &env 71 } 72 73 //Seal通过花费所需的时间作为证据来关闭信封 74 //关于散列数据的工作。 75 func (e *Envelope) Seal(options *MessageParams) error { 76 if options.PoW == 0 { 77 //不需要POW 78 return nil 79 } 80 81 var target, bestBit int 82 if options.PoW < 0 { 83 //未设置目标-函数应运行一段时间 84 //工作时间参数中指定的时间。因为我们可以预测 85 //执行时间,我们也可以调整到期时间。 86 e.Expiry += options.WorkTime 87 } else { 88 target = e.powToFirstBit(options.PoW) 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计算(如有必要)并返回工作证明目标 119 //信封的。 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 res := int(bits) 147 if res < 1 { 148 res = 1 149 } 150 return res 151 } 152 153 //hash返回信封的sha3散列,如果还没有完成,则计算它。 154 func (e *Envelope) Hash() common.Hash { 155 if (e.hash == common.Hash{}) { 156 encoded, _ := rlp.EncodeToBytes(e) 157 e.hash = crypto.Keccak256Hash(encoded) 158 } 159 return e.hash 160 } 161 162 //decoderlp从rlp数据流解码信封。 163 func (e *Envelope) DecodeRLP(s *rlp.Stream) error { 164 raw, err := s.Raw() 165 if err != nil { 166 return err 167 } 168 //信封的解码使用结构字段,但也需要 169 //计算整个RLP编码信封的散列值。这个 170 //类型具有与信封相同的结构,但不是 171 //rlp.decoder(不实现decoderlp函数)。 172 //只对公共成员进行编码。 173 type rlpenv Envelope 174 if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { 175 return err 176 } 177 e.hash = crypto.Keccak256Hash(raw) 178 return nil 179 } 180 181 //OpenAsymmetric试图解密一个信封,可能用一个特定的密钥加密。 182 func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { 183 message := &ReceivedMessage{Raw: e.Data} 184 err := message.decryptAsymmetric(key) 185 switch err { 186 case nil: 187 return message, nil 188 case ecies.ErrInvalidPublicKey: //写给别人的 189 return nil, err 190 default: 191 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 192 } 193 } 194 195 //opensymmetric试图解密一个可能用特定密钥加密的信封。 196 func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { 197 msg = &ReceivedMessage{Raw: e.Data} 198 err = msg.decryptSymmetric(key) 199 if err != nil { 200 msg = nil 201 } 202 return msg, err 203 } 204 205 //open试图解密信封,并在成功时填充消息字段。 206 func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { 207 if watcher == nil { 208 return nil 209 } 210 211 //API接口禁止过滤器同时进行对称和非对称加密。 212 if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() { 213 return nil 214 } 215 216 if watcher.expectsAsymmetricEncryption() { 217 msg, _ = e.OpenAsymmetric(watcher.KeyAsym) 218 if msg != nil { 219 msg.Dst = &watcher.KeyAsym.PublicKey 220 } 221 } else if watcher.expectsSymmetricEncryption() { 222 msg, _ = e.OpenSymmetric(watcher.KeySym) 223 if msg != nil { 224 msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 225 } 226 } 227 228 if msg != nil { 229 ok := msg.ValidateAndParse() 230 if !ok { 231 return nil 232 } 233 msg.Topic = e.Topic 234 msg.PoW = e.PoW() 235 msg.TTL = e.TTL 236 msg.Sent = e.Expiry - e.TTL 237 msg.EnvelopeHash = e.Hash() 238 } 239 return msg 240 } 241 242 //Bloom将4字节主题映射到64字节的Bloom过滤器中,并设置了3位(最多)。 243 func (e *Envelope) Bloom() []byte { 244 if e.bloom == nil { 245 e.bloom = TopicToBloom(e.Topic) 246 } 247 return e.bloom 248 } 249 250 //TopicToBloom将主题(4字节)转换为Bloom筛选器(64字节) 251 func TopicToBloom(topic TopicType) []byte { 252 b := make([]byte, BloomFilterSize) 253 var index [3]int 254 for j := 0; j < 3; j++ { 255 index[j] = int(topic[j]) 256 if (topic[3] & (1 << uint(j))) != 0 { 257 index[j] += 256 258 } 259 } 260 261 for j := 0; j < 3; j++ { 262 byteIndex := index[j] / 8 263 bitIndex := index[j] % 8 264 b[byteIndex] = (1 << uint(bitIndex)) 265 } 266 return b 267 } 268 269 //GetEnvelope通过其哈希从消息队列中检索信封。 270 //如果找不到信封,则返回零。 271 func (w *Whisper) GetEnvelope(hash common.Hash) *Envelope { 272 w.poolMu.RLock() 273 defer w.poolMu.RUnlock() 274 return w.envelopes[hash] 275 } 276