# HG changeset patch # User Brian Neal # Date 1386733776 21600 # Node ID 800a8467f07a514f3e8a1abc8d5d83068194edc1 # Parent 168a6017eb89423ea65a400083a8ecfcbf58009c Testing with complete part 1 of 14 part message. One letter is wrong out of 1285. Debugging was added to try and track it down. No solution yet. diff -r 168a6017eb89 -r 800a8467f07a purple/machine.py --- a/purple/machine.py Wed Dec 04 20:31:37 2013 -0600 +++ b/purple/machine.py Tue Dec 10 21:49:36 2013 -0600 @@ -128,8 +128,6 @@ self.alphabet = alphabet self.plugboard = {c : n for n, c in enumerate(alphabet)} - self.middle_switch_catchup = False - @classmethod def from_key_sheet(cls, switches, alphabet=None): """This class method allows one to construct a Purple97 using @@ -184,11 +182,16 @@ """ plaintext = [] - for c in ciphertext: + for i, c in enumerate(ciphertext): if c not in self.VALID_KEYS: raise Purple97Error("invalid input '{}' to decrypt".format(c)) n = self.plugboard[c] + + if i == 490 or i == 491: + print(self.sixes.pos, self.fast_switch.pos, + self.middle_switch.pos, self.slow_switch.pos) + if n < 6: # This input goes to the sixes switch x = self.sixes.decrypt(n) @@ -204,6 +207,10 @@ # Now step the switches. self.step() + if i == 490 or i == 491: + print(self.sixes.pos, self.fast_switch.pos, + self.middle_switch.pos, self.slow_switch.pos) + return ''.join(plaintext) def encrypt(self, plaintext): @@ -257,34 +264,13 @@ # However if the sixes is at the last position (24), the middle # switch steps instead. # - # But if the sixes is at the last position (24) and the middle - # switch is at the last position (24), the slow switch will step. - # The middle switch will step on the next letter in this case. - # - # Here we reproduce figure 10 from the reference paper with offsets - # adjusted for 0-based indexing to illustrate the movement. In this - # example the fast is twenties #1, middle is #2, and slow is #3. - # - # Sixes Twenties #1 Twenties #2 Twenties #3 - # ----------------------------------------------------- - # 20 0 24 4 - # 21 1 24 4 - # 22 2 24 4 - # 23 3 24 4 - # * 24 3 24 5 - # # 0 3 0 5 - # 1 4 0 5 - # - # Here we see the fast switch stepping. However at (*) both the - # sixes and middle switch have reached their last positions, so the - # slow switch steps. At the next letter (#) the middle switch plays - # "catch up" and advances while the fast switch holds steady. + # But if the sixes is at the second to last position (23) and the middle + # switch is at the last position (24), the slow switch will step. The + # middle switch will step on the next letter in this case. - if sixes_pos == 24 and middle_pos == 24: + if sixes_pos == 23 and middle_pos == 24: self.slow_switch.step() - self.middle_switch_catchup = True - elif sixes_pos == 24 or self.middle_switch_catchup: + elif sixes_pos == 24: self.middle_switch.step() - self.middle_switch_catchup = False else: self.fast_switch.step() diff -r 168a6017eb89 -r 800a8467f07a purple/tests/test_machine.py --- a/purple/tests/test_machine.py Wed Dec 04 20:31:37 2013 -0600 +++ b/purple/tests/test_machine.py Tue Dec 10 21:49:36 2013 -0600 @@ -9,24 +9,90 @@ from purple.switch import SteppingSwitchError -# The ciphertext contains garbles, indicated by '-' chars. -ciphertext = ( - "ZTXODNWKCCMAVNZXYWEETUQTCIMN" - "VEUVIWBLUAXRRTLVARGNTPCNOIUP" - "JLCIVRTPJKAUHVMUDTHKTXYZELQTVWGBUHFAWSHU" - "LBFBHEXMYHFLOWD-KWHKKNXEBVPYHHGHEKXIOHQ" - "HUHWIKYJYHPPFEALNNAKIBOOZNFRLQCFLJTTSSDDOIOCVT-" - "ZCKQTSHXTIJCNWXOKUFNQR-TAOIHWTATWV" -) +# This is part 1 of the famous 14 part message. The ciphertext and plaintext are +# laid on top of each other, every other line, with blank lines inserted for +# clarity. Garbles are indicated by '-' characters. +# +part1 = """ +ZTXODNWKCCMAVNZXYWEETUQTCIMNVEUVIWBLUAXRRTLVA +FOVTATAKIDASINIMUIMINOMOXIWOIRUBESIFYXXFCKZZR -plaintext = ( - "FOVTATAKIDASINIMUIMINOMOXIWO" - "IRUBESIFYXXFCKZZRDXOOVBTNFYX" - "FAEMEMORANDUMFIOFOVOOMOJIBAKARIFYXRAICCY" - "LFCBBCFCTHEGOVE-NMENTOFJAPANLFLPROMPTED" - "BYAGENUINEDESIRETOCOMETOANAMICABLEUNDERSTANDIN-" - "WITHTHEGOVERNMENTOFTHE-NITEDSTATES" -) +RGNTPCNOIUPJLCIVRTPJKAUHVMUDTHKTXYZELQTVWGBUHFAWSH +DXOOVBTNFYXFAEMEMORANDUMFIOFOVOOMOJIBAKARIFYXRAICC + +ULBFBHEXMYHFLOWD-KWHKKNXEBVPYHHGHEKXIOHQHUHWIKYJYH +YLFCBBCFCTHEGOVE-NMENTOFJAPANLFLPROMPTEDBYAGENUINE + +PPFEALNNAKIBOOZNFRLQCFLJTTSSDDOIOCVT-ZCKQTSHXTIJCN +DESIRETOCOMETOANAMICABLEUNDERSTANDIN-WITHTHEGOVERN + +WXOKUFNQR-TAOIHWTATWVHOTGCGAKVANKZANMUIN +MENTOFTHE-NITEDSTATESINORDERTHATTHETWOCO + +YOYJFSRDKKSEQBWKIOORJAUWKXQGUWPDUDZNDRMDHVHYPNIZXB +UNTRIESBYTHEIRJOINTEFFORTSMAYSECURETHEPEACEOFTHEPA + +GICXRMAWMFTIUDBXIENLONOQVQKYCOTVSHVNZZQPDLMXVNRUUN +CIFICAREAANDTHEREBYCONTRIBUTETOWARDTHEREALIZATIONO + +QFTCDFECZDFGMXEHHWYONHYNJDOVJUNCSUVKKEIWOLKRBUUSOZ +FWORLDPEACELFLHASCONTINUEDNEGOTIATIONSWITHTHEUTMOS + +UIGNISMWUOSBOBLJXERZJEQYQMTFTXBJNCMJKVRKOTSOPBOYMK +TSINCERITYSINCEAPRILLASTWITHTHEGOVERNMENTOFTHEUNIT + +IRETINCPSQJAWVHUFKRMAMXNZUIFNOPUEMHGLOEJHZOOKHHEED +EDSTATESREGARDINGTHEADJUSTMENTANDADVANCEMENTOFJAPA + +NIHXFXFXGPDZBSKAZABYEKYEPNIYSHVKFRFPVCJTPTOYCNEIQB +NESEVVDAMERICANRELATIONSANDTHESTABILIZATIONOFTHEPA + +FEXMERMIZLGDRXZORLZFSQYPZFATZCHUGRNHWDDTAIHYOOCOOD +CIFICAREACFCCCFTHEJAPANESEQOVERNMENXHASTHEHONORTOS + +UZYIWJROOJUMUIHRBEJFONAXGNCKAOARDIHCDZKIXPR--DIMUW +TATEFRANKLYITSVIEWSCONCERNINGTHECLAIMSTHEAM--VCANG + +OMHLTJSOUXPFKGEPWJOMTUVKMWRKTACUPIGAFEDFVRKXFXLFGU +OVERNMENTHASUERSISTENTLYMAINTAINEDASWELLASTHEMEASU + +RDETJIYOLKBHZKXOJDDOVRHMMUQBFOWRODMRMUWNAYKYPISDLH +RESTHEUNITEDSTATESANDGREATBRITAINHAVETAKENTOWARDJA + +ECKINLJORKWNWXADAJOLONOEVMUQDFIDSPEBBPWROFBOPAZJEU +PANDURINGTHKSEEIGHTMONTHSCYCCCFLFCDDCFCITISTHEIMMU + +USBHGIORCSUUQKIIEHPCTJRWSOGLETZLOUKKEOJOSMKJBWUCDD +TABLXPOLWCYOFTHEJAPANESEGOVERNMENTTOINSURETHESTABI + +CPYUUWCSSKWWVLIUPKYXGKQOKAZTEZFHGVPJFEWEUBKLIZLWKK +LITYOFEASTASIAANDTOPROMOTEWORLZPEACELFLANDTHEREBYT + +OBXLEPQPDATWUSUUPKYRHNWDZXXGTWDDNSHDCBCJXAOOEEPUBP +OEIABLEALLNATIONSTOFINDEACHITSPROPERPLACEINTHEWORL + +WFRBQSFXSEZJJYAANMG-WLYMGWAQDGIVNOHKOUTIXYFOKNGGBF +DCFCCCFEVERSINCETHE-HINAAFFAIRBROKEOUTOWINGTOTHEFA + +GANPWTUYLBEFFKUFLEXOIUUANVMMJEQUSFHFDOHQLAKWTBYYYL +ILUREONTHEPARTOFCHINATOCOMPREHENLJAPANVCFSTRUEYNTE + +NTLYTSXCGKCEEWQRYAVGRKXIANPXNOFVXGKJFAVKLTHOCXCIVK +NTIONSLFLTWEJAPANESEGOVERNMENTHASSTRIVENFORTHEREST + +OLXTJTUNCLQCICRUIIWQDDMOTPRVTJKKSKFHXFKMDIKIZWROGZ +ORATIONOFPEACEANDIMHASCONSISTENTLYEXERTEDITSBESTEF + +JYMTMNOVMFJ-OKTEIVMYANOHNNYPDLEXCFRRNEBLMNYEBGNHCZ +FORTSTOPREV-NTTHEEXTENTIONOFWARVVFLIKEVISTURBANCES + +ZCFNWGGRHRIUUTTILKLODUYZKQOZMMNHASXHLPVTNGHQDAJIUG +CFCNSIASALSOTOTHATENDTNATINSEPTEMBERLASTYEARJAPANC + +OOSZ-----ZRTGWFBLKI--------YBDABJ-----WYOEANV---OM +ONCL-----HETRIPAITI--------THGERM-----DYTALYC---OV +""" + class Purple97TestCase(unittest.TestCase): @@ -111,7 +177,11 @@ self.assertRaises(Purple97Error, Purple97.from_key_sheet, '1-9,2,20-1a') self.assertRaises(Purple97Error, Purple97.from_key_sheet, '1-9,2,20-123') - def test_decrypt_first_part_of_14_part_message(self): + def test_decrypt_part_1_message(self): + + lines = part1.split() + ciphertext = ''.join(lines[0::2]) + plaintext = ''.join(lines[1::2]) # Use 'X' in place of the garbles input_text = ciphertext.replace('-', 'X') @@ -128,6 +198,7 @@ mismatches = [] for n, (a, b) in enumerate(zip(plaintext, actual)): if a != b and a != '-': + import pdb; pdb.set_trace() mismatches.append(n) msg = None @@ -137,7 +208,11 @@ self.assertTrue(len(mismatches) == 0, msg) - def test_encrypt_first_part_of_14_part_message(self): + def test_encrypt_part_1_message(self): + + lines = part1.split() + ciphertext = ''.join(lines[0::2]) + plaintext = ''.join(lines[1::2]) # Use 'X' in place of the garbles input_text = plaintext.replace('-', 'X')