#!/usr/bin/env python3 # -*- coding:utf-8 -*- # sage -python solve.py # This file was *autogenerated* from the file rsaQuarterRecovery.sage from sage.all_cmdline import * # import sage library _sage_const_3 = Integer(3); _sage_const_2 = Integer(2); _sage_const_1 = Integer(1); _sage_const_0 = Integer(0); _sage_const_7 = Integer(7); _sage_const_4 = Integer(4); _sage_const_1024 = Integer(1024); _sage_const_200 = Integer(200); _sage_const_0p5 = RealNumber('0.5') import time, sys debug = False def ntos(x): n = hex(x)[2:].rstrip("L") if len(n)%2 != 0: n = "0"+n return n.decode("hex") # display matrix picture with 0 and X def matrix_overview(BB, bound): for ii in range(BB.dimensions()[_sage_const_0 ]): a = ('%02d ' % ii) for jj in range(BB.dimensions()[_sage_const_1 ]): a += '0' if BB[ii,jj] == _sage_const_0 else 'X' a += ' ' if BB[ii, ii] >= bound: a += '~' print a def coppersmith_howgrave_univariate(pol, modulus, beta, mm, tt, XX): """ Coppersmith revisited by Howgrave-Graham finds a solution if: * b|modulus, b >= modulus^beta , 0 < beta <= 1 * |x| < XX """ # # init # dd = pol.degree() nn = dd * mm + tt # # checks # if not _sage_const_0 < beta <= _sage_const_1 : raise ValueError("beta should belongs in (0, 1]") if not pol.is_monic(): raise ArithmeticError("Polynomial must be monic.") # # calculate bounds and display them # """ * we want to find g(x) such that ||g(xX)|| <= b^m / sqrt(n) * we know LLL will give us a short vector v such that: ||v|| <= 2^((n - 1)/4) * det(L)^(1/n) * we will use that vector as a coefficient vector for our g(x) * so we want to satisfy: 2^((n - 1)/4) * det(L)^(1/n) < N^(beta*m) / sqrt(n) so we can obtain ||v|| < N^(beta*m) / sqrt(n) <= b^m / sqrt(n) (it's important to use N because we might not know b) """ if debug: # t optimized? print "\n# Optimized t?\n" print "we want X^(n-1) < N^(beta*m) so that each vector is helpful" cond1 = RR(XX**(nn-_sage_const_1 )) print "* X^(n-1) = ", cond1 cond2 = pow(modulus, beta*mm) print "* N^(beta*m) = ", cond2 print "* X^(n-1) < N^(beta*m) \n-> GOOD" if cond1 < cond2 else "* X^(n-1) >= N^(beta*m) \n-> NOT GOOD" # bound for X print "\n# X bound respected?\n" print "we want X <= N^(((2*beta*m)/(n-1)) - ((delta*m*(m+1))/(n*(n-1)))) / 2 = M" print "* X =", XX cond2 = RR(modulus**(((_sage_const_2 *beta*mm)/(nn-_sage_const_1 )) - ((dd*mm*(mm+_sage_const_1 ))/(nn*(nn-_sage_const_1 )))) / _sage_const_2 ) print "* M =", cond2 print "* X <= M \n-> GOOD" if XX <= cond2 else "* X > M \n-> NOT GOOD" # solution possible? print "\n# Solutions possible?\n" detL = RR(modulus**(dd * mm * (mm + _sage_const_1 ) / _sage_const_2 ) * XX**(nn * (nn - _sage_const_1 ) / _sage_const_2 )) print "we can find a solution if 2^((n - 1)/4) * det(L)^(1/n) < N^(beta*m) / sqrt(n)" cond1 = RR(_sage_const_2 **((nn - _sage_const_1 )/_sage_const_4 ) * detL**(_sage_const_1 /nn)) print "* 2^((n - 1)/4) * det(L)^(1/n) = ", cond1 cond2 = RR(modulus**(beta*mm) / sqrt(nn)) print "* N^(beta*m) / sqrt(n) = ", cond2 print "* 2^((n - 1)/4) * det(L)^(1/n) < N^(beta*m) / sqrt(n) \n-> SOLUTION WILL BE FOUND" if cond1 < cond2 else "* 2^((n - 1)/4) * det(L)^(1/n) >= N^(beta*m) / sqroot(n) \n-> NO SOLUTIONS MIGHT BE FOUND (but we never know)" # warning about X print "\n# Note that no solutions will be found _for sure_ if you don't respect:\n* |root| < X \n* b >= modulus^beta\n" # # Coppersmith revisited algo for univariate # # change ring of pol and x polZ = pol.change_ring(ZZ) x = polZ.parent().gen() # compute polynomials gg = [] for ii in range(mm): for jj in range(dd): gg.append((x * XX)**jj * modulus**(mm - ii) * polZ(x * XX)**ii) for ii in range(tt): gg.append((x * XX)**ii * polZ(x * XX)**mm) # construct lattice B BB = Matrix(ZZ, nn) for ii in range(nn): for jj in range(ii+_sage_const_1 ): BB[ii, jj] = gg[ii][jj] # display basis matrix if debug: matrix_overview(BB, modulus**mm) # LLL BB = BB.LLL() # transform shortest vector in polynomial new_pol = _sage_const_0 for ii in range(nn): new_pol += x**ii * BB[_sage_const_0 , ii] / XX**ii # factor polynomial potential_roots = new_pol.roots() # print "potential roots:", potential_roots # test roots roots = [] for root in potential_roots: if root[_sage_const_0 ].is_integer(): result = polZ(ZZ(root[_sage_const_0 ])) if gcd(modulus, result) >= modulus**beta: roots.append(ZZ(root[_sage_const_0 ])) # return roots if __name__ == "__main__": # when partially know p or q N = Integer(21475596280939174139431514855487916848280293757877221629494000423065740039343165568040911365501931709899474457901218636286613252968091838444984682784515413643636881148238753087604560665820935690301341977536386047275665017274334379698691769474381442859960487730730928509631882014534379721535881772034345790413578890481396738792233363159809423111473169292217241145616333232083518177326358298078048628120127179798565879267980968193362945481320953732076711233595860392612661434058587237963218791159823174473621469045407472255263769629994834663464420068453008215132214063751047917187048914808372378795396554061907744836817) e = 65537 c = 20754532737949147742223373902498179634482610091973401913965157562215452429498008912598985786021744450617885408505714822236352995311810091314580467491358612250746471365079581324215426926430950841351364153354904788124987738423489564283310714390723281967378568516974010529197725382065316878282378564285294967866976464084855095285979327325380990150508854537668589744102474681630473341864971730762504436287798866508217036746708084200623440756971882983470032827345378642632637403720063632023394983904708937936062655036947907107788458010769639935212088808550212043364417102917046970788178629455261301698308788491373995670906 qbar = Integer(136032115030209730841795989556533149289798564864039724005919755642131398781579565419215111294655920896216631707218214703673379732583990633646915047476669276370539105011413159892850208470199569891528387660241874080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) length_N = len(N.digits(2)) F = PolynomialRing(Zmod(N), implementation='NTL', names=('x',)); (x,) = F._first_ngens(1); pol = x + qbar dd = pol.degree() # PLAY WITH THOSE: beta = RealNumber('0.4') # we should have q >= N^beta epsilon = beta / _sage_const_7 # <= beta/7 mm = ceil(beta**_sage_const_2 / (dd * epsilon)) # optimized tt = floor(dd * mm * ((_sage_const_1 /beta) - _sage_const_1 )) # optimized XX = ceil(N**((beta**_sage_const_2 /dd) - epsilon)) # we should have |diff| < X # Coppersmith start_time = time.time() roots = coppersmith_howgrave_univariate(pol, N, beta, mm, tt, XX) # output if len(roots) >= 1: r = roots[0] q = qbar + int(r) p = N/q o = (p-1)*(q-1) d = inverse_mod(e,o) print ntos(int(pow(c,d,N)))