add big number support

Extend bn.js with some convenience methods. Extension code taken from bitcore.
This commit is contained in:
Ryan X. Charles 2014-08-06 18:36:30 -07:00
parent 862235e57e
commit e0deb0407c
3 changed files with 222 additions and 1 deletions

View File

@ -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');

109
lib/bn.js Normal file
View File

@ -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;

112
test/test.bn.js Normal file
View File

@ -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');
});
});
});