密码学基础之LLL算法

admin 2024年2月9日14:37:55评论10 views字数 5607阅读18分41秒阅读模式
  • LLL & GCD

  • LLL & Gram-Schmidt

  • LLL & Gaussian Lattice Reduction

  • LLL

    • A Deeper Dive into LLL

  • 总结

LLL算法全称是 Lenstra–Lenstra–Lovász algorithm,也就是发明它的仨人的人名儿,虽然在比赛中一直用着这个算法,但其实我也没有和他“正式会面”过,只是知道它能够给我输出一个比较短的向量,能够帮助我解题(虽然在绝大多数情况下这就足够了,就像我使用空调我也并不需要知道它制冷的原理)。不过还是决定浅学一下,这样在别人问起来这个算法的时候我也能说出一二,显得自己比较有学问,嗯。
在准备学习这个算法的时候,检索发现了国外的一个博主——Kelby Ludwig(https://kel.bz/about/me/),早在17年就发出来了一篇很优秀的学习文章,能够让我们比较直观的认识 LLL 算法,当然这是在基于我们已经有点一定基础(读过这个系列前面几篇文章)的情况下。那么我也就不再重复造轮子了,这篇文章就打算浅浅翻译一下 https://kel.bz/post/lll/,然后可能会加上一些自己的理解和想法。

LLL & GCD

LLL 算法和 GCD 算法其实并没有那么的像,不过从整体层面上来看它们有着相似的流程。首先我们看到 GCD 的伪代码

def euclid_gcd(a, b):
    if b == 0# base case
        return a
    x = a mod b # reduction step
    return euclid_gcd(b, x) # swap step
GCD 先是一个 reduction step,把数字变小
然后是一个 swap step,交换数字的顺序
返回条件是当 b == 0
我们再看到 LLL 算法的伪代码(先不纠结每行代码的具体含义)
def lll(basis):
    while k <= n:
        for j in reverse(range(k-10)): # reduction step loop
            m = mu(k,j)
            basis[k] = basis[k] - mu*basis[j] # vector reduction
            # update orthogonalized basis
    if lovasz_condition:
        k += 1
    else:
        basis[k], basis[k+1] = basis[k+1], basis[k] # swap step
        # update orthogonalized basis
        k = max(k-1,1)
    return basis
LLL 算法也是先走一个 reduction step,使用的是我们上一篇文章介绍的 Gram-Schmidt 正交化,将向量变小。
然后是 swap step,交换向量的顺序
返回条件是所有的向量都满足 lovasz_condition。
不难发现这两种算法的核心思想都是使用 “减少然后交换” 的技术来实现其目标。所以在这一点上,我们可以粗略地说 LLL 是欧几里得算法的扩展,不过其适用的对象是一组 n 维向量而不是整数。

LLL & Gram-Schmidt

另一个与 LLL 算法相似的是 Gram-Schmidt 正交化算法(以下简称 GS 算法),它接受一个向量空间的一组基向量,并返回该向量空间中的一组正交化基(即基中的所有向量彼此相互正交)。那么我们为什么不能直接使用 GS 算法来进行格基规约呢?GS 算法确实能够让我们得到非常优秀的正交基,不过它并不能保证这样的基是在我们的格空间之内。
密码学基础之LLL算法
例如在上图中,灰色的向量是由 GS 算法得到的正交基,不过很可惜,并非所有的灰色向量都在格点之上。但是 GS 算法对于理解 LLL 算法仍然是非常重要的,并且 GS 算法其实也是 LLL 算法当中的一个重要子算法。

LLL & Gaussian Lattice Reduction

最后我们来看一下 LLL 算法和 Gaussian Lattice Reduction 算法之间的关系。对于二维的格子,我们可以使用 Gaussian Lattice Reduction 来进行格基规约,伪代码算法如下
def gauss_reduction(v1, v2):
    while True:
        if v2.norm() < v1.norm():
            v1, v2 = v2, v1 # swap step
        m = round( (v1 * v2) / (v1 * v1) )
        if m == 0:
            return (v1, v2)
        v2 = v2 - m*v1 # reduction step
gauss_reduction 的输入是表示格基的两个向量,首先是 swap step,确保向量 v1 的长度小于 v2,并且这也可以使得 gauss_reduction 的结果是按长度进行排序的。那么 是什么呢?是较长的向量在较短向量方向上的投影与较短的向量长度的比例。这与 GS 过程中产生的标量相同,但在高斯算法中,我们还要做一个四舍五入,以确保向量仍在格中,这是一个很重要的点。想象一下整个过程,首先将 v2 投影到 v1

密码学基础之LLL算法

然后进行一个四舍五入

密码学基础之LLL算法

最后我们计算规约后的向量
如果不舍入,我们得到的 就是

密码学基础之LLL算法

可以看到 向量并不在格中。
经过舍入后,我们得到

密码学基础之LLL算法

整体来看,在 gauss_reduction 中,通过舍入然后规约,我们得到了格的两个新基,这两个新基的长度无疑会比原来基的长度短。显然这不是巧合,新得到的基向量会“近似”正交,而在行列式不变的情况下,越接近正交的基,长度越短(这应该还是比较自然的叭)。
密码学基础之LLL算法

LLL

LLL 算法是对高斯规约算法在 n 维格上的拓展,总体来看,LLL 对输入的每一个基向量进行迭代长度缩减(这个高斯规约算法类似)。然而现在我们处理的是 n 个向量,我们还需要确保输入基的顺序不会影响我们的规约结果。为此,LLL 使用称为 Lovász 条件的启发式来确定输入基中的向量是否需要交换。LLL 算法在所有基向量都经过至少一次缩减后结束运行,并且新的基向量大致按长度排序

A Deeper Dive into LLL

为了更好地理解 LLL 算法的整个过程,我们从维基百科上找到了一份关于 LLL 算法的 python 伪代码
def LLL(B, delta):
    Q = gram_schmidt(B)

    def mu(i,j):
        v = B[i]
        u = Q[j]
        return (v*u) / (u*u)

    n, k = B.nrows(), 1
    while k < n:

        # length reduction step
        for j in reversed(range(k)):
            if abs(mu(k,j)) > .5:
                B[k] = B[k] - round(mu(k,j))*B[j]
                Q = gram_schmidt(B)

        # swap step
        if Q[k]*Q[k] >= (delta - mu(k,k-1)**2)*(Q[k-1]*Q[k-1]):
            k = k + 1
        else:
            B[k], B[k-1] = B[k-1], B[k]
            Q = gram_schmidt(B)
            k = max(k-11)

   return B

我们从 mu 函数开始分析

mu

从函数代码来看,mu 函数返回向量缩减的所需的标量,这类似于在 GS 正交化和高斯规约时向量的投影标量。唯一的区别在于,mu 中向量的投影并不在格中向量上,而是在GS正交向量上。
换句话说,假设 是我们输入的格基, 是对 应用 GS 正交化的结果(还未归一化)。产生的常数 就是格基中第 个向量 到相关 GS 正交基中第 个向量 投影的标量。
不过我们已经知道, 虽然 GS 正交化确实给我们提供了一个“理想”的正交矩阵,但它不一定能够给我们提供一个格基。因此我们考虑使用 函数,通过 GS 正交矩阵来辅助进行格基规约。

Length Reduction

我们关注代码中与长度缩减相关的部分

n, k = B.nrows(), 1
# outer loop condition
while k < n:
    # length reduction loop
    for j in reversed(range(k)):
        if abs(mu(k,j)) > .5:
            # reduce B[k]
            B[k] = B[k] - round(mu(k,j))*B[j]
            # re-calculate GS with new basis B
            Q = gram_schmidt(B)
首先我们有两个变量, 表示格基 的维度,也即行向量的个数; 表示当前函数处理的向量。
我们暂不关注外部循环条件,针对当前关注的向量 ,它将循环迭代地与 进行长度缩减的相关操作:首先检查 的绝对值是否大于 ,如果绝对值大于 ,我们将对其进行四舍五入,然后进行向量的缩减操作 B[k] = B[k] - round(mu(k,j))*B[j] ;否则将减去一个零向量,这不会造成任何影响,所以我们直接跳过。
最后,格基 在做了相应修改后,我们也需要及时更新其相关的 GS 正交化矩阵 。
对比一下,长度缩减的步骤其实基本就是 GS 正交化的整个过程,
伪代码所表示的长度缩减过程
B[0] = B[0]
B[1] = B[1] - round(mu(10))*B[0]
B[2] = B[2] - round(mu(21))*B[1] - round(mu(20))*B[0]
...
B[k] = B[k] - round(mu(k, k-1))*B[k-1] - round(mu(k, k-2))*B[k-2] - ... - round(mu(k, 0))*B[0]
GS 正交化的过程
Q[0] = B[0]
Q[1] = B[1] - mu(10)*Q[0]
Q[2] = B[2] - mu(21)*Q[1] - mu(20)*Q[0]
...
Q[k] = B[k] - mu(k, k-1)*Q[k-1] - mu(k, k-2)*Q[k-2] - ... - mu(k, 0)*Q[0]

The Lovász Condition and the Swap Step

再关注到代码中的交换部分

    # swap step
    if Q[k]*Q[k] >= (delta - mu(k,k-1)**2)*(Q[k-1]*Q[k-1]):
        k = k + 1
    else:
        B[k], B[k-1] = B[k-1], B[k]
        Q = gram_schmidt(B)
        k = max(k-11)
return B
对当前向量走完一轮长度缩减后,Lovász 条件将告诉我们是继续处理下一个基向量(代码第三行),还是将当前向量和前一个向量互换位置。
暂时忽略 Lovász 条件的具体含义,这样的交换不免让我们想起了某些排序算法。 是当前处理的基向量的索引,假设对于第 个基向量的 Lovász 条件为真,则 LLL 开始处理第 个基向量,此时大致上可以说从第 0 个基向量到第 个基向量是按长度排序的。如果 Lovász 条件为假,则将该向量放在 的位置,然后重新处理第 个基向量。在完成又一轮长度缩减后,再次回到交换步骤,决定是否需要再次交换该基向量的位置。于是我们也可以这样描述 LLL 算法:LLL 算法是一种向量排序算法,不过在向量长度缩减过程中向量变小可能会扰乱顺序,因此必须重新排序。
而对于 Lovász 条件本身,它是一种启发式,用于确定向量是否处于“良好”的顺序。启发式就是那种没法去证明的但是又能用的,就好比机器学习中的调参,调太差了不准,太好了又会过拟合,于是不断微调去找到一个大差不差的。Lovász 的描述有多种,感兴趣的读者可以参看一下这篇 StackOverflow 上的这篇文章 https://crypto.stackexchange.com/questions/39532/why-is-the-lov%C3%A1sz-condition-used-in-the-lll-algorithm/39534#39534。
根据 Lovász 条件,我们能够推出,LLL 算法输出的格 的最短基向量 满足
证明过程可以参考 《An Introduction to Mathematical Cryptography》7.13 一节 定理 7.69

而格 的最短向量 ,根据Minkowski凸集定理

于是我们在做题的时候,可以先大致判断一下自己的目标向量(不说最短,一般也是很短的向量)和构造的格是否满足这个条件(也就是我们常说的是否满足界)。

总结

这么看来,其实 LLL 算法也没有很深奥,就是一个魔改了的 GS 正交化外加一个排序。LLL 算法的向量缩减部分 对于输入的格基,能够给出一个相对正交的,短的,即所谓“优秀”的表示同一个格空间的格基。LLL 算法中的交换步骤会使得最短的基向量在最前面,这也是为什么大多时候我们运行了 LLL 算法后基本只取第一个基向量。

原文始发于微信公众号(Van1sh):密码学基础之LLL算法

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月9日14:37:55
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   密码学基础之LLL算法https://cn-sec.com/archives/2210983.html

发表评论

匿名网友 填写信息