def gen_GL_2(poly, degree):
    """Return generator of Galois Field's GF(p^degree) based on primitive polynomial poly in Zn."""
    # Order of multiplicative subgroup
    pn1 = (1 << degree) - 1
    if utils.millerRabin(pn1):
        q = [pn1]
    else:
        q = utils.findPrimeFactors(pn1)

    config.ELEMENTS = [i for i in range(1 << degree)]
    genList = config.ELEMENTS

    goodGen = None

    for gen in genList:

        # α(x)^(p^n-1) % f(x) == 1
        firstTest = poly_exp_mod_2(gen, pn1, poly)

        if firstTest == 1:
            isGood = True
            for elt in q:
                # α(x)^((p^n-1)/q) % f(x) != 1, for all q that are prime factors of p^n-1
                secondTest = poly_exp_mod_2(gen, pn1 / elt, poly)

                # DO NOT REPLACE WITH 'if secondTest', i don't know why but intA doesn't work otherwise.
                if secondTest == 1:
                    isGood = False

            if isGood:
                goodGen = gen
                break

    return goodGen
Exemple #2
0
def inv(a: int, m: int, Verbose: bool = False):
    """
    Returns inverse of a mod m.

    If a and m are prime to each other, then there is an a^(-1) such that a^(-1) * a is congruent to 1 mod m.
    """

    if ut.euclid(a, m) != 1:
        if Verbose:
            print(
                f"gcd({a}, {m}) = {ut.euclid(a, m)} != 1 thus you cannot get an invert of {a}."
            )
        raise ValueError(
            f"gcd({a}, {m}) != 1 thus you cannot get an invert of {a}.")
        # a modular multiplicative inverse can be found directly

    elif a == 0:
        if Verbose:
            print(
                f"a = 0 and 0 cannot have multiplicative inverse ( 0 * nothing = 1 ) ."
            )
        raise ValueError("0 cannot have multiplicative inverse.")

    elif ut.millerRabin(m) and m % a != 0:
        # A simple consequence of Fermat's little theorem is that if p is prime and does not divide a
        # then a^−1 ≡ a^(p − 2) (mod p) is the multiplicative
        if Verbose:
            print(
                f"From Fermat's little theorem, because {m} is prime and does not divide {a} so: {a}^-1 = {a}^({m}-2) mod {m}"
            )
        u = ut.square_and_multiply(a, m - 2, m)

    elif ut.coprime(a, m) and m < (1 << 20):
        #From Euler's theorem, if a and n are coprime, then a^−1 ≡ a^(φ(n) − 1) (mod n).
        if Verbose:
            print(
                f"From Euler's theorem, because {a} and {m} are coprime -> {a}^-1 = {a}^(phi({m})-1) mod {m}"
            )

        u = ut.square_and_multiply(a, phi(m, 1, 1, Verbose) - 1, m)

    else:
        if Verbose:
            print(
                f"Modular inverse u solves the given equation: a.u+m.v=1.\n Let's use the euclid extended algorithm tho."
            )

        # Modular inverse u solves the given equation: a.u+m.v=1
        # n number of iterations
        _, u, _, _, _ = ut.euclid_ext(a, m, Verbose)

        if u < 0: u += m

    if Verbose:
        return u, f"u = {u} + {m}k, k in Z"
    else:
        return u
Exemple #3
0
def randomPrime(nBits: int = 512,
                gen=None,
                condition=lambda p: p == p,
                k: int = 1,
                Verbose=False):
    """
    Return generated prime numbers with bitlength nBits.
    Stops after the generation of k prime numbers.

    You can verify a condition with condition method.
    """

    # Generate random odd number of nBits
    assert nBits >= 8 and nBits <= 4096

    if not gen:
        gen = randomInt

    def find(Verbose: bool):
        maybe = gen(0, nBits)

        if Verbose:
            print("Finding one who respect given condition(s).")

        while not condition(maybe):
            maybe = gen(0, nBits)

        if Verbose:
            print("Found !")

        return maybe

    maybe = find(Verbose)

    b = k
    primes = []

    while k > 0:

        if millerRabin(maybe):
            primes.append(maybe)
            k -= 1

        maybe = find(Verbose)

    if b:
        return primes[0]

    return primes
Exemple #4
0
def legendreSymbol(a: int, p: int, quadraticList=None):
    """
    https://en.wikipedia.org/wiki/Legendre_symbol

    LegendreSymbol of quadratics Residues is always 1 except for 0 and 1.
    """
    assert ut.millerRabin(p)

    if quadraticList == None:
        quadraticList = quadraticsResidues(p)

    if a % p == 0:
        return 0
    elif a % p != 0 and a in quadraticList:
        return 1
    else:
        return -1
Exemple #5
0
def safePrime_worker(nBits: int = 1024,
                     randomFunction=None,
                     easyGenerator: bool = False,
                     Verbose: bool = False,
                     flag=None,
                     returnL: list = []):
    """
    Function executed on each process for safe prime generation
    """

    import ressources.interactions as it
    from multiprocessing import Manager

    if not flag:
        flag = Manager().Value("i", 0)

    if easyGenerator:
        if Verbose:
            print("Easy generator choosen.")

        p_filter = lambda p: p % 3 == 2 and (
            p % 12 == 1 or p % 12 == 11
        )  # p = 1 mod 12 make 11 as primitive root

    else:

        p_filter = lambda p: p % 3 == 2

    while not bool(flag.value):
        # For faster searching
        # Calculate 2q +1 and (q-1)//2
        # Return Sophie Germain's prime according to what is prime.

        if randomFunction is None:
            randomFunction = randomInt

        q = randomPrime(nBits, randomFunction, p_filter, 1)

        p1 = 2 * q + 1

        p2 = (q - 1) // 2

        if Verbose:
            it.clear()
            print(f"Prime {q} candidate's.")

        if millerRabin(p1):

            if Verbose:
                print("q is prime and 2q +1 too.")
                print(f"\nSophie Germain prime's: {q}\n")

            sophieGermain_prime, safe_prime = q, p1

            # Safe prime found
            flag.value = 1
            returnL.append((safe_prime, sophieGermain_prime))

        elif millerRabin(p2):

            if Verbose:
                print("q is prime and (q-1)/2 too.")
                print(f"\nSophie Germain prime's: {p2}\n")

            sophieGermain_prime, safe_prime = p2, q

            # Safe prime found
            flag.value = 1
            returnL.append((safe_prime, sophieGermain_prime))

        else:
            if Verbose:
                print(
                    "But 2 * him + 1 and (him - 1) / 2 doesn't seem to be primes...\n"
                )
Exemple #6
0
def phi(n: int, m: int = 1, k: int = 1, Verbose: bool = False):
    """
    Totient recurcive function for integer n.
    Can compute:
        phi(n*m) with phi(n, m).
        phi(p^k) with phi(p, 1, k)
    """

    if Verbose:
        print(f"\n----------- phi(n={n}, m={m}, k={k})--------------")
    ## Special cases ##
    twoN = n // 2

    if m != 1:

        d = ut.euclid(n, m)
        if Verbose:
            print(f"gcd({n}, {m}) = {d}")
            print(f"phi({n})*phi({m})*({d}/phi({d}))")
        return phi(n, 1, k, Verbose) * phi(m, 1, k, Verbose) * int(
            (d / phi(d, 1, k, Verbose)))

    elif k != 1:
        # phi(n^k) = n ^(k-1) * phi(n)

        mult = ut.square_and_multiply(n, k - 1)

        if Verbose:
            print(f"phi(n^k) = n ^(k-1) * phi(n) = {mult} * phi({n})")

        return mult * phi(n, 1, 1, Verbose)

    else:
        if n >= 0 and n <= 123:
            # Fastest results for common totients (sequence A000010 in the OEIS)
            totients = [
                0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18,
                8, 12, 10, 22, 8, 20, 12, 18, 12, 28, 8, 30, 16, 20, 16, 24,
                12, 36, 18, 24, 16, 40, 12, 42, 20, 24, 22, 46, 16, 42, 20, 32,
                24, 52, 18, 40, 24, 36, 28, 58, 16, 60, 30, 36, 32, 48, 20, 66,
                32, 44, 24, 70, 24, 72, 36, 40, 36, 60, 24, 78, 32, 54, 40, 82,
                24, 64, 42, 56, 40, 88, 24, 72, 44, 60, 46, 72, 32, 96, 42, 60,
                40, 100, 32, 102, 48, 48, 52, 106, 36, 108, 40, 72, 48, 112,
                36, 88, 56, 72, 58, 96, 32, 110, 60, 80, 60, 100, 36, 126, 64,
                84, 48, 130, 40, 108, 66, 72, 64, 136, 44, 138, 44, 138, 48,
                92, 70, 120
            ]

            r = totients[n]

            if Verbose:
                print(f"\nCommon totient phi({n}) = {r}")

            return r

        elif ut.millerRabin(n):
            # n is a prime number so phi(p) = (p-1)
            # p^(k-1) * phi(p) = p^(k-1) * (p-1)

            if Verbose:
                print(f"\n{n} is a prime number so phi(p) = (p-1)")

            return (n - 1)

        # If even:
        elif not twoN & 1:
            if Verbose:
                print(f"\nphi({n}) = phi(2*{twoN}) = 2 * phi({twoN}).")
            return 2 * phi(twoN, m, k, Verbose)

    ## Special cases ##
        else:

            if Verbose:
                print(f"\nLet's calculate phi({n}) with prime factors way.\n")

            tot = n
            if Verbose: print("Generating primes factors ...\n")
            for factor in ut.findPrimeFactors(n):
                if Verbose: print(f"Factor : {factor}")
                tot -= tot // factor

            return tot
Exemple #7
0
def isGenerator(e: int,
                n: int,
                lagrangeWay: bool = True,
                printOther: bool = False,
                Verbose: bool = False):
    """
    Returns whether an element e is generator of Zn.
    A unit g ∈ Zn* is called a generator or primitive root of Zn* if for every a ∈ Zn* we have g^k = a for some integer k. 
    In other words, if we start with g, and keep multiplying by g eventually we see every element.
    By definition, g is a generator of Zn* if and only if that cycling does not occur before these n−1 iterations.

    lagrangeway is by default set to true.
    Base on the fact than as a consequence of Lagrange's theorem, ordn(e) always divides φ(n).
    If ordn(e) is actually equal to φ(n), and therefore as large as possible, then e is called a primitive root modulo n.
    """

    if lagrangeWay:

        totient = phi(n, 1, 1, Verbose)
        order = multiplicativeOrder(e, n, False, Verbose)

        if Verbose:
            print(
                f"\nIf phi({n}) is equal to mutliplicative order of {e} modulo {n} then it's a generator of {n}."
            )
            print(f"phi(n) = {totient} and order(e, n) = {order}.\n")

        if totient == order:

            if printOther:

                if Verbose:
                    print(f"There are {phi(phi(n))} generators in Z{n}.")
                    print(f"{e} is the a generator of Z{n}.\n")

                return True, findOtherGenerators(e, n, Verbose)

            return True
        else:
            return False

    else:
        if not ut.millerRabin(n):
            # Slowest way, keeped to verify results
            elements = []
            for i in range(1, n):
                t = ut.square_and_multiply(e, i, n)

                if t in elements:
                    continue
                else:
                    if Verbose:
                        print(f"\n{e}^{i} = {t} mod {n}")

                    #if cycling occurs
                    if t == 1 and t in elements:
                        return False
                    else:
                        elements.append(t)

            if printOther:
                if Verbose:
                    print(f"There are {phi(phi(n))} generators in Z{n}.")
                    print(
                        f"{e} is the a generator of Z{n} with elements: {elements}\n"
                    )

                return True, findOtherGenerators(e, n, Verbose)

            if Verbose:
                print(f"There are {phi(phi(n))} generators in Z{n}.")
                print(
                    f"{e} is the a generator of Z{n} with elements: {elements}\n"
                )

            return True

        elif e % n != 0:
            # We can test if some g not divisible by p is a generator of Zp*
            # by checking if g^k mod p != 1
            # with k = (p-1)/q for q each of prime factors of p-1

            L = ut.findPrimeFactors(n - 1)

            if Verbose:
                print(
                    f"{e} doesn't divide {n}, let's check if {e}^k mod {n} != 1."
                )
                print(
                    f"With k = ({n} -1 ) / q for q each of prime factors of {n}-1 ( = {L})."
                )

            for k in L:
                t = ut.square_and_multiply(e, k, n)
                if Verbose:
                    print(f"\n{e}^{k} = {t} mod {n}")
                if t == 1:
                    return False

            if printOther:
                if Verbose:
                    print(f"There are {phi(phi(n))} generators in Z{n}.")

                return True, findOtherGenerators(e, n, Verbose)

            return True
Exemple #8
0
def primitiveRoot(n: int, totient=None, Verbose: bool = False):
    """ 
    Returns primitive root modulo n.

    https://en.wikipedia.org/wiki/Fermat%27s_little_theorem
    """

    if totient == None:
        totient = phi(n, 1, 1, Verbose)

    if Verbose:
        print(f"Phi({n}) = {totient}\n")

    if n > 3 and ut.millerRabin(n):

        q = (n - 1) // 2

        if Verbose:
            print(f"\n{n} is a prime number.")

        # To deal with safe prime
        if ut.millerRabin(q):

            if Verbose:
                print(f"{n} is a Safe Prime! Because {q} prime too.")
                print("Choose random number between g [2, p-1]")

            import random as rd

            g = rd.randrange(2, n)

            if Verbose:
                print(
                    "To verify if g is a generator, you have to verify than g^2 and g^q are differents from 1."
                )

            while 1 in [
                    ut.square_and_multiply(g, 2, n),
                    ut.square_and_multiply(g, q, n)
            ]:
                g = rd.randrange(2, n)
            else:
                if Verbose:
                    print(f"{g} is a generator of Z{n}*.")
                return g

        else:
            if Verbose: print(f"Let's find all prime factors of {totient}:")
            s = ut.findPrimeFactors(totient)

            if Verbose:
                print("\n-----------------------------")
                print(f"{n} is prime and prime factors of totient are: {s} ")
                print(
                    f"Computing all g^(phi({n})/p_i) mod {n} with p_i prime factors."
                )
                print(
                    f"If all the calculated values are different from 1, then g is a primitive root."
                )
                print("-----------------------------")

            for e in range(2, totient + 1):

                # Iterate through all prime factors of phi.
                # and check if we found a power with value 1
                flag = False

                for it in s:
                    t = ut.square_and_multiply(e, totient // it, n)

                    if Verbose:
                        print(f" {e}^(phi({n})/{it}) mod {n} = {t} ")

                    if t == 1:
                        flag = True
                        break

                if not flag:
                    if Verbose:
                        print(f"Generator is: {e}")
                    return e
            # If no primitive root found
            return -1
    else:
        if Verbose:
            print(
                f"\nAccording to Euler's theorem, a is a primitive root mod {n} if and only if the multiplicative order of a is ϕ(n) = {totient}."
            )

        for e in range(1, n):
            o = multiplicativeOrder(e, n, Verbose)

            if Verbose:
                print(f"\nMultiplicative order({e}, {n}) = {o} \n")

            if o == totient:
                if Verbose:
                    print(f"Generator is: {e}")
                return e

        # If no primitive root found
        if Verbose:
            print(
                f"Since there is no number whose order is {totient}, there are no pritive roots modulo {n}."
            )
        return -1