public static bool IsPrime_M(BigInteger value) { if (value <= 1) { return(false); } if (value <= 3) { return(true); } if (value.IsEven) { return(false); } if (value < 100) { return(Consts.PRIMES_NN.Any(v => v == value)); } int valueScale = BigIntegerUtils.GetByteArrayLength(value); BigInteger d = value >> 1; int r = 0; while (d.IsEven) { d >>= 1; r++; } // if n < 3,317,044,064,679,887,385,961,981, it is enough to test a = 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, and 41. @ wiki if (value < Consts.BIPXX) { foreach (int ix in new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41 }) { BigInteger x = new BigInteger(new byte[] { (byte)ix, 0x00 }); if (IsPrime_X(x, d, r, value) == false) { return(false); } } } else { for (int k = 0; k < Ground.MillerRabin_K; k++) { BigInteger x = new BigInteger(BinTools.Join(new byte[][] { SecurityTools.CRandom.GetBytes(valueScale + 10), new byte[] { 0x00 } })) % (value - 3) + 2; // 2 ~ (value - 2) if (IsPrime_X(x, d, r, value) == false) { return(false); } } } return(true); }
// memo: // value の最小の素因数が p のとき、ランダムに選ばれた r が p の倍数である確率は 1/p また p 以外の約数も発見出来る可能性がある。 // なので、たかだか平均 p 回のトライで約数を発見出来る。 // -- 合成数のとき更に素因数分解する必要がある。処理速度に貢献していないじゃないか? // -- 愚直に 2, 3, 5, 7, 9, ... と割って試していく方法の方が速いんじゃないか? <-- トライ毎に FF_GCD() に比べ 1回の剰余で済む。 private static BigInteger FindFactor(BigInteger value) { if (Ground.IsStopped()) { throw new Cancelled(); } if (value < 2) { throw null; // bugged !!! } if (value <= 3) // 2, 3 are prime { goto retired; } int valueScale = BigIntegerUtils.GetByteArrayLength(value); if (valueScale < 1) { throw null; // souteigai !!! } for (int c = 0; c < 1000; c++) { // ここからトライ BigInteger r; if (valueScale < 100) { r = new BigInteger(BinTools.Join(new byte[][] { SecurityTools.CRandom.GetBytes(valueScale + 10), new byte[] { 0x00 } })) % (value - 2) + 2; // 2 ~ (value - 1) } else { r = new BigInteger(BinTools.Join(new byte[][] { SecurityTools.CRandom.GetBytes(valueScale / 2 + 10), new byte[] { 0x00 } })) + 2; // 2 ~ (about_sqrt(value)) } BigInteger f = FF_GCD(value, r); if (f != 1) { return(f); // トライ成功 } // トライ失敗 } retired: throw new FF_Retired(); }