From 36e87d88225877589197fda2a1350f456b509049 Mon Sep 17 00:00:00 2001 From: Esteban Ordano Date: Fri, 19 Dec 2014 15:32:57 -0300 Subject: [PATCH] PrivateKey, PublicKey, Network linted * Added 100% test coverage for them also --- lib/networks.js | 12 ++- lib/privatekey.js | 77 +++++++++++------- lib/publickey.js | 62 ++++++++------ test/networks.js | 10 +++ test/privatekey.js | 199 +++++++++++++++++++++++++++------------------ test/publickey.js | 151 ++++++++++++++++++++-------------- 6 files changed, 314 insertions(+), 197 deletions(-) diff --git a/lib/networks.js b/lib/networks.js index 1452d7a..7994b38 100644 --- a/lib/networks.js +++ b/lib/networks.js @@ -79,12 +79,22 @@ _.each(_.values(testnet), function(value) { * @member Network#getNetwork * Retrieves the network associated with a magic number or string. * @param {string|number|Network} arg + * @param {string} key - if set, only check if the magic number associated with this name matches * @return Network */ -function getNetwork(arg) { +function getNetwork(arg, key) { if (arg === livenet || arg === testnet) { return arg; } + if (key) { + var networks = [livenet, testnet]; + for (var index in networks) { + if (networks[index][key] === arg) { + return networks[index]; + } + } + return undefined; + } return networkMaps[arg]; } diff --git a/lib/privatekey.js b/lib/privatekey.js index 4a2cced..344f5ac 100644 --- a/lib/privatekey.js +++ b/lib/privatekey.js @@ -15,7 +15,6 @@ var Random = require('./crypto/random'); * * @example * ```javascript - * * // generate a new random key * var key = PrivateKey(); * @@ -29,12 +28,14 @@ var Random = require('./crypto/random'); * var imported = PrivateKey.fromWIF(exported); * ``` * - * @param {String} data - The encoded data in various formats - * @param {String} [network] - Either "livenet" or "testnet" + * @param {string} data - The encoded data in various formats + * @param {Network|string} [network] - a {@link Network} object, or a string with the network name * @returns {PrivateKey} A new valid instance of an PrivateKey * @constructor */ var PrivateKey = function PrivateKey(data, network) { + /* jshint maxstatements: 20 */ + /* jshint maxcomplexity: 8 */ if (!(this instanceof PrivateKey)) { return new PrivateKey(data, network); @@ -43,29 +44,7 @@ var PrivateKey = function PrivateKey(data, network) { return data; } - var info = { - compressed: true, - network: network ? Networks.get(network) : Networks.defaultNetwork - }; - - // detect type of data - if (_.isUndefined(data)){ - info.bn = PrivateKey._getRandomBN(); - } else if (data instanceof BN) { - info.bn = data; - } else if (data instanceof Buffer || data instanceof Uint8Array) { - info = PrivateKey._transformBuffer(data, network); - } else if (PrivateKey._isJSON(data)){ - info = PrivateKey._transformJSON(data); - } else if (typeof(data) === 'string'){ - if (JSUtil.isHexa(data)) { - info.bn = BN(new Buffer(data, 'hex')); - } else { - info = PrivateKey._transformWIF(data, network); - } - } else { - throw new TypeError('First argument is an unrecognized data type.'); - } + var info = this._classifyArguments(data, network); // validation if (!info.bn || info.bn.cmp(0) === 0){ @@ -103,7 +82,43 @@ var PrivateKey = function PrivateKey(data, network) { }; /** - * Internal function to get a random BN + * Internal helper to instantiate PrivateKey internal `info` object from + * different kinds of arguments passed to the constructor. + * + * @param {*} data + * @param {Network|string} [network] - a {@link Network} object, or a string with the network name + * @return {Object} + */ +PrivateKey.prototype._classifyArguments = function(data, network) { + /* jshint maxcomplexity: 10 */ + var info = { + compressed: true, + network: network ? Networks.get(network) : Networks.defaultNetwork + }; + + // detect type of data + if (_.isUndefined(data)){ + info.bn = PrivateKey._getRandomBN(); + } else if (data instanceof BN) { + info.bn = data; + } else if (data instanceof Buffer || data instanceof Uint8Array) { + info = PrivateKey._transformBuffer(data, network); + } else if (PrivateKey._isJSON(data)){ + info = PrivateKey._transformJSON(data); + } else if (typeof(data) === 'string'){ + if (JSUtil.isHexa(data)) { + info.bn = BN(new Buffer(data, 'hex')); + } else { + info = PrivateKey._transformWIF(data, network); + } + } else { + throw new TypeError('First argument is an unrecognized data type.'); + } + return info; +}; + +/** + * Internal function to get a random Big Number (BN) * * @returns {BN} A new randomly generated BN * @private @@ -127,14 +142,14 @@ PrivateKey._getRandomBN = function(){ * @private */ PrivateKey._isJSON = function(json) { - return JSUtil.isValidJSON(json) || (json.bn && json.network && json.compressed); + return JSUtil.isValidJSON(json) || (json.bn && json.network); }; /** * Internal function to transform a WIF Buffer into a private key * * @param {Buffer} buf - An WIF string - * @param {String} [network] - Either "livenet" or "testnet" + * @param {Network|string} [network] - a {@link Network} object, or a string with the network name * @returns {Object} An object with keys: bn, network and compressed * @private */ @@ -150,6 +165,7 @@ PrivateKey._transformBuffer = function(buf, network) { throw new Error('Length of buffer must be 33 (uncompressed) or 34 (compressed)'); } + info.network = Networks.get(buf[0], 'privatekey'); if (buf[0] === Networks.livenet.privatekey) { info.network = Networks.livenet; } else if (buf[0] === Networks.testnet.privatekey) { @@ -210,7 +226,7 @@ PrivateKey._transformJSON = function(json) { bn: bn, network: json.network, compressed: json.compressed - } + }; }; /** @@ -245,6 +261,7 @@ PrivateKey.fromRandom = function(network) { PrivateKey.getValidationError = function(data, network) { var error; try { + /* jshint nonew: false */ new PrivateKey(data, network); } catch (e) { error = e; diff --git a/lib/publickey.js b/lib/publickey.js index 26166c1..94c22e0 100644 --- a/lib/publickey.js +++ b/lib/publickey.js @@ -9,11 +9,13 @@ var _ = require('lodash'); var $ = require('./util/preconditions'); /** - * Instantiate a PublicKey from a 'PrivateKey', 'Point', 'string', 'Buffer'. + * Instantiate a PublicKey from a {@link PrivateKey}, {@link Point}, `string`, or `Buffer`. + * + * There are two internal properties, `network` and `compressed`, that deal with importing + * a PublicKey from a PrivateKey in WIF format. More details described on {@link PrivateKey} * * @example * ```javascript - * * // instantiate from a private key * var key = PublicKey(privateKey, true); * @@ -45,25 +47,7 @@ var PublicKey = function PublicKey(data, extra) { } extra = extra || {}; - var info = { - compressed: _.isUndefined(extra.compressed) || extra.compressed, - network: _.isUndefined(extra.network) ? undefined : Network.get(extra.network) - }; - - // detect type of data - if (data instanceof Point) { - info.point = data; - } else if (PublicKey._isJSON(data)) { - info = PublicKey._transformJSON(data); - } else if (typeof(data) === 'string') { - info = PublicKey._transformDER(new Buffer(data, 'hex')); - } else if (PublicKey._isBuffer(data)) { - info = PublicKey._transformDER(data); - } else if (PublicKey._isPrivateKey(data)) { - info = PublicKey._transformPrivateKey(data); - } else { - throw new TypeError('First argument is an unrecognized data format.'); - } + var info = this._classifyArgs(data, extra); // validation info.point.validate(); @@ -88,7 +72,36 @@ var PublicKey = function PublicKey(data, extra) { }; /** - * Internal function to detect if an object is a PrivateKey + * Internal function to differentiate between arguments passed to the constructor + * @param {*} data + * @param {Object} extra + */ +PublicKey.prototype._classifyArgs = function(data, extra) { + /* jshint maxcomplexity: 10 */ + var info = { + compressed: _.isUndefined(extra.compressed) || extra.compressed, + network: _.isUndefined(extra.network) ? undefined : Network.get(extra.network) + }; + + // detect type of data + if (data instanceof Point) { + info.point = data; + } else if (PublicKey._isJSON(data)) { + info = PublicKey._transformJSON(data); + } else if (typeof(data) === 'string') { + info = PublicKey._transformDER(new Buffer(data, 'hex')); + } else if (PublicKey._isBuffer(data)) { + info = PublicKey._transformDER(data); + } else if (PublicKey._isPrivateKey(data)) { + info = PublicKey._transformPrivateKey(data); + } else { + throw new TypeError('First argument is an unrecognized data format.'); + } + return info; +}; + +/** + * Internal function to detect if an object is a {@link PrivateKey} * * @param {*} param - object to test * @returns {boolean} @@ -147,6 +160,8 @@ PublicKey._transformPrivateKey = function(privkey) { * @private */ PublicKey._transformDER = function(buf, strict) { + /* jshint maxstatements: 30 */ + /* jshint maxcomplexity: 12 */ $.checkArgument(PublicKey._isBuffer(buf), new TypeError('Must be a hex buffer of DER encoded public key')); var info = {}; @@ -165,7 +180,7 @@ PublicKey._transformDER = function(buf, strict) { } x = BN(xbuf); y = BN(ybuf); - info.point = Point(x, y); + info.point = new Point(x, y); info.compressed = false; } else if (buf[0] === 0x03) { xbuf = buf.slice(1); @@ -314,6 +329,7 @@ PublicKey.fromX = function(odd, x) { PublicKey.getValidationError = function(data) { var error; try { + /* jshint nonew: false */ new PublicKey(data); } catch (e) { error = e; diff --git a/test/networks.js b/test/networks.js index af09951..a542c7b 100644 --- a/test/networks.js +++ b/test/networks.js @@ -1,5 +1,6 @@ 'use strict'; +var expect = require('chai').expect; var should = require('chai').should(); var bitcore = require('..'); var networks = bitcore.Networks; @@ -21,4 +22,13 @@ describe('Networks', function() { }); }); + it('tests only for the specified key', function() { + expect(networks.get(0x6f, 'pubkeyhash')).to.equal(networks.testnet); + expect(networks.get(0x6f, 'privatekey')).to.equal(undefined); + }); + + it('converts to string using the "name" property', function() { + networks.livenet.toString().should.equal('livenet'); + }); + }); diff --git a/test/privatekey.js b/test/privatekey.js index 6fe249d..6ecda31 100644 --- a/test/privatekey.js +++ b/test/privatekey.js @@ -17,10 +17,10 @@ var invalidbase58 = require('./data/bitcoind/base58_keys_invalid.json'); describe('PrivateKey', function() { var hex = '96c132224121b509b7d0a16245e957d9192609c5637c6228311287b1be21627a'; var buf = new Buffer(hex, 'hex'); - var enctestnet = 'cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG'; - var enctu = '92jJzK4tbURm1C7udQXxeCBvXHoHJstDXRxAMouPG1k1XUaXdsu'; - var enclivenet = 'L2Gkw3kKJ6N24QcDuH4XDqt9cTqsKTVNDGz1CRZhk9cq4auDUbJy'; - var encmu = '5JxgQaFM1FMd38cd14e3mbdxsdSa9iM2BV6DHBYsvGzxkTNQ7Un'; + var wifTestnet = 'cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG'; + var wifTestnetUncompressed = '92jJzK4tbURm1C7udQXxeCBvXHoHJstDXRxAMouPG1k1XUaXdsu'; + var wifLivenet = 'L2Gkw3kKJ6N24QcDuH4XDqt9cTqsKTVNDGz1CRZhk9cq4auDUbJy'; + var wifLivenetUncompressed = '5JxgQaFM1FMd38cd14e3mbdxsdSa9iM2BV6DHBYsvGzxkTNQ7Un'; it('should create a new random private key', function() { var a = new PrivateKey(); @@ -66,75 +66,82 @@ describe('PrivateKey', function() { }); }); - it('should not be able to instantiate private key greater than N', function() { - expect(function() { - var n = Point.getN(); - var a = new PrivateKey(n); - }).to.throw('Number must be less than N'); - }); + describe('instantiation', function() { + it('should not be able to instantiate private key greater than N', function() { + expect(function() { + return new PrivateKey(Point.getN()); + }).to.throw('Number must be less than N'); + }); - it('should not be able to instantiate private key because of network mismatch', function() { - expect(function() { - var a = new PrivateKey('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m', 'testnet'); - }).to.throw('Private key network mismatch'); - }); + it('should not be able to instantiate private key because of network mismatch', function() { + expect(function() { + return new PrivateKey('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m', 'testnet'); + }).to.throw('Private key network mismatch'); + }); - it('should not be able to instantiate private key WIF is too long', function() { - expect(function() { - var buf = base58check.decode('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m'); - var buf2 = Buffer.concat([buf, new Buffer(0x01)]); - var a = new PrivateKey(buf2); - }).to.throw('Length of buffer must be 33 (uncompressed) or 34 (compressed'); - }); + it('should not be able to instantiate private key WIF is too long', function() { + expect(function() { + var buf = base58check.decode('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m'); + var buf2 = Buffer.concat([buf, new Buffer(0x01)]); + return new PrivateKey(buf2); + }).to.throw('Length of buffer must be 33 (uncompressed) or 34 (compressed'); + }); - it('should not be able to instantiate private key WIF because of unknown network byte', function() { - expect(function() { - var buf = base58check.decode('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m'); - var buf2 = Buffer.concat([new Buffer('ff', 'hex'), buf.slice(1, 33)]); - var a = new PrivateKey(buf2); - }).to.throw('Invalid network'); - }); + it('should not be able to instantiate private key WIF because of unknown network byte', function() { + expect(function() { + var buf = base58check.decode('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m'); + var buf2 = Buffer.concat([new Buffer('ff', 'hex'), buf.slice(1, 33)]); + return new PrivateKey(buf2); + }).to.throw('Invalid network'); + }); - it('can be instantiated from a hex string', function() { - var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff'; - var pubhex = '02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc'; - var privkey = new PrivateKey(privhex); - privkey.publicKey.toString().should.equal(pubhex); - }); + it('can be instantiated from a hex string', function() { + var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff'; + var pubhex = '02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc'; + var privkey = new PrivateKey(privhex); + privkey.publicKey.toString().should.equal(pubhex); + }); - it('should not be able to instantiate because of unrecognized data', function() { - expect(function() { - var a = new PrivateKey(new Error()); - }).to.throw('First argument is an unrecognized data type.'); - }); + it('should not be able to instantiate because of unrecognized data', function() { + expect(function() { + return new PrivateKey(new Error()); + }).to.throw('First argument is an unrecognized data type.'); + }); - it('should not be able to instantiate with unknown network', function() { - expect(function() { - var a = new PrivateKey(BN(2), 'unknown'); - }).to.throw('Must specify the network ("livenet" or "testnet")'); - }); + it('should not be able to instantiate with unknown network', function() { + expect(function() { + return new PrivateKey(BN(2), 'unknown'); + }).to.throw('Must specify the network ("livenet" or "testnet")'); + }); - it('should not create a zero private key', function() { - expect(function() { - var bn = BN(0); - var privkey = new PrivateKey(bn); - }).to.throw(TypeError); - }); + it('should not create a zero private key', function() { + expect(function() { + var bn = BN(0); + return new PrivateKey(bn); + }).to.throw(TypeError); + }); - it('should create a livenet private key', function() { - var privkey = new PrivateKey(BN.fromBuffer(buf), 'livenet'); - privkey.toString().should.equal(enclivenet); - }); + it('should create a livenet private key', function() { + var privkey = new PrivateKey(BN.fromBuffer(buf), 'livenet'); + privkey.toString().should.equal(wifLivenet); + }); + + it('should create a default network private key', function() { + var a = new PrivateKey(BN.fromBuffer(buf)); + a.network.should.equal(Networks.livenet); + // change the default + Networks.defaultNetwork = Networks.testnet; + var b = new PrivateKey(BN.fromBuffer(buf)); + b.network.should.equal(Networks.testnet); + // restore the default + Networks.defaultNetwork = Networks.livenet; + }); + + it('returns the same instance if a PrivateKey is provided (immutable)', function() { + var privkey = new PrivateKey(); + new PrivateKey(privkey).should.equal(privkey); + }); - it('should create a default network private key', function() { - var a = new PrivateKey(BN.fromBuffer(buf)); - a.network.should.equal(Networks.livenet); - // change the default - Networks.defaultNetwork = Networks.testnet; - var b = new PrivateKey(BN.fromBuffer(buf)); - b.network.should.equal(Networks.testnet); - // restore the default - Networks.defaultNetwork = Networks.livenet; }); describe('#json', function() { @@ -148,13 +155,37 @@ describe('PrivateKey', function() { PrivateKey.fromJSON(json).toJSON().should.deep.equal(json); }); + it('an object with private key info can be also used as argument for "fromJSON"', function() { + expect(PrivateKey._isJSON({bn: true, network: true})).to.equal(true); + }); + + it('fails on invalid argument', function() { + expect(function() { + return PrivateKey.fromJSON('¹'); + }).to.throw(); + }); + + it('also accepts an object as argument', function() { + expect(function() { + return PrivateKey.fromJSON(new PrivateKey().toObject()); + }).to.not.throw(); + }); + }); + + it('coverage: public key cache', function() { + expect(function() { + var privateKey = new PrivateKey(); + /* jshint unused: false */ + var publicKey = privateKey.publicKey; + return privateKey.publicKey; + }).to.not.throw(); }); describe('#toString', function() { it('should output this address correctly', function() { - var privkey = PrivateKey.fromWIF(encmu); - privkey.toString().should.equal(encmu); + var privkey = PrivateKey.fromWIF(wifLivenetUncompressed); + privkey.toString().should.equal(wifLivenetUncompressed); }); }); @@ -177,14 +208,22 @@ describe('PrivateKey', function() { describe('#inspect', function() { it('should output known livenet address for console', function() { var privkey = PrivateKey.fromWIF('L3T1s1TYP9oyhHpXgkyLoJFGniEgkv2Jhi138d7R2yJ9F4QdDU2m'); - privkey.inspect().should.equal(''); + privkey.inspect().should.equal( + '' + ); }); it('should output known testnet address for console', function() { var privkey = PrivateKey.fromWIF('cR4qogdN9UxLZJXCNFNwDRRZNeLRWuds9TTSuLNweFVjiaE4gPaq'); - privkey.inspect().should.equal(''); + privkey.inspect().should.equal( + '' + ); }); + it('outputs "uncompressed" for uncompressed imported WIFs', function() { + var privkey = PrivateKey.fromWIF(wifLivenetUncompressed); + privkey.inspect().should.equal(''); + }); }); describe('#getValidationError', function(){ @@ -210,7 +249,7 @@ describe('PrivateKey', function() { describe('#toBuffer', function() { it('should output known buffer', function() { var privkey = new PrivateKey(BN.fromBuffer(buf), 'livenet'); - var b = privkey.toBuffer().toString('hex').should.equal(buf.toString('hex')); + privkey.toBuffer().toString('hex').should.equal(buf.toString('hex')); }); }); @@ -237,8 +276,8 @@ describe('PrivateKey', function() { describe('#fromWIF', function() { it('should parse this compressed testnet address correctly', function() { - var privkey = PrivateKey.fromWIF(enclivenet); - privkey.toWIF().should.equal(enclivenet); + var privkey = PrivateKey.fromWIF(wifLivenet); + privkey.toWIF().should.equal(wifLivenet); }); }); @@ -246,8 +285,8 @@ describe('PrivateKey', function() { describe('#toWIF', function() { it('should parse this compressed testnet address correctly', function() { - var privkey = PrivateKey.fromWIF(enctestnet); - privkey.toWIF().should.equal(enctestnet); + var privkey = PrivateKey.fromWIF(wifTestnet); + privkey.toWIF().should.equal(wifTestnet); }); }); @@ -255,8 +294,8 @@ describe('PrivateKey', function() { describe('#fromString', function() { it('should parse this uncompressed testnet address correctly', function() { - var privkey = PrivateKey.fromString(enctu); - privkey.toWIF().should.equal(enctu); + var privkey = PrivateKey.fromString(wifTestnetUncompressed); + privkey.toWIF().should.equal(wifTestnetUncompressed); }); }); @@ -264,13 +303,13 @@ describe('PrivateKey', function() { describe('#toString', function() { it('should parse this uncompressed livenet address correctly', function() { - var privkey = PrivateKey.fromString(encmu); - privkey.toString().should.equal(encmu); + var privkey = PrivateKey.fromString(wifLivenetUncompressed); + privkey.toString().should.equal(wifLivenetUncompressed); }); }); - describe("#toPublicKey", function() { + describe('#toPublicKey', function() { it('should convert this known PrivateKey to known PublicKey', function() { var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff'; @@ -304,12 +343,12 @@ describe('PrivateKey', function() { }); it('creates an address as expected from WIF, livenet', function() { - var privkey = new PrivateKey('5J2NYGstJg7aJQEqNwYp4enG5BSfFdKXVTtBLvHicnRGD5kjxi6') + var privkey = new PrivateKey('5J2NYGstJg7aJQEqNwYp4enG5BSfFdKXVTtBLvHicnRGD5kjxi6'); privkey.publicKey.toAddress().toString().should.equal('135bwugFCmhmNU3SeCsJeTqvo5ViymgwZ9'); }); it('creates an address as expected from WIF, testnet', function() { - var privkey = new PrivateKey('92VYMmwFLXRwXn5688edGxYYgMFsc3fUXYhGp17WocQhU6zG1kd') + var privkey = new PrivateKey('92VYMmwFLXRwXn5688edGxYYgMFsc3fUXYhGp17WocQhU6zG1kd'); privkey.publicKey.toAddress().toString().should.equal('moiAvLUw16qgrwhFGo1eDnXHC2wPMYiv7Y'); }); diff --git a/test/publickey.js b/test/publickey.js index f35330b..62ca8ff 100644 --- a/test/publickey.js +++ b/test/publickey.js @@ -1,84 +1,95 @@ 'use strict'; var should = require('chai').should(); +var expect = require('chai').expect; + var bitcore = require('..'); var Point = bitcore.crypto.Point; var BN = bitcore.crypto.BN; var PublicKey = bitcore.PublicKey; var PrivateKey = bitcore.PrivateKey; +// DER uncompressed format +/* jshint maxlen: 200 */ + describe('PublicKey', function() { + /* jshint maxstatements: 30 */ var invalidPoint = '0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; - it('should error because of missing data', function() { - (function() { - var pk = new PublicKey(); - }).should.throw('First argument is required, please include public key data.'); - }); + describe('validating errors on creation', function() { + it('errors if data is missing', function() { + (function() { + return new PublicKey(); + }).should.throw('First argument is required, please include public key data.'); + }); - it('should error because of an invalid point', function() { - (function() { - var pk = new PublicKey(invalidPoint); - }).should.throw('Invalid x,y value for curve, cannot equal 0.'); - }); + it('errors if an invalid point is provided', function() { + (function() { + return new PublicKey(invalidPoint); + }).should.throw('Invalid x,y value for curve, cannot equal 0.'); + }); - it('should error because of an invalid public key point, not on the secp256k1 curve', function() { - (function() { - var pk = new PublicKey(Point(1000, 1000)); - }).should.throw('Invalid y value for curve.'); - }); + it('errors if a point not on the secp256k1 curve is provided', function() { + (function() { + return new PublicKey(new Point(1000, 1000)); + }).should.throw('Invalid y value for curve.'); + }); - it('should error because of an unrecognized data type', function() { - (function() { - var pk = new PublicKey(new Error()); - }).should.throw('First argument is an unrecognized data format.'); + it('errors if the argument is of an unrecognized type', function() { + (function() { + return new PublicKey(new Error()); + }).should.throw('First argument is an unrecognized data format.'); + }); }); - it('should instantiate from a private key', function() { - var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff'; - var pubhex = '02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc'; - var privkey = new PrivateKey(BN(new Buffer(privhex, 'hex'))); - var pk = new PublicKey(privkey); - pk.toString().should.equal(pubhex); - }); + describe('instantiation', function() { + it('from a private key', function() { + var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff'; + var pubhex = '02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc'; + var privkey = new PrivateKey(BN(new Buffer(privhex, 'hex'))); + var pk = new PublicKey(privkey); + pk.toString().should.equal(pubhex); + }); - it('should instantiate from a compressed public key', function() { - var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'; - var publicKey = new PublicKey(publicKeyHex); - publicKey.toString().should.equal(publicKeyHex); - }); + it('from a compressed public key', function() { + var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'; + var publicKey = new PublicKey(publicKeyHex); + publicKey.toString().should.equal(publicKeyHex); + }); - it('should instantiate from another publicKey', function() { - var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'; - var publicKey = new PublicKey(publicKeyHex); - var publicKey2 = new PublicKey(publicKey); - publicKey.should.equal(publicKey2); - }); + it('from another publicKey', function() { + var publicKeyHex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'; + var publicKey = new PublicKey(publicKeyHex); + var publicKey2 = new PublicKey(publicKey); + publicKey.should.equal(publicKey2); + }); - it('should instantiate from a hex encoded DER string', function() { - var pk = new PublicKey('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); - should.exist(pk.point); - pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); - }); + it('from a hex encoded DER string', function() { + var pk = new PublicKey('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); + should.exist(pk.point); + pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); + }); - it('should instantiate from a hex encoded DER buffer', function() { - var pk = new PublicKey(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex')); - should.exist(pk.point); - pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); - }); + it('from a hex encoded DER buffer', function() { + var pk = new PublicKey(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex')); + should.exist(pk.point); + pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); + }); - it('should create a public key with a point', function() { - var p = Point('86a80a5a2bfc48dddde2b0bd88bd56b0b6ddc4e6811445b175b90268924d7d48', - '3b402dfc89712cfe50963e670a0598e6b152b3cd94735001cdac6794975d3afd'); - var a = new PublicKey(p); - should.exist(a.point); - a.point.toString().should.equal(p.toString()); - var c = PublicKey(p); - should.exist(c.point); - c.point.toString().should.equal(p.toString()); + it('from a point', function() { + var p = new Point('86a80a5a2bfc48dddde2b0bd88bd56b0b6ddc4e6811445b175b90268924d7d48', + '3b402dfc89712cfe50963e670a0598e6b152b3cd94735001cdac6794975d3afd'); + var a = new PublicKey(p); + should.exist(a.point); + a.point.toString().should.equal(p.toString()); + var c = new PublicKey(p); + should.exist(c.point); + c.point.toString().should.equal(p.toString()); + }); }); + describe('#getValidationError', function(){ it('should recieve an invalid point error', function() { @@ -107,8 +118,8 @@ describe('PublicKey', function() { describe('#fromPoint', function() { it('should instantiate from a point', function() { - var p = Point('86a80a5a2bfc48dddde2b0bd88bd56b0b6ddc4e6811445b175b90268924d7d48', - '3b402dfc89712cfe50963e670a0598e6b152b3cd94735001cdac6794975d3afd'); + var p = new Point('86a80a5a2bfc48dddde2b0bd88bd56b0b6ddc4e6811445b175b90268924d7d48', + '3b402dfc89712cfe50963e670a0598e6b152b3cd94735001cdac6794975d3afd'); var b = PublicKey.fromPoint(p); should.exist(b.point); b.point.toString().should.equal(p.toString()); @@ -132,6 +143,18 @@ describe('PublicKey', function() { PublicKey.fromJSON(json).toJSON().should.deep.equal(json); }); + it('fails if "y" is not provided', function() { + expect(function() { + return PublicKey.fromJSON('{"x": "1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a"}'); + }).to.throw(); + }); + + it('fails if invalid JSON is provided', function() { + expect(function() { + return PublicKey._transformJSON('¹'); + }).to.throw(); + }); + }); describe('#fromPrivateKey', function() { @@ -227,7 +250,7 @@ describe('PublicKey', function() { it('should error because odd was not included as a param', function() { var x = BN.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex')); (function() { - var pk = PublicKey.fromX(null, x); + return PublicKey.fromX(null, x); }).should.throw('Must specify whether y is odd or not (true or false)'); }); @@ -312,26 +335,28 @@ describe('PublicKey', function() { it('should not have an error if pubkey is valid', function() { var hex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'; - var pk = PublicKey.fromString(hex); + expect(function() { + return PublicKey.fromString(hex); + }).to.not.throw(); }); it('should throw an error if pubkey is invalid', function() { var hex = '041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a0000000000000000000000000000000000000000000000000000000000000000'; (function() { - var pk = PublicKey.fromString(hex); + return PublicKey.fromString(hex); }).should.throw('Invalid x,y value for curve, cannot equal 0.'); }); it('should throw an error if pubkey is invalid', function() { var hex = '041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a00000000000000000000000000000000000000000000000000000000000000FF'; (function() { - var pk = PublicKey.fromString(hex); + return PublicKey.fromString(hex); }).should.throw('Invalid y value for curve.'); }); it('should throw an error if pubkey is infinity', function() { (function() { - var pk = new PublicKey(Point.getG().mul(Point.getN())); + return new PublicKey(Point.getG().mul(Point.getN())); }).should.throw('Point cannot be equal to Infinity'); });