github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/enode/idscheme.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package enode 19 20 import ( 21 "crypto/ecdsa" 22 "fmt" 23 "io" 24 25 "github.com/AigarNetwork/aigar/common/math" 26 "github.com/AigarNetwork/aigar/crypto" 27 "github.com/AigarNetwork/aigar/p2p/enr" 28 "github.com/AigarNetwork/aigar/rlp" 29 "golang.org/x/crypto/sha3" 30 ) 31 32 // List of known secure identity schemes. 33 var ValidSchemes = enr.SchemeMap{ 34 "v4": V4ID{}, 35 } 36 37 var ValidSchemesForTesting = enr.SchemeMap{ 38 "v4": V4ID{}, 39 "null": NullID{}, 40 } 41 42 // v4ID is the "v4" identity scheme. 43 type V4ID struct{} 44 45 // SignV4 signs a record using the v4 scheme. 46 func SignV4(r *enr.Record, privkey *ecdsa.PrivateKey) error { 47 // Copy r to avoid modifying it if signing fails. 48 cpy := *r 49 cpy.Set(enr.ID("v4")) 50 cpy.Set(Secp256k1(privkey.PublicKey)) 51 52 h := sha3.NewLegacyKeccak256() 53 rlp.Encode(h, cpy.AppendElements(nil)) 54 sig, err := crypto.Sign(h.Sum(nil), privkey) 55 if err != nil { 56 return err 57 } 58 sig = sig[:len(sig)-1] // remove v 59 if err = cpy.SetSig(V4ID{}, sig); err == nil { 60 *r = cpy 61 } 62 return err 63 } 64 65 func (V4ID) Verify(r *enr.Record, sig []byte) error { 66 var entry s256raw 67 if err := r.Load(&entry); err != nil { 68 return err 69 } else if len(entry) != 33 { 70 return fmt.Errorf("invalid public key") 71 } 72 73 h := sha3.NewLegacyKeccak256() 74 rlp.Encode(h, r.AppendElements(nil)) 75 if !crypto.VerifySignature(entry, h.Sum(nil), sig) { 76 return enr.ErrInvalidSig 77 } 78 return nil 79 } 80 81 func (V4ID) NodeAddr(r *enr.Record) []byte { 82 var pubkey Secp256k1 83 err := r.Load(&pubkey) 84 if err != nil { 85 return nil 86 } 87 buf := make([]byte, 64) 88 math.ReadBits(pubkey.X, buf[:32]) 89 math.ReadBits(pubkey.Y, buf[32:]) 90 return crypto.Keccak256(buf) 91 } 92 93 // Secp256k1 is the "secp256k1" key, which holds a public key. 94 type Secp256k1 ecdsa.PublicKey 95 96 func (v Secp256k1) ENRKey() string { return "secp256k1" } 97 98 // EncodeRLP implements rlp.Encoder. 99 func (v Secp256k1) EncodeRLP(w io.Writer) error { 100 return rlp.Encode(w, crypto.CompressPubkey((*ecdsa.PublicKey)(&v))) 101 } 102 103 // DecodeRLP implements rlp.Decoder. 104 func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error { 105 buf, err := s.Bytes() 106 if err != nil { 107 return err 108 } 109 pk, err := crypto.DecompressPubkey(buf) 110 if err != nil { 111 return err 112 } 113 *v = (Secp256k1)(*pk) 114 return nil 115 } 116 117 // s256raw is an unparsed secp256k1 public key entry. 118 type s256raw []byte 119 120 func (s256raw) ENRKey() string { return "secp256k1" } 121 122 // v4CompatID is a weaker and insecure version of the "v4" scheme which only checks for the 123 // presence of a secp256k1 public key, but doesn't verify the signature. 124 type v4CompatID struct { 125 V4ID 126 } 127 128 func (v4CompatID) Verify(r *enr.Record, sig []byte) error { 129 var pubkey Secp256k1 130 return r.Load(&pubkey) 131 } 132 133 func signV4Compat(r *enr.Record, pubkey *ecdsa.PublicKey) { 134 r.Set((*Secp256k1)(pubkey)) 135 if err := r.SetSig(v4CompatID{}, []byte{}); err != nil { 136 panic(err) 137 } 138 } 139 140 // NullID is the "null" ENR identity scheme. This scheme stores the node 141 // ID in the record without any signature. 142 type NullID struct{} 143 144 func (NullID) Verify(r *enr.Record, sig []byte) error { 145 return nil 146 } 147 148 func (NullID) NodeAddr(r *enr.Record) []byte { 149 var id ID 150 r.Load(enr.WithEntry("nulladdr", &id)) 151 return id[:] 152 } 153 154 func SignNull(r *enr.Record, id ID) *Node { 155 r.Set(enr.ID("null")) 156 r.Set(enr.WithEntry("nulladdr", id)) 157 if err := r.SetSig(NullID{}, []byte{}); err != nil { 158 panic(err) 159 } 160 return &Node{r: *r, id: id} 161 }