github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/enode/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 19:16:41</date>
    10  //</624450104215998464>
    11  
    12  
    13  package enode
    14  
    15  import (
    16  	"crypto/ecdsa"
    17  	"fmt"
    18  	"io"
    19  
    20  	"github.com/ethereum/go-ethereum/common/math"
    21  	"github.com/ethereum/go-ethereum/crypto"
    22  	"github.com/ethereum/go-ethereum/p2p/enr"
    23  	"github.com/ethereum/go-ethereum/rlp"
    24  	"golang.org/x/crypto/sha3"
    25  )
    26  
    27  //已知安全身份方案的列表。
    28  var ValidSchemes = enr.SchemeMap{
    29  	"v4": V4ID{},
    30  }
    31  
    32  var ValidSchemesForTesting = enr.SchemeMap{
    33  	"v4":   V4ID{},
    34  	"null": NullID{},
    35  }
    36  
    37  //v4id是“v4”标识方案。
    38  type V4ID struct{}
    39  
    40  //signv4使用v4方案对记录进行签名。
    41  func SignV4(r *enr.Record, privkey *ecdsa.PrivateKey) error {
    42  //复制r以避免在签名失败时修改它。
    43  	cpy := *r
    44  	cpy.Set(enr.ID("v4"))
    45  	cpy.Set(Secp256k1(privkey.PublicKey))
    46  
    47  	h := sha3.NewLegacyKeccak256()
    48  	rlp.Encode(h, cpy.AppendElements(nil))
    49  	sig, err := crypto.Sign(h.Sum(nil), privkey)
    50  	if err != nil {
    51  		return err
    52  	}
    53  sig = sig[:len(sig)-1] //移除V
    54  	if err = cpy.SetSig(V4ID{}, sig); err == nil {
    55  		*r = cpy
    56  	}
    57  	return err
    58  }
    59  
    60  func (V4ID) Verify(r *enr.Record, sig []byte) error {
    61  	var entry s256raw
    62  	if err := r.Load(&entry); err != nil {
    63  		return err
    64  	} else if len(entry) != 33 {
    65  		return fmt.Errorf("invalid public key")
    66  	}
    67  
    68  	h := sha3.NewLegacyKeccak256()
    69  	rlp.Encode(h, r.AppendElements(nil))
    70  	if !crypto.VerifySignature(entry, h.Sum(nil), sig) {
    71  		return enr.ErrInvalidSig
    72  	}
    73  	return nil
    74  }
    75  
    76  func (V4ID) NodeAddr(r *enr.Record) []byte {
    77  	var pubkey Secp256k1
    78  	err := r.Load(&pubkey)
    79  	if err != nil {
    80  		return nil
    81  	}
    82  	buf := make([]byte, 64)
    83  	math.ReadBits(pubkey.X, buf[:32])
    84  	math.ReadBits(pubkey.Y, buf[32:])
    85  	return crypto.Keccak256(buf)
    86  }
    87  
    88  //secp256k1是保存公钥的“secp256k1”密钥。
    89  type Secp256k1 ecdsa.PublicKey
    90  
    91  func (v Secp256k1) ENRKey() string { return "secp256k1" }
    92  
    93  //encoderlp实现rlp.encoder。
    94  func (v Secp256k1) EncodeRLP(w io.Writer) error {
    95  	return rlp.Encode(w, crypto.CompressPubkey((*ecdsa.PublicKey)(&v)))
    96  }
    97  
    98  //decoderlp实现rlp.decoder。
    99  func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error {
   100  	buf, err := s.Bytes()
   101  	if err != nil {
   102  		return err
   103  	}
   104  	pk, err := crypto.DecompressPubkey(buf)
   105  	if err != nil {
   106  		return err
   107  	}
   108  	*v = (Secp256k1)(*pk)
   109  	return nil
   110  }
   111  
   112  //s256raw是一个未分析的secp256k1公钥条目。
   113  type s256raw []byte
   114  
   115  func (s256raw) ENRKey() string { return "secp256k1" }
   116  
   117  //v4compatid是“v4”方案的一个较弱且不安全的版本,它只检查
   118  //存在secp256k1公钥,但不验证签名。
   119  type v4CompatID struct {
   120  	V4ID
   121  }
   122  
   123  func (v4CompatID) Verify(r *enr.Record, sig []byte) error {
   124  	var pubkey Secp256k1
   125  	return r.Load(&pubkey)
   126  }
   127  
   128  func signV4Compat(r *enr.Record, pubkey *ecdsa.PublicKey) {
   129  	r.Set((*Secp256k1)(pubkey))
   130  	if err := r.SetSig(v4CompatID{}, []byte{}); err != nil {
   131  		panic(err)
   132  	}
   133  }
   134  
   135  //“空”是“空”的ENR身份方案。此方案存储节点
   136  //记录中没有任何签名的ID。
   137  type NullID struct{}
   138  
   139  func (NullID) Verify(r *enr.Record, sig []byte) error {
   140  	return nil
   141  }
   142  
   143  func (NullID) NodeAddr(r *enr.Record) []byte {
   144  	var id ID
   145  	r.Load(enr.WithEntry("nulladdr", &id))
   146  	return id[:]
   147  }
   148  
   149  func SignNull(r *enr.Record, id ID) *Node {
   150  	r.Set(enr.ID("null"))
   151  	r.Set(enr.WithEntry("nulladdr", id))
   152  	if err := r.SetSig(NullID{}, []byte{}); err != nil {
   153  		panic(err)
   154  	}
   155  	return &Node{r: *r, id: id}
   156  }
   157