github.com/aquanetwork/aquachain@v1.7.8/p2p/enr/enr.go (about)

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