上一篇中国剩余定理的文章请跳转到:
https://blog.csdn.net/Koz_0/article/details/109177491
一、基础知识原理
基础知识上课老师都讲了,也有相关的ppt,这里就不多说了。
而且也没人看对吧,都只想着看代码了。
这个题的难点估计就是找这个di数组了,因为这个di数组是随机生成的,
而且有递增、互素、N>K>M这三个条件,所以比较难以搞定。
其基本思想其实和剩余定理差不多。
二、算法实现
1.环境
使用的是vc 6++ 和miracl大整数库。
miracl整数库的配置可以自行去百度一下,应该也有不少。我这里提供一下miracl整数库的配置资源吧。见链接:
如果在配置的时候有什么问题可以私信或者评论,我会尽力而为的。
链接:http@@s://p@@an.baidu.c@@om/s/1HKP-v0OFQIPyZmMjRSPFJw
提取码:jops (把@删除掉就是完整链接)
2.di数组生成说明
这里面,因为秘密是500位的,而且是分成五个子秘密,恢复需要三个子秘密,所以di随机数只要设定成100-200位的,并且相互互素就可以。
我用的是167位,有一个hxd跟我说这个di的位数最好满足
(500/t + 500/t-1)/2,
算了一下,166或者167都可以,大家可以直接用。
3.主要代码
代码如下:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include"miracl.h"
#define n 5
#define t 3
#define secnum 500
big d[n],k[n];
int compbig(int x){
int i;
big one = mirvar(1);
big temp = mirvar(0);
int result = 1;
for (i = 0; i < x; i++)
{
egcd(d[x], d[i], temp);//求最大公约数
if (compare(temp, one) != 0)
{
result = 0;
}
}
mirkill(temp);
mirkill(one);
return result;
}
int find_d(big key)
{
int coprime(int x);
int i;
int res = 1;
int j;
big one;
big temp;
big N,M,K;
N = mirvar(1);
M = mirvar(1);
K = mirvar(1);
one = mirvar(1);
temp = mirvar(0);
bigdig(167,10,d[0]);
//先生成一个随机数,然后再循环生成随机数,判断是否互素
for(i=1;i<n;i++){
bigdig(167,10,d[i]);
if(compbig(i)==0){//
i--;
}
}
//冒泡排序
for(i=0; i<5; i++){
for(j=0; j<5-i-1; j++){
if(compare(d[j],d[j+1])==1){//d[j]>d[j+1]
copy(d[j],temp);//temp = d[j]
copy(d[j+1],d[j]);
copy(temp,d[j+1]);
}
}
}
printf("findi---2\n");
for(i=0;i<3;i++){
multiply(d[i],N,N);
}
for(i=3;i<5;i++){
multiply(d[i],M,M);
}
printf("findi---3");
copy(key,K);
if((compare(N,K)==1)&&(compare(N,M)==1)&&(compare(k,M)==1))
//if(compare(N,K)compare(K,M))
res = 0;
else
res = 1;
return res;
}
int main()
{
FILE *fp;
miracl *mip = mirsys(10000, 10);//初始化10的五次方
//mip->IOBASE = 10; //设置 10进制
int j = 0;
int i = 0;
int cordi = 1;
int numseq[5];
big secret;
big res;
big temp, one;
big m = mirvar(1);//m是di连乘的乘积
big Mit[5];//Mi
big Mit_1[5];//Mi的逆
big g1[5];//中间变量,计算Mi*Mi的逆*ai(a1即Ki)
//key = mirvar(1);
one = mirvar(1);
res = mirvar(0);
temp = mirvar(0);
secret = mirvar(1);
for (i=0;i<n;i++) {
d[i] = mirvar(0);
k[i] = mirvar(0);
}
fp = fopen("3.txt","r");
if (fp == NULL)
{
printf("FILE ERROR\n");
return 0;
}
cinnum(secret, fp);
cotnum(secret, stdout);
//为了能够满足N>K>M
while(cordi){
cordi = find_d(secret);//找到合法的di数组
printf("2\n");
}
for(i=0;i<n;i++){
//ki = k mod(di)
printf("\n");
printf("第%d个di和ki的值为:\n",i+1);
copy(secret,temp);
printf("\n------------------------------------------------------------------\n");
printf("\n");
cotnum(d[i],stdout);
divide(temp,d[i],d[i]);
copy(temp,k[i]);
//printf("\n------------------------------------------------------------------\n");
printf("\n");
cotnum(k[i],stdout);
printf("\n------------------------------------------------------------------\n");
}
//中国剩余定理
printf("选择3个子秘密,输入序号1-5\n");
for (i = 0; i < t; i++)
{
scanf("%d", &numseq[i]);
numseq[i]--;//
}
//初始化
for (i = 0; i < n; i++)
{
Mit[i] = mirvar(0);
Mit_1[i] = mirvar(0);
g1[i] = mirvar(0);
}
//m=d[numseq[i]]连乘
for (i = 0; i < t; i++)
{
multiply(m, d[numseq[i]], m);
}
//计算Mi
for (i = 0; i < t; i++)
{
fdiv(m, d[numseq[i]], Mit[i]);//除法
}
//计算Mi的逆
for (i = 0; i < t; i++)
{
xgcd(Mit[i], d[numseq[i]], Mit_1[i], Mit_1[i], Mit_1[i]);//求逆运算
}
for (i = 0; i < t; i++)
{
multiply(Mit[i], Mit_1[i], g1[i]);
multiply(g1[i], k[numseq[i]], g1[i]);
}
//求和
for (i = 0; i < t; i++)
{
add(res, g1[i], res);
}
powmod(res, one, m, res);// 模一次
printf("秘密是 : \n");
printf("------------------------------------------------------------------\n");
cotnum(res, stdout);
printf("------------------------------------------------------------------\n");
mirexit(); //清除MIRACL系统,释放所有的内部变量
getchar();
return 0;
}
三、总结
这个是此课程的第三个实验。
这几天牙疼,无心学习,所以才拖到周五。