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 " + } + ] +}