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