Złożoność obliczeniowa/Wykład 15: Kryptografia a złożoność: Różnice pomiędzy wersjami
Nie podano opisu zmian |
m Zastępowanie tekstu – „ </math>” na „</math>” |
||
(Nie pokazano 21 wersji utworzonych przez 4 użytkowników) | |||
Linia 3: | Linia 3: | ||
W dotychczasowych rozważaniach naszym celem było znalezienie możliwie | W dotychczasowych rozważaniach naszym celem było znalezienie możliwie | ||
efektywnego rozwiązania dla zadanych problemów; nadmierna złożoność problemu | efektywnego rozwiązania dla zadanych problemów; nadmierna złożoność problemu | ||
była przez nas traktowana jako cecha niepożądana, | była przez nas traktowana jako cecha niepożądana, utrudniająca nam | ||
zadanie. W tym rozdziale nasze podejście będzie odmienne; duża złożoność będzie | zadanie. W tym rozdziale nasze podejście będzie odmienne; duża złożoność będzie | ||
dla nas cechą bardzo cenną. Będzie nas przy tym w mniejszym niż dotychczas | dla nas cechą bardzo cenną. Będzie nas przy tym, w mniejszym niż dotychczas | ||
stopniu interesować złożoność pesymistyczna -- w końcu nie satysfakcjonuje | stopniu, interesować złożoność pesymistyczna -- w końcu nie satysfakcjonuje | ||
nas "gwarancja", | nas "gwarancja" mówiąca, że "jeżeli osoba podsłuchująca będzie miała pecha, | ||
to odszyfrowanie wiadomości będzie dla niej zadaniem czasochłonnym". | to odszyfrowanie wiadomości będzie dla niej zadaniem czasochłonnym". | ||
Wolelibyśmy, żeby odszyfrowywanie wiadomości przez osoby nieuprawnione było | Wolelibyśmy, żeby odszyfrowywanie wiadomości przez osoby nieuprawnione było | ||
czasochłonne praktycznie zawsze -- tak, by próba podsłuchiwania dawała szansę | czasochłonne, praktycznie zawsze -- tak, by próba podsłuchiwania dawała szansę | ||
sukcesu bardzo bliską zeru. Duża pesymistyczna złożoność nie będzie zatem warunkiem | sukcesu bardzo bliską zeru. Duża pesymistyczna złożoność nie będzie zatem warunkiem | ||
wystarczającym bycia dobrym kryptosystemem; przyda nam się jednak w charakterze | wystarczającym bycia dobrym kryptosystemem; przyda nam się jednak w charakterze | ||
warunku koniecznego. | warunku koniecznego. | ||
{{definicja||| | {{definicja|1.1|| | ||
Niech <math> | Niech <math>f: \{ 0, 1 \} ^\star \rightarrow \{ 0, 1 \} ^\star</math>. Mówimy, że <math>f</math> jest | ||
funkcją jednokierunkową wtedy i tylko wtedy gdy: | funkcją jednokierunkową wtedy i tylko wtedy, gdy: | ||
* <math> | * <math>f</math> jest różnowartościowa, | ||
* istnieje pewna stała <math> | * istnieje pewna stała <math>k > 1</math> taka, że <math>\forall_{x \in \{0, 1\}^\star} |x|^{1/k} \leq f(x) \leq |x|^k</math>, | ||
|x|^{1/k} \leq f(x) \leq |x|^k</math>, | * <math>f</math> jest obliczalna w czasie wielomianowym (czyli należy do klasy <math>FP</math>), | ||
* <math> | * nie istnieje wielomianowy algorytm obliczający odwrotność funkcji <math>f</math> -- czyli znajdujący dla słowa <math>y</math> słowo <math>x</math>, takie że <math>f(x) = y</math> lub stwierdzający, że takie słowo nie istnieje. | ||
* nie istnieje wielomianowy algorytm obliczający odwrotność funkcji <math> | |||
-- czyli znajdujący dla słowa <math> | |||
stwierdzający, że takie słowo nie istnieje. | |||
}} | }} | ||
Warto zauważyć, że powyższa definicja niejawnie zakłada prawdziwość zdania | Warto zauważyć, że powyższa definicja niejawnie zakłada prawdziwość zdania | ||
<math> | <math>P \neq NP</math>. | ||
{{cwiczenie||| | {{cwiczenie|1.2|| | ||
Niech <math> | Niech <math>f</math> spełnia pierwsze trzy warunki podane w definicji funkcji jednokierunkowej. | ||
Pokaż, że obliczanie odwrotności funkcji <math> | Pokaż, że obliczanie odwrotności funkcji <math>f</math> jest problemem z klasy <math>FNP</math>. | ||
}} | }} | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | ||
Z drugiego warunku wiemy, że <math> | Z drugiego warunku wiemy, że <math>f^{-1}(y)</math> ma długość co najwyżej <math>|y|^k</math>. Możemy | ||
zatem jako kandydatów na świadków rozpatrywać wszystkie słowa o długości | zatem jako kandydatów na świadków rozpatrywać wszystkie słowa o długości | ||
nie większej niż <math> | nie większej niż <math>|y|^k</math>. Takie słowa możemy następnie deterministycznie | ||
przekształcić za pomocą funkcji <math> | przekształcić za pomocą funkcji <math>f</math> i sprawdzić, czy otrzymane słowo jest równe | ||
<math> | <math>y</math>. | ||
</div></div> | </div></div> | ||
Z drugiej strony nierówność <math> | Z drugiej strony nierówność <math>P \neq NP</math> wcale nie gwaratuje istnienia funkcji | ||
jednokierunkowych; jak się okazuje istnienie tego typu funkcji jest ściśle | jednokierunkowych; jak się okazuje istnienie tego typu funkcji jest ściśle | ||
powiązane z pewną klasą złożoności, którą przedstawiamy poniżej. | powiązane z pewną klasą złożoności, którą przedstawiamy poniżej. | ||
{{definicja|Jednoznaczną maszyną Turinga | {{definicja|1.3|| | ||
nazywamy niedeterministyczną maszynę | Jednoznaczną maszyną Turinga nazywamy niedeterministyczną maszynę Turinga taką, że dla każdego słowa wejściowego <math>x</math> istnieje co najwyżej jedna akceptująca ścieżka obliczeń. | ||
Turinga taką, że dla każdego słowa wejściowego <math> | |||
akceptująca ścieżka obliczeń. | |||
}} | }} | ||
{{definicja||| | {{definicja|1.4|| | ||
Klasa <math> | Klasa <math>UP</math> to klasa problemów rozstrzygalnych za pomocą jednoznacznych maszyn | ||
Turinga w czasie wielomianowym. | Turinga w czasie wielomianowym. | ||
}} | }} | ||
{{uwaga||| | {{uwaga|1.5|| | ||
Klasę <math> | Klasę <math>UP</math>, podobnie jak klasę <math>NP</math>, można zdefiniować z użyciem pojęcia | ||
świadka: | świadka: | ||
<math> | <math>L \in UP \iff \exists_{p(x) - wielomian} \exists_{L' \in P} | ||
\forall_{n \in {\mathbb N}} \forall_{w \in \{ 0, 1 \} ^n} | \forall_{n \in {\mathbb N}} \forall_{w \in \{ 0, 1 \} ^n} | ||
[w \in L \Rightarrow ({\exists !}_{v \in \{ 0, 1 \}^{p(n)}} \langle w, v \rangle \in L')] | [w \in L \Rightarrow ({\exists !}_{v \in \{ 0, 1 \}^{p(n)}} \langle w, v \rangle \in L')] | ||
\wedge | \wedge | ||
[w \notin L \Rightarrow (\neg \exists_{v \in \{ 0, 1 \}^{p(n)}} \langle w, v \rangle \in L')]</math> | [w \notin L \Rightarrow (\neg \exists_{v \in \{ 0, 1 \}^{p(n)}} \langle w, v \rangle \in L')]</math>. | ||
W językach z klasy <math> | W językach z klasy <math>UL</math> każde słowo ma dokładnie jednego świadka. Dowód | ||
równoważności powyższych definicji jest analogiczny jak w przypadku klasy | równoważności powyższych definicji jest analogiczny jak w przypadku klasy | ||
<math> | <math>NP</math>. | ||
}} | }} | ||
Jest jasne, że <math> | Jest jasne, że <math>P \subseteq UP \subseteq NP</math> -- maszyny deterministyczne są | ||
specjalnymi przypadkami maszyn jednoznacznych. Dość powszechny jest pogląd, | specjalnymi przypadkami maszyn jednoznacznych. Dość powszechny jest pogląd, | ||
że obie powyższe relacje zawierania są właściwe (to znaczy nie zachodzi równość). | że obie powyższe relacje zawierania są właściwe (to znaczy nie zachodzi równość). | ||
Pokażemy teraz bardzo ciekawy związek pomiędzy klasą <math> | Pokażemy teraz bardzo ciekawy związek pomiędzy klasą <math>UP</math> a funkcjami | ||
jednokierunkowymi. | jednokierunkowymi. | ||
{{twierdzenie||| | {{twierdzenie|1.6|| | ||
Funkcje jednokierunkowe istnieją <math> | Funkcje jednokierunkowe istnieją wtedy i tylko wtedy, gdy <math>UP \neq P</math>. | ||
}} | }} | ||
{{dowod||| | {{dowod||| | ||
Zaczniemy od dowodu w kierunku <math> | Zaczniemy od dowodu w kierunku <math>\Rightarrow</math>. Załóżmy, że istnieje pewna funkcja | ||
jednokierunkowa <math> | jednokierunkowa <math>f</math>. Możemy wtedy zdefiniować następujący język: | ||
<math> | <math>L_f = \{ (x, y): \exists_z f(z) = y \wedge z \leq x\}</math>, | ||
przy czym mówimy, że <math> | przy czym mówimy, że <math>z \leq x</math> wtedy i tylko wtedy, gdy | ||
* <math> | * <math>|z| \leq |y|</math> lub | ||
* <math> | * <math>|z| = |y|</math> i w porządku leksykograficznym <math>z</math> występuje nie później niż <math>x</math>. | ||
<math> | |||
Łatwo można zauważyć, że <math> | Łatwo można zauważyć, że <math>L_f \in UP</math> - maszyna rozwiązująca ten problem | ||
najpierw "zgaduje" słowo <math> | najpierw "zgaduje" słowo <math>z</math> o wielkości nie większej niż <math>|y|^k</math>, po czym | ||
sprawdza, czy w ustalonym porządku występuje ono nie później niż <math> | sprawdza, czy w ustalonym porządku występuje ono nie później niż <math>x</math> i czy | ||
zachodzi <math> | zachodzi <math>f(z) = y</math>. Z własności funkcji jednokierunkowych -- konkretnie z | ||
różnowartościowości -- wynika, że maszyna ta ma co najwyżej jedną akceptującą | różnowartościowości -- wynika, że maszyna ta ma co najwyżej jedną akceptującą | ||
ścieżkę postępowania. | ścieżkę postępowania. | ||
Chcemy teraz pokazać, że <math> | Chcemy teraz pokazać, że <math>L_f \notin P</math>. Załóżmy zatem nie wprost, że istnieje | ||
jakiś wielomianowy algorytm rozwiązujący <math> | jakiś wielomianowy algorytm rozwiązujący <math>L_f</math>. Wykorzystamy go teraz do | ||
obliczenia odwrotności funkcji <math> | obliczenia odwrotności funkcji <math>f</math> w czasie wielomianowym. W pierwszym kroku | ||
zapytamy algorytm, czy <math> | zapytamy algorytm, czy <math>(1^{|y|^k}, y) \in L_f</math> (przez <math>1^{|y|^k}</math> oznaczamy | ||
tutaj ciąg <math> | tutaj ciąg <math>|y|^k</math> symboli <math>1</math>) - jeżeli otrzymamy odpowiedź NIE, to | ||
korzystając z definicji funkcji jednokierunkowej możemy od razu stwierdzić, | korzystając z definicji funkcji jednokierunkowej, możemy od razu stwierdzić, | ||
że nie istnieje słowo <math> | że nie istnieje słowo <math>x</math> takie, że <math>f(x) = y</math>. Jeżeli otrzymamy odpowiedź | ||
TAK, to z użyciem co najwyżej <math>|y|^k - 1</math> zapytań do naszego algorytmu | |||
jesteśmy w stanie ustalić długość szukanego słowa <math> | jesteśmy w stanie ustalić długość szukanego słowa <math>x</math> (pytamy kolejno o | ||
<math> | <math>(1^{|y|^k - 1}, y)</math>, <math>(1^{|y|^k - 2}, y)</math>, itd., aż do momentu, gdy uzyskamy | ||
odpowiedź | odpowiedź NIE). Gdy znamy już długość słowa <math>x</math> pozostaje nam tylko | ||
obliczyć kolejne jego bity. Pierwszy bit otrzymamy pytając o parę | obliczyć kolejne jego bity. Pierwszy bit otrzymamy, pytając o parę | ||
<math> | <math>(01^{|x| - 1}, y)</math> -- odpowiedź "tak" oznacza, że pierwszym bitem jest 0. | ||
Aby uzyskać drugi bit zapytamy -- w zależności od pierwszej odpowiedzi -- | Aby uzyskać drugi bit zapytamy -- w zależności od pierwszej odpowiedzi -- | ||
o <math> | o <math>(001^{|x| - 2}, y)</math> lub <math>(101^{|x| - 2}, y)</math>. Kolejne bity odgadujemy w | ||
analogiczny sposób -- łącznie zatem wykonamy algorytm dla <math> | analogiczny sposób -- łącznie zatem wykonamy algorytm dla <math>L_fO(|y|^k)</math> | ||
razy. W ten sposób uzyskamy deterministycznty algorytm odwracający funkcję <math> | razy. W ten sposób uzyskamy deterministycznty algorytm odwracający funkcję <math>f</math> | ||
w czasie wielomianowym. | w czasie wielomianowym. | ||
Doszliśmy więc do sprzeczności z definicją funkcji | Doszliśmy więc do sprzeczności z definicją funkcji | ||
jednokierunkowej, co oznacza, że istnienie funkcji jednokierunkowych implikuje | jednokierunkowej, co oznacza, że istnienie funkcji jednokierunkowych implikuje | ||
nierówność <math> | nierówność <math>P \neq UP</math>. | ||
Załóżmy teraz, że istnieje język <math> | Załóżmy teraz, że istnieje język <math>L \in UP - P</math>, rozpoznawany przez jednoznaczną | ||
maszynę <math> | maszynę <math>U</math>. Zdefiniujmy funkcję <math>f_U(w)</math> w następujący sposób: | ||
* jeżeli <math> | * jeżeli <math>w</math> jest zakodowaną parą słów <math>\langle x, y \rangle</math> oraz <math>x</math> jest (jedynym) świadkiem przynależności słowa <math>y</math> do <math>L</math>, to | ||
jest (jedynym) świadkiem przynależności słowa <math> | |||
<math> | <math>f_U(w) = 1y</math>, | ||
* w przeciwnym przypadku | * w przeciwnym przypadku | ||
<math> | <math>f_U(w) = 0w</math>. | ||
Widzimy, że pierwszy symbol wartości funkcji gwarantuje nam jej różnowartościowość. | Widzimy, że pierwszy symbol wartości funkcji gwarantuje nam jej różnowartościowość. | ||
Spełniony jest również drugi warunek z definicji funkcji jednokierunkowej -- | Spełniony jest również drugi warunek z definicji funkcji jednokierunkowej -- | ||
świadek dla słowa <math> | świadek dla słowa <math>y</math> nie może być nadmiernie długi (bo jego długość jest | ||
wielomianowo zależna od długości <math> | wielomianowo zależna od długości <math>y</math>), a zatem <math>f_U</math> nie może nadmiernie | ||
"skracać" słów. Funkcja <math> | "skracać" słów. Funkcja <math>f_U</math> jest też obliczalna w czasie wielomianowym | ||
-- wystarczy deterministycznie zweryfikować świadka, tak jak zrobiłaby to maszyna | -- wystarczy deterministycznie zweryfikować świadka, tak jak zrobiłaby to maszyna | ||
<math> | <math>U</math>. Pozostaje nam zatem tylko pokazanie, że funkcja odwrotna do | ||
<math> | <math>d</math> nie jest obliczalna w czasie wielomianowym. Gdyby tak jednak było, to | ||
moglibyśmy rozpoznawać język <math> | moglibyśmy rozpoznawać język <math>L</math> w czasie wielomianowym: aby sprawdzić, czy | ||
<math> | <math>y \in L</math> wystarczy zastosować odwrotność funkcji <math>f_U</math> do słowa <math>1y</math>; jeżeli | ||
<math> | <math>y \notin L</math>, to dostaniemy odpowiedź mówiącą, że <math>1y</math> nie można odwrócić; | ||
w przeciwnym przypadku otrzymamy świadka przynależności <math> | w przeciwnym przypadku otrzymamy świadka przynależności <math>y</math> do języka <math>L</math>. | ||
}} | }} | ||
Na dzień dzisiejszy nie znamy oczywiście funkcji, o której wiedzielibyśmy, że | Na dzień dzisiejszy nie znamy oczywiście funkcji, o której wiedzielibyśmy, że | ||
jest jednokierunkowa; istnienie takiej funkcji natychmiastowo implikuje przecież | jest jednokierunkowa; istnienie takiej funkcji natychmiastowo implikuje przecież | ||
nierówność <math> | nierówność <math>P \neq NP</math>. Jest jednak kilku "kandydatów" na funkcje jednokierunkowe, dla których nie znamy efektywnego algorytmu pozwalającego | ||
na ich odwrócenie. Jedną z takich funkcji jest <math>f_{MUL}</math>. Argumentami | |||
na ich odwrócenie. Jedną z takich funkcji jest | |||
tej funkcji są dwie liczby pierwsze wraz ze swoimi certyfikatami pierwszości. | tej funkcji są dwie liczby pierwsze wraz ze swoimi certyfikatami pierwszości. | ||
Wartością funkcji jest iloczyn tych dwóch liczb. Bardziej formalnie: | Wartością funkcji jest iloczyn tych dwóch liczb. Bardziej formalnie: | ||
* jeżeli <math> | * jeżeli <math>w = \langle p, C(p), q, C(q) \rangle</math>, gdzie <math>p < q</math> a <math>C(p)</math> i <math>C(q)</math> są certyfikatami pierwszości odpowiednio dla <math>p</math> i <math>q</math>, to | ||
<math> | |||
<math>f_{MUL}(w) = 1 p \cdot q</math>, | |||
* w przeciwnym przypadku | * w przeciwnym przypadku | ||
<math> | <math>f_{MUL}(w) = 0 w</math>. | ||
Korzystamy tutaj z faktu, że możemy wymusić jednoznaczną reprezentację | Korzystamy tutaj z faktu, że możemy wymusić jednoznaczną reprezentację | ||
certyfikatu pierwszości dla danej liczby | certyfikatu pierwszości dla danej liczby oraz że certyfikaty mają rozmiar | ||
wielomianowo zależny od rozmiaru certyfikowanych liczb. <math> | wielomianowo zależny od rozmiaru certyfikowanych liczb. <math>f_{MUL}</math> jest zatem | ||
różnowartościowa i nie "skraca" nadmiernie słowa wejściowego. | różnowartościowa i nie "skraca" nadmiernie słowa wejściowego. | ||
Linia 178: | Linia 170: | ||
jest na zagadnieniu z dziedziny teorii liczb -- problemie logarytmu dyskretnego. | jest na zagadnieniu z dziedziny teorii liczb -- problemie logarytmu dyskretnego. | ||
Funkcję tą można zdefiniować w następujący sposób: | Funkcję tą można zdefiniować w następujący sposób: | ||
* dla <math> | * dla <math>w</math> postaci <math>\langle p, C(p), r, x \rangle</math>, gdzie <math>p</math> jest liczbą pierwszą, <math>C(p)</math> certyfikatem jej pierwszości, <math>r</math> jest najmniejszym generatorem grupy cyklicznej <math>\mathbb{Z}_p^\star</math>, a <math>x</math> jest liczbą naturalną z zakresu <math>[1, p-1]</math> | ||
pierwszą, <math> | |||
generatorem grupy cyklicznej <math> | <math>f_{EXP}(w) = 1 \langle p, r, r^x mod p)\rangle</math> | ||
naturalną z zakresu <math> | |||
* dla pozostałych <math> | * dla pozostałych <math>w</math> | ||
<math>f_{EXP}(w) = 0 w</math>. | |||
Jak zauważyliśmy we wprowadzeniu do tego rozdziału w kryptografii duża złożoność | W tym przypadku, aby odwrócić funkcję <math>f_{EXP}</math>, musielibyśmy na podstawie | ||
liczb <math>p</math>, <math>r</math> i <math>r^x mod p</math> umieć obliczyć wartość <math>x</math>. Również dla tego, | |||
znanego od wielu lat, problemu nie potrafimy przedstawić wydajnego rozwiązania. | |||
Jak zauważyliśmy, we wprowadzeniu do tego rozdziału, w kryptografii duża złożoność | |||
pesymistyczna próby zdekodowania zaszyfrowanej wiadomości nie jest własnością | pesymistyczna próby zdekodowania zaszyfrowanej wiadomości nie jest własnością | ||
wystarczającą. Z tego powodu przytoczymy alternatywną definicję funkcji | wystarczającą. Z tego powodu przytoczymy alternatywną definicję funkcji | ||
Linia 194: | Linia 188: | ||
że definicja ta jest istotnie różna od definicji podanej wcześniej. | że definicja ta jest istotnie różna od definicji podanej wcześniej. | ||
{{definicja||| | {{definicja|1.7|| | ||
Niech <math> | Niech <math>f: \{ 0, 1 \}^\star \rightarrow \{ 0, 1 \}^\star</math>. Mówimy, że <math>f</math> jest | ||
''funkcją jednokierunkową'' wtedy i tylko wtedy gdy: | ''funkcją jednokierunkową'' wtedy i tylko wtedy, gdy: | ||
* <math> | * <math>f</math> jest obliczalna w czasie wielomianowym, | ||
* <math> | * <math>f</math> nie jest stale równa <math>\epsilon</math> (słowu pustemu), | ||
* istnieje pewna stała <math> | * istnieje pewna stała <math>k > 1</math> taka, że <math>\forall_{x \in \{0, 1\}^\star} f(x) = \epsilon \vee |x|^{1/k} \leq f(x) \leq |x|^k</math>, | ||
f(x) = \epsilon \vee |x|^{1/k} \leq f(x) \leq |x|^k</math>, | * jeżeli <math>x</math> i <math>y</math> są słowami nad alfabetem <math>\{ 0, 1 \}</math> i <math>f(x) = f(y)</math>, to <math>x = y</math> lub <math>f(x) = f(y) = \epsilon</math>, | ||
* jeżeli <math> | * dla każdej losowej maszyny Turinga <math>E</math> działającej w czasie wielomianowym, każdej liczby <math>l</math> i dostatecznie dużej liczby <math>n</math>, jeżeli <math>x</math> jest losowym słowem ze zbioru <math>\{ x': |x'| \leq n \wedge f(x') \neq \epsilon \}</math>, to | ||
to <math> | |||
* dla każdej losowej maszyny Turinga <math> | |||
każdej liczby <math> | |||
dużej liczby <math> | |||
<math> | |||
<math> | <math>Pr[E(f(x)) = x] \leq n^{-l}</math>. | ||
}} | }} | ||
W tej definicji zrezygnowaliśmy z wymagania o różnowartościowości funkcji; | W tej definicji zrezygnowaliśmy z wymagania o różnowartościowości funkcji; | ||
zamiast tego dopuszczamy, aby różne słowa dawały jako wynik wartość <math> | zamiast tego dopuszczamy, aby różne słowa dawały jako wynik wartość <math>\epsilon</math>, | ||
którą możemy traktować jako odpowiedź mówiącą, że wejście jest nieprawidłowe; | którą możemy traktować jako odpowiedź mówiącą, że wejście jest nieprawidłowe; | ||
dla przykładu przy adaptowaniu funkcji <math> | dla przykładu przy adaptowaniu funkcji <math>f_{MUL}</math> do powyższej definicji, | ||
w przypadku gdy <math> | w przypadku gdy <math>p</math> lub <math>q</math> nie będą liczbami pierwszymi lub gdy <math>C(p)</math>, lub | ||
<math> | <math>C(q)</math> nie będą odpowiednimi certyfikatami, funkcja zwróci wartość <math>\epsilon</math>. | ||
Zauważmy, że w powyższej definicji interesuje nas tylko trudność odszyfrowania | Zauważmy, że w powyższej definicji interesuje nas tylko trudność odszyfrowania | ||
wartości funkcji dla poprawnych wejść -- to znaczy w przypadku <math> | wartości funkcji dla poprawnych wejść -- to znaczy w przypadku <math>f_{MUL}</math> dla | ||
par liczb, które są pierwsze i których pierwszość jest potwierdzana przez | par liczb, które są pierwsze i których pierwszość jest potwierdzana przez | ||
<math> | <math>C(p)</math> i <math>C(q)</math>. Funkcje <math>f_{MUL}</math> | ||
jak i <math> | jak i <math>f_{EXP}</math> -- po odpowiednim ich zmodyfikowaniu w sposób przedstawiony | ||
powyżej -- są poważnymi "kandydatami" na funkcje jednokierunkowe również w | powyżej -- są poważnymi "kandydatami" na funkcje jednokierunkowe również w | ||
sensie definicji opisanej w poprzednim paragrafie. | sensie definicji opisanej w poprzednim paragrafie. | ||
Linia 229: | Linia 218: | ||
mogą się przydać w kryptografii. Otóż widzimy, że jedna ze stron -- zwyczajowo | mogą się przydać w kryptografii. Otóż widzimy, że jedna ze stron -- zwyczajowo | ||
zwana Alicją -- może wydajnie zaszyfrować swoją wiadomość, na przykład używając | zwana Alicją -- może wydajnie zaszyfrować swoją wiadomość, na przykład używając | ||
ją jako argument <math> | ją jako argument <math>x</math> do funkcji <math>f_{EXP}</math>. Niestety druga strona -- zazwyczaj | ||
o imieniu Bob -- może mieć duże trudności z odszyfrowaniem wiadomości. W tej | |||
sytuacji fakt, że osoba podsłuchująca -- Cecylia -- niczego ciekawego się | sytuacji fakt, że osoba podsłuchująca -- Cecylia -- niczego ciekawego się | ||
nie dowie, stanowi słabe pocieszenie. | nie dowie, stanowi słabe pocieszenie. | ||
Linia 237: | Linia 226: | ||
ale również możliwość odebrania tej wiadomości, Bob musi posiadać pewną tajną | ale również możliwość odebrania tej wiadomości, Bob musi posiadać pewną tajną | ||
wiedzę, pozwalającą na wydajne odwrócenie funkcji szyfrującej. Zdefiniujemy | wiedzę, pozwalającą na wydajne odwrócenie funkcji szyfrującej. Zdefiniujemy | ||
teraz pewną modyfikację pojęcia funkcji jednokierunkowej | teraz pewną modyfikację pojęcia funkcji jednokierunkowej mającą szersze | ||
zastosowanie w kryptografii. | zastosowanie w kryptografii. | ||
{{definicja||| | {{definicja|1.8|| | ||
Niech <math> | Niech <math>f: \{ 0,1 \}^\star \times \{ 0,1 \}^\star \rightarrow \{ 0,1 \}^\star</math>. | ||
Mówimy, że <math> | Mówimy, że <math>f</math> jest ''funkcją z wytrychem'' wtedy i tylko wtedy gdy istnieje | ||
losowa maszyna Turinga <math> | losowa maszyna Turinga <math>G</math> oraz funkcja | ||
<math> | <math>h:\{ 0,1 \}^\star \times \{ 0,1 \}^\star \rightarrow \{ 0,1 \}^\star</math> taka, że: | ||
* funkcje <math> | * funkcje <math>f</math> i <math>h</math> są obliczalne w czasie wielomianowym, | ||
* <math> | * <math>G</math> oczekuje na wejściu słowa nad alfabetem <math>\{ 0, 1\}</math>, zwraca zakodowaną parę słów nad alfabetem <math>\{0, 1\}</math> i działa w czasie wielomianowym, | ||
parę słów nad alfabetem <math> | * istnieje stała <math>k > 1</math> taka, że jeżeli <math>\langle i, t \rangle</math> stanowi wynik działania maszyny <math>M</math> dla słowa <math>1^n</math>, natomiast <math>x</math> jest słowem o długości nie większej niż <math>n</math>, to <math>|\langle i, x \rangle |^{1/k} \leq |\langle t, f(i, x) \rangle | \leq |\langle i, x \rangle |^k</math>, | ||
* istnieje stała <math> | * jeżeli <math>\langle i, t \rangle</math> stanowi wynik działania maszyny <math>M</math> dla słowa <math>1^n</math>, natomiast <math>x</math> i <math>y</math> są słowami o długości nie większej niż <math>n</math>, to | ||
jeżeli <math> | |||
słowa <math> | |||
<math> | |||
* jeżeli <math> | |||
słowa <math> | |||
<math>\ | <math>f(i,x) = f(i,y) \Rightarrow x=y</math>, | ||
* | |||
<math> | * dla każdej losowej maszyny Turinga <math>E</math>, każdej liczby <math>l</math> i dostatecznie dużej liczby <math>n</math>, jeżeli <math>\langle i, t \rangle</math> stanowi wynik działania maszyny <math>M</math> dla słowa <math>1^n</math>, <math>x</math> jest losowym słowem nad alfabetem <math>\{ 0, 1\}</math> nie dłuższym niż <math>n</math>, to | ||
wejściowego <math> | |||
<math>Pr[E(i, f(i, x)) = x] \leq n^{-l}</math>, | |||
* dla każdego <math>n</math>, każdego słowa <math>x</math> nie dłuższego niż <math>n</math> i każdej pary <math>\langle i, t \rangle</math> mogącej być wynikiem działania maszyny <math>G</math>, dla słowa wejściowego <math>1^nh(t, f(i, x)) = x</math>. | |||
}} | }} | ||
Linia 270: | Linia 252: | ||
kryptograficznych z kluczem publicznym. Sposób postępowania jest w tym przypadku | kryptograficznych z kluczem publicznym. Sposób postępowania jest w tym przypadku | ||
następujący: | następujący: | ||
* Bob ustala długość przekazywanych wiadomości (<math> | * Bob ustala długość przekazywanych wiadomości (<math>n</math>) oraz parametr wyznaczający prawdopodobieństwo odszyfrowania pojedynczej wiadomości (<math>k</math>), | ||
wyznaczający prawdopodobieństwo odszyfrowania pojedynczej wiadomości (<math> | * Bob uruchamia maszynę <math>G</math> i otrzymuje parę słów <math>\langle i, t\rangle</math>. Słowo <math>i</math> staje się dostępnym dla wszystkich kluczem publicznym, natomiast <math>t</math> pozostaje tajemnicą znaną tylko Bobowi, | ||
* Bob uruchamia maszynę <math> | * Alicja, chcąc wysłać wiadomość do Boba, używa znanego jej klucza publicznego <math>i</math>. Własności funkcji z wytrychem sprawiają, że odszyfrowanie wiadomości jest łatwe dla Boba, natomiast trudne dla osób trzecich nieznających klucza <math>t</math>. | ||
Słowo <math> | |||
<math> | |||
* Alicja, chcąc wysłać wiadomość do Boba, używa znanego jej klucza | |||
publicznego <math> | |||
wiadomości jest łatwe dla Boba, natomiast trudne dla osób trzecich | |||
Najbardziej znanym systemem kryptograficznym opartym na powyższej zasadzie | Najbardziej znanym systemem kryptograficznym opartym na powyższej zasadzie | ||
Linia 284: | Linia 260: | ||
mówiącego, że RSA spełnia warunki określone w definicji funkcji z wytrychem. | mówiącego, że RSA spełnia warunki określone w definicji funkcji z wytrychem. | ||
Prześledźmy teraz w jaki sposób zdefiniowane są <math> | Prześledźmy teraz, w jaki sposób zdefiniowane są <math>f</math>, <math>h</math> i <math>G</math> dla systemu RSA. | ||
Zadaniem maszyny <math> | Zadaniem maszyny <math>G</math> jest wygenerowanie pary kluczy. W tym celu losuje ona | ||
dwie liczby pierwsze <math> | dwie liczby pierwsze <math>p</math> i <math>q</math>, z których każda ma długość większą niż | ||
<math> | <math>n / 2</math> (gdzie <math>n</math> to długość przekazywanych wiadomości). Następnie oblicza | ||
ona liczbę <math> | ona liczbę <math>N = p \cdot q</math> oraz wartość funkcji Eulera dla tej liczby: | ||
<math> | <math>\phi(N) = (p-1)\cdot(q-1)</math>. W kolejnym kroku znajdywana jest dowolna liczba | ||
<math> | <math>e</math> z zakresu <math>[2, N-2]</math>, względnie pierwsza z <math>\phi(N)</math>. Dla liczby <math>e</math> | ||
znajdywana jest następnie liczba <math> | znajdywana jest następnie liczba <math>d</math> z zakresu <math>[2, N-2]</math> taka, że | ||
<math> | <math>d \cdot e = 1 mod \phi(N)</math>. | ||
Istnienie takiej liczby spowodowane jest faktem, że <math> | Istnienie takiej liczby spowodowane jest faktem, że <math>e</math> i <math>\phi(N)</math> są | ||
względnie pierwsze; liczbę <math> | względnie pierwsze; liczbę <math>d</math> można efektywnie obliczyć z użyciem uogólnionego | ||
algorytmu Euklidesa. | algorytmu Euklidesa. | ||
W tym momencie można już zdefiniować parę kluczy: | W tym momencie można już zdefiniować parę kluczy: kluczem publicznym jest | ||
para liczb <math> | para liczb <math>e</math> oraz <math>N</math>; kluczem prywatnym jest para liczb <math>d</math> oraz <math>N</math>. | ||
Szyfrowanie słowa <math> | Szyfrowanie słowa <math>x</math> wygląda następująco: | ||
<math> | <math>f(\langle e, N \rangle, x) = x^e mod N</math>, | ||
przy czym wiadomość <math> | przy czym wiadomość <math>x</math> traktujemy jako binarny zapis pewnej liczby naturalnej. | ||
Dekodowanie słowa <math> | Dekodowanie słowa <math>y</math> określone jest w praktycznie identyczny sposób: | ||
<math> | <math>h(\langle d, N \rangle, y) = y^d mod N</math>. | ||
Wystarczy teraz przypomnieć sobie, że iloczyn <math> | Wystarczy teraz przypomnieć sobie, że iloczyn <math>d \cdot e</math> jest postaci | ||
<math> | <math>k\cdot\phi(N) + 1</math>, dla pewnej liczby całkowitej <math>k</math>. W związku z tym | ||
<math> | <math>h(\langle d, N \rangle, f(\langle e, N \rangle, x)) = (x^e)^d mod N = | ||
x^{k\cdot\phi(N) + 1} mod N = x^{k\cdot\phi(N)}\cdot x mod N = x</math> | x^{k\cdot\phi(N) + 1} mod N = x^{k\cdot\phi(N)}\cdot x mod N = x</math>. | ||
Widzimy zatem, że funkcja <math> | Widzimy zatem, że funkcja <math>h</math> poprawnie dekoduje słowa zaszyfrowane z użyciem funkcji <math>f</math> -- Bob będzie zatem w stanie odtworzyć wiadomość wysłaną przez Alicję. | ||
funkcji <math> | |||
Alicję. | |||
==Systemy dowodów interaktywnych== | ==Systemy dowodów interaktywnych== | ||
W ostatnim fragmencie niniejszego kursu zajmiemy się klasą złożoności, będącą | W ostatnim fragmencie niniejszego kursu zajmiemy się klasą złożoności, będącą | ||
uogólnieniem klas <math> | uogólnieniem klas <math>NP</math> i <math>BPP</math>. W tym celu zdefiniujemy pojęcie ''systemu dowodów interaktywnych''. | ||
dowodów interaktywnych''. | |||
{{definicja|Systemem dowodów interaktywnych | {{definicja|2.1|| | ||
nazywamy parę funkcji <math> | Systemem dowodów interaktywnych nazywamy parę funkcji <math>V</math> oraz <math>P</math> o sygnaturach: | ||
sygnaturach: | |||
<math> | <math>V: \Sigma^\star \times \Sigma^\star \times \Sigma^\star \rightarrow | ||
\Sigma^\star \cup \{ accept, reject \} | \Sigma^\star \cup \{ accept, reject \}P: \Sigma^\star \times \Sigma^\star\rightarrow | ||
\Sigma^\star</math> | \Sigma^\star</math> | ||
taką, że funkcja <math> | taką, że funkcja <math>V</math> jest obliczalna na maszynie Turinga. | ||
}} | }} | ||
Działanie systemu | Działanie systemu dowodów interaktywnych polega na wymianie komunikatów między funkcjami <math>V</math> i <math>P</math>, przy czym funkcja <math>P</math> (z angielskiego ''prover'') stara się "przekonać" | ||
dowodów interaktywnych polega na wymianie komunikatów między funkcjami <math> | funkcję <math>V</math> (''verifier'') o tym, że słowo wejściowe należy do rozpatrywanego języka, natomiast ostateczna decyzja w tej sprawie należy do <math>V</math>. | ||
<math> | |||
funkcję <math> | |||
języka, natomiast ostateczna decyzja w tej sprawie należy do <math> | |||
Komunikacja odbywa się naprzemiennie: | Komunikacja odbywa się naprzemiennie: funkcja <math>V</math> generuje wiadomość, | ||
przekazywaną funkcji <math> | przekazywaną funkcji <math>P</math> jako argument; funkcja <math>P</math> z kolei generuje odpowiedź przekazywaną funkcji <math>V</math> w następnej iteracji. Taka komunikacja odbywa się do momentu zaakceptowania lub odrzucenia słowa wejściowego przez funkcję <math>V</math>. W każdym kroku obie funkcje mają do dyspozycji zarówno słowo wejściowe, jak również pełną historię przekazanych dotychczas wiadomości. | ||
odpowiedź przekazywaną funkcji <math> | |||
odbywa się do momentu zaakceptowania lub odrzucenia słowa wejściowego przez | |||
funkcję <math> | |||
wejściowe, jak również pełną historię przekazanych dotychczas wiadomości. | |||
Określmy teraz, co dokładnie oznaczają argumenty funkcji <math> | Określmy teraz, co dokładnie oznaczają argumenty funkcji <math>V</math> i <math>P</math>. Argumenty funkcji <math>V</math> będziemy oznaczać w następujący sposób: | ||
funkcji <math> | |||
<math> | <math>V(w, r, m_1 \# m_2 \# \ldots \# m_i)</math>. | ||
Mają one następujące znaczenie: | Mają one następujące znaczenie: | ||
* <math> | * <math>w</math> to słowo wejściowe, | ||
* <math> | * <math>r</math> jest losowym ciągiem bitów, | ||
* <math> | * <math>m_1 \# m_2 \# \ldots \# m_i</math> to konkatenacja dotychczasowych wiadomości, które zostały przekazane w procesie komunikacji (wiadomości o indeksach nieparzystych są wynikami działania funkcji <math>V</math>, natomiast wiadomości o indeksach parzystych są wynikami działania funkcji <math>P</math>). | ||
które zostały przekazane w procesie komunikacji (wiadomości o indeksach | |||
nieparzystych | |||
indeksach parzystych | |||
Zwróćmy uwagę, że <math> | Zwróćmy uwagę, że <math>V</math> ma do dyspozycji losowe słowo <math>r</math>; w praktyce oznacza to, | ||
że o funkcji <math> | że o funkcji <math>V</math> będziemy myśleć jako o pewnej losowej maszynie Turinga. | ||
Zakładamy, że zarówno <math> | Zakładamy, że zarówno <math>w</math> jak i <math>r</math> są stałe w kolejnych iteracjach; słowo <math>r</math> | ||
jest zatem losowane jednokrotnie, przed rozpoczęciem procesu komunikacji. Warto | jest zatem losowane jednokrotnie, przed rozpoczęciem procesu komunikacji. Warto | ||
też zauważyć, że słowa <math> | też zauważyć, że słowa <math>w</math> i <math>r</math> całkowicie determinują działanie systemu. | ||
Argumenty funkcji <math> | Argumenty funkcji <math>P</math> będziemy oznaczać następująco: | ||
<math> | <math>P(w, m_1 \# m_2 \# \ldots \# m_i)</math>. | ||
Ich znaczenie jest identyczne jak w przypadku argumentów funkcji <math> | Ich znaczenie jest identyczne jak w przypadku argumentów funkcji <math>V</math>, nie ma wśród nich jednak słowa losowego. | ||
wśród nich jednak słowa losowego. | |||
Możemy w tym momencie zdefiniować klasę <math> | Możemy w tym momencie zdefiniować klasę <math>IP</math>: | ||
{{definicja||| | {{definicja|2.2|| | ||
Niech <math> | Niech <math>L \subseteq \Sigma^\star</math>. Mówimy, że <math>L \in IP</math> wtedy i tylko wtedy, gdy istnieje system dowodów interaktywnych <math>(V, P)</math> oraz wielomiany <math>p(n)</math> i <math>q(n)</math> takie, że dla każdego słowa wejściowego <math>w</math> oraz losowego słowa <math>r</math> o długości <math>p(|x|)</math>: | ||
gdy istnieje system dowodów interaktywnych <math> | * system daje odpowiedź po co najwyżej <math>p(|x|)</math> krokach, | ||
<math> | * w każdej iteracji czas działania maszyny obliczającej funkcję <math>V</math> jest ograniczony od góry przez <math>q(|x|)</math>, | ||
że dla każdego słowa wejściowego <math> | * długość każdej wiadomości <math>m_i</math> jest nie większa niż <math>p(|x|)</math>, | ||
<math> | * jeżeli <math>w \in L</math>, to prawdopodobieństwo zaakceptowania słowa przez system wynosi co najmniej <math>2/3</math>, | ||
* system daje odpowiedź po co najwyżej <math> | * jeżeli <math>w \notin L</math> oraz <math>\bar P</math> jest dowolną funkcją o sygnaturze zgodnej z <math>P</math>, zwracającą wiadomości nie dłuższe niż <math>p(|x|)</math>, to system <math>(V, \bar P)</math> spełnia powyższe założenia na ilość iteracji, czas działania i długość wiadomości oraz akceptuje słowo <math>w</math> z prawdopodobieństwem nie większym niż <math>1/3</math>. | ||
* w każdej iteracji czas działania maszyny obliczającej funkcję <math> | |||
ograniczony od góry przez <math> | |||
* długość każdej wiadomości <math> | |||
* jeżeli <math> | |||
wynosi co najmniej <math> | |||
* jeżeli <math> | |||
z <math> | |||
spełnia powyższe założenia na ilość iteracji, czas działania i długość | |||
wiadomości oraz akceptuje słowo <math> | |||
<math> | |||
O systemie <math> | O systemie <math>(V, P)</math> mówimy, że rozpoznaje język <math>L</math> w czasie wielomianowym. | ||
}} | }} | ||
Innymi słowy jeżeli słowo <math> | Innymi słowy, jeżeli słowo <math>w</math> należy do języka, to <math>V</math> z dużym prawdopodobieństwem | ||
da się przekonać o tej przynależności przez pewną ustaloną funkcję <math> | da się przekonać o tej przynależności przez pewną ustaloną funkcję <math>P</math>. Jeżeli | ||
jednak <math> | jednak <math>w</math> nie należy do <math>L</math>, to <math>V</math> nie da się oszukać ''żadnej'' funkcji | ||
<math> | <math>\bar P</math> ze zbyt dużym prawdopodobieństwem. | ||
{{uwaga||| | {{uwaga|2.3|| | ||
Zwróćmy jeszcze uwagę, że branie pod uwagę tylko takich funkcji <math> | Zwróćmy jeszcze uwagę, że branie pod uwagę tylko takich funkcji <math>\bar P</math>, które | ||
nie zwracają zbyt długich słów nie jest istotnym ograniczeniem; funkcja <math> | nie zwracają zbyt długich słów, nie jest istotnym ograniczeniem; funkcja <math>V</math> | ||
może w każdym kroku sprawdzać, czy odpowiedź funkcji <math> | może w każdym kroku sprawdzać, czy odpowiedź funkcji <math>\bar P</math> nie jest zbyt | ||
długa i jeśli tak to odrzucać słowo. W dalszej części rozdziału będziemy | długa i jeśli tak, to odrzucać słowo. W dalszej części rozdziału będziemy | ||
zakładali takie właśnie zachowanie funkcji <math> | zakładali takie właśnie zachowanie funkcji <math>V</math>. | ||
}} | }} | ||
Widzimy zatem, że funkcja <math> | Widzimy zatem, że funkcja <math>V</math> musi być zabezpieczona przed oszustwami; jeżeli <math>V</math> mogłaby zaufać funkcji <math>P</math>, to mogłaby rozwiązać każdy problem decyzyjny -- wystarczyłoby po prostu skorzystać z nieograniczonej mocy obliczeniowej <math>P</math>. | ||
<math> | W naszym przypadku jednak nie wystarczy, aby <math>P</math> tylko rozwiązała problem decyzyjny -- musi jeszcze przekonać <math>V</math> do swojego rozwiązania. | ||
-- wystarczyłoby po prostu skorzystać z nieograniczonej mocy obliczeniowej <math> | |||
W naszym przypadku jednak nie wystarczy aby <math> | |||
decyzyjny -- musi jeszcze przekonać <math> | |||
{{przyklad||| | {{przyklad|2.4|| | ||
Rozważmy problem <math> | Rozważmy problem <math>NON-GRAPH-ISO</math>. Jest on zdefiniowany następująco: | ||
<math> | <math>NON-GRAPH-ISO = \{ \langle G, H \rangle:</math> grafy <math>G</math> i <math>H</math> nie są izomorficzne <math>\}</math>. | ||
Łatwo sie przekonać, że problem izomorfizmu grafów jest w klasie <math> | Łatwo sie przekonać, że problem izomorfizmu grafów jest w klasie <math>NP</math> -- wystarczy zgadnąć odpowiednią permutację wierzchołków, po czym zweryfikować ją w trywialny sposób. <math>NON-GRAPH-ISO</math> należy zatem do <math>coNP</math>. Nie jest jednak obecnie znana odpowiedź na pytanie o przynależność tego problemu do | ||
wystarczy zgadnąć odpowiednią permutację wierzchołków, po czym zweryfikować | klasy <math>NP</math>. Pokażemy teraz, w jaki sposób można rozwiązać <math>NON-GRAPH-ISO</math> za pomocą systemów dowodów interaktywnych, pokazując przynależność tego problemu do klasy <math>IP</math>. | ||
ją w trywialny sposób. <math> | |||
jednak obecnie znana odpowiedź na pytanie o przynależność tego problemu do | |||
klasy <math> | |||
pomocą systemów dowodów interaktywnych, pokazując przynależność tego problemu | |||
do klasy <math> | |||
System działa w prosty sposób: W kolejnych iteracjach funkcja <math> | System działa w prosty sposób: W kolejnych iteracjach funkcja <math>V</math> wybiera losowo jeden z grafów, a następnie w losowy sposób permutuje jego wierzchołki. Taki | ||
jeden z grafów, a następnie w losowy sposób permutuje jego wierzchołki. Taki | graf jest przekazywany jako wiadomość do funkcji <math>P</math>. Zadaniem funkcji <math>P</math> jest rozpoznanie, który z wyjściowych grafów został wylosowany i przekształcony przez <math>V</math>. | ||
graf jest przekazywany jako wiadomość do funkcji <math> | |||
jest rozpoznanie, który z wyjściowych grafów został wylosowany i przekształcony | |||
przez <math> | |||
}} | }} | ||
{{cwiczenie||| | {{cwiczenie|2.5|| | ||
Zdefiniuj, w jakich przypadkach <math> | Zdefiniuj, w jakich przypadkach <math>V</math> powinien zaakceptować, a w jakich | ||
odrzucić wejściową parę grafów. Oblicz, ile iteracji jest potrzebnych, aby | odrzucić wejściową parę grafów. Oblicz, ile iteracji jest potrzebnych, aby system rozpoznawał język <math>NON-GRAPH-ISO</math> w czasie wielomianowym zgodnie z wcześniejszą definicją. | ||
system rozpoznawał język <math> | |||
wcześniejszą definicją. | |||
}} | }} | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | ||
Zachowanie <math> | Zachowanie <math>V</math> powinno być następujące. Jeżeli <math>P</math> pomyli się w odpowiedzi, <math>V</math> powinno odrzucić parę grafów -- czyli stwierdzić, że są izomorficzne. | ||
<math> | <math>V</math> powinno zaakceptować grafy -- czyli stwierdzić, że nie są izomorficzne -- jeżeli <math>P</math> dwukrotnie poprawnie odgadnie, który graf został wylosowany przez <math>V</math>. Pokażemy teraz, że system ten rozpoznaje <math>NON-GRAPH-ISO</math>. Załóżmy, że grafy wejściowe nie są izomorficzne. W tym przypadku łatwo wskazać funkcję <math>P</math>, która zawsze będzie udzielała prawidłowej odpowiedzi; prawdopodobieństwo akceptacji wyniesie zatem <math>1</math>. Pozostaje jeszcze tylko pokazać, że jeżeli grafy nie są izomorficzne, to <math>V</math> nie da się oszukać żadnej funkcji <math>\bar P</math>. | ||
<math> | Funkcja <math>\bar P</math> nie ma jednak żadnej możliwości sprawdzenia, który graf został wybrany. Niezależnie zatem jak się zachowa, prawdopodobieństwo udzielenia | ||
jeżeli <math> | dwóch kolejnych poprawnych odpowiedzi będzie nie większe niż <math>1/4</math>, co kończy dowód. | ||
<math> | |||
grafy wejściowe nie są izomorficzne. W tym przypadku łatwo wskazać funkcję | |||
<math> | |||
akceptacji wyniesie zatem <math> | |||
nie są izomorficzne, to <math> | |||
Funkcja <math> | |||
został wybrany. Niezależnie zatem jak się zachowa, prawdopodobieństwo udzielenia | |||
dwóch kolejnych poprawnych odpowiedzi będzie nie większe niż <math> | |||
dowód. | |||
</div></div> | </div></div> | ||
{{cwiczenie||| | {{cwiczenie|2.6|| | ||
Pokaż, że klasa <math> | Pokaż, że klasa <math>BPP</math> jest zawarta w klasie <math>IP</math>. | ||
}} | }} | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | ||
Weźmy dowolny problem z klasy <math> | Weźmy dowolny problem z klasy <math>BPP</math> oraz program dla probabilistycznej maszyny | ||
Turinga, rozwiązujący ten problem w czasie wielomianowym. Wystarczy teraz, by | Turinga, rozwiązujący ten problem w czasie wielomianowym. Wystarczy teraz, by | ||
funkcja <math> | funkcja <math>V</math> po prostu wykonała ten program i udzieliła odpowiedzi bez angażowania | ||
<math> | <math>P</math>. | ||
</div></div> | </div></div> | ||
{{cwiczenie||| | {{cwiczenie|2.7|| | ||
Rozpatrzmy takie systemy dowodów interaktywnych, w których funkcje <math> | Rozpatrzmy takie systemy dowodów interaktywnych, w których funkcje <math>V</math> nie | ||
zależą od argumentu <math> | zależą od argumentu <math>r</math> (słowa losowego). Jaką klasę języków rozpoznają takie | ||
systemy, przy założeniach o złożoności analogicznych jak w przypadku klasy <math> | systemy, przy założeniach o złożoności analogicznych jak w przypadku klasy <math>IP</math>? | ||
}} | }} | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | ||
Zauważmy najpierw, że | Zauważmy najpierw, że tak określone protokoły komunikacyjne są w pełni deterministyczne (w tym sensie, że pozbawione są losowości). Zatem dla ustalonego systemu <math>(V, P)</math> i ustalonego słowa wejściowego odpowiedź protokołu zawsze jest taka sama. | ||
deterministyczne (w tym sensie, że pozbawione są losowości). Zatem dla | |||
ustalonego systemu <math> | |||
zawsze jest taka sama. | |||
Łatwo się przekonać, że za pomocą opisanych powyżej systemów można rozpoznać | Łatwo się przekonać, że za pomocą opisanych powyżej systemów można rozpoznać dowolny język z klasy <math>NP</math>. Protokół wygląda w następujący sposób: dla zadanego | ||
dowolny język z klasy <math> | słowa wejściowego <math>w</math> funkcja <math>P</math> zwraca świadka jego przynależności do rozważanego języka. Funkcja <math>V</math> następnie weryfikuje świadka w sposób deterministyczny w czasie wielomianowym i na tej podstawie udziela odpowiedzi. Jest jasne, że w przypadku, gdy <math>w</math> należy do rozważanego języka, odpowiednia funkcja <math>P</math> jest w stanie przekonać <math>V</math> o tej przynależności -- ponieważ nie ma żadnych restrykcji na złożoność funkcji <math>P</math>, może ona po prostu rozważyć | ||
słowa wejściowego <math> | wszystkich możliwych kandydatów na świadków o pewnej ustalonej z góry długości. Ponadto jeśli <math>w</math> nie należy do rozważanego języka, to <math>V</math> jest w stanie wykryć każdą próbę oszustwa. | ||
rozważanego języka. Funkcja <math> | |||
deterministyczny w czasie wielomianowym i na tej podstawie udziela odpowiedzi. | |||
Jest jasne, że w przypadku gdy <math> | |||
funkcja <math> | |||
ma żadnych restrykcji na złożoność funkcji <math> | |||
wszystkich możliwych kandydatów na świadków o pewnej ustalonej z góry długości. | |||
Ponadto jeśli <math> | |||
nie należy do rozważanego języka to <math> | |||
oszustwa. | |||
Pokażemy teraz, że każdy język rozpoznawalny przez systemy opisane w treści | Pokażemy teraz, że każdy język rozpoznawalny przez systemy opisane w treści zadania należy do <math>NP</math>. Ustalmy zatem pewien język <math>L</math> i rozpoznający go system <math>(V, P)</math>. Załóżmy bez straty ogólności, że system ten dla słowa wejściowego <math>w</math> wykonuje dokładnie <math>p(|w|)</math> kroków oraz że każda przekazywana wiadomość ma długość <math>p(|w|)</math>. Zdefiniujmy teraz niedeterministyczną maszynę Turinga | ||
zadania należy do <math> | <math>M</math>, rozpoznającą język <math>L</math>. Załóżmy, że maszyna oprócz taśmy roboczej ma też (początkowo pustą) taśmę służącą do przechowywania kolejnych komunikatów. Działanie maszyny <math>M</math> będzie podzielone na fazy; w fazach nieparzystych maszyna będzie symulować działanie funkcji <math>V</math> -- to znaczy <math>M</math> przeczyta historię wysłanych dotychczas wiadomości i słowo wejściowe, i na tej podstawie dopisze kolejną wiadomość. W fazach parzystych maszyna <math>M</math> w sposób niedeterministyczny wygeneruje wiadomość o długości <math>p(|w|)</math> i dopisze ją na taśmę. W przypadku, gdy <math>w \in L</math> łatwo wskazać ścieżkę postępowania dla tej maszyny, która doprowadzi do akceptacji; będzie to ścieżka, w której wygenerowane w fazach parzystych wiadomości pokrywają się z odpowiedziami udzielanymi przez funkcję <math>P</math>. Rozważmy teraz przypadek <math>w \notin L</math>. Załóżmy nie wprost, że istnieje taka ścieżka postępowania maszyny <math>M</math>, która doprowadzi | ||
system <math> | do akceptacji tego słowa. W takim przypadku możemy jednak utworzyć funkcję <math>\bar P</math>, która będzie zwracała wiadomości wygenerowane w fazach parzystych postępowania maszyny <math>M</math>. W tym przypadku funkcja <math>V</math> da się oszukać funkcji <math>\bar P</math> dla słowa <math>w</math> z prawdopodobieństwem równym 1 -- a zatem system <math>(V, P)</math> nie będzie rozpoznawał języka <math>L</math>, co jest sprzeczne z założeniem. | ||
<math> | |||
ma długość <math> | |||
<math> | |||
też (początkowo pustą) taśmę służącą do przechowywania kolejnych komunikatów. | |||
Działanie maszyny <math> | |||
fazach nieparzystych maszyna będzie symulować działanie funkcji <math> | |||
znaczy <math> | |||
i na tej podstawie dopisze kolejną wiadomość. W fazach parzystych maszyna <math> | |||
w sposób niedeterministyczny wygeneruje wiadomość o długości <math> | |||
ją na taśmę. W przypadku, gdy <math> | |||
tej maszyny, która doprowadzi do akceptacji; będzie to ścieżka, w której | |||
wygenerowane w fazach parzystych wiadomości pokrywają się z odpowiedziami | |||
udzielanymi przez funkcję <math> | |||
nie wprost, że istnieje taka ścieżka postępowania maszyny <math> | |||
do akceptacji tego słowa. W takim przypadku możemy jednak utworzyć funkcję | |||
<math> | |||
postępowania maszyny <math> | |||
<math> | |||
<math> | |||
Pokazaliśmy zatem, że protokoły zdefiniowane w treści ćwiczenia rozpoznają | Pokazaliśmy zatem, że protokoły zdefiniowane w treści ćwiczenia rozpoznają klasę języków <math>NP</math>. | ||
klasę języków <math> | |||
</div></div> | </div></div> | ||
Możemy w tym momencie przypuszczać, że klasa <math> | Możemy w tym momencie przypuszczać, że klasa <math>IP</math> jest znacząco większa od klasy <math>NP</math>. Nie wiemy obecnie, czy przypuszczenie to jest prawdziwe; przemawia jednak za nim poniższe twierdzenie. | ||
klasy <math> | |||
jednak za nim poniższe twierdzenie. | |||
{{twierdzenie||| | {{twierdzenie|2.8|| | ||
<math> | <math>IP = PSPACE</math> | ||
}} | }} | ||
{{dowod||| | {{dowod||| | ||
Pokażemy najpierw fakt <math>IP \subseteq PSPACE</math>. W tym celu wybierzemy dowolny problem z klasy <math>IP</math> i rozwiążemy go z użyciem wielomianowej ilości pamięci. | |||
Załóżmy, że system <math>(V, P')</math> akceptuje wybrany język w czasie wielomianowym. | |||
<math> | |||
Ustalmy słowo <math>w</math>. Będziemy mówić, że ciąg wiadomości <math>m_1\#m_2\#\ldots\#m_i</math> jest zgodny ze słowem losowym <math>r</math>, jeżeli stanowi on historię wiadomości po | |||
<math>i</math> iteracjach pewnego systemu <math>(V, P'')</math> używającego słowa losowego <math>r</math>. | |||
Warto zauważyć, że ciąg wiadomości może być zgodny z wieloma słowami losowymi (na przykład ciąg pusty jest zgodny z każdym słowem losowym), a słowo losowe może być zgodne z różnymi ciągami wiadomości (w zależności od funkcji <math>P''</math>). | |||
<math> | Zdefiniujmy teraz funkcję <math>P</math> w taki sposób, by miała ona następującą własność: | ||
<math>\forall_w Pr((V, P)</math> akceptuje <math>w) = max_{P''} Pr((V, P'')</math> akceptuje <math>w)</math>. | |||
Jest jasne, że <math> | Funkcja <math>P</math> zatem dla każdego słowa wejściowego zachowuje się w najlepszy możliwy sposób. Jest ona dobrze zdefiniowana, gdyż dla każdego wejściowego | ||
-- od tej pory będziemy się zatem zajmowali tym konkretnym systemem. Nasz | słowa zbiór prawdopodobieństw jest skończony -- przy ustalonym słowie <math>w</math> wszystkie możliwe funkcje <math>P''</math> można przypisać do skończonej liczby klas równoważności, w ramach których system <math>(V, P)</math> zachowuje się identycznie (pamiętajmy, że w całym procesie komunikacji funkcja <math>V</math> wykonuje co najwyżej skończoną, ustaloną dla danego słowa wejściowego liczbę kroków). | ||
Jest jasne, że <math>(V, P)</math> również akceptuje wybrany język w czasie wielomianowym -- od tej pory będziemy się zatem zajmowali tym konkretnym systemem. Nasz | |||
algorytm będzie dla każdego słowa wejściowego wprost obliczał prawdopodobieństwo | algorytm będzie dla każdego słowa wejściowego wprost obliczał prawdopodobieństwo | ||
zaakceptowania go przez system <math> | zaakceptowania go przez system <math>(V, P)</math>; tym samym, w zależności od wyniku, będzie mógł określić, czy słowo wejściowe należy do języka. Dla uproszczenia | ||
będzie mógł | założymy, że system <math>(V, P)</math> daje odpowiedzi po dokładnie <math>p(|x|)</math> krokach. | ||
założymy, że system <math> | |||
Zdefiniujmy teraz funkcję | Zdefiniujmy teraz funkcję mierzącą prawdopodobieństwo akceptacji słowa przez | ||
system <math> | system <math>(V, P)</math> przy ustalonej częściowej historii komunikacji: | ||
<math> | <math>N(m_1\#m_2\#\ldots\#m_i) = Pr(</math>słowo <math>w</math> zostanie zaakceptowane pod warunkiem, że dotychczasowe komunikaty reprezentowane są przez <math>m_1\#m_2\#\ldots\#m_i)</math>. | ||
że dotychczasowe komunikaty reprezentowane są przez <math> | |||
W przypadku, gdy nie ma słowa losowego zgodnego z <math> | W przypadku, gdy nie ma słowa losowego zgodnego z <math>m_1\#m_2\#\ldots\#m_i</math>, | ||
funkcji <math> | funkcji <math>N(m_1\#m_2\#\ldots\#m_i)</math> nadajemy wartość <math>0</math>. Łatwo jest | ||
obliczyć <math> | obliczyć <math>N(m_1\#m_2\#\ldots\#m_{p(|x|)})</math>: | ||
* jeżeli <math> | * jeżeli <math>m_{p(|x|)} = accept</math> i <math>m_1\#m_2 \#\ldots\#m_{p(|x|)}</math> jest zgodne z pewnym słowem losowym, to | ||
z pewnym słowem losowym, to | |||
<math>N(m_1\#m_2\#\ldots\#m_{p(|x|)}) = 1</math>, | |||
* w przeciwnym przypadku | * w przeciwnym przypadku | ||
<math> | <math>N(m_1\#m_2\#\ldots\#m_{p(|x|)}) = 0</math>. | ||
Do obliczania wartości <math>N</math> dla mniejszej ilości kroków, możemy posłużyć się następującym wzorem rekurencyjnym: | |||
* jeżeli <math>i</math> jest nieparzyste, to | |||
<math>N(m_1\#m_2\#\ldots\#m_i) = \max_{m_{i+1}} N(m_1\#m_2\#\ldots\#m_{i+1})</math>, | |||
* jeżeli <math>i</math> jest parzyste, to | |||
* jeżeli <math> | |||
<math> | <math>N(m_1\#m_2\#\ldots\#m_i) = \sum_{m_{i+1}} Pr(m_{i+1}|m_1\#m_2\#\ldots\#m_i) \cdot N(m_1\#m_2\#\ldots\#m_{i+1})</math>. | ||
Wzór ten jest konsekwencją zachowania <math> | Wzór ten jest konsekwencją zachowania <math>P</math> i <math>V</math>: <math>P</math> w każdym kroku maksymalizuje | ||
prawdopodobieństwo akceptacji, natomiast zachowanie <math> | prawdopodobieństwo akceptacji, natomiast zachowanie <math>V</math> zależne jest od historii wiadomości i słowa losowego. | ||
wiadomości i słowa losowego. | |||
W tym momencie wystarczą dwa spostrzeżenia | W tym momencie wystarczą dwa spostrzeżenia. Po pierwsze, <math>N(\epsilon)</math> jest poszukiwanym przez nas prawdopodobieństwem zaakceptowania przez system <math>(V, P)</math> słowa <math>w</math>. Po drugie, <math>N(\epsilon)</math> jest obliczalne w pamięci wielomianowej: | ||
poszukiwanym przez nas prawdopodobieństwem zaakceptowania przez system <math> | każde rekurencyjne wywołanie funkcji <math>N</math> powoduje sekwencyjne rozważenie wszystkich możliwych odpowiedzi, których długość jest jednak ograniczona od góry przez <math>p(|x|)</math>. Dodatkowo przy obliczeniach na poziomie zagłębienia <math>p(|x|)</math> należy rozważyć wszystkie możliwe słowa losowe i sprawdzić ich zgodność z aktualnie rozważanym ciągiem komunikatów. Wszystkie te operacje można wykonać | ||
słowa <math> | z użyciem <math>O(p(|x|)^2)</math> komórek pamięci. | ||
możliwych odpowiedzi, których długość jest jednak ograniczona od góry przez | |||
<math> | |||
należy rozważyć wszystkie możliwe słowa losowe i sprawdzić ich zgodność z | |||
aktualnie rozważanym ciągiem komunikatów. Wszystkie te operacje można wykonać | |||
z użyciem <math> | |||
Pokazaliśmy zatem, że <math> | Pokazaliśmy zatem, że <math>IP \subseteq PSPACE</math>. | ||
}} | |||
Dowód zawierania w drugą stronę odbywa się poprzez przedstawienie protokołu | Dowód zawierania w drugą stronę odbywa się poprzez przedstawienie protokołu | ||
komunikacji dla problemu <math> | komunikacji dla problemu <math>QSAT</math>. Aby przybliżyć stosowaną w tym protokole technikę, zaprezentujemy najpierw dowód przynależności do klasy <math>IP</math> problemu <math>\#SAT(D)</math> będącego wersją decyzyjną problemu <math>\#SAT</math>: | ||
technikę, zaprezentujemy najpierw dowód przynależności do klasy <math> | |||
<math> | |||
{{definicja||| | {{definicja|2.9|| | ||
<math> | <math>\#SAT(D) = \{ \langle \phi, k \rangle:</math> liczba wartościowań spełniających dla | ||
formuły <math> | formuły <math>\phi</math> jest nie mniejsza niż <math>k \}</math>. | ||
}} | }} | ||
Linia 623: | Linia 496: | ||
będziemy zastępować wielomianami w następujący sposób: | będziemy zastępować wielomianami w następujący sposób: | ||
* zmienne formuły stają się zmiennymi wielomianu, | * zmienne formuły stają się zmiennymi wielomianu, | ||
* wyrażenia typu <math> | * wyrażenia typu <math>\neg x</math> zastępujemy przez <math>(1-x)</math>, | ||
* wyrażenia typu <math> | * wyrażenia typu <math>\alpha \wedge \beta</math> zastępujemy przez <math>\alpha \cdot \beta</math>, | ||
* wyrażenia typu <math> | * wyrażenia typu <math>\alpha \vee \beta</math> zastępujemy przez <math>(1 - (1 - \alpha)\cdot(1 - \beta))</math>. | ||
Dla uproszczenia założymy na razie, że wielomiany te określone są na liczbach | Dla uproszczenia założymy na razie, że wielomiany te określone są na liczbach | ||
rzeczywistych. | rzeczywistych. | ||
{{cwiczenie||| | {{cwiczenie|2.10|| | ||
Niech <math> | Niech <math>\phi</math> będzie formułą z <math>m</math> zmiennymi, natomiast <math>W(x_1, \ldots, x_m)</math> | ||
wielomianem otrzymanych w sposób przedstawiony powyżej. Weźmy dowolne | wielomianem otrzymanych w sposób przedstawiony powyżej. Weźmy dowolne | ||
wartościowanie zmiennych formuły <math> | wartościowanie zmiennych formuły <math>\phi</math> i podstawmy je do wielomianu <math>W</math> (to znaczy podstawmy 0, gdy zmienna jest wartościowana na "fałsz" i | ||
(to znaczy podstawmy 0 gdy zmienna jest wartościowana na "fałsz" i | 1 w przeciwnym przypadku). Pokaż, że wartość wielomianu <math>W</math> jest równa 1, gdy wybrane wartościowanie jest wartościowaniem spełniającym dla <math>\phi</math> oraz 0 w przeciwnym przypadku. | ||
1 w przeciwnym przypadku). Pokaż, że wartość wielomianu <math> | |||
wybrane wartościowanie jest wartościowaniem spełniającym dla <math> | |||
0 w przeciwnym przypadku. | |||
}} | }} | ||
Linia 646: | Linia 516: | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | ||
Indukcja będzie zdefiniowana ze względu na ilość literałów w formule. Niech | Indukcja będzie zdefiniowana ze względu na ilość literałów w formule. Niech | ||
<math> | <math>\phi</math> będzie formułą z jednym literałem. Będzie ona zatem postaci <math>\phi = x</math> | ||
lub <math> | lub <math>\phi = \neg x</math>. Po zastosowaniu procesu arytmetyzacji wielomian będzie | ||
miał postać odpowiednio <math> | miał postać odpowiednio <math>W(x) = x</math> lub <math>W(x) = (1 - x)</math>. Jest zatem jasne, | ||
że dla wartościowania zmiennej <math> | że dla wartościowania zmiennej <math>x</math> na "fałsz" wartości wielomianów wynoszą | ||
odpowiednio 0 i 1, a przy wartościowaniu na "prawdę" odpowiednio 1 i 0 | odpowiednio 0 i 1, a przy wartościowaniu na "prawdę" odpowiednio 1 i 0 | ||
-- spełnione są zatem wymagania opisane w treści ćwiczenia. | -- spełnione są zatem wymagania opisane w treści ćwiczenia. | ||
Załóżmy teraz, że własność podana w treści jest spełniona dla wszystkich | Załóżmy teraz, że własność podana w treści jest spełniona dla wszystkich | ||
formuł o długości nie większej niż <math> | formuł o długości nie większej niż <math>n-1</math>; pokażemy, że jest ona również spełniona | ||
dla formuł o długości <math> | dla formuł o długości <math>n</math>. Weźmy zatem formułę <math>\phi</math> o długości <math>n</math> i załóżmy, | ||
że <math> | że <math>\phi = \alpha \wedge \beta</math>. Wielomian | ||
<math> | <math>W</math> jest zatem postaci <math>W(x_1,\ldots,x_m) = W_\alpha(x_1,\ldots,x_m) * | ||
W_\beta(x_1,\ldots,x_m)</math>. Niech <math> | W_\beta(x_1,\ldots,x_m)</math>. Niech <math>a_1,\ldots,a_m</math> będzie wartościowaniem | ||
spełniającym dla formuły <math> | spełniającym dla formuły <math>\phi</math>; jest ono zatem wartościowaniem spełniającym | ||
dla <math> | dla <math>\alpha</math> i <math>\beta</math>. Formuły <math>\alpha</math> i <math>\beta</math> mają co najwyżej <math>n-1</math> | ||
literałów -- korzystając z założenia indukcyjnego możemy stwierdzić, że | literałów -- korzystając z założenia indukcyjnego, możemy stwierdzić, że: | ||
<math> | <math>W_\alpha(a_1,\ldots,a_m) = W_\beta(a_1,\ldots,a_m) = 1</math>. | ||
W związku z tym | W związku z tym: | ||
<math> | <math>W(a_1,\ldots,a_m) = 1</math>. | ||
Załóżmy teraz, że <math> | Załóżmy teraz, że <math>a_1,\ldots,a_m</math> nie jest wartościowaniem spełniającym | ||
dla <math> | dla <math>\phi</math>. Nie jest zatem wartościowaniem spełniającym dla przynajmniej | ||
jednej z formuł <math> | jednej z formuł <math>\alpha</math> lub <math>\beta</math>. W związku z tym zachodzi własność: | ||
<math> | <math>W_\alpha(a_1,\ldots,a_m) = 0</math> | ||
lub | lub | ||
<math> | <math>W_\beta(a_1,\ldots,a_m) = 0</math>. | ||
W konsekwencji | W konsekwencji: | ||
<math> | <math>W(a_1,\ldots,a_m) = 0</math>. | ||
Dowód przypadku gdy <math> | Dowód przypadku, gdy <math>\phi = \alpha \vee \beta</math>, jest analogiczny. | ||
</div></div> | </div></div> | ||
{{cwiczenie||| | {{cwiczenie|2.11|| | ||
Niech <math> | Niech <math>n</math> oznacza liczbę -- niekoniecznie różnych -- literałów (zmiennych | ||
i ich zaprzeczeń) w formule <math> | i ich zaprzeczeń) w formule <math>\phi</math>. Pokaż, że stopień każdej zmiennej w | ||
wielomianie <math> | wielomianie <math>W</math> jest nie większy niż <math>n</math>. | ||
}} | }} | ||
Linia 699: | Linia 569: | ||
Załóżmy teraz, że własność podana w treści jest spełniona dla formuł o nie więcej niż | Załóżmy teraz, że własność podana w treści jest spełniona dla formuł o nie więcej niż | ||
<math> | <math>n-1</math> literałach; pokażemy, że jest ona też spełniona dla formuł o <math>n</math> | ||
literałach. Weźmy formułę <math> | literałach. Weźmy formułę <math>\phi</math> o <math>n</math> literałach i załóżmy, że jest ona postaci | ||
<math> | <math>\phi = \alpha \wedge \beta</math>. Oznaczmy długości formuł <math>\alpha</math> i <math>\beta</math> jako | ||
<math> | <math>l_\alpha</math> i <math>l_\beta</math>. Ustalmy też dowolną zmienną <math>x_i</math> występującą w formule | ||
<math> | <math>\phi</math>. Z założenia indukcyjnego wiemy, że stopień tej zmiennej w wielomianach | ||
<math> | <math>W_\alpha</math> i <math>W_\beta</math> jest co najwyżej równy odpowiednio <math>l_\alpha</math> lub | ||
<math> | <math>l_\beta</math>. Wielomian otrzymany z formuły <math>\phi</math> jest postaci | ||
<math> | <math>W(x_1,\ldots,x_m) = W_\alpha(x_1,\ldots,x_m) * W_\beta(x_1,\ldots,x_m)</math>. | ||
Stopień <math> | Stopień <math>W</math> jako wielomianu zmiennej <math>x_i</math> jest zatem równy co najwyżej | ||
<math> | <math>l_\alpha + l_\beta</math> -- liczba ta jest równa ilości literałów w formule <math>\phi</math>. | ||
W przypadku, gdy <math> | W przypadku, gdy <math>\phi = \alpha \vee \beta</math>, wielomian <math>W</math> jest postaci: | ||
<math> | <math>W(\ldots) = 1 - (1 - W_\alpha(\ldots))\cdot(1 - W_\beta(\ldots))</math>. | ||
Po dokonaniu mnożenia otrzymamy: | Po dokonaniu mnożenia otrzymamy: | ||
<math> | <math>W(\ldots) = W_\alpha (\ldots) + W_\beta (\ldots) - W_\alpha (\ldots) \cdot W_\beta(\ldots)</math>. | ||
Jest zatem jasne, że stopień <math> | Jest zatem jasne, że stopień <math>W</math> jako zmiennej <math>x_i</math> jest nie większy niż | ||
<math> | <math>l_\alpha + l_\beta</math>. | ||
</div></div> | </div></div> | ||
Zdefiniujmy teraz ciąg wielomianów <math> | Zdefiniujmy teraz ciąg wielomianów <math>f_0, f_1, \ldots, f_m</math> w następujący | ||
sposób: | sposób: | ||
* <math> | * <math>f_m</math> jest wielomianem otrzymanym z formuły <math>\phi</math> w wyniku procesu arytmetyzacji, | ||
arytmetyzacji, | * <math>f_i(x_1, x_2, \ldots, x_i) := f_{i+1}(x_1, x_2, \ldots, x_i, 0) + | ||
* <math> | |||
f_{i+1}(x_1, x_2, \ldots, x_i, 1)</math>. | f_{i+1}(x_1, x_2, \ldots, x_i, 1)</math>. | ||
Zauważmy, że ilość argumentów zmniejsza się w kolejnych funkcjach, a <math> | Zauważmy, że ilość argumentów zmniejsza się w kolejnych funkcjach, a <math>f_0</math> | ||
nie posiada żadnych argumentów (czyli jest stałą). Funkcje te spełniają | nie posiada żadnych argumentów (czyli jest stałą). Funkcje te spełniają | ||
następującą własność: | następującą własność: | ||
<math> | <math>\forall_{a_1,a_2,\ldots,a_i \in \{0, 1\}} f_i(a_1, a_2, \ldots, a_i) = | ||
\sum_{x_{i+1} \in \{0, 1\}} \ldots \sum_{x_{m} \in \{0, 1\}} | \sum_{x_{i+1} \in \{0, 1\}} \ldots \sum_{x_{m} \in \{0, 1\}} | ||
f_m(a_1,a_2, \ldots, a_i, x_{i+1}, \ldots, x_m)</math> | f_m(a_1,a_2, \ldots, a_i, x_{i+1}, \ldots, x_m)</math> | ||
Oznacza to, że jeżeli <math> | Oznacza to, że jeżeli <math>a_1, \ldots, a_i</math> reprezentują pewne wartościowanie | ||
zmiennych <math> | zmiennych <math>x_1, \ldots, x_i</math>, to <math>f_i(a_1,\ldots,a_i)</math> wyznacza liczbę | ||
wartościwoań spełniających formułę <math> | wartościwoań spełniających formułę <math>\phi</math> rozpoczynających się od | ||
<math> | <math>(a_1, \ldots, a_i)</math>. Oczywistym wnioskiem z powyższego spostrzeżenia jest to, | ||
że <math> | że <math>f_0()</math> jest liczbą wszystkich wartościowań spełniających <math>\phi</math>. | ||
Zauważmy jeszcze, że w wielomianach <math> | Zauważmy jeszcze, że w wielomianach <math>f_i</math> zachowana jest własność, mówiąca że | ||
każda zmienna występuje co najwyżej w stopniu <math> | każda zmienna występuje co najwyżej w stopniu <math>n</math>. Ilość wyrazów występujących | ||
w tych wielomianach może być jednak wykładnicza ze względu na długość | w tych wielomianach może być jednak wykładnicza ze względu na długość | ||
formuły; z tego powodu obliczanie tych wielomianów może być procesem | formuły; z tego powodu obliczanie tych wielomianów może być procesem | ||
czasochłonnym. | czasochłonnym. | ||
Przedstawiany protokół komunikacyjny obliczanie wielomianów <math> | Przedstawiany protokół komunikacyjny obliczanie wielomianów <math>f_0,\ldots,f_{m-1}</math> | ||
zleca funkcji <math> | zleca funkcji <math>P</math>. Ta następnie przekazuje funkcji <math>V</math> pewne informacje o | ||
wielomianach, na podstawie których <math> | wielomianach, na podstawie których <math>V</math> może z dużym prawdopodobieństwem | ||
rozstrzygnąć, czy <math> | rozstrzygnąć, czy <math>f_0,\ldots,f_{m-1}</math> zostały "uczciwie" obliczone zgodnie | ||
z powyższą rekurencyjną procedurą, czy też <math> | z powyższą rekurencyjną procedurą, czy też <math>P</math> próbuje oszukać <math>V</math>. | ||
Protokół nie operuje na liczbach rzeczywistych -- zamiast nich używamy ciała | Protokół nie operuje na liczbach rzeczywistych -- zamiast nich używamy ciała | ||
<math> | <math>{\mathbb Z}_p</math>, gdzie <math>p</math> jest liczbą pierwszą większą niż <math>2^n</math>. Wielomiany | ||
określone nad takim ciałem mają wiele cech wspólnych z wielomianami nad | określone nad takim ciałem mają wiele cech wspólnych z wielomianami nad | ||
<math> | <math>{\mathbb R}</math> -- w szczególności wielomian jednej zmiennej o stopniu <math>n</math>, | ||
który nie jest stale równy 0, ma co najwyżej <math> | który nie jest stale równy 0, ma co najwyżej <math>n</math> pierwiastków. W rezultacie | ||
dwa różne wielomiany stopnia nie większego niż <math> | dwa różne wielomiany stopnia nie większego niż <math>n</math> mogą być równe w co | ||
najwyżej <math> | najwyżej <math>n</math> punktach. | ||
W tym momencie jesteśmy gotowi do przedstawienia protokołu dla <math> | W tym momencie jesteśmy gotowi do przedstawienia protokołu dla <math>\#SAT(D)</math>: | ||
* Krok 1 (P): Znajdź liczbę pierwszą <math> | * Krok 1 (P): Znajdź liczbę pierwszą <math>p</math> z przedziału <math>[2^n, 2^{n+1}]</math> oraz jej certyfikat pierwszości (taka liczba na pewno istnieje -- wynika to z twierdzenia Bertranda--Czebyszewa). Prześlij je jako wiadomość. | ||
jej certyfikat pierwszości (taka liczba na pewno istnieje -- wynika to z | * Krok 2 (V): Sprawdź poprawność liczby <math>p</math>, odrzuć słowo wejściowe, jeśli <math>p</math> lub jej certyfikat są nieprawidłowe. | ||
twierdzenia Bertranda-Czebyszewa). Prześlij je jako wiadomość. | * Krok 3 (P): Oblicz <math>f_0()</math> i prześlij jako wiadomość. | ||
* Krok 2 (V): Sprawdź poprawność liczby <math> | * Krok 4 (V): Sprawdź, czy <math>f_0() \geq k</math> -- jeśli nie to odrzuć słowo wejściowe. | ||
<math> | * Krok 5 (P): Oblicz <math>f_1(z)</math> (wielomian ze zmienną <math>z</math>) i prześlij jego współczynniki jako wiadomość. | ||
* Krok 3 (P): Oblicz <math> | * Krok 6 (V): Sprawdź, czy <math>f_0() = f_1(0) + f_1(1)</math>. Wylosuj dowolną liczbę <math>r_1</math> z <math>{\mathbb Z}_p</math> i prześlij ją jako wiadomość, | ||
* Krok 4 (V): Sprawdź, czy <math> | * Krok 7 (P): Oblicz <math>f_2(r_1, z)</math> (to też jest wielomian z jedną zmienną <math>z</math>) i prześlij jego współczynniki jako wiadomość. | ||
wejściowe | * Krok 8 (V): Sprawdź, czy <math>f_1(r_1)=f_2(r_1,0)+f_2(r_1,1)</math>. Wylosuj dowolną liczbę <math>r_2</math> z <math>{\mathbb Z}_p</math> i prześlij ją jako wiadomość. | ||
* Krok 5 (P): Oblicz <math> | * <math>\cdots</math> | ||
współczynniki jako wiadomość | * Krok <math>2m + 4</math> (V): Sprawdź, czy <math>f_{m-1}(r_1, \ldots, r_{m-1})=f_m(r_1,\ldots,r_{m-1},0)+f_m(r_1,\ldots,r_{m-1},1)</math>. Sprawdź, czy <math>f_m(r_1,\ldots,r_{m-1},z)</math> jest wielomianem otrzymanym przez arytmetyzację formuły <math>\phi</math> i podstawienie <math>r_1,\ldots,r_{m-1}</math> jako pierwszych <math>m-1</math> argumentów otrzymanego wielomianu. Jeżeli tak, to zaakceptuj słowo wejściowe, w przeciwnym przypadku odrzuć je. | ||
* Krok 6 (V): Sprawdź, czy <math> | |||
liczbę <math> | |||
* Krok 7 (P): Oblicz <math> | |||
<math> | |||
* Krok 8 (V): Sprawdź, czy <math> | |||
dowolną liczbę <math> | |||
* <math> | |||
* Krok <math> | |||
<math> | |||
Sprawdź, czy <math> | |||
arytmetyzację formuły <math> | |||
pierwszych <math> | |||
słowo wejściowe, w przeciwnym przypadku je | |||
W przypadku gdy słowo wejściowe należy do <math> | W przypadku, gdy słowo wejściowe należy do <math>\#SAT(D)</math>, jest jasne, że funkcja <math>P</math>, | ||
postępująca zgodnie z powyższym protokołem zawsze przekona <math> | postępująca zgodnie z powyższym protokołem, zawsze przekona <math>V</math> o tej | ||
przynależności. Popatrzmy teraz, co się stanie, gdy słowo wejściowe nie należy | przynależności. Popatrzmy teraz, co się stanie, gdy słowo wejściowe nie należy | ||
do <math> | do <math>\#SAT(D)</math>; w tym przypadku wartość <math>f_0()</math> podana przez <math>\bar P</math> będzie | ||
musiała się różnić od wartości prawdziwej (oznaczmy ją jako <math> | musiała się różnić od wartości prawdziwej (oznaczmy ją jako <math>\bar {f_0}()</math>). | ||
W związku z tym przynajmniej jedna z wartości <math> | W związku z tym przynajmniej jedna z wartości <math>f_1(0)</math> lub <math>f_1(1)</math> będzie | ||
różna od oczekiwanej -- <math> | różna od oczekiwanej -- <math>\bar {f_1}(0)</math> lub <math>\bar {f_1}(1)</math> -- a co za tym | ||
idzie wielomian <math> | idzie wielomian <math>f_1(z)</math> będzie różny od <math>\bar {f_1}(z)</math>. Pokażemy teraz fakt | ||
będący sednem naszego dowodu: | będący sednem naszego dowodu: jeżeli wielomian <math>f_i(r_1,r_2,\ldots,r_{i-1},z)</math> | ||
jest różny od wielomianu <math> | jest różny od wielomianu <math>\bar {f_i}(r_1,r_2,\ldots,r_{i-1},z)</math>, to z dużym | ||
prawdopodobieństwem również <math> | prawdopodobieństwem również <math>f_{i+1}(r_1,r_2,\ldots,r_i,z)</math> będzie różny od | ||
<math> | <math>\bar {f_{i+1}}(r_1,r_2,\ldots,r_i,z)</math>. Zauważmy, że jesli <math>r_i</math> zostanie | ||
wylosowane w taki sposób, że <math> | wylosowane w taki sposób, że <math>f_i(r_1,\ldots,r_i)=\bar {f_i}(r_1,\ldots,r_i)</math>, | ||
to <math> | to <math>\bar P</math> w kolejnym kroku będzie mógł zwrócić wielomian | ||
<math> | <math>\bar {f_{i+1}} (r_1, \ldots,r_i,z)</math> -- a zatem skutecznie oszuka <math>V</math>. Aby tak | ||
się jednak stało wylosowana wartość <math> | się jednak stało wylosowana wartość <math>r_i</math> musi być jednym z punktów, w których | ||
<math> | <math>\bar {f_i}(r_1,r_2,\ldots,r_{i-1},z)</math> i <math>\bar {f_i}(r_1,r_2,\ldots,r_{i-1},z)</math> | ||
są równe. Prawdopodobieństwo takiego zdarzenia to co najwyżej <math> | są równe. Prawdopodobieństwo takiego zdarzenia to co najwyżej <math>n/{2^n}</math>. Jeżeli | ||
<math> | <math>f_i(r_1,\ldots,r_i)\neq \bar {f_i}(r_1,\ldots,r_i)</math>, to niewątpliwie | ||
<math> | <math>f_{i+1}(r_1,\ldots,r_i,0) \neq \bar {f_{i+1}}(r_1,\ldots,r_i,0)</math> lub | ||
<math> | <math>f_{i+1}(r_1,\ldots,r_i,1) \neq \bar {f_{i+1}}(r_1,\ldots,r_i,1)</math> -- a co za | ||
tym idzie wielomian <math> | tym idzie wielomian <math>f_{i+1}(r_1,\ldots,r_i,z)</math> będzie różny od wielomianu | ||
<math> | <math>\bar {f_{i+1}}(r_1,\ldots,r_i,z)</math>. | ||
Widzimy więc, że prawdopodobieństwo zdarzenia, w którym | Widzimy więc, że prawdopodobieństwo zdarzenia, w którym | ||
<math> | <math>f_m(r_1,\ldots,r_{m-1},z)</math> jest równy <math>\bar {f_m}(r_1,\ldots,r_{m-1},z)</math> jest | ||
ograniczone od góry przez wyrażenie <math> | ograniczone od góry przez wyrażenie <math>m \cdot n / {2^n}</math>, co z kolei jest nie | ||
większe niż <math> | większe niż <math>n^2 / {2^n}</math>. <math>V</math> jest w stanie wykryć niezgodność tych wielomianów | ||
w czasie wielomianowym w sposób deterministyczny -- a zatem <math> | w czasie wielomianowym w sposób deterministyczny -- a zatem <math>n^2 / {2^n}</math> jest | ||
górnym ograniczeniem na prawdopodobieństwo zaakceptowania przez <math> | górnym ograniczeniem na prawdopodobieństwo zaakceptowania przez <math>V</math> słowa | ||
spoza <math> | spoza <math>\#SAT(D)</math>. | ||
W tym momencie wystarczy już tylko zauważyć, że <math> | W tym momencie wystarczy już tylko zauważyć, że <math>n^2 / {2^n}</math> jest mniejsze od | ||
<math> | <math>1/3</math> dla każdego <math>n \geq 8</math>; protokół będziemy zatem stosować dla formuł o co | ||
najmniej 8 literałach. Pozostałe mogą zostać stablicowane przez <math> | najmniej 8 literałach. Pozostałe mogą zostać stablicowane przez <math>V</math> i rozstrzygane | ||
w czasie stałym, bez angażowania <math> | w czasie stałym, bez angażowania <math>P</math>. | ||
Powyższy protokół pokazuje zatem przynależność <math> | Powyższy protokół pokazuje zatem przynależność <math>\#SAT(D)</math> do klasy <math>IP</math>. | ||
Powróćmy teraz do problemu <math> | Powróćmy teraz do problemu <math>QSAT</math>. Możemy myśleć o kwantyfikatorach jako o | ||
pewnych transformacjach wykonywanych na zarytmetyzowanej formule logicznej, | pewnych transformacjach wykonywanych na zarytmetyzowanej formule logicznej, | ||
przedstawiając ten proces schematycznie jako: | przedstawiając ten proces schematycznie jako: | ||
<math> | <math>{Q_1}_{x_1} {Q_2}_{x_2} \ldots {Q_m}_{x_m} \langle \phi \rangle</math>, | ||
gdzie <math> | gdzie <math>Q_i \in \{ \exists, \forall \}</math>, natomiast <math>\langle \phi \rangle</math> to | ||
formuła <math> | formuła <math>\phi</math> przekształcona w procesie arytmetyzacji. Operacje <math>Q_i</math> definiujemy | ||
następująco: | następująco: | ||
* <math> | * <math>{Q_i}_{x_i} W(x_1,x_2,\ldots,x_i,\ldots,x_m) = W(x_1,x_2,\ldots,0,\ldots,x_m) \cdot | ||
W(x_1,x_2,\ldots,1,\ldots,x_m)</math> gdy <math> | W(x_1,x_2,\ldots,1,\ldots,x_m)</math> gdy <math>Q_i = \forall</math>, | ||
* <math> | * <math>{Q_i}_{x_i} W(x_1,x_2,\ldots,x_i,\ldots,x_m) = 1 - (1 - W(x_1,x_2,\ldots,0,\ldots,x_m)) \cdot | ||
(1 - W(x_1,x_2,\ldots,1,\ldots,x_m)) | (1 - W(x_1,x_2,\ldots,1,\ldots,x_m)), \mbox{ gdy }Q_i = \exists</math>. | ||
Możemy w tym momencie spróbować powtórzyć poprzedni dowód, to znaczy zdefiniować | Możemy w tym momencie spróbować powtórzyć poprzedni dowód, to znaczy zdefiniować | ||
ciąg wielomianów <math> | ciąg wielomianów <math>f_0,f_1,\ldots,f_m</math> tak, aby <math>f_m</math> był zarytmetyzowaną formułą | ||
<math> | <math>\phi</math>, a <math>f_{i-1} = {Q_i}_{x_i} f_i</math>. Niestety w tym przypadku wielomiany w | ||
kolejnych krokach są mnożone, a nie dodawane -- w związku z tym stopnie zmiennych | kolejnych krokach są mnożone, a nie dodawane -- w związku z tym stopnie zmiennych | ||
w kolejnych wielomianach mogą rosnąć eksponencjalnie; nie będziemy zatem w | w kolejnych wielomianach mogą rosnąć eksponencjalnie; nie będziemy zatem w | ||
Linia 852: | Linia 708: | ||
następującej operacji: | następującej operacji: | ||
<math> | <math>R_{x_i} W(x_1,x_2,\ldots,x_i,\ldots,x_m) = x_i \cdot W(x_1,x_2,\ldots,1,\ldots,x_m) | ||
+ (1 - x_i) \cdot W(x_1,x_2,\ldots,0,\ldots,x_m)</math> | + (1 - x_i) \cdot W(x_1,x_2,\ldots,0,\ldots,x_m)</math>. | ||
Wielomian otrzymany w wyniku takiej transformacji ma następujące cechy: | Wielomian otrzymany w wyniku takiej transformacji ma następujące cechy: | ||
* jest liniowy ze względu na <math> | * jest liniowy ze względu na <math>x_i</math>, | ||
* maksymalne stopnie pozostałych zmiennych pozostają takie same, | * maksymalne stopnie pozostałych zmiennych pozostają takie same, | ||
* nowy wielomian daje takie same wyniki co wyjściowy dla argumentów Boole'owskich | * nowy wielomian daje takie same wyniki co wyjściowy dla argumentów Boole'owskich (to znaczy dla liczb 0 i 1). | ||
(to znaczy dla liczb 0 i 1). | |||
Zmodyfikowana procedura postępowania będzie wyglądała następująco: | Zmodyfikowana procedura postępowania będzie wyglądała następująco: | ||
<math> | <math>{Q_1}_{x_1} R_{x_1} {Q_2}_{x_2} R_{x_1} R_{x_2} {Q_3}_{x_3} \ldots | ||
{Q_m}_{x_m} R_{x_1} \ldots R_{x_m} \langle \phi \rangle</math> | {Q_m}_{x_m} R_{x_1} \ldots R_{x_m} \langle \phi \rangle</math>. | ||
Zauważmy, że <math> | Zauważmy, że <math>R</math> nie zmienia ilości zmiennych wielomianu, natomiast operacje | ||
<math> | <math>Q_i</math> zmniejszają tę liczbę o 1. | ||
Liczbę transformacji oznaczymy jako <math> | Liczbę transformacji oznaczymy jako <math>k</math> -- będzie ona kwadratowo zależna od | ||
liczby zmiennych <math> | liczby zmiennych <math>m</math>. W tym momencie możemy już zdefiniować ciąg wielomianów | ||
<math> | <math>f_0,f_1,\ldots,f_k</math>: <math>f_k</math> będzie zarytmetyzowaną formułą <math>\phi</math>, natomiast | ||
<math> | <math>f_{i-1}</math> będzie otrzymywany z <math>f_i</math> za pomocą odpowiedniej transformacji | ||
<math> | <math>Q_j</math> lub <math>R</math>. Ze względu na stosowanie <math>R</math> stopień każdej zmiennej w tych | ||
wielomianach jest ograniczony przez liczbę literałów w <math> | wielomianach jest ograniczony przez liczbę literałów w <math>\phi</math> (oznaczaną | ||
ponownie jako <math> | ponownie jako <math>n</math>). Podobnie jak wcześniej, <math>f_0()</math> będzie szukanym przez nas | ||
wynikiem; wielomiany ponownie będą określone nad pewnym skończonym ciałem | wynikiem; wielomiany ponownie będą określone nad pewnym skończonym ciałem | ||
<math> | <math>{\mathbb Z}_p</math> -- tym razem jednak wystarczy nam dowolna liczba pierwsza <math>p</math> | ||
większa niż <math> | większa niż <math>n^4</math>. Taką liczbę <math>V</math> może znaleźć samodzielnie, dla uproszczenia | ||
jednak założymy, że otrzymana zostanie ona tak samo jak <math> | jednak założymy, że otrzymana zostanie ona tak samo jak <math>p</math> w protokole dla | ||
<math> | <math>\#SAT(D)</math>. | ||
Właściwy protokół będzie oparty na tej samej zasadzie | Właściwy protokół będzie oparty na tej samej zasadzie co poprzednio: <math>P</math> | ||
wypisze wartość <math> | wypisze wartość <math>f_0()</math>, po czym będzie wypisywała pewne zawężenia wielomianów | ||
<math> | <math>f_1, \ldots, f_k</math>; <math>V</math> będzie sprawdzała, czy kolejne wielomiany nie są sprzeczne | ||
z poprzednimi (czyli również z <math> | z poprzednimi (czyli również z <math>f_0</math>), a na końcu samodzielnie obliczy | ||
zawężenie wielomianu <math> | zawężenie wielomianu <math>\bar {f_k}</math> i porówna je z wielomianem otrzymanym od <math>P</math>. | ||
Ponownie jeśli <math> | Ponownie, jeśli <math>P</math> skłamie przy podawaniu wartości <math>f_0()</math>, prawdopodobieństwo | ||
tego, że uda jej się to kłamstwo zamaskować, będzie nieduże. | tego, że uda jej się to kłamstwo zamaskować, będzie nieduże. | ||
Popatrzmy teraz jak wygląda pojedynczy krok protokołu | Popatrzmy teraz jak wygląda pojedynczy krok protokołu. W tym celu oznaczmy <math>i</math>-tą | ||
transformację jako <math> | transformację jako <math>{S_i}_{y_i}</math>. Załóżmy bez utraty ogólności, że <math>{y_i} = x_1</math>, | ||
natomiast <math> | natomiast <math>y_{i-1} = x_2</math> -- założenie to ma na celu jedynie uproszczenie | ||
indeksowania. Podobnie jak w przypadku <math> | indeksowania. Podobnie jak w przypadku <math>\#SAT(D)V</math> dysponuje współczynnikami | ||
<math> | <math>f_{i-1}</math> jako wielomianu zmiennej <math>{x_2}</math>, gdzie za | ||
pozostałe zmienne zostały podstawione pewne wylosowane uprzednio stałe. Jeżeli | pozostałe zmienne zostały podstawione pewne wylosowane uprzednio stałe. Jeżeli | ||
operacja <math> | operacja <math>S_i</math> jest kwantyfikatorem, to protokół zachowuje się praktycznie identycznie | ||
jak w poprzednim dowodzie; w tym przypadku <math> | jak w poprzednim dowodzie; w tym przypadku <math>V</math> ma do dyspozycji wielomian | ||
<math> | <math>f_{i-1}(x_2,r_3,r_4,\ldots,r_s)</math>, losuje liczbę <math>r_2</math> i prosi <math>P</math> o przesłanie | ||
współczynników <math> | współczynników <math>f_i(x_1,r_2,\ldots,r_s)</math>. Jeżeli wielomian | ||
<math> | <math>f_{i-1}(x_2,r_3,r_4,\ldots,r_s)</math> nie jest prawidłowy -- czyli gdy funkcja <math>P</math> próbuje | ||
oszukać <math> | oszukać <math>V</math> i nie udało jej się jeszcze "zatrzeć śladów oszustwa" -- | ||
to prawdopodobieństwo, że wielomian <math> | to prawdopodobieństwo, że wielomian <math>f_i(x_1,r_2,\ldots,r_s)</math> będzie prawidłowy, | ||
wyniesie co najwyżej <math>n/{n^4}</math>, czyli <math>1/{n^3}</math>. | |||
Rozpatrzmy teraz przypadek, gdy <math> | Rozpatrzmy teraz przypadek, gdy <math>S_i = R</math>. <math>V</math> ma do dyspozycji wielomian | ||
<math> | <math>f_{i-1}(r_1,x_2,r_3,\ldots,r_s)</math>. W pierwszej kolejności <math>V</math> losuje pewną | ||
liczbę <math> | liczbę <math>{r'}_2</math>, po czym prosi <math>P</math> o przesłanie współczynników wielomianu | ||
<math> | <math>f_{i-1}(x_1,{r'}_2,r_3,\ldots,r_s)</math>. Następnie <math>V</math> sprawdza, czy podstawienie | ||
<math> | <math>{r'}_2</math> do pierwszego z tych wielomianów daje ten sam wynik, co podstawienie <math>r_1</math> | ||
do drugiego. Ponownie argumentujemy, że jeśli wielomian <math> | do drugiego. Ponownie argumentujemy, że jeśli wielomian <math>f_{i-1}(r_1,x_2,r_3,\ldots,r_s)</math> | ||
był nieprawidłowy -- czyli różny od "wzorcowego" wielomianu | był nieprawidłowy -- czyli różny od "wzorcowego" wielomianu | ||
<math> | <math>\bar {f_{i-1}}(r_1,x_2,r_3,\ldots,r_s)</math> -- to prawdopodobieństwo, że dla | ||
wylosowanej wartości <math> | wylosowanej wartości <math>{r'}_2</math> zachodzi | ||
<math> | <math>f_{i-1}(r_1,{r'}_2,r_3,\ldots,r_s) = \bar {f_{i-1}}(r_1,{r'}_2,r_3,\ldots,r_s)</math> | ||
jest nie większe niż <math> | jest nie większe niż <math>1/{n^3}</math>. W związku z tym wielomian | ||
<math> | <math>f_{i-1}(x_1,{r'}_2,r_3,\ldots,r_s)</math> będzie poprawny z prawdopodobieństwem co | ||
najwyżej równym <math> | najwyżej równym <math>1/{n^3}</math>. W następnym kroku <math>P</math> przesyła współczynniki wielomianu | ||
<math> | <math>f_i(x_1,{r'}_2,r_3,\ldots,r_s)</math>. Zauważmy, że <math>V</math> jest w stanie samodzielnie | ||
sprawdzić, czy wielomian <math> | sprawdzić, czy wielomian <math>f_{i-1}(x_1,{r'}_2,r_3,\ldots,r_s)</math> został otrzymany z | ||
<math> | <math>f_i(x_1,{r'}_2,r_3,\ldots,r_s)</math> w wyniku transformacji <math>R</math> -- transformacja ta | ||
jest przecież jednoznacznie określona. Jeżeli założymy zatem, że wielomian | jest przecież jednoznacznie określona. Jeżeli założymy zatem, że wielomian | ||
<math> | <math>f_{i-1}(x_1,{r'}_2,r_3,\ldots,r_s)</math> jest nieprawidłowy, to nieprawidłowy musi | ||
być też wielomian <math> | być też wielomian <math>f_i(x_1,{r'}_2,r_3,\ldots,r_s)</math>. Reasumując -- prawdopodobieństwo, | ||
że w kroku odpowiadającym pewnej transformacji <math> | że w kroku odpowiadającym pewnej transformacji <math>R</math> funkcji <math>V</math> uda się | ||
skutecznie "zatrzeć ślad" po wcześniejszym oszustwie jest nie większe niż | skutecznie "zatrzeć ślad" po wcześniejszym oszustwie, jest nie większe niż | ||
<math> | <math>1/{n^3}</math>. | ||
{{uwaga||| | {{uwaga|2.12|| | ||
Zauważmy, że w trakcie działania protokołu losujemy <math> | Zauważmy, że w trakcie działania protokołu losujemy <math>k</math> liczb; jest zatem | ||
możliwe (i pewne), że w tym procesie <math> | możliwe (i pewne), że w tym procesie <math>V</math> będzie podstawiać w miejsce tej | ||
samej zmiennej różne wylosowane liczby. Dla przykładu -- powyżej wylosowaliśmy | samej zmiennej różne wylosowane liczby. Dla przykładu -- powyżej wylosowaliśmy | ||
liczbę <math> | liczbę <math>{r'}_2</math>; być może jednak już wcześniej dokonywaliśmy innej operacji na | ||
zmiennej <math> | zmiennej <math>x_2</math> i wylosowaliśmy inną liczbę <math>r_2</math>. Widzimy zatem, że pewne | ||
wylosowane wartości zostają w tym procesie "zapomniane" i na ich miejsce | wylosowane wartości zostają w tym procesie "zapomniane" i na ich miejsce | ||
losowane są nowe. Oczywiście wyniki nowych losowań powinny być niezależne od | losowane są nowe. Oczywiście wyniki nowych losowań powinny być niezależne od | ||
poprzednich -- inaczej <math> | poprzednich -- inaczej <math>P</math> mógłby osiągnąć większe prawdopodobieństwo skutecznego | ||
oszukania <math> | oszukania <math>V</math>. | ||
}} | }} | ||
Jak zauważyliśmy wcześniej, liczba wykonywanych transformacji <math> | Jak zauważyliśmy wcześniej, liczba wykonywanych transformacji <math>k</math> jest | ||
kwadratowo zależna od <math> | kwadratowo zależna od <math>m</math>; w szczególności natychmiastowe jest oszacowanie | ||
<math> | <math>k < (m+1)^2</math>. W związku z tym prawdopodobieństwo, że <math>V</math> zaakceptuje słowo | ||
wejściowe | wejściowe nienależące do <math>QSAT</math> jest nie większe niż <math>(m+1)^2/{n^3}</math>, co | ||
z kolei jest nie większe niż <math> | z kolei jest nie większe niż <math>(n+1)^2/{n^3} = O(1/n)</math>. Ponownie zatem <math>V</math> | ||
musi "stablicować" wyniki dla pewnej skończonej liczby formuł (w tym przypadku | musi "stablicować" wyniki dla pewnej skończonej liczby formuł (w tym przypadku | ||
stablicowane muszą zostać formuły o co najwyżej 4 literałach), a dla reszty | stablicowane muszą zostać formuły o co najwyżej 4 literałach), a dla reszty | ||
protokół będzie dawał prawidłowe wyniki z wymaganym prawdopodobieństwem. | protokół będzie dawał prawidłowe wyniki z wymaganym prawdopodobieństwem. | ||
Powyższy protokół pokazuje więc przynależność <math> | Powyższy protokół pokazuje więc przynależność <math>QSAT</math> do klasy <math>IP</math>. W tym | ||
momencie wystarczy zauważyć, że klasa <math> | momencie wystarczy zauważyć, że klasa <math>IP</math> jest domknięta ze względu na redukcje | ||
wielomianowe; jeśli <math> | wielomianowe; jeśli <math>L_1</math> redukuje się do <math>L_2</math> oraz znamy protokół rozwiązujący | ||
<math> | <math>L_2</math>, to <math>V</math> może w pierwszym kroku dokonać redukcji, po czym postępować | ||
zgodnie z protokołem dla <math> | zgodnie z protokołem dla <math>L_2</math>. Korzystając z faktu, że <math>QSAT</math> jest | ||
problemem <math> | problemem <math>PSPACE</math>-zupełnym, stwierdzamy, że każdy problem z klasy <math>PSPACE</math> | ||
zawarty jest w klasie <math> | zawarty jest w klasie <math>IP</math>. | ||
{{cwiczenie||| | {{cwiczenie|2.13|| | ||
Wyjaśnij, czemu w protokole <math> | Wyjaśnij, czemu w protokole <math>\#SAT(D)</math> potrzebowaliśmy ciała o co najmniej | ||
<math> | <math>2^n</math> elementach. | ||
}} | }} | ||
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | <div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie </span><div class="mw-collapsible-content" style="display:none"> | ||
Widzimy, że aby spełnić wymagania dotyczące prawdopodobieństwa zaakceptowania | Widzimy, że aby spełnić wymagania dotyczące prawdopodobieństwa zaakceptowania | ||
słowa spoza języka, wystarczy ciało o wielkości <math> | słowa spoza języka, wystarczy ciało o wielkości <math>n^3</math>. W przypadku <math>\#SAT(D)</math> | ||
ciało <math> | ciało <math>{\mathbb Z}_p</math> służy nam jednak nie tylko jako dostarczyciel dużej | ||
przestrzeni | przestrzeni prawdopodobieństwa, lecz również do zliczania ilości spełniających | ||
wartościowań dla zadanej formuły logicznej. Z tego powodu potrzebujemy co | wartościowań dla zadanej formuły logicznej. Z tego powodu potrzebujemy co | ||
najmniej <math> | najmniej <math>2^m</math> liczb -- co oznacza, że w zdegenerowanym przypadku, gdy | ||
każda zmienna jest używana w dokładnie jednym literale wymagane ciało musi mieć | każda zmienna jest używana w dokładnie jednym literale wymagane ciało musi mieć | ||
liczność | liczność | ||
nie mniejszą niż <math> | nie mniejszą niż <math>2^n</math>. | ||
</div></div> | </div></div> | ||
==Testy końcowe== |
Aktualna wersja na dzień 11:00, 5 wrz 2023
Funkcje jednokierunkowe
W dotychczasowych rozważaniach naszym celem było znalezienie możliwie efektywnego rozwiązania dla zadanych problemów; nadmierna złożoność problemu była przez nas traktowana jako cecha niepożądana, utrudniająca nam zadanie. W tym rozdziale nasze podejście będzie odmienne; duża złożoność będzie dla nas cechą bardzo cenną. Będzie nas przy tym, w mniejszym niż dotychczas stopniu, interesować złożoność pesymistyczna -- w końcu nie satysfakcjonuje nas "gwarancja" mówiąca, że "jeżeli osoba podsłuchująca będzie miała pecha, to odszyfrowanie wiadomości będzie dla niej zadaniem czasochłonnym". Wolelibyśmy, żeby odszyfrowywanie wiadomości przez osoby nieuprawnione było czasochłonne, praktycznie zawsze -- tak, by próba podsłuchiwania dawała szansę sukcesu bardzo bliską zeru. Duża pesymistyczna złożoność nie będzie zatem warunkiem wystarczającym bycia dobrym kryptosystemem; przyda nam się jednak w charakterze warunku koniecznego.
Definicja 1.1
Niech . Mówimy, że jest funkcją jednokierunkową wtedy i tylko wtedy, gdy:
- jest różnowartościowa,
- istnieje pewna stała taka, że ,
- jest obliczalna w czasie wielomianowym (czyli należy do klasy ),
- nie istnieje wielomianowy algorytm obliczający odwrotność funkcji -- czyli znajdujący dla słowa słowo , takie że lub stwierdzający, że takie słowo nie istnieje.
Warto zauważyć, że powyższa definicja niejawnie zakłada prawdziwość zdania .
Ćwiczenie 1.2
Niech spełnia pierwsze trzy warunki podane w definicji funkcji jednokierunkowej. Pokaż, że obliczanie odwrotności funkcji jest problemem z klasy .
Z drugiej strony nierówność wcale nie gwaratuje istnienia funkcji jednokierunkowych; jak się okazuje istnienie tego typu funkcji jest ściśle powiązane z pewną klasą złożoności, którą przedstawiamy poniżej.
Definicja 1.3
Jednoznaczną maszyną Turinga nazywamy niedeterministyczną maszynę Turinga taką, że dla każdego słowa wejściowego istnieje co najwyżej jedna akceptująca ścieżka obliczeń.
Definicja 1.4
Klasa to klasa problemów rozstrzygalnych za pomocą jednoznacznych maszyn Turinga w czasie wielomianowym.
Klasę , podobnie jak klasę , można zdefiniować z użyciem pojęcia świadka:
.
W językach z klasy każde słowo ma dokładnie jednego świadka. Dowód równoważności powyższych definicji jest analogiczny jak w przypadku klasy .
Jest jasne, że -- maszyny deterministyczne są specjalnymi przypadkami maszyn jednoznacznych. Dość powszechny jest pogląd, że obie powyższe relacje zawierania są właściwe (to znaczy nie zachodzi równość).
Pokażemy teraz bardzo ciekawy związek pomiędzy klasą a funkcjami jednokierunkowymi.
Twierdzenie 1.6
Funkcje jednokierunkowe istnieją wtedy i tylko wtedy, gdy .
Dowód
Zaczniemy od dowodu w kierunku . Załóżmy, że istnieje pewna funkcja jednokierunkowa . Możemy wtedy zdefiniować następujący język:
,
przy czym mówimy, że wtedy i tylko wtedy, gdy
- lub
- i w porządku leksykograficznym występuje nie później niż .
Łatwo można zauważyć, że - maszyna rozwiązująca ten problem najpierw "zgaduje" słowo o wielkości nie większej niż , po czym sprawdza, czy w ustalonym porządku występuje ono nie później niż i czy zachodzi . Z własności funkcji jednokierunkowych -- konkretnie z różnowartościowości -- wynika, że maszyna ta ma co najwyżej jedną akceptującą ścieżkę postępowania.
Chcemy teraz pokazać, że . Załóżmy zatem nie wprost, że istnieje jakiś wielomianowy algorytm rozwiązujący . Wykorzystamy go teraz do obliczenia odwrotności funkcji w czasie wielomianowym. W pierwszym kroku zapytamy algorytm, czy (przez oznaczamy tutaj ciąg symboli ) - jeżeli otrzymamy odpowiedź NIE, to korzystając z definicji funkcji jednokierunkowej, możemy od razu stwierdzić, że nie istnieje słowo takie, że . Jeżeli otrzymamy odpowiedź TAK, to z użyciem co najwyżej zapytań do naszego algorytmu jesteśmy w stanie ustalić długość szukanego słowa (pytamy kolejno o , , itd., aż do momentu, gdy uzyskamy odpowiedź NIE). Gdy znamy już długość słowa pozostaje nam tylko obliczyć kolejne jego bity. Pierwszy bit otrzymamy, pytając o parę -- odpowiedź "tak" oznacza, że pierwszym bitem jest 0. Aby uzyskać drugi bit zapytamy -- w zależności od pierwszej odpowiedzi -- o lub . Kolejne bity odgadujemy w analogiczny sposób -- łącznie zatem wykonamy algorytm dla razy. W ten sposób uzyskamy deterministycznty algorytm odwracający funkcję w czasie wielomianowym.
Doszliśmy więc do sprzeczności z definicją funkcji jednokierunkowej, co oznacza, że istnienie funkcji jednokierunkowych implikuje nierówność .
Załóżmy teraz, że istnieje język , rozpoznawany przez jednoznaczną maszynę . Zdefiniujmy funkcję w następujący sposób:
- jeżeli jest zakodowaną parą słów oraz jest (jedynym) świadkiem przynależności słowa do , to
,
- w przeciwnym przypadku
.
Widzimy, że pierwszy symbol wartości funkcji gwarantuje nam jej różnowartościowość. Spełniony jest również drugi warunek z definicji funkcji jednokierunkowej -- świadek dla słowa nie może być nadmiernie długi (bo jego długość jest wielomianowo zależna od długości ), a zatem nie może nadmiernie "skracać" słów. Funkcja jest też obliczalna w czasie wielomianowym -- wystarczy deterministycznie zweryfikować świadka, tak jak zrobiłaby to maszyna . Pozostaje nam zatem tylko pokazanie, że funkcja odwrotna do nie jest obliczalna w czasie wielomianowym. Gdyby tak jednak było, to moglibyśmy rozpoznawać język w czasie wielomianowym: aby sprawdzić, czy wystarczy zastosować odwrotność funkcji do słowa ; jeżeli , to dostaniemy odpowiedź mówiącą, że nie można odwrócić; w przeciwnym przypadku otrzymamy świadka przynależności do języka .

Na dzień dzisiejszy nie znamy oczywiście funkcji, o której wiedzielibyśmy, że jest jednokierunkowa; istnienie takiej funkcji natychmiastowo implikuje przecież nierówność . Jest jednak kilku "kandydatów" na funkcje jednokierunkowe, dla których nie znamy efektywnego algorytmu pozwalającego na ich odwrócenie. Jedną z takich funkcji jest . Argumentami tej funkcji są dwie liczby pierwsze wraz ze swoimi certyfikatami pierwszości. Wartością funkcji jest iloczyn tych dwóch liczb. Bardziej formalnie:
- jeżeli , gdzie a i są certyfikatami pierwszości odpowiednio dla i , to
,
- w przeciwnym przypadku
.
Korzystamy tutaj z faktu, że możemy wymusić jednoznaczną reprezentację certyfikatu pierwszości dla danej liczby oraz że certyfikaty mają rozmiar wielomianowo zależny od rozmiaru certyfikowanych liczb. jest zatem różnowartościowa i nie "skraca" nadmiernie słowa wejściowego.
Łatwo zauważyć, gdzie tkwi trudność w odwracaniu tej funkcji -- nie znamy efektywnego algorytmu potrafiącego faktoryzować iloczyn dwóch liczb pierwszych; znane nam obecnie algorytmy stają się niepraktyczne już przy iloczynach liczb pierwszych o długości kilkuset bitów.
Drugi ze znanych nam "kandydatów na funkcję jednokierunkową" również oparty jest na zagadnieniu z dziedziny teorii liczb -- problemie logarytmu dyskretnego. Funkcję tą można zdefiniować w następujący sposób:
- dla postaci , gdzie jest liczbą pierwszą, certyfikatem jej pierwszości, jest najmniejszym generatorem grupy cyklicznej , a jest liczbą naturalną z zakresu
- dla pozostałych
.
W tym przypadku, aby odwrócić funkcję , musielibyśmy na podstawie liczb , i umieć obliczyć wartość . Również dla tego, znanego od wielu lat, problemu nie potrafimy przedstawić wydajnego rozwiązania.
Jak zauważyliśmy, we wprowadzeniu do tego rozdziału, w kryptografii duża złożoność pesymistyczna próby zdekodowania zaszyfrowanej wiadomości nie jest własnością wystarczającą. Z tego powodu przytoczymy alternatywną definicję funkcji jednokierunkowych, lepiej odwzorowującą nasze oczekiwania. Należy pamiętać, że definicja ta jest istotnie różna od definicji podanej wcześniej.
Definicja 1.7
Niech . Mówimy, że jest funkcją jednokierunkową wtedy i tylko wtedy, gdy:
- jest obliczalna w czasie wielomianowym,
- nie jest stale równa (słowu pustemu),
- istnieje pewna stała taka, że ,
- jeżeli i są słowami nad alfabetem i , to lub ,
- dla każdej losowej maszyny Turinga działającej w czasie wielomianowym, każdej liczby i dostatecznie dużej liczby , jeżeli jest losowym słowem ze zbioru , to
.
W tej definicji zrezygnowaliśmy z wymagania o różnowartościowości funkcji; zamiast tego dopuszczamy, aby różne słowa dawały jako wynik wartość , którą możemy traktować jako odpowiedź mówiącą, że wejście jest nieprawidłowe; dla przykładu przy adaptowaniu funkcji do powyższej definicji, w przypadku gdy lub nie będą liczbami pierwszymi lub gdy , lub nie będą odpowiednimi certyfikatami, funkcja zwróci wartość . Zauważmy, że w powyższej definicji interesuje nas tylko trudność odszyfrowania wartości funkcji dla poprawnych wejść -- to znaczy w przypadku dla par liczb, które są pierwsze i których pierwszość jest potwierdzana przez i . Funkcje jak i -- po odpowiednim ich zmodyfikowaniu w sposób przedstawiony powyżej -- są poważnymi "kandydatami" na funkcje jednokierunkowe również w sensie definicji opisanej w poprzednim paragrafie.
Warto się w tym momencie zastanowić, w jaki sposób funkcje jednokierunkowe mogą się przydać w kryptografii. Otóż widzimy, że jedna ze stron -- zwyczajowo zwana Alicją -- może wydajnie zaszyfrować swoją wiadomość, na przykład używając ją jako argument do funkcji . Niestety druga strona -- zazwyczaj o imieniu Bob -- może mieć duże trudności z odszyfrowaniem wiadomości. W tej sytuacji fakt, że osoba podsłuchująca -- Cecylia -- niczego ciekawego się nie dowie, stanowi słabe pocieszenie.
Widzimy zatem, że aby zapewnić poufność komunikacji pochodzącej od Alicji, ale również możliwość odebrania tej wiadomości, Bob musi posiadać pewną tajną wiedzę, pozwalającą na wydajne odwrócenie funkcji szyfrującej. Zdefiniujemy teraz pewną modyfikację pojęcia funkcji jednokierunkowej mającą szersze zastosowanie w kryptografii.
Definicja 1.8
Niech . Mówimy, że jest funkcją z wytrychem wtedy i tylko wtedy gdy istnieje losowa maszyna Turinga oraz funkcja taka, że:
- funkcje i są obliczalne w czasie wielomianowym,
- oczekuje na wejściu słowa nad alfabetem , zwraca zakodowaną parę słów nad alfabetem i działa w czasie wielomianowym,
- istnieje stała taka, że jeżeli stanowi wynik działania maszyny dla słowa , natomiast jest słowem o długości nie większej niż , to ,
- jeżeli stanowi wynik działania maszyny dla słowa , natomiast i są słowami o długości nie większej niż , to
,
- dla każdej losowej maszyny Turinga , każdej liczby i dostatecznie dużej liczby , jeżeli stanowi wynik działania maszyny dla słowa , jest losowym słowem nad alfabetem nie dłuższym niż , to
,
- dla każdego , każdego słowa nie dłuższego niż i każdej pary mogącej być wynikiem działania maszyny , dla słowa wejściowego .
Funkcje z wytrychem mogą zostać wykorzystane w celu stworzenia systemów kryptograficznych z kluczem publicznym. Sposób postępowania jest w tym przypadku następujący:
- Bob ustala długość przekazywanych wiadomości () oraz parametr wyznaczający prawdopodobieństwo odszyfrowania pojedynczej wiadomości (),
- Bob uruchamia maszynę i otrzymuje parę słów . Słowo staje się dostępnym dla wszystkich kluczem publicznym, natomiast pozostaje tajemnicą znaną tylko Bobowi,
- Alicja, chcąc wysłać wiadomość do Boba, używa znanego jej klucza publicznego . Własności funkcji z wytrychem sprawiają, że odszyfrowanie wiadomości jest łatwe dla Boba, natomiast trudne dla osób trzecich nieznających klucza .
Najbardziej znanym systemem kryptograficznym opartym na powyższej zasadzie jest system RSA. Pamiętajmy przy tym, że nie znamy formalnego dowodu, mówiącego, że RSA spełnia warunki określone w definicji funkcji z wytrychem.
Prześledźmy teraz, w jaki sposób zdefiniowane są , i dla systemu RSA.
Zadaniem maszyny jest wygenerowanie pary kluczy. W tym celu losuje ona dwie liczby pierwsze i , z których każda ma długość większą niż (gdzie to długość przekazywanych wiadomości). Następnie oblicza ona liczbę oraz wartość funkcji Eulera dla tej liczby: . W kolejnym kroku znajdywana jest dowolna liczba z zakresu , względnie pierwsza z . Dla liczby znajdywana jest następnie liczba z zakresu taka, że
.
Istnienie takiej liczby spowodowane jest faktem, że i są względnie pierwsze; liczbę można efektywnie obliczyć z użyciem uogólnionego algorytmu Euklidesa.
W tym momencie można już zdefiniować parę kluczy: kluczem publicznym jest para liczb oraz ; kluczem prywatnym jest para liczb oraz . Szyfrowanie słowa wygląda następująco:
,
przy czym wiadomość traktujemy jako binarny zapis pewnej liczby naturalnej. Dekodowanie słowa określone jest w praktycznie identyczny sposób:
.
Wystarczy teraz przypomnieć sobie, że iloczyn jest postaci , dla pewnej liczby całkowitej . W związku z tym
.
Widzimy zatem, że funkcja poprawnie dekoduje słowa zaszyfrowane z użyciem funkcji -- Bob będzie zatem w stanie odtworzyć wiadomość wysłaną przez Alicję.
Systemy dowodów interaktywnych
W ostatnim fragmencie niniejszego kursu zajmiemy się klasą złożoności, będącą uogólnieniem klas i . W tym celu zdefiniujemy pojęcie systemu dowodów interaktywnych.
Definicja 2.1
Systemem dowodów interaktywnych nazywamy parę funkcji oraz o sygnaturach:
taką, że funkcja jest obliczalna na maszynie Turinga.
Działanie systemu dowodów interaktywnych polega na wymianie komunikatów między funkcjami i , przy czym funkcja (z angielskiego prover) stara się "przekonać" funkcję (verifier) o tym, że słowo wejściowe należy do rozpatrywanego języka, natomiast ostateczna decyzja w tej sprawie należy do .
Komunikacja odbywa się naprzemiennie: funkcja generuje wiadomość, przekazywaną funkcji jako argument; funkcja z kolei generuje odpowiedź przekazywaną funkcji w następnej iteracji. Taka komunikacja odbywa się do momentu zaakceptowania lub odrzucenia słowa wejściowego przez funkcję . W każdym kroku obie funkcje mają do dyspozycji zarówno słowo wejściowe, jak również pełną historię przekazanych dotychczas wiadomości.
Określmy teraz, co dokładnie oznaczają argumenty funkcji i . Argumenty funkcji będziemy oznaczać w następujący sposób:
.
Mają one następujące znaczenie:
- to słowo wejściowe,
- jest losowym ciągiem bitów,
- to konkatenacja dotychczasowych wiadomości, które zostały przekazane w procesie komunikacji (wiadomości o indeksach nieparzystych są wynikami działania funkcji , natomiast wiadomości o indeksach parzystych są wynikami działania funkcji ).
Zwróćmy uwagę, że ma do dyspozycji losowe słowo ; w praktyce oznacza to, że o funkcji będziemy myśleć jako o pewnej losowej maszynie Turinga.
Zakładamy, że zarówno jak i są stałe w kolejnych iteracjach; słowo jest zatem losowane jednokrotnie, przed rozpoczęciem procesu komunikacji. Warto też zauważyć, że słowa i całkowicie determinują działanie systemu.
Argumenty funkcji będziemy oznaczać następująco:
.
Ich znaczenie jest identyczne jak w przypadku argumentów funkcji , nie ma wśród nich jednak słowa losowego.
Możemy w tym momencie zdefiniować klasę :
Definicja 2.2
Niech . Mówimy, że wtedy i tylko wtedy, gdy istnieje system dowodów interaktywnych oraz wielomiany i takie, że dla każdego słowa wejściowego oraz losowego słowa o długości :
- system daje odpowiedź po co najwyżej krokach,
- w każdej iteracji czas działania maszyny obliczającej funkcję jest ograniczony od góry przez ,
- długość każdej wiadomości jest nie większa niż ,
- jeżeli , to prawdopodobieństwo zaakceptowania słowa przez system wynosi co najmniej ,
- jeżeli oraz jest dowolną funkcją o sygnaturze zgodnej z , zwracającą wiadomości nie dłuższe niż , to system spełnia powyższe założenia na ilość iteracji, czas działania i długość wiadomości oraz akceptuje słowo z prawdopodobieństwem nie większym niż .
O systemie mówimy, że rozpoznaje język w czasie wielomianowym.
Innymi słowy, jeżeli słowo należy do języka, to z dużym prawdopodobieństwem da się przekonać o tej przynależności przez pewną ustaloną funkcję . Jeżeli jednak nie należy do , to nie da się oszukać żadnej funkcji ze zbyt dużym prawdopodobieństwem.
Zwróćmy jeszcze uwagę, że branie pod uwagę tylko takich funkcji , które nie zwracają zbyt długich słów, nie jest istotnym ograniczeniem; funkcja może w każdym kroku sprawdzać, czy odpowiedź funkcji nie jest zbyt długa i jeśli tak, to odrzucać słowo. W dalszej części rozdziału będziemy zakładali takie właśnie zachowanie funkcji .
Widzimy zatem, że funkcja musi być zabezpieczona przed oszustwami; jeżeli mogłaby zaufać funkcji , to mogłaby rozwiązać każdy problem decyzyjny -- wystarczyłoby po prostu skorzystać z nieograniczonej mocy obliczeniowej . W naszym przypadku jednak nie wystarczy, aby tylko rozwiązała problem decyzyjny -- musi jeszcze przekonać do swojego rozwiązania.
Przykład 2.4
Rozważmy problem . Jest on zdefiniowany następująco:
grafy i nie są izomorficzne .
Łatwo sie przekonać, że problem izomorfizmu grafów jest w klasie -- wystarczy zgadnąć odpowiednią permutację wierzchołków, po czym zweryfikować ją w trywialny sposób. należy zatem do . Nie jest jednak obecnie znana odpowiedź na pytanie o przynależność tego problemu do klasy . Pokażemy teraz, w jaki sposób można rozwiązać za pomocą systemów dowodów interaktywnych, pokazując przynależność tego problemu do klasy .
System działa w prosty sposób: W kolejnych iteracjach funkcja wybiera losowo jeden z grafów, a następnie w losowy sposób permutuje jego wierzchołki. Taki graf jest przekazywany jako wiadomość do funkcji . Zadaniem funkcji jest rozpoznanie, który z wyjściowych grafów został wylosowany i przekształcony przez .
Ćwiczenie 2.5
Zdefiniuj, w jakich przypadkach powinien zaakceptować, a w jakich odrzucić wejściową parę grafów. Oblicz, ile iteracji jest potrzebnych, aby system rozpoznawał język w czasie wielomianowym zgodnie z wcześniejszą definicją.
Ćwiczenie 2.6
Pokaż, że klasa jest zawarta w klasie .
Ćwiczenie 2.7
Rozpatrzmy takie systemy dowodów interaktywnych, w których funkcje nie zależą od argumentu (słowa losowego). Jaką klasę języków rozpoznają takie systemy, przy założeniach o złożoności analogicznych jak w przypadku klasy ?
Możemy w tym momencie przypuszczać, że klasa jest znacząco większa od klasy . Nie wiemy obecnie, czy przypuszczenie to jest prawdziwe; przemawia jednak za nim poniższe twierdzenie.
Twierdzenie 2.8
Dowód
Pokażemy najpierw fakt . W tym celu wybierzemy dowolny problem z klasy i rozwiążemy go z użyciem wielomianowej ilości pamięci.
Załóżmy, że system akceptuje wybrany język w czasie wielomianowym.
Ustalmy słowo . Będziemy mówić, że ciąg wiadomości jest zgodny ze słowem losowym , jeżeli stanowi on historię wiadomości po iteracjach pewnego systemu używającego słowa losowego . Warto zauważyć, że ciąg wiadomości może być zgodny z wieloma słowami losowymi (na przykład ciąg pusty jest zgodny z każdym słowem losowym), a słowo losowe może być zgodne z różnymi ciągami wiadomości (w zależności od funkcji ).
Zdefiniujmy teraz funkcję w taki sposób, by miała ona następującą własność:
akceptuje akceptuje .
Funkcja zatem dla każdego słowa wejściowego zachowuje się w najlepszy możliwy sposób. Jest ona dobrze zdefiniowana, gdyż dla każdego wejściowego słowa zbiór prawdopodobieństw jest skończony -- przy ustalonym słowie wszystkie możliwe funkcje można przypisać do skończonej liczby klas równoważności, w ramach których system zachowuje się identycznie (pamiętajmy, że w całym procesie komunikacji funkcja wykonuje co najwyżej skończoną, ustaloną dla danego słowa wejściowego liczbę kroków).
Jest jasne, że również akceptuje wybrany język w czasie wielomianowym -- od tej pory będziemy się zatem zajmowali tym konkretnym systemem. Nasz algorytm będzie dla każdego słowa wejściowego wprost obliczał prawdopodobieństwo zaakceptowania go przez system ; tym samym, w zależności od wyniku, będzie mógł określić, czy słowo wejściowe należy do języka. Dla uproszczenia założymy, że system daje odpowiedzi po dokładnie krokach.
Zdefiniujmy teraz funkcję mierzącą prawdopodobieństwo akceptacji słowa przez system przy ustalonej częściowej historii komunikacji:
słowo zostanie zaakceptowane pod warunkiem, że dotychczasowe komunikaty reprezentowane są przez .
W przypadku, gdy nie ma słowa losowego zgodnego z , funkcji nadajemy wartość . Łatwo jest obliczyć :
- jeżeli i jest zgodne z pewnym słowem losowym, to
,
- w przeciwnym przypadku
.
Do obliczania wartości dla mniejszej ilości kroków, możemy posłużyć się następującym wzorem rekurencyjnym:
- jeżeli jest nieparzyste, to
,
- jeżeli jest parzyste, to
.
Wzór ten jest konsekwencją zachowania i : w każdym kroku maksymalizuje prawdopodobieństwo akceptacji, natomiast zachowanie zależne jest od historii wiadomości i słowa losowego.
W tym momencie wystarczą dwa spostrzeżenia. Po pierwsze, jest poszukiwanym przez nas prawdopodobieństwem zaakceptowania przez system słowa . Po drugie, jest obliczalne w pamięci wielomianowej: każde rekurencyjne wywołanie funkcji powoduje sekwencyjne rozważenie wszystkich możliwych odpowiedzi, których długość jest jednak ograniczona od góry przez . Dodatkowo przy obliczeniach na poziomie zagłębienia należy rozważyć wszystkie możliwe słowa losowe i sprawdzić ich zgodność z aktualnie rozważanym ciągiem komunikatów. Wszystkie te operacje można wykonać z użyciem komórek pamięci.
Pokazaliśmy zatem, że .

Dowód zawierania w drugą stronę odbywa się poprzez przedstawienie protokołu komunikacji dla problemu . Aby przybliżyć stosowaną w tym protokole technikę, zaprezentujemy najpierw dowód przynależności do klasy problemu będącego wersją decyzyjną problemu :
Definicja 2.9
liczba wartościowań spełniających dla formuły jest nie mniejsza niż .
W dowodzie posłużymy się techniką zwaną arytmetyzacją; formuły logiczne będziemy zastępować wielomianami w następujący sposób:
- zmienne formuły stają się zmiennymi wielomianu,
- wyrażenia typu zastępujemy przez ,
- wyrażenia typu zastępujemy przez ,
- wyrażenia typu zastępujemy przez .
Dla uproszczenia założymy na razie, że wielomiany te określone są na liczbach rzeczywistych.
Ćwiczenie 2.10
Niech będzie formułą z zmiennymi, natomiast wielomianem otrzymanych w sposób przedstawiony powyżej. Weźmy dowolne wartościowanie zmiennych formuły i podstawmy je do wielomianu (to znaczy podstawmy 0, gdy zmienna jest wartościowana na "fałsz" i 1 w przeciwnym przypadku). Pokaż, że wartość wielomianu jest równa 1, gdy wybrane wartościowanie jest wartościowaniem spełniającym dla oraz 0 w przeciwnym przypadku.
Ćwiczenie 2.11
Niech oznacza liczbę -- niekoniecznie różnych -- literałów (zmiennych i ich zaprzeczeń) w formule . Pokaż, że stopień każdej zmiennej w wielomianie jest nie większy niż .
Zdefiniujmy teraz ciąg wielomianów w następujący sposób:
- jest wielomianem otrzymanym z formuły w wyniku procesu arytmetyzacji,
- .
Zauważmy, że ilość argumentów zmniejsza się w kolejnych funkcjach, a nie posiada żadnych argumentów (czyli jest stałą). Funkcje te spełniają następującą własność:
Oznacza to, że jeżeli reprezentują pewne wartościowanie zmiennych , to wyznacza liczbę wartościwoań spełniających formułę rozpoczynających się od . Oczywistym wnioskiem z powyższego spostrzeżenia jest to, że jest liczbą wszystkich wartościowań spełniających .
Zauważmy jeszcze, że w wielomianach zachowana jest własność, mówiąca że każda zmienna występuje co najwyżej w stopniu . Ilość wyrazów występujących w tych wielomianach może być jednak wykładnicza ze względu na długość formuły; z tego powodu obliczanie tych wielomianów może być procesem czasochłonnym.
Przedstawiany protokół komunikacyjny obliczanie wielomianów zleca funkcji . Ta następnie przekazuje funkcji pewne informacje o wielomianach, na podstawie których może z dużym prawdopodobieństwem rozstrzygnąć, czy zostały "uczciwie" obliczone zgodnie z powyższą rekurencyjną procedurą, czy też próbuje oszukać .
Protokół nie operuje na liczbach rzeczywistych -- zamiast nich używamy ciała , gdzie jest liczbą pierwszą większą niż . Wielomiany określone nad takim ciałem mają wiele cech wspólnych z wielomianami nad -- w szczególności wielomian jednej zmiennej o stopniu , który nie jest stale równy 0, ma co najwyżej pierwiastków. W rezultacie dwa różne wielomiany stopnia nie większego niż mogą być równe w co najwyżej punktach.
W tym momencie jesteśmy gotowi do przedstawienia protokołu dla :
- Krok 1 (P): Znajdź liczbę pierwszą z przedziału oraz jej certyfikat pierwszości (taka liczba na pewno istnieje -- wynika to z twierdzenia Bertranda--Czebyszewa). Prześlij je jako wiadomość.
- Krok 2 (V): Sprawdź poprawność liczby , odrzuć słowo wejściowe, jeśli lub jej certyfikat są nieprawidłowe.
- Krok 3 (P): Oblicz i prześlij jako wiadomość.
- Krok 4 (V): Sprawdź, czy -- jeśli nie to odrzuć słowo wejściowe.
- Krok 5 (P): Oblicz (wielomian ze zmienną ) i prześlij jego współczynniki jako wiadomość.
- Krok 6 (V): Sprawdź, czy . Wylosuj dowolną liczbę z i prześlij ją jako wiadomość,
- Krok 7 (P): Oblicz (to też jest wielomian z jedną zmienną ) i prześlij jego współczynniki jako wiadomość.
- Krok 8 (V): Sprawdź, czy . Wylosuj dowolną liczbę z i prześlij ją jako wiadomość.
- Krok (V): Sprawdź, czy . Sprawdź, czy jest wielomianem otrzymanym przez arytmetyzację formuły i podstawienie jako pierwszych argumentów otrzymanego wielomianu. Jeżeli tak, to zaakceptuj słowo wejściowe, w przeciwnym przypadku odrzuć je.
W przypadku, gdy słowo wejściowe należy do , jest jasne, że funkcja , postępująca zgodnie z powyższym protokołem, zawsze przekona o tej przynależności. Popatrzmy teraz, co się stanie, gdy słowo wejściowe nie należy do ; w tym przypadku wartość podana przez będzie musiała się różnić od wartości prawdziwej (oznaczmy ją jako ). W związku z tym przynajmniej jedna z wartości lub będzie różna od oczekiwanej -- lub -- a co za tym idzie wielomian będzie różny od . Pokażemy teraz fakt będący sednem naszego dowodu: jeżeli wielomian jest różny od wielomianu , to z dużym prawdopodobieństwem również będzie różny od . Zauważmy, że jesli zostanie wylosowane w taki sposób, że , to w kolejnym kroku będzie mógł zwrócić wielomian -- a zatem skutecznie oszuka . Aby tak się jednak stało wylosowana wartość musi być jednym z punktów, w których i są równe. Prawdopodobieństwo takiego zdarzenia to co najwyżej . Jeżeli , to niewątpliwie lub -- a co za tym idzie wielomian będzie różny od wielomianu .
Widzimy więc, że prawdopodobieństwo zdarzenia, w którym jest równy jest ograniczone od góry przez wyrażenie , co z kolei jest nie większe niż . jest w stanie wykryć niezgodność tych wielomianów w czasie wielomianowym w sposób deterministyczny -- a zatem jest górnym ograniczeniem na prawdopodobieństwo zaakceptowania przez słowa spoza .
W tym momencie wystarczy już tylko zauważyć, że jest mniejsze od dla każdego ; protokół będziemy zatem stosować dla formuł o co najmniej 8 literałach. Pozostałe mogą zostać stablicowane przez i rozstrzygane w czasie stałym, bez angażowania .
Powyższy protokół pokazuje zatem przynależność do klasy .
Powróćmy teraz do problemu . Możemy myśleć o kwantyfikatorach jako o pewnych transformacjach wykonywanych na zarytmetyzowanej formule logicznej, przedstawiając ten proces schematycznie jako:
,
gdzie , natomiast to formuła przekształcona w procesie arytmetyzacji. Operacje definiujemy następująco:
- gdy ,
- .
Możemy w tym momencie spróbować powtórzyć poprzedni dowód, to znaczy zdefiniować ciąg wielomianów tak, aby był zarytmetyzowaną formułą , a . Niestety w tym przypadku wielomiany w kolejnych krokach są mnożone, a nie dodawane -- w związku z tym stopnie zmiennych w kolejnych wielomianach mogą rosnąć eksponencjalnie; nie będziemy zatem w stanie wypisać współczynników nawet po zawężeniu do jednej zmiennej.
Aby temu zaradzić, będziemy "po drodze" przekształcać wielomiany z użyciem następującej operacji:
.
Wielomian otrzymany w wyniku takiej transformacji ma następujące cechy:
- jest liniowy ze względu na ,
- maksymalne stopnie pozostałych zmiennych pozostają takie same,
- nowy wielomian daje takie same wyniki co wyjściowy dla argumentów Boole'owskich (to znaczy dla liczb 0 i 1).
Zmodyfikowana procedura postępowania będzie wyglądała następująco:
.
Zauważmy, że nie zmienia ilości zmiennych wielomianu, natomiast operacje zmniejszają tę liczbę o 1. Liczbę transformacji oznaczymy jako -- będzie ona kwadratowo zależna od liczby zmiennych . W tym momencie możemy już zdefiniować ciąg wielomianów : będzie zarytmetyzowaną formułą , natomiast będzie otrzymywany z za pomocą odpowiedniej transformacji lub . Ze względu na stosowanie stopień każdej zmiennej w tych wielomianach jest ograniczony przez liczbę literałów w (oznaczaną ponownie jako ). Podobnie jak wcześniej, będzie szukanym przez nas wynikiem; wielomiany ponownie będą określone nad pewnym skończonym ciałem -- tym razem jednak wystarczy nam dowolna liczba pierwsza większa niż . Taką liczbę może znaleźć samodzielnie, dla uproszczenia jednak założymy, że otrzymana zostanie ona tak samo jak w protokole dla . Właściwy protokół będzie oparty na tej samej zasadzie co poprzednio: wypisze wartość , po czym będzie wypisywała pewne zawężenia wielomianów ; będzie sprawdzała, czy kolejne wielomiany nie są sprzeczne z poprzednimi (czyli również z ), a na końcu samodzielnie obliczy zawężenie wielomianu i porówna je z wielomianem otrzymanym od . Ponownie, jeśli skłamie przy podawaniu wartości , prawdopodobieństwo tego, że uda jej się to kłamstwo zamaskować, będzie nieduże. Popatrzmy teraz jak wygląda pojedynczy krok protokołu. W tym celu oznaczmy -tą transformację jako . Załóżmy bez utraty ogólności, że , natomiast -- założenie to ma na celu jedynie uproszczenie indeksowania. Podobnie jak w przypadku dysponuje współczynnikami jako wielomianu zmiennej , gdzie za pozostałe zmienne zostały podstawione pewne wylosowane uprzednio stałe. Jeżeli operacja jest kwantyfikatorem, to protokół zachowuje się praktycznie identycznie jak w poprzednim dowodzie; w tym przypadku ma do dyspozycji wielomian , losuje liczbę i prosi o przesłanie współczynników . Jeżeli wielomian nie jest prawidłowy -- czyli gdy funkcja próbuje oszukać i nie udało jej się jeszcze "zatrzeć śladów oszustwa" -- to prawdopodobieństwo, że wielomian będzie prawidłowy, wyniesie co najwyżej , czyli . Rozpatrzmy teraz przypadek, gdy . ma do dyspozycji wielomian . W pierwszej kolejności losuje pewną liczbę , po czym prosi o przesłanie współczynników wielomianu . Następnie sprawdza, czy podstawienie do pierwszego z tych wielomianów daje ten sam wynik, co podstawienie do drugiego. Ponownie argumentujemy, że jeśli wielomian był nieprawidłowy -- czyli różny od "wzorcowego" wielomianu -- to prawdopodobieństwo, że dla wylosowanej wartości zachodzi jest nie większe niż . W związku z tym wielomian będzie poprawny z prawdopodobieństwem co najwyżej równym . W następnym kroku przesyła współczynniki wielomianu . Zauważmy, że jest w stanie samodzielnie sprawdzić, czy wielomian został otrzymany z w wyniku transformacji -- transformacja ta jest przecież jednoznacznie określona. Jeżeli założymy zatem, że wielomian jest nieprawidłowy, to nieprawidłowy musi być też wielomian . Reasumując -- prawdopodobieństwo, że w kroku odpowiadającym pewnej transformacji funkcji uda się skutecznie "zatrzeć ślad" po wcześniejszym oszustwie, jest nie większe niż .
Zauważmy, że w trakcie działania protokołu losujemy liczb; jest zatem możliwe (i pewne), że w tym procesie będzie podstawiać w miejsce tej samej zmiennej różne wylosowane liczby. Dla przykładu -- powyżej wylosowaliśmy liczbę ; być może jednak już wcześniej dokonywaliśmy innej operacji na zmiennej i wylosowaliśmy inną liczbę . Widzimy zatem, że pewne wylosowane wartości zostają w tym procesie "zapomniane" i na ich miejsce losowane są nowe. Oczywiście wyniki nowych losowań powinny być niezależne od poprzednich -- inaczej mógłby osiągnąć większe prawdopodobieństwo skutecznego oszukania .
Jak zauważyliśmy wcześniej, liczba wykonywanych transformacji jest kwadratowo zależna od ; w szczególności natychmiastowe jest oszacowanie . W związku z tym prawdopodobieństwo, że zaakceptuje słowo wejściowe nienależące do jest nie większe niż , co z kolei jest nie większe niż . Ponownie zatem musi "stablicować" wyniki dla pewnej skończonej liczby formuł (w tym przypadku stablicowane muszą zostać formuły o co najwyżej 4 literałach), a dla reszty protokół będzie dawał prawidłowe wyniki z wymaganym prawdopodobieństwem.
Powyższy protokół pokazuje więc przynależność do klasy . W tym momencie wystarczy zauważyć, że klasa jest domknięta ze względu na redukcje wielomianowe; jeśli redukuje się do oraz znamy protokół rozwiązujący , to może w pierwszym kroku dokonać redukcji, po czym postępować zgodnie z protokołem dla . Korzystając z faktu, że jest problemem -zupełnym, stwierdzamy, że każdy problem z klasy zawarty jest w klasie .
Ćwiczenie 2.13
Wyjaśnij, czemu w protokole potrzebowaliśmy ciała o co najmniej elementach.