//*********************************************************************** // 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; }
//*********************************************************************** // Modulo Exponentiation //*********************************************************************** public BigInteger modPow(BigInteger exp, BigInteger n) { if ((exp.data[maxLength - 1] & 0x80000000) != 0) throw (new ArithmeticException("Positive exponents only.")); BigInteger resultNum = 1; BigInteger tempNum; bool thisNegative = false; if ((this.data[maxLength - 1] & 0x80000000) != 0) { // negative this tempNum = -this % n; thisNegative = true; } else tempNum = this % n; // ensures (tempNum * tempNum) < b^(2k) if ((n.data[maxLength - 1] & 0x80000000) != 0) // negative n n = -n; // calculate constant = b^(2k) / m BigInteger constant = new BigInteger(); int i = n.dataLength << 1; constant.data[i] = 0x00000001; constant.dataLength = i + 1; constant = constant / n; int totalBits = exp.bitCount(); int count = 0; // perform squaring and multiply exponentiation for (int pos = 0; pos < exp.dataLength; pos++) { uint mask = 0x01; //Console.WriteLine("pos = " + pos); for (int index = 0; index < 32; index++) { if ((exp.data[pos] & mask) != 0) resultNum = BarrettReduction(resultNum * tempNum, n, constant); mask <<= 1; tempNum = BarrettReduction(tempNum * tempNum, n, constant); if (tempNum.dataLength == 1 && tempNum.data[0] == 1) { if (thisNegative && (exp.data[0] & 0x1) != 0) //odd exp return -resultNum; return resultNum; } count++; if (count == totalBits) break; } } if (thisNegative && (exp.data[0] & 0x1) != 0) //odd exp return -resultNum; return resultNum; }