""" Setting debug to true will display more informations about the lattice, the bounds, the vectors... """ debug = False
""" Setting strict to true will stop the algorithm (and return (-1, -1)) if we don't have a correct upperbound on the determinant. Note that this doesn't necesseraly mean that no solutions will be found since the theoretical upperbound is usualy far away from actual results. That is why you should probably use `strict = False` """ strict = False
""" This is experimental, but has provided remarkable results so far. It tries to reduce the lattice as much as it can while keeping its efficiency. I see no reason not to use this option, but if things don't work, you should try disabling it """ helpful_only = True dimension_min = 7# stop removing if lattice reaches that dimension
# display stats on helpful vectors defhelpful_vectors(BB, modulus): nothelpful = 0 for ii inrange(BB.dimensions()[0]): if BB[ii,ii] >= modulus: nothelpful += 1
# display matrix picture with 0 and X defmatrix_overview(BB, bound): for ii inrange(BB.dimensions()[0]): a = ('%02d ' % ii) for jj inrange(BB.dimensions()[1]): a += '0'if BB[ii,jj] == 0else'X' if BB.dimensions()[0] < 60: a += ' ' if BB[ii, ii] >= bound: a += '~' print(a)
# tries to remove unhelpful vectors # we start at current = n-1 (last vector) defremove_unhelpful(BB, monomials, bound, current): # end of our recursive function if current == -1or BB.dimensions()[0] <= dimension_min: return BB
# we start by checking from the end for ii inrange(current, -1, -1): # if it is unhelpful: if BB[ii, ii] >= bound: affected_vectors = 0 affected_vector_index = 0 # let's check if it affects other vectors for jj inrange(ii + 1, BB.dimensions()[0]): # if another vector is affected: # we increase the count if BB[jj, ii] != 0: affected_vectors += 1 affected_vector_index = jj
# level:0 # if no other vectors end up affected # we remove it if affected_vectors == 0: BB = BB.delete_columns([ii]) BB = BB.delete_rows([ii]) monomials.pop(ii) BB = remove_unhelpful(BB, monomials, bound, ii-1) return BB
# level:1 # if just one was affected we check # if it is affecting someone else elif affected_vectors == 1: affected_deeper = True for kk inrange(affected_vector_index + 1, BB.dimensions()[0]): # if it is affecting even one vector # we give up on this one if BB[kk, affected_vector_index] != 0: affected_deeper = False # remove both it if no other vector was affected and # this helpful vector is not helpful enough # compared to our unhelpful one if affected_deeper andabs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]): print("* removing unhelpful vectors", ii, "and", affected_vector_index) BB = BB.delete_columns([affected_vector_index, ii]) BB = BB.delete_rows([affected_vector_index, ii]) monomials.pop(affected_vector_index) monomials.pop(ii) BB = remove_unhelpful(BB, monomials, bound, ii-1) return BB # nothing happened return BB
""" Returns: * 0,0 if it fails * -1,-1 if `strict=true`, and determinant doesn't bound * x0,y0 the solutions of `pol` """ defboneh_durfee(pol, modulus, mm, tt, XX, YY): """ Boneh and Durfee revisited by Herrmann and May finds a solution if: * d < N^delta * |x| < e^delta * |y| < e^0.5 whenever delta < 1 - sqrt(2)/2 ~ 0.292 """
# x-shifts gg = [] for kk inrange(mm + 1): for ii inrange(mm - kk + 1): xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk gg.append(xshift) gg.sort()
# x-shifts list of monomials monomials = [] for polynomial in gg: for monomial in polynomial.monomials(): if monomial notin monomials: monomials.append(monomial) monomials.sort() # y-shifts (selected by Herrman and May) for jj inrange(1, tt + 1): for kk inrange(floor(mm/tt) * jj, mm + 1): yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk) yshift = Q(yshift).lift() gg.append(yshift) # substitution # y-shifts list of monomials for jj inrange(1, tt + 1): for kk inrange(floor(mm/tt) * jj, mm + 1): monomials.append(u^kk * y^jj)
# construct lattice B nn = len(monomials) BB = Matrix(ZZ, nn) for ii inrange(nn): BB[ii, 0] = gg[ii](0, 0, 0) for jj inrange(1, ii + 1): if monomials[jj] in gg[ii].monomials(): BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)
# Prototype to reduce the lattice if helpful_only: # automatically remove BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1) # reset dimension nn = BB.dimensions()[0] if nn == 0: print("failure") return0,0
# check if vectors are helpful if debug: helpful_vectors(BB, modulus^mm) # check if determinant is correctly bounded det = BB.det() bound = modulus^(mm*nn) if det >= bound: print("We do not have det < bound. Solutions might not be found.") print("Try with highers m and t.") if debug: diff = (log(det) - log(bound)) / log(2) print("size det(L) - size e^(m*n) = ", floor(diff)) if strict: return -1, -1
# display the lattice basis if debug: matrix_overview(BB, modulus^mm)
# LLL if debug: print("optimizing basis of the lattice via LLL, this can take a long time")
BB = BB.LLL()
if debug: print("LLL is done!")
# transform vector i & j -> polynomials 1 & 2 if debug: print("looking for independent vectors in the lattice") found_polynomials = False for pol1_idx inrange(nn - 1): for pol2_idx inrange(pol1_idx + 1, nn): # for i and j, create the two polynomials PR.<w,z> = PolynomialRing(ZZ) pol1 = pol2 = 0 for jj inrange(nn): pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY) pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY)
# are these good polynomials? if rr.is_zero() or rr.monomials() == [1]: continue else: print("found them, using vectors", pol1_idx, "and", pol2_idx) found_polynomials = True break if found_polynomials: break
ifnot found_polynomials: print("no independant vectors could be found. This should very rarely happen...") return0, 0 rr = rr(q, q)
# solutions soly = rr.roots()
iflen(soly) == 0: print("Your prediction (delta) is too small") return0, 0
soly = soly[0][0] ss = pol1(q, soly) solx = ss.roots()[0][0]
# return solx, soly
defexample(): ############################################ # How To Use This Script ##########################################
# # The problem to solve (edit the following values) #
# the modulus N=0xd231f2c194d3971821984dec9cf1ef58d538975f189045ef8a706f6165aab4929096f61a3eb7dd8021bf3fdc41fe3b3b0e4ecc579b4b5e7e035ffcc383436c9656533949881dca67c26d0e770e4bf62a09718dbabc2b40f2938f16327e347f187485aa48b044432e82f5371c08f6e0bbde46c713859aec715e2a2ca66574f3eb; e=0x5b5961921a49e3089262761e89629ab6dff2da1504a0e5eba1bb7b20d63c785a013fd6d9e021c01baf1b23830954d488041b92bca2fe2c92e3373dedd7e625da11275f6f18ee4aef336d0637505545f70f805902ddbacb21bb8276d34a0f6dfe37ede87dd95bb1494dbb5763639ba3984240f1178e32aa36ee3c5fcc8115dde5; c=0x6a88a8fa2b8f28d96284298bab2061efeb35e3a086370e19523c15c429f5d783b9d4f32e31a402916f45ad4f2760ab30e77177335af44756bfbeef0f168b5e0dc8c3ddf75d141c358969cca0e7c2b8ab99ef8e33b031be1cbccd95b687682ac7b0dcc0d56f5651ee671d6358128d2e0801f247a6af4fe0dc5e8fb199eba0780f;
# the hypothesis on the private exponent (the theoretical maximum is 0.292) delta = .278# this means that d < N^delta
# # Lattice (tweak those values) #
# you should tweak this (after a first run), (e.g. increment it until a solution is found) m = 11# size of the lattice (bigger the better/slower)
# you need to be a lattice master to tweak these t = int((1-2*delta) * m) # optimization from Herrmann and May X = 2*floor(N^delta) # this _might_ be too much Y = floor(N^(1/2)) # correct if p, q are ~ same size
# # Don't touch anything below #
# Problem put in equation P.<x,y> = PolynomialRing(ZZ) A = int((N+1)/2) pol = 1 + x * (A + y)
# # Find the solutions! #
# Checking bounds if debug: print("=== checking values ===") print("* delta:", delta) print("* delta < 0.292", delta < 0.292) print("* size of e:", int(log(e)/log(2))) print("* size of N:", int(log(N)/log(2))) print("* m:", m, ", t:", t)
# found a solution? if solx > 0: d = int(pol(solx, soly) / e) pplusq = int(soly*2) import gmpy2 pminusq = gmpy2.iroot(pplusq^2-4*N,2)[0] p = (pplusq + pminusq) // 2 q = N // p
print("d =", d) print("p =",p) print("q =",q) assert p*q == N m = pow(c,d,N) print(long_to_bytes(int(m))[::-1]) ## else: print("=== no solution was found ===")
if debug: print(("=== %s seconds ===" % (time.time() - start_time)))
if __name__ == "__main__": example()
#96884485470809436429011642866838703862114673941017100586009098363273491491514356269093 #Cryptography is typically bypassed,not penetrated.
import time from subprocess import check_output from multiprocessing import Pool
defflatter(M): # compile https://github.com/keeganryan/flatter and put it in $PATH z = "[[" + "]\n[".join(" ".join(map(str, row)) for row in M) + "]]" ret = check_output(["flatter"], input=z.encode()) from re import findall return matrix(M.nrows(), M.ncols(), map(int, findall(b"-?\\d+", ret)))
# 显示有用矢量的统计数据 defhelpful_vectors(BB, modulus): nothelpful = 0 for ii inrange(BB.dimensions()[0]): if BB[ii,ii] >= modulus: nothelpful += 1
print (nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")
# 显示带有 0 和 X 的矩阵 defmatrix_overview(BB, bound): for ii inrange(BB.dimensions()[0]): a = ('%02d ' % ii) for jj inrange(BB.dimensions()[1]): a += '0'if BB[ii,jj] == 0else'X' if BB.dimensions()[0] < 60: a += ' ' if BB[ii, ii] >= bound: a += '~' #print (a)
# x-移位 gg = [] for kk inrange(mm + 1): for ii inrange(mm - kk + 1): xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk gg.append(xshift) gg.sort()
# 单项式 x 移位列表 monomials = [] for polynomial in gg: for monomial in polynomial.monomials(): #对于多项式中的单项式。单项式(): if monomial notin monomials: # 如果单项不在单项中 monomials.append(monomial) monomials.sort() # y-移位 for jj inrange(1, tt + 1): for kk inrange(floor(mm/tt) * jj, mm + 1): yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk) yshift = Q(yshift).lift() gg.append(yshift) # substitution # 单项式 y 移位列表 for jj inrange(1, tt + 1): for kk inrange(floor(mm/tt) * jj, mm + 1): monomials.append(u^kk * y^jj)
# 构造格 B nn = len(monomials) BB = Matrix(ZZ, nn) for ii inrange(nn): BB[ii, 0] = gg[ii](0, 0, 0) for jj inrange(1, ii + 1): if monomials[jj] in gg[ii].monomials(): BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)
#约化格的原型 if helpful_only: # #自动删除 BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1) # 重置维度 nn = BB.dimensions()[0] if nn == 0: print ("failure") return0,0
# 检查向量是否有帮助 if debug: helpful_vectors(BB, modulus^mm) # 检查行列式是否正确界定 det = BB.det() bound = modulus^(mm*nn) if det >= bound: if debug: diff = (log(det) - log(bound)) / log(2) print ("size det(L) - size e^(m*n) = ", floor(diff)) if strict: return -1, -1 else: print ("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")
# display the lattice basis if debug: matrix_overview(BB, modulus^mm)
# LLL if debug: print ("optimizing basis of the lattice via LLL, this can take a long time")
#BB = BB.BKZ(block_size=25) BB = flatter(BB) if debug: print ("LLL is done!")
size=512#The size of p; size=1024 in Tables 10 length_N = 2*size s=19; #s is the number of MSBs exhaustion, which can be chosen as we need. nw=3#2^nw windows delta = 0.292
N = 0xf4c548636db62ffcc7ac4a0797952bea9a65bd426175af2435f72657e67ec8194667bfa94ce23c6f1e5baf3201867ab41701f6b8768e71009c41a3d5e9e7c109455341d549c7611f9f52851a2f017906aa9ccbedb95d238468e2c8577d30ecc4f158e3811fd5e2a6051443d468e3506bbc39bba710e34a604ac9e85d0feef8b3; e = 0x16f4b438ba14e05afa944f7da9904f8c78ea52e4ca0be7fa2b5f84e22ddd7b0578a3477b19b7bb4a7f825acc45da2dd10e62dbd94a3386b97d92ee817b0c66c1507514a7860b9139bc2ac3a4e0fe304199214da00a4ca82bfcb7b18253e7e6144828e584dac2dfb9a03fabaf2376ce7c269923fbb60fc68325b9f6443e1f896f; c = 0x26b1823cf836b226e2f5c90fdcd8420dbfcd02765b26e52ef3e5c0ab494c2f4650e475e280b0b5fff0d5016621186420b09e4706a5866e4a3319f23ef09d92c4e36acba39a0f6213fbe5ee1a736ce383e6e12351e6cbfd43f10a96b7fe34bdbaf948f2fb075d9063723c9f747fe6247ae9209e5d417faf2e37e6fee2eb863556; # The parameters (N, e) can be chosen as we need. m = 12# 格大小(越大越好/越慢) #guess=100 # you need to be a lattice master to tweak these t = round(((1-2*delta) * m)) # 来自 Herrmann 和 May 的优化 X = floor(N^delta) # Y = 2*floor(N^(1/2)/2^s) # 如果 p、 q 大小相同,则正确
p0=pM*2^(size-s)+2^(size-s-1); q0=N/p0; qM=int(q0/2^(size-s)) A = N + 1-pM*2^(size-s)-qM*2^(size-s); P.<x,y> = PolynomialRing(ZZ) pol = 1 + x * (A + y) #构建的方程 if debug: ##print ("=== running algorithm ===") start_time = time.time()
solx, soly = boneh_durfee(pol, e, m, t, X, Y)
if solx > 0: #print ("=== solution found ===") ifFalse: print ("x:", solx) print ("y:", soly)
from Crypto.Util.number import * from tqdm import * import itertools from multiprocessing import Pool
#coppersmith defsmall_roots(f, bounds, m=1, d=None): ifnot 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 inrange(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.coefficient_matrix() monomials = vector(monomials) factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor) B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, 1 / factor) H = Sequence([], f.parent().change_ring(QQ)) for h infilter(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 []
from Crypto.Util.number import * from tqdm import * import itertools from multiprocessing import Pool
#coppersmith defsmall_roots(f, bounds, m=1, d=None): ifnot 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 inrange(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.coefficient_matrix() monomials = vector(monomials) factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor) B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, 1 / factor) H = Sequence([], f.parent().change_ring(QQ)) for h infilter(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 []
r = int(1024*delta) N = 0x94e4c83c67c6d6e33d83cc2953df899e8c4b33894f653d5bbc84d7dd9058e6949221897f6e5b7b8bd9013f495c906862e401436e77be585474066f6c220751dd9b2b8be66f07ad7f090547a6e759e482ba263b941b32c27c62c4b558d96dda168b28c52e550b7d7ff145a5996c0b398714cf5ee8f0ea1a3d5b17c592f1c15275; e = 0x949b2e72766be1e83ee278a56bc86a2d3268b719507068ac62c6d249a810284edaac39335e8d699630887c13864f4cdf1c0c423b2f7ae88ccc60a827332e6c410800c7c7a1677918c28aa51086991d1290fc64b8e1b0f14b482f35d86139bb3491a59e2ad99dcd35bd129a44c3b8e2667e405dc2d307a5bb5a1504d7ded3bda3; c = 0x6fd6fae8ab4e95e622e5dad2921c6f12e911df08768abf2d10d212ad9a26e4c5ec71640d7a6b3488064fd424224bc2c762b956af95a3212de37a57d74c0299936f48ae3d8b8803e644e8d1306ab735c94fd815fe8c77982b32d51e9b6f3b3d4f3753810b61fb528c3e9eb774dabd93a3c5c9919ae3fb90e8e998ed3e7f949738; d2 = dl=0x6da211f0d34b
m = 7 tau = 6 theta = ["pad"] + [2,3,4,5,6,7]
#attack A = e*d2-1 W = e*2^r X = int(N^(alpha+beta-1)) Y = int(3*N^0.5) U = int(7*N^(alpha+beta-0.5))
PR.<x,y,u> = PolynomialRing(ZZ) x,y,u = PR.gens() f = -N*x + u f_ = u - (x*y + A)
poly = [] monomials=set()
#G for t inrange(0,m+1): for j inrange(0,t+1): G = x^(t-j) * f^j * W^(m-j)
#deal with xy for mono in G.monomials(): while(mono % (x*y) == 0): temp = G.monomial_coefficient(mono) G -= temp*mono mono //= (x*y) mono *= (u-A) G += temp*mono poly.append(G) for mono in G.monomials(): monomials.add(mono)
#P for i inrange(1,tau+1): for j inrange(theta[i],m+1): P = y^i * f^j * W^(m-j)
#deal with xy for mono in P.monomials(): while(mono % (x*y) == 0): temp = P.monomial_coefficient(mono) P -= temp*mono mono //= (x*y) mono *= (u-A) P += temp*mono poly.append(P) for mono in P.monomials(): monomials.add(mono)
L = Matrix(ZZ,len(poly),len(monomials))
monomials = sorted(monomials) for row,shift inenumerate(poly): for col,monomial inenumerate(monomials): L[row,col] = shift.monomial_coefficient(monomial)*monomial(X,Y,U)
print(L.dimensions())
res = L.LLL() vec1 = res[2] vec2 = res[1]
f1 = 0 for idx,monomial inenumerate(monomials): f1 += (vec1[idx] // monomial(X,Y,U)) * monomial f1 = f1.change_ring(ZZ) f2 = 0 for idx,monomial inenumerate(monomials): f2 += (vec2[idx] // monomial(X,Y,U)) * monomial f2 = f2.change_ring(ZZ)
#p+q-1 is: #[(20669116529972280868235472642422776201909637285884516155862888589837342513282316090088342096364702368094391219552254156670270390106105101130869387179628885, 1)]
import itertools from gmpy2 import * from Crypto.Util.number import *
defsmall_roots(f, bounds, m=1, d=None): ifnot 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 inrange(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 inenumerate(factors): B.rescale_col(i, factor) B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, 1 / factor) H = Sequence([], f.parent().change_ring(QQ)) for h infilter(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 = 0xaeb75bb97217271bf312a7897da81a544fe469ba0f1cf75304f2a5629717e1e3d0a9a28e71135443cc19f78c60dd3f7ea4ea28ae64657d5ac3b46e9755020de73cb5c4f89a682e0193916221bc8f4abb595f2c058bbb99e199a66144a9a9b258a74db847b2460107233280c94e854394595043f62bf77cd96c9ed3eca71b726d; e = 0x42b63e1113b4a84d0b037006a9bb729b52db495fa6b475bb64129a855a4ed6511792d0df946c5d7e22085d0db07bce5e408454a61c0cea51cf6d25e2455a2c6dc092e4b09bf4efb2157ffc1d1db3e969499479d721330ec4ac864e656318bc7bb9831a0dccf582406c87ae5d3ab9ffec351271dbb5481a0b6ed75a760b4f7e0d; c = 0xe1f90d9f115f9ba0b65ea8826ffec785bbe1b195fbb6f93c6ea28940f0d9b571930addb3e2714999ba5a19d17af22f1bc8da49f8b515ab03b6d276140b69fedf980d1aef78d0f3c0f6effdf2e92ce9195866f85672037537021178f8c65989b57f29de2c4c9306fe3e13aef29f962f86b8d5216907e85f28260b9f41cfe2651;
R.<x,y> = PolynomialRing(Zmod(e)) f = 1+x*(n+1-y) bounds = (2^268,2^513) res = small_roots(f,bounds,m=3,d=4)
pplusq = int(res[0][1]) pminusq = iroot(pplusq^2-4*n,2)[0] p = (pplusq + pminusq) // 2 q = n // p
from Crypto.Util.number import * from multiprocessing import Pool from subprocess import check_output import time
defflatter(M): # compile https://github.com/keeganryan/flatter and put it in $PATH z = "[[" + "]\n[".join(" ".join(map(str, row)) for row in M) + "]]" ret = check_output(["flatter"], input=z.encode()) from re import findall return matrix(M.nrows(), M.ncols(), map(int, findall(b"-?\\d+", ret)))
ebits = 512 n=0xf12eac2099c4190a6f586bea0b4fc3f9dff4f23f0cb8e42cbeff950aa1df8a373c49df7974fb33b4b6619eadb2d6c01f80da1b433295b199df11b323114c439884eb31fa568bd747ae37079e885e2490c3b5a56d61b9d10533983ff78fe85e07876fe2ae07ae7ea1c71f0f9c2d6beccdcd8baf046a58549aec19d45d48d7d92d e=0xb8906f5097658f27cc448d98974d9e7ccd4e8a8f25a80007826c341dcb2ac42420f899e5a89045fbefd9163bc94e6f98b4953546203be4bec249031587a27dbf c=0x162a6dee8bcbe24698b9249137c2a157890910fa74a56e7d2792b5b4f29112aba03448995ff32ed24bec5118f7433212196d3f99e1c794b61395d8183e4658c9dc05953a87c069c9390773c7f885907840ebd29676afac7bf3374d54c81c4e404f09716b9885d243c41dc48db561f8291b88826cae32bfd575a472e523f455c4 dl=0x4cbec287edc86c5b2a9e1975d64d2a24d3930075f0d445163c7b1ceec9ee0319fe1166af348b49004d2420b83bcb82d4879e93dba01ee76c5ca1b7141490465e824bdb5e91d04016c6bbbaa41c4470747ee8163f710b2d8adb8ab2168dcc996b5ab5f85a2269dc459379fb68848cec487 leak = 910 M = 2^leak alpha = ebits/1024 Y = int(n^alpha) Z = int(3*n^0.5)
with Pool(8) as pool: r = list(pool.imap(attack, ilist[::-1]))
#p+q-1 is: #26034831836893224902673168159369440840844528954669232434446445029015830075273876167180768873144179504296085932127304140645470361784554913695920045941531153
from Crypto.Util.number import * from tqdm import *
e = 65537 n = 0xcc5b706f373a79c680cec9527aac573fd435129cf16c23334085bf97832e5a6c78b633c2f244b12a62f87ec5295dd89fcf3c808c39e45a9afdbda2f8d2d0b50d61b685c0fe9eb41a7018a40f98892f96d738e2a4e740d4e507bcbd07f68c1ecb2ca10bd780ce65265a7e4da00f1031a5db9d038878a29a5ffefcaf2119720005 c = 0x20bac8a7d73a74c9913377846c13c3d2bd9f47e6df118d1486a96ed184ca9910e0f250500065cfb44105a41dff655364cabc3067ef3cd3d7d983e75c9303b786ac97507cfe803b788b12e582232028ca9772d05004aef194076ec442e3ee55e17fbb4a57f332b4393ac056c024141cc2b82f9dbc6d3c77f6eff20cd0ecc9cbab dl = 0x20142ae2802b877eb4dfa8a462e7d017c4d348181c367fd1a661ec9b6bbcca9dcb6601ccb6c10416b7f3c20129527346bbc136ee60f9945125cba03a9bba3720f7411
defattack(k): p = var('p') p0 = solve_mod([-k*p^2 + (k*(n+1)+1-e*dl)*p -k*n == 0], 2^530) if(len(p0) != 0): for j in p0: if(n % int(j[0]) == 0): print("Found p:" , int(j[0])) returnTrue
if(1): for k in trange(1,e): find = attack(k) if(find): break
k = 22348 p = 10846327614507406655792564994667714933899253952298425269758486277699020260863878841336945944423557227322075142932155647161674834513419649086027797728283207 q = n // p phi = (p-1)*(q-1) d = inverse(e,phi)
from Crypto.Util.number import * from gmpy2 import powmod
e = 65537 n = 0xcc5b706f373a79c680cec9527aac573fd435129cf16c23334085bf97832e5a6c78b633c2f244b12a62f87ec5295dd89fcf3c808c39e45a9afdbda2f8d2d0b50d61b685c0fe9eb41a7018a40f98892f96d738e2a4e740d4e507bcbd07f68c1ecb2ca10bd780ce65265a7e4da00f1031a5db9d038878a29a5ffefcaf2119720005 c = 0x20bac8a7d73a74c9913377846c13c3d2bd9f47e6df118d1486a96ed184ca9910e0f250500065cfb44105a41dff655364cabc3067ef3cd3d7d983e75c9303b786ac97507cfe803b788b12e582232028ca9772d05004aef194076ec442e3ee55e17fbb4a57f332b4393ac056c024141cc2b82f9dbc6d3c77f6eff20cd0ecc9cbab dl = 0x20142ae2802b877eb4dfa8a462e7d017c4d348181c367fd1a661ec9b6bbcca9dcb6601ccb6c10416b7f3c20129527346bbc136ee60f9945125cba03a9bba3720f7411 d = 48934776628725324382665082114299447937340082241799544768710753959849031360081579743041602050591310715229818997116081242616359194543184338502069650397869985126397078720094810145259742806152398430221459833419493737528368084683621557302194467494851616524101832395135547354509904758069472861546701396840400516113
for k inrange(1,e): dh = k*n // e d = (dh >> 530 << 530) + dl try: print(long_to_bytes(powmod(c,d,n)).decode()[::-1]) break except: pass
#Resolving the composite numbers into their prime factors is known to be one of the most important and useful in arithmetic.
e = 65537 n = 0x8d0df1ce526c39f9b057de462778a61ceda2049c7e32ee99d40baa4b22b7fd438e9ca1dfd7467684625add252095ee97c698199f4c5991279f6d3e74d4c14d01d137d42722df0d4565ff2a5275f9cac66dc4dfdf3304f85cbdc3d18eda1e32ac5d03675141a722ceefe0ea0533b53d7e50ed7eda1a1bbce47ed0ecb966f8678d c = 0x3b42fa3dc9089a21e9dabfe18297df47272f7e0ff59bf9bf16bc55e7fa70504c03fed56ca5ae93ac028f60ce5da3c145c6d181c5bd3c267288ec4765a19ca6b957b4535a1a185bd1b87d2e39b30e2430ed648175c29fdc1fde3787c426783dd66ba17f98b42ba13a7b3532970d0aa31b5ffa5f3eae243337a1668bae456bfbfb dl = 0x19ffe8024fcf0320b3107f380f2e7deff71d561c4266c0f439d1aca20cd43d2aa6aed8679a16b2e1d3ff4ba3fc4da69cf34e35ead6f7eb79923960b9c83d9923e591b07b65275bf67f0b3d424cd7e6e6dd88ea39a5cfa27ecee61caaacc93e751dbb2a4c196f0ce0c36d44c35d6658d71b6c48b7b29400ab9161a0000000000 dh = 0x19ffe8024fcf0320b3107f380f2e7deff71d561c4266c0f439d1aca20cd43d2aa6aed8679a16b2e1d3ff4ba3fc4da69cf34e35ead6f7eb79923960b9c83d9923e591b07b65275bf67f0b3d424cd7e6e6dd88ea39a5cfa27ecee61caaacc93e751dbb2a4c196f0ce0c36d44c35d6658d71b6c48b7b29400ab9161affffffffff
k = powmod(2,e,n) k20 = powmod(k,2**20,n) tmp = 1 l = {} for i in trange(1,2**20): tmp = tmp * k20 % n l[tmp] = i
ki = invert(int(k),n) tmp = 2*powmod(ki,dl,n)
for i in trange(2**20): tmp = tmp * ki % n if tmp in l.keys(): print(i,l[tmp])
from Crypto.Util.number import * from tqdm import * import itertools
defsmall_roots(f, bounds, m=1, d=None): ifnot d: d = f.degree()
R = f.base_ring() N = R.cardinality() k = ZZ(f.coefficients().pop(0)) g = gcd(k, N) k = R(k/g)
f *= 1/k f = f.change_ring(ZZ)
vars = f.variables() G = Sequence([], f.parent()) for k inrange(m): for i inrange(m-k+1): for subvars in itertools.combinations_with_replacement(vars[1:], i): g = f**k * prod(subvars) * N**(max(d-k, 0)) G.append(g)
factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor)
B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, Integer(1)/factor)
H = Sequence([], f.parent().change_ring(QQ)) for h infilter(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 []
e = 65537 n = 0xcb5645c59c402b0edcf96cbd6a7308b64aac2f37a3c6f96be7c421c4b7f0a4adbdecd88cbea1128352fb21baae583fe4ceb3fc93c4905803ad3e9214ada050d5c0ff785a13a5c9157c3154ad8d7015a2d239fe13ef836d3279c5cd5dc96013ac40f372a9c9226d2f5fe73f312c56e11d9cdfbf9fb0db627ac1a752f5f0bd2b29 c = 0x84e4aa0be481e9c4bbd4c71dba5235cccd8312759de35c326c7e4cdda494196d1c0cae298240942af3082fac215965999c908a79bf07e093ee0c402e727a09a1c1f13831875d66ebbc3f89507163de90339af055bcd7d778574775214accfbd8ae20001f27bc196b974cb3ac215fea3debb7b17a21a8ebb1a9880a671539ef21 a = 0x4f77b72b04e6fb2d02e5a43edef4784a2e22df0d42bfc7c9093a58ec35eb21a11962103be960b0088d0cc2e0dfb473bc2ba0a22cea1c73997442c8fab5e4bad22cd131055b0382eb9264ad40ec8257abaff11b33b173ffd0168039bf40dc203eb325d884d2845fd2b5a37f41a0f64183db0c256c244500000000000000000000 k = a*e//n+1 hbits = 80
#res[0][2] is an approximate of p+q-1 #[(2540, 23935042650629633992243477175701638513817665297585812420605495051321315935163840064093820856826734951317982015362656048928090686340260908156176320805788498)]
from Crypto.Util.number import * from tqdm import * import itertools
defsmall_roots(f, bounds, m=1, d=None): ifnot d: d = f.degree()
R = f.base_ring() N = R.cardinality() k = ZZ(f.coefficients().pop(0)) g = gcd(k, N) k = R(k/g)
f *= 1/k f = f.change_ring(ZZ)
vars = f.variables() G = Sequence([], f.parent()) for k inrange(m): for i inrange(m-k+1): for subvars in itertools.combinations_with_replacement(vars[1:], i): g = f**k * prod(subvars) * N**(max(d-k, 0)) G.append(g)
factors = [monomial(*bounds) for monomial in monomials] for i, factor inenumerate(factors): B.rescale_col(i, factor)
B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor inenumerate(factors): B.rescale_col(i, Integer(1)/factor)
H = Sequence([], f.parent().change_ring(QQ)) for h infilter(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 []
e = 65537 p = getPrime(512) q = getPrime(512) n = p*q phi = (p-1)*(q-1) d = inverse(e,phi) k = (e*d-1)//phi
res = small_roots(f,bounds,m=2,d=2) print(res) leak = int(res[0][1])
#part1 get leak2 PR.<x> = PolynomialRing(RealField(1000)) f = x*(leak-x) - n ph = int(f.roots()[0][0])
PR.<x> = PolynomialRing(Zmod(n)) f = ph + x res = f.small_roots(X=2^(hbits+6), beta=0.499,epsilon=0.02)[0] p = int(ph + res) q = n // p d = inverse(e,(p-1)*(q-1)) print("d =",d) print("p =",p) print("q =",q) assert p*q == n
from Crypto.Util.number import * from tqdm import * from itertools import * from multiprocessing import Pool
################################################ gen data e = 65537 N = 0x9fac422a93f6e486e3ddae088bb5f5d06dec183ab81290042a9c98c53352961a00db3e9def7adff842381a395cedf1d06294f0b63457133e4e44cabb7633c562dcbfffdffe541d66c46ddf6a28b686c478300bcf31945f2a6495f140e64f78fa5cd47d1885233f175f28e38f1bfc422a6853ca19a7dd47a291a9e7de78a67bf1 c = 0x35476c9d0e5ad9d364ea31d8f6628b92a4f6307b1fef754e49286bc7f53ea8cd013a7ebf2a21b2327af44498d267e19526c2051a02f22cca9cab567f7ceefe5003137e396c23742370e14ec2c6a90943ca848908e87420f560d34eae4635475effa867722276710c6f4b6cb9b295777d62f3f03c57603ac815072864aadbf041 m = 1 rho = 243 a = ["pad"] + [0x8199f8d487909988daf7d692ce8b1ffb4c37aa8010c8ca337ae4398c521383dc51007645cb6a1743c9b52ec5808e9e0e6f54d5fbb143cf81651240beab342dfb4622f073c4f8ab968dd5c8d4be3b7dd55c2cb9ef9c06294cd87e5fa29e38279c850f03687dc8c83c68104dca88e3a5c8559a01c040e7d5107e4a9f2385429f90]
defattack(ii): a = ["pad"] + [0x8199f8d487909988daf7d692ce8b1ffb4c37aa8010c8ca337ae4398c521383dc51007645cb6a1743c9b52ec5808e9e0e6f54d5fbb143cf81651240beab342dfb4622f073c4f8ab968dd5c8d4be3b7dd55c2cb9ef9c06294cd87e5fa29e38279c850f03687dc8c83c68104dca88e3a5c8559a01c040e7d5107e4a9f2385429f90 - 2^243*ii]
################################################ params t,k = 20,10 R = 2^rho indices = [] for i in product([i for i inrange(t+1)] , repeat=m): if(sum(list(i)) <= t): indices.append(["pad"] + list(i))
################################################ attack PR = ZZ[tuple(f"X{i}"for i inrange(m))] X = ["pad"] + list(PR.gens()) poly = [] monomials=set() for i in indices: f = 1 for ij inrange(1,len(i)): f *= (X[ij] - a[ij])^i[ij] l = max(k-sum(i[1:]),0) f *= N^l poly.append(f) for mono in f.monomials(): monomials.add(mono)
################################################# LLL and resultant to find roots L = Matrix(ZZ,len(poly),len(monomials)) monomials = sorted(monomials) for row,shift inenumerate(poly): for col,monomial inenumerate(monomials): L[row,col] = shift.monomial_coefficient(monomial)*monomial(*([R]*m))
res = L.LLL() vec1 = res[0]
h = 0 for idx,monomial inenumerate(monomials): h += (vec1[idx] // monomial(*([R]*m))) * monomial h = h.change_ring(ZZ) res1 = h.monic().roots()
if(res1 != []): print(ii,res1)
lists = [i for i inrange(2^13)] with Pool(64) as pool: r = list(pool.imap(attack, lists[::-1]))
''' 给出初始化的种子列表Lst,初始化的噪音列表PD ''' for k inrange(1,12): if k+1in f1: p = eval(f'p{k+1}') pp = bin(p)[2:] p0 = pp[3:12] tt = Possible_Construction_1(p0)
pd = [] for i inrange(502): if pp[i] != tt[i]: pd.append(i) Lst.append([int(i) for i in p0]) else: p = eval(f'p{k+1}') pp = bin(p)[2:] p_1,p_2 = pp[3:10],pp[10:14] tt = Possible_Construction_2(p_1,p_2) print(int(tt,2),k+1,p_1,p_2)
pd = [] for i inrange(502): if pp[i] != tt[i]: pd.append(i) Lst.append([int(i) for i in p_1+p_2]) Lf2st.append([int(i) for i in p_1+p_2]) PD.append(pd)
''' 对9bit区的种子矩阵进行修正,爆破11×11的完整种子矩阵 ''' defGet_4ll_Construction(Lst,seq): LLst = [] t = 0 for i inrange(1,12): if i+1in f1: LLst.append([Lst[i-1][0]]+seq[t*2:t*2+2]+Lst[i-1][1:]) t += 1 else: LLst.append(Lst[i-1])
return LLst
''' 解线性关系 ''' bl = 509 P = matrix(11,bl+1) index = 0 for i inrange(11): for j inrange(bl): if j in PD[i]: P[i,j] = 1 else: P[i,j] = 0
PC = [] for i in P.columns(): if i: PC.append(list(i)) PC = matrix(PC)
P[4,-8] = 1 P[4,-7] = 1 P[4,-6] = 1 P[6,-8] = 1
for _ in trange(2^12): ctrl = [0,0,1,1,1,0] seq = [int(i) for i inbin(_)[2:].zfill(12)] flag = 0 for i inrange(6): if1-ctrl[i] notin seq[2*i:2*i+2]: flag = 1 if flag == 1: continue
LLst = Get_4ll_Construction(Lst,seq)
LLst = matrix(GF(2),LLst).T
try: LLst.solve_left(PC) except: continue LLst = LLst.T print(P.nrows(),P.ncols(),LLst.nrows(),[int(i) for i inbin(_)[2:].zfill(12)]) C = LLst.solve_right(P) print(LLst) #C:解矩阵,用种子向量与之相乘就能够得到噪音向量
''' for i,j in zip(Lst,LLst.T): print(j,'1' if len(i) == 9 else '2') print(i) ''' for i inrange(11): a = (matrix(LLst[i])*C)[0] a = ''.join([str(i) for i inlist(a)]) t = [] for j inrange(502): if a[j] == '1': t.append(j) #print(t) #print(PD[i]) seed = ''.join([str(j) for j inlist(LLst[i])]) if seed[1:4] notin ['111' , '000']: p = Possible_Construction_1(seed[0:1]+seed[3:11]) else: p = Possible_Construction_2(seed[0:7],seed[7:11]) #print(seed[0:7],seed[7:11])
p = int(p,2) p ^^= int(a.ljust(512,'0'),2) #print((seed[1:4] not in ['111' , '000']) , (i+2 in f1),seed,i+2,seed[1:4]) #print(p) #print(eval(f'p{i+2}')) print(eval(f'p{i+2}')-p,next_prime(p) == eval(f'p{i+2}')) print(ans) break