private static BigInteger[] LucasSequenceHelper(BigInteger P, BigInteger Q, BigInteger k, BigInteger n, BigInteger constant, int s) { BigInteger[] result = new BigInteger[3]; if ((k & 0x01) == 0) { throw (new ArgumentException("Значение аргумента k должно быть четным")); } int numbits = Length(k); uint mask = (uint)0x1 << ((numbits & 0x1F) - 1); // v = v0, v1 = v1, u1 = u1, Q_k = Q^0 BigInteger v = 2 % n, Q_k = 1 % n, v1 = P % n, u1 = Q_k; bool flag = true; uint[] k_data = SupportEDS.BigIntegerToUintArray(k); for (int i = k_data.Length - 2; i >= 0; i--) { while (mask != 0) { if (i == 0 && mask == 0x00000001) { break; } if ((k_data[i] & mask) != 0) { u1 = (u1 * v1) % n; v = ((v * v1) - (P * Q_k)) % n; v1 = BarrettReduction(v1 * v1, n, constant); v1 = (v1 - ((Q_k * Q) << 1)) % n; if (flag) { flag = false; } else { Q_k = BarrettReduction(Q_k * Q_k, n, constant); } Q_k = (Q_k * Q) % n; } else { u1 = ((u1 * v) - Q_k) % n; v1 = ((v * v1) - (P * Q_k)) % n; v = BarrettReduction(v * v, n, constant); v = (v - (Q_k << 1)) % n; if (flag) { Q_k = Q % n; flag = false; } else { Q_k = BarrettReduction(Q_k * Q_k, n, constant); } } mask >>= 1; } mask = 0x80000000; } u1 = ((u1 * v) - Q_k) % n; v = ((v * v1) - (P * Q_k)) % n; if (flag) { flag = false; } else { Q_k = BarrettReduction(Q_k * Q_k, n, constant); } Q_k = (Q_k * Q) % n; for (int i = 0; i < s; i++) { u1 = (u1 * v) % n; v = ((v * v) - (Q_k << 1)) % n; if (flag) { Q_k = Q % n; flag = false; } else { Q_k = BarrettReduction(Q_k * Q_k, n, constant); } } result[0] = u1; result[1] = v; result[2] = Q_k; return(result); }
private static bool LucasStrongTestHelper(BigInteger thisVal) { long D = 5, sign = -1, dCount = 0; bool done = false; while (!done) { int Jresult = Jacobi(D, thisVal); if (Jresult == -1) { done = true; // J(D, this) = 1 } else { if (Jresult == 0 && Math.Abs(D) < thisVal) // найден делитель { return(false); } if (dCount == 20) { BigInteger root = Sqrt(thisVal); if (root * root == thisVal) { return(false); } } D = (Math.Abs(D) + 2) * sign; sign = -sign; } dCount++; } long Q = (1 - D) >> 2; BigInteger p_add1 = thisVal + 1; uint[] data = SupportEDS.BigIntegerToUintArray(p_add1); int s = 0; for (int i = 0; i < data.Length - 1; i++) { uint mask = 0x01; for (int j = 0; j < 32; j++) { if ((data[i] & mask) != 0) { i = data.Length; break; } mask <<= 1; s++; } } BigInteger t = p_add1 >> s; // вычисление константы для Редукции Баррета = b^(2k) / m BigInteger constant = new BigInteger(); uint[] thisVal_data = SupportEDS.BigIntegerToUintArray(thisVal); int nLen = (thisVal_data.Length - 1) << 1; uint[] const_data = new uint[nLen + 2]; for (int i = 0; i < const_data.Length; i++) { if (i == nLen) { const_data[i] = 0x00000001; } else { const_data[i] = 0x0; } } constant = SupportEDS.BigIntegerFromUintArray(const_data); constant = constant / thisVal; BigInteger[] lucas = LucasSequenceHelper(1, Q, t, thisVal, constant, 0); bool isPrime = false; if ((lucas[0] == 0) || lucas[1] == 0) { // u(t) = 0 либо V(t) = 0 isPrime = true; } for (int i = 1; i < s; i++) { if (!isPrime) { lucas[1] = BarrettReduction(lucas[1] * lucas[1], thisVal, constant); lucas[1] = (lucas[1] - (lucas[2] << 1)) % thisVal; //lucas[1] = ((lucas[1] * lucas[1]) - (lucas[2] << 1)) % thisVal; if ((lucas[1] == 0)) { isPrime = true; } } lucas[2] = BarrettReduction(lucas[2] * lucas[2], thisVal, constant); //Q^k } if (isPrime) // дополнительная проверка на составные числа { BigInteger g = BigInteger.GreatestCommonDivisor(thisVal, Q); if (g == 1) { uint[] lucas_data = SupportEDS.BigIntegerToUintArray(lucas[2]); if (lucas[2] < 0) { lucas[2] += thisVal; } BigInteger temp = (Q * Jacobi(Q, thisVal)) % thisVal; if (temp < 0) { temp += thisVal; } if (lucas[2] != temp) { isPrime = false; } } } return(isPrime); }
public static BigInteger BarrettReduction(BigInteger x, BigInteger n, BigInteger constant) { uint[] n_data = SupportEDS.BigIntegerToUintArray(n); int k = Length(n_data.Length - 1), kPlusOne = k + 1, kMinusOne = k - 1; BigInteger q1 = new BigInteger(); // q1 = x / b^(k-1) uint[] x_data = SupportEDS.BigIntegerToUintArray(x); int new_lng = x_data.Length - kMinusOne; uint[] q1_data; if (new_lng > 1) { q1_data = new uint[new_lng]; } else { q1_data = new uint[2]; } q1_data[q1_data.Length - 1] = 0; for (int i = kMinusOne, j = 0; i < x_data.Length - 1; i++, j++) { q1_data[j] = x_data[i]; } q1 = SupportEDS.BigIntegerFromUintArray(q1_data); BigInteger q2 = q1 * constant; // q3 = q2 / b^(k+1) uint[] q2_data = SupportEDS.BigIntegerToUintArray(q2); int new_lng2 = q2_data.Length - kPlusOne; uint[] q3_data; if (new_lng2 > 1) { q3_data = new uint[new_lng2]; } else { q3_data = new uint[2]; } q3_data[q3_data.Length - 1] = 0; for (int i = kPlusOne, j = 0; i < q2_data.Length - 1; i++, j++) { q3_data[j] = q2_data[i]; } // r1 = x mod b^(k+1) // i.e. keep the lowest (k+1) words BigInteger r1 = new BigInteger(); int lengthToCopy = ((x_data.Length - 1) > kPlusOne) ? kPlusOne : (x_data.Length - 1); uint[] r1_data = new uint[lengthToCopy + 1]; for (int i = 0; i < lengthToCopy; i++) { r1_data[i] = x_data[i]; } r1_data[r1_data.Length - 1] = 0; // r2 = (q3 * n) mod b^(k+1) // partial multiplication of q3 and n BigInteger r2 = new BigInteger(); uint[] r2_data = new uint[kPlusOne + 1]; for (int i = 0; i < q3_data.Length - 1; i++) { if (q3_data[i] == 0) { continue; } ulong mcarry = 0; int t = i; for (int j = 0; j < n_data.Length - 1 && t < kPlusOne; j++, t++) { // t = i + j ulong val = ((ulong)q3_data[i] * (ulong)n_data[j]) + (ulong)r2_data[t] + mcarry; r2_data[t] = (uint)(val & 0xFFFFFFFF); mcarry = (val >> 32); } if (t < kPlusOne) { r2_data[t] = (uint)mcarry; } } r2_data[r2_data.Length - 1] = 0; r1 = SupportEDS.BigIntegerFromUintArray(r1_data); r2 = SupportEDS.BigIntegerFromUintArray(r2_data); r1 -= r2; if (r1 < 0) { r1 = -r1; } while (r1 >= n) { r1 -= n; } return(r1); }
public static bool isProbablePrime(BigInteger bi) { BigInteger thisVal; if (bi < 0) { thisVal = -bi; } else { thisVal = bi; } if (bi < UInt32.MaxValue) { // проверка малых значений if (thisVal == 0 || thisVal == 1) { return(false); } else if (thisVal == 2 || thisVal == 3) { return(true); } } // четные числа if ((thisVal & 0x1) == 0) { return(false); } // тест на делимость на простые < 2000 long[] primes = GetPrimes(2000); for (int p = 0; p < primes.Length; p++) { BigInteger divisor = primes[p]; if (divisor >= thisVal) { break; } BigInteger resultNum = thisVal % divisor; if ((int)resultNum == 0) { return(false); } } // Выполнения теста Рабина-Миллера р.2 BigInteger p_sub1 = thisVal - 1; int s = 0; uint[] data = SupportEDS.BigIntegerToUintArray(p_sub1); for (int i = 0; i < data.Length - 1; i++) { uint mask = 0x01; for (int j = 0; j < 32; j++) { if ((data[i] & mask) != 0) { i = data.Length; break; } mask <<= 1; s++; } } BigInteger t = p_sub1 >> s; int bits = Length(thisVal); // b = 2^t mod p BigInteger b = BigInteger.ModPow(2, t, thisVal); bool result = false; if (b == 1) // a^t mod p = 1 { result = true; } for (int j = 0; result == false && j < s; j++) { if (b == p_sub1) // a^((2^j)*t) mod p = p-1 для любого 0 <= j <= s-1 { result = true; break; } b = (b * b) % thisVal; } // если число является сложным псевдопростым по основанию 2, переходим к тяжелому тесту Лукаса if (result) { result = LucasStrongTestHelper(thisVal); } return(result); }
public static int Jacobi(BigInteger a, BigInteger b) { if ((b & 0x1) == 0) { throw (new ArgumentException("Число должно быть нечетным.")); } if (a >= b) { a %= b; } if (a == 0) { return(0); } if (a == 1) { return(1); } uint[] a_data = SupportEDS.BigIntegerToUintArray(a); uint[] b_data = SupportEDS.BigIntegerToUintArray(b); if (a < 0) { int kr = 0; if (b_data.Length == 2) { kr = 1; } if (((b_data[0] - kr) & 0x2) == 0) { return(Jacobi(-a, b)); } else { return(-Jacobi(-a, b)); } } int e = 0; for (int index = 0; index < a_data.Length - 1; index++) { uint mask = 0x01; for (int i = 0; i < 32; i++) { if ((a_data[index] & mask) != 0) { index = a_data.Length; break; } mask <<= 1; e++; } } BigInteger a1 = a >> e; uint[] a1_data = SupportEDS.BigIntegerToUintArray(a1); int s = 1; if ((e & 0x1) != 0 && ((b_data[0] & 0x7) == 3 || (b_data[0] & 0x7) == 5)) { s = -1; } if ((b_data[0] & 0x3) == 3 && (a1_data[0] & 0x3) == 3) { s = -s; } if (a1 == 1) { return(s); } else { return(s * Jacobi(b % a1, a1)); } }