bitcore-lib-zcash/test/hdprivatekey.js

312 lines
11 KiB
JavaScript
Raw Permalink Normal View History

2014-11-26 10:12:24 -08:00
'use strict';
/* jshint unused: false */
2014-11-27 14:03:27 -08:00
var _ = require('lodash');
var assert = require('assert');
2014-11-26 10:12:24 -08:00
var should = require('chai').should();
2014-11-27 14:03:27 -08:00
var expect = require('chai').expect;
2014-11-26 10:12:24 -08:00
var bitcore = require('..');
var errors = bitcore.errors;
var hdErrors = errors.HDPrivateKey;
2014-11-27 14:03:27 -08:00
var buffer = require('buffer');
2015-02-23 06:40:31 -08:00
var Networks = bitcore.Networks;
2014-12-23 05:56:16 -08:00
var BufferUtil = bitcore.util.buffer;
2014-11-26 10:12:24 -08:00
var HDPrivateKey = bitcore.HDPrivateKey;
2014-11-27 14:03:27 -08:00
var Base58Check = bitcore.encoding.Base58Check;
2014-11-26 10:12:24 -08:00
var xprivkey = 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi';
2014-11-27 14:03:27 -08:00
var json = '{"network":"livenet","depth":0,"fingerPrint":876747070,"parentFingerPrint":0,"childIndex":0,"chainCode":"873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508","privateKey":"e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35","checksum":-411132559,"xprivkey":"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi"}';
2014-11-26 10:12:24 -08:00
describe('HDPrivate key interface', function() {
2014-11-27 14:03:27 -08:00
/* jshint maxstatements: 50 */
2014-11-28 13:11:03 -08:00
var expectFail = function(func, error) {
var got = null;
try {
func();
} catch (e) {
got = e instanceof error;
}
expect(got).to.equal(true);
2014-11-27 14:03:27 -08:00
};
2014-11-26 10:12:24 -08:00
2014-11-27 14:03:27 -08:00
var expectDerivationFail = function(argument, error) {
2014-11-28 13:11:03 -08:00
return expectFail(function() {
2014-11-27 14:03:27 -08:00
var privateKey = new HDPrivateKey(xprivkey);
privateKey.derive(argument);
2014-11-28 13:11:03 -08:00
}, error);
2014-11-27 14:03:27 -08:00
};
2014-11-28 13:11:03 -08:00
var expectFailBuilding = function(argument, error) {
return expectFail(function() {
return new HDPrivateKey(argument);
}, error);
};
var expectSeedFail = function(argument, error) {
return expectFail(function() {
return HDPrivateKey.fromSeed(argument);
}, error);
};
2014-11-26 10:12:24 -08:00
it('should make a new private key from random', function() {
2014-12-10 12:50:46 -08:00
should.exist(new HDPrivateKey().xprivkey);
2014-11-27 14:03:27 -08:00
});
it('should make a new private key from random for testnet', function() {
var key = new HDPrivateKey('testnet');
should.exist(key.xprivkey);
key.network.name.should.equal('testnet');
});
it('should not be able to change read-only properties', function() {
var hdkey = new HDPrivateKey();
expect(function() {
hdkey.fingerPrint = 'notafingerprint';
}).to.throw(TypeError);
});
2014-11-27 14:03:27 -08:00
it('should error with an invalid checksum', function() {
2014-11-29 13:23:38 -08:00
expectFailBuilding(xprivkey + '1', errors.InvalidB58Checksum);
2014-11-27 14:03:27 -08:00
});
it('can be rebuilt from a json generated by itself', function() {
var regenerate = new HDPrivateKey(json);
regenerate.xprivkey.should.equal(xprivkey);
});
2014-11-28 07:11:41 -08:00
it('builds a json keeping the structure and same members', function() {
assert(_.isEqual(
new HDPrivateKey(json).toJSON(),
new HDPrivateKey(xprivkey).toJSON()
2014-11-27 14:03:27 -08:00
));
});
describe('instantiation', function() {
it('invalid argument: can not instantiate from a number', function() {
expectFailBuilding(1, hdErrors.UnrecognizedArgument);
2014-11-27 14:03:27 -08:00
});
it('allows no-new calling', function() {
HDPrivateKey(xprivkey).toString().should.equal(xprivkey);
});
2015-02-23 06:40:31 -08:00
it('allows the use of a copy constructor', function() {
HDPrivateKey(HDPrivateKey(xprivkey))
.xprivkey.should.equal(xprivkey);
});
2014-11-26 10:12:24 -08:00
});
2015-02-23 06:40:31 -08:00
describe('public key', function() {
var testnetKey = new HDPrivateKey('tprv8ZgxMBicQKsPdEeU2KiGFnUgRGriMnQxrwrg6FWCBg4jeiidHRyCCdA357kfkZiGaXEapWZsGDKikeeEbvgXo3UmEdbEKNdQH9VXESmGuUK');
var livenetKey = new HDPrivateKey('xprv9s21ZrQH143K3e39bnn1vyS7YFa1EAJAFGDoeHaSBsgBxgAkTEXeSx7xLvhNQNJxJwhzziWcK3znUFKRPRwWBPkKZ8ijUBa5YYpYPQmeBDX');
2014-12-14 12:13:01 -08:00
2015-02-23 06:40:31 -08:00
it('matches the network', function() {
testnetKey.publicKey.network.should.equal(Networks.testnet);
livenetKey.publicKey.network.should.equal(Networks.livenet);
});
2015-03-20 12:01:05 -07:00
it('cache for xpubkey works', function() {
var privateKey = new HDPrivateKey(xprivkey);
should.not.exist(privateKey._hdPublicKey);
privateKey.xpubkey.should.equal(privateKey.xpubkey);
should.exist(privateKey._hdPublicKey);
});
2014-11-26 10:12:24 -08:00
});
2015-02-23 06:40:31 -08:00
it('inspect() displays correctly', function() {
HDPrivateKey(xprivkey).inspect().should.equal('<HDPrivateKey: ' + xprivkey + '>');
});
2014-11-27 14:03:27 -08:00
it('fails when trying to derive with an invalid argument', function() {
expectDerivationFail([], hdErrors.InvalidDerivationArgument);
2014-11-27 14:03:27 -08:00
});
it('catches early invalid paths', function() {
expectDerivationFail('s', hdErrors.InvalidPath);
2014-11-27 14:03:27 -08:00
});
it('allows derivation of hardened keys by passing a very big number', function() {
var privateKey = new HDPrivateKey(xprivkey);
var derivedByNumber = privateKey.derive(0x80000000);
var derivedByArgument = privateKey.derive(0, true);
derivedByNumber.xprivkey.should.equal(derivedByArgument.xprivkey);
});
2015-02-09 10:40:06 -08:00
it('returns itself with \'m\' parameter', function() {
2014-11-27 14:03:27 -08:00
var privateKey = new HDPrivateKey(xprivkey);
privateKey.should.equal(privateKey.derive('m'));
});
it('returns InvalidArgument if invalid data is given to getSerializedError', function() {
2014-11-28 13:11:03 -08:00
expect(
2015-02-09 10:40:06 -08:00
HDPrivateKey.getSerializedError(1) instanceof hdErrors.UnrecognizedArgument
2014-11-28 13:11:03 -08:00
).to.equal(true);
2014-11-27 14:03:27 -08:00
});
it('returns InvalidLength if data of invalid length is given to getSerializedError', function() {
2015-02-09 10:40:06 -08:00
var b58s = Base58Check.encode(new buffer.Buffer('onestring'));
2014-11-28 13:11:03 -08:00
expect(
2015-02-09 10:40:06 -08:00
HDPrivateKey.getSerializedError(b58s) instanceof hdErrors.InvalidLength
2014-11-28 13:11:03 -08:00
).to.equal(true);
2014-11-27 14:03:27 -08:00
});
it('returns InvalidNetworkArgument if an invalid network is provided', function() {
2014-11-28 13:11:03 -08:00
expect(
2015-02-09 10:40:06 -08:00
HDPrivateKey.getSerializedError(xprivkey, 'invalidNetwork') instanceof errors.InvalidNetworkArgument
2014-11-28 13:11:03 -08:00
).to.equal(true);
2014-11-27 14:03:27 -08:00
});
it('recognizes that the wrong network was asked for', function() {
2014-11-28 13:11:03 -08:00
expect(
2015-02-09 10:40:06 -08:00
HDPrivateKey.getSerializedError(xprivkey, 'testnet') instanceof errors.InvalidNetwork
2014-11-28 13:11:03 -08:00
).to.equal(true);
2014-11-27 14:03:27 -08:00
});
it('recognizes the correct network', function() {
expect(HDPrivateKey.getSerializedError(xprivkey, 'livenet')).to.equal(null);
});
describe('on creation from seed', function() {
it('converts correctly from an hexa string', function() {
2014-12-10 12:50:46 -08:00
should.exist(HDPrivateKey.fromSeed('01234567890abcdef01234567890abcdef').xprivkey);
2014-11-27 14:03:27 -08:00
});
it('fails when argument is not a buffer or string', function() {
expectSeedFail(1, hdErrors.InvalidEntropyArgument);
2014-11-27 14:03:27 -08:00
});
it('fails when argument doesn\'t provide enough entropy', function() {
expectSeedFail('01', hdErrors.InvalidEntropyArgument.NotEnoughEntropy);
2014-11-27 14:03:27 -08:00
});
it('fails when argument provides too much entropy', function() {
var entropy = '0';
for (var i = 0; i < 129; i++) {
entropy += '1';
}
expectSeedFail(entropy, hdErrors.InvalidEntropyArgument.TooMuchEntropy);
2014-11-27 14:03:27 -08:00
});
});
it('correctly errors if an invalid checksum is provided', function() {
var privKey = new HDPrivateKey(xprivkey);
2014-11-28 13:11:03 -08:00
var error = null;
try {
2014-11-27 14:03:27 -08:00
var buffers = privKey._buffers;
2014-12-23 05:56:16 -08:00
buffers.checksum = BufferUtil.integerAsBuffer(0);
2014-11-28 13:11:03 -08:00
var privateKey = new HDPrivateKey(buffers);
} catch (e) {
error = e;
}
2014-11-29 13:23:38 -08:00
expect(error instanceof errors.InvalidB58Checksum).to.equal(true);
2014-11-27 14:03:27 -08:00
});
it('correctly validates the checksum', function() {
var privKey = new HDPrivateKey(xprivkey);
expect(function() {
var buffers = privKey._buffers;
return new HDPrivateKey(buffers);
}).to.not.throw();
});
2014-11-26 10:12:24 -08:00
it('shouldn\'t matter if derivations are made with strings or numbers', function() {
var privateKey = new HDPrivateKey(xprivkey);
var derivedByString = privateKey.derive('m/0\'/1/2\'');
var derivedByNumber = privateKey.derive(0, true).derive(1).derive(2, true);
derivedByNumber.xprivkey.should.equal(derivedByString.xprivkey);
});
2014-12-23 05:56:16 -08:00
2015-01-06 06:51:58 -08:00
describe('validates paths', function() {
it('validates correct paths', function() {
var valid;
2015-01-02 11:46:37 -08:00
2015-02-09 10:40:06 -08:00
valid = HDPrivateKey.isValidPath('m/0\'/1/2\'');
2015-01-06 06:51:58 -08:00
valid.should.equal(true);
2015-01-02 11:46:37 -08:00
2015-01-06 06:51:58 -08:00
valid = HDPrivateKey.isValidPath('m');
valid.should.equal(true);
valid = HDPrivateKey.isValidPath(123, true);
valid.should.equal(true);
valid = HDPrivateKey.isValidPath(123);
valid.should.equal(true);
valid = HDPrivateKey.isValidPath(HDPrivateKey.Hardened + 123);
valid.should.equal(true);
valid = HDPrivateKey.isValidPath(HDPrivateKey.Hardened + 123, true);
valid.should.equal(true);
});
2015-02-09 10:40:06 -08:00
var invalid = [
'm/-1/12',
'bad path',
'K',
'm/',
'm/12asd',
'm/1/2//3'
];
2015-01-06 06:51:58 -08:00
2015-02-09 10:40:06 -08:00
invalid.forEach(function(datum) {
it('rejects illegal path ' + datum, function() {
HDPrivateKey.isValidPath(datum).should.equal(false);
expect(HDPrivateKey._getDerivationIndexes(datum)).to.equal(null);
});
2015-01-06 06:51:58 -08:00
});
it('generates deriving indexes correctly', function() {
var indexes;
indexes = HDPrivateKey._getDerivationIndexes('m/-1/12');
2015-02-09 11:06:18 -08:00
expect(indexes).to.equal(null);
2015-01-06 06:51:58 -08:00
2015-02-09 10:40:06 -08:00
indexes = HDPrivateKey._getDerivationIndexes('m/0/12/12\'');
2015-01-06 06:51:58 -08:00
indexes.should.eql([0, 12, HDPrivateKey.Hardened + 12]);
2015-02-09 10:40:06 -08:00
indexes = HDPrivateKey._getDerivationIndexes('m/0/12/12\'');
2015-01-06 06:51:58 -08:00
indexes.should.eql([0, 12, HDPrivateKey.Hardened + 12]);
});
2015-01-02 11:46:37 -08:00
});
describe('conversion to/from buffer', function() {
var str = 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi';
it('should roundtrip to/from a buffer', function() {
var priv = new HDPrivateKey(str);
var toBuffer = priv.toBuffer();
var fromBuffer = HDPrivateKey.fromBuffer(toBuffer);
var roundTrip = new HDPrivateKey(fromBuffer.toBuffer());
roundTrip.xprivkey.should.equal(str);
});
});
2014-12-23 05:56:16 -08:00
describe('conversion to plain object/json', function() {
var plainObject = {
2015-02-09 10:40:06 -08:00
'network': 'livenet',
'depth': 0,
'fingerPrint': 876747070,
'parentFingerPrint': 0,
'childIndex': 0,
'chainCode': '873dff81c02f525623fd1fe5167eac3a55a049de3d314bb42ee227ffed37d508',
'privateKey': 'e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35',
'checksum': -411132559,
'xprivkey': 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvN' +
'KmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'
2014-12-23 05:56:16 -08:00
};
it('toObject leaves no Buffer instances', function() {
var privKey = new HDPrivateKey(xprivkey);
var object = privKey.toObject();
_.each(_.values(object), function(value) {
expect(BufferUtil.isBuffer(value)).to.equal(false);
});
});
it('roundtrips toObject', function() {
expect(HDPrivateKey.fromObject(new HDPrivateKey(xprivkey).toObject()).xprivkey).to.equal(xprivkey);
2014-12-23 05:56:16 -08:00
});
it('roundtrips to JSON and to Object', function() {
var privkey = new HDPrivateKey(xprivkey);
expect(HDPrivateKey.fromObject(privkey.toJSON()).xprivkey).to.equal(xprivkey);
2014-12-23 05:56:16 -08:00
});
it('recovers state from JSON', function() {
new HDPrivateKey(JSON.stringify(plainObject)).xprivkey.should.equal(xprivkey);
});
it('recovers state from Object', function() {
new HDPrivateKey(plainObject).xprivkey.should.equal(xprivkey);
});
});
2014-11-26 10:12:24 -08:00
});