envelope.go 6.8 KB

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