def exp_mod(a,e,b):
"""Returns a^e mod b, using repeated squaring and binary expansion.
Computes same thing as exp_mod from last time, but much faster"""
bin_rep = bin(e)[2:] # gets rid of '0b' from the binary expansion
prod = 1 # keep track of the current product
cur_a_powtwo = a % b # keeps track of a^(2^i) for higher and higher i
for i in range(len(bin_rep)):
if bin_rep[-1-i]=='1': # gets ith from last element in bin rep
prod = prod * cur_a_powtwo % b # if corresponding bit is 1,
# multiply prod by the current a^(2^i)
cur_a_powtwo = (cur_a_powtwo)^2 % b # repeated squaring step
return prod