Started on documentation
[szyfrow.git] / docs / szyfrow / railfence.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.railfence API documentation</title>
8 <meta name="description" content="[Railfence transposition cipher](https://en.wikipedia.org/wiki/Rail_fence_cipher) …" />
9 <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>
10 <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>
11 <link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
12 <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>
13 <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>
14 <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>
15 <script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
16 <script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
17 </head>
18 <body>
19 <main>
20 <article id="content">
21 <header>
22 <h1 class="title">Module <code>szyfrow.railfence</code></h1>
23 </header>
24 <section id="section-intro">
25 <p><a href="https://en.wikipedia.org/wiki/Rail_fence_cipher">Railfence transposition cipher</a>.</p>
26 <p>Works by splitting the text into sections, then reading across them to
27 generate the rows in the cipher. The rows are then combined to form the
28 ciphertext.</p>
29 <p>Example: the plaintext "hellotherefriends", with a height of four, written
30 out in the railfence as
31 h h i
32 etere*
33 lorfns
34 l e d
35 (with the * showing the one character to finish the last section).
36 Each 'section' is two columns, but unfolded. In the example, the first
37 section is 'hellot'.</p>
38 <details class="source">
39 <summary>
40 <span>Expand source code</span>
41 </summary>
42 <pre><code class="python">&#34;&#34;&#34;[Railfence transposition cipher](https://en.wikipedia.org/wiki/Rail_fence_cipher).
43
44 Works by splitting the text into sections, then reading across them to
45 generate the rows in the cipher. The rows are then combined to form the
46 ciphertext.
47
48 Example: the plaintext &#34;hellotherefriends&#34;, with a height of four, written
49 out in the railfence as
50 h h i
51 etere*
52 lorfns
53 l e d
54 (with the * showing the one character to finish the last section).
55 Each &#39;section&#39; is two columns, but unfolded. In the example, the first
56 section is &#39;hellot&#39;.
57 &#34;&#34;&#34;
58 import math
59 from enum import Enum
60 from itertools import starmap, zip_longest
61 from szyfrow.support.utilities import *
62 from szyfrow.support.language_models import *
63
64
65 def railfence_encipher(message, height, fillvalue=&#39;&#39;):
66 &#34;&#34;&#34;Railfence cipher.
67 Works by splitting the text into sections, then reading across them to
68 generate the rows in the cipher. The rows are then combined to form the
69 ciphertext.
70
71 Example: the plaintext &#34;hellotherefriends&#34;, with a height of four, written
72 out in the railfence as
73 h h i
74 etere*
75 lorfns
76 l e d
77 (with the * showing the one character to finish the last section).
78 Each &#39;section&#39; is two columns, but unfolded. In the example, the first
79 section is &#39;hellot&#39;.
80
81 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 2, fillvalue=&#39;!&#39;)
82 &#39;hlohraateerishsslnpeefetotsigaleccpeselteevsmhatetiiaogicotxfretnrifneihr!&#39;
83 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 3, fillvalue=&#39;!&#39;)
84 &#39;horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihr!!lhateihsnefttiaece!&#39;
85 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 5, fillvalue=&#39;!&#39;)
86 &#39;hresleogcseeemhetaocofrnrner!!lhateihsnefttiaece!!ltvsatiigitxetifih!!oarspeslp!&#39;
87 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 10, fillvalue=&#39;!&#39;)
88 &#39;hepisehagitnr!!lernesge!!lmtocerh!!otiletap!!tseaorii!!hassfolc!!evtitffe!!rahsetec!!eixn!&#39;
89 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 3)
90 &#39;horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihrlhateihsnefttiaece&#39;
91 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 5)
92 &#39;hresleogcseeemhetaocofrnrnerlhateihsnefttiaeceltvsatiigitxetifihoarspeslp&#39;
93 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 7)
94 &#39;haspolsevsetgifrifrlatihnettaeelemtiocxernhorersleesgcptehaiaottneihesfic&#39;
95 &#34;&#34;&#34;
96 sections = chunks(message, (height - 1) * 2, fillvalue=fillvalue)
97 n_sections = len(sections)
98 # Add the top row
99 rows = [cat([s[0] for s in sections])]
100 # process the middle rows of the grid
101 for r in range(1, height-1):
102 rows += [cat([s[r:r+1] + s[height*2-r-2:height*2-r-1] for s in sections])]
103 # process the bottom row
104 rows += [cat([s[height - 1:height] for s in sections])]
105 # rows += [wcat([s[height - 1] for s in sections])]
106 return cat(rows)
107
108 def railfence_decipher(message, height, fillvalue=&#39;&#39;):
109 &#34;&#34;&#34;Railfence decipher.
110 Works by reconstructing the grid used to generate the ciphertext, then
111 unfolding the sections so the text can be concatenated together.
112
113 Example: given the ciphertext &#39;hhieterelorfnsled&#39; and a height of 4, first
114 work out that the second row has a character missing, find the rows of the
115 grid, then split the section into its two columns.
116
117 &#39;hhieterelorfnsled&#39; is split into
118 h h i
119 etere
120 lorfns
121 l e d
122 (spaces added for clarity), which is stored in &#39;rows&#39;. This is then split
123 into &#39;down_rows&#39; and &#39;up_rows&#39;:
124
125 down_rows:
126 hhi
127 eee
128 lrn
129 led
130
131 up_rows:
132 tr
133 ofs
134
135 These are then zipped together (after the up_rows are reversed) to recover
136 the plaintext.
137
138 Most of the procedure is about finding the correct lengths for each row then
139 splitting the ciphertext into those rows.
140
141 &gt;&gt;&gt; railfence_decipher(&#39;hlohraateerishsslnpeefetotsigaleccpeselteevsmhatetiiaogicotxfretnrifneihr!&#39;, 2).strip(&#39;!&#39;)
142 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
143 &gt;&gt;&gt; railfence_decipher(&#39;horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihr!!lhateihsnefttiaece!&#39;, 3).strip(&#39;!&#39;)
144 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
145 &gt;&gt;&gt; railfence_decipher(&#39;hresleogcseeemhetaocofrnrner!!lhateihsnefttiaece!!ltvsatiigitxetifih!!oarspeslp!&#39;, 5).strip(&#39;!&#39;)
146 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
147 &gt;&gt;&gt; railfence_decipher(&#39;hepisehagitnr!!lernesge!!lmtocerh!!otiletap!!tseaorii!!hassfolc!!evtitffe!!rahsetec!!eixn!&#39;, 10).strip(&#39;!&#39;)
148 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
149 &gt;&gt;&gt; railfence_decipher(&#39;horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihrlhateihsnefttiaece&#39;, 3)
150 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
151 &gt;&gt;&gt; railfence_decipher(&#39;hresleogcseeemhetaocofrnrnerlhateihsnefttiaeceltvsatiigitxetifihoarspeslp&#39;, 5)
152 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
153 &gt;&gt;&gt; railfence_decipher(&#39;haspolsevsetgifrifrlatihnettaeelemtiocxernhorersleesgcptehaiaottneihesfic&#39;, 7)
154 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
155 &#34;&#34;&#34;
156 # find the number and size of the sections, including how many characters
157 # are missing for a full grid
158 n_sections = math.ceil(len(message) / ((height - 1) * 2))
159 padding_to_add = n_sections * (height - 1) * 2 - len(message)
160 # row_lengths are for the both up rows and down rows
161 row_lengths = [n_sections] * (height - 1) * 2
162 for i in range((height - 1) * 2 - 1, (height - 1) * 2 - (padding_to_add + 1), -1):
163 row_lengths[i] -= 1
164 # folded_rows are the combined row lengths in the middle of the railfence
165 folded_row_lengths = [row_lengths[0]]
166 for i in range(1, height-1):
167 folded_row_lengths += [row_lengths[i] + row_lengths[-i]]
168 folded_row_lengths += [row_lengths[height - 1]]
169 # find the rows that form the railfence grid
170 rows = []
171 row_start = 0
172 for i in folded_row_lengths:
173 rows += [message[row_start:row_start + i]]
174 row_start += i
175 # split the rows into the &#39;down_rows&#39; (those that form the first column of
176 # a section) and the &#39;up_rows&#39; (those that ofrm the second column of a
177 # section).
178 down_rows = [rows[0]]
179 up_rows = []
180 for i in range(1, height-1):
181 down_rows += [cat([c for n, c in enumerate(rows[i]) if n % 2 == 0])]
182 up_rows += [cat([c for n, c in enumerate(rows[i]) if n % 2 == 1])]
183 down_rows += [rows[-1]]
184 up_rows.reverse()
185 return cat(c for r in zip_longest(*(down_rows + up_rows), fillvalue=&#39;&#39;) for c in r)
186
187
188 def railfence_break(message, max_key_length=20,
189 fitness=Pbigrams, chunksize=500):
190 &#34;&#34;&#34;Breaks a railfence cipher using a range of lengths and
191 n-gram frequency analysis
192
193 &gt;&gt;&gt; railfence_break(railfence_encipher(sanitise( \
194 &#34;It is a truth universally acknowledged, that a single man in \
195 possession of a good fortune, must be in want of a wife. However \
196 little known the feelings or views of such a man may be on his \
197 first entering a neighbourhood, this truth is so well fixed in \
198 the minds of the surrounding families, that he is considered the \
199 rightful property of some one or other of their daughters.&#34;), \
200 7)) # doctest: +ELLIPSIS
201 (7, -709.46467226...)
202 &gt;&gt;&gt; railfence_break(railfence_encipher(sanitise( \
203 &#34;It is a truth universally acknowledged, that a single man in \
204 possession of a good fortune, must be in want of a wife. However \
205 little known the feelings or views of such a man may be on his \
206 first entering a neighbourhood, this truth is so well fixed in \
207 the minds of the surrounding families, that he is considered the \
208 rightful property of some one or other of their daughters.&#34;), \
209 7), \
210 fitness=Ptrigrams) # doctest: +ELLIPSIS
211 (7, -997.0129085...)
212 &#34;&#34;&#34;
213 def worker(message, height, fitness):
214 plaintext = railfence_decipher(message, height)
215 fit = fitness(plaintext)
216 return height, fit
217
218 sanitised_message = sanitise(message)
219 results = starmap(worker, [(sanitised_message, i, fitness)
220 for i in range(2, max_key_length+1)])
221 return max(results, key=lambda k: k[1])</code></pre>
222 </details>
223 </section>
224 <section>
225 </section>
226 <section>
227 </section>
228 <section>
229 <h2 class="section-title" id="header-functions">Functions</h2>
230 <dl>
231 <dt id="szyfrow.railfence.cat"><code class="name flex">
232 <span>def <span class="ident">cat</span></span>(<span>iterable, /)</span>
233 </code></dt>
234 <dd>
235 <div class="desc"><p>Concatenate any number of strings.</p>
236 <p>The string whose method is called is inserted in between each given string.
237 The result is returned as a new string.</p>
238 <p>Example: '.'.join(['ab', 'pq', 'rs']) -&gt; 'ab.pq.rs'</p></div>
239 </dd>
240 <dt id="szyfrow.railfence.lcat"><code class="name flex">
241 <span>def <span class="ident">lcat</span></span>(<span>iterable, /)</span>
242 </code></dt>
243 <dd>
244 <div class="desc"><p>Concatenate any number of strings.</p>
245 <p>The string whose method is called is inserted in between each given string.
246 The result is returned as a new string.</p>
247 <p>Example: '.'.join(['ab', 'pq', 'rs']) -&gt; 'ab.pq.rs'</p></div>
248 </dd>
249 <dt id="szyfrow.railfence.railfence_break"><code class="name flex">
250 <span>def <span class="ident">railfence_break</span></span>(<span>message, max_key_length=20, fitness=&lt;function Pbigrams&gt;, chunksize=500)</span>
251 </code></dt>
252 <dd>
253 <div class="desc"><p>Breaks a railfence cipher using a range of lengths and
254 n-gram frequency analysis</p>
255 <pre><code class="language-python-repl">&gt;&gt;&gt; railfence_break(railfence_encipher(sanitise( &quot;It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife. However little known the feelings or views of such a man may be on his first entering a neighbourhood, this truth is so well fixed in the minds of the surrounding families, that he is considered the rightful property of some one or other of their daughters.&quot;), 7)) # doctest: +ELLIPSIS
256 (7, -709.46467226...)
257 &gt;&gt;&gt; railfence_break(railfence_encipher(sanitise( &quot;It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife. However little known the feelings or views of such a man may be on his first entering a neighbourhood, this truth is so well fixed in the minds of the surrounding families, that he is considered the rightful property of some one or other of their daughters.&quot;), 7), fitness=Ptrigrams) # doctest: +ELLIPSIS
258 (7, -997.0129085...)
259 </code></pre></div>
260 <details class="source">
261 <summary>
262 <span>Expand source code</span>
263 </summary>
264 <pre><code class="python">def railfence_break(message, max_key_length=20,
265 fitness=Pbigrams, chunksize=500):
266 &#34;&#34;&#34;Breaks a railfence cipher using a range of lengths and
267 n-gram frequency analysis
268
269 &gt;&gt;&gt; railfence_break(railfence_encipher(sanitise( \
270 &#34;It is a truth universally acknowledged, that a single man in \
271 possession of a good fortune, must be in want of a wife. However \
272 little known the feelings or views of such a man may be on his \
273 first entering a neighbourhood, this truth is so well fixed in \
274 the minds of the surrounding families, that he is considered the \
275 rightful property of some one or other of their daughters.&#34;), \
276 7)) # doctest: +ELLIPSIS
277 (7, -709.46467226...)
278 &gt;&gt;&gt; railfence_break(railfence_encipher(sanitise( \
279 &#34;It is a truth universally acknowledged, that a single man in \
280 possession of a good fortune, must be in want of a wife. However \
281 little known the feelings or views of such a man may be on his \
282 first entering a neighbourhood, this truth is so well fixed in \
283 the minds of the surrounding families, that he is considered the \
284 rightful property of some one or other of their daughters.&#34;), \
285 7), \
286 fitness=Ptrigrams) # doctest: +ELLIPSIS
287 (7, -997.0129085...)
288 &#34;&#34;&#34;
289 def worker(message, height, fitness):
290 plaintext = railfence_decipher(message, height)
291 fit = fitness(plaintext)
292 return height, fit
293
294 sanitised_message = sanitise(message)
295 results = starmap(worker, [(sanitised_message, i, fitness)
296 for i in range(2, max_key_length+1)])
297 return max(results, key=lambda k: k[1])</code></pre>
298 </details>
299 </dd>
300 <dt id="szyfrow.railfence.railfence_decipher"><code class="name flex">
301 <span>def <span class="ident">railfence_decipher</span></span>(<span>message, height, fillvalue='')</span>
302 </code></dt>
303 <dd>
304 <div class="desc"><p>Railfence decipher.
305 Works by reconstructing the grid used to generate the ciphertext, then
306 unfolding the sections so the text can be concatenated together.</p>
307 <p>Example: given the ciphertext 'hhieterelorfnsled' and a height of 4, first
308 work out that the second row has a character missing, find the rows of the
309 grid, then split the section into its two columns.</p>
310 <p>'hhieterelorfnsled' is split into
311 h h i
312 etere
313 lorfns
314 l e d
315 (spaces added for clarity), which is stored in 'rows'. This is then split
316 into 'down_rows' and 'up_rows':</p>
317 <p>down_rows:
318 hhi
319 eee
320 lrn
321 led</p>
322 <p>up_rows:
323 tr
324 ofs</p>
325 <p>These are then zipped together (after the up_rows are reversed) to recover
326 the plaintext.</p>
327 <p>Most of the procedure is about finding the correct lengths for each row then
328 splitting the ciphertext into those rows.</p>
329 <pre><code class="language-python-repl">&gt;&gt;&gt; railfence_decipher('hlohraateerishsslnpeefetotsigaleccpeselteevsmhatetiiaogicotxfretnrifneihr!', 2).strip('!')
330 'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'
331 &gt;&gt;&gt; railfence_decipher('horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihr!!lhateihsnefttiaece!', 3).strip('!')
332 'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'
333 &gt;&gt;&gt; railfence_decipher('hresleogcseeemhetaocofrnrner!!lhateihsnefttiaece!!ltvsatiigitxetifih!!oarspeslp!', 5).strip('!')
334 'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'
335 &gt;&gt;&gt; railfence_decipher('hepisehagitnr!!lernesge!!lmtocerh!!otiletap!!tseaorii!!hassfolc!!evtitffe!!rahsetec!!eixn!', 10).strip('!')
336 'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'
337 &gt;&gt;&gt; railfence_decipher('horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihrlhateihsnefttiaece', 3)
338 'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'
339 &gt;&gt;&gt; railfence_decipher('hresleogcseeemhetaocofrnrnerlhateihsnefttiaeceltvsatiigitxetifihoarspeslp', 5)
340 'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'
341 &gt;&gt;&gt; railfence_decipher('haspolsevsetgifrifrlatihnettaeelemtiocxernhorersleesgcptehaiaottneihesfic', 7)
342 'hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers'
343 </code></pre></div>
344 <details class="source">
345 <summary>
346 <span>Expand source code</span>
347 </summary>
348 <pre><code class="python">def railfence_decipher(message, height, fillvalue=&#39;&#39;):
349 &#34;&#34;&#34;Railfence decipher.
350 Works by reconstructing the grid used to generate the ciphertext, then
351 unfolding the sections so the text can be concatenated together.
352
353 Example: given the ciphertext &#39;hhieterelorfnsled&#39; and a height of 4, first
354 work out that the second row has a character missing, find the rows of the
355 grid, then split the section into its two columns.
356
357 &#39;hhieterelorfnsled&#39; is split into
358 h h i
359 etere
360 lorfns
361 l e d
362 (spaces added for clarity), which is stored in &#39;rows&#39;. This is then split
363 into &#39;down_rows&#39; and &#39;up_rows&#39;:
364
365 down_rows:
366 hhi
367 eee
368 lrn
369 led
370
371 up_rows:
372 tr
373 ofs
374
375 These are then zipped together (after the up_rows are reversed) to recover
376 the plaintext.
377
378 Most of the procedure is about finding the correct lengths for each row then
379 splitting the ciphertext into those rows.
380
381 &gt;&gt;&gt; railfence_decipher(&#39;hlohraateerishsslnpeefetotsigaleccpeselteevsmhatetiiaogicotxfretnrifneihr!&#39;, 2).strip(&#39;!&#39;)
382 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
383 &gt;&gt;&gt; railfence_decipher(&#39;horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihr!!lhateihsnefttiaece!&#39;, 3).strip(&#39;!&#39;)
384 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
385 &gt;&gt;&gt; railfence_decipher(&#39;hresleogcseeemhetaocofrnrner!!lhateihsnefttiaece!!ltvsatiigitxetifih!!oarspeslp!&#39;, 5).strip(&#39;!&#39;)
386 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
387 &gt;&gt;&gt; railfence_decipher(&#39;hepisehagitnr!!lernesge!!lmtocerh!!otiletap!!tseaorii!!hassfolc!!evtitffe!!rahsetec!!eixn!&#39;, 10).strip(&#39;!&#39;)
388 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
389 &gt;&gt;&gt; railfence_decipher(&#39;horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihrlhateihsnefttiaece&#39;, 3)
390 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
391 &gt;&gt;&gt; railfence_decipher(&#39;hresleogcseeemhetaocofrnrnerlhateihsnefttiaeceltvsatiigitxetifihoarspeslp&#39;, 5)
392 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
393 &gt;&gt;&gt; railfence_decipher(&#39;haspolsevsetgifrifrlatihnettaeelemtiocxernhorersleesgcptehaiaottneihesfic&#39;, 7)
394 &#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;
395 &#34;&#34;&#34;
396 # find the number and size of the sections, including how many characters
397 # are missing for a full grid
398 n_sections = math.ceil(len(message) / ((height - 1) * 2))
399 padding_to_add = n_sections * (height - 1) * 2 - len(message)
400 # row_lengths are for the both up rows and down rows
401 row_lengths = [n_sections] * (height - 1) * 2
402 for i in range((height - 1) * 2 - 1, (height - 1) * 2 - (padding_to_add + 1), -1):
403 row_lengths[i] -= 1
404 # folded_rows are the combined row lengths in the middle of the railfence
405 folded_row_lengths = [row_lengths[0]]
406 for i in range(1, height-1):
407 folded_row_lengths += [row_lengths[i] + row_lengths[-i]]
408 folded_row_lengths += [row_lengths[height - 1]]
409 # find the rows that form the railfence grid
410 rows = []
411 row_start = 0
412 for i in folded_row_lengths:
413 rows += [message[row_start:row_start + i]]
414 row_start += i
415 # split the rows into the &#39;down_rows&#39; (those that form the first column of
416 # a section) and the &#39;up_rows&#39; (those that ofrm the second column of a
417 # section).
418 down_rows = [rows[0]]
419 up_rows = []
420 for i in range(1, height-1):
421 down_rows += [cat([c for n, c in enumerate(rows[i]) if n % 2 == 0])]
422 up_rows += [cat([c for n, c in enumerate(rows[i]) if n % 2 == 1])]
423 down_rows += [rows[-1]]
424 up_rows.reverse()
425 return cat(c for r in zip_longest(*(down_rows + up_rows), fillvalue=&#39;&#39;) for c in r)</code></pre>
426 </details>
427 </dd>
428 <dt id="szyfrow.railfence.railfence_encipher"><code class="name flex">
429 <span>def <span class="ident">railfence_encipher</span></span>(<span>message, height, fillvalue='')</span>
430 </code></dt>
431 <dd>
432 <div class="desc"><p>Railfence cipher.
433 Works by splitting the text into sections, then reading across them to
434 generate the rows in the cipher. The rows are then combined to form the
435 ciphertext.</p>
436 <p>Example: the plaintext "hellotherefriends", with a height of four, written
437 out in the railfence as
438 h h i
439 etere*
440 lorfns
441 l e d
442 (with the * showing the one character to finish the last section).
443 Each 'section' is two columns, but unfolded. In the example, the first
444 section is 'hellot'.</p>
445 <pre><code class="language-python-repl">&gt;&gt;&gt; railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 2, fillvalue='!')
446 'hlohraateerishsslnpeefetotsigaleccpeselteevsmhatetiiaogicotxfretnrifneihr!'
447 &gt;&gt;&gt; railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 3, fillvalue='!')
448 'horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihr!!lhateihsnefttiaece!'
449 &gt;&gt;&gt; railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 5, fillvalue='!')
450 'hresleogcseeemhetaocofrnrner!!lhateihsnefttiaece!!ltvsatiigitxetifih!!oarspeslp!'
451 &gt;&gt;&gt; railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 10, fillvalue='!')
452 'hepisehagitnr!!lernesge!!lmtocerh!!otiletap!!tseaorii!!hassfolc!!evtitffe!!rahsetec!!eixn!'
453 &gt;&gt;&gt; railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 3)
454 'horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihrlhateihsnefttiaece'
455 &gt;&gt;&gt; railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 5)
456 'hresleogcseeemhetaocofrnrnerlhateihsnefttiaeceltvsatiigitxetifihoarspeslp'
457 &gt;&gt;&gt; railfence_encipher('hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers', 7)
458 'haspolsevsetgifrifrlatihnettaeelemtiocxernhorersleesgcptehaiaottneihesfic'
459 </code></pre></div>
460 <details class="source">
461 <summary>
462 <span>Expand source code</span>
463 </summary>
464 <pre><code class="python">def railfence_encipher(message, height, fillvalue=&#39;&#39;):
465 &#34;&#34;&#34;Railfence cipher.
466 Works by splitting the text into sections, then reading across them to
467 generate the rows in the cipher. The rows are then combined to form the
468 ciphertext.
469
470 Example: the plaintext &#34;hellotherefriends&#34;, with a height of four, written
471 out in the railfence as
472 h h i
473 etere*
474 lorfns
475 l e d
476 (with the * showing the one character to finish the last section).
477 Each &#39;section&#39; is two columns, but unfolded. In the example, the first
478 section is &#39;hellot&#39;.
479
480 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 2, fillvalue=&#39;!&#39;)
481 &#39;hlohraateerishsslnpeefetotsigaleccpeselteevsmhatetiiaogicotxfretnrifneihr!&#39;
482 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 3, fillvalue=&#39;!&#39;)
483 &#39;horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihr!!lhateihsnefttiaece!&#39;
484 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 5, fillvalue=&#39;!&#39;)
485 &#39;hresleogcseeemhetaocofrnrner!!lhateihsnefttiaece!!ltvsatiigitxetifih!!oarspeslp!&#39;
486 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 10, fillvalue=&#39;!&#39;)
487 &#39;hepisehagitnr!!lernesge!!lmtocerh!!otiletap!!tseaorii!!hassfolc!!evtitffe!!rahsetec!!eixn!&#39;
488 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 3)
489 &#39;horaersslpeeosglcpselteevsmhatetiiaogicotxfretnrifneihrlhateihsnefttiaece&#39;
490 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 5)
491 &#39;hresleogcseeemhetaocofrnrnerlhateihsnefttiaeceltvsatiigitxetifihoarspeslp&#39;
492 &gt;&gt;&gt; railfence_encipher(&#39;hellothereavastmeheartiesthisisalongpieceoftextfortestingrailfenceciphers&#39;, 7)
493 &#39;haspolsevsetgifrifrlatihnettaeelemtiocxernhorersleesgcptehaiaottneihesfic&#39;
494 &#34;&#34;&#34;
495 sections = chunks(message, (height - 1) * 2, fillvalue=fillvalue)
496 n_sections = len(sections)
497 # Add the top row
498 rows = [cat([s[0] for s in sections])]
499 # process the middle rows of the grid
500 for r in range(1, height-1):
501 rows += [cat([s[r:r+1] + s[height*2-r-2:height*2-r-1] for s in sections])]
502 # process the bottom row
503 rows += [cat([s[height - 1:height] for s in sections])]
504 # rows += [wcat([s[height - 1] for s in sections])]
505 return cat(rows)</code></pre>
506 </details>
507 </dd>
508 <dt id="szyfrow.railfence.wcat"><code class="name flex">
509 <span>def <span class="ident">wcat</span></span>(<span>iterable, /)</span>
510 </code></dt>
511 <dd>
512 <div class="desc"><p>Concatenate any number of strings.</p>
513 <p>The string whose method is called is inserted in between each given string.
514 The result is returned as a new string.</p>
515 <p>Example: '.'.join(['ab', 'pq', 'rs']) -&gt; 'ab.pq.rs'</p></div>
516 </dd>
517 </dl>
518 </section>
519 <section>
520 </section>
521 </article>
522 <nav id="sidebar">
523 <h1>Index</h1>
524 <div class="toc">
525 <ul></ul>
526 </div>
527 <ul id="index">
528 <li><h3>Super-module</h3>
529 <ul>
530 <li><code><a title="szyfrow" href="index.html">szyfrow</a></code></li>
531 </ul>
532 </li>
533 <li><h3><a href="#header-functions">Functions</a></h3>
534 <ul class="two-column">
535 <li><code><a title="szyfrow.railfence.cat" href="#szyfrow.railfence.cat">cat</a></code></li>
536 <li><code><a title="szyfrow.railfence.lcat" href="#szyfrow.railfence.lcat">lcat</a></code></li>
537 <li><code><a title="szyfrow.railfence.railfence_break" href="#szyfrow.railfence.railfence_break">railfence_break</a></code></li>
538 <li><code><a title="szyfrow.railfence.railfence_decipher" href="#szyfrow.railfence.railfence_decipher">railfence_decipher</a></code></li>
539 <li><code><a title="szyfrow.railfence.railfence_encipher" href="#szyfrow.railfence.railfence_encipher">railfence_encipher</a></code></li>
540 <li><code><a title="szyfrow.railfence.wcat" href="#szyfrow.railfence.wcat">wcat</a></code></li>
541 </ul>
542 </li>
543 </ul>
544 </nav>
545 </main>
546 <footer id="footer">
547 <p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.9.2</a>.</p>
548 </footer>
549 </body>
550 </html>