2018-03-13 10:49:58 +00:00
|
|
|
package extkeys
|
2016-07-08 20:26:09 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
type VectorsFile struct {
|
|
|
|
Data map[string][][6]string
|
|
|
|
vectors []*Vector
|
|
|
|
}
|
|
|
|
|
|
|
|
type Vector struct {
|
2018-05-14 17:13:56 +00:00
|
|
|
language, password, input, mnemonic, seed, xprv string
|
2016-07-08 20:26:09 +00:00
|
|
|
}
|
|
|
|
|
2018-03-14 10:05:37 +00:00
|
|
|
func TestNewMnemonic(t *testing.T) {
|
2018-05-14 17:13:56 +00:00
|
|
|
m1 := NewMnemonic()
|
|
|
|
if m1.salt != defaultSalt {
|
2018-03-14 10:05:37 +00:00
|
|
|
t.Errorf("expected default salt, got: %q", m1.salt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-14 10:21:20 +00:00
|
|
|
func TestMnemonic_WordList(t *testing.T) {
|
2018-05-14 17:13:56 +00:00
|
|
|
m := NewMnemonic()
|
2018-03-14 10:21:20 +00:00
|
|
|
_, err := m.WordList(EnglishLanguage)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("expected WordList to return WordList without errors, got: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
indexes := []Language{-1, Language(len(m.wordLists))}
|
|
|
|
for _, index := range indexes {
|
|
|
|
_, err := m.WordList(index)
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("expected WordList to return an error with index %d", index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-08 20:26:09 +00:00
|
|
|
// TestMnemonicPhrase
|
|
|
|
func TestMnemonicPhrase(t *testing.T) {
|
|
|
|
|
2018-05-14 17:13:56 +00:00
|
|
|
mnemonic := NewMnemonic()
|
2016-07-08 20:26:09 +00:00
|
|
|
|
2018-03-13 10:43:30 +00:00
|
|
|
// test strength validation
|
2018-03-14 09:42:55 +00:00
|
|
|
strengths := []entropyStrength{127, 129, 257}
|
2018-03-13 10:43:30 +00:00
|
|
|
for _, s := range strengths {
|
2018-03-13 10:49:58 +00:00
|
|
|
_, err := mnemonic.MnemonicPhrase(s, EnglishLanguage)
|
|
|
|
if err != ErrInvalidEntropyStrength {
|
2018-03-13 11:51:44 +00:00
|
|
|
t.Errorf("Entropy strength '%d' should be invalid", s)
|
2018-03-13 10:43:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-08 20:26:09 +00:00
|
|
|
// test mnemonic generation
|
2016-09-08 09:45:12 +00:00
|
|
|
t.Log("Test mnemonic generation:")
|
2016-07-08 20:26:09 +00:00
|
|
|
for _, language := range mnemonic.AvailableLanguages() {
|
2018-03-14 09:42:55 +00:00
|
|
|
phrase, err := mnemonic.MnemonicPhrase(EntropyStrength128, language)
|
2018-03-13 10:49:58 +00:00
|
|
|
t.Logf("Mnemonic (%s): %s", Languages[language], phrase)
|
2016-07-08 20:26:09 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Test failed: could not create seed: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !mnemonic.ValidMnemonic(phrase, language) {
|
|
|
|
t.Error("Seed is not valid Mnenomic")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// run against test vectors
|
|
|
|
vectorsFile, err := LoadVectorsFile("mnemonic_vectors.json")
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
2016-09-08 09:45:12 +00:00
|
|
|
t.Log("Test against pre-computed seed vectors:")
|
2016-07-08 20:26:09 +00:00
|
|
|
stats := map[string]int{}
|
|
|
|
for _, vector := range vectorsFile.vectors {
|
2018-03-13 11:55:59 +00:00
|
|
|
stats[vector.language]++
|
2018-05-14 17:13:56 +00:00
|
|
|
mnemonic := NewMnemonic()
|
2016-07-08 20:26:09 +00:00
|
|
|
seed := mnemonic.MnemonicSeed(vector.mnemonic, vector.password)
|
|
|
|
if fmt.Sprintf("%x", seed) != vector.seed {
|
|
|
|
t.Errorf("Test failed (%s): incorrect seed (%x) generated (expected: %s)", vector.language, seed, vector.seed)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
//t.Logf("Test passed: correct seed (%x) generated (expected: %s)", seed, vector.seed)
|
2018-05-14 17:13:56 +00:00
|
|
|
|
|
|
|
rootKey, err := NewMaster(seed)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if rootKey.String() != vector.xprv {
|
|
|
|
t.Errorf("Test failed (%s): incorrect xprv (%s) generated (expected: %s)", vector.language, rootKey, vector.xprv)
|
|
|
|
}
|
2016-07-08 20:26:09 +00:00
|
|
|
}
|
|
|
|
for language, count := range stats {
|
|
|
|
t.Logf("[%s]: %d tests completed", language, count)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func LoadVectorsFile(path string) (*VectorsFile, error) {
|
|
|
|
fp, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Test failed: cannot open vectors file: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var vectorsFile VectorsFile
|
|
|
|
if err := json.NewDecoder(fp).Decode(&vectorsFile); err != nil {
|
|
|
|
return nil, fmt.Errorf("Test failed: cannot parse vectors file: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// load data into Vector structs
|
|
|
|
for language, data := range vectorsFile.Data {
|
|
|
|
for _, item := range data {
|
2018-05-14 17:13:56 +00:00
|
|
|
vectorsFile.vectors = append(vectorsFile.vectors, &Vector{language, item[0], item[1], item[2], item[3], item[4]})
|
2016-07-08 20:26:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &vectorsFile, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Vector) String() string {
|
2018-05-14 17:13:56 +00:00
|
|
|
return fmt.Sprintf("{password: %s, input: %s, mnemonic: %s, seed: %s, xprv: %s}",
|
|
|
|
v.password, v.input, v.mnemonic, v.seed, v.xprv)
|
2016-07-08 20:26:09 +00:00
|
|
|
}
|