讚賞碼 & 聯繫方式 & 個人閒話
【實驗名稱】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了,這是我覺得要注意的兩點。