From ba692aaa20841e3d41d902578fb16d0f74d1ea05 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Tue, 22 Apr 2014 22:18:59 -0300 Subject: [PATCH 1/5] add new SecureRandom class that does the right thing Generating random numbers properly depends on the platform. The new getRandomBuffer method does the right thing on the right platform. It will sometimes fail due to insufficient entropy. The getPseudoRandomBuffer class is also provided that will never fail, but it is not cryptographically secure and should not be used for keys. --- bitcore.js | 1 + browser/build.js | 1 + lib/BIP32.js | 3 +- lib/Connection.js | 3 +- lib/SecureRandom.js | 5 ++++ lib/browser/SecureRandom.js | 23 +++++++++++++++ lib/common/SecureRandom.js | 28 ++++++++++++++++++ lib/node/SecureRandom.js | 10 +++++++ test/index.html | 1 + test/test.SecureRandom.js | 57 +++++++++++++++++++++++++++++++++++++ util/util.js | 31 -------------------- 11 files changed, 130 insertions(+), 33 deletions(-) create mode 100644 lib/SecureRandom.js create mode 100644 lib/browser/SecureRandom.js create mode 100644 lib/common/SecureRandom.js create mode 100644 lib/node/SecureRandom.js create mode 100644 test/test.SecureRandom.js diff --git a/bitcore.js b/bitcore.js index aa0de4bc0..13f729325 100644 --- a/bitcore.js +++ b/bitcore.js @@ -20,6 +20,7 @@ requireWhenAccessed('const', './const'); requireWhenAccessed('Deserialize', './lib/Deserialize'); requireWhenAccessed('log', './util/log'); requireWhenAccessed('networks', './networks'); +requireWhenAccessed('SecureRandom', './lib/SecureRandom'); requireWhenAccessed('util', './util/util'); requireWhenAccessed('EncodedData', './util/EncodedData'); requireWhenAccessed('VersionedData', './util/VersionedData'); diff --git a/browser/build.js b/browser/build.js index 05f7a6266..38f97e466 100644 --- a/browser/build.js +++ b/browser/build.js @@ -42,6 +42,7 @@ var modules = [ 'lib/SINKey', 'lib/Script', 'lib/ScriptInterpreter', + 'lib/SecureRandom', 'lib/Sign', 'lib/Transaction', 'lib/TransactionBuilder', diff --git a/lib/BIP32.js b/lib/BIP32.js index 94a7602aa..e1f8bfde3 100644 --- a/lib/BIP32.js +++ b/lib/BIP32.js @@ -3,6 +3,7 @@ var base58 = imports.base58 || require('base58-native').base58; var coinUtil = imports.coinUtil || require('../util'); var Key = imports.Key || require('./Key'); var Point = imports.Point || require('./Point'); +var SecureRandom = imports.SecureRandom || require('./SecureRandom'); var bignum = imports.bignum || require('bignum'); var crypto = require('crypto'); var networks = require('../networks'); @@ -27,7 +28,7 @@ var BIP32 = function(bytes) { this.depth = 0x00; this.parentFingerprint = new Buffer([0, 0, 0, 0]); this.childIndex = new Buffer([0, 0, 0, 0]); - this.chainCode = Key.generateSync().private; + this.chainCode = SecureRandom.getRandomBuffer(32); this.eckey = Key.generateSync(); this.hasPrivateKey = true; this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public); diff --git a/lib/Connection.js b/lib/Connection.js index f03e95330..4b40d1621 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -17,7 +17,8 @@ var util = imports.util || require('../util'); var Parser = imports.Parser || require('../util/BinaryParser'); var buffertools = imports.buffertools || require('buffertools'); var doubleSha256 = imports.doubleSha256 || util.twoSha256; -var nonce = util.generateNonce(); +var SecureRandom = imports.SecureRandom || require('./SecureRandom'); +var nonce = function() {return SecureRandom.getPseudoRandomBuffer(8)}; var BIP0031_VERSION = 60000; diff --git a/lib/SecureRandom.js b/lib/SecureRandom.js new file mode 100644 index 000000000..fa7f5ef4d --- /dev/null +++ b/lib/SecureRandom.js @@ -0,0 +1,5 @@ +if (process.versions) { + module.exports = require('./node/SecureRandom'); + return; +} +module.exports = require('./browser/SecureRandom'); diff --git a/lib/browser/SecureRandom.js b/lib/browser/SecureRandom.js new file mode 100644 index 000000000..79f1db50c --- /dev/null +++ b/lib/browser/SecureRandom.js @@ -0,0 +1,23 @@ +var imports = require('soop'); + +var SecureRandom = require('../common/SecureRandom'); + +SecureRandom.getRandomBuffer = function(size) { + if (!window.crypto && !window.msCrypto) + throw new Error('window.crypto not available'); + + if (window.crypto && window.crypto.getRandomValues) + var crypto = window.crypto; + else if (window.msCrypto && window.msCrypto.getRandomValues) //internet explorer + var crypto = window.msCrypto; + else + throw new Error('window.crypto.getRandomValues not available'); + + var bbuf = new Uint8Array(size); + crypto.getRandomValues(bbuf); + var buf = new Buffer(bbuf); + + return buf; +}; + +module.exports = require('soop')(SecureRandom); diff --git a/lib/common/SecureRandom.js b/lib/common/SecureRandom.js new file mode 100644 index 000000000..a276d22ac --- /dev/null +++ b/lib/common/SecureRandom.js @@ -0,0 +1,28 @@ +var imports = require('soop'); + +var SecureRandom = function() { +}; + +/* secure random bytes that sometimes throws an error due to lack of entropy */ +SecureRandom.getRandomBuffer = function() {}; + +/* insecure random bytes, but it never fails */ +SecureRandom.getPseudoRandomBuffer = function(size) { + var b32 = 0x100000000; + var b = new Buffer(size); + + for (var i = 0; i <= size; i++) { + var j = Math.floor(i / 4); + var k = i - j * 4; + if (k == 0) { + r = Math.random() * b32; + b[i] = r & 0xff; + } else { + b[i] = (r = r >>> 8) & 0xff; + } + } + + return b; +}; + +module.exports = require('soop')(SecureRandom); diff --git a/lib/node/SecureRandom.js b/lib/node/SecureRandom.js new file mode 100644 index 000000000..3639f75c1 --- /dev/null +++ b/lib/node/SecureRandom.js @@ -0,0 +1,10 @@ +var imports = require('soop'); +var crypto = imports.crypto || require('crypto'); + +var SecureRandom = require('../common/SecureRandom'); + +SecureRandom.getRandomBuffer = function(size) { + return crypto.randomBytes(size); +} + +module.exports = require('soop')(SecureRandom); diff --git a/test/index.html b/test/index.html index 551c46d80..9b8da7cea 100644 --- a/test/index.html +++ b/test/index.html @@ -35,6 +35,7 @@ + diff --git a/test/test.SecureRandom.js b/test/test.SecureRandom.js new file mode 100644 index 000000000..ab8207b99 --- /dev/null +++ b/test/test.SecureRandom.js @@ -0,0 +1,57 @@ +'use strict'; + +var chai = chai || require('chai'); +var bitcore = bitcore || require('../bitcore'); +var should = chai.should(); +var assert = chai.assert; +var SecureRandom = bitcore.SecureRandom; + +describe('SecureRandom', function() { + + describe('getRandomBuffer', function() { + + it('should return a buffer', function() { + var bytes = SecureRandom.getRandomBuffer(8); + bytes.length.should.equal(8); + Buffer.isBuffer(bytes).should.equal(true); + }); + + it('should not equate two 256 bit random buffers', function() { + var bytes1 = SecureRandom.getRandomBuffer(32); + var bytes2 = SecureRandom.getRandomBuffer(32); + bytes1.toString('hex').should.not.equal(bytes2.toString('hex')); + }); + + }); + + describe('getPseudoRandomBuffer', function() { + + it('should generate 7 random bytes', function() { + var buf = SecureRandom.getPseudoRandomBuffer(7); + buf.length.should.equal(7); + }); + + it('should generate 8 random bytes', function() { + var buf = SecureRandom.getPseudoRandomBuffer(8); + buf.length.should.equal(8); + }); + + it('should generate 9 random bytes', function() { + var buf = SecureRandom.getPseudoRandomBuffer(9); + buf.length.should.equal(9); + }); + + it('should generate 90 random bytes', function() { + var buf = SecureRandom.getPseudoRandomBuffer(90); + buf.length.should.equal(90); + }); + + it('should generate two 8 byte buffers that are not equal', function() { + var buf1 = SecureRandom.getPseudoRandomBuffer(8); + var buf2 = SecureRandom.getPseudoRandomBuffer(8); + buf1.toString('hex').should.not.equal(buf2.toString('hex')); + }); + + }); + +}); diff --git a/util/util.js b/util/util.js index f89dce844..a59df4b35 100644 --- a/util/util.js +++ b/util/util.js @@ -10,7 +10,6 @@ if (inBrowser) { browser = require('../browser/vendor-bundle.js'); } - var sha256 = exports.sha256 = function(data) { return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary'); }; @@ -336,36 +335,6 @@ var createSynchrotron = exports.createSynchrotron = function(fn) { }; }; -/** - * Generate a random 64-bit number. - * - * With ideas from node-uuid: - * Copyright (c) 2010 Robert Kieffer - * https://github.com/broofa/node-uuid/ - * - * @returns Buffer random nonce - */ -var generateNonce = exports.generateNonce = function() { - var b32 = 0x100000000, - ff = 0xff; - var b = new Buffer(8), - i = 0; - - // Generate eight random bytes - r = Math.random() * b32; - b[i++] = r & ff; - b[i++] = (r = r >>> 8) & ff; - b[i++] = (r = r >>> 8) & ff; - b[i++] = (r = r >>> 8) & ff; - r = Math.random() * b32; - b[i++] = r & ff; - b[i++] = (r = r >>> 8) & ff; - b[i++] = (r = r >>> 8) & ff; - b[i++] = (r = r >>> 8) & ff; - - return b; -}; - /** * Decode difficulty bits. * From 75d2d0d390862e0c30e62a30dc1dd75c0f908d61 Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Tue, 22 Apr 2014 22:28:31 -0300 Subject: [PATCH 2/5] fix issues with ConnectionTor example and Connection class --- examples/ConnectionTor.js | 4 ++-- lib/Connection.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/ConnectionTor.js b/examples/ConnectionTor.js index 2d9d8a662..c96040fec 100644 --- a/examples/ConnectionTor.js +++ b/examples/ConnectionTor.js @@ -1,5 +1,5 @@ -var Peer = require('../Peer'); -var Connection = require('../Connection'); +var Peer = require('../lib/Peer'); +var Connection = require('../lib/Connection'); var dns = require('dns'); // get a peer from dns seed diff --git a/lib/Connection.js b/lib/Connection.js index 4b40d1621..1377545c6 100644 --- a/lib/Connection.js +++ b/lib/Connection.js @@ -18,7 +18,7 @@ var Parser = imports.Parser || require('../util/BinaryParser'); var buffertools = imports.buffertools || require('buffertools'); var doubleSha256 = imports.doubleSha256 || util.twoSha256; var SecureRandom = imports.SecureRandom || require('./SecureRandom'); -var nonce = function() {return SecureRandom.getPseudoRandomBuffer(8)}; +var nonce = SecureRandom.getPseudoRandomBuffer(8); var BIP0031_VERSION = 60000; From 4693d5bc41266f9ec7ffc6f22dc1e12a3cfa0f0b Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Tue, 22 Apr 2014 22:41:57 -0300 Subject: [PATCH 3/5] remove unnecessary "change" console.log from Electrum test --- test/test.Electrum.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test.Electrum.js b/test/test.Electrum.js index 8e82c18ad..b6bfe8e8b 100644 --- a/test/test.Electrum.js +++ b/test/test.Electrum.js @@ -66,7 +66,6 @@ describe('Electrum', function() { //change pubkey = elec.generateChangePubKey(i); addr = Address.fromPubKey(pubkey); - console.log('change'); addr.as('base58').should.equal(expected_values.change[i]); } }); From dbcf2708260a17988d9ad2889e681c6dfce877aa Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Tue, 22 Apr 2014 22:43:22 -0300 Subject: [PATCH 4/5] use SecureRandom in Key in the browser ...to make sure random numbers are generated securely --- lib/browser/Key.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/browser/Key.js b/lib/browser/Key.js index 796819d62..f5baea11c 100644 --- a/lib/browser/Key.js +++ b/lib/browser/Key.js @@ -1,5 +1,6 @@ var ECKey = require('../../browser/vendor-bundle.js').ECKey; var buffertools = require('buffertools'); +var SecureRandom = require('../SecureRandom'); var Key = function() { this._pub = null; @@ -33,13 +34,17 @@ Object.defineProperty(Key.prototype, 'public', { }); Key.generateSync = function() { - var eck = new ECKey(); + var privbuf = SecureRandom.getRandomBuffer(32); + var privhex = privbuf.toString('hex'); + var eck = new ECKey(privhex); eck.setCompressed(true); var pub = eck.getPub(); - var ret = new Key(); - ret.private = new Buffer(eck.priv.toByteArrayUnsigned()); - ret.public = new Buffer(pub); + ret = new Key(); + ret.private = privbuf; + ret.compressed = true; + ret.public = new Buffer(eck.getPub()); + return ret; }; From 350f6ae9984b706be6ab287c00017d203533f70f Mon Sep 17 00:00:00 2001 From: "Ryan X. Charles" Date: Wed, 23 Apr 2014 21:15:55 -0300 Subject: [PATCH 5/5] Key should make sure new privkey is less than N ...this involves adding a Curve class, and significant refactoring to make this possible in a clean way. --- bitcore.js | 1 + browser/build.js | 1 + lib/BIP32.js | 9 +++++--- lib/Curve.js | 22 ++++++++++++++++++++ lib/Electrum.js | 3 ++- lib/browser/Key.js | 49 +++++++++++++++++++++++++++++++++++--------- lib/browser/Point.js | 23 ++++++--------------- lib/node/Key.js | 4 +++- lib/node/Point.js | 36 ++++++++++---------------------- test/index.html | 1 + test/test.Curve.js | 37 +++++++++++++++++++++++++++++++++ test/test.Key.js | 18 ++++++++++++++++ test/test.Point.js | 6 ++++-- 13 files changed, 151 insertions(+), 59 deletions(-) create mode 100644 lib/Curve.js create mode 100644 test/test.Curve.js diff --git a/bitcore.js b/bitcore.js index 13f729325..bb92336ae 100644 --- a/bitcore.js +++ b/bitcore.js @@ -17,6 +17,7 @@ requireWhenAccessed('buffertools', 'buffertools'); requireWhenAccessed('Buffers.monkey', './patches/Buffers.monkey'); requireWhenAccessed('config', './config'); requireWhenAccessed('const', './const'); +requireWhenAccessed('Curve', './lib/Curve'); requireWhenAccessed('Deserialize', './lib/Deserialize'); requireWhenAccessed('log', './util/log'); requireWhenAccessed('networks', './networks'); diff --git a/browser/build.js b/browser/build.js index 38f97e466..0b8b59f40 100644 --- a/browser/build.js +++ b/browser/build.js @@ -28,6 +28,7 @@ var modules = [ 'lib/Block', 'lib/Bloom', 'lib/Connection', + 'lib/Curve', 'lib/Deserialize', 'lib/Electrum', 'lib/Message', diff --git a/lib/BIP32.js b/lib/BIP32.js index e1f8bfde3..6484af02e 100644 --- a/lib/BIP32.js +++ b/lib/BIP32.js @@ -289,17 +289,20 @@ BIP32.prototype.deriveChild = function(i) { var ilGkey = new Key(); ilGkey.private = il; ilGkey.regenerateSync(); - var ilG = Point.fromKey(ilGkey); + ilGkey.compressed = false; + var ilG = Point.fromUncompressedPubKey(ilGkey.public); var oldkey = new Key(); oldkey.public = this.eckey.public; - var Kpar = Point.fromKey(oldkey); - var newpub = Point.add(ilG, Kpar).toKey().public; + oldkey.compressed = false; + var Kpar = Point.fromUncompressedPubKey(oldkey.public); + var newpub = Point.add(ilG, Kpar).toUncompressedPubKey(); ret = new BIP32(null); ret.chainCode = new Buffer(ir); var eckey = new Key(); eckey.public = newpub; + eckey.compressed = true; ret.eckey = eckey; ret.hasPrivateKey = false; } diff --git a/lib/Curve.js b/lib/Curve.js new file mode 100644 index 000000000..f2d140d4a --- /dev/null +++ b/lib/Curve.js @@ -0,0 +1,22 @@ +"use strict"; +var imports = require('soop'); +var bignum = imports.bignum || require('bignum'); +var Point = imports.Point || require('./Point'); + +var n = bignum.fromBuffer(new Buffer("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 'hex'), {size: 32}); +var G = new Point(bignum.fromBuffer(new Buffer("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 'hex'), {size: 32}), + bignum.fromBuffer(new Buffer("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 'hex'), {size: 32})); + +/* secp256k1 curve */ +var Curve = function() { +}; + +Curve.getG = function() { + return G; +}; + +Curve.getN = function() { + return n; +}; + +module.exports = require('soop')(Curve); diff --git a/lib/Electrum.js b/lib/Electrum.js index 1cf499e1a..02457798f 100644 --- a/lib/Electrum.js +++ b/lib/Electrum.js @@ -31,8 +31,9 @@ Electrum.prototype.generatePubKey = function (n, for_change) { var sequence_key = new Key(); sequence_key.private = sequence.toBuffer(); sequence_key.regenerateSync(); + sequence_key.compressed = false; - var sequence_pt = Point.fromKey(sequence_key); + var sequence_pt = Point.fromUncompressedPubKey(sequence_key.public); pt = Point.add(mpk_pt, sequence_pt); diff --git a/lib/browser/Key.js b/lib/browser/Key.js index f5baea11c..8e6ed72e9 100644 --- a/lib/browser/Key.js +++ b/lib/browser/Key.js @@ -1,10 +1,10 @@ var ECKey = require('../../browser/vendor-bundle.js').ECKey; -var buffertools = require('buffertools'); var SecureRandom = require('../SecureRandom'); +var Curve = require('../Curve'); var Key = function() { this._pub = null; - this.compressed = true; // default + this._compressed = true; // default }; var bufferToArray = Key.bufferToArray = function(buffer) { @@ -18,14 +18,13 @@ var bufferToArray = Key.bufferToArray = function(buffer) { return ret; } - Object.defineProperty(Key.prototype, 'public', { set: function(p){ if (!Buffer.isBuffer(p) ) { throw new Error('Arg should be a buffer'); } var type = p[0]; - this.compressed = type!==0x04; + this._compressed = type!==0x04; this._pub = p; }, get: function(){ @@ -33,8 +32,38 @@ Object.defineProperty(Key.prototype, 'public', { } }); +Object.defineProperty(Key.prototype, 'compressed', { + set: function(c) { + var oldc = this._compressed; + this._compressed = !!c; + if (oldc == this._compressed) + return; + var oldp = this._pub; + if (this._pub) { + var eckey = new ECKey(); + eckey.setPub(bufferToArray(this.public)); + eckey.setCompressed(this._compressed); + this._pub = new Buffer(eckey.getPub()); + } + if (!this._compressed) { + //bug in eckey + //oldp.slice(1).copy(this._pub, 1); + } + }, + get: function() { + return this._compressed; + } +}); + Key.generateSync = function() { - var privbuf = SecureRandom.getRandomBuffer(32); + var privbuf; + + while(true) { + privbuf = SecureRandom.getRandomBuffer(32); + if ((bignum.fromBuffer(privbuf, {size: 32})).cmp(Curve.getN()) < 0) + break; + } + var privhex = privbuf.toString('hex'); var eck = new ECKey(privhex); eck.setCompressed(true); @@ -42,7 +71,7 @@ Key.generateSync = function() { ret = new Key(); ret.private = privbuf; - ret.compressed = true; + ret._compressed = true; ret.public = new Buffer(eck.getPub()); return ret; @@ -54,8 +83,8 @@ Key.prototype.regenerateSync = function() { } var eck = new ECKey(buffertools.toHex(this.private)); - eck.setCompressed(this.compressed); - this.public = new Buffer(eck.getPub()); + eck.setCompressed(this._compressed); + this._pub = new Buffer(eck.getPub()); return this; }; @@ -68,7 +97,7 @@ Key.prototype.signSync = function(hash) { throw new Error('Arg should be a 32 bytes hash buffer'); } var eck = new ECKey(buffertools.toHex(this.private)); - eck.setCompressed(this.compressed); + eck.setCompressed(this._compressed); var signature = eck.sign(bufferToArray(hash)); // return it as a buffer to keep c++ compatibility return new Buffer(signature); @@ -98,7 +127,7 @@ Key.prototype.verifySignatureSync = function(hash, sig) { var eck = new ECKey(); eck.setPub(bufferToArray(self.public)); - eck.setCompressed(self.compressed); + eck.setCompressed(self._compressed); var sigA = bufferToArray(sig); var ret = eck.verify(bufferToArray(hash),sigA); return ret; diff --git a/lib/browser/Point.js b/lib/browser/Point.js index b9f4c3638..fba0b3d45 100644 --- a/lib/browser/Point.js +++ b/lib/browser/Point.js @@ -51,31 +51,20 @@ Point.add = function(p1, p2) { }; //convert the public key of a Key into a Point -Point.fromKey = function(key) { +Point.fromUncompressedPubKey = function(pubkey) { var point = new Point(); - var pubKeyBuf = new Buffer(key.public); - var key2 = new ECKey(); - key2.setCompressed(key.compressed); - key2.setPub(Key.bufferToArray(pubKeyBuf)); - key2.setCompressed(false); - point.x = bignum.fromBuffer((new Buffer(key2.getPub())).slice(1, 33), {size: 32}); - point.y = bignum.fromBuffer((new Buffer(key2.getPub())).slice(33, 65), {size: 32}); + point.x = bignum.fromBuffer((new Buffer(pubkey)).slice(1, 33), {size: 32}); + point.y = bignum.fromBuffer((new Buffer(pubkey)).slice(33, 65), {size: 32}); return point; }; //convert the Point into the Key containing a compressed public key -Point.prototype.toKey = function() { +Point.prototype.toUncompressedPubKey = function() { var xbuf = this.x.toBuffer({size: 32}); var ybuf = this.y.toBuffer({size: 32}); - var key = new ECKey(); - key.setCompressed(false); var prefix = new Buffer([0x04]); - var pub = Buffer.concat([prefix, xbuf, ybuf]); //this might be wrong - key.setPub(Key.bufferToArray(pub)); - key.setCompressed(true); - var key2 = new Key(); - key2.public = new Buffer(key.getPub()); - return key2; + var pub = Buffer.concat([prefix, xbuf, ybuf]); + return pub; }; module.exports = require('soop')(Point); diff --git a/lib/node/Key.js b/lib/node/Key.js index 8e079d9d2..bec7c80a3 100644 --- a/lib/node/Key.js +++ b/lib/node/Key.js @@ -1 +1,3 @@ -module.exports = require('bindings')('KeyModule').Key; +var Key = require('bindings')('KeyModule').Key; + +module.exports = Key; diff --git a/lib/node/Point.js b/lib/node/Point.js index 38a6466b8..64d4dd7f8 100644 --- a/lib/node/Point.js +++ b/lib/node/Point.js @@ -1,8 +1,8 @@ "use strict"; var imports = require('soop').imports(); -var Key = imports.Key || require('../Key'); var bignum = imports.bignum || require('bignum'); +var CPPKey = imports.CPPKey || require('bindings')('KeyModule').Key; var assert = require('assert'); //a point on the secp256k1 curve @@ -13,41 +13,27 @@ var Point = function(x, y) { }; Point.add = function(p1, p2) { - var key1 = p1.toKey(); - key1.compressed = false; - var key2 = p2.toKey(); - key2.compressed = false; - var pubKey = Key.addUncompressed(key1.public, key2.public); - var key = new Key(); - key.compressed = false; - key.public = pubKey; - key.compressed = true; - return Point.fromKey(key); + var u1 = p1.toUncompressedPubKey(); + var u2 = p2.toUncompressedPubKey(); + var pubKey = CPPKey.addUncompressed(u1, u2); + return Point.fromUncompressedPubKey(pubKey); }; //convert the public key of a Key into a Point -Point.fromKey = function(key) { +Point.fromUncompressedPubKey = function(pubkey) { var point = new Point(); - var pubKeyBuf = new Buffer(key.public); - var key2 = new Key(); - key2.compressed = key.compressed; - key2.public = pubKeyBuf; - key2.compressed = false; - point.x = bignum.fromBuffer(key2.public.slice(1, 33), {size: 32}); - point.y = bignum.fromBuffer(key2.public.slice(33, 65), {size: 32}); + point.x = bignum.fromBuffer(pubkey.slice(1, 33), {size: 32}); + point.y = bignum.fromBuffer(pubkey.slice(33, 65), {size: 32}); return point; }; //convert the Point into the Key containing a compressed public key -Point.prototype.toKey = function() { +Point.prototype.toUncompressedPubKey = function() { var xbuf = this.x.toBuffer({size: 32}); var ybuf = this.y.toBuffer({size: 32}); - var key = new Key(); - key.compressed = false; var prefix = new Buffer([0x04]); - key.public = Buffer.concat([prefix, xbuf, ybuf]); //this might be wrong - key.compressed = true; - return key; + var pubkey = Buffer.concat([prefix, xbuf, ybuf]); + return pubkey; }; module.exports = require('soop')(Point); diff --git a/test/index.html b/test/index.html index 9b8da7cea..d8f93e414 100644 --- a/test/index.html +++ b/test/index.html @@ -21,6 +21,7 @@ + diff --git a/test/test.Curve.js b/test/test.Curve.js new file mode 100644 index 000000000..211645060 --- /dev/null +++ b/test/test.Curve.js @@ -0,0 +1,37 @@ +'use strict'; + +var chai = chai || require('chai'); +var bitcore = bitcore || require('../bitcore'); +var coinUtil = coinUtil || bitcore.util; +var buffertools = require('buffertools'); +var bignum = require('bignum'); + +var should = chai.should(); +var assert = chai.assert; + +var Curve = bitcore.Curve; + +describe('Curve', function() { + + it('should initialize the main object', function() { + should.exist(Curve); + }); + + describe('getN', function() { + it('should return a big number', function() { + var N = Curve.getN(); + should.exist(N); + N.toBuffer({size: 32}).toString('hex').length.should.equal(64); + }); + }); + + describe('getG', function() { + it('should return a Point', function() { + var G = Curve.getG(); + should.exist(G.x); + G.x.toBuffer({size: 32}).toString('hex').length.should.equal(64); + G.y.toBuffer({size: 32}).toString('hex').length.should.equal(64); + }); + }); + +}); diff --git a/test/test.Key.js b/test/test.Key.js index 25cdb263f..d2bef6105 100644 --- a/test/test.Key.js +++ b/test/test.Key.js @@ -7,6 +7,9 @@ var should = chai.should(); var assert = chai.assert; var Key = bitcore.Key; +var Point = bitcore.Point; +var bignum = require('bignum'); + describe('Key', function() { it('should initialize the main object', function() { should.exist(Key); @@ -15,6 +18,20 @@ describe('Key', function() { var k = new Key(); should.exist(k); }); + it('should set change compressed to uncompressed', function() { + var key = Key.generateSync(); + key.public.length.should.equal(33); + key.compressed = false; + key.public.length.should.equal(65); + }); + it('should change uncompressed to compressed', function() { + var key = Key.generateSync(); + key.compressed = false; + var key2 = new Key(); + key2.public = key.public; + key2.compressed = true; + key2.public.length.should.equal(33); + }); it('should be able to generateSync instance', function() { var k = Key.generateSync(); should.exist(k); @@ -112,4 +129,5 @@ describe('Key', function() { var ret= k.verifySignatureSync(a_hash, sig2); ret.should.equal(false); }); + }); diff --git a/test/test.Point.js b/test/test.Point.js index 66e32c14c..4ca45a556 100644 --- a/test/test.Point.js +++ b/test/test.Point.js @@ -49,8 +49,9 @@ describe('Point', function() { var pubKeyBufCompressedHex = "0369b154b42ff9452c31251cb341d7db01ad603dc56d64f9c5fb9e7031b89a241d"; var key = new Key(); key.public = new Buffer(pubKeyBufCompressedHex, 'hex'); + key.compressed = false; - key.public.toString('hex').should.equal(a.toKey().public.toString('hex')); + key.public.toString('hex').should.equal(a.toUncompressedPubKey().toString('hex')); }); it('should convert the public key of a Key into a Point', function() { @@ -60,8 +61,9 @@ describe('Point', function() { var pubKeyBufCompressedHex = "0369b154b42ff9452c31251cb341d7db01ad603dc56d64f9c5fb9e7031b89a241d"; var key = new Key(); key.public = new Buffer(pubKeyBufCompressedHex, 'hex'); + key.compressed = false; - var point = Point.fromKey(key); + var point = Point.fromUncompressedPubKey(key.public); point.x.toBuffer({size: 32}).toString('hex').should.equal(axhex); point.y.toBuffer({size: 32}).toString('hex').should.equal(ayhex); });