github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/enr/idscheme.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:44</date>
    10  //</624342658336165888>
    11  
    12  
    13  package enr
    14  
    15  import (
    16  	"crypto/ecdsa"
    17  	"fmt"
    18  	"sync"
    19  
    20  	"github.com/ethereum/go-ethereum/common/math"
    21  	"github.com/ethereum/go-ethereum/crypto"
    22  	"github.com/ethereum/go-ethereum/crypto/sha3"
    23  	"github.com/ethereum/go-ethereum/rlp"
    24  )
    25  
    26  //已知身份方案的注册表。
    27  var schemes sync.Map
    28  
    29  //标识方案能够验证记录签名和
    30  //派生节点地址。
    31  type IdentityScheme interface {
    32  	Verify(r *Record, sig []byte) error
    33  	NodeAddr(r *Record) []byte
    34  }
    35  
    36  //RegisterIdentityScheme向全局注册表添加标识方案。
    37  func RegisterIdentityScheme(name string, scheme IdentityScheme) {
    38  	if _, loaded := schemes.LoadOrStore(name, scheme); loaded {
    39  		panic("identity scheme " + name + " already registered")
    40  	}
    41  }
    42  
    43  //findidentityScheme将名称解析为全局注册表中的标识方案。
    44  func FindIdentityScheme(name string) IdentityScheme {
    45  	s, ok := schemes.Load(name)
    46  	if !ok {
    47  		return nil
    48  	}
    49  	return s.(IdentityScheme)
    50  }
    51  
    52  //v4id是“v4”标识方案。
    53  type v4ID struct{}
    54  
    55  func init() {
    56  	RegisterIdentityScheme("v4", v4ID{})
    57  }
    58  
    59  //signv4使用v4方案对记录进行签名。
    60  func SignV4(r *Record, privkey *ecdsa.PrivateKey) error {
    61  //复制r以避免在签名失败时修改它。
    62  	cpy := *r
    63  	cpy.Set(ID("v4"))
    64  	cpy.Set(Secp256k1(privkey.PublicKey))
    65  
    66  	h := sha3.NewKeccak256()
    67  	rlp.Encode(h, cpy.AppendElements(nil))
    68  	sig, err := crypto.Sign(h.Sum(nil), privkey)
    69  	if err != nil {
    70  		return err
    71  	}
    72  sig = sig[:len(sig)-1] //移除V
    73  	if err = cpy.SetSig("v4", sig); err == nil {
    74  		*r = cpy
    75  	}
    76  	return err
    77  }
    78  
    79  //s256raw是一个未分析的secp256k1公钥条目。
    80  type s256raw []byte
    81  
    82  func (s256raw) ENRKey() string { return "secp256k1" }
    83  
    84  func (v4ID) Verify(r *Record, sig []byte) error {
    85  	var entry s256raw
    86  	if err := r.Load(&entry); err != nil {
    87  		return err
    88  	} else if len(entry) != 33 {
    89  		return fmt.Errorf("invalid public key")
    90  	}
    91  
    92  	h := sha3.NewKeccak256()
    93  	rlp.Encode(h, r.AppendElements(nil))
    94  	if !crypto.VerifySignature(entry, h.Sum(nil), sig) {
    95  		return errInvalidSig
    96  	}
    97  	return nil
    98  }
    99  
   100  func (v4ID) NodeAddr(r *Record) []byte {
   101  	var pubkey Secp256k1
   102  	err := r.Load(&pubkey)
   103  	if err != nil {
   104  		return nil
   105  	}
   106  	buf := make([]byte, 64)
   107  	math.ReadBits(pubkey.X, buf[:32])
   108  	math.ReadBits(pubkey.Y, buf[32:])
   109  	return crypto.Keccak256(buf)
   110  }
   111