github.com/aakash4dev/cometbft@v0.38.2/crypto/sr25519/privkey.go (about)

     1  package sr25519
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/oasisprotocol/curve25519-voi/primitives/sr25519"
     9  
    10  	"github.com/aakash4dev/cometbft/crypto"
    11  )
    12  
    13  var (
    14  	_ crypto.PrivKey = PrivKey{}
    15  
    16  	signingCtx = sr25519.NewSigningContext([]byte{})
    17  )
    18  
    19  const (
    20  	// PrivKeySize is the number of bytes in an Sr25519 private key.
    21  	PrivKeySize = 32
    22  
    23  	KeyType = "sr25519"
    24  )
    25  
    26  // PrivKey implements crypto.PrivKey.
    27  type PrivKey struct {
    28  	msk sr25519.MiniSecretKey
    29  	kp  *sr25519.KeyPair
    30  }
    31  
    32  // Bytes returns the byte representation of the PrivKey.
    33  func (privKey PrivKey) Bytes() []byte {
    34  	if privKey.kp == nil {
    35  		return nil
    36  	}
    37  	return privKey.msk[:]
    38  }
    39  
    40  // Sign produces a signature on the provided message.
    41  func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
    42  	if privKey.kp == nil {
    43  		return nil, fmt.Errorf("sr25519: uninitialized private key")
    44  	}
    45  
    46  	st := signingCtx.NewTranscriptBytes(msg)
    47  
    48  	sig, err := privKey.kp.Sign(crypto.CReader(), st)
    49  	if err != nil {
    50  		return nil, fmt.Errorf("sr25519: failed to sign message: %w", err)
    51  	}
    52  
    53  	sigBytes, err := sig.MarshalBinary()
    54  	if err != nil {
    55  		return nil, fmt.Errorf("sr25519: failed to serialize signature: %w", err)
    56  	}
    57  
    58  	return sigBytes, nil
    59  }
    60  
    61  // PubKey gets the corresponding public key from the private key.
    62  func (privKey PrivKey) PubKey() crypto.PubKey {
    63  	if privKey.kp == nil {
    64  		panic("sr25519: uninitialized private key")
    65  	}
    66  
    67  	b, err := privKey.kp.PublicKey().MarshalBinary()
    68  	if err != nil {
    69  		panic("sr25519: failed to serialize public key: " + err.Error())
    70  	}
    71  
    72  	return PubKey(b)
    73  }
    74  
    75  // Equals - you probably don't need to use this.
    76  // Runs in constant time based on length of the keys.
    77  func (privKey PrivKey) Equals(other crypto.PrivKey) bool {
    78  	if otherSr, ok := other.(PrivKey); ok {
    79  		return privKey.msk.Equal(&otherSr.msk)
    80  	}
    81  	return false
    82  }
    83  
    84  func (privKey PrivKey) Type() string {
    85  	return KeyType
    86  }
    87  
    88  func (privKey PrivKey) MarshalJSON() ([]byte, error) {
    89  	var b []byte
    90  
    91  	// Handle uninitialized private keys gracefully.
    92  	if privKey.kp != nil {
    93  		b = privKey.Bytes()
    94  	}
    95  
    96  	return json.Marshal(b)
    97  }
    98  
    99  func (privKey *PrivKey) UnmarshalJSON(data []byte) error {
   100  	for i := range privKey.msk {
   101  		privKey.msk[i] = 0
   102  	}
   103  	privKey.kp = nil
   104  
   105  	var b []byte
   106  	if err := json.Unmarshal(data, &b); err != nil {
   107  		return fmt.Errorf("sr25519: failed to deserialize JSON: %w", err)
   108  	}
   109  	if len(b) == 0 {
   110  		return nil
   111  	}
   112  
   113  	msk, err := sr25519.NewMiniSecretKeyFromBytes(b)
   114  	if err != nil {
   115  		return err
   116  	}
   117  
   118  	sk := msk.ExpandEd25519()
   119  
   120  	privKey.msk = *msk
   121  	privKey.kp = sk.KeyPair()
   122  
   123  	return nil
   124  }
   125  
   126  // GenPrivKey generates a new sr25519 private key.
   127  // It uses OS randomness in conjunction with the current global random seed
   128  // in cometbft/libs/rand to generate the private key.
   129  func GenPrivKey() PrivKey {
   130  	return genPrivKey(crypto.CReader())
   131  }
   132  
   133  // genPrivKey generates a new sr25519 private key using the provided reader.
   134  func genPrivKey(rng io.Reader) PrivKey {
   135  	msk, err := sr25519.GenerateMiniSecretKey(rng)
   136  	if err != nil {
   137  		panic("sr25519: failed to generate MiniSecretKey: " + err.Error())
   138  	}
   139  
   140  	sk := msk.ExpandEd25519()
   141  
   142  	return PrivKey{
   143  		msk: *msk,
   144  		kp:  sk.KeyPair(),
   145  	}
   146  }
   147  
   148  // GenPrivKeyFromSecret hashes the secret with SHA2, and uses
   149  // that 32 byte output to create the private key.
   150  // NOTE: secret should be the output of a KDF like bcrypt,
   151  // if it's derived from user input.
   152  func GenPrivKeyFromSecret(secret []byte) PrivKey {
   153  	seed := crypto.Sha256(secret) // Not Ripemd160 because we want 32 bytes.
   154  
   155  	var privKey PrivKey
   156  	if err := privKey.msk.UnmarshalBinary(seed); err != nil {
   157  		panic("sr25519: failed to deserialize MiniSecretKey: " + err.Error())
   158  	}
   159  
   160  	sk := privKey.msk.ExpandEd25519()
   161  	privKey.kp = sk.KeyPair()
   162  
   163  	return privKey
   164  }