envelope.go 6.8 KB

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