def hensel_step(m, f, g, h, s, t):
        # step 1
        zx = ZX()
        e = zx.add(f, zx.add_inv(zx.mul(g, h)))
        e = zx.mod_elem(e, m * m)
        q = zx.mul(s, e)
        quot, rem = zx.extended_synthetic_division(q.coefs, h.coefs)
        q = zx.mod_elem(Polynomial(quot, ZZ()), m * m)
        r = zx.mod_elem(Polynomial(rem, ZZ()), m * m)
        g_star = zx.add(g, zx.mul(t, e))
        g_star = zx.add(g_star, zx.mul(q, g))
        g_star = zx.mod_elem(g_star, m * m)
        h_star = zx.mod_elem(zx.add(h, r), m * m)

        # step 2
        b = zx.mul(s, g_star)
        b = zx.add(b, zx.mul(t, h_star))
        b = zx.add(b, zx.add_inv(zx.mul_id()))
        b = zx.mod_elem(b, m * m)
        c = zx.mul(s, b)
        quot, rem = zx.extended_synthetic_division(c.coefs, h_star.coefs)
        c = zx.mod_elem(Polynomial(quot, ZZ()), m * m)
        d = zx.mod_elem(Polynomial(rem, ZZ()), m * m)
        s_star = zx.add(s, zx.add_inv(d))
        s_star = zx.mod_elem(s_star, m * m)
        t_star = zx.add(t, zx.add_inv(zx.mul(t, b)))
        t_star = zx.add(t_star, zx.add_inv(zx.mul(c, g_star)))
        t_star = zx.mod_elem(t_star, m * m)
        return g_star, h_star, s_star, t_star
예제 #2
0
    def step_b1(self):
        # xi = X * 1_F
        xi = Polynomial([self.field.add_id(), self.field.mul_id()], self.field)
        # l x l matrix with coefficients in F
        q_matrix = []
        # compute alpha = xi^q through repeated squaring.
        # we do this by making all calculations on F[X] and then computing the associated elements in E via rem with f.
        alpha = self.fx.exp(xi, self.field.cardinality())
        alpha = self.rep(alpha)

        print("Tengo el representante")

        # beta = 1_E, no quotient needed in this case.
        beta = self.fx.mul_id()

        for i in range(self._l):
            # Row_i(Q) = Vec_S(beta)
            q_matrix.append(self.vec_s(copy.deepcopy(beta.coefs)))
            # Q[i][i] = Q[i][i] - 1
            q_matrix[i][i] = self.field.add(
                q_matrix[i][i], self.field.add_inv(self.field.mul_id()))
            # beta = beta * alpha
            beta = self.rep(self.fx.mul(beta, alpha))
        print("Q = ", q_matrix)

        # compute a basis of the row null space of Q
        _, x_matrix = self.gaussian_elimination(q_matrix)
        res = [Polynomial(elem, self.field) for elem in x_matrix]
        print("base = ", res)
        return res
예제 #3
0
 def is_irreducible(self, f):
     x = Polynomial([self.base_field.add_id(), self.base_field.mul_id()], self.base_field)
     h = self.rem(x, f)
     for k in range(1, f.degree()//2+1):
         aux = h
         # calculate h = h ** card, where card = cardinality of Fq
         for j in range(1, self.base_field.cardinality()):
             h = self.mul(h, aux)
         h = self.rem(h, f)
         gcd = self.gcd(self.add(h, self.add_inv(x)), f)
         if self.div(gcd, Polynomial([gcd.get_leading_coef()], self.base_field)) != self.mul_id():
             return False
     return True
예제 #4
0
    def div_mod(self, elem1, elem2):
        if elem1.degree() < elem2.degree():
            return Polynomial([self.base_field.add_id()],
                              self.base_field), elem1

        a = list(elem1.coefs)
        a.reverse()
        b = list(elem2.coefs)
        b.reverse()
        quotient, remainder = self.extended_synthetic_division(a, b)
        quotient.reverse()
        remainder.reverse()
        return Polynomial(quotient,
                          self.base_field), Polynomial(remainder,
                                                       self.base_field)
예제 #5
0
 def add(self, elem1, elem2):
     lis = list(
         map(lambda x1, x2: self.base_field.add(x1, x2), elem1.coefs,
             elem2.coefs))
     lis.extend(elem1.coefs[len(lis):])
     lis.extend(elem2.coefs[len(lis):])
     return Polynomial(lis, self.base_field)
 def mk(self, k):
     w = self.field.k
     res = [self.field.add_id()] * (2 ** (w * k - 1) + 1)
     acc = 1
     for i in range(w * k):
         res[acc] = self.field.mul_id()
         acc *= 2
     return Polynomial(res, self.field)
 def obtain_factors(self, T, g_i, b, p):
     zx = ZX()
     g = zx.mul_id()
     for index in T:
         g = zx.mul(g_i[index], g)
     g_star = zx.mul_scalar(g, b)
     g_star_module_p = Polynomial([x % p for x in g_star.coefs], ZX())
     return self.symmetric_form(g_star_module_p, p)
예제 #8
0
 def mul(self, elem1, elem2):
     res = [self.base_field.add_id()
            ] * (elem1.degree() + elem2.degree() + 1)
     for in1, e1 in enumerate(elem1.coefs):
         for in2, e2 in enumerate(elem2.coefs):
             res[in1 + in2] = self.base_field.add(
                 res[in1 + in2], self.base_field.mul(e1, e2))
     return Polynomial(res, self.base_field)
예제 #9
0
 def primitive_part(self, elem):
     if elem == self.add_id():
         return self.add_id()
     else:
         # divide all coefficients by common gcd to obtain primitive part
         return Polynomial(
             list(
                 map(lambda x: ZZ().div(x, self.mcd_polynomial_coefs(elem)),
                     elem.coefs)), ZZ())
예제 #10
0
    def gcd(self, a, b):
        c = self.primitive_part(a)
        d = self.primitive_part(b)

        if c.degree() < d.degree():
            c, d = d, c

        while d != self.add_id():
            lc = c.get_leading_coef()
            n = c.degree() - d.degree() + 1
            aux = Polynomial([lc**n], ZZ())
            aux = self.mul(aux, c)
            r = Polynomial(
                self.extended_synthetic_division(aux.coefs, d.coefs)[1], ZZ())
            c = d
            d = self.primitive_part(r)
        gcd_ab = ZZ().gcd(self.mcd_polynomial_coefs(a),
                          self.mcd_polynomial_coefs(b))
        return self.mul(Polynomial([gcd_ab], ZZ()), c)
예제 #11
0
    def pth_root(self, f):
        # f = g(X^p), with g in PolynomialsOverFq
        g = []
        i = 0
        # x^4 + x^2 + 1 -> x^2 + x + 1 (p = 2)
        while i <= f.degree():
            g.append(f.coefs[i])
            i += self.base_field.p

        print("g*: ", g)
        h = [self.base_field.exp(a, self.base_field.p**(self.base_field.k - 1)) for a in g]
        print("h*: ", h)
        return Polynomial(h, f.base_ring)
예제 #12
0
 def m1(self):
     coefs = []
     if self.field.p > 2:
         coefs = [self.field.add_id()] * (
             (self.field.cardinality() - 1) // 2 + 1)
         coefs[(self.field.cardinality() - 1) // 2] = self.field.mul_id()
         coefs[0] = self.field.add_inv(self.field.add_id())
     else:
         # 1 + X^2 + X^4 + ...
         coefs = [
             self.field.mul_id() if i % 2 == 0 else self.field.add_id()
             for i in range(2 * self.field.k - 1)
         ]
     return Polynomial(coefs, self.field)
    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 distinct_degree_factorization(self):
        _L = []
        _X = Polynomial([self.field.add_id(), self.field.mul_id()], self.field)
        h = self.fx.rem(_X, self.f)
        k = 0
        fc = copy.deepcopy(self.f)

        while fc != self.fx.mul_id():
            h = self.fx.rem(self.fx.exp(h, self.field.cardinality()), fc)
            k += 1
            aux = self.fx.add(h, self.fx.add_inv(_X))
            g = self.fx.gcd(aux, fc)
            if g.degree() > 1:
                _L.append((g, k))
                fc = self.fx.div(fc, g)
                h = self.fx.rem(h, fc)
        return _L
    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
예제 #16
0
 def mul_field_scalar(self, elem, f_scalar):
     return Polynomial(
         [self.base_field.mul(x, f_scalar) for x in elem.coefs],
         self.base_field)
예제 #17
0
        i = 0
        # x^4 + x^2 + 1 -> x^2 + x + 1 (p = 2)
        while i <= f.degree():
            g.append(f.coefs[i])
            i += self.base_field.p

        print("g*: ", g)
        h = [self.base_field.exp(a, self.base_field.p**(self.base_field.k - 1)) for a in g]
        print("h*: ", h)
        return Polynomial(h, f.base_ring)


if __name__ == "__main__":
    Z2 = Zp(2)
    Z2X = PolynomialsOverFq(Z2)
    print(Z2X.is_irreducible(Polynomial([1, 0, 1], Z2)))
    # false
    print(Z2X.is_irreducible(Polynomial([1, 1, 1, 1, 1], Z2)))
    # true
    print(Z2X.is_irreducible(Polynomial([0, 1, 1, 1, 1], Z2)))
    # false
    print(Z2X.is_irreducible(Polynomial([1, 1, 0, 1], Z2)))
    # true
    print(Z2X.is_irreducible(Polynomial([1, 0, 1, 1], Z2)))
    # true
    print(Z2X.is_irreducible(Polynomial([1, 0, 0, 0, 1, 1], Z2)))
    # false
    F16 = FiniteField(2, 4, Polynomial([1, 1, 0, 0, 1], Z2))
    F16X = PolynomialsOverFq(F16)
    One = F16.mul_id()
    Zero = F16.add_id()
                                             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


if __name__ == "__main__":
    g = Polynomial([-15, -17, -16, -1, 1], ZZ())
    fact = FactorizationZx(g)
    print(fact.factorize_big_prime())
    print(fact.factorize_prime_power())

    p_big = Polynomial([-12, -24, -18, -2, 8, 3, 0, 2, 1], ZZ())
    # print(FactorizationZx(p_big).factorize_big_prime())
    print(FactorizationZx(p_big).factorize_prime_power())

    m = 5
    f = Polynomial([-1, 0, 0, 0, 1], ZZ())
    g = Polynomial([-2, -1, 2, 1], ZZ())
    h = Polynomial([-2, 1], ZZ())
    s = Polynomial([-2], ZZ())
    t = Polynomial([-1, -2, 2], ZZ())
예제 #19
0
 def add_inv(self, elem):
     lis = list(map(lambda x: self.base_field.add_inv(x), elem.coefs))
     return Polynomial(lis, self.base_field)
예제 #20
0
 def mul_id(self):
     return Polynomial([self.base_field.mul_id()], self.base_field)
예제 #21
0
 def add_id(self):
     return Polynomial([self.base_field.add_id()], self.base_field)
 def symmetric_form(self, pol, p):
     return Polynomial(
         [self.symmetrical_representation_number(x, p) for x in pol.coefs],
         pol.base_ring)
 def random_elem(self):
     elem = []
     for i in range(self.k):
         elem.append(random.randrange(self.p))
     return Polynomial(elem, Zp(self.p))
from generic.PolynomialsOverField import PolynomialsOverField
from specific.PadicNumber import PadicNumber


# Not much to do here, this class is mostly intended for testing purposes.
class PolynomialsOverPadics(PolynomialsOverField):
    def __init__(self, p):
        self.base_field = PadicNumber(p)


if __name__ == "__main__":
    from generic.Polynomial import Polynomial
    pp2 = PolynomialsOverPadics(2)
    p2 = PadicNumber(2)
    f1 = Polynomial([p2.mul_id(), p2.mul_id()], p2)
    f2 = Polynomial([p2.mul_id(), p2.mul_id(), p2.mul_id()], p2)
    f12 = pp2.mul(f1, f2)
    f11 = pp2.mul(f1, f1)
    f22 = pp2.mul(f2, f2)
    print("f1: ", f1)
    print("f2: ", f2)
    print("f11: ", f11)
    print("f12: ", f12)
    print("f22: ", f22)
    print("-------------------------------")
    res1 = pp2.gcd(f11, f12)
    print("gcd f11, f12: ", res1)
    print("divided by f1: ", pp2.div(res1, f1))
    print("divided by f2: ", pp2.div(res1, f2))
    print("-------------------------------")
    res2 = pp2.gcd(f11, f22)
            _H = _Hp
        return _H

    def compute(self):
        step1 = self.distinct_degree_factorization()
        # print("Step 1 result: ", step1)
        # for pol in step1:
        #    print(self.fx.obtain_monic_representation(pol[0]))
        res = []
        for elem in step1:
            # print("elem for: ", elem)
            sol = self.equal_degree_factorization(elem[0], elem[1])
            # print(sol)
            res.extend(sol)
        return res


if __name__ == "__main__":
    from generic.FiniteField import FiniteField
    from specific.Zp import Zp

    F4 = FiniteField(2, 2, Polynomial([1, 1, 1], Zp(2)))
    F4One = F4.mul_id()
    F4Zero = F4.add_id()
    F4Alpha = Polynomial([0, 1], Zp(2))
    F4AlphaPlusOne = Polynomial([1, 1], Zp(2))
    f = Polynomial([F4Alpha, F4AlphaPlusOne, F4One], F4)
    print(".............")
    print("Compute factorization through Berkelamp's algorithm")
    print(CantorZassenhaus(f).compute())
        elem = []
        for i in range(self.k):
            elem.append(random.randrange(self.p))
        return Polynomial(elem, Zp(self.p))

    def __eq__(self, other):
        if isinstance(other, FiniteField):
            return self.p == other.p and self.k == other.k
        return NotImplemented


if __name__ == "__main__":

    # test to check if rep works correctly for GF(4)
    Z2 = Zp(2)
    F4 = FiniteField(2, 2, Polynomial([1, 1, 1], Z2))
    F4One = F4.mul_id()
    F4Zero = F4.add_id()
    F4Alpha = Polynomial([0, 1], Z2)
    F4AlphaPlusOne = Polynomial([1, 1], Z2)
    # Both of the following elements should have rep [1]
    print(F4.rep(F4One), F4.rep(F4.add(F4.mul(F4Alpha, F4Alpha), F4Alpha)))
    # Multiplication table for F4.
    print("Multiplication table for F4")
    print(F4.mul(F4One, F4One))
    print(F4.mul(F4One, F4Alpha))
    print(F4.mul(F4One, F4AlphaPlusOne))
    print(F4.mul(F4Alpha, F4Alpha))
    print(F4.mul(F4Alpha, F4AlphaPlusOne))
    print(F4.mul(F4AlphaPlusOne, F4AlphaPlusOne))
 def random_polynomial_h(self, h):
     res = []
     for i in range(h.degree()):
         res.append(self.field.random_elem())
     pol = Polynomial(res, self.field)
     return self.fx.rem(pol, h)
 def add_id(self):
     return Polynomial([0], self.field)
예제 #29
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 mul_id(self):
     return Polynomial([1], self.field)