Skip to content

Commit

Permalink
release version after restructure
Browse files Browse the repository at this point in the history
  • Loading branch information
artemis-beta committed Jan 13, 2021
1 parent b087e4d commit 46eda45
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 100 deletions.
90 changes: 43 additions & 47 deletions enigma/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ class Enigma:
and simulating either an M3 or M4 variant of the famous WWII cipher
encoding/decoding machine.
"""
def __init__(self, rotor_list: List[int] = None,
user_reflector: str = None,
debug: str = 'ERROR',
enigma_type: str = 'M3') -> None:

def __init__(
self,
rotor_list: List[int] = None,
user_reflector: str = None,
debug: str = "ERROR",
enigma_type: str = "M3",
) -> None:
"""
Enigma Machine Class based on the Enigma Model 3 ciphering machine.
Expand All @@ -45,7 +49,7 @@ def __init__(self, rotor_list: List[int] = None,
debug: 'DEBUG' Set debug level, default is 'ERROR'
"""
self.version = 'v1.2.1'
self.version = "v1.2.1"
self.isBeta = False
self.type = enigma_type.upper()

Expand All @@ -58,13 +62,13 @@ def __init__(self, rotor_list: List[int] = None,
5: rotor.Rotor5(),
6: rotor.Rotor6(),
7: rotor.Rotor7(),
8: rotor.Rotor8()
8: rotor.Rotor8(),
}

# Initialise all reflectors as objects within member dictionary
self._reflector_types = {
'B': reflector.ReflectorB(),
'C': reflector.ReflectorC()
"B": reflector.ReflectorB(),
"C": reflector.ReflectorC(),
}

# Chosen rotor set stored as an ordered dictionary
Expand All @@ -76,7 +80,7 @@ def __init__(self, rotor_list: List[int] = None,
self.logger.setLevel(debug)
logging.basicConfig()

if self.type == 'M3':
if self.type == "M3":
if not rotor_list:
rotor_list = [5, 3, 1]

Expand All @@ -85,11 +89,11 @@ def __init__(self, rotor_list: List[int] = None,
except AssertionError:
raise IndexError("Invalid Rotor List Argument for Enigma M3")

self.rotors['left'] = self._rotor_types[rotor_list[0]]
self.rotors['middle'] = self._rotor_types[rotor_list[1]]
self.rotors['right'] = self._rotor_types[rotor_list[2]]
self.rotors["left"] = self._rotor_types[rotor_list[0]]
self.rotors["middle"] = self._rotor_types[rotor_list[1]]
self.rotors["right"] = self._rotor_types[rotor_list[2]]

elif self.type == 'M4':
elif self.type == "M4":
if not rotor_list:
rotor_list = [5, 3, 1, 2]

Expand All @@ -98,10 +102,10 @@ def __init__(self, rotor_list: List[int] = None,
except AssertionError:
raise IndexError("Invalid Rotor List Argument for Enigma M4")

self.rotors['left'] = self._rotor_types[rotor_list[0]]
self.rotors['middle left'] = self._rotor_types[rotor_list[1]]
self.rotors['middle right'] = self._rotor_types[rotor_list[2]]
self.rotors['right'] = self._rotor_types[rotor_list[3]]
self.rotors["left"] = self._rotor_types[rotor_list[0]]
self.rotors["middle left"] = self._rotor_types[rotor_list[1]]
self.rotors["middle right"] = self._rotor_types[rotor_list[2]]
self.rotors["right"] = self._rotor_types[rotor_list[3]]

else:
TypeError("Unrecognised Enigma type '{}'".format(self.type))
Expand All @@ -110,7 +114,7 @@ def __init__(self, rotor_list: List[int] = None,
self._rotor_dict_keys = tuple(self.rotors.keys())

# Setup the reflector choice
user_reflector = user_reflector if user_reflector else 'B'
user_reflector = user_reflector if user_reflector else "B"
self.reflector = self._reflector_types[user_reflector]

# Setup plugboard
Expand Down Expand Up @@ -150,7 +154,7 @@ def ringstellung(self, name: str, amount: int) -> None:
j,
name,
letter,
self.rotors[name].get_rotor_conversion(letter)
self.rotors[name].get_rotor_conversion(letter),
)

self.rotors[name].rotate_inner_ring()
Expand All @@ -160,7 +164,7 @@ def ringstellung(self, name: str, amount: int) -> None:
j,
name,
letter,
self.rotors[name].get_rotor_conversion(letter)
self.rotors[name].get_rotor_conversion(letter),
)

def _set_rotor(self, name: str, letter: str) -> None:
Expand Down Expand Up @@ -198,7 +202,7 @@ def _get_rotor_conv(self, name: str, letter: str) -> str:
"Rotor %s conversion: %s to %s",
name,
letter,
self.rotors[name].get_rotor_conversion(letter)
self.rotors[name].get_rotor_conversion(letter),
)

return self.rotors[name].get_rotor_conversion(letter)
Expand All @@ -222,13 +226,12 @@ def _get_rotor_conv_inv(self, name: str, letter: str) -> str:
"Rotor %s conversion: %s to %s",
name,
letter,
self.rotors[name].get_rotor_conversion_inv(letter)
self.rotors[name].get_rotor_conversion_inv(letter),
)

return self.rotors[name].get_rotor_conversion_inv(letter)

def _get_inter_rotor_conv(self, name1: str,
name2: str, letter: str) -> str:
def _get_inter_rotor_conv(self, name1: str, name2: str, letter: str) -> str:
"""
Find encoding of a given letter when passed between two rotors.
Expand Down Expand Up @@ -256,23 +259,23 @@ def _get_inter_rotor_conv(self, name1: str,
zero_point_2 = self.rotors[name2].alpha.index(self.rotors[name2].face)

# Offset between the two letter positions of the two rotors
interval = zero_point_2-zero_point_1
interval = zero_point_2 - zero_point_1

# Find the subsequent letter from the second rotor given the index on
# the first taking into account the maximum index of 25
if interval > 0:
i = list(range(26))
n = i[(terminal+interval) % len(i)]
n = i[(terminal + interval) % len(i)]
else:
i = list(range(26))
n = i[(26+terminal+interval) % len(i)]
n = i[(26 + terminal + interval) % len(i)]

self.logger.debug(
"Rotor %s rotor to %s rotor conversion: %s to %s",
name1,
name2,
letter,
self.rotors[name2].alpha[n]
self.rotors[name2].alpha[n],
)

if not self.rotors[name2].alpha[n]:
Expand All @@ -283,8 +286,7 @@ def _get_inter_rotor_conv(self, name1: str,

return self.rotors[name2].alpha[n]

def _get_inter_rotor_conv_inv(self, name1: str, name2: str,
letter: str) -> str:
def _get_inter_rotor_conv_inv(self, name1: str, name2: str, letter: str) -> str:
"""
Find inverse conversion between rotors (same as forward conversion).
Expand Down Expand Up @@ -326,8 +328,8 @@ def type_letter(self, letter: str) -> str:

# TODO not sure what to call this action...
for i, j in zip(
reversed(self._rotor_dict_keys[1:]),
reversed(self._rotor_dict_keys[:-1]),
reversed(self._rotor_dict_keys[1:]),
reversed(self._rotor_dict_keys[:-1]),
):
if self.rotors[i].face in self.rotors[i].notches:
self._move_rotor(j, 1)
Expand All @@ -337,16 +339,12 @@ def type_letter(self, letter: str) -> str:
# Get the rotor conversion for given key
cipher = self._get_rotor_conv(rotor_key, cipher)
# Get the inter rotor conversion for the key and the key-1
adj_rotor_key_index = self._rotor_dict_keys.index(rotor_key)-1
adj_rotor_key_index = self._rotor_dict_keys.index(rotor_key) - 1
# At this point we should be ready for reflection
if adj_rotor_key_index < 0:
break
adj_rotor_key = self._rotor_dict_keys[adj_rotor_key_index]
cipher = self._get_inter_rotor_conv(
rotor_key,
adj_rotor_key,
cipher
)
cipher = self._get_inter_rotor_conv(rotor_key, adj_rotor_key, cipher)
else:
assert False, "Shouldn't get here!"

Expand All @@ -358,12 +356,10 @@ def type_letter(self, letter: str) -> str:
cipher = self._get_rotor_conv_inv(rotor_key, cipher)
try:
# Get the inter rotor conv_inversion for the key and the key-1
adj_rotor_key_index = self._rotor_dict_keys.index(rotor_key)+1
adj_rotor_key_index = self._rotor_dict_keys.index(rotor_key) + 1
adj_rotor_key = self._rotor_dict_keys[adj_rotor_key_index]
cipher = self._get_inter_rotor_conv_inv(
rotor_key,
adj_rotor_key,
cipher
rotor_key, adj_rotor_key, cipher
)
except IndexError:
# At this point we should be ready for reflection
Expand Down Expand Up @@ -410,7 +406,7 @@ def type_phrase(self, phrase: str) -> str:
"""
# Remove spaces from the phrase string
phrase = phrase.replace(' ', '')
phrase = phrase.replace(" ", "")

# Determine how many extra characters are required in order to assemble
# cipher into the expected groups of 5 letters
Expand All @@ -420,15 +416,15 @@ def type_phrase(self, phrase: str) -> str:
for i in range(remainder):
phrase += random.choice(string.ascii_letters.upper())

out_str = ''
out_str = ""

# Encode the phrase one letter at a time assembling the results into
# an output string
for letter in list(phrase):
out_str += self.type_letter(letter)

# Format the output to be groups five letters in size
out_str = ' '.join(out_str[i:i+5] for i in range(0, len(out_str), 5))
out_str = " ".join(out_str[i : i + 5] for i in range(0, len(out_str), 5))

return out_str

Expand Down Expand Up @@ -467,9 +463,9 @@ def rewire_plugboard(self, letter_1: str, letter_2: str) -> None:
assert isinstance(letter_1, str) and isinstance(letter_2, str)
except AssertionError as e:
self.logger.error(
"Invalid Characters for Plugboard Rewiring '%s' and '%s'",
"Invalid Characters for Plugboard Rewiring '%s' and '%s'",
letter_1,
letter_2
letter_2,
)
raise e
try:
Expand Down
3 changes: 2 additions & 1 deletion enigma/plugboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Plugboard:
Class representing the Enigma plugboard component for manual letter
encoding by connecting two letters via a dictionary
"""

def __init__(self) -> None:
"""Initialise a plugboard instance as a Python dictionary."""

Expand Down Expand Up @@ -81,7 +82,7 @@ def plugboard_conversion_inv(self, letter: str) -> str:
for key in self._plug_board_dict:
if self._plug_board_dict[key] == letter:
return key

raise KeyError("Could not find conversion for '{}'".format(letter))

def rewire(self, letter_1: str, letter_2: str) -> None:
Expand Down
7 changes: 4 additions & 3 deletions enigma/reflector.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Reflector:
Base class for construction of a reflector which sends forward encoded
cipher back through enigma machine after translation.
"""

def __init__(self) -> None:
"""Initialise an instance of the reflector class."""
self._reflector_dict: Dict[str, str] = {}
Expand All @@ -40,13 +41,12 @@ def reflector_conversion(self, letter: str) -> str:
assert self._reflector_dict[letter]
return self._reflector_dict[letter]
except (KeyError, AssertionError):
raise KeyError(
"Could not find '{}' in Reflector Dictionary".format(letter)
)
raise KeyError("Could not find '{}' in Reflector Dictionary".format(letter))


class ReflectorB(Reflector):
"""Enigma Reflector Type B"""

def __init__(self) -> None:
"""
Initialise a Type B Enigma Reflector.
Expand Down Expand Up @@ -91,6 +91,7 @@ def __init__(self) -> None:

class ReflectorC(Reflector):
"""Enigma Reflector Type C"""

def __init__(self) -> None:
"""
Initialise a Type C Enigma Reflector.
Expand Down
Loading

0 comments on commit 46eda45

Please sign in to comment.