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