cycleStructure[perm_] := Sort[Length /@ (Cycles[perm])];
(*Function to generate random permutation with given cycle structure*)
randomPermWithStructure[structure_] :=
Module[{n = Total[structure], cycles, perm},
cycles = Table[RandomSample[Range[n], k], {k, structure}];
perm = Range[n];
Do[perm[[cycle]] = RotateLeft[perm[[cycle]]], {cycle, cycles}];
perm]
(*Function to apply permutation*)
applyPerm[perm_, x_] := perm[[x]]
(*Function to calculate match score*)
matchScore[a_, b_, plaintext_, ciphertext_] :=
Module[{m = Length[plaintext], scores},
scores = Table[Count[
Table[applyPerm[a,
applyPerm[RotateLeft[b, r],
plaintext[[i]]]] == ciphertext[[i]],
{i, 1, m}], True]/m, {r, 0, 25}];
Max[scores]]
(*Main cryptanalysis function*)
cryptanalysis[plaintext_, ciphertext_, sampleSize_ : 1000,
matchThreshold_ : 0.5] :=
Module[{n = 26, possibleStructures, bestA, bestB, bestScore = 0,
currentScore},(*Generate possible cycle structures*)
possibleStructures = IntegerPartitions[n];
(*Iterative sampling and scoring*)
Do[Module[{a =
randomPermWithStructure[RandomChoice[possibleStructures]],
b = randomPermWithStructure[RandomChoice[possibleStructures]]},
currentScore = matchScore[a, b, plaintext, ciphertext];
If[currentScore > bestScore, bestScore = currentScore;
bestA = a;
bestB = b;];], {sampleSize}];
(*Return results*)
<|
"BestA" -> If[bestScore >= matchThreshold, Cycles[bestA], {}],
"BestB" -> If[bestScore >= matchThreshold, Cycles[bestB], {}],
"BestMatchScore" -> bestScore|>]
(*Example usage*)
plaintext = {1, 2, 3, 4, 5, 6};
ciphertext = {15, 22, 3, 18, 9, 7};
result = cryptanalysis[plaintext, ciphertext];
Print["Best cycle structure for A: ", result["BestA"]];
Print["Best cycle structure for B: ", result["BestB"]];
Print["Best match score: ", result["BestMatchScore"]];
(*Function to convert cycles to readable format*)
cyclesToReadable[cycles_] :=
Map[Function[cycle,
StringJoin[Riffle[CharacterRange["A", "Z"][[cycle]], "\[Rule]"]]],
cycles]
(*Display readable cycle structures*)
Print["Readable cycle structure for A: ",
cyclesToReadable[result["BestA"]]
];
Print["Readable cycle structure for B: ",
cyclesToReadable[result["BestB"]]
];