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