github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/crypto/secp256k1/secp256k1.go (about)

     1  package secp256k1
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/sha256"
     6  	"crypto/subtle"
     7  	"fmt"
     8  	"io"
     9  	"math/big"
    10  
    11  	secp256k1 "github.com/btcsuite/btcd/btcec"
    12  	"golang.org/x/crypto/ripemd160" // nolint: staticcheck // necessary for Bitcoin address format
    13  
    14  	"github.com/tendermint/tendermint/crypto"
    15  )
    16  
    17  var _ crypto.PrivKey = PrivKey{}
    18  
    19  const (
    20  	PrivKeySize = 32
    21  	keyType     = "secp256k1"
    22  )
    23  
    24  // PrivKey implements PrivKey.
    25  type PrivKey []byte
    26  
    27  // Bytes returns the byte representation of the Private Key.
    28  func (privKey PrivKey) Bytes() []byte {
    29  	return []byte(privKey)
    30  }
    31  
    32  // PubKey performs the point-scalar multiplication from the privKey on the
    33  // generator point to get the pubkey.
    34  func (privKey PrivKey) PubKey() crypto.PubKey {
    35  	_, pubkeyObject := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey)
    36  	return PubKey(pubkeyObject.SerializeCompressed())
    37  }
    38  
    39  // Equals - you probably don't need to use this.
    40  // Runs in constant time based on length of the keys.
    41  func (privKey PrivKey) Equals(other crypto.PrivKey) bool {
    42  	if otherSecp, ok := other.(PrivKey); ok {
    43  		return subtle.ConstantTimeCompare(privKey[:], otherSecp[:]) == 1
    44  	}
    45  	return false
    46  }
    47  
    48  func (privKey PrivKey) Type() string {
    49  	return keyType
    50  }
    51  
    52  // GenPrivKey generates a new ECDSA private key on curve secp256k1 private key.
    53  // It uses OS randomness to generate the private key.
    54  func GenPrivKey() PrivKey {
    55  	return genPrivKey(crypto.CReader())
    56  }
    57  
    58  // genPrivKey generates a new secp256k1 private key using the provided reader.
    59  func genPrivKey(rand io.Reader) PrivKey {
    60  	var privKeyBytes [PrivKeySize]byte
    61  	d := new(big.Int)
    62  	for {
    63  		privKeyBytes = [PrivKeySize]byte{}
    64  		_, err := io.ReadFull(rand, privKeyBytes[:])
    65  		if err != nil {
    66  			panic(err)
    67  		}
    68  
    69  		d.SetBytes(privKeyBytes[:])
    70  		// break if we found a valid point (i.e. > 0 and < N == curverOrder)
    71  		isValidFieldElement := 0 < d.Sign() && d.Cmp(secp256k1.S256().N) < 0
    72  		if isValidFieldElement {
    73  			break
    74  		}
    75  	}
    76  
    77  	return PrivKey(privKeyBytes[:])
    78  }
    79  
    80  var one = new(big.Int).SetInt64(1)
    81  
    82  // GenPrivKeySecp256k1 hashes the secret with SHA2, and uses
    83  // that 32 byte output to create the private key.
    84  //
    85  // It makes sure the private key is a valid field element by setting:
    86  //
    87  // c = sha256(secret)
    88  // k = (c mod (n − 1)) + 1, where n = curve order.
    89  //
    90  // NOTE: secret should be the output of a KDF like bcrypt,
    91  // if it's derived from user input.
    92  func GenPrivKeySecp256k1(secret []byte) PrivKey {
    93  	secHash := sha256.Sum256(secret)
    94  	// to guarantee that we have a valid field element, we use the approach of:
    95  	// "Suite B Implementer’s Guide to FIPS 186-3", A.2.1
    96  	// https://apps.nsa.gov/iaarchive/library/ia-guidance/ia-solutions-for-classified/algorithm-guidance/suite-b-implementers-guide-to-fips-186-3-ecdsa.cfm
    97  	// see also https://github.com/golang/go/blob/0380c9ad38843d523d9c9804fe300cb7edd7cd3c/src/crypto/ecdsa/ecdsa.go#L89-L101
    98  	fe := new(big.Int).SetBytes(secHash[:])
    99  	n := new(big.Int).Sub(secp256k1.S256().N, one)
   100  	fe.Mod(fe, n)
   101  	fe.Add(fe, one)
   102  
   103  	feB := fe.Bytes()
   104  	privKey32 := make([]byte, PrivKeySize)
   105  	// copy feB over to fixed 32 byte privKey32 and pad (if necessary)
   106  	copy(privKey32[32-len(feB):32], feB)
   107  
   108  	return PrivKey(privKey32)
   109  }
   110  
   111  //-------------------------------------
   112  
   113  var _ crypto.PubKey = PubKey{}
   114  
   115  // PubKeySize is comprised of 32 bytes for one field element
   116  // (the x-coordinate), plus one byte for the parity of the y-coordinate.
   117  const PubKeySize = 33
   118  
   119  // PubKey implements crypto.PubKey.
   120  // It is the compressed form of the pubkey. The first byte depends is a 0x02 byte
   121  // if the y-coordinate is the lexicographically largest of the two associated with
   122  // the x-coordinate. Otherwise the first byte is a 0x03.
   123  // This prefix is followed with the x-coordinate.
   124  type PubKey []byte
   125  
   126  // Address returns a Bitcoin style addresses: RIPEMD160(SHA256(pubkey))
   127  func (pubKey PubKey) Address() crypto.Address {
   128  	if len(pubKey) != PubKeySize {
   129  		panic("length of pubkey is incorrect")
   130  	}
   131  
   132  	hasherSHA256 := sha256.New()
   133  	hasherSHA256.Write(pubKey) // does not error
   134  	sha := hasherSHA256.Sum(nil)
   135  
   136  	hasherRIPEMD160 := ripemd160.New()
   137  	hasherRIPEMD160.Write(sha) // does not error
   138  	return crypto.Address(hasherRIPEMD160.Sum(nil))
   139  }
   140  
   141  // Bytes returns the pubkey byte format.
   142  func (pubKey PubKey) Bytes() []byte {
   143  	return []byte(pubKey)
   144  }
   145  
   146  func (pubKey PubKey) String() string {
   147  	return fmt.Sprintf("PubKeySecp256k1{%X}", []byte(pubKey))
   148  }
   149  
   150  func (pubKey PubKey) Type() string {
   151  	return keyType
   152  }
   153  
   154  func (pubKey PubKey) Equals(other crypto.PubKey) bool {
   155  	if otherSecp, ok := other.(PubKey); ok {
   156  		return bytes.Equal(pubKey[:], otherSecp[:])
   157  	}
   158  	return false
   159  }