历史上第一个称得上算法的好像就是这个欧几里得算法,其实就是地球人都知道的辗转相除,故又叫“辗转相除法”不要小看她,她是很美的。
简单的描述就是,记gcd(a,b)表示非负整数a,b的最大公因数,那么:gcd(a,b)
= gcd(b,a%b)
Euclid算法定义:
gcd(a,b)=gcd(b, a+kb) a,b,k为任意整数,即gcd(a,b)=gcd(b, a mod b) a≥0,b>0
• Example:gcd(55,22)=gcd(22, 55mod22)=gcd(22,11)=11
证明:假定d=gcd(a,b),那么有d|a和d|b.对任何正整数b,a,可表示为如下形式: a=kb+r ≡r mod b, a mod b =r , 因此,有(a mod b )= a-kb,k为某个整数。但由于d|b,b也能整除kb, 而d|a,故有d|(a mod b), 这表明d 也是b 和(a mod b) 的公因子。由于这是可逆的,如果d 是b 和(a mod b) 的公因子,那么d|kb,且d|[kb+(a mod b)],这等同于d|a。这样a和b的公因子集合等同于b 和(a mod b) 的公因子集合。
Euclid算法的应用:
求两个数的最大公约数gcd(55,22)=gcd(22, 55mod22)=gcd(22,11)=11
最常用的就是在RSA里边求密钥
RSA算法,是非对称加密的标准算法,其实算法很简单:
找到两个素数p,q,再找一个数r,使gcd(r,(p-1)(q-1))=1,也就是说互素,然后再找一个数m,使rm=1(mod (p-1)(q-1)),然后再作乘法n=pq,然后把pq丢掉,最好是让任何人都不知道,包括自己(免得说梦话的时候被人听到),然后手里拿到r,m,n,r就是Private Key,只有你知道,而m,n就是Public Key。设信息为a,加密过程:a^r=b (mod n),b就是密文,解密过程:b^m=a(mod n),反过来用m加密,用r解密是一样的。
Euclid算法在RSA密码体系中的实现
#include<iostream.h>
#include<math.h>
#include <windows.h>
int mul(int x,int r,int n);//大树幂乘
int niyuan(int n,int u); //求逆元
int gcd(int a,int b);//求最大公约数
bool IsPrime(int a );//判断是否为素数
void main()
{
system("color 3f");
system("title ☆★ RSA公钥密码 ★☆");
cout<<"\t\t****RSA公钥密码加密解密系统****"<<endl;
int p ,q ;
cout<<" 请输入两个素数 :p , q :"<<endl;
cin>>p>>q;
int n=p*q;
int w=(p-1)*(q-1);
int e;
cout<<"请输入加密密钥 e (与"<<w<<"最大公约数为 1 )"<<endl;
cin>>e;
int d;
d=niyuan(w,e);
cout<<"经计算解密得到密钥 :"<<d<<endl;
cout<<"输入需要加密的明文:"<<endl;
int ming;
cin>>ming;
cout<<"经加密后得到的密文:"<<mul(ming,e,n)<<endl;
cout<<"退出系统请按 1 "<<endl;
cout<<"进行解密请按 2 "<<endl;
int k;
cin>>k;
if(k==2)
{
cout<<"请输入需解密的密文:"<<endl;
int miwen;
cin>>miwen;
cout<<"经解密后得到的明文:"<<mul(miwen,d,n)<<endl;
}
}
int mul(int x,int r,int n)//大树幂乘函数
{
int a=x;
int b=r;
int c=1;
while(b!=0)
{
if(b%2!=0)
{
b=b-1;
c=(c*a)%n;
}
else
{
b=b/2;
a=(a*a)%n;
}
}
return c ;
}
int niyuan(int n,int u)//求逆元
{
int n1=n;
int n2=u;
int b1=0;
int b2=1;
int q=n1/n2;
int r=n1-q*n2;
while(r!=0)
{
n1=n2;
n2=r;
int t=b2;
b2=b1-q*b2;
b1=t;
q=n1/n2;
r=n1-q*n2;
}
if(n2!=1)
{
return 0 ;
}
else
{
return (b2+n)%n;
}
}
int gcd(int a,int b)//求最大公约数
{
int n1=a;
int n2=b;
int q=n1/n2;
int r=n1-q*n2;
while(r!=0)
{
n1=n2;
n2=r;
q=n1/n2;
r=n1-q*n2;
}
return n2 ;
}
bool IsPrime(int a)//判断是否为素数
{
int b=(int)sqrt(a);
int temp;
for(int i=2;i<=b;i++)
{
temp=a%i;
}
if(temp==0)
{
return false ;
}
else
{
return true ;
}
}
shell 中求最大公约数:
#!/bin/bash
# gcd.sh: greatest common divisor
# Uses Euclid's algorithm
# The "greatest common divisor" (gcd) of two integers
#+ is the largest integer that will divide both, leaving no remainder.
# Euclid's algorithm uses successive division.
# In each pass,
#+ dividend <--- divisor
#+ divisor <--- remainder
#+ until remainder = 0.
#+ The gcd = dividend, on the final pass.
## ------------------------------------------------------
# Argument check
ARGS=2
E_BADARGS=65
if [ $# -ne "$ARGS" ]
then
echo "Usage: `basename $0` first-number second-number"
exit $E_BADARGS
fi
# ------------------------------------------------------
gcd ()
{
dividend=$1 # Arbitrary assignment.
divisor=$2 #+ It doesn't matter which of the two is larger.
# Why not?
remainder=1 # If uninitialized variable used in loop,
#+ it results in an error message
#+ on the first pass through loop.
until [ "$remainder" -eq 0 ]
do
let "remainder = $dividend % $divisor"
dividend=$divisor # Now repeat with 2 smallest numbers.
divisor=$remainder
done # Euclid's algorithm
} # Last $dividend is the gcd.
gcd $1 $2
echo; echo "GCD of $1 and $2 = $dividend"; echo
# Exercise :
# --------
# Check command-line arguments to make sure they are integers,
#+ and exit the script with an appropriate error message if not.
exit 0
---------------------相关链接--------------------
http://www.jimloy.com/number/euclids.htm
本文出自 “mr.DATABASE” 博客,谢绝转载!