基于中国剩余定理的秘密共享方案
该算法比https://blog.csdn.net/qq_42450533/article/details/102942808的代码效率更高。
秘密共享是将秘密以适当的方式拆分,拆分后的每一个子秘密由不同的参与者管理,单个参与者无法恢复秘密信息,只有若干个参与者一同协作才能恢复秘密消息。并且,当其中某些参与者出问题时,秘密仍可以恢复。
(𝒕,𝒏) 门限秘密共享方案
将秘密 𝒌 分成 𝒏 个子秘密 𝒌𝟏,𝒌𝟐,⋯,𝒌𝒏,满足下面两个条件:
(1) 如果已知任意 𝒕 个𝒌𝒊值,易于恢复出 𝒌;
(2) 如果已知任意 𝒕−𝟏 个或更少个𝒌𝒊值,不能恢复出 𝒌。
将一个密钥分成𝒏份,那么𝒏个人中至少𝒕人在场才能获得密钥。
设秘密k的位数为B,则B/t<len(d)<b/(t-1),即d值的长度在B/t与B/(t-1)之间,这样子选取d值,可以是最小的前t个数的乘积>k>最大的前t-1个数的乘积,满足条件3,又因为在本实验中d的大小顺序不是很重要,故而没有排序,那么只需要再满足条件2即可,即判断是否互素。
代码如下
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include "miracl.h"
#include<Windows.h>
#define SECRET_BITS 500 // 秘密的位数
#define N 7 // 恢复秘密所需要的最少子秘密个数t
#define T 4 // 子秘密的个数n
#define D_DIGBITS (((SECRET_BITS/T)+(SECRET_BITS/(T-1)))/2) // 定义d的位数
#define MAX_D ((N)*(D_DIGBITS)+(N)) // 定义大数系统的最大位数(稍微比N倍的d大就可以)
big ki[N], di[N];
void zhongguo()
{
int i, num[N];
big x = mirvar(0);
big one = mirvar(1);
big m = mirvar(1);//m是di连乘的乘积
big Mit[N];//Mi
big Mit_1[N];//Mi的逆
big g1[N];//中间变量,计算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(big k,int num)
{
int i;
big one = mirvar(1);//big型数值1
big q = mirvar(0);
int flag = 1;//假设互素
for (i = 0; i < num; i++)
{
egcd(di[num], di[i], 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(MAX_D, 10);
big secret = mirvar(0);//k为秘密
big one = mirvar(1);//big型数值1
int i;
char num[500]; char num1[500];
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
{
cinnum(secret, fp);//从fp文件中把大数赋值给big型变量secret
printf("\n");
cotnum(secret, stdout);//打印一下
//开始寻找di的值
bigdig(D_DIGBITS, 10, di[0]);//先找一个di[0]
for(i = 1; i<N ;i++)
{
bigdig(D_DIGBITS, 10, di[i]);
if (coprime(secret,i) == 0)//新的数不能和之前的互素,则此数作废
{
i--;
}
}
//计算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();
}
//程序结束
system("pause");
return 0;
}