github.com/murrekatt/go-ethereum@v1.5.8-0.20170123175102-fc52f2c007fb/whisper/whisperv5/envelope.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Contains the Whisper protocol Envelope element. 18 19 package whisperv5 20 21 import ( 22 "crypto/ecdsa" 23 "encoding/binary" 24 "errors" 25 "fmt" 26 "math" 27 "time" 28 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/crypto/ecies" 32 "github.com/ethereum/go-ethereum/rlp" 33 ) 34 35 // Envelope represents a clear-text data packet to transmit through the Whisper 36 // network. Its contents may or may not be encrypted and signed. 37 type Envelope struct { 38 Version []byte 39 Expiry uint32 40 TTL uint32 41 Topic TopicType 42 Salt []byte 43 AESNonce []byte 44 Data []byte 45 EnvNonce uint64 46 47 pow float64 // Message-specific PoW as described in the Whisper specification. 48 hash common.Hash // Cached hash of the envelope to avoid rehashing every time. 49 // Don't access hash directly, use Hash() function instead. 50 } 51 52 // NewEnvelope wraps a Whisper message with expiration and destination data 53 // included into an envelope for network forwarding. 54 func NewEnvelope(ttl uint32, topic TopicType, salt []byte, aesNonce []byte, msg *SentMessage) *Envelope { 55 env := Envelope{ 56 Version: make([]byte, 1), 57 Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), 58 TTL: ttl, 59 Topic: topic, 60 Salt: salt, 61 AESNonce: aesNonce, 62 Data: msg.Raw, 63 EnvNonce: 0, 64 } 65 66 if EnvelopeVersion < 256 { 67 env.Version[0] = byte(EnvelopeVersion) 68 } else { 69 panic("please increase the size of Envelope.Version before releasing this version") 70 } 71 72 return &env 73 } 74 75 func (e *Envelope) IsSymmetric() bool { 76 return len(e.AESNonce) > 0 77 } 78 79 func (e *Envelope) isAsymmetric() bool { 80 return !e.IsSymmetric() 81 } 82 83 func (e *Envelope) Ver() uint64 { 84 return bytesToIntLittleEndian(e.Version) 85 } 86 87 // Seal closes the envelope by spending the requested amount of time as a proof 88 // of work on hashing the data. 89 func (e *Envelope) Seal(options *MessageParams) error { 90 var target, bestBit int 91 if options.PoW == 0 { 92 // adjust for the duration of Seal() execution only if execution time is predefined unconditionally 93 e.Expiry += options.WorkTime 94 } else { 95 target = e.powToFirstBit(options.PoW) 96 } 97 98 buf := make([]byte, 64) 99 h := crypto.Keccak256(e.rlpWithoutNonce()) 100 copy(buf[:32], h) 101 102 finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() 103 for nonce := uint64(0); time.Now().UnixNano() < finish; { 104 for i := 0; i < 1024; i++ { 105 binary.BigEndian.PutUint64(buf[56:], nonce) 106 h = crypto.Keccak256(buf) 107 firstBit := common.FirstBitSet(common.BigD(h)) 108 if firstBit > bestBit { 109 e.EnvNonce, bestBit = nonce, firstBit 110 if target > 0 && bestBit >= target { 111 return nil 112 } 113 } 114 nonce++ 115 } 116 } 117 118 if target > 0 && bestBit < target { 119 return errors.New("Failed to reach the PoW target") 120 } 121 122 return nil 123 } 124 125 func (e *Envelope) PoW() float64 { 126 if e.pow == 0 { 127 e.calculatePoW(0) 128 } 129 return e.pow 130 } 131 132 func (e *Envelope) calculatePoW(diff uint32) { 133 buf := make([]byte, 64) 134 h := crypto.Keccak256(e.rlpWithoutNonce()) 135 copy(buf[:32], h) 136 binary.BigEndian.PutUint64(buf[56:], e.EnvNonce) 137 h = crypto.Keccak256(buf) 138 firstBit := common.FirstBitSet(common.BigD(h)) 139 x := math.Pow(2, float64(firstBit)) 140 x /= float64(len(e.Data)) // we only count e.Data, other variable-sized members are checked in Whisper.add() 141 x /= float64(e.TTL + diff) 142 e.pow = x 143 } 144 145 func (e *Envelope) powToFirstBit(pow float64) int { 146 x := pow 147 x *= float64(len(e.Data)) 148 x *= float64(e.TTL) 149 bits := math.Log2(x) 150 bits = math.Ceil(bits) 151 return int(bits) 152 } 153 154 // rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce. 155 func (e *Envelope) rlpWithoutNonce() []byte { 156 res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Salt, e.AESNonce, e.Data}) 157 return res 158 } 159 160 // Hash returns the SHA3 hash of the envelope, calculating it if not yet done. 161 func (e *Envelope) Hash() common.Hash { 162 if (e.hash == common.Hash{}) { 163 encoded, _ := rlp.EncodeToBytes(e) 164 e.hash = crypto.Keccak256Hash(encoded) 165 } 166 return e.hash 167 } 168 169 // DecodeRLP decodes an Envelope from an RLP data stream. 170 func (e *Envelope) DecodeRLP(s *rlp.Stream) error { 171 raw, err := s.Raw() 172 if err != nil { 173 return err 174 } 175 // The decoding of Envelope uses the struct fields but also needs 176 // to compute the hash of the whole RLP-encoded envelope. This 177 // type has the same structure as Envelope but is not an 178 // rlp.Decoder (does not implement DecodeRLP function). 179 // Only public members will be encoded. 180 type rlpenv Envelope 181 if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { 182 return err 183 } 184 e.hash = crypto.Keccak256Hash(raw) 185 return nil 186 } 187 188 // OpenAsymmetric tries to decrypt an envelope, potentially encrypted with a particular key. 189 func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { 190 message := &ReceivedMessage{Raw: e.Data} 191 err := message.decryptAsymmetric(key) 192 switch err { 193 case nil: 194 return message, nil 195 case ecies.ErrInvalidPublicKey: // addressed to somebody else 196 return nil, err 197 default: 198 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 199 } 200 } 201 202 // OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key. 203 func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { 204 msg = &ReceivedMessage{Raw: e.Data} 205 err = msg.decryptSymmetric(key, e.Salt, e.AESNonce) 206 if err != nil { 207 msg = nil 208 } 209 return msg, err 210 } 211 212 // Open tries to decrypt an envelope, and populates the message fields in case of success. 213 func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { 214 if e.isAsymmetric() { 215 msg, _ = e.OpenAsymmetric(watcher.KeyAsym) 216 if msg != nil { 217 msg.Dst = &watcher.KeyAsym.PublicKey 218 } 219 } else if e.IsSymmetric() { 220 msg, _ = e.OpenSymmetric(watcher.KeySym) 221 if msg != nil { 222 msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 223 } 224 } 225 226 if msg != nil { 227 ok := msg.Validate() 228 if !ok { 229 return nil 230 } 231 msg.Topic = e.Topic 232 msg.PoW = e.PoW() 233 msg.TTL = e.TTL 234 msg.Sent = e.Expiry - e.TTL 235 msg.EnvelopeHash = e.Hash() 236 msg.EnvelopeVersion = e.Ver() 237 } 238 return msg 239 }