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