daredevil1729

Untitled

Jun 12th, 2020
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.15 KB | None | 0 0
  1. import time
  2.  
  3. ############################################
  4. # Config
  5. ##########################################
  6.  
  7. """
  8. Setting debug to true will display more informations
  9. about the lattice, the bounds, the vectors...
  10. """
  11. debug = True
  12.  
  13. """
  14. Setting strict to true will stop the algorithm (and
  15. return (-1, -1)) if we don't have a correct
  16. upperbound on the determinant. Note that this
  17. doesn't necesseraly mean that no solutions
  18. will be found since the theoretical upperbound is
  19. usualy far away from actual results. That is why
  20. you should probably use `strict = False`
  21. """
  22. strict = False
  23.  
  24. """
  25. This is experimental, but has provided remarkable results
  26. so far. It tries to reduce the lattice as much as it can
  27. while keeping its efficiency. I see no reason not to use
  28. this option, but if things don't work, you should try
  29. disabling it
  30. """
  31. helpful_only = True
  32. dimension_min = 7 # stop removing if lattice reaches that dimension
  33.  
  34. ############################################
  35. # Functions
  36. ##########################################
  37.  
  38. # display stats on helpful vectors
  39. def helpful_vectors(BB, modulus):
  40.     nothelpful = 0
  41.     for ii in range(BB.dimensions()[0]):
  42.         if BB[ii,ii] >= modulus:
  43.             nothelpful += 1
  44.  
  45.     print(nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")
  46.  
  47. # display matrix picture with 0 and X
  48. def matrix_overview(BB, bound):
  49.     for ii in range(BB.dimensions()[0]):
  50.         a = ('%02d ' % ii)
  51.         for jj in range(BB.dimensions()[1]):
  52.             a += '0' if BB[ii,jj] == 0 else 'X'
  53.             if BB.dimensions()[0] < 60:
  54.                 a += ' '
  55.         if BB[ii, ii] >= bound:
  56.             a += '~'
  57.         print(a)
  58.  
  59. # tries to remove unhelpful vectors
  60. # we start at current = n-1 (last vector)
  61. def remove_unhelpful(BB, monomials, bound, current):
  62.     # end of our recursive function
  63.     if current == -1 or BB.dimensions()[0] <= dimension_min:
  64.         return BB
  65.  
  66.     # we start by checking from the end
  67.     for ii in range(current, -1, -1):
  68.         # if it is unhelpful:
  69.         if BB[ii, ii] >= bound:
  70.             affected_vectors = 0
  71.             affected_vector_index = 0
  72.             # let's check if it affects other vectors
  73.             for jj in range(ii + 1, BB.dimensions()[0]):
  74.                 # if another vector is affected:
  75.                 # we increase the count
  76.                 if BB[jj, ii] != 0:
  77.                     affected_vectors += 1
  78.                     affected_vector_index = jj
  79.  
  80.             # level:0
  81.             # if no other vectors end up affected
  82.             # we remove it
  83.             if affected_vectors == 0:
  84.                 print("* removing unhelpful vector", ii)
  85.                 BB = BB.delete_columns([ii])
  86.                 BB = BB.delete_rows([ii])
  87.                 monomials.pop(ii)
  88.                 BB = remove_unhelpful(BB, monomials, bound, ii-1)
  89.                 return BB
  90.  
  91.             # level:1
  92.             # if just one was affected we check
  93.             # if it is affecting someone else
  94.             elif affected_vectors == 1:
  95.                 affected_deeper = True
  96.                 for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
  97.                     # if it is affecting even one vector
  98.                     # we give up on this one
  99.                     if BB[kk, affected_vector_index] != 0:
  100.                         affected_deeper = False
  101.                 # remove both it if no other vector was affected and
  102.                 # this helpful vector is not helpful enough
  103.                 # compared to our unhelpful one
  104.                 if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]):
  105.                     print("* removing unhelpful vectors", ii, "and", affected_vector_index)
  106.                     BB = BB.delete_columns([affected_vector_index, ii])
  107.                     BB = BB.delete_rows([affected_vector_index, ii])
  108.                     monomials.pop(affected_vector_index)
  109.                     monomials.pop(ii)
  110.                     BB = remove_unhelpful(BB, monomials, bound, ii-1)
  111.                     return BB
  112.     # nothing happened
  113.     return BB
  114.  
  115. """
  116. Returns:
  117. * 0,0   if it fails
  118. * -1,-1 if `strict=true`, and determinant doesn't bound
  119. * x0,y0 the solutions of `pol`
  120. """
  121. def boneh_durfee(pol, modulus, mm, tt, XX, YY):
  122.     """
  123.    Boneh and Durfee revisited by Herrmann and May
  124.    
  125.    finds a solution if:
  126.    * d < N^delta
  127.    * |x| < e^delta
  128.    * |y| < e^0.5
  129.    whenever delta < 1 - sqrt(2)/2 ~ 0.292
  130.    """
  131.  
  132.     # substitution (Herrman and May)
  133.     PR.<u, x, y> = PolynomialRing(ZZ)
  134.     Q = PR.quotient(x*y + 1 - u) # u = xy + 1
  135.     polZ = Q(pol).lift()
  136.  
  137.     UU = XX*YY + 1
  138.  
  139.     # x-shifts
  140.     gg = []
  141.     for kk in range(mm + 1):
  142.         for ii in range(mm - kk + 1):
  143.             xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk
  144.             gg.append(xshift)
  145.     gg.sort()
  146.  
  147.     # x-shifts list of monomials
  148.     monomials = []
  149.     for polynomial in gg:
  150.         for monomial in polynomial.monomials():
  151.             if monomial not in monomials:
  152.                 monomials.append(monomial)
  153.     monomials.sort()
  154.    
  155.     # y-shifts (selected by Herrman and May)
  156.     for jj in range(1, tt + 1):
  157.         for kk in range(floor(mm/tt) * jj, mm + 1):
  158.             yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk)
  159.             yshift = Q(yshift).lift()
  160.             gg.append(yshift) # substitution
  161.    
  162.     # y-shifts list of monomials
  163.     for jj in range(1, tt + 1):
  164.         for kk in range(floor(mm/tt) * jj, mm + 1):
  165.             monomials.append(u^kk * y^jj)
  166.  
  167.     # construct lattice B
  168.     nn = len(monomials)
  169.     BB = Matrix(ZZ, nn)
  170.     for ii in range(nn):
  171.         BB[ii, 0] = gg[ii](0, 0, 0)
  172.         for jj in range(1, ii + 1):
  173.             if monomials[jj] in gg[ii].monomials():
  174.                 BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)
  175.  
  176.     # Prototype to reduce the lattice
  177.     if helpful_only:
  178.         # automatically remove
  179.         BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1)
  180.         # reset dimension
  181.         nn = BB.dimensions()[0]
  182.         if nn == 0:
  183.             print("failure")
  184.             return 0,0
  185.  
  186.     # check if vectors are helpful
  187.     if debug:
  188.         helpful_vectors(BB, modulus^mm)
  189.    
  190.     # check if determinant is correctly bounded
  191.     det = BB.det()
  192.     bound = modulus^(mm*nn)
  193.     if det >= bound:
  194.         print("We do not have det < bound. Solutions might not be found.")
  195.         print("Try with highers m and t.")
  196.         if debug:
  197.             diff = (log(det) - log(bound)) / log(2)
  198.             print("size det(L) - size e^(m*n) = ", floor(diff))
  199.         if strict:
  200.             return -1, -1
  201.     else:
  202.         print("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")
  203.  
  204.     # display the lattice basis
  205.     if debug:
  206.         matrix_overview(BB, modulus^mm)
  207.  
  208.     # LLL
  209.     if debug:
  210.         print("optimizing basis of the lattice via LLL, this can take a long time")
  211.  
  212.     BB = BB.LLL()
  213.  
  214.     if debug:
  215.         print("LLL is done!")
  216.  
  217.     # transform vector i & j -> polynomials 1 & 2
  218.     if debug:
  219.         print("looking for independent vectors in the lattice")
  220.     found_polynomials = False
  221.    
  222.     for pol1_idx in range(nn - 1):
  223.         for pol2_idx in range(pol1_idx + 1, nn):
  224.             # for i and j, create the two polynomials
  225.             PR.<w,z> = PolynomialRing(ZZ)
  226.             pol1 = pol2 = 0
  227.             for jj in range(nn):
  228.                 pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY)
  229.                 pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY)
  230.  
  231.             # resultant
  232.             PR.<q> = PolynomialRing(ZZ)
  233.             rr = pol1.resultant(pol2)
  234.  
  235.             # are these good polynomials?
  236.             if rr.is_zero() or rr.monomials() == [1]:
  237.                 continue
  238.             else:
  239.                 print("found them, using vectors", pol1_idx, "and", pol2_idx)
  240.                 found_polynomials = True
  241.                 break
  242.         if found_polynomials:
  243.             break
  244.  
  245.     if not found_polynomials:
  246.         print("no independant vectors could be found. This should very rarely happen...")
  247.         return 0, 0
  248.    
  249.     rr = rr(q, q)
  250.  
  251.     # solutions
  252.     soly = rr.roots()
  253.  
  254.     if len(soly) == 0:
  255.         print("Your prediction (delta) is too small")
  256.         return 0, 0
  257.  
  258.     soly = soly[0][0]
  259.     ss = pol1(q, soly)
  260.     solx = ss.roots()[0][0]
  261.  
  262.     #
  263.     return solx, soly
  264.  
  265. def example():
  266.     ############################################
  267.     # How To Use This Script
  268.     ##########################################
  269.  
  270.     #
  271.     # The problem to solve (edit the following values)
  272.     #
  273.  
  274.     # the modulus
  275.     # N = 0xc2fd2913bae61f845ac94e4ee1bb10d8531dda830d31bb221dac5f179a8f883f15046d7aa179aff848db2734b8f88cc73d09f35c445c74ee35b01a96eb7b0a6ad9cb9ccd6c02c3f8c55ecabb55501bb2c318a38cac2db69d510e152756054aaed064ac2a454e46d9b3b755b67b46906fbff8dd9aeca6755909333f5f81bf74db
  276.     N = 91043118409828550796773745518585981151180206101005135117565865602978722878478494447048783557571813980525643725323377488249838860897784683927029906188947001149632101513367258267329961684034661252866484981926055087386190015432964608927947646476193251820354738640453947833718397360834701566765504916472450194494897616371452996381159817427887623703639133290358520498419049175941584678802701606995099241245926884172985004839801270005583030514286561971825047719421487004569752638468907609110285739083279629747310953086535889932550905065172805818862336335628248528993024112446002398466115161473573451161053837400091893285717
  277.  
  278.     # the public exponent
  279.     # e = 0x19441f679c9609f2484eb9b2658d7138252b847b2ed8ad182be7976ed57a3e441af14897ce041f3e07916445b88181c22f510150584eee4b0f776a5a487a4472a99f2ddc95efdd2b380ab4480533808b8c92e63ace57fb42bac8315fa487d03bec86d854314bc2ec4f99b192bb98710be151599d60f224114f6b33f47e357517
  280.     e = 156749047558583013960513267351769479915110440411448078412590565797031533622509813352093119636835511977253033854388466854142753776146092587825440445182008237325262012698034419137157047927918635897378973846177552961727126115560551970797370239385129543828686170774323306933202481728884019420422360360849592983818405154473369790181636472137741865440233383956571081122982223602667853668754338360008279002325576495573847568301584365514417593244726435632222027817410359417329310347952169273512510934251453361933794586716533950489973436393834189505450956622286216819440777162804798432330933357058175885674184582816364542591313
  281.  
  282.     # the hypothesis on the private exponent (the theoretical maximum is 0.292)
  283.     delta = .18 # this means that d < N^delta
  284.  
  285.     #
  286.     # Lattice (tweak those values)
  287.     #
  288.  
  289.     # you should tweak this (after a first run), (e.g. increment it until a solution is found)
  290.     m = 4 # size of the lattice (bigger the better/slower)
  291.  
  292.     # you need to be a lattice master to tweak these
  293.     t = int((1-2*delta) * m)  # optimization from Herrmann and May
  294.     X = 2*floor(N^delta)  # this _might_ be too much
  295.     Y = floor(N^(1/2))    # correct if p, q are ~ same size
  296.  
  297.     #
  298.     # Don't touch anything below
  299.     #
  300.  
  301.     # Problem put in equation
  302.     P.<x,y> = PolynomialRing(ZZ)
  303.     A = int((N+1)/2)
  304.     pol = 1 + x * (A + y)
  305.  
  306.     #
  307.     # Find the solutions!
  308.     #
  309.  
  310.     # Checking bounds
  311.     if debug:
  312.         print("=== checking values ===")
  313.         print("* delta:", delta)
  314.         print("* delta < 0.292", delta < 0.292)
  315.         print("* size of e:", int(log(e)/log(2)))
  316.         print("* size of N:", int(log(N)/log(2)))
  317.         print("* m:", m, ", t:", t)
  318.  
  319.     # boneh_durfee
  320.     if debug:
  321.         print("=== running algorithm ===")
  322.         start_time = time.time()
  323.  
  324.     solx, soly = boneh_durfee(pol, e, m, t, X, Y)
  325.  
  326.     # found a solution?
  327.     if solx > 0:
  328.         print("=== solution found ===")
  329.         if False:
  330.             print "x:", solx
  331.             print "y:", soly
  332.  
  333.         d = int(pol(solx, soly) / e)
  334.         print("private key found:", d)
  335.     else:
  336.         print("=== no solution was found ===")
  337.  
  338.     if debug:
  339.         print("=== %s seconds ===" % (time.time() - start_time))
  340.  
  341. if __name__ == "__main__":
  342.     example()
Add Comment
Please, Sign In to add comment