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.

141 lines
4.2 KiB

  1. package secp256k1
  2. import (
  3. "bytes"
  4. "crypto/sha256"
  5. "crypto/subtle"
  6. "fmt"
  7. "io"
  8. "golang.org/x/crypto/ripemd160"
  9. secp256k1 "github.com/btcsuite/btcd/btcec"
  10. amino "github.com/tendermint/go-amino"
  11. "github.com/tendermint/tendermint/crypto"
  12. )
  13. //-------------------------------------
  14. const (
  15. PrivKeyAminoName = "tendermint/PrivKeySecp256k1"
  16. PubKeyAminoName = "tendermint/PubKeySecp256k1"
  17. )
  18. var cdc = amino.NewCodec()
  19. func init() {
  20. cdc.RegisterInterface((*crypto.PubKey)(nil), nil)
  21. cdc.RegisterConcrete(PubKeySecp256k1{},
  22. PubKeyAminoName, nil)
  23. cdc.RegisterInterface((*crypto.PrivKey)(nil), nil)
  24. cdc.RegisterConcrete(PrivKeySecp256k1{},
  25. PrivKeyAminoName, nil)
  26. }
  27. //-------------------------------------
  28. var _ crypto.PrivKey = PrivKeySecp256k1{}
  29. // PrivKeySecp256k1 implements PrivKey.
  30. type PrivKeySecp256k1 [32]byte
  31. // Bytes marshalls the private key using amino encoding.
  32. func (privKey PrivKeySecp256k1) Bytes() []byte {
  33. return cdc.MustMarshalBinaryBare(privKey)
  34. }
  35. // PubKey performs the point-scalar multiplication from the privKey on the
  36. // generator point to get the pubkey.
  37. func (privKey PrivKeySecp256k1) PubKey() crypto.PubKey {
  38. _, pubkeyObject := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
  39. var pubkeyBytes PubKeySecp256k1
  40. copy(pubkeyBytes[:], pubkeyObject.SerializeCompressed())
  41. return pubkeyBytes
  42. }
  43. // Equals - you probably don't need to use this.
  44. // Runs in constant time based on length of the keys.
  45. func (privKey PrivKeySecp256k1) Equals(other crypto.PrivKey) bool {
  46. if otherSecp, ok := other.(PrivKeySecp256k1); ok {
  47. return subtle.ConstantTimeCompare(privKey[:], otherSecp[:]) == 1
  48. }
  49. return false
  50. }
  51. // GenPrivKey generates a new ECDSA private key on curve secp256k1 private key.
  52. // It uses OS randomness in conjunction with the current global random seed
  53. // in tendermint/libs/common 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. privKeyBytes := [32]byte{}
  60. _, err := io.ReadFull(rand, privKeyBytes[:])
  61. if err != nil {
  62. panic(err)
  63. }
  64. // crypto.CRandBytes is guaranteed to be 32 bytes long, so it can be
  65. // casted to PrivKeySecp256k1.
  66. return PrivKeySecp256k1(privKeyBytes)
  67. }
  68. // GenPrivKeySecp256k1 hashes the secret with SHA2, and uses
  69. // that 32 byte output to create the private key.
  70. // NOTE: secret should be the output of a KDF like bcrypt,
  71. // if it's derived from user input.
  72. func GenPrivKeySecp256k1(secret []byte) PrivKeySecp256k1 {
  73. privKey32 := sha256.Sum256(secret)
  74. // sha256.Sum256() is guaranteed to be 32 bytes long, so it can be
  75. // casted to PrivKeySecp256k1.
  76. return PrivKeySecp256k1(privKey32)
  77. }
  78. //-------------------------------------
  79. var _ crypto.PubKey = PubKeySecp256k1{}
  80. // PubKeySecp256k1Size is comprised of 32 bytes for one field element
  81. // (the x-coordinate), plus one byte for the parity of the y-coordinate.
  82. const PubKeySecp256k1Size = 33
  83. // PubKeySecp256k1 implements crypto.PubKey.
  84. // It is the compressed form of the pubkey. The first byte depends is a 0x02 byte
  85. // if the y-coordinate is the lexicographically largest of the two associated with
  86. // the x-coordinate. Otherwise the first byte is a 0x03.
  87. // This prefix is followed with the x-coordinate.
  88. type PubKeySecp256k1 [PubKeySecp256k1Size]byte
  89. // Address returns a Bitcoin style addresses: RIPEMD160(SHA256(pubkey))
  90. func (pubKey PubKeySecp256k1) Address() crypto.Address {
  91. hasherSHA256 := sha256.New()
  92. hasherSHA256.Write(pubKey[:]) // does not error
  93. sha := hasherSHA256.Sum(nil)
  94. hasherRIPEMD160 := ripemd160.New()
  95. hasherRIPEMD160.Write(sha) // does not error
  96. return crypto.Address(hasherRIPEMD160.Sum(nil))
  97. }
  98. // Bytes returns the pubkey marshalled with amino encoding.
  99. func (pubKey PubKeySecp256k1) Bytes() []byte {
  100. bz, err := cdc.MarshalBinaryBare(pubKey)
  101. if err != nil {
  102. panic(err)
  103. }
  104. return bz
  105. }
  106. func (pubKey PubKeySecp256k1) String() string {
  107. return fmt.Sprintf("PubKeySecp256k1{%X}", pubKey[:])
  108. }
  109. func (pubKey PubKeySecp256k1) Equals(other crypto.PubKey) bool {
  110. if otherSecp, ok := other.(PubKeySecp256k1); ok {
  111. return bytes.Equal(pubKey[:], otherSecp[:])
  112. }
  113. return false
  114. }