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