obstacle的个人空间

These are the days we won't forget

1.univariate

题目

描述

1
I love univariate polynomials...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from Crypto.Util.number import getPrime, bytes_to_long
from secret import flag

p = getPrime(512)
q = getPrime(512)
n = p*q

m = bytes_to_long(flag.encode())
e = 65537
c = pow(m,e,n)

P.<x> = PolynomialRing(ZZ)
x = P.gens()[0]

terms = [x**i for i in range(137)]

T = RealDistribution('gaussian', 2)
coefs = [round(T.get_random_element()) for _ in range(len(terms))]

f = sum([term*coef for term,coef in zip(terms,coefs)])
w = pow(2,f(p),n)

with open('out.txt', 'w') as file:
file.write(f'{n = }\n')
file.write(f'{e = }\n')
file.write(f'{c = }\n')
file.write(f'{f = }\n')
file.write(f'{w = }\n')
n = 151510886600487624888537926759375027338192556324330182365859112926770109752858284462159488504727238764120612593911292154858008775463001345641311051184326218974685701057787672193003745574697137968457609530135969033403360561333863943223407215732526198691453110628598401583407984162075630768455052482583101773637
e = 65537
c = 74468088842131664480394073891613024559473817230309311952320910922177130990996003196602702376336093457990873018154873841543712071422931358036924937335888815556064840522100618318507080665149514719351519909821468981883880543654015414713368018500970500498936910817336501949914675483148862843329341461828563728789
f = -x^136 + x^135 - 2*x^134 - 4*x^132 + 2*x^130 - x^128 - 3*x^127 + 4*x^126 + 3*x^125 + 3*x^124 + x^123 + x^122 - 5*x^121 - 3*x^120 - x^119 - x^118 + x^117 + x^116 - 4*x^114 - 2*x^112 + 2*x^110 + x^109 + 2*x^108 - 2*x^107 + 3*x^106 - x^104 + 2*x^103 - x^102 + x^101 - 2*x^100 + 3*x^99 - 2*x^98 - x^97 - x^96 - 3*x^95 - x^94 - 2*x^93 - 2*x^91 + 3*x^90 - 2*x^89 - 2*x^88 + x^86 + x^85 - 2*x^84 - 3*x^83 + 2*x^82 + 3*x^79 - x^76 + 2*x^75 - x^74 + x^71 - 5*x^70 - x^67 + x^66 + x^65 + x^63 - x^61 + x^59 - 2*x^58 + 6*x^56 + x^55 + 3*x^54 - x^53 + 2*x^52 + 3*x^51 + x^50 + 2*x^49 + 3*x^47 + 2*x^46 - 4*x^45 + 3*x^44 + 3*x^43 - x^42 - 2*x^40 - 5*x^39 + x^38 + x^37 + 2*x^36 + 2*x^35 + x^34 - x^33 + x^32 - 5*x^31 + x^30 + x^29 + 2*x^28 - 2*x^27 + 3*x^26 - x^25 - x^23 - x^22 - 3*x^21 + 2*x^20 - x^19 - x^17 + 2*x^16 - 2*x^15 - 2*x^14 - 2*x^13 - 2*x^12 + 2*x^11 - 2*x^9 + 3*x^8 - 4*x^7 + 2*x^6 - 2*x^5 - 5*x^4 - 3*x^3 + 5*x^2 - 2
w = 86258923706084556733053644452456806418792871483898871193707132372143291757396867798433017660985422614532352743658877188445517898648519256573663299464811234251773841741466280567326570167017786562044635756348763128567054349991798640926148221279889174229551074668002853442182664523748992260830782387602048836221

思路:
根据题目描述univariate polynomials(单变量多项式),题目中也是反复利用p,所以可以从p开始下手。 从 w = pow(2,f(p),n)开始,这里也是我学习中感觉非常巧妙的地方,先了解前提知识费马小定理gcd(a,p)=1,,于是接下来就要构造出p-1。对f(p)模(p-1),就有f(p) = g(p)(p-1) + k。然后对w取p的模数。

所以w除以p的模数就为2^k, 那么​就为p的倍数,然后再与n取最大公约数就可以找出p从而解决RSA问题。即gcd(w-2^k,n).

代码(错误的)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from Crypto.Util.number import *

P.<x> = PolynomialRing(ZZ)
x = P.gens()[0]

n = 151510886600487624888537926759375027338192556324330182365859112926770109752858284462159488504727238764120612593911292154858008775463001345641311051184326218974685701057787672193003745574697137968457609530135969033403360561333863943223407215732526198691453110628598401583407984162075630768455052482583101773637
e = 65537
c = 74468088842131664480394073891613024559473817230309311952320910922177130990996003196602702376336093457990873018154873841543712071422931358036924937335888815556064840522100618318507080665149514719351519909821468981883880543654015414713368018500970500498936910817336501949914675483148862843329341461828563728789
f = -x^136 + x^135 - 2*x^134 - 4*x^132 + 2*x^130 - x^128 - 3*x^127 + 4*x^126 + 3*x^125 + 3*x^124 + x^123 + x^122 - 5*x^121 - 3*x^120 - x^119 - x^118 + x^117 + x^116 - 4*x^114 - 2*x^112 + 2*x^110 + x^109 + 2*x^108 - 2*x^107 + 3*x^106 - x^104 + 2*x^103 - x^102 + x^101 - 2*x^100 + 3*x^99 - 2*x^98 - x^97 - x^96 - 3*x^95 - x^94 - 2*x^93 - 2*x^91 + 3*x^90 - 2*x^89 - 2*x^88 + x^86 + x^85 - 2*x^84 - 3*x^83 + 2*x^82 + 3*x^79 - x^76 + 2*x^75 - x^74 + x^71 - 5*x^70 - x^67 + x^66 + x^65 + x^63 - x^61 + x^59 - 2*x^58 + 6*x^56 + x^55 + 3*x^54 - x^53 + 2*x^52 + 3*x^51 + x^50 + 2*x^49 + 3*x^47 + 2*x^46 - 4*x^45 + 3*x^44 + 3*x^43 - x^42 - 2*x^40 - 5*x^39 + x^38 + x^37 + 2*x^36 + 2*x^35 + x^34 - x^33 + x^32 - 5*x^31 + x^30 + x^29 + 2*x^28 - 2*x^27 + 3*x^26 - x^25 - x^23 - x^22 - 3*x^21 + 2*x^20 - x^19 - x^17 + 2*x^16 - 2*x^15 - 2*x^14 - 2*x^13 - 2*x^12 + 2*x^11 - 2*x^9 + 3*x^8 - 4*x^7 + 2*x^6 - 2*x^5 - 5*x^4 - 3*x^3 + 5*x^2 - 2
w = 86258923706084556733053644452456806418792871483898871193707132372143291757396867798433017660985422614532352743658877188445517898648519256573663299464811234251773841741466280567326570167017786562044635756348763128567054349991798640926148221279889174229551074668002853442182664523748992260830782387602048836221


k = f % (x-1)
k_int=ZZ(k)
q = GCD(w -2^k_int, n)
p = n // q

print(long_to_bytes(int(pow(c, inverse(e, (p-1)*(q-1)), n))))

代码报错了,检查大概知道了原因在于k的值最后是负数,所以直接2^k不行。

正确部分

1
2
3
4
5
k = f % (x-1)

p = GCD(w * pow(2, -k, n) - 1, n)
q = n // p
#b'ictf{p-1_g0es_aB$olU7eLy_w1lD!!!}'

解释:当k是负数时, 实际上是的模逆元。这是因为指数运算是周期性的,且模逆元可以看作是将指数“翻转”到模数的范围内。pow(2, -k, n) 计算的是 的模逆元。如果 k是负数,这意味着我们正在寻找一个数 y 使得 ,然后乘上w再减1就是与n有共同因子。勉强理解是这样,但我数学这方面并未深入研究,所以个人感觉纠错推导过程有点牵强,日后有新理解再做修改吧。

1.构造格解决RSA中m>n问题

首先我们肯定都对RSA加密以及解密原理有了一定认识,比如加密的这句代码:$c=m^e\mod(n)$通过这种方式来得到我们的密文c,但是这个方法有个前提就是m必须小于于n,原因下面再提。然后再看解密,$m=c^d \mod(n)$可以通过欧拉定理来证明这个过程得到$c^d\mod(n)=m\mod(n)$,显然我们能发现如果m大于n会导致得到的密文$newm=m\mod(n)$,我们得到的是newm,而不是m,所以就不完整了,自然还原出来的明文多半就是乱码,那么如何处理这类m>n的问题就是要学习的构造格。学习参考:2024-NSSCTF-密码工坊非官方dlc-wp-crypto | 糖醋小鸡块的blog

例题

1.1 2024羊城杯crypto RSA_loss

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from Crypto.Util.number import *
from gmpy2 import *
p = getPrime(100)
q = getPrime(100)
n = p * q
e = 65537
message = b""
m = bytes_to_long(message)
c = pow(m, e, n)
print(f'c = {c}')
print(f'p = {p}')
print(f'q = {q}')
d = invert(e,(p-1)*(q-1))
newm = pow(c, d, n)
print(long_to_bytes(newm))
#c = 356435791209686635044593929546092486613929446770721636839137
#p = 898278915648707936019913202333
#q = 814090608763917394723955024893
#b'X\xee\x1ey\x88\x01dX\xf6i\x91\x80h\xf4\x1f!\xa7"\x0c\x9a\x06\xc8\x06\x81\x15'

由题目可以知道进行了一个加密再解密的过程,最后解出来是乱码的原因也就是在于m大于n导致数据丢失了。

我们先猜测message范围是所有数字大小字母以及下划线,那么对应的ASCII码范围就在(48,128)之间,假设message长度为le,那么:
$$
m=256^{le-7}*pre+256m_0+suf
$$
(其中pre=b’DASCTF{‘,suf=b’}’,m_0为括号中间部分)。

那么就有:
$$
c=(256^{le-7}*pre+256m_0+suf)\mod(n)
$$
就能得到$m_0 \mod(n)$的值:
$$
m_0=256^{-1}(c-256^{le-7}pre-suf)\mod(n)
$$
然和记$m_0$每个字节为$s_i$从而用ascii的角度将其表示为:
$$
m_0=\sum_{i=0}^{le-9}256^{i}s_i=s_0+256s_1+256^{2}s_2+…+256^{le-9}s_{le-9}\mod(n)
$$
即可以写成:
$$
m_0=\sum_{i=0}^{le-9}256^is_i+kn
$$
就可以构造格来找目标向量:

$$
M = \left(
\begin{array}{*{7}{c}}
1 &0 &0 &0 & 0& 0& 1\\
0& 1 & 0& 0& 0& 0& 256\\
0& 0& \ddots & 0&0 &0 & \vdots\\
0& 0&0 & \ddots & 0&0 & \vdots\\
0& 0& 0& 0& 1 & 0& 256^{le-9}\\
0& 0& 0& 0&0 & 1 & -m_0\\
0&0 & 0&0 & 0&0 & n\\
\end{array}
\right)
$$
有:
$$
(s_0,s_1,…,s_{le-9},1,k)*M=(s_0,s_1,…,s_{le-9},1,0)
$$
这样解出来的向量预期就在48-128之间,范围太大了结果肯定不太行,优化方法就是令:
$$
t_i=s_i-88
$$
这样目标向量范围就为(-40,40)可以解了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from Crypto.Util.number import *

p = 898278915648707936019913202333
q = 814090608763917394723955024893
newm = bytes_to_long(b'X\xee\x1ey\x88\x01dX\xf6i\x91\x80h\xf4\x1f!\xa7"\x0c\x9a\x06\xc8\x06\x81\x15')
n = p * q
c = newm

prefix = b"DASCTF{"
suffix = b"}"
for le in range(33, 50):
length = le - len(prefix) - len(suffix)
#part1 remove prefix and suffix
c -= 256^(len(suffix) + length) * bytes_to_long(prefix)
c -= bytes_to_long(suffix)
c = c * inverse(256,n) % n

L = Matrix(ZZ,length+2,length+2)
for i in range(length):
L[i,i] = 1
L[i,-1] = 256^i
c -= 256^i*88

L[-2,-2] = 1
L[-2,-1] = -c
L[-1,-1] = n
L[:,-1:] *= n
res = L.BKZ()
for i in res[:-1]:
flag = ""
if(all(abs(j) <= 40 for j in i[:-2])):
if(i[-2] == 1):
for j in i[:-2][::-1]:
flag += chr(88 + j)
elif i[-2] == -1:
for j in i[:-2][::-1]:
flag += chr(88 - j)
if(flag != ""):
print(flag)
c = newm
# o0p5_m3ssaGe_to0_b1g_nv93nd0

由于此题不知道长度所以找了一个范围进行遍历求解,然后找出有意义的输出

好久好久没有更新博客了😭最近确实懈怠了一点,还有就是在了解一些web方向的内容所以密码看的比较少了。还是进入今天的正题吧,如标题所见是对coppersmith的一些学习记录。具体原理也不用深究做几道题熟悉一下脚本直接往上代数据就好了。以下是几个一元的脚本模板。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 已知 N 和 p 的高位 p_high,缺失 kbits 位
N = ...
p_high = ... # 高位部分(左对齐)
kbits = ... # 缺失的位数

R.<x> = PolynomialRing(Zmod(N))
f = p_high + x # 高位已知
roots = f.monic().small_roots(X=2^(kbits+1), beta=0.4,epsilon=0.03)
if roots:
p = int(p_high + roots[0])
print("p =", p)
print("q =", N // p)




# 已知 N 和 p ≡ p_low mod 2^k
N = ...
p_low = ...
k = ... # 低位位数

R.<x> = PolynomialRing(Zmod(N))
f = p_low + x * 2^k # 低位已知
roots = f.monic().small_roots(X=2^(k+1), beta=0.4,epsilon=0.03)
if roots:
p = int(p_low + roots[0] * 2^k)
print("p =", p)
print("q =", N // p)





N = ...
e = ...
c = ...
m0 = ... # 已知部分,例如 m0 = bytes_to_long(b"flag{")
k = ... # 未知位数

R.<x> = PolynomialRing(Zmod(N))
f = (m0 + x)^e - c
roots = f.small_roots(X=2^k, beta=1/e)
if roots:
m = int(m0 + roots[0])
print(long_to_bytes(m))

示例1—math_problem

这里以2025-L3HCTF的math_problem为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import gmpy2
from gmpy2 import *
from Crypto.Util.number import *
from random import randint
from gmpy2 import invert
from scret import flag

def myfunction(num):
output = 0
output=num**3
return output

if __name__ == '__main__':
flag_len = len(flag)
p, q = getPrime(512), getPrime(512)

while True:
r = getPrime(512)
R = bytes_to_long(str(r).encode())
if isPrime(R):
break

n = p * q * r
hint1 = R * r
mod = myfunction(n)
hint2 = pow(3*n+1, p % (2 ** 400), mod)
m = bytes_to_long(flag)
c = pow(m, 65537, n)

print('All data:')
print(f'n = {n}')
print(f'c = {c}')
print(f'hint1 = {hint1}')
print(f'hint2 = {hint2}')


'''
All data:
n = 1031361339208727791691298627543660626410606240120564103678654539403400080866317968868129842196968695881908504164493307869679126969820723174066217814377008485456923379924853652121682069359767219423414060835725846413022799109637665041081215491777412523849107017649039242068964400703052356256244423474207673552341406331476528847104738461329766566162770505123490007005634713729116037657261941371410447717090137275138353217951485412890440960756321099770208574858093921
c = 102236458296005878146044806702966879940747405722298512433320216536239393890381990624291341014929382445849345903174490221598574856359809965659167404530660264493014761156245994411400111564065685663103513911577275735398329066710295262831185375333970116921093419001584290401132157702732101670324984662104398372071827999099732380917953008348751083912048254277463410132465011554297806390512318512896160903564287060978724650580695287391837481366347198300815022619675984
hint1 = 41699797470148528118065605288197366862071963783170462567646805693192170424753713903885385414542846725515351517470807154959539734665451498128021839987009088359453952505767502787767811244460427708303466073939179073677508236152266192609771866449943129677399293427414429298810647511172104050713783858789512441818844085646242722591714271359623474775510189704720357600842458800685062043578453094042903696357669390327924676743287819794284636630926065882392099206000580093201362555407712118431477329843371699667742798025599077898845333
hint2 = 10565371682545827068628214330168936678432017129758459192768614958768416450293677581352009816968059122180962364167183380897064080110800683719854438826424680653506645748730410281261164772551926020079613841220031841169753076600288062149920421974462095373140575810644453412962829711044354434460214948130078789634468559296648856777594230611436313326135647906667484971720387096683685835063221395189609633921668472719627163647225857737284122295085955645299384331967103814148801560724293703790396208078532008033853743619829338796313296528242521122038216263850878753284443416054923259279068894310509509537975210875344702115518307484576582043341455081343814378133782821979252975223992920160189207341869819491668768770230707076868854748648405256689895041414944466320313193195829115278252603228975429163616907186455903997049788262936239949070310119041141829846270634673190618136793047062531806082102640644325030011059428082270352824026797462398349982925951981419189268790800571889709446027925165953065407940787203142846496246938799390975110032101769845148364390897424165932568423505644878118670783346937251004620653142783361686327652304482423795489977844150385264586056799848907
'''

思路:首先由hint1和n取最大公因数可以解出r(虽然这个时候把r当成n来用,$\phi(n)=r-1$,用rsa就直接可以解出来了,算是非预期吧)预期做法就是对hint2转换可以得到p的低400位然后coppersmith解出p从而解题。

令$k=p \mod 2^{400}$,$hint2=(1+3n)^k \mod n^3$,由二项式展开再消去带有$n^3$的因子的项化解完就是这样

$hint2 \equiv 1 + 3kn + \frac{9}{2}k(k-1)n^2 \pmod{n^3}$,$(hint2-1)//n\equiv 3k+\frac{9}{2}k(k-1)n \pmod{n^2}$,让$(hint2-1)//n=h$,然后再模n,$h \equiv3k \mod n$左右乘3的逆元就可以得到k即p的低四百位。

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from math import gcd
from Crypto.Util.number import *
import gmpy2
n = 1031361339208727791691298627543660626410606240120564103678654539403400080866317968868129842196968695881908504164493307869679126969820723174066217814377008485456923379924853652121682069359767219423414060835725846413022799109637665041081215491777412523849107017649039242068964400703052356256244423474207673552341406331476528847104738461329766566162770505123490007005634713729116037657261941371410447717090137275138353217951485412890440960756321099770208574858093921
c = 102236458296005878146044806702966879940747405722298512433320216536239393890381990624291341014929382445849345903174490221598574856359809965659167404530660264493014761156245994411400111564065685663103513911577275735398329066710295262831185375333970116921093419001584290401132157702732101670324984662104398372071827999099732380917953008348751083912048254277463410132465011554297806390512318512896160903564287060978724650580695287391837481366347198300815022619675984
hint1 = 41699797470148528118065605288197366862071963783170462567646805693192170424753713903885385414542846725515351517470807154959539734665451498128021839987009088359453952505767502787767811244460427708303466073939179073677508236152266192609771866449943129677399293427414429298810647511172104050713783858789512441818844085646242722591714271359623474775510189704720357600842458800685062043578453094042903696357669390327924676743287819794284636630926065882392099206000580093201362555407712118431477329843371699667742798025599077898845333
hint2 = 10565371682545827068628214330168936678432017129758459192768614958768416450293677581352009816968059122180962364167183380897064080110800683719854438826424680653506645748730410281261164772551926020079613841220031841169753076600288062149920421974462095373140575810644453412962829711044354434460214948130078789634468559296648856777594230611436313326135647906667484971720387096683685835063221395189609633921668472719627163647225857737284122295085955645299384331967103814148801560724293703790396208078532008033853743619829338796313296528242521122038216263850878753284443416054923259279068894310509509537975210875344702115518307484576582043341455081343814378133782821979252975223992920160189207341869819491668768770230707076868854748648405256689895041414944466320313193195829115278252603228975429163616907186455903997049788262936239949070310119041141829846270634673190618136793047062531806082102640644325030011059428082270352824026797462398349982925951981419189268790800571889709446027925165953065407940787203142846496246938799390975110032101769845148364390897424165932568423505644878118670783346937251004620653142783361686327652304482423795489977844150385264586056799848907

r = gcd(n, hint1)
h=(hint2-1)//n
p_low=(h*inverse(3,n))%n

kbits = 512-400
R.<x> = PolynomialRing(Zmod(n))
f = x*2^400 + p_low
roots = f.monic().small_roots(X=2^kbits, beta=0.2, epsilon=0.03)
x0 = roots[0]
p = int(p_low + x0*2^400)
q=n//p//r
e=65537
d = inverse(e,(p-1)*(q-1)*(r-1))
m = pow(c,d,n)
print(long_to_bytes(m))
#L3HCTF{1s_4h1s_r3a11y_m4th?}

示例2—SCTF2024—-signin

参考https://tangcuxiaojikuai.xyz/post/146254b2.html

其中Φ的构造是一模一样的,所以直接套用脚本就解出了,后来看好像还可以通过连分数的方式解题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
from Crypto.Util.number import *
from gmpy2 import *
import itertools
from hashlib import md5
def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()
R = f.base_ring()
N = R.cardinality()
f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)
G = Sequence([], f.parent())
for i in range(m + 1):
base = N ^ (m - i) * f ^ i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)
B, monomials = G.coefficients_monomials()
monomials = vector(monomials)
factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1 / factor)
H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B * monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []
n = 32261421478213846055712670966502489204755328170115455046538351164751104619671102517649635534043658087736634695616391757439732095084483689790126957681118278054587893972547230081514687941476504846573346232349396528794022902849402462140720882761797608629678538971832857107919821058604542569600500431547986211951
e = 334450817132213889699916301332076676907807495738301743367532551341259554597455532787632746522806063413194057583998858669641413549469205803510032623432057274574904024415310727712701532706683404590321555542304471243731711502894688623443411522742837178384157350652336133957839779184278283984964616921311020965540513988059163842300284809747927188585982778365798558959611785248767075169464495691092816641600277394649073668575637386621433598176627864284154484501969887686377152288296838258930293614942020655916701799531971307171423974651394156780269830631029915305188230547099840604668445612429756706738202411074392821840

R.<x,y>=PolynomialRing(Zmod(e))
f = 1 + x*(n^2-n+1 + (n+1)*y + y^2)
res = small_roots(f, (2^256,2^512), m=2, d=3)
pplusq = int(res[0][1])
pminusq = iroot(pplusq^2-4*n,2)[0]
p = (pplusq + pminusq) // 2
q = n // p
bp = long_to_bytes(int(p))
FLAG1 = 'SCTF{'+md5(bp).hexdigest()+'}'
print(FLAG1)
bq = long_to_bytes(int(q))
FLAG2 = 'SCTF{'+md5(bq).hexdigest()+'}'
print(FLAG2)


1.图片

往typora插入图片,图片文件夹一定要和创建的.md文件夹放在同一个文件夹下。不然文件移动位置后图片会因找不到地址而消失

1
2
格式![提示文字](图片地址)      即先!然后快捷键ctrl+k
例如:![伊蕾娜](D:\blog\source\images\Elaina.jpg)

问题

相信很多人尝试上面图片的插入方法会遇到在typora能正常显示图片,但在网页上图片却无法加载。这是因为上述地址如D:\blog\source\images\Elaina.jpg为本地地址,而hexo+github搭建的博客并不能访问本地地址所以自然无法成功。

解决

最简单粗暴的方法就是直接将图片拖到typora中,typora会直接创建博客文章同名的文件夹存放图片。但是就是感觉文章写多了有点乱乱的。

特别注意

说来也巧本以为早就解决了图片的问题结果又出现了,这次经过更长时间捣鼓得出结论上面例子里的【提示文字】不能为纯数字不然部署到GitHub上就被认定为width而不是title导致图片无法加载。

vscode配置easyx

前言:因为程序设计的作业要用到easyx图形库,又因为本人习惯用vscode,所以尝试在vscode中安装easyx但是路途确实有点艰辛,虽然最后回顾过程其实也很简单。

配置

1.安装必要文件

参考https://codebus.cn/bestans/easyx-for-mingw。

下载网址中的压缩包然后按照网址所说将压缩包中include的头文件和lib64的库文件拷贝到mingw的头文件和库文件中。

2.增加编译时的链接选项

链接选项增加:-leasyx,这样可以在编译的时候链接 libeasyx.a 库文件。

在tasks.json中添加即可

问题

这里以本人遇到一个问题为例子,本来按照教程将对应的文件复制到对应位置后就可以了但是却依然有问题如下图

现在我们尝试测试一个代码结果发现找不到这个文件。但是上图中可以看到iostream是可以被找到的,那么我们只要找到这个文件存放的位置再把easyx.h这个文件也放到相同文件夹即可。按住ctrl然后鼠标点击iostream就可以找到具体位置

如图所示我们找到该文件位置后再添加easyx.h就不报错了(话说这时候才发现自己的怎么是MSVC怪不得前面一开始不行😢,一直以为是mingw不过没什么关系。

最后也是成功运行,接下来就可以进行后续的一些工作了。

总结

一开始也是照着博客以及ai一顿捣鼓,最后终于完成还是很开心的,通过这次也对这些头文件貌似有了更深入的一些了解,也有了更多相关经验,以后也会继续探索学习。

1.RSA中leak=p^q%n + q^p%n问题

以ISCTF2024crypto蓝鲨的费马这道题为例子讲解自己学到的一个解决方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import libnum
import gmpy2
from Crypto.Util.number import *
flag=b'ISCTF{********}'
m=bytes_to_long(flag)
p=libnum.generate_prime(1024)
q=libnum.generate_prime(1024)
n=p*q
e=0x10001
c=pow(m,e,n)
d=inverse(e,(p-1)*(q-1))
leak = (d+(pow(p,q,n)+pow(q,p,n)))%n
print("c=", c)
print("n=", n)
print("leak=", leak)
"""
c= 8989289659072309605793417141528767265266446236550650613514493589798432446586991233583435051268377555448062724563967695425657559568596372723980081067589103919296476501677424322525079257328042851349095575718347302884996529329066703597604694781627113384086536158793653551546025090807063130353950841148535682974762381044510423210397947080397718080033363000599995100765708244828566873128882878164321817156170983773105693537799111546309755235573342169431295776881832991533489235535981382958295960435126843833532716436804949502318851112378495533302256759494573250596802016112398817816155228378089079806308296705261876583997
n= 13424018200035368603483071894166480724482952594135293395398366121467209427078817227870501294732149372214083432516059795712917132804111155585926502759533393295089100965059106772393520277313184519450478832376508528256865861027444446718552169503579478134286009893965458507369983396982525906466073384013443851551139147777507283791250268462136554061959016630318688169168797939873600493494258467352326974238472394214986505312411729432927489878418792288365594455065912126527908319239444514857325441614280498882524432151918146061570116187524918358453036228204087993064505391742062288050068745930452767100091519798860487150247
leak= 9192002086528025412361053058922669469031188193149143635074798633855112230489479254740324032262690315813650428270911079121913869290893574897752990491429582640499542165616254566396564016734157323265631446079744216458719690853526969359930225042993006404843355356540487296896949431969541367144841985153231095140361069256753593550199420993461786814074270171257117410848796614931926182811404655619662690700351986753661502438299236428991412206196135090756862851230228396476709412020941670878645924203989895008014836619321109848938770269989596541278600166088022166386213646074764712810133558692545401032391239330088256431881
"""

$1.\text{leak} = d + p + q$ 其中 leak 简写为 L

$2. m = \text{pow}(c, d, n),即 m = c^d \mod n.$

$3.d = L - (p + q) .$

根据欧拉函数的定义:$\phi = (p - 1)(q - 1) = pq - p - q + 1$

由于 n = pq ,因此:$\phi = n + 1 - (p + q)$

根据欧拉定理:$c^\phi \equiv1 \mod n$

代入 $\phi$的表达式:$c^{n + 1 - (p + q)} \equiv 1 \mod n$

可以进一步推导:$c^{n + 1} \equiv c^{p + q} \mod n$

因此:$c^{n + 1} \equiv c^{p + q} \mod n$

已知 d = L - (p + q) ,代入 $c^d \mod n = m$ :

$c^{L - (p + q)} \mod n = m$

根据前面的推导:$c^{n + 1} \equiv c^{p + q} \mod n$

因此:$c^{L - (n + 1)} \mod n = m$

$m = \text{pow}(c, L - n - 1, n)$

1
2
3
4
5
6
7
8
9
c= 8989289659072309605793417141528767265266446236550650613514493589798432446586991233583435051268377555448062724563967695425657559568596372723980081067589103919296476501677424322525079257328042851349095575718347302884996529329066703597604694781627113384086536158793653551546025090807063130353950841148535682974762381044510423210397947080397718080033363000599995100765708244828566873128882878164321817156170983773105693537799111546309755235573342169431295776881832991533489235535981382958295960435126843833532716436804949502318851112378495533302256759494573250596802016112398817816155228378089079806308296705261876583997
n= 13424018200035368603483071894166480724482952594135293395398366121467209427078817227870501294732149372214083432516059795712917132804111155585926502759533393295089100965059106772393520277313184519450478832376508528256865861027444446718552169503579478134286009893965458507369983396982525906466073384013443851551139147777507283791250268462136554061959016630318688169168797939873600493494258467352326974238472394214986505312411729432927489878418792288365594455065912126527908319239444514857325441614280498882524432151918146061570116187524918358453036228204087993064505391742062288050068745930452767100091519798860487150247
leak= 9192002086528025412361053058922669469031188193149143635074798633855112230489479254740324032262690315813650428270911079121913869290893574897752990491429582640499542165616254566396564016734157323265631446079744216458719690853526969359930225042993006404843355356540487296896949431969541367144841985153231095140361069256753593550199420993461786814074270171257117410848796614931926182811404655619662690700351986753661502438299236428991412206196135090756862851230228396476709412020941670878645924203989895008014836619321109848938770269989596541278600166088022166386213646074764712810133558692545401032391239330088256431881
from Crypto.Util.number import long_to_bytes, inverse
m=pow(c,leak-n-1,n)
print(m)
flag=long_to_bytes(m)
print(flag)
#b'ISCTF{u_got_it}'

2.RSA中dp泄露(已知dp,e,n,c)

dp=d mod (p-1)

dq=d mod (q-1)

因为$\phi(n)=(p-1)*(q-1)$,这里也出现了(p-1)所以这几个存在一定的联系,一旦泄露可能会造成安全隐患。

题目部分数据

1
2
3
4
5
6
7
8
import gmpy2 as gp

e = 65537
n = 248254007851526241177721526698901802985832766176221609612258877371620580060433101538328030305219918697643619814200930679612109885533801335348445023751670478437073055544724280684733298051599167660303645183146161497485358633681492129668802402065797789905550489547645118787266601929429724133167768465309665906113
dp = 905074498052346904643025132879518330691925174573054004621877253318682675055421970943552016695528560364834446303196939207056642927148093290374440210503657

c = 140423670976252696807533673586209400575664282100684119784203527124521188996403826597436883766041879067494280957410201958935737360380801845453829293997433414188838725751796261702622028587211560353362847191060306578510511380965162133472698713063592621028959167072781482562673683090590521214218071160287665180751

同样先进行推导,化简成为一个可以靠程序解决的式子。

1.dp=d mod(p-1)

2.两边同乘e,$dpe \equiv de \mod(p-1)$

3.$ed =k_1*(p-1)+dpe,而ed \equiv 1 \mod \phi(n),\phi(n)=(p-1)(q-1)$

4.$k_1*(p-1)+dpe = 1+k_2(p-1)*(q-1)$

5.接下来就合并同类项解方程

6.化简得$dp*e=(k_2(q-1)-k_1)(p-1)+1$,令$k_2(q-1)-k_1=X$

7.$dp*e=X(p-1)+1$,首先dp<(p-1),所以X<e.

8.$p-1=\frac{dp*e-1}{X}$,因为X的范围已知直接遍历爆破即可求出p-1的值从而后续就变为常规RSA问题了

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import gmpy2 as gp
from Crypto.Util.number import *
e = 65537
n = 248254007851526241177721526698901802985832766176221609612258877371620580060433101538328030305219918697643619814200930679612109885533801335348445023751670478437073055544724280684733298051599167660303645183146161497485358633681492129668802402065797789905550489547645118787266601929429724133167768465309665906113
dp = 905074498052346904643025132879518330691925174573054004621877253318682675055421970943552016695528560364834446303196939207056642927148093290374440210503657

c = 140423670976252696807533673586209400575664282100684119784203527124521188996403826597436883766041879067494280957410201958935737360380801845453829293997433414188838725751796261702622028587211560353362847191060306578510511380965162133472698713063592621028959167072781482562673683090590521214218071160287665180751


for i in range(1,e):
if(dp*e-1)%i == 0:
if n%(((dp*e-1)//i)+1) == 0:
p=((dp*e-1)//i)+1
q=n//(((dp*e-1)//i)+1)
phi=(q-1)*(p-1)
d=gp.invert(e,phi)
m=pow(c,d,n)


print(long_to_bytes(m))
#flag{wow_leaking_dp_breaks_rsa?_98924743502}

3.RSA中dp,dq泄露(dp,dq,c,p,q)

原谅我太懒了,懒得推导了直接脚本拿来用得了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from gmpy2 import *
from Crypto.Util.number import *

# dp+dq+p+q+c => m

def rsa(dp,dq,p,q,c):
m1=pow(c,dp,p)
m2=pow(c,dq,q)
p_q=invert(p,q)
m=m1+p_q*((m2-m1)%q)*p
print(long_to_bytes(m))



if __name__ == "__main__":
p = 8637633767257008567099653486541091171320491509433615447539162437911244175885667806398411790524083553445158113502227745206205327690939504032994699902053229
q = 12640674973996472769176047937170883420927050821480010581593137135372473880595613737337630629752577346147039284030082593490776630572584959954205336880228469
dp = 6500795702216834621109042351193261530650043841056252930930949663358625016881832840728066026150264693076109354874099841380454881716097778307268116910582929
dq = 783472263673553449019532580386470672380574033551303889137911760438881683674556098098256795673512201963002175438762767516968043599582527539160811120550041
c = 24722305403887382073567316467649080662631552905960229399079107995602154418176056335800638887527614164073530437657085079676157350205351945222989351316076486573599576041978339872265925062764318536089007310270278526159678937431903862892400747915525118983959970607934142974736675784325993445942031372107342103852

rsa(dp,dq,p,q,c)

#noxCTF{W31c0m3_70_Ch1n470wn}

中国剩余定理(CRT)

在做题时遇到离散对数问题中碰到很多CRT相关知识,但最初了解比较浅显,现在准备再稍微细致的回顾一下。

定义

中国剩余定理 (Chinese Remainder Theorem, CRT) 可求解如下形式的一元线性同余方程组(其中$n_1$ $n_2$ ······$n_k$ 两两互质):

$$
\begin{cases} x\equiv a_1 \pmod{n_1}\\ x\equiv a_2 \pmod{n_2}\\ x\equiv a_3 \pmod{n_3}\\ ·····\\ ·····\\ ·····\\ x\equiv a_k \pmod{n_k} \end{cases}
$$

过程

1.计算所有模数的积 n;n=$n_1*n_2*···n_k$

2.对于第 i个方程:

​ a.计算$m_i=n/n_i$;

​ b.计算$m_i在模n_i意义下的逆元m_i^{-1}$; 逆元$m_im_i^{-1}\equiv 1\pmod{n_i}$

​ c.计算$c_i=m_im_i^{-1}$

3.方程组在模n意义下的唯一解为$x=\sum_{i=1}^{k}{a_ic_i}\pmod{n}$

代码

1
2
3
4
5
6
7
8
9
10
11
12

def CRT(k, a, r):
n = 1
ans = 0
for i in range(1, k + 1):
n = n * r[i]
for i in range(1, k + 1):
m = n // r[i]
b =y=0
exgcd(m, r[i], b, y) # b * m mod r[i] = 1 exgcd是另一个用来求逆元的自定义函数未标
ans = (ans + a[i] * m * b % n) % n
return (ans % n + n) % n

当然了上述代码可能更多用于算法题中,密码学里python有很多强大的库可以直接调用CRT

1
2
3
4
from sympy.ntheory.modular import crt
a_list=[a1,a2,a3,····ak]
n_list=[n1,n2,n3,····nk]
x,n=crt(n_list,c_list) //crt会返回一个元组(x,N)其中x就是我们所需要的通解,n就是所有模数(n1,n2等)的乘积

证明

虽然说密码学里直接秒了,但我还是觉得搞清背后逻辑会更有理解。

$当i\neq j时,有m_j\equiv 0 \pmod{n_i}$

$这是因为m_j=n/n_j$

$所以c_j \equiv 0 \pmod{n_i},c_i\equiv 1 \pmod{n_i} $

$ x \equiv \sum_{j=1}^{k}{a_jc_j} \equiv a_ic_i\equiv a_i\pmod{n_i}$

$对于任意的i的取值均符合x\equiv a_i \pmod{n_i}$

所以上述方法可行

部分密码题目复现,后续应该会把没复现的几道题补上吧(或许吧

费克特尔

1
2
3
c=670610235999012099846283721569059674725712804950807955010725968103642359765806
n=810544624661213367964996895060815354972889892659483948276203088055391907479553
e=65537

简单的RSA,借助yafu对n进行质因数分解得到多了质数p1,p2,p3等。那么phi=(p1-1)(p2-1)(p3-1)·····

后续就正常RSA那一套解就好了。flag:TGCTF{f4888_6abdc_9c2bd_9036bb}

宝宝RSA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from math import gcd
from Crypto.Util.number import *
from secret import flag

# PART1
p1 = getPrime(512)
q1 = getPrime(512)
n1 = p1 * q1
phi = (p1 - 1) * (q1 - 1)
m1 = bytes_to_long(flag[:len(flag) // 2])
e1 = getPrime(18)
while gcd(e1, phi) != 1:
e1 = getPrime(17)
c1 = pow(m1, e1, n1)

print("p1 =", p1)
print("q1 =", q1)
print("c1 =", c1)

# PART2
n2 = getPrime(512) * getPrime(512)
e2 = 3
m2 = bytes_to_long(flag[len(flag) // 2:])
c2 = pow(m2, e2, n2)

print("n2 =", n2)
print("c2 =", c2)
print("e2 =", e2)

# p1 = 8362851990079664018649774360159786938757293294328116561219351503022492961843907118845919317399785168488103775809531198339213009936918460080250107807031483
# q1 = 8312546034426788223492083178829355192676175323324230533451989649056072814335528263136523605276378801682321623998646291206494179416941978672637426346496531
# c1 = 39711973075443303473292859404026809299317446021917391206568511014894789946819103680496756934914058521250438186214943037578346772475409633145435232816799913236259074769958139045997486622505579239448395807857034154142067866860431132262060279168752474990452298895511880964765819538256786616223902867436130100322
# n2 = 103873139604388138367962901582343595570773101048733694603978570485894317088745160532049473181477976966240986994452119002966492405873949673076731730953232584747066494028393377311943117296014622567610739232596396108513639030323602579269952539931712136467116373246367352649143304819856986264023237676167338361059
# c2 = 51380982170049779703682835988073709896409264083198805522051459033730166821511419536113492522308604225188048202917930917221
# e2 = 3

思路:flag拆成两部分,分别求出前后两部分然后合并即可。

前半部分知道p和q也知道e的大致范围(相对来说比较小)直接爆破即可,后半部分e很小可以进行爆破。

代码:

前半部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from sympy import primerange
from math import gcd
from Crypto.Util.number import long_to_bytes
import gmpy2

# 17位素数范围:2^16到2^17-1
primes_17 = list(primerange(2**16, 2**17))
# 18位素数范围:2^17到2^18-1
primes_18 = list(primerange(2**17, 2**18))
candidates = primes_17 + primes_18
p1 = 8362851990079664018649774360159786938757293294328116561219351503022492961843907118845919317399785168488103775809531198339213009936918460080250107807031483
q1 = 8312546034426788223492083178829355192676175323324230533451989649056072814335528263136523605276378801682321623998646291206494179416941978672637426346496531
phi = (p1 - 1) * (q1 - 1)
valid_e = [e for e in candidates if gcd(e, phi) == 1]

c1 = 39711973075443303473292859404026809299317446021917391206568511014894789946819103680496756934914058521250438186214943037578346772475409633145435232816799913236259074769958139045997486622505579239448395807857034154142067866860431132262060279168752474990452298895511880964765819538256786616223902867436130100322
n1 = p1 * q1

for e in valid_e:
d = pow(e, -1, phi)
m1 = pow(c1, d, n1)
flag_part = long_to_bytes(m1)
if b'TGCTF' in flag_part: # 根据预期flag格式调整
print(flag_part.decode())
break
#TGCTF{!!3xP_Is_S

后半部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from sympy import primerange
from math import gcd
from Crypto.Util.number import long_to_bytes
import gmpy2




n2 = 103873139604388138367962901582343595570773101048733694603978570485894317088745160532049473181477976966240986994452119002966492405873949673076731730953232584747066494028393377311943117296014622567610739232596396108513639030323602579269952539931712136467116373246367352649143304819856986264023237676167338361059
c2 = 51380982170049779703682835988073709896409264083198805522051459033730166821511419536113492522308604225188048202917930917221
e2 = 3
k = 0
while 1:
res = gmpy2.iroot(k*n2+c2,e2)
if(res[1] == True):
print(bytes.fromhex(hex(res[0])[2:]))
break
k += 1
#m@ll_But_D@ng3r0}

tRwSiAns

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from flag import FLAG
from Crypto.Util.number import getPrime, bytes_to_long
import hashlib

def generate_key(bits=512):
p = getPrime(bits)
q = getPrime(bits)
return p * q, 3


def hash(x):
return int(hashlib.md5(str(x).encode()).hexdigest(), 16)


def encrypt(m, n, e):
x1, x2 = 307, 7
c1 = pow(m + hash(x1), e, n)
c2 = pow(m + hash(x2), e, n)
return c1, c2


m = bytes_to_long(FLAG)
n, e = generate_key()
c1, c2 = encrypt(m, n, e)
print(f"n = {n}")
print(f"e = {e}")
print(f"c1 = {c1}")
print(f"c2 = {c2}")

n = 100885785256342169056765112203447042910886647238787490462506364977429519290706204521984596783537199842140535823208433284571495132415960381175163434675775328905396713032321690195499705998621049971024487732085874710868565606249892231863632731481840542506411757024315315311788336796336407286355303887021285839839
e = 3
c1 = 41973910895747673899187679417443865074160589754180118442365040608786257167532976519645413349472355652086604920132172274308809002827286937134629295632868623764934042989648498006706284984313078230848738989331579140105876643369041029438708179499450424414752031366276378743595588425043730563346092854896545408366
c2 = 41973912583926901518444642835111314526720967879172223986535984124576403651553273447618087600591347032422378272332279802860926604693828116337548053006928860031338938935746179912330961194768693506712533420818446672613053888256943921222915644107389736912059397747390472331492265060448066180414639931364582445814

Franklin-Reiter 相关消息攻击 两个密文对应的消息存在线性关系.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Util.number import long_to_bytes
import hashlib

def hash(x):
return int(hashlib.md5(str(x).encode()).hexdigest(), 16)

h1 = hash(307)
h2 = hash(7)


n = 100885785256342169056765112203447042910886647238787490462506364977429519290706204521984596783537199842140535823208433284571495132415960381175163434675775328905396713032321690195499705998621049971024487732085874710868565606249892231863632731481840542506411757024315315311788336796336407286355303887021285839839
e=3
delta = h1 - h2
c1 = 41973910895747673899187679417443865074160589754180118442365040608786257167532976519645413349472355652086604920132172274308809002827286937134629295632868623764934042989648498006706284984313078230848738989331579140105876643369041029438708179499450424414752031366276378743595588425043730563346092854896545408366
c2 = 41973912583926901518444642835111314526720967879172223986535984124576403651553273447618087600591347032422378272332279802860926604693828116337548053006928860031338938935746179912330961194768693506712533420818446672613053888256943921222915644107389736912059397747390472331492265060448066180414639931364582445814

R.<s> = PolynomialRing(Zmod(n))
f = (s+h1)^3 - c1
g = (s +h2)^3 - c2
flag = -gcd(f, g)[0]

print(long_to_bytes(int(flag)))
#TGCTF{RS4_Tw1nZ_d0You_th1nk_ItS_fun_2win?!!!1111111111}

LLLCG

咕咕咕,后续这题应该不搞了,大概去看LCG相关的题学习一下就好了

EZRSA

咕咕咕,这题emmmm也不搞了吧,学习一下p的低位泄露然后就过。后续应该放在RSA中leak问题那篇文章中

这是我的第一个博客

懒惰的我终于开始初步学习密码学中格的相关内容了,虽然很早之前就看过了,但是由于东西实在是太多了根本看不下去,看了也不理解。现在再次开始密码学之路,这篇文章算是边学边理解的感悟吧。

格的认识

经过学长的点明后,对于我目前学习最初步的格来说就把格理解为线性向量,把线性代数的知识运用上去,无非就是换了很多全新的名词,本质上按线性向量去理解会轻松很多。所以说还是要有一定线代基础不然还是很难接受(但线代本身也确实很抽象😢)

problem

目前看过来分为svp(shortest vector problem)最短向量问题和cvp(closest vector problem)最近向量问题。两个名字看中文感觉就是一回事最短和最近,但事实上区别很大。

SVP

感觉正式讲法很难理解,我自己想法就是格中有一组基向量【b1,b2】以及很多点,要通过基向量找到一个点,使得这个点离原点最近,而λ1就是最短向量。有时候因为基的点分布并不理想,很多时候找出来的是最短向量λ1的倍数,这就是svp的宽松版本了。svp

CVP

在基中找一个点t,找到距离这个点最近的格点。换句话理解就是找到一个向量λ1使得t向量(蓝色线)与λ1相减后得到的向量μ最短。同样存在cvp的宽松版本,如图中2μ,只不过目前我对于宽松版本还未很好理解。cvp

LLL算法

嗯感觉这个原理非常复杂,想理解目前水平做不到,差不多想就是LLL是一个格基约化算法,作用是将上面图片中格变得更加整齐(就是把图中倾斜绿色点变得和坐标轴一样整齐)。反正目前做一些初步题大概就是按题目意思构造一个合理的格然后对格直接用LLL.( )会得到一个短向量,然后从这些向量中可以找到我们需要的,然后差不多就可以解出题目。所以不需要理解直接用吧😢然后顺带提一下BKZ算法,也是理解为更高级的LLL,直接用别管原理什么的。

0%