Return error when using unsupported mnemonic language (#11805)

* Return error when using unsupported mnemonic language

* Fix failing tests

* More test fixes

* Add MnemonicLanguage to CreateWalletRequest

* Add MnemonicLanguage to remaining tests

* Add language to error

* Add missing (.)

* Set default language + fix renumbered fields

* Replace hardcoded language with default var

* default set

* gaz

* fix proto field setting

* fix up

* Remove WithMnemonicLanguage from tests

* Remove WithMnemonicLanguage from tests

* Fix conflicting information failure

* Gazelle + remove hardcoded english values

* fix

* Fix tests

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
Sammy Rosso
2023-01-27 00:44:38 +01:00
committed by GitHub
parent 56907bb2c6
commit 9136d30121
14 changed files with 501 additions and 458 deletions

View File

@@ -36,7 +36,7 @@ func TestDerivedKeymanager_MnemnonicPassphrase_DifferentResults(t *testing.T) {
})
require.NoError(t, err)
numAccounts := 5
err = km.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, "", "mnemonicpass", numAccounts)
err = km.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, DefaultMnemonicLanguage, "mnemonicpass", numAccounts)
require.NoError(t, err)
without25thWord, err := km.FetchValidatingPublicKeys(ctx)
require.NoError(t, err)
@@ -51,7 +51,7 @@ func TestDerivedKeymanager_MnemnonicPassphrase_DifferentResults(t *testing.T) {
})
require.NoError(t, err)
// No mnemonic passphrase this time.
err = km.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, "", "", numAccounts)
err = km.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, DefaultMnemonicLanguage, "", numAccounts)
require.NoError(t, err)
with25thWord, err := km.FetchValidatingPublicKeys(ctx)
require.NoError(t, err)
@@ -70,14 +70,14 @@ func TestDerivedKeymanager_RecoverSeedRoundTrip(t *testing.T) {
require.NoError(t, err)
wanted := bip39.NewSeed(mnemonic, "")
got, err := seedFromMnemonic(mnemonic, "", "" /* no passphrase */)
got, err := seedFromMnemonic(mnemonic, DefaultMnemonicLanguage, "" /* no passphrase */)
require.NoError(t, err)
// Ensure the derived seed matches.
assert.DeepEqual(t, wanted, got)
}
func TestDerivedKeymanager_FetchValidatingPublicKeys(t *testing.T) {
derivedSeed, err := seedFromMnemonic(constant.TestMnemonic, "", "")
derivedSeed, err := seedFromMnemonic(constant.TestMnemonic, DefaultMnemonicLanguage, "")
require.NoError(t, err)
wallet := &mock.Wallet{
Files: make(map[string]map[string][]byte),
@@ -91,7 +91,7 @@ func TestDerivedKeymanager_FetchValidatingPublicKeys(t *testing.T) {
})
require.NoError(t, err)
numAccounts := 5
err = dr.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, "", "", numAccounts)
err = dr.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, DefaultMnemonicLanguage, "", numAccounts)
require.NoError(t, err)
// Fetch the public keys.
@@ -116,7 +116,7 @@ func TestDerivedKeymanager_FetchValidatingPublicKeys(t *testing.T) {
}
func TestDerivedKeymanager_FetchValidatingPrivateKeys(t *testing.T) {
derivedSeed, err := seedFromMnemonic(constant.TestMnemonic, "", "")
derivedSeed, err := seedFromMnemonic(constant.TestMnemonic, DefaultMnemonicLanguage, "")
require.NoError(t, err)
wallet := &mock.Wallet{
Files: make(map[string]map[string][]byte),
@@ -130,7 +130,7 @@ func TestDerivedKeymanager_FetchValidatingPrivateKeys(t *testing.T) {
})
require.NoError(t, err)
numAccounts := 5
err = dr.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, "", "", numAccounts)
err = dr.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, DefaultMnemonicLanguage, "", numAccounts)
require.NoError(t, err)
// Fetch the private keys.
@@ -167,7 +167,7 @@ func TestDerivedKeymanager_Sign(t *testing.T) {
})
require.NoError(t, err)
numAccounts := 5
err = dr.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, "", "", numAccounts)
err = dr.RecoverAccountsFromMnemonic(ctx, constant.TestMnemonic, DefaultMnemonicLanguage, "", numAccounts)
require.NoError(t, err)
pubKeys, err := dr.FetchValidatingPublicKeys(ctx)

View File

@@ -20,13 +20,22 @@ type MnemonicGenerator struct {
skipMnemonicConfirm bool
}
// ErrUnsupportedMnemonicLanguage is returned when trying to use an unsupported mnemonic langauge.
var (
DefaultMnemonicLanguage = "english"
ErrUnsupportedMnemonicLanguage = errors.New("unsupported mnemonic language")
)
// GenerateAndConfirmMnemonic requires confirming the generated mnemonics.
func GenerateAndConfirmMnemonic(mnemonicLanguage string, skipMnemonicConfirm bool) (string, error) {
mnemonicRandomness := make([]byte, 32)
if _, err := rand.NewGenerator().Read(mnemonicRandomness); err != nil {
return "", errors.Wrap(err, "could not initialize mnemonic source of randomness")
}
setBip39Lang(mnemonicLanguage)
err := setBip39Lang(mnemonicLanguage)
if err != nil {
return "", err
}
m := &MnemonicGenerator{
skipMnemonicConfirm: skipMnemonicConfirm,
}
@@ -75,15 +84,18 @@ func (m *MnemonicGenerator) ConfirmAcknowledgement(phrase string) error {
// Uses the provided mnemonic seed phrase to generate the
// appropriate seed file for recovering a derived wallets.
func seedFromMnemonic(mnemonic, mnemonicLanguage, mnemonicPassphrase string) ([]byte, error) {
setBip39Lang(mnemonicLanguage)
err := setBip39Lang(mnemonicLanguage)
if err != nil {
return nil, err
}
if ok := bip39.IsMnemonicValid(mnemonic); !ok {
return nil, bip39.ErrInvalidMnemonic
}
return bip39.NewSeed(mnemonic, mnemonicPassphrase), nil
}
func setBip39Lang(lang string) {
wordlist := wordlists.English
func setBip39Lang(lang string) error {
var wordlist []string
allowedLanguages := map[string][]string{
"chinese_simplified": wordlists.ChineseSimplified,
"chinese_traditional": wordlists.ChineseTraditional,
@@ -98,6 +110,9 @@ func setBip39Lang(lang string) {
if wl, ok := allowedLanguages[lang]; ok {
wordlist = wl
} else {
return errors.Wrapf(ErrUnsupportedMnemonicLanguage, "%s", lang)
}
bip39.SetWordList(wordlist)
return nil
}

View File

@@ -3,6 +3,7 @@ package derived
import (
"testing"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
"github.com/tyler-smith/go-bip39"
@@ -24,23 +25,29 @@ func Test_setBip39Lang(t *testing.T) {
tests := []struct {
lang string
expectedWordlist []string
wantErr error
}{
{lang: "english", expectedWordlist: wordlists.English},
{lang: "chinese_traditional", expectedWordlist: wordlists.ChineseTraditional},
{lang: "chinese_simplified", expectedWordlist: wordlists.ChineseSimplified},
{lang: "czech", expectedWordlist: wordlists.Czech},
{lang: "french", expectedWordlist: wordlists.French},
{lang: "japanese", expectedWordlist: wordlists.Japanese},
{lang: "korean", expectedWordlist: wordlists.Korean},
{lang: "italian", expectedWordlist: wordlists.Italian},
{lang: "spanish", expectedWordlist: wordlists.Spanish},
{lang: "undefined", expectedWordlist: wordlists.English},
{lang: "english", expectedWordlist: wordlists.English, wantErr: nil},
{lang: "chinese_traditional", expectedWordlist: wordlists.ChineseTraditional, wantErr: nil},
{lang: "chinese_simplified", expectedWordlist: wordlists.ChineseSimplified, wantErr: nil},
{lang: "czech", expectedWordlist: wordlists.Czech, wantErr: nil},
{lang: "french", expectedWordlist: wordlists.French, wantErr: nil},
{lang: "japanese", expectedWordlist: wordlists.Japanese, wantErr: nil},
{lang: "korean", expectedWordlist: wordlists.Korean, wantErr: nil},
{lang: "italian", expectedWordlist: wordlists.Italian, wantErr: nil},
{lang: "spanish", expectedWordlist: wordlists.Spanish, wantErr: nil},
{lang: "undefined", expectedWordlist: []string{}, wantErr: errors.Wrapf(ErrUnsupportedMnemonicLanguage, "%s", "undefined")},
}
for _, tt := range tests {
t.Run(tt.lang, func(t *testing.T) {
setBip39Lang(tt.lang)
wordlist := bip39.GetWordList()
assert.DeepEqual(t, tt.expectedWordlist, wordlist, "Expected wordlist to match")
err := setBip39Lang(tt.lang)
if err != nil {
assert.Equal(t, tt.wantErr.Error(), err.Error())
} else {
assert.Equal(t, tt.wantErr, err)
wordlist := bip39.GetWordList()
assert.DeepEqual(t, tt.expectedWordlist, wordlist, "Expected wordlist to match")
}
})
}
}