github.com/luckypickle/go-ethereum-vet@v1.14.2/p2p/enr/idscheme.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package enr 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "sync" 23 24 "github.com/luckypickle/go-ethereum-vet/common/math" 25 "github.com/luckypickle/go-ethereum-vet/crypto" 26 "github.com/luckypickle/go-ethereum-vet/crypto/sha3" 27 "github.com/luckypickle/go-ethereum-vet/rlp" 28 ) 29 30 // Registry of known identity schemes. 31 var schemes sync.Map 32 33 // An IdentityScheme is capable of verifying record signatures and 34 // deriving node addresses. 35 type IdentityScheme interface { 36 Verify(r *Record, sig []byte) error 37 NodeAddr(r *Record) []byte 38 } 39 40 // RegisterIdentityScheme adds an identity scheme to the global registry. 41 func RegisterIdentityScheme(name string, scheme IdentityScheme) { 42 if _, loaded := schemes.LoadOrStore(name, scheme); loaded { 43 panic("identity scheme " + name + " already registered") 44 } 45 } 46 47 // FindIdentityScheme resolves name to an identity scheme in the global registry. 48 func FindIdentityScheme(name string) IdentityScheme { 49 s, ok := schemes.Load(name) 50 if !ok { 51 return nil 52 } 53 return s.(IdentityScheme) 54 } 55 56 // v4ID is the "v4" identity scheme. 57 type v4ID struct{} 58 59 func init() { 60 RegisterIdentityScheme("v4", v4ID{}) 61 } 62 63 // SignV4 signs a record using the v4 scheme. 64 func SignV4(r *Record, privkey *ecdsa.PrivateKey) error { 65 // Copy r to avoid modifying it if signing fails. 66 cpy := *r 67 cpy.Set(ID("v4")) 68 cpy.Set(Secp256k1(privkey.PublicKey)) 69 70 h := sha3.NewKeccak256() 71 rlp.Encode(h, cpy.AppendElements(nil)) 72 sig, err := crypto.Sign(h.Sum(nil), privkey) 73 if err != nil { 74 return err 75 } 76 sig = sig[:len(sig)-1] // remove v 77 if err = cpy.SetSig("v4", sig); err == nil { 78 *r = cpy 79 } 80 return err 81 } 82 83 // s256raw is an unparsed secp256k1 public key entry. 84 type s256raw []byte 85 86 func (s256raw) ENRKey() string { return "secp256k1" } 87 88 func (v4ID) Verify(r *Record, sig []byte) error { 89 var entry s256raw 90 if err := r.Load(&entry); err != nil { 91 return err 92 } else if len(entry) != 33 { 93 return fmt.Errorf("invalid public key") 94 } 95 96 h := sha3.NewKeccak256() 97 rlp.Encode(h, r.AppendElements(nil)) 98 if !crypto.VerifySignature(entry, h.Sum(nil), sig) { 99 return errInvalidSig 100 } 101 return nil 102 } 103 104 func (v4ID) NodeAddr(r *Record) []byte { 105 var pubkey Secp256k1 106 err := r.Load(&pubkey) 107 if err != nil { 108 return nil 109 } 110 buf := make([]byte, 64) 111 math.ReadBits(pubkey.X, buf[:32]) 112 math.ReadBits(pubkey.Y, buf[32:]) 113 return crypto.Keccak256(buf) 114 }