def close_factor(self, n, b, progress=True): # approximate phi phi_approx = n - 2 * isqrt(n) + 1 # create a look-up table look_up = {} z = 1 for i in tqdm(range(0, b + 1), disable=(not progress)): look_up[z] = i z = (z * 2) % n # check the table mu = invmod(powmod(2, phi_approx, n), n) fac = powmod(2, b, n) for i in tqdm(range(0, b + 1), disable=(not progress)): if mu in look_up: phi = phi_approx + (look_up[mu] - i * b) break mu = (mu * fac) % n else: return None m = n - phi + 1 roots = ((m - isqrt(m**2 - 4 * n)) >> 1, (m + isqrt(m**2 - 4 * n)) >> 1) if roots[0] * roots[1] == n: return roots
def euler(self, n): if n & 1 == 0: return (n >> 1, 2) if n > 2 else (2, 1) end = isqrt(n) a = 0 solutionsFound = [] firstb = -1 while a < end and len(solutionsFound) < 2: bsquare = n - a**2 if bsquare > 0: b = isqrt(bsquare) if (b**2 == bsquare) and (a != firstb) and (b != firstb): firstb = b solutionsFound.append([int(b), a]) a += 1 if len(solutionsFound) < 2: return -1 a = solutionsFound[0][0] b = solutionsFound[0][1] c = solutionsFound[1][0] d = solutionsFound[1][1] k = gcd(a - c, d - b) h = gcd(a + c, d + b) m = gcd(a + c, d - b) l = gcd(a - c, d + b) n = (k**2 + h**2) * (l**2 + m**2) return [int(k**2 + h**2) >> 1, int(l**2 + m**2) >> 1]
def fermat(self, n): """Fermat attack""" a = b = isqrt(n) b2 = pow(a, 2) - n while pow(b, 2) != b2: a += 1 b2 = pow(a, 2) - n b = isqrt(b2) p, q = (a + b), (a - b) assert n == p * q return p, q
def pre_attack_check(self, publickeys): """Basic pre Attack checks implementation""" if not isinstance(publickeys, list): publickeys = [publickeys] tmp = [] ok = True for publickey in publickeys: if publickey.n & 1 == 0: self.logger.error("[!] Public key: %s modulus should be odd." % publickey.filename) ok = False if gcd(publickey.n, publickey.e) > 1: self.logger.error( "[!] Public key: %s modulus is coprime with exponent." % publickey.filename) ok = False if not (publickey.n > 3): self.logger.error("[!] Public key: %s modulus should be > 3." % publickey.filename) ok = False if is_prime(publickey.n): self.logger.error( "[!] Public key: %s modulus should not be prime." % publickey.filename) ok = False i = isqrt(publickey.n) if publickey.n == (i**2): self.logger.error( "[!] Public key: %s modulus should not be a perfect square." % publickey.filename) publickey.p = i publickey.q = i tmp.append(publickey) ok = False return (tmp, ok)
def __init__(self, n, e, progress=True): """Constructor""" self.d = None self.p = None self.q = None sys.setrecursionlimit(100000) frac = self.rational_to_contfrac(e, n) convergents = self.convergents_from_contfrac(frac, progress) for (k, d) in tqdm(convergents, disable=(not progress)): if k != 0: ed1 = e * d - 1 phi = ed1 // k if ed1 - (k * phi) == 0: # same as ed1 % k == 0 s = n - phi + 1 discr = pow(s, 2) - (n << 2) # same as s**2 - 4*n if discr >= 0: t = isqrt(discr) if pow(t, 2) == discr: if (s + t) & 1 == 0: self.d = d x = Symbol("x") roots = solve(pow(x, 2) - s * x + n, x) if len(roots) == 2: self.p = roots[0] self.q = roots[1] break
def pollard_P_1(self, n, progress=True): """Pollard P1 implementation""" z = [] logn = math.log(int(isqrt(n))) prime = primes(997) for j in range(0, len(prime)): primej = prime[j] logp = math.log(primej) for i in range(1, int(logn / logp) + 1): z.append(primej) try: for pp in tqdm(prime, disable=(not progress)): i = 0 x = pp while 1: x = powmod(x, z[i], n) i = i + 1 y = gcd(n, x - 1) if y != 1: p = y q = n // y return p, q if i >= len(z): return 0, None except TypeError: return 0, None
def z3_solve(self, n, timeout_amount): """ Integer factorization using z3 theorem prover implementation: We can factor composite integers by SAT solving the model N=PQ directly using the clasuse (n==p*q), wich gives a lot of degree of freedom to z3, so we want to contraint the search space. Since every composite number n=pq, there always exists some p>sqrt(n) and q<sqrt(n). We can safely asume the divisor p is in the range n > p >= next_prime(sqrt(n)) if this later clause doesn't hold and sqrt(p) is prime the number is a perfect square. We can also asume that p and q are alyaws odd otherwise our whole composite is even. Not all composite numbers generate a valid model that z3 can SAT. SAT solving is efficient with low bit count set in the factors, the complexity of the algorithm grows exponential with every bit set. The problem of SAT solving integer factorization still is NP complete, making this just a showcase. Don't expect big gains. """ s = Solver() s.set("timeout", timeout_amount * 1000) p = Int("p") q = Int("q") i = int(isqrt(n)) np = int(next_prime(i)) s.add(p * q == n, n > p, n > q, p >= np, q < i, q > 1, p > 1, q % 2 != 0, p % 2 != 0) try: s_check_output = s.check() if s_check_output == sat: res = s.model() P, Q = res[p].as_long(), res[q].as_long() assert P * Q == n return P, Q else: return None, None except: return None, None
def __init__(self, n, e, progress=True): """Constructor""" self.d = None self.p = None self.q = None sys.setrecursionlimit(100000) frac = self.rational_to_contfrac(e, n) convergents = self.convergents_from_contfrac(frac, progress) for (k, d) in tqdm(convergents, disable=(not progress)): if k != 0 and (e * d - 1) % k == 0: phi = (e * d - 1) // k s = n - phi + 1 discr = s * s - 4 * n if discr >= 0: t = isqrt(discr) if t**2 == discr: if (s + t) & 1 == 0: self.d = d x = Symbol("x") roots = solve(x**2 - s * x + n, x) if len(roots) == 2: self.p = roots[0] self.q = roots[1] break
def SQUFOF(N): s = int(isqrt(N) + 0.5) L = int(2 * isqrt(2 * s)) if (s ** 2 == N): return s for k in range(0,len(multiplier)): D = multiplier[k] * N Po = Pprev = P = isqrt(D) Qprev = 1 Q = D - pow(Po, 2) B = 3 * L c0 = True i = 2 while c0: b = int((Po + P) // Q) P = b * Q - P q = Q Q = Qprev + b * (Pprev - P) r = int(isqrt(Q) + 0.5) if (not(i & 1) and (pow(r, 2) == Q)): break Qprev = q Pprev = P i += 1 c0 = (i <= B) b = ((Po - P) // r) Pprev = P = b * r + P Qprev = r Q = (D - pow(Pprev, 2)) // Qprev i = 0 c1 = True while(c1): b = int((Po + P) // Q) Pprev = P P = b * Q - P q = Q; Q = Qprev + b * (Pprev - P) Qprev = q i += 1 c1 = (P != Pprev) r = gcd(N, Qprev) if (1 < r < N): return r,N // r return -1
def euler(self, n): if n & 1 == 0: return (n >> 1, 2) if n > 2 else (2, 1) end = isqrt(n) a = 0 solutionsFound = [] firstb = -1 while a < end and len(solutionsFound) < 2: bsquare = n - pow(a, 2) if bsquare > 0: b = isqrt(bsquare) if (pow(b, 2) == bsquare) and (a != firstb) and (b != firstb): firstb = b solutionsFound.append([b, a]) a += 1 if len(solutionsFound) < 2: return None a = solutionsFound[0][0] b = solutionsFound[0][1] c = solutionsFound[1][0] d = solutionsFound[1][1] k = pow(gcd(a - c, d - b), 2) h = pow(gcd(a + c, d + b), 2) m = pow(gcd(a + c, d - b), 2) l = pow(gcd(a - c, d + b), 2) p, q = gcd(k + h, n), gcd(l + m, n) if n > p > 1: return p, n // p if n > q > 1: return q, n // q
def dixon_factor(N, B=7, explain=False): if is_prime(N): return N, 1 start = isqrt(N) if (start ** 2) == N: return start, start base = primes(B) lqbf = pow(base[-1], 2) + 1 QBF = bitarray.bitarray(lqbf) # This is our quasi-bloom-filter basej2N = [] for j in range(0, len(base)): p = powmod(base[j], 2, N) basej2N.append(p) QBF[p] = 1 # We populate our quasi-bloom-filter i = start while i < N: i2N = pow(i, 2, N) if i2N < lqbf and QBF[i2N] == 1: for k in range(0, len(base)): if QBF[basej2N[k]] == 1: # if i2N == basej2N[k]: # this is replaced with a quasi-bloom-filter f = gcd(i - base[k], N) if explain: print("N = %d" % N) print("%d = isqrt(N)" % start) print("%d = pow(%d,2,n)" % (i2N, i)) print("%d = pow(%d,2,n)" % (basej2N[k], base[k])) print("%d - %d = %d" % (i, base[k], f)) print("%d = gcd(%d - % d, N)" % (f, i, base[k])) print( "%d = gcd(%d + % d, N)" % (gcd(i + base[k], N), i, base[k]) ) if 1 < f < N: return f, N // f i += 1 return None, None
def close_factor(self, n, b, progress=True): # approximate phi phi_approx = n - 2 * isqrt(n) + 1 # create a look-up table look_up = {} z = 1 for i in tqdm(range(0, b + 1), disable=(not progress)): look_up[z] = i z = (z << 1) % n # check the table mu = invmod(powmod(2, phi_approx, n), n) fac = powmod(2, b, n) for i in tqdm(range(0, b + 1), disable=(not progress)): if mu in look_up: phi = phi_approx + (look_up[mu] - (i * b)) r = trivial_factorization_with_n_phi(n, phi) if r != None: return r mu = (mu * fac) % n else: return None