求解目标
首先从代码里抽取出下面这个等式:
同乘有:
···························(1)
此外加密时可以得到等式:
一样同乘有:
考虑(1)式可得到:
···························(2)
从向量的角度来看(2)式,巧妙地构造如下两个二维向量
那么向量可以用
表示
我们的目标就是通过求解出
,这里需要了解一些关于格的知识,如SVP问题、高斯启发、高斯格基规约算法
线性代数的基础
学好线代很重要.......但我基本都忘了,只好再复习一遍(wuwuwu)。原来线代里在群和域有很不错的例子。
线性无关:
给出向量组,若有
即不能写成线性组合的形式,那么说
线性无关
线性无关可以写成线性方程组的形式:
记矩阵,
线性无关等价于方程组
只有唯一
解
基向量:
基向量是一组线性无关且可以生成某个空间的一组向量
施密特正交化:
将线性无关的向量组化为正交向量组(两两作内积为0),具体方法如下:
设为原始向量组,
为正交化之后的向量(这里不用将其单位化)
令
根据正交有
即
解出
所以
这一点将会用于高斯格基规约化算法
格的定义与相关问题
格:
在m维欧氏空间上给出n维线性无关的向量组,由它们生成的整系数线性组合
的集合称为格,记为L,同时记向量组
为格基B
与一般的线性空间不同的是,格是由整系数线性组合生成的,而不是在实数域上选取的。那么我们可以将格看作是线性空间上一些离散的向量,如下图所示:
上图表示格L的基B为,由
的整数线性组合生成的是蓝色的点,这些离散的点共同构成了格L
SVP问题
正是由于格是离散的向量组成,那么这里面一定存在非零模长最短的向量。求解该向量称为SVP问题。在低维度的格,求解该问题是可行的。实际上,LAB4就是求解二维格的最短向量。
高斯启发式
不加证明地给出最短向量长度的估计值:
其中为格的维度,
为格的行列式,格的行列式定义如下:
设是格
的基,那么
构成一个矩阵
则我们定义 其中
为B的行列式绝对值
最短向量的模长下界
记是格基
的施密特正交化,那么最短向量的下界为:
其中
是
的模长
高斯格基规约算法
由最短向量的下界可知,求解最短向量可化为求解最短的正交基。在线性空间的施密特正交化方法可以得出
然而求解该问题得到的系数 并不一定是整数,这样不满足格对整系数线性组合的要求
于是就有了高斯格基规约算法:
类似于欧几里得算法求最大公约数,高斯算法也是不断进行“辗转相除”:
首先在二维格L中,设格基为 且
利用 代替
然后利用施密特正交化可以解出
如果,那么算法结束,否则交换
继续正交化,最后得出的结果
就是最短
非零向量
我个人认为算法的大致原理就是通过类似施密特正交化不断地将一个格基向量作线性变换,每次变换得到的结果都在逼近于正交基。
注意:在线性空间中,基做线性变换并不能得到变换后的还是一组基,但是当线性变换的核时,映射之后还是一组基。这里的核在群论的视角看就是正规子群。但是高斯算法没有将每一个基作线性变换,而是只对其中一个变换,得到的
仍然是一组基。
至于算法的正确性,参考:格基规约算法:算法详解_su1yu4n's Blog-CSDN博客_格基规约
高斯算法如下,参考lihao的代码:
import numpy as np
def GLR(a,b):
if a @ a > b @ a:
a, b = b, a
m = (a @ b) // (a @ a) # @符号即为量向量点乘,计算施密特正交化的系数
while m > 0:
b = b - m * a
if a @ a > b @ b:
a, b = b, a
m = (a @ b) // (a @ a)
return a
LAB4
首先对(f,g)进行估计,猜测其就是要求的最短向量(不确定是否有数学方法直接证明是(f,g)就是最短向量,这里只能先猜测估计)
根据高斯启发给出的估计值,先计算基矩阵的行列式值
可以算出最小的向量模长在附近,同样在代码里给出的范围,发现
所以猜测(f,g)就是最短的向量
代码如下,"借鉴"lihaoooo的代码(手动狗头):
from libnum import n2s,invmod
import numpy as np
def func(e, f, g, q):
a = (f * e) % q
b = (invmod(f, g) * a) % g
return n2s(b)
def GLR(h, q):
a = np.array([1, h], dtype=object)
b = np.array([0, q], dtype=object)
if a @ a > b @ a:
a, b = b, a
m = (a @ b) // (a @ a)
while m > 0:
b = b - m * a
if a @ a > b @ b:
a, b = b, a
m = (a @ b) // (a @ a)
(f, g) = a
return f, g
e=48953801553956075632630973525713256336678525493000461583515578737484335752866054745032875148523940930815671297944556770294647342931586523862235049355437962717298443021620612871828326212526353675586983455347376619665675133788140124881419206246849076991960211099984639980187450574216593522602772954227058146628
public = (
93608760163776111600863892826402691327519685094787906078746228077571092521304859442042456730909349785689012146093193253902807071155381352862768229328037820332815675322315117655139453490127179129628411522424188523742244679612622892809260922425808662067275656156484642984826411084304557228322662340507691788187,
64368557732138634874513838535508558186827301262837820980941444795968457904383650242005576157872393467551461621029526150327355155845775238340889139580533053629136238729532953235835489170694435285713143025428178403803981561282204618848861297267176084408551460029890017500515417082756129583125574305678548485412)
q, h = public
f, g = GLR(h, q)
# f,g=(5757417223335213455957769909472949689244437567260338949667212415336770281702458911397296283119947916250854554668903077755211962319976997781105452685944734 ,5696879148822213991671548047430119693046517873220919339547277415084747545432938774463358955765949728198554500808728640503617161495190933986520108322621869)
print(func(elf,g,q))