Section 11.2 Encryption
ΒΆSage note 11.2.1. Reminder to evaluate definitions.
Don't forget to evaluate the first cell of commands so we can use words as messages instead of just numbers.
xxxxxxxxxx
def encode(s): # Input must be in quotes!
s = str(s).upper()
return sum((ord(s[i])-64)*26^i for i in range(len(s)))
β
def decode(n):
n = Integer(n)
list = []
while n != 0:
if n%26==0:
list.append(chr(64+26))
n -= 1
else:
list.append(chr(n%26+64))
n //=26
return ''.join(list)
Subsection 11.2.1 Simple ciphers
ΒΆIn the past, one would usually assume that both the sender and the receiver keep their keys secret (seems reasonable!), which is called symmetric key cryptography. The symmetry is that both people need to keep it secret. One early example of this supposedly goes back to C. Julius Caesar. To encrypt a message, first convert it to numbers, and then add three to each number (βwrapping aroundβ as in modular arithmetic if needed), and convert back to letters.xxxxxxxxxx
message='MathIsCool'
secret=[encode(letter) for letter in message]
secret
xxxxxxxxxx
code=[(x+3)%26 for x in secret]
print(code)
print(''.join([decode(m) for m in code]))
Subsection 11.2.2 Decryption and inverses
ΒΆHow will I decrypt it, if I get this mysterious message? Here is the main point about mathematical ciphers; they need to come from operations that have inverses! So in number theoretic ciphers, they'll need to come from (somehow) invertible operations. In this case, the operation is modular addition, which certainly has inverses. If your encoded numerical message is x, your key is a, and you are working modulo (n), then your encrypted message m is
mβ‘x+a mod(n)
To get x back, you just use the additive inverse to a modulo n, which is βa.
Since β3 is the inverse of 3, this one is easy to decipher.
xxxxxxxxxx
''.join([decode((x-3)%26) for x in code])
xxxxxxxxxx
message='Mathiscool'
secret=[encode(message[2*i:2*i+2]) for i in range(len(message)/2)]
secret
Subsection 11.2.3 Getting more sophisticated
ΒΆLet's do something a little more interesting to encrypt our βsecretβ about how cool math is. What else has inverses? Well, sometimes multiplication mod (n) does! We could make a cipher that gets m by performing
mβ‘ax+b (mod n).
Here, let's choose a=5 and b=18; we'll use n=677, the next prime after 262, since we have blocks of two letters each.
xxxxxxxxxx
n = next_prime(26^2)
code=[(5*x+18)%n for x in secret]
print(code)
print(''.join([decode(m) for m in code]))
Fact 11.2.2.
To make modular encryption by a linear function workable, we need gcd(a,n)=1. In that case there is a number aβ² such that
a(aβ²)β‘1 (mod n),
so we can decode via
mβΌaβ²(mβb)β‘x (mod n).
xxxxxxxxxx
''.join([decode(271*(x-18)%677) for x in code])
Subsection 11.2.4 Linear algebra and encryption
ΒΆThere is another way of using blocks of size two or more, which we won't pursue very far, but which is a big piece of how standard encryption works (see here and here). Let's look at our message again.xxxxxxxxxx
message='Mathiscool'
secret=[encode(letter) for letter in message]
secret
xxxxxxxxxx
[(secret[i]+secret[i+1])%26 if i%2==0 else secret[i] for i in range(len(secret))]
(1101)
To invert this cipher, we would need an inverse to this matrix modulo 26. (People don't do something quite so naive, as there aren't too many inverses modulo 26, but for our purposes this suffices.)
In any case, this is another connection to the rest of mathematics! And it is a huge reason why linear algebra over finite algebraic structures is very important in security.