github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:46</date>
    10  //</624450124268965888>
    11  
    12  
    13  //包含Whisper协议信封元素。
    14  
    15  package whisperv5
    16  
    17  import (
    18  	"crypto/ecdsa"
    19  	"encoding/binary"
    20  	"fmt"
    21  	gmath "math"
    22  	"math/big"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/common/math"
    27  	"github.com/ethereum/go-ethereum/crypto"
    28  	"github.com/ethereum/go-ethereum/crypto/ecies"
    29  	"github.com/ethereum/go-ethereum/rlp"
    30  )
    31  
    32  //信封表示一个明文数据包,通过耳语进行传输。
    33  //网络。其内容可以加密或不加密和签名。
    34  type Envelope struct {
    35  	Version  []byte
    36  	Expiry   uint32
    37  	TTL      uint32
    38  	Topic    TopicType
    39  	AESNonce []byte
    40  	Data     []byte
    41  	EnvNonce uint64
    42  
    43  pow  float64     //消息特定的POW,如Whisper规范中所述。
    44  hash common.Hash //信封的缓存哈希,以避免每次重新刷新。
    45  //不要直接访问哈希,而是使用hash()函数。
    46  }
    47  
    48  //大小返回信封发送时的大小(即仅公共字段)
    49  func (e *Envelope) size() int {
    50  	return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data)
    51  }
    52  
    53  //rlpwithoutnonce返回rlp编码的信封内容,nonce除外。
    54  func (e *Envelope) rlpWithoutNonce() []byte {
    55  	res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data})
    56  	return res
    57  }
    58  
    59  //newenvelope用过期和目标数据包装了一条私语消息
    60  //包含在信封中,用于网络转发。
    61  func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *sentMessage) *Envelope {
    62  	env := Envelope{
    63  		Version:  make([]byte, 1),
    64  		Expiry:   uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
    65  		TTL:      ttl,
    66  		Topic:    topic,
    67  		AESNonce: aesNonce,
    68  		Data:     msg.Raw,
    69  		EnvNonce: 0,
    70  	}
    71  
    72  	if EnvelopeVersion < 256 {
    73  		env.Version[0] = byte(EnvelopeVersion)
    74  	} else {
    75  		panic("please increase the size of Envelope.Version before releasing this version")
    76  	}
    77  
    78  	return &env
    79  }
    80  
    81  func (e *Envelope) IsSymmetric() bool {
    82  	return len(e.AESNonce) > 0
    83  }
    84  
    85  func (e *Envelope) isAsymmetric() bool {
    86  	return !e.IsSymmetric()
    87  }
    88  
    89  func (e *Envelope) Ver() uint64 {
    90  	return bytesToUintLittleEndian(e.Version)
    91  }
    92  
    93  //Seal通过花费所需的时间作为证据来关闭信封
    94  //关于散列数据的工作。
    95  func (e *Envelope) Seal(options *MessageParams) error {
    96  	var target, bestBit int
    97  	if options.PoW == 0 {
    98  //仅当无条件地预先定义执行时间时,才调整seal()执行的持续时间
    99  		e.Expiry += options.WorkTime
   100  	} else {
   101  		target = e.powToFirstBit(options.PoW)
   102  		if target < 1 {
   103  			target = 1
   104  		}
   105  	}
   106  
   107  	buf := make([]byte, 64)
   108  	h := crypto.Keccak256(e.rlpWithoutNonce())
   109  	copy(buf[:32], h)
   110  
   111  	finish := time.Now().Add(time.Duration(options.WorkTime) * time.Second).UnixNano()
   112  	for nonce := uint64(0); time.Now().UnixNano() < finish; {
   113  		for i := 0; i < 1024; i++ {
   114  			binary.BigEndian.PutUint64(buf[56:], nonce)
   115  			d := new(big.Int).SetBytes(crypto.Keccak256(buf))
   116  			firstBit := math.FirstBitSet(d)
   117  			if firstBit > bestBit {
   118  				e.EnvNonce, bestBit = nonce, firstBit
   119  				if target > 0 && bestBit >= target {
   120  					return nil
   121  				}
   122  			}
   123  			nonce++
   124  		}
   125  	}
   126  
   127  	if target > 0 && bestBit < target {
   128  		return fmt.Errorf("failed to reach the PoW target, specified pow time (%d seconds) was insufficient", options.WorkTime)
   129  	}
   130  
   131  	return nil
   132  }
   133  
   134  func (e *Envelope) PoW() float64 {
   135  	if e.pow == 0 {
   136  		e.calculatePoW(0)
   137  	}
   138  	return e.pow
   139  }
   140  
   141  func (e *Envelope) calculatePoW(diff uint32) {
   142  	buf := make([]byte, 64)
   143  	h := crypto.Keccak256(e.rlpWithoutNonce())
   144  	copy(buf[:32], h)
   145  	binary.BigEndian.PutUint64(buf[56:], e.EnvNonce)
   146  	d := new(big.Int).SetBytes(crypto.Keccak256(buf))
   147  	firstBit := math.FirstBitSet(d)
   148  	x := gmath.Pow(2, float64(firstBit))
   149  	x /= float64(e.size())
   150  	x /= float64(e.TTL + diff)
   151  	e.pow = x
   152  }
   153  
   154  func (e *Envelope) powToFirstBit(pow float64) int {
   155  	x := pow
   156  	x *= float64(e.size())
   157  	x *= float64(e.TTL)
   158  	bits := gmath.Log2(x)
   159  	bits = gmath.Ceil(bits)
   160  	return int(bits)
   161  }
   162  
   163  //hash返回信封的sha3散列,如果还没有完成,则计算它。
   164  func (e *Envelope) Hash() common.Hash {
   165  	if (e.hash == common.Hash{}) {
   166  		encoded, _ := rlp.EncodeToBytes(e)
   167  		e.hash = crypto.Keccak256Hash(encoded)
   168  	}
   169  	return e.hash
   170  }
   171  
   172  //decoderlp从rlp数据流解码信封。
   173  func (e *Envelope) DecodeRLP(s *rlp.Stream) error {
   174  	raw, err := s.Raw()
   175  	if err != nil {
   176  		return err
   177  	}
   178  //信封的解码使用结构字段,但也需要
   179  //计算整个RLP编码信封的散列值。这个
   180  //类型具有与信封相同的结构,但不是
   181  //rlp.decoder(不实现decoderlp函数)。
   182  //只对公共成员进行编码。
   183  	type rlpenv Envelope
   184  	if err := rlp.DecodeBytes(raw, (*rlpenv)(e)); err != nil {
   185  		return err
   186  	}
   187  	e.hash = crypto.Keccak256Hash(raw)
   188  	return nil
   189  }
   190  
   191  //OpenAsymmetric试图解密一个信封,可能用一个特定的密钥加密。
   192  func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, error) {
   193  	message := &ReceivedMessage{Raw: e.Data}
   194  	err := message.decryptAsymmetric(key)
   195  	switch err {
   196  	case nil:
   197  		return message, nil
   198  case ecies.ErrInvalidPublicKey: //写给别人的
   199  		return nil, err
   200  	default:
   201  		return nil, fmt.Errorf("unable to open envelope, decrypt failed: %v", err)
   202  	}
   203  }
   204  
   205  //opensymmetric试图解密一个可能用特定密钥加密的信封。
   206  func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
   207  	msg = &ReceivedMessage{Raw: e.Data}
   208  	err = msg.decryptSymmetric(key, e.AESNonce)
   209  	if err != nil {
   210  		msg = nil
   211  	}
   212  	return msg, err
   213  }
   214  
   215  //open试图解密信封,并在成功时填充消息字段。
   216  func (e *Envelope) Open(watcher *Filter) (msg *ReceivedMessage) {
   217  	if e.isAsymmetric() {
   218  		msg, _ = e.OpenAsymmetric(watcher.KeyAsym)
   219  		if msg != nil {
   220  			msg.Dst = &watcher.KeyAsym.PublicKey
   221  		}
   222  	} else if e.IsSymmetric() {
   223  		msg, _ = e.OpenSymmetric(watcher.KeySym)
   224  		if msg != nil {
   225  			msg.SymKeyHash = crypto.Keccak256Hash(watcher.KeySym)
   226  		}
   227  	}
   228  
   229  	if msg != nil {
   230  		ok := msg.Validate()
   231  		if !ok {
   232  			return nil
   233  		}
   234  		msg.Topic = e.Topic
   235  		msg.PoW = e.PoW()
   236  		msg.TTL = e.TTL
   237  		msg.Sent = e.Expiry - e.TTL
   238  		msg.EnvelopeHash = e.Hash()
   239  		msg.EnvelopeVersion = e.Ver()
   240  	}
   241  	return msg
   242  }
   243