DAY09_baby step gaint step

20 篇文章 1 订阅

首先说一下我遇到的问题:

DH密钥交换中 X % P= B^a % P  (P为素数)

已知X,P,B求一组(或者一个)a,存入数据库的问题。


得先求出最小的一个:

归结到数论的“baby step gaint step”

1.小步

将B^1.B^2...存入HASH表【上边界之后说,可以直接选P,但是复杂度比较高】

2.大步

降低运算的复杂度选一个上边界m = (int)ceil(sqrt((double)(p - 1))),并同时作为大步的步长

3.令a = i*m + j

走大步B^(-i*m)去HASH表中查看数值是否存在,如果存在则找到最小值a【我在是现在中用的是数组+排序+二分查找】

在求B^(-i*m)的时候要用费马小定理B^(P-1) %P = 1 %P,简单的套路证明:http://www.zybang.com/question/482b889ecae431c36ec2109bb0247461.html


找周期:

首先算出的周期是P-1,但是在验证的时候对于小素数不成立,这个问题还得想想,大家可以给一些建议


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL __int64
#define N 1000000
using namespace std;
/*
 *author by delia
*/
struct Node{
	int idx;
	LL val;
}baby[N];
bool cmp(Node n1,Node n2){
	return n1.val!=n2.val?n1.val<n2.val:n1.idx<n2.idx;
}

//先根据费马定理得到-1次方的值,然后再求出m次的值
LL PowMod(LL a,LL b,LL MOD){
	LL ret=1;
	a%=MOD;
	while(b){
		if(b&1)
			ret=((LL)ret*a)%MOD;
		a=((LL)a*a)%MOD;
		b>>=1;
	}
	return ret;
}
//BinSearch(current size, target value)
int BinSearch(int m,LL num){
	int low=0,high=m-1,mid;
	while(low<=high){
		mid=(low+high)>>1;
		if(baby[mid].val==num)
			return baby[mid].idx;
		if(baby[mid].val<num)
			low=mid+1;
		else
			high=mid-1;
	}
	return -1;
}

int main(){
	LL p,b,n;
	while(scanf("%lld%lld%lld",&p,&b,&n)!=EOF){
        //这样来取的原因是要平衡复杂度
		int m = (int)ceil(sqrt((double)(p - 1)));

		//小步:1.初始化数组0位元素 2.之后按b累计幂
		baby[0].idx=0;
		baby[0].val=1;
		for(int i=1;i<m;i++){
			baby[i].idx=i;
			baby[i].val=((LL)baby[i-1].val*b)%p;   //b^i
		}
		//形成新的有序&没有相同值的数组(id,val)
		sort(baby,baby+m,cmp);
		int cnt=1;
		for(int i=1;i<m;i++)
			if(baby[i].val!=baby[cnt-1].val)
				baby[cnt++]=baby[i];

        //大步:找出基本跨步大小m = b^(-m),累计比较是否有有相应的小步
		LL bm=PowMod(PowMod(b,p-2,p),m,p);
		int ans=-1;
		LL tmp=n;
		for(int j=0;j<m;j++){
			int pos=BinSearch(cnt,tmp);
			if(pos!=-1){
				ans=j*m+pos;
				break;
			}
			tmp=((LL)tmp*bm)%p;
		}
		if(ans<0)
			puts("no solution");
		else{
            printf("a值::%d\n",ans);

        //寻找最小周期
        //初步推断出来的最小为P-1
        int t = 0;
        LL val1 = (PowMod(b,ans+1,p))%p;
        LL val2 = n % p;
        while(val1!=val2){
            t++;
            val1 = (val1*b)%p;
        }
        t++;
        printf("对于素数%lld,最小的周期是%d\n",p,t);

		}

	}
	return 0;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值