LLL利用LLL来解决线性方程组
AiY0uLLL在密码学中是一个非常好用的工具。
我们知道格对于密码学分析有着极其重要的意义 对于一个方程组,如果我们能够证明它的解是格中的一个短向量,那么,我们就可以利用格来绕过传统的解方程方法,转而使用LLL来直接获得该解。
这篇文章主要讨论的是,假设我们从问题中抽象出了一个线性方程组,那么我们可以如何进行求解
一、使用LLL寻找一个多元线性方程的解
假设我们从某个问题中获得了方程:
a0x0+a1x1+...+anxn=s
并且我们确信,我们所要找的解很小。
那么我们可以选择这样的构造这样的基:
$\mathbf{B} = \begin{pmatrix} \mathbf{I} & k\mathbf{a} \ 0 & -ks \end{pmatrix} $
其中,a代表列向量(a0 a1 ... an)T
注:每一行为一个基向量
这样构造之后,我们就会发现:
对于一个行向量v=(v1 v2 ... vn 1)
$\mathbf{v}\mathbf{B} = \begin{pmatrix} v_1 & v_2& …& v_n& k(a_1v_1+a_2v_2 +…+a_nv_n-s)\end{pmatrix} $
由此可见,当我们把k设置的足够大,
那么当最后一个元素为0时,vB就足够短。
那么LLL在拼命寻找由基B优化而来的基时,不可避免的会发现这个向量
那么LLL会有相当大的概率返回给我们最后一个元素为0时对应的vB, 其中通过也就包含了我们要求解的x
\
sagemath中的矩阵对象自带.LLL()方法,这里给出一段示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| # 1. 准备数据 coeffs = [12, 23, 34] target = 127 n = len(coeffs) K = 1000 # 权重,要足够大
# 2. 初始化矩阵 (n+1) x (n+1) # 这里的 ZZ 非常重要! B = Matrix(ZZ, n + 1, n + 1)
# 3. 填充矩阵 # 填充单位阵部分 for i in range(n): B[i, i] = 1
# 填充最后一列(系数部分) for i in range(n): B[i, n] = K * coeffs[i]
# 填充最后一行(目标值部分) B[n, n] = -K * target
# 执行 LLL 算法 # 结果是一个新的矩阵,包含了规约后的基 res = B.LLL()
print("\nLLL 规约后的矩阵:") print(res)
|
二、拓展到寻找多元线性方程组的解
当我们将问题从单一方程推广到方程组时,核心思想并没有改变:
我们将每一个方程视为一个独立的约束,并将这个约束映射到矩阵的一列中。 假设我们要解如下的线性方程组,包含 n 个变量和 m 个方程:
⎩⎨⎧a1,1x1+a1,2x2+⋯+a1,nxn=s1a2,1x1+a2,2x2+⋯+a2,nxn=s2⋮am,1x1+am,2x2+⋯+am,nxn=sm
我们需要构造一个维度为 (n+1)×(n+m) 的格基矩阵 B。 左侧 n 列为单位阵,右侧 m 列对应 m 个方程的系数(乘以权重 K)。
构造出的矩阵 B 如下所示:
B=10⋮0001⋮00⋯⋯⋱⋯⋯00⋮10Ka1,1Ka1,2⋮Ka1,n−Ks1Ka2,1Ka2,2⋮Ka2,n−Ks2⋯⋯⋱⋯⋯Kam,1Kam,2⋮Kam,n−Ksm
对于解向量 v=(x1,…,xn,1),计算 vB 后,右侧的 m 个分量将全部归零: $$ \mathbf{v}\mathbf{B} = \left( x_1, \ x_2, \ \dots, \ x_n, \ \ \underbrace{0, \ 0, \ \dots, \ 0}_{m \text{ 个}} \right) $$
也即是说LLL会很愿意返回给我们解向量 v=(x1,…,xn,1)
三、进阶:处理模线性方程组
在密码学场景中,我们遇到的往往是定义在模 M 上的方程组:
i=1∑naj,ixi≡sj(modM)(j=1,…,m)
为了利用格消除模数的影响,我们需要为每一个方程增加一行,用于表示模数 M 的倍数。
矩阵大小变为 (n+m+1)×(n+m)。
Bmod=0⋮00In⋯⋱⋯⋯0⋮00Ka1,1⋮Ka1,nKM⋮0−Ks1⋯⋱⋯⋯⋱⋯⋯Kam,1⋮Kam,n0⋮KM−Ksm
中间增加的 m×m 对角块允许格向量在每个方程的列上减去 KM 的整数倍,从而实现同余式归零。