大数判定是否是质数

187 阅读1分钟

大数判定是否是质数


// #include < NTL / ZZ.h >
var prime = require("./genPrime")
var primeList = prime.getPrimes(2000).map(BigInt)
/**
 * 
 * @param {bigint} n n为素数候选者
 * @param {bigint} x x为随机数
 * @returns 
 */
function witness(n, x) {
  let d, y, z;
  let j, s;

  if (x == 0n) return 0n;

  //计算s,d,使得n-1 = 2^s * d, d是奇数:
  s = 1;
  d = n / 2n;
  while (d % 2n == 0) {
    s++;
    d /= 2n;
  }

  /*在NTL内置的函数中,有一个刚好满足我们的要求:
  m = n - 1;
  k = MakeOdd(m);
  */

  // z = PowerMod(x, d, n); // z = x^d % n
  z = PowerMod(x, d, n)
  if (z == 1n) return 0;

  j = 0;
  do {
    y = z;
    z = (y * y) % n;
    j++;
  } while (j < s && z != 1);

  return z != 1n || y != n - 1n;
}

/**
 * 
 * @param {BigInt} n n为待检测素数
 * @param {BigInt} t t为检测次数
 * @returns 
 */
function PrimeTest(n, t) {
  if (n <= 1n) return false;

  //用2000以内的素数对n进行初筛
  // PrimeSeq s;  // 生成一个素数数列
  let p;
  p = primeList[0];
  // first prime is always 2
  let index = 0;
  while (p && p < 2000n) {
    if ((n % p) == 0n)
      return (n == p);
    index++;
    p = primeList[index];
  }

  //Miller-Rabin法推演n的素性
  let x;

  for (var i = 0; i < t; i++) {
    x = (BigInt(Math.random() * 0xffffffffffffff) * n / 0xffffffffffffffn)
     // 随机数 between 0 and n-1
    if (witness(n, x))//有凭证
      return false;
  }

  return true;
}

/**
 * x^d%n
 * @param {bigint} x 
 * @param {bigint} d 
 * @param {bigint} n 
 * @returns {bigint} 
 */
function PowerMod(x, d, n) {
  let d2 = d.toString(2).split("").map(BigInt)
  let collect = new Array(d2.length).fill(0n)
 
  collect[d2.length - 1] = x % n
    
  for (let index = 1; index < d2.length; index++) {
    collect[d2.length - index - 1] = (collect[d2.length - index] * collect[d2.length - index]) % n
  }
  let temp1 = 1n;
  for (let index = 0; index < collect.length; index++) {
    if (d2[index])
      temp1 = (temp1 * collect[index]) % n
  }
  return temp1
}
// console.log(PowerMod(4n, 4n, 7n));

console.log(PrimeTest(10865294066886871n, 1n))

genPrime 文件

function getPrimes(limit = 0x100000) {
	var res = [];
	res[0] = 2;
	for (var i = 1, k = 3; k < limit; k += 2) {
		var sqrt = Math.ceil(Math.sqrt(k));
		for (var j = 0; j < i && res[j] <= sqrt; j++)
			if (k % res[j] === 0)
				break;

		if (i !== j && res[j] <= sqrt)
			continue;

		res[i++] = k;
	}
	return res;
}
module.exports = { getPrimes}