# Some builtin functions for number theory
is_prime(2^603-1) # tests whether a number is prime
# much more efficient than trial division
next_prime(21) # returns next prime bigger than n
next_prime(23) # returns first prime bigger than n
next_prime(2^100)
is_prime(1267650600228229401496703205653)
is_prime(next_prime(2^1000)) # takes a few seconds
power_mod(2,5,29) # power_mod(a,e,n) computes a^e % n (same thing as exp_mod)
randint(1,1000) # NOT cryptographically secure
# Diffie-Helmann algorithm for key-exchange
# Step 1: generate p prime
# Alice, Bob will know this (so will Eve)
p = next_prime(2^10);p
# Step 2: Alice and Bob each pick secret numbers (best to use random)
# Alice:
a = randint(1,2^10); print(a)
# Bob:
b = randint(1,2^10); print(b)
# Step 3: Alice and Bob each do a computation using the secret number
# Alice:
c = power_mod(3,a,p); print(c)
# Bob:
d = power_mod(3,b,p); print(d)
# Step 4: Alice sends Bob c,
# and Bob sends Alice d
# Eve (the eavesdropper) can see these
# Step 5: Both Alice and Bob can compute the same number, which is 3^(ab) mod p
# Alice:
KA = power_mod(d,a,p); print(KA)
# Bob:
KB = power_mod(c,b,p); print(KB)
# Why can't Eve also find K = KA = KB?
# She knows p, c = 3^a mod p, and d = 3^b mod p, since she sees the communication between Alice, Bob
# She also knows that that 3 is the base being used.
# But it is not easy to compute 3^(ab) mod p from this info.
# One approach would be to use 'brute-force' to find a, b by going through all the possiblilites and
# testing if 3^a mod p equals c for that guess of a. But there are so many possibilities
# for a that this would not be feasible.
# Fermat's little theorem
# a^(p-1) = 1 mod p, for any prime p, and any a not divisible by p
power_mod(3,16,17)
power_mod(4,28,29)
# Euler's theorem
# a^phi(n) = 1 mod n, for any n, a relatively prime to n
power_mod(4, euler_phi(9), 9)
power_mod(5, euler_phi(99), 99)
# phi(n) is the number of integers between 1,n that are relatively prime to n
euler_phi(9)