最近没有什么事情,打算把之前的作业整理一下发出来,有需要的学弟学妹们可以参考一下。
相关:某电的密码学实验,信安专业必选实验
实验题目:中国剩余定理
实验目的
(包括实验环境、实现目标等等)
实验环境:
Windows 10
Visual studio 2017
Miracl库
实验目标:
1.通过算法编程,熟悉使用miracl库的基本函数操作
2.通过编程实现中国剩余定理,加深对于中国剩余定理的理解与运用
3.体会密码学与数论的紧密联系
4.提高逻辑思维能力
方案设计
2.1背景
一千多年前的《孙子算经》中,有这样一道算术题:“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?”按照今天的话来说:个数除以三余二,除以五余三,除以七余二,求这个数。《孙子算经》给出了一个非常有效的巧妙解法。术曰:“三、三数之剩二,置一百四十;五、五数之剩三,置六十三;七、七数之剩二,置三十,并之,得二百三十三。以二百一十减之,即得。凡三、三数之剩一,则置七十;五、五数之剩一,则置二十一;七、七数之剩一,则置十五。一百六以上,一百五减之,即得。
后来流传的《孙子歌》中所说“七十稀”、“廿一枝”和“正半月”,就是暗指这三个关键的数字。《孙子算经》没有说明这三个数的来历。实际上,它们具有如下特性:也就是说,这三个数可以从最小公倍数M=3×5×7=105中各约去模数3、5、7后,再分别乘以整数2、1、1而得到。假令k1=2,K2=1,K3=1,那么整数Ki(i=1,2,3)的选取使所得到的三数70、21、15被相应模数相除的时候余数都是1。由此出发,立即可以推出,在余数是R1、R2、R3的情况下的情况。应用上述推理,可以完全类似地把孙子算法推广到一般情形:设有一数N,分别被两两互素的几个数a1,a2,…,an相除得余数R1,R2,…,Rn,即N≡Ri(mod ai)(i=1,2,…,n),只需求出一组数K,使满足1(mod ai)(i=1,2,…,n),那么适合已给一次同余组的最小正数解是P是整数,M=a1×a2×…×an),就是现代数论中著名的剩余定理。
2.2原理
2.3 原理证明
2.4算法步骤
方案实现
3.1 算法流程图
3.2 主要函数
(1)mirsys()
函数原型:miracl *mirsys(nd,nb)
参数类型:int nd,nb
功能:初始化MIRACL系统,该函数必须在调用MIRACL库函数之前先执行,函数的返回值是是一个miracl实例指针,通过它可以访问所有实例变量,如果没有足够的内存来创建实例,则为NULL
Eg: miracl *mip=mirsys(500,10);
意思是定义的这些变量最大长度都是500位(这个位是后面进制的位数),输入、输出、运算用的进制都是10进制。
(2)mirvar()
函数原型:flash mirvar(iv)
参数类型:int iv
功能:通过为big/flash变量保留适当数量的内存位置来初始化该变量。这个内存可以通过随后调用mirkill函数来释放, 在程序中,每个big型变量都必须赋初始值,否则会出错。
(3)cinnum()
函数原型:int cinnum(x,f)
参数类型:big x; FILE *f
功能:从键盘或文件中输入一个big类型变量,以实例变量IOBASE的当前值作为数。从键盘输入时,将f指定为stdin,否则指定为其他打开文件的描述符。
(4)cotnum()
函数原型:int cotnum(x,f)
参数类型:big/flash x;FILE *f
功能:将当前分配给实例变量IOBASE的值作为基数,输出一个big/flash的变量到屏幕或文件中参数一个big/flash x和一个文件描述符f。如果f是stdout,则输出到屏幕,否则输出到用描述符f打开的文件。
(5)egcd()
函数原型:int egcd(x,y,z)
参数类型:big x,y,z;
功能:用来计算两个大数的最大公约数, 即z=gcd(x,y)。
(6)mr_compare()
函数原型:int mr_compare(x,y)
参数类型:big x; big y
函数功能:比较两个大数的大小
返回值:x>y时返回+1, x=y时返回0, x<y时返回-1 在这里需要注意的是,mr_compare()函数比较的是两个big类型的数,此函数的返回值是int型的+1和-1。
(7)multiply()
函数原型:void multiply(x,y,z)
参数类型:big x,y,z
功能:计算两个大数的乘积,即z=x*y。
(8)xgcd()
函数原型:int xgcd(x,y,xd,yd,z)
参数类型: big x,y,xd,yd,z;
功能: 计算两个大数的扩展最大公约数,也可以用来计算模逆,这个函数比mad函数运算速度稍慢。z=gcd(x,y)=x.xd+y.yd,在此算法实现中,我选择此函数来进行模逆运算。
(9)add()
函数原型:void add(x,y,z)
参数类型:big x,y,z
功能:计算两个大数的和,即z=x+y。
(10)powmod()
函数原型:void powmod(x,y,z,w)
参数类型:big x,y,z,w;
功能:用来进行模幂运算,用表达式表示为w=x^y mod z。
3.3算法实现的代码
#include<stdlib.h>
#include "miracl.h"
#define MAXSIZE 100
int main()
{
miracl *mip = mirsys(5000, 160); //初始化miracl系统
mip->IOBASE = 10;
FILE *fp;
char fname[MAXSIZE];//存放文件名称的数组
big a1, a2, a3, m1, m2, m3, e1, e2, e3, one, Ma, Mb, Mc, Ma1, Mb1, Mc1, fu, x, m;
a1 = mirvar(0);//初始化参数
a2 = mirvar(0);
a3 = mirvar(0);
m1 = mirvar(0);
m2 = mirvar(0);
m3 = mirvar(0);
e1 = mirvar(0);
e2 = mirvar(0);
e3 = mirvar(0);
one = mirvar(1);
fu = mirvar(-1);
x = mirvar(0);
m = mirvar(0);
Ma = mirvar(0);
Mb = mirvar(0);
Mc = mirvar(0);
Ma1 = mirvar(0);
Mb1= mirvar(0);
Mc1= mirvar(0);
printf("please input the path of file: ");
scanf("%s", fname);
fp = fopen(fname, "r+");
if (fp == NULL)
{
printf("File open error!");
return 0;
}
else
{//读入数据
cinnum(a1, fp);
cinnum(a2, fp);
cinnum(a3, fp);
cinnum(m1, fp);
cinnum(m2, fp);
cinnum(m3, fp);
}
fclose(fp);
//数字读取完毕,输出到屏幕上
printf("a1 = ");
cotnum(a1, stdout);
printf("a2 = ");
cotnum(a2, stdout);
printf("a3 = ");
cotnum(a3, stdout);
printf("m1 = ");
cotnum(m1, stdout);
printf("m2 = ");
cotnum(m2, stdout);
printf("m3 = ");
cotnum(m3, stdout);
//判断mi是否互素
egcd(m1, m2, e1);//e1=gcd(m1,m2)
egcd(m1, m3, e2);
egcd(m2, m3, e3);
if (mr_compare(e1, one) == 0 && mr_compare(e2, one) == 0 && mr_compare(e3, one) == 0)
{
//计算M1 M2 M3
multiply(m2, m3, Ma);//Ma=m2*m3
multiply(m1, m3, Mb);
multiply(m1, m2, Mc);
//计算M1^-1 M2^-1 M3^-1
xgcd(Ma, m1, Ma1, Ma1, Ma1);
xgcd(Mb, m2, Mb1, Mb1, Mb1);
xgcd(Mc, m3, Mc1, Mc1, Mc1);
//计算X=M1M1^-1a1+M2M2^-1a2+M3^-1a3
multiply(Ma, Ma1, e1);//e1=Ma*Ma^-1
multiply(e1, a1, e1);//e1=Ma*Ma^-1*a1
multiply(Mb, Mb1, e2);//e1=Mb*Mb^-1
multiply(e2, a2, e2);//e1=Mb*Mb^-1*a2
multiply(Mc, Mc1, e3);//e1=Mc*Mc^-1
multiply(e3, a3, e3);//e1=Mc*Mc^-1*a3
add(e1, e2, x);//x=e1+e2
add(x, e3, x);//x=e1+e2+e3
multiply(m1, m2, m);
multiply(m, m3, m);//m=m1*m2*m3
powmod(x, one, m, x);//x = x的一次方 mod m
printf("\nX = ");
cotnum(x, stdout);
printf("\nmod ");
cotnum(m, stdout);
}
else
{
printf("\n(由于mi不互素)不能直接利用中国剩余定理!");
}
mirexit();// 清除MIRACL系统,释放所有内部变量
return 0;
}
数据分析
通过测试老师验收时所给的数据,来验证编写算法代码的正确性
通过多组实验数据验证,可以确定程序的正确性没有问题,在同余方程组有解时,可以将其对应的解x计算出来。