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.

163 lines
4.9 KiB

  1. package secp256k1
  2. import (
  3. "bytes"
  4. "crypto/sha256"
  5. "crypto/subtle"
  6. "fmt"
  7. "io"
  8. secp256k1 "github.com/tendermint/btcd/btcec"
  9. amino "github.com/tendermint/go-amino"
  10. "golang.org/x/crypto/ripemd160"
  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. // Sign creates an ECDSA signature on curve Secp256k1, using SHA256 on the msg.
  36. func (privKey PrivKeySecp256k1) Sign(msg []byte) ([]byte, error) {
  37. priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
  38. sig, err := priv.Sign(crypto.Sha256(msg))
  39. if err != nil {
  40. return nil, err
  41. }
  42. return sig.Serialize(), nil
  43. }
  44. // PubKey performs the point-scalar multiplication from the privKey on the
  45. // generator point to get the pubkey.
  46. func (privKey PrivKeySecp256k1) PubKey() crypto.PubKey {
  47. _, pubkeyObject := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:])
  48. var pubkeyBytes PubKeySecp256k1
  49. copy(pubkeyBytes[:], pubkeyObject.SerializeCompressed())
  50. return pubkeyBytes
  51. }
  52. // Equals - you probably don't need to use this.
  53. // Runs in constant time based on length of the keys.
  54. func (privKey PrivKeySecp256k1) Equals(other crypto.PrivKey) bool {
  55. if otherSecp, ok := other.(PrivKeySecp256k1); ok {
  56. return subtle.ConstantTimeCompare(privKey[:], otherSecp[:]) == 1
  57. }
  58. return false
  59. }
  60. // GenPrivKey generates a new ECDSA private key on curve secp256k1 private key.
  61. // It uses OS randomness in conjunction with the current global random seed
  62. // in tendermint/libs/common to generate the private key.
  63. func GenPrivKey() PrivKeySecp256k1 {
  64. return genPrivKey(crypto.CReader())
  65. }
  66. // genPrivKey generates a new secp256k1 private key using the provided reader.
  67. func genPrivKey(rand io.Reader) PrivKeySecp256k1 {
  68. privKeyBytes := [32]byte{}
  69. _, err := io.ReadFull(rand, privKeyBytes[:])
  70. if err != nil {
  71. panic(err)
  72. }
  73. // crypto.CRandBytes is guaranteed to be 32 bytes long, so it can be
  74. // casted to PrivKeySecp256k1.
  75. return PrivKeySecp256k1(privKeyBytes)
  76. }
  77. // GenPrivKeySecp256k1 hashes the secret with SHA2, and uses
  78. // that 32 byte output to create the private key.
  79. // NOTE: secret should be the output of a KDF like bcrypt,
  80. // if it's derived from user input.
  81. func GenPrivKeySecp256k1(secret []byte) PrivKeySecp256k1 {
  82. privKey32 := sha256.Sum256(secret)
  83. // sha256.Sum256() is guaranteed to be 32 bytes long, so it can be
  84. // casted to PrivKeySecp256k1.
  85. return PrivKeySecp256k1(privKey32)
  86. }
  87. //-------------------------------------
  88. var _ crypto.PubKey = PubKeySecp256k1{}
  89. // PubKeySecp256k1Size is comprised of 32 bytes for one field element
  90. // (the x-coordinate), plus one byte for the parity of the y-coordinate.
  91. const PubKeySecp256k1Size = 33
  92. // PubKeySecp256k1 implements crypto.PubKey.
  93. // It is the compressed form of the pubkey. The first byte depends is a 0x02 byte
  94. // if the y-coordinate is the lexicographically largest of the two associated with
  95. // the x-coordinate. Otherwise the first byte is a 0x03.
  96. // This prefix is followed with the x-coordinate.
  97. type PubKeySecp256k1 [PubKeySecp256k1Size]byte
  98. // Address returns a Bitcoin style addresses: RIPEMD160(SHA256(pubkey))
  99. func (pubKey PubKeySecp256k1) Address() crypto.Address {
  100. hasherSHA256 := sha256.New()
  101. hasherSHA256.Write(pubKey[:]) // does not error
  102. sha := hasherSHA256.Sum(nil)
  103. hasherRIPEMD160 := ripemd160.New()
  104. hasherRIPEMD160.Write(sha) // does not error
  105. return crypto.Address(hasherRIPEMD160.Sum(nil))
  106. }
  107. // Bytes returns the pubkey marshalled with amino encoding.
  108. func (pubKey PubKeySecp256k1) Bytes() []byte {
  109. bz, err := cdc.MarshalBinaryBare(pubKey)
  110. if err != nil {
  111. panic(err)
  112. }
  113. return bz
  114. }
  115. func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig []byte) bool {
  116. pub, err := secp256k1.ParsePubKey(pubKey[:], secp256k1.S256())
  117. if err != nil {
  118. return false
  119. }
  120. parsedSig, err := secp256k1.ParseSignature(sig[:], secp256k1.S256())
  121. if err != nil {
  122. return false
  123. }
  124. // Underlying library ensures that this signature is in canonical form, to
  125. // prevent Secp256k1 malleability from altering the sign of the s term.
  126. return parsedSig.Verify(crypto.Sha256(msg), pub)
  127. }
  128. func (pubKey PubKeySecp256k1) String() string {
  129. return fmt.Sprintf("PubKeySecp256k1{%X}", pubKey[:])
  130. }
  131. func (pubKey PubKeySecp256k1) Equals(other crypto.PubKey) bool {
  132. if otherSecp, ok := other.(PubKeySecp256k1); ok {
  133. return bytes.Equal(pubKey[:], otherSecp[:])
  134. }
  135. return false
  136. }