Mercurial > public > enigma
changeset 7:39297f695cff
First version of EnigmaMachine class. Simple main to test operations.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Sat, 26 May 2012 17:21:22 -0500 |
parents | 7a90beffd8f2 |
children | 19f6859a3d19 |
files | enigma/__init__.py enigma/machine.py enigma/main.py enigma/rotors/factory.py enigma/rotors/rotor.py |
diffstat | 5 files changed, 141 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/enigma/__init__.py Sat May 26 15:19:48 2012 -0500 +++ b/enigma/__init__.py Sat May 26 17:21:22 2012 -0500 @@ -0,0 +1,13 @@ +# Copyright (C) 2012 by Brian Neal. +# This file is part of Py-Enigma, the Enigma Machine simulation. +# Py-Enigma is released under the MIT License (see License.txt). + +"""This package is a simulation of the wartime Enigma Machines used by the +German military branches. These include the army (Wehrmacht), air force +(Luftwaffe), and navy (Kriegsmarine). For our purposes, the Wehrmacht and +Luftwaffe versions are identical. The Kriegsmarine models M3 and M4 can be +simulated by configuring an EnigmaMachine object with the suitable rotors. + +For a list of the rotors and reflectors we simulate, see the module rotors.data. + +"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/enigma/machine.py Sat May 26 17:21:22 2012 -0500 @@ -0,0 +1,89 @@ +# Copyright (C) 2012 by Brian Neal. +# This file is part of Py-Enigma, the Enigma Machine simulation. +# Py-Enigma is released under the MIT License (see License.txt). + +"""This module contains the top-level EnigmaMachine class for the Enigma Machine +simulation. + +""" +import string + +class EnigmaError(Exception): + pass + + +class EnigmaMachine: + """Top-level class for the Enigma Machine simulation.""" + + def __init__(self, rotors, reflector): + """Configures the Enigma Machine. Parameters are as follows: + + rotors - a list containing 3 or 4 (for the Kriegsmarine M4 version) + 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). + + reflector - a rotor object to represent the reflector + + Note that on the military Enigma machines we are simulating, the entry + wheel is a simple straight-pass through and is not simulated here. It + would not be too hard to add a parameter for the entry wheel and pass a + Rotor object for it if it is desired to simulate a non-military Enigma + machine. + + """ + if len(rotors) not in [3, 4]: + raise EnigmaError("Must supply 3 or 4 rotors") + + self.rotors = rotors + self.rotor_count = len(rotors) + self.reflector = reflector + + + def set_display(self, val): + + for i, rotor in enumerate(self.rotors): + self.rotors[i].set_display(val[i]) + + + def cipher(self, plaintext): + + # TODO: This is just placeholder code until I can figure out what I am + # doing...! + + if len(plaintext) != 1: + raise EnigmaError("not implemented yet") + if plaintext[0] not in string.ascii_uppercase: + raise EnigmaError("invalid input: %s" % plaintext) + + x = ord(plaintext[0]) - ord('A') + + x = self.rotors[-1].signal_in(x) + print(chr(x + ord('A'))) + x = self.rotors[-2].signal_in(x) + print(chr(x + ord('A'))) + x = self.rotors[-3].signal_in(x) + print(chr(x + ord('A'))) + + if self.rotor_count == 4: + x = self.rotors[-4].signal_in(x) + print(chr(x + ord('A'))) + + x = self.reflector.signal_in(x) + print(chr(x + ord('A'))) + + x = self.rotors[0].signal_out(x) + print(chr(x + ord('A'))) + x = self.rotors[1].signal_out(x) + print(chr(x + ord('A'))) + x = self.rotors[2].signal_out(x) + print(chr(x + ord('A'))) + + if self.rotor_count == 4: + x = self.rotors[3].signal_out(x) + print(chr(x + ord('A'))) + + ciphertext = chr(x + ord('A')) + + print("%s => %s" % (plaintext, ciphertext)) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/enigma/main.py Sat May 26 17:21:22 2012 -0500 @@ -0,0 +1,34 @@ +# Copyright (C) 2012 by Brian Neal. +# This file is part of Py-Enigma, the Enigma Machine simulation. +# Py-Enigma is released under the MIT License (see License.txt). + + +from rotors.factory import create_rotor +from rotors.factory import create_reflector +from machine import EnigmaMachine + +def main(): + + rotors = [] + rotors.append(create_rotor('I')) + rotors.append(create_rotor('II')) + rotors.append(create_rotor('III')) + + reflector = create_reflector('B') + + machine = EnigmaMachine(rotors=rotors, reflector=reflector) + + machine.set_display('AAB') + machine.cipher('A') + machine.set_display('AAC') + machine.cipher('A') + machine.set_display('AAD') + machine.cipher('A') + machine.set_display('AAE') + machine.cipher('A') + machine.set_display('AAF') + machine.cipher('A') + + +if __name__ == '__main__': + main()
--- a/enigma/rotors/factory.py Sat May 26 15:19:48 2012 -0500 +++ b/enigma/rotors/factory.py Sat May 26 17:21:22 2012 -0500 @@ -4,12 +4,12 @@ """Contains factory functions for creating rotors and reflectors.""" -from enigma.rotors import RotorError -from enigma.rotors.rotor import Rotor -from enigma.rotors.data import ROTORS, REFLECTORS +from . import RotorError +from .rotor import Rotor +from .data import ROTORS, REFLECTORS -def create_rotor(model, ring_setting, alpha_labels=True): +def create_rotor(model, ring_setting=0, alpha_labels=True): """Factory function to create and return a rotor of the given model name.""" if model in ROTORS:
--- a/enigma/rotors/rotor.py Sat May 26 15:19:48 2012 -0500 +++ b/enigma/rotors/rotor.py Sat May 26 17:21:22 2012 -0500 @@ -96,7 +96,7 @@ self.wiring_str = wiring.upper() self.ring_setting = ring_setting self.alpha_labels = alpha_labels - self.pos = None # not installed in an Enigma machine yet + self.pos = 0 # check wiring length if len(self.wiring_str) != 26: