changeset 16:adaca0a6b2b4

Build encrypt wiring tables once.
author Brian Neal <bgneal@gmail.com>
date Tue, 03 Dec 2013 19:20:48 -0600
parents 672ba8b2269f
children 0e5c0f2896be
files purple/data.py purple/switch.py purple/tests/test_switch.py
diffstat 3 files changed, 86 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/purple/data.py	Mon Dec 02 20:58:36 2013 -0600
+++ b/purple/data.py	Tue Dec 03 19:20:48 2013 -0600
@@ -132,9 +132,24 @@
 
 # Convert wiring data to be 0-based.
 
-_WIRING_DATA = [SIXES_DATA, TWENTIES_1_DATA, TWENTIES_2_DATA, TWENTIES_3_DATA]
+DECRYPT_DATA = [SIXES_DATA, TWENTIES_1_DATA, TWENTIES_2_DATA, TWENTIES_3_DATA]
 
-for table in _WIRING_DATA:
+for table in DECRYPT_DATA:
     for i in range(len(table)):
         for j in range(len(table[i])):
             table[i][j] = table[i][j] - 1
+
+
+def build_encrypt_wiring(dec_wiring):
+    """This function builds a reciprocal encrypt wiring table from the supplied
+    decrypt wiring table.
+
+    """
+    enc_wiring = []
+    for level in dec_wiring:
+        enc_wiring.append(
+            [level.index(n) for n in range(len(level))])
+    return enc_wiring
+
+# Build reciprocal encrypt wiring tables:
+ENCRYPT_DATA = [build_encrypt_wiring(wiring) for wiring in DECRYPT_DATA]
--- a/purple/switch.py	Mon Dec 02 20:58:36 2013 -0600
+++ b/purple/switch.py	Tue Dec 03 19:20:48 2013 -0600
@@ -21,25 +21,35 @@
     in the PURPLE cipher machine.
 
     """
-    def __init__(self, wiring, init_pos=0):
-        """Construct a SteppingSwitch from a wiring list, which must be a list
+    def __init__(self, dec_wiring, enc_wiring=None, init_pos=0):
+        """Construct a SteppingSwitch.
+
+        dec_wiring is the decrypt wiring table, which must be a list
         of lists (one list per input level). Each inner list is a list of
-        integers representing the output contacts. The initial position of the
-        switch can also be set; this defaults to 0.
+        integers representing the output contacts.
 
-        The wiring lists are assumed to be 0-based and represent the decrypt
-        path through the switch. A reciprocal encrypt wiring map will be
-        constructed from this argument internally.
+        enc_wiring is the encrypt wiring table. If None, a reciprocal table is
+        built from the dec_wiring parameter.
+
+        init_pos is the initial position of the switch; this defaults to 0.
 
         """
-        self.dec_wiring = wiring
-        self.num_positions = len(wiring)
-        self.num_levels = len(wiring[0])
+        self.dec_wiring = dec_wiring
+        self.num_positions = len(dec_wiring)
+        self.num_levels = len(dec_wiring[0])
 
-        if not all(self.num_levels == len(level) for level in wiring):
-            raise SteppingSwitchError("Ragged wiring table")
+        if not all(self.num_levels == len(level) for level in self.dec_wiring):
+            raise SteppingSwitchError("Invalid decrypt wiring dimensions")
 
-        self._build_encrypt_wiring()
+        self.enc_wiring = (enc_wiring if enc_wiring else
+                data.build_encrypt_wiring(dec_wiring))
+
+        if self.num_positions != len(self.enc_wiring):
+            raise SteppingSwitchError("Encrypt/Decrypt positions mismatch")
+
+        if not all(self.num_levels == len(level) for level in self.enc_wiring):
+            raise SteppingSwitchError("Invalid encrypt wiring dimensions")
+
         self.set_pos(init_pos)
 
     def set_pos(self, pos):
@@ -78,16 +88,6 @@
         """
         return self.enc_wiring[self.pos][level]
 
-    def _build_encrypt_wiring(self):
-        """This method builds an encrypt wiring table from the decrypt wiring
-        table member.
-
-        """
-        self.enc_wiring = []
-        for level in self.dec_wiring:
-            self.enc_wiring.append(
-                [level.index(n) for n in range(self.num_levels)])
-
 
 def create_switch(switch_type, init_pos=0):
     """Factory function for building a SteppingSwitch of the requested
@@ -102,14 +102,9 @@
     A ValueError will be raised if switch_type is an illegal value.
 
     """
-    wiring_map = {
-        SIXES: data.SIXES_DATA,
-        TWENTIES_1: data.TWENTIES_1_DATA,
-        TWENTIES_2: data.TWENTIES_2_DATA,
-        TWENTIES_3: data.TWENTIES_3_DATA,
-    }
-    wiring = wiring_map.get(switch_type)
-    if not wiring:
+    if switch_type not in [SIXES, TWENTIES_1, TWENTIES_2, TWENTIES_3]:
         raise ValueError("illegal switch type")
 
-    return SteppingSwitch(wiring, init_pos)
+    return SteppingSwitch(dec_wiring=data.DECRYPT_DATA[switch_type],
+            enc_wiring=data.ENCRYPT_DATA[switch_type],
+            init_pos=init_pos)
--- a/purple/tests/test_switch.py	Mon Dec 02 20:58:36 2013 -0600
+++ b/purple/tests/test_switch.py	Tue Dec 03 19:20:48 2013 -0600
@@ -23,10 +23,48 @@
             [0, 1, 2]
         ]
         self.assertRaises(SteppingSwitchError, SteppingSwitch, bad_wiring)
-        self.assertRaises(SteppingSwitchError, SteppingSwitch, bad_wiring, 0)
-        self.assertRaises(SteppingSwitchError, SteppingSwitch, good_wiring, -1)
-        self.assertRaises(SteppingSwitchError, SteppingSwitch, good_wiring, 3)
-        self.assertRaises(SteppingSwitchError, SteppingSwitch, bad_wiring, 3)
+        self.assertRaises(SteppingSwitchError, SteppingSwitch, bad_wiring,
+                init_pos=0)
+        self.assertRaises(SteppingSwitchError, SteppingSwitch, good_wiring,
+                init_pos=-1)
+        self.assertRaises(SteppingSwitchError, SteppingSwitch, good_wiring,
+                init_pos=3)
+        self.assertRaises(SteppingSwitchError, SteppingSwitch, bad_wiring,
+                init_pos=3)
+
+    def test_wiring_table_mismatch_in_dimensions(self):
+
+        wiring_1 = [
+            [1, 2, 0],
+            [2, 1, 0],
+            [0, 1, 2],
+        ]
+        wiring_2 = [
+            [1, 2, 3, 0],
+            [1, 2, 3, 0],
+            [1, 2, 3, 0],
+        ]
+        wiring_3 = [
+            [1, 2, 3, 0],
+            [1, 2, 3, 0],
+            [1, 2, 3, 0],
+            [1, 2, 3, 0],
+        ]
+        bad_wiring = [
+            [1, 2, 0],
+            [2, 1],
+            [0, 1, 2]
+        ]
+        self.assertRaises(SteppingSwitchError, SteppingSwitch, wiring_1,
+                wiring_2)
+        self.assertRaises(SteppingSwitchError, SteppingSwitch, wiring_2,
+                wiring_1)
+        self.assertRaises(SteppingSwitchError, SteppingSwitch, wiring_1,
+                bad_wiring)
+        self.assertRaises(SteppingSwitchError, SteppingSwitch, wiring_2,
+                wiring_3)
+        self.assertRaises(SteppingSwitchError, SteppingSwitch, wiring_3,
+                wiring_2)
 
     def test_bad_set_pos(self):