예제 #1
0
    def croot(self):
        """
            Computes the cth root of the element, where c is the characteristic
            of the ring
        """
        if self == self.ring.zero:
            return self

        # Assumes generator is primitive
        # Multiplicative ring order
        if self.ring.char() == self.ring.order():
            return self

        Z = externals.Z

        o = self.ring.order() - 1
        p = self.ring.char()
        g = self.ring.build([0, 1])
        log = externals.discrete_log(g, self)
        assuming(log is not None,
                 "The chosen field generator is not primitive")
        # Find an integer x such that x*p = log (mod o)
        gcd, __, inv = externals.eea(Z.build(o), Z.build(p))
        if gcd != Z.one:
            assuming(
                gcd.is_unit(),
                f"Could not find c-th root of {self} in {type(self)}. Is the field well constructed?"
            )
            inv = inv // gcd
        x = inv * Z.build(log) % Z.build(o)
        return g**(x.val)
예제 #2
0
    def __init__(self, val):

        while hasattr(val, "val"):
            val = val.val

        assuming(hasattr(val, "__int__"), f"Can't build an integer from {val}")
        self.val = int(val)
예제 #3
0
def rabin_test(pol):
    """
        Rabin's test of irreducibility for polynomials with coefficients in a finite field
    """

    PR = pol.ring       # polinomial ring
    R = PR.coefRing         # coefficient ring (field)
    assuming(R.is_finite())

    p = R.order()
    n = pol.deg()

    quotRing = GetRingQuotient(PR,(PR*pol))

    x = quotRing.build([R.zero,R.one])

    if (x**(p**n)-x) != quotRing.zero:
        return False

    factors = set(prime_factors(n).keys())
    for f in factors:
        ni = n//f
        if not gcd(pol, (x**(p**ni)-x).val).is_unit():
            return False

    return True
예제 #4
0
def FiniteField(p, pol=None, var=None):
    if pol is None:
        return GetQuotient(Z, p * Z)
    else:
        Pols = GetPolynomials(Z / (p * Z), var)
        assuming(
            Pols(pol).is_prime(), f"{Pols(pol)} is not irreducible on {Pols}")
        if not Pols(pol).is_primitive_field():
            print(
                f"Warning: building FF{p**(len(pol)-1)} with a non-primitive polynomial"
            )
        return GetQuotient(Pols, Pols * Pols(pol))
예제 #5
0
    def __init__(self, ring, generators):

        assuming(len(generators) > 0, "At least one generator is needed")
        assuming(ring.is_euclidean(), "Ring must be Euclidean")

        gen = [ring(g) for g in generators]

        # We can calculate the generator as the gcd of all the given elements

        if len(generators) > 1:
            self.generator = externals.gcd(*gen)
        else:
            self.generator = gen[0]

        super().__init__(ring, [self.generator])
예제 #6
0
    def __init__(self, num, den=1):

        while hasattr(num, "val"):
            num = num.val

        if hasattr(num, "__len__") and len(num) == 2:
            num, den = num

        assuming(
            hasattr(num, "__int__") and hasattr(den, "__int__")
            and int(den) != 0, f"Can't build a rational from {num}, {den}")

        num, den = int(num), int(den)

        g = int_gcd(num, den)

        self.num = num // g
        self.den = den // g
        self.val = (self.num, self.den)
예제 #7
0
def hensel_lifting(f, g, h, s, t):
    """
        Input: polynomials in Z/(qZ)[x], q = p^r
        where f = gh, sg + th = 1
        Returns f', g', h', s' and t' in Z/(q^2)[x] lifted from g,h,s,t respectively
        which satisfy the same constraints
    """

    # Implements algorithm 2.4.6

    R = f.ring.coefRing

    q = R.ideal.generator

    newR = R.baseRing / (R.baseRing * (q**2))
    RX = newR[f.ring.var]

    # Move to the higher ring
    fp = RX(f)
    gp = RX(g)
    hp = RX(h)
    sp = RX(s)
    tp = RX(t)

    # Calculate lifted polynomials
    nabla = fp - gp * hp

    newg = gp * (RX.one + (sp * nabla // hp)) + tp * nabla
    newh = hp + (sp * nabla % hp)

    delta = sp * newg + tp * newh - RX.one
    news = sp - (sp * delta % newh)
    newt = (RX.one - delta) * tp - newg * (sp * delta // newh)

    # Check output meets requirements
    assuming(fp == newg * newh, "Hensel lifting failed")
    assuming(RX.one == news * newg + newt * newh, "Hensel lifting failed")

    return fp, newg, newh, news, newt
예제 #8
0
 def inverse(self):
     # This does not work
     assuming(self.is_unit(), "Can't invert non-unit")
     return type(self)(self.coefs[0].inverse())
예제 #9
0
 def inverse(self):
     assuming(self.is_unit(), "Can't invert non-unit")
     return self
예제 #10
0
def zx_factorization(f):
    """
    """

    # Implements Algorithm 2.4.3

    def norm(f):
        return sqrt(sum([int(a)**2 for a in f.coefs]))

    L = f.coefs[f.deg()]

    prim = primes()
    next(prim)
    p = next(prim)
    while True:
        RX = (Z / (p * Z))["x"]
        f_ = RX.build([a.val for a in f.coefs])
        if L.val % p != 0 and f_.der() != RX.zero and gcd(f_,
                                                          f_.der()).is_unit():
            break
        p = next(prim)

    factors = berlekamp_cantor_zassenhaus(f_)

    nfac = len(factors)

    N = 1
    nor = norm(f)
    while p**N < (2**(f.deg() + 1)) * nor:
        N += 1

    n_lifts = int(ceil(log2(N)))

    for i in range(n_lifts):
        # Hensel lifting from p**k to p**2k

        RX = f_.ring
        RX.setRepr("reduced")
        newfactors = []
        nh = None
        nf = None

        for j in range(nfac - 1):

            g = factors[j]
            h = reduce(RX.Element.__mul__, factors[j + 1:], RX.one)
            prod = g * h

            gc, s, t = eea(g, h)

            if gc != gc.normal():
                s /= gc
                t /= gc

            assuming(gc.is_unit(), "Factorization failed")

            nf, ng, nh, ns, nt = hensel_lifting(prod, g, h, s, t)

            newfactors.append(ng)

        newfactors.append(nh)
        f_ = type(nf)(f_)
        factors = newfactors

    return recover_factors(f, factors)
예제 #11
0
 def inverse(self):
     assuming(self.is_unit(), "Can't invert non-unit")
     return type(self)(self.val[0].inverse())
예제 #12
0
 def inverse(self):
     assuming(self.is_unit(), "Can't invert non-unit")
     return next(u for u in type(self).units()
                 if u * self == type(self).one)
예제 #13
0
 def __truediv__(self, other):
     assuming(other.is_unit(), "Can't divide by non-unit")
     return self * other.inverse()