Was bisher geschah Funktionale Programmierung in Haskell: 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 Einfügen in (anfangs leeren) binären Suchbaum Inorder-Ausgabe
Klassische Sortier-Verfahren 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 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 symmetrisches Verschlüsselungs-Verfahren: derselbe Schlüssel zum Ver- und Entschlüsseln Substitutionschiffre: Ersetzung jedes Klartextsymboles durch ein Chiffretextsymbol 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: Buchstabe durch Zahl {0,..., 25} ersetzen b2int :: Char -> Int b2int b = ord b - ord a Zahl durch entsprechenden Buchstaben ersetzen int2b :: Int -> Char int2b n = chr (ord a + n) 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 hinreichend lang, natürlichsprachig (deutsch), mit Verschiebechiffre verschlüsselt gesucht: Klartext ( und evtl. Schlüssel ) Ideen für Angriffe: Brute Force: Ausprobieren aller 26 Schlüssel 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 erwartet: e R {0,...,25} 0 (häufigkeitstabelle) im Text t aufgetreten: a R {0,...,25} 0 (häufigkeiten t) e, a R {0,...,25} n 1 0 : χ 2 (a, e) = i=0 (a i e i ) 2 e i 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 -> String crack c = decode k c where k = head ( positions (minimum chitab ) chitab ) chitab = [ chiquad (rotate n (häufigkeiten c)) häufigkeitstabelle n <- [0.. 25]]