Started on documentation
[szyfrow.git] / docs / szyfrow / cadenus.html
1 <!doctype html>
2 <html lang="en">
3 <head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
6 <meta name="generator" content="pdoc 0.9.2" />
7 <title>szyfrow.cadenus API documentation</title>
8 <meta name="description" content="Enciphering and deciphering using the [Cadenus cipher](https://www.thonky.com/kryptos/cadenus-cipher).
9 Also attempts to break messages that use a …" />
10 <link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
11 <link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
12 <link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
13 <style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
14 <style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
15 <style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
16 <script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
17 <script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
18 </head>
19 <body>
20 <main>
21 <article id="content">
22 <header>
23 <h1 class="title">Module <code>szyfrow.cadenus</code></h1>
24 </header>
25 <section id="section-intro">
26 <p>Enciphering and deciphering using the <a href="https://www.thonky.com/kryptos/cadenus-cipher">Cadenus cipher</a>.
27 Also attempts to break messages that use a Cadenus cipher.</p>
28 <p>The plaintext is written out in a grid, with one column per letter of the
29 keyword. The plaintext is written out left to right in rows. The plaintext
30 needs to fill 25 rows: if it is shorter, the text is padded; if longer, it is
31 broken into 25-row chunks.</p>
32 <p>For instance, the 100 letter chunk:</p>
33 <blockquote>
34 <p>Whoever has made a voyage up the Hudson must remember the Kaatskill mountains.
35 They are a dismembered branch of the great</p>
36 </blockquote>
37 <p>and the keyword "wink" would written out as the leftmost grid below.</p>
38 <p>The columns are then rotated according to the <em>keycolumn</em>. For each column, the
39 keyword letter in that column is found in the keycolumn. This identifies a
40 specific row in the grid. That column only is rotated upwards until the selected
41 row is at the top of the column. Each column is rotated independently, according
42 to its keyword letter.</p>
43 <p>For instance, the middle grid below is formed from the leftmost grid by
44 rotating the first column up four positions, the second column up 17 positions,
45 and so on. (The letters chosen to head the new colums are capitalised in the
46 leftmost grid.)</p>
47 <p>Finally, each row is transposed given the alphabetic order of the keyword (as
48 seen in the rightmost grid below).</p>
49 <p>The ciphertext is read out in rows, starting with the now-leftmost column. For
50 the example, the ciphertext would be </p>
51 <blockquote>
52 <p>antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaasuvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned'</p>
53 </blockquote>
54 <pre><code>w i n k w i n k i k n w
55 ------- ------- -------
56 w h o e a o a t n a n t o
57 v e r h z e d l e d e l e
58 a s m a y h e u e e e u h
59 d e a v x d r i s r s i d
60 O y a g vw m r h b r b h m
61 e u p t u r h r d h d r r
62 h e h u t m h i n h n i m
63 d s o n s t e m f e f m t
64 m u s t r a h e g h g e a
65 r e m e q k e a t e t a k
66 m b e r p m s o e s e o m
67 t h e k o t e e h e h e t
68 a a T s n s y a a y a a s
69 k i l l m y u o v u v o y
70 m o u n l a e r g e g r a
71 t a i N k m s m t s t m m
72 s t h e j e u a u u u a e
73 y A r e i b e a n e n a b
74 a d i s h c b p t b t p c
75 m e m b g t h h e h e h t
76 e r e d f r a o r a r o r
77 b r a n e w i s k i k s w
78 c h o f d v o m s o s m v
79 t h e g c a a e l a l e a
80 r e a t b d t e n t n e d
81 </code></pre>
82 <details class="source">
83 <summary>
84 <span>Expand source code</span>
85 </summary>
86 <pre><code class="python">&#34;&#34;&#34;Enciphering and deciphering using the [Cadenus cipher](https://www.thonky.com/kryptos/cadenus-cipher).
87 Also attempts to break messages that use a Cadenus cipher.
88
89 The plaintext is written out in a grid, with one column per letter of the
90 keyword. The plaintext is written out left to right in rows. The plaintext
91 needs to fill 25 rows: if it is shorter, the text is padded; if longer, it is
92 broken into 25-row chunks.
93
94 For instance, the 100 letter chunk:
95
96 &gt; Whoever has made a voyage up the Hudson must remember the Kaatskill mountains.
97 &gt; They are a dismembered branch of the great
98
99 and the keyword &#34;wink&#34; would written out as the leftmost grid below.
100
101 The columns are then rotated according to the _keycolumn_. For each column, the
102 keyword letter in that column is found in the keycolumn. This identifies a
103 specific row in the grid. That column only is rotated upwards until the selected
104 row is at the top of the column. Each column is rotated independently, according
105 to its keyword letter.
106
107 For instance, the middle grid below is formed from the leftmost grid by
108 rotating the first column up four positions, the second column up 17 positions,
109 and so on. (The letters chosen to head the new colums are capitalised in the
110 leftmost grid.)
111
112 Finally, each row is transposed given the alphabetic order of the keyword (as
113 seen in the rightmost grid below).
114
115 The ciphertext is read out in rows, starting with the now-leftmost column. For
116 the example, the ciphertext would be
117
118 &gt; antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaasuvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned&#39;
119
120 ```
121 w i n k w i n k i k n w
122 ------- ------- -------
123 w h o e a o a t n a n t o
124 v e r h z e d l e d e l e
125 a s m a y h e u e e e u h
126 d e a v x d r i s r s i d
127 O y a g vw m r h b r b h m
128 e u p t u r h r d h d r r
129 h e h u t m h i n h n i m
130 d s o n s t e m f e f m t
131 m u s t r a h e g h g e a
132 r e m e q k e a t e t a k
133 m b e r p m s o e s e o m
134 t h e k o t e e h e h e t
135 a a T s n s y a a y a a s
136 k i l l m y u o v u v o y
137 m o u n l a e r g e g r a
138 t a i N k m s m t s t m m
139 s t h e j e u a u u u a e
140 y A r e i b e a n e n a b
141 a d i s h c b p t b t p c
142 m e m b g t h h e h e h t
143 e r e d f r a o r a r o r
144 b r a n e w i s k i k s w
145 c h o f d v o m s o s m v
146 t h e g c a a e l a l e a
147 r e a t b d t e n t n e d
148 ```
149
150 &#34;&#34;&#34;
151 from itertools import chain
152 import multiprocessing
153 from szyfrow.support.utilities import *
154 from szyfrow.support.language_models import *
155
156
157 def make_cadenus_keycolumn(doubled_letters = &#39;vw&#39;, start=&#39;a&#39;, reverse=False):
158 &#34;&#34;&#34;Makes the key column for a Cadenus cipher (the column down between the
159 rows of letters)
160
161 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;a&#39;]
162 0
163 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;b&#39;]
164 1
165 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;c&#39;]
166 2
167 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;v&#39;]
168 21
169 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;w&#39;]
170 21
171 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;z&#39;]
172 24
173 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;a&#39;]
174 1
175 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;b&#39;]
176 0
177 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;c&#39;]
178 24
179 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;i&#39;]
180 18
181 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;j&#39;]
182 18
183 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;v&#39;]
184 6
185 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;z&#39;]
186 2
187 &#34;&#34;&#34;
188 index_to_remove = string.ascii_lowercase.find(doubled_letters[0])
189 short_alphabet = string.ascii_lowercase[:index_to_remove] + string.ascii_lowercase[index_to_remove+1:]
190 if reverse:
191 short_alphabet = cat(reversed(short_alphabet))
192 start_pos = short_alphabet.find(start)
193 rotated_alphabet = short_alphabet[start_pos:] + short_alphabet[:start_pos]
194 keycolumn = {l: i for i, l in enumerate(rotated_alphabet)}
195 keycolumn[doubled_letters[0]] = keycolumn[doubled_letters[1]]
196 return keycolumn
197
198 def cadenus_encipher(message, keyword, keycolumn, fillvalue=&#39;a&#39;):
199 &#34;&#34;&#34;Encipher with the Cadenus cipher
200
201 &gt;&gt;&gt; cadenus_encipher(sanitise(&#39;Whoever has made a voyage up the Hudson &#39; \
202 &#39;must remember the Kaatskill mountains. &#39; \
203 &#39;They are a dismembered branch of the great&#39;), \
204 &#39;wink&#39;, \
205 make_cadenus_keycolumn(doubled_letters=&#39;vw&#39;, start=&#39;a&#39;, reverse=True))
206 &#39;antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaasuvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned&#39;
207 &gt;&gt;&gt; cadenus_encipher(sanitise(&#39;a severe limitation on the usefulness of &#39; \
208 &#39;the cadenus is that every message must be &#39; \
209 &#39;a multiple of twenty-five letters long&#39;), \
210 &#39;easy&#39;, \
211 make_cadenus_keycolumn(doubled_letters=&#39;vw&#39;, start=&#39;a&#39;, reverse=True))
212 &#39;systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtofarenuseieeieltarlmentieetogevesitfaisltngeeuvowul&#39;
213 &#34;&#34;&#34;
214 transpositions = transpositions_of(keyword)
215 enciphered_chunks = []
216 for message_chunk in chunks(message, len(transpositions) * 25,
217 fillvalue=fillvalue):
218 rows = chunks(message_chunk, len(transpositions), fillvalue=fillvalue)
219 columns = zip(*rows)
220 rotated_columns = [col[start:] + col[:start] for start, col in zip([keycolumn[l] for l in keyword], columns)]
221 rotated_rows = zip(*rotated_columns)
222 transposed = [transpose(r, transpositions) for r in rotated_rows]
223 enciphered_chunks.append(cat(chain(*transposed)))
224 return cat(enciphered_chunks)
225
226 def cadenus_decipher(message, keyword, keycolumn, fillvalue=&#39;a&#39;):
227 &#34;&#34;&#34;
228 &gt;&gt;&gt; cadenus_decipher(&#39;antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaa&#39; \
229 &#39;suvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned&#39;, \
230 &#39;wink&#39;, \
231 make_cadenus_keycolumn(reverse=True))
232 &#39;whoeverhasmadeavoyageupthehudsonmustrememberthekaatskillmountainstheyareadismemberedbranchofthegreat&#39;
233 &gt;&gt;&gt; cadenus_decipher(&#39;systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtof&#39; \
234 &#39;arenuseieeieltarlmentieetogevesitfaisltngeeuvowul&#39;, \
235 &#39;easy&#39;, \
236 make_cadenus_keycolumn(reverse=True))
237 &#39;aseverelimitationontheusefulnessofthecadenusisthateverymessagemustbeamultipleoftwentyfiveletterslong&#39;
238 &#34;&#34;&#34;
239 transpositions = transpositions_of(keyword)
240 deciphered_chunks = []
241 for message_chunk in chunks(message, len(transpositions) * 25,
242 fillvalue=fillvalue):
243 rows = chunks(message_chunk, len(transpositions), fillvalue=fillvalue)
244 untransposed_rows = [untranspose(r, transpositions) for r in rows]
245 columns = zip(*untransposed_rows)
246 rotated_columns = [col[-start:] + col[:-start] for start, col in zip([keycolumn[l] for l in keyword], columns)]
247 rotated_rows = zip(*rotated_columns)
248 deciphered_chunks.append(cat(chain(*rotated_rows)))
249 return cat(deciphered_chunks)
250
251
252
253 def cadenus_break(message, wordlist=None,
254 doubled_letters=&#39;vw&#39;, fitness=Pbigrams):
255 &#34;&#34;&#34;Breaks a Cadenus cipher using a dictionary and
256 frequency analysis
257
258 If `wordlist` is not specified, use
259 [`szyfrow.support.langauge_models.keywords`](support/language_models.html#szyfrow.support.language_models.keywords).
260 &#34;&#34;&#34;
261 if wordlist is None:
262 wordlist = keywords
263
264 # c = make_cadenus_keycolumn(reverse=True)
265 # valid_words = [w for w in wordlist
266 # if len(transpositions_of(w)) == len(message) // 25]
267 with multiprocessing.Pool() as pool:
268 results = pool.starmap(cadenus_break_worker,
269 [(message, w,
270 make_cadenus_keycolumn(doubled_letters=doubled_letters,
271 start=s, reverse=r),
272 fitness)
273 for w in wordlist
274 for s in string.ascii_lowercase
275 for r in [True, False]
276 # if max(transpositions_of(w)) &lt;= len(
277 # make_cadenus_keycolumn(
278 # doubled_letters=doubled_letters, start=s, reverse=r))
279 ])
280 # return list(results)
281 return max(results, key=lambda k: k[1])
282
283 def cadenus_break_worker(message, keyword, keycolumn, fitness):
284 # message_chunks = chunks(message, 175)
285 # plaintext = &#39;&#39;.join(cadenus_decipher(c, keyword, keycolumn) for c in message_chunks)
286 plaintext = cadenus_decipher(message, keyword, keycolumn)
287 fit = fitness(plaintext)
288 return (keyword, keycolumn), fit
289
290 if __name__ == &#34;__main__&#34;:
291 import doctest</code></pre>
292 </details>
293 </section>
294 <section>
295 </section>
296 <section>
297 </section>
298 <section>
299 <h2 class="section-title" id="header-functions">Functions</h2>
300 <dl>
301 <dt id="szyfrow.cadenus.cadenus_break"><code class="name flex">
302 <span>def <span class="ident">cadenus_break</span></span>(<span>message, wordlist=None, doubled_letters='vw', fitness=&lt;function Pbigrams&gt;)</span>
303 </code></dt>
304 <dd>
305 <div class="desc"><p>Breaks a Cadenus cipher using a dictionary and
306 frequency analysis</p>
307 <p>If <code>wordlist</code> is not specified, use
308 <a href="support/language_models.html#szyfrow.support.language_models.keywords"><code>szyfrow.support.langauge_models.keywords</code></a>.</p></div>
309 <details class="source">
310 <summary>
311 <span>Expand source code</span>
312 </summary>
313 <pre><code class="python">def cadenus_break(message, wordlist=None,
314 doubled_letters=&#39;vw&#39;, fitness=Pbigrams):
315 &#34;&#34;&#34;Breaks a Cadenus cipher using a dictionary and
316 frequency analysis
317
318 If `wordlist` is not specified, use
319 [`szyfrow.support.langauge_models.keywords`](support/language_models.html#szyfrow.support.language_models.keywords).
320 &#34;&#34;&#34;
321 if wordlist is None:
322 wordlist = keywords
323
324 # c = make_cadenus_keycolumn(reverse=True)
325 # valid_words = [w for w in wordlist
326 # if len(transpositions_of(w)) == len(message) // 25]
327 with multiprocessing.Pool() as pool:
328 results = pool.starmap(cadenus_break_worker,
329 [(message, w,
330 make_cadenus_keycolumn(doubled_letters=doubled_letters,
331 start=s, reverse=r),
332 fitness)
333 for w in wordlist
334 for s in string.ascii_lowercase
335 for r in [True, False]
336 # if max(transpositions_of(w)) &lt;= len(
337 # make_cadenus_keycolumn(
338 # doubled_letters=doubled_letters, start=s, reverse=r))
339 ])
340 # return list(results)
341 return max(results, key=lambda k: k[1])</code></pre>
342 </details>
343 </dd>
344 <dt id="szyfrow.cadenus.cadenus_break_worker"><code class="name flex">
345 <span>def <span class="ident">cadenus_break_worker</span></span>(<span>message, keyword, keycolumn, fitness)</span>
346 </code></dt>
347 <dd>
348 <div class="desc"></div>
349 <details class="source">
350 <summary>
351 <span>Expand source code</span>
352 </summary>
353 <pre><code class="python">def cadenus_break_worker(message, keyword, keycolumn, fitness):
354 # message_chunks = chunks(message, 175)
355 # plaintext = &#39;&#39;.join(cadenus_decipher(c, keyword, keycolumn) for c in message_chunks)
356 plaintext = cadenus_decipher(message, keyword, keycolumn)
357 fit = fitness(plaintext)
358 return (keyword, keycolumn), fit</code></pre>
359 </details>
360 </dd>
361 <dt id="szyfrow.cadenus.cadenus_decipher"><code class="name flex">
362 <span>def <span class="ident">cadenus_decipher</span></span>(<span>message, keyword, keycolumn, fillvalue='a')</span>
363 </code></dt>
364 <dd>
365 <div class="desc"><pre><code class="language-python-repl">&gt;&gt;&gt; cadenus_decipher('antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaa' 'suvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned', 'wink', make_cadenus_keycolumn(reverse=True))
366 'whoeverhasmadeavoyageupthehudsonmustrememberthekaatskillmountainstheyareadismemberedbranchofthegreat'
367 &gt;&gt;&gt; cadenus_decipher('systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtof' 'arenuseieeieltarlmentieetogevesitfaisltngeeuvowul', 'easy', make_cadenus_keycolumn(reverse=True))
368 'aseverelimitationontheusefulnessofthecadenusisthateverymessagemustbeamultipleoftwentyfiveletterslong'
369 </code></pre></div>
370 <details class="source">
371 <summary>
372 <span>Expand source code</span>
373 </summary>
374 <pre><code class="python">def cadenus_decipher(message, keyword, keycolumn, fillvalue=&#39;a&#39;):
375 &#34;&#34;&#34;
376 &gt;&gt;&gt; cadenus_decipher(&#39;antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaa&#39; \
377 &#39;suvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned&#39;, \
378 &#39;wink&#39;, \
379 make_cadenus_keycolumn(reverse=True))
380 &#39;whoeverhasmadeavoyageupthehudsonmustrememberthekaatskillmountainstheyareadismemberedbranchofthegreat&#39;
381 &gt;&gt;&gt; cadenus_decipher(&#39;systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtof&#39; \
382 &#39;arenuseieeieltarlmentieetogevesitfaisltngeeuvowul&#39;, \
383 &#39;easy&#39;, \
384 make_cadenus_keycolumn(reverse=True))
385 &#39;aseverelimitationontheusefulnessofthecadenusisthateverymessagemustbeamultipleoftwentyfiveletterslong&#39;
386 &#34;&#34;&#34;
387 transpositions = transpositions_of(keyword)
388 deciphered_chunks = []
389 for message_chunk in chunks(message, len(transpositions) * 25,
390 fillvalue=fillvalue):
391 rows = chunks(message_chunk, len(transpositions), fillvalue=fillvalue)
392 untransposed_rows = [untranspose(r, transpositions) for r in rows]
393 columns = zip(*untransposed_rows)
394 rotated_columns = [col[-start:] + col[:-start] for start, col in zip([keycolumn[l] for l in keyword], columns)]
395 rotated_rows = zip(*rotated_columns)
396 deciphered_chunks.append(cat(chain(*rotated_rows)))
397 return cat(deciphered_chunks)</code></pre>
398 </details>
399 </dd>
400 <dt id="szyfrow.cadenus.cadenus_encipher"><code class="name flex">
401 <span>def <span class="ident">cadenus_encipher</span></span>(<span>message, keyword, keycolumn, fillvalue='a')</span>
402 </code></dt>
403 <dd>
404 <div class="desc"><p>Encipher with the Cadenus cipher</p>
405 <pre><code class="language-python-repl">&gt;&gt;&gt; cadenus_encipher(sanitise('Whoever has made a voyage up the Hudson ' 'must remember the Kaatskill mountains. ' 'They are a dismembered branch of the great'), 'wink', make_cadenus_keycolumn(doubled_letters='vw', start='a', reverse=True))
406 'antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaasuvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned'
407 &gt;&gt;&gt; cadenus_encipher(sanitise('a severe limitation on the usefulness of ' 'the cadenus is that every message must be ' 'a multiple of twenty-five letters long'), 'easy', make_cadenus_keycolumn(doubled_letters='vw', start='a', reverse=True))
408 'systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtofarenuseieeieltarlmentieetogevesitfaisltngeeuvowul'
409 </code></pre></div>
410 <details class="source">
411 <summary>
412 <span>Expand source code</span>
413 </summary>
414 <pre><code class="python">def cadenus_encipher(message, keyword, keycolumn, fillvalue=&#39;a&#39;):
415 &#34;&#34;&#34;Encipher with the Cadenus cipher
416
417 &gt;&gt;&gt; cadenus_encipher(sanitise(&#39;Whoever has made a voyage up the Hudson &#39; \
418 &#39;must remember the Kaatskill mountains. &#39; \
419 &#39;They are a dismembered branch of the great&#39;), \
420 &#39;wink&#39;, \
421 make_cadenus_keycolumn(doubled_letters=&#39;vw&#39;, start=&#39;a&#39;, reverse=True))
422 &#39;antodeleeeuhrsidrbhmhdrrhnimefmthgeaetakseomehetyaasuvoyegrastmmuuaeenabbtpchehtarorikswosmvaleatned&#39;
423 &gt;&gt;&gt; cadenus_encipher(sanitise(&#39;a severe limitation on the usefulness of &#39; \
424 &#39;the cadenus is that every message must be &#39; \
425 &#39;a multiple of twenty-five letters long&#39;), \
426 &#39;easy&#39;, \
427 make_cadenus_keycolumn(doubled_letters=&#39;vw&#39;, start=&#39;a&#39;, reverse=True))
428 &#39;systretomtattlusoatleeesfiyheasdfnmschbhneuvsnpmtofarenuseieeieltarlmentieetogevesitfaisltngeeuvowul&#39;
429 &#34;&#34;&#34;
430 transpositions = transpositions_of(keyword)
431 enciphered_chunks = []
432 for message_chunk in chunks(message, len(transpositions) * 25,
433 fillvalue=fillvalue):
434 rows = chunks(message_chunk, len(transpositions), fillvalue=fillvalue)
435 columns = zip(*rows)
436 rotated_columns = [col[start:] + col[:start] for start, col in zip([keycolumn[l] for l in keyword], columns)]
437 rotated_rows = zip(*rotated_columns)
438 transposed = [transpose(r, transpositions) for r in rotated_rows]
439 enciphered_chunks.append(cat(chain(*transposed)))
440 return cat(enciphered_chunks)</code></pre>
441 </details>
442 </dd>
443 <dt id="szyfrow.cadenus.cat"><code class="name flex">
444 <span>def <span class="ident">cat</span></span>(<span>iterable, /)</span>
445 </code></dt>
446 <dd>
447 <div class="desc"><p>Concatenate any number of strings.</p>
448 <p>The string whose method is called is inserted in between each given string.
449 The result is returned as a new string.</p>
450 <p>Example: '.'.join(['ab', 'pq', 'rs']) -&gt; 'ab.pq.rs'</p></div>
451 </dd>
452 <dt id="szyfrow.cadenus.lcat"><code class="name flex">
453 <span>def <span class="ident">lcat</span></span>(<span>iterable, /)</span>
454 </code></dt>
455 <dd>
456 <div class="desc"><p>Concatenate any number of strings.</p>
457 <p>The string whose method is called is inserted in between each given string.
458 The result is returned as a new string.</p>
459 <p>Example: '.'.join(['ab', 'pq', 'rs']) -&gt; 'ab.pq.rs'</p></div>
460 </dd>
461 <dt id="szyfrow.cadenus.make_cadenus_keycolumn"><code class="name flex">
462 <span>def <span class="ident">make_cadenus_keycolumn</span></span>(<span>doubled_letters='vw', start='a', reverse=False)</span>
463 </code></dt>
464 <dd>
465 <div class="desc"><p>Makes the key column for a Cadenus cipher (the column down between the
466 rows of letters)</p>
467 <pre><code class="language-python-repl">&gt;&gt;&gt; make_cadenus_keycolumn()['a']
468 0
469 &gt;&gt;&gt; make_cadenus_keycolumn()['b']
470 1
471 &gt;&gt;&gt; make_cadenus_keycolumn()['c']
472 2
473 &gt;&gt;&gt; make_cadenus_keycolumn()['v']
474 21
475 &gt;&gt;&gt; make_cadenus_keycolumn()['w']
476 21
477 &gt;&gt;&gt; make_cadenus_keycolumn()['z']
478 24
479 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['a']
480 1
481 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['b']
482 0
483 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['c']
484 24
485 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['i']
486 18
487 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['j']
488 18
489 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['v']
490 6
491 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters='ij', start='b', reverse=True)['z']
492 2
493 </code></pre></div>
494 <details class="source">
495 <summary>
496 <span>Expand source code</span>
497 </summary>
498 <pre><code class="python">def make_cadenus_keycolumn(doubled_letters = &#39;vw&#39;, start=&#39;a&#39;, reverse=False):
499 &#34;&#34;&#34;Makes the key column for a Cadenus cipher (the column down between the
500 rows of letters)
501
502 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;a&#39;]
503 0
504 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;b&#39;]
505 1
506 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;c&#39;]
507 2
508 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;v&#39;]
509 21
510 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;w&#39;]
511 21
512 &gt;&gt;&gt; make_cadenus_keycolumn()[&#39;z&#39;]
513 24
514 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;a&#39;]
515 1
516 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;b&#39;]
517 0
518 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;c&#39;]
519 24
520 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;i&#39;]
521 18
522 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;j&#39;]
523 18
524 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;v&#39;]
525 6
526 &gt;&gt;&gt; make_cadenus_keycolumn(doubled_letters=&#39;ij&#39;, start=&#39;b&#39;, reverse=True)[&#39;z&#39;]
527 2
528 &#34;&#34;&#34;
529 index_to_remove = string.ascii_lowercase.find(doubled_letters[0])
530 short_alphabet = string.ascii_lowercase[:index_to_remove] + string.ascii_lowercase[index_to_remove+1:]
531 if reverse:
532 short_alphabet = cat(reversed(short_alphabet))
533 start_pos = short_alphabet.find(start)
534 rotated_alphabet = short_alphabet[start_pos:] + short_alphabet[:start_pos]
535 keycolumn = {l: i for i, l in enumerate(rotated_alphabet)}
536 keycolumn[doubled_letters[0]] = keycolumn[doubled_letters[1]]
537 return keycolumn</code></pre>
538 </details>
539 </dd>
540 <dt id="szyfrow.cadenus.wcat"><code class="name flex">
541 <span>def <span class="ident">wcat</span></span>(<span>iterable, /)</span>
542 </code></dt>
543 <dd>
544 <div class="desc"><p>Concatenate any number of strings.</p>
545 <p>The string whose method is called is inserted in between each given string.
546 The result is returned as a new string.</p>
547 <p>Example: '.'.join(['ab', 'pq', 'rs']) -&gt; 'ab.pq.rs'</p></div>
548 </dd>
549 </dl>
550 </section>
551 <section>
552 </section>
553 </article>
554 <nav id="sidebar">
555 <h1>Index</h1>
556 <div class="toc">
557 <ul></ul>
558 </div>
559 <ul id="index">
560 <li><h3>Super-module</h3>
561 <ul>
562 <li><code><a title="szyfrow" href="index.html">szyfrow</a></code></li>
563 </ul>
564 </li>
565 <li><h3><a href="#header-functions">Functions</a></h3>
566 <ul class="">
567 <li><code><a title="szyfrow.cadenus.cadenus_break" href="#szyfrow.cadenus.cadenus_break">cadenus_break</a></code></li>
568 <li><code><a title="szyfrow.cadenus.cadenus_break_worker" href="#szyfrow.cadenus.cadenus_break_worker">cadenus_break_worker</a></code></li>
569 <li><code><a title="szyfrow.cadenus.cadenus_decipher" href="#szyfrow.cadenus.cadenus_decipher">cadenus_decipher</a></code></li>
570 <li><code><a title="szyfrow.cadenus.cadenus_encipher" href="#szyfrow.cadenus.cadenus_encipher">cadenus_encipher</a></code></li>
571 <li><code><a title="szyfrow.cadenus.cat" href="#szyfrow.cadenus.cat">cat</a></code></li>
572 <li><code><a title="szyfrow.cadenus.lcat" href="#szyfrow.cadenus.lcat">lcat</a></code></li>
573 <li><code><a title="szyfrow.cadenus.make_cadenus_keycolumn" href="#szyfrow.cadenus.make_cadenus_keycolumn">make_cadenus_keycolumn</a></code></li>
574 <li><code><a title="szyfrow.cadenus.wcat" href="#szyfrow.cadenus.wcat">wcat</a></code></li>
575 </ul>
576 </li>
577 </ul>
578 </nav>
579 </main>
580 <footer id="footer">
581 <p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
582 </footer>
583 </body>
584 </html>