コード例 #1
0
        private static BigInteger Pow2ModPow(BigInteger X, BigInteger Y, int N)
        {
            // PRE: (base > 0), (exponent > 0) and (j > 0)
            BigInteger res         = BigInteger.One;
            BigInteger e           = Y.Copy();
            BigInteger baseMod2toN = X.Copy();
            BigInteger res2;

            // If 'base' is odd then it's coprime with 2^j and phi(2^j) = 2^(j-1);
            // so we can reduce reduce the exponent (mod 2^(j-1)).
            if (X.TestBit(0))
            {
                InplaceModPow2(e, N - 1);
            }

            InplaceModPow2(baseMod2toN, N);

            for (int i = e.BitLength - 1; i >= 0; i--)
            {
                res2 = res.Copy();
                InplaceModPow2(res2, N);
                res = res.Multiply(res2);
                if (BitLevel.TestBit(e, i))
                {
                    res = res.Multiply(baseMod2toN);
                    InplaceModPow2(res, N);
                }
            }
            InplaceModPow2(res, N);

            return(res);
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        private static BigInteger SlidingWindow(BigInteger X2, BigInteger A2, BigInteger Exponent, BigInteger Modulus, int N2)
        {
            // Implements the Montgomery modular exponentiation based in The sliding windows algorithm and the Mongomery Reduction
            // ar.org.fitc.ref "A. Menezes,P. van Oorschot, S. Vanstone - Handbook of Applied Cryptography"
            BigInteger[] pows = new BigInteger[8];
            BigInteger   res  = X2;
            int          lowexp;
            BigInteger   x3;
            int          acc3;

            // fill odd low pows of a2
            pows[0] = A2;
            x3      = MonPro(A2, A2, Modulus, N2);

            for (int i = 1; i <= 7; i++)
            {
                pows[i] = MonPro(pows[i - 1], x3, Modulus, N2);
            }

            for (int i = Exponent.BitLength - 1; i >= 0; i--)
            {
                if (BitLevel.TestBit(Exponent, i))
                {
                    lowexp = 1;
                    acc3   = i;

                    for (int j = System.Math.Max(i - 3, 0); j <= i - 1; j++)
                    {
                        if (BitLevel.TestBit(Exponent, j))
                        {
                            if (j < acc3)
                            {
                                acc3   = j;
                                lowexp = (lowexp << (i - j)) ^ 1;
                            }
                            else
                            {
                                lowexp = lowexp ^ (1 << (j - acc3));
                            }
                        }
                    }

                    for (int j = acc3; j <= i; j++)
                    {
                        res = MonPro(res, res, Modulus, N2);
                    }

                    res = MonPro(pows[(lowexp - 1) >> 1], res, Modulus, N2);
                    i   = acc3;
                }
                else
                {
                    res = MonPro(res, res, Modulus, N2);
                }
            }

            return(res);
        }
コード例 #4
0
        /// <summary>
        /// Return the greatest common divisor of X and Y
        /// </summary>
        ///
        /// <param name="X">Operand 1, must be greater than zero</param>
        /// <param name="Y">Operand 2, must be greater than zero</param>
        ///
        /// <returns>Returns <c>GCD(X, Y)</c></returns>
        internal static BigInteger GcdBinary(BigInteger X, BigInteger Y)
        {
            // Divide both number the maximal possible times by 2 without rounding * gcd(2*a, 2*b) = 2 * gcd(a,b)
            int lsb1      = X.LowestSetBit;
            int lsb2      = Y.LowestSetBit;
            int pow2Count = System.Math.Min(lsb1, lsb2);

            BitLevel.InplaceShiftRight(X, lsb1);
            BitLevel.InplaceShiftRight(Y, lsb2);
            BigInteger swap;

            // I want op2 > op1
            if (X.CompareTo(Y) == BigInteger.GREATER)
            {
                swap = X;
                X    = Y;
                Y    = swap;
            }

            do
            { // INV: op2 >= op1 && both are odd unless op1 = 0
                // Optimization for small operands (op2.bitLength() < 64) implies by INV (op1.bitLength() < 64)
                if ((Y.m_numberLength == 1) || ((Y.m_numberLength == 2) && (Y.m_digits[1] > 0)))
                {
                    Y = BigInteger.ValueOf(Division.GcdBinary(X.ToInt64(), Y.ToInt64()));
                    break;
                }

                // Implements one step of the Euclidean algorithm
                // To reduce one operand if it's much smaller than the other one
                if (Y.m_numberLength > X.m_numberLength * 1.2)
                {
                    Y = Y.Remainder(X);

                    if (Y.Signum() != 0)
                    {
                        BitLevel.InplaceShiftRight(Y, Y.LowestSetBit);
                    }
                }
                else
                {
                    // Use Knuth's algorithm of successive subtract and shifting
                    do
                    {
                        Elementary.InplaceSubtract(Y, X);              // both are odd
                        BitLevel.InplaceShiftRight(Y, Y.LowestSetBit); // op2 is even
                    } while (Y.CompareTo(X) >= BigInteger.EQUALS);
                }
                // now op1 >= op2
                swap = Y;
                Y    = X;
                X    = swap;
            } while (X.m_sign != 0);

            return(Y.ShiftLeft(pow2Count));
        }
コード例 #5
0
        /// <summary>
        /// Returns this BigInteger as an double value.
        /// <para>If this is too big to be represented as an double, then Double.POSITIVE_INFINITY or
        /// Double.NEGATIVE_INFINITY} is returned.</para>
        /// </summary>
        ///
        /// <param name="Value">The value to convert</param>
        ///
        /// <returns>Returns a BigInteger as a double value</returns>
        ///
        /// <remarks>
        /// Note, that not all integers x in the range [-Double.MAX_VALUE, Double.MAX_VALUE] can be represented as a double.
        /// The double representation has a mantissa of length 53. For example, 2^53+1 = 9007199254740993 is returned as double 9007199254740992.0.
        /// </remarks>
        internal static double BigInteger2Double(BigInteger Value)
        {
            // val.bitLength() < 64
            if ((Value._numberLength < 2) || ((Value._numberLength == 2) && (Value._digits[1] > 0)))
            {
                return(Value.ToInt64());
            }

            // val.bitLength() >= 33 * 32 > 1024
            if (Value._numberLength > 32)
            {
                return((Value._sign > 0) ? Double.PositiveInfinity : Double.NegativeInfinity);
            }

            int  bitLen   = Value.Abs().BitLength;
            long exponent = bitLen - 1;
            int  delta    = bitLen - 54;
            // We need 54 top bits from this, the 53th bit is always 1 in lVal.
            long lVal = Value.Abs().ShiftRight(delta).ToInt64();

            // Take 53 bits from lVal to mantissa. The least significant bit is needed for rounding.
            long mantissa = lVal & 0x1FFFFFFFFFFFFFL;

            if (exponent == 1023)
            {
                if (mantissa == 0X1FFFFFFFFFFFFFL)
                {
                    return((Value._sign > 0) ? Double.PositiveInfinity : Double.NegativeInfinity);
                }

                if (mantissa == 0x1FFFFFFFFFFFFEL)
                {
                    return((Value._sign > 0) ? Double.MaxValue : -Double.MaxValue);
                }
            }
            // Round the mantissa
            if (((mantissa & 1) == 1) && (((mantissa & 2) == 2) || BitLevel.NonZeroDroppedBits(delta, Value._digits)))
            {
                mantissa += 2;
            }

            mantissa >>= 1; // drop the rounding bit
            // long resSign = (val.sign < 0) ? 0x8000000000000000L : 0;
            long resSign = (Value._sign < 0) ? Int64.MinValue : 0;

            exponent = ((1023 + exponent) << 52) & 0x7FF0000000000000L;
            long result = resSign | exponent | mantissa;

            return(BitConverter.Int64BitsToDouble(result));
        }
コード例 #6
0
        private static BigInteger SquareAndMultiply(BigInteger X2, BigInteger A2, BigInteger Exponent, BigInteger Modulus, int N2)
        {
            BigInteger res = X2;

            for (int i = Exponent.BitLength - 1; i >= 0; i--)
            {
                res = MonPro(res, res, Modulus, N2);

                if (BitLevel.TestBit(Exponent, i))
                {
                    res = MonPro(res, A2, Modulus, N2);
                }
            }

            return(res);
        }
コード例 #7
0
        private static BigInteger ModPow2Inverse(BigInteger X, int N)
        {
            // PRE: (x > 0), (x is odd), and (n > 0)
            BigInteger y = new BigInteger(1, new int[1 << N]);

            y.m_numberLength = 1;
            y.m_digits[0]    = 1;
            y.m_sign         = 1;

            for (int i = 1; i < N; i++)
            {
                if (BitLevel.TestBit(X.Multiply(y), i))
                {
                    // Adding 2^i to y (setting the i-th bit)
                    y.m_digits[i >> 5] |= (1 << (i & 31));
                }
            }
            return(y);
        }
コード例 #8
0
        private static BigInteger ModInverseLorencz(BigInteger X, BigInteger Modulo)
        {
            // Based on "New Algorithm for Classical Modular Inverse" Róbert Lórencz. LNCS 2523 (2002)
            // PRE: a is coprime with modulo, a < modulo
            int max = System.Math.Max(X.m_numberLength, Modulo.m_numberLength);

            int[] uDigits = new int[max + 1]; // enough place to make all the inplace operation
            int[] vDigits = new int[max + 1];
            Array.Copy(Modulo.m_digits, 0, uDigits, 0, Modulo.m_numberLength);
            Array.Copy(X.m_digits, 0, vDigits, 0, X.m_numberLength);

            BigInteger u = new BigInteger(Modulo.m_sign, Modulo.m_numberLength, uDigits);
            BigInteger v = new BigInteger(X.m_sign, X.m_numberLength, vDigits);
            BigInteger r = new BigInteger(0, 1, new int[max + 1]); // BigInteger.ZERO;
            BigInteger s = new BigInteger(1, 1, new int[max + 1]);

            s.m_digits[0] = 1;
            // r == 0 && s == 1, but with enough place

            int coefU = 0, coefV = 0;
            int n = Modulo.BitLength;
            int k;

            while (!IsPowerOfTwo(u, coefU) && !IsPowerOfTwo(v, coefV))
            {
                // modification of original algorithm: I calculate how many times the algorithm will enter in the same branch of if
                k = HowManyIterations(u, n);
                if (k != 0)
                {
                    BitLevel.InplaceShiftLeft(u, k);
                    if (coefU >= coefV)
                    {
                        BitLevel.InplaceShiftLeft(r, k);
                    }
                    else
                    {
                        BitLevel.InplaceShiftRight(s, System.Math.Min(coefV - coefU, k));

                        if (k - (coefV - coefU) > 0)
                        {
                            BitLevel.InplaceShiftLeft(r, k - coefV + coefU);
                        }
                    }
                    coefU += k;
                }

                k = HowManyIterations(v, n);
                if (k != 0)
                {
                    BitLevel.InplaceShiftLeft(v, k);
                    if (coefV >= coefU)
                    {
                        BitLevel.InplaceShiftLeft(s, k);
                    }
                    else
                    {
                        BitLevel.InplaceShiftRight(r, System.Math.Min(coefU - coefV, k));

                        if (k - (coefU - coefV) > 0)
                        {
                            BitLevel.InplaceShiftLeft(s, k - coefU + coefV);
                        }
                    }
                    coefV += k;
                }

                if (u.Signum() == v.Signum())
                {
                    if (coefU <= coefV)
                    {
                        Elementary.CompleteInPlaceSubtract(u, v);
                        Elementary.CompleteInPlaceSubtract(r, s);
                    }
                    else
                    {
                        Elementary.CompleteInPlaceSubtract(v, u);
                        Elementary.CompleteInPlaceSubtract(s, r);
                    }
                }
                else
                {
                    if (coefU <= coefV)
                    {
                        Elementary.CompleteInPlaceAdd(u, v);
                        Elementary.CompleteInPlaceAdd(r, s);
                    }
                    else
                    {
                        Elementary.CompleteInPlaceAdd(v, u);
                        Elementary.CompleteInPlaceAdd(s, r);
                    }
                }

                if (v.Signum() == 0 || u.Signum() == 0)
                {
                    throw new ArithmeticException("BigInteger not invertible");
                }
            }

            if (IsPowerOfTwo(v, coefV))
            {
                r = s;
                if (v.Signum() != u.Signum())
                {
                    u = u.Negate();
                }
            }
            if (u.TestBit(n))
            {
                if (r.Signum() < 0)
                {
                    r = r.Negate();
                }
                else
                {
                    r = Modulo.Subtract(r);
                }
            }

            if (r.Signum() < 0)
            {
                r = r.Add(Modulo);
            }

            return(r);
        }
コード例 #9
0
        /// <summary>
        /// Calculates x.modInverse(p) Based on: Savas, E; Koc, C "The Montgomery Modular Inverse - Revised"
        /// </summary>
        ///
        /// <param name="X">BigInteger X</param>
        /// <param name="P">BigInteger P</param>
        ///
        /// <returns>Returns <c>1/X Mod M</c></returns>
        internal static BigInteger ModInverseMontgomery(BigInteger X, BigInteger P)
        {
            // ZERO hasn't inverse
            if (X.m_sign == 0)
            {
                throw new ArithmeticException("BigInteger not invertible!");
            }

            // montgomery inverse require even modulo
            if (!P.TestBit(0))
            {
                return(ModInverseLorencz(X, P));
            }

            int m = P.m_numberLength * 32;
            // PRE: a \in [1, p - 1]
            BigInteger u, v, r, s;

            u = P.Copy();  // make copy to use inplace method
            v = X.Copy();

            int max = System.Math.Max(v.m_numberLength, u.m_numberLength);

            r             = new BigInteger(1, 1, new int[max + 1]);
            s             = new BigInteger(1, 1, new int[max + 1]);
            s.m_digits[0] = 1;

            int k    = 0;
            int lsbu = u.LowestSetBit;
            int lsbv = v.LowestSetBit;
            int toShift;

            if (lsbu > lsbv)
            {
                BitLevel.InplaceShiftRight(u, lsbu);
                BitLevel.InplaceShiftRight(v, lsbv);
                BitLevel.InplaceShiftLeft(r, lsbv);
                k += lsbu - lsbv;
            }
            else
            {
                BitLevel.InplaceShiftRight(u, lsbu);
                BitLevel.InplaceShiftRight(v, lsbv);
                BitLevel.InplaceShiftLeft(s, lsbu);
                k += lsbv - lsbu;
            }

            r.m_sign = 1;
            while (v.Signum() > 0)
            {
                // INV v >= 0, u >= 0, v odd, u odd (except last iteration when v is even (0))

                while (u.CompareTo(v) > BigInteger.EQUALS)
                {
                    Elementary.InplaceSubtract(u, v);
                    toShift = u.LowestSetBit;
                    BitLevel.InplaceShiftRight(u, toShift);
                    Elementary.InplaceAdd(r, s);
                    BitLevel.InplaceShiftLeft(s, toShift);
                    k += toShift;
                }

                while (u.CompareTo(v) <= BigInteger.EQUALS)
                {
                    Elementary.InplaceSubtract(v, u);

                    if (v.Signum() == 0)
                    {
                        break;
                    }

                    toShift = v.LowestSetBit;
                    BitLevel.InplaceShiftRight(v, toShift);
                    Elementary.InplaceAdd(s, r);
                    BitLevel.InplaceShiftLeft(r, toShift);
                    k += toShift;
                }
            }

            // in u is stored the gcd
            if (!u.IsOne())
            {
                throw new ArithmeticException("BigInteger not invertible.");
            }

            if (r.CompareTo(P) >= BigInteger.EQUALS)
            {
                Elementary.InplaceSubtract(r, P);
            }

            r = P.Subtract(r);

            // Have pair: ((BigInteger)r, (Integer)k) where r == a^(-1) * 2^k mod (module)
            int n1 = CalcN(P);

            if (k > m)
            {
                r = MonPro(r, BigInteger.One, P, n1);
                k = k - m;
            }

            r = MonPro(r, BigInteger.GetPowerOfTwo(m - k), P, n1);

            return(r);
        }
コード例 #10
0
        /// <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 ^ long.MinValue) > (rightHand ^ long.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);
        }