github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/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/line/ostracon/crypto"
    15  	tmjson "github.com/line/ostracon/libs/json"
    16  )
    17  
    18  //-------------------------------------
    19  const (
    20  	PrivKeyName = "tendermint/PrivKeySecp256k1"
    21  	PubKeyName  = "tendermint/PubKeySecp256k1"
    22  
    23  	KeyType     = "secp256k1"
    24  	PrivKeySize = 32
    25  )
    26  
    27  func init() {
    28  	tmjson.RegisterType(PubKey{}, PubKeyName)
    29  	tmjson.RegisterType(PrivKey{}, PrivKeyName)
    30  }
    31  
    32  var _ crypto.PrivKey = PrivKey{}
    33  
    34  // PrivKey implements PrivKey.
    35  type PrivKey []byte
    36  
    37  // Bytes marshalls the private key using amino encoding.
    38  func (privKey PrivKey) Bytes() []byte {
    39  	return []byte(privKey)
    40  }
    41  
    42  // VRFProve is not supported in Secp256k1.
    43  func (privKey PrivKey) VRFProve(seed []byte) (crypto.Proof, error) {
    44  	return nil, fmt.Errorf("VRF prove is not supported by the secp256k1")
    45  }
    46  
    47  // PubKey performs the point-scalar multiplication from the privKey on the
    48  // generator point to get the pubkey.
    49  func (privKey PrivKey) PubKey() crypto.PubKey {
    50  	_, pubkeyObject := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey)
    51  
    52  	pk := pubkeyObject.SerializeCompressed()
    53  
    54  	return PubKey(pk)
    55  }
    56  
    57  // Equals - you probably don't need to use this.
    58  // Runs in constant time based on length of the keys.
    59  func (privKey PrivKey) Equals(other crypto.PrivKey) bool {
    60  	if otherSecp, ok := other.(PrivKey); ok {
    61  		return subtle.ConstantTimeCompare(privKey[:], otherSecp[:]) == 1
    62  	}
    63  	return false
    64  }
    65  
    66  func (privKey PrivKey) Type() string {
    67  	return KeyType
    68  }
    69  
    70  // GenPrivKey generates a new ECDSA private key on curve secp256k1 private key.
    71  // It uses OS randomness to generate the private key.
    72  func GenPrivKey() PrivKey {
    73  	return genPrivKey(crypto.CReader())
    74  }
    75  
    76  // genPrivKey generates a new secp256k1 private key using the provided reader.
    77  func genPrivKey(rand io.Reader) PrivKey {
    78  	var privKeyBytes [PrivKeySize]byte
    79  	d := new(big.Int)
    80  
    81  	for {
    82  		privKeyBytes = [PrivKeySize]byte{}
    83  		_, err := io.ReadFull(rand, privKeyBytes[:])
    84  		if err != nil {
    85  			panic(err)
    86  		}
    87  
    88  		d.SetBytes(privKeyBytes[:])
    89  		// break if we found a valid point (i.e. > 0 and < N == curverOrder)
    90  		isValidFieldElement := 0 < d.Sign() && d.Cmp(secp256k1.S256().N) < 0
    91  		if isValidFieldElement {
    92  			break
    93  		}
    94  	}
    95  
    96  	return PrivKey(privKeyBytes[:])
    97  }
    98  
    99  var one = new(big.Int).SetInt64(1)
   100  
   101  // GenPrivKeySecp256k1 hashes the secret with SHA2, and uses
   102  // that 32 byte output to create the private key.
   103  //
   104  // It makes sure the private key is a valid field element by setting:
   105  //
   106  // c = sha256(secret)
   107  // k = (c mod (n − 1)) + 1, where n = curve order.
   108  //
   109  // NOTE: secret should be the output of a KDF like bcrypt,
   110  // if it's derived from user input.
   111  func GenPrivKeySecp256k1(secret []byte) PrivKey {
   112  	secHash := sha256.Sum256(secret)
   113  	// to guarantee that we have a valid field element, we use the approach of:
   114  	// "Suite B Implementer’s Guide to FIPS 186-3", A.2.1
   115  	// https://apps.nsa.gov/iaarchive/library/ia-guidance/ia-solutions-for-classified/algorithm-guidance/suite-b-implementers-guide-to-fips-186-3-ecdsa.cfm
   116  	// see also https://github.com/golang/go/blob/0380c9ad38843d523d9c9804fe300cb7edd7cd3c/src/crypto/ecdsa/ecdsa.go#L89-L101
   117  	fe := new(big.Int).SetBytes(secHash[:])
   118  	n := new(big.Int).Sub(secp256k1.S256().N, one)
   119  	fe.Mod(fe, n)
   120  	fe.Add(fe, one)
   121  
   122  	feB := fe.Bytes()
   123  	privKey32 := make([]byte, PrivKeySize)
   124  	// copy feB over to fixed 32 byte privKey32 and pad (if necessary)
   125  	copy(privKey32[32-len(feB):32], feB)
   126  
   127  	return PrivKey(privKey32)
   128  }
   129  
   130  // used to reject malleable signatures
   131  // see:
   132  //  - https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/signature_nocgo.go#L90-L93
   133  //  - https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/crypto.go#L39
   134  var secp256k1halfN = new(big.Int).Rsh(secp256k1.S256().N, 1)
   135  
   136  // Sign creates an ECDSA signature on curve Secp256k1, using SHA256 on the msg.
   137  // The returned signature will be of the form R || S (in lower-S form).
   138  func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
   139  	priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey)
   140  
   141  	sig, err := priv.Sign(crypto.Sha256(msg))
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	sigBytes := serializeSig(sig)
   147  	return sigBytes, nil
   148  }
   149  
   150  //-------------------------------------
   151  
   152  var _ crypto.PubKey = PubKey{}
   153  
   154  // PubKeySize is comprised of 32 bytes for one field element
   155  // (the x-coordinate), plus one byte for the parity of the y-coordinate.
   156  const PubKeySize = 33
   157  
   158  // PubKey implements crypto.PubKey.
   159  // It is the compressed form of the pubkey. The first byte depends is a 0x02 byte
   160  // if the y-coordinate is the lexicographically largest of the two associated with
   161  // the x-coordinate. Otherwise the first byte is a 0x03.
   162  // This prefix is followed with the x-coordinate.
   163  type PubKey []byte
   164  
   165  // Address returns a Bitcoin style addresses: RIPEMD160(SHA256(pubkey))
   166  func (pubKey PubKey) Address() crypto.Address {
   167  	if len(pubKey) != PubKeySize {
   168  		panic("length of pubkey is incorrect")
   169  	}
   170  	hasherSHA256 := sha256.New()
   171  	_, _ = hasherSHA256.Write(pubKey) // does not error
   172  	sha := hasherSHA256.Sum(nil)
   173  
   174  	hasherRIPEMD160 := ripemd160.New()
   175  	_, _ = hasherRIPEMD160.Write(sha) // does not error
   176  
   177  	return crypto.Address(hasherRIPEMD160.Sum(nil))
   178  }
   179  
   180  // Bytes returns the pubkey marshaled with amino encoding.
   181  func (pubKey PubKey) Bytes() []byte {
   182  	return []byte(pubKey)
   183  }
   184  
   185  func (pubKey PubKey) String() string {
   186  	return fmt.Sprintf("PubKeySecp256k1{%X}", []byte(pubKey))
   187  }
   188  
   189  // VRFVerify is not supported in Secp256k1.
   190  func (pubKey PubKey) VRFVerify(proof crypto.Proof, seed []byte) (crypto.Output, error) {
   191  	return nil, fmt.Errorf("VRF verify is not supported by the secp256k1")
   192  }
   193  
   194  func (pubKey PubKey) Equals(other crypto.PubKey) bool {
   195  	if otherSecp, ok := other.(PubKey); ok {
   196  		return bytes.Equal(pubKey[:], otherSecp[:])
   197  	}
   198  	return false
   199  }
   200  
   201  func (pubKey PubKey) Type() string {
   202  	return KeyType
   203  }
   204  
   205  // VerifySignature verifies a signature of the form R || S.
   206  // It rejects signatures which are not in lower-S form.
   207  func (pubKey PubKey) VerifySignature(msg []byte, sigStr []byte) bool {
   208  	if len(sigStr) != 64 {
   209  		return false
   210  	}
   211  
   212  	pub, err := secp256k1.ParsePubKey(pubKey, secp256k1.S256())
   213  	if err != nil {
   214  		return false
   215  	}
   216  
   217  	// parse the signature:
   218  	signature := signatureFromBytes(sigStr)
   219  	// Reject malleable signatures. libsecp256k1 does this check but btcec doesn't.
   220  	// see: https://github.com/ethereum/go-ethereum/blob/f9401ae011ddf7f8d2d95020b7446c17f8d98dc1/crypto/signature_nocgo.go#L90-L93
   221  	if signature.S.Cmp(secp256k1halfN) > 0 {
   222  		return false
   223  	}
   224  
   225  	return signature.Verify(crypto.Sha256(msg), pub)
   226  }
   227  
   228  // Read Signature struct from R || S. Caller needs to ensure
   229  // that len(sigStr) == 64.
   230  func signatureFromBytes(sigStr []byte) *secp256k1.Signature {
   231  	return &secp256k1.Signature{
   232  		R: new(big.Int).SetBytes(sigStr[:32]),
   233  		S: new(big.Int).SetBytes(sigStr[32:64]),
   234  	}
   235  }
   236  
   237  // Serialize signature to R || S.
   238  // R, S are padded to 32 bytes respectively.
   239  func serializeSig(sig *secp256k1.Signature) []byte {
   240  	rBytes := sig.R.Bytes()
   241  	sBytes := sig.S.Bytes()
   242  	sigBytes := make([]byte, 64)
   243  	// 0 pad the byte arrays from the left if they aren't big enough.
   244  	copy(sigBytes[32-len(rBytes):32], rBytes)
   245  	copy(sigBytes[64-len(sBytes):64], sBytes)
   246  	return sigBytes
   247  }