# HG changeset patch # User Brian Neal # Date 1338694362 18000 # Node ID 4a9c4d3ced135928aedf0c0c94d36183e9648c0c # Parent b01f1bb3ad579263c870ac9593e87d8c446ce473 More documentation work. diff -r b01f1bb3ad57 -r 4a9c4d3ced13 enigma/docs/source/guide.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/enigma/docs/source/guide.rst Sat Jun 02 22:32:42 2012 -0500 @@ -0,0 +1,2 @@ +User's guide +============ diff -r b01f1bb3ad57 -r 4a9c4d3ced13 enigma/docs/source/index.rst --- a/enigma/docs/source/index.rst Fri Jun 01 23:10:17 2012 -0500 +++ b/enigma/docs/source/index.rst Sat Jun 02 22:32:42 2012 -0500 @@ -21,10 +21,11 @@ Documentation contents: .. toctree:: - :maxdepth: 2 + :maxdepth: 3 overview - library + guide + reference pyenigma keyfile diff -r b01f1bb3ad57 -r 4a9c4d3ced13 enigma/docs/source/library.rst --- a/enigma/docs/source/library.rst Fri Jun 01 23:10:17 2012 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -Library Documentation -===================== - -The Py-Enigma simulation is made up of several Python classes as described -below. - -EnigmaMachine Class Reference ------------------------------ - -The top-level ``EnigmaMachine`` class represents an assembled Enigma machine. -The ``EnigmaMachine`` class resides in the ``enigma.machine`` module. - -.. class:: enigma.machine.EnigmaMachine(rotors, reflector, plugboard) - - Top-level class that represents Enigma machines. - - :param rotors: A list containing 3 or 4 (for the Kriegsmarine M4 version) - :class:`Rotor ` objects. The order of the - list is important. The first rotor is the left-most rotor, and the last - rotor is the right-most (from the operator's perspective sitting at the - machine). - :param reflector: A :class:`Rotor ` object that - represents the reflector (*UKW*). - :param plugboard: A :class:`Plugboard ` object - that represents the state of the plugboard (*Steckerbrett*). - - .. classmethod:: from_key_sheet([rotors='I II III'[, ring_settings=None[, \ - reflector='B'[, plugboard_settings=None]]]]) - - Convenience function to build an EnigmaMachine from the data as you - might find it on a monthly key sheet (code book). - - :param rotors: Either a list of strings naming the rotors from left to - right or a single string: e.g. ``["I", "III", "IV"]`` or ``"I III IV"``. - :param ring_settings: Either a list/tuple of integers, a string, or ``None`` - to represent the ring settings to be applied to the rotors in the - rotors list (see below). - :param reflector: A string that names the reflector to use. - :param plugboard_settings: A string of plugboard settings as you might - find on a key sheet (see below). - - The ``ring_settings`` parameter can accept either: - - * A list/tuple of integers with values between 0-25. - * A string; either space separated letters or numbers, e.g. - ``'B U L'`` or ``'1 20 11'``. - * ``None`` means all ring settings are 0. - - The ``plugboard_settings`` parameter can accept either: - - * A string of space separated letter pairs; e.g. ``'PO ML IU KJ NH YT GB VF RE DC'``. - * A string of slash separated number pairs; e.g. ``'18/26 17/4 21/6 3/16 19/14 22/7 8/1 12/25 5/9 10/15'``. - * A value of ``None`` means no plugboard connections are made. - - .. classmethod:: from_key_file(fp[, day=None]) - - Convenience function to build an EnigmaMachine by reading key parameters - from a file. - - :param fp: A file-like object that contains daily key settings, one day's - settings per line. - :param day: The line in the file labeled with the day number (1-31) will - be used for the settings. If day is ``None``, the day number will be - determined from today's date. - - For more information on the file format, see :doc:`Key File Format `. - - .. method:: set_display(val) - - Sets the simulated rotor operator windows to *val*. This establishes a new - starting position for a subsequent encrypt or decrypt operation. See also - :meth:`get_display`. - - :param val: Must be a string or iterable containing uppercase letter values, one - for each window from left to right. For example, a valid value for a 3 rotor - machine would be ``'ABC'``. - - .. method:: get_display(val) - - This method returns the current position of the rotors as a string. See - also :meth:`set_display`. - - :returns: a string of uppercase letters, one for each rotor - :rtype: string - -.. class:: enigma.rotors.rotor.Rotor(x, y) - - Rotor class diff -r b01f1bb3ad57 -r 4a9c4d3ced13 enigma/docs/source/reference.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/enigma/docs/source/reference.rst Sat Jun 02 22:32:42 2012 -0500 @@ -0,0 +1,369 @@ +Reference manual +================ + +The Py-Enigma simulation is made up of several Python classes as described +below. + +EnigmaMachines +-------------- + +The ``EnigmaMachine`` class represents an assembled Enigma machine that consists +of rotors, a plugboard, a keyboard, and indicator lamps. + + +EnigmaMachine class reference +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The top-level ``EnigmaMachine`` class represents an assembled Enigma machine. +The ``EnigmaMachine`` class resides in the ``enigma.machine`` module. + +.. class:: enigma.machine.EnigmaMachine(rotors, reflector, plugboard) + + Top-level class that represents Enigma machines. + + :param rotors: A list containing 3 or 4 (for the Kriegsmarine M4 version) + :class:`Rotor ` objects. The order of the + list is important. The first rotor is the left-most rotor, and the last + rotor is the right-most (from the operator's perspective sitting at the + machine). + + :param reflector: A :class:`Rotor ` object that + represents the reflector (*UKW*). + + :param plugboard: A :class:`Plugboard ` object + that represents the state of the plugboard (*Steckerbrett*). + + .. classmethod:: from_key_sheet([rotors='I II III'[, ring_settings=None[, \ + reflector='B'[, plugboard_settings=None]]]]) + + Convenience function to build an EnigmaMachine from the data as you + might find it on a monthly key sheet (code book). + + :param rotors: Either a list of strings naming the rotors from left to + right or a single string: e.g. ``["I", "III", "IV"]`` or ``"I III IV"``. + + :param ring_settings: Either a list/tuple of integers, a string, or ``None`` + to represent the ring settings to be applied to the rotors in the + rotors list (see below). + + :param reflector: A string that names the reflector to use. + + :param plugboard_settings: A string of plugboard settings as you might + find on a key sheet (see below). + + The ``ring_settings`` parameter can accept either: + + * A list/tuple of integers with values between 0-25. + * A string; either space separated letters or numbers, e.g. + ``'B U L'`` or ``'1 20 11'``. + * ``None`` means all ring settings are 0. + + The ``plugboard_settings`` parameter can accept either: + + * A string of space separated letter pairs; e.g. ``'PO ML IU KJ NH YT GB VF RE DC'``. + * A string of slash separated number pairs; e.g. ``'18/26 17/4 21/6 3/16 19/14 22/7 8/1 12/25 5/9 10/15'``. + * A value of ``None`` means no plugboard connections are made. + + .. classmethod:: from_key_file(fp[, day=None]) + + Convenience function to build an EnigmaMachine by reading key parameters + from a file. + + :param fp: A file-like object that contains daily key settings, one day's + settings per line. + + :param day: The line in the file labeled with the day number (1-31) will + be used for the settings. If day is ``None``, the day number will be + determined from today's date. + + For more information on the file format, see :doc:`Key File Format `. + + .. method:: set_display(val) + + Sets the simulated rotor operator windows to *val*. This establishes a new + starting position for a subsequent encrypt or decrypt operation. See also + :meth:`get_display`. + + :param val: Must be a string or iterable containing uppercase letter values, one + for each window from left to right. For example, a valid value for a 3 rotor + machine would be ``'ABC'``. + + .. method:: get_display(val) + + This method returns the current position of the rotors as a string. See + also :meth:`set_display`. + + :returns: a string of uppercase letters, one for each rotor (left to + right) + :rtype: string + + .. method:: key_press(key) + + Simulate a front panel key press. First the rotors are stepped by + simulating the mechanical action of the machine. Next a simulated current + is run through the machine. The lamp that is lit by this key press is + returned as a string (a single uppercase letter A-Z). + + :param key: the letter pressed (A-Z) + :type key: string + :returns: the lamp that is lit (A-Z) + :rtype: string + + .. method:: process_text(text[, replace_char='X']) + + This is a convenience function for processing a string of text. For each + character in the input text, :meth:`key_press` is called. The output text + is returned as a string. + + This function performs some pre-processing of the input text, unlike + :meth:`key_press`. First, all input is converted to uppercase. Secondly, + the parameter ``replace_char`` controls what is done to input characters + that are not ``A-Z``. If the input text contains a character not on the + keyboard, it is replaced with ``replace_char``. If ``replace_char`` is + ``None`` the character is dropped from the input. ``replace_char`` + defaults to ``X``. + + :param string text: the text to process + :param replace_char: invalid input is replaced with this string or dropped + if it is ``None`` + + +EnigmaMachine exceptions +~~~~~~~~~~~~~~~~~~~~~~~~ + +:class:`EnigmaMachine ` operations may raise +``enigma.machine.EnigmaError`` under error conditions. The two ``classmethod`` +constructors, :meth:`from_key_sheet ` +and :meth:`from_key_file ` assemble +an :class:`EnigmaMachine ` from parts, and those +parts may raise these exceptions themselves: + +* ``rotor.rotors.RotorError`` +* ``plugboard.PlugboardError`` + + +Rotors & Reflectors +------------------- + +The ``Rotor`` class represents the Enigma rotors, also known as the wheels or +*Walzen* in German. They are the most important parts of the machine. + +Rotors have little use on their own. They are placed inside an :class:`EnigmaMachine +` object, which then calls the public ``Rotor`` +methods. + +Rotor class reference +~~~~~~~~~~~~~~~~~~~~~ + +.. class:: enigma.rotors.rotor.Rotor(model_name, wiring[, ring_setting=0[, stepping=None]]) + + A rotor has 26 circularly arranged pins on the right (entry) side and 26 + contacts on the left side. Each pin is connected to a single contact by + internal wiring, thus establishing a substitution cipher. We represent this + wiring by establishing a mapping from a pin to a contact (and vice versa for + the return path). Internally we number the pins and contacts from 0-25 in a + clockwise manner with 0 being the "top". + + An alphabetic or numeric ring is fastened to the rotor by the operator. The + labels of this ring are displayed to the operator through a small window on + the top panel. The ring can be fixed to the rotor in one of 26 different + positions; this is called the ring setting (*Ringstellung*). We will number + the ring settings from 0-25 where 0 means no offset (e.g. the letter "A" is + mapped to pin 0 on an alphabetic ring). A ring setting of 1 means the letter + "B" is mapped to pin 0. + + Each rotor can be in one of 26 positions on the spindle, with position 0 + where pin/contact 0 is being indicated in the operator window. The rotor + rotates towards the operator by mechanical means during normal operation as + keys are being pressed during data entry. Position 1 is thus defined to be + one step from position 0. Likewise, position 25 is the last position before + another step returns it to position 0, completing 1 trip around the spindle. + + Finally, a rotor has a "stepping" or "turnover" parameter. Physically this + is implemented by putting a notch on the alphabet ring and it controls when + the rotor will "kick" the rotor to its left, causing the neighbor rotor to + rotate. Most rotors had one notch, but some Kriegsmarine rotors had 2 + notches and thus rotated twice as fast. + + Note that we allow the ``stepping`` parameter to be ``None``. This indicates + the rotor does not rotate. This allows us to model the entry wheel and + reflectors as stationary rotors. The fourth rotor on the Kriegsmarine M4 + models (*Beta* or *Gamma*) did not rotate. + + The rotor constructor establishes the rotor characteristics. + + :param string model_name: e.g. "I", "II", "III", "Beta", "Gamma" + + :param string wiring: This should be a string of 26 uppercase characters + A-Z that represent the internal wiring transformation of the signal + as it enters from the right side. This is the format used in various online + resources. For example, for the Wehrmacht Enigma type I rotor the + mapping is ``"EKMFLGDQVZNTOWYHXUSPAIBRCJ"``. + + :param integer ring_setting: This should be an integer from 0-25, inclusive, + which indicates the *Ringstellung*. A value of 0 means there is no offset; e.g. + the letter ``A`` is fixed to pin ``0``. A value of 1 means ``B`` is mapped + to pin ``0``. + + :param stepping: This is the stepping or turnover parameter. When it is an + iterable, for example a string such as "Q", this indicates that when + the rotor transitions from "Q" to "R" (by observing the operator + window), the rotor will "kick" the rotor to its left, causing it to + rotate. If the rotor has more than one notch, a string of length 2 could + be used, e.g. "ZM". Another way to think of this parameter is that when + a character in the stepping string is visible in the operator window, a + notch is lined up with the pawl on the left side of the rotor. This + will allow the pawl to push up on the rotor *and* the rotor to the left + when the next key is depressed. A value of ``None`` means this rotor does + not rotate. + + :raises RotorError: when an invalid parameter is supplied + + Note that for purposes of simulation, our rotors will always use alphabetic + labels A-Z. In reality, the Heer & Luftwaffe devices used numbers 01-26, and + Kriegsmarine devices used A-Z. Our usage of A-Z is simply for simulation + convenience. In the future we may allow either display. + + .. method:: set_display(val) + + Spin the rotor such that the string ``val`` appears in the operator + window. This sets the internal position of the rotor on the axle and thus + rotates the pins and contacts accordingly. + + A value of 'A' for example puts the rotor in position 0, assuming an + internal ring setting of 0. + + :param string val: rotor position which must be in the range ``A-Z`` + :raises RotorError: when an invalid position value is supplied + + .. method:: get_display() + + :returns: current rotor position in the range ``A-Z`` + :rtype: string + + .. method:: signal_in(n) + + Simulate a signal entering the rotor from the right at a given pin + position n. + + :param integer n: pin number between 0 and 25 + :returns: the contact number of the output signal (0-25) + :rtype: integer + + .. method:: signal_out(n) + + Simulate a signal entering the rotor from the left at a given contact + position n. + + :param integer n: contact number between 0 and 25 + :returns: the pin number of the output signal (0-25) + :rtype: integer + + .. method:: notch_over_pawl() + + Returns ``True`` if this rotor has a notch in the stepping position and + ``False`` otherwise. + + :rtype: Boolean + + .. method:: rotate() + + Rotates the rotor forward. + + +A note on the entry wheel and reflectors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The entry wheel (*ETW*) is a special non-movable rotor that sits on the far +right of the rotor array. It connects the rotor array with the plugboard wiring. +On Wehrmacht Enigmas, the entry wheel performs a straight-through mapping. In +other words, the wire from the 'A' key is passed to pin position 0, 'B' to pin +position 1, etc. Thus there is no need to simulate the entry wheel given our +current scope to model only military Enigmas. + +The reflector, or *Umkehrwalze* (UKW), sits at the far left of the rotor array. +It simply reflects the incoming signal coming from the right back through the +left side of the rotors. We can thus model the reflector as a special non-movable +rotor. + +If you decide to create your own reflector, and you desire to maintain +reciprocal encryption & decryption, your connections must be made in pairs. Thus +if you wire 'A' to 'G', you must also wire 'G' to 'A', and so on. + + +Rotor & reflector factory functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +While it is possible to create your own rotor type, for convenience two factory +functions have been created to return rotors and reflectors used by the +Wehrmacht. These factory functions let you refer to the rotors and reflectors by +name instead of providing their internal wiring every time you need one (which +would be both tedious and error prone). + +The following table lists the names of the rotors we currently simulate. + +.. _rotor-table-label: + +.. table:: Simulated rotor models + + +-------------------+------------------------+ + | Rotor names | Enigma Models | + +===================+========================+ + | I, II, III, IV, V | All Wehrmacht models | + +-------------------+------------------------+ + | VI, VII, VIII | Kriegsmarine M3 & M4 | + +-------------------+------------------------+ + | Beta, Gamma | Kriegsmarine M4 | + | | (with thin reflectors) | + +-------------------+------------------------+ + +Any of the names in the first column of the above table can be used by the +factory function :func:`enigma.rotors.factory.create_rotor`, described below. + +Likewise there exists a factory function to create reflectors by name. The +following table lists the names of the supported reflectors. + +.. _reflector-table-label: + +.. table:: Simulated reflector types + + +-------------------+------------------------+ + | Reflector names | Enigma Models | + +===================+========================+ + | B, C | All Wehrmacht models | + +-------------------+------------------------+ + | B-Thin, C-Thin | Kriegsmarine M4 | + | | (with Beta & Gamma | + | | rotors) | + +-------------------+------------------------+ + +The two factory functions are described next: + +.. function:: enigma.rotors.factory.create_rotor(model[, ring_setting=0]) + + Create and return a :class:`Rotor ` object with + the given ring setting. + + :param string model: the model name to create; see the :ref:`rotor-table-label` table + :param integer ring_setting: the ring setting (0-25) to use + :returns: the newly created :class:`Rotor ` + + +.. function:: enigma.rotors.factory.create_reflector(model) + + Create and return a :class:`Rotor ` object that + is meant to be used in the reflector role. + + :param string model: the model name to create; see the :ref:`reflector-table-label` table + :returns: the newly created reflector, which is actually of type + :class:`Rotor ` + + +Rotor exceptions +~~~~~~~~~~~~~~~~ + +:class:`Rotor ` objects may raise +``enigma.rotors.RotorError`` when an invalid constructor argument is given, or +if the rotor object is given an invalid parameter during a :meth:`set_display +` operation. +