格 Lattice
给定一组线性无关的基向量v1, v2, ..., vn
,那么这些基向量的所有整系数线性组合
a
1
v
1
+
a
2
v
2
+
⋯
+
a
n
v
n
,
a
i
∈
Z
\LARGE a_1 v_1+a_2 v_2+\cdots+a_n v_n, \quad a_i \in \mathbb{Z}
a1v1+a2v2+⋯+anvn,ai∈Z
所形成的集合,就叫做这组基向量所张成的格(lattice)。(空间(span))
系数不再是任何实数,变成了是任何整数
从无数个连续的点变成了无数个离散的点,基底 i ⃗ = ( 1 , 0 ) , j ⃗ = ( 0 , 1 ) \vec{i}=(1,0),\vec{j}=(0,1) i=(1,0),j=(0,1)
对原基底进行整系数线性转换得到的新的基底,张成的lattice仍旧不变:
[
i
′
j
′
]
=
[
1
1
−
2
−
1
]
=
[
1
1
−
2
−
1
]
[
1
0
0
1
]
=
T
[
i
j
]
\left[\begin{array}{c} i^{\prime} \\ j^{\prime} \end{array}\right]=\left[\begin{array}{cc} 1 & 1 \\ -2 & -1 \end{array}\right]=\left[\begin{array}{cc} 1 & 1 \\ -2 & -1 \end{array}\right]\left[\begin{array}{ll} 1 & 0 \\ 0 & 1 \end{array}\right]=T\left[\begin{array}{l} i \\ j \end{array}\right]
[i′j′]=[1−21−1]=[1−21−1][1001]=T[ij]
新的基底
i
′
⃗
=
(
1
,
1
)
,
j
′
⃗
=
(
−
2
,
−
1
)
\vec{i'}=(1,1),\vec{j'}=(-2,-1)
i′=(1,1),j′=(−2,−1)
例子123
EX1 基础题目
题目
from Crypto.Util.number import *
import gmpy2
from flag import flag
def generate():
p = getStrongPrime(2048)
while True:
f = getRandomNBitInteger(1024)
g = getStrongPrime(768)
h = gmpy2.invert(f, p) * g % p
return (p, f, g, h)
def encrypt(plaintext, p, h):
m = bytes_to_long(plaintext)
r = getRandomNBitInteger(1024)
c = (r * h + m) % p
return c
p, f, g, h = generate()
c = encrypt(flag, p, h)
with open("cipher.txt", "w") as f:
f.write("h = " + str(h) + "\n")
f.write("p = " + str(p) + "\n")
f.write("c = " + str(c) + "\n")
这道题目可以对应一个脆弱的密码方案
密钥生成过程:
p
: 一个2048-bit的强素数 (“强”在于p-1
和p+1
都至少有一个很大的素因数,以防某些攻击)f
:一个1024-bit的随机数g
:一个768-bit的强素数
f < p / 2 , p / 4 < g < p / 2 , gcd ( f , p g ) = 1 f<\sqrt{p / 2}, \quad \sqrt{p / 4}<g<\sqrt{p / 2}, \quad \operatorname{gcd}(f, p g)=1 f<p/2,p/4<g<p/2,gcd(f,pg)=1
f,g远小于p 且f与p,g互质,其次 $ h \equiv f^{-1} \cdot g \quad(\bmod p) (1)$ ,可以估算出h
大小与p接近,O§级别,2000bit;
加密过程:
生成了一个1024bit的随机数r
,计算密文
c
≡
r
⋅
h
+
m
(
m
o
d
p
)
(
2
)
c \equiv r \cdot h+m \quad(\bmod p) (2)
c≡r⋅h+m(modp)(2)
已知h,p,c ,理论上知道r即可以求解m,但随机数r无法直接求得
所以换个思路,从f,g出发做文章
解密过程:
将同余式(1)代入(2),并对式子两边同乘f
,得到
c
⋅
f
≡
r
⋅
g
+
m
⋅
f
(
m
o
d
p
)
(3)
c \cdot f \equiv r \cdot g+m \cdot f \quad(\bmod p)\tag 3
c⋅f≡r⋅g+m⋅f(modp)(3)
根据大小关系可推知,
r
g
+
f
m
<
p
2
p
2
+
p
2
p
4
<
p
r g+f m<\sqrt{\frac{p}{2}} \sqrt{\frac{p}{2}}+\sqrt{\frac{p}{2}} \sqrt{\frac{p}{4}}<\boldsymbol{p}
rg+fm<2p2p+2p4p<p
因此可以得到一个等式 $a= rg+fm $ ,对等式取模g,得到 a ≡ m ⋅ f ( m o d g ) a \equiv m \cdot f \quad(\bmod g) a≡m⋅f(modg)
由此可以发现只需要得到f,g 就可以得到m, m ≡ a ⋅ f − 1 ( m o d g ) m \equiv a \cdot f^{-1} \quad(\bmod g) m≡a⋅f−1(modg)
p.s
- 这里是在
mod g
下运算,还记得g
是一个768-bit的强素数么?这就保证了,虽然f
是个1024-bit的数,但是在mod g
下,f' = f - k*g
的逆元必定存在。- 此处的 f − 1 ( m o d g ) f^{-1}(mod g) f−1(modg)与
h = f^-1 * g (mod p)
里的不是同一个东西。g
有768-bit,768/8=96,flag字符串一般来说不会超过96个字符长,因此m
比g
小,所以最终算出来的就是完完整整m
。
利用格求解
求解 h ≡ f − 1 ⋅ g ( m o d p ) \Large h \equiv f^{-1} \cdot g \quad(\bmod p) h≡f−1⋅g(modp) ,即 f ⋅ h ≡ g ( m o d p ) \Large f \cdot h \equiv g \quad(\bmod p) f⋅h≡g(modp)
由下面这个矩阵M
中的两个行向量(1,h), (0,p)
所张成的lattice
M
=
[
1
h
0
p
]
M=\left[\begin{array}{ll} 1 & h \\ 0 & p \end{array}\right]
M=[10hp]
证明向量**(f, g)
**是在这个lattice上的
Proof:
首先将同余式改写成等式
f
⋅
h
=
g
+
u
⋅
p
→
f
⋅
h
−
u
⋅
p
=
g
\large f \cdot h=g+u \cdot p ~\rightarrow f \cdot h-u \cdot p=g
f⋅h=g+u⋅p →f⋅h−u⋅p=g 可以得到
(
f
,
−
u
)
M
=
(
f
,
−
u
)
[
1
h
0
p
]
=
(
f
+
(
−
u
)
⋅
0
,
f
⋅
h
+
(
−
u
)
⋅
p
)
=
(
f
,
f
⋅
h
−
u
⋅
p
)
=
(
f
,
g
)
\Large \begin{aligned} (f,-u) M &=(f,-u)\left[\begin{array}{ll} 1 & h \\ 0 & p \end{array}\right] \\ &=(f+(-u) \cdot 0, f \cdot h+(-u) \cdot p) \\ &=(f, f \cdot h-u \cdot p) \\ &=(f, g) \end{aligned}
(f,−u)M=(f,−u)
10hp
=(f+(−u)⋅0,f⋅h+(−u)⋅p)=(f,f⋅h−u⋅p)=(f,g)
向量(f,g)
可以由两组基向量M
的某种整系数线性组合(f, -u)
来表示,因此向量(f,g)
就在这个lattice上。
看看h,p,f,g大小
h
:2000多bitp
:2048-bitf
:1024-bitg
:768-bit
相对于两个基底向量(1, h), (0, p)
来说,向量(f, g)
的长度要小得多得多:
根据Gaussian heurstic可知,在这个lattice中最短向量的长度大概在sqrt(2^2048)=2^1024
左右。因此,很大概率上,这个(f, g)
就是这个lattice的最短向量。
可见,一开始参数的大小设置,是很关键的一点。
Ex2: 子集合问题-(背包问题)4
SVP(最短向量问题)
-
Gauss Lattice Reduction
令
L
是由两个基向量v1, v2
所张成的2维lattice,假定|v1| < |v2|
,我们现在通过减去v1
的某个倍数来使得v2
变短。
v 2 ∗ = v 2 − v 1 ⋅ v 2 ∥ v 1 ∥ 2 v 1 \Large v_2^*=v_2-\frac{v_1 \cdot v_2}{\left\|v_1\right\|^2} v_1 v2∗=v2− v1 2v1⋅v2v1
得到一个与v1
正交(垂直)的新向量v2*
,且使得v2
变短了
在格里面只能减去整数倍的v1,如果v1 > v2
,那么交换v1, v2
,继续;否则,就结束。
v
2
−
m
v
1
with
m
=
⌊
v
1
⋅
v
2
∥
v
1
∥
2
⌉
v_2-m v_1 \quad \text { with } \quad m=\left\lfloor\frac{v_1 \cdot v_2}{\left\|v_1\right\|^2}\right\rceil
v2−mv1 with m=⌊∥v1∥2v1⋅v2⌉
-
LLL算法
sage中自带
# sage
def GaussLatticeReduction(v1, v2):
while True:
if v2.norm() < v1.norm():
v1, v2 = v2, v1
m = round( v1*v2 / v1.norm()^2 )
if m == 0:
return (v1, v2)
v2 = v2 - m*v1
h = 7257231567493321493497732423756001924698993879741072696808433246581786362611889417289029671240997843541696187487722285762633068287623369923457879458577466240950224087015909821079480431797917376609839097610864517760515986973340148901898582075413756737310797402537478388864632901178463429574227279668004092519322204990617969134092793157225082977967228366838748193084097651575835471869030934527383379794480007872562067799484905159381690179011192017159985260435844246766711550315143517066359521598424992244464723490166447105679062078049379153154659732304112563255058750656946353654402824529058734270363154894216317570784
p = 23969137365202547728693945383611572667294904799854243194734466236017441545927679469239814785947383727854265554138290421827510545078908517696536495567625593439996528098119344504866817224169113920532528233185011693829122447604993468817512696036673804626830507903206709121383065701222707251053362179946170981868061834734684494881504724254812067180384269711822738708203454131838741703416329765575995359232573740932069147491776326045743679105041246906081872936901848272288949389026129761726749334006319072981386763830897454245553866145620689939497868469730297795063648030738668273210516497399954626983672357236110363894081
c = 6388077150013017095358415295704360631706672647932184267739118115740221804173068089559645506533240372483689997499821300861865955720630884024099415936433339512125910973936154713306915269365877588850574948033131161679256849814325373882706559635563285860782658950169507940368219930971600522754831612134153314448445006958300840618894359885321144158064446236744722180819829183828290798747455324761671198097712539900569386477647697973195787663298318786718012522378981137877863153067057280649127202971806609339007027052518049995341356359016898069863799529357397514218249272201695539181908803360181347114492616706419618151757
# Construct lattice.
v1 = vector(ZZ, [1, h])
v2 = vector(ZZ, [0, p])
m = matrix([v1,v2]);
# Solve SVP.
shortest_vector = m.LLL()[0]
# shortest_vector = GaussLatticeReduction(v1, v2)[0]
f, g = shortest_vector
print(f, g)
# Decrypt.
a = f*c % p % g
m = a * inverse_mod(f, g) % g
print(hex(m).decode('hex'))
# flag{c3bb1f88-2c0b-48fc-9902-beada6d50df6}