You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

111 lines
3.0 KiB

  1. package p2p
  2. import (
  3. "bytes"
  4. "encoding/hex"
  5. "fmt"
  6. "io/ioutil"
  7. crypto "github.com/tendermint/go-crypto"
  8. cmn "github.com/tendermint/tmlibs/common"
  9. )
  10. // ID is a hex-encoded crypto.Address
  11. type ID string
  12. // IDByteLength is the length of a crypto.Address. Currently only 20.
  13. // TODO: support other length addresses ?
  14. const IDByteLength = 20
  15. //------------------------------------------------------------------------------
  16. // Persistent peer ID
  17. // TODO: encrypt on disk
  18. // NodeKey is the persistent peer key.
  19. // It contains the nodes private key for authentication.
  20. type NodeKey struct {
  21. PrivKey crypto.PrivKey `json:"priv_key"` // our priv key
  22. }
  23. // ID returns the peer's canonical ID - the hash of its public key.
  24. func (nodeKey *NodeKey) ID() ID {
  25. return PubKeyToID(nodeKey.PubKey())
  26. }
  27. // PubKey returns the peer's PubKey
  28. func (nodeKey *NodeKey) PubKey() crypto.PubKey {
  29. return nodeKey.PrivKey.PubKey()
  30. }
  31. // PubKeyToID returns the ID corresponding to the given PubKey.
  32. // It's the hex-encoding of the pubKey.Address().
  33. func PubKeyToID(pubKey crypto.PubKey) ID {
  34. return ID(hex.EncodeToString(pubKey.Address()))
  35. }
  36. // LoadOrGenNodeKey attempts to load the NodeKey from the given filePath.
  37. // If the file does not exist, it generates and saves a new NodeKey.
  38. func LoadOrGenNodeKey(filePath string) (*NodeKey, error) {
  39. if cmn.FileExists(filePath) {
  40. nodeKey, err := loadNodeKey(filePath)
  41. if err != nil {
  42. return nil, err
  43. }
  44. return nodeKey, nil
  45. }
  46. return genNodeKey(filePath)
  47. }
  48. func loadNodeKey(filePath string) (*NodeKey, error) {
  49. jsonBytes, err := ioutil.ReadFile(filePath)
  50. if err != nil {
  51. return nil, err
  52. }
  53. nodeKey := new(NodeKey)
  54. err = cdc.UnmarshalJSON(jsonBytes, nodeKey)
  55. if err != nil {
  56. return nil, fmt.Errorf("Error reading NodeKey from %v: %v", filePath, err)
  57. }
  58. return nodeKey, nil
  59. }
  60. func genNodeKey(filePath string) (*NodeKey, error) {
  61. privKey := crypto.GenPrivKeyEd25519()
  62. nodeKey := &NodeKey{
  63. PrivKey: privKey,
  64. }
  65. jsonBytes, err := cdc.MarshalJSON(nodeKey)
  66. if err != nil {
  67. return nil, err
  68. }
  69. err = ioutil.WriteFile(filePath, jsonBytes, 0600)
  70. if err != nil {
  71. return nil, err
  72. }
  73. return nodeKey, nil
  74. }
  75. //------------------------------------------------------------------------------
  76. // MakePoWTarget returns the big-endian encoding of 2^(targetBits - difficulty) - 1.
  77. // It can be used as a Proof of Work target.
  78. // NOTE: targetBits must be a multiple of 8 and difficulty must be less than targetBits.
  79. func MakePoWTarget(difficulty, targetBits uint) []byte {
  80. if targetBits%8 != 0 {
  81. panic(fmt.Sprintf("targetBits (%d) not a multiple of 8", targetBits))
  82. }
  83. if difficulty >= targetBits {
  84. panic(fmt.Sprintf("difficulty (%d) >= targetBits (%d)", difficulty, targetBits))
  85. }
  86. targetBytes := targetBits / 8
  87. zeroPrefixLen := (int(difficulty) / 8)
  88. prefix := bytes.Repeat([]byte{0}, zeroPrefixLen)
  89. mod := (difficulty % 8)
  90. if mod > 0 {
  91. nonZeroPrefix := byte(1<<(8-mod) - 1)
  92. prefix = append(prefix, nonZeroPrefix)
  93. }
  94. tailLen := int(targetBytes) - len(prefix)
  95. return append(prefix, bytes.Repeat([]byte{0xFF}, tailLen)...)
  96. }