Ejemplo n.º 1
0
def signing(M: bytes,
            privateK: tuple = None,
            saving: bool = False,
            Verbose: bool = False):
    """
    Signing a message M (bytes).
    """

    from ..hashbased import hashFunctions as hashF

    # y choosed randomly between 1 and p-2 with condition than y coprime to p-1
    if not privateK:
        privateK = it.extractKeyFromFile("private_key")

    p, g, x = privateK

    size = it.getKeySize(privateK)

    # M = bm.fileToBytes(M)
    # M = "Blablabla".encode()

    if Verbose:
        print("Hashing in progress...")

    hm = hashF.sponge(M, size)
    # #base64 to int
    hm = bm.bytes_to_int(bm.mult_to_bytes(hm))

    if Verbose:
        print("Hashing done.\n")

    p1 = p - 1

    k = rd.randrange(2, p - 2)

    while not ut.coprime(k, p1):
        k = rd.randrange(2, p - 2)

    if Verbose:
        print(f"Your secret integer is: {k}")

    s1 = ut.square_and_multiply(g, k, p)

    s2 = (multGroup.inv(k, p1) * (hm - x * s1)) % p1

    # In the unlikely event that s2 = 0 start again with a different random k.

    if s2 == 0:
        if Verbose:
            print("Unlikely, s2 is equal to 0. Restart signing...")
        signing(M, privateK, saving, Verbose)

    else:
        sign = (s1, s2)

        if saving:
            sign = it.writeKeytoFile(sign, "elG_signature")

        return sign
Ejemplo n.º 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
Ejemplo n.º 3
0
def carmichaelFunction(n):
    """
    The Carmichael function associates to every positive integer n a positive integer λ(n), defined as the smallest positive integer m such that
    a^m ≡ 1   (mod n)
    for every integer a between 1 and n that is coprime to n. In algebraic terms, λ(n) is the exponent of the multiplicative group of integers modulo n.

    https://mathworld.wolfram.com/CarmichaelFunction.html
    """
    return max(multiplicativeOrder(a, n) for a in range(n + 1) if ut.coprime(a, n))
Ejemplo n.º 4
0
def key_gen(size: int = 2048, randomFunction=None, saving=False, Verbose=False):
    """
    RSA key generation.

    n: number of bits for safe prime generation.\n

    randomFunction: prng choosen for random prime number generation (default = randbits from secrets module).

    As a transitional measure, the use of RSA-based signature and confidentiality mechanisms with a key size of at least 2000 bits remain conform for the year 2023.

    saving: True if you want to save the private key to a file.
    """

    sizeB = size // 2

    # 1- Choose two distinct prime numbers p and q

    if Verbose:
        print(f"Let's try to generate two distinct prime numbers p and q of {size} bits.")

    p, q = prng.randomPrime(sizeB, randomFunction, Verbose=Verbose), prng.randomPrime(sizeB, randomFunction, Verbose=Verbose)

    # 2- Compute n = pq.
    n = p * q  # new modulus

    # 3- Compute λ(n), where λ is Carmichael's totient function.
    # since p and q are prime, λ(p) = φ(p) = p − 1 and likewise λ(q) = q − 1. Hence λ(n) = lcm(p − 1, q − 1).
    carmichaelTotient = ut.lcm(p - 1, q - 1)

    # 4- Choosing e, part of the public key
    e = rd.randrange(1, carmichaelTotient)

    while not ut.coprime(e, carmichaelTotient) or bm.hammingWeight(e) > (0.995 * sizeB):
        e = rd.randrange(1, carmichaelTotient)
        # e having a short bit-length and small Hamming weight results in more efficient encryption
        # https://en.wikipedia.org/wiki/Hamming_weight

    # 5- Chossing d, modular multiplicative inverse of e modulo carmichaelTotient(n)
    d = multGroup.inv(e, carmichaelTotient)  # Private Key exponent

    #  p, q, and λ(n) must also be kept secret because they can be used to calculate d. In fact, they can all be discarded after d has been computed.
    del p, q, carmichaelTotient

    public_key, private_key = (n, e), (n, d)

    if saving:
        public_key = it.writeKeytoFile(public_key, "public_key", config.DIRECTORY_PROCESSING, ".kpk")
        it.writeKeytoFile(private_key, "private_key", config.DIRECTORY_PROCESSING, ".kpk")

    if Verbose:
        print("\nYour private key has been generated Bob, keep it safe and never distibute them !")
        print("\nThe public key has been generated, send this to your Alice: ", end="")

        it.prGreen(public_key)

    if not saving:
        return (public_key, private_key)
Ejemplo n.º 5
0
def congruenceClasses(e: int):
    """
    Returns coprimes elements of e.
    If n is a positive integer, the integers between 0 and n − 1 that are coprime to n (or equivalently, the congruence classes coprime to n) form a group.
    """
    elements = []
    for i in range(e):
        if ut.coprime(i, e) and i not in elements:
            elements.append(i)

    return elements