1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
| import time debug = True strict = False helpful_only = True dimension_min = 7 def helpful_vectors(BB, modulus): nothelpful = 0 for ii in range(BB.dimensions()[0]): if BB[ii,ii] >= modulus: nothelpful += 1 print( nothelpful, "/", BB.dimensions()[0], " vectors are not helpful") def matrix_overview(BB, bound): for ii in range(BB.dimensions()[0]): a = ('%02d ' % ii) for jj in range(BB.dimensions()[1]): a += '0' if BB[ii,jj] == 0 else 'X' if BB.dimensions()[0] < 60: a += ' ' if BB[ii, ii] >= bound: a += '~' print( a) def remove_unhelpful(BB, monomials, bound, current): if current == -1 or BB.dimensions()[0] <= dimension_min: return BB for ii in range(current, -1, -1): if BB[ii, ii] >= bound: affected_vectors = 0 affected_vector_index = 0 for jj in range(ii + 1, BB.dimensions()[0]): if BB[jj, ii] != 0: affected_vectors += 1 affected_vector_index = jj if affected_vectors == 0: print( "* removing unhelpful vector", ii) BB = BB.delete_columns([ii]) BB = BB.delete_rows([ii]) monomials.pop(ii) BB = remove_unhelpful(BB, monomials, bound, ii-1) return BB elif affected_vectors == 1: affected_deeper = True for kk in range(affected_vector_index + 1, BB.dimensions()[0]): if BB[kk, affected_vector_index] != 0: affected_deeper = False if affected_deeper and abs(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 return BB def boneh_durfee(pol, modulus, mm, tt, XX, YY): PR.<u, x, y> = PolynomialRing(ZZ) Q = PR.quotient(x*y + 1 - u) polZ = Q(pol).lift()
UU = XX*YY + 1
gg = [] for kk in range(mm + 1): for ii in range(mm - kk + 1): xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk gg.append(xshift) gg.sort()
monomials = [] for polynomial in gg: for monomial in polynomial.monomials(): if monomial not in monomials: monomials.append(monomial) monomials.sort() for jj in range(1, tt + 1): for kk in range(floor(mm/tt) * jj, mm + 1): yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk) yshift = Q(yshift).lift() gg.append(yshift) for jj in range(1, tt + 1): for kk in range(floor(mm/tt) * jj, mm + 1): monomials.append(u^kk * y^jj)
nn = len(monomials) BB = Matrix(ZZ, nn) for ii in range(nn): BB[ii, 0] = gg[ii](0, 0, 0) for jj in range(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") return 0,0 if debug: helpful_vectors(BB, modulus^mm) 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 else: print( "det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)") if debug: matrix_overview(BB, modulus^mm) 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!") if debug: print( "looking for independent vectors in the lattice") found_polynomials = False for pol1_idx in range(nn - 1): for pol2_idx in range(pol1_idx + 1, nn): PR.<w,z> = PolynomialRing(ZZ) pol1 = pol2 = 0 for jj in range(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) PR.<q> = PolynomialRing(ZZ) rr = pol1.resultant(pol2) 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 if not found_polynomials: print( "no independant vectors could be found. This should very rarely happen...") return 0, 0 rr = rr(q, q) soly = rr.roots() if len(soly) == 0: print( "Your prediction (delta) is too small") return 0, 0 soly = soly[0][0] ss = pol1(q, soly) solx = ss.roots()[0][0] return solx, soly def example(): N = e = c = delta = .291 m = 4
t = int((1-2*delta) * m) X = 2*floor(N^delta) Y = floor(N^(1/2)) P.<x,y> = PolynomialRing(ZZ) A = int((N+1)/2) pol = 1 + x * (A + y) 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)
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 ===") if False: print( "x:", solx) print( "y:", soly)
d = int(pol(solx, soly) / e) m = pow(c,d,N) print( '[-]d is ' + str(d)) print( '[-]m is: ' + str(m)) print( '[-]hex(m) is: ' + '{:x}'.format(int(m))) else: print( "[!]no solution was found!") print( '[!]All Done!')
if debug: print(("[!]Timer: %s s" % (time.time() - start_time))) print( '[!]All Done!')
if __name__ == "__main__": example()
|