crypto/hd: add 'm/' prefix to hd path (#7970)

* crypto/hd: add 'm/' prefix to hd path

* update fundraiser path

* fix some tests

* tests

* fix test case

* changelog

* fix ledger tests
This commit is contained in:
Federico Kunze 2020-11-18 19:42:45 +01:00 committed by GitHub
parent f02a46263f
commit 97d96612c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 172 additions and 138 deletions

View File

@ -42,6 +42,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
* Updated iavl dependency to v0.15-rc2
* (version) [\#7848](https://github.com/cosmos/cosmos-sdk/pull/7848) [\#7941](https://github.com/cosmos/cosmos-sdk/pull/7941) `version --long` output now shows the list of build dependencies and replaced build dependencies.
### Bug Fixes
* (crypto) [\#7966](https://github.com/cosmos/cosmos-sdk/issues/7966) `Bip44Params` `String()` function now correctly returns the absolute HD path by adding the `m/` prefix.
## [v0.40.0-rc3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.40.0-rc3) - 2020-11-06
### Client Breaking

View File

@ -27,7 +27,7 @@ type addrData struct {
}
func TestFullFundraiserPath(t *testing.T) {
require.Equal(t, "44'/118'/0'/0/0", hd.NewFundraiserParams(0, 118, 0).String())
require.Equal(t, "m/44'/118'/0'/0/0", hd.NewFundraiserParams(0, 118, 0).String())
}
func initFundraiserTestVectors(t *testing.T) []addrData {
@ -63,8 +63,9 @@ func TestFundraiserCompatibility(t *testing.T) {
t.Logf("ROUND: %d MNEMONIC: %s", i, d.Mnemonic)
master, ch := hd.ComputeMastersFromSeed(seed)
priv, err := hd.DerivePrivateKeyForPath(master, ch, "44'/118'/0'/0/0")
priv, err := hd.DerivePrivateKeyForPath(master, ch, "m/44'/118'/0'/0/0")
require.NoError(t, err)
privKey := &secp256k1.PrivKey{Key: priv}
pub := privKey.PubKey()

View File

@ -36,52 +36,66 @@ func NewParams(purpose, coinType, account uint32, change bool, addressIdx uint32
}
}
// Parse the BIP44 path and unmarshal into the struct.
// NewParamsFromPath parses the BIP44 path and unmarshals it into a Bip44Params. It supports both
// absolute and relative paths.
func NewParamsFromPath(path string) (*BIP44Params, error) {
spl := strings.Split(path, "/")
// Handle absolute or relative paths
switch {
case spl[0] == path:
return nil, fmt.Errorf("path %s doesn't contain '/' separators", path)
case strings.TrimSpace(spl[0]) == "":
return nil, fmt.Errorf("ambiguous path %s: use 'm/' prefix for absolute paths, or no leading '/' for relative ones", path)
case strings.TrimSpace(spl[0]) == "m":
spl = spl[1:]
}
if len(spl) != 5 {
return nil, fmt.Errorf("path length is wrong. Expected 5, got %d", len(spl))
return nil, fmt.Errorf("invalid path length %s", path)
}
// Check items can be parsed
purpose, err := hardenedInt(spl[0])
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid HD path purpose %s: %w", spl[0], err)
}
coinType, err := hardenedInt(spl[1])
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid HD path coin type %s: %w", spl[1], err)
}
account, err := hardenedInt(spl[2])
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid HD path account %s: %w", spl[2], err)
}
change, err := hardenedInt(spl[3])
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid HD path change %s: %w", spl[3], err)
}
addressIdx, err := hardenedInt(spl[4])
if err != nil {
return nil, err
return nil, fmt.Errorf("invalid HD path address index %s: %w", spl[4], err)
}
// Confirm valid values
if spl[0] != "44'" {
return nil, fmt.Errorf("first field in path must be 44', got %v", spl[0])
return nil, fmt.Errorf("first field in path must be 44', got %s", spl[0])
}
if !isHardened(spl[1]) || !isHardened(spl[2]) {
return nil,
fmt.Errorf("second and third field in path must be hardened (ie. contain the suffix ', got %v and %v", spl[1], spl[2])
fmt.Errorf("second and third field in path must be hardened (ie. contain the suffix ', got %s and %s", spl[1], spl[2])
}
if isHardened(spl[3]) || isHardened(spl[4]) {
return nil,
fmt.Errorf("fourth and fifth field in path must not be hardened (ie. not contain the suffix ', got %v and %v", spl[3], spl[4])
fmt.Errorf("fourth and fifth field in path must not be hardened (ie. not contain the suffix ', got %s and %s", spl[3], spl[4])
}
if !(change == 0 || change == 1) {
@ -135,6 +149,8 @@ func (p BIP44Params) DerivationPath() []uint32 {
}
}
// String returns the full absolute HD path of the BIP44 (https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) params:
// m / purpose' / coin_type' / account' / change / address_index
func (p BIP44Params) String() string {
var changeStr string
if p.Change {
@ -142,8 +158,7 @@ func (p BIP44Params) String() string {
} else {
changeStr = "0"
}
// m / Purpose' / coin_type' / Account' / Change / address_index
return fmt.Sprintf("%d'/%d'/%d'/%s/%d",
return fmt.Sprintf("m/%d'/%d'/%d'/%s/%d",
p.Purpose,
p.CoinType,
p.Account,
@ -165,6 +180,13 @@ func DerivePrivateKeyForPath(privKeyBytes, chainCode [32]byte, path string) ([]b
data := privKeyBytes
parts := strings.Split(path, "/")
switch {
case parts[0] == path:
return nil, fmt.Errorf("path '%s' doesn't contain '/' separators", path)
case strings.TrimSpace(parts[0]) == "m":
parts = parts[1:]
}
for _, part := range parts {
// do we have an apostrophe?
harden := part[len(part)-1:] == "'"
@ -178,7 +200,7 @@ func DerivePrivateKeyForPath(privKeyBytes, chainCode [32]byte, path string) ([]b
// index values are in the range [0, 1<<31-1] aka [0, max(int32)]
idx, err := strconv.ParseUint(part, 10, 31)
if err != nil {
return []byte{}, fmt.Errorf("invalid BIP 32 path: %s", err)
return []byte{}, fmt.Errorf("invalid BIP 32 path %s: %w", path, err)
}
data, chainCode = derivePrivateKey(data, chainCode, uint32(idx), harden)
@ -188,7 +210,7 @@ func DerivePrivateKeyForPath(privKeyBytes, chainCode [32]byte, path string) ([]b
n := copy(derivedKey, data[:])
if n != 32 || len(data) != 32 {
return []byte{}, fmt.Errorf("expected a (secp256k1) key of length 32, got length: %v", len(data))
return []byte{}, fmt.Errorf("expected a key of length 32, got length: %d", len(data))
}
return derivedKey, nil

View File

@ -9,7 +9,6 @@ import (
"github.com/cosmos/cosmos-sdk/types"
bip39 "github.com/cosmos/go-bip39"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -20,26 +19,22 @@ func mnemonicToSeed(mnemonic string) []byte {
return bip39.NewSeed(mnemonic, defaultBIP39Passphrase)
}
// nolint:govet
func ExampleStringifyPathParams() {
func TestPathParamsString(t *testing.T) {
path := hd.NewParams(44, 0, 0, false, 0)
fmt.Println(path.String())
require.Equal(t, "m/44'/0'/0'/0/0", path.String())
path = hd.NewParams(44, 33, 7, true, 9)
fmt.Println(path.String())
// Output:
// 44'/0'/0'/0/0
// 44'/33'/7'/1/9
require.Equal(t, "m/44'/33'/7'/1/9", path.String())
}
func TestStringifyFundraiserPathParams(t *testing.T) {
path := hd.NewFundraiserParams(4, types.CoinType, 22)
require.Equal(t, "44'/118'/4'/0/22", path.String())
require.Equal(t, "m/44'/118'/4'/0/22", path.String())
path = hd.NewFundraiserParams(4, types.CoinType, 57)
require.Equal(t, "44'/118'/4'/0/57", path.String())
require.Equal(t, "m/44'/118'/4'/0/57", path.String())
path = hd.NewFundraiserParams(4, 12345, 57)
require.Equal(t, "44'/12345'/4'/0/57", path.String())
require.Equal(t, "m/44'/12345'/4'/0/57", path.String())
}
func TestPathToArray(t *testing.T) {
@ -55,95 +50,101 @@ func TestParamsFromPath(t *testing.T) {
params *hd.BIP44Params
path string
}{
{&hd.BIP44Params{44, 0, 0, false, 0}, "44'/0'/0'/0/0"},
{&hd.BIP44Params{44, 1, 0, false, 0}, "44'/1'/0'/0/0"},
{&hd.BIP44Params{44, 0, 1, false, 0}, "44'/0'/1'/0/0"},
{&hd.BIP44Params{44, 0, 0, true, 0}, "44'/0'/0'/1/0"},
{&hd.BIP44Params{44, 0, 0, false, 1}, "44'/0'/0'/0/1"},
{&hd.BIP44Params{44, 1, 1, true, 1}, "44'/1'/1'/1/1"},
{&hd.BIP44Params{44, 118, 52, true, 41}, "44'/118'/52'/1/41"},
{&hd.BIP44Params{44, 0, 0, false, 0}, "m/44'/0'/0'/0/0"},
{&hd.BIP44Params{44, 1, 0, false, 0}, "m/44'/1'/0'/0/0"},
{&hd.BIP44Params{44, 0, 1, false, 0}, "m/44'/0'/1'/0/0"},
{&hd.BIP44Params{44, 0, 0, true, 0}, "m/44'/0'/0'/1/0"},
{&hd.BIP44Params{44, 0, 0, false, 1}, "m/44'/0'/0'/0/1"},
{&hd.BIP44Params{44, 1, 1, true, 1}, "m/44'/1'/1'/1/1"},
{&hd.BIP44Params{44, 118, 52, true, 41}, "m/44'/118'/52'/1/41"},
}
for i, c := range goodCases {
params, err := hd.NewParamsFromPath(c.path)
errStr := fmt.Sprintf("%d %v", i, c)
assert.NoError(t, err, errStr)
assert.EqualValues(t, c.params, params, errStr)
assert.Equal(t, c.path, c.params.String())
require.NoError(t, err, errStr)
require.EqualValues(t, c.params, params, errStr)
require.Equal(t, c.path, c.params.String())
}
badCases := []struct {
path string
}{
{"43'/0'/0'/0/0"}, // doesnt start with 44
{"44'/1'/0'/0/0/5"}, // too many fields
{"44'/0'/1'/0"}, // too few fields
{"44'/0'/0'/2/0"}, // change field can only be 0/1
{"44/0'/0'/0/0"}, // first field needs '
{"44'/0/0'/0/0"}, // second field needs '
{"44'/0'/0/0/0"}, // third field needs '
{"44'/0'/0'/0'/0"}, // fourth field must not have '
{"44'/0'/0'/0/0'"}, // fifth field must not have '
{"44'/-1'/0'/0/0"}, // no negatives
{"44'/0'/0'/-1/0"}, // no negatives
{"a'/0'/0'/-1/0"}, // valid values
{"0/X/0'/-1/0"}, // valid values
{"44'/0'/X/-1/0"}, // valid values
{"44'/0'/0'/%/0"}, // valid values
{"44'/0'/0'/0/%"}, // valid values
{"m/43'/0'/0'/0/0"}, // doesn't start with 44
{"m/44'/1'/0'/0/0/5"}, // too many fields
{"m/44'/0'/1'/0"}, // too few fields
{"m/44'/0'/0'/2/0"}, // change field can only be 0/1
{"m/44/0'/0'/0/0"}, // first field needs '
{"m/44'/0/0'/0/0"}, // second field needs '
{"m/44'/0'/0/0/0"}, // third field needs '
{"m/44'/0'/0'/0'/0"}, // fourth field must not have '
{"m/44'/0'/0'/0/0'"}, // fifth field must not have '
{"m/44'/-1'/0'/0/0"}, // no negatives
{"m/44'/0'/0'/-1/0"}, // no negatives
{"m/a'/0'/0'/-1/0"}, // invalid values
{"m/0/X/0'/-1/0"}, // invalid values
{"m/44'/0'/X/-1/0"}, // invalid values
{"m/44'/0'/0'/%/0"}, // invalid values
{"m/44'/0'/0'/0/%"}, // invalid values
{"m44'0'0'00"}, // no separators
{" /44'/0'/0'/0/0"}, // blank first component
}
for i, c := range badCases {
params, err := hd.NewParamsFromPath(c.path)
errStr := fmt.Sprintf("%d %v", i, c)
assert.Nil(t, params, errStr)
assert.Error(t, err, errStr)
require.Nil(t, params, errStr)
require.Error(t, err, errStr)
}
}
// nolint:govet
func ExampleSomeBIP32TestVecs() {
func TestBIP32Vecs(t *testing.T) {
seed := mnemonicToSeed("barrel original fuel morning among eternal " +
"filter ball stove pluck matrix mechanic")
master, ch := hd.ComputeMastersFromSeed(seed)
fmt.Println("keys from fundraiser test-vector (cosmos, bitcoin, ether)")
fmt.Println()
// cosmos
// cosmos, absolute path
priv, err := hd.DerivePrivateKeyForPath(master, ch, types.FullFundraiserPath)
if err != nil {
fmt.Println("INVALID")
} else {
fmt.Println(hex.EncodeToString(priv[:]))
}
require.NoError(t, err)
require.NotEmpty(t, priv)
fmt.Println(hex.EncodeToString(priv[:]))
absPrivKey := hex.EncodeToString(priv[:])
// cosmos, relative path
priv, err = hd.DerivePrivateKeyForPath(master, ch, "44'/118'/0'/0/0")
require.NoError(t, err)
require.NotEmpty(t, priv)
relPrivKey := hex.EncodeToString(priv[:])
// check compatibility between relative and absolute HD paths
require.Equal(t, relPrivKey, absPrivKey)
// bitcoin
priv, err = hd.DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/0")
if err != nil {
fmt.Println("INVALID")
} else {
fmt.Println(hex.EncodeToString(priv[:]))
}
priv, err = hd.DerivePrivateKeyForPath(master, ch, "m/44'/0'/0'/0/0")
require.NoError(t, err)
require.NotEmpty(t, priv)
fmt.Println(hex.EncodeToString(priv[:]))
// ether
priv, err = hd.DerivePrivateKeyForPath(master, ch, "44'/60'/0'/0/0")
if err != nil {
fmt.Println("INVALID")
} else {
fmt.Println(hex.EncodeToString(priv[:]))
}
priv, err = hd.DerivePrivateKeyForPath(master, ch, "m/44'/60'/0'/0/0")
require.NoError(t, err)
require.NotEmpty(t, priv)
fmt.Println(hex.EncodeToString(priv[:]))
// INVALID
priv, err = hd.DerivePrivateKeyForPath(master, ch, "X/0'/0'/0/0")
if err != nil {
fmt.Println("INVALID")
} else {
fmt.Println(hex.EncodeToString(priv[:]))
}
priv, err = hd.DerivePrivateKeyForPath(master, ch, "-44/0'/0'/0/0")
if err != nil {
fmt.Println("INVALID")
} else {
fmt.Println(hex.EncodeToString(priv[:]))
}
priv, err = hd.DerivePrivateKeyForPath(master, ch, "m/X/0'/0'/0/0")
require.Error(t, err)
require.Empty(t, priv)
priv, err = hd.DerivePrivateKeyForPath(master, ch, "m/-44/0'/0'/0/0")
require.Error(t, err)
require.Empty(t, priv)
fmt.Println()
fmt.Println("keys generated via https://coinomi.com/recovery-phrase-tool.html")
@ -153,13 +154,14 @@ func ExampleSomeBIP32TestVecs() {
"advice process birth april short trust crater change bacon monkey medal garment " +
"gorilla ranch hour rival razor call lunar mention taste vacant woman sister")
master, ch = hd.ComputeMastersFromSeed(seed)
priv, _ = hd.DerivePrivateKeyForPath(master, ch, "44'/1'/1'/0/4")
priv, _ = hd.DerivePrivateKeyForPath(master, ch, "m/44'/1'/1'/0/4")
fmt.Println(hex.EncodeToString(priv[:]))
seed = mnemonicToSeed("idea naive region square margin day captain habit " +
"gun second farm pact pulse someone armed")
master, ch = hd.ComputeMastersFromSeed(seed)
priv, _ = hd.DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/420")
priv, err = hd.DerivePrivateKeyForPath(master, ch, "m/44'/0'/0'/0/420")
require.NoError(t, err)
fmt.Println(hex.EncodeToString(priv[:]))
fmt.Println()
@ -169,7 +171,8 @@ func ExampleSomeBIP32TestVecs() {
// bip32 path: m/0/7
seed = mnemonicToSeed("monitor flock loyal sick object grunt duty ride develop assault harsh history")
master, ch = hd.ComputeMastersFromSeed(seed)
priv, _ = hd.DerivePrivateKeyForPath(master, ch, "0/7")
priv, err = hd.DerivePrivateKeyForPath(master, ch, "m/0/7")
require.NoError(t, err) // TODO: shouldn't this error?
fmt.Println(hex.EncodeToString(priv[:]))
// Output: keys from fundraiser test-vector (cosmos, bitcoin, ether)
@ -177,8 +180,6 @@ func ExampleSomeBIP32TestVecs() {
// bfcb217c058d8bbafd5e186eae936106ca3e943889b0b4a093ae13822fd3170c
// e77c3de76965ad89997451de97b95bb65ede23a6bf185a55d80363d92ee37c3d
// 7fc4d8a8146dea344ba04c593517d3f377fa6cded36cd55aee0a0bb968e651bc
// INVALID
// INVALID
//
// keys generated via https://coinomi.com/recovery-phrase-tool.html
//
@ -201,9 +202,9 @@ func TestCreateHDPath(t *testing.T) {
args args
want hd.BIP44Params
}{
{"44'/0'/0'/0/0", args{0, 0, 0}, hd.BIP44Params{Purpose: 44}},
{"44'/114'/0'/0/0", args{114, 0, 0}, hd.BIP44Params{Purpose: 44, CoinType: 114, Account: 0, AddressIndex: 0}},
{"44'/114'/1'/1/0", args{114, 1, 1}, hd.BIP44Params{Purpose: 44, CoinType: 114, Account: 1, AddressIndex: 1}},
{"m/44'/0'/0'/0/0", args{0, 0, 0}, hd.BIP44Params{Purpose: 44}},
{"m/44'/114'/0'/0/0", args{114, 0, 0}, hd.BIP44Params{Purpose: 44, CoinType: 114, Account: 0, AddressIndex: 0}},
{"m/44'/114'/1'/1/0", args{114, 1, 1}, hd.BIP44Params{Purpose: 44, CoinType: 114, Account: 1, AddressIndex: 1}},
}
for _, tt := range tests {
tt := tt
@ -227,36 +228,44 @@ func TestDeriveHDPathRange(t *testing.T) {
wantErr string
}{
{
path: "1'/2147483648/0'/0/0",
path: "m/1'/2147483648/0'/0/0",
wantErr: "out of range",
},
{
path: "2147483648'/1/0/0",
path: "m/2147483648'/1/0/0",
wantErr: "out of range",
},
{
path: "2147483648'/2147483648/0'/0/0",
path: "m/2147483648'/2147483648/0'/0/0",
wantErr: "out of range",
},
{
path: "1'/-5/0'/0/0",
path: "m/1'/-5/0'/0/0",
wantErr: "invalid syntax",
},
{
path: "-2147483646'/1/0/0",
path: "m/-2147483646'/1/0/0",
wantErr: "invalid syntax",
},
{
path: "-2147483648'/-2147483648/0'/0/0",
path: "m/-2147483648'/-2147483648/0'/0/0",
wantErr: "invalid syntax",
},
{
path: "m44'118'0'00",
wantErr: "path 'm44'118'0'00' doesn't contain '/' separators",
},
{
path: "",
wantErr: "path '' doesn't contain '/' separators",
},
{
// Should pass.
path: "1'/2147483647/0'/0/0",
path: "m/1'/2147483647'/1/0'/0/0",
},
{
// Should pass.
path: "2147483647'/1/0'/0/0",
path: "1'/2147483647'/1/0'/0/0",
},
}
@ -267,9 +276,9 @@ func TestDeriveHDPathRange(t *testing.T) {
_, err := hd.DerivePrivateKeyForPath(master, ch, tt.path)
if tt.wantErr == "" {
require.Nil(t, err, "unexpected error")
require.NoError(t, err, "unexpected error")
} else {
require.NotNil(t, err, "expected a report of an int overflow")
require.Error(t, err, "expected a report of an int overflow")
require.Contains(t, err.Error(), tt.wantErr)
}
})

View File

@ -45,7 +45,7 @@ func TestInMemoryCreateLedger(t *testing.T) {
path, err := restoredKey.GetPath()
require.NoError(t, err)
require.Equal(t, "44'/118'/3'/0/1", path.String())
require.Equal(t, "m/44'/118'/3'/0/1", path.String())
}
// TestSignVerify does some detailed checks on how we sign and validate
@ -123,5 +123,5 @@ func TestAltKeyring_SaveLedgerKey(t *testing.T) {
path, err := restoredKey.GetPath()
require.NoError(t, err)
require.Equal(t, "44'/118'/3'/0/1", path.String())
require.Equal(t, "m/44'/118'/3'/0/1", path.String())
}

View File

@ -4,11 +4,10 @@ import (
"encoding/hex"
"testing"
"github.com/stretchr/testify/assert"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
func Test_writeReadLedgerInfo(t *testing.T) {
@ -17,28 +16,27 @@ func Test_writeReadLedgerInfo(t *testing.T) {
copy(tmpKey[:], bz)
lInfo := newLedgerInfo("some_name", &secp256k1.PubKey{Key: tmpKey}, *hd.NewFundraiserParams(5, sdk.CoinType, 1), hd.Secp256k1Type)
assert.Equal(t, TypeLedger, lInfo.GetType())
require.Equal(t, TypeLedger, lInfo.GetType())
path, err := lInfo.GetPath()
assert.NoError(t, err)
assert.Equal(t, "44'/118'/5'/0/1", path.String())
assert.Equal(t,
require.NoError(t, err)
require.Equal(t, "m/44'/118'/5'/0/1", path.String())
require.Equal(t,
"cosmospub1addwnpepqddddqg2glc8x4fl7vxjlnr7p5a3czm5kcdp4239sg6yqdc4rc2r5wmxv8p",
sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, lInfo.GetPubKey()))
// Serialize and restore
serialized := marshalInfo(lInfo)
restoredInfo, err := unmarshalInfo(serialized)
assert.NoError(t, err)
assert.NotNil(t, restoredInfo)
require.NoError(t, err)
require.NotNil(t, restoredInfo)
// Check both keys match
assert.Equal(t, lInfo.GetName(), restoredInfo.GetName())
assert.Equal(t, lInfo.GetType(), restoredInfo.GetType())
assert.Equal(t, lInfo.GetPubKey(), restoredInfo.GetPubKey())
require.Equal(t, lInfo.GetName(), restoredInfo.GetName())
require.Equal(t, lInfo.GetType(), restoredInfo.GetType())
require.Equal(t, lInfo.GetPubKey(), restoredInfo.GetPubKey())
restoredPath, err := restoredInfo.GetPath()
assert.NoError(t, err)
assert.Equal(t, path, restoredPath)
require.NoError(t, err)
require.Equal(t, path, restoredPath)
}

View File

@ -24,7 +24,7 @@ func TestErrorHandling(t *testing.T) {
func TestPublicKeyUnsafe(t *testing.T) {
path := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
priv, err := NewPrivKeySecp256k1Unsafe(path)
require.Nil(t, err, "%s", err)
require.NoError(t, err)
require.NotNil(t, priv)
require.Equal(t, "eb5ae98721034fef9cd7c4c63588d3b03feb5281b9d232cba34d6f3d71aee59211ffbfe1fe87",
@ -62,10 +62,10 @@ func TestPublicKeyUnsafeHDPath(t *testing.T) {
// Check with device
for i := uint32(0); i < 10; i++ {
path := *hd.NewFundraiserParams(0, sdk.CoinType, i)
fmt.Printf("Checking keys at %v\n", path)
t.Logf("Checking keys at %v\n", path)
priv, err := NewPrivKeySecp256k1Unsafe(path)
require.Nil(t, err, "%s", err)
require.NoError(t, err)
require.NotNil(t, priv)
// Check other methods
@ -100,7 +100,7 @@ func TestPublicKeySafe(t *testing.T) {
path := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
priv, addr, err := NewPrivKeySecp256k1(path, "cosmos")
require.Nil(t, err, "%s", err)
require.NoError(t, err)
require.NotNil(t, priv)
require.Nil(t, ShowAddress(path, priv.PubKey(), sdk.GetConfig().GetBech32AccountAddrPrefix()))
@ -155,10 +155,10 @@ func TestPublicKeyHDPath(t *testing.T) {
// Check with device
for i := uint32(0); i < 10; i++ {
path := *hd.NewFundraiserParams(0, sdk.CoinType, i)
fmt.Printf("Checking keys at %v\n", path)
t.Logf("Checking keys at %s\n", path)
priv, addr, err := NewPrivKeySecp256k1(path, "cosmos")
require.Nil(t, err, "%s", err)
require.NoError(t, err)
require.NotNil(t, addr)
require.NotNil(t, priv)
@ -209,14 +209,14 @@ func TestSignaturesHD(t *testing.T) {
msg := getFakeTx(account)
path := *hd.NewFundraiserParams(account, sdk.CoinType, account/5)
fmt.Printf("Checking signature at %v --- PLEASE REVIEW AND ACCEPT IN THE DEVICE\n", path)
t.Logf("Checking signature at %v --- PLEASE REVIEW AND ACCEPT IN THE DEVICE\n", path)
priv, err := NewPrivKeySecp256k1Unsafe(path)
require.Nil(t, err, "%s", err)
require.NoError(t, err)
pub := priv.PubKey()
sig, err := priv.Sign(msg)
require.Nil(t, err)
require.NoError(t, err)
valid := pub.VerifySignature(msg, sig)
require.True(t, valid, "Is your device using test mnemonic: %s ?", testutil.TestMnemonic)
@ -227,11 +227,11 @@ func TestRealDeviceSecp256k1(t *testing.T) {
msg := getFakeTx(50)
path := *hd.NewFundraiserParams(0, sdk.CoinType, 0)
priv, err := NewPrivKeySecp256k1Unsafe(path)
require.Nil(t, err, "%s", err)
require.NoError(t, err)
pub := priv.PubKey()
sig, err := priv.Sign(msg)
require.Nil(t, err)
require.NoError(t, err)
valid := pub.VerifySignature(msg, sig)
require.True(t, valid)
@ -246,7 +246,7 @@ func TestRealDeviceSecp256k1(t *testing.T) {
// signing with the loaded key should match the original pubkey
sig, err = priv.Sign(msg)
require.Nil(t, err)
require.NoError(t, err)
valid = pub.VerifySignature(msg, sig)
require.True(t, valid)

View File

@ -31,15 +31,15 @@ const (
// AddrLen defines a valid address length
AddrLen = 20
// Bech32PrefixAccAddr defines the Bech32 prefix of an account's address
// Bech32MainPrefix defines the main SDK Bech32 prefix of an account's address
Bech32MainPrefix = "cosmos"
// Atom in https://github.com/satoshilabs/slips/blob/master/slip-0044.md
// CoinType is the ATOM coin type as defined in SLIP44 (https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
CoinType = 118
// BIP44Prefix is the parts of the BIP44 HD path that are fixed by
// what we used during the fundraiser.
FullFundraiserPath = "44'/118'/0'/0/0"
// FullFundraiserPath is the parts of the BIP44 HD path that are fixed by
// what we used during the ATOM fundraiser.
FullFundraiserPath = "m/44'/118'/0'/0/0"
// PrefixAccount is the prefix for account keys
PrefixAccount = "acc"