Skip to content

Instantly share code, notes, and snippets.

@waltervargas
Created April 30, 2018 11:43
Show Gist options
  • Save waltervargas/7b0436f3475ed34170c4c376d179a732 to your computer and use it in GitHub Desktop.
Save waltervargas/7b0436f3475ed34170c4c376d179a732 to your computer and use it in GitHub Desktop.
Caesar Crack Haskell Example
import Data.Char
positions :: Eq a => a -> [a] -> [Int]
positions x xs = [i | (x', i) <- zip xs [0..], x==x']
lowers :: String -> Int
lowers xs = length [x | x <- xs, x >= 'a' && x <= 'z']
count :: Char -> String -> Int
count x xs = length [x' | x' <- xs, x == x']
let2int :: Char -> Int
let2int c = ord c - ord 'a'
int2let :: Int -> Char
int2let n = chr (ord 'a' + n)
shift :: Int -> Char -> Char
shift n c | isLower c = int2let ((let2int c + n) `mod` 26)
| otherwise = c
encode :: Int -> String -> String
encode n xs = [shift n x | x <- xs]
table :: [Float]
table = [8.167, 1.492, 2.782, 4.253, 12.702, 2.228,
2.015, 6.094, 6.966, 0.153, 0.772, 4.025,
2.406, 6.749, 7.507, 1.929, 0.095, 5.987,
6.327, 9.056, 2.758, 0.978, 2.361, 0.150,
1.974, 0.074]
percent :: Int -> Int -> Float
percent n m = (fromIntegral n / fromIntegral m) * 100
freqs :: String -> [Float]
freqs xs = [percent (count x xs) n | x <- ['a'..'z']]
where n = lowers xs
-- cracking the cipher
-- chi-square statistic that returns the match value between two frequency lists
chisqr :: [Float] -> [Float] -> Float
chisqr os es = sum [((o-e)^2)/e | (o,e) <- zip os es]
rotate :: Int -> [a] -> [a]
rotate n xs = drop n xs ++ take n xs
crack :: String -> String
crack xs = encode (-factor) xs
where
factor = head (positions (minimum chitab) chitab)
chitab = [chisqr (rotate n table') table | n <- [0..25]]
table' = freqs xs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment