summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Master/texmf-dist/doc/context/third/enigma/enigma/COPYING22
-rw-r--r--Master/texmf-dist/doc/context/third/enigma/enigma/README29
-rw-r--r--Master/texmf-dist/doc/context/third/enigma/enigma/enigma-doc.pdfbin0 -> 265288 bytes
-rw-r--r--Master/texmf-dist/doc/context/third/enigma/enigma/enigma_manual.tex498
-rw-r--r--Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-context.tex59
-rw-r--r--Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-latex.tex53
-rw-r--r--Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-plain.tex50
-rw-r--r--Master/texmf-dist/scripts/context/lua/third/enigma/mtx-t-enigma.lua/mtx-t-enigma.lua72
-rw-r--r--Master/texmf-dist/tex/context/third/enigma/t-enigma.mkv/t-enigma.mkvi157
-rw-r--r--Master/texmf-dist/tex/generic/enigma/enigma.lua1662
-rw-r--r--Master/texmf-dist/tex/latex/enigma/enigma.sty7
-rw-r--r--Master/texmf-dist/tex/plain/enigma/enigma.tex130
-rwxr-xr-xMaster/tlpkg/bin/tlpkg-ctan-check3
-rwxr-xr-xMaster/tlpkg/libexec/ctan2tds30
-rw-r--r--Master/tlpkg/tlpsrc/collection-luatex.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/enigma.tlpsrc0
16 files changed, 2771 insertions, 2 deletions
diff --git a/Master/texmf-dist/doc/context/third/enigma/enigma/COPYING b/Master/texmf-dist/doc/context/third/enigma/enigma/COPYING
new file mode 100644
index 00000000000..dad85d026eb
--- /dev/null
+++ b/Master/texmf-dist/doc/context/third/enigma/enigma/COPYING
@@ -0,0 +1,22 @@
+Copyright 2011-2013 Philipp Gesang. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/Master/texmf-dist/doc/context/third/enigma/enigma/README b/Master/texmf-dist/doc/context/third/enigma/enigma/README
new file mode 100644
index 00000000000..1da3eb07903
--- /dev/null
+++ b/Master/texmf-dist/doc/context/third/enigma/enigma/README
@@ -0,0 +1,29 @@
+Description of files:
+
+./enigma-example-context.tex usage example for Context
+./enigma-example-latex.tex usage example for LaTeX
+./enigma-example-plain.tex usage example for Plain
+./COPYING License (BSD)
+./enigma_manual.tex manual source (Context)
+./enigma-doc.pdf compiled manual
+./mtx-t-enigma.lua mtx script (run as “mtxrun --script enigma”)
+./enigma.lua format independent code
+./t-enigma.mkvi Context interface
+./enigma.sty wrapper for LaTeX (inputs enigma.tex)
+./enigma.tex Plain interface
+
+This is the directory layout I have in mind:
+
+enigma_manual.tex -> ./doc/context/third/enigma/enigma_manual.tex
+enigma-example-plain.tex -> ./doc/context/third/enigma/examples/enigma-example-plain.tex
+enigma-example-latex.tex -> ./doc/context/third/enigma/examples/enigma-example-latex.tex
+enigma-example-context.tex -> ./doc/context/third/enigma/examples/enigma-example-context.tex
+enigma-doc.pdf -> ./doc/context/third/enigma/enigma-doc.pdf
+COPYING -> ./doc/context/third/enigma/COPYING
+mtx-t-enigma.lua -> ./scripts/context/lua/third/enigma/mtx-t-enigma.lua
+t-enigma.mkvi -> ./tex/context/third/enigma/t-enigma.mkvi
+enigma.sty -> ./tex/latex/enigma/enigma.sty
+enigma.tex -> ./tex/plain/enigma/enigma.tex
+enigma.lua -> ./tex/generic/enigma/enigma.lua
+
+
diff --git a/Master/texmf-dist/doc/context/third/enigma/enigma/enigma-doc.pdf b/Master/texmf-dist/doc/context/third/enigma/enigma/enigma-doc.pdf
new file mode 100644
index 00000000000..2a9a2f9ab78
--- /dev/null
+++ b/Master/texmf-dist/doc/context/third/enigma/enigma/enigma-doc.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/context/third/enigma/enigma/enigma_manual.tex b/Master/texmf-dist/doc/context/third/enigma/enigma/enigma_manual.tex
new file mode 100644
index 00000000000..4331521900e
--- /dev/null
+++ b/Master/texmf-dist/doc/context/third/enigma/enigma/enigma_manual.tex
@@ -0,0 +1,498 @@
+%% If you’re looking for instructions concerning how to build this
+%% manual, please for now drop me an email: ·phg42.2a at gmail dot com·
+%% as you will need a certain mtx-script.
+\defineitemgroup [credits]
+\setupitemgroup [credits] [
+ % before={\startnarrower[middle]},
+ % after=\stopnarrower,
+ left=,
+ right=,
+ margin=,
+ option=2,
+]
+
+\pushcatcodetable
+\setcatcodetable\txtcatcodes
+\useurl [chickenize] [https://github.com/alt/chickenize]
+\useurl [codebook] [http://simonsingh.net/books/the-code-book/]
+\useurl [key_procedure] [http://users.telenet.be/d.rijmenants/en/enigmaproc.htm]
+\useurl [luatex-web] [http://www.luatex.org/]
+\useurl [rotor_wirings] [http://www.ellsbury.com/ultraenigmawirings.htm]
+\useurl [wp:day_key] [http://en.wikipedia.org/wiki/Cryptanalysis_of_the_Enigma#Key_setting]
+ [] [\hyphenatedurl{http://en.wikipedia.org/wiki/Cryptanalysis_of_the_Enigma\#Key_setting}]
+\useurl [wp:ring] [http://en.wikipedia.org/wiki/Enigma_rotor_details#The_ring_setting]
+ [] [\hyphenatedurl{http://en.wikipedia.org/wiki/Enigma_rotor_details\#The_ring_setting}]
+\useurl [initialization] [http://w1tp.com/enigma/mewirg.htm]
+\useurl [model-i] [http://www.cryptomuseum.com/crypto/enigma/i/index.htm]
+\useurl [ecollection] [http://cryptocellar.org/enigma/]
+\useurl [heinz_diss] [http://rzbl04.biblio.etc.tu-bs.de:8080/docportal/receive/DocPortal_document_00001705]
+\popcatcodetable
+
+\startdocchapter[title=Introduction]
+ This module implements an \emph{Enigma} cipher that is equivalent to
+ the most widely distributed model: the Enigma~I (subtypes {\sc m1}
+ {\sc m2} and {\sc m3}).%
+ \footnote{%
+ See \from[model-i] for a showcase.
+ }
+ Machines of this type had three rotors, a non-moving reflector and,
+ as a novelty at the time of their introduction, a plugboard.
+ The simulation accepts arbitrary configurations of these components,
+ as well as the starting position of the rotors, and then processes
+ text accordingly.
+ Depending on the input, this yields the plaintext or ciphertext, as
+ encryption and decryption are the same.
+
+ The code is provided as a module (interface for \CONTEXT) as well as
+ a package (\PLAIN, \LATEX).
+ It is subject to the {\sc bsd} license, see below,
+ \at{page}[license], for details.
+\stopdocchapter
+
+\startdocchapter[title=Usage]
+
+\startdocsection[title=Loading the Module / Package]
+ The intention is for the \modulename{Enigma} codebase to integrate
+ with the three most popular (as of 2012) \TEX\ formats:
+ \CONTEXT,
+ \PLAIN, and
+ \LATEX.
+ If the user interface does not fully conform with the common practice
+ of the latter two, please be lenient toward the author whose
+ intuitions are for the most part informed by \CONTEXT.
+ For this reason, a couple words concerning the interfaces will be
+ necessary.
+ The examples in this manual will be cycling through all three
+ formats, but once you get the general idea of how it works, you will
+ have no problem translating between coding styles.
+ Those familiar with \CONTEXT\ might, therefore, skip the following
+ paragraphs and continue directly with the next section on
+ \at{page}[sec:opts].%
+
+ The package is loaded as usual. For \PLAIN, issue a
+ \type{\input{enigma}}.
+ \LATEX-users need to place \type{\usepackage{enigma}} somewhere
+ inside the preamble.
+ (There are no package options.)
+ From this point on, instructions for both formats are the same.
+
+ The interface provides two basic macros from which all functionality
+ will be derived:
+ \texmacro{defineenigma} and \texmacro{setupenigma}.
+ Both are a kind of \emph{meta-macros}, meaning that they generate
+ other macros which may then be employed to access the functionality
+ of the package.
+ As such they naturally belong inside the preamble (if you chose to
+ use
+ \modulename{Enigma} with \LATEX, that is).
+ The correct order is to \texmacro{defineenigma} an enigma machine
+ first and then \texmacro{setupenigma} it.
+ The definition takes a single, setups a double mandatory argument.
+ Thus, \type{\defineenigma{encrypt}} creates a new environment
+ consisting of the macros \texmacro{beginencrypt} and
+ \texmacro{endencrypt}.%
+ \footnote{%
+ \CONTEXT-users will have noticed that there is no direct macro
+ \type{\encrypt{foo}}. The reason for this is that the callback
+ which the module relies on operates on node-level.
+ This means that for the Enigma encryption to have an effect it will
+ have to process entire paragraphs.
+ As encrypted passages are supposed to stand on their own, this
+ small limitation should not have a severe impact on functionality.
+ If you should, however, need a macro that works for smaller
+ portions of text, please send a feature request to the maintainer
+ (\ichdparameter{email}).
+ }
+ These correspond to \texmacro{startencrypt}/\texmacro{stopencrypt} in
+ the \CONTEXT\ interface.
+ The \CONTEXT-examples below are easily translated to
+ Plain/\LATEX-syntax by replacing curly brackets (groups) with
+ square brackets and substituting environment prefixes:
+ \type{\start<foo>} becomes \type{\begin<foo>} and
+ \type{\stop<foo>} becomes \type{\end<foo>}.
+ Except for those conventions the syntax, even in key-value
+ assignments, is identical.
+
+ However, the environment is not usable right away, as we still have
+ to set the initial state of the machine.
+ This is achieved by the second meta-macro,
+ \type{\setupenigma{encrypt}{<args>}}, where \type{<args>} is a
+ placeholder for a list of \emph{assignments}, i.\,e. pairs of
+ \emph{key=value} statements by means of which all further parameters
+ are specified.
+ The possible parameters are listed in the next section,
+ examples of their effects will be given further below in the section
+ on functionality (see \at{page}[sec:fun]).%
+ \footnote{%
+ If you grasp the concept of paired \type{\define<foo>}
+ \endash\space \type{\setup<foo>} macros, then congratulations are
+ in order: you qualify for migration from your current macro package
+ to \CONTEXT.
+ }
+\stopdocsection
+\startdocsection[title=Options Explained,reference=sec:opts]
+
+At the moment, the \texmacro{setupenigma} macro in any format accepts
+the following parameters.
+% \startpostponing[+2]%% messes up floats -- why?
+ \startplacefigure[
+ location={right,high},
+ title={Usage example for the \PLAIN\ format.},
+ ]
+ % \framed[align=right,frameoffset=1em]{%
+ \startframed[
+ align=right,
+ frameoffset=1em,
+ frame=off,
+ ]%
+ \startlatextyping[before=,after=,]
+ \input {enigma}
+ %% Definition ··········· %%
+ \defineenigma {encryption}
+ %% Setup ················ %%
+ \setupenigma {encryption} {
+ other_chars = no,
+ day_key = I II III
+ 01 01 01,
+ rotor_setting = aaa,
+ spacing = yes,
+ verbose = 1,
+ }
+ %% Usage ················ %%
+ \beginencryption
+ aaaaa aaaaa aaaaa
+ aaaaa aaaaa aaaaa
+ \endencryption
+ \beginencryption
+ Nobody in Poland is going
+ to be able to read this,
+ har har!
+ \endencryption
+ \bye
+ \stoplatextyping
+ \stopframed
+ \stopplacefigure
+% \stoppostponing
+\startitemize
+ \setuptolerance[tolerant]%% it’s crowded in here due to the float
+ \let\olditem\item
+ \let\item\undefined
+ \def\item#1#2{% 1 name, 2 type
+ \olditem
+ \identifier{#1}%
+ \reference[option:#1]{}%
+ \space
+ <\emph{#2}>%
+ \hskip1em%
+ }
+ \item{other_chars}{boolean} How to handle non-encodable characters,
+ i.\,e. glyphs outside the bare set of Latin letters; see below on
+ \at{page}[explained:other_chars].
+ \item{day_key}{string} Encryption key, i.\,e. a description of the
+ initial setup of an Enigma machine: the reflector used, the choice
+ and positions of the three rotors, the ring settings, and the
+ plugboard wiring.
+ \item{rotor_setting}{string} The initial rotor advancement.
+ \item{spacing}{boolean} Auto-space output?
+ \item{verbose}{integer} Controls overall verbosity level
+ (\emph{global}\/!).
+\stopitemize
+
+%% day key
+\noindentation
+To state the obvious, the value of \identifier{day_key} serves as the
+\emph{day key} for encryption. An Enigma day key ordinarily consists of
+(1) a list of the the rotor configuration,
+(2) the ring settings, and
+(3) the plugboard connections.\footnote{%
+ For a description of the initialization process see
+ \from[initialization].
+}
+Together these have the denotation \emph{day key}, because they are
+meant to be supplied in special code books by central authority, one
+for each day.\footnote{%
+ Read about the historical directives for daily key renewal at
+ \from[key_procedure].
+ there are some {\sc pdf}s with images of \emph{Kenngruppenbücher} at
+ \from[ecollection], section \emph{Enigma Messages and Keys}.
+ Also, while you’re at it, don’t miss the explanation on Wikipedia:
+ \from[wp:day_key].
+}
+In the \modulename{Enigma} setup, the day key starts
+with a triple of Roman numerals ({\sc i} to {\sc v}) describing which
+of the five rotors is located in which of the three slots.
+(e.\,g. \type{I VI II}).\footnote{%
+ For the individual wirings of the five rotors see
+ \from[rotor_wirings], as well as the implementation below at
+ \at{page}[listing:rotor_wiring].
+}
+Its next part is the ring setting, a triple of two-digit integers that
+are the amount by which the internal wiring of each rotor has been
+shifted (\type{03 23 11}). As the Enigma encrypts only the letters of
+the Latin alphabet, sane values range from one (first position: no
+shift) to twenty six.\footnote{%
+ Consult \from[wp:ring] for an introduction into the ring mechanics.
+}
+The third section specifies which pairs of letters are substituted by
+each other by means of plugboard connections (\type{NI CE GO LD ...}).
+There can be zero to thirteen of these redirections, thus the presence
+of this section is entirely optional.
+Also part of the \identifier{day_key}, but not mentioned yet, is the
+choice of the \emph{reflector}.
+It may be specified as one of the three letters \type{A}, \type{B} and
+\type{C} as the first item. If no reflector is requested explicitly,
+the machine defaults to \type{B}, which is actually the only one of the
+three models that had been in widespread use
+(see below on \at{page}[listing:reflector] for the wirings).
+
+Initialization is not complete without a \identifier{rotor_setting}.
+This is a triple of letters, each representing the initial state of one
+rotor (e.\,g. \type{fkd}). Historically this was not part of the day
+key but supposed to be chosen at random by the operating signal
+officer.
+
+The output can be automatically grouped into sequences of five
+characters, delimited by spaces (option \identifier{spacing}). This
+does not only conform with traditional crypto-style, but also allows
+for the resulting text to be sanely broken into lines by \TEX.
+
+%%% other_chars
+Most documents don’t naturally adhere to the machine-imposed
+restriction to the 26 letters of the Latin alphabet. The original
+encipherment directives comprised substitution tables to compensate for
+a set of intrinsic peculiarities of the German language, like umlauts
+and common digraphs. The \modulename{Enigma} simulation module strives
+to apply these automatically but there is no guarantee of completeness.
+
+However,\reference[explained:other_chars]{} the Enigma lacks means of
+handling languages other than German. When the substitution lookup
+fails, there are two ways of proceeding: either to ignore the current
+character or to pass it on to the output as if nothing happened. The
+default behaviour is to drop alien letters and move on. If the user
+intends to keep these foreign characters instead, E can achieve this by
+setting the \identifier{other_chars} key in the \modulename{Enigma}
+setup to the value \emph{true}. An example of how the result of both
+methods may look, other things being equal, is given in below listing
+(example for \CONTEXT; see the file \type{enigma-example-context.tex}
+in the \type{doc/} subtree of your installation path).
+
+\startcontexttyping
+\usemodule [enigma]
+\defineenigma [secretmessage]
+\setupenigma [secretmessage] [
+ other_chars = yes,
+ day_key = B V III II 12 03 01 GI JV KZ WM PU QY AD CN ET FL,
+ rotor_setting = ben,
+]
+
+\defineenigma [othermessage] [secretmessage]
+\setupenigma [othermessage] [other_chars=wrong]
+
+\starttext
+
+\startsecretmessage
+ føo bąr baž
+\stopsecretmessage
+\startothermessage
+ føo bąr baž
+\stopothermessage
+
+\stoptext
+\stopcontexttyping
+
+Both methods have their disadvantages: if the user chooses to have the
+unknown characters removed it might distort the decrypted text to
+becoming illegible. Far more serious, however, are the consequences of
+keeping them. As artefacts in the ciphertext they would convey
+information about the structure of the plain text.
+
+\stopdocsection
+
+\startdocsection[title=Basic Functionality,reference=sec:fun]
+
+Encrypt the text of your document using the script interface. For
+a start try out the settings as given in below listing.
+
+\starttyping
+mtxrun --script mtx-t-enigma \
+ --setup="day_key = B I II III 01 01 01, \
+ rotor_setting = xyz, \
+ verbose=0" \
+ --text="Gentlemen don’t read each other’s mail, Mr. Turing\!"
+\stoptyping
+
+This will result in the thoroughly scrambled string
+\typ{omribshpwfrfjovkntgqgi abbkhjpxmhdztapkatwrvf}.
+Then, use the same settings you encrypted the text with in your
+document.
+
+\startcontexttyping
+\usemodule[enigma]
+\defineenigma [secretmessage]
+\setupenigma [secretmessage] [
+ day_key = B I II III 01 01 01,
+ rotor_setting = xyz,
+ verbose=3,
+]
+
+\starttext
+
+\startsecretmessage
+ omribshpwfrfjovkntgqgiabbkhjpxmhdztapkatwrvf
+\stopsecretmessage
+
+\stoptext
+\stopcontexttyping
+
+If you compile this document with \CONTEXT, the plain text will
+reappear.
+Notice that punctuation is substituted with the letter “x” before
+encryption and that spaces are omitted.
+
+\useURL[kgbuch] [http://de.wikipedia.org/wiki/Kenngruppenbuch]
+ [] [code book]
+Now it’s certainly not wise to carry around the key to encrypted
+documents as plain text within those documents. The keys will have to
+be distributed via an independent channel, e.\,g. a \from[kgbuch].
+Keys in general don’t have to be supplied inside the document. If there
+is none specified, the module will interrupt the \TEX\ run and
+\emph{ask} for user input. Suppose Alice wanted to send an encrypted
+file to Bob and already generated the cipher text as follows:
+
+\starttyping
+mtxrun --script mtx-t-enigma \
+ --setup="day_key =B I IV V 22 07 10 AZ DG IE YJ QM CW, \
+ rotor_setting = bar, \
+ verbose=0" \
+ --text="I have nothing to hide. From the NSA, that is."
+\stoptyping
+
+Alice would then include the result of this line in her \LATEX\
+document as follows:
+
+\startlatextyping
+\documentclass{scrartcl}
+\usepackage{enigma}
+\defineenigma{decryption}
+%% Encryption key not given in the setup.
+\setupenigma{decryption}{
+ rotor_setting = bar,
+ verbose = 3,
+}
+\begin{document}
+
+\begindecryption
+usbatbwcaajhzgeyzkqskupzbmdhbdepccgeh
+\enddecryption
+
+\end{document}
+\stoplatextyping
+
+She subsequently mails this file to Bob and conveys the key through a
+secure channel. They only thing that will be left for Bob to do now, is
+to enter the key at the prompt when compiling the document with
+\LUALATEX.
+\stopdocsection
+
+\startdocsection[title=Uses and Abuses]
+
+In \LUATEX, \identifier{callback}s may stack. This allows filtering the
+input through many enigma machines successively. For instance, in the
+following listing, two instances of the same machine are generated and
+applied.
+
+\startcontexttyping
+\usemodule [enigma] %% load the module
+\defineenigma [secretmessage] %% generate and
+\setupenigma [secretmessage] [ %% configure a machine
+ day_key = B IV V II 01 01 01 AD CN ET FL GI JV KZ PU QY WX,
+ rotor_setting = foo,
+ verbose=3,
+]
+
+%% now, copy the first machine’s settings
+\defineenigma [othermessage] [secretmessage]
+
+%% here we go!
+\starttext
+
+\startothermessage %% enable machine 1
+\startsecretmessage %% enable machine 2 while no 1 is active
+Encryption equals decryption.
+\stopothermessage
+\stopsecretmessage
+
+\stoptext \endinput
+\stopcontexttyping
+
+\stopdocsection
+
+\stopdocchapter
+
+\startdocchapter[title=Metadata]
+\startdocsection[title=License,reference=license]
+
+© 2012--2013 \emph{Philipp Gesang}. All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the following
+conditions are met:
+
+\startitemize[n]
+ \item Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
+ \item Redistributions in binary form must reproduce the
+ above copyright notice, this list of conditions and the
+ following disclaimer in the documentation and/or other
+ materials provided with the distribution.
+\stopitemize
+
+\begingroup
+\setuptolerance [horizontal,strict]
+\startalignment [right,nothyphenated]
+\noindentation\startsmallcaps
+ this software is provided by the copyright
+ holder “as is” and any express or implied warranties,
+ including, but not limited to, the implied warranties of
+ merchantability and fitness for a particular purpose are
+ disclaimed. in no event shall the copyright holder or
+ contributors be liable for any direct, indirect, incidental,
+ special, exemplary, or consequential damages (including, but
+ not limited to, procurement of substitute goods or services;
+ loss of use, data, or profits; or business interruption)
+ however caused and on any theory of liability, whether in
+ contract, strict liability, or tort (including negligence or
+ otherwise) arising in any way out of the use of this software,
+ even if advised of the possibility of such damage.
+\stopsmallcaps\endgraf
+\stopalignment
+\endgroup
+\stopdocsection
+
+\startdocsection[title=Acknowledgements]
+\startcredits
+ \item The idea to implement the \emph{Enigma} cipher for \TEX\ came
+ up while I was reading \emph{The Code Book} by Simon Singh.
+ This work contains an excellent portrayal of the history of
+ German military cryptography and Allied cryptanalysis before
+ and during the Second World War.\par
+ \from[codebook]
+ \item A more detailed account from a historical-cryptological
+ perspective is provided by Ulrich Heinz in his Dissertation (in
+ German), which is freely available.
+ Includes an interesting albeit speculative note on the
+ effectiveness of the Soviet code breaking efforts (chapter
+ seven).\par
+ \from[heinz_diss]
+ \item Also, the \modulename{Enigma} module drew lots of inspiration
+ from Arno Trautmann’s \modulename{Chickenize} package, which
+ remains the unsurpassed hands-on introduction to callback
+ trickery.\par
+ \from[chickenize]
+ \item Finally, without \LUATEX, encryption on node-level would not
+ have been possible.\par
+ \from[luatex-web]
+\stopcredits
+\stopdocsection
+\stopdocchapter
diff --git a/Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-context.tex b/Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-context.tex
new file mode 100644
index 00000000000..051e719697f
--- /dev/null
+++ b/Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-context.tex
@@ -0,0 +1,59 @@
+\usemodule [enigma]
+%\usetypescript [computer-modern-unicode]
+%\setupbodyfont [computer-modern-unicode,20pt]
+%\usetypescript [iwona]
+%\setupbodyfont [iwona,20pt]
+\usetypescript [modern]
+\setupbodyfont [modern,20pt]
+
+\defineenigma [nilsettings]
+\setupenigma [nilsettings] [ %% a machine with vanilla settings
+ other_chars = no,
+ day_key = I II III 01 01 01,
+ rotor_setting = aaa,
+ spacing = yes,
+ verbose = 3,
+]
+
+\defineenigma [othernilsettings] [nilsettings]
+
+\defineenigma [secretmessage]
+\setupenigma [secretmessage] [
+ other_chars = yes,
+ day_key = B V III II 12 03 01 GI JV KZ WM PU QY AD CN ET FL,
+ rotor_setting = ben,
+]
+
+\defineenigma [othersecretmessage] [secretmessage]
+
+\defineenigma [othermessage] [secretmessage]
+\setupenigma [othermessage] [other_chars=wrong]
+
+\starttext
+
+\placefigure{Enigma output and its reversal using nil settings}{
+ \framed [width=.7\hsize,frame=off,align=middle]{
+ \startnilsettings
+ aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aaaaa aa
+ \stopnilsettings
+
+ \startothernilsettings
+ bdzgo wcxlt ksbtm cdlpb muqof xyhcx tgyjf linhn xs
+ \stopothernilsettings
+ }
+}
+
+\startsecretmessage
+ føo bąr baž
+\stopsecretmessage
+
+\startothersecretmessage
+ iøtyąwqiž
+\stopothersecretmessage
+
+\startothermessage
+ føo bąr baž
+\stopothermessage
+
+\stoptext
+% vim:ft=context:tw=71:ts=2:sw=2:expandtab
diff --git a/Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-latex.tex b/Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-latex.tex
new file mode 100644
index 00000000000..ea825cf1e9e
--- /dev/null
+++ b/Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-latex.tex
@@ -0,0 +1,53 @@
+\documentclass[a5paper]{scrartcl}
+\parindent0pt
+%%····································································%
+\usepackage {enigma}
+%%····································································%
+%% The first machine will be used for encryption of our plain text.
+\defineenigma {encryption}
+\setupenigma {encryption} {
+ other_chars = yes,
+ day_key = B V III II 12 03 01 GI JV KZ WM PU QY AD CN ET FL,
+ rotor_setting = ben,
+ spacing = yes,
+ verbose = 2,
+}
+%%····································································%
+%% This second machine below will be used to decrypt the string. It is
+%% initialized with exactly the same settings as the first one. The
+%% reason for this is that we can’t reuse the “encryption” machine as
+%% it will already have progressed to some later state after the
+%% encryption. Applying it on the ciphertext would yield a totally
+%% different string. Hence the need for another machine.
+\defineenigma{decryption}
+\setupenigma{decryption}{
+ other_chars = yes,
+ day_key = B V III II 12 03 01 GI JV KZ WM PU QY AD CN ET FL,
+ rotor_setting = ben,
+}
+%%····································································%
+\begin{document}
+
+%%····································································%
+%% Ciphertext in the PDF. Rely on the addressee to decrypt the document
+%% externally.
+\beginencryption
+ Never underestimate the amount of money, time, and effort someone
+ will expend to thwart a security system.
+\endencryption
+
+%%····································································%
+%% Input string generated with:
+%% mtxrun --script t-enigma \
+%% --setup="day_key=B V III II 12 03 01 GI JV KZ WM PU QY AD CN ET FL,\
+%% rotor_setting=ben,\
+%% other_chars=yes"\
+%% --text="Never underestimate the amount of money,\
+%% time, and effort someone will expend to\
+%% thwart a security system."
+\begindecryption
+ aqsnwyxgqarpuzrdktscbslaqmdhyonywxkwhcdgphvuqsspfjwhlszahygjbzmfpcpbniahvfcuradntepxsfchnn
+\enddecryption
+%%····································································%
+\end{document}
+% vim:ft=tex:tw=71:expandtab:ts=2:sw=2
diff --git a/Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-plain.tex b/Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-plain.tex
new file mode 100644
index 00000000000..bd50c93ca4a
--- /dev/null
+++ b/Master/texmf-dist/doc/context/third/enigma/enigma/examples/enigma-example-plain.tex
@@ -0,0 +1,50 @@
+\parindent0pt
+%%····································································%
+\input {enigma}
+%%····································································%
+%% The first machine will be used for encryption of our plain text.
+\defineenigma {encryption}
+\setupenigma {encryption} {
+ other_chars = yes,
+ day_key = B V III II 12 03 01 GI JV KZ WM PU QY AD CN ET FL,
+ rotor_setting = ben,
+ spacing = yes,
+ verbose = 1,
+}
+%%····································································%
+%% This second machine below will be used to decrypt the string.
+\defineenigma{decryption}
+\setupenigma{decryption}{
+ other_chars = yes,
+ day_key = B V III II 12 03 01 GI JV KZ WM PU QY AD CN ET FL,
+ rotor_setting = ben,
+}
+%%····································································%
+%% main
+%%····································································%
+%% Ciphertext in the PDF. Rely on the addressee to decrypt the document
+%% externally.
+%%····································································%
+%% encryption of plain text
+%%····································································%
+\beginencryption
+ Never underestimate the amount of money, time, and effort someone
+ will expend to thwart a security system.
+\endencryption
+
+%%····································································%
+%% decryption of ciphertext
+%%····································································%
+%% Input string generated with:
+%% mtxrun --script t-enigma \
+%% --setup="day_key=B V III II 12 03 01 GI JV KZ WM PU QY AD CN ET FL,\
+%% rotor_setting=ben,\
+%% other_chars=yes"\
+%% --text="Never underestimate the amount of money,\
+%% time, and effort someone will expend to\
+%% thwart a security system."
+\begindecryption
+ aqsnwyxgqarpuzrdktscbslaqmdhyonywxkwhcdgphvuqsspfjwhlszahygjbzmfpcpbniahvfcuradntepxsfchnn
+\enddecryption
+%%·····································································%
+\bye
diff --git a/Master/texmf-dist/scripts/context/lua/third/enigma/mtx-t-enigma.lua/mtx-t-enigma.lua b/Master/texmf-dist/scripts/context/lua/third/enigma/mtx-t-enigma.lua/mtx-t-enigma.lua
new file mode 100644
index 00000000000..1b093afb759
--- /dev/null
+++ b/Master/texmf-dist/scripts/context/lua/third/enigma/mtx-t-enigma.lua/mtx-t-enigma.lua
@@ -0,0 +1,72 @@
+--
+--------------------------------------------------------------------------------
+-- FILE: mtx-t-enigma.lua
+-- USAGE: mtxrun --script enigma --setup="s" --text="t"
+-- DESCRIPTION: context script interface for the Enigma module
+-- REQUIREMENTS: latest ConTeXt MkIV
+-- AUTHOR: Philipp Gesang (Phg), <gesang@stud.uni-heidelberg.de>
+-- CREATED: 2013-03-28 02:14:05+0100
+--------------------------------------------------------------------------------
+--
+
+environment.loadluafile("enigma")
+
+local iowrite = io.write
+
+local helpinfo = [[
+===============================================================
+ The Enigma module, command line interface.
+ © 2012--2013 Philipp Gesang. License: 2-clause BSD.
+ Home: <https://bitbucket.org/phg/enigma/>
+===============================================================
+
+USAGE:
+
+ mtxrun --script enigma --setup="settings" --text="text"
+ --verbose=int
+
+ where the settings are to be specified as a comma-delimited
+ conjunction of “key=value” statements, and “text” refers to
+ the text to be encoded. Note that due to the involutory
+ design of the enigma cipher, the text can be both plaintext
+ and ciphertext.
+
+===============================================================
+]]
+
+local application = logs.application {
+ name = "mtx-t-enigma",
+ banner = "The Enigma for ConTeXt, hg-rev 37+",
+ helpinfo = helpinfo,
+}
+
+local ea = environment.argument
+
+local setup, text = ea"setup" or ea"s", ea"text" or ea"t"
+local verbose = ea"verbose" or ea"v"
+
+local out = function (str)
+ iowrite(str)
+end
+
+local machine_id = "external"
+if setup and text then
+ local args = enigma.parse_args(setup)
+ if not args then
+ application.help()
+ iowrite"\n\n[Error] Could not process enigma setup!\n\n"
+ end
+ enigma.save_raw_args(args, machine_id)
+ --local machine = enigma.new_machine(enigma.parse_args(setup))
+ local machine = enigma.new_machine(machine_id)
+ --machine.name = machine_id
+ local result = machine:encode_string(text)
+ if result then
+ out(result)
+ else
+ application.help()
+ end
+else
+ application.help()
+end
+
diff --git a/Master/texmf-dist/tex/context/third/enigma/t-enigma.mkv/t-enigma.mkvi b/Master/texmf-dist/tex/context/third/enigma/t-enigma.mkv/t-enigma.mkvi
new file mode 100644
index 00000000000..b5fea293a88
--- /dev/null
+++ b/Master/texmf-dist/tex/context/third/enigma/t-enigma.mkv/t-enigma.mkvi
@@ -0,0 +1,157 @@
+%D \module
+%D [ file=t-enigma.mkvi,
+%D version=2013-03-28 02:15:37+0100,
+%D title=\CONTEXT\ User Module,
+%D subtitle=Enigma,
+%D author=Philipp Gesang,
+%D date=\currentdate,
+%D copyright=Philipp Gesang,
+%D license=2-clause BSD,
+%D email={phg42 dot 2a at gmail dot com}]
+%C This module is licensed under the conditions of the BSD license with
+%C two clauses. There is a copy in a file named "COPYING" in the
+%C t-enigma source tree.
+
+\unprotect
+
+\writestatus{loading} {ConTeXt module / Enigma Document Encryption}
+
+\startinterface all
+ \setinterfacevariable {enigma} {enigma}
+\stopinterface
+
+\definenamespace [\v!enigma] [
+ \v!command=\v!no,
+ comment=Enigma Document Encryption,
+ \s!name=\v!enigma,
+ \s!parent=\v!enigma,
+ % setup=\v!list,
+ setup=\v!no,
+ style=\v!no,
+ type=module,
+ version=hg-tip,
+]
+
+%D Loading the \LUA\ conversion routines.
+
+\startluacode
+thirddata = thirddata or { }
+\stopluacode
+\registerctxluafile{enigma}
+
+%D \startdocsection[title=Macro Generator]
+%D \startparagraph
+%D The main setup.\reference[listing:define]{} The
+%D \texmacro{defineenigma} macro does not adhere to the reommended
+%D practis of automatical macro derivation. Rather, we have our own
+%D parser do the job of setting globals. This is a consequence of the
+%D intention to offer the same behavior in any of the three main
+%D formats, \PLAIN, \CONTEXT and \LATEX. Hence, we don’t rely on the
+%D internal mechanisms but implement our own macro generator.
+%D \stopparagraph
+
+\def\enigma_define_indeed#id{%
+ \edef\enigmaid{#id}%
+ \expandafter\gdef\csname \e!start\enigmaid\endcsname{%
+ \endgraf
+ \bgroup
+ \ctxlua{
+ if thirddata.enigma.machines["#id"] then
+ nodes.tasks.enableaction("processors",
+ "thirddata.enigma.callbacks.#id")
+ else
+ print([[ENIGMA: No machine of that name: #id!]])
+ end
+ }%
+ }%
+ %
+ \expandafter\gdef\csname \e!stop\enigmaid\endcsname{%
+ \endgraf%% We need to force a paragraph here for the callback to be
+ %% applied.
+ \ctxlua{
+ nodes.tasks.disableaction("processors",
+ "thirddata.enigma.callbacks.#id")
+ thirddata.enigma.machines["#id"]:processed_chars()
+ }%
+ \egroup%
+ }%
+}
+
+%D \startparagraph
+%D The \texmacro{enigma_inherit}\reference[listing:inherit]{} is called
+%D as an intermediate step when deriving one machine from an already
+%D existing one. It gets the stored configuration of its ancestor,
+%D relying on the \luafunction{retrieve_raw_args} function (see
+%D \at{page}[listing:retrieve].
+%D \stopparagraph
+\def\enigma_inherit#to#from{%
+ \ctxlua{%
+ local enigma = thirddata.enigma
+ local current_args = enigma.retrieve_raw_args(\!!bs#from\!!es)
+ enigma.save_raw_args(current_args, \!!bs#to\!!es)
+ enigma.new_callback(enigma.new_machine(\!!bs#to\!!es),
+ \!!bs#to\!!es)
+ }%
+ \enigma_define_indeed{#to}%
+}
+
+\def\enigma_define[#id][#secondid]{%
+ \ifsecondargument %% Copy an existing machine and callback.
+ \enigma_inherit{#id}{#secondid}%
+ \else %% Create a new machine.
+ \iffirstargument
+ \enigma_define_indeed{#id}%
+ \else
+ \donothing
+ \fi
+ \fi
+ \endgroup%
+}
+
+\def\defineenigma{%
+ \begingroup
+ \dodoubleempty\enigma_define
+}
+
+%D \stopdocsection
+
+%D \startdocsection[title=Setup]
+\def\enigma_setup_indeed#args{%
+ \ctxlua{
+ local enigma = thirddata.enigma
+ local current_args =
+ enigma.parse_args(\!!bs\detokenize{#args}\!!es)
+ enigma.save_raw_args(current_args, \!!bs\currentenigmaid\!!es)
+ enigma.new_callback(
+ enigma.new_machine(\!!bs\currentenigmaid\!!es),
+ \!!bs\currentenigmaid\!!es)
+ }%
+}
+
+%D \startparagraph
+%D The module setup \texmacro{setupenigma} expects key=value, notation.
+%D All the logic is at the Lua end, not much to see here …
+%D \stopparagraph
+
+\def\enigma_setup[#id][#args]{%
+ \ifsecondargument
+ \edef\currentenigmaid{#id}
+ \pushcatcodetable
+ \catcodetable \txtcatcodes
+ \enigma_setup_indeed{#args}%
+ \else
+ \donothing
+ \fi
+ \popcatcodetable
+ \egroup%
+}
+
+\def\setupenigma{%
+ \bgroup
+ \dodoubleempty\enigma_setup%
+}
+
+%D \stopdocsection
+
+\protect
+% vim:ft=context:sw=2:ts=2:tw=71
diff --git a/Master/texmf-dist/tex/generic/enigma/enigma.lua b/Master/texmf-dist/tex/generic/enigma/enigma.lua
new file mode 100644
index 00000000000..9da428842bd
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/enigma/enigma.lua
@@ -0,0 +1,1662 @@
+#!/usr/bin/env texlua
+-----------------------------------------------------------------------
+-- FILE: enigma.lua
+-- USAGE: Call via interface from within a TeX session.
+-- DESCRIPTION: Enigma logic.
+-- REQUIREMENTS: LuaTeX capable format (Luaplain, ConTeXt).
+-- AUTHOR: Philipp Gesang (Phg), <phg42 dot 2a at gmail dot com>
+-- VERSION: release
+-- CREATED: 2013-03-28 02:12:03+0100
+-----------------------------------------------------------------------
+--
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[title=Format Dependent Code]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\startparagraph
+Exported functionality will be collected in the table
+\identifier{enigma}.
+\stopparagraph
+--ichd]]--
+
+local enigma = { machines = { }, callbacks = { } }
+local format_is_context = false
+
+--[[ichd--
+\startparagraph
+Afaict, \LATEX\ for \LUATEX\ still lacks a globally accepted
+namespacing convention. This is more than bad, but we’ll have to cope
+with that. For this reason we brazenly introduce
+\identifier{packagedata} (in analogy to \CONTEXT’s
+\identifier{thirddata}) table as a package namespace proposal. If this
+module is called from a \LATEX\ or plain session, the table
+\identifier{packagedata} will already have been created so we will
+identify the format according to its presence or absence, respectively.
+\stopparagraph
+--ichd]]--
+
+if packagedata then -- latex or plain
+ packagedata.enigma = enigma
+elseif thirddata then -- context
+ format_is_context = true
+ thirddata.enigma = enigma
+else -- external call, mtx-script or whatever
+ _ENV.enigma = enigma
+end
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[title=Prerequisites]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startparagraph
+First of all, we generate local copies of all those library functions
+that are expected to be referenced frequently.
+The format-independent stuff comes first; it consists of functions from
+the
+\identifier{io},
+\identifier{lpeg},
+\identifier{math},
+\identifier{string},
+\identifier{table}, and
+\identifier{unicode}
+libraries.
+\stopparagraph
+--ichd]]--
+
+local get_debug_info = debug.getinfo
+local ioread = io.read
+local iowrite = io.write
+local mathfloor = math.floor
+local mathrandom = math.random
+local next = next
+local nodecopy = node and node.copy
+local nodeid = node and node.id
+local nodeinsert_before = node and node.insert_before
+local nodeinsert_after = node and node.insert_after
+local nodelength = node and node.length
+local nodenew = node and node.new
+local noderemove = node and node.remove
+local nodeslide = node and node.slide
+local nodetraverse = node and node.traverse
+local nodetraverse_id = node and node.traverse_id
+local nodesinstallattributehandler
+local nodestasksappendaction
+local nodestasksdisableaction
+if format_is_context then
+ nodesinstallattributehandler = nodes.installattributehandler
+ nodestasksappendaction = nodes.tasks.appendaction
+ nodestasksdisableaction = nodes.tasks.disableaction
+end
+local stringfind = string.find
+local stringformat = string.format
+local stringlower = string.lower
+local stringsub = string.sub
+local stringupper = string.upper
+local tableconcat = table.concat
+local tonumber = tonumber
+local type = type
+local utf8byte = unicode.utf8.byte
+local utf8char = unicode.utf8.char
+local utf8len = unicode.utf8.len
+local utf8lower = unicode.utf8.lower
+local utf8sub = unicode.utf8.sub
+local utfcharacters = string.utfcharacters
+
+--- debugging tool (careful, this *will* break context!)
+--dofile(kpse.find_file("lualibs-table.lua")) -- archaic version :(
+--table.print = function (...) print(table.serialize(...)) end
+
+local tablecopy
+if format_is_context then
+ tablecopy = table.copy
+else -- could use lualibs instead but not worth the overhead
+ tablecopy = function (t) -- ignores tables as keys
+ local result = { }
+ for k, v in next, t do
+ if type(v) == table then
+ result[k] = tablecopy(v)
+ else
+ result[k] = v
+ end
+ end
+ return result
+ end
+end
+
+local GLYPH_NODE = node and nodeid"glyph"
+local GLUE_NODE = node and nodeid"glue"
+local GLUE_SPEC_NODE = node and nodeid"glue_spec"
+local KERN_NODE = node and nodeid"kern"
+local DISC_NODE = node and nodeid"disc"
+local HLIST_NODE = node and nodeid"hlist"
+local VLIST_NODE = node and nodeid"vlist"
+
+local IGNORE_NODES = node and {
+--[GLUE_NODE] = true,
+ [KERN_NODE] = true,
+--[DISC_NODE] = true,
+} or { }
+
+--[[ichd--
+\startparagraph
+The initialization of the module relies heavily on parsers generated by
+\type{LPEG}.
+\stopparagraph
+--ichd]]--
+
+local lpeg = require "lpeg"
+
+local C, Cb, Cc, Cf, Cg,
+ Cmt, Cp, Cs, Ct
+ = lpeg.C, lpeg.Cb, lpeg.Cc, lpeg.Cf, lpeg.Cg,
+ lpeg.Cmt, lpeg.Cp, lpeg.Cs, lpeg.Ct
+
+local P, R, S, V, lpegmatch
+ = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.match
+
+--local B = lpeg.version() == "0.10" and lpeg.B or nil
+
+--[[ichd--
+\startparagraph
+By default the output to \type{stdout} will be zero. The verbosity
+level can be adjusted in order to alleviate debugging.
+\stopparagraph
+--ichd]]--
+--local verbose_level = 42
+local verbose_level = 0
+
+--[[ichd--
+\startparagraph
+Historically, Enigma-encoded messages were restricted to a size of 250
+characters. With sufficient verbosity we will indicate whether this
+limit has been exceeded during the \TEX\ run.
+\stopparagraph
+--ichd]]--
+local max_msg_length = 250
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[title=Globals]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startparagraph
+The following mappings are used all over the place as we convert back
+and forth between the characters (unicode) and their numerical
+representation.
+\stopparagraph
+--ichd]]--
+
+local value_to_letter -- { [int] -> chr }
+local letter_to_value -- { [chr] -> int }
+local alpha_sorted -- string, length 26
+local raw_rotor_wiring -- { string0, .. string5, }
+local notches -- { [int] -> int } // rotor num -> notch pos
+local reflector_wiring -- { { [int] -> int }, ... } // symmetrical
+do
+ value_to_letter = {
+ "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",
+ }
+
+ letter_to_value = {
+ a = 01, b = 02, c = 03, d = 04, e = 05, f = 06, g = 07, h = 08,
+ i = 09, j = 10, k = 11, l = 12, m = 13, n = 14, o = 15, p = 16,
+ q = 17, r = 18, s = 19, t = 20, u = 21, v = 22, w = 23, x = 24,
+ y = 25, z = 26,
+ }
+--[[ichd--
+\startparagraph
+The five rotors to simulate.\reference[listing:rotor_wiring]{}
+Their wirings are created from strings at runtime, see below the
+function \luafunction{get_rotors}.
+\stopparagraph
+--ichd]]--
+
+ --[[
+ Nice: http://www.ellsbury.com/ultraenigmawirings.htm
+ ]]--
+ alpha_sorted = "abcdefghijklmnopqrstuvwxyz"
+ raw_rotor_wiring = {
+ [0] = alpha_sorted,
+ "ekmflgdqvzntowyhxuspaibrcj",
+ "ajdksiruxblhwtmcqgznpyfvoe",
+ "bdfhjlcprtxvznyeiwgakmusqo",
+ "esovpzjayquirhxlnftgkdcmwb",
+ "vzbrgityupsdnhlxawmjqofeck",
+ }
+
+--[[ichd--
+\startparagraph
+Notches are assigned to rotors according to the Royal Army
+mnemonic.
+\stopparagraph
+--ichd]]--
+ notches = { }
+ do
+ local raw_notches = "rfwkannnn"
+ --local raw_notches = "qevjz"
+ local n = 1
+ for chr in utfcharacters(raw_notches) do
+ local pos = stringfind(alpha_sorted, chr)
+ notches[n] = pos - 1
+ n = n + 1
+ end
+ end
+
+--[[ichd--
+\placetable[here][listing:reflector]%
+ {The three reflectors and their substitution rules.}{%
+ \starttabulate[|r|l|]
+ \NC UKW a \NC AE BJ CM DZ FL GY HX IV KW NR OQ PU ST \NC \NR
+ \NC UKW b \NC AY BR CU DH EQ FS GL IP JX KN MO TZ VW \NC \NR
+ \NC UKW c \NC AF BV CP DJ EI GO HY KR LZ MX NW QT SU \NC \NR
+ \stoptabulate
+}
+--ichd]]--
+
+ reflector_wiring = { }
+ local raw_ukw = {
+ { a = "e", b = "j", c = "m", d = "z", f = "l", g = "y", h = "x",
+ i = "v", k = "w", n = "r", o = "q", p = "u", s = "t", },
+ { a = "y", b = "r", c = "u", d = "h", e = "q", f = "s", g = "l",
+ i = "p", j = "x", k = "n", m = "o", t = "z", v = "w", },
+ { a = "f", b = "v", c = "p", d = "j", e = "i", g = "o", h = "y",
+ k = "r", l = "z", m = "x", n = "w", q = "t", s = "u", },
+ }
+ for i=1, #raw_ukw do
+ local new_wiring = { }
+ local current_ukw = raw_ukw[i]
+ for from, to in next, current_ukw do
+ from = letter_to_value[from]
+ to = letter_to_value[to]
+ new_wiring[from] = to
+ new_wiring[to] = from
+ end
+ reflector_wiring[i] = new_wiring
+ end
+end
+
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[title=Pretty printing for debug purposes]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startparagraph
+The functions below allow for formatting of the terminal output; they
+have no effect on the workings of the enigma simulator.
+\stopparagraph
+--ichd]]--
+
+local emit
+local pprint_ciphertext
+local pprint_encoding
+local pprint_encoding_scheme
+local pprint_init
+local pprint_machine_step
+local pprint_new_machine
+local pprint_rotor
+local pprint_rotor_scheme
+local pprint_step
+local polite_key_request
+local key_invalid
+do
+ local eol = "\n"
+
+ local colorstring_template = "\027[%d;1m%s\027[0m"
+ local colorize = function (s, color)
+ color = color and color < 38 and color > 29 and color or 31
+ return stringformat(colorstring_template,
+ color,
+ s)
+ end
+
+ local underline = function (s)
+ return stringformat("\027[4;37m%s\027[0m", s)
+ end
+
+ local s_steps = [[Total characters encoded with machine “]]
+ local f_warnsteps = [[ (%d over permitted maximum)]]
+ pprint_machine_step = function (n, name)
+ local sn
+ name = colorize(name, 36)
+ if n > max_msg_length then
+ sn = colorize(n, 31) .. stringformat(f_warnsteps,
+ n - max_msg_length)
+ else
+ sn = colorize(n, 37)
+ end
+ return s_steps .. name .. "”: " .. sn .. "."
+ end
+ local rotorstate = "[s \027[1;37m%s\027[0m n\027[1;37m%2d\027[0m]> "
+ pprint_rotor = function (rotor)
+ local visible = rotor.state % 26 + 1
+ local w, n = rotor.wiring, (rotor.notch - visible) % 26 + 1
+ local tmp = { }
+ for i=1, 26 do
+ local which = (i + rotor.state - 1) % 26 + 1
+ local chr = value_to_letter[rotor.wiring.from[which]]
+ if i == n then -- highlight positions of notches
+ tmp[i] = colorize(stringupper(chr), 32)
+ --elseif chr == value_to_letter[visible] then
+ ---- highlight the character in window
+ -- tmp[i] = colorize(chr, 33)
+ else
+ tmp[i] = chr
+ end
+ end
+ return stringformat(rotorstate,
+ stringupper(value_to_letter[visible]),
+ n)
+ .. tableconcat(tmp)
+ end
+
+ local rotor_scheme = underline"[rot not]"
+ .. " "
+ .. underline(alpha_sorted)
+ pprint_rotor_scheme = function ()
+ return rotor_scheme
+ end
+
+ local s_encoding_scheme = eol
+ .. [[in > 1 => 2 => 3 > UKW > 3 => 2 => 1]]
+ pprint_encoding_scheme = function ()
+ return underline(s_encoding_scheme)
+ end
+ local s_step = " => "
+ local stepcolor = 36
+ local finalcolor = 32
+ pprint_encoding = function (steps)
+ local nsteps, result = #steps, { }
+ for i=0, nsteps-1 do
+ result[i+1] = colorize(value_to_letter[steps[i]], stepcolor)
+ .. s_step
+ end
+ result[nsteps+1] = colorize(value_to_letter[steps[nsteps]],
+ finalcolor)
+ return tableconcat(result)
+ end
+
+ local init_announcement
+ = colorize("\n" .. [[Initial position of rotors: ]],
+ 37)
+ pprint_init = function (init)
+ local result = ""
+ result = value_to_letter[init[1]] .. " "
+ .. value_to_letter[init[2]] .. " "
+ .. value_to_letter[init[3]]
+ return init_announcement .. colorize(stringupper(result), 34)
+ end
+
+ local machine_announcement =
+ [[Enigma machine initialized with the following settings.]] .. eol
+ local s_ukw = colorize(" Reflector:", 37)
+ local s_pb = colorize("Plugboard setting:", 37)
+ local s_ring = colorize(" Ring positions:", 37)
+ local empty_plugboard = colorize(" ——", 34)
+ pprint_new_machine = function (m)
+ local result = { "" }
+ result[#result+1] = underline(machine_announcement)
+ result[#result+1] = s_ukw
+ .. " "
+ .. colorize(
+ stringupper(value_to_letter[m.reflector]),
+ 34
+ )
+ local rings = ""
+ for i=1, 3 do
+ local this = m.ring[i]
+ rings = rings
+ .. " "
+ .. colorize(stringupper(value_to_letter[this + 1]), 34)
+ end
+ result[#result+1] = s_ring .. rings
+ if m.__raw.plugboard then
+ local tpb, pb = m.__raw.plugboard, ""
+ for i=1, #tpb do
+ pb = pb .. " " .. colorize(tpb[i], 34)
+ end
+ result[#result+1] = s_pb .. pb
+ else
+ result[#result+1] = s_pb .. empty_plugboard
+ end
+ result[#result+1] = ""
+ result[#result+1] = pprint_rotor_scheme()
+ for i=1, 3 do
+ result[#result+1] = pprint_rotor(m.rotors[i])
+ end
+ return tableconcat(result, eol) .. eol
+ end
+
+ local step_template = colorize([[Step № ]], 37)
+ local chr_template = colorize([[ —— Input ]], 37)
+ local pbchr_template = colorize([[ → ]], 37)
+ pprint_step = function (n, chr, pb_chr)
+ return eol
+ .. step_template
+ .. colorize(n, 34)
+ .. chr_template
+ .. colorize(stringupper(value_to_letter[chr]), 34)
+ .. pbchr_template
+ .. colorize(stringupper(value_to_letter[pb_chr]), 34)
+ .. eol
+ end
+
+ -- Split the strings into lines, group them in bunches of five etc.
+ local tw = 30
+ local pprint_textblock = function (s)
+ local len = utf8len(s)
+ local position = 1 -- position in string
+ local nline = 5 -- width of current line
+ local out = utf8sub(s, position, position+4)
+ repeat
+ position = position + 5
+ nline = nline + 6
+ if nline > tw then
+ out = out .. eol .. utf8sub(s, position, position+4)
+ nline = 1
+ else
+ out = out .. " " .. utf8sub(s, position, position+4)
+ end
+ until position > len
+ return out
+ end
+
+ local intext = colorize([[Input text:]], 37)
+ local outtext = colorize([[Output text:]], 37)
+ pprint_ciphertext = function (input, output, upper_p)
+ if upper_p then
+ input = stringupper(input)
+ output = stringupper(output)
+ end
+ return eol
+ .. intext
+ .. eol
+ .. pprint_textblock(input)
+ .. eol .. eol
+ .. outtext
+ .. eol
+ .. pprint_textblock(output)
+ end
+
+--[[ichd--
+\startparagraph
+\luafunction{emit} is the main wrapper function for
+\identifier{stdout}. Checks if the global verbosity setting exceeds
+the specified threshold, and only then pushes the output.
+\stopparagraph
+--ichd]]--
+ emit = function (v, f, ...)
+ if f and v and verbose_level >= v then
+ iowrite(f(...) .. eol)
+ end
+ return 0
+ end
+--[[ichd--
+\startparagraph
+The \luafunction{polite_key_request} will be called in case the
+\identifier{day_key} field of the machine setup is empty at the time of
+initialization.
+\stopparagraph
+--ichd]]--
+ local s_request = "\n\n "
+ .. underline"This is an encrypted document." .. [[
+
+
+ Please enter the document key for enigma machine
+ “%s”.
+
+ Key Format:
+
+Ref R1 R2 R3 I1 I2 I3 [P1 ..] Ref: reflector A/B/C
+ Rn: rotor, I through V
+ In: ring position, 01 through 26
+ Pn: optional plugboard wiring, upto 32
+
+>]]
+ polite_key_request = function (name)
+ return stringformat(s_request, colorize(name, 33))
+ end
+
+ local s_invalid_key = colorize"Warning!"
+ .. " The specified key is invalid."
+ key_invalid = function ()
+ return s_invalid_key
+ end
+end
+
+--[[ichd--
+\startparagraph
+The functions \luafunction{new} and \luafunction{ask_for_day_key} are
+used outside their scope, so we declare them beforehand.
+\stopparagraph
+--ichd]]--
+local new
+local ask_for_day_key
+do
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[title=Rotation]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startparagraph
+The following function \luafunction{do_rotate} increments the
+rotational state of a single rotor. There are two tests for notches:
+\startitemize[n]
+ \item whether it’s at the current character, and
+ \item whether it’s at the next character.
+\stopitemize
+The latter is an essential prerequisite for double-stepping.
+\stopparagraph
+--ichd]]--
+ local do_rotate = function (rotor)
+ rotor.state = rotor.state % 26 + 1
+ return rotor,
+ rotor.state == rotor.notch,
+ rotor.state + 1 == rotor.notch
+ end
+
+--[[ichd--
+\startparagraph
+The \luafunction{rotate} function takes care of rotor (\emph{Walze})
+movement. This entails incrementing the next rotor whenever the notch
+has been reached and covers the corner case \emph{double stepping}.
+\stopparagraph
+--ichd]]--
+ local rotate = function (machine)
+ local rotors = machine.rotors
+ local rc, rb, ra = rotors[1], rotors[2], rotors[3]
+
+ ra, nxt = do_rotate(ra)
+ if nxt or machine.double_step then
+ rb, nxt, nxxt = do_rotate(rb)
+ if nxt then
+ rc = do_rotate(rc)
+ end
+ if nxxt then
+ --- weird: home.comcast.net/~dhhamer/downloads/rotors1.pdf
+ machine.double_step = true
+ else
+ machine.double_step = false
+ end
+ end
+ machine.rotors = { rc, rb, ra }
+ end
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[title=Input Preprocessing]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startparagraph
+Internally, we will use lowercase strings as they are a lot more
+readable than uppercase. Lowercasing happens prior to any further
+dealings with input. After the encoding or decoding has been
+accomplished, there will be an optional (re-)uppercasing.
+\stopparagraph
+
+\startparagraph
+Substitutions \reference[listing:preproc]{}are applied onto the
+lowercased input. You might want to avoid some of these, above all the
+rules for numbers, because they translate single digits only. The
+solution is to write out numbers above ten.
+\stopparagraph
+--ichd]]--
+
+ local pp_substitutions = {
+ -- Umlauts are resolved.
+ ["ö"] = "oe",
+ ["ä"] = "ae",
+ ["ü"] = "ue",
+ ["ß"] = "ss",
+ -- WTF?
+ ["ch"] = "q",
+ ["ck"] = "q",
+ -- Punctuation -> “x”
+ [","] = "x",
+ ["."] = "x",
+ [";"] = "x",
+ [":"] = "x",
+ ["/"] = "x",
+ ["’"] = "x",
+ ["‘"] = "x",
+ ["„"] = "x",
+ ["“"] = "x",
+ ["“"] = "x",
+ ["-"] = "x",
+ ["–"] = "x",
+ ["—"] = "x",
+ ["!"] = "x",
+ ["?"] = "x",
+ ["‽"] = "x",
+ ["("] = "x",
+ [")"] = "x",
+ ["["] = "x",
+ ["]"] = "x",
+ ["<"] = "x",
+ [">"] = "x",
+ -- Spaces are omitted.
+ [" "] = "",
+ ["\n"] = "",
+ ["\t"] = "",
+ ["\v"] = "",
+ ["\\"] = "",
+ -- Numbers are resolved.
+ ["0"] = "null",
+ ["1"] = "eins",
+ ["2"] = "zwei",
+ ["3"] = "drei",
+ ["4"] = "vier",
+ ["5"] = "fuenf",
+ ["6"] = "sechs",
+ ["7"] = "sieben",
+ ["8"] = "acht",
+ ["9"] = "neun",
+ }
+
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[
+ title={Main function chain to be applied to single characters},
+]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\startparagraph
+As far as the Enigma is concerned, there is no difference between
+encoding and decoding. Thus, we need only one function
+(\luafunction{encode_char}) to achieve the complete functionality.
+However, within every encoding step, characters will be wired
+differently in at least one of the rotors according to its rotational
+state. Rotation is simulated by adding the \identifier{state} field of
+each rotor to the letter value (its position on the ingoing end).
+\stopparagraph
+\placetable[here][table:dirs]{Directional terminology}{%
+ \starttabulate[|l|r|l|]
+ \NC boolean \NC direction \NC meaning \NC \AR
+ \NC true \NC “from” \NC right to left \NC \AR
+ \NC false \NC “to” \NC left to right \NC \AR
+ \stoptabulate%
+}
+\startparagraph
+The function \luafunction{do_do_encode_char} returns the character
+substitution for one rotor. As a letter passes through each rotor
+twice, the argument \identifier{direction} determines which way the
+substitution is applied.
+\stopparagraph
+--ichd]]--
+ local do_do_encode_char = function (char, rotor, direction)
+ local rw = rotor.wiring
+ local rs = rotor.state
+ local result = char
+ if direction then -- from
+ result = (result + rs - 1) % 26 + 1
+ result = rw.from[result]
+ result = (result - rs - 1) % 26 + 1
+ else -- to
+ result = (result + rs - 1) % 26 + 1
+ result = rw.to[result]
+ result = (result - rs - 1) % 26 + 1
+ end
+ return result
+ end
+
+--[[ichd--
+\startparagraph
+Behind the plugboard, every character undergoes seven substitutions:
+two for each rotor plus the central one through the reflector. The
+function \luafunction{do_encode_char}, although it returns the final
+result only, keeps every intermediary step inside a table for debugging
+purposes. This may look inefficient but is actually a great advantage
+whenever something goes wrong.
+\stopparagraph
+--ichd]]--
+ --- ra -> rb -> rc -> ukw -> rc -> rb -> ra
+ local do_encode_char = function (rotors, reflector, char)
+ local rc, rb, ra = rotors[1], rotors[2], rotors[3]
+ local steps = { [0] = char }
+ --
+ steps[1] = do_do_encode_char(steps[0], ra, true)
+ steps[2] = do_do_encode_char(steps[1], rb, true)
+ steps[3] = do_do_encode_char(steps[2], rc, true)
+ steps[4] = reflector_wiring[reflector][steps[3]]
+ steps[5] = do_do_encode_char(steps[4], rc, false)
+ steps[6] = do_do_encode_char(steps[5], rb, false)
+ steps[7] = do_do_encode_char(steps[6], ra, false)
+ emit(2, pprint_encoding_scheme)
+ emit(2, pprint_encoding, steps)
+ return steps[7]
+ end
+
+--[[ichd--
+\startparagraph
+Before an input character is passed on to the actual encoding routing,
+the function \luafunction{encode_char} matches it agains the latin
+alphabet.
+Characters failing this test are either passed through or ignored,
+depending on the machine option \identifier{other_chars}.
+Also, the counter of encoded characters is incremented at this stage
+and some pretty printer hooks reside here.
+\stopparagraph
+
+\startparagraph
+\luafunction{encode_char} contributes only one element of the encoding
+procedure: the plugboard (\emph{Steckerbrett}).
+Like the rotors described above, a character passed through this
+device twice; the plugboard marks the beginning and end of every step.
+For debugging purposes, the first substitution is stored in a separate
+local variable, \identifier{pb_char}.
+\stopparagraph
+--ichd]]--
+
+ local encode_char = function (machine, char)
+ machine.step = machine.step + 1
+ machine:rotate()
+ local pb = machine.plugboard
+ char = letter_to_value[char]
+ local pb_char = pb[char] -- first plugboard substitution
+ emit(2, pprint_step, machine.step, char, pb_char)
+ emit(3, pprint_rotor_scheme)
+ emit(3, pprint_rotor, machine.rotors[1])
+ emit(3, pprint_rotor, machine.rotors[2])
+ emit(3, pprint_rotor, machine.rotors[3])
+ char = do_encode_char(machine.rotors,
+ machine.reflector,
+ pb_char)
+ return value_to_letter[pb[char]] -- second plugboard substitution
+ end
+
+ local get_random_pattern = function ()
+ local a, b, c
+ = mathrandom(1,26), mathrandom(1,26), mathrandom(1,26)
+ return value_to_letter[a]
+ .. value_to_letter[b]
+ .. value_to_letter[c]
+ end
+
+ local pattern_to_state = function (pat)
+ return {
+ letter_to_value[stringsub(pat, 1, 1)],
+ letter_to_value[stringsub(pat, 2, 2)],
+ letter_to_value[stringsub(pat, 3, 3)],
+ }
+ end
+
+ local set_state = function (machine, state)
+ local rotors = machine.rotors
+ for i=1, 3 do
+ rotors[i].state = state[i] - 1
+ end
+ end
+
+--[[ichd--
+\startparagraph
+When \modulename{Enigma} is called from \TEX, the encoding
+proceeds character by character as we iterate one node at a time.
+\luafunction{encode_string} is a wrapper for use with strings, e.~g. in
+the mtx-script (\at{page}[sec:fun]).
+It handles iteration and extraction of successive characters from the
+sequence.
+\stopparagraph
+--ichd]]--
+ local encode_string = function (machine, str) --, pattern)
+ local result = { }
+ for char in utfcharacters(str) do
+ local tmp = machine:encode(char)
+ if tmp ~= false then
+ if type(tmp) == "table" then
+ for i=1, #tmp do
+ result[#result+1] = tmp[i]
+ end
+ else
+ result[#result+1] = tmp
+ end
+ end
+ end
+ machine:processed_chars()
+ return tableconcat(result)
+ end
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[title=Initialization string parser]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\placetable[here][]{Initialization strings}{%
+ \bTABLE
+ \bTR
+ \bTD Reflector \eTD
+ \bTD[nc=3] Rotor \eTD
+ \bTD[nc=3] Initial \eTD
+ \bTD[nc=10] Plugboard wiring \eTD
+ \eTR
+ \eTR
+ \bTR
+ \bTD in slot \eTD
+ \bTD[nc=3] setting \eTD
+ \bTD[nc=3] rotor \eTD
+ \eTR
+ \bTR
+ \bTD \eTD
+ \bTD 1 \eTD\bTD 2 \eTD\bTD 3 \eTD
+ \bTD 1 \eTD\bTD 2 \eTD\bTD 3 \eTD
+ \bTD 1 \eTD\bTD 2 \eTD\bTD 3 \eTD\bTD 4 \eTD\bTD 5 \eTD
+ \bTD 6 \eTD\bTD 7 \eTD\bTD 8 \eTD\bTD 9 \eTD\bTD 10 \eTD
+ \eTR
+ \bTR
+ \bTD B \eTD
+ \bTD I \eTD\bTD IV \eTD\bTD III \eTD
+ \bTD 16 \eTD\bTD 26 \eTD\bTD 08 \eTD
+ \bTD AD \eTD\bTD CN \eTD\bTD ET \eTD
+ \bTD FL \eTD\bTD GI \eTD\bTD JV \eTD
+ \bTD KZ \eTD\bTD PU \eTD\bTD QY \eTD
+ \bTD WX \eTD
+ \eTR
+ \eTABLE
+}
+--ichd]]--
+ local roman_digits = {
+ i = 1, I = 1,
+ ii = 2, II = 2,
+ iii = 3, III = 3,
+ iv = 4, IV = 4,
+ v = 5, V = 5,
+ }
+
+ local p_init = P{
+ "init",
+ init = V"whitespace"^-1 * Ct(V"do_init"),
+ do_init = (V"reflector" * V"whitespace")^-1
+ * V"rotors" * V"whitespace"
+ * V"ring"
+ * (V"whitespace" * V"plugboard")^-1
+ ,
+ reflector = Cg(C(R("ac","AC")) / stringlower, "reflector")
+ ,
+
+ rotors = Cg(Ct(V"rotor" * V"whitespace"
+ * V"rotor" * V"whitespace"
+ * V"rotor"),
+ "rotors")
+ ,
+ rotor = Cs(V"roman_five" / roman_digits
+ + V"roman_four" / roman_digits
+ + V"roman_three" / roman_digits
+ + V"roman_two" / roman_digits
+ + V"roman_one" / roman_digits)
+ ,
+ roman_one = P"I" + P"i",
+ roman_two = P"II" + P"ii",
+ roman_three = P"III" + P"iii",
+ roman_four = P"IV" + P"iv",
+ roman_five = P"V" + P"v",
+
+ ring = Cg(Ct(V"double_digit" * V"whitespace"
+ * V"double_digit" * V"whitespace"
+ * V"double_digit"),
+ "ring")
+ ,
+ double_digit = C(R"02" * R"09"),
+
+ plugboard = Cg(V"do_plugboard", "plugboard"),
+ --- no need to enforce exactly ten substitutions
+ --do_plugboard = Ct(V"letter_combination" * V"whitespace"
+ -- * V"letter_combination" * V"whitespace"
+ -- * V"letter_combination" * V"whitespace"
+ -- * V"letter_combination" * V"whitespace"
+ -- * V"letter_combination" * V"whitespace"
+ -- * V"letter_combination" * V"whitespace"
+ -- * V"letter_combination" * V"whitespace"
+ -- * V"letter_combination" * V"whitespace"
+ -- * V"letter_combination" * V"whitespace"
+ -- * V"letter_combination")
+ do_plugboard = Ct(V"letter_combination"
+ * (V"whitespace" * V"letter_combination")^0)
+ ,
+ letter_combination = C(R("az", "AZ") * R("az", "AZ")),
+
+ whitespace = S" \n\t\v"^1,
+ }
+
+
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[title=Initialization routines]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\startparagraph
+The plugboard is implemented as a pair of hash tables.
+\stopparagraph
+--ichd]]--
+ local get_plugboard_substitution = function (p)
+ --- Plugboard wirings are symmetrical, thus we have one table for
+ --- each direction.
+ local tmp, result = { }, { }
+ for _, str in next, p do
+ local one, two = stringlower(stringsub(str, 1, 1)),
+ stringlower(stringsub(str, 2))
+ tmp[one] = two
+ tmp[two] = one
+ end
+ local n_letters = 26
+
+ local lv = letter_to_value
+ for n=1, n_letters do
+ local letter = value_to_letter[n]
+ local sub = tmp[letter] or letter
+ -- Map each char either to the plugboard substitution or itself.
+ result[lv[letter]] = lv[sub or letter]
+ end
+ return result
+ end
+
+--[[ichd--
+\startparagraph
+Initialization of the rotors requires some precautions to be taken.
+The most obvious of which is adjusting the displacement of its wiring
+by the ring setting.
+\stopparagraph
+\startparagraph
+Another important task is to store the notch position in order for it
+to be retrievable by the rotation subroutine at a later point.
+\stopparagraph
+\startparagraph
+The actual bidirectional mapping is implemented as a pair of tables.
+The initial order of letters, before the ring shift is applied, is
+alphabetical on the input (right, “from”) side and, on the output
+(left, “to”) side taken by the hard wired correspondence as specified
+in the rotor wirings above.
+NB the descriptions in terms of “output” and “input” directions is
+misleading in so far as during any encoding step the electricity will
+pass through every rotor in both ways.
+Hence, the “input” (right, from) direction literally applies only to
+the first half of the encoding process between plugboard and reflector.
+\stopparagraph
+\startparagraph
+The function \luafunction{do_get_rotor} creates a single rotor instance
+and populates it with character mappings. The \identifier{from} and
+\identifier{to} subfields of its \identifier{wiring} field represent
+the wiring in the respective directions.
+This initital wiring was specified in the corresponding
+\identifier{raw_rotor_wiring} table; the ringshift is added modulo the
+alphabet size in order to get the correctly initialized rotor.
+\stopparagraph
+--ichd]]--
+ local do_get_rotor = function (raw, notch, ringshift)
+ local rotor = {
+ wiring = {
+ from = { },
+ to = { },
+ },
+ state = 0,
+ notch = notch,
+ }
+ local w = rotor.wiring
+ for from=1, 26 do
+ local to = letter_to_value[stringsub(raw, from, from)]
+ --- The shift needs to be added in both directions.
+ to = (to + ringshift - 1) % 26 + 1
+ from = (from + ringshift - 1) % 26 + 1
+ rotor.wiring.from[from] = to
+ rotor.wiring.to [to ] = from
+ end
+ --table.print(rotor, "rotor")
+ return rotor
+ end
+
+--[[ichd--
+\startparagraph
+Rotors are initialized sequentially accordings to the initialization
+request.
+The function \luafunction{get_rotors} walks over the list of
+initialization instructions and calls \luafunction{do_get_rotor} for
+the actual generation of the rotor table. Each rotor generation request
+consists of three elements:
+\stopparagraph
+\startitemize[n]
+ \item the choice of rotor (one of five),
+ \item the notch position of said rotor, and
+ \item the ring shift.
+\stopitemize
+--ichd]]--
+ local get_rotors = function (rotors, ring)
+ local s, r = { }, { }
+ for n=1, 3 do
+ local nr = tonumber(rotors[n])
+ local ni = tonumber(ring[n]) - 1 -- “1” means shift of zero
+ r[n] = do_get_rotor(raw_rotor_wiring[nr], notches[nr], ni)
+ s[n] = ni
+ end
+ return r, s
+ end
+
+ local decode_char = encode_char -- hooray for involutory ciphers
+
+--[[ichd--
+\startparagraph
+The function \luafunction{encode_general} is an intermediate step for
+the actual single-character encoding / decoding routine
+\luafunction{enchode_char}.
+Its purpose is to ensure encodability of a given character before
+passing it along.
+Characters are first checked against the replacement table
+\identifier{pp_substitutions} (see \at{page}[listing:preproc]).
+For single-character replacements the function returns the encoded
+character (string).
+However, should the replacement turn out to consist of more than one
+character, each one will be encoded successively, yielding a list.
+\stopparagraph
+--ichd]]--
+ local encode_general = function (machine, chr)
+ local chr = utf8lower(chr)
+ local replacement
+ = pp_substitutions[chr] or letter_to_value[chr] and chr
+ if not replacement then
+ if machine.other_chars then
+ return chr
+ else
+ return false
+ end
+ end
+
+ if utf8len(replacement) == 1 then
+ return encode_char(machine, replacement)
+ end
+ local result = { }
+ for new_chr in utfcharacters(replacement) do
+ result[#result+1] = encode_char(machine, new_chr)
+ end
+ return result
+ end
+
+ local process_message_key
+ local alpha = R"az"
+ local alpha_dec = alpha / letter_to_value
+ local whitespace = S" \n\t\v"
+ local mkeypattern = Ct(alpha_dec * alpha_dec * alpha_dec)
+ * whitespace^0
+ * C(alpha * alpha *alpha)
+ process_message_key = function (machine, message_key)
+ message_key = stringlower(message_key)
+ local init, three = lpegmatch(mkeypattern, message_key)
+ -- to be implemented
+ end
+
+ local decode_string = function (machine, str, message_key)
+ machine.kenngruppe, str = stringsub(str, 3, 5), stringsub(str, 6)
+ machine:process_message_key(message_key)
+ local decoded = encode_string(machine, str)
+ return decoded
+ end
+
+ local testoptions = {
+ size = 42,
+
+ }
+ local generate_header = function (options)
+ end
+
+ local processed_chars = function (machine)
+ emit(1, pprint_machine_step, machine.step, machine.name)
+ end
+
+--[[ichd--
+\startparagraph
+The day key is entrusted to the function \luafunction{handle_day_key}.
+If the day key is the empty string or \type{nil}, it will ask for a key
+on the terminal. (Cf. below, \at{page}[listing:ask_for_day_key].)
+Lesson: don’t forget providing day keys in your setups when running in
+batch mode.
+\stopparagraph
+--ichd]]--
+ local handle_day_key handle_day_key = function (dk, name, old)
+ local result
+ if not dk or dk == "" then
+ dk = ask_for_day_key(name, old)
+ end
+ result = lpegmatch(p_init, dk)
+ result.reflector = result.reflector or "b"
+ -- If we don’t like the key we’re going to ask again. And again....
+ return result or handle_day_key(nil, name, dk)
+ end
+
+--[[ichd--
+\startparagraph
+The enigma encoding is restricted to an input -- and, naturally, output
+-- alphabet of exactly twenty-seven characters. Obviously, this would
+severely limit the set of encryptable documents. For this reason the
+plain text would be \emph{preprocessed} prior to encoding, removing
+spaces and substituting a range of characters, e.\,g. punctuation, with
+placeholders (“X”) from the encodable spectrum. See above
+\at{page}[listing:preproc] for a comprehensive list of substitutions.
+\stopparagraph
+
+\startparagraph
+The above mentioned preprocessing, however, does not even nearly extend
+to the whole unicode range that modern day typesetting is expected to
+handle. Thus, sooner or later an Enigma machine will encounter
+non-preprocessable characters and it will have to decide what to do
+with them. The Enigma module offers two ways to handle this kind of
+situation: \emph{drop} those characters, possibly distorting the
+deciphered plain text, or to leave them in, leaving hints behind as to
+the structure of the encrypted text. None of these is optional, so it
+is nevertheless advisable to not include non-latin characters in the
+plain text in the first place. The settings key
+\identifier{other_chars} (type boolean) determines whether we will keep
+or drop offending characters.
+\stopparagraph
+--ichd]]--
+
+ new = function (name, args)
+ local setup_string, pattern = args.day_key, args.rotor_setting
+ local raw_settings = handle_day_key(setup_string, name)
+ local rotors, ring =
+ get_rotors(raw_settings.rotors, raw_settings.ring)
+ local plugboard
+ = raw_settings.plugboard
+ and get_plugboard_substitution(raw_settings.plugboard)
+ or get_plugboard_substitution{ }
+ local machine = {
+ name = name,
+ step = 0, -- n characters encoded
+ init = {
+ rotors = raw_settings.rotors,
+ ring = raw_settings.ring
+ },
+ rotors = rotors,
+ ring = ring,
+ state = init_state,
+ other_chars = args.other_chars,
+ spacing = args.spacing,
+ ---> a>1, b>2, c>3
+ reflector = letter_to_value[raw_settings.reflector],
+ plugboard = plugboard,
+ --- functionality
+ rotate = rotate,
+ --process_message_key = process_message_key,
+ encode_string = encode_string,
+ encode_char = encode_char,
+ encode = encode_general,
+ decode_string = decode_string,
+ decode_char = decode_char,
+ set_state = set_state,
+ processed_chars = processed_chars,
+ --- <badcodingstyle> -- hackish but occasionally useful
+ __raw = raw_settings
+ --- </badcodingstyle>
+ } --- machine
+ local init_state
+ = pattern_to_state(pattern or get_random_pattern())
+ emit(1, pprint_init, init_state)
+ machine:set_state(init_state)
+
+ --table.print(machine.rotors)
+ emit(1, pprint_new_machine, machine)
+ return machine
+ end
+
+end
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+
+--[[ichd--
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\startdocsection[title=Setup Argument Handling]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+--ichd]]--
+do
+--[[ichd--
+\startparagraph
+As the module is intended to work both with the Plain and \LATEX\
+formats as well as \CONTEXT, we can’t rely on format dependent setups.
+Hence the need for an argument parser. Should be more efficient anyways
+as all the functionality resides in Lua.
+\stopparagraph
+--ichd]]--
+
+ local p_args = P{
+ "args",
+ args = Cf(Ct"" * (V"kv_pair" + V"emptyline")^0, rawset),
+ kv_pair = Cg(V"key"
+ * V"separator"
+ * (V"value" * V"final"
+ + V"empty"))
+ * V"rest_of_line"^-1
+ ,
+ key = V"whitespace"^0 * C(V"key_char"^1),
+ key_char = (1 - V"whitespace" - V"eol" - V"equals")^1,
+ separator = V"whitespace"^0 * V"equals" * V"whitespace"^0,
+ empty = V"whitespace"^0 * V"comma" * V"rest_of_line"^-1
+ * Cc(false)
+ ,
+ value = C((V"balanced" + (1 - V"final"))^1),
+ final = V"whitespace"^0 * V"comma" + V"rest_of_string",
+ rest_of_string = V"whitespace"^0
+ * V"eol_comment"^-1
+ * V"eol"^0
+ * V"eof"
+ ,
+ rest_of_line = V"whitespace"^0 * V"eol_comment"^-1 * V"eol",
+ eol_comment = V"comment_string" * (1 - (V"eol" + V"eof"))^0,
+ comment_string = V"lua_comment" + V"TeX_comment",
+ TeX_comment = V"percent",
+ lua_comment = V"double_dash",
+ emptyline = V"rest_of_line",
+
+ balanced = V"balanced_brk" + V"balanced_brc",
+ balanced_brk = V"lbrk"
+ * (V"balanced" + (1 - V"rbrk"))^0
+ * V"rbrk"
+ ,
+ balanced_brc = V"lbrc"
+ * (V"balanced" + (1 - V"rbrc"))^0
+ * V"rbrc"
+ ,
+ -- Terminals
+ eol = P"\n\r" + P"\r\n" + P"\n" + P"\r",
+ eof = -P(1),
+ whitespace = S" \t\v",
+ equals = P"=",
+ dot = P".",
+ comma = P",",
+ dash = P"-", double_dash = V"dash" * V"dash",
+ percent = P"%",
+ lbrk = P"[", rbrk = P"]",
+ lbrc = P"{", rbrc = P"}",
+ }
+
+
+--[[ichd--
+\startparagraph
+In the next step we process the arguments, check the input for sanity
+etc. The function \luafunction{parse_args} will test whether a value
+has a sanitizer routine and, if so, apply it to its value.
+\stopparagraph
+--ichd]]--
+
+ local boolean_synonyms = {
+ ["1"] = true,
+ doit = true,
+ indeed = true,
+ ok = true,
+ ["⊤"] = true,
+ ["true"] = true,
+ yes = true,
+ }
+ local toboolean
+ = function (value) return boolean_synonyms[value] or false end
+ local alpha = R("az", "AZ")
+ local digit = R"09"
+ local space = S" \t\v"
+ local ans = alpha + digit + space
+ local p_ans = Cs((ans + (1 - ans / ""))^1)
+ local alphanum_or_space = function (str)
+ if type(str) ~= "string" then return nil end
+ return lpegmatch(p_ans, str)
+ end
+ local ensure_int = function (n)
+ n = tonumber(n)
+ if not n then return 0 end
+ return mathfloor(n + 0.5)
+ end
+ p_alpha = Cs((alpha + (1 - alpha / ""))^1)
+ local ensure_alpha = function (s)
+ s = tostring(s)
+ return lpegmatch(p_alpha, s)
+ end
+
+ local sanitizers = {
+ other_chars = toboolean, -- true = keep, false = drop
+ spacing = toboolean,
+ day_key = alphanum_or_space,
+ rotor_setting = ensure_alpha,
+ verbose = ensure_int,
+ }
+ enigma.parse_args = function (raw)
+ local args = lpegmatch(p_args, raw)
+ for k, v in next, args do
+ local f = sanitizers[k]
+ if f then
+ args[k] = f(v)
+ else
+ -- OPTIONAL be fascist and permit only predefined args
+ args[k] = v
+ end
+ end
+ return args
+ end
+--[[ichd--
+\startparagraph
+If the machine setting lacks key settings then we’ll go ahead and ask
+\reference[listing:ask_for_day_key]{}%
+the user directly, hence the function \luafunction{ask_for_day_key}.
+We abort after three misses lest we annoy the user \dots
+\stopparagraph
+--ichd]]--
+ local max_tries = 3
+ ask_for_day_key = function (name, old, try)
+ if try == max_tries then
+ iowrite[[
+Aborting. Entered invalid key three times.
+]]
+ os.exit()
+ end
+ if old then
+ emit(0, key_invalid)
+ end
+ emit(0, polite_key_request, name)
+ local result = ioread()
+ iowrite("\n")
+ return alphanum_or_space(result) or
+ ask_for_day_key(name, (try and try + 1 or 1))
+ end
+end
+
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+--[[ichd--
+\startdocsection[title=Callback]
+\startparagraph
+This is the interface to \TEX. We generate a new callback handler for
+each defined Enigma machine. \CONTEXT\ delivers the head as third
+argument of a callback only (...‽), so we’ll have to do some variable
+shuffling on the function side.
+\stopparagraph
+
+\startparagraph
+When grouping output into the traditional blocks of five letters we
+insert space nodes. As their properties depend on the font we need to
+recreate the space item for every paragraph. Also, as \CONTEXT\ does
+not preload a font we lack access to font metrics before
+\type{\starttext}. Thus creating the space earlier will result in an
+error.
+The function \luafunction{generate_space} will be called inside the
+callback in order to get an appropriate space glue.
+\stopparagraph
+--ichd]]--
+
+local generate_space = function ( )
+ local current_fontparms = font.getfont(font.current()).parameters
+ local space_node = nodenew(GLUE_NODE)
+ space_node.spec = nodenew(GLUE_SPEC_NODE)
+ space_node.spec.width = current_fontparms.space
+ space_node.spec.shrink = current_fontparms.space_shrink
+ space_node.spec.stretch = current_fontparms.space_stretch
+ return space_node
+end
+
+--[[ichd--
+\startparagraph
+\useURL[khaled_hosny_texsx] [http://tex.stackexchange.com/a/11970]
+ [] [tex.sx]
+Registering a callback (“node attribute”?, “node task”?, “task
+action”?) in \CONTEXT\ is not straightforward, let alone documented.
+The trick is to create, install and register a handler first in order
+to use it later on \dots\ many thanks to Khaled Hosny, who posted an
+answer to \from[khaled_hosny_texsx].
+\stopparagraph
+--ichd]]--
+
+local new_callback = function (machine, name)
+ enigma.machines [name] = machine
+ local format_is_context = format_is_context
+ local current_space_node
+ local mod_5 = 0
+
+ --- First we need to choose an insertion method. If autospacing is
+ --- requested, a space will have to be inserted every five
+ --- characters. The rationale behind using differend functions to
+ --- implement each method is that it should be faster than branching
+ --- for each character.
+ local insert_encoded
+
+ if machine.spacing then -- auto-group output
+ insert_encoded = function (head, n, replacement)
+ local insert_glyph = nodecopy(n)
+ if replacement then -- inefficient but bulletproof
+ insert_glyph.char = utf8byte(replacement)
+ --print(utf8char(n.char), "=>", utf8char(insertion.char))
+ end
+ --- if we insert a space we need to return the
+ --- glyph node in order to track positions when
+ --- replacing multiple nodes at once (e.g. ligatures)
+ local insertion = insert_glyph
+ mod_5 = mod_5 + 1
+ if mod_5 > 5 then
+ mod_5 = 1
+ insertion = nodecopy(current_space_node)
+ insertion.next, insert_glyph.prev = insert_glyph, insertion
+ end
+ if head == n then --> replace head
+ local succ = head.next
+ if succ then
+ insert_glyph.next, succ.prev = succ, insert_glyph
+ end
+ head = insertion
+ else --> replace n
+ local pred, succ = n.prev, n.next
+ pred.next, insertion.prev = insertion, pred
+ if succ then
+ insert_glyph.next, succ.prev = succ, insert_glyph
+ end
+ end
+
+ --- insertion becomes the new head
+ return head, insert_glyph -- so we know where to insert
+ end
+ else
+
+ insert_encoded = function (head, n, replacement)
+ local insertion = nodecopy(n)
+ if replacement then
+ insertion.char = utf8byte(replacement)
+ end
+ if head == n then
+ local succ = head.next
+ if succ then
+ insertion.next, succ.prev = succ, insertion
+ end
+ head = insertion
+ else
+ nodeinsert_before(head, n, insertion)
+ noderemove(head, n)
+ end
+ return head, insertion
+ end
+ end
+
+ --- The callback proper starts here.
+ local aux aux = function (head, recurse)
+ if recurse == nil then recurse = 0 end
+ for n in nodetraverse(head) do
+ local nid = n.id
+ --print(utf8char(n.char), n)
+ if nid == GLYPH_NODE then
+ local chr = utf8char(n.char)
+ --print(chr, n)
+ local replacement = machine:encode(chr)
+ --print(chr, replacement, n)
+ local treplacement = replacement and type(replacement)
+ --if replacement == false then
+ if not replacement then
+ noderemove(head, n)
+ elseif treplacement == "string" then
+ --print(head, n, replacement)
+ head, _ = insert_encoded(head, n, replacement)
+ elseif treplacement == "table" then
+ local current = n
+ for i=1, #replacement do
+ head, current = insert_encoded(head, current, replacement[i])
+ end
+ end
+ elseif nid == GLUE_NODE then
+ if n.subtype ~= 15 then -- keeping the parfillskip
+ noderemove(head, n)
+ end
+ elseif IGNORE_NODES[nid] then
+ -- drop spaces and kerns
+ noderemove(head, n)
+ elseif nid == DISC_NODE then
+ --- ligatures need to be resolved if they are characters
+ local npre, npost = n.pre, n.post
+ if nodeid(npre) == GLYPH_NODE and
+ nodeid(npost) == GLYPH_NODE then
+ if npre.char and npost.char then -- ligature between glyphs
+ local replacement_pre = machine:encode(utf8char(npre.char))
+ local replacement_post = machine:encode(utf8char(npost.char))
+ insert_encoded(head, npre, replacement_pre)
+ insert_encoded(head, npost, replacement_post)
+ else -- hlists or whatever
+ -- pass
+ --noderemove(head, npre)
+ --noderemove(head, npost)
+ end
+ end
+ noderemove(head, n)
+ elseif nid == HLIST_NODE or nid == VLIST_NODE then
+ if nodelength(n.list) > 0 then
+ n.list = aux(n.list, recurse + 1)
+ end
+-- else
+-- -- TODO other node types
+-- print(n)
+ end
+ end
+ nodeslide(head)
+ return head
+ end -- callback auxiliary
+
+ --- Context requires
+ --- × argument shuffling; a properly registered “action” gets the
+ --- head passed as its third argument
+ --- × hacking our way around the coupling of pre_linebreak_filter
+ --- and hpack_filter; background:
+ --- http://www.ntg.nl/pipermail/ntg-context/2012/067779.html
+ local cbk = function (a, _, c)
+ local head
+ current_space_node = generate_space ()
+ mod_5 = 0
+ if format_is_context == true then
+ head = c
+ local cbk_env = get_debug_info(4) -- no getenv in lua 5.2
+ --inspect(cbk_env)
+ if cbk_env.func == nodes.processors.pre_linebreak_filter then
+ -- how weird is that?
+ return aux(head)
+ end
+ return head
+ end
+ head = a
+ return aux(head)
+ end
+
+ if format_is_context then
+ local cbk_id = "enigma_" .. name
+ enigma.callbacks[name] = nodesinstallattributehandler{
+ name = cbk_id,
+ namespace = thirddata.enigma,
+ processor = cbk,
+ }
+ local cbk_location = "thirddata.enigma.callbacks." .. name
+ nodestasksappendaction("processors",
+ --"characters",
+ --"finalizers",
+ --- this one is tagged “for users”
+ --- (cf. node-tsk.lua)
+ "before",
+ cbk_location)
+ nodestasksdisableaction("processors", cbk_location)
+ else
+ enigma.callbacks[name] = cbk
+ end
+end
+
+--[[ichd--
+\startparagraph
+Enigma\reference[listing:retrieve]{} machines can be copied and derived
+from one another at will, cf. the \texmacro{defineenigma} on
+\at{page}[listing:define]. Two helper functions residing inside the
+\identifier{thirddata.enigma} namespace take care of these actions:
+\luafunction{save_raw_args} and \luafunction{retrieve_raw_args}. As
+soon as a machine is defined, we store its parsed options inside the
+table \identifier{configurations} for later reference. For further
+details on the machine derivation mechanism see
+\at{page}[listing:inherit].
+\stopparagraph
+--ichd]]--
+local configurations = { }
+
+local save_raw_args = function (conf, name)
+ local current = configurations[name] or { }
+ for k, v in next, conf do
+ current[k] = v
+ end
+ configurations[name] = current
+end
+
+local retrieve_raw_args = function (name)
+ local cn = configurations[name]
+ return cn and tablecopy(cn) or { }
+end
+
+enigma.save_raw_args = save_raw_args
+enigma.retrieve_raw_args = retrieve_raw_args
+
+
+--[[ichd--
+\startparagraph
+The function \luafunction{new_machine} instantiates a table containing
+the complete specification of a workable \emph{Enigma} machine and
+other metadata. The result is intended to be handed over to the
+callback creation mechanism (\luafunction{new_callback}). However, the
+arguments table is usally stored away in the
+\identifier{thirddata.enigma} namespace anyway
+(\luafunction{save_raw_args}), so that the specification of any machine
+can be inherited by some new setup later on.
+\stopparagraph
+--ichd]]--
+local new_machine = function (name)
+ local args = configurations[name]
+ --table.print(configurations)
+ verbose_level = args and args.verbose or verbose_level
+ local machine = new(name, args)
+ return machine
+end
+
+enigma.new_machine = new_machine
+enigma.new_callback = new_callback
+
+--[[ichd--
+\stopdocsection
+--ichd]]--
+
+-- vim:ft=lua:sw=2:ts=2:tw=71:expandtab
diff --git a/Master/texmf-dist/tex/latex/enigma/enigma.sty b/Master/texmf-dist/tex/latex/enigma/enigma.sty
new file mode 100644
index 00000000000..07bb8e78c93
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/enigma/enigma.sty
@@ -0,0 +1,7 @@
+\ProvidesPackage
+ {enigma}
+ [2013/03/28 Enigma Document Encryption]
+\RequirePackage{luatexbase}
+\input{enigma}
+\endinput
+% vim:ft=tex:sw=2:ts=2:expandtab:tw=71
diff --git a/Master/texmf-dist/tex/plain/enigma/enigma.tex b/Master/texmf-dist/tex/plain/enigma/enigma.tex
new file mode 100644
index 00000000000..d18b72ffa18
--- /dev/null
+++ b/Master/texmf-dist/tex/plain/enigma/enigma.tex
@@ -0,0 +1,130 @@
+\newif\ifenigmaisrunningplain
+\ifcsname ver@enigma.sty\endcsname\else
+ \enigmaisrunningplaintrue
+ \input{luatexbase.sty}
+ \catcode`\@=11
+% \else latex
+\fi
+\catcode`\_=11 % There’s no reason why this shouldn’t be the case.
+\catcode`\!=11
+%D Nice tool from luat-ini.mkiv. This really helps with those annoying
+%D string separators of Lua’s that clutter the source.
+% this permits \typefile{self} otherwise nested b/e sep problems
+\def\luastringsep{===}
+\edef\!!bs{[\luastringsep[}
+\edef\!!es{]\luastringsep]}
+%D \startdocsection[title=Prerequisites]
+%D \startparagraph
+%D Package loading and the namespacing issue are commented on in
+%D \identifier{enigma.lua}.
+%D \stopparagraph
+\directlua{
+ packagedata = packagedata or { }
+ dofile(kpse.find_file\!!bs enigma.lua\!!es)
+}
+
+%D \startparagraph
+%D First, create somthing like \CONTEXT’s asciimode. We found
+%D \texmacro{newluatexcatcodetable} in \identifier{luacode.sty} and it
+%D seems to get the job done.
+%D \stopparagraph
+\newluatexcatcodetable \enigmasetupcatcodes
+\bgroup
+ \def\escapecatcode {0}
+ \def\begingroupcatcode {1}
+ \def\endgroupcatcode {2}
+ \def\spacecatcode {10}
+ \def\lettercatcode {11}
+ \setluatexcatcodetable\enigmasetupcatcodes {
+ \catcode`\^^I = \spacecatcode % tab
+ \catcode`\ = \spacecatcode
+ \catcode`\{ = \begingroupcatcode
+ \catcode`\} = \endgroupcatcode
+ \catcode`\^^L = \lettercatcode % form feed
+ \catcode`\^^M = \lettercatcode % eol
+ }
+\egroup
+%D \stopdocsection
+
+%D \startdocsection[title=Setups]
+%D \startparagraph
+%D Once the proper catcodes are in place, the setup macro
+%D \texmacro{do_setup_enigma} doesn’t to anything besides passing stuff
+%D through to Lua.
+%D \stopparagraph
+\def\do_setup_enigma#1{%
+ \directlua{
+ local enigma = packagedata.enigma
+ local current_args = enigma.parse_args(\!!bs\detokenize{#1}\!!es)
+ enigma.save_raw_args(current_args, \!!bs\current_enigma_id\!!es)
+ enigma.new_callback(
+ enigma.new_machine(\!!bs\current_enigma_id\!!es),
+ \!!bs\current_enigma_id\!!es)
+ }%
+ \egroup%
+}
+
+%D The module setup \texmacro{setupenigma} expects key=value, notation.
+%D All the logic is at the Lua end, not much to see here …
+\def\setupenigma#1{%
+ \bgroup
+ \edef\current_enigma_id{#1}
+ \luatexcatcodetable \enigmasetupcatcodes
+ \do_setup_enigma%
+}
+%D \stopdocsection
+
+%D \startdocsection[title=Encoding Macros]
+%D \startparagraph
+%D The environment of \texmacro{begin<enigmaid>} and
+%D \texmacro{end<enigmaid>} toggles Enigma encoding.
+%D (Regarding environment delimiters we adhere to Knuth’s
+%D practice of prefixing with \type{begin}/\type{end}.)
+%D \stopparagraph
+
+\def\e!start{begin} %{start}
+\def \e!stop{end} %{stop}
+\edef\c!pre_linebreak_filter{pre_linebreak_filter}
+\def\do_define_enigma#1{%
+ \@EA\gdef\csname \e!start\current_enigma_id\endcsname{%
+ \endgraf
+ \bgroup%
+ \directlua{%
+ if packagedata.enigma and
+ packagedata.enigma.machines[ \!!bs#1\!!es] then
+ luatexbase.add_to_callback(
+ \!!bs\c!pre_linebreak_filter\!!es,
+ packagedata.enigma.callbacks[ \!!bs#1\!!es],
+ \!!bs#1\!!es)
+ else
+ print\!!bs ENIGMA: No machine of that name: #1!\!!es
+ os.exit()
+ end
+ }%
+ }%
+ \@EA\gdef\csname \e!stop\current_enigma_id\endcsname{%
+ \endgraf
+ \directlua{
+ luatexbase.remove_from_callback(
+ \!!bs\c!pre_linebreak_filter\!!es,
+ \!!bs#1\!!es)
+ packagedata.enigma.machines[ \!!bs#1\!!es]:processed_chars()
+ }%
+ \egroup%
+ }%
+}
+
+\def\defineenigma#1{%
+ \begingroup
+ \let\@EA\expandafter
+ \edef\current_enigma_id{#1}%
+ \@EA\do_define_enigma\@EA{\current_enigma_id}%
+ \endgroup%
+}
+
+%D \stopdocsection
+
+\catcode`\_=8 % \popcatcodes
+\catcode`\!=12 % reserved according to source2e
+\ifenigmaisrunningplain\catcode`\@=12\fi
+% vim:ft=plaintex:sw=2:ts=2:expandtab:tw=71
diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check
index 997b01cf0d1..0ae75a8ae2d 100755
--- a/Master/tlpkg/bin/tlpkg-ctan-check
+++ b/Master/tlpkg/bin/tlpkg-ctan-check
@@ -152,7 +152,8 @@ my @TLP_working = qw(
elteikthesis eltex elvish
emarks embrac emptypage emulateapj emp
encxvlna endfloat endheads endiagram endnotes
- engpron engrec engtlc enotez enumitem enumitem-zref envbig environ envlab
+ engpron engrec engtlc enigma enotez
+ enumitem enumitem-zref envbig environ envlab
epigrafica epigram epigraph epiolmec eplain
epsdice epsf epsincl epslatex-fr epspdf epspdfconversion epstopdf
eqell eqlist eqname eqnarray eqparbox errata es-tex-faq
diff --git a/Master/tlpkg/libexec/ctan2tds b/Master/tlpkg/libexec/ctan2tds
index 519d2a9911d..5e990a5624e 100755
--- a/Master/tlpkg/libexec/ctan2tds
+++ b/Master/tlpkg/libexec/ctan2tds
@@ -100,7 +100,7 @@ chomp ($Build = `cd $Master/../Build/source && pwd`);
'analogclock', "die 'skipping, requires system font installation",
'annot_pro', "die 'skipping, per author (dps) request'",
'ans', "die 'skipping, LaTeX 2.09'",
- 'ant-worker-tasks', "die 'skipping, Java'",
+ 'ant-worker-tasks', "die 'skipping, Java'",
'antomega', "die 'skipping, not ready'", #"&MAKEflatten",
'antp', "die 'skipping, use poltawski'",
'antt', "&MAKEcopy",
@@ -110,6 +110,8 @@ chomp ($Build = `cd $Master/../Build/source && pwd`);
'ar', "die 'skipping, use aspectratio'",
'arabi', "&MAKEarabi",
'arabtex', "&MAKEarabtex",
+ 'aramaic', "die 'skipping, use archaic'",
+ 'aramaic-serto', "&MAKEflatten",
'arbeit', "die 'skipping, latex 2.09 and never in tl'",
'archaic', "&MAKEwilson",
'arev', "&MAKEcopy",
@@ -1114,6 +1116,7 @@ chomp ($Build = `cd $Master/../Build/source && pwd`);
'dehyph-exptl' => '&POSTdehyph_exptl',
'doipubmed' => '&POSTlatex2html',
'download' => '&POST_savepdf',
+ 'enigma' => '&POSTenigma',
'eplain' => '&POSTeplain',
'epspdf' => '&POSTepspdf',
'fixme' => '&POSTfixme',
@@ -1324,6 +1327,7 @@ $standardtex='\.(.bx|cfg|sty|clo|ldf|cls|def|fd|cmap|4ht)$';
'einfuehrung', 'NULL', # doc package
'eltex', 'eltex.*tex',
'elsarticle', 'elsarticle.cls', # no rvdtx, pdfwidgets
+ 'enigma', 'NULL',
'epigram', 'epigram.tex',
'epsf', 'epsf.(tex|sty)',
'epslatex-fr', 'NULL',
@@ -5140,6 +5144,30 @@ sub POSTdehyph_exptl {
print "POST$package - *YOU* must update tlpsrc directives, right now!\n";
}
+sub POSTenigma {
+ print "POST$package - move everything per README\n";
+ #
+ &mv_with_mkdir ("mtx-t-enigma.lua",
+ "$DEST/scripts/context/lua/third/enigma/mtx-t-enigma.lua/");
+ &mv_with_mkdir ("t-enigma.mkvi",
+ "$DEST/tex/context/third/enigma/t-enigma.mkv/");
+ &mv_with_mkdir ("enigma.sty", "$DEST/tex/latex/enigma/");
+ &mv_with_mkdir ("enigma.tex", "$DEST/tex/plain/enigma/");
+ &mv_with_mkdir ("enigma.lua", "$DEST/tex/generic/enigma/");
+ #
+ &mv_with_mkdir ("enigma-example*", "examples/");
+ #
+ &xchdir ("..");
+ &mv_with_mkdir ("enigma", "$DEST/doc/context/third/enigma/");
+}
+
+sub mv_with_mkdir {
+ my @args = @_;
+ my $destdir = pop (@args);
+ &xmkdir ($destdir);
+ &SYSTEM ("$MV @args $destdir");
+}
+
sub POSTeplain {
print "POST$package - eplain.info, man\n";
diff --git a/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc b/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
index db54305b491..f2b6af1907d 100644
--- a/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc
@@ -7,6 +7,7 @@ depend collection-basic
#
depend checkcites
depend chickenize
+depend enigma
depend interpreter
depend lua-check-hyphen
depend lua-visual-debug
diff --git a/Master/tlpkg/tlpsrc/enigma.tlpsrc b/Master/tlpkg/tlpsrc/enigma.tlpsrc
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/enigma.tlpsrc