Zodiac Discussion Forum

A Solver for Mac Us…
 
Notifications
Clear all

A Solver for Mac Users

27 Posts
4 Users
0 Reactions
3,996 Views
(@largo)
Posts: 454
Honorable Member
Topic starter
 

Hi,

I’m one of those people who always like to learn new things. That’s why I took a closer look at the programming language "Swift 4.1" and app development on the Mac. Since z340 is also a hobby of mine, it was obvious to combine these two. The result is a simple solver that is a combination of Peek-a-boo and AZDecrypt. Since it is not a port of Peek-a-boo, I chose a different name: "Your Secret Pal". A little macabre and ambiguous, I know.
So far I have only implemented the absolute basic functions, but homophonic encryptions can be solved very well. Depending on the settings, z408 takes between 0.17 and 0.7 seconds (iMac 27′ late 2013). I don’t support multithreading at the moment.
The statistics for the Unigram distribution are quite nice, because they update themselves live. If you type something in the left text window, you will see the results immediately. As with peek-a-boo, I attach great importance to visual representations.
The solver is quite robust, but not yet as reliable as AZDecrypt.
My goal is to develop a general cipher tool that focuses not only on homophonic encryption and z340. If I find the time, I’ll add Vigenere and other methods. I just enjoy working on things like that :)

Here is a screenshot:

Depending on how much time I find, I will release a first version in the next days/weeks. If you are using a Mac and would like to beta test it, please send me a private message and I will send you a preview. That would really help me develop a more stable version.

Translated with http://www.DeepL.com/Translator

 
Posted : August 30, 2018 2:50 pm
Jarlve
(@jarlve)
Posts: 2547
Famed Member
 

It looks good Largo, don’t have a Mac though.

AZdecrypt

 
Posted : August 30, 2018 5:12 pm
doranchak
(@doranchak)
Posts: 2614
Member Admin
 

Nice job Largo! I am on Mac and would enjoy playing around with this new solver.
Thanks!

http://zodiackillerciphers.com

 
Posted : September 4, 2018 1:59 pm
(@largo)
Posts: 454
Honorable Member
Topic starter
 

I have added some new features in the last days. However, I don’t want to release today, because the version is not stable enough yet.

However, I’m pretty excited right now, because my experiments with my transposition solver have just delivered some useful results.

To break stacked transpositions, I don’t use a hillclimber, but a genetic algorithm. For a first test I transposed a plaintext in four different steps and then encoded it monoalphabetically. Tests with homophonic encryption will follow as soon as my test results are somewhat better.

Plaintext: First 340 letters of z408 (I LIKE…)

Transposition steps:
– Rotate clockwise
– Transpose Period 3
– Transpose Diagonal 9. This means "Start Top Left, reverse each second diagonal line" (in other words: alternating reading directions)
– Reverse

Cipher:

TTSLTOMLOTTWUTEURSKS
SERRSOCAMEASFMAGWQFT
TITOFDDSFBCQGEADCGIF
MWDOOLSBXODFFASTGTMF
TFSMOFTAUFSSWTMYAOKM
GOTAZWZOWTAYDAITFTBO
RKTOHTCTOUUKKBATSGOL
LOAADOHOASODMIOSMOZT
MISTMUKFOAMFFYTTMOAM
AWFATIDKTMSFTHALAIOL
KMOYDTOAKTGSAOHCIUSO
TGTGDKITTGZGLTTCUXXS
XCAOMMMSKGLZOLHKTGTM
TKIDMQUGGSXOTASOMKET
IGAKGFLSTOAFLLSBIFIS
GUYZTMFYROGMWSMQWSYZ
UDLWEIEOELOBQTRMTQOZ

After 19 generations the following solution was found:

EYOUWIGPEOPLILIKEKILLINSSOMUCEBECA
USEITIEFUNTHHFUNITIAMORLDGAMEANKIL
LINGWITBECAUINTHEFORRESOATDANSEMAN
ISTHEMLOFALLGEROUEANAMAHINGGITOKIL
LSOMETTTHRILVESMETHEMOACEETISLINGE
SPERENHANGETEVENBETTERTKSOFFWTINGY
OURROCBESTPAITHAGIRLTHEWHENIRTOFIT
IATHAEBORNIDIEIWILLBEREALLTHNPARAD
ICEANDWILLBEIHAVEKILLEDSIWILECOMEM
YSLAVEYNAMELNOTGIVEYOUMLLTRYBECAUS

That’s far from perfect, but not bad for a first try.
There is still a lot to do…

Translated with http://www.DeepL.com/Translator

 
Posted : September 13, 2018 10:10 pm
Jarlve
(@jarlve)
Posts: 2547
Famed Member
 

Amazing Largo! What is a generation? How many iterations are these?

AZdecrypt

 
Posted : September 14, 2018 4:31 pm
smokie treats
(@smokie-treats)
Posts: 1626
Noble Member
 

Largo:

The computer chooses a random path through the message, but with some periocity or pattern? Lots of different paths that are slightly different, and then save the ones with the best scores and combine them somehow? Do another generation, again and again? How does this work?

 
Posted : September 14, 2018 9:34 pm
(@largo)
Posts: 454
Honorable Member
Topic starter
 

Jarlve, smokie:

Currently the method is quite simple and the algorithm is rather "naive". So far I have only implemented predefined transposition steps. Smokie, the idea with the paths is very interesting, but also difficult to implement. I’ll give it a try, I like that idea!

That’s how it works at the moment:

A Gene:
A "gene" is simply an integer that represents a certain transposition. Like this:

0 = No transposition
1 = Flip
2 = Mirror
3 = Reverse
4 = Untranspose best Period
5 = Diagonal 1
6 = Diagonal 2

And so on and so forth. Currently I have implemented about 25 transpositions/untranspositions.

Individuals (DNA):
An "individual" is a sequence of the genes shown above, i.e. a DNA strand. The length must be determined first because all individuals have the same length. For example 2, 5, 4, 1 means "Mirror/Diagonal 1/Untranspose best period/Flip"

Population:
A population is a collection of individuals. All individuals of a population are run through for each run. For each individual, the original cipher is transposed using the DNA values. The result is then transferred to the substitution solver. The achieved score is stored in the individual as a fitness value.
Afterwards the next generation is generated. For this, the individuals of the current population are picked out, whereby the fittest are given more preference. These are then crossed with each other (crossover) and mutated on the basis of a probability (the transposition of a gene is randomly exchanged). Thus, a new population is created by simulated genetic inheritance of the old population. This will continue until a defined termination condition is reached. Either a maximum number of generations or a threshold value of the score is reached.

The concept of genetic algorithms is explained in more detail on the following page:
http://www.ai-junkie.com/ga/intro/gat1.html

The drawback is that transpositions can repeat and override each other when the DNA strand is long. For example, 0-2-2-3-3-5 would simply be "Diagonal 1". Another disadvantage is that many similar transpositions can currently be found in the DNA strand directly after each other. For example, 2-5-6 is a rather unlikely solution (mirror, followed by diagonal 1 and diagonal 2). However, here I have an idea that I will implement next:

A gene will get additional information to describe the transposition in more detail. Then, for example, there will only be one gene for "diagonal", which will then contain the reading order as additional information. When mutating, either the entire gene will be exchanged, or only the additional information will be modified. This then gives me the possibility to apply transpositions only to certain areas of the cipher (start and end points are given as additional information).

The difficulty at the moment is to set the parameters in a meaningful way. In the example shown above, each generation has a population size of 150 individuals with a DNA length of 4. The substitution part is solved with a hillclimber and simulated annealing, just like Jarlve does. For a monoalphabetic substitution between 1000 and 5000 iterations are sufficient. For the solution shown above 150*19(generations)*5000 = 14.250.000 iterations were required. With a homophonic substitution this amount increases.

As I said, all this is still in its beginnings and is not yet effective/performant. So far, however, I like the approach. If, for example, Feynman 1 is substituted with homophone substitution, my solver will find a solution. Unfortunately, it takes 1-2 Minutes to get a reasonable solve.

Starting test: Evolve Stacked Transpositions

;aXLdhFoc9nwxlkE:JjA
uDq3iC7=y+Y0T1sRYPrX
=g2GXAUN5V=KBpaXLqYF
EZdxw=2MWXsN37LjyYDH
:TYp+=kXlbI=tnGRuev0
PgaXYJ;VUFAqBIw=x73i
:jy2p+ZsNFR;0obA12ht
dPLHDpuFg;wasnIKlxkX
3=yq+EI20NiPBJpGU7RE
XZdg=e;LSVtM:wHckXna
FA2xpqDTQsC3GFy+70bN
VRQ5=rXP2=LtAloiThI1
qKpXg;nwGVavZSrF=2X=
peBbFsx3cMyQtuojUC25
hdYepnF1c2YK7lNXC5Mh
opFRl+;Lc0TDIP:AGgqu
axVTCY243t=wyQYp7sTi
N5+nLhF0PZlwlQ2sd1gN
pFKHRJacxDTA2pFq72Ll

Generation: 1 Fittest: 13646.7785752307
Reverse, None, Untranspose best period, None

WTANTHATIRCALLAWITHH
OMETOYBUTMOOTISHASBO
CHTYORRACSTHISTRALSY
STOSTABOOSYINDWITHES
UREEDREDNEINEWICHLIS
OFLORWHOSTREESFUNDAN
DEUSIMTHERCOMEWHANGE
RHOLYTIEDWITHHISTWAY
SINBURTTONTRACEGHASH
INERALDHOLTINGHIESTT
HASINGBACCORREEINGTH
EDONDEMONNATISTONSHE
LARHASTICRECOMESDCON
NEANDERACEROWALETRAD
ENRULODDITHATSCURANA
LSTANDDHSWITHORANDYM
OREIDISHTARNITYBYANT
ICCOLICESSHINNYLONDE
NROLDSOCOONONRALCEIR

Generation: 4 Fittest: 13688.0369016262
None, Rotate Right, Rotate Right, Untranspose best period

WSENTHATAPRILREWITHH
ICSSOURASCOOTESHADRO
GHTEOFTERMSHATSPELME
DTOTSAROOSEANDWITHED
AWARDWEDNAINSWICHLIM
ORLOFWHIMSWERTRANCEN
DRADICTHEFLOURWHENCE
PHILUSEEMWITHHISSWEE
SECRAFTSINSPIRETHATH
INAWELDHORTINTHEESST
HESENTRACROPPESINTTH
ADONCECONNASITSINTHE
LETHISSILWECOURSDRON
NEENDSTALAFOWALASTAM
ENTALODDETHATSLAPENE
RTSANDCHSWITHOPANDEC
OPRIMESHSATNATUREINS
IRCOLAGESTHINNERONCA
NFORMSOGOONONPILGRIT

Generation: 5 Fittest: 13694.9350762968
Rotate Left, Reverse, Flip, Untranspose best period

WHANTHATAPRILLEWITHS
INDHOTHESNOOTESSEDHO
GSTEOFMARCHSATHPENCE
DTOTHEHOOSEANADITSAD
EMARTMETRAINDWICHLIC
OWNOFWHICHMARTWENGER
AREDINTHEFLOURWSANCA
PSINTSEEDWITHHISSWEE
SETHEFTHINSPIRETHATS
INAMENTHOLTINTHEASHT
HESENTHECROPPEDIRTTH
ATORGANONNEHITHINTHA
NAMSISHILMACOURSTRON
NEANADMALAFOWELASMAD
ARMELOATETHATSLEPENA
LTHERTGSSWITSOPENTEN
OPRIDESSHEMRATTHEIRH
IRCONAGESTSINNELONGA
NFOLDSOGOONONPILGRIM

Translated with http://www.DeepL.com/Translator

 
Posted : September 14, 2018 11:06 pm
(@largo)
Posts: 454
Honorable Member
Topic starter
 

A new test:

The first 340 characters of z408 were disrupted into 68 parts of 5 characters each. These fragments were randomly rearranged. Example:

Plaintext:
THISISASAMPLECIPHERX

Fragmented:
THISI SASAM PLECI PHERX

Fragments shuffled:
PLECI SASAM PHERX THISI

Fragmented plaintext:
PLECISASAMPHERXTHISI

This was then substituted and passed to my solver. With a monoalphabetic substitution the solver manages to create a reasonably readable plaintext. With homophonic encryption it doesn’t work yet. I also don’t know whether the search space isn’t much too large (68 factorial). Let’s see… Either my idea works or I can throw it into the bin ;)

Translated with http://www.DeepL.com/Translator

 
Posted : September 15, 2018 12:23 pm
doranchak
(@doranchak)
Posts: 2614
Member Admin
 

Nice idea! Hopefully it will work. The search space seems daunting. Isn’t it actually around 68! times 26^63 (if you used 63 symbols in the substitution)?

I think it is roughly equivalent to an untransposed homophonic with a key length of 131. Reasoning: 26^n = 68!*(26^63), then solve for n.

http://zodiackillerciphers.com

 
Posted : September 15, 2018 1:21 pm
(@largo)
Posts: 454
Honorable Member
Topic starter
 

The search space seems daunting. Isn’t it actually around 68! times 26^63 (if you used 63 symbols in the substitution)?

Yes, that’s right. The search space of 68! referred only to the transposition. If homophonic encryption is added, it is extended by the factor 26^63 (for 63 Symbols). With a monoalphabetic substitution the factor is 26!.

I run the test overnight and get only a few fragments of the plaintext. If I didn’t know the plaintext, I wouldn’t be able to tell if the fragments are random or represent parts of the real plaintext. Another problem with this test is the correlation of the fragment size and the nGram size of the solver (both 5). It is no surprise that fragments can be found sometimes.
This test was mainly used to find out how big the search space can be. The fragmentation into 68 parts was purely arbitrary and had no direct connection to z340. Nevertheless, it would have been a big step to solve such a problem.
For now I will extend my general transposition solver. The disadvantage of this solver is that it only works with pre-defined methods (Flip/Diagonal/Reverse/Period etc.). It fails with routes or interlocks. I like Smokie’s idea of letting a route evolve. Unfortunately, I don’t have any idea how to do this yet. If you generate a route similar to the one in the game "Snake", you have to make sure that no paths cross each other. You also have to make sure that as many characters as possible are covered. In addition, one would have to calculate how large the search space is in this case. This is not an easy task either.
Does anyone have any suggestions? I don’t want to give up trying genetic algorithms because there is potential.

Translated with http://www.DeepL.com/Translator

 
Posted : September 16, 2018 12:48 pm
doranchak
(@doranchak)
Posts: 2614
Member Admin
 

There’s probably an algorithm description somewhere already but I couldn’t find it. However, I went ahead and wrote one in Java just to see if I could. Here’s the result:

package com.zodiackillerciphers.tests;

import java.util.ArrayList;
import java.util.List;

/**
 * generate all possible routes in a grid, but only return routes that visit all
 * positions.
 * 
 * http://zodiackillersite.com/viewtopic.php?p=65066#p65066
 * 
 **/
public class GridRoutes {
	public static void search(int height, int width) {
		boolean[][] grid = new boolean[height][width];
		List<String> visited = new ArrayList<String>();
		for (int row=0; row<height; row++) {
			for (int col=0; col<width; col++) {
				System.out.println("Starting at (" + row + ", " + col + "):");
				search(grid, height, width, row, col, visited);
			}
		}
	}

	public static void search(boolean[][] grid, int height, int width, int row, int col, List<String> visited) {

		// bounds check
		if (row < 0 || row == height || col < 0 || col == width) {
			return;
		}

		if (grid[row][col]) {
			return; // already visited this position so return (we don't allow routes to intersect
					// with themselves)
		}

		grid[row][col] = true;

		// add current position to list of visited positions
		visited.add("(" + row + "," + col + ")");

		// if we visited every position, print the route and return
		if (visited.size() == height * width) {
			System.out.println(visited);
			visited.remove(visited.size() - 1);
			grid[row][col] = false;
			return;
		}

		// visit all neighbors (horizontal and vertical moves only)
		search(grid, height, width, row, col + 1, visited);
		search(grid, height, width, row + 1, col, visited);
		search(grid, height, width, row, col - 1, visited);
		search(grid, height, width, row - 1, col, visited);
		visited.remove(visited.size() - 1);
		grid[row][col] = false;

	}

	public static void main(String[] args) {
		search(3, 4);
	}
}

It starts at each position of the grid with the given dimensions, then generates all possible routes that visit every grid position. Each route is not allowed to cross itself.

Sample output for grid with height 3 and width 4:

Starting at (0, 0):
[(0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (1,1), (1,2)]
[(0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (1,2), (1,1), (2,1), (2,0), (1,0)]
[(0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (1,2), (1,1), (1,0), (2,0), (2,1)]
[(0,0), (0,1), (0,2), (0,3), (1,3), (1,2), (1,1), (1,0), (2,0), (2,1), (2,2), (2,3)]
[(0,0), (0,1), (0,2), (1,2), (1,1), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3)]
[(0,0), (0,1), (1,1), (1,2), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0)]
[(0,0), (0,1), (1,1), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (1,2), (0,2), (0,3)]
[(0,0), (0,1), (1,1), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (1,2)]
[(0,0), (0,1), (1,1), (1,0), (2,0), (2,1), (2,2), (1,2), (0,2), (0,3), (1,3), (2,3)]
[(0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (1,2), (1,1), (0,1), (0,2), (0,3)]
[(0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (1,2), (1,1), (0,1)]
[(0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (1,1), (1,2)]
[(0,0), (1,0), (2,0), (2,1), (2,2), (1,2), (1,1), (0,1), (0,2), (0,3), (1,3), (2,3)]
[(0,0), (1,0), (2,0), (2,1), (1,1), (1,2), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1)]
[(0,0), (1,0), (2,0), (2,1), (1,1), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (1,2)]
[(0,0), (1,0), (2,0), (2,1), (1,1), (0,1), (0,2), (0,3), (1,3), (1,2), (2,2), (2,3)]
[(0,0), (1,0), (2,0), (2,1), (1,1), (0,1), (0,2), (1,2), (2,2), (2,3), (1,3), (0,3)]
Starting at (0, 1):
[(0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (1,2), (1,1), (2,1), (2,0), (1,0), (0,0)]
[(0,1), (1,1), (1,2), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0)]
[(0,1), (0,0), (1,0), (1,1), (1,2), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0)]
[(0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (1,2), (1,1)]
[(0,1), (0,0), (1,0), (2,0), (2,1), (1,1), (1,2), (2,2), (2,3), (1,3), (0,3), (0,2)]
[(0,1), (0,0), (1,0), (2,0), (2,1), (1,1), (1,2), (0,2), (0,3), (1,3), (2,3), (2,2)]
Starting at (0, 2):
[(0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (1,1), (1,2)]
[(0,2), (0,3), (1,3), (2,3), (2,2), (1,2), (1,1), (2,1), (2,0), (1,0), (0,0), (0,1)]
[(0,2), (0,3), (1,3), (2,3), (2,2), (1,2), (1,1), (0,1), (0,0), (1,0), (2,0), (2,1)]
[(0,2), (0,3), (1,3), (1,2), (1,1), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3)]
[(0,2), (1,2), (1,1), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3)]
[(0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (1,1), (1,2), (2,2), (2,3), (1,3), (0,3)]
Starting at (0, 3):
[(0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (1,1), (1,2), (0,2), (0,1), (0,0)]
[(0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (1,2), (1,1)]
[(0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (1,1), (1,2), (0,2)]
[(0,3), (1,3), (2,3), (2,2), (2,1), (1,1), (1,2), (0,2), (0,1), (0,0), (1,0), (2,0)]
[(0,3), (1,3), (2,3), (2,2), (1,2), (1,1), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2)]
[(0,3), (1,3), (2,3), (2,2), (1,2), (0,2), (0,1), (1,1), (2,1), (2,0), (1,0), (0,0)]
[(0,3), (1,3), (2,3), (2,2), (1,2), (0,2), (0,1), (0,0), (1,0), (1,1), (2,1), (2,0)]
[(0,3), (1,3), (2,3), (2,2), (1,2), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (1,1)]
[(0,3), (0,2), (1,2), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (1,1), (0,1), (0,0)]
[(0,3), (0,2), (1,2), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (1,1)]
[(0,3), (0,2), (1,2), (1,3), (2,3), (2,2), (2,1), (1,1), (0,1), (0,0), (1,0), (2,0)]
[(0,3), (0,2), (1,2), (1,1), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3)]
[(0,3), (0,2), (0,1), (1,1), (1,2), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0)]
[(0,3), (0,2), (0,1), (0,0), (1,0), (1,1), (1,2), (1,3), (2,3), (2,2), (2,1), (2,0)]
[(0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (1,2), (1,1)]
[(0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (1,1), (1,2), (1,3), (2,3), (2,2)]
[(0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (1,1), (1,2), (2,2), (2,3), (1,3)]
Starting at (1, 0):
[(1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (1,2), (1,1), (0,1), (0,0)]
[(1,0), (2,0), (2,1), (1,1), (1,2), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0)]
[(1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (1,2), (1,1), (2,1), (2,0)]
[(1,0), (0,0), (0,1), (1,1), (1,2), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0)]
Starting at (1, 1):
[(1,1), (1,2), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3)]
[(1,1), (1,2), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3)]
[(1,1), (1,2), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1)]
[(1,1), (1,2), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3)]
[(1,1), (1,2), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1)]
[(1,1), (1,2), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3)]
[(1,1), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (1,2)]
[(1,1), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (1,2), (2,2), (2,3)]
[(1,1), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (1,2), (2,2), (2,3), (1,3), (0,3)]
[(1,1), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (1,2), (0,2), (0,3)]
[(1,1), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (1,2)]
[(1,1), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (1,2), (0,2), (0,3), (1,3), (2,3)]
Starting at (1, 2):
[(1,2), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (1,1), (2,1), (2,0), (1,0), (0,0)]
[(1,2), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (1,1), (2,1), (2,0)]
[(1,2), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (1,1)]
[(1,2), (1,1), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0)]
[(1,2), (1,1), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2)]
[(1,2), (1,1), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0)]
[(1,2), (1,1), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0)]
[(1,2), (1,1), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0)]
[(1,2), (1,1), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2)]
[(1,2), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (1,1), (0,1), (0,0)]
[(1,2), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (1,1)]
[(1,2), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (1,1), (0,1), (0,0), (1,0), (2,0)]
Starting at (1, 3):
[(1,3), (2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (1,1), (1,2), (0,2), (0,3)]
[(1,3), (2,3), (2,2), (1,2), (1,1), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3)]
[(1,3), (0,3), (0,2), (1,2), (1,1), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (2,3)]
[(1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (1,1), (1,2), (2,2), (2,3)]
Starting at (2, 0):
[(2,0), (2,1), (2,2), (2,3), (1,3), (1,2), (1,1), (1,0), (0,0), (0,1), (0,2), (0,3)]
[(2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (1,2), (1,1), (1,0), (0,0), (0,1)]
[(2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (1,2), (1,1), (0,1), (0,0), (1,0)]
[(2,0), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (1,1), (1,2)]
[(2,0), (2,1), (2,2), (1,2), (1,1), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3)]
[(2,0), (2,1), (1,1), (1,2), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0)]
[(2,0), (2,1), (1,1), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (1,2)]
[(2,0), (2,1), (1,1), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (1,2), (2,2), (2,3)]
[(2,0), (2,1), (1,1), (1,0), (0,0), (0,1), (0,2), (1,2), (2,2), (2,3), (1,3), (0,3)]
[(2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1), (1,1), (1,2)]
[(2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (1,2), (1,1), (2,1)]
[(2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (1,2), (1,1), (2,1), (2,2), (2,3)]
[(2,0), (1,0), (0,0), (0,1), (0,2), (1,2), (1,1), (2,1), (2,2), (2,3), (1,3), (0,3)]
[(2,0), (1,0), (0,0), (0,1), (1,1), (1,2), (0,2), (0,3), (1,3), (2,3), (2,2), (2,1)]
[(2,0), (1,0), (0,0), (0,1), (1,1), (2,1), (2,2), (2,3), (1,3), (1,2), (0,2), (0,3)]
[(2,0), (1,0), (0,0), (0,1), (1,1), (2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (1,2)]
[(2,0), (1,0), (0,0), (0,1), (1,1), (2,1), (2,2), (1,2), (0,2), (0,3), (1,3), (2,3)]
Starting at (2, 1):
[(2,1), (2,2), (2,3), (1,3), (0,3), (0,2), (1,2), (1,1), (0,1), (0,0), (1,0), (2,0)]
[(2,1), (2,0), (1,0), (1,1), (1,2), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0)]
[(2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3), (2,2), (1,2), (1,1)]
[(2,1), (2,0), (1,0), (0,0), (0,1), (1,1), (1,2), (2,2), (2,3), (1,3), (0,3), (0,2)]
[(2,1), (2,0), (1,0), (0,0), (0,1), (1,1), (1,2), (0,2), (0,3), (1,3), (2,3), (2,2)]
[(2,1), (1,1), (1,2), (2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0)]
Starting at (2, 2):
[(2,2), (2,3), (1,3), (1,2), (1,1), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3)]
[(2,2), (2,3), (1,3), (0,3), (0,2), (1,2), (1,1), (2,1), (2,0), (1,0), (0,0), (0,1)]
[(2,2), (2,3), (1,3), (0,3), (0,2), (1,2), (1,1), (0,1), (0,0), (1,0), (2,0), (2,1)]
[(2,2), (2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (1,1), (1,2)]
[(2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (1,1), (1,2), (0,2), (0,3), (1,3), (2,3)]
[(2,2), (1,2), (1,1), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (2,3)]
Starting at (2, 3):
[(2,3), (2,2), (2,1), (2,0), (1,0), (1,1), (1,2), (1,3), (0,3), (0,2), (0,1), (0,0)]
[(2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3), (1,2), (1,1)]
[(2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (1,1), (1,2), (1,3), (0,3), (0,2)]
[(2,3), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (1,1), (1,2), (0,2), (0,3), (1,3)]
[(2,3), (2,2), (2,1), (1,1), (1,2), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0)]
[(2,3), (2,2), (1,2), (1,3), (0,3), (0,2), (0,1), (1,1), (2,1), (2,0), (1,0), (0,0)]
[(2,3), (2,2), (1,2), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (1,1), (2,1), (2,0)]
[(2,3), (2,2), (1,2), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (1,1)]
[(2,3), (2,2), (1,2), (1,1), (2,1), (2,0), (1,0), (0,0), (0,1), (0,2), (0,3), (1,3)]
[(2,3), (1,3), (0,3), (0,2), (1,2), (2,2), (2,1), (2,0), (1,0), (1,1), (0,1), (0,0)]
[(2,3), (1,3), (0,3), (0,2), (1,2), (2,2), (2,1), (2,0), (1,0), (0,0), (0,1), (1,1)]
[(2,3), (1,3), (0,3), (0,2), (1,2), (2,2), (2,1), (1,1), (0,1), (0,0), (1,0), (2,0)]
[(2,3), (1,3), (0,3), (0,2), (1,2), (1,1), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2)]
[(2,3), (1,3), (0,3), (0,2), (0,1), (1,1), (1,2), (2,2), (2,1), (2,0), (1,0), (0,0)]
[(2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (1,1), (1,2), (2,2), (2,1), (2,0)]
[(2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (2,2), (1,2), (1,1)]
[(2,3), (1,3), (0,3), (0,2), (0,1), (0,0), (1,0), (2,0), (2,1), (1,1), (1,2), (2,2)]

There are 124 routes found for that 3×4 grid (if my algorithm is correct). It jumps to 2,012 routes for a 4×5 grid, and 47,391 routes for a 5×6 grid. I’m afraid to run it on 20×17 due to the exponential growth in routes. I have no idea how to explicitly count the search space in advance. Surely some mathematician somewhere has done this exercise before.

http://zodiackillerciphers.com

 
Posted : September 16, 2018 2:00 pm
Jarlve
(@jarlve)
Posts: 2547
Famed Member
 

Thanks for the explanation Largo. I can see that the genetic algorithm is well suited for the task since it tries out a great variety of things.

The first 340 characters of z408 were disrupted into 68 parts of 5 characters each.

There’s a chance AZdecrypt’s row bound solver (smokie’s concept) can get this if you dimension the cipher into 68 by 5.

Test on the 408 capped at 340 (a bit easier) with the parts randomized does reveal the correct substitution but the parts are still out of order.

Score: 25728.34 Ioc: 0.06021
Ngrams: 273 PC-cycles: 664

Ngram size: 4

ARTOF (422)
OUMYN (266)
DICES (354)
AVESM (351)
ETHEM (449)
ADIOT (333)
YOUWI (405)
BECOU (363)
ERANC (379)
EITAS (386)
OODTH (402)
AVEKI (352)
LBERE (380)
ITISS (394)
RILLI (395)
HINGG (383)
COMEM (369)
FALLT (404)
BESTP (381)
ILIKE (439)
ANGAR (361)
MOODF (330)
DHOGI (255)
OFFWI (353)
SOMET (455)
NGEXP (368)
LLTRY (379)
THEFO (410)
LLNOD (295)
TUEIN (313)
ENIFI (395)
ETDER (295)
OKILL (406)
SEMAN (386)
NPARI (340)
ILLBE (429)
ETTIN (443)
AMEBE (375)
HANKI (348)
GYOUR (443)
LLEDW (372)
BORNI (363)
NGPEO (397)
CAUSE (464)
ROCKS (374)
IMEAN (434)
FUNIT (359)
ISTHE (462)
EVENB (384)
GIVEY (390)
THAAH (233)
RREST (407)
THING (486)
WILDG (308)
ESIWI (333)
LLING (450)
NFALL (384)
CAUSE (464)
YSLOV (347)
PLEBE (381)
AFUND (361)
RLTHA (373)
KILLA (386)
ASMOR (398)
OMUCH (434)
OMALO (346)
HIAWH (281)
EAWIL (338)

AZdecrypt

 
Posted : September 16, 2018 4:02 pm
(@largo)
Posts: 454
Honorable Member
Topic starter
 

There’s probably an algorithm description somewhere already but I couldn’t find it. However, I went ahead and wrote one in Java just to see if I could. Here’s the result:

Many thanks for the algorithm, it works very well! I just ported it to Swift 4.1 and experimented a bit with it. But for a 5×6 grid I get 53992 routes. I will check again if I overlooked something while porting.

At 17×3 there are 179840 possible routes just for the start position 0, 0. Again, the search space seems to be way too large. Even with a genetic algorithm that builds the routes on the fly. I don’t see any way to evolve routes. Even if it were a text without substitution.

There’s a chance AZdecrypt’s row bound solver (smokie’s concept) can get this if you dimension the cipher into 68 by 5.

Test on the 408 capped at 340 (a bit easier) with the parts randomized does reveal the correct substitution but the parts are still out of order.

Wow, that’s impressive! I know this feature of AZDecrypt, but I haven’t tried it with such short fragments yet. Amazing how well this works. Here is the AZDecrypt result of my test cipher (59 Symbols).

DYOUR (443)
THAGI (335)
ILIKE (436)
NPARA (358)
FUNIT (356)
OUMYN (264)
THEIS (418)
LBERE (378)
EVERB (401)
OFFWI (351)
AMALO (332)
NDUNP (307)
ISTHO (378)
NGALL (401)
BORNI (360)
OUEAR (328)
MOATW (266)
HINGD (389)
SANKI (307)
WILDG (306)
LLNOT (400)
OATTH (392)
ETTER (447)
THEFO (407)
PLEBE (378)
UIWIL (339)
ORIGI (402)
SOMET (452)
ILLBE (426)
DIVEY (317)
ITIAT (360)
ESIWI (331)
ARTOF (419)
EETIN (394)
KILLI (403)
UTSOM (410)
BECAU (456)
AVEKI (349)
SEMAN (383)
LLTRY (377)
CAUSE (461)
CAUSE (461)
NGPEO (395)
URONC (311)
RILLI (392)
RRENT (430)
OMUCH (431)
ARDER (399)
AMEBE (372)
LLING (447)
WICEA (371)
AMEIN (395)
UTTIN (416)
HAOWS (184)
YOUWI (402)
LLEDW (369)
RLTHE (371)
THARD (400)
BESTP (379)
YSLAV (320)
FALLT (402)
IVESM (366)
ITINS (377)
EFUNT (358)
COMEM (366)
IAMOR (333)
OKILL (403)
ROCKS (372)
 
Posted : September 16, 2018 4:32 pm
doranchak
(@doranchak)
Posts: 2614
Member Admin
 

There’s probably an algorithm description somewhere already but I couldn’t find it. However, I went ahead and wrote one in Java just to see if I could. Here’s the result:

Many thanks for the algorithm, it works very well! I just ported it to Swift 4.1 and experimented a bit with it. But for a 5×6 grid I get 53992 routes. I will check again if I overlooked something while porting.

I re-ran my algorithm and got 53992 routes for 5×6 this time. Maybe I miscounted before.

http://zodiackillerciphers.com

 
Posted : September 16, 2018 4:51 pm
smokie treats
(@smokie-treats)
Posts: 1626
Noble Member
 

Thanks for the explanation, Largo. I like your creativity. And Jarlve’s fragment solve above is really amazing.

What about fragments ranging from 1 to some high number, but starting out average 68 fragments of length 5 ( average length of English word ). Each fragment is a gene. The direction is pre-set.

Example cipher: Four, side by side 5 x 17 inscription rectangles, direction of diagonal inscription left right bottom top ( North East ). Then transcribe into a 17 x 20 rectangle left right top bottom and homophonic substitute.

To solve: redraft the message into 20 x 17, set the reading direction to North East, break into fragments. There could be a population of 100, all with different fragments ( genes ). Keep the 50 that get the highest substitution scores and kill the 50 with the lowest scores. Make 25 of the surviving 50 male, and 25 female. Pair them up and breed them, each couple having four children. Not sure how to splice the genes together. Test the new population of 100 and repeat.

Could the program find the borders of the four inscription rectangles?

 
Posted : September 16, 2018 5:04 pm
Page 1 / 2
Share: