Skip to content
This repository was archived by the owner on Apr 3, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 44 additions & 21 deletions lib/mnemonic.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ var Mnemonic = function(data, wordlist) {

// check and detect wordlist
wordlist = wordlist || Mnemonic._getDictionary(phrase);
// _getDictionary returns an array of wordlists, so if length is 1, remove the outer array
if (wordlist) {
if (wordlist.length == 1) wordlist = wordlist[0];
}
if (phrase && !wordlist) {
throw new errors.UnknownWordlist(phrase);
}
Expand All @@ -71,14 +75,24 @@ var Mnemonic = function(data, wordlist) {
phrase = Mnemonic._entropy2mnemonic(seed, wordlist);
}


// if multiple wordlists matched (highly unlikely)
if (phrase && wordlist.length > 1 && wordlist.length < 1000) {
var isvalid = false;
for (var i = 0; i < wordlist.length; i++) {
if (Mnemonic.isValid(phrase, wordlist[i])) {
isvalid = true;
wordlist = wordlist[i];
break;
};
};
if (!isvalid) throw new errors.InvalidMnemonic(phrase);
// validate phrase and ent
if (phrase && !Mnemonic.isValid(phrase, wordlist)) {
} else if (phrase && !Mnemonic.isValid(phrase, wordlist)) {
throw new errors.InvalidMnemonic(phrase);
}
};
if (ent % 32 !== 0 || ent < 128) {
throw new bitcore.errors.InvalidArgument('ENT', 'Values must be ENT > 128 and ENT % 32 == 0');
}
};

phrase = phrase || Mnemonic._mnemonic(ent, wordlist);

Expand Down Expand Up @@ -114,24 +128,31 @@ Mnemonic.isValid = function(mnemonic, wordlist) {
if (!wordlist) {
return false;
}

// turn wordlist into an array of wordlists, always
if (wordlist.length > 1000) wordlist = [wordlist];

var words = mnemonic.split(' ');
var bin = '';
for (var i = 0; i < words.length; i++) {
var ind = wordlist.indexOf(words[i]);
if (ind < 0) return false;
bin = bin + ('00000000000' + ind.toString(2)).slice(-11);
}

var cs = bin.length / 33;
var hash_bits = bin.slice(-cs);
var nonhash_bits = bin.slice(0, bin.length - cs);
var buf = new Buffer(nonhash_bits.length / 8);
for (i = 0; i < nonhash_bits.length / 8; i++) {
buf.writeUInt8(parseInt(bin.slice(i * 8, (i + 1) * 8), 2), i);
}
var expected_hash_bits = Mnemonic._entropyChecksum(buf);
return expected_hash_bits === hash_bits;
// loop through wordlists and check if one is true
var isvalid = false;
for (var j = 0; j < wordlist.length; j++) {
var bin = '';
for (var i = 0; i < words.length; i++) {
var ind = wordlist[j].indexOf(words[i]);
if (ind < 0) return false;
bin = bin + ('00000000000' + ind.toString(2)).slice(-11);
}
var cs = bin.length / 33;
var hash_bits = bin.slice(-cs);
var nonhash_bits = bin.slice(0, bin.length - cs);
var buf = new Buffer(nonhash_bits.length / 8);
for (i = 0; i < nonhash_bits.length / 8; i++) {
buf.writeUInt8(parseInt(bin.slice(i * 8, (i + 1) * 8), 2), i);
}
var expected_hash_bits = Mnemonic._entropyChecksum(buf);
if (expected_hash_bits === hash_bits) isvalid = true;
};
return isvalid;
};

/**
Expand Down Expand Up @@ -160,12 +181,14 @@ Mnemonic._getDictionary = function(mnemonic) {
if (!mnemonic) return null;

var dicts = Object.keys(Mnemonic.Words);
var matches = [];
for (var i = 0; i < dicts.length; i++) {
var key = dicts[i];
if (Mnemonic._belongsToWordlist(mnemonic, Mnemonic.Words[key])) {
return Mnemonic.Words[key];
matches.push(Mnemonic.Words[key]);
}
}
if (matches.length > 0) return matches;
return null;
};

Expand Down
16 changes: 16 additions & 0 deletions test/mnemonic.unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ describe('Mnemonic', function() {
mnemonic.wordlist.should.equal(Mnemonic.Words.SPANISH);
});

it('constructor should detect standard wordlist even if all words contained in 2 wordlists', function() {
var mnemonic = new Mnemonic('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon brave');
mnemonic.wordlist.should.equal(Mnemonic.Words.FRENCH);
});

});


Expand Down Expand Up @@ -130,6 +135,17 @@ describe('Mnemonic', function() {
var valid2 = Mnemonic.isValid('caution opprimer époque belote devenir ficeler filleul caneton apologie nectar frapper fouiller');
valid2.should.equal(true);
});

it('validates phrases that match multiple wordlists', function() {
var valid = Mnemonic.isValid('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon brave');
valid.should.equal(true);

var invalid = Mnemonic.isValid('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon brave', Mnemonic.Words.ENGLISH);
invalid.should.equal(false);

var valid2 = Mnemonic.isValid('abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon brave', Mnemonic.Words.FRENCH);
valid2.should.equal(true);
});

it('has a toString method', function() {
var mnemonic = new Mnemonic();
Expand Down