diff --git a/index.js b/index.js
index 17e3d9f..51ed86a 100644
--- a/index.js
+++ b/index.js
@@ -18,7 +18,10 @@ bitcore.encoding.BufferReader = require('./lib/encoding/bufferreader');
bitcore.encoding.BufferWriter = require('./lib/encoding/bufferwriter');
bitcore.encoding.Varint = require('./lib/encoding/varint');
-bitcore.util = require('./lib/util');
+bitcore.util = {};
+bitcore.util.bitcoin = require('./lib/util/bitcoin');
+bitcore.util.buffer = require('./lib/util/buffer');
+bitcore.util.js = require('./lib/util/js');
// main bitcoin library
bitcore.Address = require('./lib/address');
diff --git a/lib/crypto/point.js b/lib/crypto/point.js
index d457b18..22ac66a 100644
--- a/lib/crypto/point.js
+++ b/lib/crypto/point.js
@@ -4,9 +4,10 @@ var BN = require('./bn');
var elliptic = require('elliptic');
var ec = elliptic.curves.secp256k1;
-var ecpoint = ec.curve.point.bind(ec.curve)
+var ecpoint = ec.curve.point.bind(ec.curve);
var p = ec.curve.point();
-var Curve = Object.getPrototypeOf(ec.curve);
+
+var bufferUtil = require('../util/buffer');
var Point = function Point(x, y, isRed) {
return ecpoint(x, y, isRed);
@@ -27,7 +28,6 @@ Point.getN = function() {
Point.prototype._getX = Point.prototype.getX;
Point.prototype.getX = function() {
- var n = BN(this._getX().toArray());
return BN(this._getX().toArray());
};
@@ -38,15 +38,34 @@ Point.prototype.getY = function() {
//https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf
Point.prototype.validate = function() {
+ /* jshint maxcomplexity: 8 */
var p2 = Point.fromX(this.getY().isOdd(), this.getX());
- if (!(p2.y.cmp(this.y) === 0))
+ if (p2.y.cmp(this.y) !== 0) {
throw new Error('Invalid y value of public key');
- if (!(this.getX().gt(-1) && this.getX().lt(Point.getN()))
- ||!(this.getY().gt(-1) && this.getY().lt(Point.getN())))
+ }
+ var xValidRange = (this.getX().gt(-1) && this.getX().lt(Point.getN()));
+ var yValidRange = (this.getY().gt(-1) && this.getY().lt(Point.getN()));
+ if (!(xValidRange && yValidRange)) {
throw new Error('Point does not lie on the curve');
- if (!(this.mul(Point.getN()).isInfinity()))
+ }
+ if (!(this.mul(Point.getN()).isInfinity())) {
throw new Error('Point times N must be infinity');
+ }
return this;
};
+Point.pointToCompressed = function pointToCompressed(point) {
+ var xbuf = point.getX().toBuffer({size: 32});
+ var ybuf = point.getY().toBuffer({size: 32});
+
+ var prefix;
+ var odd = ybuf[ybuf.length - 1] % 2;
+ if (odd) {
+ prefix = new Buffer([0x03]);
+ } else {
+ prefix = new Buffer([0x02]);
+ }
+ return bufferUtil.concat([prefix, xbuf]);
+};
+
module.exports = Point;
diff --git a/lib/hdprivatekey.js b/lib/hdprivatekey.js
index 78d5e53..d3e0acf 100644
--- a/lib/hdprivatekey.js
+++ b/lib/hdprivatekey.js
@@ -1,6 +1,10 @@
'use strict';
+
+var assert = require('assert');
+var buffer = require('buffer');
var _ = require('lodash');
+
var BN = require('./crypto/bn');
var Base58 = require('./encoding/base58');
var Base58Check = require('./encoding/base58check');
@@ -11,9 +15,8 @@ var Point = require('./crypto/point');
var PrivateKey = require('./privatekey');
var Random = require('./crypto/random');
-var assert = require('assert');
-var buffer = require('buffer');
-var util = require('./util');
+var bufferUtil = require('./util/buffer');
+var jsUtil = require('./util/js');
var MINIMUM_ENTROPY_BITS = 128;
var BITS_TO_BYTES = 1/8;
@@ -29,10 +32,10 @@ function HDPrivateKey(arg) {
return new HDPrivateKey(arg);
}
if (arg) {
- if (_.isString(arg) || buffer.Buffer.isBuffer(arg)) {
+ if (_.isString(arg) || bufferUtil.isBuffer(arg)) {
if (HDPrivateKey.isValidSerialized(arg)) {
this._buildFromSerialized(arg);
- } else if (util.isValidJson(arg)) {
+ } else if (jsUtil.isValidJson(arg)) {
this._buildFromJson(arg);
} else {
throw new Error(HDPrivateKey.getSerializedError(arg));
@@ -73,12 +76,12 @@ HDPrivateKey.prototype._deriveWithNumber = function(index, hardened) {
return cached;
}
- var indexBuffer = util.integerAsBuffer(index);
+ var indexBuffer = bufferUtil.integerAsBuffer(index);
var data;
if (hardened) {
- data = buffer.Buffer.concat([new buffer.Buffer([0]), this.privateKey.toBuffer(), indexBuffer]);
+ data = bufferUtil.concat([new buffer.Buffer([0]), this.privateKey.toBuffer(), indexBuffer]);
} else {
- data = buffer.Buffer.concat([this.publicKey.toBuffer(), indexBuffer]);
+ data = bufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]);
}
var hash = Hash.sha512hmac(data, this._buffers.chainCode);
var leftPart = BN().fromBuffer(hash.slice(0, 32), {size: 32});
@@ -143,7 +146,7 @@ HDPrivateKey.isValidSerialized = function(data, network) {
*/
HDPrivateKey.getSerializedError = function(data, network) {
/* jshint maxcomplexity: 10 */
- if (!(_.isString(data) || buffer.Buffer.isBuffer(data))) {
+ if (!(_.isString(data) || bufferUtil.isBuffer(data))) {
return HDPrivateKey.Errors.InvalidArgument;
}
if (!Base58.validCharacters(data)) {
@@ -172,7 +175,7 @@ HDPrivateKey._validateNetwork = function(data, network) {
return HDPrivateKey.Errors.InvalidNetworkArgument;
}
var version = data.slice(0, 4);
- if (util.integerFromBuffer(version) !== network.xprivkey) {
+ if (bufferUtil.integerFromBuffer(version) !== network.xprivkey) {
return HDPrivateKey.Errors.InvalidNetwork;
}
return null;
@@ -186,13 +189,13 @@ HDPrivateKey.prototype._buildFromObject = function(arg) {
/* jshint maxcomplexity: 12 */
// TODO: Type validation
var buffers = {
- version: arg.network ? util.integerAsBuffer(Network.get(arg.network).xprivkey) : arg.version,
- depth: util.integerAsSingleByteBuffer(arg.depth),
- parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? util.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint,
- childIndex: _.isNumber(arg.childIndex) ? util.integerAsBuffer(arg.childIndex) : arg.childIndex,
- chainCode: _.isString(arg.chainCode) ? util.hexToBuffer(arg.chainCode) : arg.chainCode,
- privateKey: (_.isString(arg.privateKey) && util.isHexa(arg.privateKey)) ? util.hexToBuffer(arg.privateKey) : arg.privateKey,
- checksum: arg.checksum ? (arg.checksum.length ? arg.checksum : util.integerAsBuffer(arg.checksum)) : undefined
+ version: arg.network ? bufferUtil.integerAsBuffer(Network.get(arg.network).xprivkey) : arg.version,
+ depth: bufferUtil.integerAsSingleByteBuffer(arg.depth),
+ parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? bufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint,
+ childIndex: _.isNumber(arg.childIndex) ? bufferUtil.integerAsBuffer(arg.childIndex) : arg.childIndex,
+ chainCode: _.isString(arg.chainCode) ? bufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode,
+ privateKey: (_.isString(arg.privateKey) && jsUtil.isHexa(arg.privateKey)) ? bufferUtil.hexToBuffer(arg.privateKey) : arg.privateKey,
+ checksum: arg.checksum ? (arg.checksum.length ? arg.checksum : bufferUtil.integerAsBuffer(arg.checksum)) : undefined
};
return this._buildFromBuffers(buffers);
};
@@ -220,8 +223,8 @@ HDPrivateKey.prototype._generateRandomly = function(network) {
HDPrivateKey.fromSeed = function(hexa, network) {
/* jshint maxcomplexity: 8 */
- if (util.isHexaString(hexa)) {
- hexa = util.hexToBuffer(hexa);
+ if (jsUtil.isHexaString(hexa)) {
+ hexa = bufferUtil.hexToBuffer(hexa);
}
if (!Buffer.isBuffer(hexa)) {
throw new Error(HDPrivateKey.Errors.InvalidEntropyArg);
@@ -269,7 +272,7 @@ HDPrivateKey.prototype._buildFromBuffers = function(arg) {
var sequence = [
arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode,
- util.emptyBuffer(1), arg.privateKey
+ bufferUtil.emptyBuffer(1), arg.privateKey
];
if (!arg.checksum || !arg.checksum.length) {
arg.checksum = Base58Check.checksum(buffer.Buffer.concat(sequence));
@@ -284,8 +287,8 @@ HDPrivateKey.prototype._buildFromBuffers = function(arg) {
} else {
this.xprivkey = arg.xprivkey;
}
- this.network = Network.get(util.integerFromBuffer(arg.version));
- this.depth = util.integerFromSingleByteBuffer(arg.depth);
+ this.network = Network.get(bufferUtil.integerFromBuffer(arg.version));
+ this.depth = bufferUtil.integerFromSingleByteBuffer(arg.depth);
this.privateKey = new PrivateKey(BN().fromBuffer(arg.privateKey));
this.publicKey = this.privateKey.toPublicKey();
@@ -301,7 +304,7 @@ HDPrivateKey.prototype._buildFromBuffers = function(arg) {
HDPrivateKey._validateBufferArguments = function(arg) {
var checkBuffer = function(name, size) {
var buff = arg[name];
- assert(buffer.Buffer.isBuffer(buff), name + ' argument is not a buffer');
+ assert(bufferUtil.isBuffer(buff), name + ' argument is not a buffer');
assert(
buff.length === size,
name + ' has not the expected size: found ' + buff.length + ', expected ' + size
@@ -324,14 +327,14 @@ HDPrivateKey.prototype.toString = function() {
HDPrivateKey.prototype.toObject = function() {
return {
- network: Network.get(util.integerFromBuffer(this._buffers.version)).name,
- depth: util.integerFromSingleByteBuffer(this._buffers.depth),
- fingerPrint: util.integerFromBuffer(this.fingerPrint),
- parentFingerPrint: util.integerFromBuffer(this._buffers.parentFingerPrint),
- childIndex: util.integerFromBuffer(this._buffers.childIndex),
- chainCode: util.bufferToHex(this._buffers.chainCode),
+ network: Network.get(bufferUtil.integerFromBuffer(this._buffers.version)).name,
+ depth: bufferUtil.integerFromSingleByteBuffer(this._buffers.depth),
+ fingerPrint: bufferUtil.integerFromBuffer(this.fingerPrint),
+ parentFingerPrint: bufferUtil.integerFromBuffer(this._buffers.parentFingerPrint),
+ childIndex: bufferUtil.integerFromBuffer(this._buffers.childIndex),
+ chainCode: bufferUtil.bufferToHex(this._buffers.chainCode),
privateKey: this.privateKey.toBuffer().toString('hex'),
- checksum: util.integerFromBuffer(this._buffers.checksum),
+ checksum: bufferUtil.integerFromBuffer(this._buffers.checksum),
xprivkey: this.xprivkey
};
};
diff --git a/lib/hdpublickey.js b/lib/hdpublickey.js
index faf5fbd..8f335a1 100644
--- a/lib/hdpublickey.js
+++ b/lib/hdpublickey.js
@@ -12,8 +12,9 @@ var Point = require('./crypto/point');
var PublicKey = require('./publickey');
var assert = require('assert');
-var buffer = require('buffer');
-var util = require('./util');
+
+var jsUtil = require('./util/js');
+var bufferUtil = require('./util/buffer');
function HDPublicKey(arg) {
@@ -26,10 +27,10 @@ function HDPublicKey(arg) {
return new HDPublicKey(arg);
}
if (arg) {
- if (_.isString(arg) || buffer.Buffer.isBuffer(arg)) {
+ if (_.isString(arg) || bufferUtil.isBuffer(arg)) {
if (HDPublicKey.isValidSerialized(arg)) {
return this._buildFromSerialized(arg);
- } else if (util.isValidJson(arg)) {
+ } else if (jsUtil.isValidJson(arg)) {
return this._buildFromJson(arg);
} else {
var error = HDPublicKey.getSerializedError(arg);
@@ -73,8 +74,8 @@ HDPublicKey.prototype._deriveWithNumber = function (index, hardened) {
return cached;
}
- var indexBuffer = util.integerAsBuffer(index);
- var data = buffer.Buffer.concat([this.publicKey.toBuffer(), indexBuffer]);
+ var indexBuffer = bufferUtil.integerAsBuffer(index);
+ var data = bufferUtil.concat([this.publicKey.toBuffer(), indexBuffer]);
var hash = Hash.sha512hmac(data, this._buffers.chainCode);
var leftPart = BN().fromBuffer(hash.slice(0, 32), {size: 32});
var chainCode = hash.slice(32, 64);
@@ -140,7 +141,7 @@ HDPublicKey.isValidSerialized = function (data, network) {
HDPublicKey.getSerializedError = function (data, network) {
/* jshint maxcomplexity: 10 */
/* jshint maxstatements: 20 */
- if (!(_.isString(data) || buffer.Buffer.isBuffer(data))) {
+ if (!(_.isString(data) || bufferUtil.isBuffer(data))) {
return HDPublicKey.Errors.InvalidArgument;
}
if (!Base58.validCharacters(data)) {
@@ -161,7 +162,7 @@ HDPublicKey.getSerializedError = function (data, network) {
}
}
network = Network.get(network) || Network.defaultNetwork;
- if (util.integerFromBuffer(data.slice(0, 4)) === network.xprivkey) {
+ if (bufferUtil.integerFromBuffer(data.slice(0, 4)) === network.xprivkey) {
return HDPublicKey.Errors.ArgumentIsPrivateExtended;
}
return null;
@@ -173,7 +174,7 @@ HDPublicKey._validateNetwork = function (data, network) {
return HDPublicKey.Errors.InvalidNetworkArgument;
}
var version = data.slice(HDPublicKey.VersionStart, HDPublicKey.VersionEnd);
- if (util.integerFromBuffer(version) !== network.xpubkey) {
+ if (bufferUtil.integerFromBuffer(version) !== network.xpubkey) {
return HDPublicKey.Errors.InvalidNetwork;
}
return null;
@@ -186,8 +187,8 @@ HDPublicKey.prototype._buildFromJson = function (arg) {
HDPublicKey.prototype._buildFromPrivate = function (arg) {
var args = _.clone(arg._buffers);
var point = Point.getG().mul(BN().fromBuffer(args.privateKey));
- args.publicKey = util.pointToCompressed(point);
- args.version = util.integerAsBuffer(Network.get(util.integerFromBuffer(args.version)).xpubkey);
+ args.publicKey = Point.pointToCompressed(point);
+ args.version = bufferUtil.integerAsBuffer(Network.get(bufferUtil.integerFromBuffer(args.version)).xpubkey);
args.privateKey = undefined;
args.checksum = undefined;
args.xprivkey = undefined;
@@ -198,14 +199,14 @@ HDPublicKey.prototype._buildFromObject = function (arg) {
/* jshint maxcomplexity: 10 */
// TODO: Type validation
var buffers = {
- version: arg.network ? util.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version,
- depth: util.integerAsSingleByteBuffer(arg.depth),
- parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? util.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint,
- childIndex: util.integerAsBuffer(arg.childIndex),
- chainCode: _.isString(arg.chainCode) ? util.hexToBuffer(arg.chainCode) : arg.chainCode,
- publicKey: _.isString(arg.publicKey) ? util.hexToBuffer(arg.publicKey) :
- buffer.Buffer.isBuffer(arg.publicKey) ? arg.publicKey : arg.publicKey.toBuffer(),
- checksum: _.isNumber(arg.checksum) ? util.integerAsBuffer(arg.checksum) : arg.checksum
+ version: arg.network ? bufferUtil.integerAsBuffer(Network.get(arg.network).xpubkey) : arg.version,
+ depth: bufferUtil.integerAsSingleByteBuffer(arg.depth),
+ parentFingerPrint: _.isNumber(arg.parentFingerPrint) ? bufferUtil.integerAsBuffer(arg.parentFingerPrint) : arg.parentFingerPrint,
+ childIndex: bufferUtil.integerAsBuffer(arg.childIndex),
+ chainCode: _.isString(arg.chainCode) ? bufferUtil.hexToBuffer(arg.chainCode) : arg.chainCode,
+ publicKey: _.isString(arg.publicKey) ? bufferUtil.hexToBuffer(arg.publicKey) :
+ bufferUtil.isBuffer(arg.publicKey) ? arg.publicKey : arg.publicKey.toBuffer(),
+ checksum: _.isNumber(arg.checksum) ? bufferUtil.integerAsBuffer(arg.checksum) : arg.checksum
};
return this._buildFromBuffers(buffers);
};
@@ -253,7 +254,7 @@ HDPublicKey.prototype._buildFromBuffers = function (arg) {
arg.version, arg.depth, arg.parentFingerPrint, arg.childIndex, arg.chainCode,
arg.publicKey
];
- var concat = buffer.Buffer.concat(sequence);
+ var concat = bufferUtil.concat(sequence);
var checksum = Base58Check.checksum(concat);
if (!arg.checksum || !arg.checksum.length) {
arg.checksum = checksum;
@@ -264,13 +265,13 @@ HDPublicKey.prototype._buildFromBuffers = function (arg) {
}
if (!arg.xpubkey) {
- this.xpubkey = Base58Check.encode(buffer.Buffer.concat(sequence));
+ this.xpubkey = Base58Check.encode(bufferUtil.concat(sequence));
} else {
this.xpubkey = arg.xpubkey;
}
- this.network = Network.get(util.integerFromBuffer(arg.version));
- this.depth = util.integerFromSingleByteBuffer(arg.depth);
+ this.network = Network.get(bufferUtil.integerFromBuffer(arg.version));
+ this.depth = bufferUtil.integerFromSingleByteBuffer(arg.depth);
this.publicKey = PublicKey.fromString(arg.publicKey);
this.fingerPrint = Hash.sha256ripemd160(this.publicKey.toBuffer()).slice(0, HDPublicKey.ParentFingerPrintSize);
@@ -280,7 +281,7 @@ HDPublicKey.prototype._buildFromBuffers = function (arg) {
HDPublicKey._validateBufferArguments = function (arg) {
var checkBuffer = function(name, size) {
var buff = arg[name];
- assert(buffer.Buffer.isBuffer(buff), name + ' argument is not a buffer, it\'s ' + typeof buff);
+ assert(bufferUtil.isBuffer(buff), name + ' argument is not a buffer, it\'s ' + typeof buff);
assert(
buff.length === size,
name + ' has not the expected size: found ' + buff.length + ', expected ' + size
@@ -303,14 +304,14 @@ HDPublicKey.prototype.toString = function () {
HDPublicKey.prototype.toObject = function () {
return {
- network: Network.get(util.integerFromBuffer(this._buffers.version)).name,
- depth: util.integerFromSingleByteBuffer(this._buffers.depth),
- fingerPrint: util.integerFromBuffer(this.fingerPrint),
- parentFingerPrint: util.integerFromBuffer(this._buffers.parentFingerPrint),
- childIndex: util.integerFromBuffer(this._buffers.childIndex),
- chainCode: util.bufferToHex(this._buffers.chainCode),
+ network: Network.get(bufferUtil.integerFromBuffer(this._buffers.version)).name,
+ depth: bufferUtil.integerFromSingleByteBuffer(this._buffers.depth),
+ fingerPrint: bufferUtil.integerFromBuffer(this.fingerPrint),
+ parentFingerPrint: bufferUtil.integerFromBuffer(this._buffers.parentFingerPrint),
+ childIndex: bufferUtil.integerFromBuffer(this._buffers.childIndex),
+ chainCode: bufferUtil.bufferToHex(this._buffers.chainCode),
publicKey: this.publicKey.toString(),
- checksum: util.integerFromBuffer(this._buffers.checksum),
+ checksum: bufferUtil.integerFromBuffer(this._buffers.checksum),
xpubkey: this.xpubkey
};
};
diff --git a/lib/util.js b/lib/util.js
deleted file mode 100644
index d4e8af4..0000000
--- a/lib/util.js
+++ /dev/null
@@ -1,81 +0,0 @@
-'use strict';
-
-var _ = require('lodash');
-var buffer = require('buffer');
-var assert = require('assert');
-
-var isHexa = function isHexa(value) {
- if (!_.isString(value)) {
- return false;
- }
- return /^[0-9a-fA-F]+$/.test(value);
-};
-
-var shallowEquals = function(obj1, obj2) {
- var keys1 = _.keys(obj1);
- var keys2 = _.keys(obj2);
- if (_.size(keys1) !== _.size(keys2)) {
- return false;
- }
- var compare = function(key) { return obj1[key] === obj2[key]; };
- return _.all(keys1, compare) && _.all(keys2, compare);
-};
-
-module.exports = {
- shallowEquals: shallowEquals,
- isValidJson: function isValidJson(arg) {
- try {
- JSON.parse(arg);
- return true;
- } catch (e) {
- return false;
- }
- },
- emptyBuffer: function emptyBuffer(bytes) {
- var result = new Buffer(bytes);
- for (var i = 0; i < bytes; i++) {
- result.write('\0', i);
- }
- return result;
- },
- integerAsSingleByteBuffer: function integerAsSingleByteBuffer(integer) {
- return new Buffer([integer & 0xff]);
- },
- integerAsBuffer: function integerAsBuffer(integer) {
- var bytes = [];
- bytes.push((integer >> 24) & 0xff);
- bytes.push((integer >> 16) & 0xff);
- bytes.push((integer >> 8) & 0xff);
- bytes.push(integer & 0xff);
- return new Buffer(bytes);
- },
- isHexa: isHexa,
- isHexaString: isHexa,
-
- integerFromBuffer: function integerFromBuffer(buffer) {
- return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
- },
- integerFromSingleByteBuffer: function integerFromBuffer(buffer) {
- return buffer[0];
- },
- bufferToHex: function bufferToHex(buffer) {
- return buffer.toString('hex');
- },
- hexToBuffer: function hexToBuffer(string) {
- assert(isHexa(string));
- return new buffer.Buffer(string, 'hex');
- },
- pointToCompressed: function pointToCompressed(point) {
- var xbuf = point.getX().toBuffer({size: 32});
- var ybuf = point.getY().toBuffer({size: 32});
-
- var prefix;
- var odd = ybuf[ybuf.length - 1] % 2;
- if (odd) {
- prefix = new Buffer([0x03]);
- } else {
- prefix = new Buffer([0x02]);
- }
- return buffer.Buffer.concat([prefix, xbuf]);
- }
-};
diff --git a/lib/util/bitcoin.js b/lib/util/bitcoin.js
new file mode 100644
index 0000000..821c04d
--- /dev/null
+++ b/lib/util/bitcoin.js
@@ -0,0 +1,18 @@
+/**
+ * @file util/bitcoin.js
+ * Contains utilities to handle magnitudes inside of bitcoin
+ */
+'use strict';
+
+var SATOSHIS_PER_BTC = 1e8;
+
+module.exports = {
+ /**
+ * @param number satoshis - amount of satoshis to convert
+ * @return string an exact representation of such amount, in form of a string
+ * (avoids duplicate representations in ieee756 of the same number)
+ */
+ satoshisToBitcoin: function(satoshis) {
+ return satoshis / SATOSHIS_PER_BTC;
+ }
+};
diff --git a/lib/util/buffer.js b/lib/util/buffer.js
new file mode 100644
index 0000000..5b9e65a
--- /dev/null
+++ b/lib/util/buffer.js
@@ -0,0 +1,109 @@
+'use strict';
+
+var buffer = require('buffer');
+var assert = require('assert');
+
+var js = require('./js');
+
+module.exports = {
+ /**
+ * Returns true if the given argument is an instance of a buffer. Tests for
+ * both node's Buffer and Uint8Array
+ *
+ * @param {*} arg
+ * @return {boolean}
+ */
+ isBuffer: function isBuffer(arg) {
+ return buffer.Buffer.isBuffer(arg) || arg instanceof Uint8Array;
+ },
+
+ /**
+ * Returns a zero-filled byte array
+ *
+ * @param {number} bytes
+ * @return {Buffer}
+ */
+ emptyBuffer: function emptyBuffer(bytes) {
+ var result = new buffer.Buffer(bytes);
+ for (var i = 0; i < bytes; i++) {
+ result.write('\0', i);
+ }
+ return result;
+ },
+
+ /**
+ * Concatenates a buffer
+ *
+ * Shortcut for buffer.Buffer.concat
+ */
+ concat: buffer.Buffer.concat,
+
+ /**
+ * Transforms a number from 0 to 255 into a Buffer of size 1 with that value
+ *
+ * @param {number} integer
+ * @return {Buffer}
+ */
+ integerAsSingleByteBuffer: function integerAsSingleByteBuffer(integer) {
+ return new buffer.Buffer([integer & 0xff]);
+ },
+
+ /**
+ * Transform a 4-byte integer into a Buffer of length 4.
+ *
+ * @param {number} integer
+ * @return {Buffer}
+ */
+ integerAsBuffer: function integerAsBuffer(integer) {
+ var bytes = [];
+ bytes.push((integer >> 24) & 0xff);
+ bytes.push((integer >> 16) & 0xff);
+ bytes.push((integer >> 8) & 0xff);
+ bytes.push(integer & 0xff);
+ return new Buffer(bytes);
+ },
+
+ /**
+ * Transform the first 4 values of a Buffer into a number, in little endian encoding
+ *
+ * @param {Buffer} buffer
+ * @return {number}
+ */
+ integerFromBuffer: function integerFromBuffer(buffer) {
+ return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
+ },
+
+ /**
+ * Transforms the first byte of an array into a number ranging from -128 to 127
+ * @param {Buffer} buffer
+ * @return {number}
+ */
+ integerFromSingleByteBuffer: function integerFromBuffer(buffer) {
+ return buffer[0];
+ },
+
+ /**
+ * Transforms a buffer into a string with a number in hexa representation
+ *
+ * Shorthand for buffer.toString('hex')
+ *
+ * @param {Buffer} buffer
+ * @return {string}
+ */
+ bufferToHex: function bufferToHex(buffer) {
+ return buffer.toString('hex');
+ },
+
+ /**
+ * Transforms an hexa encoded string into a Buffer with binary values
+ *
+ * Shorthand for Buffer(string, 'hex')
+ *
+ * @param {string} string
+ * @return {Buffer}
+ */
+ hexToBuffer: function hexToBuffer(string) {
+ assert(js.isHexa(string));
+ return new buffer.Buffer(string, 'hex');
+ }
+};
diff --git a/lib/util/js.js b/lib/util/js.js
new file mode 100644
index 0000000..a4b2e3a
--- /dev/null
+++ b/lib/util/js.js
@@ -0,0 +1,35 @@
+'use strict';
+
+var _ = require('lodash');
+
+/**
+ * Determines whether a string contains only hexadecimal values
+ *
+ * @param {string} value
+ * @return {boolean} true if the string is the hexa representation of a number
+ */
+var isHexa = function isHexa(value) {
+ if (!_.isString(value)) {
+ return false;
+ }
+ return /^[0-9a-fA-F]+$/.test(value);
+};
+
+module.exports = {
+ /**
+ * Test if an argument is a valid JSON object. If it is, returns a truthy
+ * value (the json object decoded), so no double JSON.parse call is necessary
+ *
+ * @param {string} arg
+ * @return {Object|boolean} false if the argument is not a JSON string.
+ */
+ isValidJson: function isValidJson(arg) {
+ try {
+ return JSON.parse(arg);
+ } catch (e) {
+ return false;
+ }
+ },
+ isHexa: isHexa,
+ isHexaString: isHexa
+};
diff --git a/test/hdprivatekey.js b/test/hdprivatekey.js
index bba1d9c..e40a0a3 100644
--- a/test/hdprivatekey.js
+++ b/test/hdprivatekey.js
@@ -6,7 +6,7 @@ var should = require('chai').should();
var expect = require('chai').expect;
var bitcore = require('..');
var buffer = require('buffer');
-var util = bitcore.util;
+var bufferUtil = bitcore.util.buffer;
var HDPrivateKey = bitcore.HDPrivateKey;
var Base58Check = bitcore.encoding.Base58Check;
@@ -41,7 +41,7 @@ describe('HDPrivate key interface', function() {
});
it('builds a json keeping the structure and same members', function() {
- assert(util.shallowEquals(
+ assert(_.isEqual(
JSON.parse(new HDPrivateKey(json).toJson()),
JSON.parse(new HDPrivateKey(xprivkey).toJson())
));
@@ -130,7 +130,7 @@ describe('HDPrivate key interface', function() {
var privKey = new HDPrivateKey(xprivkey);
expect(function() {
var buffers = privKey._buffers;
- buffers.checksum = util.integerAsBuffer(0);
+ buffers.checksum = bufferUtil.integerAsBuffer(0);
return new HDPrivateKey(buffers);
}).to.throw(HDPrivateKey.Errors.InvalidB58Checksum);
});
diff --git a/test/hdpublickey.js b/test/hdpublickey.js
index 219eaee..a9e150f 100644
--- a/test/hdpublickey.js
+++ b/test/hdpublickey.js
@@ -7,7 +7,7 @@ var should = require('chai').should();
var expect = require('chai').expect;
var bitcore = require('..');
var buffer = require('buffer');
-var util = bitcore.util;
+var bufferUtil = bitcore.util.buffer;
var HDPrivateKey = bitcore.HDPrivateKey;
var HDPublicKey = bitcore.HDPublicKey;
var Base58Check = bitcore.encoding.Base58Check;
@@ -71,7 +71,7 @@ describe('HDPublicKey interface', function() {
});
it('can generate a json that has a particular structure', function() {
- assert(util.shallowEquals(
+ assert(_.isEqual(
JSON.parse(new HDPublicKey(json).toJson()),
JSON.parse(new HDPublicKey(xpubkey).toJson())
));
@@ -83,7 +83,7 @@ describe('HDPublicKey interface', function() {
it('checks the checksum', function() {
var buffers = new HDPublicKey(xpubkey)._buffers;
- buffers.checksum = util.integerAsBuffer(1);
+ buffers.checksum = bufferUtil.integerAsBuffer(1);
expectFail(buffers, HDPublicKey.Errors.InvalidB58Checksum)();
});