LatticeNotes5
huangx607087学习格密码的笔记5
0. About
这个笔记接着之前发布的笔记4,继续往后面扩展新的内容。
12.格约简算法
12x01 2维高斯格约简
假如我们已知$v_1,v_2$是格$L$中的一组基底,假设$v_1$的长度小于$v_2$,(如果不小于,则交换两向量的长度)。那么我们可以用以下的脚本逐步约简二维格中最短向量的长度。
1 |
|
12x02 LLL格约简算法
高斯的晶格约简算法给出了在维数$2$的晶格中找到最短非零向量的有效方法,但随着维数的增加,最短向量问题变得更加困难。 随着LLL算法的发表,1982年取得了重大进展。 在本节中,我们给出了LLL算法的完整描述,在下一节中,我们简要描述了它的一些推广。
当我们得到格$L$的一个基底时,我们肯定希望对于任意两个不同的基向量$\vec v_i,\vec v_j(i \not =j)$,使得$\cos <\vec v_i,\vec v_j>=\dfrac{\vec v_i·\vec v_j}{|\vec v_i||\vec v_j|}$越接近$0$越好。或者在更好的基上的向量尽可能短,首先是我们可以找到的最短向量,然后是长度尽可能慢地增加的向量,直到我们到达基中的最后一个向量。
前面的笔记,我提到过这样一个式子$\det L =\text{Vol }(F)≤ \prod _{i=1}^n |\vec v_i|$
其中$F$是格$L$的基本域。而如果基越正交,那么不等号两边就越接近。而为了能够得到一个更好的基底,我们可以使用施密特正交化的方法取得正交基。不过这里出现了一个问题:因为施密特正交化的方法中:由
$$
\vec v_i^*=v_i-\sum_{j=1}^{i-1}u_{ij}\vec v_j*
$$
注意到里面有这样一项$u_{ij}$并且这一项不能保证是整数。所以进行施密特正交化后的基$B^*$与原来的基$B$之间的转换出现了非整数的系数。而实际上,基$B$与基$B^*$的行列式是相同的。不过如果出现了这样两个条件,就说明$B$被约简了一次:
UPD 2021.2.9:原来这里的公式改成了图片,因为在网页上公式显示异常。
关于LLL算法一些其他的原理,以后会不定期补充。Sagemath中自带了矩阵的LLL计算,很方便。
以下是用Sagemath中的LLL算法计算矩阵$M$的对应矩阵$M^{LLL}$的。可以看出,最短的向量在第一行,的确断了不少。
当然,同一个矩阵使用LLL算法后,可能会算得不同的结果。如下图的矩阵,也是$M$经过LLL算法的一个答案。不过计算一下,可以看出$M$与$M^{LLL}$的行列式绝对值相同,例子中均为$777406251$。并且$H(M)=0.47,H(M^{LLL})=0.87897$,因此$M^{LLL}$中的向量基的确更加正交。但$M_2^{LLL}$中的$H$值约为$0.88824$。查看源码可知,Sagemath中的条件$2$的判断参数是$0.99$,而$M_2^{LLL}$使用的参数是$0.75$。因此,LLL算法对其使用的参数具有比较高的依赖性。。也有用$0.85$做的,不过无论如何,最上面一行的值总是一样的(至多差一个$-1$倍)
12x03 使用LLL解决apprCVP问题:
我们在笔记3中解释了,如果晶格L具有正交基,那么SVP和CVP都很容易求解。 LLL算法不返回正交基,但它确实产生了一个基向量是准正交的基,即它们之间是合理正交的。 因此,我们可以将LLL算法与Babai算法相结合,形成一种求解APRCVP的算法。
这个算法很简单,先求出$M^{LLL}$中的向量作为基底,然后在Babai算法中使用LLL约简基进行计算。
13.LLL在密码分析中的应用
13x01 回顾笔记1中的同余密码系统
当我们知道$q=1000170007,h=999304853$时,就可以使用高斯约简向量$(1,h)$和$(0,q)$,计算约简后的向量为$(-19653, -18557)$和$(-18497, 33426)$。最短的向量为前者。因此$f=19653,g=18557$,成功破解。
13x02 回顾笔记1中背包密码中的LLL算法破解
涉及到的理论可以参见笔记1中的相关内容
下图展示了LLL在前两个例子中的体现
13x03 回顾笔记3中的GGH公钥密码系统
攻击此密码系统,可以将向量组$W$约简。得到$\vec w_1=(61,11,67),\vec w_2=(36,-30,-86),\vec w_3=(-10,102,-40)$,密文$\vec v=(−79081427, −35617462, 11035473)$
此时$H(W)$高达$0.956$。因此我们很快就找到了答案为
$$
\vec v=35\vec w_1-86\vec w_2+32\vec w_3=(79081423, 35617459, −11035471)
$$
所以最后的答案是$35,-86,32$。考虑到原来$|v_2|<|\vec v_1|<|\vec v_3|$,因此调换顺序,成功破解明文为$(-86,35,32)$
13x04 回顾笔记4中的NTRU算法
在笔记4中我们举的那个例子里,在$N=7,q=41,d=2$的情况下,我们算得$h(x)$的表达式为
$$
h(x)=20x^6+40x^5+2x^4+38x^3+8x^2+26x+30
$$
然后,我们可以构造下图的矩阵
同样地,我们可以使用LLL算法。算出结果后,将其对半分开,考虑到LLL算法有的时候会相差一个负号或者出现旋转的问题,因此,我们有$3$行答案符合条件,并且这$3$行互为旋转。
以用红色标出来的第一行为例:此时的$f(x)=-x^6-x^5+x^3-x^2+1,g(x)=x^5+x^4-x^2-1$。
不过,我们可以给$f(x)$乘上$-x^4$,那么有$-x^4f(x)=x^6-x^4+x^3+x^2-1$,$-x^4g(x)=x^6+x^4-x^2-x$。刚好与之前Alice和Bob所计算的结果是一样的,因此攻击者计算出来的$f(x),g(x)$也可以作为解密密钥使用。
14.例题选讲[UPDATE 2021.2.20]
14x01 NPUCTF2020[BABYLCG]
update 2021.2.8
STEP 1 读取题目
我们先来看一下题目:
1 |
|
线性同余生成器简称LCG,就是通过$y\equiv ax+b\pmod m$的线性方程迭代产生随机数,随机数比较有规律可循。
题目给出$a,b,m$的同时,还给出了连续$20$个产生的数字,不过我们知道的只有它们的最高$64$位,低的$64$位不知道。
STEP 2 初步分析,确定构建格矩阵的法则
为了简便,我们可以先从两个数字开始,假设我们已知的是高位部分是$c_1,c_2$,未知的低位部分是$d_1,d_2$,那么我们可以得到
$$
c_2+d_2\equiv a(c_1+d_1)+b \pmod m
$$
去掉同余号,可以得到下面的式子,其中$k$也是未知量
$$
c_2+d_2=ac_1+ad_1+b+km
$$
如果我们对这个式子进行移项,那就有
$$
d_2=ad_1+km+ac_1+b-c_2=f(k,d_1)
$$
很显然,我们建立了$d_2$与$d_1$之间的递推关系。因此,我们要建立向量$\vec v,\vec w$和矩阵$M$,使得$\vec vM=\vec w$。而想要建立矩阵和向量,就要保证等式右边有几个未知数,向量就至少要有几维,并且两个向量要覆盖到所有的未知量。而矩阵中的数字,只能是已知量,并且还要覆盖到题目给出的所有参数。因为到时候直接放入Sagemath中进行LLL算法的是所有元素均为已知量的矩阵$M$而不是带有未知数向量。
STEP 3 从理论走向实践
根据刚刚总结的理论,我们有确定了等号右边有$2$个未知数,因此向量维数至少是$2$。然而,构造$2$维的向量很困难,因为我们上面$d_2$关于$d_1,k$的表达式实际上应该写成这个样子:
$$
d_2=ad_1+km+(ac_1+b-c_2)=f(k,d_1)+C
$$
不要小看这个$+C$的作用,因为这样我们直接就重构了表达式为$d_2=f(k,d_1)+C$。而$C$是已知量,与$k,d_1$全部无关。故我们必须要构建三维的向量,并彻底确定$\vec v=(k,d_1,1)$。矩阵$M$的第一列为$(m,a,C)^T$,向量$\vec w$的第一个分量为$d_2$。
因此,下图就表示我们构建格的雏形了。
此时,未知量$k,d_1,d_2$已经全部被包含,已知量$a,b,m,c_1,c_2$也全部被包含,没有什么必要的东西了。不过注意到一个问题:$\vec w$实际上是最后对矩阵M约简时的最短向量(这个很重要)。而相对于$k$来讲,我们更希望知道的时$d_1$,因此我们就让$\vec w$的第二个分量为$d_1$,完善了矩阵。
为了让最后一个数字尽可能地简单,我们可以把这个矩阵的第三列的前两个数全填成$0$。这样求最短向量的时候,最后一维也就是个固定的常数了。不过问题来了:矩阵右下角的那个数字真的可以随便取吗?
当然不是
我们在笔记2的时候就讲过Hermite定理:维数为$n$的每一个格$L$中都包含一个长度不超过$\sqrt n \sqrt[n]{\det L}$的向量$\vec v$。这里$n=3$,假如右下角这个数是$x$。那么很容易计算$\det L=mx$,其中$m$是模数,$128$位。也就是说,最短向量一定小于$\sqrt[6]{27m^2x^2}$。因此提高$x$的值准确度更高。以下就是当$x$很大和较小时解出来的值。如果算出来的$d_1,d_2$中有一个时负数,那就只能换一组数据了 (直接去绝对值即可,Upd by shallow)
因此,我们就恢复了一个数的低位。一旦这个数的低位被恢复,那我们就恢复了被省略掉的低位,获得了一个状态,那我们就立刻地推出了所有的答案了,flag也就解出来了。
4. Reference
因为自己的做法确实有些局限性,为了获得更普遍的方法,我还是跟shallow大佬讨论了以下这道题的做法,但我可能还是太菜了,思考了两小时都没能实现这个做法。
1 |
|
14x02 ACTF2021 [hashgame]
Updated 2021.2.20
1.读取题目:
1 |
|
Step 2:初步分析,构造矩阵
对于题目中给出的计算,我们可以进行简单地化简,在阅读题目要求后,我们可以理解为:题目要求我们找两组数字$x,y$,每组数字$32$个,并且数组$x$和数组$y$不能完全相同。最后就是找到满足条件的$2$组数字,使得
$$
hg^{32}+\sum_{i=1}^{32} x_i g^{33-i}\equiv hg^{32}+\sum_{i=1}^{32} y_i g^{33-i} \pmod{2^{256}}
$$
很显然地,我们可以约去两边的$hg^{32}$,等式变成了
$$
\sum_{i=1}^{32} x_i g^{33-i}\equiv\sum_{i=1}^{32} y_i g^{33-i} \pmod{2^{256}}
$$
然后将模式写成等式,得
$$
\sum_{i=1}^{32} x_i g^{32-i}=\sum_{i=1}^{32} y_i g^{33-i} +2^{256}k
$$
然后我们可以合并一下两边:
$$
\sum_{i=1}^{32}(x_i-y_i)g^{33-i}=2^{256}k
$$
可以顺带进行移项
$$
\sum_{i=1}^{32}(x_i-y_i)g^{33-i}-2^{256}k=0
$$
观察化简后的式子,其中未知量是$x_i-y_i$和$k$,已知量是$g$。因此我们应该建立相应的递推式。
为了简化表达,我们先假设$i$的取值从$1$到$32$缩减成$1$到$3$来模拟构造矩阵。
在只有$3$组差值的情况下,并且我们最后要求出来的是$x_i-y_i$的值,因此,$E_3=\text{diag}(1,1,1)$必须是我们构造矩阵中的一个子矩阵。并且$k$也是未知的,因此我们矩阵中还要加一个元素$k$。这样我们的向量就是$4$维行向量$(x_1-y_1,x_2-y_2,x_3-y_3,k)$,最后我们期望得到的内容就是前$3$个参量,而又因为$g^3(x_1-y_1)+g^2(x_2-y_2)+g(x_3-y_3)-2^{256}k=0$。因此我们矩阵需要增加至$5$列。最后一列为列向量$(g^3,g^2,g,2^{256})^T$,负号扔给$k$。而最后我们得到的向量就是$(x_1-y_1,x_2-y_2,x_3-y_3,-k,0)$,向量的最后一列必须是$0$。
所以我们可以尝试构造一个这样的矩阵及其计算方式。
我们到最后只需要找到尾数是$0$的那一列,那么就成功了。
但这样好像是失败了(,因为LLL算法后结出来的最后的结果不为$0$。
看来,这里的计算应该是跟上面那个例子除了相同的问题。
Step 3:构造并调整矩阵
因此我们现在就需要对上面的矩阵进行调整。因为最短向量总是小于$\sqrt n \sqrt[n]{\det L}$。当格$L$对应的矩阵$M$不是方阵的时候,我们规定格$L$的行列式$\det L=\det MM^T$。而当$\det L$太小的时候,就会导致最后解出来的向量更短,导致计算错误。因为:
$$
a^2+b^2<(a+b)^2
$$
这就意味着符合条件时,最后一个$0$参数会被微小提升,来缓解其他分量的负担,向量长度变小了,但却不是我们想要的结果。
因此我们就要扩大$\det L$。而我们又想保持住等号右边的向量的形式,因此我们就需要对矩阵最右边一列所有数字同时乘上一个数$C$(不取模),然后这样格$L$的行列式就会提升到原来的$C^8$倍(如果构造出的是$M$规模是$33\text x34$,则$MM^T$就是$33\text x33$方阵,最右边乘上$C$就会导致矩阵行列式提升到原来的$C^{66}$倍)。而向量的长度,提升倍数将会小于$\sqrt[33]{C^{66}}=C^2$倍。
因此,我们最后期望得到的矩阵计算是这样的,而在这道题中,$C$取$70$多就够了,然而我还是取了$2^{700}$为了保险。
构造矩阵运行了一下,可以发现,向量的所有分量都小于$255$。然后我们就可以构造一段模板$x$和一段变化过的$y$就行了。
这里有个问题:解出来的值有正有负,这个时候我们可以把所有正数都基于$\text{00H}$作为模板,负数基于$\text{FFH}$作为模板。例如,假如解出来的前$4$个数字是$32,-64,-96,128$,那么我们$x$组就构造$\text{00FFFF00H}$,$y$组构造$\text{20BF9F80}$。
1 |
|
4.Reference
一开始自己想的是构造$64\text{x}64$的矩阵,想分出$y_{32}$,构造从$(x_1,x_2,…,x_{32},y_1,y_2,…,y_{31},k)$递推出$(x_1,x_2,…,y_{32},y_1,y_2,…,y_{31},k)$的想法,不过发现这样做构造矩阵并不可以。可能是因为这种构造下,$x_1$和$y_1$孤立,导致直接出$0$解。也就是说,这样由于是构造的方阵,可以直接使得LLL之后的向量结果,每一行的行向量都是单位矩阵中对应行向量的某个整数的倍数,直接构造出了$H(B)=1$的完全正交基……。
这件事还是暴露了一个严重的问题就是:huangx607087 is a feiwu
15.总结
到这里为止,格密码的5篇笔记全部投放完毕。由于最后一篇限于时间,没有过多地提及LLL算法的原理,仅仅是简单地提了一下LLL算法的使用方法,和解决了之前所抛出来的几个问题。后面主要就是将这些算法应用到CTF中的题目里去。可能会投放Notes6。但Notes6大概率会属于ExpLog。
以后有可能会对LLL算法的相关原理进行补充。