github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/whisper/whisperv5/envelope.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:51</date>
    10  //</624342688589680640>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  //
    29  
    30  package whisperv5
    31  
    32  import (
    33  	"crypto/ecdsa"
    34  	"encoding/binary"
    35  	"fmt"
    36  	gmath "math"
    37  	"math/big"
    38  	"time"
    39  
    40  	"github.com/ethereum/go-ethereum/common"
    41  	"github.com/ethereum/go-ethereum/common/math"
    42  	"github.com/ethereum/go-ethereum/crypto"
    43  	"github.com/ethereum/go-ethereum/crypto/ecies"
    44  	"github.com/ethereum/go-ethereum/rlp"
    45  )
    46  
    47  //
    48  //
    49  type Envelope struct {
    50  	Version  []byte
    51  	Expiry   uint32
    52  	TTL      uint32
    53  	Topic    TopicType
    54  	AESNonce []byte
    55  	Data     []byte
    56  	EnvNonce uint64
    57  
    58  pow  float64     //
    59  hash common.Hash //
    60  //
    61  }
    62  
    63  //
    64  func (e *Envelope) size() int {
    65  	return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data)
    66  }
    67  
    68  //
    69  func (e *Envelope) rlpWithoutNonce() []byte {
    70  	res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data})
    71  	return res
    72  }
    73  
    74  //
    75  //
    76  func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *sentMessage) *Envelope {
    77  	env := Envelope{
    78  		Version:  make([]byte, 1),
    79  		Expiry:   uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
    80  		TTL:      ttl,
    81  		Topic:    topic,
    82  		AESNonce: aesNonce,
    83  		Data:     msg.Raw,
    84  		EnvNonce: 0,
    85  	}
    86  
    87  	if EnvelopeVersion < 256 {
    88  		env.Version[0] = byte(EnvelopeVersion)
    89  	} else {
    90  		panic("please increase the size of Envelope.Version before releasing this version")
    91  	}
    92  
    93  	return &env
    94  }
    95  
    96  func (e *Envelope) IsSymmetric() bool {
    97  	return len(e.AESNonce) > 0
    98  }
    99  
   100  func (e *Envelope) isAsymmetric() bool {
   101  	return !e.IsSymmetric()
   102  }
   103  
   104  func (e *Envelope) Ver() uint64 {
   105  	return bytesToUintLittleEndian(e.Version)
   106  }
   107  
   108  //
   109  //
   110  func (e *Envelope) Seal(options *MessageParams) error {
   111  	var target, bestBit int
   112  	if options.PoW == 0 {
   113  //
   114  		e.Expiry += options.WorkTime
   115  	} else {
   116  		target = e.powToFirstBit(options.PoW)
   117  		if target < 1 {
   118  			target = 1
   119  		}
   120  	}
   121  
   122  	buf := make([]byte, 64)
   123  	h := crypto.Keccak256(e.rlpWithoutNonce())
   124  	copy(buf[:32], h)
   125  
   126  	finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano()
   127  	for nonce := uint64(0); time.Now().UnixNano() < finish; {
   128  		for i := 0; i < 1024; i++ {
   129  			binary.BigEndian.PutUint64(buf[56:], nonce)
   130  			d := new(big.Int).SetBytes(crypto.Keccak256(buf))
   131  			firstBit := math.FirstBitSet(d)
   132  			if firstBit > bestBit {
   133  				e.EnvNonce, bestBit = nonce, firstBit
   134  				if target > 0 && bestBit >= target {
   135  					return nil
   136  				}
   137  			}
   138  			nonce++
   139  		}
   140  	}
   141  
   142  	if target > 0 && bestBit < target {
   143  		return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime)
   144  	}
   145  
   146  	return nil
   147  }
   148  
   149  func (e *Envelope) PoW() float64 {
   150  	if e.pow == 0 {
   151  		e.calculatePoW(0)
   152  	}
   153  	return e.pow
   154  }
   155  
   156  func (e *Envelope) calculatePoW(diff uint32) {
   157  	buf := make([]byte, 64)
   158  	h := crypto.Keccak256(e.rlpWithoutNonce())
   159  	copy(buf[:32], h)
   160  	binary.BigEndian.PutUint64(buf[56:], e.EnvNonce)
   161  	d := new(big.Int).SetBytes(crypto.Keccak256(buf))
   162  	firstBit := math.FirstBitSet(d)
   163  	x := gmath.Pow(2, float64(firstBit))
   164  	x /= float64(e.size())
   165  	x /= float64(e.TTL + diff)
   166  	e.pow = x
   167  }
   168  
   169  func (e *Envelope) powToFirstBit(pow float64) int {
   170  	x := pow
   171  	x *= float64(e.size())
   172  	x *= float64(e.TTL)
   173  	bits := gmath.Log2(x)
   174  	bits = gmath.Ceil(bits)
   175  	return int(bits)
   176  }
   177  
   178  //
   179  func (e *Envelope) Hash() common.Hash {
   180  	if (e.hash == common.Hash{}) {
   181  		encoded, _ := rlp.EncodeToBytes(e)
   182  		e.hash = crypto.Keccak256Hash(encoded)
   183  	}
   184  	return e.hash
   185  }
   186  
   187  //
   188  func (e *Envelope) DecodeRLP(s *rlp.Stream) error {
   189  	raw, err := s.Raw()
   190  	if err != nil {
   191  		return err
   192  	}
   193  //
   194  //
   195  //
   196  //
   197  //
   198  	type rlpenv Envelope
   199  	if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil {
   200  		return err
   201  	}
   202  	e.hash = crypto.Keccak256Hash(raw)
   203  	return nil
   204  }
   205  
   206  //
   207  func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) {
   208  	message := &ReceivedMessage{Raw: e.Data}
   209  	err := message.decryptAsymmetric(key)
   210  	switch err {
   211  	case nil:
   212  		return message, nil
   213  case ecies.ErrInvalidPublicKey: //
   214  		return nil, err
   215  	default:
   216  		return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err)
   217  	}
   218  }
   219  
   220  //
   221  func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
   222  	msg = &ReceivedMessage{Raw: e.Data}
   223  	err = msg.decryptSymmetric(key, e.AESNonce)
   224  	if err != nil {
   225  		msg = nil
   226  	}
   227  	return msg, err
   228  }
   229  
   230  //
   231  func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) {
   232  	if e.isAsymmetric() {
   233  		msg, _ = e.OpenAsymmetric(watcher.KeyAsym)
   234  		if msg != nil {
   235  			msg.Dst = &watcher.KeyAsym.PublicKey
   236  		}
   237  	} else if e.IsSymmetric() {
   238  		msg, _ = e.OpenSymmetric(watcher.KeySym)
   239  		if msg != nil {
   240  			msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym)
   241  		}
   242  	}
   243  
   244  	if msg != nil {
   245  		ok := msg.Validate()
   246  		if !ok {
   247  			return nil
   248  		}
   249  		msg.Topic = e.Topic
   250  		msg.PoW = e.PoW()
   251  		msg.TTL = e.TTL
   252  		msg.Sent = e.Expiry - e.TTL
   253  		msg.EnvelopeHash = e.Hash()
   254  		msg.EnvelopeVersion = e.Ver()
   255  	}
   256  	return msg
   257  }
   258