2020-10-06 18:57:55 +00:00
|
|
|
package hd
|
2020-08-11 15:01:15 +00:00
|
|
|
|
|
|
|
import (
|
2020-09-29 20:10:56 +00:00
|
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
|
|
"github.com/btcsuite/btcutil/hdkeychain"
|
2021-04-17 10:00:07 +00:00
|
|
|
bip39 "github.com/tyler-smith/go-bip39"
|
2020-08-11 15:01:15 +00:00
|
|
|
|
2021-09-03 18:06:36 +00:00
|
|
|
"github.com/ethereum/go-ethereum/accounts"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2020-08-11 15:01:15 +00:00
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/hd"
|
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
|
|
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
2020-10-06 18:57:55 +00:00
|
|
|
|
2022-09-07 06:36:11 +00:00
|
|
|
"github.com/cerc-io/laconicd/crypto/ethsecp256k1"
|
2020-08-11 15:01:15 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2021-04-17 10:00:07 +00:00
|
|
|
// EthSecp256k1Type defines the ECDSA secp256k1 used on Ethereum
|
|
|
|
EthSecp256k1Type = hd.PubKeyType(ethsecp256k1.KeyType)
|
2020-08-11 15:01:15 +00:00
|
|
|
)
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
var (
|
|
|
|
// SupportedAlgorithms defines the list of signing algorithms used on Ethermint:
|
|
|
|
// - eth_secp256k1 (Ethereum)
|
|
|
|
// - secp256k1 (Tendermint)
|
|
|
|
SupportedAlgorithms = keyring.SigningAlgoList{EthSecp256k1, hd.Secp256k1}
|
|
|
|
// SupportedAlgorithmsLedger defines the list of signing algorithms used on Ethermint for the Ledger device:
|
|
|
|
// - eth_secp256k1 (Ethereum)
|
|
|
|
// - secp256k1 (Tendermint)
|
|
|
|
SupportedAlgorithmsLedger = keyring.SigningAlgoList{EthSecp256k1, hd.Secp256k1}
|
|
|
|
)
|
2020-08-11 15:01:15 +00:00
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
// EthSecp256k1Option defines a function keys options for the ethereum Secp256k1 curve.
|
|
|
|
// It supports eth_secp256k1 and secp256k1 keys for accounts.
|
|
|
|
func EthSecp256k1Option() keyring.Option {
|
|
|
|
return func(options *keyring.Options) {
|
|
|
|
options.SupportedAlgos = SupportedAlgorithms
|
|
|
|
options.SupportedAlgosLedger = SupportedAlgorithmsLedger
|
2020-08-11 15:01:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
var (
|
|
|
|
_ keyring.SignatureAlgo = EthSecp256k1
|
2020-08-11 15:01:15 +00:00
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
// EthSecp256k1 uses the Bitcoin secp256k1 ECDSA parameters.
|
|
|
|
EthSecp256k1 = ethSecp256k1Algo{}
|
|
|
|
)
|
|
|
|
|
2021-09-05 11:03:06 +00:00
|
|
|
type ethSecp256k1Algo struct{}
|
2020-08-11 15:01:15 +00:00
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
// Name returns eth_secp256k1
|
|
|
|
func (s ethSecp256k1Algo) Name() hd.PubKeyType {
|
|
|
|
return EthSecp256k1Type
|
|
|
|
}
|
2020-09-29 20:10:56 +00:00
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
// Derive derives and returns the eth_secp256k1 private key for the given mnemonic and HD path.
|
|
|
|
func (s ethSecp256k1Algo) Derive() hd.DeriveFn {
|
2021-09-05 11:03:06 +00:00
|
|
|
return func(mnemonic, bip39Passphrase, path string) ([]byte, error) {
|
2021-09-03 18:06:36 +00:00
|
|
|
hdpath, err := accounts.ParseDerivationPath(path)
|
2021-04-17 10:00:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-11 15:01:15 +00:00
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
seed, err := bip39.NewSeedWithErrorChecking(mnemonic, bip39Passphrase)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-11 15:01:15 +00:00
|
|
|
|
2021-09-07 17:29:24 +00:00
|
|
|
// create a BTC-utils hd-derivation key chain
|
2021-04-17 10:00:07 +00:00
|
|
|
masterKey, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
|
2020-09-29 20:10:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-11 15:01:15 +00:00
|
|
|
|
2021-04-17 10:00:07 +00:00
|
|
|
key := masterKey
|
|
|
|
for _, n := range hdpath {
|
2021-06-09 11:54:08 +00:00
|
|
|
key, err = key.Derive(n)
|
2021-04-17 10:00:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-07 17:29:24 +00:00
|
|
|
// btc-utils representation of a secp256k1 private key
|
2021-04-17 10:00:07 +00:00
|
|
|
privateKey, err := key.ECPrivKey()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-09-07 17:29:24 +00:00
|
|
|
// cast private key to a convertible form (single scalar field element of secp256k1)
|
|
|
|
// and then load into ethcrypto private key format.
|
|
|
|
// TODO: add links to godocs of the two methods or implementations of them, to compare equivalency
|
2021-04-17 10:00:07 +00:00
|
|
|
privateKeyECDSA := privateKey.ToECDSA()
|
2021-09-03 18:06:36 +00:00
|
|
|
derivedKey := crypto.FromECDSA(privateKeyECDSA)
|
2021-04-17 10:00:07 +00:00
|
|
|
|
|
|
|
return derivedKey, nil
|
2020-08-11 15:01:15 +00:00
|
|
|
}
|
2021-04-17 10:00:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generate generates a eth_secp256k1 private key from the given bytes.
|
|
|
|
func (s ethSecp256k1Algo) Generate() hd.GenerateFn {
|
|
|
|
return func(bz []byte) cryptotypes.PrivKey {
|
2021-09-05 11:03:06 +00:00
|
|
|
bzArr := make([]byte, ethsecp256k1.PrivKeySize)
|
2021-04-17 10:00:07 +00:00
|
|
|
copy(bzArr, bz)
|
2020-08-11 15:01:15 +00:00
|
|
|
|
2021-09-07 17:29:24 +00:00
|
|
|
// TODO: modulo P
|
|
|
|
return ðsecp256k1.PrivKey{
|
|
|
|
Key: bzArr,
|
|
|
|
}
|
2021-04-17 10:00:07 +00:00
|
|
|
}
|
2020-08-11 15:01:15 +00:00
|
|
|
}
|