def factorize_prime_power(self):
        # step 1
        if self.n == 1:
            return [self.f]
        b = self.f.get_leading_coef()
        B = ceil(sqrt(self.n + 1) * pow(2, self.n) * self.A * b)
        C = (self.n + 1)**(2 * self.n) * (self.A**(2 * self.n - 1))
        gamma = ceil(2 * log2(C))

        # step 2
        p = ZZ().obtain_random_prime_in_range(3, ceil(2 * gamma * log(gamma)))
        f_bar = Polynomial(self.f.coefs, Zp(p))
        f_bar_der = f_bar.derivative()
        fx = PolynomialsOverField(Zp(p))

        while b % p == 0 or fx.gcd(f_bar, f_bar_der).degree() > 1:
            p = ZZ().obtain_random_prime_in_range(2,
                                                  ceil(2 * gamma * log(gamma)))
            f_bar = Polynomial(self.f.coefs, Zp(p))
            f_bar_der = f_bar.derivative()
        l = ceil(log(2 * B + 1, p))

        # step 3
        h_i = self.modular_factorization(f_bar, p, fx)

        # step 4
        fact = self.multifactor_hensel_lifting(p, self.f, h_i, l)
        g_i = [self.symmetric_form(factor, p**l) for factor in fact]

        # step 5
        r = len(g_i)
        f_star = copy.deepcopy(self.f)
        T = set(range(r))
        s = 1
        G = []

        # step 6
        while 2 * s <= len(T):
            goto = False
            combination = list(combinations(T, s))
            for subset_tuple in combination:
                subset = set(subset_tuple)
                g_star = self.obtain_factors(subset, g_i, b, p**l)
                h_star = self.obtain_factors(T.difference(subset), g_i, b,
                                             p**l)
                if ZX().onenorm(g_star) * ZX().onenorm(h_star) <= B:
                    T = T.difference(subset)
                    G.append(ZX().primitive_part(g_star))
                    f_star = ZX().primitive_part(h_star)
                    b = f_star.get_leading_coef()
                    goto = True
                    break
            if not goto:
                s += 1
        G.append(f_star)
        return G
    def multifactor_hensel_lifting(self, p, f, fr, l):
        zx = ZX()
        r = len(fr)
        # step 1
        if r == 1:
            # extended gcd in ZZ
            if f.get_leading_coef() == 1:
                return [f]

            pl = p**l
            _, w, _ = ZZ().extended_gcd(f.get_leading_coef(), pl)
            return [zx.mod_elem(zx.mul_scalar(f, w), pl)]

        # step 2
        k = floor(r / 2)
        d = ceil(log2(l))

        # step 3
        g = reduce(zx.mul, fr[0:k])
        g = zx.mul_scalar(g, f.get_leading_coef())
        g = zx.mod_elem(g, p)
        h = reduce(zx.mul, fr[k:r])
        h = zx.mod_elem(h, p)

        # step 4: ZZ/<p> is always a field (namely Zp), since p is prime
        zpx = PolynomialsOverField(Zp(p))
        coef, s, t = zpx.extended_gcd(g, h)
        s = zpx.mul_scalar(s, Zp(p).mul_inv(coef.coefs[0]))
        t = zpx.mul_scalar(t, Zp(p).mul_inv(coef.coefs[0]))

        # step 5
        m = p
        for j in range(d):
            # step 6
            g, h, s, t = self.hensel_step(m, f, g, h, s, t)
            m **= 2

        _k1 = self.multifactor_hensel_lifting(p, g, fr[0:k], l)
        _k2 = self.multifactor_hensel_lifting(p, h, fr[k:r], l)
        _k1.extend(_k2)
        return _k1
    def factorize_big_prime(self):
        if self.n == 1:
            return [self.f]
        b = self.f.get_leading_coef()
        B = ceil(sqrt(self.n + 1) * pow(2, self.n) * self.A * b)

        p = ZZ().obtain_random_prime_in_range(2 * B + 1, 4 * B - 1)
        f_bar = Polynomial(self.f.coefs, Zp(p))
        f_bar_der = f_bar.derivative()
        fx = PolynomialsOverField(Zp(p))

        while fx.gcd(f_bar, f_bar_der).degree() > 1:
            p = ZZ().obtain_random_prime_in_range(2 * B + 1, 4 * B - 1)
            f_bar = Polynomial(self.f.coefs, Zp(p))
            f_bar_der = f_bar.derivative()

        g_i = self.modular_factorization(f_bar, p, fx)
        r = len(g_i)
        f_star = copy.deepcopy(self.f)
        T = set(range(r))
        s = 1
        G = []
        while 2 * s <= len(T):
            goto = False
            combination = list(combinations(T, s))
            for subset_tuple in combination:
                subset = set(subset_tuple)
                g_star = self.obtain_factors(subset, g_i, b, p)
                h_star = self.obtain_factors(T.difference(subset), g_i, b, p)
                if ZX().onenorm(g_star) * ZX().onenorm(h_star) <= B:
                    T = T.difference(subset)
                    G.append(ZX().primitive_part(g_star))
                    f_star = ZX().primitive_part(h_star)
                    b = f_star.get_leading_coef()
                    goto = True
                    break
            if not goto:
                s += 1
        G.append(f_star)
        return G
Beispiel #4
0
from generic.FiniteField import FiniteField
from specific.ZZ import ZZ
from generic.Polynomial import Polynomial
from generic.PolynomialsOverField import PolynomialsOverField
from generic.Ring import Ring
from specific.Zp import Zp

# ZZ = ZZ()
# print(ZZ.chinese_remainder_theorem([0, 3, 4], [3, 4, 5]))
Z2 = Zp(2)
Z2X = PolynomialsOverField(Z2)
# print(Zp(7).mul_inv(6))
print(Z2X.gcd(Polynomial([1], Z2), Polynomial([1, 1], Z2)).coefs)
print(Z2X.add_id() == Polynomial([0], Z2))
print(Z2X.div(Polynomial([0, 0, 1], Z2), Polynomial([1, 1, 1], Z2)).coefs)
print(Z2X.rem(Polynomial([0, 0, 1], Z2), Polynomial([1, 1, 1], Z2)).coefs)
print(
    Z2X.chinese_remainder_theorem(
        [Polynomial([1], Z2), Polynomial([1, 1], Z2)],
        [Polynomial([1, 1], Z2),
         Polynomial([1, 1, 1], Z2)]).coefs)

# print(ZZ.rem(5, 3))
# print(ZZ.add_id())
# print(ZZ.mul_id())
# print(ZZ.mul(7, -2))
# print(ZZ.gcd(178, 4))
# print(ZZ.gcd(7, -5))
# print(ZZ.extended_gcd(15, 25))
# print(ZZ.extended_gcd(25, 15))
# print(ZZ.extended_gcd(7, 25))
 def __init__(self, f):
     # field = Fq, f = f, fx = F[X]
     self.field = f.base_ring
     self.f = f
     self.fx = PolynomialsOverField(f.base_ring)
     self._l = f.degree()
 def __init__(self, p, k, f):
     self.p, self.k, self.f = p, k, f
     self.field = PolynomialsOverField(Zp(p))
Beispiel #7
0
    # f = Polynomial([F4Alpha, F4AlphaPlusOne, F4One], F4)
    # print(".............")
    # print(Berlekamp(f).step_b1())
    #
    # print(".............")
    # print("Compute factorization through Berkelamp's algorithm")
    # print(Berlekamp(f).step_b2([Polynomial([F4One], F4), Polynomial([F4Zero, F4One], F4)]))
    # print(Berlekamp(f).compute())
    # factors = Berlekamp(f).compute()
    # for factor in factors:
    #     print("Factor", PolynomialsOverField(F4).obtain_monic_representation(factor))
    #
    # Z7 = Zp(7)
    # g = Polynomial([6,11,6,1], Z7)
    # factors = Berlekamp(g).compute()
    # for factor in factors:
    #     print("Factor", PolynomialsOverField(Z7).obtain_monic_representation(factor))

    # Z6473 = Zp(1201)
    # g = Polynomial([-40, -62, -21, 2,1], Z6473)
    # factors = Berlekamp(g).compute()
    # for factor in factors:
    #     print("Factor", PolynomialsOverField(Z6473).obtain_monic_representation(factor))

    Z3 = Zp(3)
    g = Polynomial([1, 1, 2, 3, 1], Z3)
    factors = Berlekamp(g).compute()
    for factor in factors:
        print("Factor",
              PolynomialsOverField(Z3).obtain_monic_representation(factor))