Beispiel #1
0
    def bound_primes_from_approximate_sum(self, sumpq, eps):
        """
        p + q = s + e, 0 <= e < eps
        p + n/p = s+e
        p**2 - (s+e)*p + n = 0

        p = (s + e - sqrt((s + e)**2 - 4*n)) / 2
        q = (s + e + sqrt((s + e)**2 - 4*n)) / 2
        """
        n = self.n
        if sumpq**2 <= 4 * n:
            mx = sumpq + eps
            sumpq = ceil(ZZ(4 * n).sqrt())
            eps = mx - sumpq
        assert (sumpq + eps)**2 > 4 * n
        assert eps >= 0

        Dmin = floor(ZZ(sumpq**2 - 4 * n).sqrt())
        Dmax = ceil(ZZ((sumpq + eps)**2 - 4 * n).sqrt())

        p_max = (sumpq - Dmin) // 2
        p_min = (sumpq + eps - Dmax) // 2
        assert p_min <= p_max

        q_min = (sumpq + Dmin) // 2
        q_max = (sumpq + eps + Dmax) // 2
        assert q_min <= q_max

        # do not have to hold
        if not (p_max * q_min <= n) or not (p_min * q_max >= n):
            warnings.warn("strangely, bounds can be improved")
            q_min = max(q_min, n // p_max + 1)
            q_max = min(q_max, n // p_min)
        return (p_min, p_max), (q_min, q_max)
Beispiel #2
0
    def __init__(self, spec, m=None):
        if is_Polynomial(spec):
            poly = spec
            assert len(poly.variables()) == 1

            fld = poly.base_ring()
            if m is None:
                m = ZZ(fld.order() - 1).nbits()
            spec = [
                poly.subs(fld.fetch_int(x)).integer_representation()
                for x in range(len(fld))
            ]

        self._S = tuple(map(int, spec))
        self.n = ZZ(len(self._S) - 1).nbits()
        self.m = ZZ(max(self._S)).nbits()
        if m is not None:
            m = int(m)
            lim = 1 << self.m
            assert all(0 <= y < lim for y in self._S)
        else:
            m = ZZ(max(self._S)).nbits()
        self.m = m
        assert self.input_size() >= 1
        assert self.output_size() >= 0
Beispiel #3
0
    def factor_with_prime_hint(self, low_mod=None, bounds=None, beta=0.49):
        """
        """
        if low_mod is None:
            low_mod = 0, 1
        low, mod = low_mod
        assert 0 <= low < mod

        if bounds is None:
            bounds = 0, self.n_sqrt()
        pmin, pmax = bounds

        if beta < 0.5:
            assert pmax <= self.n_sqrt(), \
                "upper bound must be <= sqrt(n) when beta < 0.5"
        else:
            assert pmin >= self.n_sqrt(), \
                "lower bound must be >= sqrt(n) when beta >= 0.5"
        assert 1 <= pmin <= pmax

        # next value hitting low % mod
        if pmin % mod <= low:
            pmin = pmin - pmin % mod + low
        else:
            pmin = pmin - pmin % mod + mod + low

        xmax = ZZ(pmax - pmin) // mod

        PR, x = self.polyring()
        poly = (mod * x + pmin).monic()

        # for debugging
        # global p
        # assert p % mod == low
        # sol = (p-pmin)//mod
        # print("sol size", ZZ(sol).nbits(), "<xmax?", 0 <= sol <= xmax)
        # print(poly.subs(x=sol) % p )
        # print("poly", poly)

        # X = 1/2 n**(beta**2/degree - epsilon)
        # log_n 2X = beta**2 - epsilon
        # epsilon = beta**2 - log_n 2X
        epsilon = beta**2 - RR(log(2 * xmax, self.n))
        assert epsilon > 0, "impossible attack"

        roots = poly.small_roots(X=xmax, beta=beta, epsilon=epsilon)
        for sol in roots:
            p = int(poly.subs(x=sol))
            p = abs(gcd(p, self.n))
            if 1 < p < self.n:
                q = self.n // p
                assert self.n == p * q, "multi-prime? ouch"
                self.update(p=p, q=q)
                break
        else:
            raise RuntimeError("attack failed")
        return p, q
Beispiel #4
0
 def n_sqrt(self):
     if self._n_sqrt is None:
         self._n_sqrt = floor(ZZ(self.n).sqrt())
     return self._n_sqrt