辗转相除法求模逆(C语言)

其实,一直就想写这篇博客的,因为上次在写RSA程序,我看了网上的资料都不够简洁,有的提到了方法,但是代码却不够简便,例如欧几里得扩展算法的矩阵形式,以及商的倒序求逆,方法众多,但是代码实现却感觉有点复杂。况且我也看了前人的博客,需要开辟空间对商进行存储。这次我就把我目前感觉最简单的求模逆方法分享给大家~有错误请大家多多指出!

问题:

求e关于模p的逆元d,即要求出整数d,使e * d mod p = 1 (或 ed+px=1),这里要求e与p互素。

方法:

这里是引用初等数论(严士健 第三版)第27页的辗转相除法的表格形式的辗转相除法。

首先我们先要引入概念:
对于二元一次不定方程的求解:
即 ax+by=1的求解方法,

ax+by=1,(a,b)=1
a=bq1 + r 1 , 01 b=r1q2 + r 2 , 02 1 ,
……
rn-2 =rn-1 qn + rn , 0n n-1 ,
rn-1 =rn qn+1 .

因为(a,b)=1,故rn =1
于是有 a[(-1)n-1Qn ]+b[(-1)nPn ]=1
P0 =1 , P1 =q1 ,Pk =qk Pk-1 +Pk-1 ,
Q0 =0 , Q1 =1,Qk =qk Qk-1 +Qk-1 ,
k=2,…,n.

由于我时间不是很多,我就不举具体例子了 ,防止大家视疲劳我还是手写吧。
辗转相除法求模逆(C语言)_第1张图片
直接上代码 ,代码思想就是我所列举的辗转相除法思想,具体证明过程有兴趣的朋友可以参考:《初等数论》(第三版)作者:闵嗣鹤 严士健
第一章ξ3定理1的证明过程 以及 第二章ξ1定理2的证明过程
(不过看到好像这么多观看量,我还是列出来吧~~)

数学证明:

定理1:若a,b是任意两个正整数,则
Qk a - Pk b = (-1)k-1 rk ,k=1,…,n;
其中
P0 =1 , P1 =q1 ,Pk =qk Pk-1 +Pk-2 ,
Q0 =0 , Q1 =1,Qk =qk Qk-1 +Qk-2 ,
k=2,…,n.

证:

当k=1时,上式显然成立,当k=2时,
r2 = -[aq2 - b(1 +q1 q2 )].

1 +q1 q2 =q2 P1 +P0 ,
q2 =q2 *1 +0 = q2 Q1 +Q0 ,

Q2 a - P2 b = (-1)2-1 r2 ,
P2 =q2 P1 +P0 ,
Q2 =q2 Q1 +Q0
假定上述式子对于不超过k>=2的正整数都成立,则
(-1)k rk+1
= (-1)k (rk-1 - qk+1 rk )
= (Qk-1 a - Pk-1 b) + qk+1 (Qk a - Pk b)
= (qk+1 Qk + Qk-1 )a - (qk+1 Pk + Pk-1 )b.

Qk a - Pk b = (-1)k-1 rk ,
其中
Pk+1 =qk+1 Pk +Pk-1 , Qk+1 =qk+1 Qk +Qk-1 ,
由归纳法,定理为真

代码:

我们先判断素数,素数的判断方法我所知道的有三种,纳筛法,miller-素性检验,暴力求解,miller-素性检验和纳筛法由于我的实验报告被我清理文件的时候删了,我就用我同学的暴力求解法(一般小素数我们为了节约时间优先考虑纳筛法,但是对于大素数推荐采用miller-素性检验,但是miller素性检验是概率算法,1/4可能性会产生伪素数,需要多次验证,验证k次,产生伪素数的可能性就减少为(1/4)k

//判断n是否为素数,此处使用最暴力的方法,将n取余小于n的所有值
void searchprime(int n)
{
	   int i;
	   for(i=2;i<=n-1;i++)
	   {
		   if(n%i==0)
			   break;
	   }//将小于n的数依次除n,若可以整除,则不是素数,退出循环
       if(i<n-1)
		  printf("%d不是素数\n",n);
	   else
		  printf("%d是素数\n",n);
}

然后我们进行求模逆操作

//模逆运算,用模逆算法,此处编写程序时候u,v为实际计算过程中v的各个值
int mod_invese(int d,int n)//求d模n的逆,n 为正整数
{
    int a,b,q,r,u=0,v=1,t;//a为被除数,b为除数,q为商
    a=n;
    b=(d>=0)?(d%n):-(d%n);//规定正负数mod(n)都取正;
    while(b!=0)
	{
        q=(int)a/b;
        r=a-b*q;
        a=b;
        b=r;
        t=v;
        v=u-q*v;
        u=t;//把每次没有进行运算的v的值给u
	}//辗转相除,直到余数b=0,跳出循环
    if(a!=1) return 0;
    return((u<0)?u+n:u);//返回的值都是mod(n)后的值,使得最后的值是正数;
}

你可能感兴趣的:(数论,数论,辗转相除法,求模逆,c语言)