github.com/Finschia/ostracon@v1.1.5/crypto/sr25519/privkey.go (about)

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