ap = a (mod p)

本文介绍了一道编程题目,该题目要求通过费马小定理来判断一个数是否为特定基数下的伪素数。文章提供了一个C++实现的示例代码,其中包括了快速幂算法模板及质数判断函数。
B - B
Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu

Description

Fermat's theorem states that for any prime number p and for any integer a > 1, ap = a (mod p). That is, if we raise a to the pth power and divide by p, the remainder is a. Some (but not very many) non-prime values of p, known as base-pseudoprimes, have this property for some a. (And some, known as Carmichael Numbers, are base-a pseudoprimes for all a.)

Given 2 < p ≤ 1000000000 and 1 < a < p, determine whether or not p is a base-a pseudoprime.

Input

Input contains several test cases followed by a line containing "0 0". Each test case consists of a line containing p and a.

Output

For each test case, output "yes" if p is a base-a pseudoprime; otherwise output "no".

Sample Input

3 2
10 3
341 2
341 3
1105 2
1105 3
0 0

Sample Output

no
no
yes
no
yes
yes
如果理解题意就很简单了。。
题解:先判断p是不是质数,如果是输出no然后判断a的p次方对p取模是否等于a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<stdio.h>
#include<math.h>
int s(long long a)
{
	if(a==2)
	return 1;
	for(int i=2;i*i<=a;i++)
	if(a%i==0)
	return 0;
	return 1;
}
long long f(long long a,long long b,long long c)//快速幂模板
{
	long long t=1%c;
	a=a%c;
	while(b>0)
	{
		if(b%2==1)
		t=t*a%c;
		b=b/2;
		a=a*a%c;
	}
	return t;
}
int main()
{
__int64 a,p;
	while(~scanf("%I64d%I64d",&p,&a)&&!(a==0&&p==0))
	{
		if(s(p))
		printf("no\n");
		else
		{
			if(f(a,p,p)==a)
    	    printf("yes\n");
	       else
	       printf("no\n");	
		}
	
	}
	return 0;
}

 
   
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <stdbool.h> typedef long long ll; typedef unsigned long long ull; // 定义椭圆曲线点结构 typedef struct { ll x; ll y; bool is_infinity; // 标记是否为无穷远点 } ECPoint; // 定义椭圆曲线参数 typedef struct { ll p; // 素数模数 ll a; // 曲线参数a ll b; // 曲线参数b ECPoint G; // 生成点 ll n; // G的阶 } ECC_Params; // 函数声明 ll mod(ll a, ll m);// 计算a mod m ll mod_inverse(ll a, ll m);// 扩展欧几里得算法计算模逆元 ECPoint point_add(ECPoint P, ECPoint Q, ECC_Params params);// 椭圆曲线点加法 ECPoint point_multiply(ll k, ECPoint P, ECC_Params params);// 椭圆曲线点乘法 int is_prime(ll n);// 检查是否为质数 ull hash(char *message);// 简单哈希函数 void ecdsa_init(ECC_Params *params);// 初始化椭圆曲线参数 void generate_keypair(ECC_Params params, ll *private_key, ECPoint *public_key);// 生成Schnorr密钥对 void schnorr_sign(ECC_Params params,ll private_key, ECPoint public_key, char *msg,ECPoint *R, ll *s);// Schnorr签名生成 int schnorr_verify(ECC_Params params, char *msg, ECPoint R, ECPoint public_key, ll s);// Schnorr签名验证 void aggregate_sign(ECC_Params params, char *msg,ECPoint *ag_P, ECPoint *ag_R, ll *ag_s);// 组签名 void aggregate_verify(ECC_Params params,char *msg, ECPoint ag_R, ECPoint ag_P, ll ag_s);//聚合签名验证 // 计算a mod m,确保结果为正数 ll mod(ll a, ll m) { ll result = a % m; if (result < 0) result += m; return result; } // 扩展欧几里得算法计算模逆元 ll mod_inverse(ll a, ll m) { ll m0 = m, t, q; ll y = 0, x = 1; if (m == 1) return 0; while (a > 1) { q = a / m; t = m; m = a % m; a = t; t = y; y = x - q * y; x = t; } // 确保x为正数 if (x < 0)x += m0; return x; } // 椭圆曲线点加法 P + Q ECPoint point_add(ECPoint P, ECPoint Q, ECC_Params params) { ECPoint R; R.is_infinity = false; // 处理无穷远点情况 if (P.is_infinity) return Q; if (Q.is_infinity) return P; // 如果P和Q是互逆点,结果为无穷远点 if (P.x == Q.x && mod(P.y + Q.y, params.p) == 0) { R.is_infinity = true; return R; } ll lambda; // 斜率 // 计算lambda if (P.x == Q.x && P.y == Q.y) { // 点加倍,P = Q if (P.y == 0) { R.is_infinity = true; return R;// 无穷远点 } ll numerator = mod(3 * P.x * P.x + params.a, params.p); ll denominator = mod(2 * P.y, params.p); lambda = mod(numerator * mod_inverse(denominator, params.p), params.p); } else { // 不同点,P != Q ll numerator = mod(Q.y - P.y, params.p); ll denominator = mod(Q.x - P.x, params.p); lambda = mod(numerator * mod_inverse(denominator, params.p), params.p); } // 计算结果点坐标 R.x = mod(lambda * lambda - P.x - Q.x, params.p); R.y = mod(lambda * (P.x - R.x) - P.y, params.p); return R; } // 椭圆曲线点乘法 k*P(使用快速加倍-加法算法) ECPoint point_multiply(ll k, ECPoint P, ECC_Params params) { ECPoint R; R.is_infinity = true; // 初始化为无穷远点(单位元) k = mod(k, params.n); // 由于n是G的阶,k可以简化为k mod n while (k > 0) { if (k % 2 == 1) { // 如果当前位为1,将current加到result上 if (R.is_infinity == true) {R = P;} else R = point_add(R, P, params); } // 加倍 P = point_add(P,P,params); // 右移k k = k / 2; } return R; } // 检查是否为质数 int is_prime(ll n) { if (n <= 1) return 0; if (n <= 3) return 1; if (n % 2 == 0 || n % 3 == 0) return 0; for (ll i = 5; i * i <= n; i += 6) { if (n % i == 0 || n % (i + 2) == 0) return 0; } return 1; } // 简单哈希函数 ull hash(char *message) { ull hash = 5381; int c; while ((c = *message++)) hash = ((hash << 5) + hash) + c; // hash * 33 + c return hash; } // 初始化椭圆曲线参数 void ecdsa_init(ECC_Params *params) { params->p = 23; // 素数模数 params->a = 1; // 曲线参数a params->b = 4; // 曲线参数b,曲线方程: y² = x³ + x + 4 mod 23 params->G.x = 0; // 生成点x坐标 params->G.y = 2; // 生成点y坐标 params->G.is_infinity = false; params->n = 29; // G的阶 printf("椭圆曲线参数初始化:\n"); printf("p = %lld, a = %lld, b = %lld\n", params->p, params->a, params->b); printf("生成点G: (%lld, %lld)\t", params->G.x, params->G.y); printf("n = %lld\n", params->n); } // 生成Schnorr密钥对 void generate_keypair(ECC_Params params, ll *private_key, ECPoint *public_key) { // 私钥d: 1 < d < n *private_key = rand() % (params.n - 2) + 2; // 公钥Q = d * G *public_key = point_multiply(*private_key, params.G, params); printf("生成密钥对:\n"); printf("私钥 d = %lld\n", *private_key); printf("公钥 Q = (%lld, %lld)\n", public_key->x, public_key->y); } // Schnorr签名生成 // 选择一个随机数k,令R=kG // 令s=k+xH(m||R||P) void schnorr_sign(ECC_Params params,ll private_key, ECPoint public_key, char *msg,ECPoint *R, ll *s) { ll k = rand() % (params.n - 1) + 1; // 随机数k *R = point_multiply(k, params.G, params); // 计算 e = H(m || R.x || R.y || P.x || P.y) mod n char buffer[1024]; sprintf(buffer, "%s%lld%lld%lld%lld", msg, (*R).x, (*R).y,public_key.x,public_key.y); ll e = hash(buffer) % params.n; *s = mod((k + private_key * e), params.n); printf("签名生成\n"); // printf("随机数 k: %lld\n", k); printf("临时点 R: (%lld, %lld)\n", (*R).x, (*R).y); // printf("哈希值 e: %lld\n", e); printf("签名值 s: %lld\n", *s); } // Schnorr签名验证 //sG=R+P⋅H(m||R||P) int schnorr_verify(ECC_Params params, char *msg, ECPoint R, ECPoint public_key, ll s) { // 计算 e = H(m || R.x || R.y || P.x || P.y) mod n char buffer[1024]; sprintf(buffer, "%s%lld%lld%lld%lld", msg, R.x,R.y,public_key.x,public_key.y); ll e = hash(buffer) % params.n; ECPoint sG = point_multiply(s,params.G,params); ECPoint eP = point_multiply(e, public_key, params); ECPoint reP = point_add(R, eP, params); // printf("验证过程\n"); // printf("计算 sG: (%lld, %lld)\n", sG.x, sG.y); // printf("计算 eP: (%lld, %lld)\n", eP.x, eP.y); // printf("计算 reP: (%lld, %lld)\n", reP.x, reP.y); // 验证 sG == R + eP bool valid = false; if (sG.is_infinity && reP.is_infinity) { valid = true; // 两者都是无穷远点 } else if (!sG.is_infinity && !reP.is_infinity) { valid = (sG.x == reP.x) && (sG.y == reP.y); } printf("验证结果: %s\n", valid ? "成功" : "失败"); return valid; } // 组签名 // 私钥:x_1,x_2,对应的公钥P_1=x_1 G,P_2=x_2 G, // 随机数:k_1,k_2,并有R_1=k_1 G,R_2=k_2 G, // 组公钥:P=P_1+P_2 // 组签名:(R, s) R = R_1 + R_2, s = s_1 + s_2 void aggregate_sign(ECC_Params params, char *msg,ECPoint *ag_P, ECPoint *ag_R, ll *ag_s) { printf("聚合签名\n"); printf("message : %s\n", msg); ll x_1, x_2, s_1, s_2, k_1, k_2; ECPoint P_1, P_2, R_1, R_2; generate_keypair(params, &x_1, &P_1); generate_keypair(params, &x_2, &P_2); // 计算组公钥 P = P1 + P2 *ag_P = point_add(P_1, P_2 ,params);//组公钥 printf("ag_P = (%lld,%lld)\n",(*ag_P).x,(*ag_P).y); // 生成随机数并计算 R1 和 R2 k_1 = rand() % (params.n - 1) + 1; R_1 = point_multiply(k_1, params.G, params); k_2 = rand() % (params.n - 1) + 1; R_2 = point_multiply(k_2, params.G, params); *ag_R = point_add(R_1, R_2, params); printf("ag_R = (%lld,%lld)\n",(*ag_R).x,(*ag_R).y); // 计算 e = H(m || R.x || R.y || P.x || P.y) mod n char buffer[1024]; sprintf(buffer, "%s%lld%lld%lld%lld", msg, (*ag_R).x, (*ag_R).y,(*ag_P).x,(*ag_P).y); ll e = hash(buffer) % params.n; // printf("聚合哈希 e: %lld\n", e); // 计算各签名者s值并聚合 s_1 = mod(k_1 + e * x_1, params.n); s_2 = mod(k_2 + e * x_2, params.n); *ag_s = mod(s_1 + s_2, params.n); printf("ag_s = %lld\n", *ag_s); } //聚合签名验证 void aggregate_verify(ECC_Params params,char *msg, ECPoint ag_R, ECPoint ag_P, ll ag_s) { int valid = schnorr_verify(params, msg, ag_R, ag_P, ag_s); // 验证 printf("聚合签名最终验证结果: %s\n", valid ? "签名有效" : "签名无效"); } int main() { // 初始化随机数生成器 srand(time(NULL)); // 1. 初始化椭圆曲线参数 ECC_Params params; ecdsa_init(&params); // 2. 生成密钥对 ll private_key; ECPoint public_key; generate_keypair(params, &private_key, &public_key); // 3. 待签名的消息 char original_message[] = "测试消息,用于签名演示"; // char original_message[1024] = {0}; //明文 // printf("请输入要加密的信息: "); // fgets(original_message, sizeof(original_message), stdin); // original_message[strcspn(original_message, "\n")] = '\0';// 去除换行符 printf("原始消息: %s\n", original_message); // 4. 对消息进行签名 ll s; ECPoint R; schnorr_sign(params, private_key,public_key,original_message, &R, &s); // 生成签名 int valid = schnorr_verify(params, original_message, R, public_key, s); // 验证 printf("最终验证结果: %s\n\n", valid ? "签名有效" : "签名无效"); ECPoint ag_P, ag_R; ll ag_s; aggregate_sign(params, original_message, &ag_P, &ag_R, &ag_s); aggregate_verify(params, original_message, ag_R, ag_P, ag_s); return 0; } 已知上述代码,使用上述代码并进行简单编程,完成ZSS签名,ZSS中 双线性配对模拟 详细执行 使用c语言实现过程
最新发布
09-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值