diff --git a/index.js b/index.js index e0e45e800..614b38496 100644 --- a/index.js +++ b/index.js @@ -11,10 +11,10 @@ privsec.deps.ripemd160 = require('ripemd160'); privsec.address = require('./lib/address'); privsec.base58 = require('./lib/base58'); privsec.base58check = require('./lib/base58check'); +privsec.bn = require('./lib/bn'); privsec.constants = require('./lib/constants'); privsec.hash = require('./lib/hash'); -//privsec.bn = require('lib/bn'); //privsec.key = require('lib/key'); //privsec.point = require('lib/point'); //privsec.privkey = require('lib/privkey'); diff --git a/lib/bn.js b/lib/bn.js new file mode 100644 index 000000000..ad1ba0561 --- /dev/null +++ b/lib/bn.js @@ -0,0 +1,109 @@ +var _bnjs = require('bn.js'); + +var bnjs = function bnjs_extended(n) { + if (!(this instanceof bnjs_extended)) { + return new bnjs(n); + } + arguments[0] = n; + return _bnjs.apply(this, arguments); +}; + +module.exports = bnjs; + +bnjs.prototype = _bnjs.prototype; + +var reversebuf = function(buf, nbuf) { + for (var i = 0; i < buf.length; i++) { + nbuf[i] = buf[buf.length-1-i]; + } +}; + +bnjs.fromBuffer = function(buf, opts) { + if (typeof opts !== 'undefined' && opts.endian === 'little') { + var nbuf = new Buffer(buf.length); + reversebuf(buf, nbuf); + buf = nbuf; + } + var hex = buf.toString('hex'); + if (hex.length % 2) + hex = "0" + hex; + var bn = new bnjs(hex, 16); + return bn; +}; + +bnjs.prototype.toBuffer = function(opts) { + var buf; + if (opts && opts.size) { + var hex = this.toString(16); + if (hex.length % 2) + hex = "0" + hex; + var natlen = hex.length/2; + buf = new Buffer(hex, 'hex'); + + if (natlen == opts.size) + buf = buf; + + else if (natlen > opts.size) { + buf = buf.slice(natlen - buf.length, buf.length); + } + + else if (natlen < opts.size) { + var rbuf = new Buffer(opts.size); + //rbuf.fill(0); + for (var i = 0; i < buf.length; i++) + rbuf[rbuf.length-1-i] = buf[buf.length-1-i]; + for (var i = 0; i < opts.size - natlen; i++) + rbuf[i] = 0; + buf = rbuf; + } + } + else { + var hex = this.toString(16); + if (hex.length % 2) + hex = "0" + hex; + buf = new Buffer(hex, 'hex'); + } + + if (typeof opts !== 'undefined' && opts.endian === 'little') { + var nbuf = new Buffer(buf.length); + reversebuf(buf, nbuf); + buf = nbuf; + } + + return buf; +}; + +function decorate(name) { + bnjs.prototype['_' + name] = _bnjs.prototype[name]; + var f = function(b) { + if (typeof b === 'string') + b = new _bnjs(b); + else if (typeof b === 'number') + b = new _bnjs(b.toString()); + return this['_' + name](b); + }; + bnjs.prototype[name] = f; +}; + +_bnjs.prototype.gt = function(b) { + return this.cmp(b) > 0; +}; + +_bnjs.prototype.lt = function(b) { + return this.cmp(b) < 0; +}; + +decorate('add'); +decorate('sub'); +decorate('mul'); +decorate('mod'); +decorate('div'); +decorate('cmp'); +decorate('gt'); +decorate('lt'); + +bnjs.prototype.toNumber = function() { + return parseInt(this['toString'](10), 10); +}; + +module.exports = bnjs; diff --git a/test/test.bn.js b/test/test.bn.js new file mode 100644 index 000000000..1e963626a --- /dev/null +++ b/test/test.bn.js @@ -0,0 +1,112 @@ +var chai = chai || require('chai'); +var should = chai.should(); +var assert = chai.assert; +var BN = require('../lib/bn'); + +describe('BN', function() { + it('should create a bn', function() { + var bn = new BN(50); + should.exist(bn); + bn.toString().should.equal('50'); + }); + + it('should parse this number', function() { + var bn = new BN(999970000); + bn.toString().should.equal('999970000'); + }); + + it('should parse numbers below and at bn.js internal word size', function() { + var bn = new BN(Math.pow(2, 26) - 1); + bn.toString().should.equal((Math.pow(2, 26) - 1).toString()); + var bn = new BN(Math.pow(2, 26)); + bn.toString().should.equal((Math.pow(2, 26)).toString()); + }); + + describe('#add', function() { + + it('should add two small numbers together', function() { + var bn1 = new BN(50); + var bn2 = new BN(75); + var bn3 = bn1.add(bn2); + bn3.toString().should.equal('125'); + }); + + }); + + describe('#sub', function() { + + it('should subtract a small number', function() { + var bn1 = new BN(50); + var bn2 = new BN(25); + var bn3 = bn1.sub(bn2); + bn3.toString().should.equal('25'); + }); + + }); + + describe('#gt', function() { + + it('should say 1 is greater than 0', function() { + var bn1 = new BN(1); + var bn0 = new BN(0); + bn1.gt(bn0).should.equal(true); + }); + + it('should say a big number is greater than a small big number', function() { + var bn1 = new BN('24023452345398529485723980457'); + var bn0 = new BN('34098234283412341234049357'); + bn1.gt(bn0).should.equal(true); + }); + + it('should say a big number is great than a standard number', function() { + var bn1 = new BN('24023452345398529485723980457'); + var bn0 = new BN(5); + bn1.gt(bn0).should.equal(true); + }); + + }); + + describe('#fromBuffer', function() { + + it('should work with big endian', function() { + var bn = BN.fromBuffer(new Buffer('0001', 'hex'), {endian: 'big'}); + bn.toString().should.equal('1'); + }); + + it('should work with big endian 256', function() { + var bn = BN.fromBuffer(new Buffer('0100', 'hex'), {endian: 'big'}); + bn.toString().should.equal('256'); + }); + + it('should work with little endian if we specify the size', function() { + var bn = BN.fromBuffer(new Buffer('0100', 'hex'), {size: 2, endian: 'little'}); + bn.toString().should.equal('1'); + }); + + }); + + describe('#toBuffer', function() { + + it('should create a 4 byte buffer', function() { + var bn = new BN(1); + bn.toBuffer({size: 4}).toString('hex').should.equal('00000001'); + }); + + it('should create a 4 byte buffer in little endian', function() { + var bn = new BN(1); + bn.toBuffer({size: 4, endian: 'little'}).toString('hex').should.equal('01000000'); + }); + + it('should create a 2 byte buffer even if you ask for a 1 byte', function() { + var bn = new BN('ff00', 16); + bn.toBuffer({size: 1}).toString('hex').should.equal('ff00'); + }); + + it('should create a 4 byte buffer even if you ask for a 1 byte', function() { + var bn = new BN('ffffff00', 16); + bn.toBuffer({size: 4}).toString('hex').should.equal('ffffff00'); + }); + + }); + +});