Was bisher geschah Funktionale Programmierung in Haskell: I I I I I I I I I I I I I Algebraische Datentypen Pattern Matching Polymorphie Typklassen Rekursive Datentypen: Peano-Zahlen, Listen, Bäume Rekursive Funktionen strukturelle Induktion Rekursionsschemata für Peano-Zahlen, Listen, Bäume Funktionen höherer Ordnung (mit Funktionen als Argumenten) λ-Kalkül, β-Reduktion fold auf rekursiven Datentypen (Peano-Zahlen, Listen, Bäume) map auf Listen und Bäumen, filter auf Listen Bedarfsauswertung (lazy evaluation): leftmost outermost reduction + sharing Sortieren sortiert :: Ord a => [a] -> Bool sortiert xs = foldr (&&) True $ zipWith (<=) xs $ tail xs sort :: Ord a => [a] -> [a] z.B. durch I Einfügen in (anfangs leeren) binären Suchbaum I Inorder-Ausgabe Klassische Sortier-Verfahren I Sortieren durch Einfügen insert :: Ord a => a -> [ a ] -> [ a ] insert x [] = [x] insert x ( y : ys ) | x <= y = x : y : ys | x > y = y : (insert x ys) isort :: Ord a => [a] -> [a] isort [] = [] isort (x:xs) = insert x $ isort xs I Quicksort qsort :: Ord a => [a] -> [a] qsort [] = [] qsort (x:xs) = qsort [ y | y <- xs, y <= x] ++ [x] ++ qsort [ y | y <- xs, y > x] Mergesort merge :: Ord a => [a] -> [a] -> [a] merge xs [] = xs merge [] ys = ys merge (x : xs) (y : ys) | x <= y = x : merge xs ( y : ys ) | otherwise = y : merge ( x : xs ) ys msort :: Ord a => [a] -> [a] msort [] = [] msort [ x ] = [ x ] msort xs = merge ( msort l ) ( msort r ) where ( l , r ) = splitAt halb xs halb = div (length xs) 2 Ver- und Entschlüsseln Verschiebe-Chiffre I symmetrisches Verschlüsselungs-Verfahren: derselbe Schlüssel zum Ver- und Entschlüsseln I Substitutionschiffre: Ersetzung jedes Klartextsymboles durch ein Chiffretextsymbol I monoalphabetisch: Klartextsymbol überall durch dasselbe Chiffretextsymbol ersetzt Klartextmenge: M = {a, b, . . . , z}∗ Chiffretextmenge: C = {a, b, . . . , z}∗ Schlüsselmenge: K = {0, . . . , 25} Verschlüsselung: jeden Buchstaben durch Buchstaben k Positionen später im Alphabet ersetzen Entschlüsselung: jeden Buchstaben durch Buchstaben k Positionen früher im Alphabet ersetzen klassisches Beispiel: Caesar-Chiffre k = 3 Verschlüsseln für jeden (Klein-)Buchstaben im Klartext: I Buchstabe durch Zahl ∈ {0, . . . , 25} ersetzen b2int :: Char -> Int b2int b = ord b - ord ’a’ I Zahl durch entsprechenden Buchstaben ersetzen int2b :: Int -> Char int2b n = chr (ord ’a’ + n) I Buchstabe mit Schlüssel k verschlüsseln: enc :: Int -> Char -> Char enc k b | isLower b = int2b ( mod (k + b2int b) 26) | otherwise = b Klartext verschlüsseln: encode :: Int -> String -> String encode k = map ( enc k ) Chiffretext entschlüsseln: . . . Angriffe auf Verschiebechiffren Ciphertext-Only-Angriffe auf Verschiebechiffren gegeben: verschlüsselter Text I hinreichend lang, I natürlichsprachig (deutsch), I mit Verschiebechiffre verschlüsselt gesucht: Klartext ( und evtl. Schlüssel ) Ideen für Angriffe: I Brute Force: Ausprobieren aller 26 Schlüssel I typische Häufigkeiten von Buchstaben, Buchstabengruppen Funktionen auf Listen / Strings Anzahl der Vorkommen eines Elementes in einer Liste: countEl :: Eq a => a -> [ a ] -> Int countEl b = ( foldr (\x y -> y + 1) 0 ) . filter ( == b ) z.B. countEl ’o’ "foo" = 2 Anzahl der Kleinbuchstaben in einer Zeichenkette: lowers :. String -> Int lowers = ( foldr (\x y -> y + 1) 0 ) . filter ( isLower ) z.B. lowers "Foo !" = 2 Funktionen auf Listen / Strings alle Positionen eines Elementes in einer Liste: positions :: Eq a => a -> [ a ] -> [ Int ] positions x xs = ( map fst ) $ filter (\ ( _ , y) -> y == x ) $ zip [ 0 .. ] xs z.B. positions ’o’ "foo" = [1,2] Rotieren von Listen rotate :: Int -> [ a ] -> [ a ] rotate n xs = drop n xs ++ take n xs Buchstaben-Häufigkeiten Häufigkeiten (in deutschen Texten): haeufigkeitstabelle :: [ Float ] haeufigkeitstabelle = [6.51, 1.89, 3.06, 5.08, 17.4, 1.66, 3.01, 4.76, 7.55, 0.27, 1.21, 3.44, 2.53, 9.78, 2.51, 0.79, 0.02, 7.00, 7.27, 6.15, 4.35, 0.67, 1.89, 0.03, 0.04, 1.13] zip [’a’ .. ’z’] häufigkeitstabelle proz :: Int -> Int -> Float proz m n = (fromIntegral m / fromIntegral n) * 100 Prozentuale Häufigkeit im (verschlüsselten) Text: häufigkeiten :: String -> [ Float ] häufigkeiten t = [ proz ( countEl x t ) n | x <- [ ’a’ .. ’z’ ] ] where n = lowers t Statistik Test auf (annähernd) gleiche Verteilung durch Chi-Quadrat-Test für Buchstabenhäufigkeiten R{0,...,25} I erwartet: e ∈ ≥0 (häufigkeitstabelle) I im Text t aufgetreten: a ∈ (häufigkeiten t) ∀e, a ∈ R{0,...,25} : ≥0 R{0,...,25} ≥0 χ2 (a, e) = n−1 X (ai − ei )2 ei i=0 chiquad :: [ Float ] -> [ Float ] -> Float chiquad a e = foldr (\x y -> x + y) 0 $ zipWith (\ x y -> (x - y)^2 / y) a e chiquad (häufigkeiten "ipiqirx") häufigkeitstabelle Knacken der Verschiebechiffre Chi-Test für alle möglichen Schlüssel k ∈ {0, . . . , 25} für Chiffretext c: chitab = [ chiquad ( rotate k ( häufigkeiten c ) ) häufigkeitstabelle | k <- [ 0 .. 25 ] ] Index (Verschiebung) des kleinsten χ2 -Wertes: k = head ( positions (minimum chitab ) chitab ) where chitab = [ chiquad (rotate n (häufigkeiten c)) häufigkeitstabelle | n <- [ 0 .. 25 ] ] ist (wahrscheinlich) der Schlüssel crack :: String -> crack c = decode k where k = head ( chitab = [ String c positions (minimum chitab ) chitab ) chiquad (rotate n (häufigkeiten c)) häufigkeitstabelle | n <- [0 .. 25]]