文章目录
backpack Cryptography没出
Mathematics
Lattices
1. Vectors
基本的向量于标量之间的运算
题目:
v = (2,6,3)
, w = (1,0,0)
and u = (7,7,2)
, calculate 3*(2*v - w) ∙ 2*u
.
直接使用sage计算
sage: v = vector([2,6,3])
sage: w = vector([1,0,0])
sage: u = vector([7,7,2])
sage: 3*(2*v-w)*2*u
702
flag是702
2. Size and Basis
一组向量
v
1
,
v
2
.
.
.
v
k
∈
V
v_1,v_2...v_k\in V
v1,v2...vk∈V是线性无关的,当且仅当
a
1
v
1
+
a
2
v
2
+
.
.
.
+
a
k
v
k
=
0
a_1v_1+a_2v_2+...+a_kv_k=0
a1v1+a2v2+...+akvk=0
仅在
a
1
=
a
2
=
.
.
.
=
a
k
=
0
a_1=a_2=...=a_k=0
a1=a2=...=ak=0时成立
基中的元素个数
是向量空间的维数
向量的大小,定义为||v||
,是自己和自己的内积==
∣
∣
v
∣
∣
2
=
v
⋅
v
||v||^2=v\cdot v
∣∣v∣∣2=v⋅v==
一组正交基(orthogonal)
v
1
,
v
2
,
.
.
.
,
v
n
∈
V
v_1,v_2,...,v_n\in V
v1,v2,...,vn∈V,任意两个元素的内积为0==
v
i
⋅
v
j
=
0
,
i
≠
j
v_i\cdot v_j=0,i≠j
vi⋅vj=0,i=j==
一组标准正交基(orthonormal)
,是对于所有
i
∈
[
1
,
n
]
i\in[1,n]
i∈[1,n]都满足满足==
∣
∣
v
i
∣
∣
=
1
||v_i||=1
∣∣vi∣∣=1==的正交基
题目:
计算 v = ( 4 , 6 , 2 , 5 ) v=(4,6,2,5) v=(4,6,2,5)的大小(size)
∣ ∣ v ∣ ∣ = v ⋅ v = ( 4 , 6 , 2 , 5 ) ⋅ ( 4 , 6 , 2 , 5 ) = 81 = 9 ||v||=\sqrt{v\cdot v}=\sqrt{(4,6,2,5)\cdot(4,6,2,5)}=\sqrt{81}=9 ∣∣v∣∣=v⋅v=(4,6,2,5)⋅(4,6,2,5)=81=9
flag就是9
3. Gram Schmidt
施密特算法
可以将向量组 v 1 , v 2 . . . v k ∈ V v_1,v_2...v_k\in V v1,v2...vk∈V正交化为 u 1 , u 2 , . . . , u k ∈ V u_1,u_2,...,u_k\in V u1,u2,...,uk∈V
u 1 = v 1 u_1=v_1 u1=v1
Loop i = 2 , 3 , . . . , n i=2,3,...,n i=2,3,...,n
Compute μ i j = v i ⋅ u j ∣ ∣ u j ∣ ∣ ( 1 ≤ j < i ) \mu_{ij}=\frac{v_i·u_j}{||u_j||}(1\le j<i) μij=∣∣uj∣∣vi⋅uj(1≤j<i) Set u i = ∑ 1 ≤ j < i v i − μ i j ∗ u j u_i=\sum_{1\le j<i}v_i-\mu_{ij}*u_j ui=∑1≤j<ivi−μij∗uj
End Loop
题目:
v1 = (4,1,3,-1), v2 = (2,1,-3,4), v3 = (1,0,-2,7), v4 = (6, 2, 9, -5)
使用Gram Schmidt算法
计算标准基
写了半天手搓线性代数,全是bug,不写了
寄了
一晚上全学线代了,
连个施密特都写不出来
Sage有内置的Gram Schmidt
sage: v0 = vector([4,1,3,-1])
sage: v1 = vector([2,1,-3,4])
sage: v2 = vector([1,0,-2,7])
sage: v3 = vector([6,2,9,-5])
sage: M = Matrix([v0,v1,v2,v3])
sage: M.gram_schmidt()
(
[ 4 1 3 -1]
[ 70/27 31/27 -23/9 104/27]
[ -287/397 -405/397 799/397 844/397]
[-1456/4023 273/298 1729/8046 455/4023],
[ 1 0 0 0]
[ -4/27 1 0 0]
[ -1/3 468/397 1 0]
[ 58/27 -659/794 439/4023 1]
)
sage: M
[ 4 1 3 -1]
[ 2 1 -3 4]
[ 1 0 -2 7]
[ 6 2 9 -5]
flag就是0.91611
(四舍五入)
我也贴一个别人的solution,实现了题目所给的算法,作为学习参考
import numpy as np
v = [
np.array([4,1,3,-1]),
np.array([2,1,-3,4]),
np.array([1,0,-2,7]),
np.array([6,2,9,-5]),
]
"""
u1 = v1
Loop i = 2,3...,n
Compute μij = vi ∙ uj / ||uj||2, 1 ≤ j < i.
Set ui = vi - μij * uj (Sum over j for 1 ≤ j < i)
End Loop
"""
u = [v[0]]
for vi in v[1:]:
mi = [np.dot(vi, uj) / np.dot(uj, uj) for uj in u]
u += [vi - sum([mij * uj for (mij, uj) in zip(mi,u)])]
print(round(u[3][1], 5))
4. What’s Lattice?
格的基本空间F
给定一组线性无关的向量
v
1
,
v
2
,
.
.
.
,
v
n
∈
R
m
v_1,v_2,...,v_n\in R^m
v1,v2,...,vn∈Rm,则由这组向量生成的格
L
L
L 是由
v
1
,
v
2
,
.
.
.
,
v
n
v_1,v_2,...,v_n
v1,v2,...,vn和对应整系数的组合
L
=
{
a
1
∗
v
1
+
a
2
∗
v
2
+
.
.
.
+
a
k
∗
v
k
:
a
1
,
a
2
,
.
.
.
,
a
n
∈
Z
}
L=\{a_1*v_1+a_2*v_2+...+a_k*v_k:a_1,a_2,...,a_n\in Z\}
L={a1∗v1+a2∗v2+...+ak∗vk:a1,a2,...,an∈Z}
格L
的基,可以是任意一组生成L的线性无关的向量。基的选择不唯一
The choice of basis is far from unique
由一组基向量和与基向量相乘的数,可以到达任何一点。一组基向量定义了一块基本空间(fundamental domain)
F
(
v
1
,
.
.
.
,
v
n
)
=
{
t
1
v
1
+
t
2
v
2
+
.
.
.
+
t
n
v
n
:
0
≤
t
i
<
1
}
F(v_1,...,v_n)=\{t_1v_1+t_2v_2+...+t_nv_n:0\le t_i<1\}
F(v1,...,vn)={t1v1+t2v2+...+tnvn:0≤ti<1}
对于二维向量,基向量组成的基本空间就是
v
1
⃗
\vec{v_1}
v1和
u
1
⃗
\vec{u_1}
u1组成的平行四边形
我们可以通过基向量来计算基本空间。题目:
已知
v
1
=
(
6
,
2
,
−
3
)
,
v
2
=
(
5
,
1
,
4
)
,
v
3
=
(
2
,
7
,
1
)
v_1 = (6, 2, -3), v_2 = (5, 1, 4), v_3 = (2, 7, 1)
v1=(6,2,−3),v2=(5,1,4),v3=(2,7,1),计算基本空间的体积(the volume of the fundamental domain)
V
o
l
(
F
)
=
∣
d
e
t
(
A
)
∣
=
∣
∣
6
2
−
3
5
1
4
2
7
1
∣
∣
Vol(F)=|det(A)|=\left|\left| \begin{matrix} 6 & 2 & -3\\ 5 & 1 & 4\\ 2 & 7 & 1 \end{matrix} \right|\right|
Vol(F)=∣det(A)∣=∣∣∣∣∣∣∣∣∣∣∣∣652217−341∣∣∣∣∣∣∣∣∣∣∣∣
使用sage计算
sage: v = vector
sage: v1 = v([6,2,-3])
sage: v2 = v([5,1,4])
sage: v3 = v([2,7,1])
sage: A = matrix([v1,v2,v3])
sage: A
[ 6 2 -3]
[ 5 1 4]
[ 2 7 1]
sage: det(A)
-255
flag就是255
5. Gaussian Reduction
如果你仔细观察,“格”开始出现在密码学中的每一个角落。 有时它们操纵一个加密系统,破坏了(生成)不够安全的参数。 最著名的例子是 Coppersmith 对 RSA 加密的攻击。
格也可用于构建加密协议,其安全性基于两个基本的“难”问题:
- The Shortest Vector Problem (SVP)
给定的基向量和格,找到格 L L L中的长度最短非零向量。换言之,找到一个非零向量 v ∈ L v\in L v∈L使 ∣ ∣ v ∣ ∣ ||v|| ∣∣v∣∣ 最小
- The Closest Vector Problem (CVP)
给定的基向量、格,和一个不在格上的目标向量,找到距离目标向量最近的格向量。
给定一个不在格 L L L中的向量 w ∈ R m w\in R^m w∈Rm,找到向量 v ∈ L v\in L v∈L使 ∣ ∣ v − w ∣ ∣ ||v-w|| ∣∣v−w∣∣ 最小
对于一般的格,SVP问题十分困难,但对于相对简单的情况,我们有非常有效的算法可以计算出问题的解或者近似解。当格的维数小于等于4时,可以在多项式时间内计算出确定解,对于更高维,只能求出近似解。
高斯发明了一种算法来找到给定任意基的二维格 L L L 的最佳基。算法的输出 v1 是 L L L 中最短的非零向量,由此解决了二维的SVP问题。
高斯的算法大致通过从另一个基向量中减去一个基向量的倍数来达到目标,直到不再可能使它们变得更小。这适用于二维,因此可以很好地可视化。
一句一句的翻译已经很累了,不想再敲公式了,直接放图吧
脚本也不想写了
直接交互式命令行吧
import numpy as np
ar = np.array
v = ar([846835985, 9834798552],dtype='i8')
u = ar([87502093, 123094980],dtype='i8')
v1,v2 = u,v
>>> if siz2(v2) < siz2(v1):
print('swap')
v1,v2 = v2,v1
>>> m = int(v1.dot(v2)/v1.dot(v1));m
56
>>> v2 = v2 - m*v1;v2
array([-4053281223, 2941479672], dtype=int64)
>>> if siz2(v2) < siz2(v1):
print('swap')
v1,v2 = v2,v1
>>> m = int(v1.dot(v2)/v1.dot(v1));m
0
>>> v1
array([ 87502093, 123094980], dtype=int64)
>>> v2
array([-4053281223, 2941479672], dtype=int64)
>>> v1.dot(v2)
7410790865146821
flag即7410790865146821
6. Find the Lattice
这种题在各类比赛里比较常见了,可以参考一下这个
https://xz.aliyun.com/t/7163
题目
from Crypto.Util.number import getPrime, inverse, bytes_to_long
import random
import math
FLAG = b'crypto{?????????????????????}'
def gen_key():
q = getPrime(512)
upper_bound = int(math.sqrt(q // 2))
lower_bound = int(math.sqrt(q // 4))
f = random.randint(2, upper_bound)
while True:
g = random.randint(lower_bound, upper_bound)
if math.gcd(f, g) == 1:
break
h = (inverse(f, q)*g) % q
return (q, h), (f, g)
def encrypt(q, h, m):
assert m < int(math.sqrt(q // 2))
r = random.randint(2, int(math.sqrt(q // 2)))
e = (r*h + m) % q
return e
def decrypt(q, h, f, g, e):
a = (f*e) % q
m = (a*inverse(f, g)) % g
return m
public, private = gen_key()
q, h = public
f, g = private
m = bytes_to_long(FLAG)
e = encrypt(q, h, m)
print(f'Public key: {(q,h)}')
print(f'Encrypted Flag: {e}')
已知的值有
q,h,e
其中
h
≡
f
−
1
g
m
o
d
p
e
≡
(
r
h
+
m
)
m
o
d
p
h\equiv f^{-1}g\mod p\\ e\equiv (rh+m)\mod p
h≡f−1gmodpe≡(rh+m)modp
q 512位
f,g 低于256位
h,e 512位
r 256位
m为flag,大小约为231bit
要求得m,需要获得函数decrypt
的参数,还剩f
和g
是未知的
而,我们唯一知道的关于f
和g
的关系式,只有
f
⋅
h
≡
g
m
o
d
p
f\cdot h\equiv g\mod p
f⋅h≡gmodp
这里需要使用上一题的格的思想
我们可以构造一个由下面这个矩阵M
中的两个行向量(1,h),(0,q)
所张成的lattice:
M
=
[
1
h
0
q
]
M= \left[ \begin{matrix} 1&h\\ 0&q \end{matrix} \right]
M=[10hq]
首先,向量(f,g)
是在这个格上的,即存在系数
a
a
a,
b
b
b 使
a
(
1
,
h
)
+
b
(
0
,
q
)
=
(
f
,
p
)
a(1,h)+b(0,q)=(f,p)
a(1,h)+b(0,q)=(f,p)
f
⋅
h
≡
g
m
o
d
q
f
⋅
h
=
g
+
u
⋅
q
f
⋅
h
−
u
⋅
q
=
g
f\cdot h\equiv g\mod q\\ f·h=g+u·q\\ f·h-u·q=g\\
f⋅h≡gmodqf⋅h=g+u⋅qf⋅h−u⋅q=g
即
a
,
b
=
f
,
−
u
a,b=f,-u
a,b=f,−u满足条件
向量(f,g)
可以由两组基向量M
的某种整系数线性组合(f, -u)
来表示,因此向量(f,g)
就在这个lattice上。
对于两个基底向量,
(1,h) : 512位
(0,q) : 512位
而向量 (f,g) 的长度 : 大约256位
相比于基底向量,是非常小的。
很大概率上,这个(f, g)
就是这个lattice的最短向量,(Gaussian heurstic)。
上一题我没写程序,现在补回来…
# sage
# GaussLatticeReduction
def Gauss(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
sage: v = vector([1,h])
sage: u = vector([0,q])
sage: Gauss(u,v)
((47251817614431369468151088301948722761694622606220578981561236563325808178756, 43997957885147078115851147456370880089696256470389782348293341937915504254589),
(-67269010250212717075432182693043963184097648880165008621907831284647116025901, 99012763459529858809608436133564630524350106000242070336818304053467942269178))
输出的第一个向量即所求的(f,g)
>>> len(bin(f)[2:])
255
>>> len(bin(g)[2:])
255
长度也满足
现在直接运行decrypt
函数即可得到flag
q, h = (7638232120454925879231554234011842347641017888219021175304217358715878636183252433454896490677496516149889316745664606749499241420160898019203925115292257, 2163268902194560093843693572170199707501787797497998463462129592239973581462651622978282637513865274199374452805292639586264791317439029535926401109074800)
e = 5605696495253720664142881956908624307570671858477482119657436163663663844731169035682344974286379049123733356009125671924280312532755241162267269123486523
f,g = 47251817614431369468151088301948722761694622606220578981561236563325808178756, 43997957885147078115851147456370880089696256470389782348293341937915504254589
print(l2b(decrypt(q,h,f,g,e)))
crypto{}
7. Backpack Cryptography
背包加密算法
参考密码学——公钥密码体系之背包算法1_摆渡沧桑-CSDN博客
这是一种早期的公钥算法,背包算法的安全性起源于背包难题,即子集和问题,他是一个NP完全问题,但后来发现该算法并不安全,但是它证明了如何将NP完全问题用于公开秘钥密码学
对于易解的背包问题,可以选择超递增序列,那么相应的背包问题容易求解。
超递增序列:它的每一项都大于它之前所有项之和,例如{1,3,6,13,27,52}是一个超递增序列,而{1,3,4,9,15,25}则不是。
非超递增序列的背包是困难的问题,它们没有快速算法。
背包加密算法在于,公钥是一个非超递增序列背包,私钥是超递增序列和将两者互相转换的 r r r
背包问题的解密及破解_Taotaoboke的博客-CSDN博客_超递增序列背包问题
破译的基本思想是不必找出正确的模数 q q q 和乘数 r r r(即陷门信息)只需要找到出任意模数 k ′ k' k′ 和乘数 t ′ t' t′,然后用 k ′ k' k′ 和 t ′ t' t′ 对公开的背包向量 b b b 求出新的超递增向量即可。
方式是通过构造一个格,用LLL直接日。
记已知的公钥数组为
p
k
pk
pk ,加密后的结果为
e
n
c
enc
enc,则可以构造:
A
=
(
2
0
0
⋯
0
p
k
[
0
]
0
2
0
⋯
0
p
k
[
1
]
0
0
2
⋯
0
p
k
[
2
]
⋮
⋮
⋮
⋱
⋮
⋮
0
0
0
…
2
p
k
[
−
1
]
1
1
1
…
1
e
n
c
)
A=\begin{pmatrix} 2 & 0 & 0 & \cdots & 0 & pk[0] \\ 0 & 2 & 0 & \cdots & 0 & pk[1] \\ 0 & 0 & 2 & \cdots & 0 & pk[2] \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots \\ 0 & 0 & 0 & \dots & 2 & pk[-1] \\ 1 & 1 & 1 & \dots & 1 & enc \\ \end{pmatrix}
A=⎝⎜⎜⎜⎜⎜⎜⎜⎛200⋮01020⋮01002⋮01⋯⋯⋯⋱……000⋮21pk[0]pk[1]pk[2]⋮pk[−1]enc⎠⎟⎟⎟⎟⎟⎟⎟⎞
计算A.LLL(),在每一行中寻找满足条件的。
from output import *
from Crypto.Util.number import isPrime, bytes_to_long, inverse, long_to_bytes
nbit = len(pk)
# N = nextprime(gmpy2.iroot(nbit,2)[0]//2)
A = [[0] * (nbit+1) for _ in range(nbit+1)]
for i in range(nbit):
A[i][i] = 2
A[i][-1] = pk[i]# *N
A[-1][i] = 1
A[-1][-1] = int(enc)# *N
A = Matrix(ZZ,A)
r = A.LLL()
for i in r:
if len(set(i[:-1])) == 2:
F = i
print(long_to_bytes(int(''.join(str(i) for i in [1 if i == -1 else 0 for i in F][::-1]),2)))
# crypto{my_kn4ps4ck_1s_l1ghtw31ght}
有更多的格的构造方法,能够求解更大密度的背包问题,详细可以参考2020密码数学挑战赛第三题