private static void MonReduction(int[] Result, BigInteger Modulus, int N2) { // res + m*modulus_digits int[] modulus_digits = Modulus._digits; int modulusLen = Modulus._numberLength; long outerCarry = 0; for (int i = 0; i < modulusLen; i++) { long innnerCarry = 0; int m = (int)Multiplication.UnsignedMultAddAdd(Result[i], N2, 0, 0); for (int j = 0; j < modulusLen; j++) { innnerCarry = Multiplication.UnsignedMultAddAdd(m, modulus_digits[j], Result[i + j], (int)innnerCarry); Result[i + j] = (int)innnerCarry; innnerCarry = IntUtils.URShift(innnerCarry, 32); } outerCarry += (Result[i + modulusLen] & 0xFFFFFFFFL) + innnerCarry; Result[i + modulusLen] = (int)outerCarry; outerCarry = IntUtils.URShift(outerCarry, 32); } Result[modulusLen << 1] = (int)outerCarry; // res / r for (int j = 0; j < modulusLen + 1; j++) { Result[j] = Result[j + modulusLen]; } }
private static long DivideLongByBillion(long N) { long quot; long rem; if (N >= 0) { long bLong = 1000000000L; quot = (N / bLong); rem = (N % bLong); } else { /* * Make the dividend positive shifting it right by 1 bit then get * the quotient an remainder and correct them properly */ long aPos = IntUtils.URShift(N, 1); long bPos = IntUtils.URShift(1000000000L, 1); quot = aPos / bPos; rem = aPos % bPos; // double the remainder and add 1 if 'a' is odd rem = (rem << 1) + (N & 1); } return((rem << 32) | (quot & 0xFFFFFFFFL)); }
/// <summary> /// Returns a new BigInteger whose value is <c>this >> N</c> /// <para>For negative arguments, the result is also negative. /// The shift distance may be negative which means that this is shifted left. /// </para> /// </summary> /// /// <param name="Result">The result</param> /// <param name="ResultLen">The result length</param> /// <param name="Value">The source BigIntger</param> /// <param name="IntCount">The number integers</param> /// <param name="N">Shift distance</param> /// /// <returns>this >> N, if N >= 0; this << (-n) otherwise</returns> internal static bool ShiftRight(int[] Result, int ResultLen, int[] Value, int IntCount, int N) { int i; bool allZero = true; for (i = 0; i < IntCount; i++) { allZero &= Value[i] == 0; } if (N == 0) { Array.Copy(Value, IntCount, Result, 0, ResultLen); i = ResultLen; } else { int leftShiftCount = 32 - N; allZero &= (Value[i] << leftShiftCount) == 0; for (i = 0; i < ResultLen - 1; i++) { Result[i] = IntUtils.URShift(Value[i + IntCount], N) | (Value[i + IntCount + 1] << leftShiftCount); } Result[i] = IntUtils.URShift(Value[i + IntCount], N); i++; } return(allZero); }
private static int[] Square(int[] X, int XLen, int[] Result) { long carry; for (int i = 0; i < XLen; i++) { carry = 0; for (int j = i + 1; j < XLen; j++) { carry = UnsignedMultAddAdd(X[i], X[j], Result[i + j], (int)carry); Result[i + j] = (int)carry; carry = IntUtils.URShift(carry, 32); } Result[i + XLen] = (int)carry; } BitLevel.ShiftLeftOneBit(Result, Result, XLen << 1); carry = 0; for (int i = 0, index = 0; i < XLen; i++, index++) { carry = UnsignedMultAddAdd(X[i], X[i], Result[index], (int)carry); Result[index] = (int)carry; carry = IntUtils.URShift(carry, 32); index++; carry += Result[index] & 0xFFFFFFFFL; Result[index] = (int)carry; carry = IntUtils.URShift(carry, 32); } return(Result); }
/// <summary> /// Performs the same as GcdBinary(BigInteger, BigInteger)}, but with numbers of 63 bits, /// represented in positives values of long type. /// </summary> /// /// <param name="X">A positive number</param> /// <param name="Y">A positive number></param> /// /// <returns>Returns <c>Gcd(X, Y)</c></returns> internal static long GcdBinary(long X, long Y) { // (op1 > 0) and (op2 > 0) int lsb1 = IntUtils.NumberOfTrailingZeros(X); int lsb2 = IntUtils.NumberOfTrailingZeros(Y); int pow2Count = System.Math.Min(lsb1, lsb2); if (lsb1 != 0) { X = IntUtils.URShift(X, lsb1); } if (lsb2 != 0) { Y = IntUtils.URShift(Y, lsb2); } do { if (X >= Y) { X -= Y; X = IntUtils.URShift(X, IntUtils.NumberOfTrailingZeros(X)); } else { Y -= X; Y = IntUtils.URShift(Y, IntUtils.NumberOfTrailingZeros(Y)); } } while (X != 0); return(Y << pow2Count); }
/// <summary> /// A random number is generated until a probable prime number is found /// </summary> internal static BigInteger ConsBigInteger(int BitLength, int Certainty, SecureRandom Rnd) { // PRE: bitLength >= 2; // For small numbers get a random prime from the prime table if (BitLength <= 10) { int[] rp = _offsetPrimes[BitLength]; return(_biPrimes[rp[0] + Rnd.NextInt32(rp[1])]); } int shiftCount = (-BitLength) & 31; int last = (BitLength + 31) >> 5; BigInteger n = new BigInteger(1, last, new int[last]); last--; do {// To fill the array with random integers for (int i = 0; i < n._numberLength; i++) { n._digits[i] = Rnd.Next(); } // To fix to the correct bitLength // n.digits[last] |= 0x80000000; n._digits[last] |= Int32.MinValue; n._digits[last] = IntUtils.URShift(n._digits[last], shiftCount); // To create an odd number n._digits[0] |= 1; } while (!IsProbablePrime(n, Certainty)); return(n); }
private static BigInteger MultiplyPAP(BigInteger X, BigInteger Y) { // Multiplies two BigIntegers. Implements traditional scholar algorithm described by Knuth. // PRE: a >= b int aLen = X._numberLength; int bLen = Y._numberLength; int resLength = aLen + bLen; int resSign = (X._sign != Y._sign) ? -1 : 1; // A special case when both numbers don't exceed int if (resLength == 2) { long val = UnsignedMultAddAdd(X._digits[0], Y._digits[0], 0, 0); int valueLo = (int)val; int valueHi = (int)IntUtils.URShift(val, 32); return((valueHi == 0) ? new BigInteger(resSign, valueLo) : new BigInteger(resSign, 2, new int[] { valueLo, valueHi })); } int[] aDigits = X._digits; int[] bDigits = Y._digits; int[] resDigits = new int[resLength]; // Common case MultiplyArraysPAP(aDigits, aLen, bDigits, bLen, resDigits); BigInteger result = new BigInteger(resSign, resLength, resDigits); result.CutOffLeadingZeroes(); return(result); }
/// <summary> /// Multiplies a number by a positive integer. /// </summary> /// /// <param name="X">An arbitrary BigInteger</param> /// <param name="Factor">A positive int number</param> /// /// <returns>X * Factor</returns> internal static BigInteger MultiplyByPositiveInt(BigInteger X, int Factor) { int resSign = X._sign; if (resSign == 0) { return(BigInteger.Zero); } int aNumberLength = X._numberLength; int[] aDigits = X._digits; if (aNumberLength == 1) { long res = UnsignedMultAddAdd(aDigits[0], Factor, 0, 0); int resLo = (int)res; int resHi = (int)IntUtils.URShift(res, 32); return((resHi == 0) ? new BigInteger(resSign, resLo) : new BigInteger(resSign, 2, new int[] { resLo, resHi })); } // Common case int resLength = aNumberLength + 1; int[] resDigits = new int[resLength]; resDigits[aNumberLength] = MultiplyByInt(resDigits, aDigits, aNumberLength, Factor); BigInteger result = new BigInteger(resSign, resLength, resDigits); result.CutOffLeadingZeroes(); return(result); }
/// <summary> /// Divides an array by an integer value. Implements the Knuth's division algorithm. /// <para>See D. Knuth, The Art of Computer Programming, vol. 2.</para> /// </summary> /// /// <param name="Destination">The quotient</param> /// <param name="Source">The dividend</param> /// <param name="SourceLength">The length of the dividend</param> /// <param name="Divisor">The divisor</param> /// /// <returns>Returns the remainder</returns> internal static int DivideArrayByInt(int[] Destination, int[] Source, int SourceLength, int Divisor) { long rem = 0; long bLong = Divisor & 0xffffffffL; for (int i = SourceLength - 1; i >= 0; i--) { long temp = (rem << 32) | (Source[i] & 0xffffffffL); long quot; if (temp >= 0) { quot = (temp / bLong); rem = (temp % bLong); } else { // make the dividend positive shifting it right by 1 bit then // get the quotient an remainder and correct them properly long aPos = IntUtils.URShift(temp, 1); long bPos = IntUtils.URShift(Divisor, 1); quot = aPos / bPos; rem = aPos % bPos; // double the remainder and add 1 if a is odd rem = (rem << 1) + (temp & 1); if ((Divisor & 1) != 0) { // the divisor is odd if (quot <= rem) { rem -= quot; } else { if (quot - rem <= bLong) { rem += bLong - quot; quot -= 1; } else { rem += (bLong << 1) - quot; quot -= 2; } } } } Destination[i] = (int)(quot & 0xffffffffL); } return((int)rem); }
private static int MultiplyByInt(int[] Result, int[] X, int Size, int Factor) { // Multiplies an array of integers by an integer value and saves the result in Res long carry = 0; for (int i = 0; i < Size; i++) { carry = UnsignedMultAddAdd(X[i], Factor, (int)carry, 0); Result[i] = (int)carry; carry = IntUtils.URShift(carry, 32); } return((int)carry); }
private static long DivideLongByInt(long X, int Y) { // divides an unsigned long X by an unsigned int Y // long quot; long rem; long bLong = Y & 0xffffffffL; if (X >= 0) { quot = (X / bLong); rem = (X % bLong); } else { /* * Make the dividend positive shifting it right by 1 bit then get * the quotient an remainder and correct them properly */ long aPos = IntUtils.URShift(X, 1); long bPos = IntUtils.URShift(Y, 1); quot = aPos / bPos; rem = aPos % bPos; // double the remainder and add 1 if a is odd rem = (rem << 1) + (X & 1); if ((Y & 1) != 0) { // the divisor is odd if (quot <= rem) { rem -= quot; } else { if (quot - rem <= bLong) { rem += bLong - quot; quot -= 1; } else { rem += (bLong << 1) - quot; quot -= 2; } } } } return((rem << 32) | (quot & 0xffffffffL)); }
/// <summary> /// Performs <c>X = X Mod (2<sup>N</sup>)</c> /// </summary> /// <param name="X">A positive number, it will store the result</param> /// <param name="N">A positive exponent of 2</param> internal static void InplaceModPow2(BigInteger X, int N) { // PRE: (x > 0) and (n >= 0) int fd = N >> 5; int leadingZeros; if ((X._numberLength < fd) || (X.BitLength <= N)) { return; } leadingZeros = 32 - (N & 31); X._numberLength = fd + 1; X._digits[fd] &= (leadingZeros < 32) ? (IntUtils.URShift(-1, leadingZeros)) : 0; X.CutOffLeadingZeroes(); }
/// <summary> /// Shifts the source digits left one bit, creating a value whose magnitude is doubled. /// </summary> /// /// <param name="Result">The result</param> /// <param name="Value">The source BigIntger</param> /// <param name="ValueLen">The value length</param> internal static void ShiftLeftOneBit(int[] Result, int[] Value, int ValueLen) { int carry = 0; for (int i = 0; i < ValueLen; i++) { int val = Value[i]; Result[i] = (val << 1) | carry; carry = IntUtils.URShift(val, 31); } if (carry != 0) { Result[ValueLen] = carry; } }
/// <summary> /// Multiplies an array by int and subtracts it from a subarray of another array /// </summary> /// /// <param name="X">The array to subtract from</param> /// <param name="Start">The start element of the subarray of X</param> /// <param name="Y">The array to be multiplied and subtracted</param> /// <param name="YLength">The length of Y</param> /// <param name="Multiplier">The multiplier of Y</param> /// /// <returns>Returns the carry element of subtraction</returns> internal static int MultiplyAndSubtract(int[] X, int Start, int[] Y, int YLength, int Multiplier) { long carry0 = 0; long carry1 = 0; for (int i = 0; i < YLength; i++) { carry0 = Multiplication.UnsignedMultAddAdd(Y[i], Multiplier, (int)carry0, 0); carry1 = (X[Start + i] & 0xffffffffL) - (carry0 & 0xffffffffL) + carry1; X[Start + i] = (int)carry1; carry1 >>= 32; // -1 or 0 carry0 = IntUtils.URShift(carry0, 32); } carry1 = (X[Start + YLength] & 0xffffffffL) - carry0 + carry1; X[Start + YLength] = (int)carry1; return((int)(carry1 >> 32)); // -1 or 0 }
private static void MultPAP(int[] X, int[] Y, int[] T, int ALen, int BLen) { if (X == Y && ALen == BLen) { Square(X, ALen, T); return; } for (int i = 0; i < ALen; i++) { long carry = 0; int aI = X[i]; for (int j = 0; j < BLen; j++) { carry = UnsignedMultAddAdd(aI, Y[j], T[i + j], (int)carry); T[i + j] = (int)carry; carry = IntUtils.URShift(carry, 32); } T[i + BLen] = (int)carry; } }
/// <summary> /// Abstractly shifts left an array of integers in little endian (i.e. shift it right). /// Total shift distance in bits is intCount * 32 + count /// </summary> /// /// <param name="Result">The result</param> /// <param name="Value">The source BigIntger</param> /// <param name="IntCount">The number integers</param> /// <param name="N">The number of bits to shift</param> internal static void ShiftLeft(int[] Result, int[] Value, int IntCount, int N) { if (N == 0) { Array.Copy(Value, 0, Result, IntCount, Result.Length - IntCount); } else { int rightShiftCount = 32 - N; Result[Result.Length - 1] = 0; for (int i = Result.Length - 1; i > IntCount; i--) { Result[i] |= IntUtils.URShift(Value[i - IntCount - 1], rightShiftCount); Result[i - 1] = Value[i - IntCount - 1] << N; } } for (int i = 0; i < IntCount; i++) { Result[i] = 0; } }
/// <summary> /// See BigInteger#add(BigInteger) /// </summary> internal static BigInteger Add(BigInteger A, BigInteger B) { int[] resDigits; int resSign; int op1Sign = A._sign; int op2Sign = B._sign; if (op1Sign == 0) { return(B); } if (op2Sign == 0) { return(A); } int op1Len = A._numberLength; int op2Len = B._numberLength; if (op1Len + op2Len == 2) { long a = (A._digits[0] & 0xFFFFFFFFL); long b = (B._digits[0] & 0xFFFFFFFFL); long res; int valueLo; int valueHi; if (op1Sign == op2Sign) { res = a + b; valueLo = (int)res; valueHi = (int)IntUtils.URShift(res, 32); return((valueHi == 0) ? new BigInteger(op1Sign, valueLo) : new BigInteger(op1Sign, 2, new int[] { valueLo, valueHi })); } return(BigInteger.ValueOf((op1Sign < 0) ? (b - a) : (a - b))); } else if (op1Sign == op2Sign) { resSign = op1Sign; // an augend should not be shorter than addend resDigits = (op1Len >= op2Len) ? Add(A._digits, op1Len, B._digits, op2Len) : Add(B._digits, op2Len, A._digits, op1Len); } else { // signs are different int cmp = ((op1Len != op2Len) ? ((op1Len > op2Len) ? 1 : -1) : CompareArrays(A._digits, B._digits, op1Len)); if (cmp == BigInteger.EQUALS) { return(BigInteger.Zero); } // a minuend should not be shorter than subtrahend if (cmp == BigInteger.GREATER) { resSign = op1Sign; resDigits = Subtract(A._digits, op1Len, B._digits, op2Len); } else { resSign = op2Sign; resDigits = Subtract(B._digits, op2Len, A._digits, op1Len); } } BigInteger result = new BigInteger(resSign, resDigits.Length, resDigits); result.CutOffLeadingZeroes(); return(result); }
/// <summary> /// Divides the array 'a' by the array 'b' and gets the quotient and the remainder. /// <para>Implements the Knuth's division algorithm. See D. Knuth, The Art of Computer Programming, /// vol. 2. Steps D1-D8 correspond the steps in the algorithm description.</para> /// </summary> /// /// <param name="Quotient">The quotient</param> /// <param name="QuotientLen">The quotient's length</param> /// <param name="X">The dividend</param> /// <param name="XLen">The dividend's length</param> /// <param name="Y">The divisor</param> /// <param name="YLength">The divisor's length</param> /// /// <returns>eturn the remainder</returns> internal static int[] Divide(int[] Quotient, int QuotientLen, int[] X, int XLen, int[] Y, int YLength) { int[] normA = new int[XLen + 1]; // the normalized dividend // an extra byte is needed for correct shift int[] normB = new int[YLength + 1]; // the normalized divisor; int normBLength = YLength; // Step D1: normalize a and b and put the results to a1 and b1 the // normalized divisor's first digit must be >= 2^31 int divisorShift = IntUtils.NumberOfLeadingZeros(Y[YLength - 1]); if (divisorShift != 0) { BitLevel.ShiftLeft(normB, Y, 0, divisorShift); BitLevel.ShiftLeft(normA, X, 0, divisorShift); } else { Array.Copy(X, 0, normA, 0, XLen); Array.Copy(Y, 0, normB, 0, YLength); } int firstDivisorDigit = normB[normBLength - 1]; // Step D2: set the quotient index int i = QuotientLen - 1; int j = XLen; while (i >= 0) { // Step D3: calculate a guess digit guessDigit int guessDigit = 0; if (normA[j] == firstDivisorDigit) { // set guessDigit to the largest unsigned int value guessDigit = -1; } else { long product = (((normA[j] & 0xffffffffL) << 32) + (normA[j - 1] & 0xffffffffL)); long res = Division.DivideLongByInt(product, firstDivisorDigit); guessDigit = (int)res; // the quotient of divideLongByInt int rem = (int)(res >> 32); // the remainder of // divideLongByInt // decrease guessDigit by 1 while leftHand > rightHand if (guessDigit != 0) { long leftHand = 0; long rightHand = 0; bool rOverflowed = false; guessDigit++; // to have the proper value in the loop // below do { guessDigit--; if (rOverflowed) { break; } // leftHand always fits in an unsigned long leftHand = (guessDigit & 0xffffffffL) * (normB[normBLength - 2] & 0xffffffffL); // rightHand can overflow; in this case the loop // condition will be true in the next step of the loop rightHand = ((long)rem << 32) + (normA[j - 2] & 0xffffffffL); long longR = (rem & 0xffffffffL) + (firstDivisorDigit & 0xffffffffL); // checks that longR does not fit in an unsigned int; // this ensures that rightHand will overflow unsigned long in the next step if (IntUtils.NumberOfLeadingZeros((int)IntUtils.URShift(longR, 32)) < 32) { rOverflowed = true; } else { rem = (int)longR; } } while ((leftHand ^ Int64.MinValue) > (rightHand ^ Int64.MinValue)); } } // Step D4: multiply normB by guessDigit and subtract the production from normA. if (guessDigit != 0) { int borrow = Division.MultiplyAndSubtract(normA, j - normBLength, normB, normBLength, guessDigit); // Step D5: check the borrow if (borrow != 0) { // Step D6: compensating addition guessDigit--; long carry = 0; for (int k = 0; k < normBLength; k++) { carry += (normA[j - normBLength + k] & 0xffffffffL) + (normB[k] & 0xffffffffL); normA[j - normBLength + k] = (int)carry; carry = IntUtils.URShift(carry, 32); } } } if (Quotient != null) { Quotient[i] = guessDigit; } // Step D7 j--; i--; } // Step D8: we got the remainder in normA. Denormalize it as needed if (divisorShift != 0) { // reuse normB BitLevel.ShiftRight(normB, normBLength, normA, 0, divisorShift); return(normB); } Array.Copy(normA, 0, normB, 0, YLength); return(normA); }