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.

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