关于随机选取16bit的素数
16bit的十进制数范围为[0—65535] ,[20,216-1],将这个范围内所有素数(大致6000+个)求出来放在数组中,通过随机选取数组元素的编号,实现随机选取p,q
关于数据类型
16bit的p,q产生的n的位数必然在32bit范围内,而对于过程中的一些辅助变量(比如高次方幂运算是会大于32bit的)
下面是各种数据类型的字节、位数、有无符号:
数据类型 | 位数 | 字节数 | 有无符号 | 数范围 |
---|---|---|---|---|
unsigned short (int) | 16位 | 2 | 无 | [0,216-1] |
int | 32位 | 4 | 有 | [-231,231-1] |
unsigned (int) | 32位 | 4 | 无 | [0,232-1] |
unsigned long long | 64位 | 8 | 无 | [0,264-1] |
所以:全局大部分变量用的是无符号的32位 unsigned int
部分变量使用64位 unsigned long long
#include
#include
using namespace std;
#define Prime_Count 6541 // [3, 65535]内的所有素数,总共有6541个素数,这6541个素数随机选取两个作为P,Q
#define BinarySize 40 // 部分数组的大小 这里只是因为40>32
//判断素数 Eratosthenes筛法:正整数n是素数,当且仅当它不能被任何一个小于sqrt(n)的素数整除
unsigned IsPrime(unsigned n)
{
unsigned temp = (unsigned )sqrt(n);
for (unsigned i = 2; i <= temp; i++)
{
if (n % i == 0) return 0;//n不是素数的话返回0
}
return 1;//n是素数的话返回1
}
//计算16bit的所有素数,即范围在[3, 65535]内的所有素数,总共有6541个素数,并赋值到数组Prime[]中 . 这里不考虑2,因为计算欧拉函数后相当于只是一个素数的欧拉函数(2-1)*(Q-1)
void All_Prime_Number(unsigned Prime[])
{
unsigned j = 0;
for (unsigned i = 3; i < 65535; i = i + 2)//i+2跳过偶数(加快循环)
{
if (IsPrime(i) == 1)
{
Prime[j] = i;
j++;
}
}
}
//在Prime[Prime_Count]中,随机挑选两个不相同的素数p,q
void RandomChoose_Prime_Number(unsigned &p, unsigned &q, unsigned Prime[])
{
srand((unsigned)time(NULL));//确保随机性
unsigned Choose_P =(unsigned)rand() % (Prime_Count );//在从[0,6540]共6541个数里面随机选一个
//cout << "Choose_P=" << Choose_P << endl;
//Plus_Q表示在P的数组标号上的增量,为了P,Q不相等(即数组下标不相等),增量的范围是[1,6540]
unsigned Plus_Q = (unsigned)rand() % (Prime_Count - 1)+1;//增量的范围是[1,6540]
//cout << "Plus_Q=" << Plus_Q << endl;
unsigned Choose_Q = (Choose_P + Plus_Q) % (Prime_Count );// % Prime_Count 是因为Choose_P + Plus_Q可能会超过6541
//cout << "Choose_Q=" << Choose_Q << endl;
p = Prime[Choose_P];
q = Prime[Choose_Q];
cout << " Bob选取的两素数为:p=" << p << "," << "q=" << q << endl;
}
//计算n和n的欧拉函数值
void N(unsigned p, unsigned q, unsigned &n, unsigned &Euler_n)
{
n =p *q;
Euler_n = (p-1) * (q-1);
cout << " Bob计算出的公钥为:{ e=5,n=" << n << "}"<<endl;
}
//求逆元d 扩展欧几里得算法(递归版) y是中间负责传递值的变量
void Eucild_D(unsigned e, unsigned Euler_n, unsigned long long& d, unsigned long long& y) // d 是 e mod Euler_n 的乘法逆元
{
if (0 == Euler_n)
{
d = 1, y = 0;
return;
}
Eucild_D(Euler_n, e % Euler_n, d, y);
unsigned long long flag = d;
d = y;
y = flag - e / Euler_n * y;
}
/*
//这是一开始的求逆元算法,一个数一个数的试,数字小还能算出来,数字大的时候时间超慢超长
void Euild_D(unsigned e, unsigned Euler_n, unsigned & d)
{
unsigned Sign_of_Inverse_Element = 0;//判断是否求出逆元的标志:Sign_of_Inverse_Element。当Sign_of_Inverse_Element=1,则求出了逆元
do
{
for (unsigned i = Euler_n/e; i < Euler_n; i++)
{
unsigned long pro=((unsigned long)i * (unsigned long)e) % Euler_n;
if (pro == 1)
{
Sign_of_Inverse_Element = 1; //Sign_of_Inverse_Element=1时表面求出了逆元d
d = i;
}
}
} while (Sign_of_Inverse_Element != 1);
cout <<"d="<< d << endl;
}
*/
//将明文串的ASCII值('abc'=(int)6382179)转为比特串,然后根据n的大小来对比特串分组,将分割后的数放入m_partition[BinarySize]中;
//Partition_count比特串分组组数 m_partition_bits比特串分组每组的位数 m_partition[]存放比特串分组的数组
void WholeASCII_to_WholeInt_to_WholeBinary_to_PartitionBinary_to_PartitionInt(unsigned n, unsigned &Partition_count, unsigned & m_partition_bits ,unsigned m_partition[])
{
//ASCII
unsigned m;
m = (unsigned )'abc';
cout <<" Alice想要发送的明文为"<< "abc"<<endl;
cout <<" 明文abc的ASCII值为" << m<< endl;
//ASCII转比特串
unsigned Positive_Binary[BinarySize] = {
0 }; //正序存放二进制数0和1,二进制的小端放在数组的小序号
unsigned Reverse_Binary[BinarySize] = {
0 }; //倒序存放二进制数0和1,二进制的大端放在数组的小序号(这个是真正的二进制表示)因为十进制整数转二进制,先逐步模二取余,然后倒序排列
unsigned remainder;//余数
unsigned index=0;//计数量
while (m != 0)
{
remainder = m % 2; //m除以2的余数
m= m / 2; //m被2整除的商
Positive_Binary[index] = remainder; //将余数存放在数组Positive_Binary[BinarySize]中,这里是正序排放,
index++;
}
cout << " 明文abc转为比特串后的比特串位数为:" << index <<"位"<< endl;
//倒序比特串
for (unsigned long i = 0; i < index; i++)
{
Reverse_Binary[i] = Positive_Binary[index-i-1];//求倒叙排列
}
cout << " 总的明文比特串为:";
for (unsigned i = 0; i < index; i++)
{
cout << Reverse_Binary[i] << setw(1);
}
cout << endl;
m_partition_bits = (unsigned )(log(n) / log(2));//对m的二进制截取的位数m_partition_bits<=[log2(n)]向下取整
cout <<" 比特串分割后每组的位数为:"<< m_partition_bits <<"位"<< endl;
unsigned Sign_of_Round_up;//向上取整的标志
if (index % m_partition_bits != 0)
{
Sign_of_Round_up = 1;}
else
{
Sign_of_Round_up = 0; }
//cout << "Sign_of_Round_up=" << Sign_of_Round_up << endl;
Partition_count = (unsigned)(index / m_partition_bits) + Sign_of_Round_up;//m根据截取的位数m_partition_bits被划分成m_Partition_count个部分
cout << " 共有" << Partition_count << "个比特串分割小组"<<endl ;
//将每个比特串分组(二进制)都转成十进制 (for 循环表达)//下面注释里还有while表达(似乎while没成功)
for (unsigned i = 0 ; i < Partition_count; i++)
{
unsigned Sign;//比特串分组的尾部元素的取值
if (index-1 <=(i + 1) * m_partition_bits - 1 )
{
Sign = index - 1;}
else
{
Sign = (i + 1) * m_partition_bits - 1; }
unsigned Sum=0;
for (unsigned j = i* m_partition_bits; j <= Sign; j++)
{
//求2的( j % m_partition_bits)次方
unsigned pow=1;
for (unsigned k = 0; k < j % m_partition_bits; k++)
{
pow = pow * 2;
}
Sum = Sum + Positive_Binary[j]*pow;// 这里用的是Positive_Binary[](小端对小端),所以是j(且用Positive_Binary[]明显要比 Reverse_Binary[BinarySize] 便于计算)
}
m_partition[i] =(unsigned )Sum;
cout << " 第" << i +1<< "个明文分割小组的值为" << m_partition[i] << endl;
}
/*
unsigned ZLS=0;
while (ZLS < Partition_count)
{
cout << "ZLS=" << ZLS << endl;
unsigned Sign;
if (index - 1 <= (ZLS + 1) * m_partition_bits - 1)
{
Sign = index - 1;
}
else
{
Sign = (ZLS + 1) * m_partition_bits - 1;
}
cout << "Sign=" << Sign << endl;
unsigned Sum = 0;
for (unsigned j =ZLS * m_partition_bits; j <= Sign; j++)
{
unsigned pow = 1;
for (unsigned k = 0; k < j % m_partition_bits; k++)
{
pow = pow * 2;
}
cout << "pow = " << pow << endl;
Sum = Sum + Positive_Binary[j] * pow;// 这里用的是Positive_Binary[](小端对小端),所以是j(且用Positive_Binary[]明显要比 Reverse_Binary[BinarySize] 便于计算)
}
m_partition[ZLS] = (unsigned )Sum;
cout << "m_partition[" << ZLS << "]=" << m_partition[ZLS] << endl;
ZLS = ZLS + 1;
}
*/
}
//对于明文m_partition[BinarySize]的加密,得到c_partition[BinarySize]
void E_M(unsigned m_partition[], unsigned Partition_count, unsigned e, unsigned n, unsigned c_partition[])
{
for (unsigned i = 0; i < Partition_count; i++)
{
unsigned long long product = 1;//product表示m_partition[i]自身不断相乘的积
for (unsigned j = 1; j <= e ; j++)//用e来控制m_partition[i]的指数
{
product = (product * m_partition[i]) % n;//注意不要忘记%n
}
c_partition[i] = (unsigned )product;
cout << " 第" << i +1<< "个明文分割小组加密后的值为" << c_partition[i] << endl;
}
//cout << endl;
}
//把c_partition[BinarySize] 以二进制的形式在信道传播
//对密文c_partition[BinarySize]的解密,得到After_m_partition[BinarySize]
void D_C(unsigned c_partition[], unsigned Partition_count, unsigned d, unsigned n, unsigned After_m_partition[])
{
unsigned long long N = (unsigned long long)n;
for (unsigned i = 0; i < Partition_count; i++)
{
unsigned long long product = 1;//product表示c_partition[BinarySize]自身不断相乘的积
for (unsigned long long j = 1; j <= d; j++)//用d来控制c_partition[BinarySize]的指数
{
product = ( product * (unsigned long long)c_partition[i]) % N;//注意不要忘记%n
}
After_m_partition[i] = (unsigned)product;
cerr << " 第" << i +1<< "个密文分割小组解密后的值为" << After_m_partition[i] << endl;
}
}
//将分割的After_m_partition[BinarySize]合并成大整数,然后转为字符串C
void PartitionInt_to_WholeInt_to_WholeASCII(unsigned After_m_partition[], unsigned m_partition_bits,unsigned Partition_count,char str[])
{
unsigned Sum_After_m_partition_bits=0;
unsigned C_Sum=0;
for (unsigned i = 0; i < Partition_count; i++)
{
unsigned pow = 1;
for (unsigned k = 0; k < Sum_After_m_partition_bits; k++)
{
pow = pow * 2;
}
//cout << "pow=" << pow << endl;
C_Sum = C_Sum + pow* After_m_partition[i];
//cout << "C_Sum=" << C_Sum << endl;
Sum_After_m_partition_bits = Sum_After_m_partition_bits+ m_partition_bits;
}
//如何把str[]直接转成char C?
str[0] = (char)(C_Sum & 0xff);
str[1] = (char)((C_Sum >> 8) & 0xff);
str[2] = (char)((C_Sum >> 16) & 0xff);
str[3] = (char)((C_Sum >> 24) & 0xff);
cout << " Bob解密后得到的明文为:" << str[2] << str[1] << str[0] << endl;
}
int main()
{
unsigned Prime[Prime_Count];
unsigned p , q ;
unsigned n, Euler_n;
unsigned e = 5;
unsigned long long d,y;
unsigned Partition_count;
unsigned m_partition_bits;
unsigned m_partition[BinarySize];
unsigned c_partition[BinarySize];
unsigned After_m_partition[BinarySize];
cout << "《Bob想要收到来自他人的信息,于是Bob开始制作公私密钥》" << endl;
cout << "{"<<endl;
//求所有素数,并随机选取两素数
All_Prime_Number(Prime);
RandomChoose_Prime_Number(p, q, Prime);
//计算n,和n的欧拉函数
N(p, q,n, Euler_n);
//计算逆元d
Eucild_D( e, Euler_n, d,y);
cout << " Bob计算出的秘密钥:{ d=" << d << ",n="<<n<<"}"<<endl;
cout << "}" << endl;
cout << endl<<endl;
cout << "《Bob将计算出来的公钥广播发给所有人:"<<"“ 我是Bob,想要给我发消息,就用这个公钥:{ e=5,n=" << n << "}”》"<< endl<<endl<<endl;
cout << "《Alice想要给Bob发送明文,于是Alice开始对明文加密》" << endl;
cout << "{" << endl;
//对明文分割并加密明文
WholeASCII_to_WholeInt_to_WholeBinary_to_PartitionBinary_to_PartitionInt( n, Partition_count, m_partition_bits, m_partition);
E_M(m_partition, Partition_count, e, n, c_partition);
cout << "}" << endl;
cout <<endl<<endl;
//Alice将密文通过信道发送给Bob
cout << "《Alice将密文通过信道发送给Bob》"<<endl<<endl<<endl;
cout << "《Bob收到密文后开始解密》"<<endl;
cout << "{" << endl;
//解密密文
D_C(c_partition, Partition_count, d, n, After_m_partition);
char str[4];
PartitionInt_to_WholeInt_to_WholeASCII(After_m_partition, m_partition_bits,Partition_count, str);
cout << "}" << endl;
cout << endl << endl<<endl;
system("pause");
return 0;
}
1.欧几里得求逆元的函数是从别处找的代码,还没研究具体流程和原理是什么。但是已经发现有时候d会被赋值为1,造成解码出错
2.当d大于15亿,运算时间超长,算不出来结果。