# copied from last time
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
# Alice does Setup stage
# Choose large primes
p = next_prime(2^100 + randint(1,10000)); p
q = next_prime(2^100 + randint(1,2^99)); q
n=p*q; n
e = 17; gcd(e, (p-1)*(q-1)) # if not 1, choose new e
(a,b,c) = xgcd(e, (p-1)*(q-1)); (a,b,c)
b*e + c*(p-1)*(q-1) # so b is the inverse of e mod (p-1)(q-1)
d = b % ((p-1)*(q-1)); d # d is b reduce mod (p-1)(q-1)
# public key = (e,n)
# private key = d
# Setup stage is complete
# Bob encrypts message m
m = 1234567891212
c = exp_mod(m,e,n); c # The ciphertext that Bob sends to Alice
# Alice decrypts:
exp_mod(c,d,n) # should equal original message
factor(n)
# this takes a couple seconds,
# so for secure use, primes should be bigger
%%time
next_prime(2^1024 + randint(1,10000))
# 1024-bit primes are often used
%%time
# test how long factoring takes
factor(next_prime(2^50 + randint(1,10000))\
*next_prime(2^50 + randint(1,2^10)))
# Suppose Eve knows message is either m=10, 11
# She intercepts a ciphertext c.
# Wants to know which m it corresponds to.
# Eve knows public key, so she can try encrypting
# 10 and 11, and see which one messages the intercepted c.
m1 = 10
c1 = exp_mod(m1,e,n); c1
m2 = 11
c2 = exp_mod(m2,e,n); c2
# Always use random padding at end of message
# This also makes sure that m^e is big (much bigger than n)