From d8883e8d32fdc51e9e99221d06a55d4106bafb00 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Thu, 24 Apr 2014 07:22:10 +1000 Subject: [PATCH 1/2] Adds BI.toPaddedBuffer and toBuffer --- src/base58.js | 9 ++++---- src/bigi.js | 27 ++++++++++++++++++++++++ src/eckey.js | 8 +------ src/message.js | 17 +++++---------- test/bigi.js | 46 +++++++++++++++++++++++++++++++++++++++++ test/ecdsa.js | 2 +- test/fixtures/base58.js | 2 +- test/fixtures/bigi.js | 46 +++++++++++++++++++++++++++++++++++++++++ 8 files changed, 131 insertions(+), 26 deletions(-) create mode 100644 test/bigi.js create mode 100644 test/fixtures/bigi.js diff --git a/src/base58.js b/src/base58.js index 690f897..f6f86a1 100644 --- a/src/base58.js +++ b/src/base58.js @@ -55,12 +55,11 @@ function decode(string) { i++ } - // FIXME: If BigInteger supported buffers, this could be a copy - var buffer = new Buffer(num.toByteArrayUnsigned()) - var padding = new Buffer(i) - padding.fill(0) + var buffer = num.toBuffer() + var leadz = new Buffer(i) + leadz.fill(0) - return Buffer.concat([padding, buffer]) + return Buffer.concat([leadz, buffer]) } module.exports = { diff --git a/src/bigi.js b/src/bigi.js index 9c4b1aa..ee17b3a 100644 --- a/src/bigi.js +++ b/src/bigi.js @@ -1,7 +1,17 @@ var assert = require('assert') var BigInteger = require('bigi') +// Import operations +BigInteger.fromHex = function(hex) { + var buffer = new Buffer(hex, 'hex') + assert.equal(buffer.length, Buffer.byteLength(hex) / 2) + + return BigInteger.fromBuffer(buffer) +} + BigInteger.fromBuffer = function(buffer) { + assert(Array.isArray(buffer) || Buffer.isBuffer(buffer)) // FIXME: Transitionary + // FIXME: Transitionary if (Buffer.isBuffer(buffer)) { buffer = Array.prototype.slice.call(buffer) @@ -10,4 +20,21 @@ BigInteger.fromBuffer = function(buffer) { return BigInteger.fromByteArrayUnsigned(buffer) } +// Export operations +BigInteger.prototype.toBuffer = function() { + return new Buffer(this.toByteArrayUnsigned()) +} + +BigInteger.prototype.toHex = function() { + return this.toBuffer().toString('hex') +} + +BigInteger.prototype.toPaddedBuffer = function(s) { + var buffer = this.toBuffer() + var padded = new Buffer(s - buffer.length) + padded.fill(0) + + return Buffer.concat([padded, buffer], s) +} + module.exports = BigInteger diff --git a/src/eckey.js b/src/eckey.js index 6b82ea0..af3b7f1 100644 --- a/src/eckey.js +++ b/src/eckey.js @@ -65,13 +65,7 @@ ECKey.prototype.sign = function(hash) { // Export functions ECKey.prototype.toBuffer = function() { - var buffer = new Buffer(this.D.toByteArrayUnsigned()) - - // pad out to atleast 32 bytes - var padded = new Buffer(32 - buffer.length) - padded.fill(0) - - return Buffer.concat([padded, buffer]) + return this.D.toPaddedBuffer(32) } ECKey.prototype.toHex = function() { return this.toBuffer().toString('hex') diff --git a/src/message.js b/src/message.js index 8fc558c..8bb9203 100644 --- a/src/message.js +++ b/src/message.js @@ -25,25 +25,18 @@ function magicHash(message) { // TODO: parameterize compression instead of using ECKey.compressed function sign(key, message) { var hash = magicHash(message) - var sig = key.sign(hash) - var obj = ecdsa.parseSig(sig) - var i = ecdsa.calcPubKeyRecoveryParam(key.pub.Q, obj.r, obj.s, hash) + var sig = ecdsa.parseSig(key.sign(hash)) + var i = ecdsa.calcPubKeyRecoveryParam(key.pub.Q, sig.r, sig.s, hash) i += 27 if (key.pub.compressed) { i += 4 } - var rBa = obj.r.toByteArrayUnsigned() - var sBa = obj.s.toByteArrayUnsigned() + var rB = sig.r.toPaddedBuffer(32) + var sB = sig.s.toPaddedBuffer(32) - // Pad to 32 bytes per value - while (rBa.length < 32) rBa.unshift(0); - while (sBa.length < 32) sBa.unshift(0); - - sig = [i].concat(rBa, sBa) - - return sig + return Buffer.concat([new Buffer([i]), rB, sB], 65) } // FIXME: stricter API? diff --git a/test/bigi.js b/test/bigi.js new file mode 100644 index 0000000..8963920 --- /dev/null +++ b/test/bigi.js @@ -0,0 +1,46 @@ +var assert = require('assert') +var BigInteger = require('../').BigInteger + +var fixtures = require('./fixtures/bigi') + +describe('BigInteger', function() { + describe('fromBuffer/fromHex', function() { + it('should match the test vectors', function() { + fixtures.valid.forEach(function(f) { + assert.deepEqual(BigInteger.fromHex(f.hex).toString(), f.dec) + assert.deepEqual(BigInteger.fromHex(f.hexPadded).toString(), f.dec) + }) + }) + + fixtures.invalid.forEach(function(f) { + it('throws on ' + f.description, function() { + assert.throws(function() { + BigInteger.fromHex(f.string) + }) + }) + }) + }) + + describe('toBuffer/toHex', function() { + it('should match the test vectors', function() { + fixtures.valid.forEach(function(f) { + var actualHex = new BigInteger(f.dec).toHex() + + assert.equal(actualHex, f.hex) + }) + }) + }) + + describe('toPaddedBuffer', function() { + it('should match the test vectors', function() { + fixtures.valid.forEach(function(f) { + var actualBuf = new BigInteger(f.dec).toPaddedBuffer(32) + + assert.equal(actualBuf.length, 32) + assert.equal(actualBuf.toString('hex'), f.hexPadded) + }) + }) + }) +}) + +module.exports = BigInteger diff --git a/test/ecdsa.js b/test/ecdsa.js index bdb7a44..f31e841 100644 --- a/test/ecdsa.js +++ b/test/ecdsa.js @@ -39,7 +39,7 @@ describe('ecdsa', function() { var sig_a = s1.sign([0]) assert.ok(sig_a, 'Sign null') - assert.ok(s1.pub.verify(BigInteger.ZERO, sig_a)) + assert.ok(s1.pub.verify([0], sig_a)) var message = new Buffer(1024) // More or less random :P var hash = crypto.sha256(message) diff --git a/test/fixtures/base58.js b/test/fixtures/base58.js index d19683d..761d446 100644 --- a/test/fixtures/base58.js +++ b/test/fixtures/base58.js @@ -71,4 +71,4 @@ module.exports = { "string": " \t\n\u000b\f\r skip \r\f\u000b\n\t a" } ] -} \ No newline at end of file +} diff --git a/test/fixtures/bigi.js b/test/fixtures/bigi.js new file mode 100644 index 0000000..4456dcf --- /dev/null +++ b/test/fixtures/bigi.js @@ -0,0 +1,46 @@ +module.exports = { + "valid": [ + { + "dec": "1", + "hex": "01", + "hexPadded": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "dec": "158798437896437949616241483468158498679", + "hex": "77777777777777777777777777777777", + "hexPadded": "0000000000000000000000000000000077777777777777777777777777777777" + }, + { + "dec": "115792089237316195423570985008687907852837564279074904382605163141518161494336", + "hex": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "hexPadded": "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140" + }, + { + "dec": "48968302285117906840285529799176770990048954789747953886390402978935544927851", + "hex": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b", + "hexPadded": "6c4313b03f2e7324d75e642f0ab81b734b724e13fec930f309e222470236d66b" + } + ], + "invalid": [ + { + "description": "non-hex string", + "string": "invalid" + }, + { + "description": "non-hex alphabet", + "string": "c2F0b3NoaQo=" + }, + { + "description": "internal whitespace", + "string": "11111 11111" + }, + { + "description": "leading whitespace", + "string": " 1111111111" + }, + { + "description": "trailing whitespace", + "string": "1111111111 " + } + ] +} From df6ea8aea2b2b1bbea036f44aa42de9dd7773680 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Fri, 25 Apr 2014 00:18:13 +1000 Subject: [PATCH 2/2] Removes toPaddedBuffer and extends toBuffer --- src/bigi.js | 22 ++++++++++------------ src/eckey.js | 2 +- src/message.js | 4 ++-- test/bigi.js | 24 ++++++++++++------------ 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/bigi.js b/src/bigi.js index ee17b3a..118db69 100644 --- a/src/bigi.js +++ b/src/bigi.js @@ -21,20 +21,18 @@ BigInteger.fromBuffer = function(buffer) { } // Export operations -BigInteger.prototype.toBuffer = function() { - return new Buffer(this.toByteArrayUnsigned()) +BigInteger.prototype.toBuffer = function(s) { + if (s != undefined) assert(Number.isFinite(s)) + + var buffer = new Buffer(this.toByteArrayUnsigned()) + var padded = new Buffer(s - buffer.length) + padded.fill(0) + + return Buffer.concat([padded, buffer], s) } -BigInteger.prototype.toHex = function() { - return this.toBuffer().toString('hex') -} - -BigInteger.prototype.toPaddedBuffer = function(s) { - var buffer = this.toBuffer() - var padded = new Buffer(s - buffer.length) - padded.fill(0) - - return Buffer.concat([padded, buffer], s) +BigInteger.prototype.toHex = function(s) { + return this.toBuffer(s).toString('hex') } module.exports = BigInteger diff --git a/src/eckey.js b/src/eckey.js index af3b7f1..bb2b3a0 100644 --- a/src/eckey.js +++ b/src/eckey.js @@ -65,7 +65,7 @@ ECKey.prototype.sign = function(hash) { // Export functions ECKey.prototype.toBuffer = function() { - return this.D.toPaddedBuffer(32) + return this.D.toBuffer(32) } ECKey.prototype.toHex = function() { return this.toBuffer().toString('hex') diff --git a/src/message.js b/src/message.js index 8bb9203..f389398 100644 --- a/src/message.js +++ b/src/message.js @@ -33,8 +33,8 @@ function sign(key, message) { i += 4 } - var rB = sig.r.toPaddedBuffer(32) - var sB = sig.s.toPaddedBuffer(32) + var rB = sig.r.toBuffer(32) + var sB = sig.s.toBuffer(32) return Buffer.concat([new Buffer([i]), rB, sB], 65) } diff --git a/test/bigi.js b/test/bigi.js index 8963920..4df4aad 100644 --- a/test/bigi.js +++ b/test/bigi.js @@ -7,8 +7,8 @@ describe('BigInteger', function() { describe('fromBuffer/fromHex', function() { it('should match the test vectors', function() { fixtures.valid.forEach(function(f) { - assert.deepEqual(BigInteger.fromHex(f.hex).toString(), f.dec) - assert.deepEqual(BigInteger.fromHex(f.hexPadded).toString(), f.dec) + assert.equal(BigInteger.fromHex(f.hex).toString(), f.dec) + assert.equal(BigInteger.fromHex(f.hexPadded).toString(), f.dec) }) }) @@ -24,21 +24,21 @@ describe('BigInteger', function() { describe('toBuffer/toHex', function() { it('should match the test vectors', function() { fixtures.valid.forEach(function(f) { - var actualHex = new BigInteger(f.dec).toHex() + var bi = new BigInteger(f.dec) - assert.equal(actualHex, f.hex) + assert.equal(bi.toHex(), f.hex) + assert.equal(bi.toHex(32), f.hexPadded) }) }) - }) - describe('toPaddedBuffer', function() { - it('should match the test vectors', function() { - fixtures.valid.forEach(function(f) { - var actualBuf = new BigInteger(f.dec).toPaddedBuffer(32) + it('throws on non-finite padding value', function() { + var bi = new BigInteger('1') - assert.equal(actualBuf.length, 32) - assert.equal(actualBuf.toString('hex'), f.hexPadded) - }) + assert.throws(function() { bi.toHex({}) }) + assert.throws(function() { bi.toHex([]) }) + assert.throws(function() { bi.toHex('') }) + assert.throws(function() { bi.toHex(0 / 0) }) + assert.throws(function() { bi.toHex(1 / 0) }) }) }) })