github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/whisper/whisperv6/envelope.go (about) 1 // Copyright 2016 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Contains the Whisper protocol Envelope element. 18 19 package whisperv6 20 21 import ( 22 "crypto/ecdsa" 23 "encoding/binary" 24 "fmt" 25 gmath "math" 26 "math/big" 27 "time" 28 29 "github.com/SmartMeshFoundation/Spectrum/common" 30 "github.com/SmartMeshFoundation/Spectrum/common/math" 31 "github.com/SmartMeshFoundation/Spectrum/crypto" 32 "github.com/SmartMeshFoundation/Spectrum/crypto/ecies" 33 "github.com/SmartMeshFoundation/Spectrum/rlp" 34 ) 35 36 // Envelope represents a clear-text data packet to transmit through the Whisper 37 // network. Its contents may or may not be encrypted and signed. 38 type Envelope struct { 39 Expiry uint32 40 TTL uint32 41 Topic TopicType 42 Data []byte 43 Nonce uint64 44 45 pow float64 // Message-specific PoW as described in the Whisper specification. 46 hash common.Hash // Cached hash of the envelope to avoid rehashing every time. 47 // Don't access hash directly, use Hash() function instead. 48 } 49 50 // size returns the size of envelope as it is sent (i.e. public fields only) 51 func (e *Envelope) size() int { 52 return EnvelopeHeaderLength + len(e.Data) 53 } 54 55 // rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce. 56 func (e *Envelope) rlpWithoutNonce() []byte { 57 res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Data}) 58 return res 59 } 60 61 // NewEnvelope wraps a Whisper message with expiration and destination data 62 // included into an envelope for network forwarding. 63 func NewEnvelope(ttl uint32, topic TopicType, msg *sentMessage) *Envelope { 64 env := Envelope{ 65 Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()), 66 TTL: ttl, 67 Topic: topic, 68 Data: msg.Raw, 69 Nonce: 0, 70 } 71 72 return &env 73 } 74 75 // Seal closes the envelope by spending the requested amount of time as a proof 76 // of work on hashing the data. 77 func (e *Envelope) Seal(options *MessageParams) error { 78 var target, bestBit int 79 if options.PoW == 0 { 80 // adjust for the duration of Seal() execution only if execution time is predefined unconditionally 81 e.Expiry += options.WorkTime 82 } else { 83 target = e.powToFirstBit(options.PoW) 84 if target < 1 { 85 target = 1 86 } 87 } 88 89 buf := make([]byte, 64) 90 h := crypto.Keccak256(e.rlpWithoutNonce()) 91 copy(buf[:32], h) 92 93 finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano() 94 for nonce := uint64(0); time.Now().UnixNano() < finish; { 95 for i := 0; i < 1024; i++ { 96 binary.BigEndian.PutUint64(buf[56:], nonce) 97 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 98 firstBit := math.FirstBitSet(d) 99 if firstBit > bestBit { 100 e.Nonce, bestBit = nonce, firstBit 101 if target > 0 && bestBit >= target { 102 return nil 103 } 104 } 105 nonce++ 106 } 107 } 108 109 if target > 0 && bestBit < target { 110 return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime) 111 } 112 113 return nil 114 } 115 116 func (e *Envelope) PoW() float64 { 117 if e.pow == 0 { 118 e.calculatePoW(0) 119 } 120 return e.pow 121 } 122 123 func (e *Envelope) calculatePoW(diff uint32) { 124 buf := make([]byte, 64) 125 h := crypto.Keccak256(e.rlpWithoutNonce()) 126 copy(buf[:32], h) 127 binary.BigEndian.PutUint64(buf[56:], e.Nonce) 128 d := new(big.Int).SetBytes(crypto.Keccak256(buf)) 129 firstBit := math.FirstBitSet(d) 130 x := gmath.Pow(2, float64(firstBit)) 131 x /= float64(e.size()) 132 x /= float64(e.TTL + diff) 133 e.pow = x 134 } 135 136 func (e *Envelope) powToFirstBit(pow float64) int { 137 x := pow 138 x *= float64(e.size()) 139 x *= float64(e.TTL) 140 bits := gmath.Log2(x) 141 bits = gmath.Ceil(bits) 142 return int(bits) 143 } 144 145 // Hash returns the SHA3 hash of the envelope, calculating it if not yet done. 146 func (e *Envelope) Hash() common.Hash { 147 if (e.hash == common.Hash{}) { 148 encoded, _ := rlp.EncodeToBytes(e) 149 e.hash = crypto.Keccak256Hash(encoded) 150 } 151 return e.hash 152 } 153 154 // DecodeRLP decodes an Envelope from an RLP data stream. 155 func (e *Envelope) DecodeRLP(s *rlp.Stream) error { 156 raw, err := s.Raw() 157 if err != nil { 158 return err 159 } 160 // The decoding of Envelope uses the struct fields but also needs 161 // to compute the hash of the whole RLP-encoded envelope. This 162 // type has the same structure as Envelope but is not an 163 // rlp.Decoder (does not implement DecodeRLP function). 164 // Only public members will be encoded. 165 type rlpenv Envelope 166 if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil { 167 return err 168 } 169 e.hash = crypto.Keccak256Hash(raw) 170 return nil 171 } 172 173 // OpenAsymmetric tries to decrypt an envelope, potentially encrypted with a particular key. 174 func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) { 175 message := &ReceivedMessage{Raw: e.Data} 176 err := message.decryptAsymmetric(key) 177 switch err { 178 case nil: 179 return message, nil 180 case ecies.ErrInvalidPublicKey: // addressed to somebody else 181 return nil, err 182 default: 183 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 184 } 185 } 186 187 // OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key. 188 func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) { 189 msg = &ReceivedMessage{Raw: e.Data} 190 err = msg.decryptSymmetric(key) 191 if err != nil { 192 msg = nil 193 } 194 return msg, err 195 } 196 197 // Open tries to decrypt an envelope, and populates the message fields in case of success. 198 func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) { 199 // The API interface forbids filters doing both symmetric and 200 // asymmetric encryption. 201 if watcher.expectsAsymmetricEncryption() && watcher.expectsSymmetricEncryption() { 202 return nil 203 } 204 205 if watcher.expectsAsymmetricEncryption() { 206 msg, _ = e.OpenAsymmetric(watcher.KeyAsym) 207 if msg != nil { 208 msg.Dst = &watcher.KeyAsym.PublicKey 209 } 210 } else if watcher.expectsSymmetricEncryption() { 211 msg, _ = e.OpenSymmetric(watcher.KeySym) 212 if msg != nil { 213 msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym) 214 } 215 } 216 217 if msg != nil { 218 ok := msg.Validate() 219 if !ok { 220 return nil 221 } 222 msg.Topic = e.Topic 223 msg.PoW = e.PoW() 224 msg.TTL = e.TTL 225 msg.Sent = e.Expiry - e.TTL 226 msg.EnvelopeHash = e.Hash() 227 } 228 return msg 229 }