You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
4.3 KiB

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