enigmapython 1.1.0__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. {enigmapython-1.1.0 → enigmapython-1.2.0}/PKG-INFO +41 -9
  2. enigmapython-1.2.0/enigmapython/Alphabets.py +6 -0
  3. enigmapython-1.2.0/enigmapython/Clonable.py +9 -0
  4. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/Enigma.py +38 -16
  5. enigmapython-1.2.0/enigmapython/EnigmaB_A133.py +12 -0
  6. enigmapython-1.2.0/enigmapython/EnigmaB_A133Etw.py +7 -0
  7. enigmapython-1.2.0/enigmapython/EnigmaB_A133RotorI.py +18 -0
  8. enigmapython-1.2.0/enigmapython/EnigmaB_A133RotorII.py +18 -0
  9. enigmapython-1.2.0/enigmapython/EnigmaB_A133RotorIII.py +18 -0
  10. enigmapython-1.2.0/enigmapython/EnigmaDRotorI.py +18 -0
  11. enigmapython-1.2.0/enigmapython/EnigmaDRotorII.py +18 -0
  12. enigmapython-1.2.0/enigmapython/EnigmaDRotorIII.py +18 -0
  13. enigmapython-1.2.0/enigmapython/EnigmaINorwayRotorI.py +18 -0
  14. enigmapython-1.2.0/enigmapython/EnigmaINorwayRotorII.py +18 -0
  15. enigmapython-1.2.0/enigmapython/EnigmaINorwayRotorIII.py +19 -0
  16. enigmapython-1.2.0/enigmapython/EnigmaINorwayRotorIV.py +19 -0
  17. enigmapython-1.2.0/enigmapython/EnigmaINorwayRotorV.py +19 -0
  18. enigmapython-1.2.0/enigmapython/EnigmaIRotorI.py +18 -0
  19. enigmapython-1.2.0/enigmapython/EnigmaIRotorII.py +19 -0
  20. enigmapython-1.2.0/enigmapython/EnigmaIRotorIII.py +19 -0
  21. enigmapython-1.2.0/enigmapython/EnigmaIRotorIV.py +20 -0
  22. enigmapython-1.2.0/enigmapython/EnigmaIRotorV.py +19 -0
  23. enigmapython-1.2.0/enigmapython/EnigmaISonderRotorI.py +18 -0
  24. enigmapython-1.2.0/enigmapython/EnigmaISonderRotorII.py +18 -0
  25. enigmapython-1.2.0/enigmapython/EnigmaISonderRotorIII.py +19 -0
  26. enigmapython-1.2.0/enigmapython/EnigmaM3RotorI.py +19 -0
  27. enigmapython-1.2.0/enigmapython/EnigmaM3RotorII.py +19 -0
  28. enigmapython-1.2.0/enigmapython/EnigmaM3RotorIII.py +19 -0
  29. enigmapython-1.2.0/enigmapython/EnigmaM3RotorIV.py +19 -0
  30. enigmapython-1.2.0/enigmapython/EnigmaM3RotorV.py +19 -0
  31. enigmapython-1.2.0/enigmapython/EnigmaM3RotorVI.py +20 -0
  32. enigmapython-1.2.0/enigmapython/EnigmaM3RotorVII.py +20 -0
  33. enigmapython-1.2.0/enigmapython/EnigmaM3RotorVIII.py +19 -0
  34. enigmapython-1.2.0/enigmapython/EnigmaM4RotorBeta.py +19 -0
  35. enigmapython-1.2.0/enigmapython/EnigmaM4RotorGamma.py +18 -0
  36. enigmapython-1.2.0/enigmapython/EnigmaM4RotorI.py +19 -0
  37. enigmapython-1.2.0/enigmapython/EnigmaM4RotorII.py +19 -0
  38. enigmapython-1.2.0/enigmapython/EnigmaM4RotorIII.py +19 -0
  39. enigmapython-1.2.0/enigmapython/EnigmaM4RotorIV.py +19 -0
  40. enigmapython-1.2.0/enigmapython/EnigmaM4RotorV.py +19 -0
  41. enigmapython-1.2.0/enigmapython/EnigmaM4RotorVI.py +19 -0
  42. enigmapython-1.2.0/enigmapython/EnigmaM4RotorVII.py +19 -0
  43. enigmapython-1.2.0/enigmapython/EnigmaM4RotorVIII.py +20 -0
  44. enigmapython-1.2.0/enigmapython/EnigmaZ.py +12 -0
  45. enigmapython-1.2.0/enigmapython/EnigmaZEtw.py +7 -0
  46. enigmapython-1.2.0/enigmapython/EnigmaZRotorI.py +18 -0
  47. enigmapython-1.2.0/enigmapython/EnigmaZRotorII.py +18 -0
  48. enigmapython-1.2.0/enigmapython/EnigmaZRotorIII.py +18 -0
  49. enigmapython-1.2.0/enigmapython/Etw.py +19 -0
  50. enigmapython-1.2.0/enigmapython/Journaled.py +12 -0
  51. enigmapython-1.2.0/enigmapython/Plugboard.py +20 -0
  52. enigmapython-1.2.0/enigmapython/PlugboardPassthrough.py +8 -0
  53. enigmapython-1.2.0/enigmapython/Reflector.py +4 -0
  54. enigmapython-1.2.0/enigmapython/ReflectorDUKW.py +13 -0
  55. enigmapython-1.2.0/enigmapython/ReflectorNorwayUKW.py +14 -0
  56. enigmapython-1.2.0/enigmapython/ReflectorSonderUKW.py +13 -0
  57. enigmapython-1.2.0/enigmapython/ReflectorUKWA.py +13 -0
  58. enigmapython-1.2.0/enigmapython/ReflectorUKWB.py +13 -0
  59. enigmapython-1.2.0/enigmapython/ReflectorUKWBThin.py +13 -0
  60. enigmapython-1.2.0/enigmapython/ReflectorUKWC.py +15 -0
  61. enigmapython-1.2.0/enigmapython/ReflectorUKWCThin.py +15 -0
  62. enigmapython-1.2.0/enigmapython/ReflectorUKW_EnigmaB_A133.py +15 -0
  63. enigmapython-1.2.0/enigmapython/ReflectorZUKW.py +19 -0
  64. enigmapython-1.2.0/enigmapython/RotatingReflector.py +4 -0
  65. enigmapython-1.2.0/enigmapython/Rotor.py +50 -0
  66. enigmapython-1.2.0/enigmapython/Scrambler.py +63 -0
  67. enigmapython-1.1.0/enigmapython/SwappablePlugboard.py → enigmapython-1.2.0/enigmapython/Swappable.py +3 -10
  68. enigmapython-1.2.0/enigmapython/SwappablePlugboard.py +12 -0
  69. enigmapython-1.2.0/enigmapython/Utils.py +118 -0
  70. enigmapython-1.2.0/enigmapython/__init__.py +0 -0
  71. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython.egg-info/PKG-INFO +41 -9
  72. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython.egg-info/SOURCES.txt +18 -0
  73. {enigmapython-1.1.0 → enigmapython-1.2.0}/setup.py +1 -1
  74. enigmapython-1.1.0/enigmapython/EnigmaDRotorI.py +0 -11
  75. enigmapython-1.1.0/enigmapython/EnigmaDRotorII.py +0 -11
  76. enigmapython-1.1.0/enigmapython/EnigmaDRotorIII.py +0 -11
  77. enigmapython-1.1.0/enigmapython/EnigmaINorwayRotorI.py +0 -11
  78. enigmapython-1.1.0/enigmapython/EnigmaINorwayRotorII.py +0 -11
  79. enigmapython-1.1.0/enigmapython/EnigmaINorwayRotorIII.py +0 -12
  80. enigmapython-1.1.0/enigmapython/EnigmaINorwayRotorIV.py +0 -12
  81. enigmapython-1.1.0/enigmapython/EnigmaINorwayRotorV.py +0 -12
  82. enigmapython-1.1.0/enigmapython/EnigmaIRotorI.py +0 -11
  83. enigmapython-1.1.0/enigmapython/EnigmaIRotorII.py +0 -11
  84. enigmapython-1.1.0/enigmapython/EnigmaIRotorIII.py +0 -11
  85. enigmapython-1.1.0/enigmapython/EnigmaIRotorIV.py +0 -12
  86. enigmapython-1.1.0/enigmapython/EnigmaIRotorV.py +0 -12
  87. enigmapython-1.1.0/enigmapython/EnigmaISonderRotorI.py +0 -11
  88. enigmapython-1.1.0/enigmapython/EnigmaISonderRotorII.py +0 -12
  89. enigmapython-1.1.0/enigmapython/EnigmaISonderRotorIII.py +0 -12
  90. enigmapython-1.1.0/enigmapython/EnigmaM3RotorI.py +0 -10
  91. enigmapython-1.1.0/enigmapython/EnigmaM3RotorII.py +0 -10
  92. enigmapython-1.1.0/enigmapython/EnigmaM3RotorIII.py +0 -10
  93. enigmapython-1.1.0/enigmapython/EnigmaM3RotorIV.py +0 -10
  94. enigmapython-1.1.0/enigmapython/EnigmaM3RotorV.py +0 -10
  95. enigmapython-1.1.0/enigmapython/EnigmaM3RotorVI.py +0 -12
  96. enigmapython-1.1.0/enigmapython/EnigmaM3RotorVII.py +0 -12
  97. enigmapython-1.1.0/enigmapython/EnigmaM3RotorVIII.py +0 -12
  98. enigmapython-1.1.0/enigmapython/EnigmaM4RotorBeta.py +0 -12
  99. enigmapython-1.1.0/enigmapython/EnigmaM4RotorGamma.py +0 -12
  100. enigmapython-1.1.0/enigmapython/EnigmaM4RotorI.py +0 -10
  101. enigmapython-1.1.0/enigmapython/EnigmaM4RotorII.py +0 -10
  102. enigmapython-1.1.0/enigmapython/EnigmaM4RotorIII.py +0 -10
  103. enigmapython-1.1.0/enigmapython/EnigmaM4RotorIV.py +0 -9
  104. enigmapython-1.1.0/enigmapython/EnigmaM4RotorV.py +0 -9
  105. enigmapython-1.1.0/enigmapython/EnigmaM4RotorVI.py +0 -9
  106. enigmapython-1.1.0/enigmapython/EnigmaM4RotorVII.py +0 -9
  107. enigmapython-1.1.0/enigmapython/EnigmaM4RotorVIII.py +0 -10
  108. enigmapython-1.1.0/enigmapython/Etw.py +0 -22
  109. enigmapython-1.1.0/enigmapython/Plugboard.py +0 -15
  110. enigmapython-1.1.0/enigmapython/PlugboardPassthrough.py +0 -7
  111. enigmapython-1.1.0/enigmapython/Reflector.py +0 -4
  112. enigmapython-1.1.0/enigmapython/ReflectorDUKW.py +0 -9
  113. enigmapython-1.1.0/enigmapython/ReflectorNorwayUKW.py +0 -9
  114. enigmapython-1.1.0/enigmapython/ReflectorSonderUKW.py +0 -9
  115. enigmapython-1.1.0/enigmapython/ReflectorUKWA.py +0 -9
  116. enigmapython-1.1.0/enigmapython/ReflectorUKWB.py +0 -9
  117. enigmapython-1.1.0/enigmapython/ReflectorUKWBThin.py +0 -9
  118. enigmapython-1.1.0/enigmapython/ReflectorUKWC.py +0 -10
  119. enigmapython-1.1.0/enigmapython/ReflectorUKWCThin.py +0 -10
  120. enigmapython-1.1.0/enigmapython/Rotor.py +0 -94
  121. enigmapython-1.1.0/enigmapython/Utils.py +0 -31
  122. enigmapython-1.1.0/enigmapython/__init__.py +0 -58
  123. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/EnigmaD.py +0 -0
  124. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/EnigmaDEtw_JWULCM.py +0 -0
  125. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/EnigmaDEtw_QWERTZ.py +0 -0
  126. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/EnigmaI.py +0 -0
  127. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/EnigmaINorway.py +0 -0
  128. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/EnigmaISonder.py +0 -0
  129. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/EnigmaM3.py +0 -0
  130. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/EnigmaM4.py +0 -0
  131. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/EtwPassthrough.py +0 -0
  132. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/Observable.py +0 -0
  133. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython/Observer.py +0 -0
  134. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython.egg-info/dependency_links.txt +0 -0
  135. {enigmapython-1.1.0 → enigmapython-1.2.0}/enigmapython.egg-info/top_level.txt +0 -0
  136. {enigmapython-1.1.0 → enigmapython-1.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: enigmapython
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: A simple yet faithful library to emulate different Enigma machines models using Python
5
5
  Home-page: https://github.com/denismaggior8/enigma-python
6
6
  Author: Denis Maggiorotto
@@ -8,7 +8,9 @@ Description-Content-Type: text/markdown
8
8
 
9
9
  # Enigma Python library
10
10
 
11
- ![](img/logo.jpg)
11
+ <div class="img-container" style="text-align: center;">
12
+ <img src="img/logo.jpg" alt="drawing" width="200" />
13
+ </div>
12
14
 
13
15
  ## About
14
16
 
@@ -24,6 +26,18 @@ Welcome to **enigmapython**, a Python package designed to emulate the legendary
24
26
 
25
27
  The following Enigma machine models (along with their rotors, reflectors and plugboards) have been implemented:
26
28
 
29
+ ### Enigma B (Sweden, s/n: A-133)*
30
+
31
+ | Scrambler | Wiring | Notch | Implemented |
32
+ |------- |---------------------------- |------- |------------- |
33
+ | ETW (passthrough) | abcdefghijklmnopqrstuvxyzåäö | N/A | ✅ |
34
+ | Rotor I | psbgöxqjdhoäucfrtezvåinlymka | ä | ✅ |
35
+ | Rotor II | chnsyöadmotrzxbäigåekqupflvj | ä | ✅ |
36
+ | Rotor III | åvqiaäxrjbözspcfyunthdomekgl | ä | ✅ |
37
+ | Reflector UKW | ldgbäncpskjavfzhxuiårmqöotey | N/A | ✅ |
38
+
39
+ *given the rarity of this model and the little documentation/simulators available, although I expect an encryption consistency on par with newer models, I was unable to test it as I would have liked
40
+
27
41
  ### Enigma D
28
42
 
29
43
  | Scrambler | Wiring | Notch | Implemented |
@@ -35,6 +49,19 @@ The following Enigma machine models (along with their rotors, reflectors and plu
35
49
  | Rotor III | bdfhjlcprtxvznyeiwgakmusqo | n | ✅ |
36
50
  | Reflector UKW | imetcgfraysqbzxwlhkdvupojn | N/A | ✅ |
37
51
 
52
+
53
+ ### Enigma Z (Z30 Mark I)*
54
+
55
+ | Scrambler | Wiring | Notch | Implemented |
56
+ |------- |----------------------------|-------|-------------|
57
+ | ETW (passthrough) | 1234567890 | N/A | ✅ |
58
+ | Rotor I | 6418270359 | 9 | ✅ |
59
+ | Rotor II | 5841097632 | 9 | ✅ |
60
+ | Rotor III | 3581620794 | 9 | ✅ |
61
+ | Reflector UKW | 5079183642 | N/A | ✅ |
62
+
63
+ *given the rarity of this model and the little documentation/simulators available, although I expect an encryption consistency on par with newer models, I was unable to test it as I would have liked
64
+
38
65
  ### Enigma I
39
66
 
40
67
  | Scrambler | Wiring | Notch | Implemented |
@@ -126,16 +153,18 @@ An initial documentation draft can be found [here](./docs/README.md), but in mos
126
153
 
127
154
  Here's a list containing all the known Enigma simulators that use the **enigmapython** API.
128
155
 
129
- - [Retrocampus BBS Enigma simulator](https://retrocampus.com/bbs/). When connected to the BBS, type E to access an Enigma M3 cypher machine. ![](img/retrocampus_enigma.png)
156
+ - [Enigma TUI](https://github.com/denismaggior8/enigma-tui). **Enigma TUI** is a **T**erminal **U**ser **I**nterface for Enigma machines, allowing you to simulate different Enigma machine models from the terminal. It employs **enigmapython** as Enigma engine.
130
157
 
131
- In the case you leveraged **enigmapython** API in a project, either public or not, drop me an email at __denis.maggiorotto[at]gmail.com__ and I'll be happy to list you here.
158
+ <div class="img-container" style="text-align: center;">
159
+ <img src="img/enigmatui.png" alt="drawing" width="400" align="center"/>
160
+ </div>
132
161
 
133
162
 
134
- ## Known implementations
163
+ - [Retrocampus BBS Enigma simulator](https://retrocampus.com/bbs/). When connected to the BBS, type E to access an Enigma M3 cypher machine whose backend is based on **enigmapython**.
135
164
 
136
- Here's a list containing all the known Enigma simulators that use the **enigmapython** API.
137
-
138
- - [Retrocampus BBS Enigma simulator](https://retrocampus.com/bbs/). When connected to the BBS, type E to access an Enigma M3 cypher machine. ![](img/retrocampus_enigma.png)
165
+ <div class="img-container" style="text-align: center;">
166
+ <img src="img/retrocampus_enigma.png" alt="drawing" width="400" align="center"/>
167
+ </div>
139
168
 
140
169
  In the case you leveraged **enigmapython** API in a project, either public or not, drop me an email at __denis.maggiorotto[at]gmail.com__ and I'll be happy to list you here.
141
170
 
@@ -150,7 +179,10 @@ In the case you leveraged **enigmapython** API in a project, either public or no
150
179
  - PyEnigma https://pypi.org/project/pyenigma/
151
180
  - 101 computing https://www.101computing.net/enigma-machine-emulator/
152
181
  - DenCode Enigma simulator https://dencode.com/cipher/enigma
153
-
182
+ - Enigma simulation in Javascript/HTML by Daniel Palloks https://people.physik.hu-berlin.de/~palloks/js/enigma/index_en.html
183
+ - Enigma B A133 simulation in Javascript/HTML by Daniel Palloks https://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-a133_v261_en.html
184
+ - Enigma Z simulation in Javascript/HTML by Daniel Palloks https://people.physik.hu-berlin.de/~palloks/js/enigma/enigma-z_v262b_en.html
185
+
154
186
  for having helped me testing the correctness of the generated ciphertexts
155
187
 
156
188
 
@@ -0,0 +1,6 @@
1
+ class Alphabets:
2
+ lookup = {
3
+ 'latin_i18n_26chars_lowercase': 'abcdefghijklmnopqrstuvwxyz',
4
+ 'enigma_b_a133_28chars_lowercase': 'abcdefghijklmnopqrstuvxyzåäö',
5
+ 'enigma_z_10chars_numbers': '1234567890'
6
+ }
@@ -0,0 +1,9 @@
1
+ import copy
2
+
3
+ class Clonable:
4
+ def clone(self):
5
+ """
6
+ Creates a deep copy of the current instance.
7
+ Override this method in subclasses if custom logic is needed.
8
+ """
9
+ return copy.deepcopy(self)
@@ -1,9 +1,12 @@
1
1
  from .Observer import Observer
2
- from string import ascii_lowercase
2
+ from .RotatingReflector import RotatingReflector
3
+ from .Alphabets import Alphabets
4
+ from .Journaled import Journaled
5
+ from .Clonable import Clonable
3
6
  import logging
4
7
 
5
8
 
6
- class Enigma(Observer):
9
+ class Enigma(Observer,Journaled,Clonable):
7
10
 
8
11
  plugboard = None
9
12
  rotors = None
@@ -13,7 +16,9 @@ class Enigma(Observer):
13
16
 
14
17
  alphabet_list = None
15
18
 
16
- def __init__(self, plugboard, rotors, reflector,etw,auto_increment_rotors=False, alphabet=ascii_lowercase):
19
+ def __init__(self, plugboard, rotors, reflector,etw,auto_increment_rotors=False, alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")):
20
+ Journaled.__init__(self)
21
+ Clonable.__init__(self)
17
22
  self.plugboard = plugboard
18
23
  self.rotors = rotors
19
24
  self.reflector = reflector
@@ -34,13 +39,20 @@ class Enigma(Observer):
34
39
  logging.info("Input char: {}".format(char))
35
40
  ## Triggering rotors extra rotation due to double step issue
36
41
  for rotor in self.rotors:
37
- ## Rotor extra rotation should be done only if the rotor is not the last one in the list
42
+ ## Rotor extra rotation should be done only if it's not the last one in the list
38
43
  if rotor.double_step_triggered == True and self.rotors.index(rotor) < len(self.rotors)-1:
39
44
  rotor.increment_position()
40
45
  rotor.double_step_triggered = False
46
+ if isinstance(self.reflector, RotatingReflector) and self.reflector.double_step_triggered == True:
47
+ self.reflector.increment_position()
48
+ self.reflector.double_step_triggered = False
41
49
  if self.auto_increment_rotors == True:
42
50
  self.rotors[0].increment_position()
43
51
  scrambled_char = self.process_char(char)
52
+ super().append_to_journal({
53
+ 'input_char': char,
54
+ 'output_char': scrambled_char
55
+ })
44
56
  return scrambled_char
45
57
 
46
58
  """
@@ -56,33 +68,33 @@ class Enigma(Observer):
56
68
  --- --- --- --- --- ---
57
69
  """
58
70
  def process_char(self, char):
59
- scrambled_char = self.plugboard.switch_char(char)
71
+ scrambled_char = self.plugboard.scramble_char(self.plugboard.wiring,self.plugboard.alphabet_list.index(char),0)
60
72
  logging.debug("Scrambled letter from plugboard: {}".format(scrambled_char))
61
- scrambled_char = self.etw.process_char_forward(scrambled_char,0)
73
+ scrambled_char = self.etw.scramble_char(self.etw.wiring,self.alphabet_list.index(scrambled_char), 0)
62
74
  logging.debug("Scrambled letter from ETW: {}".format(scrambled_char))
63
75
  iteration = 0
64
76
  for rotor in self.rotors:
65
77
  if iteration == 0:
66
- scrambled_char = rotor.scramble_letter_index(rotor.wiring,self.alphabet_list.index(scrambled_char))
78
+ scrambled_char = rotor.scramble_char(rotor.wiring,self.alphabet_list.index(scrambled_char), rotor.position)
67
79
  else:
68
- scrambled_char = rotor.scramble_letter_index(rotor.wiring,self.alphabet_list.index(scrambled_char)-self.rotors[iteration-1].position)
80
+ scrambled_char = rotor.scramble_char(rotor.wiring,self.alphabet_list.index(scrambled_char)-self.rotors[iteration-1].position, rotor.position)
69
81
  iteration +=1
70
82
  logging.debug("Scrambled letter from rotor{}: {}".format(str(iteration),scrambled_char))
71
- scrambled_char = self.reflector.scramble_letter_index(self.reflector.wiring,(self.alphabet_list.index(scrambled_char)-self.rotors[iteration-1].position))
83
+ scrambled_char = self.reflector.scramble_char(self.reflector.wiring,(self.alphabet_list.index(scrambled_char)-self.rotors[iteration-1].position), 0)
72
84
  logging.debug("Scrambled letter from reflector: {}".format(scrambled_char))
73
85
  for rotor in reversed(self.rotors):
74
86
  if iteration == len(self.rotors):
75
- scrambled_char = rotor.scramble_letter_index(self.alphabet_list,(rotor.wiring.index(self.shift_letter(scrambled_char,rotor.position,self.alphabet_list))-rotor.position))
87
+ scrambled_char = rotor.scramble_char(self.alphabet_list,(rotor.wiring.index(self.shift_letter(scrambled_char,rotor.position,self.alphabet_list))-rotor.position), rotor.position)
76
88
  else:
77
- scrambled_char = rotor.scramble_letter_index(self.alphabet_list,(rotor.wiring.index(self.shift_letter(scrambled_char, (rotor.position - self.rotors[iteration].position),self.alphabet_list)) - rotor.position))
89
+ scrambled_char = rotor.scramble_char(self.alphabet_list,(rotor.wiring.index(self.shift_letter(scrambled_char, (rotor.position - self.rotors[iteration].position),self.alphabet_list)) - rotor.position), rotor.position)
78
90
  iteration -=1
79
91
  logging.debug("Scrambled letter from rotor{}: {}".format(str(iteration+1),scrambled_char))
80
92
 
81
93
  # Processing rotor 1 returning signal by ETW
82
- scrambled_char = self.etw.process_char_backward(scrambled_char,self.rotors[iteration].position)
94
+ scrambled_char = self.etw.scramble_char(self.alphabet_list,(self.etw.wiring.index(self.shift_letter(scrambled_char, (0 - self.rotors[iteration].position),self.alphabet_list))), 0)
83
95
  logging.debug("Scrambled letter from ETW: {}".format(scrambled_char))
84
96
 
85
- scrambled_char = self.plugboard.switch_char(scrambled_char)
97
+ scrambled_char = self.plugboard.scramble_char(self.plugboard.wiring,self.plugboard.alphabet_list.index(scrambled_char),0)
86
98
  logging.debug("Scrambled letter from plugboard: {}".format(scrambled_char))
87
99
  logging.info("Scrambled letter to lamp: {}".format(scrambled_char))
88
100
  return scrambled_char
@@ -91,14 +103,24 @@ class Enigma(Observer):
91
103
  # If there is rotor N+1, increment its position by 1
92
104
  if observable in self.rotors and self.rotors.index(observable) < len(self.rotors)-1:
93
105
  self.rotors[self.rotors.index(observable)+1].increment_position()
106
+ logging.debug("Rotor at index {} has been incremented by 1 position".format(self.rotors.index(observable)+1))
94
107
  # Engaging the enigma double step issue, only if the next rotor position is in its notch indexe/s
95
108
  if self.rotors[self.rotors.index(observable)+1].position in self.rotors[self.rotors.index(observable)+1].notch_indexes:
96
109
  self.rotors[self.rotors.index(observable)+1].double_step_triggered = True
110
+ # If the rotor is the last one in the list, but the machine has a rotating reflector, increment it position by 1
111
+ if observable in self.rotors and self.rotors.index(observable) == len(self.rotors)-1 and isinstance(self.reflector, RotatingReflector):
112
+ self.reflector.increment_position()
113
+ logging.debug("Reflector has been incremented by 1 position")
114
+ # Engaging the enigma double step issue, only if the next rotor position is in its notch indexe/s
115
+ if self.reflector.position in self.reflector.notch_indexes:
116
+ self.reflector.double_step_triggered = True
97
117
 
98
118
  @staticmethod
99
119
  def shift_letter(letter,shift,alphabet_list):
100
120
  return alphabet_list[(alphabet_list.index(letter)+shift) % len(alphabet_list)]
101
121
 
102
-
103
-
104
-
122
+ def clone(self):
123
+ new_enigma = super().clone()
124
+ for rotor in new_enigma.rotors:
125
+ rotor.add_observer(new_enigma)
126
+ return new_enigma
@@ -0,0 +1,12 @@
1
+ from .Enigma import Enigma
2
+ from .Alphabets import Alphabets
3
+ from .PlugboardPassthrough import PlugboardPassthrough
4
+
5
+
6
+ class EnigmaB_A133(Enigma):
7
+
8
+ alphabet=Alphabets.lookup.get("enigma_b_a133_28chars_lowercase")
9
+
10
+ def __init__(self,rotor1, rotor2, rotor3,reflector,etw,auto_increment_rotors=False):
11
+ rotors = [rotor1, rotor2, rotor3]
12
+ super().__init__(PlugboardPassthrough(alphabet=self.alphabet),rotors,reflector,etw,auto_increment_rotors, alphabet=self.alphabet)
@@ -0,0 +1,7 @@
1
+ from .Etw import Etw
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaB_A133Etw(Etw):
5
+ wiring = "abcdefghijklmnopqrstuvxyzåäö"
6
+ def __init__(self):
7
+ super().__init__(self.wiring, alphabet=Alphabets.lookup.get("enigma_b_a133_28chars_lowercase"))
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaB_A133RotorI(Rotor):
5
+
6
+ wiring = 'psbgöxqjdhoäucfrtezvåinlymka'
7
+ notch_indexes = [11]
8
+ tag = "B_A133_I"
9
+
10
+ def __init__(self, position = 0, ring = 0):
11
+ super().__init__(
12
+ wiring=self.wiring,
13
+ position=position,
14
+ ring=ring,
15
+ notch_indexes=self.notch_indexes,
16
+ alphabet=Alphabets.lookup.get("enigma_b_a133_28chars_lowercase")
17
+ )
18
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaB_A133RotorII(Rotor):
5
+
6
+ wiring = 'chnsyöadmotrzxbäigåekqupflvj'
7
+ notch_indexes = [15]
8
+ tag = "B_A133_II"
9
+
10
+ def __init__(self, position = 0, ring = 0):
11
+ super().__init__(
12
+ wiring=self.wiring,
13
+ position=position,
14
+ ring=ring,
15
+ notch_indexes=self.notch_indexes,
16
+ alphabet=Alphabets.lookup.get("enigma_b_a133_28chars_lowercase")
17
+ )
18
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaB_A133RotorIII(Rotor):
5
+
6
+ wiring = 'åvqiaäxrjbözspcfyunthdomekgl'
7
+ notch_indexes = [5]
8
+ tag = "B_A133_III"
9
+
10
+ def __init__(self, position = 0, ring = 0):
11
+ super().__init__(
12
+ wiring=self.wiring,
13
+ position=position,
14
+ ring=ring,
15
+ notch_indexes=self.notch_indexes,
16
+ alphabet=Alphabets.lookup.get("enigma_b_a133_28chars_lowercase")
17
+ )
18
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaDRotorI(Rotor):
5
+
6
+ wiring = 'lpgszmhaeoqkvxrfybutnicjdw'
7
+ notch_indexes = [24]
8
+ tag = "D_I"
9
+
10
+ def __init__(self, position = 0, ring = 0):
11
+ super().__init__(
12
+ wiring=self.wiring,
13
+ position=position,
14
+ ring=ring,
15
+ notch_indexes=self.notch_indexes,
16
+ alphabet=Alphabets.lookup.get('latin_i18n_26chars_lowercase')
17
+ )
18
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaDRotorII(Rotor):
5
+
6
+ wiring = 'slvgbtfxjqohewirzyamkpcndu'
7
+ notch_indexes = [4]
8
+ tag = "D_II"
9
+
10
+ def __init__(self, position = 0, ring = 0):
11
+ super().__init__(
12
+ wiring=self.wiring,
13
+ position=position,
14
+ ring=ring,
15
+ notch_indexes=self.notch_indexes,
16
+ alphabet=Alphabets.lookup.get('latin_i18n_26chars_lowercase')
17
+ )
18
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaDRotorIII(Rotor):
5
+
6
+ wiring = 'cjgdpshkturawzxfmynqobvlie'
7
+ notch_indexes = [13]
8
+ tag = "D_III"
9
+
10
+ def __init__(self, position = 0, ring = 0):
11
+ super().__init__(
12
+ wiring=self.wiring,
13
+ position=position,
14
+ ring=ring,
15
+ notch_indexes=self.notch_indexes,
16
+ alphabet=Alphabets.lookup.get('latin_i18n_26chars_lowercase')
17
+ )
18
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaINorwayRotorI(Rotor):
5
+
6
+ wiring = 'wtokasuyvrbxjhqcpzefmdinlg'
7
+ notch_indexes = [16]
8
+ tag = "IN_I"
9
+
10
+ def __init__(self, position = 0, ring = 0):
11
+ super().__init__(
12
+ wiring=self.wiring,
13
+ position=position,
14
+ ring=ring,
15
+ notch_indexes=self.notch_indexes,
16
+ alphabet=Alphabets.lookup.get('latin_i18n_26chars_lowercase')
17
+ )
18
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+
5
+ class EnigmaINorwayRotorII(Rotor):
6
+
7
+ wiring = 'gjlpubswemctqvhxaofzdrkyni'
8
+ notch_indexes = [4]
9
+ tag = "IN_II"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring=self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get('latin_i18n_26chars_lowercase')
18
+ )
@@ -0,0 +1,19 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+
5
+ class EnigmaINorwayRotorIII(Rotor):
6
+
7
+ wiring = 'jwfmhnbpusdytixvzgrqlaoekc'
8
+ notch_indexes = [21]
9
+ tag = "IN_III"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring=self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get('latin_i18n_26chars_lowercase')
18
+ )
19
+
@@ -0,0 +1,19 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+
5
+ class EnigmaINorwayRotorIV(Rotor):
6
+
7
+ wiring = 'fgzjmvxepbwshqtliudykcnrao'
8
+ notch_indexes = [21]
9
+ tag = "IN_IV"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring=self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get('latin_i18n_26chars_lowercase')
18
+ )
19
+
@@ -0,0 +1,19 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+
5
+ class EnigmaINorwayRotorV(Rotor):
6
+
7
+ wiring = 'hejxqotzbvfdascilwpgynmurk'
8
+ notch_indexes = [25]
9
+ tag = "IN_V"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring=self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get('latin_i18n_26chars_lowercase')
18
+ )
19
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaIRotorI(Rotor):
5
+
6
+ wiring = 'ekmflgdqvzntowyhxuspaibrcj'
7
+ notch_indexes = [16]
8
+ tag = "I_I"
9
+
10
+ def __init__(self, position = 0, ring = 0):
11
+ super().__init__(
12
+ wiring = self.wiring,
13
+ position=position,
14
+ ring=ring,
15
+ notch_indexes=self.notch_indexes,
16
+ alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")
17
+ )
18
+
@@ -0,0 +1,19 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaIRotorII(Rotor):
5
+
6
+ wiring = 'ajdksiruxblhwtmcqgznpyfvoe'
7
+ notch_indexes = [4]
8
+
9
+ tag = "I_II"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring = self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")
18
+ )
19
+
@@ -0,0 +1,19 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaIRotorIII(Rotor):
5
+
6
+ wiring = 'bdfhjlcprtxvznyeiwgakmusqo'
7
+ notch_indexes = [21]
8
+
9
+ tag = "I_III"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring = self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")
18
+ )
19
+
@@ -0,0 +1,20 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+
5
+ class EnigmaIRotorIV(Rotor):
6
+
7
+ wiring = 'esovpzjayquirhxlnftgkdcmwb'
8
+ notch_indexes = [9]
9
+
10
+ tag = "I_IV"
11
+
12
+ def __init__(self, position = 0, ring = 0):
13
+ super().__init__(
14
+ wiring = self.wiring,
15
+ position=position,
16
+ ring=ring,
17
+ notch_indexes=self.notch_indexes,
18
+ alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")
19
+ )
20
+
@@ -0,0 +1,19 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+
5
+ class EnigmaIRotorV(Rotor):
6
+
7
+ wiring = 'vzbrgityupsdnhlxawmjqofeck'
8
+ notch_indexes = [25]
9
+ tag = "I_V"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring = self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")
18
+ )
19
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaISonderRotorI(Rotor):
5
+
6
+ wiring = 'veosirzujdqckgwypnxaflthmb'
7
+ notch_indexes = [16]
8
+ tag = "IS_I"
9
+
10
+ def __init__(self, position = 0, ring = 0):
11
+ super().__init__(
12
+ wiring = self.wiring,
13
+ position=position,
14
+ ring=ring,
15
+ notch_indexes=self.notch_indexes,
16
+ alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")
17
+ )
18
+
@@ -0,0 +1,18 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+
5
+ class EnigmaISonderRotorII(Rotor):
6
+
7
+ wiring = 'uemoatqlshpkcyfwjzbgvxidnr'
8
+ notch_indexes = [4]
9
+ tag = "IS_II"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring = self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")
18
+ )
@@ -0,0 +1,19 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+
5
+ class EnigmaISonderRotorIII(Rotor):
6
+
7
+ wiring = 'tzhxmbsipnurjfdkeqvcwglaoy'
8
+ notch_indexes = [21]
9
+ tag = "IS_III"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring = self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")
18
+ )
19
+
@@ -0,0 +1,19 @@
1
+ from .Rotor import Rotor
2
+ from .Alphabets import Alphabets
3
+
4
+ class EnigmaM3RotorI(Rotor):
5
+
6
+ wiring = 'ekmflgdqvzntowyhxuspaibrcj'
7
+ notch_indexes = [16]
8
+
9
+ tag = "M3_I"
10
+
11
+ def __init__(self, position = 0, ring = 0):
12
+ super().__init__(
13
+ wiring = self.wiring,
14
+ position=position,
15
+ ring=ring,
16
+ notch_indexes=self.notch_indexes,
17
+ alphabet=Alphabets.lookup.get("latin_i18n_26chars_lowercase")
18
+ )
19
+