{-

1.  Let KEYSIZE be the guessed length of the key; try values from 2 to (say) 40.

2.  Write a function to compute the edit distance/Hamming distance between two
    strings. The Hamming distance is just the number of differing bits. The
    distance between:

      this is a test

    and

      wokka wokka!!!

    is 37. Make sure your code agrees before you proceed.

3.  For each KEYSIZE, take the first KEYSIZE worth of bytes, and the second
    KEYSIZE worth of bytes, and find the edit distance between them. Normalize
    this result by dividing by KEYSIZE.
    The KEYSIZE with the smallest normalized edit distance is probably the key.
    You could proceed perhaps with the smallest 2-3 KEYSIZE values. Or take 4
    KEYSIZE blocks instead of 2 and average the distances.

4.  Now that you probably know the KEYSIZE: break the ciphertext into blocks of
    KEYSIZE length.

5.  Now transpose the blocks: make a block that is the first byte of every block,
    and a block that is the second byte of every block, and so on.
-
6.  Solve each block as if it was single-character XOR. You already have code to
    do this.

7.  For each block, the single-byte XOR key that produces the best looking
    histogram is the repeating-key XOR key byte for that block.

8.  Put them together and you have the key.
-}
search :: B.ByteString -> [(B.ByteString, B.ByteString)]
search bs =
  let
    -- step 1, 2 an 3 happen in findKeyLength
    keyLengths =
      findKeyLength bs
      |> take 2   -- We may have a keysize. To be sure we take the best
                  -- matching keysizes.

    -- for all candidate keylengths, determine the key according to step 4 to 8.
    -- one of these should be the one.
    keys =
      map ((findKey bs) . fst) keyLengths

    -- here is where the actual decryption takes place.
    -- cycleKey takes a key and a ByteString, and then cycles the key as long
    -- is required (as long as the bytestring is), and 'xors' the resulting
    -- bytestring agains the given one.
    decrypt k =
      (k, cycleKey bs k)

  in
    -- returns a number of results. Of which one is presumably the one
    map decrypt keys
search :: B.ByteString -> [(B.ByteString, B.ByteString)]
search bs =
  let
    -- step 1, 2 an 3 happen in findKeyLength
    keyLengths =
      findKeyLength bs
      |> take 2   -- We may have a keysize. To be sure we take the best
                  -- matching keysizes.

    -- for all candidate keylengths, determine the key according to step 4 to 8.
    -- one of these should be the one.
    keys =
      map ((findKey bs) . fst) keyLengths

    -- here is where the actual decryption takes place.
    -- cycleKey takes a key and a ByteString, and then cycles the key as long
    -- is required (as long as the bytestring is), and 'xors' the resulting
    -- bytestring agains the given one.
    decrypt k =
      (k, cycleKey bs k)

  in
    -- returns a number of results. Of which one is presumably the one
    map decrypt keys
search bs =
  let
    -- step 1, 2 an 3 happen in findKeyLength
    keyLengths =
      findKeyLength bs
      |> take 2   -- We may have a keysize. To be sure we take the best
                  -- matching keysizes.

    -- for all candidate keylengths, determine the key according to step 4 to 8.
    -- one of these should be the one.
    keys =
      map ((findKey bs) . fst) keyLengths

    -- here is where the actual decryption takes place.
    -- cycleKey takes a key and a ByteString, and then cycles the key as long
    -- is required (as long as the bytestring is), and 'xors' the resulting
    -- bytestring agains the given one.
    decrypt k =
      (k, cycleKey bs k)

  in
    -- returns a number of results. Of which one is presumably the one
    map decrypt keys