Advertisement
Guest User

Untitled

a guest
Oct 22nd, 2019
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.10 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 solve(N,e):
  266.     delta = .292
  267.     m = 4
  268.     t = int((1-2*delta) * m)  # optimization from Herrmann and May
  269.     X = 2*floor(N^delta)  # this _might_ be too much
  270.     Y = floor(N^(1/2))    # correct if p, q are ~ same size
  271.  
  272.     #
  273.     # Don't touch anything below
  274.     #
  275.  
  276.     # Problem put in equation
  277.     P.<x,y> = PolynomialRing(ZZ)
  278.     A = int((N+1)/2)
  279.     pol = 1 + x * (A + y)
  280.     solx, soly = boneh_durfee(pol, e, m, t, X, Y)
  281.  
  282.     # found a solution?
  283.     if solx > 0:
  284.         d = int(pol(solx, soly) / e)
  285.         return d
  286.     else:
  287.         return -1
  288.  
  289. if __name__ == "__main__":
  290.     #chiamare solve sulle coppie (N,e)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement