In [1]:
# copied from last time
# will be useful for key exhange
def exp_mod(a,e,b):
    """Return a^e % b, computed using repeated squaring."""
    
    bin_rep=bin(e) # first find binary representation of e 
    prod = 1    
    cur_pow_two = a # this will run through a^(2^0), a^(2^1), a^(2^2),...
    for i in range(len(bin_rep)-2): 
        if bin_rep[-1-i]=='1':
            prod = prod * cur_pow_two % b # multiply by cur_pow_two if the corresponding bit is 1
        cur_pow_two = (cur_pow_two)^2 % b  
    return prod

# runtime (for fixed a,b) is approx number of bits of e
In [2]:
# exp_mod is very fast
exp_mod(3, 2^1000,11)
Out[2]:
3
In [3]:
# Diffie-Helmann algorithm for key exchange
In [4]:
p = next_prime(2^200); p # Alice, Bob agree on p
Out[4]:
1606938044258990275541962092341162602522202993782792835301611
In [5]:
#Alice chooses e
e = randint((p+1)/2,p); e
Out[5]:
987809857206351872800037583613466286724519509253371117488952L
In [6]:
# Bob chooses d
d = randint((p+1)/2,p); d
Out[6]:
1491263715907023267276609911398896564541731640320921037164179L
In [7]:
# Alice computes 3^e mod p
alice_to_bob = exp_mod(3,e,p)
# sends to Bob; Eve also sees 
In [8]:
# Bob computes 3^d mod p 
bob_to_alice = exp_mod(3,d,p)
# sends to Alice; Eve also sees 
In [9]:
# Alice knows p,e,bob_to_alice
# She computes the shared secret:
exp_mod(bob_to_alice,e,p)
Out[9]:
1402878183291959712207425945423548726661941353636085432238591
In [10]:
# Bob knows p,d,alice_to_bob
# He computes the shared secret: 
exp_mod(alice_to_bob,d,p)
Out[10]:
1402878183291959712207425945423548726661941353636085432238591
In [11]:
# both compute the same number
# can use as key in a symmetric key system
In [12]:
# Eve sees p, alice_to_bob, bob_to_alice
# To compute shared secret, she would need
# to solve a discret log problem to find d or e
# Doing this is very hard (not practically feasible)