github.com/csquan/dpos-go-ethereum@v1.9.7/p2p/enode/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 enode 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "io" 23 24 "github.com/ethereum/go-ethereum/common/math" 25 "github.com/ethereum/go-ethereum/crypto" 26 "github.com/ethereum/go-ethereum/p2p/enr" 27 "github.com/ethereum/go-ethereum/rlp" 28 "golang.org/x/crypto/sha3" 29 ) 30 31 // List of known secure identity schemes. 32 var ValidSchemes = enr.SchemeMap{ 33 "v4": V4ID{}, 34 } 35 36 var ValidSchemesForTesting = enr.SchemeMap{ 37 "v4": V4ID{}, 38 "null": NullID{}, 39 } 40 41 // v4ID is the "v4" identity scheme. 42 type V4ID struct{} 43 44 // SignV4 signs a record using the v4 scheme. 45 func SignV4(r *enr.Record, privkey *ecdsa.PrivateKey) error { 46 // Copy r to avoid modifying it if signing fails. 47 cpy := *r 48 cpy.Set(enr.ID("v4")) 49 cpy.Set(Secp256k1(privkey.PublicKey)) 50 51 h := sha3.NewLegacyKeccak256() 52 rlp.Encode(h, cpy.AppendElements(nil)) 53 sig, err := crypto.Sign(h.Sum(nil), privkey) 54 if err != nil { 55 return err 56 } 57 sig = sig[:len(sig)-1] // remove v 58 if err = cpy.SetSig(V4ID{}, sig); err == nil { 59 *r = cpy 60 } 61 return err 62 } 63 64 func (V4ID) Verify(r *enr.Record, sig []byte) error { 65 var entry s256raw 66 if err := r.Load(&entry); err != nil { 67 return err 68 } else if len(entry) != 33 { 69 return fmt.Errorf("invalid public key") 70 } 71 72 h := sha3.NewLegacyKeccak256() 73 rlp.Encode(h, r.AppendElements(nil)) 74 if !crypto.VerifySignature(entry, h.Sum(nil), sig) { 75 return enr.ErrInvalidSig 76 } 77 return nil 78 } 79 80 func (V4ID) NodeAddr(r *enr.Record) []byte { 81 var pubkey Secp256k1 82 err := r.Load(&pubkey) 83 if err != nil { 84 return nil 85 } 86 buf := make([]byte, 64) 87 math.ReadBits(pubkey.X, buf[:32]) 88 math.ReadBits(pubkey.Y, buf[32:]) 89 return crypto.Keccak256(buf) 90 } 91 92 // Secp256k1 is the "secp256k1" key, which holds a public key. 93 type Secp256k1 ecdsa.PublicKey 94 95 func (v Secp256k1) ENRKey() string { return "secp256k1" } 96 97 // EncodeRLP implements rlp.Encoder. 98 func (v Secp256k1) EncodeRLP(w io.Writer) error { 99 return rlp.Encode(w, crypto.CompressPubkey((*ecdsa.PublicKey)(&v))) 100 } 101 102 // DecodeRLP implements rlp.Decoder. 103 func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error { 104 buf, err := s.Bytes() 105 if err != nil { 106 return err 107 } 108 pk, err := crypto.DecompressPubkey(buf) 109 if err != nil { 110 return err 111 } 112 *v = (Secp256k1)(*pk) 113 return nil 114 } 115 116 // s256raw is an unparsed secp256k1 public key entry. 117 type s256raw []byte 118 119 func (s256raw) ENRKey() string { return "secp256k1" } 120 121 // v4CompatID is a weaker and insecure version of the "v4" scheme which only checks for the 122 // presence of a secp256k1 public key, but doesn't verify the signature. 123 type v4CompatID struct { 124 V4ID 125 } 126 127 func (v4CompatID) Verify(r *enr.Record, sig []byte) error { 128 var pubkey Secp256k1 129 return r.Load(&pubkey) 130 } 131 132 func signV4Compat(r *enr.Record, pubkey *ecdsa.PublicKey) { 133 r.Set((*Secp256k1)(pubkey)) 134 if err := r.SetSig(v4CompatID{}, []byte{}); err != nil { 135 panic(err) 136 } 137 } 138 139 // NullID is the "null" ENR identity scheme. This scheme stores the node 140 // ID in the record without any signature. 141 type NullID struct{} 142 143 func (NullID) Verify(r *enr.Record, sig []byte) error { 144 return nil 145 } 146 147 func (NullID) NodeAddr(r *enr.Record) []byte { 148 var id ID 149 r.Load(enr.WithEntry("nulladdr", &id)) 150 return id[:] 151 } 152 153 func SignNull(r *enr.Record, id ID) *Node { 154 r.Set(enr.ID("null")) 155 r.Set(enr.WithEntry("nulladdr", id)) 156 if err := r.SetSig(NullID{}, []byte{}); err != nil { 157 panic(err) 158 } 159 return &Node{r: *r, id: id} 160 }