Week 8 notes

Comp 163-002, Spring 2020, MWF, 12:35-1:25, in Mundelein 620

The primary goal of this course is to become familiar with some of the basic mathematical ideas used in programming.


5.2: Number Theory

Revised proof of Fermat's "little" theorem ∀a≠0  ap-1 ≡ 1 (mod p)

The order of a ∈ Zp is the smallest k>0 such that ak ≡ 1 (mod p)

There always is such a k. The set {a, a2, a3, ... } cannot be infinite, so there are i and j, i<j, so ai ≡ aj. But then aj-i ≡ 1 mod p.

The next step is to prove that order(a) divides p-1. That's it!

Let A = {a, a2, a3, ... }. We show that we can partition {1,...,p-1} into multiple disjoint sets each the same size as A. That proves |A| divides p-1.

    Z13 example    3 has order 3, 5 has order 4. A = A5 = {5, 12, 8, 1}.

    2A = {10, 11,  3,  2}
    3A = {2,  10, 11,  3}
    4A = {7,   9,   6,   4}
    5A = {12, 8,   1,  5}
    6A = {4,   7,   9,  6}
    7A = {9,   7,   4,  7}

# returns the list a, a*a, a^3, ..., a^n, all mod n
def powerlist(a,n):
    lis = []
pow = a % n
    lis.append(pow)
    while True:
pow = a*pow % n
        lis.append(pow)
if pow == 1: break
    return lis

Diffie-Hellman-Merkle key exchange.

How can Alice and Bob exchange public data and end up with a number that each knows, but which is not something an eavesdropper can find?

Let p=10007 and let g=5. I picked g because it has order p-1 modulo p.

Alice picks a, and Bob picks b, at random, say a=2418 and b = 5071.

Alice calculates A = ga and Bob calculates B= gb, both mod p. This can be done quickly with repeated squaring.

def power(x,e,n):  # computes x^e mod n
    pow = 1
    while e>0:
       if e%2 == 1: pow = pow*x % n
       x = x*x % n
       e = e//2    # // denotes integer division
    return pow

Alice gets A=1244 and Bob gets B=1994. They then exchange these values. Then Alice calculates Ba = 2479 and Bob calculates Ab = 2479.

Why are these equal? Both are equal to ga*b.

Now suppose Mal wants to figure out this number. Mal knows ga. However, to retrieve a from this is pretty much trial and error; there is no efficient way to calculate "logarithms" mod p. There are 10006 values to try. Mal could do that. But what if p is one of the 1024-bit primes below:

p1=114902778697775519243807582051986688206847636430271634702090657275218782716669464081032413884549344387394094087259661654561022881327078127526384809970858979402103006488401086094663281066582049708990541731967260736593494404957317697229498732453262923700475346089068944768390560557693732452373340611891958308767
p2=129651718124678942765016021538496745064647313888372133585127299150859811165629622930013191157953033177630211720672149680439864625436496084772520694105903693008684888736409307947154035655552124537557394420237669184331457034861315538355045456127862243908432618239395413896768931129135699998148774027350339433807
p3=151411492943903525609159107145531406770633646696963185633236924633911832081036003031702063446653228002679225218550123734827047095217950004631562077061399454195110745548303886078631576580775359988946688323293943535764774586171656801705899544663796306356213080590904250975733938158955953730614248028384783770231
p4=161544667656054348363670806479142750827145269232707609926486480974617939756921910563751432024988427071665740937104815499857383413860057098052108342878109563493606496842708022250662702555047793114379471958451772222496672257164937505127026521511592892670705383853224735942627931798116107444487204168945425126021

At this point trial-and-error is impossible. But Alice and Bob can still calculate ga and gb very quickly!

But how can somebody quickly determine that the values above are in fact primes? It turns out there are fast primality checks. But nobody has discovered a fast logarithm calculation.

What can we do modulo 35? For multiplications to have inverses, we need numbers a that are relatively prime to 35. (For primes, that's all the numbers from 1 to p-1 automatically). For 35, we have to skip multiples of 5 and of 7: {0,5,7,10,14,15,20,21,25,28,30}. The number of values remaining is (5-1)*(7-1) = 24.