Lattice
题目:
import gmpy2
from Crypto.Util.number import *
from enc import flagm = bytes_to_long(flag)
n = getPrime(1024)
x = getPrime(200)
hint = (x*gmpy2.invert(m,n)) % n
print(f'n = {n}')
print(f'hint = {hint}')
'''
n = 135468605513880715606160882767765787154992546140468650057512573698684612475952478442814762328886660927143257644564134230892428444605363739481966015067533502387771994796933314650597759164542382096028864516989227078865314961731612554274030804378847341544941485447330710625751160113655721360522825842304325648661
hint = 4535444892439469356191795531860980185017935336250370459110841353738315673311973758532357439742440370098258890761750332474316301902006965178488232784675254754714945846956685367697549284904368943678089682352903895702618452358063454221008706189296038769220252217025015109037299722951003889830047605895164204665
'''
最标准的格
做之前最好先判断是否满足hermite定理
脚本:
#sage
import gmpy2
from Crypto.Util.number import *n = 135468605513880715606160882767765787154992546140468650057512573698684612475952478442814762328886660927143257644564134230892428444605363739481966015067533502387771994796933314650597759164542382096028864516989227078865314961731612554274030804378847341544941485447330710625751160113655721360522825842304325648661
hint = 4535444892439469356191795531860980185017935336250370459110841353738315673311973758532357439742440370098258890761750332474316301902006965178488232784675254754714945846956685367697549284904368943678089682352903895702618452358063454221008706189296038769220252217025015109037299722951003889830047605895164204665# hint*m=x%n
# hint*m=x+kn
# x=hint*m-kn# [m,-k][1,hint]=[m,x]
# [0,n]
m=getPrime(37*8)
x = getPrime(200)
length1=gmpy2.iroot(2*n,2)[0]
length2=gmpy2.iroot(x**2+m**2,2)[0]
print(length1.bit_length())
print(length2.bit_length())Ge=Matrix(ZZ,[[1,hint],[0,n]])
m=abs(Ge.LLL()[0][0])
print(long_to_bytes(int(m)))
这里的m位数也是根据常识预估一下
babylcg
题目:
from Crypto.Util.number import *
from enc import flagseed = bytes_to_long(flag)a = getPrime(400)
b = getPrime(400)
p = getPrime(400)
c = []
for i in range(3):seed = (seed*a+b)%pc.append(seed>>80)
print(f'a = {a}')
print(f'b = {b}')
print(f'p = {p}')
print(f'c = {c}')'''
a = 2480723693416197023777639119379107915577379442319446556514537465902730221165988032585937040968036882125810398538496323351
b = 1904193709124547126225055171380429984044969427702757019616077686519603583212249311116383727431445401398594522230612229733
p = 1532358535804235132496312416063170109053232217889240979567714057566239469579822887828122819499504563106464882747447051359
c = [813530482014456574209632986607111359200629085246367954186877618366451174001463654876753005264098, 1054295430131833360658465071066491055652904289373961069213308535490435549697560050854110548843919, 374976866832751055109605198170602358027434683548463528601734580123896818157824411065383601884240]
'''
非常规lcg,因为这里的see>>80,高位泄露了
c[0]=813530482014456574209632986607111359200629085246367954186877618366451174001463654876753005264098
print(c[0].bit_length())
#319>>80
这里用c0,c1套一下
H1+L1=((H0+L0)*a+b)%p
#H1,L1是c1的高位和低位,c0同理
构建多项式环:
f=(H0+L0)*a+b)-(H1+L1)
其中L0和L1未知,令其为x和y
即f=(H0+x)*a+b)-(H1+y)
这样即可得到x,即得到c0
而从根据a的逆元反推seed
这里最难的点感觉就是求小根那个函数
这里用的其他师傅的脚本,没实力啊~
import itertools
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^ifor shifts in itertools.product(range(d), repeat=f.nvariables()):g = base * prod(map(power, f.variables(), shifts))G.append(g)B, monomials = G.coefficient_matrix()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 rootsreturn []
# sage
a = 2480723693416197023777639119379107915577379442319446556514537465902730221165988032585937040968036882125810398538496323351
b = 1904193709124547126225055171380429984044969427702757019616077686519603583212249311116383727431445401398594522230612229733
p = 1532358535804235132496312416063170109053232217889240979567714057566239469579822887828122819499504563106464882747447051359
c = [813530482014456574209632986607111359200629085246367954186877618366451174001463654876753005264098,1054295430131833360658465071066491055652904289373961069213308535490435549697560050854110548843919,374976866832751055109605198170602358027434683548463528601734580123896818157824411065383601884240,
]PR.<x,y> = PolynomialRing(Zmod(p))
f = ((c[0]<<80)+ x) * a + b - ((c[1]<<80) + y)
roots = small_roots(f,(2^80, 2^80), m=4, d=4)
s1 = (c[0]<<80) + roots[0][0]
m = (s1 - b) * inverse_mod(a, p) % p
print(bytes.fromhex(hex(m)[2:]))
大学×高中√
题目:
from Crypto.Util.number import *
from enc import flagm = bytes_to_long(flag)
assert len(flag)==47
leak = cos(m).n(1000)
print(leak)
# 0.0998850707771875936255320441622758414273045504083276270807057373186889944319840434839754884311751169692981949171665523641780707944615961482956134641228858117430417240690757611709757603218395869292050704312456085723639395453639137813691195138264605914554001589394663177610703870989537946983548789434829
这道题思路也是构造格的形式
leak = cos(m).n(1000)
可以写成
m-arcos(leak)-2k π \pi π=0
其中arcos(leak)求的是一个周期(2 π \pi π)内的具体值
这样我们就构造出来了一个三维格
令x=arccos(leak)
如下所示
[ m − 1 2 ∗ k ] [ 1 0 1 0 1 x 0 0 π ] ⇒ [ m − 1 0 ] \begin{bmatrix} m&-1&2*k\\ \end{bmatrix} \begin{bmatrix} 1&0&1\\ 0&1&x\\ 0&0&\pi\\ \end{bmatrix} \Rightarrow \begin{bmatrix} m&-1&0\\ \end{bmatrix} [m−12∗k] 1000101xπ ⇒[m−10]
经过计算发现不满足hermite定理
#Hermite定理判断
#初次判断长度
#iroot函数参数只能是整数,这里用3代替pi,其实大小而言根本不影响
length1=gmpy2.iroot(3,2)[0]*gmpy2.iroot(3,3)[0]
print(length1.bit_length())//1length2=gmpy2.iroot(m**2+1,2)[0]
print(length2.bit_length())//377
我们只能给中间矩阵添加一些值
使目标矩阵的值小于行列式的值
正确的矩阵构造如下
[ m − 1 2 ∗ k ] [ 1 0 t ∗ 1 0 a t ∗ x 0 0 t ∗ π ] ⇒ [ m − a 0 ] \begin{bmatrix} m&-1&2*k\\ \end{bmatrix} \begin{bmatrix} 1&0&t*1\\ 0&a&t*x\\ 0&0&t*\pi\\ \end{bmatrix} \Rightarrow \begin{bmatrix} m&-a&0\\ \end{bmatrix} [m−12∗k] 1000a0t∗1t∗xt∗π ⇒[m−a0]
因为这里的m比特长度是478,所以将将a的长度也设置位478(如果不这样设置会导致目标向量各个维度长度不均衡,不容易规约出来结果),然后找到合适的t
下面是两个错误构造的情况:
一: [ m − 1 2 ∗ k ] [ 1 0 t ∗ 1 0 1 t ∗ x 0 0 t ∗ π ] ⇒ [ m − a 0 ] \begin{bmatrix} m&-1&2*k\\ \end{bmatrix} \begin{bmatrix} 1&0&t*1\\ 0&1&t*x\\ 0&0&t*\pi\\ \end{bmatrix} \Rightarrow \begin{bmatrix} m&-a&0\\ \end{bmatrix} [m−12∗k] 100010t∗1t∗xt∗π ⇒[m−a0]
二:
[ t m − 2 ∗ k ] [ t 0 − x 0 1 1 0 0 π ] ⇒ [ t m 0 ] \begin{bmatrix} t&m&-2*k\\ \end{bmatrix} \begin{bmatrix} t&0&-x\\ 0&1&1\\ 0&0&\pi\\ \end{bmatrix} \Rightarrow \begin{bmatrix} t&m&0\\ \end{bmatrix} [tm−2∗k] t00010−x1π ⇒[tm0]
下面是脚本代码
import gmpy2
from Crypto.Util.number import *#求出pi的小数点后1000位
RF = RealField(1000)
pi = RF(pi)m=2**(47*8)
leak=0.0998850707771875936255320441622758414273045504083276270807057373186889944319840434839754884311751169692981949171665523641780707944615961482956134641228858117430417240690757611709757603218395869292050704312456085723639395453639137813691195138264605914554001589394663177610703870989537946983548789434829
x=arccos(leak)#Hermite定理判断
#初次判断长度
#iroot函数参数只能是整数,这里用3代替pi,其实大小而言根本不影响
length1=gmpy2.iroot(3,2)[0]*gmpy2.iroot(3,3)[0]
print(length1.bit_length())length2=gmpy2.iroot(m**2+1,2)[0]
print(length2.bit_length())#添加常数再判断
#这样添加是为了让我们的目标向量数值变得均衡[m,a,0]
t=2**756
a=2**(47*8)
length1=gmpy2.iroot(3,2)[0]*gmpy2.iroot(t*3*a,3)[0]
print(length1.bit_length())length2=gmpy2.iroot(m**2+1+a**2,2)[0]
print(length2.bit_length())#m-arcos(leak)-2kpi=0
#格的形式
# [1,0,t*1 ]
# [m,-1,-2*k][0,a,t*x ]=[m,-a,0]
# [0,0,t*pi]#这种构造随着行列式的增大,目标向量也变大,而且目标向量始终大于行列式
#所以不行
# [t,0,-x]
# [t,m,-2*k] [0,1,1 ]=[t,m,0]
# [0,0,pi]#构造
Ge=Matrix(QQ,[[1,0,t],[0,a,t*x],[0,0,t*pi]])
m=Ge.LLL()[0][0]
m=abs(m)
print(long_to_bytes(int(m)))
Shamir
题目:
from Crypto.Util.number import getPrime,bytes_to_long
import random
from os import getenvBANNER = """__ __ _ _______ _____ _ _ \ \ / / | | |__ __| / ____| | (_) \ \ /\ / /__| | ___ ___ _ __ ___ ___ | | ___ | (___ | |__ __ _ _ __ ___ _ _ __ \ \/ \/ / _ \ |/ __/ _ \| '_ ` _ \ / _ \ | |/ _ \ \___ \| '_ \ / _` | '_ ` _ \| | '__|\ /\ / __/ | (_| (_) | | | | | | __/ | | (_) | ____) | | | | (_| | | | | | | | | \/ \/ \___|_|\___\___/|_| |_| |_|\___| |_|\___/ |_____/|_| |_|\__,_|_| |_| |_|_|_|
"""
print(BANNER)flag = getenv("GZCTF_FLAG","GZCTF_NOT_DEFINE")
m = bytes_to_long(flag.encode())
n = getPrime(1024)
coefficients = [m] + [random.randrange(1,n-1) for i in range(100)]
print(f"n = {n}")def f(x):sum = 0for i in range(len(coefficients)):sum += coefficients[i]*pow(x,i,n) % nsum %= nreturn sumwhile 1:x = int(input("Please Input x: "))if x == 0:print("Not Allowed!!!")exit()res = (x,f(x))print(res)
这里coefficients = [m] + [random.randrange(1,n-1) for i in range(100)]
是为了生成
f ( x ) = m + a 1 x + a 2 x 2 + ⋯ + a k − 1 x k − 1 f(x) = m + a_1 x + a_2 x^2 + \cdots + a_{k-1} x^{k-1} f(x)=m+a1x+a2x2+⋯+ak−1xk−1
其中包含100个系数 a 1 , a 2 . . . a n a_1,a_2...a_n a1,a2...an
f(x)是为了计算当输入x后的值
…
本人小菜,所以直接来分析脚本
from pwn import *
from Crypto.Util.number import *ip_address = ""
port =
sh = remote(ip,port)
sh.recvuntil(b"n = ")
n = int(sh.recvline().decode())
PT = []
for i in range(101):sh.sendlineafter(b"Please Input x:",str(i+1).encode())res = eval(sh.recvline().decode())PT.append(res)R.<x> = PolynomialRing(Zmod(n))
recover_f = R.lagrange_polynomial(PT)
m = recover_f(0)
flag = long_to_bytes(int(m))
print(flag)
首先是先远程连接,然后等到服务器输出‘n=’时停止
接收n的值
然后循环101次,从1开始,依次得到f(x),因为源码禁止从0开始(从0开始可以直接得到m)
下面采用拉格朗日插值法:
PT = [(1, f(1)), (2, f(2)), (3, f(3)), …, 101, f(101))]
R.lagrange_polynomial(PT) 返回一个多项式,该多项式在给定的点对 PT后可以恢复f(x)
(这里不讨论拉格朗日插值法实现的原理,感兴趣可以自行查找资料)
下面我们就可以令x=0来计算
m = recover_f(0)
Approximate_n
baby_lock
这两道题目有空再分析