Deklarative Programmierung

Werbung
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]]
Herunterladen