現代密碼學實驗4 Miller-Rabin算法

讚賞碼 & 聯繫方式 & 個人閒話

【實驗名稱】Miller-Rabin算法

 

【實驗目的】

1、理解Miller-Rabin算法的數學原理;

2、通過實驗掌握Miller-Rabin素數判定的算法。

 

【實驗原理】

Miller-Rabin算法是目前主流的基於概率的素數測試算法,在構建密碼安全體系中佔有重要的地位。

基本原理:令n表示一個整數,假設存在整數x和y滿足x2 ≡ y2(mod n),但x≠ ±y(mod n),那麼n是合數。而且gcd(x-y,n)給出了n的一個非平凡因子。

Miller-Rabin素數判定: (n-1=2km,m爲奇數),如果對所有的r∈[0,k-1],若am mod n≠1且a^(2^r m) mod n≠-1,則n是合數。

【實驗內容】

實驗內容: 編程實現Miller-Rabin素數判定算法,並判斷23456789是否是素數?

代碼:(代碼解釋見代碼中註釋)

//現代密碼學實驗4  Miller_Rabin算法
#include<stdio.h>
#include <stdlib.h>
#include <time.h>
#include<math.h>
#define LL long long

//冪次運算,含模運算,防止溢出
LL My_Pow(LL a, LL m, LL input)
{
	LL result = 1;
	for (int i = 0; i < m; i++)
	{
		result = (result*a) % input;
	}
	return result;
}

//Miller_Rabin算法
int Miller_Rabin(LL input)
{
	if (input == 2 || input == 3)
	{
		//2、3特判爲素數
		return 1;
	}
	else if (input % 2 == 0 || input == 1)
	{
		//偶數和1特判爲非素數
		return -1;
	}
	else
	{
		int ji = 0;
		LL b;
		LL m = input - 1;
		//計算k,即ji
		while (m % 2 == 0)
		{
			m = m / 2;
			ji++;
		}
		srand(time(NULL));
		LL a = 0;
		//隨機取a
		while (a <= 1)
		{
			a = rand() % (input - 1);
		}
		b = My_Pow(a, m, input);
		//若b0=1或-1
		if (b == 1 || b == input - 1)
		{
			return 1;
		}
		else
		{
			double r = 0;
			for (r = 0;; )
			{
				//循環直到r<k-1
				r++;
				LL temp1 = LL(m*(pow(2, r)));
				LL temp = My_Pow(a, temp1, input);
				if (temp == input - 1)
				{
					//等於-1則爲素數
					return 1;
				}
				else if (temp == 1)
				{
					//等於1一定爲合數
					return -1;
				}
				else
				{
					if (r < ji - 1)
					{
						//都不等於則繼續
						continue;
					}
					else
					{
						//達到次數則返回該數爲合數
						return -1;
					}
				}
			}
		}
	}
}


int main()
{
	printf("****************************************\n");
	printf("***        歡迎來到素數判斷器        ***\n");
	printf("***1.輸入一個數判斷是否爲素數        ***\n");
	printf("***2.輸入一個數輸出這個數內的素數    ***\n");
	printf("***3.退出程序                        ***\n");
	printf("****************************************\n\n");
	int judge;
	while (true)
	{
		printf("請選擇功能:");
		scanf("%d", &judge);
		if (judge == 1)
		{
			//輸入一個數判斷是否爲素數
			LL input;
			printf("請輸入待判斷的整數:");
			scanf("%lld", &input);
			int flag = 1;
			for (int i = 0; i < 10; i++)
			{
				if (Miller_Rabin(input) == -1)
				{
					flag = -1;
					break;
				}
			}
			if (flag == 1)
			{
				printf("%lld是素數\n\n", input);
			}
			else
			{
				printf("%lld不是素數\n\n", input);
			}
		}
		else if(judge==2)
		{
			//輸入一個數輸出這個數內的素數
			printf("你想求多少以內的素數:");
			LL number;
			scanf("%lld", &number);
			for (LL i = 2; i <= number; i++)
			{
				int flag = 1;
				for (int j = 0; j < 10; j++)
				{
					if (Miller_Rabin(i) == -1)
					{
						flag = -1;
						break;
					}
				}
				if (flag == 1)
				{
					printf("%lld   ", i);
				}
			}
			printf("\n\n");
		}
		else if (judge == 3)
		{
			//退出
			printf("退出成功!\n");
			break;
		}
	}
	return 0;
}

運行演示:

 

【小結或討論】

這次算法比起上次的AES可以說是簡單很多了,只是完成RSA算法的一部分——用於素數判斷的Miller-Rabin算法。這次的實驗讓我重新認識了素數判定,原本我只知道那種遍歷到基礎算法,沒想到還可以根據費馬小定理來進行這種概率性素數判斷,感到十分新鮮。

坦誠地說,雖然算法並不複雜,但是其背後的數學原理確實是有些晦澀難懂的。書中在這提出了一個新的“基本定理”和信息安全數學基礎中的“費馬小定理”,並把其結合成Miller-Rabin素數判定算法。這一塊書上寫的的解釋和證明,我覺得略微簡略了一點,看起來比較費勁,特別是第一個b0和第二個b1的mod n的結果判斷比較難懂,兩者一個都用了費馬小定理,另一個“1”時用的是基本定理、“-1”時用的是費馬小定理。但是隻要把解釋看懂了,整個算法也就比較明白了。

看懂了後,在算法實現的過程中我覺得還有兩個小坑吧。一個當然就是冪次運算的溢出,由於C語言的模運算%限制必須要是整型,而整型最大的就是long long型,這對於大數冪次運算是遠遠不夠的,所以我自己寫了個My_Pow冪次運算,每次乘法都mod n這樣就能解決溢出問題;其次還有一個就是算法中mod運算結果-1應該是n-1,因爲按My_Pow算的話保持數是正數,那麼在模運算中-1也就等於n-1了,這是我覺得要注意的兩點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章