github.com/bcskill/bcschain/v3@v3.4.9-beta2/p2p/enr/enr.go (about)

     1  // Copyright 2017 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 implements Ethereum Node Records as defined in EIP-778. A node record holds
    18  // arbitrary information about a node on the peer-to-peer network.
    19  //
    20  // Records contain named keys. To store and retrieve key/values in a record, use the Entry
    21  // interface.
    22  //
    23  // Records must be signed before transmitting them to another node. Decoding a record verifies
    24  // its signature. When creating a record, set the entries you want, then call Sign to add the
    25  // signature. Modifying a record invalidates the signature.
    26  //
    27  // Package enr supports the "secp256k1-keccak" identity scheme.
    28  package enr
    29  
    30  import (
    31  	"bytes"
    32  	"crypto/ecdsa"
    33  	"errors"
    34  	"fmt"
    35  	"io"
    36  	"sort"
    37  
    38  	"golang.org/x/crypto/sha3"
    39  
    40  	"github.com/bcskill/bcschain/v3/crypto"
    41  	"github.com/bcskill/bcschain/v3/rlp"
    42  )
    43  
    44  const SizeLimit = 300 // maximum encoded size of a node record in bytes
    45  
    46  const ID_SECP256k1_KECCAK = ID("secp256k1-keccak") // the default identity scheme
    47  
    48  var (
    49  	errNoID           = errors.New("unknown or unspecified identity scheme")
    50  	errInvalidSigsize = errors.New("invalid signature size")
    51  	errInvalidSig     = errors.New("invalid signature")
    52  	errNotSorted      = errors.New("record key/value pairs are not sorted by key")
    53  	errDuplicateKey   = errors.New("record contains duplicate key")
    54  	errIncompletePair = errors.New("record contains incomplete k/v pair")
    55  	errTooBig         = fmt.Errorf("record bigger than %d bytes", SizeLimit)
    56  	errEncodeUnsigned = errors.New("can't encode unsigned record")
    57  	errNotFound       = errors.New("no such key in record")
    58  )
    59  
    60  // Record represents a node record. The zero value is an empty record.
    61  type Record struct {
    62  	seq       uint64 // sequence number
    63  	signature []byte // the signature
    64  	raw       []byte // RLP encoded record
    65  	pairs     []pair // sorted list of all key/value pairs
    66  }
    67  
    68  // pair is a key/value pair in a record.
    69  type pair struct {
    70  	k string
    71  	v rlp.RawValue
    72  }
    73  
    74  // Signed reports whether the record has a valid signature.
    75  func (r *Record) Signed() bool {
    76  	return r.signature != nil
    77  }
    78  
    79  // Seq returns the sequence number.
    80  func (r *Record) Seq() uint64 {
    81  	return r.seq
    82  }
    83  
    84  // SetSeq updates the record sequence number. This invalidates any signature on the record.
    85  // Calling SetSeq is usually not required because signing the redord increments the
    86  // sequence number.
    87  func (r *Record) SetSeq(s uint64) {
    88  	r.signature = nil
    89  	r.raw = nil
    90  	r.seq = s
    91  }
    92  
    93  // Load retrieves the value of a key/value pair. The given Entry must be a pointer and will
    94  // be set to the value of the entry in the record.
    95  //
    96  // Errors returned by Load are wrapped in KeyError. You can distinguish decoding errors
    97  // from missing keys using the IsNotFound function.
    98  func (r *Record) Load(e Entry) error {
    99  	i := sort.Search(len(r.pairs), func(i int) bool { return r.pairs[i].k >= e.ENRKey() })
   100  	if i < len(r.pairs) && r.pairs[i].k == e.ENRKey() {
   101  		if err := rlp.DecodeBytes(r.pairs[i].v, e); err != nil {
   102  			return &KeyError{Key: e.ENRKey(), Err: err}
   103  		}
   104  		return nil
   105  	}
   106  	return &KeyError{Key: e.ENRKey(), Err: errNotFound}
   107  }
   108  
   109  // Set adds or updates the given entry in the record.
   110  // It panics if the value can't be encoded.
   111  func (r *Record) Set(e Entry) {
   112  	r.signature = nil
   113  	r.raw = nil
   114  	blob, err := rlp.EncodeToBytes(e)
   115  	if err != nil {
   116  		panic(fmt.Errorf("enr: can't encode %s: %v", e.ENRKey(), err))
   117  	}
   118  
   119  	i := sort.Search(len(r.pairs), func(i int) bool { return r.pairs[i].k >= e.ENRKey() })
   120  
   121  	if i < len(r.pairs) && r.pairs[i].k == e.ENRKey() {
   122  		// element is present at r.pairs[i]
   123  		r.pairs[i].v = blob
   124  		return
   125  	} else if i < len(r.pairs) {
   126  		// insert pair before i-th elem
   127  		el := pair{e.ENRKey(), blob}
   128  		r.pairs = append(r.pairs, pair{})
   129  		copy(r.pairs[i+1:], r.pairs[i:])
   130  		r.pairs[i] = el
   131  		return
   132  	}
   133  
   134  	// element should be placed at the end of r.pairs
   135  	r.pairs = append(r.pairs, pair{e.ENRKey(), blob})
   136  }
   137  
   138  // EncodeRLP implements rlp.Encoder. Encoding fails if
   139  // the record is unsigned.
   140  func (r Record) EncodeRLP(w io.Writer) error {
   141  	if !r.Signed() {
   142  		return errEncodeUnsigned
   143  	}
   144  	_, err := w.Write(r.raw)
   145  	return err
   146  }
   147  
   148  // DecodeRLP implements rlp.Decoder. Decoding verifies the signature.
   149  func (r *Record) DecodeRLP(s *rlp.Stream) error {
   150  	raw, err := s.Raw()
   151  	if err != nil {
   152  		return err
   153  	}
   154  	if len(raw) > SizeLimit {
   155  		return errTooBig
   156  	}
   157  
   158  	// Decode the RLP container.
   159  	dec := Record{raw: raw}
   160  	s = rlp.NewStream(bytes.NewReader(raw), 0)
   161  	rlp.Discard(s)
   162  	if _, err := s.List(); err != nil {
   163  		return err
   164  	}
   165  	if err = s.Decode(&dec.signature); err != nil {
   166  		return err
   167  	}
   168  	if err = s.Decode(&dec.seq); err != nil {
   169  		return err
   170  	}
   171  	// The rest of the record contains sorted k/v pairs.
   172  	var prevkey string
   173  	for i := 0; ; i++ {
   174  		var kv pair
   175  		if err := s.Decode(&kv.k); err != nil {
   176  			if err == rlp.EOL {
   177  				break
   178  			}
   179  			return err
   180  		}
   181  		if err := s.Decode(&kv.v); err != nil {
   182  			if err == rlp.EOL {
   183  				return errIncompletePair
   184  			}
   185  			return err
   186  		}
   187  		if i > 0 {
   188  			if kv.k == prevkey {
   189  				return errDuplicateKey
   190  			}
   191  			if kv.k < prevkey {
   192  				return errNotSorted
   193  			}
   194  		}
   195  		dec.pairs = append(dec.pairs, kv)
   196  		prevkey = kv.k
   197  	}
   198  	if err := s.ListEnd(); err != nil {
   199  		return err
   200  	}
   201  
   202  	// Verify signature.
   203  	if err = dec.verifySignature(); err != nil {
   204  		return err
   205  	}
   206  	*r = dec
   207  	return nil
   208  }
   209  
   210  type s256raw []byte
   211  
   212  func (s256raw) ENRKey() string { return "secp256k1" }
   213  
   214  // NodeAddr returns the node address. The return value will be nil if the record is
   215  // unsigned.
   216  func (r *Record) NodeAddr() []byte {
   217  	var entry s256raw
   218  	if r.Load(&entry) != nil {
   219  		return nil
   220  	}
   221  	return crypto.Keccak256(entry)
   222  }
   223  
   224  // Sign signs the record with the given private key. It updates the record's identity
   225  // scheme, public key and increments the sequence number. Sign returns an error if the
   226  // encoded record is larger than the size limit.
   227  func (r *Record) Sign(privkey *ecdsa.PrivateKey) error {
   228  	r.seq = r.seq + 1
   229  	r.Set(ID_SECP256k1_KECCAK)
   230  	r.Set(Secp256k1(privkey.PublicKey))
   231  	return r.signAndEncode(privkey)
   232  }
   233  
   234  func (r *Record) appendPairs(list []interface{}) []interface{} {
   235  	list = append(list, r.seq)
   236  	for _, p := range r.pairs {
   237  		list = append(list, p.k, p.v)
   238  	}
   239  	return list
   240  }
   241  
   242  func (r *Record) signAndEncode(privkey *ecdsa.PrivateKey) error {
   243  	// Put record elements into a flat list. Leave room for the signature.
   244  	list := make([]interface{}, 1, len(r.pairs)*2+2)
   245  	list = r.appendPairs(list)
   246  
   247  	// Sign the tail of the list.
   248  	h := sha3.NewLegacyKeccak256()
   249  	rlp.Encode(h, list[1:])
   250  	sig, err := crypto.Sign(h.Sum(nil), privkey)
   251  	if err != nil {
   252  		return err
   253  	}
   254  	sig = sig[:len(sig)-1] // remove v
   255  
   256  	// Put signature in front.
   257  	r.signature, list[0] = sig, sig
   258  	r.raw, err = rlp.EncodeToBytes(list)
   259  	if err != nil {
   260  		return err
   261  	}
   262  	if len(r.raw) > SizeLimit {
   263  		return errTooBig
   264  	}
   265  	return nil
   266  }
   267  
   268  func (r *Record) verifySignature() error {
   269  	// Get identity scheme, public key, signature.
   270  	var id ID
   271  	var entry s256raw
   272  	if err := r.Load(&id); err != nil {
   273  		return err
   274  	} else if id != ID_SECP256k1_KECCAK {
   275  		return errNoID
   276  	}
   277  	if err := r.Load(&entry); err != nil {
   278  		return err
   279  	} else if len(entry) != 33 {
   280  		return fmt.Errorf("invalid public key")
   281  	}
   282  
   283  	// Verify the signature.
   284  	list := make([]interface{}, 0, len(r.pairs)*2+1)
   285  	list = r.appendPairs(list)
   286  	h := sha3.NewLegacyKeccak256()
   287  	rlp.Encode(h, list)
   288  	if !crypto.VerifySignature(entry, h.Sum(nil), r.signature) {
   289  		return errInvalidSig
   290  	}
   291  	return nil
   292  }