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); }