114 lines
2.2 KiB
JavaScript
114 lines
2.2 KiB
JavaScript
|
var bn = require('bn.js');
|
||
|
var brorand = require('brorand');
|
||
|
|
||
|
function MillerRabin(rand) {
|
||
|
this.rand = rand || new brorand.Rand();
|
||
|
}
|
||
|
module.exports = MillerRabin;
|
||
|
|
||
|
MillerRabin.create = function create(rand) {
|
||
|
return new MillerRabin(rand);
|
||
|
};
|
||
|
|
||
|
MillerRabin.prototype._rand = function _rand(n) {
|
||
|
var len = n.bitLength();
|
||
|
var buf = this.rand.generate(Math.ceil(len / 8));
|
||
|
|
||
|
// Set low bits
|
||
|
buf[0] |= 3;
|
||
|
|
||
|
// Mask high bits
|
||
|
var mask = len & 0x7;
|
||
|
if (mask !== 0)
|
||
|
buf[buf.length - 1] >>= 7 - mask;
|
||
|
|
||
|
return new bn(buf);
|
||
|
}
|
||
|
|
||
|
MillerRabin.prototype.test = function test(n, k, cb) {
|
||
|
var len = n.bitLength();
|
||
|
var red = bn.mont(n);
|
||
|
var rone = new bn(1).toRed(red);
|
||
|
|
||
|
if (!k)
|
||
|
k = Math.max(1, (len / 48) | 0);
|
||
|
|
||
|
// Find d and s, (n - 1) = (2 ^ s) * d;
|
||
|
var n1 = n.subn(1);
|
||
|
var n2 = n1.subn(1);
|
||
|
for (var s = 0; !n1.testn(s); s++) {}
|
||
|
var d = n.shrn(s);
|
||
|
|
||
|
var rn1 = n1.toRed(red);
|
||
|
|
||
|
var prime = true;
|
||
|
for (; k > 0; k--) {
|
||
|
var a = this._rand(n2);
|
||
|
if (cb)
|
||
|
cb(a);
|
||
|
|
||
|
var x = a.toRed(red).redPow(d);
|
||
|
if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
|
||
|
continue;
|
||
|
|
||
|
for (var i = 1; i < s; i++) {
|
||
|
x = x.redSqr();
|
||
|
|
||
|
if (x.cmp(rone) === 0)
|
||
|
return false;
|
||
|
if (x.cmp(rn1) === 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (i === s)
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return prime;
|
||
|
};
|
||
|
|
||
|
MillerRabin.prototype.getDivisor = function getDivisor(n, k) {
|
||
|
var len = n.bitLength();
|
||
|
var red = bn.mont(n);
|
||
|
var rone = new bn(1).toRed(red);
|
||
|
|
||
|
if (!k)
|
||
|
k = Math.max(1, (len / 48) | 0);
|
||
|
|
||
|
// Find d and s, (n - 1) = (2 ^ s) * d;
|
||
|
var n1 = n.subn(1);
|
||
|
var n2 = n1.subn(1);
|
||
|
for (var s = 0; !n1.testn(s); s++) {}
|
||
|
var d = n.shrn(s);
|
||
|
|
||
|
var rn1 = n1.toRed(red);
|
||
|
|
||
|
for (; k > 0; k--) {
|
||
|
var a = this._rand(n2);
|
||
|
|
||
|
var g = n.gcd(a);
|
||
|
if (g.cmpn(1) !== 0)
|
||
|
return g;
|
||
|
|
||
|
var x = a.toRed(red).redPow(d);
|
||
|
if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)
|
||
|
continue;
|
||
|
|
||
|
for (var i = 1; i < s; i++) {
|
||
|
x = x.redSqr();
|
||
|
|
||
|
if (x.cmp(rone) === 0)
|
||
|
return x.fromRed().subn(1).gcd(n);
|
||
|
if (x.cmp(rn1) === 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (i === s) {
|
||
|
x = x.redSqr();
|
||
|
return x.fromRed().subn(1).gcd(n);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
};
|