예제 #1
0
	//***********************************************************************
	// Performs the calculation of the kth term in the Lucas Sequence.
	// For details of the algorithm, see reference [9].
	//
	// k must be odd.  i.e LSB == 1
	//***********************************************************************

	private static BigInteger[] LucasSequenceHelper(BigInteger P, BigInteger Q,
		BigInteger k, BigInteger n,
		BigInteger constant, int s)
	{
		BigInteger[] result = new BigInteger[3];

		if((k.data[0] & 0x00000001) == 0)
			throw (new ArgumentException("Argument k must be odd."));

		int numbits = k.bitCount();
		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;

		for(int i = k.dataLength - 1; i >= 0 ; i--)     // iterate on the binary expansion of k
		{
			//Console.WriteLine("round");
			while(mask != 0)
			{
				if(i == 0 && mask == 0x00000001)        // last bit
					break;

				if((k.data[i] & mask) != 0)             // bit is set
				{
					// index doubling with addition

					u1 = (u1 * v1) % n;

					v = ((v * v1) - (P * Q_k)) % n;
					v1 = n.BarrettReduction(v1 * v1, n, constant);
					v1 = (v1 - ((Q_k * Q) << 1)) % n;

					if(flag)
						flag = false;
					else
						Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);

					Q_k = (Q_k * Q) % n;
				}
				else
				{
					// index doubling
					u1 = ((u1 * v) - Q_k) % n;

					v1 = ((v * v1) - (P * Q_k)) % n;
					v = n.BarrettReduction(v * v, n, constant);
					v = (v - (Q_k << 1)) % n;

					if(flag)
					{
						Q_k = Q % n;
						flag = false;
					}
					else
						Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
				}

				mask >>= 1;
			}
			mask = 0x80000000;
		}

		// at this point u1 = u(n+1) and v = v(n)
		// since the last bit always 1, we need to transform u1 to u(2n+1) and v to v(2n+1)

		u1 = ((u1 * v) - Q_k) % n;
		v = ((v * v1) - (P * Q_k)) % n;
		if(flag)
			flag = false;
		else
			Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);

		Q_k = (Q_k * Q) % n;


		for(int i = 0; i < s; i++)
		{
			// index doubling
			u1 = (u1 * v) % n;
			v = ((v * v) - (Q_k << 1)) % n;

			if(flag)
			{
				Q_k = Q % n;
				flag = false;
			}
			else
				Q_k = n.BarrettReduction(Q_k * Q_k, n, constant);
		}

		result[0] = u1;
		result[1] = v;
		result[2] = Q_k;

		return result;
	}
예제 #2
0
	private bool LucasStrongTestHelper(BigInteger thisVal)
	{
		// Do the test (selects D based on Selfridge)
		// Let D be the first element of the sequence
		// 5, -7, 9, -11, 13, ... for which J(D,n) = -1
		// Let P = 1, Q = (1-D) / 4

		long D = 5, sign = -1, dCount = 0;
		bool done = false;

		while(!done)
		{
			int Jresult = BigInteger.Jacobi(D, thisVal);

			if(Jresult == -1)
				done = true;    // J(D, this) = 1
			else
			{
				if(Jresult == 0 && Math.Abs(D) < thisVal)       // divisor found
					return false;

				if(dCount == 20)
				{
					// check for square
					BigInteger root = thisVal.sqrt();
					if(root * root == thisVal)
						return false;
				}

				//Console.WriteLine(D);
				D = (Math.Abs(D) + 2) * sign;
				sign = -sign;
			}
			dCount++;
		}

		long Q = (1 - D) >> 2;

		/*
				Console.WriteLine("D = " + D);
				Console.WriteLine("Q = " + Q);
				Console.WriteLine("(n,D) = " + thisVal.gcd(D));
				Console.WriteLine("(n,Q) = " + thisVal.gcd(Q));
				Console.WriteLine("J(D|n) = " + BigInteger.Jacobi(D, thisVal));
				*/

		BigInteger p_add1 = thisVal + 1;
		int s = 0;

		for(int index = 0; index < p_add1.dataLength; index++)
		{
			uint mask = 0x01;

			for(int i = 0; i < 32; i++)
			{
				if((p_add1.data[index] & mask) != 0)
				{
					index = p_add1.dataLength;      // to break the outer loop
					break;
				}
				mask <<= 1;
				s++;
			}
		}

		BigInteger t = p_add1 >> s;

		// calculate constant = b^(2k) / m
		// for Barrett Reduction
		BigInteger constant = new BigInteger();

		int nLen = thisVal.dataLength << 1;
		constant.data[nLen] = 0x00000001;
		constant.dataLength = nLen + 1;

		constant = constant / thisVal;

		BigInteger[] lucas = LucasSequenceHelper(1, Q, t, thisVal, constant, 0);
		bool isPrime = false;

		if((lucas[0].dataLength == 1 && lucas[0].data[0] == 0) ||
			(lucas[1].dataLength == 1 && lucas[1].data[0] == 0))
		{
			// u(t) = 0 or V(t) = 0
			isPrime = true;
		}

		for(int i = 1; i < s; i++)
		{
			if(!isPrime)
			{
				// doubling of index
				lucas[1] = thisVal.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].dataLength == 1 && lucas[1].data[0] == 0))
					isPrime = true;
			}

			lucas[2] = thisVal.BarrettReduction(lucas[2] * lucas[2], thisVal, constant);     //Q^k
		}


		if(isPrime)     // additional checks for composite numbers
		{
			// If n is prime and gcd(n, Q) == 1, then
			// Q^((n+1)/2) = Q * Q^((n-1)/2) is congruent to (Q * J(Q, n)) mod n

			BigInteger g = thisVal.gcd(Q);
			if(g.dataLength == 1 && g.data[0] == 1)         // gcd(this, Q) == 1
			{
				if((lucas[2].data[maxLength-1] & 0x80000000) != 0)
					lucas[2] += thisVal;

				BigInteger temp = (Q * BigInteger.Jacobi(Q, thisVal)) % thisVal;
				if((temp.data[maxLength-1] & 0x80000000) != 0)
					temp += thisVal;

				if(lucas[2] != temp)
					isPrime = false;
			}
		}

		return isPrime;
	}