定义
给定一个由正整数列表(M1,M2,...,Mn)和另一个整数S(目标和)。问题在于找到该列表的一个子集,使其元素之和恰好等于S。
这个问题也可以用二进制向量来描述:寻找一个二进制向量x=(x1,x2,...,xn),使得S=∑i=1nxiMi,向量x中的1小时对应位置的整数Mi被选中加入子集。
问题的困难性
一般情况:子集和问题通常是一个NP-complete问题,这意味着在计算上通常被认为是困难的
暴力破解:通过检查所有可能的2n个二进制向量可以找到解,但效率特别低。
碰撞算法:存在一种碰撞算法,可以将运行时间缩短到O(22/n),但需要巨大的存储空间。
“易解”的情况:超递增序列
如果整数列表r=(r1,r2,...,rn)是超递增的,那么这个问题就会变得特别容易解决。
- 定义:一个序列是超递增的,如果每一项都大于前面所有项的和,即ri+1≥∑j=1irj
- 解法:对于超递增序列,可以使用贪心算法快速找到解,从最大元素rn开始,如果S≥ri,则把xi设为1并从S中减去ri,否则xi设为0
背包密码系统(Merkle-Hellman)
Merkle和Hellman利用上述特性设计了一种公钥密码系统,其核心思想是将一个“易解”的超递增子集和问题,通过模运算“伪装”成一个看似困难的一般子集和问题
- 密钥生成:
- 私钥:一个超递增序列r=(r1,r2,...,rn),以及两个大整数A,B,满足B>2rn且gcd(A,B)=1
- 公钥:一个伪装后的序列M=(M1,M2,...,Mn),其中Mi≡Ari(modB),这个序列M看起来不再是超递增的
- 加密:发送方将明文消息转化为二进制向量x,计算密文S=x⋅M发送给接受者
- 解密:接收方(拥有私钥 A,B ),首先计算 S′=A−1S(modB) 。由于 B 很大,这个同余式实际上是一个等式 S′=∑xiri 。接收方随后利用超递增序列 r 轻松解出 x 。
安全性和基于格的攻击
- 主要弱点:教材指出,背包密码系统的根本弱点在于,它可以被重新表述为格中寻找短向量的问题
- 攻击方法:攻击者可以构造一个特定的格,其中包含公钥 M 和密文 S。如果使用格基规约算法(例如 LLL算法)找到了该格中的一个特定短向量,就能直接恢复出明文x。
格的构造:
假设公钥序列为M=(M1,M2,...,Mn),密文为 S 。攻击者希望找到二进制向量 x=(x1,x2,...,xn) 使得 S=∑i=1nxiMi
构造如下(n+1)×(n+1) 矩阵:
⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛200⋮01020⋮01002⋮01⋯⋯⋯⋱⋯⋯000⋮21m1m2m3⋮mnS⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞
-
格的基:这个矩阵的每一行构成了一个格 L 的基向量。记前 n 行为v1,v2,...,vn 最后一行为 vn+1。
-
目标短向量:如果存在解 x=(x1,x2,...,xn) ,那么格 L 中必然包含一个特定的短向量 t 。这个向量可以通过基向量的线性组合得到:
t=i=1∑nxivi−vn+1
-
向量的分量:
- 前 n 格分量为 2xi−1。由于 xi 只能是 0 或 1 ,所以这些分量的值只能是 1 或 -1。
- 最后一个分量为 ∑ximi−S 。因为 x 是解,所以这个和等于 S ,因此最后一个分量为 0
- 所以,这个特定的短向量 t 的形式为 (±1,±1,...,±1,0)
-
这个向量 t 的长度为 n ,这相对于格中其他向量(通常长度很大,与 mi 和 S 的大小有关)来说非常小。使用格基规约算法(如 LLL算法)很有可能找到这个异常短的向量 t,从而恢复出 xi 的值(如果 t 的第 i 个分量是 1,则 xi=1,反之为 0),破解密码系统。
2026.1.23:
注:注意解出来的向量可能是反向的,还有大端序小端序问题。