The Vigenère cipher is a substitution cipher where the encryption of each letter of the plaintext depends on a different character in a keyword. This stops you using simple methods of frequency analysis to guess the correct substitution. However, the keyword is repeated if it is shorter than the plaintext. This is a weakness. If the length of the keyword is known (n, say), however, and is much shorter than the message, then you can decompose the message into separate sections by taking every nth letter. You can then use frequency analysis on these.
The Kasiski examination is a method to work out the most likely key lengths. It does this by considering identical substrings which happen to be a multiple of the key length apart. They are therefore encrypted in the same way. Turning this round, identical substrings in the ciphertext are likely to be a multiple of the key length apart. If you identify these distances, then the key length is likely to be a common factor of all these distances.
Your job is to write a function or program that can guess the most likely length of the keyword, given some encrypted text. To be precise, the function or program (just called function below) will satisfy the following:
- Inputs consist of a string representing the ciphertext and a positive integer (len, for the purposes of this spec) representing the shortest common substring to look at.
- The ciphertext will consist of upper case A-Z characters only. Any length is permitted.
- You can assume valid inputs without checking.
- The inputs may be passed in, or read from stdin.
- The function will identify all pairs of identical substrings in the ciphertext which have a length of at least len.
- Substrings in each pair may not overlap but substrings in different pairs can overlap.
- The function will return, or write to stdout, the highest common factor of the distances between the starts of these identical pairs.
- If there are no identical substrings then the function will return 0.
"AAAAAAAAAAAAAAAAAA", n returns 1 for any n from 1 to 8, 9 for n = 9 (as the only possible non-overlapping substrings of length 9 happen to be the same) and 0 otherwise.
"ABCDEFGHIJKL", n returns 0 for any n
"ABCDEABCDE", n returns 5 for n<=5 and 0 otherwise
"ABCABABCAB", 2 returns 1 because "AB" pairs are separated by 2,3,5 & 8
"ABCABABCAB", 3 returns 5
"VHVSSPQUCEMRVBVBBBVHVSURQGIBDUGRNICJQUCERVUAXSSR", 4 returns 6 because the repeating "VHVS" are 18 characters apart, while "QUCE" is separated by 30 characters
Naturally, lowest byte count wins and avoid standard loopholes.