github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/whisper/whisperv5/envelope.go (about)

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