def discrete_log(prime, public_key, primitive_root):
    m = int(math.floor((prime - 1) ** .5))
    base_exponents = {}
    for j in xrange(0, m):
        base_exponents[fast_exponentiation(primitive_root, j, prime)] = j
    
    inverse_b = extended_euclidean_algorithm(primitive_root, prime) % prime
    c = fast_exponentiation(inverse_b, m, prime)
    x = public_key
    for i in xrange(0, m):
        if x in base_exponents:
            return (m * i) + base_exponents[x] 
        else:
            x = (x * c) % prime
def decrypt(message, header, l, p):
    c_r = fast_exponentiation(header, l, p)
    inverse = extended_euclidean_algorithm(c_r, p)
    plaintext = (inverse * message) % p
    return plaintext
def multiplicative_inverse(phi_n, key):
    inverse_n = extended_euclidean_algorithm(phi_n, key)
    inverse_n = inverse_n % phi_n
    return inverse_n