idscheme.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. package enr
  17. import (
  18. "crypto/ecdsa"
  19. "fmt"
  20. "sync"
  21. "github.com/ethereum/go-ethereum/common/math"
  22. "github.com/ethereum/go-ethereum/crypto"
  23. "github.com/ethereum/go-ethereum/crypto/sha3"
  24. "github.com/ethereum/go-ethereum/rlp"
  25. )
  26. // Registry of known identity schemes.
  27. var schemes sync.Map
  28. // An IdentityScheme is capable of verifying record signatures and
  29. // deriving node addresses.
  30. type IdentityScheme interface {
  31. Verify(r *Record, sig []byte) error
  32. NodeAddr(r *Record) []byte
  33. }
  34. // RegisterIdentityScheme adds an identity scheme to the global registry.
  35. func RegisterIdentityScheme(name string, scheme IdentityScheme) {
  36. if _, loaded := schemes.LoadOrStore(name, scheme); loaded {
  37. panic("identity scheme " + name + " already registered")
  38. }
  39. }
  40. // FindIdentityScheme resolves name to an identity scheme in the global registry.
  41. func FindIdentityScheme(name string) IdentityScheme {
  42. s, ok := schemes.Load(name)
  43. if !ok {
  44. return nil
  45. }
  46. return s.(IdentityScheme)
  47. }
  48. // v4ID is the "v4" identity scheme.
  49. type v4ID struct{}
  50. func init() {
  51. RegisterIdentityScheme("v4", v4ID{})
  52. }
  53. // SignV4 signs a record using the v4 scheme.
  54. func SignV4(r *Record, privkey *ecdsa.PrivateKey) error {
  55. // Copy r to avoid modifying it if signing fails.
  56. cpy := *r
  57. cpy.Set(ID("v4"))
  58. cpy.Set(Secp256k1(privkey.PublicKey))
  59. h := sha3.NewKeccak256()
  60. rlp.Encode(h, cpy.AppendElements(nil))
  61. sig, err := crypto.Sign(h.Sum(nil), privkey)
  62. if err != nil {
  63. return err
  64. }
  65. sig = sig[:len(sig)-1] // remove v
  66. if err = cpy.SetSig("v4", sig); err == nil {
  67. *r = cpy
  68. }
  69. return err
  70. }
  71. // s256raw is an unparsed secp256k1 public key entry.
  72. type s256raw []byte
  73. func (s256raw) ENRKey() string { return "secp256k1" }
  74. func (v4ID) Verify(r *Record, sig []byte) error {
  75. var entry s256raw
  76. if err := r.Load(&entry); err != nil {
  77. return err
  78. } else if len(entry) != 33 {
  79. return fmt.Errorf("invalid public key")
  80. }
  81. h := sha3.NewKeccak256()
  82. rlp.Encode(h, r.AppendElements(nil))
  83. if !crypto.VerifySignature(entry, h.Sum(nil), sig) {
  84. return errInvalidSig
  85. }
  86. return nil
  87. }
  88. func (v4ID) NodeAddr(r *Record) []byte {
  89. var pubkey Secp256k1
  90. err := r.Load(&pubkey)
  91. if err != nil {
  92. return nil
  93. }
  94. buf := make([]byte, 64)
  95. math.ReadBits(pubkey.X, buf[:32])
  96. math.ReadBits(pubkey.Y, buf[32:])
  97. return crypto.Keccak256(buf)
  98. }