Sm473 Crypto Lecture Notes
Sm473 Crypto Lecture Notes
Information Security
sm473 class notes
Prof David Joyner, [email protected]
January 9, 2015
Contents
1 Security terminology and concepts 7
3 Substitution cipher 26
4 Bifid cipher 29
1
8 PK Cryptosystems 56
8.1 RSA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
8.1.1 Set up and examples . . . . . . . . . . . . . . . . . . . 57
8.2 Kid RSA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
8.3 Breaking Kid RSA . . . . . . . . . . . . . . . . . . . . . . . . 63
8.4 The discrete log problem . . . . . . . . . . . . . . . . . . . . . 64
8.5 Diffie-Hellman-Merkle key exchange . . . . . . . . . . . . . . . 64
8.6 ElGamal encryption . . . . . . . . . . . . . . . . . . . . . . . 66
9 Stream ciphers 67
9.1 Binary stream ciphers . . . . . . . . . . . . . . . . . . . . . . 67
9.2 Background on solving recurrence equations . . . . . . . . . . 69
9.3 Matrix reformulation . . . . . . . . . . . . . . . . . . . . . . . 70
9.4 Linear feedback shift registers . . . . . . . . . . . . . . . . . . 76
9.5 Computations with LFSRs . . . . . . . . . . . . . . . . . . . . 80
9.6 Blum-Blum-Shub (BBS) stream cipher . . . . . . . . . . . . . 90
10 Bent functions 91
10.1 Functions with a given least support . . . . . . . . . . . . . . 91
10.2 Cipherstreams via a filter function . . . . . . . . . . . . . . . . 92
10.3 The Walsh transform . . . . . . . . . . . . . . . . . . . . . . . 95
11 Error-correcting codes 99
11.1 The communication model . . . . . . . . . . . . . . . . . . . . 99
11.2 Basic definitions . . . . . . . . . . . . . . . . . . . . . . . . . . 100
11.3 Binary hamming codes . . . . . . . . . . . . . . . . . . . . . . 104
11.4 The covering radius . . . . . . . . . . . . . . . . . . . . . . . . 107
12 Steganography 109
12.1 Basic terminology . . . . . . . . . . . . . . . . . . . . . . . . . 110
12.2 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
2
From Wikipedia: Set on Sullivan’s Island, South Carolina, the plot follows
William Legrand, who was recently bitten by a gold-colored bug. His ser-
vant, Jupiter, fears Legrand is going insane and goes to Legrand’s friend,
an unnamed narrator, who agrees to visit his old friend. Legrand pulls the
other two into an adventure after deciphering a secret message that will lead
to a buried treasure.
3
time to crack an enemy WWII code and solve the mystery surrounding the
woman he loves.
• The Thomas Beale Cipher (2010, short film), directed by Andrew Allen
(https://vimeo.com/19115071),
IMDB logine: Professor White, cryptographer extraordinaire, is on the trail
of the notoriously uncrackable Thomas Beale cipher, a century-old riddle
hiding the location of a fortune in gold. But White is not alone-shadowy
forces are tight on his tail.
4
In 2010, there was even an AMC TV series Rubicon (http://en.wikipedia.
org/wiki/Rubicon_(TV_series) featuring a running theme of messages hid-
den in newpaper crossword puzzles.
Cryptography is all around us, any time secrecy is a goal.
Error-correcting codes are all around us as well. A sender uses an error-
correcting code on a message when thay want that message to arrive in a
readable form. The communication channel might have noise, but by encod-
ing the message with an error-correcting code, enough redundancy is added
so that the receiver can recover the original message from the possible cor-
rupted data they received. Reliable communication, at a low cost, is the goal
here. Cell-phones, music CDs, video DVDs, all use error-correcting codes.
There is another type of code which we won’t study here much. Codes
were developed by communication companies to send information in a more
compressed format (e.g., telegraph companies made telegraph codes, data
processing companies made ASCII codes, etc). Here is some Python code for
converting back-and-forth between ascii and letter strings:
Sage
def num2bin(x):
"""
Converts integer in range (1,255) to binary.
EXAMPLES:
sage: num2bin(129)
[1, 0, 0, 0, 0, 0, 0, 1]
"""
return [floor(x/2**(7-i))%2 for i in range(8)]
def string2ascii(m):
"""
Converts a string of characters to a sequence of
0’s and 1’s using the Python ord command.
"""
L = []
for a in m:
L.append(ord(a))
M = [num2bin(x) for x in L]
return flatten(M)
def ascii2string(M):
"""
M is a ciphertext message of 0’s and 1’s of length 8k.
This returns a string of characters representing that
list in ascii.
"""
m = len(M)
5
k = int(m/8)
S = []
for i in range(k):
s = sum([2**(7-j)*M[8*i+j] for j in range(8)])
S.append(chr(s))
sumS = ""
for s in S:
sumS = sumS + s
return sumS
attach "/mypath/classical-ciphers-examples.sage"
at the command line or into a cell of the notebook. (Here mypath is the
full path to whereever you saved the file to.) For the SymPy commands, the
commands are included in version 0.7.4 or later of SymPy, available from the
sympy website. For windows installation, you may wish to try
http://nipy.bic.berkeley.edu/sympy-dist/
6
1 Security terminology and concepts
Basic setup: A cryptosystem is a collection of
Ek : P → C,
a corresponding deciphering key k 0 ∈ K, and a deciphering map
Dk0 : C → P,
such that
Dk0 ◦ Ek (p) = p,
for any p ∈ P.
You should know all these and be able to provide examples (when appro-
priate).
1. Basic terms
7
(b) key - a parameter that determines the output of a cryptographic
algorithm. A key is used as part of the enciphering (and decipher-
ing) process.
In asymmetric cryptosystems, keys are divided into two parts -
the private key and the public key. In general, some part of the
key must be kept secret.
(c) key space - the set of all possible keys
(d) encrypt/encipher - disguising the plaintext in some way, using the
key, resulting in ciphertext
(e) ciphertext - the result of encryption (depends on the key)
(f) decrypt/decipher - the process of ”undoing” the encryption, (“usu-
ally”) resulting in the original plaintext
(g) cryptosystem - the combined systems of the encryption and de-
cryption algorithms
(h) cryptanalysis ((from the Greek “hidden, secret” and “to untie”) -
the art and science of “attacking” or “breaking” cryptosystems
(i) cryptography or cryptology - (from Greek “study of hidden or
secret writing”) the practice and study of techniques for secure
communication in the presence of third parties
(j) attack or break - an method of cryptanalysis applied to a spe-
cific cryptosystem which circumvents the decryption algorithm
and tries to recover the key or the plaintext.
(k) Brute force attack is a search through the entire keyspace to de-
termine the key used. (Other attacks are discussed later.)
(l) A “successful” attack/break occurs when the method results in
a decryption method which is significantly more efficient than a
brute force attack.
(m) symmetric-key cryptosystems (also called “secret-key cryptosys-
tems”) - a cryptosystem which uses the same key for encryption
and for decryption.
(n) public-key cryptosystems (also called “asymmetric-key cryptosystems”)-
a cryptosystem which uses one key for encryption and another for
decryption; the encryption key is made public, but the decryption
key is kept secret.
8
2. Data security terms.
(a) Secrecy - ensuring that the data is available only to those people
who are authorized to have it.
(b) Integrity - ensuring data is not manipulated during the transmis-
sion1 .
(c) Authentication - ensuring that the receiver (Bob) can verify that
the message was indeed sent by the presumed sender (Alice).
(d) Non-repudiation - ensuring that the sender (Alice) can’t deny
sending the message received by Bob.
3. Auguste Kerckhoff articulated six rules for cryptographic security in
his 1883 article, “La cryptographie militaire” (available here: http:
//www.petitcolas.net/fabien/kerckhoffs/).
9
4. Attacks:
5. Cryptographic problems:
(a) key exchange - Alice and Bob want to communicate using a secret-
key cryptosystem For that, they must exchange keys secretly.
(b) digital signatures - a mathematical scheme for demonstrating the
authenticity of a digital message or document. A valid digital
signature gives a recipient reason to believe that the message was
created by a known sender, and that it was not altered in transit
10
(c) timestamps - authenticating the date or time at which a certain
event occurred
(d) coin-flipping - find a reliable way to use a “coin flip” to settle a
dispute between two parties if they cannot both see the coin
(e) key distribution - Consider a system with N members, all of whom
wish to communicate in secret with each other. In a secret-key
cryptosystem, each pair must have a different key (which is a lot
of keys).
(f) key generation - In a given cryptographic system, the person or
party responsible for generating the key(s) but do so in a secure
manner.
11
Julius Caesar, pug Caesar or shift cipher diagram
12
Figure 2: The alphabet, as integers, in the shift cipher.
INPUT:
k - an integer from 0 to 25 (the secret "key")
m - string of upper-case letters (the "plaintext" message)
OUTPUT:
c - string of upper-case letters (the "ciphertext" message)
Identify the alphabet A, ..., Z with the integers 0, ..., 25.
Step 1: Compute from the string m a list L1 of corresponding integers.
Step 2: Compute from the list L1 a new list L2, given by
adding k (mod 26) to each element in L1.
Step 3: Compute from the list L2 a string c of corresponding letters.
There are many alphabets possible in Sage- the usual English letter,
the binary alphabet, etc. See the reference manual of Sage’s (http://
www.sagemath.org/doc/reference/sage/crypto/classical.html Classi-
cal Cryptosystem module, for details.
13
We shall use the Sage notebook interface in the next few Sage examples,
so you will not see the sage: prompt on the input line.
Sage
AS = AlphabeticStrings()
A = AS.alphabet()
print A
print A[25]
(’A’, ’B’, ’C’, ’D’, ’E’, ’F’, ’G’, ’H’, ’I’, ’J’, ’K’, ’L’, ’M’,
’N’, ’O’, ’P’, ’Q’, ’R’, ’S’, ’T’, ’U’, ’V’, ’W’, ’X’, ’Y’, ’Z’)
Z
Using the SymPy version, one can use the default alphabet, or you can
make up your own:
SymPy
>>> alphabet_of_cipher()
[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
>>> L = [str(i) for i in range(10)]+["a","b","c"]; L
[’0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’, ’8’, ’9’, ’a’, ’b’, ’c’]
>>> A = "".join(L); A
’0123456789abc’
>>> alphabet_of_cipher(A)
[’0’, ’1’, ’2’, ’3’, ’4’, ’5’, ’6’, ’7’, ’8’, ’9’, ’a’, ’b’, ’c’]
Whether you use Sage or SymPy, you will need to initialize an alphabet.
Sage
14
Figure 3: The tabula recta.
Sage
CS = ShiftCryptosystem(AS)
15
m = CS.encoding(s) # the plaintext message, again
c = CS.enciphering(1, m) # the ciphertext
print m
print c
GONAVYBEATARMY
HPOBWZCFBUBSNZ
>>> pt = "GONAVYBEATARMY"
>>> shift_cipher_encrypt(pt, 1)
HPOBWZCFBUBSNZ
>>> shift_cipher_encrypt(pt, 0)
GONAVYBEATARMY
>>> shift_cipher_encrypt(pt, -1)
FNMZUXADZSZQLX
ALGORITHM:
INPUT:
a, b - a pair integers, where gcd(a, 26) = 1 (the secret "key")
m - string of upper-case letters (the "plaintext" message)
OUTPUT:
c - string of upper-case letters (the "ciphertext" message)
16
integers.
Step 2: Compute from the list L1 a new list L2, given by
replacing x by a*x+b (k mod 26), for each element x in L1.
Step 3: Compute from the list L2 a string c of corresponding
letters.
sage: AS = AlphabeticStrings()
sage: A = AS.alphabet()
sage: ACS = AffineCryptosystem(AS)
sage: ACS
Affine cryptosystem on Free alphabetic string monoid on A-Z
sage: AS = AlphabeticStrings()
sage: A = AS.alphabet()
sage: ACS = AffineCryptosystem(AS)
sage: m = "Go Navy! Beat Army!"
sage: p = ACS.encoding(m)
sage: c = ACS.enciphering(3,4,p); c
WUREPYHQEJEDOY
sage: ACS.deciphering(3,4,c)
GONAVYBEATARMY
sage: pp = ACS.encoding("WUREPYHQEJEDOY")
sage: cc = ACS.enciphering(9,16,pp); cc
GONAVYBEATARMY
print CS.enciphering(25, c)
print CS.deciphering(1, c)
17
These commands produce the following output.
Sage
GONAVYBEATARMY
GONAVYBEATARMY
We could also search over the entire keyspace of 26 letters and see which shift
makes the most sense as the plaintext.
Solution: We brute force search over the entire key space. Note the 11th line
below.
Sage
ct = "LRZZOACZZQTDZYPESLEXLVPDFDHTDPC"
c = CS.encoding(ct)
for i in range(26):
print i, CS.deciphering(i, c)
0 LRZZOACZZQTDZYPESLEXLVPDFDHTDPC
1 KQYYNZBYYPSCYXODRKDWKUOCECGSCOB
2 JPXXMYAXXORBXWNCQJCVJTNBDBFRBNA
3 IOWWLXZWWNQAWVMBPIBUISMACAEQAMZ
4 HNVVKWYVVMPZVULAOHATHRLZBZDPZLY
5 GMUUJVXUULOYUTKZNGZSGQKYAYCOYKX
6 FLTTIUWTTKNXTSJYMFYRFPJXZXBNXJW
7 EKSSHTVSSJMWSRIXLEXQEOIWYWAMWIV
8 DJRRGSURRILVRQHWKDWPDNHVXVZLVHU
9 CIQQFRTQQHKUQPGVJCVOCMGUWUYKUGT
10 BHPPEQSPPGJTPOFUIBUNBLFTVTXJTFS
11 AGOODPROOFISONETHATMAKESUSWISER
12 ZFNNCOQNNEHRNMDSGZSLZJDRTRVHRDQ
13 YEMMBNPMMDGQMLCRFYRKYICQSQUGQCP
14 XDLLAMOLLCFPLKBQEXQJXHBPRPTFPBO
18
15 WCKKZLNKKBEOKJAPDWPIWGAOQOSEOAN
16 VBJJYKMJJADNJIZOCVOHVFZNPNRDNZM
17 UAIIXJLIIZCMIHYNBUNGUEYMOMQCMYL
18 TZHHWIKHHYBLHGXMATMFTDXLNLPBLXK
19 SYGGVHJGGXAKGFWLZSLESCWKMKOAKWJ
20 RXFFUGIFFWZJFEVKYRKDRBVJLJNZJVI
21 QWEETFHEEVYIEDUJXQJCQAUIKIMYIUH
22 PVDDSEGDDUXHDCTIWPIBPZTHJHLXHTG
23 OUCCRDFCCTWGCBSHVOHAOYSGIGKWGSF
24 NTBBQCEBBSVFBARGUNGZNXRFHFJVFRE
25 MSAAPBDAARUEAZQFTMFYMWQEGEIUEQD
>>> ct = "LRZZOACZZQTDZYPESLEXLVPDFDHTDPC"
>>> for i in range(1,26): print encipher_shift(ct, i)
MSAAPBDAARUEAZQFTMFYMWQEGEIUEQD
NTBBQCEBBSVFBARGUNGZNXRFHFJVFRE
OUCCRDFCCTWGCBSHVOHAOYSGIGKWGSF
PVDDSEGDDUXHDCTIWPIBPZTHJHLXHTG
QWEETFHEEVYIEDUJXQJCQAUIKIMYIUH
RXFFUGIFFWZJFEVKYRKDRBVJLJNZJVI
SYGGVHJGGXAKGFWLZSLESCWKMKOAKWJ
TZHHWIKHHYBLHGXMATMFTDXLNLPBLXK
UAIIXJLIIZCMIHYNBUNGUEYMOMQCMYL
VBJJYKMJJADNJIZOCVOHVFZNPNRDNZM
WCKKZLNKKBEOKJAPDWPIWGAOQOSEOAN
XDLLAMOLLCFPLKBQEXQJXHBPRPTFPBO
YEMMBNPMMDGQMLCRFYRKYICQSQUGQCP
ZFNNCOQNNEHRNMDSGZSLZJDRTRVHRDQ
AGOODPROOFISONETHATMAKESUSWISER
BHPPEQSPPGJTPOFUIBUNBLFTVTXJTFS
CIQQFRTQQHKUQPGVJCVOCMGUWUYKUGT
DJRRGSURRILVRQHWKDWPDNHVXVZLVHU
EKSSHTVSSJMWSRIXLEXQEOIWYWAMWIV
FLTTIUWTTKNXTSJYMFYRFPJXZXBNXJW
GMUUJVXUULOYUTKZNGZSGQKYAYCOYKX
HNVVKWYVVMPZVULAOHATHRLZBZDPZLY
IOWWLXZWWNQAWVMBPIBUISMACAEQAMZ
JPXXMYAXXORBXWNCQJCVJTNBDBFRBNA
19
KQYYNZBYYPSCYXODRKDWKUOCECGSCOB
20
Figure 4: The frequency histogram for English
raven = "Once upon a midnight dreary, while I pondered, weak and weary,
Over many a quaint and curious volume of forgotten lore, While I nodded,
nearly napping, suddenly there came a tapping, As of some one gently
21
rapping, rapping at my chamber door. ’Tis some visiter,’ I muttered,
’tapping at my chamber door -- Only this, and nothing more.’"
print raven
(The string raven must be entered into Sage all on one line; it appears on 5
lines above merely for typographical reasons.) These two commands produce
the following output.
Sage
Once upon a midnight dreary, while I pondered, weak and weary, Over
many a quaint and curious volume of forgotten lore, While I nodded,
nearly napping, suddenly there came a tapping, As of some one gently
rapping, rapping at my chamber door. ’Tis some visiter,’ I muttered,
’tapping at my chamber door -- Only this, and nothing more.’
m = CS.encoding(raven)
fd = m.frequency_distribution()
dict_fd = fd.function()
list_fd = [[dict_fd[x],x] for x in dict_fd.keys()]
list_fd.sort()
list_fd.reverse()
list_fd
22
SymPy
In either case, we see that “E” is the most frequent and “K” and “Q” are
the least frequent (of those letters actually used). The slight differences in
the statistics are due to the fact that one of them is counting the non-alpha-
numerical characters and one is not.
How does this compare with “typical” (whatever that means) English
language use? See Figure 4.
ct =
"VUJLBWVUHTPKUPNOAKYLHYFDOPSLPWVUKLYLKDLHR
HUKDLHYFVCLYTHUFHXBHPUAHUKJBYPVBZCVSBTLVMM
VYNVAALUSVYLDOPSLPUVKKLKULHYSFUHWWPUNZBKKL
USFAOLYLJHTLHAHWWPUNHZVMZVTLVULNLUAS FYHWW
PUNYHWWPUNHATFJOHTILYKVVYAPZZVTLCPZPALYPTBAA
LYLKAHWWPUNHATFJOHTILYKVVYVUSFAOPZHUKUVA’’
23
c = CS.encoding(ct)
fd = c.frequency_distribution()
dict_fd = fd.function()
list_fd = [[dict_fd[x],x] for x in dict_fd.keys()]
list_fd.sort()
list_fd.reverse()
list_fd
24
>>> L
[(0.107569721116, L), (0.0916334661355, U), (0.0916334661355, H),
(0.0836653386454, V), (0.0717131474104, Y), (0.0717131474104, P),
(0.0637450199203, A), (0.0597609561753, K), (0.0478087649402, W),
(0.0438247011952, T), (0.0358565737052, F), (0.0318725099602, Z),
(0.0318725099602, S), (0.0318725099602, N), (0.0278884462151, O),
(0.0278884462151, B), (0.0199203187251, J), (0.0159362549801, D),
(0.0119521912351, M), (0.0119521912351, C), (0.00796812749004, I),
(0.00398406374502, X), (0.00398406374502, R), (0.0, Q), (0.0, G), (0.0, E)]
CS.deciphering(11-4, c)
ONCEUPONAMIDNIGHTDREARYWHILEIPONDEREDWEAKANDWEARYOVERMANYAQUAINTANDC\
URIOUSVOLUMEOFFORGOTTENLOREWHILEINODDEDNEARLYNAPPINGSUDDENLYTHERECAM\
EATAPPINGASOFSOMEONEGENTLYRAPPINGRAPPINGATMYCHAMBERDOORTISSOMEVISITE\
RIMUTTEREDTAPPINGATMYCHAMBERDOORONLYTHISANDNOTHINGMORE
25
Lemma 1. If p is any plaintext message and if c is a ciphertext encipherment
using a monoalphabetic substitution cipher then
IC(p) = IC(c).
Proof. Exercise.
Example 2. Consider the text from Edgar Alan Poe’s “The Raven”.
Sage
sage: AS = AlphabeticStrings()
sage: CS = ShiftCryptosystem(AS)
sage: m = ’’ONCEUPONAMIDNIGHTDREARYWHILEIPONDEREDWEAKANDWEARYOVERMANYAQUAINTANDC\
URIOUSVOLUMEOFFORGOTTENLOREWHILEINODDEDNEARLYNAPPINGSUDDENLYTHERECAM\
EATAPPINGASOFSOMEONEGENTLYRAPPINGRAPPINGATMYCHAMBERDOORTISSOMEVISITE\
RIMUTTEREDTAPPINGATMYCHAMBERDOORONLYTHISANDNOTHINGMORE’’
sage: m = CS.encoding(m)
sage: m.coincidence_index()
0.0614424034024070
sage: c = CS.enciphering(1, m)
sage: c.coincidence_index()
0.0614424034024070
sage: VC = VigenereCryptosystem(AS, 3)
sage: key = AS("KEY")
sage: m = VC.encoding(raven1) # raven1 is in an example
sage: c = VC.enciphering(key, m)
sage: m.coincidence_index()
0.0614424034024070
sage: c.coincidence_index()
0.0468132597351673
Note that the index of coincidence did not change under a monoalphabetic
substitution cipher but it did change under a polyalphabetic substitution
cipher.
3 Substitution cipher
A substitution cipher is a cryptosystem by which string “units” are replaced
with other sstrings. When the “units” are single letters then it is called a
simple substitution. A monoalphabetic substitution cipher uses fixed substi-
tution over the entire message, whereas a polyalphabetic substitution cipher
uses a number of substitutions at different positions in the message.
The algorithm to encipher a message of a simple monoalphabetic sub-
stitution cipher is simply to apply a fixed permutation p of the alphabet to
26
each of the characters in the plaintext, one after the other. The algorithm to
decipher a message of a simple monoalphabetic substitution cipher is simply
to apply the inverse of this fixed permutation to each of the characters in the
ciphertext, one after the other.
In a simple substitution, the key is a permutation of the 26 letters of the
alphabet. Therefore, the key space is 26!
Sage
sage: M = AlphabeticStrings()
sage: E = SubstitutionCryptosystem(M)
sage: E
Substitution cryptosystem on Free alphabetic string monoid on A-Z
sage: K = M([ 25-i for i in range(26) ])
sage: K
ZYXWVUTSRQPONMLKJIHGFEDCBA
sage: e = E(K)
sage: m = M("THECATINTHEHAT")
sage: e(m)
GSVXZGRMGSVSZG
27
To analyze this in Sage, we must exchange these 21 symbols (5, 3, . . . )
for the capital letters of the alphabet (5 → A, 3 → B, . . . ). This gives us a
cipher:
"ABCCDBEAFFGHIJKSGFJCFJCFLIKEGHIJKDKMGEFFKAINCKHOCPIOCHKDKBPKKFAHDI
JGPIKKHRGHQIKFHCPIJKAFIAHDSOHCPIJRAGHSPAHTJFKMKHIJEGRSKAFIFGDKFJCCI
NPCRIJKEKNIKOKCNIJKDKAIJFJKADASKKEGHKNPCRIJKIPKKIJPCQBJIJKFJCINGNIONKKICQI"
Sage
sage: AS = AlphabeticStrings()
sage: AS
Free alphabetic string monoid on A-Z
sage:
sage:goldbugcipher="ABCCDBEAFFGHIJKSGFJCLFJCFIKEGHIJKDKMGEFFK
AINCKHOCPIOCHKDKBPKKFAHDIJGPIKKHRGHQIKFHCPIJKAFIAHDSOHCP
IJRAGHSPAHTJFKMKHIJEGRSKAFIFGDKFJCCINPCRIJKEKNIKOKCNIJKDKAIJFJ
KADASKKEGHKNPCRIJKIPKKIJPCQBJIJKFJCINGNIONKKICQI"
sage: m = AS.encoding(goldbugcipher)
sage: m.frequency_distribution()
Discrete probability space defined by {A: 0.0579710144927536,
C: 0.0821256038647343, B: 0.0193236714975845, E: 0.0289855072463768,
D: 0.0386473429951691, G: 0.0531400966183575, F: 0.0772946859903381,
I: 0.125603864734299, H: 0.0676328502415459, K: 0.164251207729468,
J: 0.0917874396135265, M: 0.00966183574879227, L: 0.00483091787439614,
O: 0.0241545893719807, N: 0.0386473429951691, Q: 0.0144927536231884,
P: 0.0483091787439614, S: 0.0241545893719807, R: 0.0241545893719807,
T: 0.00483091787439614}
sage: m.character_count()
{A: 12, C: 17, B: 4, E: 6, D: 8, G: 11, F: 16, I: 26, H: 14, K: 34, J: 19, M: 2,
L: 1, O: 5, N: 8, Q: 3, P: 10, S: 5, R: 5, T: 1}
sage: fd = m.frequency_distribution()
sage: dict_fd = fd.function()
sage: list_fd = [[dict_fd[x],x] for x in dict_fd.keys()]
sage: list_fd.sort()
sage: list_fd.reverse()
sage: list_fd
[[0.164251207729468, K], [0.125603864734299, I], [0.0917874396135265, J],
[0.0821256038647343, C], [0.0772946859903381, F], [0.0676328502415459, H],
[0.0579710144927536, A], [0.0531400966183575, G], [0.0483091787439614, P],
[0.0386473429951691, N], [0.0386473429951691, D], [0.0289855072463768, E],
[0.0241545893719807, S], [0.0241545893719807, R], [0.0241545893719807, O],
[0.0193236714975845, B], [0.0144927536231884, Q], [0.00966183574879227, M],
[0.00483091787439614, T], [0.00483091787439614, L]]
28
Sage
sage: SC = SubstitutionCryptosystem(AS)
sage: key = "AGODLSINTHEPVFYRUMBCJKQWXZ"
sage: key = A("AGODLSINTHEBPVFRYUMCJKQWXZ"); key
AGODLSINTHEBPVFRYUMCJKQWXZ
sage: SC.enciphering(key, AS(goldbugcipher))
AGOODGLASSINTHEBISHOPSHOSTELINTHEDEVILSSEATFORTYONEDEGREESANDTHIRTEENMINUTES
NORTHEASTANDBYNORTHMAINBRANCHSEVENTHLIMBEASTSIDESHOOTFROMTHELEFTEYEOFTHE
DEATHSHEADABEELINEFROMTHETREETHROUGHTHESHOTFIFTYFEETOUT
(I’ve written down the inverse of the key, so enciphering is really decipher-
ing.)
SymPy
>>> goldbug="ABCCDBEAFFGHIJKSGFJCFJCFLIKEGHIJKDKMGEFFKAINCKHOCPIO
CHKDKBPKKFAHDIJGPIKKHRGHQIKFHCPIJKAFIAHDSOHCPIJRAGHSPAHTJFKMKHIJE
GRSKAFIFGDKFJCCINPCRIJKEKNIKOKCNIJKDKAIJFJKADASKKEGHKNPCRIJKIPKKI
JPCQBJIJKFJCINGNIONKKICQI"
>>> key = "AGODLSINTHEPVFYRUMBCJKQWXZ"
>>> encipher_substitution(goldbug, key)
AGOODGLASSINTHEBISHOSHOSPTELINTHEDEVILSSEATFOENYORTYONEDEGREESAND
THIRTEENMINUTESNORTHEASTANDBYNORTHMAINBRANCHSEVENTHLIMBEASTSIDESHOOT
FROMTHELEFTEYEOFTHEDEATHSHEADABEELINEFROMTHETREETHROUGHTHESHOTFIFTYFEETOUT
4 Bifid cipher
The Bifid cipher was invented around 1901 by Felix Delastelle. It is a “frac-
tional substitution” cipher, where letters are replaced by pairs of symbols
from a smaller alphabet. The cipher uses a 5 × 5 square filled with some
ordering of the alphabet, except that I’s and J’s are identified (this is a so-
called Polybius square). There is a 6 × 6 analog if you add back in the J’s
29
and also append onto the usual 26 letter alphabet, the digits 0, 1, . . . , 9). Ac-
cording to Helen Gaines’ book [G], this type of cipher was used in the field
by the German Army during World War I.
OUTPUT:
ct - ciphertext message
Step 1:
Create the 6x6 Polybius square S associated to the k as follows:
bottom,
a) starting top left, moving left-to-right, top-to- place the letters
of the key into a 6x6 matrix,
b) when finished, add those letters of the alphabet, followed
by the digits 0, ..., 9, which are not in the key, until the 6x6
square is filled
Step 2:
Create a list P of pairs of numbers which are the coordinates
in the Polybius square of the letters in pt.
Step 3:
Let L1 be the list of all first coordinates of P (length of L1= n),
let L2 be the list of all second coordinates of P (so the length of L2
is also n)
Step 4:
Let L be the concatenation of L1 and L2 (so length L = 2n),
except that consecutive numbers are paired (L[2i], L[2i+1]).
You can regard L as a list of pairs of length n.
Step 5: Let C be the list of all letters which are of the form
S[i,j], fr all (i,j) in L. As a string, this is the ciphertext ct.
30
E N C R Y
P T A B D
F G H I K .
L M O Q S
U V W X Z
If the key is “encrypt” and the plaintext is “meet me on monday” then the
ciphertext is “LNLLQNPPNPGADK”. We can verify this using SymPy.
SymPy
31
>>> pt = "meet me on monday at 8am"
>>> encipher_bifid6(pt, key)
HNHOKNTA5MEPEGNQZYG
>>> encipher_bifid6(pt, key, verbose = True)
[[2, 5], [0, 0], [0, 0], [1, 0], [2, 5], [0, 0], [3, 0],
[0, 1], [2, 5], [3, 0], [0, 1], [1, 3], [1, 1], [0, 4],
[1, 1], [1, 0], [5, 4], [1, 1], [2, 5]]
HNHOKNTA5MEPEGNQZYG
>>> ct = "HNHOKNTA5MEPEGNQZYG"
>>> decipher_bifid6(ct, key)
MEETMEONMONDAYAT8AM
OUTPUT:
pt - plaintext message
Step 1:
Create the 6x6 Polybius square S associated to the key as follows:
bottom,
a) starting top left, moving left-to-right, top-to- place the letters
of the key into a 6x6 matrix,
b) when finished, add those letters of the alphabet, followed
by the digits 0, ..., 9, which are not in the key, until the 6x6
square is filled
We call the list of all symbols in the square, taken top-to-bottom,
left-to-right, the "long key"
Step 2:
From the "long key", find the coordinates corresponding to each
symbol in the cipher text: the coordinate of x is (i,j) if x
is the m-th element of the long key and m = 6i+j.
Step 3: Read the i’s then the j’s off consecutively, then use
the Polybius square to find the corresponding symbols.
This is the plaintext pt.
Example 5. What about the larger bifid squares? The problem is - how are
the squares to be filled in? With integers?
32
Here is an example:
SymPy
You see the ambiguity in deciphering: Is the “11“ an 11 or two 1’s? You
can’t use numbers in 7 × 7 or higher bifid squares without running into these
ambiguities.
33
cipher in the 1800’s: once it is known that the key is, say, n characters long,
frequency analysis can be applied to every n−th letter of the ciphertext to de-
termine the plaintext. This method is called Kasiski examination, although
it was first discovered by Babbage.
This cipher was used in the 1700’s, for example, during the American Civil
War. The Confederacy used a brass cipher disk to implement the Vigenère
cipher (now on display in the NSA Museum in Fort Meade).
The so-called Vigenère cipher is a generalization of the shift cipher. Whereas
the shift cipher shifts each letter by the same amount (that amount being
the key of the shift cipher) the so-called Vigenère cipher shifts a letter by an
amount determined by the key, which is a word or phrase known only to the
sender and receiver).
For example, if the key was a single letter, such as “C”, then the so-called
Vigenère cipher is actually a shift cipher with a shift of 2 (since “C” is the
2nd letter of the alphabet, if you start counting at 0). If the key was a word
with two letters, such as “CA”, then the so-called Vigenère cipher will shift
letters in even positions by 2 and letters in odd positions are left alone (or
shifted by 0, since “A” is the 0th letter, if you start counting at 0).
ALGORITHM:
INPUT:
key - a string of upper-case letters (the secret "key")
m - string of upper-case letters (the "plaintext" message)
OUTPUT:
c - string of upper-case letters (the "ciphertext" message)
34
ing this cipher. To encipher using this table, simply look up each letter of the
plaintext along the top (this specifies a column), then the corresponding let-
ter of the key along the side (this specifies the row), and record as ciphertext
that letter which is in that row and column of the table. To decrypt, using
this table, simply look up each letter of the ciphertext along the top (this
specifies a column), then find the corresponding letter of the negative of the
key along the side (this specifies the row), and record as plaintext that letter
which is in that row and column of the table. For example, the key is USNA
(which corresponds to the sequence (20, 18, 13, 0)) then the negative of the
key is GINA (which corresponds to the sequence (6, 8, 13, 0) = −(20, 18, 13, 0)
(mod 26)).
Sage
sage: AS = AlphabeticStrings()
sage: A = AS.alphabet()
sage: key = AS("A")
sage: VC = VigenereCryptosystem(AS, 1)
sage: m = VC.encoding("Beat Army!"); m
BEATARMY
sage: VC.enciphering(key, m)
BEATARMY
sage: key = AS("B")
sage: VC.enciphering(key, m)
CFBUBSNZ
sage: VC.deciphering(key, c)
BEATARMY
sage: VC.enciphering(AS("Z"), c)
BEATARMY
35
Next, we decryption:
Sage
sage: VC = VigenereCryptosystem(AS, 2)
sage: key = AS("CA")
sage: m = VC.encoding("Beat Army!"); m
BEATARMY
sage: VC.enciphering(key, m)
DECTCROY
sage: c = VC.encoding("DECTCROY")
sage: c
DECTCROY
sage: VC.deciphering(key, c)
BEATARMY
sage: c = AS("DECTCROY")
sage: VC.deciphering(key, c)
BEATARMY
ALGORITHM:
INPUT:
key - a string of upper-case letters (the secret "key")
m - string of upper-case letters (the "plaintext" message)
OUTPUT:
36
c - string of upper-case letters (the "ciphertext" message)
37
(1) Find the “leading bit” ak by determining the largest power of 2 less
than or equal to a. Call this power k and let ak = 1.
(2) Subtract this power from a and replace a by this difference.
(3) If the result is non-zero, go to step 1; otherwise, stop.
This determines all the non-zero bits in the binary representation of a. The
other bits are 0.
Example 6. Find the binary representation of 130. The largest power of 2
less than or equal to 130 is 128 = 27 , so a7 = 1. The largest power of 2 less
than or equal to 2 = 130 − 128 is 2 = 21 , so a1 = 1. The other bits are zero:
a6 = a5 = a4 = a3 = a2 = a0 = 0, so
130 = 128 + 2 ∼ 10000010.
More generally, let us fix an integer m > 1. Each natural number can be
written in an m-ary expansion
a = ak mk + ... + a1 m + a0 ,
where 0 ≤ ai ≤ m − 1 are the m-ary digits. Again, the m-ary representation
of a is written as a ∼ ak ...a1 a0 . Clearly, m|a if and only if a0 = 0. To find
the m-ary expansion of a natural number, perform the following steps.
(1) Find ak by determining the largest power of m less than or equal to a.
Call this power k.
(2) Find the largest positive integer multiple of this power which is less
than or equal to a. This multiple will be the k-th digit ak .
(3) Subtract ak mk from a and replace a by this difference.
(4) If the result is non-zero, go to step 1; otherwise, stop.
Example 7. Find the 3-ary representation of 211. The largest power of 3
less than or equal to 211 is 81 = 34 , and 211 > 2 · 81 = 162 so a4 = 2.
The largest power of 3 less than or equal to 49 = 211 − 162 is 27 = 33 , and
49 < 2·27 so a3 = 1. The largest power of 3 less than or equal to 22 = 49−27
is 9 = 32 , and 22 > 2 · 9 so a2 = 2. The largest power of 3 less than or equal
to 4 = 22 − 18 is 3 = 31 , and 4 < 2 · 3 so a1 = 1. The last “bit” is 1:
a4 = 2, a3 = 1, a2 = 2, a1 = 1, a0 = 1, so
211 = 2 · 34 + 1 · 33 + 2 · 32 + 1 · 3 + 1 ∼ 21211.
38
Example 8. Convert 100101 from binary to 5-ary. In decimal (or “10-ary”),
100101 is
1 · 25 + 0 · 24 + 0 · 23 + 1 · 22 + 0 · 21 + 1 · 20 = 32 + 4 + 1 = 37.
In 5-ary,
37 = 1 · 52 + 2 · 51 + 2 · 50 ∼ 122.
a ≡ b (mod m),
if their difference a − b is an integer multiple of m. We write m|n if the
integer m divides the integer n, so m|n if and only if n ≡ 0 (mod m). The
number m is called the modulus of the congruence. This congruence symbol
≡ satisfies the same properties as = between integers, except (possibly) for
the cancellation law. All the following hold:
a ≡ c (mod m).
• For all c ∈ Z,
a ≡ a + cm (mod m).
39
If bc ≡ 1 (mod m) then we say b is the modular inverse of c (mod m),
written
40
1. Write n as a sum of powers of 2 (the “binary expansion” of n):
c1 = c2 (mod m),
then
3.
c2 = c21 (mod m) = (c2 )2 = c4 (mod m),
k
etc, until you get to c2 . This requires k multiplications (mod m).
a 1 2 3 4 5 6 7 8 9 10
1
a
1 6 4 3 9 2 8 7 5 10
For example, 7−1 ≡ 8 (mod 11) because 7·8 = 56 = 1+55 ≡ 1 (mod 11).
Lemma 12. (Bezout’s Lemma) If a > 1 and b > 1 are integers with greatest
common divisor d, then there exist integers x and y such that
ax + by = d.
3
The “big O” notation is defined as follows: We say f (n) = O(log(n)) if and only if
there is a constant C > 0 such that f (n) ≤ C log(n) for all n > 1. The constant C will, in
this case, implicitly depends on m.
41
proof: Consider the set
>>> gcdex(15,12)
(1, -1, 3)
sage: xgcd(15,12)
(3, 1, -1)
42
Additionally, d is the smallest positive integer for which there are integer
solutions x and y for the preceding equation.
i q r u v
−1 b 1 0
0 a 0 1
x = vk−1 , y = uk−1 .
43
Example 14.
i q r u v
−1 2697 1 0
0 2553 0 1
1 1 144 1 −1
2 17 105 −17 18
3 1 39 18 −19
4 2 27 −53 56
5 1 12 71 −75
6 2 3 −195 206
7 4 0 −− −−
Thus k = 7, so x = v6 = −195, y = u6 = 206. Indeed, 3 = gcd(2697, 2553) =
(−195) · 2697 + (206) · 2553.
44
Here is the simplest example, sometimes called the Boolean field, written
GF (2).
Example 16. Let F = {0, 1}, with two binary operations, + (addition
(mod 2)), and · (integer multiplication). This field is used is the mathematics
of electrical circuits, with1 being “on” and 0 being “off ”.
The addition table is
+ 0 1
0 0 1
1 1 0
The multiplication table is
· 0 1
0 0 0
1 0 1
Example 17. Let F = {0, 1, 2}, with two binary operations, + (addition),
and · (multiplication), where each is computed (mod 3). This field is some-
times denoted GF (3).
The addition table is
+ 0 1 2
0 0 1 2
1 1 2 0
2 2 0 1
The multiplication table is
· 0 1 2
0 0 0 0
1 0 1 2
2 0 2 1
If p is any prime, then the integers (mod p), written Z/pZ, is a finite
field with p elements. It will also be denoted GF (p) and is called a prime
(Galois) field.
However, if m is any composite then Z/mZ (the integers (mod m)) is
not a field. For example, Z/4Z and Z/6Z is not a field. In neither case does
the element 2 have an inverse. (If you don’t know this already, then this is a
good exercise for yourself to verify this.)
45
Example 18. Here is an example of using Sage to compute in GF (5):
Sage
Sage computed the additive inverse of 2 in GF (5) and the multiplicative in-
verse of 2 in GF (5). Both (by an unusual coincidence) are equal to 3.
Here is a similar example using SymPy:
SymPy
>>> F = FF(2)
>>> F = FF(5)
>>> a= F(1)
>>> a+a
2 mod 5
>>> a+a+a
3 mod 5
>>> a+a+a+a
4 mod 5
>>> a+a+a+a+a
0 mod 5
>>> b = a+a+a
>>> a*b
3 mod 5
>>> a/b
2 mod 5
46
Here are some SymPy commands to produce (more or less) a multiplica-
tion table for Z/5Z:
SymPy
>>> L = [["*"]+range(5)]
>>> L = L+[[i]+[(i*x)%5 for x in range(5)] for i in range(5)]
>>> L
[[*, 0, 1, 2, 3, 4],
[0, 0, 0, 0, 0, 0],
[1, 0, 1, 2, 3, 4],
[2, 0, 2, 4, 1, 3],
[3, 0, 3, 1, 4, 2],
[4, 0, 4, 3, 2, 1]]
>>> L = [["*"]+range(6)]
>>> L = L+[[i]+[(i*x)%6 for x in range(6)] for i in range(6)]
>>> L
[[*, 0, 1, 2, 3, 4, 5],
[0, 0, 0, 0, 0, 0, 0],
[1, 0, 1, 2, 3, 4, 5],
[2, 0, 2, 4, 0, 2, 4],
[3, 0, 3, 0, 3, 0, 3],
[4, 0, 4, 2, 0, 4, 2],
[5, 0, 5, 4, 3, 2, 1]]
You see the difference? The “lower right-hand corner” of the 5 × 5 table
is a Latin square. The “lower right-hand corner” of the 6 × 6 table is not.
47
then F is called a subfield of E and E is called an extension field of F , written
E/F .
It is a theorem (proven in most any textbook in abstract algebra) that if
F is a finite field then F must have pk elements, where p is a prime and k is
an integer. If k = 1 then F must be isomorphic to GF (p). (Two fields are
“isomorphic” if there is a bijective map from one to the other which preserves
the addition, multiplication operations.) The fields with k > 1 are so-called
extension fields and will not arise in these lectures.
c = Kp, (2)
48
and rewriting the resulting matrix as a string over the same alphabet. De-
cryption is performed similarly by computing
p = K −1 c. (3)
• Method 3:
5 2
Example 20. The example of (mod 35) is not so easy to compute
7 3
using row-reduction by hand (try it!). However, it is easy to compute using
the adjoint formula and, of course, Sage can do it.
49
Sage
−1 3 33
So. K = .
28 5
ALGORITHM:
INPUT:
key - a kxk invertible matrix K, all of whose entries are in Z26
m - string of n upper-case letters (the "plaintext" message)
(Note: Sage assumes that n is a multiiple of k.)
OUTPUT:
c - string of upper-case letters (the "ciphertext" message)
50
The deciphering algorithm is basically the same, except that it uses the
inverse matrix K −1 (mod 26).
Example 21. Here is an example. We will encrypt “Go Navy! Beat Army!”
using Sage’s Hill cipher implementation.
Sage
sage: AS = AlphabeticStrings()
sage: HC = HillCryptosystem(AS,3)
sage: Z26 = IntegerModRing(26)
sage: K = matrix(Z26, [[1,0,1],[0,1,1],[2,2,3]])
sage: det(K)
25
sage: m = "GONAVYBEATARMYX"
sage: m = HC.encoding(m)
sage: ct = HC.enciphering(K, m)
sage: ct
GOHWRPBEFBISGSB
sage: HC.deciphering(K, c)
GONAVYBEATARMYX
# You can always have \sage pick the key for you:
sage: K = HC.random_key(); K
[ 0 3 25]
[ 0 13 2]
[19 8 8]
sage: det(K)
23
sage: AS = AlphabeticStrings()
sage: HC = HillCryptosystem(AS,3)
sage: Z26 = IntegerModRing(26)
sage: K = matrix(Z26, [[1,0,1],[0,1,1],[2,2,3]])
51
sage: m = "GONAVYBEATARMYX"
sage: pt = HC.encoding("GONAVYBEATARMYX")
sage: ct = HC.enciphering(K, pt); ct
GOHWRPBEFBISGSB
sage: [A.index(x) for x in m]
[6, 14, 13, 0, 21, 24, 1, 4, 0, 19, 0, 17, 12, 24, 23]
Next, we put these numbers into a list and find the corresponding letters:
Sage
sage: ct0 = [19, 1, 1, 24, 19, 10, 1, 4, 10, 10, 17, 11, 9, 21, 11]
sage: [A[i] for i in ct0]
[’T’, ’B’, ’B’, ’Y’, ’T’, ’K’, ’B’, ’E’, ’K’, ’K’, ’R’, ’L’, ’J’, ’V’, ’L’]
52
The problem is that the Sage implementation uses matrix multiplication
on the left, not on the right as we are used to in the United Stated (and many
other parts of the world). Therefore, we must replace K by it’s transpose,
K t.
Sage
sage: Kt = K.transpose()
sage: Kt
[1 0 2]
[0 1 2]
[1 1 3]
sage: c1t = Kt*v1; c1t
(6, 14, 7)
sage: c2t = Kt*v2; c2t
(22, 17, 15)
sage: c3t = Kt*v3; c3t
(1, 4, 5)
sage: c4t = Kt*v4; c4t
(1, 8, 18)
sage: c5t = Kt*v5; c5t
(6, 18, 1)
This does indeed agree with the above list, [6, 14, 13, 0, 21, 24, 1, 4, 0, 19, 0, 17, 12, 24, 23],
of numbers corresponding to the letters in the cipher text.
Example 22. Next, let’s try using SymPy to work through an example.
SymPy
53
Using the plaintext “Meet me on Monday” (which is translated into “MEET-
MEONMONDAY”) and a block size of k = 2, SymPy gives the ciphertext
“UEQDUEODOCTCWQ.” On the other hand, using the similar plaintext
“Meet me on Tuesday” (which is translated into “MEETMEONTUESDAY”)
and a block size of k = 2, SymPy gives the similar ciphertext “UEQDUEOD-
HBOYDJYU.”
We can also decrypt using SymPy:
SymPy
>>> ct = "UEQDUEODOCTCWQ"
>>> key = Matrix( ((1,2), (3,5)) )
>>> decipher_hill(ct, key)
MEETMEONMONDAY
>>> ct = "UEQDUEODHBOYDJYU"
>>> decipher_hill(ct, key)
MEETMEONTUESDAYA
Example 23. Let us try another example, this time using Sage.
Sage
sage: AS = AlphabeticStrings()
sage: HC = HillCryptosystem(AS,2)
sage: Z26 = IntegerModRing(26)
sage: K = matrix(Z26, [[2,1],[13,20]])
sage: det(K)
1
We see the block size is 2. Again, let’s encrypt “Go Navy! Beat Army!”
First, we use Sage’s implementation of Hill’s cipher.
54
Sage
sage: m = "GONAVYBEATARMY"
sage: pt = HC.encoding(m)
sage: ct = HC.enciphering(K, pt); ct
MAANQHCDNQNCYY
sage: A = AS.alphabet()
sage: [A.index(x) for x in m]
[6, 14, 13, 0, 21, 24, 1, 4, 0, 19, 0, 17, 12, 24]
sage: c = "MAANQHCDNQNCYY"
sage: [A.index(x) for x in c]
[12, 0, 0, 13, 16, 7, 2, 3, 13, 16, 13, 2, 24, 24]
55
[’M’, ’A’, ’A’, ’N’, ’Q’, ’H’, ’C’, ’D’, ’N’, ’Q’, ’N’, ’C’, ’Y’, ’Y’]
8 PK Cryptosystems
This section discusses some commonly used public key (PK) cryptosystems.
8.1 RSA
RSA stands for Ron Rivest, Adi Shamir and Leonard Adleman, who first
publicly described the algorithm in 1977. In 1997, the work of Clifford Cocks,
a mathematician at GCHQ, was declassified. He had developed an equivalent
cryptosystem in 1973.
56
8.1.1 Set up and examples
Alice wants to talk to Bob.
Bob secretly chooses two large distinct primes p, q. He computes n = pq
and sends that to Alice. The length of n in bits is the “key length.”
Next, Bob computes φ(n) = (p − 1)(q − 1), where φ is Euler’s totient
function, and chooses an integer e such that 1 < e < φ(n) and greatest
common divisor gcd(e, φ(n)) = 1. Bob sends e to Alice - this is the “public
key exponent.”
The public key is the pair (n, e).
Finally, Bob determine d, the multiplicative inverse of e (mod φ(n)). We
call d the private key exponent or private key4 .
Encryption: Alice wishes to send a message M to Bob. She first turns
M into an integer (or a sequence of such integers) m, such that 0 ≤ m <
n by using an agreed-upon protocol. She then computes the ciphertext c
corresponding to m by
4
Sometimes - with some slight inaccuracy - we call (n, d) the private key.
57
Next, we compute the public key.
Sage
58
Here is another example.
Example 25. This time, we use some Sage code to do the computations.
Sage
59
Here is a SymPy example.
Example 27. First, we pick our primes and compute the public key.
SymPy
60
a product of primes.
(2) Since φ(n) = (p − 1)(q − 1) = pq − p − q + 1 = n − p − q + 1, if we could
somehow get only p + q (as opposed to p and q individually, that would be
enough to break RSA. In other words, given that an integer n is a product of
two primes, can you find the sum of the factors? This too seems to be very
hard.
(3) When e = 3, it turns out that RSA is insecure in some cases. See Boneh’s
survey [Bo].
(4) Under the “generalized Riemann hypothesis” (which is too technical to
define here, but widely believed by mathematicians to be true), it has been
shown by the computer scientist Gary Miller that the following computations
are of equal computational complexity, up to a polynomial: (1) factoring n
into p and q, (2) computing d, given n and e. For details, see Miller [Mi].
61
Here is Sage code to compute the public and private keys, with an exam-
ple.
Sage
sage: a, b, A, B = 3, 4, 5, 6
sage: n, e = kid_rsa_public_key(a,b,A,B)
sage: n;e
369
58
sage: d = kid_rsa_private_key(a,b,A,B); d
70
sage: pt = 200
sage: pk = kid_rsa_public_key(a,b,A,B)
sage: kid_rsa_encrypt(pt, pk)
161
sage: d = kid_rsa_private_key(a,b,A,B)
sage: pt = 200
sage: pk = kid_rsa_public_key(a,b,A,B)
sage: ct = kid_rsa_encrypt(pt, pk)
sage: kid_rsa_decrypt(ct, pk, d)
200
Here is the (very similar) SymPy code for Kid RSA. First, the keys.
SymPy
>>> a, b, A, B = 3, 4, 5, 6
>>> n, e = kid_rsa_public_key(a,b,A,B)
>>> n, e
(369, 58)
>>> d = kid_rsa_private_key(a,b,A,B); d
70
62
Next, the encryption and decryption.
SymPy
>>> pt = 200
>>> pk = kid_rsa_public_key(a,b,A,B)
>>> kid_rsa_encrypt(pt, pk)
161
>>> d = kid_rsa_private_key(a,b,A,B)
>>> pt = 200
>>> pk = kid_rsa_public_key(a,b,A,B)
>>> ct = encipher_kid_rsa(pt, pk)
>>> decipher_kid_rsa(ct, pk, d)
200
de = nM + 1.
This last equation allows us to compute d (mod n) by computing e−1 (mod n)
using Bezout’s Lemma 12.
63
Sage
sage: n = 369; e = 58
sage: n = 369; e = 58
sage: xgcd(n,e)
(1, -11, 70)
sage: d = xgcd(n,e)[2]; d
70
We see that if (n, e) = (369, 58) then the Extended Euclidean algorithm com-
putes the private key d = 70.
Similar commands will work using SymPy’s gcdex command instead. (See
Example 13 for comparison.)
b ≡ ax (mod m),
then we say that x is the discrete log of b (mod m): x = loga (b). Finding x,
given a, b (and of course m) is called the discrete log problem (DLP). There
are no known “fast, efficient” ways to solve this problem in general.
The “brute force” algorithm for solving the discrete logarithm problem
for loga (b) is to compute 1, a, a2 , . . . until a match is found with b. There are
faster methods than this, but none that are polynomial time in the length of
m (as a binary string).
64
two parties that have no prior knowledge of each other to jointly establish
a shared secret key over an insecure communications channel. This key can
then be used to encrypt subsequent communications using a symmetric key
cipher.
The scheme was first published by Diffie and Hellman in 1976, although it
later emerged that it had been separately invented a few years earlier within
GCHQ, the British signals intelligence agency, by Malcolm J. Williamson but
was kept classified. In 2002, Hellman suggested the algorithm be called Diffie-
Hellman-Merkle key exchange in recognition of Ralph Merkle’s contribution
to the invention of public-key cryptography.
1. Alice and Bob decide on a large prime number p and a primitive element
a of Z/pZ, both of which can be made public.
2. Alice chooses a secret random x with gcd(x, p1) = 1 and Bob chooses
a secret random y with gcd(y, p1) = 1.
3. Alice sends Bob ax (mod p) and Bob sends Alice ay (mod p).
65
66
sage: 99ˆx%p # Alice
66
• Alice uses her private key to compute dp−1−k (mod p)) and dp−1−k ≡
(a−k` (mod p)).
Example 33. Using the numerical position in the alphabet, “A” is the 1st
letter, which corresponds numerically to 01, “B” to 02, ..., “Z” to 26. A word
corresponds to the associated string of numbers. Note, for example, “ab” is
0102 = 102 but “ob” is 1502.
Pick p = 150001, a = 7. Pick k = 113, so that ak = 7113 ≡ 66436 (mod p).
Alice’s public key is (150001, 7, 66436). Alice’s private key is 113. Suppose
Bob is Alice’s son and wants to send the message “Hi Mom”. He converts this
66
to m = 080913 = 809 and m = 131513. Bob picks ` = 1000 and computes
7` ≡ 90429 (mod 150001)), so d = 90429. The encryption is 809 · (7113 )1000 ≡
15061 = e (mod 150001)) and 131513 · (7113 )1000 ≡ 57422 = e (mod 150001)),
so c = (90429, 15061) and c = (90429, 57422) are sent to Alice.
Alice computes dp−1−k = 90427149887 ≡ 80802 (mod 150001)). Then m ≡
80802 · e (mod 150001)) returns the original messages m = 809 and m =
131513. Since 809 has an odd number of digits, the first digit must have
been a 0. Alice can see that 809 must mean that the first letter comes from
the 8 = 08, the second letter comes from a 09. These spell out “hi”. For
m = 131513, the third letter must come from the 13, the fourth letter must
come from the 15, and the last must be a 13. These spell out “hi” and “mom”.
Adding a space and proper capitalization, this is “Hi Mom”!
Exercise 8.1. (a) Let p = 541, a = 2. Pick k = 113, ` = 101. Encrypt the
messages m = 200 and m = 201 using ElGamal.
(a) Let p = 541, a = 2, k = 101. Decrypt the ElGamal ciphers c =
(54, 300) and c = (54, 301).
9 Stream ciphers
A “stream cipher” is a cryptosystem derived using a sequence of digits as
the key, where the plaintext is another such sequence and these streams are
combined in some prescribed manner to create the ciphertext.
67
2. The runs of consecutive 1’s or 0’s frequently occur with short runs more
frequent than long runs.
SPACE = 0000
L = 1111
A = 0001
! = 1000
B = 0010
# = 1001
E = 0011
? = 1010
M = 0100
; = 1011
R = 0101
, = 1100
T = 0110
. = 1101
Y = 0111
Q = 1110
pt = 0010001100010110000000010101010001111000.
68
In order to generate a stream cipher that only Alice and Bob know, to be used
as the key, some method of secret key exchange is required. For example, each
person can generate a pseudo-random sequence of sufficient length. Alice will
send her sequence to Bob and Bob will send his sequence to Alice. They
will then add their sequences together bit-wise to produce a common stream
cipher. (It will be known to only to the two of them unless someone has
intercepted both of their communications.) For our purposes, suppose the
resultant sequence from the two individual sequences is
k = 1101011001000111101011001000111101011001
Alice now has a message in binary format and a cipher to encode the mes-
sage. Adding the cipher to the message, Alice gets the encrypted message or
ciphertext, ct:
0010001100010110000000010101010001111000 pt
+ 1101011001000111101011001000111101011001 k
-----------------------------------------
1111010101010001101011011101101100100001 ct
If a third party, Charlie, were to intercept the ciphertext and tried to read it,
knowing that the computers used the above table to talk to one another, he
would decrypt the ciphertext as “LRRA?..;BA”. Notice that both ‘A’s in the
original message where changed to two different letters (‘R’ the first time and
‘.’ the second time) and that ‘E’ and ‘A’ both are changed to ‘R’ and ‘T’ and
‘!’ are both changed to ‘A’. This helps prevent a cryptanalyst from breaking
the code by mapping each character to something different everytime. The
mapping appears random since the stream cipher used was a pseudo-random
sequence. When Bob receives the ciphertext, however, he is able to decrypt it
since he has the stream cipher that he and Alice created earlier. By adding
the stream cipher to the ciphertext, he will uncover the original message:
ct + k = pt. (6)
Now Bob can use the table to decode the message from binary into English
and receives “BEAT ARMY!” from Alice.
69
A linear homogeneous recurrence relation with constant coefficients is an
equation of the form:
an = k1 rn + k2 nrn + · · · + kd nd−1 rn .
Linear recursive sequences are precisely the sequences whose generating
function is a rational function: the denominator is the polynomial obtained
from the auxiliary polynomial by reversing the order of the coefficients, and
the numerator is determined by the initial values of the sequence.
70
0 1 0 ··· 0
0
0 1 ··· 0
.. .
. .. .. ..
C=. . . . .
0 0 0 ··· 1
cd cd−1 cd−2 ··· c1
In other words,
fn = fn−1 + fn−2 , f0 = 0, f1 = 1.
We have p(t) = t2 − t − 1, and
0 1
C=
1 1
71
and the above identity becomes
fn−1 fn−2
=C·
fn fn−1
For example, taking n = 2 gives the initial condition
f1 0 1 f
= · 0
f2 1 1 f1
Here is a Sage example.
Sage
72
[2]
an+d−1 ad−1
.. n . n n n
. = C .. = C (b1 v1 +· · ·+bd vd ) = λ1 b1 v1 +· · ·+λd bd vd (12)
an a0
Example 36. The example in the case of the Fibonacci numbers has become
known as Binet’s formula:
ϕn − ψ n ϕn − ψ n
fn = = √ (13)
ϕ−ψ 5
where √
1+ 5
ϕ= ≈ 1.6180339887 . . .
2
73
is the golden ratio (sequence A001622 in the online OEIS, http: // oeis.
org/ ), and √
1− 5 1
ψ= =1−ϕ=− .
2 ϕ
To see this, note that ϕ and ψ are both solutions of the equation
x2 = x + 1.
λ1 = 3, λ1 = 2, λ1 = −1,
and corresponding eigenvectors are
1 1 1
~v1 = 3 , ~v2 = 2 ,
~v3 = −1 .
9 4 1
74
If
1 1 1
P = 3 2 −1
9 4 1
is the matrix of eigenvectors and
3 0 0
D= 0 2 0
0 0 −1
the diagonal matrix of eigenvalues then
A = P DP −1
is the diagonalization. We compute arbitrary poswers using An = P Dn P −1 .
This can be computed efficiently (mod p) using
repeated squares.
4 −1 −6
Incidently, the eigenvalues of 1 0 0 are
0 1 0
λ1 = 3, λ1 = 2, λ1 = −1,
and corresponding eigenvectors are
9 4 1
~v1 = 3 , ~v2 = 2 , ~v3 = −1 .
1 1 1
Therefore, a similar calculation works for the latter matrix reformulation
above.
Sage
75
sage: P = matrix(QQ, [[1,1,1],[3,2,-1],[9,4,1]])
sage: D = Pˆ(-1)*A*P; D
[ 3 0 0]
[ 0 2 0]
[ 0 0 -1]
s0 , s1 , s2 , . . . , sL−1
76
the initial contents of the L stages of the register. In general, the binary linear
feedback shift register (LFSR) sequence is defined by the following recursion
relation
L
X
sj = ci sj−i (mod 2),
i=1
for j ≥ L. The coefficients c1 , ..., cL are fixed and form the key to the cryp-
tographic bitstream.
The key may be represented as a vector
c = [c1 , c2 , . . . , cL ],
but is more often defined by a polynomial, known as the connection polyno-
mial
C(x) = 1 + c1 x + c2 x2 + · · · + cL xL . (14)
We say a binary sequence a0 , a1 , . . . is periodic with period P if
ai = ai+P ,
for all i. By this definition, if {an }n≥0 is periodic with period P then it also
has period 2P , 3P , . . . . Therefore, we often assume that P > 0 is choosen
as small as possible.
Example 38. If you divide a k digit positive integer by the number with k
9s, the digits in the decimal representation of the resulting rational number
is a repeating decimal. For example, 274/999 = 0.274274274274 . . . .)
We say a binary sequence a0 , a1 , . . . is eventually periodic with period P
if there is an i0 > 0 such that ai = ai+P , for all i > i0 .
Example 39. The decimal expansion of the rational number obtained by
dividing any positive integer by another is eventually repeating decimal. For
example, 1/7 = 0.142857142857143 . . . .)
Question: Why is this eventually periodic?
Example 40. If we are given the key as a vector c = [1, 0, 0, 1] and the initial
fill as a vector s = [1, 1, 0, 1] in GF (2), we can create the sequence
1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, . . . .
77
The auto-correlation function of a periodic sequence X = {x0 .x1 , . . . } (of
real numbers) with period P is defined by
P
X
AC(X, k) = (1/P ) xi xi+k (15)
i=1
2. Low Autocorrelation:
1, k = 0,
AC(A, k) =
6 0,
, k =
where is “small.”
3. Proportional Runs Property: In each period, half the runs are length 1,
one-fourth are length 2, one-eighth are length 3, etc. Moveover, there
are as many runs of 1’s as there are of 0’s.
Example 42. Consider the sequence of period 7 defined by the values of the
linear function f : GF (2)3 → GF (2) given by f1 (x0 , x1 , x2 ) = x1 + x2 ,
A = {0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, . . . },
where Ai = f (vi ) and GF (2)3 − {(0, 0, 0)} = {v1 , v2 , . . . , v7 }. The following
Sage code computes the values of the autocorrelation function:
Sage
78
sage: flist2 = 2*flist
sage: flist
[0, 1, 1, 1, 1, 0, 0]
sage: flist2
[0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0]
sage: autocorr = [[j,sum([(-1)ˆ(flist2[i]+flist2[i+j]) for i in range(7)])] for j in range(7)]
sage: autocorr
[[0, 7], [1, 3], [2, -1], [3, -5], [4, -5], [5, -1], [6, 3]]
In other words,
1, k = 0,
3/7, k = 1, 6,
AC(A, k) =
−1/7, k = 2, 5,
−5/7, k = 3, 4.
Example 43. Consider the sequence of period 7 defined by the values of the
linear function f : GF (2)3 → GF (2) given by f1 (x0 , x1 , x2 ) = x0 + x1 + x2 ,
A = {1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, . . . },
where Ai = f (vi ) and GF (2)3 − {(0, 0, 0)} = {v1 , v2 , . . . , v7 }. The following
Sage code computes the values of the autocorrelation function:
Sage
In other words,
1, k = 0,
AC(A, k) =
−1/7, k =
6 0.
Example 44. Consider the sequence of period 7 defined by the values of the
non-linear function f : GF (2)3 → GF (2) given by f1 (x0 , x1 , x2 ) = x1 + x0 x2 ,
79
A = {0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, . . . },
where Ai = f (vi ) and GF (2)3 − {(0, 0, 0)} = {v1 , v2 , . . . , v7 }. The following
Sage code computes the values of the autocorrelation function:
Sage
In other words,
1, k = 0,
3/7, k = 3, 4,
AC(A, k) =
−1/7,
k = 1, 6,
−5/7, k = 2, 5.
sage: F = GF(2)
sage: o = F(0); l = F(1)
sage: key = [l,o,o,l]; fill = [l,l,o,l]; n = 20
sage: s = lfsr_sequence(key,fill,n); s
[1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0]
sage: massey(s)
xˆ4 + x + 1
80
an = c1 an−1 + ... + ck an−k
is
an = an−1 + an−4 ,
and a0 = 1, a1 = 1, a2 = 0, a3 = 1. This gives
a0 , a1 , · · · = 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, . . . .
sage: F = GF(2)
sage: o = F(0); l = F(1)
sage: key = [l,o,o,l]; fill = [l,l,o,l]; n = 20
sage: s = lfsr_sequence(key,fill,n); s
[1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0]
sage: # Let’s do this "by hand":
sage: a1 = l
sage: a2 = o
sage: a3 = o
sage: a4 = l
sage: lfsr = lambda x: a1*x[0]+a2*x[1]+a3*x[2]+a4*x[3]
sage: s0 = fill
sage: lfsr(s0)
0
sage: s1 = [1,0,1,0]
sage: lfsr(s1)
1
sage: s2 = [0,1,0,1]
sage: lfsr(s2)
1
sage: s3 = [1,0,1,1]
sage: lfsr(s3)
0
sage: A = matrix(GF(2), [[0,1,0,0],[0,0,1,0],[0,0,0,1],[1,0,0,1]])
sage: s0 = vector(GF(2), [1, 1, 0, 1])
sage: s1 = A*s0; s1
(1, 0, 1, 0)
81
sage: s2 = A*s1; s2
(0, 1, 0, 1)
Now, suppose we know the {an }’s but not the key. Suppose we know
Note that mod 2, this is [1, 0, 0, 1], the key. Another way:
Sage
82
Sage
sage: a1 = -6
sage: a2 = -1
sage: a3 = 4
sage: rr = lambda x: a1*x[0]+a2*x[1]+a3*x[2]
sage: s0 = [0,1,2]
sage: rr(s0)
7
sage: s1 = [1,2,7]
sage: rr(s1)
20
sage: s2 = [2,7,20]
sage: rr(s2)
61
sage: s3 = [7,20,61]
sage: rr(s3)
182
We can generate the sequence using the recurrance relation. We can also use
the corresponding matrix to generate the terms.
For
xn = 4xn−1 − xn−2 − 6xn−3 ,
and x0 = 0, x1 = 1, x2 = 2, we have:
Sage
83
For
xn = 3xn−1 + xn−2 − 3xn−3 ,
and x0 = 0, x1 = 1, x2 = 2, we have:
Sage
For
xn = 7xn−2 + 6xn−3 ,
and x0 = 0, x1 = 1, x2 = 2, we have:
Sage
We see that several different matrices can be used to generate the terms.
84
To “solve” for xn , we want to compute the diagonalization of one of these
matrices, say
0 1 0
A= 0 0 1 .
−6 −1 4
To find the diagonalization, we need the eigenvalues and eigenvectors. Sage
can doe this easily.
Sage
Now, let’s work over the finite field GF (5). In this case, the recursion
becomes
x0 , x1 , · · · = 0, 1, 2, 2, 0, 1, 2, 2, . . . .
We check this using Sage:
Sage
85
sage: s1 = A*s0
sage: s2 = A*s1
sage: s3 = A*s2
sage: s4 = A*s3
sage: print s0.list()+[s1[2]]+[s2[2]]+[s3[2]]+[s4[2]]
[0, 1, 2, 2, 0, 1, 2]
sage: A = matrix(GF(5), [[0,1,0],[0,0,1],[-3,1,3]])
sage: s0 = vector(GF(5), [0,1,2])
sage: s1 = A*s0
sage: s2 = A*s1
sage: s3 = A*s2
sage: s4 = A*s3
sage: print s0.list()+[s1[2]]+[s2[2]]+[s3[2]]+[s4[2]]
[0, 1, 2, 2, 0, 1, 2]
Suppose we know the {xn }’s but not the key. Suppose we know
2 = 2 · c1 + 1 · c2 + 0 · c3 ,
0 = 2 · c1 + 2 · c2 + 1 · c3 ,
1 = 0 · c1 + 2 · c2 + 2 · c3 ,
2 = 1 · c1 + 0 · c2 + 2 · c3 ,
..
.,
and so on. Taking, say, the last three equations above, we obtain a system of
linear equations with augmented matrix
2 2 1 0
A= 0 2 2 1
1 0 2 2
with row-reduced echelon form
1 0 2 2
0 1 1 3
0 0 0 0
Therefore,
c1 = 2 + 3c3 , c2 = 3 + 4c3 .
Let’s look at this case-by-case.
86
• c3 = 0. Then the key is (c1 , c2 , c3 ) = (2, 3, 0). The equation xn =
2xn−1 + 3xn−2 gives
x0 , x1 , · · · = 0, 1, 2, 2, 0, 1, . . . ,
agreeing with the original sequence, but with a different key than the
one we started with.
x0 , x1 , · · · = 0, 1, 2, 2, 0, 1, . . . ,
agreeing with the original sequence, but with a different key than the
one we started with.
x0 , x1 , · · · = 0, 1, 2, 2, 0, 1, . . . ,
agreeing with the original sequence, but with a different key than the
one we started with.
x0 , x1 , · · · = 0, 1, 2, 2, 0, 1, . . . ,
agreeing with the original sequence, but with a different key than the
one we started with.
x0 , x1 , · · · = 0, 1, 2, 2, 0, 1, . . . ,
agreeing with the original sequence, and with same key than we started
with.
87
In any case, we can “break” this cipher very easily using linear algebra.
Here are some more Sage computations regarding this example. First, we
show that, in this example, we can diagonalize the matrix over GF (5).
Sage
This recursive equation can be written having a “shorter” key length (as we
already saw in the above itemized list, case c3 = 0):
Sage
sage: berlekamp_massey(s)
xˆ2 + 3*x + 2
sage: A = matrix(GF(5), [[0,1,0],[0,0,1],[-6,-1,4]])
sage: A
[0 1 0]
[0 0 1]
[4 4 4]
sage: A.eigenspaces_right()
[
(4, Vector space of degree 3 and dimension 1 over Finite Field of size 5
User basis matrix:
[1 4 1]),
(3, Vector space of degree 3 and dimension 1 over Finite Field of size 5
User basis matrix:
[1 3 4]),
(2, Vector space of degree 3 and dimension 1 over Finite Field of size 5
User basis matrix:
88
[1 2 4])
]
sage: F = GF(5); key = [F(-2), F(-3)]; fill = [F(0), F(1)]; n = 20
sage: s = lfsr_sequence(key,fill,n); s
[0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2]
an = α1 r1n + · · · + αk rkn
for some α1 , . . . , αk determined by the initial fill.
The generating function A(x) of a sequence {an } is
∞
X
A(x) = a0 + a1 x + ... = an x n . (16)
n=0
Example 47.
(1 + x + x3 )/(x4 + x3 + 1) = 1 + x + x3 + x4 + x5 + x7 + x8 + x9 + x11
+x12 + x13 + x15 + x16 + x17 + x19 + x20
+x21 + x23 + x24 + x25 + x27 + x28 + x29 + O(x30 ).
Example 48. We return to the finite field GF (5) and the recursion
89
x0 , x1 , · · · = 0, 1, 2, 2, 0, 1, 2, 2, . . . .
A key is (c1 , c2 , c3 ) = (2, 3, 0). We check Fact 2 above using Sage:
Sage
90
10 Bent functions
Recall a LFSR in GF (q) of length k is defined by an order k linear homoge-
neous recurrence relation with constant coefficients of the form:
Ωf = {x ∈ GF (2)n | v ≤ x},
where ≤ is the partial order defined above. We call f atomic if there is some
v 6= 0 such that f is atomic based on v.
Definition 52. Let f : GF (2)n → GF (2) be any monotone function. We
say that Γ ⊂ GF (2)n is the least support of f if Γ consists of all vectors in
Ωf which are smallest in the partial ordering ≤ on GF (2)n .
Theorem 53. Let f be a monotone Boolean function whose least support
vectors are given by Γ ⊂ GF (2)n . Then
Y
f (x) = 1 + (xv + 1). (17)
v∈Γ
91
where Γ is the set of least support vectors for a monotone Boolean function
f.
For x ∈ GF (2)n , define the subset Sx of least support vectors v ∈ Γ such
that v ≤ x as
Sx = {v ∈ Γ | v ≤ x}.
We will show f = g by proving f (x) = 0 ⇔ g(x) = 0.
(⇒) Let y ∈ GF (2)n satisfy f (y) = 0. Then, y 6∈ Ωf and Sy = ∅. Thus,
for every v ∈ Γ, there exists an i such that vi = 1 and yi = 0. Consequently,
from the definition of g, we have
Y
g(y) = 1 + (y v + 1) = 1 + 1 = 0.
v∈Γ
f : GF (q)m → GF (q)
be a given function. Label the N = q k elements of GF (q)n as follows:
f : GF (q)m → GF (q)
92
be a given function. Let a0 , a1 , . . . be a LFSR of key length k over GF (q)
having period P = q k − 1.
let
GF (2)m = {v0 , v1 , . . . , vM −1 },
where M = 2m . For any Boolean function f : GF (2)m → GF (2), define
Example 54. Let V = GF (2)2 = {(0, 0), (1, 0), (0, 1), (1, 1)}. The linear
functions on V are
These correspond to
fˆ0 = (1, 1, 1, 1), fˆ1 = (1, −1, 1, −1), fˆ2 = (1, 1, −1, −1), fˆ3 = (1, −1, −1, 1).
It is easy to check that fˆi ⊥ fˆj , for i 6= j. For a non-linear example, consider
g(x0 , x1 ) = x0 x1 , which coresponds to ĝ = (1, 1, 1, −1). Note this is not
perpendicular to any of the fˆi .
93
Figure 6: The plot of the autocorrelation function of f .
X = {xn } : 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, . . . .
94
Figure 7: The plot of the autocorrelation function of f .
X = {xn } : 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, . . . .
The table of values of the autocorrelation function is
k 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
AC(k,X) 1 -1/15 1/5 -1/15 -1/15 -1/15 -1/3 1/5 1/5 -1/3 -1/15 -1/15 -1/15 1/5 -1/15
95
Lemma 57. Let
L∧ = {fˆ | f ∈ L}.
A Boolean function f : GF (2)m → GF (2) is affine if and only if fˆ is perpen-
dicular to all but one of the vectors in L∧ .
(⇐): First, let us assume f is linear and show that it is perpendicular to all
but one of the vectors in L∧ . Suppose f (x) = x · a, for some a ∈ V . Then
X X
fˆ · ĝ = (−1)x·a+x·b = (−1)x·(a+b) .
x∈V x∈V
The following fact is easy to verify: given any non-zero c ∈ V , the number
of times x · c = 0 is 2m /2 and the number of times x · c = 1 is 2m /2. Based
on this, we see that
m
ˆ 2 , a + b = 0,
f · ĝ = (18)
0, a + b 6= 0.
(⇒): Now, suppose f is any function which has the property that
X
fˆ · ĝ = (−1)f (x)+x·b
x∈V
is equal to 0 for all b ∈ V except for one (to be discussed below). In other
words, if we multiply the vector fˆ by the 2m × 2m matrix
96
H 2 = M · IM ,
where IM is the m × M identity matrix. Therefore, H −1 = M −1 H. This
implies that
fˆ = H −1~v = M −1 H~v ,
where w~ = (w1 , . . . , wM ) ∈ RM is zero for all but one coordinate, say w` 6= 0.
Therefore, fˆ is a constant multiple of the `-th column of H. This forces fˆ to
be of the form cĝ, for some constant c and some linear function g. If c = 1
then f is linear and if c = −1 then f is affine.
This motivates the following question: What is the most non-linear func-
tion one can find?
A Boolean function
f : GF (2)m → GF (2)
is bent (also called perfectly non-linear) if, for all a ∈ GF (2)m ,
Computing Wf (a):
Order GF (2)m lexicographically
97
where M = 2m − 1. Using this order, define the character of f by
H = ((−1)vi ·vj | 0 ≤ i, j ≤ M )
Then the Walsh transform can be expressed in terms of this matrix transfor-
mation:
Wf = Hf ∗ .
f : GF (2)m → GF (2)
f (x) = x · b.
f : GF (2)m → GF (2)
is any Boolean function satisfying
0, if a 6= b,
Wf (a) =
2m , if a = b,
for some b ∈ GF (2)m , then f (x) = x · b.
98
11 Error-correcting codes
Roughly speaking a code is a system for converting a message into another
form for the purpose of communicating the message more efficiently or reli-
ably. A few examples are listed below.
A code could be used as a cipher, but most codes are not created with se-
curity in mind. For example, during the Prohibition Era, rumrunners used
slightly modified telegraph codes to transmit shipment information and meet-
ing places for ship-loads of alchohol. Such ciphers were routinely broken by
Coast Guard cryptographers.
Some codes are designed for compression - to store digital data more com-
pactly. Some codes are designed for reliability - to communicate information
over a noisy channel, yet to correct the errors which arise.
99
11.2 Basic definitions
The theory of error-correcting codes was originated by Richard Hamming
in the late 1940’s, a mathematician who worked for Bell Telephone. Some
specific examples of his codes actually arose earlier in various isolated con-
nections - for example, statistical design theory and in soccer betting(!).
Hamming’s motivation was to program a computer to correct “bugs” which
arose in punch-card programs. The overall goal behind the theory of error-
correcting codes is to reliably enable digital communication.
Let F = GF (q) be any finite field.
A (linear error-correcting) code C of length n over F is a vector subspace
of Fn (provided with the standard basis5 ) and its elements are called code-
words. When F = GF (2) it is called a binary code. These are the most
important codes from the practical point of view. Think of the following
scenario: You are sending an n-vector of 0’s and 1’s (the codeword) across
a noisy channel to your friend. Your friend gets a corrupted version (the
received word differs from the codeword in a certain number of error posi-
tions). Depending on how the code C was constructed and the number of
errors made, it is possible that the original codeword can be recovered. This
raises the natural question: given C, how many errors can be corrected? Stay
tuned...
A code of length n and dimension k (as a vector space over F) is called
an [n, k]-code. In abstract terms, an [n, k]-code is given by a short exact
sequence6
G H
0 → Fk → Fn → Fn−k → 0. (19)
We identify C with the image of G. The function
G : Fk → C,
~ 7−→ mG,
m ~
5
It is important that the code be provided with a fixed basis which never changes.
This is because the minimum distance function is not invariant under a change of basis.
However, the minimum distance is one quantity used to measure how “good” a code is,
from the practical point of view.
6
“Short exact” is a compact way of specifying the following three conditions at once:
(1) the first map G is injective, i.e., G is a full-rank k × n matrix, (2) the second map H
is surjective, and (3) image(G) = kernel(H).
100
is called the encoder. Since the sequence (19) is exact, a vector ~v ∈ Fn is a
codeword if and only if H(~v ) = 0. If Fn is given the usual standard vector
space basis then the matrix of G is a generating matrix of C and the matrix
of H is a check matrix of C. In other words,
C = {~c | ~c = mG,
~ some m ~ ∈ Fk }
= {~c ∈ Fn | H~c = ~0}.
When G has the block matrix form
G = (Ik | A),
d : Fn × Fn → R,
~ ~0).
~ = |{i | vi 6= wi }| = d(~v − w,
d(~v , w)
The Hamming weight of a vector is simply its distance from the origin:
101
n
Answer: (q − 1)r . Think about it! (Hint: “distance r” means that there
r
are exactly r non-zero coordinates. The binomial coefficient describes the number
of ways to choose these r coordinates.)
The minimum distance of C is defined to be the number
(It is not hard to see that this is equal to the closest distance between any
two distinct codewords in C.) An [n, k]-code with minimum distance d is
called an [n, k, d]-code.
k + d ≤ n + 1.
Note: this bound does not depend on the size of F. A code C whose
parameters satisfy k + d = n + 1 is called maximum distance separable or
MDS. Such codes, when they exist, are in some sense best possible.
proof: Fix a basis of Fnq and write all the codewords in this basis. Delete
the first d − 1 coordinates in each code word. Call this new code C 0 . Since
C has minimum distance d, these codewords of C 0 are still distinct. There
are therefore q k of them. But there cannot be more than q n−d+1 = |Fn−d+1
q |
of them. This gives the inequality.
The rate of the code is R = k/n - this measures how much information
the code can transmit. The relative minimum distance of the code is δ = d/n
- this is directly related to how many errors can be corrected.
~ ∈ Fn | d(~v , w)
Br (~v ) = {w ~ ≤ r}
contains at most one codeword in C.
This follows easily from the fact that the Hamming metric is, in fact, a
metric. Here is a picture of the idea.
102
◦ • • ◦ • • ◦
• • • • • • •
• • • •'• •$•
◦ • • ◦ • • ◦
• • • •&• •%•
• • • • • • •
◦ • • ◦ • • ◦
Lemma 63. (sphere-packing bound) For any code C ⊂ Fn , we have
t
X n
|C| (q − 1)i ≤ q n ,
i
i=0
elements. The result follows from the fact that ∪~c∈C Bt (~c) ⊂ Fn and |Fn | = q n .
Suppose (a) you sent ~c ∈ C, (b) your friend received ~v ∈ Fn , (c) you
know (or are very confident) that the number t of errors made is less than or
equal to [ d−1
2
]. By the lemma above, the “ball” about ~v of radius t contains a
unique codeword. It must be ~c, so your friend can recover what you sent (by
searching though all the vectors in the ball and checking which one is in C)
even though she/he only knows C and ~v . This is called the nearest neighbor
decoding algorithm:
1. Input: A received vector ~v ∈ Fn .
Output: A codeword ~c ∈ C closest to ~v .
2. Enumerate the elements of the ball Bt (~v ) about the received word. Set
~c =“fail”.
103
3. For each w~ ∈ Bt (~v ), check if w
~ ∈ C. If so, put ~c = w
~ and break to the next
step; otherwise, discard w ~ and move to the next element.
4. Return ~c.
• the speed at which a “good” encoder for the code can be implemented,
• the speed at which a “good” decoder for the code can be implemented.
Definition 65. Let r > 1. The Hamming [n, k, 3]-code C is the linear code
with
n = 2r − 1, k = 2r − r − 1,
and parity check matrix H defined to be the matrix whose columns are all the
(distinct) non-zero vectors in GF (2)r . By Lemma 66, this code has minimum
distance d = 3.
104
Proof. Indeed, if C has a code wode of weight 1 then the parity check matrix
H of C would have to have a column which consists of the zero vector,
contradicting the definition of H. Likewise, if C has a code wode of weight
2 then the parity check matrix H of C would have to have two identical
columns, contradicting the definition of H. Thus d ≥ 3.
Since
1 0 1
0 1 1
0 0
, , and 0 ,
.. .. ..
. . .
0 0 0
form three columns of the parity check matrix H of C - say the 1st , 2nd , and
3rd columns - the vector (1, 1, 1, 0, ..., 0) must be a code word. Thus d ≤ 3.
Example 67.r = 2 The Hamming [3, 1]-code has parity check matrix
1 0 1
H=
0 1 1
The matrix
1 1 0 1 0 0 0
0 1 1 0 1 0 0
G=
1
0 1 0 0 1 0
1 1 1 0 0 0 1
is a generating matrix.
Example 68. Consider the Hamming [7, 4] example above. The meaning of
the statement that G is a generator matrix is that a vector
105
'$
'$
A 1'$
4 2 B
7 5
6&%
&%
3
&%
x1
x2
x3
~x =
x4
x5
x6
x7
is a codeword if and only if ~x is a linear combination of the rows of G. The
meaning of the statement that H is a check matrix is H~x = ~0, ie
x1 + x4 + x6 + x7 = 0, x2 + x4 + x5 + x7 = 0, x3 + x5 + x6 + x7 = 0.
106
Sage
sage: C = codes.HammingCode(3,GF(2)); C
Linear code of length 7, dimension 4 over Finite Field of size 2
sage: C.minimum_distance()
3
sage: H = matrix(GF(2), 3, 7, [[1, 0, 0, 1, 0, 1, 1], [0, 1, 0, 1, 1, 0, 1], [0, 0, 1, 0, 1, 1, 1]])
sage: H
[1 0 0 1 0 1 1]
[0 1 0 1 1 0 1]
[0 0 1 0 1 1 1]
sage: C = codes.LinearCodeFromCheckMatrix(H)
sage: C.check_mat()
[1 0 0 1 0 1 1]
[0 1 0 1 1 0 1]
[0 0 1 0 1 1 1]
sage: C.minimum_distance()
3
sage: C.list()
[(0, 0, 0, 0, 0, 0, 0),
(1, 0, 0, 0, 1, 0, 1),
(0, 1, 0, 0, 0, 1, 1),
(1, 1, 0, 0, 1, 1, 0),
(0, 0, 1, 0, 1, 1, 1),
(1, 0, 1, 0, 0, 1, 0),
(0, 1, 1, 0, 1, 0, 0),
(1, 1, 1, 0, 0, 0, 1),
(0, 0, 0, 1, 1, 1, 0),
(1, 0, 0, 1, 0, 1, 1),
(0, 1, 0, 1, 1, 0, 1),
(1, 1, 0, 1, 0, 0, 0),
(0, 0, 1, 1, 0, 0, 1),
(1, 0, 1, 1, 1, 0, 0),
(0, 1, 1, 1, 0, 1, 0),
(1, 1, 1, 1, 1, 1, 1)]
107
it does, C is called perfect) How much larger do we have to make the radius
so that the union of these balls does cover all of V ? In other words, we want
to increase the radius r = [(d − 1)/2] to some new radius rho so that
∪c∈C B(c, ρ) = V.
This new radius is called the covering radius. In general, it is hard to find
good upper bounds on ρ. A coset is a subset of GF (q)n of the form C + v for
some v ∈ GF (q)n . Equivalently, a coset is a pre-image of some y in GF (q)n−k
under the check matrix H : GF (q)n → GF (q)n−k . Let S be a coset of C.
Then, a coset leader of S is an element of S having smallest weight.
Theorem 69. The coset leaders of a Hamming code are those vectors of
wt ≤ 1.
Proof. Let the Hamming code be defined as a [n, k, d] code as above where
for some integer r, n = 2r − 1, k = 2r − 1 − r, and d = r. In the binary case,
the size of the ambient space is q n = 2n = |GF (q)n | and the size of the code
is q k = 2k = |C|. Thus, the size of any coset S of C is
w1 = v1 + c1 , w2 = v1 + c2 .
So,
w1 − w2 = c1 − c2 ∈ C.
And, since wt(w1 − w2 ) = 2 and d(C) = 3 for a Hamming code, we have a
contradiction. Also, by the Pigeonhole Principle, each coset contains exactly
one vector of wt = 1. Thus, the claim holds, and this also proves the theorem.
Proof. Since d(C) = 3 for Hamming codes, we desire to show that equality
holds in
ρ = [(d − 1)/2] = 1.
108
To attain a contradiction, assume
ρ= max d(x, C) > 1;
x∈GF (q)n
then for some x ∈ GF (q)n , d(x, C) > 1. But by the previous theorem, the
coset x + C must contain a coset leader of wt ≤ 1, a contradiction to the
assumption that d(x, C) > 1. Thus, ρ = 1.
12 Steganography
Basic idea:
Steganography, meaning “covered writing,” is the science of secret com-
munication. The medium used to carry the information is called the ”cover”
or ”stego-cover.” The term ”digital steganography” refers to secret commu-
nication where the cover is a digital media file.
Cryptography is usually devoted to messages between parties where the
ciphertext is known. In steganography, one tries to hide the existence of the
communication itself. Early examples include writing on the backing of a
wax tablet before covering it, shaving and tattooing the head of a slave, only
to let the hair re-grow, or using invisible ink.
One of the most common systems of digital steganography is the Least
Significant Bit (LSB) system. In this system, the encoder embeds one bit of
information in the least significant bit of a binary number representing the
darkness of a pixel of a given image. In this situation, a greyscale image is
regarded as an array of pixels, where each pixel is represented by a binary
vector of a certain fixed length. Care must be taken with this system to ensure
that the changes made do not betray the stego-cover, while still maximizing
the information hidden.
From a short note of Crandell [Cr] in 1998, it was realized that error-
correcting codes can give rise to “stego-schemes,” ie, methods by which a
message can be hidden in a digital file efficiently.
Usages:
Espionage: In the summer of 2010, 11 suspected Russian spies were ar-
rested in the United States. According to the FBI’s charging documents,
these individuals used a steganographic system that embedded information
into images.
Terrorism: Stegonagraphy is discussed in “Technical Mujahid, Issue #2”
from February 2007. Despite numerous newspaper reports (eg, USA Today
109
Figure 8: The plot of two “tanks” using matrix plot.
in the early 2000’s), there are no (publicly) known cases of terrorist groups
using steganography.
A really simple illustration can be made using Sage’s matrix plot com-
mand.
Here is Sage code used to create the “tank” on the left side of Figure 8.
What matrix produces the “tank” on the right?
Sage
T = [[1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1],
[1,1,1,1,0,0,1,1,1],
[1,0,0,0,0,0,0,1,1],
[1,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,1,1],
[1,0,0,1,1,0,0,1,1]]
A = matrix(T)
matrix_plot(A)
The images look very similar, since we have only changed one “pixel.” Where
that changed pixel is located can communicate (hidden) information.
The rest of our discussion will follow Tucker-Davis’ thesis [TD].
110
where
and
rec(emb(c, m, k), k) = m, (20)
for all m ∈ M, c ∈ C, K ∈ K. We will assume that a fixed key K ∈ K is
used, and therefore, the dependence on an element in the keyspace K can
be ignored. The original cover c is called the plain cover, m is called the
message, and emb(c, m, k) = emb(c, m) is called the stegocover. Let C be
GF (q)n , representing both plain and stego covers. Also, let M be GF (q)k ,
where k is a fixed integer such that 0 ≤ k ≤ n.
An (n, k, t) stegocoding function over finite field GF (q) is a vector-valued
linear transformation L(x) = (`1 (x), `2 (x), . . . , `k (x)) : GF (q)n → GF (q)k
satisfying the following condition: For any given x ∈ GF (q)n and y ∈
GF (q)k , there exists a z ∈ GF (q)n such that wt(z) ≤ t and L(x + z) = y.
We call the matrix L an (n, k, t) stego-code matrix.
In this case,
• y is the message,
111
12.2 Examples
First, we consider and example from a linear error-correcting block code, C.
Example 71. Let C be the [n, n−k, d] binary linear code of dimension n−k
and minimum distance d having check matrix L. In other words, C is given
by C = ker(L), where L is a k × n matrix of full rank over GF (2). Choose
t such that it is the largest weight of all the coset leaders of C. For each
y ∈ GF (2)k , let v = v(y) ∈ GF (2)n be such that L−1 (y) = C + v. For each
x ∈ GF (2)n , select z to be an element of C + v + x of smallest weight, i.e. a
coset leader.
112
Example 73. First, new notation must be defined. For any positive integer
m, [m]2 denotes the binary representation of m. Similarly, for any binary
representation x, [x]10 denotes the associated positive integer. Therefore, for
any binary x, [[x]10 ]2 = x, and for any positive integer m, [[m]2 ]10 = m.
In this system, the embedding map is defined as
At this point, note that the message is in GF (2)q , and both the plain
text and stegocover are in GF (2)n .
The recovery map is
Theorem 74. With emb and rec as in (22) and (24), respectively, we have
rec(emb(c, m)) = m.
References
[BF] J. Bierbrauer and J. Fridrich. Constructing good covering codes for ap-
plications in steganography, preprint, 2006.
http://www.math.mtu.edu/jbierbra/.
113
[Bo] D. Boneh, Twenty years of attacks on the RSA cryptosystem, Notices
of the American Mathematical Society 46 (1999) 203213.
http://crypto.stanford.edu/~dabo/abstracts/
RSAattack-survey.html
[Br] Timothy Brock’s Honors Project 2005-2006, Linear Feedback Shift Reg-
isters and Cyclic Codes in Sage,
http://www.usna.edu/Users/math/wdj/_files/documents/brock/
[C] C. Celerier, Feedback with carry shift registers and bent sequences,
Honors Project 2011-2012.
http://www.usna.edu/Users/math/wdj/_files/documents/
celerier/
[Cry] Cryptologia, a scholarly journal dealing with the history and technol-
ogy of communications intelligence.
http://www.tandfonline.com/loi/ucry20
[D] Arthur Conan Doyle, Sherlock Holmes tale The Adventure of the Danc-
ing Men, http://en.wikipedia.org/wiki/The_Adventure_of_the_
Dancing_Men
114
[JKT] David Joyner, Richard Kreminski, JoAnn Turisco, Applied Abstract
Algebra, Johns Hopkins Univ. Press, 2004.
[K] David Kahn, The Codebreakers, 1996.
[Ko] David Kohel, Cryptography, notes 2008 (138 pages with Sage code).
http://www.sagemath.org/files/kohel-book-2008.pdf
[McA] A. McAndrew, Introduction to Cryptography with Open-
source Software, CRC Press, 2011
[MvOV] Alfred J. Menezes, Paul C. van Oorschot and Scott A. Vanstone ,
Handbook of Applied Cryptography, CRC Press, 1996.
http://www.cacr.math.uwaterloo.ca/hac/
(All chapters are free online.)
[Mi] Gary L. Miller, Riemann’s hypothesis and tests for primality, In
Proceedings of Seventh Annual ACM Symposium on Theory
of Computing, pp. 234239, May 1975.
http://www.cs.cmu.edu/~glmiller/Publications/Papers/Mi75.
pdf.
[Mu] Munuera, Carlos, Steganography from a Coding Theory Point of View,
preprint, 2010.
http://www.singacom.uva.es/oldsite/Actividad/s3cm/s3cm10/
10courses.html
[Po] Edgar Allan Poe, The Raven, http://en.wikipedia.org/wiki/The_
Raven
The Gold-Bug, http://en.wikipedia.org/wiki/The_Gold-Bug
[P] C. Praeger, Course notes at
http://school.maths.uwa.edu.au/~praeger/teaching/3CC/WWW/
chapter2.html
[St] A. Stanoyevitch, Introduction to Cryptography with Mathemat-
ical Foundation, CRC Press, 2010.
[TD] Kyle Tucker-Davis, ”An analysis of the F5 steganographic system”,
Honors Project 2010-2011
http://www.usna.edu/Users/math/wdj/_files/documents/
tucker-davis/
115
[ZL] W. Zhang and S. Li. Steganographic Codes- a New Problem of Coding
Theory, preprint, 2005.
http://arxiv.org/abs/cs/0505072.
116