简述:
- 公钥密码
公钥密码又称非对称密码,所谓非对称密码即加解密使用的不是同一个密钥。
在公钥密码体系中,使用每个人拥有两种密钥,公钥和私钥,公钥是公开的,用来加密,私钥是私自保存的,用于解密。如:
只有用自己的私钥才能解开自己公钥加密的信息,而且通过公钥钥是不能推出私钥的。
公钥密码将辅助信息(陷门信息)作为私钥,这类密码的安全强度取决于它所依据的问题的计算复杂度。
常见的公钥密码有RSA公钥密码、ElGamal公钥密码、椭圆曲线密码。
- 背包问题
背包问题:假设有一堆物品,体积各不相同,问能否从这堆物品中找出几个正好装满一个给定容量的背包?(假定物品之间不留空隙)
记物品的体积分别为v1,V2,…,n,背包的容量为C,则背包问题可表示为:b1v1+b2v2+…+bnvn=C
,其中,bi(i=1,2,…,n)
等于1或者0。
bi = 1表示第i个物品在背包中,bi=0表示第i个物品不在背包中,称物品体积的序列(v1,V2,…,vn)
为背包向量。
目前没有一个高效的算法来解决这个问题,只是进行穷举式搜索,但当数据足够多时,达到2的1024或2048位时,穷举式搜索将不再现实,问题就很复杂了。
- 超递增背包
并非所有的背包问题都没有有效算法,有一类特殊的背包问题是容易求解的,这就是超递增背包问题。
设V=(v1,2,…,vn)
是一个背包向量,若V满足V中每一项都大于它前面所有项之和,则称V是一个超递增向量,或者称序列v1,V2,,n是一个超递增序列,以V为背包向量的背包问题被称做超递增背包问题。
比如,序列1,2,4,16,…… ,2^n
就是一个超递增序列。
超递增背包问题的解可以通过以下方法找到:
假设背包容量为C,从右到左依次检查超递增背包向量中的每一个元素Vi,如果C >= Vi
,则C = C - Vi
,并将对应的bi置为1,否则跳过,继续检查下一元素,直至遍历完所有元素。如果此时C等于0,则该超递增背包问题有解,解为bi中的1对应的超递增背包向量中的元素,否则表示该问题无解。
例如:
加解密:
背包算法具体如下:私有密钥设置为将一个超递增向量 V 转换为非超递增向量 U 的
参数t 、t的逆元和 k,公开密钥设置为非超递增向量 U,具体的加解密过程如下:
- 加密
首先将二进制明文消息划分成长度与非超递增向量U长度相等的明文分组b1 b2 …… bn;
然后计算明文分组向量 B =(b1,b2,……,bn)与非超递增向量 U= (u1,u2,……,un)的内积 B * U = b1u1 + b2u2+ ……+bnun
,所得结果为密文。
- 解密
先还原出超递增背包向量V = t的逆元 * U mod k=t * t的逆元 * V mod k
;
再将密文 B * U 模 k 乘以 t逆元 的结果作为超递增背包问题的背包容量,求解超递增背包问题,得到消息明文。
代码实现:
import random
from my_modules import modules
# 初始化
def init(length, interval):
listV = [] # 超递增向量
listV_b = [] # 每个元素对应的乘数
bagCapacity = 1000 # 背包容积
# 初始化超递增向量与listV_b
for i in range(length):
listV.append(sum(listV) + random.randrange(1, interval))
listV_b.append(0)
# 求超递增背包的解
bagCapacityTmp = bagCapacity
for i in range(len(listV)-1, -1, -1):
if bagCapacityTmp >= listV[i]:
bagCapacityTmp -= listV[i]
listV_b[i] = 1
return listV
# 产生私钥:k、t、t的逆元
def creatPKey(listV):
# listV = init()
while True:
k = int(input("输入私钥k(大于%d):" % (sum(listV))))
if k <= sum