我们如何理解Coppersmith算法
我们如何理解Coppersmith算法
AiY0u博客很久没有更新了
我们先来讨论一个,在我萌新时代,困扰我很久的问题:RSA低位泄露
比如说RSA的p,原本是512位,但我们已经知晓了它的低400位,我们该如何复原p?
当时我只检索到这个要用到coppersmith算法求小根,但是对当时初入数论模运算都搞不明白的我来说,它过于超纲,拼尽全力无法战胜。
题目
这里随便找了一个题
1 | import gmpy2 |
Coppersmith
问题转化
前面的二项式展开我们都不提,就说我们已经求出了p的低400位,记为
那么我们的p就可以表示为关于x (即)的一个方程,
显然
我们就把RSA低位泄露问题转化成了一个寻找多项式 在模 p 下的根 x₀ 的问题
这样的方程不好求解。
但是我们可以试着找到一个新的多项式 g(x),它必须满足两个关键条件:
- 条件A (共享根):
g(x)必须也以x₀为根,即g(x₀) ≡ 0 (mod p)。 - 条件B (系数小):
g(x)作为整数多项式(暂时忽略模p),它的系数必须非常小。
这里我们还发现,因为 相对 来说非常小,我们可以认为它是一个小根。
魔法发生
因为 本身很小(这是前提),并且 g(x) 的系数也很小(条件B),那么当我们计算 g(x₀) 的整数值时,这个结果 |g(x₀)| 也将是一个非常小的整数。
同时,我们又知道 g(x₀) 是 p 的倍数(条件A)。
现在想象一下:一个数,它既是 p 的倍数(p 是一个非常大的数),又是另一个非常小的数。唯一的可能性是什么?
这个数只能是 0!
所以,我们得出结论: 在整数域上成立!
所以我们只需要求 的根就好,问题变得尤为简单!
那么问题来了,说了一大堆,这个 从哪来
LLL
这时候需要请我们LLL算法出场
我们先来简单回顾一下什么叫格,LLL算法在做什么。
格(Lattice)
想象一下,我们在平面上画出一个平面直角坐标系,然后取两个向量 和 (把它们称为基向量).这时候,由这两个向量线性组合,可以得到一个网格。网格上存在十字交叉点(即),格就是所有这些点组成的集合
同理,我们可以用不同数量的不同向量作为基向量,并想象任由它们做线性组合,最终能够产生一张有很多点的复杂大网。
我们用的基向量如果长度太长且“非常不正交”,那它表示这张大网的某个点,应该会很不简洁,很不舒服。
我们这里说用来表示这个格的基向量是“坏向量”。
而LLL算法的作用就是
我们嫌弃一个格的基向量太坏了,就把这些基向量喂给LLL,LLL算法会返回给我们,比较短且近乎正交的新的基向量。
我们用它给的基向量就能很舒服的表达格上的每个点,它是“好向量”
所以LLL就是把一个格的“坏向量”转化成“好向量”。
LLL的作用
那么我们回归问题
我们希望构建一个由根是 的多项式们组成的格
这样的话,需要基也是根为 的多项式。
这样把基向量喂给LLL,他就会返回一组更好的基,这些基应当足够短。
我们就取其中的第一个向量 ,它就代表一个系数很小的、根是 的多项式
我们只要通过 就能反解出 了
这个想法很顺,但是我们需要考虑喂给LLL一组什么样的基。
构造基
显然只要我们喂的基两两非线性,LLL算法就能跑的动。但是跑的动不代表跑的好。
-
考虑维度
我们必须清楚,LLL算法找到的短向量 v* 的长度与格的维度 和行列式密切相关。一个粗略的公式是:
$ ||v^*|| ≤ 2^{((w-1)/4)} * det(B)^{(1/w)}$
我们在构造基向量的时候,维度越高越容易找到短向量。
-
考虑让g(x_0)小于模数
正如"魔法发生"那里提到的, 应当小于模数
因此我们可能需要将模数放大
综合这两个要求,我们可以采用这样的聪明的构造方法:
取正整数m(在实际应用中我们常让m从小到大不断尝试)
构造
我们不难发现, 应当是 的倍数
于是我们就可以放心把模数放大为
同时也通过这种方式构建了m个方程,也是增大了维度。
所以我们只要把这样构建出来的一组基,喂给LLL,得到一个短向量,求解 ,什么问题都解决了!
总结
你说这玩意咋寻思出来的呢(嚼嚼嚼嚼嚼)

