public void BarrettReduction (BigInteger x)
{
BigInteger n = mod;
uint k = n.length,
kPlusOne = k+1,
kMinusOne = k-1;
// x < mod, so nothing to do.
if (x.length < k) return;
BigInteger q3;
//
// Validate pointers
//
if (x.data.Length < x.length) throw new IndexOutOfRangeException ("x out of range");
// q1 = x / b^ (k-1)
// q2 = q1 * constant
// q3 = q2 / b^ (k+1), Needs to be accessed with an offset of kPlusOne
// TODO: We should the method in HAC p 604 to do this (14.45)
q3 = new BigInteger (Sign.Positive, x.length - kMinusOne + constant.length);
Kernel.Multiply (x.data, kMinusOne, x.length - kMinusOne, constant.data, 0, constant.length, q3.data, 0);
// r1 = x mod b^ (k+1)
// i.e. keep the lowest (k+1) words
uint lengthToCopy = (x.length > kPlusOne) ? kPlusOne : x.length;
x.length = lengthToCopy;
x.Normalize ();
// r2 = (q3 * n) mod b^ (k+1)
// partial multiplication of q3 and n
BigInteger r2 = new BigInteger (Sign.Positive, kPlusOne);
Kernel.MultiplyMod2p32pmod (q3.data, (int)kPlusOne, (int)q3.length - (int)kPlusOne, n.data, 0, (int)n.length, r2.data, 0, (int)kPlusOne);
r2.Normalize ();
if (r2 < x) {
Kernel.MinusEq (x, r2);
} else {
BigInteger val = new BigInteger (Sign.Positive, kPlusOne + 1);
val.data [kPlusOne] = 0x00000001;
Kernel.MinusEq (val, r2);
Kernel.PlusEq (x, val);
}
while (x >= n)
Kernel.MinusEq (x, n);
}