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  }