private BigInteger OddPow(BigInteger b, BigInteger exp)
			{
				BigInteger resultNum = new BigInteger(Montgomery.ToMont(1, mod), mod.length << 1);
				BigInteger tempNum = new BigInteger(Montgomery.ToMont(b, mod), mod.length << 1);  // ensures (tempNum * tempNum) < b^ (2k)
				uint mPrime = Montgomery.Inverse(mod.data[0]);
				uint totalBits = (uint)exp.BitCount();

				uint[] wkspace = new uint[mod.length << 1];

				// perform squaring and multiply exponentiation
				for (uint pos = 0; pos < totalBits; pos++)
				{
					if (exp.TestBit(pos))
					{

						Array.Clear(wkspace, 0, wkspace.Length);
						Kernel.Multiply(resultNum.data, 0, resultNum.length, tempNum.data, 0, tempNum.length, wkspace, 0);
						resultNum.length += tempNum.length;
						uint[] t = wkspace;
						wkspace = resultNum.data;
						resultNum.data = t;

						Montgomery.Reduce(resultNum, mod, mPrime);
					}

					Kernel.SquarePositive(tempNum, ref wkspace);
					Montgomery.Reduce(tempNum, mod, mPrime);
				}

				Montgomery.Reduce(resultNum, mod, mPrime);
				return resultNum;
			}
			private unsafe BigInteger EvenPow(uint b, BigInteger exp)
			{
				exp.Normalize();
				uint[] wkspace = new uint[mod.length << 1 + 1];
				BigInteger resultNum = new BigInteger((BigInteger)b, mod.length << 1 + 1);

				uint pos = (uint)exp.BitCount() - 2;

				//
				// We know that the first itr will make the val b
				//

				do
				{
					//
					// r = r ^ 2 % m
					//
					Kernel.SquarePositive(resultNum, ref wkspace);
					if (!(resultNum.length < mod.length))
						BarrettReduction(resultNum);

					if (exp.TestBit(pos))
					{

						//
						// r = r * b % m
						//

						// TODO: Is Unsafe really speeding things up?
						fixed (uint* u = resultNum.data)
						{

							uint i = 0;
							ulong mc = 0;

							do
							{
								mc += (ulong)u[i] * (ulong)b;
								u[i] = (uint)mc;
								mc >>= 32;
							} while (++i < resultNum.length);

							if (resultNum.length < mod.length)
							{
								if (mc != 0)
								{
									u[i] = (uint)mc;
									resultNum.length++;
									while (resultNum >= mod)
										Kernel.MinusEq(resultNum, mod);
								}
							}
							else if (mc != 0)
							{

								//
								// First, we estimate the quotient by dividing
								// the first part of each of the numbers. Then
								// we correct this, if necessary, with a subtraction.
								//

								uint cc = (uint)mc;

								// We would rather have this estimate overshoot,
								// so we add one to the divisor
								uint divEstimate = (uint)((((ulong)cc << 32) | (ulong)u[i - 1]) /
									(mod.data[mod.length - 1] + 1));

								uint t;

								i = 0;
								mc = 0;
								do
								{
									mc += (ulong)mod.data[i] * (ulong)divEstimate;
									t = u[i];
									u[i] -= (uint)mc;
									mc >>= 32;
									if (u[i] > t) mc++;
									i++;
								} while (i < resultNum.length);
								cc -= (uint)mc;

								if (cc != 0)
								{

									uint sc = 0, j = 0;
									uint[] s = mod.data;
									do
									{
										uint a = s[j];
										if (((a += sc) < sc) | ((u[j] -= a) > ~a)) sc = 1;
										else sc = 0;
										j++;
									} while (j < resultNum.length);
									cc -= sc;
								}
								while (resultNum >= mod)
									Kernel.MinusEq(resultNum, mod);
							}
							else
							{
								while (resultNum >= mod)
									Kernel.MinusEq(resultNum, mod);
							}
						}
					}
				} while (pos-- > 0);

				return resultNum;
			}
			public BigInteger EvenPow(BigInteger b, BigInteger exp)
			{
				BigInteger resultNum = new BigInteger((BigInteger)1, mod.length << 1);
				BigInteger tempNum = new BigInteger(b % mod, mod.length << 1);  // ensures (tempNum * tempNum) < b^ (2k)

				uint totalBits = (uint)exp.BitCount();

				uint[] wkspace = new uint[mod.length << 1];

				// perform squaring and multiply exponentiation
				for (uint pos = 0; pos < totalBits; pos++)
				{
					if (exp.TestBit(pos))
					{

						Array.Clear(wkspace, 0, wkspace.Length);
						Kernel.Multiply(resultNum.data, 0, resultNum.length, tempNum.data, 0, tempNum.length, wkspace, 0);
						resultNum.length += tempNum.length;
						uint[] t = wkspace;
						wkspace = resultNum.data;
						resultNum.data = t;

						BarrettReduction(resultNum);
					}

					Kernel.SquarePositive(tempNum, ref wkspace);
					BarrettReduction(tempNum);

					if (tempNum == 1)
					{
						return resultNum;
					}
				}

				return resultNum;
			}