github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/crypto/sr25519/privkey.go (about)

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