github.com/iotexproject/iotex-core@v1.14.1-rc1/ioctl/newcmd/hdwallet/hdwallet_test.go (about)

     1  // Copyright (c) 2020 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package hdwallet
     7  
     8  import (
     9  	"encoding/hex"
    10  	"fmt"
    11  	"testing"
    12  
    13  	ecrypt "github.com/ethereum/go-ethereum/crypto"
    14  	"github.com/golang/mock/gomock"
    15  	"github.com/iotexproject/go-pkgs/crypto"
    16  	hdwallet "github.com/miguelmota/go-ethereum-hdwallet"
    17  	"github.com/stretchr/testify/require"
    18  	"github.com/tyler-smith/go-bip39"
    19  
    20  	"github.com/iotexproject/iotex-core/ioctl/config"
    21  	"github.com/iotexproject/iotex-core/ioctl/util"
    22  	"github.com/iotexproject/iotex-core/test/mock/mock_ioctlclient"
    23  )
    24  
    25  func TestNewHdwalletCmd(t *testing.T) {
    26  	require := require.New(t)
    27  	ctrl := gomock.NewController(t)
    28  	defer ctrl.Finish()
    29  	client := mock_ioctlclient.NewMockClient(ctrl)
    30  	client.EXPECT().SelectTranslation(gomock.Any()).Return("hdwallet usage", config.English).Times(6)
    31  	cmd := NewHdwalletCmd(client)
    32  	result, err := util.ExecuteCmd(cmd)
    33  	require.NoError(err)
    34  	require.Contains(result, "Available Commands")
    35  }
    36  
    37  func Test_Hdwallet(t *testing.T) {
    38  	require := require.New(t)
    39  
    40  	// simulating 'hdwallet create' here
    41  	password := "123"
    42  
    43  	entropy, _ := bip39.NewEntropy(128)
    44  	mnemonic, _ := bip39.NewMnemonic(entropy)
    45  
    46  	enctxt := append([]byte(mnemonic), util.HashSHA256([]byte(mnemonic))...)
    47  	enckey := util.HashSHA256([]byte(password))
    48  
    49  	out, err := util.Encrypt(enctxt, enckey)
    50  	require.NoError(err)
    51  
    52  	// simulating 'hdwallet use' here
    53  	enckey = util.HashSHA256([]byte(password))
    54  
    55  	dectxt, err := util.Decrypt(out, enckey)
    56  	require.NoError(err)
    57  
    58  	dectxtLen := len(dectxt)
    59  	require.True(dectxtLen > 32)
    60  
    61  	mnemonic1, hash := dectxt[:dectxtLen-32], dectxt[dectxtLen-32:]
    62  
    63  	require.Equal(hash, util.HashSHA256(mnemonic1))
    64  
    65  	wallet, err := hdwallet.NewFromMnemonic(string(mnemonic))
    66  	require.NoError(err)
    67  
    68  	derivationPath := fmt.Sprintf("%s/0'/%d/%d", DefaultRootDerivationPath, 1, 2)
    69  
    70  	path := hdwallet.MustParseDerivationPath(derivationPath)
    71  	account, err := wallet.Derive(path, false)
    72  	require.NoError(err)
    73  
    74  	private1, err := wallet.PrivateKey(account)
    75  	require.NoError(err)
    76  
    77  	// simulating 'hdwallet import' here
    78  	enctxt = append([]byte(mnemonic), util.HashSHA256([]byte(mnemonic))...)
    79  	enckey = util.HashSHA256([]byte(password))
    80  
    81  	_, err = util.Encrypt(enctxt, enckey)
    82  	require.NoError(err)
    83  
    84  	// compare import and create
    85  	wallet, err = hdwallet.NewFromMnemonic(string(mnemonic))
    86  	require.NoError(err)
    87  
    88  	derivationPath = fmt.Sprintf("%s/0'/%d/%d", DefaultRootDerivationPath, 1, 2)
    89  
    90  	path = hdwallet.MustParseDerivationPath(derivationPath)
    91  	account, err = wallet.Derive(path, false)
    92  	require.NoError(err)
    93  
    94  	private2, err := wallet.PrivateKey(account)
    95  	require.NoError(err)
    96  	require.Equal(private1, private2)
    97  
    98  	//test DeriveKey
    99  	account1 := 0
   100  	change := 1
   101  	index := 2
   102  
   103  	derivationPath = fmt.Sprintf("%s/%d'/%d/%d", DefaultRootDerivationPath, account1, change, index)
   104  	path = hdwallet.MustParseDerivationPath(derivationPath)
   105  	account, err = wallet.Derive(path, false)
   106  	require.NoError(err)
   107  
   108  	private3, err := wallet.PrivateKey(account)
   109  	require.NoError(err)
   110  
   111  	require.Equal(private2, private3)
   112  
   113  	account1 = 123
   114  	derivationPath = fmt.Sprintf("%s/%d'/%d/%d", DefaultRootDerivationPath, account1, change, index)
   115  	path = hdwallet.MustParseDerivationPath(derivationPath)
   116  	account, err = wallet.Derive(path, false)
   117  	require.NoError(err)
   118  
   119  	private4, err := wallet.PrivateKey(account)
   120  	require.NoError(err)
   121  	require.NotEqual(private2, private4)
   122  }
   123  
   124  func TestEncryptDecryptWithMnemonic(t *testing.T) {
   125  	require := require.New(t)
   126  
   127  	mnemonic := "lake stove quarter shove dry matrix hire split wide attract argue core"
   128  	password := "123"
   129  
   130  	enckey := util.HashSHA256([]byte(password))
   131  
   132  	storedTxt, err := hex.DecodeString("4da6571c2897e88568cbcce59dcf9574355d718da25f2ea6f2e6847b9254fc18eacd852d282f1be7b51024fb05e70ee41bc08c0a8a07c549b0c29f185de0fb35462f98b429ebc4b79bfbcab41b795fe1e59262ae0695a4107dcc57a8bad24eb2323b2c976a9fb3dafc8788a9fccbf5b8c36e3388e458")
   133  	require.NoError(err)
   134  
   135  	dectxt, err := util.Decrypt(storedTxt, enckey)
   136  	require.NoError(err)
   137  
   138  	dectxtLen := len(dectxt)
   139  
   140  	mnemonic1, hash := dectxt[:dectxtLen-32], dectxt[dectxtLen-32:]
   141  
   142  	require.Equal(mnemonic, string(mnemonic1))
   143  	require.Equal(util.HashSHA256(mnemonic1), hash)
   144  }
   145  
   146  func TestFixedMnemonicAndDerivationPath(t *testing.T) {
   147  	require := require.New(t)
   148  
   149  	mnemonic := "lake stove quarter shove dry matrix hire split wide attract argue core"
   150  	wallet, err := hdwallet.NewFromMnemonic(mnemonic)
   151  	require.NoError(err)
   152  
   153  	derivationPath := "m/44'/304'/0'/1/3"
   154  
   155  	path := hdwallet.MustParseDerivationPath(derivationPath)
   156  	account, err := wallet.Derive(path, false)
   157  	require.NoError(err)
   158  
   159  	private, err := wallet.PrivateKey(account)
   160  	require.NoError(err)
   161  	prvKey, err := crypto.BytesToPrivateKey(ecrypt.FromECDSA(private))
   162  	require.NoError(err)
   163  	addr := prvKey.PublicKey().Address()
   164  	require.NotNil(addr)
   165  
   166  	require.Equal(addr.String(), "io13hwqt04le40puf73aa9w9zm9fq04qqn7qcjc6z")
   167  
   168  }