Configurable Bip44 CoinType & HdPath for SDK users (#4300)
Closes: #4144
This commit is contained in:
parent
5cae008fbe
commit
1db10b0033
1
.pending/features/sdk/4144-Configurable-Be
Normal file
1
.pending/features/sdk/4144-Configurable-Be
Normal file
@ -0,0 +1 @@
|
||||
#4144 Allow for configurable BIP44 HD path and coin type.
|
||||
@ -25,12 +25,6 @@ import (
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
)
|
||||
|
||||
// BIP44Prefix is the parts of the BIP32 HD path that are fixed by what we used during the fundraiser.
|
||||
const (
|
||||
BIP44Prefix = "44'/118'/"
|
||||
FullFundraiserPath = BIP44Prefix + "0'/0/0"
|
||||
)
|
||||
|
||||
// BIP44Params wraps BIP 44 params (5 level BIP 32 path).
|
||||
// To receive a canonical string representation ala
|
||||
// m / purpose' / coinType' / account' / change / addressIndex
|
||||
@ -130,10 +124,10 @@ func isHardened(field string) bool {
|
||||
}
|
||||
|
||||
// NewFundraiserParams creates a BIP 44 parameter object from the params:
|
||||
// m / 44' / 118' / account' / 0 / address_index
|
||||
// m / 44' / coinType' / account' / 0 / address_index
|
||||
// The fixed parameters (purpose', coin_type', and change) are determined by what was used in the fundraiser.
|
||||
func NewFundraiserParams(account uint32, addressIdx uint32) *BIP44Params {
|
||||
return NewParams(44, 118, account, false, addressIdx)
|
||||
func NewFundraiserParams(account, coinType, addressIdx uint32) *BIP44Params {
|
||||
return NewParams(44, coinType, account, false, addressIdx)
|
||||
}
|
||||
|
||||
// DerivationPath returns the BIP44 fields as an array.
|
||||
|
||||
@ -5,6 +5,8 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
bip39 "github.com/cosmos/go-bip39"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -29,11 +31,14 @@ func ExampleStringifyPathParams() {
|
||||
}
|
||||
|
||||
func TestStringifyFundraiserPathParams(t *testing.T) {
|
||||
path := NewFundraiserParams(4, 22)
|
||||
path := NewFundraiserParams(4, types.CoinType, 22)
|
||||
require.Equal(t, "44'/118'/4'/0/22", path.String())
|
||||
|
||||
path = NewFundraiserParams(4, 57)
|
||||
path = NewFundraiserParams(4, types.CoinType, 57)
|
||||
require.Equal(t, "44'/118'/4'/0/57", path.String())
|
||||
|
||||
path = NewFundraiserParams(4, 12345, 57)
|
||||
require.Equal(t, "44'/12345'/4'/0/57", path.String())
|
||||
}
|
||||
|
||||
func TestPathToArray(t *testing.T) {
|
||||
@ -105,7 +110,7 @@ func ExampleSomeBIP32TestVecs() {
|
||||
fmt.Println("keys from fundraiser test-vector (cosmos, bitcoin, ether)")
|
||||
fmt.Println()
|
||||
// cosmos
|
||||
priv, err := DerivePrivateKeyForPath(master, ch, FullFundraiserPath)
|
||||
priv, err := DerivePrivateKeyForPath(master, ch, types.FullFundraiserPath)
|
||||
if err != nil {
|
||||
fmt.Println("INVALID")
|
||||
} else {
|
||||
|
||||
@ -115,13 +115,15 @@ func (kb dbKeybase) CreateMnemonic(name string, language Language, passwd string
|
||||
}
|
||||
|
||||
seed := bip39.NewSeed(mnemonic, DefaultBIP39Passphrase)
|
||||
info, err = kb.persistDerivedKey(seed, passwd, name, hd.FullFundraiserPath)
|
||||
fullFundraiserPath := types.GetConfig().GetFullFundraiserPath()
|
||||
info, err = kb.persistDerivedKey(seed, passwd, name, fullFundraiserPath)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateAccount converts a mnemonic to a private key and persists it, encrypted with the given password.
|
||||
func (kb dbKeybase) CreateAccount(name, mnemonic, bip39Passwd, encryptPasswd string, account uint32, index uint32) (Info, error) {
|
||||
hdPath := hd.NewFundraiserParams(account, index)
|
||||
coinType := types.GetConfig().GetCoinType()
|
||||
hdPath := hd.NewFundraiserParams(account, coinType, index)
|
||||
return kb.Derive(name, mnemonic, bip39Passwd, encryptPasswd, *hdPath)
|
||||
}
|
||||
|
||||
@ -142,7 +144,8 @@ func (kb dbKeybase) CreateLedger(name string, algo SigningAlgo, hrp string, acco
|
||||
return nil, ErrUnsupportedSigningAlgo
|
||||
}
|
||||
|
||||
hdPath := hd.NewFundraiserParams(account, index)
|
||||
coinType := types.GetConfig().GetCoinType()
|
||||
hdPath := hd.NewFundraiserParams(account, coinType, index)
|
||||
priv, _, err := crypto.NewPrivKeyLedgerSecp256k1(*hdPath, hrp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@ -383,7 +383,7 @@ func TestSeedPhrase(t *testing.T) {
|
||||
require.NotNil(t, err)
|
||||
|
||||
// let us re-create it from the mnemonic-phrase
|
||||
params := *hd.NewFundraiserParams(0, 0)
|
||||
params := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
||||
newInfo, err := cstore.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, n2, newInfo.GetName())
|
||||
@ -406,8 +406,8 @@ func ExampleNew() {
|
||||
// return info here just like in List
|
||||
fmt.Println(bob.GetName())
|
||||
}
|
||||
cstore.CreateMnemonic("Alice", English, "secret", sec)
|
||||
cstore.CreateMnemonic("Carl", English, "mitm", sec)
|
||||
_, _, _ = cstore.CreateMnemonic("Alice", English, "secret", sec)
|
||||
_, _, _ = cstore.CreateMnemonic("Carl", English, "mitm", sec)
|
||||
info, _ := cstore.List()
|
||||
for _, i := range info {
|
||||
fmt.Println(i.GetName())
|
||||
|
||||
@ -335,7 +335,7 @@ func TestLazySeedPhrase(t *testing.T) {
|
||||
require.NotNil(t, err)
|
||||
|
||||
// let us re-create it from the mnemonic-phrase
|
||||
params := *hd.NewFundraiserParams(0, 0)
|
||||
params := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
||||
newInfo, err := kb.Derive(n2, mnemonic, DefaultBIP39Passphrase, p2, params)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, n2, newInfo.GetName())
|
||||
|
||||
@ -19,7 +19,7 @@ func Test_writeReadLedgerInfo(t *testing.T) {
|
||||
lInfo := ledgerInfo{
|
||||
"some_name",
|
||||
tmpKey,
|
||||
*hd.NewFundraiserParams(5, 1)}
|
||||
*hd.NewFundraiserParams(5, types.CoinType, 1)}
|
||||
assert.Equal(t, TypeLedger, lInfo.GetType())
|
||||
|
||||
path, err := lInfo.GetPath()
|
||||
|
||||
@ -41,7 +41,7 @@ func (mock LedgerSECP256K1Mock) GetPublicKeySECP256K1(derivationPath []uint32) (
|
||||
if derivationPath[0] != 44 {
|
||||
return nil, errors.New("Invalid derivation path")
|
||||
}
|
||||
if derivationPath[1] != 118 {
|
||||
if derivationPath[1] != types.CoinType {
|
||||
return nil, errors.New("Invalid derivation path")
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ func TestLedgerErrorHandling(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPublicKeyUnsafe(t *testing.T) {
|
||||
path := *hd.NewFundraiserParams(0, 0)
|
||||
path := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
||||
priv, err := NewPrivKeyLedgerSecp256k1Unsafe(path)
|
||||
require.Nil(t, err, "%s", err)
|
||||
require.NotNil(t, priv)
|
||||
@ -63,7 +63,7 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) {
|
||||
|
||||
// Check with device
|
||||
for i := uint32(0); i < 10; i++ {
|
||||
path := *hd.NewFundraiserParams(0, i)
|
||||
path := *hd.NewFundraiserParams(0, sdk.CoinType, i)
|
||||
fmt.Printf("Checking keys at %v\n", path)
|
||||
|
||||
priv, err := NewPrivKeyLedgerSecp256k1Unsafe(path)
|
||||
@ -99,7 +99,7 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPublicKeySafe(t *testing.T) {
|
||||
path := *hd.NewFundraiserParams(0, 0)
|
||||
path := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
||||
priv, addr, err := NewPrivKeyLedgerSecp256k1(path, "cosmos")
|
||||
|
||||
require.Nil(t, err, "%s", err)
|
||||
@ -154,7 +154,7 @@ func TestPublicKeyHDPath(t *testing.T) {
|
||||
|
||||
// Check with device
|
||||
for i := uint32(0); i < 10; i++ {
|
||||
path := *hd.NewFundraiserParams(0, i)
|
||||
path := *hd.NewFundraiserParams(0, sdk.CoinType, i)
|
||||
fmt.Printf("Checking keys at %v\n", path)
|
||||
|
||||
priv, addr, err := NewPrivKeyLedgerSecp256k1(path, "cosmos")
|
||||
@ -208,7 +208,7 @@ func TestSignaturesHD(t *testing.T) {
|
||||
for account := uint32(0); account < 100; account += 30 {
|
||||
msg := getFakeTx(account)
|
||||
|
||||
path := *hd.NewFundraiserParams(account, account/5)
|
||||
path := *hd.NewFundraiserParams(account, sdk.CoinType, account/5)
|
||||
fmt.Printf("Checking signature at %v --- PLEASE REVIEW AND ACCEPT IN THE DEVICE\n", path)
|
||||
|
||||
priv, err := NewPrivKeyLedgerSecp256k1Unsafe(path)
|
||||
@ -225,7 +225,7 @@ func TestSignaturesHD(t *testing.T) {
|
||||
|
||||
func TestRealLedgerSecp256k1(t *testing.T) {
|
||||
msg := getFakeTx(50)
|
||||
path := *hd.NewFundraiserParams(0, 0)
|
||||
path := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
|
||||
priv, err := NewPrivKeyLedgerSecp256k1Unsafe(path)
|
||||
require.Nil(t, err, "%s", err)
|
||||
|
||||
|
||||
@ -20,6 +20,13 @@ const (
|
||||
// Bech32PrefixAccAddr defines the Bech32 prefix of an account's address
|
||||
Bech32MainPrefix = "cosmos"
|
||||
|
||||
// Atom in https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
||||
CoinType = 118
|
||||
|
||||
// BIP44Prefix is the parts of the BIP32 HD path that are fixed by
|
||||
// what we used during the fundraiser.
|
||||
FullFundraiserPath = "44'/118'/0'/0/0"
|
||||
|
||||
// PrefixAccount is the prefix for account keys
|
||||
PrefixAccount = "acc"
|
||||
// PrefixValidator is the prefix for validator keys
|
||||
|
||||
@ -10,6 +10,8 @@ type Config struct {
|
||||
mtx sync.RWMutex
|
||||
sealed bool
|
||||
bech32AddressPrefix map[string]string
|
||||
coinType uint32
|
||||
fullFundraiserPath string
|
||||
txEncoder TxEncoder
|
||||
addressVerifier func([]byte) error
|
||||
}
|
||||
@ -26,7 +28,9 @@ var (
|
||||
"validator_pub": Bech32PrefixValPub,
|
||||
"consensus_pub": Bech32PrefixConsPub,
|
||||
},
|
||||
txEncoder: nil,
|
||||
coinType: CoinType,
|
||||
fullFundraiserPath: FullFundraiserPath,
|
||||
txEncoder: nil,
|
||||
}
|
||||
)
|
||||
|
||||
@ -81,6 +85,16 @@ func (config *Config) SetAddressVerifier(addressVerifier func([]byte) error) {
|
||||
config.addressVerifier = addressVerifier
|
||||
}
|
||||
|
||||
func (config *Config) SetCoinType(coinType uint32) {
|
||||
config.assertNotSealed()
|
||||
config.coinType = coinType
|
||||
}
|
||||
|
||||
func (config *Config) SetFullFundraiserPath(fullFundraiserPath string) {
|
||||
config.assertNotSealed()
|
||||
config.fullFundraiserPath = fullFundraiserPath
|
||||
}
|
||||
|
||||
// Seal seals the config such that the config state could not be modified further
|
||||
func (config *Config) Seal() *Config {
|
||||
config.mtx.Lock()
|
||||
@ -129,3 +143,11 @@ func (config *Config) GetTxEncoder() TxEncoder {
|
||||
func (config *Config) GetAddressVerifier() func([]byte) error {
|
||||
return config.addressVerifier
|
||||
}
|
||||
|
||||
func (config *Config) GetCoinType() uint32 {
|
||||
return config.coinType
|
||||
}
|
||||
|
||||
func (config *Config) GetFullFundraiserPath() string {
|
||||
return config.fullFundraiserPath
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user