2020-10-06 18:57:55 +00:00
|
|
|
package ethsecp256k1
|
2018-12-18 16:10:04 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/ecdsa"
|
|
|
|
|
|
|
|
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
2020-10-06 18:57:55 +00:00
|
|
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
2018-12-18 16:10:04 +00:00
|
|
|
|
|
|
|
tmcrypto "github.com/tendermint/tendermint/crypto"
|
|
|
|
)
|
|
|
|
|
2020-10-06 18:57:55 +00:00
|
|
|
const (
|
|
|
|
// PrivKeySize defines the size of the PrivKey bytes
|
|
|
|
PrivKeySize = 32
|
|
|
|
// KeyType is the string constant for the EthSecp256k1 algorithm
|
|
|
|
KeyType = "eth_secp256k1"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Amino encoding names
|
|
|
|
const (
|
|
|
|
// PrivKeyName defines the amino encoding name for the EthSecp256k1 private key
|
|
|
|
PrivKeyName = "ethermint/PrivKeyEthSecp256k1"
|
|
|
|
// PubKeyName defines the amino encoding name for the EthSecp256k1 public key
|
|
|
|
PubKeyName = "ethermint/PubKeyEthSecp256k1"
|
|
|
|
)
|
|
|
|
|
2018-12-18 16:10:04 +00:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// secp256k1 Private Key
|
|
|
|
|
2020-10-06 18:57:55 +00:00
|
|
|
var _ tmcrypto.PrivKey = PrivKey{}
|
2018-12-18 16:10:04 +00:00
|
|
|
|
2020-10-06 18:57:55 +00:00
|
|
|
// PrivKey defines a type alias for an ecdsa.PrivateKey that implements
|
2018-12-18 16:10:04 +00:00
|
|
|
// Tendermint's PrivateKey interface.
|
2020-10-06 18:57:55 +00:00
|
|
|
type PrivKey []byte
|
2018-12-18 16:10:04 +00:00
|
|
|
|
|
|
|
// GenerateKey generates a new random private key. It returns an error upon
|
|
|
|
// failure.
|
2020-10-06 18:57:55 +00:00
|
|
|
func GenerateKey() (PrivKey, error) {
|
2018-12-18 16:10:04 +00:00
|
|
|
priv, err := ethcrypto.GenerateKey()
|
|
|
|
if err != nil {
|
2020-10-06 18:57:55 +00:00
|
|
|
return PrivKey{}, err
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
2020-10-06 18:57:55 +00:00
|
|
|
return PrivKey(ethcrypto.FromECDSA(priv)), nil
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// PubKey returns the ECDSA private key's public key.
|
2020-10-06 18:57:55 +00:00
|
|
|
func (privkey PrivKey) PubKey() tmcrypto.PubKey {
|
2019-08-11 14:42:46 +00:00
|
|
|
ecdsaPKey := privkey.ToECDSA()
|
2020-10-06 18:57:55 +00:00
|
|
|
return PubKey(ethcrypto.CompressPubkey(&ecdsaPKey.PublicKey))
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bytes returns the raw ECDSA private key bytes.
|
2020-10-06 18:57:55 +00:00
|
|
|
func (privkey PrivKey) Bytes() []byte {
|
2020-08-11 15:01:15 +00:00
|
|
|
return CryptoCodec.MustMarshalBinaryBare(privkey)
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sign creates a recoverable ECDSA signature on the secp256k1 curve over the
|
|
|
|
// Keccak256 hash of the provided message. The produced signature is 65 bytes
|
|
|
|
// where the last byte contains the recovery ID.
|
2020-10-06 18:57:55 +00:00
|
|
|
func (privkey PrivKey) Sign(msg []byte) ([]byte, error) {
|
2018-12-18 16:10:04 +00:00
|
|
|
return ethcrypto.Sign(ethcrypto.Keccak256Hash(msg).Bytes(), privkey.ToECDSA())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Equals returns true if two ECDSA private keys are equal and false otherwise.
|
2020-10-06 18:57:55 +00:00
|
|
|
func (privkey PrivKey) Equals(other tmcrypto.PrivKey) bool {
|
|
|
|
if other, ok := other.(PrivKey); ok {
|
2018-12-18 16:10:04 +00:00
|
|
|
return bytes.Equal(privkey.Bytes(), other.Bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToECDSA returns the ECDSA private key as a reference to ecdsa.PrivateKey type.
|
2020-09-07 13:04:50 +00:00
|
|
|
// The function will panic if the private key is invalid.
|
2020-10-06 18:57:55 +00:00
|
|
|
func (privkey PrivKey) ToECDSA() *ecdsa.PrivateKey {
|
2020-09-07 13:04:50 +00:00
|
|
|
key, err := ethcrypto.ToECDSA(privkey)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2019-08-11 14:42:46 +00:00
|
|
|
return key
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// secp256k1 Public Key
|
|
|
|
|
2020-10-06 18:57:55 +00:00
|
|
|
var _ tmcrypto.PubKey = (*PubKey)(nil)
|
2018-12-18 16:10:04 +00:00
|
|
|
|
2020-10-06 18:57:55 +00:00
|
|
|
// PubKey defines a type alias for an ecdsa.PublicKey that implements Tendermint's PubKey
|
2020-09-07 13:04:50 +00:00
|
|
|
// interface. It represents the 33-byte compressed public key format.
|
2020-10-06 18:57:55 +00:00
|
|
|
type PubKey []byte
|
2018-12-18 16:10:04 +00:00
|
|
|
|
|
|
|
// Address returns the address of the ECDSA public key.
|
2020-09-07 13:04:50 +00:00
|
|
|
// The function will panic if the public key is invalid.
|
2020-10-06 18:57:55 +00:00
|
|
|
func (key PubKey) Address() tmcrypto.Address {
|
2020-09-07 13:04:50 +00:00
|
|
|
pubk, err := ethcrypto.DecompressPubkey(key)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
2019-08-11 14:42:46 +00:00
|
|
|
return tmcrypto.Address(ethcrypto.PubkeyToAddress(*pubk).Bytes())
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bytes returns the raw bytes of the ECDSA public key.
|
2020-09-07 13:04:50 +00:00
|
|
|
// The function panics if the key cannot be marshaled to bytes.
|
2020-10-06 18:57:55 +00:00
|
|
|
func (key PubKey) Bytes() []byte {
|
2020-08-11 15:01:15 +00:00
|
|
|
bz, err := CryptoCodec.MarshalBinaryBare(key)
|
2019-09-15 16:12:59 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return bz
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// VerifyBytes verifies that the ECDSA public key created a given signature over
|
|
|
|
// the provided message. It will calculate the Keccak256 hash of the message
|
|
|
|
// prior to verification.
|
2020-10-06 18:57:55 +00:00
|
|
|
func (key PubKey) VerifyBytes(msg []byte, sig []byte) bool {
|
2018-12-18 16:10:04 +00:00
|
|
|
if len(sig) == 65 {
|
|
|
|
// remove recovery ID if contained in the signature
|
|
|
|
sig = sig[:len(sig)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
// the signature needs to be in [R || S] format when provided to VerifySignature
|
2020-10-06 18:57:55 +00:00
|
|
|
return secp256k1.VerifySignature(key, ethcrypto.Keccak256Hash(msg).Bytes(), sig)
|
2018-12-18 16:10:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Equals returns true if two ECDSA public keys are equal and false otherwise.
|
2020-10-06 18:57:55 +00:00
|
|
|
func (key PubKey) Equals(other tmcrypto.PubKey) bool {
|
|
|
|
if other, ok := other.(PubKey); ok {
|
2018-12-18 16:10:04 +00:00
|
|
|
return bytes.Equal(key.Bytes(), other.Bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|