github.com/vipernet-xyz/tendermint-core@v0.32.0/crypto/sr25519/privkey.go (about)

     1  package sr25519
     2  
     3  import (
     4  	"crypto/subtle"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/tendermint/tendermint/crypto"
     9  
    10  	schnorrkel "github.com/ChainSafe/go-schnorrkel"
    11  )
    12  
    13  // PrivKeySr25519Size is the number of bytes in an Sr25519 private key.
    14  const PrivKeySr25519Size = 32
    15  
    16  // PrivKeySr25519 implements crypto.PrivKey.
    17  type PrivKeySr25519 [PrivKeySr25519Size]byte
    18  
    19  // Bytes marshals the privkey using amino encoding.
    20  func (privKey PrivKeySr25519) Bytes() []byte {
    21  	return cdc.MustMarshalBinaryBare(privKey)
    22  }
    23  
    24  // Sign produces a signature on the provided message.
    25  func (privKey PrivKeySr25519) Sign(msg []byte) ([]byte, error) {
    26  	miniSecretKey, err := schnorrkel.NewMiniSecretKeyFromRaw(privKey)
    27  	if err != nil {
    28  		return []byte{}, err
    29  	}
    30  	secretKey := miniSecretKey.ExpandEd25519()
    31  
    32  	signingContext := schnorrkel.NewSigningContext([]byte{}, msg)
    33  
    34  	sig, err := secretKey.Sign(signingContext)
    35  	if err != nil {
    36  		return []byte{}, err
    37  	}
    38  
    39  	sigBytes := sig.Encode()
    40  	return sigBytes[:], nil
    41  }
    42  
    43  // PubKey gets the corresponding public key from the private key.
    44  func (privKey PrivKeySr25519) PubKey() crypto.PubKey {
    45  	miniSecretKey, err := schnorrkel.NewMiniSecretKeyFromRaw(privKey)
    46  	if err != nil {
    47  		panic(fmt.Sprintf("Invalid private key: %v", err))
    48  	}
    49  	secretKey := miniSecretKey.ExpandEd25519()
    50  
    51  	pubkey, err := secretKey.Public()
    52  	if err != nil {
    53  		panic(fmt.Sprintf("Could not generate public key: %v", err))
    54  	}
    55  
    56  	return PubKeySr25519(pubkey.Encode())
    57  }
    58  
    59  // Equals - you probably don't need to use this.
    60  // Runs in constant time based on length of the keys.
    61  func (privKey PrivKeySr25519) Equals(other crypto.PrivKey) bool {
    62  	if otherEd, ok := other.(PrivKeySr25519); ok {
    63  		return subtle.ConstantTimeCompare(privKey[:], otherEd[:]) == 1
    64  	}
    65  	return false
    66  }
    67  
    68  // GenPrivKey generates a new sr25519 private key.
    69  // It uses OS randomness in conjunction with the current global random seed
    70  // in tendermint/libs/common to generate the private key.
    71  func GenPrivKey() PrivKeySr25519 {
    72  	return genPrivKey(crypto.CReader())
    73  }
    74  
    75  // genPrivKey generates a new sr25519 private key using the provided reader.
    76  func genPrivKey(rand io.Reader) PrivKeySr25519 {
    77  	var seed [64]byte
    78  
    79  	out := make([]byte, 64)
    80  	_, err := io.ReadFull(rand, out)
    81  	if err != nil {
    82  		panic(err)
    83  	}
    84  
    85  	copy(seed[:], out)
    86  
    87  	return schnorrkel.NewMiniSecretKey(seed).ExpandEd25519().Encode()
    88  }
    89  
    90  // GenPrivKeyFromSecret hashes the secret with SHA2, and uses
    91  // that 32 byte output to create the private key.
    92  // NOTE: secret should be the output of a KDF like bcrypt,
    93  // if it's derived from user input.
    94  func GenPrivKeyFromSecret(secret []byte) PrivKeySr25519 {
    95  	seed := crypto.Sha256(secret) // Not Ripemd160 because we want 32 bytes.
    96  	var bz [PrivKeySr25519Size]byte
    97  	copy(bz[:], seed)
    98  	privKey, _ := schnorrkel.NewMiniSecretKeyFromRaw(bz)
    99  	return privKey.ExpandEd25519().Encode()
   100  }