network: add more helper functions.

This commit is contained in:
Christopher Jeffrey 2017-05-13 21:35:58 -07:00
parent 2997333122
commit 11a660aeab
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
6 changed files with 366 additions and 366 deletions

View File

@ -82,25 +82,14 @@ HD.fromJSON = function fromJSON(json, network) {
/**
* Instantiate an HD key from serialized data.
* @param {Buffer} data
* @param {Network?} network
* @returns {HDPrivateKey|HDPublicKey}
*/
HD.fromRaw = function fromRaw(data) {
if (HDPrivateKey.isRaw(data))
return HDPrivateKey.fromRaw(data);
return HDPublicKey.fromRaw(data);
};
/**
* Instantiate HD key from extended serialized data.
* @param {Buffer} data
* @returns {HDPrivateKey|HDPublicKey}
*/
HD.fromExtended = function fromExtended(data) {
if (HDPrivateKey.isRaw(data))
return HDPrivateKey.fromExtended(data);
return HDPublicKey.fromRaw(data);
HD.fromRaw = function fromRaw(data, network) {
if (HDPrivateKey.isRaw(data, network))
return HDPrivateKey.fromRaw(data, network);
return HDPublicKey.fromRaw(data, network);
};
/**
@ -117,11 +106,11 @@ HD.from = function from(options, network) {
if (HD.isHD(options))
return options;
if (HD.isBase58(options))
if (HD.isBase58(options, network))
return HD.fromBase58(options, network);
if (HD.isRaw(options))
return HD.fromRaw(options);
if (HD.isRaw(options, network))
return HD.fromRaw(options, network);
if (options && typeof options === 'object')
return HD.fromMnemonic(options, network);
@ -132,23 +121,25 @@ HD.from = function from(options, network) {
/**
* Test whether an object is in the form of a base58 hd key.
* @param {String} data
* @param {Network?} network
* @returns {Boolean}
*/
HD.isBase58 = function isBase58(data) {
return HDPrivateKey.isBase58(data)
|| HDPublicKey.isBase58(data);
HD.isBase58 = function isBase58(data, network) {
return HDPrivateKey.isBase58(data, network)
|| HDPublicKey.isBase58(data, network);
};
/**
* Test whether an object is in the form of a serialized hd key.
* @param {Buffer} data
* @param {Network?} network
* @returns {NetworkType}
*/
HD.isRaw = function isRaw(data) {
return HDPrivateKey.isRaw(data)
|| HDPublicKey.isRaw(data);
HD.isRaw = function isRaw(data, network) {
return HDPrivateKey.isRaw(data, network)
|| HDPublicKey.isRaw(data, network);
};
/**

View File

@ -10,7 +10,6 @@ var assert = require('assert');
var util = require('../utils/util');
var crypto = require('../crypto/crypto');
var ec = require('../crypto/ec');
var networks = require('../protocol/networks');
var Network = require('../protocol/network');
var StaticWriter = require('../utils/staticwriter');
var BufferReader = require('../utils/reader');
@ -142,18 +141,6 @@ HDPrivateKey.prototype.xpubkey = function xpubkey() {
return this.toPublic().xpubkey();
};
/**
* Verify network.
* @param {(NetworkType|Network)} network
* @returns {Boolean}
*/
HDPrivateKey.prototype.verifyNetwork = function verifyNetwork(network) {
network = Network.get(network);
return this.network.keyPrefix.xprivkey === network.keyPrefix.xprivkey
&& this.network.keyPrefix.coinType === network.keyPrefix.coinType;
};
/**
* Destroy the key (zeroes chain code, privkey, and pubkey).
* @param {Boolean} pub - Destroy hd public key as well.
@ -189,19 +176,11 @@ HDPrivateKey.prototype.destroy = function destroy(pub) {
* @returns {HDPrivateKey}
*/
HDPrivateKey.prototype.derive = function derive(index, hardened, cache) {
HDPrivateKey.prototype.derive = function derive(index, hardened) {
var bw, id, data, hash, left, right, key, child;
if (typeof hardened !== 'boolean') {
cache = hardened;
hardened = false;
}
if (!cache)
cache = common.cache;
if (typeof index === 'string')
return this.derivePath(index, cache);
return this.derivePath(index);
hardened = index >= common.HARDENED ? true : hardened;
@ -214,12 +193,11 @@ HDPrivateKey.prototype.derive = function derive(index, hardened, cache) {
if (this.depth >= 0xff)
throw new Error('Depth too high.');
if (cache) {
id = this.getID(index);
child = cache.get(id);
if (child)
return child;
}
id = this.getID(index);
child = common.cache.get(id);
if (child)
return child;
bw = new StaticWriter(37);
@ -241,7 +219,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened, cache) {
try {
key = ec.privateKeyTweakAdd(this.privateKey, left);
} catch (e) {
return this.derive(index + 1, cache);
return this.derive(index + 1);
}
if (!this.fingerPrint)
@ -256,8 +234,7 @@ HDPrivateKey.prototype.derive = function derive(index, hardened, cache) {
child.privateKey = key;
child.publicKey = ec.publicKeyCreate(key, true);
if (cache)
cache.set(id, child);
common.cache.set(id, child);
return child;
};
@ -282,13 +259,13 @@ HDPrivateKey.prototype.getID = function getID(index) {
* @throws Error if key is not a master key.
*/
HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(accountIndex, cache) {
HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(accountIndex) {
assert(util.isNumber(accountIndex), 'Account index must be a number.');
assert(this.isMaster(), 'Cannot derive account index.');
return this
.derive(44, true, cache)
.derive(this.network.keyPrefix.coinType, true, cache)
.derive(accountIndex, true, cache);
.derive(44, true)
.derive(this.network.keyPrefix.coinType, true)
.derive(accountIndex, true);
};
/**
@ -296,9 +273,9 @@ HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(accountIndex,
* @returns {HDPrivateKey}
*/
HDPrivateKey.prototype.derivePurpose45 = function derivePurpose45(cache) {
HDPrivateKey.prototype.derivePurpose45 = function derivePurpose45() {
assert(this.isMaster(), 'Cannot derive purpose 45.');
return this.derive(45, true, cache);
return this.derive(45, true);
};
/**
@ -332,33 +309,38 @@ HDPrivateKey.prototype.isPurpose45 = function isPurpose45() {
/**
* Test whether an object is in the form of a base58 xprivkey.
* @param {String} data
* @param {Network?} network
* @returns {Boolean}
*/
HDPrivateKey.isBase58 = function isBase58(data) {
var i, type, prefix;
HDPrivateKey.isBase58 = function isBase58(data, network) {
var prefix;
if (typeof data !== 'string')
return false;
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
prefix = networks[type].keyPrefix.xprivkey58;
if (data.indexOf(prefix) === 0)
return true;
}
if (data.length < 4)
return false;
return false;
prefix = data.substring(0, 4);
try {
Network.fromPrivate58(prefix, network);
return true;
} catch (e) {
return false;
}
};
/**
* Test whether a buffer has a valid network prefix.
* @param {Buffer} data
* @returns {NetworkType}
* @param {Network?} network
* @returns {Boolean}
*/
HDPrivateKey.isRaw = function isRaw(data) {
var i, version, prefix, type;
HDPrivateKey.isRaw = function isRaw(data, network) {
var version;
if (!Buffer.isBuffer(data))
return false;
@ -368,14 +350,12 @@ HDPrivateKey.isRaw = function isRaw(data) {
version = data.readUInt32BE(0, true);
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
prefix = networks[type].keyPrefix.xprivkey;
if (version === prefix)
return type;
try {
Network.fromPrivate(version, network);
return true;
} catch (e) {
return false;
}
return false;
};
/**
@ -404,13 +384,13 @@ HDPrivateKey.isValidPath = function isValidPath(path) {
* @throws Error if `path` is not a valid path.
*/
HDPrivateKey.prototype.derivePath = function derivePath(path, cache) {
HDPrivateKey.prototype.derivePath = function derivePath(path) {
var indexes = common.parsePath(path, common.MAX_INDEX);
var key = this;
var i;
for (i = 0; i < indexes.length; i++)
key = key.derive(indexes[i], cache);
key = key.derive(indexes[i]);
return key;
};
@ -530,8 +510,7 @@ HDPrivateKey.fromSeed = function fromSeed(seed, network) {
HDPrivateKey.prototype.fromMnemonic = function fromMnemonic(mnemonic, network) {
assert(mnemonic instanceof Mnemonic);
this.fromSeed(mnemonic.toSeed(), network);
return this;
return this.fromSeed(mnemonic.toSeed(), network);
};
/**
@ -622,42 +601,31 @@ HDPrivateKey.generate = function generate(network) {
*/
HDPrivateKey.prototype.fromBase58 = function fromBase58(xkey, network) {
this.fromRaw(base58.decode(xkey));
assert(typeof xkey === 'string');
this._xprivkey = xkey;
if (network && !this.verifyNetwork(network))
throw new Error('Network mismatch for HD private key.');
return this;
return this.fromRaw(base58.decode(xkey), network);
};
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} raw
* @param {(Network|NetworkType)?} network
*/
HDPrivateKey.prototype.fromReader = function fromReader(br) {
var i, version, type, prefix;
HDPrivateKey.prototype.fromReader = function fromReader(br, network) {
var version = br.readU32BE();
version = br.readU32BE();
this.network = Network.fromPrivate(version, network);
this.depth = br.readU8();
this.parentFingerPrint = br.readBytes(4);
this.childIndex = br.readU32BE();
this.chainCode = br.readBytes(32);
br.readU8();
this.privateKey = br.readBytes(32);
br.verifyChecksum();
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
prefix = networks[type].keyPrefix.xprivkey;
if (version === prefix)
break;
}
assert(i < networks.types.length, 'Network not found.');
this.publicKey = ec.publicKeyCreate(this.privateKey, true);
this.network = Network.get(type);
br.verifyChecksum();
return this;
};
@ -666,10 +634,11 @@ HDPrivateKey.prototype.fromReader = function fromReader(br) {
* Inject properties from serialized data.
* @private
* @param {Buffer} raw
* @param {(Network|NetworkType)?} network
*/
HDPrivateKey.prototype.fromRaw = function fromRaw(raw) {
return this.fromReader(new BufferReader(raw));
HDPrivateKey.prototype.fromRaw = function fromRaw(raw, network) {
return this.fromReader(new BufferReader(raw), network);
};
/**
@ -739,21 +708,23 @@ HDPrivateKey.fromBase58 = function fromBase58(xkey, network) {
/**
* Instantiate key from buffer reader.
* @param {BufferReader} br
* @param {(Network|NetworkType)?} network
* @returns {HDPrivateKey}
*/
HDPrivateKey.fromReader = function fromReader(br) {
return new HDPrivateKey().fromReader(br);
HDPrivateKey.fromReader = function fromReader(br, network) {
return new HDPrivateKey().fromReader(br, network);
};
/**
* Instantiate key from serialized data.
* @param {Buffer} raw
* @param {(Network|NetworkType)?} network
* @returns {HDPrivateKey}
*/
HDPrivateKey.fromRaw = function fromRaw(raw) {
return new HDPrivateKey().fromRaw(raw);
HDPrivateKey.fromRaw = function fromRaw(raw, network) {
return new HDPrivateKey().fromRaw(raw, network);
};
/**
@ -803,7 +774,7 @@ HDPrivateKey.isHDPrivateKey = function isHDPrivateKey(obj) {
return obj
&& typeof obj.derive === 'function'
&& typeof obj.fromMnemonic === 'function'
&& obj.chainCode !== undefined;
&& Buffer.isBuffer(obj.chainCode);
};
/*

View File

@ -10,7 +10,6 @@ var assert = require('assert');
var util = require('../utils/util');
var crypto = require('../crypto/crypto');
var ec = require('../crypto/ec');
var networks = require('../protocol/networks');
var Network = require('../protocol/network');
var StaticWriter = require('../utils/staticwriter');
var BufferReader = require('../utils/reader');
@ -121,18 +120,6 @@ HDPublicKey.prototype.xpubkey = function() {
return this._xpubkey;
};
/**
* Verify network.
* @param {(NetworkType|Network)} network
* @returns {Boolean}
*/
HDPublicKey.prototype.verifyNetwork = function verifyNetwork(network) {
network = Network.get(network);
return this.network.keyPrefix.xpubkey === network.keyPrefix.xpubkey
&& this.network.keyPrefix.coinType === network.keyPrefix.coinType;
};
/**
* Destroy the key (zeroes chain code and pubkey).
*/
@ -162,19 +149,11 @@ HDPublicKey.prototype.destroy = function destroy() {
* @throws on `hardened`
*/
HDPublicKey.prototype.derive = function derive(index, hardened, cache) {
HDPublicKey.prototype.derive = function derive(index, hardened) {
var bw, id, data, hash, left, right, key, child;
if (typeof hardened !== 'boolean') {
cache = hardened;
hardened = false;
}
if (!cache)
cache = common.cache;
if (typeof index === 'string')
return this.derivePath(index, cache);
return this.derivePath(index);
if (index >= common.HARDENED || hardened)
throw new Error('Index out of range.');
@ -185,12 +164,11 @@ HDPublicKey.prototype.derive = function derive(index, hardened, cache) {
if (this.depth >= 0xff)
throw new Error('Depth too high.');
if (cache) {
id = this.getID(index);
child = cache.get(id);
if (child)
return child;
}
id = this.getID(index);
child = common.cache.get(id);
if (child)
return child;
bw = new StaticWriter(37);
bw.writeBytes(this.publicKey);
@ -204,7 +182,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened, cache) {
try {
key = ec.publicKeyTweakAdd(this.publicKey, left, true);
} catch (e) {
return this.derive(index + 1, cache);
return this.derive(index + 1);
}
if (!this.fingerPrint)
@ -218,8 +196,7 @@ HDPublicKey.prototype.derive = function derive(index, hardened, cache) {
child.chainCode = right;
child.publicKey = key;
if (cache)
cache.set(id, child);
common.cache.set(id, child);
return child;
};
@ -320,13 +297,13 @@ HDPublicKey.isValidPath = function isValidPath(path) {
* @throws Error if hardened.
*/
HDPublicKey.prototype.derivePath = function derivePath(path, cache) {
HDPublicKey.prototype.derivePath = function derivePath(path) {
var indexes = common.parsePath(path, common.HARDENED);
var key = this;
var i;
for (i = 0; i < indexes.length; i++)
key = key.derive(indexes[i], cache);
key = key.derive(indexes[i]);
return key;
};
@ -427,47 +404,53 @@ HDPublicKey.fromJSON = function fromJSON(json, network) {
/**
* Test whether an object is in the form of a base58 xpubkey.
* @param {String} data
* @param {(Network|NetworkType)?} network
* @returns {Boolean}
*/
HDPublicKey.isBase58 = function isBase58(data) {
var i, type, prefix;
HDPublicKey.isBase58 = function isBase58(data, network) {
var prefix;
if (typeof data !== 'string')
return false;
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
prefix = networks[type].keyPrefix.xpubkey58;
if (data.indexOf(prefix) === 0)
return true;
}
if (data.length < 4)
return false;
return false;
prefix = data.substring(0, 4);
try {
Network.fromPublic58(prefix, network);
return true;
} catch (e) {
return false;
}
};
/**
* Test whether a buffer has a valid network prefix.
* @param {Buffer} data
* @param {(Network|NetworkType)?} network
* @returns {NetworkType}
*/
HDPublicKey.isRaw = function isRaw(data) {
var i, version, prefix, type;
HDPublicKey.isRaw = function isRaw(data, network) {
var version;
if (!Buffer.isBuffer(data))
return false;
if (data.length < 4)
return false;
version = data.readUInt32BE(0, true);
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
prefix = networks[type].keyPrefix.xpubkey;
if (version === prefix)
return type;
try {
Network.fromPublic(version, network);
return true;
} catch (e) {
return false;
}
return false;
};
/**
@ -478,41 +461,30 @@ HDPublicKey.isRaw = function isRaw(data) {
*/
HDPublicKey.prototype.fromBase58 = function fromBase58(xkey, network) {
this.fromRaw(base58.decode(xkey));
assert(typeof xkey === 'string');
this._xpubkey = xkey;
if (network && !this.verifyNetwork(network))
throw new Error('Network mismatch for HD public key.');
return this;
return this.fromRaw(base58.decode(xkey), network);
};
/**
* Inject properties from serialized data.
* @private
* @param {Buffer} raw
* @param {(Network|NetworkType)?} network
*/
HDPublicKey.prototype.fromReader = function fromReader(br) {
var i, version, type, prefix;
HDPublicKey.prototype.fromReader = function fromReader(br, network) {
var version = br.readU32BE();
version = br.readU32BE();
this.network = Network.fromPublic(version, network);
this.depth = br.readU8();
this.parentFingerPrint = br.readBytes(4);
this.childIndex = br.readU32BE();
this.chainCode = br.readBytes(32);
this.publicKey = br.readBytes(33);
br.verifyChecksum();
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
prefix = networks[type].keyPrefix.xpubkey;
if (version === prefix)
break;
}
assert(i < networks.types.length, 'Network not found.');
this.network = Network.get(type);
return this;
};
@ -520,15 +492,16 @@ HDPublicKey.prototype.fromReader = function fromReader(br) {
* Inject properties from serialized data.
* @private
* @param {Buffer} raw
* @param {(Network|NetworkType)?} network
*/
HDPublicKey.prototype.fromRaw = function fromRaw(raw) {
return this.fromReader(new BufferReader(raw));
HDPublicKey.prototype.fromRaw = function fromRaw(raw, network) {
return this.fromReader(new BufferReader(raw), network);
};
/**
* Serialize key data to base58 extended key.
* @param {Network|String} network
* @param {(Network|NetworkType)?} network
* @returns {Base58String}
*/
@ -539,7 +512,7 @@ HDPublicKey.prototype.toBase58 = function toBase58(network) {
/**
* Write the key to a buffer writer.
* @param {BufferWriter} bw
* @param {Network|NetworkType} network
* @param {(Network|NetworkType)?} network
*/
HDPublicKey.prototype.toWriter = function toWriter(bw, network) {
@ -570,7 +543,7 @@ HDPublicKey.prototype.getSize = function getSize() {
/**
* Serialize the key.
* @param {Network|NetworkType} network
* @param {(Network|NetworkType)?} network
* @returns {Buffer}
*/
@ -592,21 +565,23 @@ HDPublicKey.fromBase58 = function fromBase58(xkey, network) {
/**
* Instantiate key from serialized data.
* @param {BufferReader} br
* @param {(Network|NetworkType)?} network
* @returns {HDPublicKey}
*/
HDPublicKey.fromReader = function fromReader(br) {
return new HDPublicKey().fromReader(br);
HDPublicKey.fromReader = function fromReader(br, network) {
return new HDPublicKey().fromReader(br, network);
};
/**
* Instantiate key from serialized data.
* @param {Buffer} raw
* @param {(Network|NetworkType)?} network
* @returns {HDPublicKey}
*/
HDPublicKey.fromRaw = function fromRaw(data) {
return new HDPublicKey().fromRaw(data);
HDPublicKey.fromRaw = function fromRaw(data, network) {
return new HDPublicKey().fromRaw(data, network);
};
/**
@ -618,8 +593,8 @@ HDPublicKey.fromRaw = function fromRaw(data) {
HDPublicKey.isHDPublicKey = function isHDPublicKey(obj) {
return obj
&& typeof obj.derive === 'function'
&& typeof obj.toExtended !== 'function'
&& obj.chainCode !== undefined;
&& obj.fromMnemonic === undefined
&& Buffer.isBuffer(obj.chainCode);
};
/*

View File

@ -9,7 +9,6 @@
var assert = require('assert');
var Network = require('../protocol/network');
var networks = require('../protocol/networks');
var encoding = require('../utils/encoding');
var util = require('../utils/util');
var crypto = require('../crypto/crypto');
@ -22,12 +21,7 @@ var bech32 = require('../utils/bech32');
* Represents an address.
* @alias module:primitives.Address
* @constructor
* @param {Object} options
* @param {Buffer|Hash} options.hash - Address hash.
* @param {AddressPrefix} options.type - Address type
* `{witness,}{pubkeyhash,scripthash}`.
* @param {Number} [options.version=-1] - Witness program version.
* @param {(Network|NetworkType)?} options.network - Network name.
* @param {Object?} options
* @property {Buffer} hash
* @property {AddressPrefix} type
* @property {Number} version
@ -105,30 +99,6 @@ Address.prototype.getHash = function getHash(enc) {
return this.hash;
};
/**
* Get a network address prefix for the address.
* @param {Network?} network
* @returns {Number}
*/
Address.prototype.getPrefix = function getPrefix(network) {
if (!network)
network = this.network;
network = Network.get(network);
return Address.getPrefix(this.type, this.hash, network);
};
/**
* Verify an address network (compares prefixes).
* @param {Network} network
* @returns {Boolean}
*/
Address.prototype.verifyNetwork = function verifyNetwork(network) {
assert(network);
return this.getPrefix() === this.getPrefix(network);
};
/**
* Test whether the address is null.
* @returns {Boolean}
@ -153,13 +123,46 @@ Address.prototype.isNull = function isNull() {
/**
* Get the address type as a string.
* @returns {AddressPrefix}
* @returns {String}
*/
Address.prototype.getType = function getType() {
return Address.typesByVal[this.type].toLowerCase();
};
/**
* Get a network address prefix for the address.
* @param {Network?} network
* @returns {Number}
*/
Address.prototype.getPrefix = function getPrefix(network) {
var prefixes;
if (!network)
network = this.network;
network = Network.get(network);
prefixes = network.addressPrefix;
switch (this.type) {
case Address.types.PUBKEYHASH:
return prefixes.pubkeyhash;
case Address.types.SCRIPTHASH:
return prefixes.scripthash;
case Address.types.WITNESS:
if (this.hash.length === 20)
return prefixes.witnesspubkeyhash;
if (this.hash.length === 32)
return prefixes.witnessscripthash;
break;
}
return -1;
};
/**
* Calculate size of serialized address.
* @returns {Number}
@ -225,7 +228,7 @@ Address.prototype.toBech32 = function toBech32(network) {
var hrp;
assert(version !== -1,
'Cannot convert non-segwit address to bech32.');
'Cannot convert non-program address to bech32.');
if (!network)
network = this.network;
@ -245,28 +248,18 @@ Address.prototype.toBech32 = function toBech32(network) {
*/
Address.prototype.fromString = function fromString(addr, network) {
var i, type, hrp, expect;
var hrp;
assert(typeof addr === 'string');
assert(addr.length >= 2);
hrp = addr.substring(0, 2).toLowerCase();
if (network) {
network = Network.get(network);
expect = network.addressPrefix.bech32;
if (hrp === expect)
return this.fromBech32(addr, network);
} else {
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
expect = networks[type].addressPrefix.bech32;
if (hrp === expect)
return this.fromBech32(addr, type);
}
try {
hrp = addr.substring(0, 2).toLowerCase();
network = Network.fromBech32(hrp, network);
} catch (e) {
return this.fromBase58(addr, network);
}
return this.fromBase58(addr, network);
return this.fromBech32(addr, network);
};
/**
@ -312,23 +305,16 @@ Address.prototype.inspect = function inspect() {
* @throws Parse error
*/
Address.prototype.fromRaw = function fromRaw(data) {
Address.prototype.fromRaw = function fromRaw(data, network) {
var br = new BufferReader(data, true);
var i, prefix, network, type, version, hash;
var prefix, type, version, hash;
if (data.length > 40)
throw new Error('Address is too long.');
prefix = br.readU8();
for (i = 0; i < networks.types.length; i++) {
network = networks[networks.types[i]];
type = Address.getType(prefix, network);
if (type !== -1)
break;
}
assert(i < networks.types.length, 'Unknown address prefix.');
network = Network.fromAddress(prefix, network);
type = Address.getType(prefix, network);
if (data.length > 25) {
version = br.readU8();
@ -351,87 +337,69 @@ Address.prototype.fromRaw = function fromRaw(data) {
* @throws Parse error.
*/
Address.fromRaw = function fromRaw(data) {
return new Address().fromRaw(data);
Address.fromRaw = function fromRaw(data, network) {
return new Address().fromRaw(data, network);
};
/**
* Inject properties from base58 address.
* @private
* @param {Base58Address} str
* @param {Base58Address} data
* @param {Network?} network
* @throws Parse error
*/
Address.prototype.fromBase58 = function fromBase58(str, network) {
assert(typeof str === 'string');
Address.prototype.fromBase58 = function fromBase58(data, network) {
assert(typeof data === 'string');
if (str.length > 55)
if (data.length > 55)
throw new Error('Address is too long.');
this.fromRaw(base58.decode(str));
if (network && !this.verifyNetwork(network))
throw new Error('Network mismatch for address.');
return this;
return this.fromRaw(base58.decode(data), network);
};
/**
* Create an address object from a base58 address.
* @param {Base58Address} str
* @param {Base58Address} data
* @param {Network?} network
* @returns {Address}
* @throws Parse error.
*/
Address.fromBase58 = function fromBase58(str, network) {
return new Address().fromBase58(str, network);
Address.fromBase58 = function fromBase58(data, network) {
return new Address().fromBase58(data, network);
};
/**
* Inject properties from bech32 address.
* @private
* @param {String} str
* @param {String} data
* @param {Network?} network
* @throws Parse error
*/
Address.prototype.fromBech32 = function fromBech32(str, network) {
Address.prototype.fromBech32 = function fromBech32(data, network) {
var type = Address.types.WITNESS;
var i, addr;
var addr;
assert(typeof str === 'string');
assert(typeof data === 'string');
addr = bech32.decode(str);
addr = bech32.decode(data);
network = Network.fromBech32(addr.hrp, network);
if (network) {
network = Network.get(network);
if (addr.hrp !== network.addressPrefix.bech32)
throw new Error('Network mismatch for bech32 address.');
} else {
for (i = 0; i < networks.types.length; i++) {
network = networks[networks.types[i]];
if (addr.hrp === network.addressPrefix.bech32)
break;
}
assert(i < networks.types.length, 'Unknown bech32 address prefix.');
}
return this.fromHash(addr.hash, type, addr.version, network.type);
return this.fromHash(addr.hash, type, addr.version, network);
};
/**
* Create an address object from a bech32 address.
* @param {String} str
* @param {String} data
* @param {Network?} network
* @returns {Address}
* @throws Parse error.
*/
Address.fromBech32 = function fromBech32(str, network) {
return new Address().fromBech32(str, network);
Address.fromBech32 = function fromBech32(data, network) {
return new Address().fromBech32(data, network);
};
/**
@ -877,37 +845,11 @@ Address.getHash = function getHash(data, enc) {
: hash;
};
/**
* Get a network address prefix for a specified address type.
* @param {AddressPrefix} type
* @param {Buffer} hash
* @param {Network} network
* @returns {Number}
*/
Address.getPrefix = function getPrefix(type, hash, network) {
var prefixes = network.addressPrefix;
switch (type) {
case Address.types.PUBKEYHASH:
return prefixes.pubkeyhash;
case Address.types.SCRIPTHASH:
return prefixes.scripthash;
case Address.types.WITNESS:
if (hash.length === 20)
return prefixes.witnesspubkeyhash;
if (hash.length === 32)
return prefixes.witnessscripthash;
assert(false, 'No witness prefix defined.');
default:
return -1;
}
};
/**
* Get an address type for a specified network address prefix.
* @param {Number} prefix
* @param {Network} network
* @returns {AddressPrefix}
* @returns {AddressType}
*/
Address.getType = function getType(prefix, network) {
@ -922,7 +864,7 @@ Address.getType = function getType(prefix, network) {
case prefixes.witnessscripthash:
return Address.types.WITNESS;
default:
return -1;
throw new Error('Unknown address prefix.');
}
};

View File

@ -11,7 +11,6 @@ var assert = require('assert');
var util = require('../utils/util');
var encoding = require('../utils/encoding');
var crypto = require('../crypto/crypto');
var networks = require('../protocol/networks');
var Network = require('../protocol/network');
var BufferReader = require('../utils/reader');
var StaticWriter = require('../utils/staticwriter');
@ -124,7 +123,7 @@ KeyRing.prototype.refresh = function refresh() {
* @private
* @param {Buffer} key
* @param {Boolean?} compressed
* @param {(NetworkType|Network)} network
* @param {(NetworkType|Network)?} network
*/
KeyRing.prototype.fromPrivate = function fromPrivate(key, compressed, network) {
@ -147,7 +146,7 @@ KeyRing.prototype.fromPrivate = function fromPrivate(key, compressed, network) {
* Instantiate keyring from a private key.
* @param {Buffer} key
* @param {Boolean?} compressed
* @param {(NetworkType|Network)} network
* @param {(NetworkType|Network)?} network
* @returns {KeyRing}
*/
@ -159,7 +158,7 @@ KeyRing.fromPrivate = function fromPrivate(key, compressed, network) {
* Inject data from public key.
* @private
* @param {Buffer} key
* @param {(NetworkType|Network)} network
* @param {(NetworkType|Network)?} network
*/
KeyRing.prototype.fromPublic = function fromPublic(key, network) {
@ -203,7 +202,7 @@ KeyRing.generate = function(compressed, network) {
/**
* Instantiate keyring from a public key.
* @param {Buffer} publicKey
* @param {(NetworkType|Network)} network
* @param {(NetworkType|Network)?} network
* @returns {KeyRing}
*/
@ -215,7 +214,7 @@ KeyRing.fromPublic = function fromPublic(key, network) {
* Inject data from public key.
* @private
* @param {Buffer} privateKey
* @param {(NetworkType|Network)} network
* @param {(NetworkType|Network)?} network
*/
KeyRing.prototype.fromKey = function fromKey(key, compressed, network) {
@ -235,7 +234,7 @@ KeyRing.prototype.fromKey = function fromKey(key, compressed, network) {
/**
* Instantiate keyring from a public key.
* @param {Buffer} publicKey
* @param {(NetworkType|Network)} network
* @param {(NetworkType|Network)?} network
* @returns {KeyRing}
*/
@ -248,7 +247,7 @@ KeyRing.fromKey = function fromKey(key, compressed, network) {
* @private
* @param {Buffer} key
* @param {Script} script
* @param {(NetworkType|Network)} network
* @param {(NetworkType|Network)?} network
*/
KeyRing.prototype.fromScript = function fromScript(key, script, compressed, network) {
@ -269,7 +268,7 @@ KeyRing.prototype.fromScript = function fromScript(key, script, compressed, netw
* Instantiate keyring from script.
* @param {Buffer} key
* @param {Script} script
* @param {(NetworkType|Network)} network
* @param {(NetworkType|Network)?} network
* @returns {KeyRing}
*/
@ -302,13 +301,18 @@ KeyRing.prototype.getSecretSize = function getSecretSize() {
* @returns {Base58String}
*/
KeyRing.prototype.toSecret = function toSecret() {
KeyRing.prototype.toSecret = function toSecret(network) {
var size = this.getSecretSize();
var bw = new StaticWriter(size);
assert(this.privateKey, 'Cannot serialize without private key.');
bw.writeU8(this.network.keyPrefix.privkey);
if (!network)
network = this.network;
network = Network.get(network);
bw.writeU8(network.keyPrefix.privkey);
bw.writeBytes(this.privateKey);
if (this.publicKey.length === 33)
@ -323,23 +327,15 @@ KeyRing.prototype.toSecret = function toSecret() {
* Inject properties from serialized CBitcoinSecret.
* @private
* @param {Base58String} secret
* @param {Network?} network
* @param {(Network|NetworkType)?} network
*/
KeyRing.prototype.fromSecret = function fromSecret(data, network) {
var br = new BufferReader(base58.decode(data), true);
var i, prefix, version, type, key, compressed;
var version, key, compressed;
version = br.readU8();
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
prefix = networks[type].keyPrefix.privkey;
if (version === prefix)
break;
}
assert(i < networks.types.length, 'Network not found.');
network = Network.fromWIF(version, network);
key = br.readBytes(32);
@ -352,18 +348,13 @@ KeyRing.prototype.fromSecret = function fromSecret(data, network) {
br.verifyChecksum();
this.fromPrivate(key, compressed, type);
if (network && !this.verifyNetwork(network))
throw new Error('Network mismatch for WIF.');
return this;
return this.fromPrivate(key, compressed, network);
};
/**
* Instantiate a keyring from a serialized CBitcoinSecret.
* @param {Base58String} secret
* @param {Network?} network
* @param {(Network|NetworkType)?} network
* @returns {KeyRing}
*/
@ -371,17 +362,6 @@ KeyRing.fromSecret = function fromSecret(data, network) {
return new KeyRing().fromSecret(data, network);
};
/**
* Verify network.
* @param {(NetworkType|Network)} network
* @returns {Boolean}
*/
KeyRing.prototype.verifyNetwork = function verifyNetwork(network) {
network = Network.get(network);
return this.network.keyPrefix.privkey === network.keyPrefix.privkey;
};
/**
* Get private key.
* @param {String?} enc - Can be `"hex"`, `"base58"`, or `null`.

View File

@ -235,22 +235,121 @@ Network.ensure = function ensure(type) {
};
/**
* Get a network by its magic number.
* Get a network by an associated comparator.
* @private
* @param {Object} value
* @param {Function} compare
* @param {Network|null} network
* @param {String} name
* @returns {Network}
*/
Network.fromMagic = function fromMagic(magic) {
Network.by = function by(value, compare, network, name) {
var i, type;
if (network) {
network = Network.get(network);
if (compare(network, value))
return network;
throw new Error('Network mismatch for ' + name + '.');
}
for (i = 0; i < networks.types.length; i++) {
type = networks.types[i];
if (magic === networks[type].magic)
break;
network = networks[type];
if (compare(network, value))
return Network.get(type);
}
assert(i < networks.types.length, 'Network not found.');
throw new Error('Network not found for ' + name + '.');
};
return Network.get(type);
/**
* Get a network by its magic number.
* @param {Number} value
* @param {Network?} network
* @returns {Network}
*/
Network.fromMagic = function fromMagic(value, network) {
return Network.by(value, cmpMagic, network, 'magic number');
};
/**
* Get a network by its WIF prefix.
* @param {Number} value
* @param {Network?} network
* @returns {Network}
*/
Network.fromWIF = function fromWIF(prefix, network) {
return Network.by(prefix, cmpWIF, network, 'WIF');
};
/**
* Get a network by its xpubkey prefix.
* @param {Number} value
* @param {Network?} network
* @returns {Network}
*/
Network.fromPublic = function fromPublic(prefix, network) {
return Network.by(prefix, cmpPub, network, 'xpubkey');
};
/**
* Get a network by its xprivkey prefix.
* @param {Number} value
* @param {Network?} network
* @returns {Network}
*/
Network.fromPrivate = function fromPrivate(prefix, network) {
return Network.by(prefix, cmpPriv, network, 'xprivkey');
};
/**
* Get a network by its xpubkey base58 prefix.
* @param {String} prefix
* @param {Network?} network
* @returns {Network}
*/
Network.fromPublic58 = function fromPublic58(prefix, network) {
return Network.by(prefix, cmpPub58, network, 'xpubkey');
};
/**
* Get a network by its xprivkey base58 prefix.
* @param {String} prefix
* @param {Network?} network
* @returns {Network}
*/
Network.fromPrivate58 = function fromPrivate58(prefix, network) {
return Network.by(prefix, cmpPriv58, network, 'xprivkey');
};
/**
* Get a network by its base58 address prefix.
* @param {Number} value
* @param {Network?} network
* @returns {Network}
*/
Network.fromAddress = function fromAddress(prefix, network) {
return Network.by(prefix, cmpAddress, network, 'base58 address');
};
/**
* Get a network by its bech32 address prefix.
* @param {String} hrp
* @param {Network?} network
* @returns {Network}
*/
Network.fromBech32 = function fromBech32(hrp, network) {
return Network.by(hrp, cmpBech32, network, 'bech32 address');
};
/**
@ -302,6 +401,48 @@ function cmpNode(a, b) {
return a.height - b.height;
}
function cmpMagic(network, magic) {
return network.magic === magic;
}
function cmpWIF(network, prefix) {
return network.keyPrefix.privkey === prefix;
}
function cmpPub(network, prefix) {
return network.keyPrefix.xpubkey === prefix;
}
function cmpPriv(network, prefix) {
return network.keyPrefix.xprivkey === prefix;
}
function cmpPub58(network, prefix) {
return network.keyPrefix.xpubkey58 === prefix;
}
function cmpPriv58(network, prefix) {
return network.keyPrefix.xprivkey58 === prefix;
}
function cmpAddress(network, prefix) {
var prefixes = network.addressPrefix;
switch (prefix) {
case prefixes.pubkeyhash:
case prefixes.scripthash:
case prefixes.witnesspubkeyhash:
case prefixes.witnessscripthash:
return true;
}
return false;
}
function cmpBech32(network, hrp) {
return network.addressPrefix.bech32 === hrp;
}
/*
* Expose
*/