Chapter 21 – Hacking the Vigenère Cipher 349
As you can see, by passing 'ABC' and the integer 4 for the repeat keyword argument,
itertools.product() returns an “itertools product” object that, when converted to a list,
has tuples of four values with every possible combination of 'A', 'B', and 'C'. (This results in
a list with a total of 3 ^ 4 or 81 tuples in it.)
Since range objects returned from range() are also list-like, they can be passed to
itertools.product() as well. Try typing the following into the interactive shell:
import itertools
list(itertools.product(range(8), repeat=5))
[(0, 0, 0, 0, 0), (0, 0, 0, 0, 1), (0, 0, 0, 0, 2), (0, 0, 0, 0, 3), (0, 0, 0,
0, 4), (0, 0, 0, 0, 5), (0, 0, 0, 0, 6), (0, 0, 0, 0, 7), (0, 0, 0, 1, 0), (0,
0, 0, 1, 1), (0, 0, 0, 1, 2), (0, 0, 0, 1, 3), (0, 0, 0, 1, 4),
...skipped for brevity...
(7, 7, 7, 6, 6), (7, 7, 7, 6, 7), (7, 7, 7, 7, 0), (7, 7, 7, 7, 1), (7, 7, 7,
7, 2), (7, 7, 7, 7, 3), (7, 7, 7, 7, 4), (7, 7, 7, 7, 5), (7, 7, 7, 7, 6), (7,
7 , 7, 7, 7)]
When the range object returned from range(8) is passed to itertools.product() (along
with 5 for the repeat keyword argument), the list that is generated has tuples of 5 values, and
each value are from the integers 0 to 7.
The itertools.product() function is an easy way to generate a list with every possible
combination of some group of values. This is how our hacking program will create integer
indexes to test every possible combination of possible subkeys.
vigenereHacker.py
186. # Try every combination of the most likely letters for each position
187. # in the key.
188. for indexes in itertools.product(range(NUM_MOST_FREQ_LETTERS),
repeat=mostLikelyKeyLength):
The allFreqScores variable is a list of lists of tuples such that allFreqScores[i] will
evaluate to a list of tuples of possible letters for a single subkey. That is, allFreqScores[0]
has a list of tuples for the first subkey, allFreqScores[1] has a list of tuples for the second
subkey, and so on.
Also, since the NUM_MOST_FREQ_LETTERS constant is set to 4 ,
itertools.product(range(NUM_MOST_FREQ_LETTERS),
repeat=mostLikelyKeyLength) will cause the for loop to have a tuple of integers (from
0 to 3 ) for the indexes variable. If 5 was passed for mostLikelyKeyLength, then the
following values would be set to indexes for each iteration: