基于中国剩余定理的秘密共享方案(miracl库)

注意:本文算法效率极低,大数在3位数时就会运行10分钟左右,若是更大的数字,博主等不了没试过。请移步https://blog.csdn.net/qq_42450533/article/details/102996536查看最新算法

某电信安数基实验
备注:
该实验本意是在大数的场景下运行,故而需要使用miracl库,具体使用方法请看https://blog.csdn.net/qq_42450533/article/details/102493504的后半部分
注意:本文代码效率极低,大数在3位数时就会运行10分钟左右,若是更大的数字,博主等不了没试过。
基于中国剩余定理的秘密共享方案
秘密共享是将秘密以适当的方式拆分,拆分后的每一个子秘密由不同的参与者管理,单个参与者无法恢复秘密信息,只有若干个参与者一同协作才能恢复秘密消息。并且,当其中某些参与者出问题时,秘密仍可以恢复。
(𝒕,𝒏) 门限秘密共享方案
将秘密 𝒌 分成 𝒏 个子秘密 𝒌𝟏,𝒌𝟐,⋯,𝒌𝒏,满足下面两个条件:
(1) 如果已知任意 𝒕 个𝒌𝒊值,易于恢复出 𝒌;
(2) 如果已知任意 𝒕−𝟏 个或更少个𝒌𝒊值,不能恢复出 𝒌。
将一个密钥分成𝒏份,那么𝒏个人中至少𝒕人在场才能获得密钥。

分解秘密在这里插入图片描述
恢复秘密在这里插入图片描述
c语言代码:

注意:代码使用了大量栈,需要做以下修改:
右键项目名,属性,链接器,系统,把堆栈保留大小改为100000000(堆提交大小改为100000000)

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include "miracl.h"
#include<Windows.h>
FILE *fp;
char fpname[100];//文件名
int num[100000];//选择的子秘密

big K ;//K作为秘密
int t, n;//秘密被分割为n分,只需要t份就可以复原秘密
int i, j, flag;
big ki[100000];//假定秘密被分的分数最大上限为100000
big di[100000];//d用于 mod d
big N;//N用于t个最小的di相乘,初始化为1
big M;//M用于t-1个最大的di相乘,初始化为1

void zhongguo()
{
	big x = mirvar(0);
	big one = mirvar(1);
	big mt = mirvar(1);
	big Mit[100000];//Mi
	big Mit_1[100000];//Mi的逆
	big g1[100000];//中间变量,计算Mi*Mi的逆*ai(a1即Ki)
	for (i = 0; i < 100000; i++)
	{
		Mit[i] = mirvar(0);
		Mit_1[i] = mirvar(0);
		g1[i] = mirvar(0);
	}
	int i, j;
	for (i = 0; i < t; i++)
	{
		multiply(mt,di[num[i]] ,mt );//di[num[i]]表示的就是mi
	}//mt=di[num[i]]连乘
	for (i = 0; i < t; i++)
	{
		fdiv(mt, di[num[i]], Mit[i]);//Mit[t]=mt/di[num[i]],即计算Mi
	}
	for (i = 0; i < t; i++)
	{
		xgcd(Mit[i],di[num[i]] , Mit_1[i], Mit_1[i], Mit_1[i]);//Mit_1为Mit的逆
	}
	for (i = 0; i < t; i++)
	{
		multiply(Mit[i], Mit_1[i], g1[i]);
		multiply(g1[i], ki[num[i]], g1[i]);
	}
	for (i = 0; i < t; i++)
	{
		add(x, g1[i], x);
	}
	powmod(x, one, mt, x);// g1 = g1的一次方 mod m
	printf("\n");
	printf("秘密 is : \n");
	cotnum(x, stdout);
	printf("\n");
}

void add_di(int i)
{
	big p = mirvar(0); 
	decr(K, 1, p);//p=K-1
	if (compare(di[i], p) < 0)// di[i] < p 的时候,即di[i]达到最大值以前,给加1操作
	{
		incr(di[i], 1, di[i]);//di[i]++

	}
	else if ((compare(di[i], p) == 0)&&(i==0))//当第一位已经计数到K-1的时候,该程序已经无法找到合适的di数组
	{
		printf("找不到所需di\n");
		flag = 2;
	}
	else//若di[i]加一==K-1,则上一位加1,本位设置为上一位的值+1
	{
		add_di(i - 1);//递归
		incr(di[i - 1], 1, di[i]);//di[i]=di[i-1]+1
	}
	mirkill(p);//关闭big p
}
int Coprime()//判断是否两两互素
{
	int i, j;
	big one = mirvar(1);//big型数值1
	big q = mirvar(0);

	int flag = 1;
	for (i = 0; i < n; i++)
	{
		for (j = i + 1; j < n; j++)
		{
			egcd(di[i], di[j], q);//q为di[i]与di[j]的最大公约数
			if (compare(q, one)!=0)
			{
				flag = 0;
				goto loop;
			}
		}
	}
	loop:
	mirkill(q);
	mirkill(one);
	return flag;//如果不能够两两互素,则返回0,若能,则返回1
}
int NM()
{
	int i;
	N = mirvar(1);//每次都要对NM置为1
	M = mirvar(1);
	for (i = 0; i < t; i++)
	{
		multiply(N, di[i], N);
	}
	for (i = 0; i < t - 1; i++)
	{
		multiply(M, di[n - 1 - i], M);
	}
	if ((compare(N, K) > 0) && compare(K, M) > 0)
	{
		flag = 1;
	}
	else flag = 0;
	return flag;//若N>K>M,则返回1

}
int main()
{
	miracl *mip = mirsys(500, 10);
	K = mirvar(0);
	N = mirvar(1);
	M = mirvar(1);
	big one = mirvar(1);//big型数值1
	big zero = mirvar(0);//big型数值0
	for (i = 0; i < 100000; i++)
	{
		ki[i] = mirvar(0);//对每一个ki[]进行初始化
		di[i] = mirvar(0);//对每一个di[]进行初始化
	}
	printf("输入大数k的文件完整路径\n");
	scanf("%s", fpname);
	if ((fp = fopen(fpname, "r")) == NULL)
	{
		printf("fail to open the file\n");
		system("pause");
		exit(0);
	}
	else
	{
		cinnum(K, fp);//从fp文件中把大数赋值给big型变量k
		printf("输入参数 n 与参数 t ,按照顺序输入\n");
		scanf("%d", &n);
		scanf("%d", &t);
		//开始选择di

		//下面循环开始初始化di,设di[0]=2,此后每一位在上一位的基础上加一
		for (i = 0; i < n; i++)
		{
			incr(zero, i + 2, di[i]);//di[i]=i+2;
		}
		decr(di[n-1], 1, di[n-1]);//对最后一位先减1,后面进入循环后会加一补回
		flag = 0;
		while (1)//开始计算di
		{		
			if (flag == 1)
			{
				break;//找到所需的di数组,离开
			}
			else if (flag == 2)
			{
				system("pause");
				//scanf("%d", &t);
				goto eloop;//结束程序
			}
			else
			{
				add_di(n - 1);//对最后一位加一,K进制
			}
			//flag = 0;
			//判断
			flag = Coprime();//判断是否两两互素,如果不能够两两互素,则返回0,若能,则返回1
			if (flag == 0)continue;
			flag = NM();//若N>K>M,则返回1
				//判断完毕
		}
		//开始计算ki
		for (i = 0; i < n; i++)
		{
			powmod(K, one, di[i], ki[i]);//ki[i]=k(mod di[i])
		}
		//开始输出子秘密
		for (i = 0; i < n; i++)
		{
			printf("--------------------\n");
			cotnum(di[i], stdout);
			cotnum(ki[i], stdout);
			printf("--------------------\n");
		}
		
		//接下来进行秘密复原
		
		printf("请选择%d个子秘密,输入序号0~t-1\n", t);
		for (i = 0; i < t; i++)
		{
			scanf("%d", &num[i]);
		}
		
		//开始使用中国剩余定理
		
		zhongguo();


	}


	eloop:
	fclose(fp);
	mirexit();
	//scanf("%d", &t);
	system("pause");

	return 0;
}

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值