hd: do not store mnemonic on hd private key.
This commit is contained in:
parent
d7e2942117
commit
aa7e550f91
@ -5,8 +5,9 @@ var bench = require('./bench');
|
||||
var HD = require('../lib/hd');
|
||||
var Mnemonic = require('../lib/hd/mnemonic');
|
||||
|
||||
var key = HD.fromMnemonic();
|
||||
var phrase = key.mnemonic.getPhrase();
|
||||
var mnemonic = new Mnemonic();
|
||||
var key = HD.fromMnemonic(mnemonic);
|
||||
var phrase = mnemonic.getPhrase();
|
||||
var i, end;
|
||||
|
||||
assert.equal(Mnemonic.fromPhrase(phrase).getPhrase(), phrase);
|
||||
|
||||
@ -27,14 +27,12 @@ var HDPublicKey = require('./public');
|
||||
* @constructor
|
||||
* @param {Object|Base58String} options
|
||||
* @param {Base58String?} options.xkey - Serialized base58 key.
|
||||
* @param {Mnemonic?} options.mnemonic
|
||||
* @param {Number?} options.depth
|
||||
* @param {Buffer?} options.parentFingerPrint
|
||||
* @param {Number?} options.childIndex
|
||||
* @param {Buffer?} options.chainCode
|
||||
* @param {Buffer?} options.privateKey
|
||||
* @property {Network} network
|
||||
* @property {Mnemonic?} mnemonic
|
||||
* @property {Number} depth
|
||||
* @property {Buffer} parentFingerPrint
|
||||
* @property {Number} childIndex
|
||||
@ -56,8 +54,6 @@ function HDPrivateKey(options) {
|
||||
this.publicKey = encoding.ZERO_KEY;
|
||||
this.fingerPrint = null;
|
||||
|
||||
this.mnemonic = null;
|
||||
|
||||
this._xprivkey = null;
|
||||
|
||||
this._hdPublicKey = null;
|
||||
@ -91,16 +87,6 @@ HDPrivateKey.prototype.fromOptions = function fromOptions(options) {
|
||||
this.privateKey = options.privateKey;
|
||||
this.publicKey = ec.publicKeyCreate(options.privateKey, true);
|
||||
|
||||
if (options.mnemonic) {
|
||||
assert(options.mnemonic instanceof Mnemonic);
|
||||
this.mnemonic = options.mnemonic;
|
||||
}
|
||||
|
||||
if (options.xprivkey) {
|
||||
assert(typeof options.xprivkey === 'string');
|
||||
this._xprivkey = options.xprivkey;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@ -194,11 +180,6 @@ HDPrivateKey.prototype.destroy = function destroy(pub) {
|
||||
}
|
||||
|
||||
this._xprivkey = null;
|
||||
|
||||
if (this.mnemonic) {
|
||||
this.mnemonic.destroy();
|
||||
this.mnemonic = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -543,21 +524,19 @@ HDPrivateKey.fromSeed = function fromSeed(seed, network) {
|
||||
/**
|
||||
* Inject properties from a mnemonic.
|
||||
* @private
|
||||
* @param {Mnemonic|Object} mnemonic
|
||||
* @param {Mnemonic} mnemonic
|
||||
* @param {(Network|NetworkType)?} network
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.fromMnemonic = function fromMnemonic(mnemonic, network) {
|
||||
if (!(mnemonic instanceof Mnemonic))
|
||||
mnemonic = new Mnemonic(mnemonic);
|
||||
assert(mnemonic instanceof Mnemonic);
|
||||
this.fromSeed(mnemonic.toSeed(), network);
|
||||
this.mnemonic = mnemonic;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an hd private key from a mnemonic.
|
||||
* @param {Mnemonic|Object} mnemonic
|
||||
* @param {Mnemonic} mnemonic
|
||||
* @param {(Network|NetworkType)?} network
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
@ -566,6 +545,30 @@ HDPrivateKey.fromMnemonic = function fromMnemonic(mnemonic, network) {
|
||||
return new HDPrivateKey().fromMnemonic(mnemonic, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from a mnemonic.
|
||||
* @private
|
||||
* @param {String} mnemonic
|
||||
* @param {(Network|NetworkType)?} network
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.fromPhrase = function fromPhrase(phrase, network) {
|
||||
var mnemonic = Mnemonic.fromPhrase(phrase);
|
||||
this.fromMnemonic(mnemonic, network);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an hd private key from a phrase.
|
||||
* @param {String} phrase
|
||||
* @param {(Network|NetworkType)?} network
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HDPrivateKey.fromPhrase = function fromPhrase(phrase, network) {
|
||||
return new HDPrivateKey().fromPhrase(phrase, network);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from privateKey and entropy.
|
||||
* @private
|
||||
@ -722,97 +725,6 @@ HDPrivateKey.prototype.toRaw = function toRaw(network) {
|
||||
return this.toWriter(new StaticWriter(82), network).render();
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate extended serialization size.
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.getExtendedSize = function getSize() {
|
||||
var size = this.getSize();
|
||||
|
||||
size += 1;
|
||||
|
||||
if (this.mnemonic)
|
||||
size += this.mnemonic.getSize();
|
||||
|
||||
return size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write the key in "extended"
|
||||
* format to a buffer writer.
|
||||
* @param {BufferWriter} bw
|
||||
* @param {(Network|NetworkType)?} network
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.toExtendedWriter = function toExtendedWriter(bw, network) {
|
||||
this.toWriter(bw, network);
|
||||
|
||||
if (this.mnemonic) {
|
||||
bw.writeU8(1);
|
||||
this.mnemonic.toWriter(bw);
|
||||
} else {
|
||||
bw.writeU8(0);
|
||||
}
|
||||
|
||||
return bw;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize the key in "extended"
|
||||
* format (includes the mnemonic).
|
||||
* @param {(Network|NetworkType)?} network
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.toExtended = function toExtended(network) {
|
||||
var size = this.getExtendedSize();
|
||||
return this.toExtendedWriter(new StaticWriter(size), network).render();
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from buffer reader.
|
||||
* @private
|
||||
* @param {BufferReader} br
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.fromExtendedReader = function fromExtendedReader(br) {
|
||||
this.fromReader(br);
|
||||
if (br.readU8() === 1)
|
||||
this.mnemonic = Mnemonic.fromReader(br);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from extended serialized data.
|
||||
* @private
|
||||
* @param {Buffer} data
|
||||
*/
|
||||
|
||||
HDPrivateKey.prototype.fromExtended = function fromExtended(data) {
|
||||
return this.fromExtendedReader(new BufferReader(data));
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate key from "extended" buffer reader.
|
||||
* @param {BufferReader} br
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HDPrivateKey.fromExtendedReader = function fromExtendedReader(br) {
|
||||
return new HDPrivateKey().fromExtendedReader(br);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate key from "extended" serialized data.
|
||||
* @param {Buffer} data
|
||||
* @returns {HDPrivateKey}
|
||||
*/
|
||||
|
||||
HDPrivateKey.fromExtended = function fromExtended(data) {
|
||||
return new HDPrivateKey().fromExtended(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate an HD private key from a base58 string.
|
||||
* @param {Base58String} xkey
|
||||
@ -851,8 +763,7 @@ HDPrivateKey.fromRaw = function fromRaw(raw) {
|
||||
|
||||
HDPrivateKey.prototype.toJSON = function toJSON() {
|
||||
return {
|
||||
xprivkey: this.xprivkey(),
|
||||
mnemonic: this.mnemonic ? this.mnemonic.toJSON() : null
|
||||
xprivkey: this.xprivkey()
|
||||
};
|
||||
};
|
||||
|
||||
@ -868,9 +779,6 @@ HDPrivateKey.prototype.fromJSON = function fromJSON(json, network) {
|
||||
|
||||
this.fromBase58(json.xprivkey, network);
|
||||
|
||||
if (json.mnemonic)
|
||||
this.mnemonic = Mnemonic.fromJSON(json.mnemonic);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@ -894,7 +802,7 @@ HDPrivateKey.fromJSON = function fromJSON(json, network) {
|
||||
HDPrivateKey.isHDPrivateKey = function isHDPrivateKey(obj) {
|
||||
return obj
|
||||
&& typeof obj.derive === 'function'
|
||||
&& typeof obj.toExtended === 'function'
|
||||
&& typeof obj.fromMnemonic === 'function'
|
||||
&& obj.chainCode !== undefined;
|
||||
};
|
||||
|
||||
|
||||
@ -79,11 +79,6 @@ HDPublicKey.prototype.fromOptions = function fromOptions(options) {
|
||||
this.chainCode = options.chainCode;
|
||||
this.publicKey = options.publicKey;
|
||||
|
||||
if (options.xpubkey) {
|
||||
assert(typeof options.xpubkey === 'string');
|
||||
this._xpubkey = options.xpubkey;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ var BufferReader = require('../utils/reader');
|
||||
var StaticWriter = require('../utils/staticwriter');
|
||||
var encoding = require('../utils/encoding');
|
||||
var HD = require('../hd/hd');
|
||||
var Mnemonic = HD.Mnemonic;
|
||||
|
||||
/**
|
||||
* Master BIP32 key which can exist
|
||||
@ -32,6 +33,7 @@ function MasterKey(options) {
|
||||
this.iv = null;
|
||||
this.ciphertext = null;
|
||||
this.key = null;
|
||||
this.mnemonic = null;
|
||||
|
||||
this.alg = MasterKey.alg.PBKDF2;
|
||||
this.N = 50000;
|
||||
@ -103,10 +105,15 @@ MasterKey.prototype.fromOptions = function fromOptions(options) {
|
||||
}
|
||||
|
||||
if (options.key) {
|
||||
assert(HD.isHD(options.key));
|
||||
assert(HD.isPrivate(options.key));
|
||||
this.key = options.key;
|
||||
}
|
||||
|
||||
if (options.mnemonic) {
|
||||
assert(options.mnemonic instanceof Mnemonic);
|
||||
this.mnemonic = options.mnemonic;
|
||||
}
|
||||
|
||||
if (options.alg != null) {
|
||||
if (typeof options.alg === 'string') {
|
||||
this.alg = MasterKey.alg[options.alg.toUpperCase()];
|
||||
@ -195,7 +202,7 @@ MasterKey.prototype._unlock = co(function* _unlock(passphrase, timeout) {
|
||||
key = yield this.derive(passphrase);
|
||||
data = crypto.decipher(this.ciphertext, key, this.iv);
|
||||
|
||||
this.key = HD.fromExtended(data);
|
||||
this.fromKeyRaw(data);
|
||||
|
||||
this.start(timeout);
|
||||
|
||||
@ -382,7 +389,7 @@ MasterKey.prototype._decrypt = co(function* decrypt(passphrase, clean) {
|
||||
key = yield this.derive(passphrase);
|
||||
data = crypto.decipher(this.ciphertext, key, this.iv);
|
||||
|
||||
this.key = HD.fromExtended(data);
|
||||
this.fromKeyRaw(data);
|
||||
this.encrypted = false;
|
||||
this.iv = null;
|
||||
this.ciphertext = null;
|
||||
@ -426,7 +433,7 @@ MasterKey.prototype._encrypt = co(function* encrypt(passphrase, clean) {
|
||||
if (!passphrase)
|
||||
throw new Error('No passphrase provided.');
|
||||
|
||||
data = this.key.toExtended();
|
||||
data = this.toKeyRaw();
|
||||
iv = crypto.randomBytes(16);
|
||||
|
||||
this.stop();
|
||||
@ -435,6 +442,7 @@ MasterKey.prototype._encrypt = co(function* encrypt(passphrase, clean) {
|
||||
data = crypto.encipher(data, key, iv);
|
||||
|
||||
this.key = null;
|
||||
this.mnemonic = null;
|
||||
this.encrypted = true;
|
||||
this.iv = iv;
|
||||
this.ciphertext = data;
|
||||
@ -447,6 +455,59 @@ MasterKey.prototype._encrypt = co(function* encrypt(passphrase, clean) {
|
||||
return key;
|
||||
});
|
||||
|
||||
/**
|
||||
* Calculate key serialization size.
|
||||
* @returns {Number}
|
||||
*/
|
||||
|
||||
MasterKey.prototype.getKeySize = function getKeySize() {
|
||||
var size = 0;
|
||||
|
||||
size += this.key.getSize();
|
||||
size += 1;
|
||||
|
||||
if (this.mnemonic)
|
||||
size += this.mnemonic.getSize();
|
||||
|
||||
return size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serialize key and menmonic to a single buffer.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
MasterKey.prototype.toKeyRaw = function toKeyRaw() {
|
||||
var bw = new StaticWriter(this.getKeySize());
|
||||
|
||||
this.key.toWriter(bw);
|
||||
|
||||
if (this.mnemonic) {
|
||||
bw.writeU8(1);
|
||||
this.mnemonic.toWriter(bw);
|
||||
} else {
|
||||
bw.writeU8(0);
|
||||
}
|
||||
|
||||
return bw.render();
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject properties from serialized key.
|
||||
* @param {Buffer} data
|
||||
*/
|
||||
|
||||
MasterKey.prototype.fromKeyRaw = function fromKeyRaw(data) {
|
||||
var br = new BufferReader(data);
|
||||
|
||||
this.key = HD.fromReader(br);
|
||||
|
||||
if (br.readU8() === 1)
|
||||
this.mnemonic = Mnemonic.fromReader(br);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate serialization size.
|
||||
* @returns {Number}
|
||||
@ -464,7 +525,7 @@ MasterKey.prototype.getSize = function getSize() {
|
||||
}
|
||||
|
||||
size += 1;
|
||||
size += encoding.sizeVarlen(this.key.getExtendedSize());
|
||||
size += encoding.sizeVarlen(this.getKeySize());
|
||||
|
||||
return size;
|
||||
};
|
||||
@ -493,7 +554,19 @@ MasterKey.prototype.toRaw = function toRaw() {
|
||||
}
|
||||
|
||||
bw.writeU8(0);
|
||||
bw.writeVarBytes(this.key.toExtended());
|
||||
|
||||
// NOTE: useless varint
|
||||
size = this.getKeySize();
|
||||
bw.writeVarint(size);
|
||||
|
||||
bw.writeBytes(this.key.toRaw());
|
||||
|
||||
if (this.mnemonic) {
|
||||
bw.writeU8(1);
|
||||
this.mnemonic.toWriter(bw);
|
||||
} else {
|
||||
bw.writeU8(0);
|
||||
}
|
||||
|
||||
return bw.render();
|
||||
};
|
||||
@ -524,7 +597,13 @@ MasterKey.prototype.fromRaw = function fromRaw(raw) {
|
||||
return this;
|
||||
}
|
||||
|
||||
this.key = HD.fromExtended(br.readVarBytes());
|
||||
// NOTE: useless varint
|
||||
br.skipVarint();
|
||||
|
||||
this.key = HD.fromRaw(br.readBytes(82));
|
||||
|
||||
if (br.readU8() === 1)
|
||||
this.mnemonic = Mnemonic.fromReader(br);
|
||||
|
||||
return this;
|
||||
};
|
||||
@ -542,24 +621,27 @@ MasterKey.fromRaw = function fromRaw(raw) {
|
||||
* Inject properties from an HDPrivateKey.
|
||||
* @private
|
||||
* @param {HDPrivateKey} key
|
||||
* @param {Mnemonic?} mnemonic
|
||||
*/
|
||||
|
||||
MasterKey.prototype.fromKey = function fromKey(key) {
|
||||
MasterKey.prototype.fromKey = function fromKey(key, mnemonic) {
|
||||
this.encrypted = false;
|
||||
this.iv = null;
|
||||
this.ciphertext = null;
|
||||
this.key = key;
|
||||
this.mnemonic = mnemonic || null;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate master key from an HDPrivateKey.
|
||||
* @param {HDPrivateKey} key
|
||||
* @param {Mnemonic?} mnemonic
|
||||
* @returns {MasterKey}
|
||||
*/
|
||||
|
||||
MasterKey.fromKey = function fromKey(key) {
|
||||
return new MasterKey().fromKey(key);
|
||||
MasterKey.fromKey = function fromKey(key, mnemonic) {
|
||||
return new MasterKey().fromKey(key, mnemonic);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -585,7 +667,8 @@ MasterKey.prototype.toJSON = function toJSON(unsafe) {
|
||||
|
||||
return {
|
||||
encrypted: false,
|
||||
key: unsafe ? this.key.toJSON() : undefined
|
||||
key: unsafe ? this.key.toJSON() : undefined,
|
||||
mnemonic: unsafe && this.mnemonic ? this.mnemonic.toJSON() : undefined
|
||||
};
|
||||
};
|
||||
|
||||
@ -596,8 +679,13 @@ MasterKey.prototype.toJSON = function toJSON(unsafe) {
|
||||
|
||||
MasterKey.prototype.inspect = function inspect() {
|
||||
var json = this.toJSON(true);
|
||||
|
||||
if (this.key)
|
||||
json.key = this.key.toJSON();
|
||||
|
||||
if (this.mnemonic)
|
||||
json.mnemonic = this.mnemonic.toJSON();
|
||||
|
||||
return json;
|
||||
};
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ var MasterKey = require('./masterkey');
|
||||
var LRU = require('../utils/lru');
|
||||
var policy = require('../protocol/policy');
|
||||
var consensus = require('../protocol/consensus');
|
||||
var Mnemonic = HD.Mnemonic;
|
||||
|
||||
/**
|
||||
* BIP44 Wallet
|
||||
@ -102,26 +103,24 @@ util.inherits(Wallet, EventEmitter);
|
||||
|
||||
Wallet.prototype.fromOptions = function fromOptions(options) {
|
||||
var key = options.master;
|
||||
var id, token;
|
||||
var id, token, mnemonic;
|
||||
|
||||
if (MasterKey.isMasterKey(key)) {
|
||||
this.master.fromOptions(key);
|
||||
} else {
|
||||
if (!key)
|
||||
key = HD.fromMnemonic(null, this.network);
|
||||
|
||||
if (HD.isBase58(key))
|
||||
if (key) {
|
||||
if (typeof key === 'string')
|
||||
key = HD.fromBase58(key, this.network);
|
||||
|
||||
assert(HD.isPrivate(key),
|
||||
'Must create wallet with hd private key.');
|
||||
|
||||
assert(key.verifyNetwork(this.network),
|
||||
'Network mismatch for master key.');
|
||||
|
||||
this.master.fromKey(key);
|
||||
} else {
|
||||
mnemonic = new Mnemonic(options.mnemonic);
|
||||
key = HD.fromMnemonic(mnemonic, this.network);
|
||||
}
|
||||
|
||||
assert(key.verifyNetwork(this.network),
|
||||
'Network mismatch for master key.');
|
||||
|
||||
this.master.fromKey(key, mnemonic);
|
||||
|
||||
if (options.wid != null) {
|
||||
assert(util.isNumber(options.wid));
|
||||
this.wid = options.wid;
|
||||
|
||||
@ -87,7 +87,7 @@ describe('HD', function() {
|
||||
});
|
||||
|
||||
it('should deserialize and reserialize', function() {
|
||||
var key = HD.fromMnemonic();
|
||||
var key = HD.generate();
|
||||
assert.equal(HD.fromJSON(key.toJSON()).toBase58(), key.toBase58());
|
||||
});
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ MemWallet.prototype.init = function init() {
|
||||
var i;
|
||||
|
||||
if (!this.master)
|
||||
this.master = HD.PrivateKey.fromMnemonic(null, this.network);
|
||||
this.master = HD.PrivateKey.generate();
|
||||
|
||||
if (!this.key)
|
||||
this.key = this.master.deriveAccount44(this.account);
|
||||
|
||||
@ -154,7 +154,7 @@ describe('Wallet', function() {
|
||||
n: 2
|
||||
});
|
||||
|
||||
k = HD.fromMnemonic().deriveAccount44(0).toPublic();
|
||||
k = HD.generate().deriveAccount44(0).toPublic();
|
||||
|
||||
yield w.addSharedKey(k);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user