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.

112 lines
3.1 KiB

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