github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/whisper/whisperv2/envelope.go (about) 1 // Copyright 2014 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. For formal details please see 18 // the specs at https://github.com/ethereum/wiki/wiki/Whisper-PoC-1-Protocol-Spec#envelopes. 19 20 package whisperv2 21 22 import ( 23 "crypto/ecdsa" 24 "encoding/binary" 25 "fmt" 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 // Whisper protocol specifies int32, really should be int64 40 TTL uint32 // ^^^^^^ 41 Topics []Topic 42 Data []byte 43 Nonce uint32 44 45 hash common.Hash // Cached hash of the envelope to avoid rehashing every time 46 } 47 48 // NewEnvelope wraps a Whisper message with expiration and destination data 49 // included into an envelope for network forwarding. 50 func NewEnvelope(ttl time.Duration, topics []Topic, msg *Message) *Envelope { 51 return &Envelope{ 52 Expiry: uint32(time.Now().Add(ttl).Unix()), 53 TTL: uint32(ttl.Seconds()), 54 Topics: topics, 55 Data: msg.bytes(), 56 Nonce: 0, 57 } 58 } 59 60 // Seal closes the envelope by spending the requested amount of time as a proof 61 // of work on hashing the data. 62 func (self *Envelope) Seal(pow time.Duration) { 63 d := make([]byte, 64) 64 copy(d[:32], self.rlpWithoutNonce()) 65 66 finish, bestBit := time.Now().Add(pow).UnixNano(), 0 67 for nonce := uint32(0); time.Now().UnixNano() < finish; { 68 for i := 0; i < 1024; i++ { 69 binary.BigEndian.PutUint32(d[60:], nonce) 70 71 d := new(big.Int).SetBytes(crypto.Keccak256(d)) 72 firstBit := math.FirstBitSet(d) 73 if firstBit > bestBit { 74 self.Nonce, bestBit = nonce, firstBit 75 } 76 nonce++ 77 } 78 } 79 } 80 81 // rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce. 82 func (self *Envelope) rlpWithoutNonce() []byte { 83 enc, _ := rlp.EncodeToBytes([]interface{}{self.Expiry, self.TTL, self.Topics, self.Data}) 84 return enc 85 } 86 87 // Open extracts the message contained within a potentially encrypted envelope. 88 func (self *Envelope) Open(key *ecdsa.PrivateKey) (msg *Message, err error) { 89 // Split open the payload into a message construct 90 data := self.Data 91 92 message := &Message{ 93 Flags: data[0], 94 Sent: time.Unix(int64(self.Expiry-self.TTL), 0), 95 TTL: time.Duration(self.TTL) * time.Second, 96 Hash: self.Hash(), 97 } 98 data = data[1:] 99 100 if message.Flags&signatureFlag == signatureFlag { 101 if len(data) < signatureLength { 102 return nil, fmt.Errorf("unable to open envelope. First bit set but len(data) < len(signature)") 103 } 104 message.Signature, data = data[:signatureLength], data[signatureLength:] 105 } 106 message.Payload = data 107 108 // Decrypt the message, if requested 109 if key == nil { 110 return message, nil 111 } 112 err = message.decrypt(key) 113 switch err { 114 case nil: 115 return message, nil 116 117 case ecies.ErrInvalidPublicKey: // Payload isn't encrypted 118 return message, err 119 120 default: 121 return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err) 122 } 123 } 124 125 // Hash returns the SHA3 hash of the envelope, calculating it if not yet done. 126 func (self *Envelope) Hash() common.Hash { 127 if (self.hash == common.Hash{}) { 128 enc, _ := rlp.EncodeToBytes(self) 129 self.hash = crypto.Keccak256Hash(enc) 130 } 131 return self.hash 132 } 133 134 // DecodeRLP decodes an Envelope from an RLP data stream. 135 func (self *Envelope) DecodeRLP(s *rlp.Stream) error { 136 raw, err := s.Raw() 137 if err != nil { 138 return err 139 } 140 // The decoding of Envelope uses the struct fields but also needs 141 // to compute the hash of the whole RLP-encoded envelope. This 142 // type has the same structure as Envelope but is not an 143 // rlp.Decoder so we can reuse the Envelope struct definition. 144 type rlpenv Envelope 145 if err := rlp.DecodeBytes(raw, (*rlpenv)(self)); err != nil { 146 return err 147 } 148 self.hash = crypto.Keccak256Hash(raw) 149 return nil 150 }