github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/p2p/key.go (about)

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