Fixed the merge conflict
[cipher-training.git] / slides / keyword-encipher.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>Affine ciphers</title>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
6 <style type="text/css">
7 /* Slideshow styles */
8 body {
9 font-size: 20px;
10 }
11 h1, h2, h3 {
12 font-weight: 400;
13 margin-bottom: 0;
14 }
15 h1 { font-size: 3em; }
16 h2 { font-size: 2em; }
17 h3 { font-size: 1.6em; }
18 a, a > code {
19 text-decoration: none;
20 }
21 code {
22 -moz-border-radius: 5px;
23 -web-border-radius: 5px;
24 background: #e7e8e2;
25 border-radius: 5px;
26 font-size: 16px;
27 }
28 .plaintext {
29 background: #272822;
30 color: #80ff80;
31 text-shadow: 0 0 20px #333;
32 padding: 2px 5px;
33 }
34 .ciphertext {
35 background: #272822;
36 color: #ff6666;
37 text-shadow: 0 0 20px #333;
38 padding: 2px 5px;
39 }
40 .float-right {
41 float: right;
42 }
43 </style>
44 </head>
45 <body>
46 <textarea id="source">
47
48 # Keyword ciphers
49
50 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
51 --|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|--
52 k | e | y | w | o | r | d | a | b | c | f | g | h | i | j | l | m | n | p | q | s | t | u | v | x | z
53
54 * Taking a more Pythonic approach
55
56 ---
57
58 # The cipher
59
60 * Still character-by-character substitution, still monosubstitution.
61
62 Ciphertext alphabet: start with a keyword, write out the rest of the alphabet, removing duplicates.
63
64 ## Three variants
65
66 Write out the rest of the alphabet...
67
68 1. ...starting from 'a' (keywordabcf...)
69 2. ...starting from the last letter of the keyword (keywordfgh...)
70 3. ...starting from the largest letter of the keyword (keywordzabc...)
71
72 ---
73
74 # A more Pythonic way
75
76 _string_`.translate()` and _string_`.maketrans()`
77
78 * Make the 'ciphertext' alphabet, relate to the 'plaintext' alphabet (`string.ascii_lowercase`)
79 * Use those to make the translation table
80 * Enciphering is simply applying `plaintext.translate(enciphering_table)`
81 * Deciphering just uses a different table
82
83 ---
84
85 # Making the cipher alphabet from a keyword
86
87 Three challenges:
88
89 1. How to say which type of cipher alphabet to use
90 2. Where to start the rest of the alphabet
91 3. Removing duplicate letters
92
93 Solutions:
94
95 1. Keyword arguments for procedures
96 2. sort and slices
97 3. Use something like an ordered set
98
99 Both enciphering and deciphering need the same keyword-based alphabet, so pull this out into another procedure.
100
101 ---
102
103 # Keyword arguments
104
105 Used to:
106 1. give a default value for a parameter
107 2. allow parameters to be named (not just positional)
108
109 Give our `keyword_encipher` and `keyword_decipher` procedures a keyword parameter of `wrap_alphabet`.
110
111 Pass this parameter to the `keyword_alphabet` procedure.
112
113 ## Note: `Enum` introduced in Python 3.4. This is a better solution.
114
115 ---
116
117 # Deduplicating a sequence
118
119 We need
120
121 * Something set-like
122 * Something ordered
123
124 No ordered set in Python, but do have an ordered dict.
125
126 * Keys of a dict are a set.
127 * Keys in an ordered dict retain their order (subsequent instances are ignored)
128
129 `deduplicated_list = list(collections.OrderedDict.fromkeys(list))`
130
131 ---
132
133 # Sorts and slices
134
135 ## Recap
136 Write out the rest of the alphabet...
137
138 1. ...starting from 'a' (keywordabcf...)
139 2. ...starting from the last letter of the keyword (keywordfgh...)
140 3. ...starting from the largest letter of the keyword (keywordzabc...)
141
142 * Santitise the keyword before we use it
143
144 ## Cases
145 1. As we're deduplicating anyway, just add the entire alphabet to the end of the keyword, then deduplicate.
146 `deduplicate(keyword + string.ascii_lowercase)`
147
148 2. and 3. How to find the appropriate letter of the keyword.
149
150 Indexing pulls out letters. `'keyword'[0]` = 'k' ; `'keyword'[3]` = 'w' ; `'keyword'[-1]` = 'd'
151 Slices pulls out substrings. `'keyword'[1:4]` = 'eyw' ; `'keyword'[:3]` = 'key' ; `'keyword'[5:]` = 'rd'
152
153 `deduplicate(keyword + string_ascii_lowercase[from:] + string.ascii_lowercase)`
154
155 Question: why not take a slice of the second alphabet copy?
156
157 Question: what do we use as the last letter of 'character'? 'r' or 'e'?
158
159 `sorted()` will put a string in lexicographical order.
160 `.find()` will find an item in a sequence
161
162 ---
163
164 # Keyword enciphering
165
166 Now we've got the keyword-based cipher alphabet, simply use `.translate()` to do the enciphering/deciphering.
167
168 Use `''.maketrans()` to make the translation table.
169
170 Sorted!
171
172 Does it pass the tests?
173
174 </textarea>
175 <script src="http://gnab.github.io/remark/downloads/remark-0.6.0.min.js" type="text/javascript">
176 </script>
177
178 <script type="text/javascript"
179 src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML&delayStartupUntil=configured"></script>
180
181 <script type="text/javascript">
182 var slideshow = remark.create({ ratio: "16:9" });
183
184 // Setup MathJax
185 MathJax.Hub.Config({
186 tex2jax: {
187 skipTags: ['script', 'noscript', 'style', 'textarea', 'pre']
188 }
189 });
190 MathJax.Hub.Queue(function() {
191 $(MathJax.Hub.getAllJax()).map(function(index, elem) {
192 return(elem.SourceElement());
193 }).parent().addClass('has-jax');
194 });
195 MathJax.Hub.Configured();
196 </script>
197 </body>
198 </html>