用生日攻击方法求解离散对数问题(C语言实现)-大三密码学实验

实验原理:

生日攻击:输入为生成元a的阶p-1和元b,输出为离散对数x= log_{a}^{b}。设置两个长度为p的列表:

1)列表1包含a^{k} mod p,通过随机选取p个k得到;                                                                         

 2)列表2包含b a^{-l}modp,通过随机选取p个l得到;                                                                     

则在两个列表中很有可能出现重复的项,即a^{k}=ba^{-l},因此a^{k+l}=b(mod p),那么x=k+l(mod(p-1))就是要找的离散对数。

生日攻击是一个概率算法,无法保证一定能得到输出结果。

实验内容:

 a.简单的同余函数的构造

int tongyu(int a,int m,int n){//递归原理 
	long long int temp=a%n,ans;
	if(m==1){
		ans=temp;
	}
	else if(m>=2){
		ans=(temp*tongyu(a,m-1,n))%n;
	}
	return ans;
}

 原理:(a*b)mod c=((a mod c)*(b mod c))mod c

这里是a^{m}mod n,m逐步减小,直到1

但是这个顶多m为10000多,再多就不能运行了,而我们如果需要计算很大的m,就需要分解计算

b.对较大数字的拆分

void chaifen(int a,int b[10]){//把a按照万,千,百,十,个位上的数字区分开来,便于计算 
	int i,temp=10000;
	for(i=0;i<5;i++){
		b[i]=a/temp;
		a=a%temp;
		temp/=10;
	}
}

数组b是用来储存a的万位,千位,百位,十位,个位上的值

类似于水仙花数的处理

c.求a的10000,1000,100,10,1的次方的mod p

void qiu_cd(int c1[10],int a,int p){
	int temp=10000;
	for(int i=0;i<5;i++)//求对于a的10000,1000等次方对于p的求余 
	{
		c1[i]=tongyu(a,temp,p);
		temp/=10;
	}

}

d.对a的万位,千位,百位,十位,个位的值的次方分别求余

void cheng(int p,int c1[10],int c11[10],int c111[10]){//各位上的数字的求余 
	for(int i=0;i<5;i++){
		if(c11[i]>0){
			c111[i]=tongyu(c1[i],c11[i],p);
		}
		else{
			c111[i]=0;
		}
	}
}

如果c11[i]=0,直接置0,否则就用用到tongyu函数,(a*b)mod c=((a mod c)*(b mod c))mod c

 e.对a各个位的值整合起来

long long int result_c(int a, int c1[10],int p,int c11[10],int c111[10]){//输出列表的值 
	long long int temp=1; 
	chaifen(a,c11);
	cheng(p,c1,c11,c111);
	for(int j=0;j<5;j++){//万位到个位上的求余结合起来 
		if(c111[j]!=0){
			temp=((temp%p)*(c111[j]%p))%p;			
		}
	}
	return temp;
}

也是利用那个公式(a*b)mod c=((a mod c)*(b mod c))mod c

但是c111[j]=0不能带进去,因为会使得一个乘数为0,整体为0

f.构造列表并比较

void bijiao(int p,int a, int b,int p1,long long int c[15000][2],unsigned long long int ans,long long int d[15000][2],int c1[10],int c11[10],int c111[10],int count){
	int flag=0;
	for(int i=0;i<p1;i++){//求第一个列表 
		c[i][0] = 1+ rand() % (p-2);
		c[i][1] = result_c(c[i][0],c1,p,c11,c111);
	}
	for(int i=0;i<p1;i++){//求第二个列表 
		d[i][0] = 1+ rand() % (p-2);
		ans=result_c(d[i][0],c1,p,c11,c111);
		ans=((b%p)*ans)%p;
		d[i][1]=ans;
	}
	for(int i=0;i<p1;i++){		
		for(int j=0;j<p1;j++){
			if(c[i][1]==d[j][1]){//如果找到 
				cout<<"能找到离散对数x="<<c[i][0]-d[j][0]<<"(mod "<<p-1<<")"; 
				flag=1;
				break;
			}
		}
		if(flag==1){//如果找到了,跳出循环 
			break;
		}
	}
	count++;
	if(count>10){//超过十轮,还是没找到 
		cout<<"找不到";
		flag=1;
	}
	if(flag==0){
		bijiao(p,a,b,p1,c,ans,d,c1,c11,c111,count);
	}
}

rand是随机数,rand()%(b),表明随机生成0-b之间的数字

两个for循环找相同值,找不到继续找,进入下一轮,再次调用bijiao函数,如果找了十轮还没找到,就说明真的很难找,建议不找,找到了通过flag跳出两个for循环。

g.总函数

#include<iostream>
#include<stdlib.h>
#include<time.h>
#include<math.h>
using namespace std;
int tongyu(int a,int m,int n){//递归原理 
	long long int temp=a%n,ans;
	if(m==1){
		ans=temp;
	}
	else if(m>=2){
		ans=(temp*tongyu(a,m-1,n))%n;
	}
	return ans;
}

void cheng(int p,int c1[10],int c11[10],int c111[10]){//各位上的数字的求余 
	for(int i=0;i<5;i++){
		if(c11[i]>0){
			c111[i]=tongyu(c1[i],c11[i],p);
		}
		else{
			c111[i]=0;
		}
	}
}

void chaifen(int a,int b[10]){//把a按照万,千,百,十,个位上的数字区分开来,便于计算 
	int i,temp=10000;
	for(i=0;i<5;i++){
		b[i]=a/temp;
		a=a%temp;
		temp/=10;
	}
}

void qiu_cd(int c1[10],int a,int p){
	int temp=10000;
	for(int i=0;i<5;i++)//求对于a的10000,1000等次方对于p的求余 
	{
		c1[i]=tongyu(a,temp,p);
		temp/=10;
	}

}


long long int result_c(int a, int c1[10],int p,int c11[10],int c111[10]){//输出列表的值 
	long long int temp=1; 
	chaifen(a,c11);
	cheng(p,c1,c11,c111);
	for(int j=0;j<5;j++){//万位到个位上的求余结合起来 
		if(c111[j]!=0){
			temp=((temp%p)*(c111[j]%p))%p;			
		}
	}
	return temp;
}
void bijiao(int p,int a, int b,int p1,long long int c[15000][2],unsigned long long int ans,long long int d[15000][2],int c1[10],int c11[10],int c111[10],int count){
	int flag=0;
	for(int i=0;i<p1;i++){//求第一个列表 
		c[i][0] = 1+ rand() % (p-2);
		c[i][1] = result_c(c[i][0],c1,p,c11,c111);
	}
	for(int i=0;i<p1;i++){//求第二个列表 
		d[i][0] = 1+ rand() % (p-2);
		ans=result_c(d[i][0],c1,p,c11,c111);
		ans=((b%p)*ans)%p;
		d[i][1]=ans;
	}
	for(int i=0;i<p1;i++){		
		for(int j=0;j<p1;j++){
			if(c[i][1]==d[j][1]){//如果找到 
				cout<<"能找到离散对数x="<<c[i][0]-d[j][0]<<"(mod "<<p-1<<")"; 
				flag=1;
				break;
			}
		}
		if(flag==1){//如果找到了,跳出循环 
			break;
		}
	}
	count++;
	if(count>10){//超过十轮,还是没找到 
		cout<<"找不到";
		flag=1;
	}
	if(flag==0){
		bijiao(p,a,b,p1,c,ans,d,c1,c11,c111,count);
	}
}
int main(){
	int a,b,p,p1,count=0;
	unsigned long long int ans=0;//p1为p的开方,ans中间值,count为轮数 
	long long int c[15000][2],d[15000][2];//c,d为两个列表 
	int c1[10],c11[10],c111[10];//c1为求a的10000等对p的余,c11为随机数的各个位上的数,c111为各个位上余数的集合 
	cout<<"输入三个数:";
	cin>>a>>b>>p;
	p1=int(sqrt(p));//求关于p的开方 
	qiu_cd(c1,a,p);//求c1 
	bijiao(p,a,b,p1,c,ans,d,c1,c11,c111,count);
	return 0;
}

h.测试结果

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值