UNPKG

pollardsrho

Version:

integer factorization using Pollard's rho algorithm with Brent cycle detection, Miller–Rabin primality test

123 lines (114 loc) 3.03 kB
function log2(x) { return BigInt(x.toString(16).length * 4); } function modPow(base, exponent, modulus) { // left-to-right method is preferred as the base is small const e = exponent.toString(2); let accumulator = 1n; for (let i = 0; i < e.length; i += 1) { accumulator = (accumulator * accumulator) % modulus; if (+e.charCodeAt(i) !== +'0'.charCodeAt(0)) { accumulator = (accumulator * base) % modulus; } } return accumulator; } function primes(MAX) { const sieve = new Array(MAX + 1).fill(true); const result = []; result.push(2); for (let i = 3; i <= MAX; i += 2) { if (sieve[i]) { result.push(i); if (i <= Math.floor(MAX / i)) { for (let j = i * i; j <= MAX; j += 2 * i) { sieve[j] = false; } } } } return result; } function getBases(n) { // https://en.wikipedia.org/wiki/Miller–Rabin_primality_test#Testing_against_small_sets_of_bases if (typeof n !== 'bigint') { throw new TypeError(); } if (n < 2047n) { return [2]; } if (n < 1373653n) { return [2, 3]; } if (n < 25326001n) { return [2, 3, 5]; } if (n < 3215031751n) { return [2, 3, 5, 7]; } if (n < 2152302898747n) { return [2, 3, 5, 7, 11]; } if (n < 3474749660383n) { return [2, 3, 5, 7, 11, 13]; } if (n < 341550071728321n) { return [2, 3, 5, 7, 11, 13, 17]; } if (n < 3825123056546413051n) { return [2, 3, 5, 7, 11, 13, 17, 19, 23]; } if (n < 318665857834031151167461n) { return [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]; } if (n < 3317044064679887385961981n) { return [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]; } // https://primes.utm.edu/prove/prove2_3.html const lnN = Number(log2(n)) * Math.log(2); return primes(Math.floor(1 / Math.log(2) * lnN * Math.log(lnN))); } function isPrime(n) { if (typeof n !== "bigint") { throw new RangeError(); } if (n < 0n) { throw new RangeError(); } if (n < 2n) { return false; } const smallPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]; const s = Number(n % 304250263527210n); for (let i = 0; i < smallPrimes.length; i += 1) { const p = smallPrimes[i]; if (s - Math.floor(s / p) * p === 0) { return n === BigInt(p); } } if (n < 43 * 43) { return true; } // https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Deterministic_variants let r = 0; let d = n - 1n; while (d % 2n === 0n) { d /= 2n; r += 1; } const bases = getBases(n); for (const a of bases) { let x = modPow(BigInt(a), d, n); if (x !== 1n) { for (let i = r - 1; i > 0 && x !== n - 1n; i -= 1) { x = (x * x) % n; } if (x !== n - 1n) { //if (bases.indexOf(base) >= 1) console.log(n, bases.indexOf(base)); return false; } } } return true; } export default isPrime;