github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:46</date> 10 //</624450124268965888> 11 12 13 //包含Whisper协议信封元素。 14 15 package whisperv5 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 Version []byte 36 Expiry uint32 37 TTL uint32 38 Topic TopicType 39 AESNonce []byte 40 Data []byte 41 EnvNonce uint64 42 43 pow float64 //消息特定的POW,如Whisper规范中所述。 44 hash common.Hash //信封的缓存哈希,以避免每次重新刷新。 45 //不要直接访问哈希,而是使用hash()函数。 46 } 47 48 //大小返回信封发送时的大小(即仅公共字段) 49 func (e *Envelope) size() int { 50 return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data) 51 } 52 53 //rlpwithoutnonce返回rlp编码的信封内容,nonce除外。 54 func (e *Envelope) rlpWithoutNonce() []byte { 55 res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data}) 56 return res 57 } 58 59 //newenvelope用过期和目标数据包装了一条私语消息 60 //包含在信封中,用于网络转发。 61 func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *sentMessage) *Envelope { 62 env := Envelope{ 63 Version: make([]byte, 1), 64 Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), 65 TTL: ttl, 66 Topic: topic, 67 AESNonce: aesNonce, 68 Data: msg.Raw, 69 EnvNonce: 0, 70 } 71 72 if EnvelopeVersion < 256 { 73 env.Version[0] = byte(EnvelopeVersion) 74 } else { 75 panic("please increase the size of Envelope.Version before releasing this version") 76 } 77 78 return &env 79 } 80 81 func (e *Envelope) IsSymmetric() bool { 82 return len(e.AESNonce) > 0 83 } 84 85 func (e *Envelope) isAsymmetric() bool { 86 return !e.IsSymmetric() 87 } 88 89 func (e *Envelope) Ver() uint64 { 90 return bytesToUintLittleEndian(e.Version) 91 } 92 93 //Seal通过花费所需的时间作为证据来关闭信封 94 //关于散列数据的工作。 95 func (e *Envelope) Seal(options *MessageParams) error { 96 var target, bestBit int 97 if options.PoW == 0 { 98 //仅当无条件地预先定义执行时间时,才调整seal()执行的持续时间 99 e.Expiry += options.WorkTime 100 } else { 101 target = e.powToFirstBit(options.PoW) 102 if target < 1 { 103 target = 1 104 } 105 } 106 107 buf := make([]byte, 64) 108 h := crypto.Keccak256(e.rlpWithoutNonce()) 109 copy(buf[:32], h) 110 111 finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() 112 for nonce := uint64(0); time.Now().UnixNano() < finish; { 113 for i := 0; i < 1024; i++ { 114 binary.BigEndian.PutUint64(buf[56:], nonce) 115 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 116 firstBit := math.FirstBitSet(d) 117 if firstBit > bestBit { 118 e.EnvNonce, bestBit = nonce, firstBit 119 if target > 0 && bestBit >= target { 120 return nil 121 } 122 } 123 nonce++ 124 } 125 } 126 127 if target > 0 && bestBit < target { 128 return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) 129 } 130 131 return nil 132 } 133 134 func (e *Envelope) PoW() float64 { 135 if e.pow == 0 { 136 e.calculatePoW(0) 137 } 138 return e.pow 139 } 140 141 func (e *Envelope) calculatePoW(diff uint32) { 142 buf := make([]byte, 64) 143 h := crypto.Keccak256(e.rlpWithoutNonce()) 144 copy(buf[:32], h) 145 binary.BigEndian.PutUint64(buf[56:], e.EnvNonce) 146 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 147 firstBit := math.FirstBitSet(d) 148 x := gmath.Pow(2, float64(firstBit)) 149 x /= float64(e.size()) 150 x /= float64(e.TTL + diff) 151 e.pow = x 152 } 153 154 func (e *Envelope) powToFirstBit(pow float64) int { 155 x := pow 156 x *= float64(e.size()) 157 x *= float64(e.TTL) 158 bits := gmath.Log2(x) 159 bits = gmath.Ceil(bits) 160 return int(bits) 161 } 162 163 //hash返回信封的sha3散列,如果还没有完成,则计算它。 164 func (e *Envelope) Hash() common.Hash { 165 if (e.hash == common.Hash{}) { 166 encoded, _ := rlp.EncodeToBytes(e) 167 e.hash = crypto.Keccak256Hash(encoded) 168 } 169 return e.hash 170 } 171 172 //decoderlp从rlp数据流解码信封。 173 func (e *Envelope) DecodeRLP(s *rlp.Stream) error { 174 raw, err := s.Raw() 175 if err != nil { 176 return err 177 } 178 //信封的解码使用结构字段,但也需要 179 //计算整个RLP编码信封的散列值。这个 180 //类型具有与信封相同的结构,但不是 181 //rlp.decoder(不实现decoderlp函数)。 182 //只对公共成员进行编码。 183 type rlpenv Envelope 184 if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { 185 return err 186 } 187 e.hash = crypto.Keccak256Hash(raw) 188 return nil 189 } 190 191 //OpenAsymmetric试图解密一个信封,可能用一个特定的密钥加密。 192 func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { 193 message := &ReceivedMessage{Raw: e.Data} 194 err := message.decryptAsymmetric(key) 195 switch err { 196 case nil: 197 return message, nil 198 case ecies.ErrInvalidPublicKey: //写给别人的 199 return nil, err 200 default: 201 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 202 } 203 } 204 205 //opensymmetric试图解密一个可能用特定密钥加密的信封。 206 func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { 207 msg = &ReceivedMessage{Raw: e.Data} 208 err = msg.decryptSymmetric(key, e.AESNonce) 209 if err != nil { 210 msg = nil 211 } 212 return msg, err 213 } 214 215 //open试图解密信封,并在成功时填充消息字段。 216 func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { 217 if e.isAsymmetric() { 218 msg, _ = e.OpenAsymmetric(watcher.KeyAsym) 219 if msg != nil { 220 msg.Dst = &watcher.KeyAsym.PublicKey 221 } 222 } else if e.IsSymmetric() { 223 msg, _ = e.OpenSymmetric(watcher.KeySym) 224 if msg != nil { 225 msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 226 } 227 } 228 229 if msg != nil { 230 ok := msg.Validate() 231 if !ok { 232 return nil 233 } 234 msg.Topic = e.Topic 235 msg.PoW = e.PoW() 236 msg.TTL = e.TTL 237 msg.Sent = e.Expiry - e.TTL 238 msg.EnvelopeHash = e.Hash() 239 msg.EnvelopeVersion = e.Ver() 240 } 241 return msg 242 } 243