Know-Plaintext attack, 2015, by George Lasry ============================================ Introduction ------------ In 2014, George Lasry solved several problems of my M-209 Challenge. He used the Hill Climbing Algorithm. In 2015 he published in Cryptologia his algorithm using a revolutionary fitness function: the ADE function. I wrote a program in Python based on his algorithm, I call it HC_KPA.py. Cage representation ------------------- It is possible to represent the Cage with the position of each lugs on each bar, for example: Bar 01: 1-5 Bar 07: 2-0 Bar 13: 2-0 Bar 19: 0-4 Bar 25: 0-6 Bar 02: 2-5 Bar 08: 2-0 Bar 14: 2-0 Bar 20: 0-5 Bar 26: 0-6 Bar 03: 2-5 Bar 09: 2-0 Bar 15: 2-0 Bar 21: 0-6 Bar 27: 0-6 Bar 04: 2-5 Bar 10: 2-0 Bar 16: 3-0 Bar 22: 0-6 Bar 05: 3-5 Bar 11: 2-0 Bar 17: 3-0 Bar 23: 0-6 Bar 06: 4-5 Bar 12: 2-0 Bar 18: 3-0 Bar 24: 0-6 There are 21 possible lugs settings for each bar, as follows: 1. Only one of the two lugs is set to be against one of the 6 wheels, and the second is set to the neutral position (0). There are 6 possible such settings: 0-1, 0-2, 0-3, 0-4, 0-5 and 0-6. 2. Both lugs are set. This case is known as lug overlap. There are 15 possible lugs settings with overlap: 1-2, 1-3, 1-4, 1-5, 1-6, 2-3, 2-4, 2-5, 2-6, 3-4, 3-5, 3-6, 4-5, 4-6, 5-6 If we want to represent the whole cage, it is simple to add each bar contribution for each case on the Array of 21 cases. If we translate the last example: 1:12:4:2:7:7:0:0:0:1:0:0:0:3:0:0:1:0:1:0:0 The overlaps (4): 1-5:1 2-5:3 3-5:1 4-5:1 If we separe the Array in two (without and with Overlaps): 1:12:4:2:7:7 0:0:0:1:0:0:0:3:0:0:1:0:1:0:0 The first part is known as the Array of "Kicks" Algorithm --------- 1. Set the external initial wheels settings to the default value "AAAAAA", or to the original external settings if those are known. 2. Generate initial random pins and lugs setting, decrypt and compute an inital score with the ADE fitness function. 3. Repeat the following three loops (3.1, 3.2, and 3.3) until the ADE no longer improves. 3.1. Repeatedly perform the set of all pins setting transformation as long as the ADE can be improved. 3.1.1. Repeatedly perform the Toggle transformation as long as the ADE gives a better score. Each Pin is considered in turn. 3.1.1.1. Toogle the state of one the pins of one of the wheels. This means that if the pin is currently effective, then set it to ineffective, and if it is currently infeffective, then set it to effective. 3.1.1.2. Decrypt and Compute the fitness function 3.1.1.3. If the score with the new pins setting is better, keep the new pins setting. Otherwise, discard the new pins setting. 3.1.2. Repatedly perform the Swap transformation as long as the ADE gives a better score. Each pair of pins is considered in turn. 3.1.2.1. For a pair of pins, where the pins are not in the same state, toggle the state of both bins. For this transformation we consider any pair of pins, i.e. Either two pins in the same wheel or in different wheels. 3.1.2.2. Decrypt and Compute the ADE function 3.1.2.3. If the score with the new pins setting is better, keep the new pins setting. Otherwise, discard the new pins setting. 3.2. Repeatedly perform a subset of the lugs transformation which do not involve lugs overlap as long as the ADE can be improved. For each one of the 6 kicks, and the remaining 5 kicks, do the following steps: Remark: the kicks are the number of lugs front of a wheel. 3.2.1. Reduce the count of the first kick and increase the count of the second kick. 3.2.2. Decrypt and Compute the fitness function 3.2.3. If the score with the new pins setting is better, keep the new lugs setting. Otherwise, discard the new lugs setting. 3.3. Repeatedly perform the complete set of the lugs transformation as long as the ADE can be improved. a) Swap between two types of lugs settings without overlaps: For each of the 6 non-overlap types, and each one of the remaining 5, reduce the count for the first type, and increase the count for the second type. If the first type already had a count of 0, we skip this case. b) Swap between any two types of lugs settings, with or without overlap: for each of the 21 types, and each one of the remaining 20, reduce the count for the first type, and increase the count for the second type. If the first type is already had a count of 0, we skip the case. 3.3.1. Swap between elements (with or without overlaps). 3.3.2. Decrypt and Compute the fitness function 3.3.3. If the score with the new pins setting is better, keep the new lugs setting. Otherwise, discard the new lugs setting. 4. If the new score if better that better score, fix the better score to the new one and print this score, the key and the beginning of the plain text discovered. 5. Repeat from step 1, i.e. restart with new random pins and lugs setting. Stop if the timeout is reached. The ADE fitness function ------------------------ George Lasry started to use a very simple fitness function (I call it PLN): He just count the number of plaintext letters correctly found after decryption. But it was necessary to have a ciphertext of at least 300 characters long to find the key. Then he created the ADE (Aggregate Displacement Error) fitness function. It sums the differences between the Expected displacement (deduced from the true plaintext) and the Actual displacement (deduced from the current key tried). sum = 0 For each letter "i", ExpectedDisplacement[i] = (CipherLetter[i] + PlaintextLetter[i] - Z)%26 sum = sum + abs(ExpectedDisplacement[i] - ActualDisplacement[i]) Shorter the sum is, better is the score. If the sum is 0, we have found the key. Special care is needed for expected displacement values 0 et 1, which can be ambigous. Because of the modulo 26 operation, there is no way to differenciate between original displacement values of 0 and 26, as well as between displacement values of 1 and 27. When we compare the actual displacement which may have value 26 or 27, we assue the lowest (optimistic) possible displacement error value. For example, if ExpectedDisplacement[i]=0 and actualDisplacement[i]=23, then the error is assumed to be 26-23=3, rather than an error of 23-0=23. Remark: In my software, higher the ADE score is, better it is. I chose this strategy to be able to treat it in the same way that other fitness functions. Remark: Rafael Pascual wrote an implementation of George Lasry's algorithm (with it, he solved my 12th bonus). He changed slightly ADE algorithm: In any case, he takes the smallest difference between the theoretical and calculated displacements: sum = 0 For each letter "i", ExpectedDisplacement[i] = (CipherLetter[i] + PlaintextLetter[i] - Z)%26 difference = abs(ExpectedDisplacement[i] - ActualDisplacement[i]) if difference > 13 then difference = abs( difference - 26 ) sum = sum + difference I found that its algorithm converges faster That original ADE algorithm. I called ADE2 this new fitness function. References ---------- "Automated Know-Plaintex Cryptanalysis of Short Hagelin M-209 Messages" by George Lasry, Nils Kopal & Arno Wacker, Cryptologia, Published online: 06 Jul 2015. Examples -------- In the following examples, I tried to find the key of several ciphertexts. I start with a message of about 500 characters (wiki2.cry), then with a text of 200 characters, until 75 characters. I used statistics based on English texts with spaces replaced by "Z" letters (like the M-209 convention). My software finds Pins and Lugs setting. I used mainly the Lasry's ADE fitness function, but I tried also the PLN fitness function. $ cat MSGS/wiki2.cry # The Cryptogram APQGD JBTIH IWNOK CNSDS DXGPK DSAGX TDMZL SKHCO UBVOA DBCZI KZHWB JZQCZ UTFIW GEHME JWVHX CZZBU JDMZE VXPKL IUJZA FFZGC GDAQG KGHDE CAXMP RYLOL TKTIM PEYQK GVUMJ XXKWO BLKEV PHHWE JRVKW AHTHW ZHBWN OJGMP EADMB ITTYZ DIUSS UWVFP DRXUS RSSJE JJYAQ AYLRB XHICN CDKER VAHQE AAYIC WPWCK KUJMX VARAJ VTZPT VLVTD YJEYW VTAKC WWXMD PWKHF OUARN ZGLFC DOPYS CADQL LCQQW KVAXI GZBIV XFTME ODBPA LITHH PIRQE RWULW HYNUI YAIVP ACOWT LDOLO ADBZM XUYOG GLKGB DHHQG LPELQ OLUYT XJFUX MSCXU CHXWI CXLVP NODAH FQLWD JHAUC FRLXC ODKIT OPCBW KWORV OKZNE IPBSV ETWFY XDFNK SSIKS IMIPK PXVFB FZWVH YNDGK XDJJV SDJWQ TPFRU DRIKQ OXCYX OFQHY OCHKL LRZWG KFAKA WKYHT VVVLG GDAIQ DOASL $ cat MSGS/wiki.txt # The Plain text TOZEN CIPHE RZAZM ESSAG EZTHE ZOPER ATORZ SETSZ THEZK EYZWH EELSZ TOZAZ RANDO MZSEQ UENCE ZOFZL ETTER SZANZ ENCIP HERIN GZDEC IPHER INGZK NOBZO NZTHE ZLEFT ZSIDE ZOFZT HEZMA CHINE ZISZS ETZTO ZENCI PHERZ AZDIA LZKNO WNZAS ZTHEZ INDIC ATORZ DISKZ ALSOZ ONZTH EZLEF TZSID EZISZ TURNE DZTOZ THEZF IRSTZ LETTE RZINZ THEZM ESSAG EZTHI SZLET TERZI SZENC ODEDZ BYZTU RNING ZAZHA NDZCR ANKZO RZPOW ERZHA NDLEZ ONZTH EZRIG HTZSI DEZOF ZTHEZ MACHI NEZAT ZTHEZ ENDZO FZTHE ZCYCL EZTHE ZCIPH ERTEX TZLET TERZI SZPRI NTEDZ ONTOZ AZPAP ERZTA PEZTH EZKEY ZWHEE LSZEA CHZAD VANCE ZONEZ LETTE RZAND ZTHEZ MACHI NEZIS ZREAD YZFOR ZENTR YZOFZ THEZN EXTZC HARAC TERZI NZTHE ZMESS AGEZ $ python HC_KPA.py -h usage: -c crypto The cryptogram -M method The method (BIG,TRI,...), default: ADE -m file_method The file used with method -l letter The letter (shift, default: Z -P pins The Pins -L lugs The lugs (ex: 1:5:4:13:2:7) -O overlaps The overlaps (ex: 0:0:1...:1:1) -S list Skip P(ins), L(ugs), O(verlaps) -t tries Number of tries, default: 15 =========== 1) Try to discover the key of a text about 500 characters $ time python HC_KPA.py -c MSGS/wiki2.cry -M ADE -m MSGS/wiki.txt -t 5000 0 >>>MAX SCORE: 14234 == UOAENCIPIEQZAZMERSAGEZTHFYNPESBTORZSETSZTHEZKEYYWH CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 9, 1, 3, 12, 1] [0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 3] 1 >>>MAX SCORE: 14258 == TOZENCHPHERZAYMERSAGEZTHFZOPESATPRZSEUSZTHFZKEYYWG CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 8, 2, 3, 12, 1] [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 3] 3 >>>MAX SCORE: 14404 == TOZENCIPHERZAZMESSAGEZTHEZOPERATORZSETSZTHEZKEYZWH CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 8, 1, 3, 12, 2] [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3] Then We can decipher the ciphered message with the key: $ python m209_tui.py -L 4:8:1:3:12:2 -O 0:0:0:0:0:0:1:0:0:0:0:0:0:1:1 -P 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 < MSGS/wiki2.cry TOZENCIPHERZAZMESSAGEZTHEZOPERATORZSETSZTHEZKEYZWHEELSZTOZAZRANDOMZSEQUENCE ZOFZLETTERSZANZENCIPHERINGZDECIPHERINGZKNOBZONZTHEZLEFTZSIDEZOFZTHEZMACHINE ZISZSETZTOZENCIPHERZAZDIALZKNOWNZASZTHEZINDICATORZDISKZALSOZONZTHEZLEFTZSID EZISZTURNEDZTOZTHEZFIRSTZLETTERZINZTHEZMESSAGEZTHISZLETTERZISZENCODEDZBYZTU RNINGZAZHANDZCRANKZORZPOWERZHANDLEZONZTHEZRIGHTZSIDEZOFZTHEZMACHINEZATZTHEZ ENDZOFZTHEZCYCLEZTHEZCIPHERTEXTZLETTERZISZPRINTEDZONTOZAZPAPERZTAPEZTHEZKEY ZWHEELSZEACHZADVANCEZONEZLETTERZANDZTHEZMACHINEZISZREADYZFORZENTRYZOFZTHEZN EXTZCHARACTERZINZTHEZMESSAGEZ =========== 2) Try to discover the key of a text of 200 characters $ time python HC_KPA.py -c MSGS/wiki200.cry -M ADE -m MSGS/wiki.txt -t 5000 0 >>>MAX SCORE: 4501 == VPXCPEIPJEOPGWMJASBEHXFWFOOLCSDXNRZTAGSXTJBZJDUSXD CLE: 00111110110100010101100101111100001011101000011001110001110111110111101110010100101010100010000111110101001010110011000111001001000 [2, 5, 5, 5, 7, 4] [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1] 2 >>>MAX SCORE: 5078 == SPZFNDIPHERZBXMFTRBFFZTHEZOQDSZTQRYTEVRBUHEALEXXWH CLE: 00101100110000011001001001101100101010100001001001101101011101101011001111110001100101101100011101110100001010110000000000000000000 [5, 7, 3, 3, 13, 1] [0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 5] 7 >>>MAX SCORE: 5118 == SQAFOCIPIERXBZNFTRAGFBTIFZOQESAUOSYTETTATHEYLEXZVH CLE: 00101100110000011001001001101100101010100001001001100101000101100011000111110001100101101100011101110100001010110011000110011010101 [6, 8, 1, 3, 12, 2] [1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5] 8 >>>MAX SCORE: 5176 == TPZDNCIPHERZAZMESSZGEZTHEZOQERATORZRETSZTHEZJEYZWG CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [5, 8, 1, 2, 12, 2] [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 3] 16 >>>MAX SCORE: 5200 == TOZENCIPHERZAZMESSAGEZTHEZOPERATORZSETSZTHEZKEYZWH CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 8, 1, 3, 12, 2] [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3] =========== 3) Try to discover the key of a text of 150 characters $ time python HC_KPA.py -c MSGS/wiki150.cry -M ADE -m MSGS/wiki.txt -t 5000 0 >>>MAX SCORE: 3366 == VXBDNDIOJHWVBXIFZUGNIYLBBLPMFRPPSSFREJRYOLMYEGUAWE CLE: 10111110011111011101101100111000000110111001100001101001010100011010011011000110101000111010101100110100101010000010100001010101110 [3, 5, 5, 5, 6, 5] [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2] 2 >>>MAX SCORE: 3447 == VRYANJNMHFLSZXJGQXCDDBEEFWNPGXASASZREUSSXLNBNCTXPJ CLE: 10110000010110011111001101001100001010110001111000100000000110111000111011111111101011111000000101110100101010010010100000111000101 [2, 5, 6, 5, 8, 4] [0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 3] 14 >>>MAX SCORE: 3539 == UOZKNDMRKGQTJYKFUUFEEZTDAOPQFUBPRSBVKFSYSGFBPARBVH CLE: 01101100100000010010001100111100111010101001011001111111010111000111001101110101100010101010111101110100101010110001010000000001100 [4, 6, 4, 6, 7, 4] [0, 0, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4] 20 >>>MAX SCORE: 3752 == TOZEPFIPIFNZCYHESQZGDBTHCZNQGSAURRBRDSRWSHDYNFYZVE CLE: 00101100110000011001101101101100101010100001001001100100000110101010101110101000100011101100010101110100001010110000101110011000100 [4, 7, 3, 4, 11, 2] [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 4] 21 >>>MAX SCORE: 3880 == TPZDNCIPHERZAZMESSZGEZTHEZOQERATORZRETSZTHEZJEYZWG CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [5, 8, 1, 2, 12, 2] [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 3] 46 >>>MAX SCORE: 3900 == TOZENCIPHERZAZMESSAGEZTHEZOPERATORZSETSZTHEZKEYZWH CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 8, 1, 3, 12, 2] [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3] =========== 4) Try to discover the key of a text of 100 characters $ time python HC_KPA.py -c MSGS/wiki100.cry -M ADE -m MSGS/wiki.txt -t 50000 0 >>>MAX SCORE: 2238 == VVZILCMPDEWSBZIHRQIPGPTDISOKRRGSORZRHLOYYEIRIKAWVJ CLE: 00000001001110111100101110111110000101111001101000011111011010010110101010011110011000011010011010000100111011010011011101010000101 [7, 10, 3, 1, 5, 1] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2 >>>MAX SCORE: 2253 == TPBDNDIOIDUYAZMKUFKNEQKUDRTOFWJWISZSJMOYSIKWKEVAPH CLE: 10000010010101011100001100111100111011011010000001000011011100111011111001001101101000000010001001101100011010010011000000101001011 [5, 3, 8, 11, 3, 3] [0, 1, 1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 1, 0, 6] 3 >>>MAX SCORE: 2271 == VLYGRFJTHDITABQGZXBBEYTGEQTQERBXSNZVMZRZTHBASGSQSC CLE: 11000110001110011001001111101010101011001101010100010110010010111110111000100010101111011110001101100000001111111011000111000110001 [7, 5, 6, 4, 4, 1] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 4 >>>MAX SCORE: 2276 == YQBHPGNNHMQZYZLFUSHGEYTGBRPPGPYPMQZSFOOWVHVZKINVYM CLE: 10010000101110110000010011011101101010001001101101101000000011011110111110111100101100011010000111111100011011110001010011111011110 [8, 3, 4, 3, 8, 5] [0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 4] 6 >>>MAX SCORE: 2280 == MPZQNDJRGDPVAWPHVGJHHVSDIZSPFQDMRRBQFJYWWHDYLEQKYH CLE: 10100111000101010011001001010010100111110011011011101000001101101100010001011010100100111011110101110000100011100011100010011101111 [8, 8, 2, 2, 6, 1] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 8 >>>MAX SCORE: 2291 == ZSBHOBELHETVABNHVRHHEUJCIONMBSGZPPPTETSBSHRYKEYXKH CLE: 10100010110110111100001100111100001010011000100001011011101010001011001001000111011001011100111100000111011011110001001101001111011 [4, 10, 2, 1, 8, 3] [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] 9 >>>MAX SCORE: 2335 == SVZHLBIQKDKXCZJFGSIFEUTSPTOOFSCQPUZWETTZTGEARHVBQH CLE: 10100010110110111101101111111100011011001001110001000011110000110000000100010100011010010010001101110101011011001000001001110011001 [7, 4, 6, 4, 8, 2] [0, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4] 10 >>>MAX SCORE: 2396 == UMZFOEFOIEOYYZLFYSJEGWTHENOPEUAYNRZUDPSXVHBBMFXZWH CLE: 11101100110010010000001001111101101010101001000001111111111011101010111100100000000000000110001101100100011010110001110011000111001 [5, 6, 5, 4, 11, 2] [2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 6] 71 >>>MAX SCORE: 2398 == TPBGRCIPGGPZEBLDSSBHEYHEDOOMEVYTPPZTCKRZTGEZNCTMWD CLE: 10111100111110110101101000111100101011101001101001111001111010110010001111010110111101010110000101110100001010110011110010000111000 [3, 8, 2, 1, 9, 4] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 147 >>>MAX SCORE: 2406 == TOZDNCLOKCPYCYNCNUIHEYTIEXNPDVAURTBXEMSVVIDBJEXGVH CLE: 00001110110010010000001101101101101010100001001001100011010010000100001111100000010100100011000101110101011010110000011111011011101 [5, 5, 4, 1, 11, 5] [0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4] 148 >>>MAX SCORE: 2422 == TOZEKCFQHNNYAYMDSSCGGZGHDGLNMSATNQZRESSYVEFBMGXQZH CLE: 00011100110110011010101001101100101011100001001001011110111011111010000100110001000101100110011111110100001010110001110011000110000 [2, 7, 4, 4, 10, 2] [0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2] 179 >>>MAX SCORE: 2477 == TQZFLBTPFERYBZLDSUAEFYTIEPNOEQASORZTETQYTHDBKEYYYG CLE: 01101110110000011000000001100100100010100001001001110010000010001010000100110011001111000110011101110100001010111010100010110101100 [5, 10, 5, 3, 11, 1] [3, 0, 0, 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8] 212 >>>MAX SCORE: 2549 == TOYFNDJOGERZAAMFTSAGEZTIEZOPFRYTQRZRFVTZTIEZJEYAWG CLE: 00101100110000011001001001101100101010100001001001100000000100001000000000110001100101101100011101110100001010110011101111111011101 [4, 8, 2, 2, 13, 3] [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5] 234 >>>MAX SCORE: 2555 == TPZFNCIOHERZAZMDRRAFEAUIGYNPETATORYSDTSZTGEZKEYZWH CLE: 00101100110000011001001001101100101010100001001001111110011101111111001101110001100101101100011101110100001010110011101111001001101 [4, 8, 1, 3, 12, 1] [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2] 558 >>>MAX SCORE: 2558 == ROZEOCJOIERABZNESSAHDZTIFYNPFSAUOSZSETUZTGEZKEYZXH CLE: 00101100110000011001001001101100101010100001001001110111110110101001000011110001100101001100011101110100001010110011101111011010101 [4, 9, 1, 3, 12, 2] [0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 4] 763 >>>MAX SCORE: 2573 == TPZENCHQHEQZAZMESSAGFZTHEZPPDRATPRZSEUSZTIEZKEYYWG CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [5, 8, 2, 2, 12, 1] [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3] 1144 >>>MAX SCORE: 2574 == TPZENDHPHDRZAZMFSRAGFZTHEYOPERATORYSETSATHEZKEYYWH CLE: 00101100110000011001001001101100101010100001001001101101001101101011010111110001100101101100011101110100001010110011101111011010101 [5, 8, 1, 3, 12, 1] [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 3] 1416 >>>MAX SCORE: 2600 == TOZENCIPHERZAZMESSAGEZTHEZOPERATORZSETSZTHEZKEYZWH CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 8, 1, 3, 12, 2] [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3] =========== 5) Try to discover the key of a text of 75 characters $ time python HC_KPA.py -c MSGS/wiki075.cry -M ADE -m MSGS/wiki.txt -t 50000 0 >>>MAX SCORE: 1723 == SNZGNTNRHERUBPMCSGEHPZVKCNNPFRIXMRBXQTQYTNEZUCYBYF CLE: 01101110110011110010011110000100111010110001000101001000110011011111110000001101001011101010101110101101101110110100101011111001100 [2, 8, 2, 13, 1, 1] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2 >>>MAX SCORE: 1748 == SQYEMHKPNFNZABNISSBMEBIOENORIXBNIUWSEUNVSHNBHEXBYJ CLE: 01110001100001110101110001001110011110001100100001101010010001111110010010111101101000100010111101101100000011010000100101011001110 [3, 2, 4, 9, 9, 2] [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2] 5 >>>MAX SCORE: 1785 == PUZFNCJQHEXZCBPHNTHCGWPGBRNLESRQSRZSETSBQKEBLHUPWH CLE: 11110110101111111100101000111101101011001000101001001011110011111010000110000100011010001111100111100101010001110001000101110111101 [5, 6, 5, 1, 6, 5] [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1] 8 >>>MAX SCORE: 1789 == UPKCKEFLHGQZYZMEUTBEFWUJHOQPFSASQQZSDTSXYJPZOEYSWH CLE: 11110010101110101100011001101101001010101010001000111000001001101111000100110011101111001111001111110100001010110001001111111010000 [1, 6, 4, 5, 9, 2] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 24 >>>MAX SCORE: 1795 == OQBINDNPFBRYEBKFSTBEIWUGEZTTEPLVRNYRDRUBRFFZMCVBPF CLE: 10100010110011011000101110111100001010100011101000001011110010011100000010000100101011001011001100110101011010010010100001101001101 [5, 11, 1, 3, 5, 4] [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2] 43 >>>MAX SCORE: 1816 == SMZEPDKMJFYZBZMKWTAHFZTIEZPOHRYSNRBTEVRZUJEYKHRTOG CLE: 00100100101010010010001000101101101010100000101000101110001001001100101110100101101111101101101110110110001010110001001011000011000 [4, 7, 2, 4, 11, 3] [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 4] 67 >>>MAX SCORE: 1856 == UMZFMCKRJEPZYZLFSSAFEYVGHHLPDSBSTRZRDWSZTHEXLEWBWH CLE: 11101000110000111001101001101100101010100001001001110011110011111011001101111001100111101110111101110100001010110011000010011000000 [2, 7, 2, 4, 10, 4] [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2] 420 >>>MAX SCORE: 1876 == TPZENEIOGFQABZMBSSBHCXTHFMMPESYTPRZSFTSZTGEBJCYYXJ CLE: 00101100110010101001001001101100101010101001001001111010011111100011001101110011111101000111010101110100001010110011101101000110000 [3, 8, 2, 1, 13, 2] [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 2] 554 >>>MAX SCORE: 1891 == SPZFKCIPHERZZZODQSAHEZUHEBOPERTTORZSDUTZWHEZKBYYWH CLE: 00111100110000111000001001101100101010100001001001111100001110011111000111010000100101101000011101110100001010110010100000000001100 [4, 10, 1, 3, 12, 2] [0, 0, 1, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 5] 2194 >>>MAX SCORE: 1915 == SQAFOCHPGERYAAMESSBGEXTHFZOQESAUORZSEUSZTHEZKEYZWG CLE: 00101100110000011001001001101100101010100001001001100000000110000011000111110011101101101110011101110100001010110010111111011111001 [5, 7, 1, 2, 12, 2] [0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2] 7467 >>>MAX SCORE: 1923 == SPZEPDHPHERYAZMESRAGFZTHFZNQESATORXSETSZTHEZKEYYVH CLE: 00101100110000011001001001101100101010100001001001100100001101000000000101110001100101101110011101110100001010110010111110011011101 [5, 8, 1, 3, 13, 1] [0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 4] 12176 >>>MAX SCORE: 1950 == TOZENCIPHERZAZMESSAGEZTHEZOPERATORZSETSZTHEZKEYZWH CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 8, 1, 3, 12, 2] [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3] =========== 6) Try to discover the key of a text of about 500 characters but I used the PLN fitness function. Remark: I tried also the PLN fitness function with shorter messages (200 characters), but without result. $ python HC_KPA.py -c MSGS/wiki2.cry -M PLN -m MSGS/wiki.txt -t 50000 0 >>>MAX SCORE: 0.140794223827 == FGXFLFVHKEDBAZABRBAUKEMMICMAEQVLGNAWZIOWCZGIFAOZTZ CLE: 10110010010101001111110111001010000100010110100010011101101010101111100011001100001010010000100100110001011000011011111110011001111 [10, 3, 1, 8, 4, 1] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 1 >>>MAX SCORE: 0.151624548736 == VVACZEVGAGIPFZYRSDGBQOTHZZYNBQDMUKPYIWOZDPWDKHOOKN CLE: 01000111000110111011011111110011000111010010000101011100101011011001001110110011101111111001110000111110000100111010000110001010011 [2, 4, 7, 8, 1, 5] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 6 >>>MAX SCORE: 0.191335740072 == MZBLPBIPIDMWZBHFOXAGZXBLFZTJIBTRQLFSETYXVBXERCSZVJ CLE: 01100011001110110111110001101100101010100101101001111100110111101011000111000010101010011100011101110100001010110010110111001101111 [1, 8, 2, 6, 9, 1] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 11 >>>MAX SCORE: 0.4440433213 == SRYFOEJOGESZAAMETSAHEZWHEZORFRZTQSZTEVTBTGFZLEYAWG CLE: 00101100110000011001001001101100101010100001001001111111111111111111111111110001000101101100011101110100001010110000000000000000000 [4, 8, 3, 1, 11, 2] [0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2] 47 >>>MAX SCORE: 0.51083032491 == AVZXUCBWHXRSAZFLZLAGLSTAEZVWXRHMOYSLETLZTOEZDLYZPH CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [11, 1, 1, 3, 12, 2] [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3] 149 >>>MAX SCORE: 0.723826714801 == TOZENCIPHERZAZMDRSAHEZTHEZOPERATPRZSEUTZTHFZKDYYWG CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 9, 2, 2, 12, 1] [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 3] 271 >>>MAX SCORE: 1.0 == TOZENCIPHERZAZMESSAGEZTHEZOPERATORZSETSZTHEZKEYZWH CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 8, 1, 3, 12, 2] [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3] ============ 7) Try to discover the key of a text of 75 characters but with the Rafael Pascual's modified ADE function (ADE2) Remark: the number of Shutgun restart is less than the George Lasry's original ADE function. $ pypy HC_KPA.py -c MSGS/w2_075.cry -M ADE2 -m MSGS/wiki.txt -t 5000 0 >>>MAX SCORE: 0.877435897436 == OJZEPCUPFGVZFAQFWUKIWYPHVWVPURIXVSXSBLQCTHYELGYAQF CLE: 10100000010111111100000000011000100000011001110001100011001111101000011110001110101001111010110111000000110110001001101100010101111 [5, 1, 1, 8, 3, 10] [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] NoD: 22253 6.88939595222 1 >>>MAX SCORE: 0.911794871795 == TPBENAHOIFRWHZWEXSIGESXFDAPPHPYQNRVVENOZVGDXJEJBUZ CLE: 11100100100011010101100011111010111010100011100010111001010111001110000110110100000010100000101000110000111101110110010001001001111 [7, 7, 4, 6, 1, 3] [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] NoD: 40167 11.7436609268 2 >>>MAX SCORE: 0.923076923077 == VOAHNBIPKCWABZMXTTXEEUTFCPONJQTRRSBUCSQZSHAFQEVAXE CLE: 00100011110011100100100010111110111010101011101010001101100110101010000110100010110110100011000101100110011000110010101001110101000 [4, 10, 5, 3, 5, 4] [2, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 4] NoD: 84583 23.434278965 9 >>>MAX SCORE: 0.924102564103 == VQDENDKRHDXZCZLGAWCBFYPJEONQETXBPRZSGRRZUIFXKFUIWI CLE: 11111110111111011101001010111100101011111010100001001111110010111010011110101101000000110011110101100100111011110001000000010001001 [4, 6, 5, 2, 6, 5] [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] NoD: 340682 87.513217926 11 >>>MAX SCORE: 0.945128205128 == YPZFNFBOFEOBXANBSSQHCZVHHDORDUAXPRYSETSWUGDCMCYZVH CLE: 10111111110001011001001001111100101010101001000001101111000110111001111101110010111101101100111101100100011010110010100110010111000 [3, 7, 2, 1, 13, 2] [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] NoD: 402044 103.00925684 21 >>>MAX SCORE: 0.951282051282 == TPAENXGPHERAFZMCTSWGFAXFWAOPERZUNSZSDTRZUHEZKDYZVI CLE: 10101111110001011000101111111100111010100001001001110011011111101011011100110011110101110110010101110100011010100010101010000011110 [3, 6, 2, 2, 13, 2] [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1] NoD: 744359 188.655479908 433 >>>MAX SCORE: 0.986153846154 == TOZFOCIOGERZZAMERSAHEZTIFZOPERATORZSEUSZUGDAKDYZWH CLE: 00101100110000011001001001101100101010100001001001110110111101101001000101110011100101101110011101110100001010110010101011001011001 [4, 8, 1, 3, 12, 2] [0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 3] NoD: 14547653 3594.73553586 3667 >>>MAX SCORE: 1.0 == TOZENCIPHERZAZMESSAGEZTHEZOPERATORZSETSZTHEZKEYZWH CLE: 00101100110000011001001001101100101010100001001001101101001101101011000111110001100101101100011101110100001010110011101111011010101 [4, 8, 1, 3, 12, 2] [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 3] NoD: 121795651 59420.5847399