static void DebugGetFactoredKeyLengthWeightings() { Console.Write("Text> "); string text = Console.ReadLine().ToUpper(); Console.Write("Discard single occurences (1/0)?> "); bool discardSingle = int.Parse(Console.ReadLine()) != 0; Repetition[] repetitions = Repetition.GetTextRepetitions(text); Dictionary <int, int> keyLengthWeightings = KeyLengthDeduction.GetKeyLengthWeights(repetitions, discardSingle); Dictionary <int, int> factoredWeightings = KeyLengthDeduction.GetFactoredKeyLengthWeights(keyLengthWeightings); foreach (int factoredkeyLength in factoredWeightings.Keys) { Console.WriteLine($"{factoredkeyLength} : {factoredWeightings[factoredkeyLength]}"); } Console.WriteLine(); Console.Write("Get Top x Results> "); int count = int.Parse(Console.ReadLine()); Dictionary <int, int> topResults = ProgramMath.GetTopDictionaryKeysByValue(factoredWeightings, count); foreach (int topResult in topResults.Keys) { Console.WriteLine($"{topResult} : {topResults[topResult]}"); } }
static void DebugListActivePossibilities() { Console.Write("Range> "); int range = int.Parse(Console.ReadLine()); List <int> input = new List <int>(); for (int i = 0; i < range; i++) { input.Add(i); } List <List <int> > possibilities = ProgramMath.GetListActivePossibilities(input); foreach (List <int> possibility in possibilities) { foreach (int n in possibility) { Console.Write(n.ToString() + ' '); } Console.WriteLine(); } }
static int KeyLengthSelection(string text) { Console.Write("Discard single-occurence key lengths (1/0)?> "); bool discardSingle = int.Parse(Console.ReadLine()) != 0; Repetition[] repetitions = Repetition.GetTextRepetitions(text); Dictionary <int, int> keyLengthWeightings = KeyLengthDeduction.GetKeyLengthWeights(repetitions, discardSingle); Dictionary <int, int> factoredWeightings = KeyLengthDeduction.GetFactoredKeyLengthWeights(keyLengthWeightings); Console.Write("View how many top lengths?> "); int topLengthsCount = int.Parse(Console.ReadLine()); int requestCount = topLengthsCount < factoredWeightings.Count ? topLengthsCount : factoredWeightings.Count; Dictionary <int, int> topLengths = ProgramMath.GetTopDictionaryKeysByValue(factoredWeightings, requestCount); Console.WriteLine(); Console.WriteLine("(English average IOC is about 0.0667)"); Console.WriteLine("Top Key Lengths:"); foreach (int length in topLengths.Keys) { decimal ioc = KeyLengthDeduction.GetAverageIOCOfTextByOffset(text, length); Console.WriteLine($"{length} (weighting = {topLengths[length]}) - Average IOC = {ioc}"); } Console.Write("Select chosen key length> "); int keyLengthSelection = int.Parse(Console.ReadLine()); return(keyLengthSelection); }
private static string ConstructCurrentDeciphering(string[] selections, int[] selectionShifts) { string[] currentSelections = new string[selections.Length]; for (int i = 0; i < currentSelections.Length; i++) { currentSelections[i] = FrequencyAnalysis.DecipherTextByMapping(selections[i], ProgramMath.GetCharacterMappingByCaesarCipherOffset(selectionShifts[i])); } return(FrequencyAnalysis.ReconstructTextFromOffsetSelections(currentSelections)); }
static void DebugGetPermutations() { Console.Write("Values> "); string[] values = Console.ReadLine().Split(','); foreach (List <string> perm in ProgramMath.GetPermutations(new List <string>(values))) { foreach (string part in perm) { Console.Write(part); } Console.WriteLine(); } }
public static Dictionary <char, char> GetOptimalCharacterMappingNonCaesar(Dictionary <char, double> textCharProportion, Dictionary <char, double> targetCharProportion, out double mappingDifference) { /*Mappings are { inputTextChar : actualChar }*/ double minDifference = double.MaxValue; Dictionary <char, char> optimalMapping = null; foreach (List <char> charList in ProgramMath.GetPermutations(new List <char>(Program.validCharacters))) { /*Create Character Mapping*/ Dictionary <char, char> mapping = new Dictionary <char, char>(); for (int i = 0; i < Program.validCharacters.Length; i++) { mapping[charList[i]] = Program.validCharacters[i]; } /*Test character mapping*/ Dictionary <char, double> mappedCharProportions = new Dictionary <char, double>(); foreach (char key in textCharProportion.Keys) { mappedCharProportions[mapping[key]] = textCharProportion[key]; } double difference = ProgramMath.GetKeyFrequencyDifference(mappedCharProportions, targetCharProportion); /*Compare mapping to best*/ if (difference < minDifference) { minDifference = difference; optimalMapping = new Dictionary <char, char>(mapping); } } mappingDifference = minDifference; return(optimalMapping); }
public static Dictionary <char, char> GetOptimalCharacterMapping(Dictionary <char, double> textCharProportion, Dictionary <char, double> targetCharProportion, out double mappingDifference, out int mappingShiftAmount) { /*Mappings are { inputTextChar : actualChar }*/ double minDifference = double.MaxValue; Dictionary <char, char> optimalMapping = null; int optimalShiftAmount = 0; for (int i = 0; i < 26; i++) { /*Create Character Mapping*/ Dictionary <char, char> mapping = ProgramMath.GetCharacterMappingByCaesarCipherOffset((26 - i) % 26); /*Test character mapping*/ Dictionary <char, double> mappedCharProportions = new Dictionary <char, double>(); foreach (char key in textCharProportion.Keys) { mappedCharProportions[mapping[key]] = textCharProportion[key]; } double difference = ProgramMath.GetKeyFrequencyDifference(mappedCharProportions, targetCharProportion); /*Compare mapping to best*/ if (difference < minDifference) { minDifference = difference; optimalMapping = new Dictionary <char, char>(mapping); optimalShiftAmount = i; } } mappingDifference = minDifference; mappingShiftAmount = optimalShiftAmount; return(optimalMapping); }
static void DebugBinaryPossibilities() { Console.Write("Length> "); int length = int.Parse(Console.ReadLine()); List <List <bool> > possibilities = ProgramMath.GetBinaryPossibilities(length); Console.WriteLine($"{possibilities.Count} found"); foreach (List <bool> possibility in possibilities) { foreach (bool value in possibility) { Console.Write(value ? "1" : "0"); } Console.WriteLine(); } }
public static Dictionary <int, int> GetFactoredKeyLengthWeights(Dictionary <int, int> originalKeyLengthWeightings) { Dictionary <int, int> outputWeightings = new Dictionary <int, int>(); foreach (int keyLength in originalKeyLengthWeightings.Keys) { int[] lengthFactors = ProgramMath.GetFactors(keyLength); foreach (int factor in lengthFactors) { if (outputWeightings.ContainsKey(factor)) { outputWeightings[factor] += originalKeyLengthWeightings[keyLength]; } else { outputWeightings.Add(factor, originalKeyLengthWeightings[keyLength]); } } } return(outputWeightings); }
/// <summary> /// Get the likelihood of possible key lengths given repetitions that have been found in a text /// </summary> /// <param name="repetitions">The repetitions that have been found in a text</param> /// <returns>{keyLength : occurences}</returns> public static Dictionary <int, int> GetKeyLengthWeights(Repetition[] repetitions, bool discardSingleOccurence = false) { Dictionary <int, int> lengthWeightings = new Dictionary <int, int>(); foreach (Repetition repetition in repetitions) { List <List <int> > positionsActivePossibilities = ProgramMath.GetListActivePossibilities(repetition.positions, true); foreach (List <int> positions in positionsActivePossibilities) { //Try each combination of repetitions being checked and not being checked in case some where coincidence bool valid = true; /*All spacings are equal*/ int spacing = positions[1] - positions[0]; if (positions.Count > 2) { for (int i = 2; i < positions.Count; i++) { if (positions[i] - positions[i - 1] != spacing) { valid = false; } } } if (valid) { if (lengthWeightings.ContainsKey(spacing)) { lengthWeightings[spacing]++; } else { lengthWeightings.Add(spacing, 1); } } } } if (discardSingleOccurence) { Dictionary <int, int> newOutput = new Dictionary <int, int>(); foreach (int key in lengthWeightings.Keys) { if (lengthWeightings[key] > 1) { newOutput.Add(key, lengthWeightings[key]); } } return(newOutput); } else { return(lengthWeightings); } }
public static string RunDeciphering(string originalText, int keyLength, out string keyword) { //TODO: allow for keyLength bigger than seperateKeyColors.Length Debug.Assert(keyLength < seperateKeyColors.Length); string[] originalSelections = FrequencyAnalysis.SplitTextByOffset(originalText, keyLength); int[] selectionShifts = new int[originalSelections.Length]; for (int i = 0; i < originalSelections.Length; i++) { selectionShifts[i] = 0; } #region Instructions PrintSeperator(); Console.WriteLine("To shift a selection with id i by n (n can be negative), use \"{i}:{n}\""); Console.WriteLine("To set the current mapping to a calculated optimal mapping, use SET OPTIMAL"); Console.WriteLine("To print the text in one color, use PRINT PLAIN"); PrintSeperator(); for (int i = 0; i < keyLength; i++) { Console.ForegroundColor = seperateKeyColors[i]; Console.Write(i + " "); } Console.ForegroundColor = defaultConsoleColor; Console.WriteLine(); PrintSeperator(); #endregion bool running = true; while (running) { Console.WriteLine("Current Keyword: " + ProgramMath.GetKeywordFromOffsets(selectionShifts)); Console.WriteLine("Current Text:"); PrintColoredTextByKey(ConstructCurrentDeciphering(originalSelections, selectionShifts), keyLength); Console.Write("> "); string inputRequest = Console.ReadLine().ToUpper(); if (inputRequest == "" || inputRequest == "END") { running = false; } else if (Regex.IsMatch(inputRequest, @"^\d+:-?\d+$", RegexOptions.IgnoreCase)) { string[] parts = inputRequest.Split(':'); Debug.Assert(parts.Length == 2); int selectionId = int.Parse(parts[0]); int shiftAmount = int.Parse(parts[1]); if (selectionId < 0 || selectionId >= originalSelections.Length) { Console.WriteLine("Invalid selection id"); } else { selectionShifts[selectionId] = (selectionShifts[selectionId] + shiftAmount + Program.validCharacters.Length) % Program.validCharacters.Length; } } else if (inputRequest == "SET OPTIMAL" || inputRequest == "SETOPTIMAL") { for (int selectionIndex = 0; selectionIndex < originalSelections.Length; selectionIndex++) { string selection = originalSelections[selectionIndex]; Dictionary <char, double> selectionProportions = FrequencyAnalysis.CharFrequencyToCharProportion(FrequencyAnalysis.GetTextCharFrequency(selection)); double _; int optimalShiftAmount; FrequencyAnalysis.GetOptimalCharacterMapping(selectionProportions, EnglishLetterFrequency.GetLetterProportions(), out _, out optimalShiftAmount); selectionShifts[selectionIndex] = optimalShiftAmount; } } else if (inputRequest == "PRINT PLAIN" || inputRequest == "PRINTPLAIN") { Console.WriteLine(ConstructCurrentDeciphering(originalSelections, selectionShifts)); } else { Console.WriteLine("Unknown Request"); } } keyword = ProgramMath.GetKeywordFromOffsets(selectionShifts); return(ConstructCurrentDeciphering(originalSelections, selectionShifts)); }
static void ReleaseMain(string[] args) { Console.Write("Text> "); string text; string input = Console.ReadLine().ToUpper().Replace(" ", "").ToUpper(); if (input[0] == '\\') { text = GetTextFromFile(input.Substring(1)).ToUpper(); } else { text = input; } foreach (char c in text) { if (!validCharacters.Contains(c)) { Console.WriteLine($"Error: Invalid character in text ({c})"); return; } } int keyLengthSelection = KeyLengthSelection(text); Console.Write("Automatically decipher text (0/1)?> "); bool autoDecipher = int.Parse(Console.ReadLine()) != 0; if (autoDecipher) { string[] offsetTextSelections = FrequencyAnalysis.SplitTextByOffset(text, keyLengthSelection); string[] decipheredStrings = new string[offsetTextSelections.Length]; int[] shiftAmounts = new int[offsetTextSelections.Length]; for (int i = 0; i < decipheredStrings.Length; i++) { string selection = offsetTextSelections[i]; double _; Dictionary <char, double> selectionProportions = FrequencyAnalysis.CharFrequencyToCharProportion(FrequencyAnalysis.GetTextCharFrequency(selection)); Dictionary <char, char> optimalMapping = FrequencyAnalysis.GetOptimalCharacterMapping(selectionProportions, EnglishLetterFrequency.GetLetterProportions(), out _, out shiftAmounts[i]); decipheredStrings[i] = FrequencyAnalysis.DecipherTextByMapping(selection, optimalMapping); } string fullDeciphering = FrequencyAnalysis.ReconstructTextFromOffsetSelections(decipheredStrings); Console.WriteLine("Keyword: " + ProgramMath.GetKeywordFromOffsets(shiftAmounts)); Console.WriteLine("Deciphered Text:"); Console.WriteLine(fullDeciphering); } else { string keyword; string fullDeciphering = ManualMappingDeciphering.RunDeciphering(text, keyLengthSelection, out keyword); Console.WriteLine("Keyword: " + keyword); Console.WriteLine("Deciphered Text:"); Console.WriteLine(fullDeciphering); } }
static void DebugOptimalCharacterMappingFull() { Console.Write("Text> "); string text = Console.ReadLine().ToUpper(); const bool discardSingle = true; Repetition[] repetitions = Repetition.GetTextRepetitions(text); Dictionary <int, int> keyLengthWeightings = KeyLengthDeduction.GetKeyLengthWeights(repetitions, discardSingle); Dictionary <int, int> factoredWeightings = KeyLengthDeduction.GetFactoredKeyLengthWeights(keyLengthWeightings); const int topLengthsCount = 7; Dictionary <int, int> topLengths = ProgramMath.GetTopDictionaryKeysByValue(factoredWeightings, topLengthsCount); Console.WriteLine(); Console.WriteLine("Top Key Lengths:"); foreach (int length in topLengths.Keys) { Console.WriteLine($"{length} (weighting = {topLengths[length]})"); } Console.Write("Select chosen key length> "); int keyLengthSelection = int.Parse(Console.ReadLine()); string[] selections = FrequencyAnalysis.SplitTextByOffset(text, keyLengthSelection); Console.WriteLine(); Console.WriteLine("Text Offset Selections:"); for (int i = 0; i < selections.Length; i++) { Console.WriteLine(i + ") " + selections[i]); } Console.Write("Select text offset selection> "); int offsetSelectionIndex = int.Parse(Console.ReadLine()); Debug.Assert(0 <= offsetSelectionIndex && offsetSelectionIndex < selections.Length); string selectedTextOffsetSelection = selections[offsetSelectionIndex]; Dictionary <char, double> selectionCharacterProportion = FrequencyAnalysis.CharFrequencyToCharProportion(FrequencyAnalysis.GetTextCharFrequency(selectedTextOffsetSelection)); Dictionary <char, double> englishCharacterProportions = EnglishLetterFrequency.GetLetterProportions(); double mappingDifference; int _; Dictionary <char, char> optimalMapping = FrequencyAnalysis.GetOptimalCharacterMapping(selectionCharacterProportion, englishCharacterProportions, out mappingDifference, out _); Console.WriteLine(); Console.WriteLine($"Mapping Difference: {mappingDifference}"); foreach (char textChar in optimalMapping.Keys) { Console.WriteLine($"{textChar} -> {optimalMapping[textChar]}"); } }