RSA大数运算实现(1024位n)(6)Miller-Rabin素性检测

简介

  在(1)中,素性检验使用的是费马小定理,对于待检测的数n,如果an-1≡1(mod n),则认为n是素数,为了运算更快,a不是取随机的,而是取2、3、5、7。这样做不是很严谨,即便随机取a,费马检测对于一些伪素数也会失效,如561【对所有的正整数x,1<x<n,若xn-1≡1(mod n),但是n是一个合数,这样的n成为Carmichael数】。
  而Miller-Rabin素性检验,每做一次,出错概率至多为1/4,对于同一个数,多次检验,就能够在概率上保证一个数是素数。如果对一个数n,选25个不同的x进行Miller-Rabin检测,若每次都判定为n是素数,则n是合数的概率小于1015分之一。

算法描述

输入:奇整数n,n=1+2k·q
输出:1(n是素数) 或 0(n是合数)

  1. 随机选取x,使得1<x<n。
  2. 令j=0,计算y=xq(mod n)。
  3. 如果y=n-1,或者y=1且j=0,结束算法,返回1;如果y=1且j>0,进入步骤5(否则,进入步骤4)。
  4. j=j+1,如果j<k,计算y=y2(mod n),进入步骤3。
  5. 返回0。

代码

int miller_b(BN n,int t=3)
{
	if ((n[1] & 1U) == 0)
		return 0;
	srand((unsigned)time(NULL));
	BN n_1 = { 0 }, q = { 0 }, temp = { 0 };
	BN x = { 0 };//x是随机获得的
	BN y = { 0 };
	int flag = 1;//假设是素数
	cpy_b(n_1, n);
	n_1[1] = n_1[1] - 1U;//n-1
	
	int bits = getbits_b(n_1);
	int k = 0;
	
	cpy_b(q, n_1);
	for (int i = 1; i < bits; i++)
	{
		if (uint32_t(q[1] & 1U) == 0U)
		{
			k++;
			shr_b(q);
		}
		else
			break;
	}

	for (int times = 0; times < t; times++)//默认做3次检验
	{
		memset(x, 0U, sizeof(x));
		randBN(x, getbits_b(n));
		if (cmp_b(x, n))
			shr_b(x);
		//cout << "x = " << bn2str(x)<<endl;
		//cout << "x 有 " << getbits_b(x) << "位" << endl;
		//cout << "q= " << bn2str(q) << endl;
		//cout << "k= " << k << endl << endl;
		modexp_b(x, q, n, y);//y=x^q(mod n)
		if ((y[0] == 1U && y[1] == 1U) || !cmp_b(y, n_1))
			continue;

		for (int j = 1; j < k; j++)
		{
			modmul(y, y, n, temp);
			if (temp[0] == 1U && temp[1] == 1U)
				break;
			else if (!cmp_b(temp, n_1))
				goto prime;
			cpy_b(y, temp);
		}
		flag=0;//是合数
		break;
	prime://素数
		;
	}
	return flag;
}

运行结果

运行速度并不是很慢,一次十几毫秒。找素数比openssl慢不少,openssl产生一个2048位的素数只需要不超过3秒。
在这里插入图片描述

以下是一个简单的C语言代码实现大数版本的RSA: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <math.h> #include <gmp.h> #define KEY_SIZE 2048 void generate_key_pair(mpz_t n, mpz_t e, mpz_t d); void generate_prime(mpz_t prime); void extended_euclidean_algorithm(mpz_t a, mpz_t b, mpz_t x, mpz_t y); int main() { mpz_t p, q, n, e, d, plaintext, ciphertext, decrypted_text; char message[256]; char *ptr; int i; // Initialize variables mpz_init(p); mpz_init(q); mpz_init(n); mpz_init(e); mpz_init(d); mpz_init(plaintext); mpz_init(ciphertext); mpz_init(decrypted_text); // Set random seed srand(time(NULL)); // Generate key pair generate_key_pair(n, e, d); // Prompt for plaintext message printf("Enter message to encrypt: "); fgets(message, 256, stdin); ptr = strchr(message, '\n'); if (ptr != NULL) { *ptr = '\0'; } // Convert message to a big integer mpz_set_str(plaintext, message, 10); // Encrypt message mpz_powm(ciphertext, plaintext, e, n); // Print ciphertext printf("Ciphertext: "); mpz_out_str(stdout, 10, ciphertext); printf("\n"); // Decrypt message mpz_powm(decrypted_text, ciphertext, d, n); // Print decrypted message printf("Decrypted message: "); mpz_out_str(stdout, 10, decrypted_text); printf("\n"); // Clean up mpz_clear(p); mpz_clear(q); mpz_clear(n); mpz_clear(e); mpz_clear(d); mpz_clear(plaintext); mpz_clear(ciphertext); mpz_clear(decrypted_text); return 0; } void generate_key_pair(mpz_t n, mpz_t e, mpz_t d) { mpz_t phi_n, p_minus_1, q_minus_1, gcd, x, y; int prime_check; int i; // Initialize variables mpz_init(phi_n); mpz_init(p_minus_1); mpz_init(q_minus_1); mpz_init(gcd); mpz_init(x); mpz_init(y); // Generate two distinct primes generate_prime(p); do { generate_prime(q); } while (mpz_cmp(p, q) == 0); // Calculate n and phi(n) mpz_mul(n, p, q); mpz_sub_ui(p_minus_1, p, 1); mpz_sub_ui(q_minus_1, q, 1); mpz_mul(phi_n, p_minus_1, q_minus_1); // Choose a random e such that 1 < e < phi(n) and gcd(e, phi(n)) = 1 do { prime_check = 0; do { mpz_urandomb(e, rand(), KEY_SIZE / 2); } while (mpz_cmp_ui(e, 1) <= 0 || mpz_cmp(e, phi_n) >= 0); mpz_gcd(gcd, e, phi_n); if (mpz_cmp_ui(gcd, 1) == 0) { prime_check = 1; } } while (prime_check == 0); // Calculate d such that ed ≡ 1 (mod phi(n)) extended_euclidean_algorithm(e, phi_n, x, y); mpz_set(d, x); if (mpz_cmp_ui(d, 0) < 0) { mpz_add(d, d, phi_n); } // Clean up mpz_clear(phi_n); mpz_clear(p_minus_1); mpz_clear(q_minus_1); mpz_clear(gcd); mpz_clear(x); mpz_clear(y); } void generate_prime(mpz_t prime) { int prime_check = 0; while (prime_check == 0) { // Generate a random odd number mpz_urandomb(prime, rand(), KEY_SIZE); mpz_setbit(prime, KEY_SIZE - 1); // Test for primality using the Miller-Rabin algorithm prime_check = mpz_probab_prime_p(prime, 25); } } void extended_euclidean_algorithm(mpz_t a, mpz_t b, mpz_t x, mpz_t y) { mpz_t r, q, x1, x2, y1, y2, tmp; // Initialize variables mpz_init(r); mpz_init(q); mpz_init(x1); mpz_init(x2); mpz_init(y1); mpz_init(y2); mpz_init(tmp); // Set initial values mpz_set(x2, a); mpz_set(x1, b); mpz_set_ui(y2, 0); mpz_set_ui(y1, 1); while (mpz_cmp_ui(x1, 0) != 0) { // Calculate quotient and remainder mpz_fdiv_qr(q, r, x2, x1); // Update x and y values mpz_mul(tmp, q, x1); mpz_sub(r, x2, tmp); mpz_mul(tmp, q, y1); mpz_sub(tmp, y2, tmp); // Shift values mpz_set(x2, x1); mpz_set(x1, r); mpz_set(y2, y1); mpz_set(y1, tmp); } // Set output values mpz_set(x, y2); mpz_set(y, x2); // Clean up mpz_clear(r); mpz_clear(q); mpz_clear(x1); mpz_clear(x2); mpz_clear(y1); mpz_clear(y2); mpz_clear(tmp); } ``` 该代码使用了 GMP 库来处理大数运算。它生成一个 2048 RSA 密钥对,并使用 Miller-Rabin 算法来检查素性。它还实现了扩展欧几里得算法来计算模反元素。需要注意的是,生成密钥对和加解密的过程可能会非常耗时。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值