Skip to content

Instantly share code, notes, and snippets.

@supki
Created June 11, 2012 18:52
Show Gist options
  • Save supki/2911904 to your computer and use it in GitHub Desktop.
Save supki/2911904 to your computer and use it in GitHub Desktop.
Cryptography coursera class exercise #1.
{-# LANGUAGE UnicodeSyntax #-}
module Main where
import Control.Applicative ((<$>))
import Control.Monad (forM_, when)
import Control.Monad.State (execState, modify)
import Data.Bits (Bits, xor)
import Data.Char (chr, isAlpha)
import Data.List (maximumBy, group, sort, zip4)
import Data.List.Split (splitEvery)
import Data.IntMap (IntMap)
import Data.Ord (comparing)
import qualified Data.IntMap as M
-- | Read ciphers from "ciphers.txt", try to guess a key and decrypt secret message
main ∷ IO ()
main = do
ciphers ← readCiphers "ciphers.txt"
let key = M.elems $ chooseMostFrequent $ distribution $ combineWith xor ciphers
mapM_ (putStrLn . map chr . zipWith xor key) ciphers
-- | Read routine
readCiphers ∷ Read α ⇒ FilePath → IO [[α]]
readCiphers fp = map readCipher . lines <$> readFile fp
where readCipher = map (read . ("0x" ++)) . splitEvery 2
-- | Get all xored ciphers pairs
combineWith ∷ (α → α → β) → [[α]] → [([α], [α], [β])]
combineWith f cs = [ (a,b,zipWith f a b) | a ← cs, b ← cs ]
-- | Construct frequency IntMap
distribution ∷ Bits α ⇒ [([α], [α], [Int])] → IntMap [α]
distribution xs = flip execState (M.empty) $
forM_ xs $ \(as,bs,cs) →
forM_ (zip4 [0..] as bs cs) $ \(i,a,b,c) → do
let hui = M.insertWith (++) i $ map (xor 32) [a, b]
when (isAlpha $ chr c) $ modify hui
-- | NOTE: head is safe here since there is no empty lists
-- while construction distribution IntMap
chooseMostFrequent ∷ (Eq α, Ord α) ⇒ IntMap [α] → IntMap α
chooseMostFrequent = M.map (head . maximumBy (comparing length) . group . sort)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment