Beispiel #1
0
        /// <summary>
        /// Перегрузка оператора инкримента
        /// </summary>
        public static BigInt32 operator ++(BigInt32 bi1)
        {
            BigInt32 result = new BigInt32(bi1);

            long val, carry = 1;
            int  index = 0;

            while (carry != 0 && index < maxLength)
            {
                val = (long)(result.data[index]);
                val++;

                result.data[index] = (uint)(val & 0xFFFFFFFF);
                carry = val >> 32;

                index++;
            }

            if (index > result.dataLength)
            {
                result.dataLength = index;
            }
            else
            {
                while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0)
                {
                    result.dataLength--;
                }
            }

            return(result);
        }
Beispiel #2
0
        /// <summary>
        /// Выполняет модульное деление числа, возведенного в степень exp.
        /// </summary>
        /// <param name="exp">экспонента</param>
        /// <param name="n">модуль</param>
        /// <returns></returns>
        public BigInt32 modPow(BigInt32 exp, BigInt32 n)
        {
            BigInt32 resultRemainder = 1;       // конечный остаток

            BigInt32 tempRemainder = this % n;  // временный остаток

            BigInt32 constant = new BigInt32(); //константа "мю" для алгоритма баррета

            int i = n.dataLength << 1;

            constant.data[i] = 0x00000001;

            constant.dataLength = i + 1;

            constant = constant / n;

            for (int pos = 0; pos < exp.dataLength; pos++)
            {
                uint mask = 0x00000001;

                for (int index = 0; index < 32; index++)
                {
                    if ((exp.data[pos] & mask) != 0)
                    {
                        resultRemainder = AlgorithmOfBarrettReduction(resultRemainder * tempRemainder, n, constant);
                    }

                    mask <<= 1;

                    tempRemainder = AlgorithmOfBarrettReduction(tempRemainder * tempRemainder, n, constant);
                }
            }

            return(resultRemainder);
        }
Beispiel #3
0
        /// <summary>
        /// Перегрузка оператора декримента
        /// </summary>
        public static BigInt32 operator --(BigInt32 bi1)
        {
            BigInt32 result = new BigInt32(bi1);

            long val;
            bool carryIn = true;
            int  index   = 0;

            while (carryIn && index < maxLength)
            {
                val = (long)(result.data[index]);
                val--;

                result.data[index] = (uint)(val & 0xFFFFFFFF);

                if (val >= 0)
                {
                    carryIn = false;
                }

                index++;
            }

            if (index > result.dataLength)
            {
                result.dataLength = index;
            }

            while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0)
            {
                result.dataLength--;
            }

            return(result);
        }
Beispiel #4
0
        /// <summary>
        /// Перегрузка оператора сдвига вправо >>
        /// </summary>
        /// <param name="bi1"></param>
        /// <param name="shiftVal"></param>
        public static BigInt32 operator >>(BigInt32 bi1, int shiftVal)
        {
            BigInt32 result = new BigInt32(bi1);

            result.dataLength = shiftRight(result.data, shiftVal);


            if ((bi1.data[maxLength - 1] & 0x90000000) != 0) // если отрицательное
            {
                for (int i = maxLength - 1; i >= result.dataLength; i--)
                {
                    result.data[i] = 0xFFFFFFFF;
                }

                uint mask = 0x90000000;
                for (int i = 0; i < 32; i++)
                {
                    if ((result.data[result.dataLength - 1] & mask) != 0)
                    {
                        break;
                    }

                    result.data[result.dataLength - 1] |= mask;
                    mask >>= 1;
                }
                result.dataLength = maxLength;
            }

            return(result);
        }
Beispiel #5
0
        /// <summary>
        /// Вырабатывает ЭЦП сообщения-Text
        /// </summary>
        /// <param name="Text">Сообщение</param>
        /// <returns>Подпись</returns>
        public static BigInt32 CreateSignature(byte[] Text, BigInt32 d, BigInt32 n)
        {
            byte[]   hash    = MD5hash(Text);
            BigInt32 BI_Text = new BigInt32(hash);

            return(BI_Text.modPow(d, n));
        }
Beispiel #6
0
        /// <summary>
        /// Создание ЭЦП файла
        /// </summary>
        /// <param name="filename">Имя файла, который мы хотим подписать</param>
        static void CreateFilesOfSign(string filename)
        {
            Encoding enc = Encoding.Default;

            byte[] test_byte = File.ReadAllBytes(filename);    // байтовое представление исходного файла

            FileStream   Stream = new FileStream("SecretKey.txt", FileMode.Open, FileAccess.Read);
            StreamReader Reader = new StreamReader(Stream);
            string       D      = Reader.ReadLine();
            string       N      = Reader.ReadLine();

            Reader.Close();
            Stream.Close();

            BigInt32 d    = new BigInt32(D);
            BigInt32 n    = new BigInt32(N);
            BigInt32 Sign = RSA.CreateSignature(test_byte, d, n);      // ЭЦП файла
            string   FileNameIsSignature = "Sign_" + filename;

            Stream = new FileStream(FileNameIsSignature, FileMode.Create, FileAccess.Write);
            StreamWriter Writer = new StreamWriter(Stream);

            Writer.WriteLine(Sign);
            Writer.WriteLine(filename);
            Writer.Close();
            Stream.Close();

            Stream = new FileStream(FileNameIsSignature, FileMode.Append, FileAccess.Write);
            BinaryWriter WriterByte = new BinaryWriter(Stream);

            WriterByte.Write(test_byte);
            WriterByte.Close();
            Console.WriteLine("Cоздан файл: {0}", FileNameIsSignature);
        }
Beispiel #7
0
        /// <summary>
        /// Расширенный алгоритм Евклида (для нахождения обратного элемента по некоторому модулю)
        /// </summary>
        private static void Evklid(BigInt32 a, BigInt32 b, ref BigInt32 x, ref BigInt32 y, ref BigInt32 d)
        {
            BigInt32 q = new BigInt32();

            BigInt32 r  = new BigInt32();
            BigInt32 x1 = new BigInt32();
            BigInt32 x2 = new BigInt32();
            BigInt32 y1 = new BigInt32();
            BigInt32 y2 = new BigInt32();

            BigInt32 one = new BigInt32(1);
            BigInt32 O   = new BigInt32(0);

            if (b == O)
            {
                d = a; x = new BigInt32(1); y = new BigInt32(0);
                return;
            }
            x2 = new BigInt32(1); x1 = new BigInt32(0); y2 = new BigInt32(0); y1 = new BigInt32(1);
            while (b > O)
            {
                q = a / b; r = a % b;
                x = x2 - (q * x1); if (q == O || y1 == O)
                {
                    y = y2;
                }
                else
                {
                    y = y2 - (q * y1);
                }
                a  = b; b = r;
                x2 = (x1); x1 = (x); y2 = (y1); y1 = (y);
            }
            d = (a); x = (x2); y = (y2);
        }
Beispiel #8
0
        /// <summary>
        /// Перегрузка оператора сложения
        /// </summary>
        public static BigInt32 operator +(BigInt32 bi1, BigInt32 bi2)
        {
            BigInt32 result = new BigInt32();

            result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; //найдет наибольшее

            long carry = 0;                                                                          //перенос

            for (int i = 0; i < result.dataLength; i++)
            {
                long sum = (long)bi1.data[i] + (long)bi2.data[i] + carry;
                carry          = sum >> 32;
                result.data[i] = (uint)(sum & 0xFFFFFFFF);
            }

            if (carry != 0 && result.dataLength < maxLength)
            {
                result.data[result.dataLength] = (uint)(carry);
                result.dataLength++;
            }

            while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0)
            {
                result.dataLength--;
            }

            return(result);
        }
Beispiel #9
0
        /// <summary>
        /// Перегрузка оператора сдвига влево <<
        /// </summary>
        /// <param name="bi1"> Папаметр значения </param>
        /// <param name="shiftVal"> Величина сдвига</param>
        public static BigInt32 operator <<(BigInt32 bi1, int shiftVal)
        {
            BigInt32 result = new BigInt32(bi1);

            result.dataLength = shiftLeft(result.data, shiftVal);

            return(result);
        }
Beispiel #10
0
 /// <summary>
 /// Возвращает минимальный BigInt32
 /// </summary>
 public BigInt32 min(BigInt32 bi)
 {
     if (this < bi)
     {
         return(new BigInt32(this));
     }
     else
     {
         return(new BigInt32(bi));
     }
 }
Beispiel #11
0
 /// <summary>
 /// Возвращает максимальный BigInt32
 /// </summary>
 public BigInt32 max(BigInt32 bi)
 {
     if (this > bi)
     {
         return(new BigInt32(this));
     }
     else
     {
         return(new BigInt32(bi));
     }
 }
Beispiel #12
0
        /// <summary>
        /// Конструктор копирования
        /// </summary>
        public BigInt32(BigInt32 bi)
        {
            data = new uint[maxLength];

            dataLength = bi.dataLength;

            for (int i = 0; i < dataLength; i++)
            {
                data[i] = bi.data[i];
            }
        }
Beispiel #13
0
        /// <summary>
        /// Проверка цифровой подписи файла на подлинность
        /// </summary>
        /// <param name="filename"> Имя подписанного файла</param>
        static void VerificationSignature(string filename)
        {
            FileStream   Stream    = new FileStream(filename, FileMode.Open, FileAccess.Read);
            StreamReader Reader    = new StreamReader(Stream);
            string       Sign      = Reader.ReadLine(); //подпись
            string       Test_file = Reader.ReadLine(); //имя проверяемого файла

            Reader.Close();
            Stream.Close();

            Stream = new FileStream(filename, FileMode.Open, FileAccess.Read);
            BinaryReader ReaderBinary = new BinaryReader(Stream);
            FileInfo     f            = new FileInfo(filename);

            int fil = (int)f.Length - (Sign.Length + Test_file.Length);

            byte[] s1        = ReaderBinary.ReadBytes(Sign.Length + 2);      //
            byte[] s2        = ReaderBinary.ReadBytes(Test_file.Length + 2); //
            byte[] test_byte = ReaderBinary.ReadBytes(fil);                  // байтовое представление проверяемых данные

            Stream = new FileStream("OpenKey.txt", FileMode.Open, FileAccess.Read);
            Reader = new StreamReader(Stream);
            string E = Reader.ReadLine();
            string N = Reader.ReadLine();

            Reader.Close();
            Stream.Close();

            Encoding enc = Encoding.Default;


            BigInt32 Signature = new BigInt32(Sign);        //подпись
            BigInt32 e         = new BigInt32(E);           //открытый ключ
            BigInt32 n         = new BigInt32(N);           //модуль
            bool     finish    = false;

            finish = RSA.VerifySignature(test_byte, Signature, e, n);  // проверка ЭЦП
            if (finish)
            {
                Console.WriteLine("Подпись верна.");
                string str_new = "New_" + Test_file;
                Stream = new FileStream(str_new, FileMode.Create, FileAccess.Write);
                BinaryWriter Writer = new BinaryWriter(Stream);
                Writer.Write(test_byte);
                Writer.Close();
                Stream.Close();
                Console.WriteLine("Создан файл: {0}", str_new);
            }
            else
            {
                Console.WriteLine("Подпись не верна");
            }
        }
Beispiel #14
0
        /// <summary>
        /// Проверка цифровой подписи Signature текста Text
        /// </summary>
        /// <param name="Text">Текст</param>
        /// <param name="Signature">Подпись</param>
        /// <param name="e">Открытый ключ</param>
        /// <param name="n">Модуль</param>
        /// <returns>true если подпись верна, false в обратном случае</returns>
        public static bool VerifySignature(byte[] Text, BigInt32 Signature, BigInt32 e, BigInt32 n)
        {
            BigInt32 R = new BigInt32(MD5hash(Text));
            //Console.WriteLine(R);
            BigInt32 S = new BigInt32(Signature.modPow(e, n));

            //Console.WriteLine(S);
            if (R == S)
            {
                return(true);
            }
            return(false);
        }
Beispiel #15
0
        /// <summary>
        /// Алгоритм Евклида
        /// </summary>
        /// <returns> НОД </returns>
        public BigInt32 gcd(BigInt32 bi)
        {
            BigInt32 x = this;
            BigInt32 y = bi;
            BigInt32 g = x;

            while (x.dataLength > 1 || (x.dataLength == 1 && x.data[0] != 0))
            {
                g = x;
                x = y % x;
                y = g;
            }
            return(g);
        }
Beispiel #16
0
//***************************************************************************************
//***************************************************************************************
        /// <summary>
        /// Генерирует положительный  BigInt32. С большой вероятностью простое.+
        /// </summary>
        public static BigInt32 GetPseudoPrime(int bits, int confidence, Random rand)
        {
            BigInt32 result = new BigInt32();
            bool     done   = false;

            while (!done)
            {
                result.GetRandomBits(bits, rand);
                result.data[0] = 0x01;                     // делает сгенерированное число нечетным

                done = result.RabinMillerTest(confidence); //проверяем на простоту
            }
            return(result);
        }
Beispiel #17
0
 /// <summary>
 /// Статический НОД чисел а и в
 /// </summary>
 public static BigInt32 NOD(BigInt32 a, BigInt32 b)
 {
     while (a != 0 && b != 0)
     {
         if (a >= b)
         {
             a = a % b;
         }
         else
         {
             b = b % a;
         }
     }
     return(a + b);
 }
Beispiel #18
0
        /// <summary>
        /// Определяет считаются ли равными объекты класса BigInt32
        /// </summary>
        public override bool Equals(object o)
        {
            BigInt32 bi = (BigInt32)o;

            if (this.dataLength != bi.dataLength)
            {
                return(false);
            }

            for (int i = 0; i < this.dataLength; i++)
            {
                if (this.data[i] != bi.data[i])
                {
                    return(false);
                }
            }
            return(true);
        }
Beispiel #19
0
        /// <summary>
        /// Возвращает строку из BigInt32
        /// </summary>
        public override string ToString()
        {
            string result = "";

            BigInt32 a         = this;
            BigInt32 quotient  = new BigInt32();
            BigInt32 remainder = new BigInt32();

            while (a.dataLength > 1 || (a.dataLength == 1 && a.data[0] != 0))
            {
                AlgorithmOfDivideSingleByte(a, 10, quotient, remainder);

                result = remainder.data[0] + result;

                a = quotient;
            }

            return(result);
        }
Beispiel #20
0
        /// <summary>
        /// Перегрузка оператора вычитания
        /// </summary>
        public static BigInt32 operator -(BigInt32 bi1, BigInt32 bi2)
        {
            BigInt32 result = new BigInt32();

            result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength; // ищет наибольший

            long carryIn = 0;

            for (int i = 0; i < result.dataLength; i++)
            {
                long diff;

                diff           = (long)bi1.data[i] - (long)bi2.data[i] - carryIn;
                result.data[i] = (uint)(diff & 0xFFFFFFFF);

                if (diff < 0)
                {
                    carryIn = 1;
                }
                else
                {
                    carryIn = 0;
                }
            }

            // взять обратный
            if (carryIn != 0)
            {
                for (int i = result.dataLength; i < maxLength; i++)
                {
                    result.data[i] = 0xFFFFFFFF;
                }
                result.dataLength = maxLength;
            }

            while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0)
            {
                result.dataLength--;
            }

            return(result);
        }
Beispiel #21
0
        /// <summary>
        /// Представляет длинное число из строки
        /// </summary>
        /// <param name="value">Исходная строка</param>
        /// <param name="radix">Основание</param>
        public BigInt32(string value)
        {
            BigInt32 multiplier = new BigInt32(1);
            BigInt32 result     = new BigInt32();

            for (int i = value.Length - 1; i >= 0; i--)
            {
                int posVal = value[i];

                if (posVal >= '0' && posVal <= '9')
                {
                    posVal -= '0';
                }
                else
                {
                    posVal = 9999999;
                }

                if (value[0] == '-')
                {
                    posVal = -posVal;
                }

                result = result + (multiplier * posVal);

                if ((i - 1) >= 0)
                {
                    multiplier = multiplier * 10;
                }
            }

            data = new uint[maxLength];
            for (int i = 0; i < result.dataLength; i++)
            {
                data[i] = result.data[i];
            }

            dataLength = result.dataLength;
        }
Beispiel #22
0
        /// <summary>
        /// Ищет обратный элемент к e по модулю n
        /// </summary>
        public static BigInt32 Inverse(BigInt32 е, BigInt32 n)
        {
            BigInt32 O   = new BigInt32(0);
            BigInt32 ONE = new BigInt32(1);
            BigInt32 d   = new BigInt32(0);
            BigInt32 x   = new BigInt32(0);
            BigInt32 y   = new BigInt32(0);

            Evklid(е, n, ref x, ref y, ref d);
            if (d == ONE)
            {
                if (x < O)
                {
                    return(x + n);
                }
                else
                {
                    return(x);
                }
            }
            return(O);
        }
Beispiel #23
0
        /// <summary>
        /// Перегрузка оператора присваивания остатка
        /// </summary>
        public static BigInt32 operator %(BigInt32 bi1, BigInt32 bi2)
        {
            BigInt32 quotient  = new BigInt32();
            BigInt32 remainder = new BigInt32(bi1);

            if (bi1 < bi2)
            {
                return(remainder);
            }
            else
            {
                if (bi2.dataLength == 1)
                {
                    AlgorithmOfDivideSingleByte(bi1, bi2, quotient, remainder);
                }
                else
                {
                    AlgorithmOfDivideMultiByte(bi1, bi2, quotient, remainder);
                }

                return(remainder);
            }
        }
Beispiel #24
0
        /// <summary>
        /// Перегрузка оператора деления
        /// </summary>
        public static BigInt32 operator /(BigInt32 bi1, BigInt32 bi2)
        {
            BigInt32 quotient  = new BigInt32(); //частное
            BigInt32 remainder = new BigInt32(); //остаток

            if (bi1 < bi2)
            {
                return(quotient); //0
            }

            else
            {
                if (bi2.dataLength == 1)
                {
                    AlgorithmOfDivideSingleByte(bi1, bi2, quotient, remainder);
                }
                else
                {
                    AlgorithmOfDivideMultiByte(bi1, bi2, quotient, remainder);
                }

                return(quotient);
            }
        }
Beispiel #25
0
        /// <summary>
        /// Конструктор. Генерирует и проверяет ключи.
        /// </summary>
        public RSA()
        {
            Random uy = new Random();

            const int KeyOFLenght = 128; // Длина p и q
            BigInt32  p           = BigInt32.GetPseudoPrime(KeyOFLenght, 10, uy);
            BigInt32  q           = BigInt32.GetPseudoPrime(KeyOFLenght - 1, 10, uy);

            //Console.WriteLine("q = {0}, p = {1}", q, p);
            n = p * q;
            //Console.WriteLine("n= {0}", n);
            p--;
            q--;
            BigInt32 w = p * q;                   // функция Эйлера

            e = new BigInt32();                   // открытый ключ

            do
            {
                e.GetRandomBits(KeyOFLenght * 2, uy);
            }while (BigInt32.NOD(e, w) != 1 && (e > n));

            d = BigInt32.Inverse(e, w);           // d - закрытый ключ (обратный к е по модулю w)
        }                                         // d - существует <=> НОД(e,w) = 1
Beispiel #26
0
        /// <summary>
        /// Перегрузка оператора отрицания
        /// </summary>
        public static BigInt32 operator -(BigInt32 bi1)
        {
            if (bi1.dataLength == 1 && bi1.data[0] == 0)
            {
                return(new BigInt32(1));
            }

            BigInt32 result = new BigInt32(bi1);

            for (int i = 0; i < maxLength; i++)
            {
                result.data[i] = (uint)(~(bi1.data[i]));
            }

            long val, carry = 1;
            int  index = 0;

            while (carry != 0 && index < maxLength)
            {
                val = (long)(result.data[index]);
                val++;

                result.data[index] = (uint)(val & 0xFFFFFFFF);
                carry = val >> 32;

                index++;
            }

            result.dataLength = maxLength;

            while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0)
            {
                result.dataLength--;
            }
            return(result);
        }
Beispiel #27
0
        /// <summary>
        /// Создает файлы "OpenKey.txt" с открытым ключом и "Secret.txt" c закрытым
        /// </summary>
        static void CreateFilesOfKeys()
        {
            RSA      rsa = new RSA();
            BigInt32 E   = new BigInt32(rsa.e);
            BigInt32 D   = new BigInt32(rsa.d);
            BigInt32 N   = new BigInt32(rsa.n);

            FileStream   Stream = new FileStream("OpenKey.txt", FileMode.Create, FileAccess.Write);
            StreamWriter Writer = new StreamWriter(Stream);

            Writer.WriteLine(E);
            Writer.WriteLine(N);
            Writer.Close();
            Stream.Close();

            Stream = new FileStream("SecretKey.txt", FileMode.Create, FileAccess.Write);
            Writer = new StreamWriter(Stream);
            Writer.WriteLine(D);
            Writer.WriteLine(N);
            Writer.Close();
            Stream.Close();

            Console.WriteLine("Файлы созданы.");
        }
Beispiel #28
0
        /// <summary>
        /// Алгоритм деления числа BigInt32 на однозначное число
        /// </summary>
        private static void AlgorithmOfDivideSingleByte(BigInt32 bi1, BigInt32 bi2, BigInt32 Quotient, BigInt32 Remainder)
        {
            uint[] result    = new uint[maxLength];
            int    resultPos = 0;

            // Копируем ....
            for (int i = 0; i < maxLength; i++)
            {
                Remainder.data[i] = bi1.data[i];
            }
            Remainder.dataLength = bi1.dataLength;

            while (Remainder.dataLength > 1 && Remainder.data[Remainder.dataLength - 1] == 0)
            {
                Remainder.dataLength--;
            }

            ulong divisor  = (ulong)bi2.data[0];
            int   pos      = Remainder.dataLength - 1;
            ulong dividend = (ulong)Remainder.data[pos];

            if (dividend >= divisor)
            {
                ulong quotient = dividend / divisor;
                result[resultPos++] = (uint)quotient;

                Remainder.data[pos] = (uint)(dividend % divisor);
            }
            pos--;

            while (pos >= 0)
            {
                dividend = ((ulong)Remainder.data[pos + 1] << 32) + (ulong)Remainder.data[pos];
                ulong quotient = dividend / divisor;
                result[resultPos++] = (uint)quotient;

                Remainder.data[pos + 1] = 0;
                Remainder.data[pos--]   = (uint)(dividend % divisor);
            }

            Quotient.dataLength = resultPos;
            int j = 0;

            for (int i = Quotient.dataLength - 1; i >= 0; i--, j++)
            {
                Quotient.data[j] = result[i];
            }
            for (; j < maxLength; j++)
            {
                Quotient.data[j] = 0;
            }

            while (Quotient.dataLength > 1 && Quotient.data[Quotient.dataLength - 1] == 0)
            {
                Quotient.dataLength--;
            }

            if (Quotient.dataLength == 0)
            {
                Quotient.dataLength = 1;
            }

            while (Remainder.dataLength > 1 && Remainder.data[Remainder.dataLength - 1] == 0)
            {
                Remainder.dataLength--;
            }
        }
Beispiel #29
0
        /// <summary>
        /// Алгоритм деления двух больших чисел.
        /// Делитель содержит больше 1 цифры
        /// </summary>
        /// <param name="bi1">Делимое</param>
        /// <param name="bi2">Делитель</param>
        /// <param name="Quotient">Частное</param>
        /// <param name="Remainder">Остаток</param>
        private static void AlgorithmOfDivideMultiByte(BigInt32 bi1, BigInt32 bi2, BigInt32 Quotient, BigInt32 Remainder)
        {
            uint[] result = new uint[maxLength];

            int remainderLen = bi1.dataLength + 1;

            uint[] remainder = new uint[remainderLen];

            uint mask = 0x90000000; //битовая маска
            uint val = bi2.data[bi2.dataLength - 1];
            int  shift = 0, resultPos = 0;

            while (mask != 0 && (val & mask) == 0)
            {
                shift++; mask >>= 1;
            }

            for (int i = 0; i < bi1.dataLength; i++)
            {
                remainder[i] = bi1.data[i];
            }
            shiftLeft(remainder, shift);
            bi2 = bi2 << shift;

            int j   = remainderLen - bi2.dataLength;
            int pos = remainderLen - 1;

            ulong firstDivisorByte  = bi2.data[bi2.dataLength - 1];
            ulong secondDivisorByte = bi2.data[bi2.dataLength - 2];

            int divisorLen = bi2.dataLength + 1;

            uint[] dividendPart = new uint[divisorLen];

            while (j > 0)
            {
                ulong dividend = ((ulong)remainder[pos] << 32) + (ulong)remainder[pos - 1];

                ulong q_hat = dividend / firstDivisorByte;
                ulong r_hat = dividend % firstDivisorByte;

                bool done = false;
                while (!done)
                {
                    done = true;

                    if (q_hat == 0x100000000 ||
                        (q_hat * secondDivisorByte) > ((r_hat << 32) + remainder[pos - 2]))
                    {
                        q_hat--;
                        r_hat += firstDivisorByte;

                        if (r_hat < 0x100000000)
                        {
                            done = false;
                        }
                    }
                }

                for (int h = 0; h < divisorLen; h++)
                {
                    dividendPart[h] = remainder[pos - h];
                }

                BigInt32 kk = new BigInt32(dividendPart);
                BigInt32 ss = bi2 * (long)q_hat;

                while (ss > kk)
                {
                    q_hat--;
                    ss -= bi2;
                }
                BigInt32 yy = kk - ss;

                for (int h = 0; h < divisorLen; h++)
                {
                    remainder[pos - h] = yy.data[bi2.dataLength - h];
                }

                result[resultPos++] = (uint)q_hat;

                pos--;
                j--;
            }

            Quotient.dataLength = resultPos;
            int y = 0;

            for (int x = Quotient.dataLength - 1; x >= 0; x--, y++)
            {
                Quotient.data[y] = result[x];
            }
            for (; y < maxLength; y++)
            {
                Quotient.data[y] = 0;
            }

            while (Quotient.dataLength > 1 && Quotient.data[Quotient.dataLength - 1] == 0)
            {
                Quotient.dataLength--;
            }

            if (Quotient.dataLength == 0)
            {
                Quotient.dataLength = 1;
            }

            Remainder.dataLength = shiftRight(remainder, shift);

            for (y = 0; y < Remainder.dataLength; y++)
            {
                Remainder.data[y] = remainder[y];
            }
            for (; y < maxLength; y++)
            {
                Remainder.data[y] = 0;
            }
        }
Beispiel #30
0
        /// <summary>
        /// Перегрузка оператора умножения
        /// </summary>
        public static BigInt32 operator *(BigInt32 bi1, BigInt32 bi2)
        {
            int  lastPos = maxLength - 1;
            bool bi1Neg = false, bi2Neg = false;

            // берем bi1 и bi2 по модулю

            if ((bi1.data[lastPos] & 0x90000000) != 0)         // bi1 отрицательный
            {
                bi1Neg = true; bi1 = -bi1;
            }
            if ((bi2.data[lastPos] & 0x90000000) != 0)         // bi2 отрицательный
            {
                bi2Neg = true; bi2 = -bi2;
            }

            BigInt32 result = new BigInt32();

            // Умножение абсолютных велечин
            for (int i = 0; i < bi1.dataLength; i++)
            {
                if (bi1.data[i] == 0)
                {
                    continue;
                }

                ulong mcarry = 0;
                for (int j = 0, k = i; j < bi2.dataLength; j++, k++)
                {
                    // k = i + j
                    ulong val = ((ulong)bi1.data[i] * (ulong)bi2.data[j]) +
                                (ulong)result.data[k] + mcarry;

                    result.data[k] = (uint)(val & 0xFFFFFFFF);
                    mcarry         = (val >> 32);
                }

                if (mcarry != 0)
                {
                    result.data[i + bi2.dataLength] = (uint)mcarry;
                }
            }

            result.dataLength = bi1.dataLength + bi2.dataLength;
            if (result.dataLength > maxLength)
            {
                result.dataLength = maxLength;
            }

            while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0)
            {
                result.dataLength--;
            }

            // проверка переполнения
            if ((result.data[lastPos] & 0x90000000) != 0)
            {
                if (bi1Neg != bi2Neg && result.data[lastPos] == 0x90000000)    // bi1 и bi2 разного знака
                {
                    //обрабатывать особый случай, когда умножение производит
                    // максимальное отрицательное число в 2сс

                    if (result.dataLength == 1)
                    {
                        return(result);
                    }
                    else
                    {
                        bool isMaxNeg = true;
                        for (int i = 0; i < result.dataLength - 1 && isMaxNeg; i++)
                        {
                            if (result.data[i] != 0)
                            {
                                isMaxNeg = false;
                            }
                        }

                        if (isMaxNeg)
                        {
                            return(result);
                        }
                    }
                }
            }

            // Если знаки разные
            if (bi1Neg != bi2Neg)
            {
                return(-result);
            }

            return(result);
        }