公钥算法之背包算法

这是一个非对称算法,即可生成多个不同的公钥,分发给其他人,然后其他人用各自的公钥加密文件,而算法只生成一个私钥(自己保存),这私钥可解密不同公钥加密的文件。在不知道私钥的前提下,破解文件是一个NP难问题。

下面贴上高老师的讲义:

1.背包算法基于背包问题的简化版,即子集和问题( Subset sum)。
2.子集和问题:给定一个整数集 A(俗称为背包)和整数 b,要求找出 A的一个子集,使得其中元素之和等于 b
3.子集和问题是 NP完全问题。然而若集合 A是一个超级增长序列( Superincreasing),则可以使用简单的贪婪策略在多项式时间求解。
4.超级增长序列指集合中后一个元素大于前面所有元素之和。如 {2, 7, 11, 21, 42, 89, 180, 354}。
 
算法流程:
选择一个超级增长序列 w = ( w 1, w 2, ..., wn ) ,以及一个随机数 q ,满足 q > w i ,以及另一个随机数 r,使得 qr互素,即 gcd( r , q ) = 1
 
公钥计算:算集合 β   = ( β 1, β 2, ..., β n) ,其中β i = ( r × w i ) mod q,公钥就是 β,私钥就是 ( w , q , r )
 
加密:给定 n位二进制信息α = ( α 1, α 2, ..., α n), 利用公钥β   = ( β 1, β 2, ..., β n)计算如下: C= ∑α i * β i , C即密文
 
解密:解密的关键是利用 ( w , q , r )求出的逆元 s 。此即求解方程: s*r mod q =1。即满足 sr = kq + 1 。由于 gcd( r , q )=1,所以可以使用扩展欧几里德算法找出 s k

附上自己的代码:

/*该程序加解密文本长度最多为16个二进制位(包括16字节),即2字节*/
#include <stdio.h>
#define N 30
bool text[N],detext[N];//储存待加密文本和解密文本
int n,pubkey[N];//公钥β
int w[N];//超级增长序列

typedef struct Tri//三元组结构体
{
	int d,x,y;
}Tri;

Tri Extend_Euclid(int a,int b)//扩展欧几里德算法
{
	Tri t1,t2;
	if(b==0)
	{
		t1.d=a,t1.x=1,t1.y=0;//(a,1,0)
		return t1;
	}
//(d,x,y)←(d',y',x'-a/b*y')
	t2=Extend_Euclid(b,a%b);
	t1.d=t2.d;
	t1.x=t2.y;
	t1.y=t2.x-a/b*t2.y;
	return t1;
}

void Create_Super_Growth()//创建超级增长序列
{
	int i,sum=0;
	for(w[0]=1,i=1;i<N;i++)
		sum+=w[i-1]+1,w[i]=sum;
	return ;
}

int Encode(int q,int r)//加密
{
	int i,c=0;
	printf("公钥序列:\n");
	for(i=0;i<n;i++)//计算公钥β
	{
		pubkey[i]=w[i]*r%q;
		printf("%d: %d\n",i,pubkey[i]);
	}
	for(i=0;i<n;i++)//加密文本
		c=(c+text[i]*pubkey[i])%q;
	return c;
}

void Decode(int q,int r,int c)//解密
{
	int i;
	__int64 k,s;//防止k=c*s%q结果溢出
	Tri t;
	for(i=0;i<n;i++) detext[i]=0;
	t=Extend_Euclid(r,q);//扩展欧几里德求r逆元
	s=t.x;
	while(s<0) s+=q;//把负逆元转换为正逆元
	printf("r逆元:%d\n",s);
//开始解密
	k=s*c%q;
	printf("k=%d\n",k);
	for(i=n-1;i>=0;i--)//贪心策略解子集合问题,解密出二进制文本
		if(k>=w[i]) k-=w[i],detext[i]++;
	return ;
}

int main()
{//随机选择q和r,q>w序列1到n范围内元素之和,q和r要互素
	int i,c,q=0,r;//r为乘数,q为模数
	Tri t;
	Create_Super_Growth();//创建超级增长序列
	for(i=0;i<16;i++)//假设q=w[0]+...+w[15]+1,即加密长度不超过16byte
		q+=w[i];
	q++;
	for(i=2;;i++)//寻找第一个与q互数r(不一定要第一个)
	{
		t=Extend_Euclid(q,i);
		if(t.d==1) {r=i;break;}
	}
//	freopen("公钥算法之背包算法.txt","r",stdin);
	while(scanf("%d",&n)!=EOF)
	{
		for(i=0;i<n;i++)
			scanf("%d",&text[i]);//二进制待加密文本
		c=Encode(q,r);//加密,得到密文
		printf("密文:%d\n",c);
		Decode(q,r,c);//解密
		printf("解密后文本:\n");
		for(i=0;i<n;i++)
			printf("%d ",detext[i]);
		printf("\n");
	}
	return 0;
}

 样例输入:

16 1 0 0 1 1 0 1 0 1 1 1 0 0 1 1 0

样例输出:
公钥序列:
0: 3
1: 6
2: 15
3: 33
4: 69
5: 141
6: 285
7: 573
8: 1149
9: 2301
10: 4605
11: 9213
12: 18429
13: 36861
14: 73725
15: 49165
密文:20743
r逆元:32763
k=39677
解密后文本:
1 0 0 1 1 0 1 0 1 1 1 0 0 1 1 0

在这里感谢高老师的辛勤教导!!

转载于:https://www.cnblogs.com/Veegin/archive/2011/08/08/2130632.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值