大整数运算包的设计与实现

1.问题描述

大整数运算是现代密码学算法实现的基础,重要性不言而喻。大整数我们指的是二进制位512、1024和2048的数,一般的语言不支持。

2.基本要求

以类库头文件的形式实现。

3.实现提示

   在选择了大整数的存储结构之后,主要实现以下运算:

①    模加;

②    模减;

③    模乘;

④    模整除;

⑤    模取余。这五种运算模拟手算实现。

⑥    幂模:利用“平方-乘法”算法实现。

⑦    GCD:利用欧几里得算法实现。

⑧    乘法逆: 利用扩展的欧几里得算法实现。

⑨    素数判定与生成:概率性素数产生方法产生的数仅仅是伪素数,其缺点在于,尽管其产生合数的可能性很小,但是这种可能性仍然存在:其优点是产生的伪素数没有规律性,而且产生的速度也比较快。此类方法是生成大素数的主要方法,其中较著名的算法有:Miller Rabin算法、Solovay-Strassen算法等。本文讨论Miller  Rabin算法。

Miller Rabin素性测试法是在实际中应用非常广的一种素性测试方案,可以用来判定某随机数是否为素数。其定义如下:

设n>2是一个奇数,设n-1=2sm,其中s是非负整数,m>0是奇数,设0<b<n,如果

bm≡-1(modn),

或者存在一个r,0≤r<s,使得

b 2^r m≡-1(modn)

则称n通过以b为基的Miller-Rabin测试。

可以利用Miller-Rabin素性测试算法来随机生成大素数,随即生成一个奇数n>2,随即均匀的选取序列b1,b2...,bk∈{1,2,...,n-1},对n进行k次Miller-Rabin素性测试,如果每次输出都为“n可能是素数”,则n是合数的概率小于 1/4k当k足够大时,1/4k是一个十分小的数。

    同学们在具体实现时,为了提高速度最好以空间换时间,在主程序运行前先构造一个大素数表。


具体的代码如下:

BigInteger.h

#pragma once
#include <cstring>
#include <string>
#include <algorithm>
#include <assert.h>
#include <ctime>
#include <iostream>using namespace std;
const int maxLength = 512;
const int primeLength = 50;
const int primesBelow2000[303] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293,307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499,503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599,601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691,701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887,907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097,1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193,1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297,1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399,1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499,1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597,1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699,1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789,1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999 };class BigInteger
{typedef unsigned char byte;
public:BigInteger(void);BigInteger(__int64 value);BigInteger(unsigned __int64 value);BigInteger(const BigInteger &bi);BigInteger(string value, int radix);BigInteger(byte inData[], int inLen);BigInteger(unsigned int inData[], int inLen);BigInteger operator -();BigInteger operator =(const BigInteger &bi2);BigInteger operator +(BigInteger &bi2);BigInteger operator -(BigInteger bi2);BigInteger operator /(BigInteger bi2);BigInteger operator *(BigInteger bi2);void singleByteDivide(BigInteger &bi1, BigInteger &bi2, BigInteger &outQuotient, BigInteger &outRemainder);void multiByteDivide(BigInteger &bi1, BigInteger &bi2, BigInteger &outQuotient, BigInteger &outRemainder);BigInteger operator %(BigInteger bi2);BigInteger operator +=(BigInteger bi2);BigInteger operator -=(BigInteger bi2);int bitCount();BigInteger modPow(BigInteger exp, BigInteger n);friend ostream& operator<<(ostream& output, BigInteger &bi1);friend BigInteger GetPrime();friend bool Miller_Robin(BigInteger &bi1);friend BigInteger MultipInverse(BigInteger &bi1, BigInteger &n);friend BigInteger extended_euclidean(BigInteger n, BigInteger m, BigInteger &x, BigInteger &y); friend BigInteger MultipInverse(BigInteger &bi1, BigInteger &n);   //求乘法逆friend BigInteger Gcd(BigInteger &bi1, BigInteger &bi2);   //求最大公约数BigInteger BarrettReduction(BigInteger x, BigInteger n, BigInteger constant);bool operator >=(BigInteger bi2){return ((*this) == bi2 || (*this) > bi2);}bool operator >(BigInteger bi2);bool operator ==(BigInteger bi2);bool operator !=(BigInteger bi2);int shiftRight(unsigned int buffer[], int bufLen, int shiftVal);BigInteger operator <<(int shiftVal);int shiftLeft(unsigned int buffer[], int bufLen, int shiftVal);bool operator <(BigInteger bi2);string DecToHex(unsigned int value, string format);string ToHexString();public:~BigInteger(void);    public:int dataLength;// number of actual chars usedunsigned int *data;
};

BigInteger.cpp

#include "BigInteger.h"BigInteger::BigInteger(void)   //默认的构造函数
: dataLength(0), data(0)
{data = new unsigned int[maxLength];memset(data, 0, maxLength * sizeof(unsigned int));dataLength = 1;
}BigInteger::BigInteger(__int64 value)   //用一个64位的值来初始化大数
{data = new unsigned int[maxLength];memset(data, 0, maxLength * sizeof(unsigned int));   //先清零__int64 tempVal = value;dataLength = 0;while (value != 0 && dataLength < maxLength){data[dataLength] = (unsigned int)(value & 0xFFFFFFFF);   //取低位value = value >> 32;   //进位dataLength++;}if (tempVal > 0)         // overflow check for +ve value{if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0)assert(false);}else if (tempVal < 0)    // underflow check for -ve value{if (value != -1 || (data[dataLength - 1] & 0x80000000) == 0)assert(false);}if (dataLength == 0)dataLength = 1;
}BigInteger::BigInteger(unsigned __int64 value)   //用一个无符号的64位整数来初始化大数
{data = new unsigned int[maxLength];memset(data, 0, maxLength * sizeof(unsigned int));dataLength = 0;while (value != 0 && dataLength < maxLength){data[dataLength] = (unsigned int)(value & 0xFFFFFFFF);value >>= 32;dataLength++;}if (value != 0 || (data[maxLength - 1] & 0x80000000) != 0)assert(false);if (dataLength == 0)   //防止输入的value=0dataLength = 1;
}BigInteger::BigInteger(const BigInteger &bi)   //用大数初始化大数
{data = new unsigned int[maxLength];dataLength = bi.dataLength;for (int i = 0; i < maxLength; i++)   //考虑到有负数的情况,所以每一位都要复制data[i] = bi.data[i];
}BigInteger::~BigInteger(void)
{if (data != NULL){delete []data;}
}BigInteger::BigInteger(string value, int radix)   //输入转换函数,将字符串转换成对应进制的大数
{   //一般不处理负数BigInteger multiplier((__int64)1);BigInteger result;transform(value.begin(), value.end(), value.begin(), toupper);   //将小写字母转换成为大写int limit = 0;if (value[0] == '-')   limit = 1;for (int i = value.size() - 1; i >= limit; i--){int posVal = (int)value[i];if (posVal >= '0' && posVal <= '9')  //将字符转换成数字posVal -= '0';else if (posVal >= 'A' && posVal <= 'Z')posVal = (posVal - 'A') + 10;elseposVal = 9999999;       // arbitrary large 输入别的字符if (posVal >= radix)   //不能大于特定的进制,否则终止{assert(false);}else{result = result + (multiplier * BigInteger((__int64)posVal));if ((i - 1) >= limit)   //没有到达尾部multiplier = multiplier * BigInteger((__int64)radix);}}if (value[0] == '-')   //符号最后再处理result = -result;if (value[0] == '-')     //输入为负数,但得到的结果为正数,可能溢出了{if ((result.data[maxLength - 1] & 0x80000000) == 0)   assert(false);}else    //或者说,输入为正数,得到的结果为负数,也可能溢出了{if ((result.data[maxLength - 1] & 0x80000000) != 0)  assert(false);}data = new unsigned int[maxLength];//memset(data, 0, maxLength * sizeof(unsigned int));for (int i = 0; i < maxLength; i++)data[i] = result.data[i];dataLength = result.dataLength;
}BigInteger::BigInteger(byte inData[], int inLen)   //用一个char类型的数组来初始化大数
{dataLength = inLen >> 2;   //一个unsigned int占32位,而一个unsigned char只占8位//因此dataLength应该是至少是inLen/4,不一定整除int leftOver = inLen & 0x3;  //取最低两位的数值,为什么要这样干呢?实际上是为了探测len是不是4的倍数,好确定dataLength的长度if (leftOver != 0)    //不能整除的话,dataLength要加1dataLength++;if (dataLength > maxLength)assert(false);data = new unsigned int[maxLength];memset(data, 0, maxLength * sizeof(unsigned int));for (int i = inLen - 1, j = 0; i >= 3; i -= 4, j++)   {data[j] = (unsigned int)((inData[i - 3] << 24) + (inData[i - 2] << 16) + (inData[i - 1] << 8) + inData[i]);
//我们知道:一个unsigned int占32位,而一个unsigned char只占8位,因此四个unsigned char才能组成一个unsigned int
//因此取inData[i - 3]为前32-25位,inData[i - 2]为前24-17~~~
//i % 4 = 0 or 1 or 2 or 3 余0表示恰好表示完}if (leftOver == 1)data[dataLength - 1] = (unsigned int)inData[0];else if (leftOver == 2)data[dataLength - 1] = (unsigned int)((inData[0] << 8) + inData[1]);else if (leftOver == 3)data[dataLength - 1] = (unsigned int)((inData[0] << 16) + (inData[1] << 8) + inData[2]);while (dataLength > 1 && data[dataLength - 1] == 0)dataLength--;
}BigInteger::BigInteger(unsigned int inData[], int inLen)   //用一个unsigned int型数组初始化大数
{dataLength = inLen;if (dataLength > maxLength)assert(false);data = new unsigned int[maxLength];memset(data, 0, maxLength * sizeof(maxLength));for (int i = dataLength - 1, j = 0; i >= 0; i--, j++)data[j] = inData[i];while (dataLength > 1 && data[dataLength - 1] == 0)dataLength--;
}BigInteger BigInteger::operator *(BigInteger bi2)   //乘法的重载
{BigInteger bi1(*this);int lastPos = maxLength - 1;bool bi1Neg = false, bi2Neg = false;//首先对两个乘数取绝对值try{if ((this->data[lastPos] & 0x80000000) != 0)     //bi1为负数{bi1Neg = true; bi1 = -bi1;}if ((bi2.data[lastPos] & 0x80000000) != 0)     //bi2为负数{bi2Neg = true; bi2 = -bi2;}}catch (...) { }BigInteger result;//绝对值相乘try{for (int i = 0; i < bi1.dataLength; i++){if (bi1.data[i] == 0) continue;unsigned __int64 mcarry = 0;for (int j = 0, k = i; j < bi2.dataLength; j++, k++){// k = i + junsigned __int64 val = ((unsigned __int64)bi1.data[i] * (unsigned __int64)bi2.data[j]) + (unsigned __int64)result.data[k] + mcarry;result.data[k] = (unsigned __int64)(val & 0xFFFFFFFF);   //取低位mcarry = (val >> 32);   //进位}if (mcarry != 0)result.data[i + bi2.dataLength] = (unsigned int)mcarry;}}catch (...){assert(false);}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--;// overflow check (result is -ve)溢出检查if ((result.data[lastPos] & 0x80000000) != 0)  //结果为负数{if (bi1Neg != bi2Neg && result.data[lastPos] == 0x80000000)    //两乘数符号不同{// handle the special case where multiplication produces// a max negative number in 2's complement.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;}}assert(false);}//两乘数符号不同,结果为负数if (bi1Neg != bi2Neg)return -result;return result;
}BigInteger BigInteger::operator =(const BigInteger &bi2)
{if (&bi2 == this){return *this;}if (data != NULL){delete []data;data = NULL;}data = new unsigned int[maxLength];memset(data, 0, maxLength * sizeof(unsigned int));dataLength = bi2.dataLength;for (int i = 0; i < maxLength; i++)data[i] = bi2.data[i];return *this;
}BigInteger BigInteger::operator +(BigInteger &bi2)
{int lastPos = maxLength - 1;bool bi1Neg = false, bi2Neg = false;BigInteger bi1(*this);BigInteger result;if ((this->data[lastPos] & 0x80000000) != 0)     //bi1为负数bi1Neg = true; if ((bi2.data[lastPos] & 0x80000000) != 0)     //bi2为负数bi2Neg = true; if(bi1Neg == false && bi2Neg == false)   //bi1与bi2都是正数{result.dataLength = (this->dataLength > bi2.dataLength) ? this->dataLength : bi2.dataLength;__int64 carry = 0;for (int i = 0; i < result.dataLength; i++)   //从低位开始,逐位相加{__int64 sum = (__int64)this->data[i] + (__int64)bi2.data[i] + carry;carry = sum >> 32;   //进位result.data[i] = (unsigned int)(sum & 0xFFFFFFFF);  //取低位结果}if (carry != 0 && result.dataLength < maxLength){result.data[result.dataLength] = (unsigned int)(carry);result.dataLength++;}while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0)result.dataLength--;//溢出检查if ((this->data[lastPos] & 0x80000000) == (bi2.data[lastPos] & 0x80000000) &&(result.data[lastPos] & 0x80000000) != (this->data[lastPos] & 0x80000000)){assert(false);}return result;}//关键在于,负数全部要转化成为正数来做if(bi1Neg == false && bi2Neg == true)   //bi1正,bi2负{BigInteger bi3 = -bi2;if(bi1 > bi3){result = bi1 - bi3; return result;}else{result = -(bi3 - bi1);return result;}}if(bi1Neg == true && bi2Neg == false)  //bi1负,bi2正{BigInteger bi3 = -bi1;if(bi3 > bi2){result = -(bi3 - bi2);return result;}else{result = bi2 - bi3;return result;}}if(bi1Neg == true && bi2Neg == true)  //bi1负,bi2负{result = - ((-bi1) + (-bi2));return result;}
}BigInteger BigInteger::operator -()
{//逐位取反并+1if (this->dataLength == 1 && this->data[0] == 0)return *this;BigInteger result(*this);for (int i = 0; i < maxLength; i++)result.data[i] = (unsigned int)(~(this->data[i]));   //取反__int64 val, carry = 1;int index = 0;while (carry != 0 && index < maxLength)  //+1;{val = (__int64)(result.data[index]);val++;   //由于值加了1个1,往前面的进位最多也只是1个1,因此val++就完了result.data[index] = (unsigned int)(val & 0xFFFFFFFF);   //取低位部分carry = val >> 32;   //进位index++;}if ((this->data[maxLength - 1] & 0x80000000) == (result.data[maxLength - 1] & 0x80000000))result.dataLength = maxLength;while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0)result.dataLength--;return result;
}BigInteger BigInteger::modPow(BigInteger exp, BigInteger n)   //求this^exp mod n
{if ((exp.data[maxLength - 1] & 0x80000000) != 0)   //指数是负数return BigInteger((__int64)0);BigInteger resultNum((__int64)1);BigInteger tempNum;bool thisNegative = false;if ((this->data[maxLength - 1] & 0x80000000) != 0)   //底数是负数{tempNum = -(*this) % n;thisNegative = true;}elsetempNum = (*this) % n;  //保证(tempNum * tempNum) < b^(2k)if ((n.data[maxLength - 1] & 0x80000000) != 0)   //n为负n = -n;//计算 constant = b^(2k) / m//constant主要用于后面的Baeert Reduction算法BigInteger constant;int i = n.dataLength << 1;constant.data[i] = 0x00000001;constant.dataLength = i + 1;constant = constant / n;int totalBits = exp.bitCount();int count = 0;//平方乘法算法for (int pos = 0; pos < exp.dataLength; pos++){unsigned int mask = 0x01;for (int index = 0; index < 32; index++){if ((exp.data[pos] & mask) != 0)  //某一个bit不为0resultNum = BarrettReduction(resultNum * tempNum, n, constant);//resultNum = resultNum * tempNum mod nmask <<= 1; //不断左移tempNum = BarrettReduction(tempNum * tempNum, n, constant);//tempNum = tempNum * tempNum mod nif (tempNum.dataLength == 1 && tempNum.data[0] == 1){if (thisNegative && (exp.data[0] & 0x1) != 0)    //指数为奇数return -resultNum;return resultNum;}count++;if (count == totalBits)break;}}if (thisNegative && (exp.data[0] & 0x1) != 0)    //底数为负数,指数为奇数return -resultNum;return resultNum;
}int BigInteger::bitCount()   //计算字节数
{while (dataLength > 1 && data[dataLength - 1] == 0)dataLength--;unsigned int value = data[dataLength - 1];unsigned int mask = 0x80000000;int bits = 32;while (bits > 0 && (value & mask) == 0)   //计算最高位的bit{bits--;mask >>= 1;}bits += ((dataLength - 1) << 5);   //余下的位都有32bit//左移5位,相当于乘以32,即2^5return bits;
}BigInteger BigInteger::BarrettReduction(BigInteger x, BigInteger n, BigInteger constant)
{//算法,Baeert Reduction算法,在计算大规模的除法运算时很有优势
//原理如下
//Z mod N=Z-[Z/N]*N=Z-{[Z/b^(n-1)]*[b^2n/N]/b^(n+1)}*N=Z-q*N
//q=[Z/b^(n-1)]*[b^2n/N]/b^(n+1)
//其中,[]表示取整运算,A^B表示A的B次幂int k = n.dataLength,kPlusOne = k + 1,kMinusOne = k - 1;BigInteger q1;// q1 = x / b^(k-1)for (int i = kMinusOne, j = 0; i < x.dataLength; i++, j++)q1.data[j] = x.data[i];q1.dataLength = x.dataLength - kMinusOne;if (q1.dataLength <= 0)q1.dataLength = 1;BigInteger q2 = q1 * constant;BigInteger q3;// q3 = q2 / b^(k+1)for (int i = kPlusOne, j = 0; i < q2.dataLength; i++, j++)q3.data[j] = q2.data[i];q3.dataLength = q2.dataLength - kPlusOne;if (q3.dataLength <= 0)q3.dataLength = 1;// r1 = x mod b^(k+1)// i.e. keep the lowest (k+1) wordsBigInteger r1;int lengthToCopy = (x.dataLength > kPlusOne) ? kPlusOne : x.dataLength;for (int i = 0; i < lengthToCopy; i++)r1.data[i] = x.data[i];r1.dataLength = lengthToCopy;// r2 = (q3 * n) mod b^(k+1)// partial multiplication of q3 and nBigInteger r2;for (int i = 0; i < q3.dataLength; i++){if (q3.data[i] == 0) continue;unsigned __int64 mcarry = 0;int t = i;for (int j = 0; j < n.dataLength && t < kPlusOne; j++, t++){// t = i + junsigned __int64 val = ((unsigned __int64)q3.data[i] * (unsigned __int64)n.data[j]) +(unsigned __int64)r2.data[t] + mcarry;r2.data[t] = (unsigned int)(val & 0xFFFFFFFF);mcarry = (val >> 32);}if (t < kPlusOne)r2.data[t] = (unsigned int)mcarry;}r2.dataLength = kPlusOne;while (r2.dataLength > 1 && r2.data[r2.dataLength - 1] == 0)r2.dataLength--;r1 -= r2;if ((r1.data[maxLength - 1] & 0x80000000) != 0)        // negative{BigInteger val;val.data[kPlusOne] = 0x00000001;val.dataLength = kPlusOne + 1;r1 += val;}while (r1 >= n)r1 -= n;return r1;
}bool BigInteger::operator >(BigInteger bi2)
{int pos = maxLength - 1;BigInteger bi1(*this);// bi1 is negative, bi2 is positiveif ((bi1.data[pos] & 0x80000000) != 0 && (bi2.data[pos] & 0x80000000) == 0)return false;// bi1 is positive, bi2 is negativeelse if ((bi1.data[pos] & 0x80000000) == 0 && (bi2.data[pos] & 0x80000000) != 0)return true;// same signint len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;for (pos = len - 1; pos >= 0 && bi1.data[pos] == bi2.data[pos]; pos--) ;if (pos >= 0){if (bi1.data[pos] > bi2.data[pos])return true;return false;}return false;
}bool BigInteger::operator ==(BigInteger bi2)
{if (this->dataLength != bi2.dataLength)return false;for (int i = 0; i < this->dataLength; i++){if (this->data[i] != bi2.data[i])return false;}return true;
}bool BigInteger::operator !=(BigInteger bi2)
{if(this->dataLength != bi2.dataLength)return true;for(int i = 0; i < this->dataLength; i++){if(this->data[i] != bi2.data[i])return true;}return false;
}BigInteger BigInteger::operator %(BigInteger bi2)
{BigInteger bi1(*this);BigInteger quotient;BigInteger remainder(bi1);int lastPos = maxLength - 1;bool dividendNeg = false;if ((bi1.data[lastPos] & 0x80000000) != 0)     // bi1 negative{bi1 = -bi1;dividendNeg = true;}if ((bi2.data[lastPos] & 0x80000000) != 0)     // bi2 negativebi2 = -bi2;if (bi1 < bi2){return remainder;}else{if (bi2.dataLength == 1)singleByteDivide(bi1, bi2, quotient, remainder);   //bi2只占一个位置时,用singleByteDivide更快elsemultiByteDivide(bi1, bi2, quotient, remainder);   //bi2占多个位置时,用multiByteDivide更快if (dividendNeg)return -remainder;return remainder;}
}void BigInteger::singleByteDivide(BigInteger &bi1, BigInteger &bi2,BigInteger &outQuotient, BigInteger &outRemainder)
{//outQuotient商,outRemainder余数unsigned int result[maxLength];   //用来存储结果memset(result, 0, sizeof(unsigned int) * maxLength);int resultPos = 0;for (int i = 0; i < maxLength; i++)   //将bi1复制至outRemainderoutRemainder.data[i] = bi1.data[i];outRemainder.dataLength = bi1.dataLength;while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0)outRemainder.dataLength--;unsigned __int64 divisor = (unsigned __int64)bi2.data[0];int pos = outRemainder.dataLength - 1;unsigned __int64 dividend = (unsigned __int64)outRemainder.data[pos];   //取最高位的数值if (dividend >= divisor)   //被除数>除数{unsigned __int64 quotient = dividend / divisor;result[resultPos++] = (unsigned __int64)quotient;   //结果outRemainder.data[pos] = (unsigned __int64)(dividend % divisor);   //余数}pos--;while (pos >= 0){dividend = ((unsigned __int64)outRemainder.data[pos + 1] << 32) + (unsigned __int64)outRemainder.data[pos];   //前一位的余数和这一位的值相加unsigned __int64 quotient = dividend / divisor;   //得到结果result[resultPos++] = (unsigned int)quotient;   //结果取低位outRemainder.data[pos + 1] = 0;   //前一位的余数清零outRemainder.data[pos--] = (unsigned int)(dividend % divisor);   //得到这一位的余数}outQuotient.dataLength = resultPos;   //商的长度是resultPos的长度int j = 0;for (int i = outQuotient.dataLength - 1; i >= 0; i--, j++)  //将商反转过来 outQuotient.data[j] = result[i];for (; j < maxLength; j++)   //商的其余位都要置0outQuotient.data[j] = 0;while (outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength - 1] == 0)outQuotient.dataLength--;if (outQuotient.dataLength == 0)outQuotient.dataLength = 1;while (outRemainder.dataLength > 1 && outRemainder.data[outRemainder.dataLength - 1] == 0)outRemainder.dataLength--;
}void BigInteger::multiByteDivide(BigInteger &bi1, BigInteger &bi2,BigInteger &outQuotient, BigInteger &outRemainder)
{unsigned int result[maxLength];memset(result, 0, sizeof(unsigned int) * maxLength);   //结果置零 int remainderLen = bi1.dataLength + 1;   //余数长度unsigned int *remainder = new unsigned int[remainderLen];memset(remainder, 0, sizeof(unsigned int) * remainderLen);   //余数置零unsigned int mask = 0x80000000;unsigned int val = bi2.data[bi2.dataLength - 1];int shift = 0, resultPos = 0;while (mask != 0 && (val & mask) == 0){shift++; mask >>= 1;}   //最高位从高到低找出shift个0位for (int i = 0; i < bi1.dataLength; i++)remainder[i] = bi1.data[i];   //将bi1复制到remainder之中this->shiftLeft(remainder, remainderLen, shift);   //remainder左移shift位bi2 = bi2 << shift;   //向左移shift位,将空位填满//由于两个数都扩大了相同的倍数,所以结果不变int j = remainderLen - bi2.dataLength;   //j表示两个数长度的差值,也是要计算的次数int pos = remainderLen - 1;   //pos指示余数的最高位的位置,现在pos=bi1.dataLength//以下的步骤并没有别的意思,主要是用来试商unsigned __int64 firstDivisorByte = bi2.data[bi2.dataLength - 1];   //第一个除数unsigned __int64 secondDivisorByte = bi2.data[bi2.dataLength - 2];  //第二个除数 int divisorLen = bi2.dataLength + 1;   //除数的长度unsigned int *dividendPart = new unsigned int[divisorLen];   //起名为除数的部分memset(dividendPart, 0, sizeof(unsigned int) * divisorLen);while (j > 0){unsigned __int64 dividend = ((unsigned __int64)remainder[pos] << 32) + (unsigned __int64)remainder[pos - 1];   //取余数的高两位unsigned __int64 q_hat = dividend / firstDivisorByte;   //得到一个商unsigned __int64 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 * secondDivisorByte) > ((r_hat << 32) + remainder[pos - 2]))是害怕上的商过大,减之后变为负数//商q_hat也不能超过32bit{q_hat--;   //否则的话,就商小一点,余数大一点r_hat += firstDivisorByte;if (r_hat < 0x100000000)   //如果余数小于32bit,就继续循环done = false;}}for (int h = 0; h < divisorLen; h++)   //取被除数的高位部分,高位部分长度与除数长度一致dividendPart[h] = remainder[pos - h];BigInteger kk(dividendPart, divisorLen);BigInteger ss = bi2 * BigInteger((__int64)q_hat);while (ss > kk)   //调节商的大小{q_hat--;ss -= bi2;}BigInteger yy = kk - ss;   //得到余数for (int h = 0; h < divisorLen; h++)  //将yy高位和remainder低位拼接起来,得到余数remainder[pos - h] = yy.data[bi2.dataLength - h];   //取得真正的余数result[resultPos++] = (unsigned int)q_hat;pos--;j--;}outQuotient.dataLength = resultPos;int y = 0;for (int x = outQuotient.dataLength - 1; x >= 0; x--, y++)   //将商反转过来outQuotient.data[y] = result[x];for (; y < maxLength; y++)   //商的其余位都要置0outQuotient.data[y] = 0;while (outQuotient.dataLength > 1 && outQuotient.data[outQuotient.dataLength - 1] == 0)outQuotient.dataLength--;if (outQuotient.dataLength == 0)outQuotient.dataLength = 1;outRemainder.dataLength = this->shiftRight(remainder, remainderLen, shift);for (y = 0; y < outRemainder.dataLength; y++)outRemainder.data[y] = remainder[y];for (; y < maxLength; y++)outRemainder.data[y] = 0;delete []remainder;delete []dividendPart;
}int BigInteger::shiftRight(unsigned int buffer[], int bufferLen,int shiftVal)   //右移操作
{//自己用图画模拟一下移位操作,就能很快明白意义了int shiftAmount = 32;int invShift = 0;int bufLen = bufferLen;while (bufLen > 1 && buffer[bufLen - 1] == 0)bufLen--;for (int count = shiftVal; count > 0; ){if (count < shiftAmount){shiftAmount = count;invShift = 32 - shiftAmount;}unsigned __int64 carry = 0;for (int i = bufLen - 1; i >= 0; i--){unsigned __int64 val = ((unsigned __int64)buffer[i]) >> shiftAmount;val |= carry;carry = ((unsigned __int64)buffer[i]) << invShift;buffer[i] = (unsigned int)(val);}count -= shiftAmount;}while (bufLen > 1 && buffer[bufLen - 1] == 0)bufLen--;return bufLen;
}BigInteger BigInteger::operator <<(int shiftVal)
{BigInteger result(*this);result.dataLength = shiftLeft(result.data, maxLength, shiftVal);return result;
}int BigInteger::shiftLeft(unsigned int buffer[], int bufferLen, int shiftVal)
{int shiftAmount = 32;int bufLen = bufferLen;while (bufLen > 1 && buffer[bufLen - 1] == 0)bufLen--;for (int count = shiftVal; count > 0; ){if (count < shiftAmount)shiftAmount = count;unsigned __int64 carry = 0;for (int i = 0; i < bufLen; i++){unsigned __int64 val = ((unsigned __int64)buffer[i]) << shiftAmount;val |= carry;buffer[i] = (unsigned int)(val & 0xFFFFFFFF);carry = val >> 32;}if (carry != 0){if (bufLen + 1 <= bufferLen){buffer[bufLen] = (unsigned int)carry;bufLen++;}}count -= shiftAmount;}return bufLen;
}bool BigInteger::operator <(BigInteger bi2)
{BigInteger bi1(*this);int pos = maxLength - 1;// bi1 is negative, bi2 is positiveif ((bi1.data[pos] & 0x80000000) != 0 && (bi2.data[pos] & 0x80000000) == 0)return true;// bi1 is positive, bi2 is negativeelse if ((bi1.data[pos] & 0x80000000) == 0 && (bi2.data[pos] & 0x80000000) != 0)return false;// same signint len = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;for (pos = len - 1; pos >= 0 && bi1.data[pos] == bi2.data[pos]; pos--) ;if (pos >= 0){if (bi1.data[pos] < bi2.data[pos])return true;return false;}return false;
}BigInteger BigInteger::operator +=(BigInteger bi2)
{*this = *this + bi2;return *this;
}BigInteger BigInteger::operator /(BigInteger bi2)
{BigInteger bi1(*this);BigInteger quotient;BigInteger remainder;int lastPos = maxLength - 1;bool divisorNeg = false, dividendNeg = false;if ((bi1.data[lastPos] & 0x80000000) != 0)     // bi1 negative{bi1 = -bi1;dividendNeg = true;}if ((bi2.data[lastPos] & 0x80000000) != 0)     // bi2 negative{bi2 = -bi2;divisorNeg = true;}if (bi1 < bi2){return quotient;}else{if (bi2.dataLength == 1)singleByteDivide(bi1, bi2, quotient, remainder);elsemultiByteDivide(bi1, bi2, quotient, remainder);if (dividendNeg != divisorNeg)return -quotient;return quotient;}
}BigInteger BigInteger::operator -=(BigInteger bi2)
{*this = *this - bi2;return *this;
}BigInteger BigInteger::operator -(BigInteger bi2)   //减法的重载
{BigInteger bi1(*this);BigInteger result;int lastPos = maxLength - 1;bool bi1Neg = false, bi2Neg = false;if ((this->data[lastPos] & 0x80000000) != 0)     // bi1 negativebi1Neg = true; if ((bi2.data[lastPos] & 0x80000000) != 0)     // bi1 negativebi2Neg = true;if(bi1Neg == false && bi2Neg == false)   //bi1,bi2都为正数{if(bi1 < bi2){result = -(bi2 - bi1);return result;}result.dataLength = (bi1.dataLength > bi2.dataLength) ? bi1.dataLength : bi2.dataLength;__int64 carryIn = 0;for (int i = 0; i < result.dataLength; i++)   //从低位开始减{__int64 diff;diff = (__int64)bi1.data[i] - (__int64)bi2.data[i] - carryIn;result.data[i] = (unsigned int)(diff & 0xFFFFFFFF);if (diff < 0)carryIn = 1;elsecarryIn = 0;}if (carryIn != 0){for (int i = result.dataLength; i < maxLength; i++)result.data[i] = 0xFFFFFFFF;result.dataLength = maxLength;}// fixed in v1.03 to give correct datalength for a - (-b)while (result.dataLength > 1 && result.data[result.dataLength - 1] == 0)result.dataLength--;// overflow checkif ((bi1.data[lastPos] & 0x80000000) != (bi2.data[lastPos] & 0x80000000) &&(result.data[lastPos] & 0x80000000) != (bi1.data[lastPos] & 0x80000000)){assert(false);}return result;}if(bi1Neg == true && bi2Neg == false)    //bi1负,bi2正{result = -(-bi1 + bi2);return result;}if(bi1Neg == false && bi2Neg == true)   //bi1正,bi2负{result = bi1 + (-bi2);return result;}if(bi1Neg == true && bi2Neg == true)   //bi1,bi2皆为负{BigInteger bi3 = -bi1, bi4 = -bi2;if(bi3 > bi4){result = -(bi3 - bi4);return result;}else{result = bi4 - bi3;return result;}}
}string BigInteger::DecToHex(unsigned int value, string format)   //10进制数转换成16进制数,并用string表示
{string HexStr;int a[100]; int i = 0; int m = 0;int mod = 0; char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};while(value > 0) { mod = value % 16; a[i++] = mod; value = value/16; } for(i = i - 1; i >= 0; i--){ m=a[i];HexStr.push_back(hex[m]);} while (format == string("X8") && HexStr.size() < 8){HexStr = "0" + HexStr;}return HexStr;
}string BigInteger::ToHexString()  //功能:将一个大数用16进制的string表示出来
{string result = DecToHex(data[dataLength - 1], string("X"));for (int i = dataLength - 2; i >= 0; i--){result += DecToHex(data[i], string("X8"));}return result;
}ostream& operator<<(ostream& output, BigInteger &obj)//以16进制输出数值
{//if ((obj.data[obj.dataLength-1] & 0x80000000) != 0)     // bi1 negativefor(int i = obj.dataLength - 1; i >= 0; i--)output << hex << obj.data[i];return output;
}bool Miller_Robin(BigInteger &bi1)   //Miller_Robin算法
{BigInteger one((__int64)1), two((__int64)2), sum, a, b, temp;int k = 0, len = primeLength / 2;temp = sum = bi1 - one;while((sum.data[0] & 0x00000001) == 0)   //只要sum不为奇数,sum就一直往右移{sum.dataLength = sum.shiftRight(sum.data, maxLength, 1);   //右移一位k++;}//sum即为要求的奇数,k即是要求的2的次数srand((unsigned)time(0));for(int i = 0; i < len; i++){a.data[i] =(unsigned int)rand ();if(a.data[i] != 0) a.dataLength = i + 1;}b = a.modPow(sum, bi1);  //b = a^m mod bi1if (b == one) return true;   for(int i = 0; i < k; i++){if(b == temp) return true;else b = b.modPow(two, bi1);  //b = b^2 mod bi1}return false;
}BigInteger GetPrime()
{BigInteger one((__int64)1), two((__int64)2), result, zero;srand((unsigned)time(0));bool flag = false;   //flag=false表示猜测该数为素数,flag=true表示该数一定为合数//随机产生一个大整数for(int i = 0; i < primeLength; i++){result.data[i] =(unsigned int)rand ();if(result.data[i] != 0)result.dataLength = i + 1;}result.data[0] |= 0x00000001;   //保证这个整数为奇数while (!flag){for(int i = 0; i < 303; i++)   //先用一些素数对这个整数进行筛选{BigInteger prime((__int64)primesBelow2000[i]);if(result % prime == zero){flag = true;break;}}if(!flag){cout << "第一轮素性检验通过… … … …" << endl;cout << "正在进行Miller_Robin素性检验… … … …" << endl;if(Miller_Robin(result))   //进行1次Miller_Robin检验return result;   //通过了就返回resultelse flag = true;   //表明result是合数,没有通过检验}if(flag)   //如果没有通过检验,就+2,继续检验result = result + two;cout << "检验没有通过,进行下一个数的检验,运行之中… … … …" << endl;cout << endl;flag = false;}
}BigInteger extended_euclidean(BigInteger n, BigInteger m, BigInteger &x, BigInteger &y)   //扩展的欧几里德算法
{  BigInteger x1((__int64)1), x2, x3(n);  BigInteger y1, y2((__int64)1), y3(m); BigInteger zero;while(x3 % y3 != zero)  {  BigInteger d = x3 / y3;  BigInteger t1, t2, t3;  t1 = x1 - d * y1;  t2 = x2 - d * y2;  t3 = x3 - d * y3;  x1 = y1; x2 = y2; x3 = y3;  y1 = t1; y2 = t2; y3 = t3;  }  x = y1; y = y2;  return y3;
} /*
BigInteger extended_euclidean(BigInteger n,BigInteger m,BigInteger &x,BigInteger &y)
{  BigInteger zero, one((__int64)1);if(m == zero) { x = one; y = zero; return n; }  BigInteger g = extended_euclidean(m, n%m, x, y);  BigInteger t = x - n / m * y;  x = y;  y = t;  return g;
}
*/BigInteger Gcd(BigInteger &bi1, BigInteger &bi2)
{BigInteger x, y;BigInteger g = extended_euclidean(bi1, bi2, x, y);return g;
}BigInteger MultipInverse(BigInteger &bi1, BigInteger &n)   //求乘法逆元
{BigInteger x, y;extended_euclidean(bi1, n, x, y);if ((x.data[maxLength-1] & 0x80000000) != 0)     // x negativex = x + n;// unsigned int i =  x.data[maxLength-1] & 0x80000000;// cout << i << endl;return x;
}

main.cpp

#include "BigInteger.h"
#include <iostream>
using namespace std;int main ( )
{string a1, b1,c1;cin >> a1;cin >> b1; BigInteger a(a1, 10),b(b1, 10); //以10进制输入//事先声明一句,答案全部以16进制输出//BigInteger c;//cout << a << endl;//c = MultipInverse(a, b);  //求乘法逆//c = Gcd(a, b);  //求a.b最大公约数//BigInteger c, one((__int64)1);//for(int i = 0; i < maxLength; i++)//    c.data[i] = 0xffffffff;//for(int i = 0; i < 10; i++)//cout << hex << c.data[i] << endl;//cout << hex << c.data[1] << endl;//cout << hex << c.data[maxLength-1];//if ((c.data[maxLength-1] & 0x8000000) != 0)//cout << flag << endl;cout << GetPrime() << endl;  //产生大素数//c = MultipInverse(a, b);//a.dataLength = a.shiftRight(a.data, maxLength, 1);//cout << c1 << endl;//c1 = a.modPow(b, n);//的确是幂模运算//cout << c1 << endl;//cout << a << endl;//cout << b << endl;//c = a / b;//c1 = c.ToHexString();  //将c变成16进制的字符串//cout << c1 << endl;//cout << c << endl;//cout << b << endl;system ("pause");return 0;
}

信息安全——大整数包的设计!相关推荐

  1. 关于大整数包的设计!

            C/C++中的int类型能表示的范围是-2E31-2E31–1.unsigned类型能表示的范围是0-2E32–1,即 0-4294967295.所以,int和unsigned类型变量 ...

  2. C++ 大整数运算 高精度除法

    前言 这篇文章主要是对于大整数类的设计过程中,如何实现并改进长除法(模拟竖式法)的一个总结. 高精度除法的分类和比较 虽然有些文章在讨论大整数的除法运算时,喜欢分成高精度除以高精度和高精度除以低精度( ...

  3. 《Python Cookbook 3rd》笔记(3.5):字节到大整数的打包与解包

    字节到大整数的打包与解包 问题 你有一个字节字符串并想将它解压成一个整数.或者,你需要将一个大整数转换为一个字节字符串. 解法 假设你的程序需要处理一个拥有 128 位长的 16 个元素的字节字符串. ...

  4. Go语言的big包实现大整数运算

    程序虽然写出来了,但是不知道如何用一个大数(例如100位的大数)去初始化一个大数变量,比较遗憾! Go语言程序: // bigint project main.go package mainimpor ...

  5. python基础第五课--从字符串中打包和解包大整数(小白piao分享)

    #4.从字符串打包和解包大整数 #将一个字符串解包成一个大整数,将一个大整数打包成一个字符串 #4.1 解决方案: #假设程序需要处理一个有16个元素的字节串,其中保存着一个128位的大整数 data ...

  6. Python字节到大整数的打包与解包

    需求:处理一个拥有128位长的16个元素的字节字符串 将bytes解析为整数,使用 int.from_bytes() 方法,并像下面这样指定字节顺序: # 为了将bytes解析为整数,使用 int.f ...

  7. Python面试题:字节到大整数的打包与解包

    需求:处理一个拥有128位长的16个元素的字节字符串 将bytes解析为整数,使用 int.from_bytes() 方法,并像下面这样指定字节顺序: # 为了将bytes解析为整数,使用 int.f ...

  8. 算法设计与分析(第四周)大整数相乘 分治法【不能解决溢出问题】

    思路 二进制 分成两半,先算左边,再算右边 结果: 2344344 110101 直接相乘:258114618744 优化算法:258114618744 请按任意键继续. . . 代码 同理写了一个十 ...

  9. 计算机算法设计与分析 大整数乘法

    大整数乘法 问题描述 求两个不超过200位的非负整数的积. 输入形式 有两行,每行是一个不超过200位的非负整数,没有多余的前导0. 输出形式 一行,即相乘后的结果.结果里不能有多余的前导0,即如果结 ...

最新文章

  1. 按下回车键指向下一个位置的一个函数
  2. poj3264(ST表模版)
  3. python 去掉字符串的
  4. vs2012中程序集生成无法自动在网站Bin目录下生成Dll文件?(已解决!)
  5. C语言各种变量的初始化
  6. springmvc登路示例(注解)
  7. 程序员的自我修养六可执行文件的装载与进程
  8. Service生命周期
  9. 【原】关于AdaBoost的一些再思考
  10. 最全编程语言在线 API 文档
  11. 设置jstree只展示到2级_你做的私域流量属于什么级别?80%的商家都还只在第2级...
  12. 【“互联网+”大赛华为云赛道】GaussDB命题攻略:支持三种开发语言,轻松完成数据库缓冲池
  13. pysimplegui 显示 html,PySimpleGUI 的第一个桌面软件
  14. 【掩耳盗铃】[转载]北京铁路局:“北京站37号窗口售票员内部大量出票”是为分区售票...
  15. 向程序发送命令失败_Word提示:“向程序发送命令时出现问题”重装软件也没用?...
  16. 从输入url到页面(二):TCP/IP 与 http协议
  17. PHP报错: Can't use method return value in write context
  18. 在软件测试中,UT,IT,ST,UAT分别是什么意思?
  19. spring核心概念
  20. 适配器模式【插头与插孔】

热门文章

  1. 基于springboot手工diy网站 毕业设计-附源码 310226
  2. (附源码)springboot基于JAVA的电影推荐系统的开发与实现 毕业设计112306
  3. 生活品质-装修(01)马桶怎么选?
  4. 若查找课程表中课程名称是计算机或英语,若查找“课程表”中课程名称是“计算机”或“英语”的记录,应在查询设计视图的“课程名称”列条件行中输入()。...
  5. 优酷路由宝增加php,优酷路由宝旗舰版YK-L2刷改华硕[N14U N54U]5G 2G的7620老毛子Padavan固件方法...
  6. [ctf.show.reverse] re3
  7. 《乔布斯传》圈点(2)
  8. cartoon drawing_drawing cartoon s是什么意思?
  9. 为什么服务器未响应ins,9修复Instagram无法正常工作,加载或崩溃的最佳方法
  10. echarts的toolbox五个小工具