基于中国剩余定理的秘密共享方案(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) 如果已知任意 − 个或更少个值,不能恢复出 。
将一个密钥分成份,那么个人中至少人在场才能获得密钥。

分解秘密基于中国剩余定理的秘密共享方案(miracl库)_第1张图片
恢复秘密基于中国剩余定理的秘密共享方案(miracl库)_第2张图片
c语言代码:

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

#include
#include
#include
#include "miracl.h"
#include
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;
}

你可能感兴趣的:(基于中国剩余定理的秘密共享方案(miracl库))