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 generate_keys():
    '''Alice builds a dicsrete-log public-key cipher system.

    '''

    cyclic_group = large_random_prime()
    generator = random_near_primitive_root(cyclic_group)
    private_key = random.randint(1, cyclic_group - 1)
    public_key = fast_exponentiation(generator, private_key, cyclic_group)

    return (generator, public_key, cyclic_group), private_key
def miller_rabin(n, b):
    '''Miller-Rabin test for primality.
    
    '''

    r = 0
    m = n - 1
    while m % 2 == 0:
        r += 1 
        m = m / 2
    if fast_exponentiation(b, m, n) in (n - 1, 1):
        return True
    power = 1
    while power < r - 1:
        b_m_squared_mod_n = fast_exponentiation(b, m * (2 ** power), n)
        if b_m_squared_mod_n == 1:
            return False
        elif b_m_squared_mod_n == n - 1:
            return True
        else:
            power = power * 2
    return False
    def test_attack_elgamal(self):
        #Alice

        p = 1009
        b = 101
        c = 482
        l = discrete_log(prime=p,
                         primitive_root=b,
                         public_key=c)
        
        #Bob
        x = 559
        r = 291
        c_to_the_r = fast_exponentiation(c, r, p)
        encrypted_message = x * c_to_the_r % p
        header = fast_exponentiation(b, r, p)        
        
        decrypted_message = decrypt(encrypted_message, header, l, p)
        
        print attack_elgamal(_primitive_root=b,
                             _public_key=c,
                             _prime=p,
                             message=encrypted_message,
                             header=header)
def primitive_root(group, divisors, prime):
    for q in divisors:
        if fast_exponentiation(group, (prime - 1) / q, prime) == 1:
            return False
    return True
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 encrypt(message, b, c, p):
    r = large_random_prime()
    c_r = fast_exponentiation(c, r, p)
    encrypted_message = message * c_r % p
    header = fast_exponentiation(b, r, p)
    return encrypted_message, header
def encrypt(n, encrypt_key, message):
    return fast_exponentiation(message, encrypt_key, n)
def decrypt(encrypted_message, decrypt_key, n):
    return fast_exponentiation(encrypted_message, decrypt_key, n)