某电信安数基实验
该实验本意是在大数的场景下运行,故而需要使用miracl库,具体使用方法请看https://blog.csdn.net/qq_42450533/article/details/102493504的后半部分
基于中国剩余定理的秘密共享方案
秘密共享是将秘密以适当的方式拆分,拆分后的每一个子秘密由不同的参与者管理,单个参与者无法恢复秘密信息,只有若干个参与者一同协作才能恢复秘密消息。并且,当其中某些参与者出问题时,秘密仍可以恢复。
(𝒕,𝒏) 门限秘密共享方案
将秘密 𝒌 分成 𝒏 个子秘密 𝒌𝟏,𝒌𝟐,⋯,𝒌𝒏,满足下面两个条件:
(1) 如果已知任意 𝒕 个𝒌𝒊值,易于恢复出 𝒌;
(2) 如果已知任意 𝒕−𝟏 个或更少个𝒌𝒊值,不能恢复出 𝒌。
将一个密钥分成𝒏份,那么𝒏个人中至少𝒕人在场才能获得密钥。
在本实验中,我们以(3,5)门门限秘密共享方案为例,k值为500位左右的大整数
在程序编写过程中,我们发现如果使用穷举的方法去寻找d值的话,计算速度会非常慢,只要大数文件稍微大一些,运行时间就会指数级增长。
由于我们的k值是一个500位的大整数,所以我们可以这么想:寻找5个200位的整数,使其递增而且都是质数,由于我们的位数足够大,所以我们很容易能够找到这样子的5个数。
满足上述条件的5个大整数,由于其都是质数,所以两两互素;前3个数的乘积是600位的整数,这个乘积大于k值(500位),后2位的整数的乘积是400位的整数,这个乘积小于k值(500位)。故而满足上述条件即满足 d值递增,d值两两互素,N>k>M三个条件。
关于中国剩余定理的应用请看另一篇博文中国剩余定理的算法实现(基于c语言miracl库)
注意:测试运行时大数文件中的大整数必须在500位左右,必须关闭安全检查(属性,C/C++,代码生成,关闭安全检测)
程序运行需要几秒钟时间
C语言代码
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include "miracl.h"
#include<Windows.h>
big ki[5], di[5];
void zhongguo(int t,int n)
{
int i,num[5];//
big x = mirvar(0);
big one = mirvar(1);
big m = mirvar(1);//m是di连乘的乘积
big Mit[5];//Mi
big Mit_1[5];//Mi的逆
big g1[5];//中间变量,计算Mi*Mi的逆*ai(a1即Ki)
printf("\n请选择%d个子秘密,输入序号1 - %d\n", t, n);
for (i = 0; i < t; i++)
{
scanf("%d", &num[i]);
num[i]--;//使序号从1 - t ,转化为 0 - t-1,符合数组下标的实际情况
}
//初始化
for (i = 0; i < n; i++)
{
Mit[i] = mirvar(0);
Mit_1[i] = mirvar(0);
g1[i] = mirvar(0);
}
//m=di[num[i]]连乘
for (i = 0; i < t; i++)
{
multiply(m, di[num[i]], m);//di[num[i]]表示的就是中国剩余定理中的mi
}
//Mit[t]=mt/di[num[i]],即计算Mi
for (i = 0; i < t; i++)
{
fdiv(m, di[num[i]], Mit[i]);//除法
}
//Mit_1为Mit的逆
for (i = 0; i < t; i++)
{
xgcd(Mit[i], di[num[i]], Mit_1[i], Mit_1[i], Mit_1[i]);//求逆运算
}
//g1 = Mi t* Mit_1 * ki[ num[i] ]
for (i = 0; i < t; i++)
{
multiply(Mit[i], Mit_1[i], g1[i]);
multiply(g1[i], ki[num[i]], g1[i]);
}
//x=g1[1]+g1[2]+...+g1[t]
for (i = 0; i < t; i++)
{
add(x, g1[i], x);
}
powmod(x, one, m, x);// g1 = g1的一次方 mod m
printf("\n");
printf("秘密 is : \n");
cotnum(x, stdout);
printf("\n");
}
int coprime(int n)
{
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);
if (compare(q, one) != 0)
{
flag = 0;
}
}
}
mirkill(q);
mirkill(one);
return flag;//如果不能够两两互素,则返回0,若能,则返回1
}
int main()
{
FILE *fp;
char fpname[100];//文件名
miracl *mip = mirsys(800, 10);
big secret = mirvar(0);//k为秘密
big one = mirvar(1);//big型数值1
big zero = mirvar(0);//big型数值0
big p = mirvar(0);
int i;
int n = 5, t = 3;//这是一个(t,n)门的秘密共享方案
char num[250];
for (i = 0; i < n; i++)
{
ki[i] = mirvar(0);//对每一个ki[]进行初始化
di[i] = mirvar(0);//对每一个di[]进行初始化
}
//
printf("输入大数secret的文件完整路径\n");
scanf("%s", fpname);
if ((fp = fopen(fpname, "r")) == NULL)
{
printf("fail to open the file\n");
system("pause");
exit(0);
}
else
{
/*随机创建一个秘密,这个秘密有500为
bigdig(500, 10, secret);
printf("随机的秘密为:\n");
cotnum(secret, stdout);
*/
cinnum(secret, fp);//从fp文件中把大数赋值给big型变量secret
printf("\n");
cotnum(secret, stdout);//打印一下
//创建一个字符串,这个字符串以1开头,以1结尾,一共有200位数
num[0] = '1';
for (i = 1; i < 200; i++)
{
num[i] = '0';
}
num[i - 1] = '1';
num[i] = '\0';
//将num转化为大数
i = cinstr(p, num);
//开始寻找di的值
loop:for (i = 0; i < 5;)//找到5个符合条件的di就跳出
{
if (isprime(p))//判断p是否为素数,是的话把p赋给di[]
{
copy(p, di[i]);//di[i]=p,赋值操作
i++;
}
incr(p, 2, p);//不管p是否为素数,每次循环加2
}
if (coprime(n) == 0)//fermat素性检测算法有极小概率出问题,故而验证d值是否两两互素,若不互素,则重新寻找一组d值
{
goto loop;
}
//计算ki
for (i = 0; i < n; i++)
{
powmod(secret, one, di[i], ki[i]);//ki[i]=k(mod di[i])
}
//打印子秘密
for (i = 0; i < n; i++)
{
printf("\n第%d个子秘密(di,ki)为:----------------------------\n", i + 1);
cotnum(di[i], stdout);
cotnum(ki[i], stdout);
printf("---------------------------------------------------\n");
}
//接下来进行秘密复原
zhongguo(t, n);
}
//程序结束
system("pause");
return 0;
}
结果截图