@btwiuse/bn.js
Version:
Big number implementation in pure javascript
497 lines (452 loc) • 11.7 kB
JavaScript
/* global BigInt */
/* eslint-disable new-cap, no-new, no-unused-expressions */
var benchmark = require('benchmark');
var crypto = require('crypto');
var bn = require('../');
var bignum;
try {
bignum = require('bignum');
} catch (err) {
console.log('Load bignum error: ' + err.message.split('\n')[0]);
}
var sjcl = require('eccjs').sjcl.bn;
var bigi = require('bigi');
var BigInteger = require('js-big-integer').BigInteger;
var SilentMattBigInteger = require('biginteger').BigInteger;
var XorShift128Plus = require('xorshift.js').XorShift128Plus;
var benchmarks = [];
var selfOnly = process.env.SELF_ONLY;
var seed = process.env.SEED || crypto.randomBytes(16).toString('hex');
console.log('Seed: ' + seed);
var prng = new XorShift128Plus(seed);
var fixtures = [];
var findex = 0;
function findexRefresh () {
findex = 0;
}
function add (op, obj) {
benchmarks.push({
name: op,
start: function start () {
var suite = new benchmark.Suite();
console.log('Benchmarking: ' + op);
Object.keys(obj).forEach(function (name) {
if (name === 'BigInt' && typeof BigInt === 'undefined') {
return;
}
if (name === 'bignum' && bignum === undefined) {
return;
}
if (!selfOnly || name === 'bn.js') {
var testFn = obj[name];
suite.add(name + '#' + op, function () {
var fixture = fixtures[findex++];
if (findex === fixtures.length) {
findexRefresh();
}
testFn(fixture);
}, {
onStart: findexRefresh,
onCycle: findexRefresh
});
}
});
suite
.on('cycle', function (event) {
console.log(String(event.target));
})
.on('complete', function () {
console.log('------------------------');
console.log('Fastest is ' + this.filter('fastest')[0].name);
})
.run();
console.log('========================');
}
});
}
function start () {
var re = process.argv[2] ? new RegExp(process.argv[2], 'i') : /./;
benchmarks
.filter(function (b) {
return re.test(b.name);
})
.forEach(function (b) {
b.start();
});
}
if (/fast/i.test(process.argv[3])) {
console.log('Running in fast mode...');
benchmark.options.minTime = 0.3;
benchmark.options.maxTime = 1;
benchmark.options.minSamples = 3;
} else {
benchmark.options.minTime = 1;
}
while (fixtures.length < 25) {
var fixture = {};
fixtures.push(fixture);
var a = prng.randomBytes(32).toString('hex');
var b = prng.randomBytes(32).toString('hex');
var aj = prng.randomBytes(768).toString('hex');
var bj = prng.randomBytes(768).toString('hex');
fixture.a10base = new bn(a, 16).toString(10);
fixture.a16base = new bn(a, 16).toString(16);
// BN
fixture.a1 = new bn(a, 16);
fixture.b1 = new bn(b, 16);
fixture.a1j = new bn(aj, 16);
fixture.b1j = new bn(bj, 16);
fixture.as1 = fixture.a1.mul(fixture.a1).iaddn(0x2adbeef);
fixture.am1 = fixture.a1.toRed(bn.red('k256'));
fixture.pow1 = fixture.am1.fromRed();
// BigInt
fixture.a2 = BigInt(fixture.a1.toString(10));
fixture.b2 = BigInt(fixture.b1.toString(10));
fixture.a2j = BigInt(fixture.a1j.toString(10));
fixture.b2j = BigInt(fixture.b1j.toString(10));
fixture.as2 = fixture.a2 * fixture.a2 + 0x2adbeefn;
// bignum
if (bignum) {
fixture.a3 = new bignum(a, 16);
fixture.b3 = new bignum(b, 16);
fixture.a3j = new bignum(aj, 16);
fixture.b3j = new bignum(bj, 16);
fixture.as3 = fixture.a3.mul(fixture.a3).add(0x2adbeef);
}
// bigi
fixture.a4 = new bigi(a, 16);
fixture.b4 = new bigi(b, 16);
fixture.a4j = new bigi(aj, 16);
fixture.b4j = new bigi(bj, 16);
fixture.as4 = fixture.a4.multiply(fixture.a4).add(bigi.valueOf(0x2adbeef));
// sjcl
fixture.a5 = new sjcl(a, 16);
fixture.b5 = new sjcl(b, 16);
fixture.a5j = new sjcl(aj, 16);
fixture.b5j = new sjcl(bj, 16);
// fixture.as5 = fixture.a5.mul(fixture.a5).add(0x2adbeef);
fixture.am5 = new sjcl.prime.p256k(fixture.a5);
// BigInteger
fixture.a6 = new BigInteger(a, 16);
fixture.b6 = new BigInteger(b, 16);
fixture.a6j = new BigInteger(aj, 16);
fixture.b6j = new BigInteger(bj, 16);
fixture.as6 = fixture.a6.multiply(fixture.a6).add(
new BigInteger('2adbeef', 16));
// SilentMattBigInteger
fixture.a7 = SilentMattBigInteger.parse(a, 16);
fixture.b7 = SilentMattBigInteger.parse(b, 16);
fixture.a7j = SilentMattBigInteger.parse(aj, 16);
fixture.b7j = SilentMattBigInteger.parse(aj, 16);
fixture.as7 = fixture.a7.multiply(fixture.a7).add(
SilentMattBigInteger.parse('2adbeef', 16));
}
add('create-10', {
'bn.js': function (fixture) {
new bn(fixture.a10base, 10);
},
BigInt: function (fixture) {
BigInt(fixture.a10base);
},
bignum: function (fixture) {
new bignum(fixture.a10base, 10);
},
bigi: function (fixture) {
new bigi(fixture.a10base, 10);
},
yaffle: function (fixture) {
new BigInteger(fixture.a10base, 10);
},
'silentmatt-biginteger': function (fixture) {
SilentMattBigInteger.parse(fixture.a10base, 10);
}
});
add('create-hex', {
'bn.js': function (fixture) {
new bn(fixture.a16base, 16);
},
bignum: function (fixture) {
new bignum(fixture.a16base, 16);
},
bigi: function (fixture) {
new bigi(fixture.a16base, 16);
},
sjcl: function (fixture) {
new sjcl(fixture.a16base);
},
yaffle: function (fixture) {
new BigInteger(fixture.a16base, 16);
},
'silentmatt-biginteger': function (fixture) {
SilentMattBigInteger.parse(fixture.a16base, 16);
}
});
add('toString-10', {
'bn.js': function (fixture) {
fixture.a1.toString(10);
},
BigInt: function (fixture) {
fixture.a2.toString(10);
},
bignum: function (fixture) {
fixture.a3.toString(10);
},
bigi: function (fixture) {
fixture.a4.toString(10);
},
yaffle: function (fixture) {
fixture.a6.toString(10);
},
'silentmatt-biginteger': function (fixture) {
fixture.a7.toString(10);
}
});
add('toString-hex', {
'bn.js': function (fixture) {
fixture.a1.toString(16);
},
BigInt: function (fixture) {
fixture.a2.toString(16);
},
bignum: function (fixture) {
fixture.a3.toString(16);
},
bigi: function (fixture) {
fixture.a4.toString(16);
},
sjcl: function (fixture) {
fixture.a5.toString(16);
},
yaffle: function (fixture) {
fixture.a6.toString(16);
},
'silentmatt-biginteger': function (fixture) {
fixture.a7.toString(16);
}
});
add('add', {
'bn.js': function (fixture) {
fixture.a1.add(fixture.b1);
},
BigInt: function (fixture) {
fixture.a2 + fixture.b2;
},
bignum: function (fixture) {
fixture.a3.add(fixture.b3);
},
bigi: function (fixture) {
fixture.a4.add(fixture.b4);
},
sjcl: function (fixture) {
fixture.a5.add(fixture.b5);
},
yaffle: function (fixture) {
fixture.a6.add(fixture.b6);
},
'silentmatt-biginteger': function (fixture) {
fixture.a7.add(fixture.a7);
}
});
add('sub', {
'bn.js': function (fixture) {
fixture.b1.sub(fixture.a1);
},
BigInt: function (fixture) {
fixture.a2 - fixture.b2;
},
bignum: function (fixture) {
fixture.b3.sub(fixture.a3);
},
bigi: function (fixture) {
fixture.b4.subtract(fixture.a4);
},
sjcl: function (fixture) {
fixture.b5.sub(fixture.a5);
},
yaffle: function (fixture) {
fixture.b6.subtract(fixture.a6);
},
'silentmatt-biginteger': function (fixture) {
fixture.b7.subtract(fixture.a7);
}
});
add('mul', {
'bn.js': function (fixture) {
fixture.a1.mul(fixture.b1);
},
'bn.js[FFT]': function (fixture) {
fixture.a1.mulf(fixture.b1);
},
BigInt: function (fixture) {
fixture.a2 * fixture.b2;
},
bignum: function (fixture) {
fixture.a3.mul(fixture.b3);
},
bigi: function (fixture) {
fixture.a4.multiply(fixture.b4);
},
sjcl: function (fixture) {
fixture.a5.mul(fixture.b5);
},
yaffle: function (fixture) {
fixture.a6.multiply(fixture.b6);
},
'silentmatt-biginteger': function (fixture) {
fixture.a7.multiply(fixture.b7);
}
});
add('mul-jumbo', {
'bn.js': function (fixture) {
fixture.a1j.mul(fixture.b1j);
},
'bn.js[FFT]': function (fixture) {
fixture.a1j.mulf(fixture.b1j);
},
BigInt: function (fixture) {
fixture.a2j * fixture.b2j;
},
bignum: function (fixture) {
fixture.a3j.mul(fixture.b3j);
},
bigi: function (fixture) {
fixture.a4j.multiply(fixture.b4j);
},
sjcl: function (fixture) {
fixture.a5j.mul(fixture.b5j);
},
yaffle: function (fixture) {
fixture.a6j.multiply(fixture.b6j);
},
'silentmatt-biginteger': function (fixture) {
fixture.a7j.multiply(fixture.b7j);
}
});
add('sqr', {
'bn.js': function (fixture) {
fixture.a1.mul(fixture.a1);
},
BigInt: function (fixture) {
fixture.a2 * fixture.a2;
},
bignum: function (fixture) {
fixture.a3.mul(fixture.a3);
},
bigi: function (fixture) {
fixture.a4.square();
},
sjcl: function (fixture) {
fixture.a5.mul(fixture.a5);
},
yaffle: function (fixture) {
fixture.a6.multiply(fixture.a6);
},
'silentmatt-biginteger': function (fixture) {
fixture.a7.multiply(fixture.a7);
}
});
add('div', {
'bn.js': function (fixture) {
fixture.as1.div(fixture.a1);
},
BigInt: function (fixture) {
fixture.as2 / fixture.a2;
},
bignum: function (fixture) {
fixture.as3.div(fixture.a3);
},
bigi: function (fixture) {
fixture.as4.divide(fixture.a4);
},
yaffle: function (fixture) {
fixture.as6.divide(fixture.a6);
},
'silentmatt-biginteger': function (fixture) {
fixture.as7.divide(fixture.a7);
}
});
add('mod', {
'bn.js': function (fixture) {
fixture.as1.mod(fixture.a1);
},
BigInt: function (fixture) {
fixture.as2 / fixture.a2;
},
bignum: function (fixture) {
fixture.as3.mod(fixture.a3);
},
bigi: function (fixture) {
fixture.as4.mod(fixture.a4);
},
yaffle: function (fixture) {
var remainder = fixture.as6.remainder(fixture.a6);
return remainder.compareTo(BigInteger.ZERO) < 0
? remainder.add(fixture.a6)
: remainder;
},
'silentmatt-biginteger': function (fixture) {
var remainder = fixture.as7.remainder(fixture.a7);
return remainder.compare(BigInteger.ZERO) < 0
? remainder.add(fixture.a7)
: remainder;
}
});
add('mul-mod k256', {
'bn.js': function (fixture) {
fixture.am1.redSqr();
},
sjcl: function (fixture) {
fixture.am5.square().fullReduce();
}
});
var prime1;
if (bignum) {
prime1 = new bignum(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
16);
}
// var prime4 = new bigi(
// 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
// 16);
var prime5 = new sjcl(
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f');
add('pow k256', {
'bn.js': function (fixture) {
fixture.am1.redPow(fixture.pow1);
},
bignum: function (fixture) {
fixture.a3.powm(fixture.a3, prime1);
}
});
add('invm k256', {
'bn.js': function (fixture) {
fixture.am1.redInvm();
},
sjcl: function (fixture) {
fixture.am5.inverseMod(prime5);
}
});
add('gcd', {
'bn.js': function (fixture) {
fixture.a1.gcd(fixture.b1);
},
bigi: function (fixture) {
fixture.a4.gcd(fixture.b4);
}
});
add('egcd', {
'bn.js': function (fixture) {
fixture.a1.egcd(fixture.b1);
}
});
add('bitLength', {
'bn.js': function () {
fixture.a1.bitLength();
}
});
add('toArray', {
'bn.js': function () {
fixture.a1j.toArray();
}
});
start();