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