| 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._randbelow = function _randbelow(n) { |
| var len = n.bitLength(); |
| var min_bytes = Math.ceil(len / 8); |
| |
| // Generage random bytes until a number less than n is found. |
| // This ensures that 0..n-1 have an equal probability of being selected. |
| do |
| var a = new bn(this.rand.generate(min_bytes)); |
| while (a.cmp(n) >= 0); |
| |
| return a; |
| }; |
| |
| MillerRabin.prototype._randrange = function _randrange(start, stop) { |
| // Generate a random number greater than or equal to start and less than stop. |
| var size = stop.sub(start); |
| return start.add(this._randbelow(size)); |
| }; |
| |
| 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); |
| 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._randrange(new bn(2), n1); |
| 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); |
| 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._randrange(new bn(2), n1); |
| |
| 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; |
| }; |