与背包算法一样,这算法也是一个非对称算法。这里不写证明之类的定理推论了,需要的话网上可以搜到到很多,书本例如算法导论也有详细的证明。简写一下算法的步骤:
#include <stdio.h> #include <stdlib.h> #include <time.h> int bi[1000]; typedef struct Tri//三元组结构 { __int64 d,x,y; }Tri; __int64 Modular_Exponentiation(__int64 a,__int64 b,__int64 n) { __int64 i,c=0,d=1; for(i=0;b;i++)//十进制转为二进制 { bi[i]=b%2; b=b>>1; } for(i=i-1;i>=0;i--)//由二进制高位开始反复平方 {//变量c没实际用处,只用来理解运算过程 c=c*2,d=d*d%n; if(bi[i]) c=c+1,d=d*a%n; // printf("%I64d: bi=%I64d c=%I64d d=%I64d\n",i,bi[i],c,d); } return d; } bool Witness(__int64 a,__int64 n) {//以a作基,测试n是否为合数,返回true为合数,false不为合数。 __int64 x,temp,i,b=n-1,t,len,u=0,sum;//n-1=2^t*u,u为奇数 for(i=0;b;i++) {bi[i]=b%2;b=b>>1;} len=i-1; for(i=t=0;!bi[i];i++) t++; for(i=t;i<=len;i++)//求出u { temp=i-t; if(bi[i]==0) continue; sum=1; while(temp) { sum*=2; temp--; } u+=sum; } // printf("u=%I64d\n",u); x=Modular_Exponentiation(a,u,n); for(i=0;i<t;i++) { temp=x; x=x*x%n; if(x==1&&temp!=1&&temp!=n-1) return true;//仅当n为合数时,对模n才可能存在1的非平凡平方根 } if(x!=1) return true;//费马定理 return false; } bool Miller_Rabin(__int64 n,__int64 s) {//判断素数 __int64 i,a; for(i=0;i<s;i++) { a=0; while(!a) a=rand()%n+1; // printf("a=%I64d\n",a); if(Witness(a,n)) return false;//确定是合数 } return true;//很可能是素数 } Tri Extend_Euclid(__int64 a,__int64 b) {//扩展欧几里德算法 Tri t,t2; if(b==0) {t.d=a,t.x=1,t.y=0;return t;} t2=Extend_Euclid(b,a%b); t.d=t2.d;t.x=t2.y;t.y=t2.x-a/b*t2.y; return t; } __int64 Find_E(__int64 n) {//寻找与(P-1)*(Q-1)互质的小奇数E Tri t; __int64 i; do { i=rand()%97+3;//随即生成3-100内的数 // printf("i=%I64d\n",i); if(i%2)//判断是否奇数 t=Extend_Euclid(i,n); if(t.d==1) return i;//若互质,找到 }while(1); return 0; } __int64 Encode(__int64 PT,__int64 E,__int64 N) { __int64 CT; CT=Modular_Exponentiation(PT,E,N); return CT; } __int64 Decode(__int64 CT,__int64 D,__int64 N) { __int64 PT; PT=Modular_Exponentiation(CT,D,N); return PT; } void RSA() { Tri t; __int64 D,E,N,P,Q,sign,input,CT,PT; srand(time(NULL)); do//假设随机选出50-100内的素数P { P=rand()%50+50; // printf("P:%I64d\n",P); }while(!Miller_Rabin(P,10)); do//假设随机选出50-100内的素数Q { Q=rand()%50+50; if(P==Q) continue;//P不能等于Q // printf("Q:%I64d\n",Q); }while(!Miller_Rabin(Q,10)); printf("随机素数P=%I64d,Q=%I64d\n",P,Q); N=P*Q; printf("N=P*Q=%I64d\n",N); E=Find_E((P-1)*(Q-1));//随即产生公钥 printf("公钥E为:%I64d\n",E); t=Extend_Euclid(E,(P-1)*(Q-1));//求逆元私钥 D=t.x; while(D<=0) D+=(P-1)*(Q-1);//将负逆元转正 printf("私钥D为:%I64d\n",D); printf("请输入解密(0)/加密(1)标记和数字文本(%I64d<=数字<=%I64d)\n",-N+2,N-2); printf("输入:%I64d %I64d退出\n",N,N); while(scanf("%I64d %I64d",&sign,&input),sign!=N||input!=N) { if(sign)//加密 { CT=Encode(input,E,N); printf("加密后密文:%I64d\n",CT); } else//解密 { PT=Decode(input,D,N); printf("解密后明文:%I64d\n",PT); } } return ; } int main() { RSA(); return 0; }