diff --git a/lib/primitives/keyring.js b/lib/primitives/keyring.js index a388962a..cd411c19 100644 --- a/lib/primitives/keyring.js +++ b/lib/primitives/keyring.js @@ -40,7 +40,6 @@ function KeyRing(options, network) { this.publicKey = constants.ZERO_KEY; this.privateKey = null; this.script = null; - this.path = null; this._keyHash = null; this._keyAddress = null; @@ -152,11 +151,12 @@ KeyRing.prototype.fromPublic = function fromPublic(key, network) { /** * Generate a keyring. + * @private * @param {(Network|NetworkType)?} network * @returns {KeyRing} */ -KeyRing.generate = function(compressed, network) { +KeyRing.prototype.generate = function(compressed, network) { var key; if (typeof compressed !== 'boolean') { @@ -166,7 +166,17 @@ KeyRing.generate = function(compressed, network) { key = ec.generatePrivateKey(); - return KeyRing.fromKey(key, compressed, network); + return this.fromKey(key, compressed, network); +}; + +/** + * Generate a keyring. + * @param {(Network|NetworkType)?} network + * @returns {KeyRing} + */ + +KeyRing.generate = function(compressed, network) { + return new KeyRing().generate(compressed, network); }; /** @@ -793,12 +803,6 @@ KeyRing.prototype.toJSON = function toJSON() { publicKey: this.publicKey.toString('hex'), script: this.script ? this.script.toRaw().toString('hex') : null, type: constants.scriptTypesByVal[this.type].toLowerCase(), - wid: this.path ? this.path.wid : undefined, - id: this.path ? this.path.id : undefined, - name: this.path ? this.path.name : undefined, - account: this.path ? this.path.account : undefined, - change: this.path ? this.path.change : undefined, - index: this.path ? this.path.index : undefined, address: this.getAddress('base58'), programAddress: this.getProgramAddress('base58') }; diff --git a/lib/wallet/account.js b/lib/wallet/account.js index 37b17b8b..3fd2e5bf 100644 --- a/lib/wallet/account.js +++ b/lib/wallet/account.js @@ -15,7 +15,7 @@ var BufferReader = require('../utils/reader'); var BufferWriter = require('../utils/writer'); var Path = require('./path'); var Script = require('../script/script'); -var KeyRing = require('../primitives/keyring'); +var KeyRing = require('./kr'); /** * Represents a BIP44 Account belonging to a {@link Wallet}. @@ -463,7 +463,6 @@ Account.prototype.derivePath = function derivePath(path, master) { } ring = KeyRing.fromRaw(data, this.network); - ring.witness = this.witness; ring.path = path; return ring; @@ -483,7 +482,7 @@ Account.prototype.derivePath = function derivePath(path, master) { Account.prototype.deriveAddress = function deriveAddress(change, index, master) { var keys = []; - var i, key, shared, ring; + var i, key, shared, ring, hash; change = +change; @@ -517,11 +516,29 @@ Account.prototype.deriveAddress = function deriveAddress(change, index, master) if (key.privateKey) ring.privateKey = key.privateKey; - ring.path = Path.fromHD(this, ring, change, index); + hash = ring.getHash('hex'); + + ring.path = Path.fromHD(this, hash, change, index); return ring; }; +/** + * Get address type. + * @returns {ScriptType} + */ + +Account.prototype.getAddressType = function getAddressType() { + if (this.witness) { + if (this.type === Account.types.MULTISIG) + return Script.types.WITNESSSCRIPTHASH; + return Script.types.WITNESSPUBKEYHASH; + } + if (this.type === Account.types.MULTISIG) + return Script.types.SCRIPTHASH; + return Script.types.PUBKEYHASH; +}; + /** * Save the account to the database. Necessary * when address depth and keys change. diff --git a/lib/wallet/kr.js b/lib/wallet/kr.js new file mode 100644 index 00000000..b01443d0 --- /dev/null +++ b/lib/wallet/kr.js @@ -0,0 +1,173 @@ +/*! + * walletkey.js - walletkey object for bcoin + * Copyright (c) 2014-2015, Fedor Indutny (MIT License) + * Copyright (c) 2014-2016, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var constants = require('../protocol/constants'); +var KeyRing = require('../primitives/keyring'); +var utils = require('../utils/utils'); + +/** + * Represents a key ring which amounts to an address. + * @exports WalletKey + * @constructor + * @param {Object} options + * @param {HDPrivateKey|HDPublicKey|Buffer} options.key + * @param {Buffer[]} options.keys - Shared multisig keys. + * @param {Number?} options.m - Multisig `m` value. + * @param {Number?} options.n - Multisig `n` value. + * @param {Boolean?} options.witness - Whether witness programs are enabled. + */ + +function WalletKey(options, network) { + if (!(this instanceof WalletKey)) + return new WalletKey(options, network); + + KeyRing.call(this, options, network); + + this.path = null; +} + +utils.inherits(WalletKey, KeyRing); + +/** + * Instantiate key ring from options. + * @param {Object} options + * @returns {WalletKey} + */ + +WalletKey.fromOptions = function fromOptions(options) { + return new WalletKey().fromOptions(options); +}; + +/** + * Instantiate keyring from a private key. + * @param {Buffer} key + * @param {Boolean?} compressed + * @param {(NetworkType|Network}) network + * @returns {WalletKey} + */ + +WalletKey.fromPrivate = function fromPrivate(key, compressed, network) { + return new WalletKey().fromPrivate(key, compressed, network); +}; + +/** + * Generate a keyring. + * @param {(Network|NetworkType)?} network + * @returns {WalletKey} + */ + +WalletKey.generate = function(compressed, network) { + return new WalletKey().generate(compressed, network); +}; + +/** + * Instantiate keyring from a public key. + * @param {Buffer} publicKey + * @param {(NetworkType|Network}) network + * @returns {WalletKey} + */ + +WalletKey.fromPublic = function fromPublic(key, network) { + return new WalletKey().fromPublic(key, network); +}; + +/** + * Instantiate keyring from a public key. + * @param {Buffer} publicKey + * @param {(NetworkType|Network}) network + * @returns {WalletKey} + */ + +WalletKey.fromKey = function fromKey(key, compressed, network) { + return new WalletKey().fromKey(key, compressed, network); +}; + +/** + * Instantiate keyring from script. + * @param {Buffer} key + * @param {Script} script + * @param {(NetworkType|Network}) network + * @returns {WalletKey} + */ + +WalletKey.fromScript = function fromScript(key, script, compressed, network) { + return new WalletKey().fromScript(key, script, compressed, network); +}; + +/** + * Instantiate a keyring from a serialized CBitcoinSecret. + * @param {Base58String} secret + * @returns {WalletKey} + */ + +WalletKey.fromSecret = function fromSecret(data) { + return new WalletKey().fromSecret(data); +}; + +/** + * Convert an WalletKey to a more json-friendly object. + * @returns {Object} + */ + +WalletKey.prototype.toJSON = function toJSON() { + return { + network: this.network.type, + witness: this.witness, + publicKey: this.publicKey.toString('hex'), + script: this.script ? this.script.toRaw().toString('hex') : null, + type: constants.scriptTypesByVal[this.type].toLowerCase(), + wid: this.path.wid, + id: this.path.id, + name: this.path.name, + account: this.path.account, + change: this.path.change, + index: this.path.index, + address: this.getAddress('base58'), + programAddress: this.getProgramAddress('base58') + }; +}; + +/** + * Instantiate an WalletKey from a jsonified transaction object. + * @param {Object} json - The jsonified transaction object. + * @returns {WalletKey} + */ + +WalletKey.fromJSON = function fromJSON(json) { + return new WalletKey().fromJSON(json); +}; + +/** + * Instantiate a keyring from serialized data. + * @param {Buffer} data + * @returns {WalletKey} + */ + +WalletKey.fromRaw = function fromRaw(data) { + return new WalletKey().fromRaw(data); +}; + +/** + * Test whether an object is a WalletKey. + * @param {Object} obj + * @returns {Boolean} + */ + +WalletKey.isWalletKey = function isWalletKey(obj) { + return obj + && obj.path !== undefined + && Buffer.isBuffer(obj.publicKey) + && typeof obj.toSecret === 'function'; +}; + +/* + * Expose + */ + +module.exports = WalletKey; diff --git a/lib/wallet/path.js b/lib/wallet/path.js index 8883c351..3d918013 100644 --- a/lib/wallet/path.js +++ b/lib/wallet/path.js @@ -186,7 +186,7 @@ Path.prototype.toRaw = function toRaw(writer) { * @param {Number} index */ -Path.prototype.fromHD = function fromHD(account, ring, change, index) { +Path.prototype.fromHD = function fromHD(account, hash, change, index) { this.wid = account.wid; this.name = account.name; this.account = account.accountIndex; @@ -195,11 +195,11 @@ Path.prototype.fromHD = function fromHD(account, ring, change, index) { this.keyType = Path.types.HD; - this.version = ring.witness ? 0 : -1; - this.type = ring.getAddressType(); + this.version = account.witness ? 0 : -1; + this.type = account.getAddressType(); this.id = account.id; - this.hash = ring.getHash('hex'); + this.hash = hash; return this; };