Browse Source

Added bitcore-mnemonic.

master
Emilio Almansi 7 years ago
parent
commit
4eac309002
  1. 2
      dist/bitcoincashjs.0.1.7.min.js
  2. 7
      lib/bitcoincash.js
  3. 13
      lib/errors/spec.js
  4. 3
      lib/mnemonic/index.js
  5. 289
      lib/mnemonic/mnemonic.js
  6. 71
      lib/mnemonic/pbkdf2.js
  7. 5
      lib/mnemonic/words/chinese.js
  8. 5
      lib/mnemonic/words/english.js
  9. 6
      lib/mnemonic/words/french.js
  10. 10
      lib/mnemonic/words/index.js
  11. 5
      lib/mnemonic/words/italian.js
  12. 5
      lib/mnemonic/words/japanese.js
  13. 5
      lib/mnemonic/words/spanish.js
  14. 5
      package-lock.json
  15. 3
      package.json
  16. 7
      src/bitcoincash.js
  17. 13
      src/errors/spec.js
  18. 1
      src/mnemonic/index.js
  19. 292
      src/mnemonic/mnemonic.js
  20. 71
      src/mnemonic/pbkdf2.js
  21. 5
      src/mnemonic/words/chinese.js
  22. 5
      src/mnemonic/words/english.js
  23. 5
      src/mnemonic/words/french.js
  24. 8
      src/mnemonic/words/index.js
  25. 5
      src/mnemonic/words/italian.js
  26. 5
      src/mnemonic/words/japanese.js
  27. 5
      src/mnemonic/words/spanish.js
  28. 2
      test/block/block.js
  29. 4
      test/block/blockheader.js
  30. 15
      test/crypto/ecdsa.js
  31. 300
      test/data/mnemonics.json
  32. 6
      test/index.html
  33. 225
      test/mnmenonic/mnemonic.js
  34. 44
      test/mnmenonic/pbkdf2.js
  35. 2
      test/mocha.opts
  36. 3
      test/transaction/deserialize.js

2
dist/bitcoincashjs.0.1.7.min.js

File diff suppressed because one or more lines are too long

7
lib/bitcoincash.js

@ -42,19 +42,20 @@ bch.errors = require('./errors');
// main bitcoin library
bch.Address = require('./address');
bch.Block = require('./block');
bch.MerkleBlock = require('./block/merkleblock');
bch.Message = require('./message');
bch.BlockHeader = require('./block/blockheader');
bch.HDPrivateKey = require('./hdprivatekey.js');
bch.HDPublicKey = require('./hdpublickey.js');
bch.MerkleBlock = require('./block/merkleblock');
bch.Message = require('./message');
bch.Mnemonic = require('./mnemonic');
bch.Networks = require('./networks');
bch.Opcode = require('./opcode');
bch.PrivateKey = require('./privatekey');
bch.PublicKey = require('./publickey');
bch.Script = require('./script');
bch.Transaction = require('./transaction');
bch.URI = require('./uri');
bch.Unit = require('./unit');
bch.URI = require('./uri');
// dependencies, subject to change
bch.deps = {};

13
lib/errors/spec.js

@ -175,4 +175,17 @@ module.exports = [{
name: 'UnrecognizedArgument',
message: 'Invalid argument for creation, must be string, json, buffer, or object'
}]
}, {
name: 'Mnemonic',
message: 'Internal Error on bitcore-mnemonic module {0}',
errors: [{
name: 'InvalidEntropy',
message: 'Entropy length must be an even multiple of 11 bits: {0}'
}, {
name: 'UnknownWordlist',
message: 'Could not detect the used word list: {0}'
}, {
name: 'InvalidMnemonic',
message: 'Mnemonic string is invalid: {0}'
}]
}];

3
lib/mnemonic/index.js

@ -0,0 +1,3 @@
'use strict';
module.exports = require('./mnemonic');

289
lib/mnemonic/mnemonic.js

@ -0,0 +1,289 @@
'use strict';
var _ = require('lodash');
var $ = require('../util/preconditions');
var BN = require('../crypto/bn');
var errors = require('../errors');
var Hash = require('../crypto/hash');
var HDPrivateKey = require('../hdprivatekey');
var Random = require('../crypto/random');
var unorm = require('unorm');
/**
* This is an immutable class that represents a BIP39 Mnemonic code.
* See BIP39 specification for more info: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
* A Mnemonic code is a a group of easy to remember words used for the generation
* of deterministic wallets. A Mnemonic can be used to generate a seed using
* an optional passphrase, for later generate a HDPrivateKey.
*
* @example
* // generate a random mnemonic
* var mnemonic = new Mnemonic();
* var phrase = mnemonic.phrase;
*
* // use a different language
* var mnemonic = new Mnemonic(Mnemonic.Words.SPANISH);
* var xprivkey = mnemonic.toHDPrivateKey();
*
* @param {*=} data - a seed, phrase, or entropy to initialize (can be skipped)
* @param {Array=} wordlist - the wordlist to generate mnemonics from
* @returns {Mnemonic} A new instance of Mnemonic
* @constructor
*/
var Mnemonic = function Mnemonic(data, wordlist) {
if (!(this instanceof Mnemonic)) {
return new Mnemonic(data, wordlist);
}
if (_.isArray(data)) {
wordlist = data;
data = null;
}
// handle data overloading
var ent, phrase, seed;
if (Buffer.isBuffer(data)) {
seed = data;
} else if (_.isString(data)) {
phrase = unorm.nfkd(data);
} else if (_.isNumber(data)) {
ent = data;
} else if (data) {
throw new errors.InvalidArgument('data', 'Must be a Buffer, a string or an integer');
}
ent = ent || 128;
// check and detect wordlist
wordlist = wordlist || Mnemonic._getDictionary(phrase);
if (phrase && !wordlist) {
throw new errors.UnknownWordlist(phrase);
}
wordlist = wordlist || Mnemonic.Words.ENGLISH;
if (seed) {
phrase = Mnemonic._entropy2mnemonic(seed, wordlist);
}
// validate phrase and ent
if (phrase && !Mnemonic.isValid(phrase, wordlist)) {
throw new errors.InvalidMnemonic(phrase);
}
if (ent % 32 !== 0 || ent < 128) {
throw new errors.InvalidArgument('ENT', 'Values must be ENT > 128 and ENT % 32 == 0');
}
phrase = phrase || Mnemonic._mnemonic(ent, wordlist);
Object.defineProperty(this, 'wordlist', {
configurable: false,
value: wordlist
});
Object.defineProperty(this, 'phrase', {
configurable: false,
value: phrase
});
};
Mnemonic.Words = require('./words');
/**
* Will return a boolean if the mnemonic is valid
*
* @example
*
* var valid = Mnemonic.isValid('lab rescue lunch elbow recall phrase perfect donkey biology guess moment husband');
* // true
*
* @param {String} mnemonic - The mnemonic string
* @param {String} [wordlist] - The wordlist used
* @returns {boolean}
*/
Mnemonic.isValid = function (mnemonic, wordlist) {
mnemonic = unorm.nfkd(mnemonic);
wordlist = wordlist || Mnemonic._getDictionary(mnemonic);
if (!wordlist) {
return false;
}
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;
};
/**
* Internal function to check if a mnemonic belongs to a wordlist.
*
* @param {String} mnemonic - The mnemonic string
* @param {String} wordlist - The wordlist
* @returns {boolean}
*/
Mnemonic._belongsToWordlist = function (mnemonic, wordlist) {
var words = unorm.nfkd(mnemonic).split(' ');
for (var i = 0; i < words.length; i++) {
var ind = wordlist.indexOf(words[i]);
if (ind < 0) return false;
}
return true;
};
/**
* Internal function to detect the wordlist used to generate the mnemonic.
*
* @param {String} mnemonic - The mnemonic string
* @returns {Array} the wordlist or null
*/
Mnemonic._getDictionary = function (mnemonic) {
if (!mnemonic) return null;
var dicts = Object.keys(Mnemonic.Words);
for (var i = 0; i < dicts.length; i++) {
var key = dicts[i];
if (Mnemonic._belongsToWordlist(mnemonic, Mnemonic.Words[key])) {
return Mnemonic.Words[key];
}
}
return null;
};
/**
* Will generate a seed based on the mnemonic and optional passphrase.
*
* @param {String} [passphrase]
* @returns {Buffer}
*/
Mnemonic.prototype.toSeed = function (passphrase) {
passphrase = passphrase || '';
return Mnemonic.pbkdf2(unorm.nfkd(this.phrase), unorm.nfkd('mnemonic' + passphrase), 2048, 64);
};
/**
* Will generate a Mnemonic object based on a seed.
*
* @param {Buffer} [seed]
* @param {string} [wordlist]
* @returns {Mnemonic}
*/
Mnemonic.fromSeed = function (seed, wordlist) {
$.checkArgument(Buffer.isBuffer(seed), 'seed must be a Buffer.');
$.checkArgument(_.isArray(wordlist) || _.isString(wordlist), 'wordlist must be a string or an array.');
return new Mnemonic(seed, wordlist);
};
/**
*
* Generates a HD Private Key from a Mnemonic.
* Optionally receive a passphrase and bitcoin network.
*
* @param {String=} [passphrase]
* @param {Network|String|number=} [network] - The network: 'livenet' or 'testnet'
* @returns {HDPrivateKey}
*/
Mnemonic.prototype.toHDPrivateKey = function (passphrase, network) {
var seed = this.toSeed(passphrase);
return HDPrivateKey.fromSeed(seed, network);
};
/**
* Will return a the string representation of the mnemonic
*
* @returns {String} Mnemonic
*/
Mnemonic.prototype.toString = function () {
return this.phrase;
};
/**
* Will return a string formatted for the console
*
* @returns {String} Mnemonic
*/
Mnemonic.prototype.inspect = function () {
return '<Mnemonic: ' + this.toString() + ' >';
};
/**
* Internal function to generate a random mnemonic
*
* @param {Number} ENT - Entropy size, defaults to 128
* @param {Array} wordlist - Array of words to generate the mnemonic
* @returns {String} Mnemonic string
*/
Mnemonic._mnemonic = function (ENT, wordlist) {
var buf = Random.getRandomBuffer(ENT / 8);
return Mnemonic._entropy2mnemonic(buf, wordlist);
};
/**
* Internal function to generate mnemonic based on entropy
*
* @param {Number} entropy - Entropy buffer
* @param {Array} wordlist - Array of words to generate the mnemonic
* @returns {String} Mnemonic string
*/
Mnemonic._entropy2mnemonic = function (entropy, wordlist) {
var bin = '';
for (var i = 0; i < entropy.length; i++) {
bin = bin + ('00000000' + entropy[i].toString(2)).slice(-8);
}
bin = bin + Mnemonic._entropyChecksum(entropy);
if (bin.length % 11 !== 0) {
throw new errors.InvalidEntropy(bin);
}
var mnemonic = [];
for (i = 0; i < bin.length / 11; i++) {
var wi = parseInt(bin.slice(i * 11, (i + 1) * 11), 2);
mnemonic.push(wordlist[wi]);
}
var ret;
if (wordlist === Mnemonic.Words.JAPANESE) {
ret = mnemonic.join('\u3000');
} else {
ret = mnemonic.join(' ');
}
return ret;
};
/**
* Internal function to create checksum of entropy
*
* @param entropy
* @returns {string} Checksum of entropy length / 32
* @private
*/
Mnemonic._entropyChecksum = function (entropy) {
var hash = Hash.sha256(entropy);
var bits = entropy.length * 8;
var cs = bits / 32;
var hashbits = new BN(hash.toString('hex'), 16).toString(2);
// zero pad the hash bits
while (hashbits.length % 256 !== 0) {
hashbits = '0' + hashbits;
}
var checksum = hashbits.slice(0, cs);
return checksum;
};
Mnemonic.pbkdf2 = require('./pbkdf2');
module.exports = Mnemonic;

71
lib/mnemonic/pbkdf2.js

@ -0,0 +1,71 @@
'use strict';
var crypto = require('crypto');
/**
* PDKBF2
* Credit to: https://github.com/stayradiated/pbkdf2-sha512
* Copyright (c) 2014, JP Richardson Copyright (c) 2010-2011 Intalio Pte, All Rights Reserved
*/
function pbkdf2(key, salt, iterations, dkLen) {
/* jshint maxstatements: 31 */
/* jshint maxcomplexity: 9 */
var hLen = 64; //SHA512 Mac length
if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
throw Error('Requested key length too long');
}
if (typeof key !== 'string' && !Buffer.isBuffer(key)) {
throw new TypeError('key must a string or Buffer');
}
if (typeof salt !== 'string' && !Buffer.isBuffer(salt)) {
throw new TypeError('salt must a string or Buffer');
}
if (typeof key === 'string') {
key = new Buffer(key);
}
if (typeof salt === 'string') {
salt = new Buffer(salt);
}
var DK = new Buffer(dkLen);
var U = new Buffer(hLen);
var T = new Buffer(hLen);
var block1 = new Buffer(salt.length + 4);
var l = Math.ceil(dkLen / hLen);
var r = dkLen - (l - 1) * hLen;
salt.copy(block1, 0, 0, salt.length);
for (var i = 1; i <= l; i++) {
block1[salt.length + 0] = i >> 24 & 0xff;
block1[salt.length + 1] = i >> 16 & 0xff;
block1[salt.length + 2] = i >> 8 & 0xff;
block1[salt.length + 3] = i >> 0 & 0xff;
U = crypto.createHmac('sha512', key).update(block1).digest();
U.copy(T, 0, 0, hLen);
for (var j = 1; j < iterations; j++) {
U = crypto.createHmac('sha512', key).update(U).digest();
for (var k = 0; k < hLen; k++) {
T[k] ^= U[k];
}
}
var destPos = (i - 1) * hLen;
var len = i === l ? r : hLen;
T.copy(DK, destPos, 0, len);
}
return DK;
}
module.exports = pbkdf2;

5
lib/mnemonic/words/chinese.js

File diff suppressed because one or more lines are too long

5
lib/mnemonic/words/english.js

File diff suppressed because one or more lines are too long

6
lib/mnemonic/words/french.js

File diff suppressed because one or more lines are too long

10
lib/mnemonic/words/index.js

@ -0,0 +1,10 @@
'use strict';
module.exports = {
'CHINESE': require('./chinese'),
'ENGLISH': require('./english'),
'FRENCH': require('./french'),
'ITALIAN': require('./italian'),
'JAPANESE': require('./japanese'),
'SPANISH': require('./spanish')
};

5
lib/mnemonic/words/italian.js

File diff suppressed because one or more lines are too long

5
lib/mnemonic/words/japanese.js

File diff suppressed because one or more lines are too long

5
lib/mnemonic/words/spanish.js

File diff suppressed because one or more lines are too long

5
package-lock.json

@ -10906,6 +10906,11 @@
"integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=",
"dev": true
},
"unorm": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.4.1.tgz",
"integrity": "sha1-NkIA1fE2RsqLzURJAnEzVhR5IwA="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

3
package.json

@ -51,7 +51,8 @@
"cashaddrjs": "^0.1.4",
"elliptic": "=3.0.3",
"inherits": "=2.0.1",
"lodash": "^4.17.4"
"lodash": "^4.17.4",
"unorm": "^1.4.1"
},
"devDependencies": {
"babel-cli": "^6.26.0",

7
src/bitcoincash.js

@ -44,19 +44,20 @@ bch.errors = require('./errors');
// main bitcoin library
bch.Address = require('./address');
bch.Block = require('./block');
bch.MerkleBlock = require('./block/merkleblock');
bch.Message = require('./message');
bch.BlockHeader = require('./block/blockheader');
bch.HDPrivateKey = require('./hdprivatekey.js');
bch.HDPublicKey = require('./hdpublickey.js');
bch.MerkleBlock = require('./block/merkleblock');
bch.Message = require('./message');
bch.Mnemonic = require('./mnemonic');
bch.Networks = require('./networks');
bch.Opcode = require('./opcode');
bch.PrivateKey = require('./privatekey');
bch.PublicKey = require('./publickey');
bch.Script = require('./script');
bch.Transaction = require('./transaction');
bch.URI = require('./uri');
bch.Unit = require('./unit');
bch.URI = require('./uri');
// dependencies, subject to change
bch.deps = {};

13
src/errors/spec.js

@ -174,4 +174,17 @@ module.exports = [{
name: 'UnrecognizedArgument',
message: 'Invalid argument for creation, must be string, json, buffer, or object'
}]
}, {
name: 'Mnemonic',
message: 'Internal Error on bitcore-mnemonic module {0}',
errors: [{
name: 'InvalidEntropy',
message: 'Entropy length must be an even multiple of 11 bits: {0}'
}, {
name: 'UnknownWordlist',
message: 'Could not detect the used word list: {0}'
}, {
name: 'InvalidMnemonic',
message: 'Mnemonic string is invalid: {0}'
}]
}];

1
src/mnemonic/index.js

@ -0,0 +1 @@
module.exports = require('./mnemonic');

292
src/mnemonic/mnemonic.js

@ -0,0 +1,292 @@
'use strict';
var _ = require('lodash');
var $ = require('../util/preconditions');
var BN = require('../crypto/bn');
var errors = require('../errors');
var Hash = require('../crypto/hash');
var HDPrivateKey = require('../hdprivatekey');
var Random = require('../crypto/random');
var unorm = require('unorm');
/**
* This is an immutable class that represents a BIP39 Mnemonic code.
* See BIP39 specification for more info: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
* A Mnemonic code is a a group of easy to remember words used for the generation
* of deterministic wallets. A Mnemonic can be used to generate a seed using
* an optional passphrase, for later generate a HDPrivateKey.
*
* @example
* // generate a random mnemonic
* var mnemonic = new Mnemonic();
* var phrase = mnemonic.phrase;
*
* // use a different language
* var mnemonic = new Mnemonic(Mnemonic.Words.SPANISH);
* var xprivkey = mnemonic.toHDPrivateKey();
*
* @param {*=} data - a seed, phrase, or entropy to initialize (can be skipped)
* @param {Array=} wordlist - the wordlist to generate mnemonics from
* @returns {Mnemonic} A new instance of Mnemonic
* @constructor
*/
var Mnemonic = function(data, wordlist) {
if (!(this instanceof Mnemonic)) {
return new Mnemonic(data, wordlist);
}
if (_.isArray(data)) {
wordlist = data;
data = null;
}
// handle data overloading
var ent, phrase, seed;
if (Buffer.isBuffer(data)) {
seed = data;
} else if (_.isString(data)) {
phrase = unorm.nfkd(data);
} else if (_.isNumber(data)) {
ent = data;
} else if (data) {
throw new errors.InvalidArgument('data', 'Must be a Buffer, a string or an integer');
}
ent = ent || 128;
// check and detect wordlist
wordlist = wordlist || Mnemonic._getDictionary(phrase);
if (phrase && !wordlist) {
throw new errors.UnknownWordlist(phrase);
}
wordlist = wordlist || Mnemonic.Words.ENGLISH;
if (seed) {
phrase = Mnemonic._entropy2mnemonic(seed, wordlist);
}
// validate phrase and ent
if (phrase && !Mnemonic.isValid(phrase, wordlist)) {
throw new errors.InvalidMnemonic(phrase);
}
if (ent % 32 !== 0 || ent < 128) {
throw new errors.InvalidArgument('ENT', 'Values must be ENT > 128 and ENT % 32 == 0');
}
phrase = phrase || Mnemonic._mnemonic(ent, wordlist);
Object.defineProperty(this, 'wordlist', {
configurable: false,
value: wordlist
});
Object.defineProperty(this, 'phrase', {
configurable: false,
value: phrase
});
};
Mnemonic.Words = require('./words');
/**
* Will return a boolean if the mnemonic is valid
*
* @example
*
* var valid = Mnemonic.isValid('lab rescue lunch elbow recall phrase perfect donkey biology guess moment husband');
* // true
*
* @param {String} mnemonic - The mnemonic string
* @param {String} [wordlist] - The wordlist used
* @returns {boolean}
*/
Mnemonic.isValid = function(mnemonic, wordlist) {
mnemonic = unorm.nfkd(mnemonic);
wordlist = wordlist || Mnemonic._getDictionary(mnemonic);
if (!wordlist) {
return false;
}
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;
};
/**
* Internal function to check if a mnemonic belongs to a wordlist.
*
* @param {String} mnemonic - The mnemonic string
* @param {String} wordlist - The wordlist
* @returns {boolean}
*/
Mnemonic._belongsToWordlist = function(mnemonic, wordlist) {
var words = unorm.nfkd(mnemonic).split(' ');
for (var i = 0; i < words.length; i++) {
var ind = wordlist.indexOf(words[i]);
if (ind < 0) return false;
}
return true;
};
/**
* Internal function to detect the wordlist used to generate the mnemonic.
*
* @param {String} mnemonic - The mnemonic string
* @returns {Array} the wordlist or null
*/
Mnemonic._getDictionary = function(mnemonic) {
if (!mnemonic) return null;
var dicts = Object.keys(Mnemonic.Words);
for (var i = 0; i < dicts.length; i++) {
var key = dicts[i];
if (Mnemonic._belongsToWordlist(mnemonic, Mnemonic.Words[key])) {
return Mnemonic.Words[key];
}
}
return null;
};
/**
* Will generate a seed based on the mnemonic and optional passphrase.
*
* @param {String} [passphrase]
* @returns {Buffer}
*/
Mnemonic.prototype.toSeed = function(passphrase) {
passphrase = passphrase || '';
return Mnemonic.pbkdf2(unorm.nfkd(this.phrase), unorm.nfkd('mnemonic' + passphrase), 2048, 64);
};
/**
* Will generate a Mnemonic object based on a seed.
*
* @param {Buffer} [seed]
* @param {string} [wordlist]
* @returns {Mnemonic}
*/
Mnemonic.fromSeed = function(seed, wordlist) {
$.checkArgument(Buffer.isBuffer(seed), 'seed must be a Buffer.');
$.checkArgument(_.isArray(wordlist) || _.isString(wordlist), 'wordlist must be a string or an array.');
return new Mnemonic(seed, wordlist);
};
/**
*
* Generates a HD Private Key from a Mnemonic.
* Optionally receive a passphrase and bitcoin network.
*
* @param {String=} [passphrase]
* @param {Network|String|number=} [network] - The network: 'livenet' or 'testnet'
* @returns {HDPrivateKey}
*/
Mnemonic.prototype.toHDPrivateKey = function(passphrase, network) {
var seed = this.toSeed(passphrase);
return HDPrivateKey.fromSeed(seed, network);
};
/**
* Will return a the string representation of the mnemonic
*
* @returns {String} Mnemonic
*/
Mnemonic.prototype.toString = function() {
return this.phrase;
};
/**
* Will return a string formatted for the console
*
* @returns {String} Mnemonic
*/
Mnemonic.prototype.inspect = function() {
return '<Mnemonic: ' + this.toString() + ' >';
};
/**
* Internal function to generate a random mnemonic
*
* @param {Number} ENT - Entropy size, defaults to 128
* @param {Array} wordlist - Array of words to generate the mnemonic
* @returns {String} Mnemonic string
*/
Mnemonic._mnemonic = function(ENT, wordlist) {
var buf = Random.getRandomBuffer(ENT / 8);
return Mnemonic._entropy2mnemonic(buf, wordlist);
};
/**
* Internal function to generate mnemonic based on entropy
*
* @param {Number} entropy - Entropy buffer
* @param {Array} wordlist - Array of words to generate the mnemonic
* @returns {String} Mnemonic string
*/
Mnemonic._entropy2mnemonic = function(entropy, wordlist) {
var bin = '';
for (var i = 0; i < entropy.length; i++) {
bin = bin + ('00000000' + entropy[i].toString(2)).slice(-8);
}
bin = bin + Mnemonic._entropyChecksum(entropy);
if (bin.length % 11 !== 0) {
throw new errors.InvalidEntropy(bin);
}
var mnemonic = [];
for (i = 0; i < bin.length / 11; i++) {
var wi = parseInt(bin.slice(i * 11, (i + 1) * 11), 2);
mnemonic.push(wordlist[wi]);
}
var ret;
if (wordlist === Mnemonic.Words.JAPANESE) {
ret = mnemonic.join('\u3000');
} else {
ret = mnemonic.join(' ');
}
return ret;
};
/**
* Internal function to create checksum of entropy
*
* @param entropy
* @returns {string} Checksum of entropy length / 32
* @private
*/
Mnemonic._entropyChecksum = function(entropy) {
var hash = Hash.sha256(entropy);
var bits = entropy.length * 8;
var cs = bits / 32;
var hashbits = new BN(hash.toString('hex'), 16).toString(2);
// zero pad the hash bits
while (hashbits.length % 256 !== 0) {
hashbits = '0' + hashbits;
}
var checksum = hashbits.slice(0, cs);
return checksum;
};
Mnemonic.pbkdf2 = require('./pbkdf2');
module.exports = Mnemonic;

71
src/mnemonic/pbkdf2.js

@ -0,0 +1,71 @@
'use strict';
var crypto = require('crypto');
/**
* PDKBF2
* Credit to: https://github.com/stayradiated/pbkdf2-sha512
* Copyright (c) 2014, JP Richardson Copyright (c) 2010-2011 Intalio Pte, All Rights Reserved
*/
function pbkdf2(key, salt, iterations, dkLen) {
/* jshint maxstatements: 31 */
/* jshint maxcomplexity: 9 */
var hLen = 64; //SHA512 Mac length
if (dkLen > (Math.pow(2, 32) - 1) * hLen) {
throw Error('Requested key length too long');
}
if (typeof key !== 'string' && !Buffer.isBuffer(key)) {
throw new TypeError('key must a string or Buffer');
}
if (typeof salt !== 'string' && !Buffer.isBuffer(salt)) {
throw new TypeError('salt must a string or Buffer');
}
if (typeof key === 'string') {
key = new Buffer(key);
}
if (typeof salt === 'string') {
salt = new Buffer(salt);
}
var DK = new Buffer(dkLen);
var U = new Buffer(hLen);
var T = new Buffer(hLen);
var block1 = new Buffer(salt.length + 4);
var l = Math.ceil(dkLen / hLen);
var r = dkLen - (l - 1) * hLen;
salt.copy(block1, 0, 0, salt.length);
for (var i = 1; i <= l; i++) {
block1[salt.length + 0] = (i >> 24 & 0xff);
block1[salt.length + 1] = (i >> 16 & 0xff);
block1[salt.length + 2] = (i >> 8 & 0xff);
block1[salt.length + 3] = (i >> 0 & 0xff);
U = crypto.createHmac('sha512', key).update(block1).digest();
U.copy(T, 0, 0, hLen);
for (var j = 1; j < iterations; j++) {
U = crypto.createHmac('sha512', key).update(U).digest();
for (var k = 0; k < hLen; k++) {
T[k] ^= U[k];
}
}
var destPos = (i - 1) * hLen;
var len = (i === l ? r : hLen);
T.copy(DK, destPos, 0, len);
}
return DK;
}
module.exports = pbkdf2;

5
src/mnemonic/words/chinese.js

File diff suppressed because one or more lines are too long

5
src/mnemonic/words/english.js

File diff suppressed because one or more lines are too long

5
src/mnemonic/words/french.js

File diff suppressed because one or more lines are too long

8
src/mnemonic/words/index.js

@ -0,0 +1,8 @@
module.exports = {
'CHINESE': require('./chinese'),
'ENGLISH': require('./english'),
'FRENCH': require('./french'),
'ITALIAN': require('./italian'),
'JAPANESE': require('./japanese'),
'SPANISH': require('./spanish')
};

5
src/mnemonic/words/italian.js

File diff suppressed because one or more lines are too long

5
src/mnemonic/words/japanese.js

File diff suppressed because one or more lines are too long

5
src/mnemonic/words/spanish.js

File diff suppressed because one or more lines are too long

2
test/block/block.js

@ -1,7 +1,7 @@
'use strict';
var bch = require('../..');
var BN = require('../../lib/crypto/bn');
var BN = bch.crypto.BN;
var BufferReader = bch.encoding.BufferReader;
var BufferWriter = bch.encoding.BufferWriter;
var BlockHeader = bch.BlockHeader;

4
test/block/blockheader.js

@ -1,7 +1,7 @@
'use strict';
var bch = require('../..');
var BN = require('../../lib/crypto/bn');
var BN = bch.crypto.BN;
var BufferReader = bch.encoding.BufferReader;
var BufferWriter = bch.encoding.BufferWriter;
@ -9,7 +9,7 @@ var BlockHeader = bch.BlockHeader;
var fs = require('fs');
var should = require('chai').should();
// https://test-insight.bitpay.com/block/000000000b99b16390660d79fcc138d2ad0c89a0d044c4201a02bdf1f61ffa11
// https://test-insight.bitpaycrypto.com/block/000000000b99b16390660d79fcc138d2ad0c89a0d044c4201a02bdf1f61ffa11
var dataRawBlockBuffer = fs.readFileSync('test/data/blk86756-testnet.dat');
var dataRawBlockBinary = fs.readFileSync('test/data/blk86756-testnet.dat', 'binary');
var dataRawId = '000000000b99b16390660d79fcc138d2ad0c89a0d044c4201a02bdf1f61ffa11';

15
test/crypto/ecdsa.js

@ -1,12 +1,13 @@
'use strict';
var ECDSA = require('../../lib/crypto/ecdsa');
var Hash = require('../../lib/crypto/hash');
var Privkey = require('../../lib/privatekey');
var Pubkey = require('../../lib/publickey');
var Signature = require('../../lib/crypto/signature');
var BN = require('../../lib/crypto/bn');
var point = require('../../lib/crypto/point');
var bch = require('../..');
var ECDSA = bch.crypto.ECDSA;
var Hash = bch.crypto.Hash;
var Privkey = bch.PrivateKey;
var Pubkey = bch.PublicKey;
var Signature = bch.crypto.Signature;
var BN = bch.crypto.BN;
var point = bch.crypto.Point;
var should = require('chai').should();
var vectors = require('../data/ecdsa');

300
test/data/mnemonics.json

@ -0,0 +1,300 @@
{
"english": [
[
"TREZOR",
"00000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about",
"c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04"
],
[
"TREZOR",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank yellow",
"2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607"
],
[
"TREZOR",
"80808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage above",
"d71de856f81a8acc65e6fc851a38d4d7ec216fd0796d0a6827a3ad6ed5511a30fa280f12eb2e47ed2ac03b5c462a0358d18d69fe4f985ec81778c1b370b652a8"
],
[
"TREZOR",
"ffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong",
"ac27495480225222079d7be181583751e86f571027b0497b5b5d11218e0a8a13332572917f0f8e5a589620c6f15b11c61dee327651a14c34e18231052e48c069"
],
[
"TREZOR",
"000000000000000000000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon agent",
"035895f2f481b1b0f01fcf8c289c794660b289981a78f8106447707fdd9666ca06da5a9a565181599b79f53b844d8a71dd9f439c52a3d7b3e8a79c906ac845fa"
],
[
"TREZOR",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal will",
"f2b94508732bcbacbcc020faefecfc89feafa6649a5491b8c952cede496c214a0c7b3c392d168748f2d4a612bada0753b52a1c7ac53c1e93abd5c6320b9e95dd"
],
[
"TREZOR",
"808080808080808080808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter always",
"107d7c02a5aa6f38c58083ff74f04c607c2d2c0ecc55501dadd72d025b751bc27fe913ffb796f841c49b1d33b610cf0e91d3aa239027f5e99fe4ce9e5088cd65"
],
[
"TREZOR",
"ffffffffffffffffffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo when",
"0cd6e5d827bb62eb8fc1e262254223817fd068a74b5b449cc2f667c3f1f985a76379b43348d952e2265b4cd129090758b3e3c2c49103b5051aac2eaeb890a528"
],
[
"TREZOR",
"0000000000000000000000000000000000000000000000000000000000000000",
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
"bda85446c68413707090a52022edd26a1c9462295029f2e60cd7c4f2bbd3097170af7a4d73245cafa9c3cca8d561a7c3de6f5d4a10be8ed2a5e608d68f92fcc8"
],
[
"TREZOR",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title",
"bc09fca1804f7e69da93c2f2028eb238c227f2e9dda30cd63699232578480a4021b146ad717fbb7e451ce9eb835f43620bf5c514db0f8add49f5d121449d3e87"
],
[
"TREZOR",
"8080808080808080808080808080808080808080808080808080808080808080",
"letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic bless",
"c0c519bd0e91a2ed54357d9d1ebef6f5af218a153624cf4f2da911a0ed8f7a09e2ef61af0aca007096df430022f7a2b6fb91661a9589097069720d015e4e982f"
],
[
"TREZOR",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo vote",
"dd48c104698c30cfe2b6142103248622fb7bb0ff692eebb00089b32d22484e1613912f0a5b694407be899ffd31ed3992c456cdf60f5d4564b8ba3f05a69890ad"
],
[
"TREZOR",
"77c2b00716cec7213839159e404db50d",
"jelly better achieve collect unaware mountain thought cargo oxygen act hood bridge",
"b5b6d0127db1a9d2226af0c3346031d77af31e918dba64287a1b44b8ebf63cdd52676f672a290aae502472cf2d602c051f3e6f18055e84e4c43897fc4e51a6ff"
],
[
"TREZOR",
"b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b",
"renew stay biology evidence goat welcome casual join adapt armor shuffle fault little machine walk stumble urge swap",
"9248d83e06f4cd98debf5b6f010542760df925ce46cf38a1bdb4e4de7d21f5c39366941c69e1bdbf2966e0f6e6dbece898a0e2f0a4c2b3e640953dfe8b7bbdc5"
],
[
"TREZOR",
"3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982",
"dignity pass list indicate nasty swamp pool script soccer toe leaf photo multiply desk host tomato cradle drill spread actor shine dismiss champion exotic",
"ff7f3184df8696d8bef94b6c03114dbee0ef89ff938712301d27ed8336ca89ef9635da20af07d4175f2bf5f3de130f39c9d9e8dd0472489c19b1a020a940da67"
],
[
"TREZOR",
"0460ef47585604c5660618db2e6a7e7f",
"afford alter spike radar gate glance object seek swamp infant panel yellow",
"65f93a9f36b6c85cbe634ffc1f99f2b82cbb10b31edc7f087b4f6cb9e976e9faf76ff41f8f27c99afdf38f7a303ba1136ee48a4c1e7fcd3dba7aa876113a36e4"
],
[
"TREZOR",
"72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f",
"indicate race push merry suffer human cruise dwarf pole review arch keep canvas theme poem divorce alter left",
"3bbf9daa0dfad8229786ace5ddb4e00fa98a044ae4c4975ffd5e094dba9e0bb289349dbe2091761f30f382d4e35c4a670ee8ab50758d2c55881be69e327117ba"
],
[
"TREZOR",
"2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416",
"clutch control vehicle tonight unusual clog visa ice plunge glimpse recipe series open hour vintage deposit universe tip job dress radar refuse motion taste",
"fe908f96f46668b2d5b37d82f558c77ed0d69dd0e7e043a5b0511c48c2f1064694a956f86360c93dd04052a8899497ce9e985ebe0c8c52b955e6ae86d4ff4449"
],
[
"TREZOR",
"eaebabb2383351fd31d703840b32e9e2",
"turtle front uncle idea crush write shrug there lottery flower risk shell",
"bdfb76a0759f301b0b899a1e3985227e53b3f51e67e3f2a65363caedf3e32fde42a66c404f18d7b05818c95ef3ca1e5146646856c461c073169467511680876c"
],
[
"TREZOR",
"7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78",
"kiss carry display unusual confirm curtain upgrade antique rotate hello void custom frequent obey nut hole price segment",
"ed56ff6c833c07982eb7119a8f48fd363c4a9b1601cd2de736b01045c5eb8ab4f57b079403485d1c4924f0790dc10a971763337cb9f9c62226f64fff26397c79"
],
[
"TREZOR",
"4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef",
"exile ask congress lamp submit jacket era scheme attend cousin alcohol catch course end lucky hurt sentence oven short ball bird grab wing top",
"095ee6f817b4c2cb30a5a797360a81a40ab0f9a4e25ecd672a3f58a0b5ba0687c096a6b14d2c0deb3bdefce4f61d01ae07417d502429352e27695163f7447a8c"
],
[
"TREZOR",
"18ab19a9f54a9274f03e5209a2ac8a91",
"board flee heavy tunnel powder denial science ski answer betray cargo cat",
"6eff1bb21562918509c73cb990260db07c0ce34ff0e3cc4a8cb3276129fbcb300bddfe005831350efd633909f476c45c88253276d9fd0df6ef48609e8bb7dca8"
],
[
"TREZOR",
"18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4",
"board blade invite damage undo sun mimic interest slam gaze truly inherit resist great inject rocket museum chief",
"f84521c777a13b61564234bf8f8b62b3afce27fc4062b51bb5e62bdfecb23864ee6ecf07c1d5a97c0834307c5c852d8ceb88e7c97923c0a3b496bedd4e5f88a9"
],
[
"TREZOR",
"15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419",
"beyond stage sleep clip because twist token leaf atom beauty genius food business side grid unable middle armed observe pair crouch tonight away coconut",
"b15509eaa2d09d3efd3e006ef42151b30367dc6e3aa5e44caba3fe4d3e352e65101fbdb86a96776b91946ff06f8eac594dc6ee1d3e82a42dfe1b40fef6bcc3fd"
],
[
"TREZOR",
"38fe1937dd2135d7ca5e472565c41ded449d8cea2e70e1c93571c21831c82f0f466c3d94f29bff1d0cce3e85a22b93364627af716ee91a477d6e2e55abf4e761",
"decline valid evil ripple battle typical city similar century comfort alter surround endorse shoe post sock tide endless fragile loud loan tomato rotate trip history uncover device dawn vault major decline spawn peasant frame snow middle kit reward roof cash electric twin merit prize satisfy inhale lyrics lucky",
"d9a9b65c54df4104349d5ce6f9275f249160ddf378deff6e540f5492e449e0378ee20b1622bef982f6dddb003568e449fee66335cb45cbe3f8a41050b251238a"
]
],
"japanese": [
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"00000000000000000000000000000000",
"あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あおぞら",
"a262d6fb6122ecf45be09c50492b31f92e9beb7d9a845987a02cefda57a15f9c467a17872029a9e92299b5cbdf306e3a0ee620245cbd508959b6cb7ca637bd55"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかめ",
"aee025cbe6ca256862f889e48110a6a382365142f7d16f2b9545285b3af64e542143a577e9c144e101a6bdca18f8d97ec3366ebf5b088b1c1af9bc31346e60d9"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"80808080808080808080808080808080",
"そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あかちゃん",
"e51736736ebdf77eda23fa17e31475fa1d9509c78f1deb6b4aacfbd760a7e2ad769c714352c95143b5c1241985bcb407df36d64e75dd5a2b78ca5d2ba82a3544"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"ffffffffffffffffffffffffffffffff",
"われる われる われる われる われる われる われる われる われる われる われる ろんぶん",
"4cd2ef49b479af5e1efbbd1e0bdc117f6a29b1010211df4f78e2ed40082865793e57949236c43b9fe591ec70e5bb4298b8b71dc4b267bb96ed4ed282c8f7761c"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"000000000000000000000000000000000000000000000000",
"あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あらいぐま",
"d99e8f1ce2d4288d30b9c815ae981edd923c01aa4ffdc5dee1ab5fe0d4a3e13966023324d119105aff266dac32e5cd11431eeca23bbd7202ff423f30d6776d69"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れいぎ",
"eaaf171efa5de4838c758a93d6c86d2677d4ccda4a064a7136344e975f91fe61340ec8a615464b461d67baaf12b62ab5e742f944c7bd4ab6c341fbafba435716"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"808080808080808080808080808080808080808080808080",
"そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら いきなり",
"aec0f8d3167a10683374c222e6e632f2940c0826587ea0a73ac5d0493b6a632590179a6538287641a9fc9df8e6f24e01bf1be548e1f74fd7407ccd72ecebe425"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"ffffffffffffffffffffffffffffffffffffffffffffffff",
"われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる りんご",
"f0f738128a65b8d1854d68de50ed97ac1831fc3a978c569e415bbcb431a6a671d4377e3b56abd518daa861676c4da75a19ccb41e00c37d086941e471a4374b95"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"0000000000000000000000000000000000000000000000000000000000000000",
"あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん いってい",
"23f500eec4a563bf90cfda87b3e590b211b959985c555d17e88f46f7183590cd5793458b094a4dccc8f05807ec7bd2d19ce269e20568936a751f6f1ec7c14ddd"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f",
"そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん やちん そつう れきだい ほんやく わかす りくつ ばいか ろせん まんきつ",
"cd354a40aa2e241e8f306b3b752781b70dfd1c69190e510bc1297a9c5738e833bcdc179e81707d57263fb7564466f73d30bf979725ff783fb3eb4baa86560b05"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"8080808080808080808080808080808080808080808080808080808080808080",
"そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる いよく そとづら あまど おおう あこがれる いくぶん けいけん あたえる うめる",
"6b7cd1b2cdfeeef8615077cadd6a0625f417f287652991c80206dbd82db17bf317d5c50a80bd9edd836b39daa1b6973359944c46d3fcc0129198dc7dc5cd0e68"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
"われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる われる らいう",
"a44ba7054ac2f9226929d56505a51e13acdaa8a9097923ca07ea465c4c7e294c038f3f4e7e4b373726ba0057191aced6e48ac8d183f3a11569c426f0de414623"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"77c2b00716cec7213839159e404db50d",
"せまい うちがわ あずき かろう めずらしい だんち ますく おさめる ていぼう あたる すあな えしゃく",
"344cef9efc37d0cb36d89def03d09144dd51167923487eec42c487f7428908546fa31a3c26b7391a2b3afe7db81b9f8c5007336b58e269ea0bd10749a87e0193"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"b63a9c59a6e641f288ebc103017f1da9f8290b3da6bdef7b",
"ぬすむ ふっかつ うどん こうりつ しつじ りょうり おたがい せもたれ あつめる いちりゅう はんしゃ ごますり そんけい たいちょう らしんばん ぶんせき やすみ ほいく",
"b14e7d35904cb8569af0d6a016cee7066335a21c1c67891b01b83033cadb3e8a034a726e3909139ecd8b2eb9e9b05245684558f329b38480e262c1d6bc20ecc4"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"3e141609b97933b66a060dcddc71fad1d91677db872031e85f4c015c5e7e8982",
"くのう てぬぐい そんかい すろっと ちきゅう ほあん とさか はくしゅ ひびく みえる そざい てんすう たんぴん くしょう すいようび みけん きさらぎ げざん ふくざつ あつかう はやい くろう おやゆび こすう",
"32e78dce2aff5db25aa7a4a32b493b5d10b4089923f3320c8b287a77e512455443298351beb3f7eb2390c4662a2e566eec5217e1a37467af43b46668d515e41b"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"0460ef47585604c5660618db2e6a7e7f",
"あみもの いきおい ふいうち にげる ざんしょ じかん ついか はたん ほあん すんぽう てちがい わかめ",
"0acf902cd391e30f3f5cb0605d72a4c849342f62bd6a360298c7013d714d7e58ddf9c7fdf141d0949f17a2c9c37ced1d8cb2edabab97c4199b142c829850154b"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"72f60ebac5dd8add8d2a25a797102c3ce21bc029c200076f",
"すろっと にくしみ なやむ たとえる へいこう すくう きない けってい とくべつ ねっしん いたみ せんせい おくりがな まかい とくい けあな いきおい そそぐ",
"9869e220bec09b6f0c0011f46e1f9032b269f096344028f5006a6e69ea5b0b8afabbb6944a23e11ebd021f182dd056d96e4e3657df241ca40babda532d364f73"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"2c85efc7f24ee4573d2b81a6ec66cee209b2dcbd09d8eddc51e0215b0b68e416",
"かほご きうい ゆたか みすえる もらう がっこう よそう ずっと ときどき したうけ にんか はっこう つみき すうじつ よけい くげん もくてき まわり せめる げざい にげる にんたい たんそく ほそく",
"713b7e70c9fbc18c831bfd1f03302422822c3727a93a5efb9659bec6ad8d6f2c1b5c8ed8b0b77775feaf606e9d1cc0a84ac416a85514ad59f5541ff5e0382481"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"eaebabb2383351fd31d703840b32e9e2",
"めいえん さのう めだつ すてる きぬごし ろんぱ はんこ まける たいおう さかいし ねんいり はぶらし",
"06e1d5289a97bcc95cb4a6360719131a786aba057d8efd603a547bd254261c2a97fcd3e8a4e766d5416437e956b388336d36c7ad2dba4ee6796f0249b10ee961"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"7ac45cfe7722ee6c7ba84fbc2d5bd61b45cb2fe5eb65aa78",
"せんぱい おしえる ぐんかん もらう きあい きぼう やおや いせえび のいず じゅしん よゆう きみつ さといも ちんもく ちわわ しんせいじ とめる はちみつ",
"1fef28785d08cbf41d7a20a3a6891043395779ed74503a5652760ee8c24dfe60972105ee71d5168071a35ab7b5bd2f8831f75488078a90f0926c8e9171b2bc4a"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"4fa1a8bc3e6d80ee1316050e862c1812031493212b7ec3f3bb1b08f168cabeef",
"こころ いどう きあつ そうがんきょう へいあん せつりつ ごうせい はいち いびき きこく あんい おちつく きこえる けんとう たいこ すすめる はっけん ていど はんおん いんさつ うなぎ しねま れいぼう みつかる",
"43de99b502e152d4c198542624511db3007c8f8f126a30818e856b2d8a20400d29e7a7e3fdd21f909e23be5e3c8d9aee3a739b0b65041ff0b8637276703f65c2"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"18ab19a9f54a9274f03e5209a2ac8a91",
"うりきれ さいせい じゆう むろん とどける ぐうたら はいれつ ひけつ いずれ うちあわせ おさめる おたく",
"3d711f075ee44d8b535bb4561ad76d7d5350ea0b1f5d2eac054e869ff7963cdce9581097a477d697a2a9433a0c6884bea10a2193647677977c9820dd0921cbde"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"18a2e1d81b8ecfb2a333adcb0c17a5b9eb76cc5d05db91a4",
"うりきれ うねる せっさたくま きもち めんきょ へいたく たまご ぜっく びじゅつかん さんそ むせる せいじ ねくたい しはらい せおう ねんど たんまつ がいけん",
"753ec9e333e616e9471482b4b70a18d413241f1e335c65cd7996f32b66cf95546612c51dcf12ead6f805f9ee3d965846b894ae99b24204954be80810d292fcdd"
],
[
"メートルガバヴァぱばぐゞちぢ十人十色",
"15da872c95a13dd738fbf50e427583ad61f18fd99f628c417a61cf8343c90419",
"うちゅう ふそく ひしょ がちょう うけもつ めいそう みかん そざい いばる うけとる さんま さこつ おうさま ぱんつ しひょう めした たはつ いちぶ つうじょう てさぎょう きつね みすえる いりぐち かめれおん",
"346b7321d8c04f6f37b49fdf062a2fddc8e1bf8f1d33171b65074531ec546d1d3469974beccb1a09263440fc92e1042580a557fdce314e27ee4eabb25fa5e5fe"
]
]
}

6
test/index.html

@ -4,13 +4,13 @@
<title>Mocha</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../node_modules/bitcore-build/node_modules/mocha/mocha.css" />
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="../node_modules/bitcore-build/node_modules/mocha/mocha.js"></script>
<script src="../node_modules/mocha/mocha.js"></script>
<script>mocha.setup('bdd')</script>
<script src="../tests.js"></script>
<script src="../build/tests.js"></script>
<script>
mocha.run();
</script>

225
test/mnmenonic/mnemonic.js

@ -0,0 +1,225 @@
'use strict';
var chai = require('chai');
var should = chai.should();
var bch = require('../..');
var Mnemonic = bch.Mnemonic;
var errors = bch.errors;
var bip39_vectors = require('../data/mnemonics.json');
describe('Mnemonic', function() {
this.timeout(30000);
it('should initialize the class', function() {
should.exist(Mnemonic);
});
describe('# Mnemonic', function() {
describe('Constructor', function() {
it('does not require new keyword', function() {
var mnemonic = Mnemonic(); // jshint ignore:line
mnemonic.should.be.instanceof(Mnemonic);
});
it('should fail with invalid data', function() {
(function() {
return new Mnemonic({});
}).should.throw(errors.InvalidArgument);
});
it('should fail with unknown word list', function() {
(function() {
return new Mnemonic('pilots foster august tomorrow kit daughter unknown awesome model town village master');
}).should.throw(errors.UnknownWordlist);
});
it('should fail with invalid mnemonic', function() {
(function() {
return new Mnemonic('monster foster august tomorrow kit daughter unknown awesome model town village pilot');
}).should.throw(errors.InvalidMnemonic);
});
it('should fail with invalid ENT', function() {
(function() {
return new Mnemonic(64);
}).should.throw(errors.InvalidArgument);
});
it('constructor defaults to english worldlist', function() {
var mnemonic = new Mnemonic();
mnemonic.wordlist.should.equal(Mnemonic.Words.ENGLISH);
});
it('allow using different worldlists', function() {
var mnemonic = new Mnemonic(Mnemonic.Words.SPANISH);
mnemonic.wordlist.should.equal(Mnemonic.Words.SPANISH);
});
it('constructor honor both length and wordlist', function() {
var mnemonic = new Mnemonic(32 * 7, Mnemonic.Words.SPANISH);
mnemonic.phrase.split(' ').length.should.equal(21);
mnemonic.wordlist.should.equal(Mnemonic.Words.SPANISH);
});
it('constructor should detect standard wordlist', function() {
var mnemonic = new Mnemonic('afirmar diseño hielo fideo etapa ogro cambio fideo toalla pomelo número buscar');
mnemonic.wordlist.should.equal(Mnemonic.Words.SPANISH);
});
});
it('english wordlist is complete', function() {
Mnemonic.Words.ENGLISH.length.should.equal(2048);
Mnemonic.Words.ENGLISH[0].should.equal('abandon');
});
it('spanish wordlist is complete', function() {
Mnemonic.Words.SPANISH.length.should.equal(2048);
Mnemonic.Words.SPANISH[0].should.equal('ábaco');
});
it('japanese wordlist is complete', function() {
Mnemonic.Words.JAPANESE.length.should.equal(2048);
Mnemonic.Words.JAPANESE[0].should.equal('あいこくしん');
});
it('chinese wordlist is complete', function() {
Mnemonic.Words.CHINESE.length.should.equal(2048);
Mnemonic.Words.CHINESE[0].should.equal('的');
});
it('french wordlist is complete', function() {
Mnemonic.Words.FRENCH.length.should.equal(2048);
Mnemonic.Words.FRENCH[0].should.equal('abaisser');
});
it('italian wordlist is complete', function() {
Mnemonic.Words.ITALIAN.length.should.equal(2048);
Mnemonic.Words.ITALIAN[0].should.equal('abaco');
});
it('allows use different phrase lengths', function() {
var mnemonic;
mnemonic = new Mnemonic(32 * 4);
mnemonic.phrase.split(' ').length.should.equal(12);
mnemonic = new Mnemonic(32 * 5);
mnemonic.phrase.split(' ').length.should.equal(15);
mnemonic = new Mnemonic(32 * 6);
mnemonic.phrase.split(' ').length.should.equal(18);
mnemonic = new Mnemonic(32 * 7);
mnemonic.phrase.split(' ').length.should.equal(21);
mnemonic = new Mnemonic(32 * 8);
mnemonic.phrase.split(' ').length.should.equal(24);
});
it('validates a phrase', function() {
var valid = Mnemonic.isValid('afirmar diseño hielo fideo etapa ogro cambio fideo toalla pomelo número buscar');
valid.should.equal(true);
var invalid = Mnemonic.isValid('afirmar diseño hielo fideo etapa ogro cambio fideo hielo pomelo número buscar');
invalid.should.equal(false);
var invalid2 = Mnemonic.isValid('afirmar diseño hielo fideo etapa ogro cambio fideo hielo pomelo número oneInvalidWord');
invalid2.should.equal(false);
var invalid3 = Mnemonic.isValid('totally invalid phrase');
invalid3.should.equal(false);
var valid2 = Mnemonic.isValid('caution opprimer époque belote devenir ficeler filleul caneton apologie nectar frapper fouiller');
valid2.should.equal(true);
});
it('has a toString method', function() {
var mnemonic = new Mnemonic();
mnemonic.toString().should.equal(mnemonic.phrase);
});
it('has a toString method', function() {
var mnemonic = new Mnemonic();
mnemonic.inspect().should.have.string('<Mnemonic:');
});
it('derives a seed without a passphrase', function() {
var mnemonic = new Mnemonic();
var seed = mnemonic.toSeed();
should.exist(seed);
});
it('derives a seed using a passphrase', function() {
var mnemonic = new Mnemonic();
var seed = mnemonic.toSeed('my passphrase');
should.exist(seed);
});
it('derives an extended private key', function() {
var mnemonic = new Mnemonic();
var pk = mnemonic.toHDPrivateKey();
should.exist(pk);
});
it('Mnemonic.fromSeed should fail with invalid wordlist', function() {
(function() {
return Mnemonic.fromSeed(new Buffer(1));
}).should.throw(errors.InvalidArgument);
});
it('Mnemonic.fromSeed should fail with invalid seed', function() {
(function() {
return Mnemonic.fromSeed();
}).should.throw(errors.InvalidArgument);
});
it('Constructor should fail with invalid seed', function() {
(function() {
return new Mnemonic(new Buffer(1));
}).should.throw(errors.InvalidEntropy);
});
// To add new vectors for different languages:
// 1. Add and implement the wordlist so it appears in Mnemonic.Words
// 2. Add the vectors and make sure the key is lowercase of the key for Mnemonic.Words
var vector_wordlists = {};
for (var key in Mnemonic.Words) {
if (Mnemonic.Words.hasOwnProperty(key)) {
vector_wordlists[key.toLowerCase()] = Mnemonic.Words[key];
}
}
var test_vector = function(v, lang) {
it('should pass test vector for ' + lang + ' #' + v, function() {
var wordlist = vector_wordlists[lang];
var vector = bip39_vectors[lang][v];
var code = vector[1];
var mnemonic = vector[2];
var seed = vector[3];
var mnemonic1 = Mnemonic.fromSeed(new Buffer(code, 'hex'), wordlist).phrase;
mnemonic1.should.equal(mnemonic);
var m = new Mnemonic(mnemonic);
var seed1 = m.toSeed(vector[0]);
seed1.toString('hex').should.equal(seed);
Mnemonic.isValid(mnemonic, wordlist).should.equal(true);
});
};
for (var key in bip39_vectors) {
if (bip39_vectors.hasOwnProperty(key)) {
for (var v = 0; v < bip39_vectors[key].length; v++) {
test_vector(v, key);
}
}
}
});
});

44
test/mnmenonic/pbkdf2.js

@ -0,0 +1,44 @@
'use strict';
var chai = require('chai');
var should = chai.should();
var bch = require('../..');
var pbkdf2 = bch.Mnemonic.pbkdf2;
describe('pbkdf2', function() {
this.timeout(10000);
// http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors
it('passes test vector 1', function() {
var key = 'password';
var salt = 'salt';
var res = pbkdf2(key, salt, 1, 64);
res.toString('hex').should.equal('867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce');
});
it('passes test vector 2', function() {
var key = 'password';
var salt = 'salt';
var res = pbkdf2(key, salt, 2, 64);
res.toString('hex').should.equal('e1d9c16aa681708a45f5c7c4e215ceb66e011a2e9f0040713f18aefdb866d53cf76cab2868a39b9f7840edce4fef5a82be67335c77a6068e04112754f27ccf4e');
});
it('passes test vector 3', function() {
var key = 'password';
var salt = 'salt';
var res = pbkdf2(key, salt, 4096, 64);
res.toString('hex').should.equal('d197b1b33db0143e018b12f3d1d1479e6cdebdcc97c5c0f87f6902e072f457b5143f30602641b3d55cd335988cb36b84376060ecd532e039b742a239434af2d5');
});
it('passes test vector 4', function() {
var key = 'passwordPASSWORDpassword';
var salt = 'saltSALTsaltSALTsaltSALTsaltSALTsalt';
var res = pbkdf2(key, salt, 4096, 64);
res.toString('hex').should.equal('8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b868c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30225c583a186cd82bd4daea9724a3d3b8');
});
});

2
test/mocha.opts

@ -1,2 +1,2 @@
--recursive
--timeout 5000
--timeout 7000

3
test/transaction/deserialize.js

@ -1,6 +1,7 @@
'use strict';
var Transaction = require('../../lib/transaction');
var bch = require('../..');
var Transaction = bch.Transaction;
var vectors_valid = require('../data/bitcoind/tx_valid.json');
var vectors_invalid = require('../data/bitcoind/tx_invalid.json');

Loading…
Cancel
Save