Fermat素性检验算法

Fermat素性检验算法(信息安全数学实验一)

所有的实验均使用C语言完成,其中的miracl大数库需要自行编译,环境需要配置成功才能正常使用代码。希望学弟学妹们能从代码中借鉴灵感。
五次实验均是使用vs2017+miracl库环境下编译成功。(且上交实验报告和个人演示总评为优秀)

代码的流程思路

在这里插入图片描述
在这里插入图片描述
在编写代码过程中需要了解解题思路,并且我们需要调用一些大数库函数。在这里给出相关的参考资料网站。为了方便,我也将信息内容copy下来。

来源于个人博客

函数原型: void absol(big x, big y);
功能说明: 取x的绝对值,y=|x|
 
 
函数原型: void add(big x, big y, big z);
功能说明: 两个大数相加,z=x+y
Example: add(x,x,x); // This doubles the value of x.
 
 
函数原型: void bigbits(int n, big x);
功能说明: 产生一个n位的大整数,初始化随机种子由irand函数实现
Example: bigbits(100,x); //This generates a 100 bitrandom number
 
 
函数原型: int cinstr(big x, char*s);
功能说明: 将大数字符串转换成大数
返回值: 输入字符数的个数
Example:    mip->IOBASE=16; // input large hex number into big x
            cinstr(x,”AF12398065BFE4C96DB723A”);
 
 
函数原型: int compare(big x, big y);
功能说明: 比较两个大数的大小
返回值: x>y时返回+1, x=y时返回0, x<y时返回-1
 
 
函数原型: void convert(int n, big x);
功能说明: 将一个整数n转换成一个大数x
 
 
函数原型: void copy(big x, big y);
功能说明: 将一个大数赋值给另一个大数,y=x
 
 
函数原型: int cotstr(big x, char *s);
功能说明: 将一个大数根据其进制转换成一个字符串
返回值: 字符串长度
 
 
函数原型: void decr(big x, int n, big z) ;
功能说明: 将一个大数减去一个整数, z=x-n.
 
 
函数原型: void divide(big x, big y, big z);
功能说明: 两个大数相除,z=x/y; x=x mod y,当变量y和z相同时,x为余数,商不返回(即y的值不变);当x和z相同时,x为商,余数不返回。
Example:    divide(x,y,y);//x为余数,y值不变
 
 
函数原型: BOOL divisible(big x, big y)
功能说明: 测试x能否整除y
返回值: y除x余数为0,返回TRUE,否则返回FALSE
 
 
函数原型: intigcd(int x, int y) ;
功能说明: 返回两个整数的最大公约数
 
函数原型: void incr(big x, int n, big z);
功能说明: 将一个大数加上一个整数, z=x+n
Example:    incr(x,2,x);  /* This increments x by 2. */
 
 
函数原型: void mirkill(big x);
功能说明: 释放内存大数所占的内存
 
 
函数原型: miracl *mirsys(int nd, int nb);
功能说明: 初始化MIRACL系统,该函数必须在调用MIRACL库函数之前先执行
Example:    miracl *mip=mirsys(500,10);//初始化500位的10进行制数
 
 
函数原型: void mirexit();
功能说明: 清除MIRACL系统,释放所有内部变量
 
 
函数原型: void multiply(big x, big y, big z);
功能说明: 两个大数相乘,z=x.y
 
 
函数原型: void negify(big x, big y);
功能说明: 大数取负号,y=-x.
 
 
函数原型: int numdig(big x);
功能说明: 返回大数x中数字的个数
 
 
函数原型: void premult(big x, int n, big z);
功能说明: 一个大数乘以一个整数,z=n.x
 
 
函数原型: int subdiv(big x, int n, big z);
功能说明: 一个大数除以一个整数,z=x/n.
返回值: 余数
 
 
函数原型: BOOL subdivisible(big x, int n)
功能说明: 测试n能否整除x
返回值: x除以n余数为0,返回TRUE,否则返回FALSE
 
 
函数原型: void bigdig(int n, int b, big x);
功能说明: 产生一个指定长度的进制的随机数,该函数使用内置的随机数发生器,初始化种子调用irand函数
Example: bigdig(100,10,x);  //产生一个100位的10进制随机数
 
函数原型: void bigrand(big w, big x);
功能说明: 使用内置的随机数发生器,产生一个小于w的大数随机数,x<w
 
 
函数原型:   int egcd(bigx, big y, big z);
功能说明:计算两个大数的最大公约数,z=gcd(x,y)
 
 
函数原型: void expb2(int n, big x)
功能说明: 计算2的n次方的大数
Example:    expb2(1398269,x);   //2^1398269
            decr(x,1,x);        //x = x - 1
            mip->IOBASE=10;     //使用10进制
            cotnum(x,stdout);   //输出到屏幕
This calculates and prints out the largest known primenumber (on a true 32-bit computer with lots of memory!)
 
函数原型:   void expint(intb, int n, big x);
功能说明: 计算b的n次方的大数
 
 
函数原型: void fft_mult(big x, big y, big z);
功能说明: 使用Fast Fourier算法计算两个大数乘积,z=x.y
 
 
函数原型:   unsigned int invers(unsigned int x, unsigned int y);
功能说明:计算两个无符号整数(要求互素)的模逆,返回x-1  mod y
 
 
函数原型:   BOOL isprime(bigx);
功能说明:判断一个大数是否为素数,使用概率测试算法
返回值: x为素数返回TRUE,否则返回FALSE
 
 
函数原型: void powmod(big x, big y,big z, big w);
功能说明: 模幂运算,w=xy mod z
 
 
函数原型: void sftbit(big x, int n,big z);
功能说明:将一个大数左移或右移n位,n为正数时左移,负数时右移
 
 
函数原型: int xgcd(bigx, big y, big xd, big yd, big z);
功能说明: 计算两个大数的扩展最大公约数,也可以用来计算模逆,这个函数比mad 函数运算速度稍慢。z=gcd(x,y)=x.xd+y.yd
Example:    xgcd(x,p,x,x,x);  //计算x^-1 mod p
/* x = 1/x mod p  (p is prime) */

以上是对于一些函数的描述,我们需要根据算法流程对函数进行合理的使用。以下对核心函数进行分析。

//按照题意的算法
int fermat_examine(big number, int k) {
	big a, m, g, r, one, two, m_1;
	int i, num;
	miracl *mip = mirsys(5000, 10);
	mip->IOBASE = 10;
	//初始化
	num = 0;
	a = mirvar(0);
	m = mirvar(0);
	g = mirvar(0);
	r = mirvar(0);
	one = mirvar(1);
	two = mirvar(2);
	m_1 = mirvar(0);
	//将传入的参数用函数内部的变量表示
	copy(number, m);
	decr(m, 1, m_1);
	//随机生成函数(跟随时间的不同生成不同的数字)
	srand((unsigned int)time(NULL));
	for (i = 0; i < k; i++) {
		//知道满足条件2<=a<m-1
		//其中a和m都是整数
		bigrand(m_1, a);
		while (compare(a, two) == -1) {
			bigrand(m_1, a);
		}
		//计算g
		egcd(a, m, g);
		//printf("输出g:");
		//cotnum(g, stdout);
		//m可能是素数
		if (compare(g, one) == 0) {
			powmod(a, m_1, m, r);
			//printf("输出r:");
			//cotnum(r, stdout);
			if (compare(r, one) == 0) {
				num++;
			}
			else if (compare(r, one) != 0) {
				printf("m是合数!n");
				return 1;
			}
 
		}
		else if (compare(g, one) != 0) {
			printf("m是合数!n");
			return 1;
		}
	}
 
	mirkill(a);
	mirkill(m);
	mirkill(m_1);
	mirkill(r);
	mirkill(g);
	mirkill(one);
	mirkill(two);
	if (num == k) {
		printf("m为素数的概率为%2.2f%%n", (1 - 1 / pow(2, k)) * 100);
		return 0;
	}
	else
		return 1;
 
}
/*
以上就是核心函数,我们需要注意一些细节:
a的取值区间,使用bigrand函数时,还需要一些限制条件以满足这个区间范围,具体请仔细查阅函数的使用方式,我们在下方放置源代码,以帮助你学习这方面知识。
*/

源代码

//引入c编译环境
extern "C" {
#include "miracl.h"
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//#include <conio.h>
#include <math.h>
 
 
//读文件
void read_file(char addr[20], int k,int your_num);
//手动输入数字
void handy_number(int k, char str[5000], char addr_in[20],int your_num);
//输出提示信息
void print_welcome();
//判断选择的不同数字,调用不同的函数进行操作
void choose_function(int your_num, int k, char addr[20], char str[5000], char addr_in[20]);
//核心函数:判断读入的数是否是素数
int fermat_examine(big number, int k);
//文件输入信息
void print_file_info(int flag, int k);
 
 
//主函数
int main()
{
	int your_num, k;
 
	char ch[] = "data1.txt";
	char str[5000], addr_in[] = "temp.txt";
	while (1) {
		print_welcome();
		scanf("%d", &your_num);
		if (your_num == 1) {
			printf("请输入数字:n");
			scanf("%s", str);
		}
		if (your_num == 0)
			return 0;
		printf("k=");
		scanf("%d", &k);
		//printf("请输入地址:n");
		//gets_s(addr_in);
		choose_function(your_num, k, ch, str, addr_in);
	}
 
	return 0;
}
 
//提示信息
void print_welcome() {
	int i;
	for (i = 0; i < 30; i++)
		printf("*");
	printf("欢迎来到程序世界!");
	for (i = 0; i < 30; i++)
		printf("*");
	printf("nn请您键入数字选择接下来的操作!(键入数字后需要回车)nn");
	printf("1 键盘输入大数	2 读取文件内的大数	0 退出程序nn");
}
 
//选择函数
void choose_function(int your_num, int k, char addr[], char str[], char addr_in[]) {
	switch (your_num) {
	case 1:handy_number(k, str, addr_in,your_num); break;
	case 2:read_file(addr, k,your_num); break;
		//case 0: break;
	default:printf("您输入了错误的信息,请从0-2中选择一个数字输入!n");
	}
}
 
//手动输入大数
void handy_number(int k, char str[], char addr_in[],int your_num) {
	printf("您选择了手动输入大字方式,请注意输入0-F的数字,我们采用的是十六进制数!n");
	FILE *fp;
	big data;
	miracl *mip = mirsys(5000, 10);
	data = mirvar(0);
	fp = fopen(addr_in, "w");
	fputs(str, fp);
	fclose(fp);
	read_file(addr_in, k,your_num);
 
 
}
 
 
//按照题意的算法
int fermat_examine(big number, int k) {
	big a, m, g, r, one, two, m_1;
	int i, num;
	miracl *mip = mirsys(5000, 10);
	mip->IOBASE = 10;
	//初始化
	num = 0;
	a = mirvar(0);
	m = mirvar(0);
	g = mirvar(0);
	r = mirvar(0);
	one = mirvar(1);
	two = mirvar(2);
	m_1 = mirvar(0);
	//将传入的参数用函数内部的变量表示
	copy(number, m);
	decr(m, 1, m_1);
	//随机生成函数(跟随时间的不同生成不同的数字)
	srand((unsigned int)time(NULL));
	for (i = 0; i < k; i++) {
		//知道满足条件2<=a<m-1
		//其中a和m都是整数
		bigrand(m_1, a);
		while (compare(a, two) == -1) {
			bigrand(m_1, a);
		}
		//计算g
		egcd(a, m, g);
		//printf("输出g:");
		//cotnum(g, stdout);
		//m可能是素数
		if (compare(g, one) == 0) {
			powmod(a, m_1, m, r);
			//printf("输出r:");
			//cotnum(r, stdout);
			if (compare(r, one) == 0) {
				num++;
			}
			else if (compare(r, one) != 0) {
				printf("m是合数!n");
				return 1;
			}
 
		}
		else if (compare(g, one) != 0) {
			printf("m是合数!n");
			return 1;
		}
	}
 
	mirkill(a);
	mirkill(m);
	mirkill(m_1);
	mirkill(r);
	mirkill(g);
	mirkill(one);
	mirkill(two);
	if (num == k) {
		printf("m为素数的概率为%2.2f%%n", (1 - 1 / pow(2, k)) * 100);
		return 0;
	}
	else
		return 1;
 
}
 
//读文件函数
void read_file(char addr[], int k,int your_num) {
	FILE *fp;
	big data;
	int i;
	miracl *mip = mirsys(5000, 10);
	mip->IOBASE = 10;
	data = mirvar(0);
	if ((fp = fopen(addr, "r+")) == NULL) {
		printf("打开文件错误,或者文件为空。n");
		exit(0);
	}
	else {
		//未读写文件到文件结尾,一直进行读写
		printf("打开文件正常,开始读文件信息。n");
		while (!feof(fp)) {
			cinnum(data, fp);
			cotnum(data, stdout);
			//可以接下来将参数放入核心函数里
			i = fermat_examine(data, k);
		}
		fclose(fp);
		if(your_num==1)
		print_file_info(i, k);
		mirkill(data);
		mirexit();
	}
}
 
//文件信息输入
void print_file_info( int flag, int k) {
	//将信息输出到文件中
	FILE *in, *fp;
	char ch;
	if ((in = fopen("temp.txt", "r+")) == NULL) {
		printf("打开文件data1.txt失败!n");
	}
		if ((fp = fopen("data.txt", "a")) == NULL) {
			printf("打开文件data.txt失败!n");
		}
		
			ch = fgetc(in);
			while(!feof(in)) {
				fputc(ch,fp);
				ch=fgetc(in);
		}
	if (flag == 1)
		fputs("nm是合数!n", fp);
	else {
		fprintf(fp, "nk=%d", k);
		fprintf(fp, "nm为素数的概率为%2.2f%%n", (1 - 1 / pow(2, k)) * 100);
	}
		
	fclose(in);
	fclose(fp);
}

总结

第一次实验还是比较简单的,重要的是去学会配置环境和使用函数,一些细节处理等等,前人栽树,后人乘凉。帮助到你,点个赞吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值