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 isxxxxxxxxxx
''.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 modxxxxxxxxxx
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
so we can decode via
xxxxxxxxxx
''.join([decode(271*(x-18)%677) for x in code])
xxxxxxxxxx
message='hiphiphooray'
a = 5
b = 18
secret=[encode(message[2*i:2*i+2]) for i in range(len(message)/2)]
n = 677
ainv = mod(a,n)^-1
code=[(a*x+b)%n for x in secret]
print(''.join([decode(m) for m in code]))
print(''.join([decode(ainv*(x-b)%n) 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))]