Różnica pomiędzy stronami "Testy pierwszości. Liczby pseudopierwsze Lucasa i liczby silnie pseudopierwsze Lucasa. Test BPSW" i "Protokół Diffiego-Hellmana. Szyfrowanie RSA. Podpis cyfrowy"

Z Henryk Dąbrowski
(Różnica między stronami)
Przejdź do nawigacji Przejdź do wyszukiwania
 
 
Linia 1: Linia 1:
<div style="text-align:right; font-size: 130%; font-style: italic; font-weight: bold;">11.01.2023</div>
+
<div style="text-align:right; font-size: 130%; font-style: italic; font-weight: bold;">22.11.2023</div>
  
 
__FORCETOC__
 
__FORCETOC__
Linia 5: Linia 5:
  
  
== Ciągi Lucasa ==
+
== Protokół Diffiego-Hellmana ==
  
<span style="font-size: 110%; font-weight: bold;">Definicja N1</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q1</span><br/>
Niech <math>P, Q \in \mathbb{Z} \setminus \{0\}</math> oraz <math>D = P^2 - 4 Q \neq 0</math>. Ciągi Lucasa <math>U_n = U_n (P, Q)</math> i <math>V_n = V_n (P, Q)</math> definiujemy następująco
+
Metoda ta została opracowana przez W. Diffiego i&nbsp;M. Hellmana<ref name="DiffieHellman1"/><ref name="DiffieHellman2"/> w 1976 roku. Opisana niżej procedura nie jest metodą szyfrowania i&nbsp;z&nbsp;założenia jej cel jest zupełnie inny. Umożliwia ona osobom mogącym kontaktować się ze sobą jedynie przez niezabezpieczone przed podsłuchem środki łączności ustalenie (tajnej) liczby, zwanej kluczem. Dysponując wspólną liczbą-kluczem osoby te mogą kodować i&nbsp;odczytywać wiadomości wybraną metodą szyfrowania. Przedstawimy w&nbsp;punktach procedurę postępowania wraz z&nbsp;przykładowymi danymi.
  
::<math>U_n = {\small\frac{\alpha^n - \beta^n}{\alpha - \beta}} = {\small\frac{\alpha^n - \beta^n}{\sqrt{D}}}</math>
+
::1. Agencja i&nbsp;Bolek wybierają (jawną) liczbę pierwszą <math>p = 541</math> i (jawną) liczbę <math>g = 2</math><ref name="generator1"/>
  
::<math>V_n = \alpha^n + \beta^n</math>
+
::2. Agencja ustala (tajny, znany tylko sobie) wykładnik <math>a = 2718</math>
  
gdzie liczby
+
::3. Bolek ustala (tajny, znany tylko sobie) wykładnik <math>b = 3141</math>
  
::<math>\alpha = {\small\frac{P + \sqrt{D}}{2}}</math>
+
::4. Agencja oblicza (jawną) liczbę <math>X = R_p (g^a) = 300</math> i&nbsp;wysyła ją do Bolka
  
::<math>\beta = {\small\frac{P - \sqrt{D}}{2}}</math>
+
::5. Bolek oblicza (jawną) liczbę <math>Y = R_p (g^b) = 191</math> i&nbsp;wysyła ją do Agencji
  
są pierwiastkami równania <math>x^2 - P x + Q = 0</math>.
+
::6. Agencja oblicza (tajną) liczbę <math>k_A = R_p (Y^a) = 493</math>
  
 +
::7. Bolek oblicza (tajną) liczbę <math>k_B = R_p (X^b) = 493</math>
  
 +
::8. Modulo <math>p</math> mamy
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N2</span><br/>
+
::::<math>k_A = R_p (Y^a) \equiv Y^a = [R_p (g^b)]^a \equiv (g^b)^a \equiv g^{a b} \equiv (g^a)^b \equiv [R_p (g^a)]^b = X^b \equiv R_p (X^b) = k_B \!\! \pmod{p}</math>
Zauważmy, że:
 
  
::<math>P = \alpha + \beta</math>
+
::9. Z&nbsp;definicji liczby <math>k_A, k_B \in [0, p - 1]</math>, zatem <math>0 \leqslant | k_A - k_B | \leqslant p - 1</math>. Ponieważ liczby <math>k_A, k_B</math> przystają do siebie modulo <math>p</math>, to muszą być sobie równe, czyli liczba <math>k = k_A = k_B</math> jest poszukiwanym kluczem.
  
::<math>Q = \alpha \beta</math>
 
  
::<math>\sqrt{D} = \alpha - \beta</math>
 
  
::<math>U_0 = 0</math>, <math>U_1 = 1</math>, <math>V_0 = 2</math> i <math>V_1 = P</math>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q2</span><br/>
 +
Liczby <math>a</math> i <math>b</math> mogą być losowo wybranymi liczbami dodatnimi nie większymi od <math>p</math>. Istotnie, jeżeli <math>a = k \cdot (p - 1) + r</math>, to
  
 +
::<math>g^a \equiv (g^{p - 1})^k \cdot g^r \equiv g^r \!\! \pmod{p}</math>
  
Warunek <math>P^2 - 4 Q \neq 0</math> wyklucza następujące pary <math>(P, Q)</math>
+
W naszym przykładzie możemy użyć liczb <math>a = 18</math> oraz <math>b = 441</math> otrzymując te same rezultaty. W&nbsp;praktyce ten problem nie występuje, bo gdy liczba pierwsza <math>p</math> ma co najmniej sto cyfr, to trudno wybrać jeszcze większy wykładnik.
  
::<math>(0, 0), (\pm 2, 1), (\pm 4, 4), (\pm 6, 9), (\pm 8, 16), (\pm 10, 25), (\pm 12, 36), ..., (\pm 2 n, n^2), ...</math>
 
  
  
 +
<span style="font-size: 110%; font-weight: bold;">Przykład Q3</span><br/>
 +
Zobaczmy, jak wpłynie na protokół zmiana liczby <math>g</math>. Niech <math>p = 541</math> i <math>g = 15</math>.
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N3</span><br/>
+
::{| class="wikitable plainlinks"  style="font-size: 90%; text-align: center; margin-right: auto;"
Oczywiście liczby <math>\alpha</math> i <math>\beta</math> są również pierwiastkami równania
 
 
 
::<math>x^{n + 2} - P x^{n + 1} + Q x^n = 0</math>
 
 
 
Wynika stąd, że ciągi <math>(\alpha^n)</math> i <math>(\beta^n)</math> spełniają równania rekurencyjne
 
 
 
::<math>\alpha^{n + 2} = P \alpha^{n + 1} - Q \alpha^n</math>
 
 
 
::<math>\beta^{n + 2} = P \beta^{n + 1} - Q \beta^n</math>
 
 
 
Ciągi Lucasa <math>(U_n)</math> i <math>(V_n)</math> spełniają identyczne równania rekurencyjne jak ciągi <math>(\alpha^n)</math> i <math>(\beta^n)</math>. Istotnie, odejmując i&nbsp;dodając stronami wypisane powyżej równania, otrzymujemy
 
 
 
::<math>U_{n + 2} = P U_{n + 1} - Q U_n</math>
 
 
 
::<math>V_{n + 2} = P V_{n + 1} - Q V_n</math>
 
 
 
Dlatego możemy zdefiniować ciągi Lucasa <math>(U_n)</math> i <math>(V_n)</math> w&nbsp;sposób równoważny
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Definicja N4</span><br/>
 
Niech <math>P, Q \in \mathbb{Z} \setminus \{0\}</math> oraz <math>D = P^2 - 4 Q \neq 0</math>. Ciągi Lucasa <math>(U_n)</math> i <math>(V_n)</math> określone są następującymi wzorami rekurencyjnymi
 
 
 
::<math>U_0 = 0</math>, <math>U_1 = 1</math>, <math>U_n = P U_{n - 1} - Q U_{n - 2}</math>
 
 
 
::<math>V_0 = 2</math>, <math>V_1 = P</math>, <math>V_n = P V_{n - 1} - Q V_{n - 2}</math>
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Przykład N5</span><br/>
 
Początkowe wyrazy ciągów Lucasa
 
 
 
::{| class="wikitable plainlinks"  style="font-size: 100%; text-align: left; margin-right: auto;"
 
 
|-
 
|-
! <math>\boldsymbol{n}</math> !! <math>\boldsymbol{U_n (P, Q)}</math> !! <math>\boldsymbol{V_n (P, Q)}</math>
+
! <math>\boldsymbol{a}</math> || <math>\boldsymbol{b}</math> || <math>\boldsymbol{R_p(g^a)}</math> || <math>\boldsymbol{R_p(g^b)}</math> || <math>\boldsymbol{R_p(g^{a b})}</math>
 
|-
 
|-
| &nbsp;&nbsp;<math>0</math>&nbsp;&nbsp; || <math>0</math> || <math>2</math>
+
| <math>2985</math> || <math>4683</math> || <math>411</math> || <math>129</math> || <math>1</math>
 
|-
 
|-
| &nbsp;&nbsp;<math>1</math>&nbsp;&nbsp; || <math>1</math> || <math>P</math>
+
| <math>4270</math> || <math>8998</math> || <math>312</math> || <math>214</math> || <math>15</math>
 
|-
 
|-
| &nbsp;&nbsp;<math>2</math>&nbsp;&nbsp; || <math>P</math> || <math>P^2 - 2 Q</math>
+
| <math>9749</math> || <math>3921</math> || <math>225</math> || <math>411</math> || <math>129</math>
 
|-
 
|-
| &nbsp;&nbsp;<math>3</math>&nbsp;&nbsp; || <math>P^2 - Q</math> || <math>P^3 - 3 P Q</math>
+
| <math>8993</math> || <math>6479</math> || <math>225</math> || <math>505</math> || <math>214</math>
 
|-
 
|-
| &nbsp;&nbsp;<math>4</math>&nbsp;&nbsp; || <math>P^3 - 2 P Q</math> || <math>P^4 - 4 P^2 Q + 2 Q^2</math>
+
| <math>2146</math> || <math>8663</math> || <math>312</math> || <math>352</math> || <math>225</math>
 
|-
 
|-
| &nbsp;&nbsp;<math>5</math>&nbsp;&nbsp; || <math>P^4 - 3 P^2 Q + Q^2</math> || <math>P^5 - 5 P^3 Q + 5 P Q^2</math>
+
| <math>9941</math> || <math>6182</math> || <math>352</math> || <math>505</math> || <math>312</math>
 
|-
 
|-
| &nbsp;&nbsp;<math>6</math>&nbsp;&nbsp; || <math>P^5 - 4 P^3 Q + 3 P Q^2</math> || <math>P^6 - 6 P^4 Q + 9 P^2 Q^2 - 2 Q^3</math>
+
| <math>8944</math> || <math>8120</math> || <math>214</math> || <math>225</math> || <math>352</math>
 
|-
 
|-
| &nbsp;&nbsp;<math>7</math>&nbsp;&nbsp; || <math>P^6 - 5 P^4 Q + 6 P^2 Q^2 - Q^3</math> || <math>P^7 - 7 P^5 Q + 14 P^3 Q^2 - 7 P Q^3</math>
+
| <math>2928</math> || <math>9314</math> || <math>129</math> || <math>505</math> || <math>411</math>
 
|-
 
|-
| &nbsp;&nbsp;<math>8</math>&nbsp;&nbsp; || <math>P^7 - 6 P^5 Q + 10 P^3 Q^2 - 4 P Q^3</math> || <math>P^8 - 8 P^6 Q + 20 P^4 Q^2 - 16 P^2 Q^3 + 2 Q^4</math>
+
| <math>7436</math> || <math>3172</math> || <math>225</math> || <math>312</math> || <math>505</math>
|-
 
| &nbsp;&nbsp;<math>9</math>&nbsp;&nbsp; || <math>P^8 - 7 P^6 Q + 15 P^4 Q^2 - 10 P^2 Q^3 + Q^4</math> || <math>P^9 - 9 P^7 Q + 27 P^5 Q^2 - 30 P^3 Q^3 + 9 P Q^4</math>
 
 
|}
 
|}
  
 +
Czytelnik może wybierać dowolne inne wykładniki <math>a</math> i <math>b</math>, ale innych wartości <math>R_p (g^{a b})</math> już nie uzyska. Wybór liczby <math>g = 2</math> w&nbsp;zamieszczonym powyżej opisie metody, nie był przypadkowy. Liczba <math>2</math> jest generatorem modulo <math>541</math>. Generator modulo liczba pierwsza <math>p</math>, to taka liczba <math>g</math>, że zbiór potęg
  
 +
::<math>\{ g^1, g^2, g^3, \ldots, g^{p - 1} \}</math>
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N6</span><br/>
+
rozpatrywany modulo <math>p</math> jest identyczny ze zbiorem
W PARI/GP możemy napisać prosty kod, który pozwoli obliczyć wartości wyrazów <math>U_n (P, Q)</math> i <math>V_n (P, Q)</math>
 
  
<span style="font-size: 90%; color:black;">LucasU(n, P, Q) = '''if'''( n == 0, 0, '''if'''( n == 1, 1, P*LucasU(n-1, P, Q) - Q*LucasU(n-2, P, Q) ) )</span>
+
::<math>\{ 1, 2, 3, \ldots, p - 1 \}</math>
  
<span style="font-size: 90%; color:black;">LucasV(n, P, Q) = '''if'''( n == 0, 2, '''if'''( n == 1, P, P*LucasV(n-1, P, Q) - Q*LucasV(n-2, P, Q) ) )</span>
+
Wybierając liczbę <math>g</math> tak, aby była generatorem modulo <math>p</math>, zapewniamy sobie, że w&nbsp;ostatniej kolumnie mogą pojawić się wszystkie liczby od <math>1</math> do <math>p - 1</math>. Taki wybór <math>g</math> zwiększa ilość możliwych wartości dla ustalanego klucza <math>k = R_p (g^{a b})</math>, a&nbsp;tym samym zwiększa bezpieczeństwo procedury. Zauważmy, że liczby <math>p</math> i <math>g</math> są jawne. Osoba próbująca poznać ustalony klucz <math>k</math> z&nbsp;pewnością ucieszy się, gdy sprawdzi, że niewłaściwy wybór liczby <math>g</math> zredukował ilość możliwych kluczy i&nbsp;ułatwił jej pracę.
  
 +
Każda liczba pierwsza ma generator modulo, ale znalezienie go dla dużych liczb pierwszych nie jest proste i&nbsp;może trwać bardzo długo. Pomocne w&nbsp;tej sytuacji jest następujące twierdzenie.
  
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N7</span><br/>
 
Niech <math>D = P^2 - 4 Q</math>. Wyrazy ciągów Lucasa można przedstawić w&nbsp;postaci sumy
 
  
::<math>2^{n - 1} U_n = \sum_{k = 0}^{\lfloor (n - 1) / 2 \rfloor} \binom{n}{2 k + 1} P^{n - 2 k - 1} D^k</math>
+
<span style="font-size: 110%; font-weight: bold;">Twierdzenie Q4</span><br/>
 
+
Niech <math>p = 2 q + 1</math> będzie liczbą pierwszą, gdzie <math>q \geqslant 3</math> jest również liczbą pierwszą. Jeżeli <math>g</math> jest liczbą niekwadratową modulo <math>p</math> i <math>g \not\equiv - 1 \!\! \pmod{p}</math>, to <math>g</math> jest generatorem modulo <math>p</math>.
::<math>2^{n - 1} V_n = \sum_{k = 0}^{\lfloor n / 2 \rfloor} \binom{n}{2 k} P^{n - 2 k} D^k</math>
 
  
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
Oznaczmy <math>\delta = \sqrt{D}</math>, zatem <math>2 \alpha = P + \delta</math> i <math>2 \beta = P - \delta</math>. Ze wzoru dwumianowego, mamy
+
Dowód jest na tyle prosty i&nbsp;elegancki, że postanowiliśmy go zamieścić, choć wykracza on poza omówiony wcześniej materiał. Czytelnik może ten dowód pominąć. Dowód poprzedzamy kilkoma prostymi, ale istotnymi komentarzami.
  
::<math>2^n \alpha^n = (P + \delta)^n = \sum_{j = 0}^{n} \binom{n}{j} P^{n - j} \delta^j</math>
+
'''Komentarz 1.'''
  
::<math>2^n \beta^n = (P - \delta)^n = \sum_{j = 0}^{n} \binom{n}{j} P^{n - j} (- \delta)^j</math>
+
'''Bez dowodu''' przyjmujemy fakt, że istnieje dokładnie <math>\varphi (p - 1)</math> różnych generatorów modulo <math>p</math>, gdzie <math>\varphi</math> jest funkcją Eulera<ref name="funkcjaphi1"/>. Funkcja Eulera <math>\varphi (n)</math> jest równa ilości liczb całkowitych dodatnich nie większych od <math>n</math> i&nbsp;względnie pierwszych z <math>n</math>.
  
Obliczając sumę powyższych wzorów, otrzymujemy
+
'''Komentarz 2.'''
  
::<math>2^n (\alpha^n + \beta^n) = \sum_{j = 0}^{n} \binom{n}{j} P^{n - j} (\delta^j + (- \delta)^j)</math>
+
Udowodnimy, że jeżeli <math>g</math> jest generatorem modulo <math>p</math>, to <math>g</math> jest liczbą niekwadratową modulo <math>p</math>.
  
:::::<math>\quad \: = \sum_{k = 0}^{\lfloor n / 2 \rfloor} \binom{n}{2 k} P^{n - 2 k} \cdot 2 \delta^{2 k}</math>
+
Przypuśćmy, że <math>g</math> jest liczbą kwadratową modulo <math>p</math>, zatem (zobacz J31)
  
:::::<math>\quad \: = 2 \sum_{k = 0}^{\lfloor n / 2 \rfloor} \binom{n}{2 k} P^{n - 2 k} D^k</math>
+
::<math>g^{(p - 1) / 2} \equiv 1 \!\! \pmod{p}</math>
  
gdzie <math>j = 2 k</math> i&nbsp;sumowanie przebiega od <math>k = 0</math> do <math>k = \lfloor n / 2 \rfloor</math>
+
Wynika stąd, że zbiór
  
Zatem
+
::<math>S = \{ g^1, g^2, g^3, \ldots, g^{p - 1} \}</math>
  
::<math>2^{n - 1} V_n = \sum_{k = 0}^{\lfloor n / 2 \rfloor} \binom{n}{2 k} P^{n - 2 k} D^k</math>
+
::<math>\;\;\,\, = \left\{ g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1}, g^{\tfrac{p - 1}{2}}, g^{\tfrac{p - 1}{2} + 1}, g^{\tfrac{p - 1}{2} + 2}, g^{\tfrac{p - 1}{2} + 3}, \ldots, g^{p - 3}, g^{p - 2}, g^{p - 1} \right\}</math>
  
 +
jest identyczny modulo <math>p</math> ze zbiorem
  
Obliczając różnicę tych wzorów, mamy
+
::<math>S' = \left\{ g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1}, 1, g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1} \right\}</math>
  
::<math>2^n (\alpha^n - \beta^n) = \sum_{j = 0}^{n} \binom{n}{j} P^{n - j} (\delta^j - (- \delta)^j)</math>
+
::<math>\quad \, = \left\{ 1, g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1} \right\}</math>
  
:::::<math>\quad \: = \sum_{k = 0}^{\lfloor (n - 1) / 2 \rfloor} \binom{n}{2 k + 1} P^{n - 2 k - 1} \cdot 2 \delta^{2 k + 1}</math>
+
i nie może być identyczny modulo <math>p</math> ze zbiorem <math>T = \{ 1, 2, 3, \ldots, p - 1 \}</math>, bo <math>S'</math> zawiera co najwyżej połowę elementów zbioru <math>T</math>. Uzyskana sprzeczność dowodzi, że generator musi być liczbą niekwadratową modulo <math>p</math>.
  
:::::<math>\quad \: = 2 \delta \sum_{k = 0}^{\lfloor (n - 1) / 2 \rfloor} \binom{n}{2 k + 1} P^{n - 2 k - 1} D^k</math>
+
'''Komentarz 3.'''
  
gdzie <math>j = 2 k + 1</math> i&nbsp;sumowanie przebiega od <math>k = 0</math> do <math>k = \lfloor (n - 1) / 2 \rfloor</math>
+
Ponieważ funkcja Eulera <math>\varphi (n)</math> jest równa ilości liczb całkowitych dodatnich nie większych od <math>n</math> i&nbsp;względnie pierwszych z <math>n</math>, to dla liczby pierwszej <math>p</math> mamy <math>\varphi (p) = p - 1</math>, bo wszystkie liczby <math>1, 2, 3, \ldots, p - 1</math> są względnie pierwsze z&nbsp;liczbą pierwszą <math>p</math>.
  
 +
'''Komentarz 4.'''
  
Zatem
+
Ponieważ funkcja Eulera <math>\varphi (n)</math> jest równa ilości liczb całkowitych dodatnich nie większych od <math>n</math> i&nbsp;względnie pierwszych z
 +
<math>n</math>, to dla liczby pierwszej nieparzystej <math>p</math> mamy <math>\varphi (2 p) = p - 1</math>, bo
  
::<math>2^{n - 1} \cdot {\small\frac{\alpha^n - \beta^n}{\sqrt{D}}} = 2^{n - 1} U_n = \sum_{k = 0}^{\lfloor (n - 1) / 2 \rfloor} \binom{n}{2 k + 1} P^{n - 2 k - 1} D^k</math>
+
:* wszystkie liczby parzyste <math>2, 4, 6, \ldots, 2 p - 2</math> mają z&nbsp;liczbą <math>2 p</math> wspólny dzielnik równy <math>2</math> i&nbsp;nie mogą być względnie pierwsze z&nbsp;liczbą <math>2 p</math>
 +
:* wszystkie liczby nieparzyste <math>1, 3, 5, \ldots, 2 p - 1</math> (których jest <math>p</math>) są względnie pierwsze z&nbsp;liczbą <math>2 p</math>, poza liczbą nieparzystą <math>p</math>, która nie jest względnie pierwsza z&nbsp;liczbą <math>2 p</math>
  
Co należało pokazać.<br/>
 
&#9633;
 
{{\Spoiler}}
 
  
 +
Wracając do dowodu twierdzenia Q4, zauważmy, że liczba <math>- 1</math> jest liczbą niekwadratową modulo <math>p = 2 q + 1</math>. Istotnie, obliczając symbol Jacobiego, otrzymujemy
  
 +
::<math>\left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} = (- 1)^{\tfrac{p - 1}{2}} = (- 1)^q = - 1</math>
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N8</span><br/>
+
Zauważmy też, że dla liczb pierwszych <math>p \geqslant 5</math> liczba <math>- 1</math> nie jest generatorem modulo <math>p</math>. Ponieważ <math>(- 1)^n = \pm 1</math>, to zbiór potęg
Korzystając z&nbsp;twierdzenia N7, możemy napisać proste funkcje do znajdowania postaci kolejnych wyrazów <math>U_n (P, Q)</math> i <math>V_n (P, Q)</math>
 
  
<span style="font-size: 90%; color:black;">U(n) = 2^(1 - n)*'''sum'''(k=0, '''floor'''((n-1)/2), '''binomial'''(n, 2*k+1) * P^(n-2*k-1) * (P^2-4*Q)^k)</span>
+
::<math>\{ g^1, g^2, g^3, \ldots, g^{p - 1} \}</math>
  
<span style="font-size: 90%; color:black;">V(n) = 2^(1 - n)*'''sum'''(k=0, '''floor'''(n/2), '''binomial'''(n, 2*k) * P^(n-2*k) * (P^2-4*Q)^k)</span>
+
składa się tylko z&nbsp;dwóch elementów <math>\{ - 1, 1 \}</math> i&nbsp;dla liczb pierwszych <math>p \geqslant 5</math> nie może być identyczny modulo <math>p</math> ze zbiorem <math>\{ 1, 2, 3, \ldots, p - 1 \}</math>.
  
  
 +
Ilość generatorów modulo <math>p</math> dla liczby pierwszej <math>p = 2 q + 1</math> jest równa
  
Często możemy spotkać założenie <math>P \geqslant 1</math>. Poniższe twierdzenie wyjaśnia, dlaczego tak jest.
+
::<math>\varphi (p - 1) = \varphi (2 q) = q - 1 = {\small\frac{p - 1}{2}} - 1</math>
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N9</span><br/>
+
Ponieważ istnieje <math>{\small\frac{p - 1}{2}}</math> liczb niekwadratowych modulo <math>p</math> (zobacz J30), to liczb niekwadratowych modulo <math>p</math>, różnych od <math>- 1</math>, jest <math>{\small\frac{p - 1}{2}} - 1</math>, czyli tyle samo, co generatorów modulo <math>p</math>, a&nbsp;żadna z&nbsp;pozostałych liczb (kwadratowych modulo <math>p</math>) nie może być generatorem modulo <math>p</math>. Co kończy dowód.<br/>
Jeżeli <math>(U_n)</math> i <math>(V_n)</math> są ciągami Lucasa, to
 
 
 
::<math>U_n (- P, Q) = (- 1)^{n - 1} U_n (P, Q)</math>
 
 
 
::<math>V_n (- P, Q) = (- 1)^n V_n (P, Q)</math>
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
Niech
 
 
 
::<math>\alpha = \frac{P + \sqrt{D}}{2} \qquad \qquad \;\; \beta = \frac{P - \sqrt{D}}{2}</math>
 
 
 
::<math>a = \frac{- P + \sqrt{D}}{2} \qquad \qquad b = \frac{- P - \sqrt{D}}{2}</math>
 
 
 
Liczby <math>\alpha, \beta</math> oraz <math>a, b</math> są odpowiednio pierwiastkami równań
 
 
 
::<math>x^2 - P x + Q = 0</math>
 
 
 
::<math>x^2 + P x + Q = 0</math>
 
 
 
Zatem definiują one ciągi Lucasa
 
 
 
::<math>U_n (P, Q) = \frac{\alpha^n - \beta^n}{\alpha - \beta} \qquad \qquad \;\; V_n (P, Q) = \alpha^n + \beta^n</math>
 
 
 
::<math>U_n (- P, Q) = \frac{a^n - b^n}{a - b} \qquad \qquad V_n (- P, Q) = a^n + b^n</math>
 
 
 
Zauważmy, że
 
 
 
::<math>\alpha - \beta = a - b = \sqrt{D}</math>
 
 
 
::<math>\frac{a}{\beta} = \frac{b}{\alpha} = - 1</math>
 
 
 
Łatwo znajdujemy
 
 
 
::<math>U_n (- P, Q) = \frac{a^n - b^n}{a - b} = \frac{(- \beta)^n - (- \alpha)^n}{\sqrt{D}} = (- 1)^n \cdot \frac{\beta^n - \alpha^n}{\alpha - \beta} = (- 1)^{n - 1} \cdot U_n (P, Q)</math>
 
 
 
::<math>V_n (- P, Q) = a^n + b^n = (- \beta)^n + (- \alpha)^n = (- 1)^n \cdot (\alpha^n + \beta^n) = (- 1)^n \cdot V_n (P, Q)</math>
 
 
 
Co należało pokazać.<br/>
 
 
&#9633;
 
&#9633;
 
{{\Spoiler}}
 
{{\Spoiler}}
Linia 216: Linia 147:
  
  
<span style="font-size: 110%; font-weight: bold;">Zadanie N10</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q5</span><br/>
Pokazać, że jeżeli <math>P, Q \in \mathbb{Z} \setminus \{ 0 \}</math> i <math>D = P^2 - 4 Q \neq 0</math>, to
+
Jeśli nie potrzebujemy wyliczyć najmniejszego generatora modulo <math>p = 2 q + 1</math>, to z&nbsp;twierdzenia Q4 można łatwo pokazać, że liczba <math>- 4</math> jest generatorem dla wszystkich liczb pierwszych <math>p = 2 q + 1 \geqslant 7</math>, a&nbsp;liczba <math>- 3</math> dla wszystkich liczb pierwszych <math>p = 2 q + 1 \geqslant 11</math>. Ponieważ <math>q = 2 k + 1</math>, to <math>p = 4 k + 3</math>.
  
::<math>U_n (2 P, 4 Q) = 2^{n - 1} U_n (P, Q)</math>
+
1. Pokażemy, że <math>- 4</math> jest liczbą niekwadratową modulo <math>p</math>. Liczba <math>k</math> może być postaci <math>2 j</math> lub <math>2 j + 1</math>, co daje odpowiednio <math>p = 8 j + 3</math> lub <math>p = 8 j + 7</math>. Zatem
  
::<math>V_n (2 P, 4 Q) = 2^n V_n (P, Q)</math>
+
::<math>\left( {\small\frac{- 4}{p}} \right)_{\small{\!\! J}} = \left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} \cdot \left( {\small\frac{2}{p}} \right)_{\small{\!\! J}}^{\! 2} = (- 1) \cdot (\pm 1)^2 = - 1</math>
  
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Rozwiązanie|Hide=Ukryj rozwiązanie}}
+
Zobacz twierdzenie J42 p.6.
Niech
 
  
::<math>\alpha = {\small\frac{P + \sqrt{D}}{2}} \qquad \qquad \;\; \beta = {\small\frac{P - \sqrt{D}}{2}}</math>
 
  
::<math>a = P + \sqrt{D} \qquad \qquad \;\; b = P - \sqrt{D}</math>
+
2. Pokażemy, że <math>- 3</math> jest liczbą niekwadratową modulo <math>p</math>. Liczba <math>k</math> może być postaci <math>3 j, 3 j + 1, 3 j + 2</math>, co daje odpowiednio
  
Liczby <math>\alpha, \beta</math> oraz <math>a, b</math> są odpowiednio pierwiastkami równań
+
::<math>k = 3 j \qquad \qquad \;\!\!\! p = 12 j + 3 \qquad \;\; q = 6 j + 1</math>
  
::<math>x^2 - P x + Q = 0</math>
+
::<math>k = 3 j + 1 \qquad p = 12 j + 7 \qquad \;\; q = 6 j + 3</math>
  
::<math>x^2 - 2 P x + 4 Q = 0</math>
+
::<math>k = 3 j + 2 \qquad p = 12 j + 11 \qquad q = 6 j + 5</math>
  
Zatem definiują one ciągi Lucasa
+
Pierwsza i&nbsp;druga postać liczby <math>k</math> nie jest możliwa, bo albo liczba <math>p</math>, albo liczba <math>q</math> byłyby liczbami złożonymi. Zatem
  
::<math>U_n (P, Q) = {\small\frac{\alpha^n - \beta^n}{\alpha - \beta}} \qquad \qquad \;\;\; V_n (P, Q) = \alpha^n + \beta^n</math>
+
::<math>\left( {\small\frac{- 3}{p}} \right)_{\small{\!\! J}} = \left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} \cdot \left( {\small\frac{3}{p}} \right)_{\small{\!\! J}} = (- 1) \cdot (+ 1) = - 1</math>
  
::<math>U_n (2 P, 4 Q) = {\small\frac{a^n - b^n}{a - b}} \qquad \qquad V_n (2 P, 4 Q) = a^n + b^n</math>
+
Zobacz twierdzenie J42 p.6 i&nbsp;zadanie J47.
  
Zauważmy, że
 
  
::<math>\alpha - \beta = \sqrt{D}</math>
 
  
::<math>a - b = 2 \sqrt{D}</math>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q6</span><br/>
 +
O ile w&nbsp;ogólnym przypadku liczb pierwszych <math>p</math> liczących setki cyfr znalezienie najmniejszego generatora modulo <math>p</math> może trwać godzinami, to w&nbsp;przypadku liczb pierwszych <math>p = 2 q + 1</math>, gdzie <math>q</math> jest również liczbą pierwszą, wystarczy znaleźć liczbę niekwadratową modulo <math>p</math>, a&nbsp;obliczenie symbolu Jacobiego trwa bardzo krótko, zaś wyszukanie liczb pierwszych postaci <math>p = 2 q + 1</math> też jest zaskakująco szybkie. Dlatego napisaliśmy w&nbsp;PARI/GP prosty program, który wyszukuje w&nbsp;zadanym przedziale <math>[m, n]</math> liczbę pierwszą <math>p</math> taką, że <math>p = 2 q + 1</math> i&nbsp;zwraca <math>p</math> oraz najmniejszy generator modulo <math>p</math>.
  
::<math>{\small\frac{a}{\alpha}} = {\small\frac{b}{\beta}} = 2</math>
+
Należy zwrócić uwagę, że funkcje <code>ispseudoprime()</code> i <code>randomprime()</code> sprawdzają pierwszość liczby na tym samym poziomie – wykonywany jest test Millera-Rabina. Dlatego używamy ich łącznie, co przyspiesza wyszukanie odpowiedniej liczby pierwszej. Następnie, już silniejszym testem, potwierdzamy pierwszość obydwu liczb: <math>p</math> i <math>(p - 1) / 2</math>.
  
Łatwo znajdujemy
+
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
 
+
<span style="font-size: 90%; color:black;">SafePrime(m, n) =  
::<math>U_n (2 P, 4 Q) = {\small\frac{a^n - b^n}{a - b}} = {\small\frac{(2 \alpha)^n - (2 \beta)^n}{2 \sqrt{D}}} = 2^{n - 1} \cdot {\small\frac{\alpha^n - \beta^n}{\alpha - \beta}} = 2^{n - 1} U_n (P, Q)</math>
+
  \\ zwraca wektor [p, g], gdzie p i (p-1)/2 są liczbami pierwszymi, a g jest generatorem modulo p
 
 
::<math>V_n (2 P, 4 Q) = a^n + b^n = (2 \alpha)^n + (2 \beta)^n = 2^n (\alpha^n + \beta^n) = 2^n V_n (P, Q)</math>
 
 
 
Co należało pokazać.<br/>
 
&#9633;
 
{{\Spoiler}}
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Zadanie N11</span><br/>
 
Pokazać, że jeżeli <math>Q \in \mathbb{Z} \setminus \{ 0 \}</math> oraz <math>P = 4 Q - 1</math>, to
 
 
 
::<math>U_{2 k} (P, P Q) = - (- P)^k U_{2 k} (1, Q)</math>
 
 
 
::<math>U_{2 k + 1} (P, P Q) = (- P)^k V_{2 k + 1} (1, Q)</math>
 
 
 
::<math>V_{2 k} (P, P Q) = (- P)^k V_{2 k} (1, Q)</math>
 
 
 
::<math>V_{2 k + 1} (P, P Q) = - (- P)^{k + 1} U_{2 k + 1} (1, Q)</math>
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Rozwiązanie|Hide=Ukryj rozwiązanie}}
 
Niech
 
 
 
::<math>\alpha = {\small\frac{1 + \sqrt{- P}}{2}} \qquad \qquad \beta = {\small\frac{1 - \sqrt{- P}}{2}}</math>
 
 
 
::<math>a = {\small\frac{P + \sqrt{- P}}{2}} \qquad \qquad b = {\small\frac{P - \sqrt{- P}}{2}}</math>
 
 
 
Liczby <math>\alpha, \beta</math> oraz <math>a, b</math> są odpowiednio pierwiastkami równań
 
 
 
::<math>x^2 - x + {\small\frac{P + 1}{4}} = 0</math>
 
 
 
::<math>x^2 - P x + {\small\frac{P (P + 1)}{4}} = 0</math>
 
 
 
Z założenia <math>P = 4 Q - 1</math>, zatem
 
 
 
::<math>x^2 - x + Q = 0</math>
 
 
 
::<math>x^2 - P x + P Q = 0</math>
 
 
 
Czyli definiują one ciągi Lucasa
 
 
 
::<math>U_n (1, Q) = {\small\frac{\alpha^n - \beta^n}{\alpha - \beta}} \qquad \qquad \:\:\: V_n (1, Q) = \alpha^n + \beta^n</math>
 
 
 
::<math>U_n (P, P Q) = {\small\frac{a^n - b^n}{a - b}} \qquad \qquad V_n (P, P Q) = a^n + b^n</math>
 
 
 
Zauważmy, że
 
 
 
::<math>\alpha - \beta = a - b = \sqrt{- P}</math>
 
 
 
::<math>{\small\frac{a}{\beta}} = {\small\frac{P + \sqrt{- P}}{1 - \sqrt{- P}}} = \sqrt{- P}</math>
 
 
 
::<math>{\small\frac{b}{\alpha}} = {\small\frac{P - \sqrt{- P}}{1 + \sqrt{- P}}} = - \sqrt{- P}</math>
 
 
 
 
 
Łatwo znajdujemy
 
 
 
::<math>U_{2 k} (P, P Q) = \frac{a^{2 k} - b^{2 k}}{a - b} = \frac{\left( \beta \sqrt{- P} \right)^{2 k} - \left( - \alpha \sqrt{- P} \right)^{2 k}}{\sqrt{- P}} = \frac{(- P)^k (\beta^{2 k} - \alpha^{2 k})}{\alpha - \beta} = - (- P)^k U_{2 k} (1, Q)</math>
 
 
 
 
 
::<math>U_{2 k + 1} (P, P Q) = \frac{a^{2 k + 1} - b^{2 k + 1}}{a - b} = \frac{\left( \beta \sqrt{- P} \right)^{2 k + 1} - \left( - \alpha \sqrt{- P} \right)^{2 k + 1}}{\sqrt{- P}} = (- P)^k (\beta^{2 k + 1} + \alpha^{2 k + 1}) = (- P)^k V_{2 k + 1} (1, Q)</math>
 
 
 
 
 
::<math>V_{2 k} (P, P Q) = a^{2 k} + b^{2 k} = \left( \beta \sqrt{- P} \right)^{2 k} + \left( - \alpha \sqrt{- P} \right)^{2 k} = (- P)^k (\alpha^{2 k} + \beta^{2 k}) = (- P)^k V_{2 k} (1, Q)</math>
 
 
 
 
 
::<math>V_{2 k + 1} (P, P Q) = a^{2 k + 1} + b^{2 k + 1} = \left( \beta \sqrt{- P} \right)^{2 k + 1} + \left( - \alpha \sqrt{- P} \right)^{2 k + 1} = (- P)^{k + 1} \cdot \frac{\beta^{2 k + 1} - \alpha^{2 k + 1}}{\sqrt{- P}} = - (- P)^{k + 1} U_{2 k + 1} (1, Q)</math>
 
 
 
Co należało pokazać.<br/>
 
&#9633;
 
{{\Spoiler}}
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Zadanie N12</span><br/>
 
Pokazać, że jeżeli <math>Q \in \mathbb{Z} \setminus \{ 0 \}</math> oraz <math>P = 4 Q + 1</math>, to
 
 
 
::<math>U_{2 k} (P, P Q) = P^k U_{2 k} (1, - Q)</math>
 
 
 
::<math>U_{2 k + 1} (P, P Q) = P^k V_{2 k + 1} (1, - Q)</math>
 
 
 
::<math>V_{2 k} (P, P Q) = P^k V_{2 k} (1, - Q)</math>
 
 
 
::<math>V_{2 k + 1} (P, P Q) = P^{k + 1} U_{2 k + 1} (1, - Q)</math>
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Rozwiązanie|Hide=Ukryj rozwiązanie}}
 
Niech
 
 
 
::<math>\alpha = {\small\frac{1 + \sqrt{P}}{2}} \qquad \qquad \beta = {\small\frac{1 - \sqrt{P}}{2}}</math>
 
 
 
::<math>a = {\small\frac{P + \sqrt{P}}{2}} \qquad \qquad b = {\small\frac{P - \sqrt{P}}{2}}</math>
 
 
 
Liczby <math>\alpha, \beta</math> oraz <math>a, b</math> są odpowiednio pierwiastkami równań
 
 
 
::<math>x^2 - x - {\small\frac{P - 1}{4}} = 0</math>
 
 
 
::<math>x^2 - P x + {\small\frac{P (P - 1)}{4}} = 0</math>
 
 
 
Z założenia <math>P = 4 Q + 1</math>, zatem
 
 
 
::<math>x^2 - x - Q = 0</math>
 
 
 
::<math>x^2 - P x + P Q = 0</math>
 
 
 
Czyli definiują one ciągi Lucasa
 
 
 
::<math>U_n (1, - Q) = {\small\frac{\alpha^n - \beta^n}{\alpha - \beta}} \qquad \qquad V_n (1, - Q) = \alpha^n + \beta^n</math>
 
 
 
::<math>U_n (P, P Q) = {\small\frac{a^n - b^n}{a - b}} \qquad \qquad V_n (P, P Q) = a^n + b^n</math>
 
 
 
Zauważmy, że
 
 
 
::<math>\alpha - \beta = a - b = \sqrt{P}</math>
 
 
 
::<math>{\small\frac{a}{\alpha}} = {\small\frac{P + \sqrt{P}}{1 + \sqrt{P}}} = \sqrt{P}</math>
 
 
 
::<math>{\small\frac{b}{\beta}} = {\small\frac{P - \sqrt{P}}{1 - \sqrt{P}}} = - \sqrt{P}</math>
 
 
 
 
 
Łatwo znajdujemy
 
 
 
::<math>U_{2 k} (P, P Q) = \frac{a^{2 k} - b^{2 k}}{a - b} = \frac{\left( \alpha \sqrt{P} \right)^{2 k} - \left( - \beta \sqrt{P} \right)^{2 k}}{\sqrt{P}} = \frac{P^k (\alpha^{2 k} - \beta^{2 k})}{\alpha - \beta} = P^k U_{2 k} (1, - Q)</math>
 
 
 
 
 
::<math>U_{2 k + 1} (P, P Q) = \frac{a^{2 k + 1} - b^{2 k + 1}}{a - b} = \frac{\left( \alpha \sqrt{P} \right)^{2 k + 1} - \left( - \beta \sqrt{P} \right)^{2 k + 1}}{\sqrt{P}} = P^k (\alpha^{2 k + 1} + \beta^{2 k + 1}) = P^k V_{2 k + 1} (1, - Q)</math>
 
 
 
 
 
::<math>V_{2 k} (P, P Q) = a^{2 k} + b^{2 k} = \left( \alpha \sqrt{P} \right)^{2 k} + \left( - \beta \sqrt{P} \right)^{2 k} = P^k (\alpha^{2 k} + \beta^{2 k}) = P^k V_{2 k} (1, - Q)</math>
 
 
 
 
 
::<math>V_{2 k + 1} (P, P Q) = a^{2 k + 1} + b^{2 k + 1} = \left( \alpha \sqrt{P} \right)^{2 k + 1} + \left( - \beta \sqrt{P} \right)^{2 k + 1} = P^{k + 1} \cdot \frac{\alpha^{2 k + 1} - \beta^{2 k + 1}}{\sqrt{P}} = P^{k + 1} U_{2 k + 1} (1, - Q)</math>
 
 
 
Co należało pokazać.<br/>
 
&#9633;
 
{{\Spoiler}}
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N13</span><br/>
 
Dla wyrazów ciągów Lucasa prawdziwe są wzory
 
 
 
{| class="wikitable plainlinks" style="display: inline-table; margin-left: 5px; margin-right: 50px; font-size: 100%; text-align: left;"
 
|-
 
| <math>1.</math> || <math>U_{m + n} = U_m U_{n + 1} - Q U_{m - 1} U_n</math> ||
 
|-
 
| <math>2.</math> || <math>V_{m + n} = V_m V_n - Q^n V_{m - n}</math> || <math>m \geqslant n</math>
 
|-
 
| <math>3.</math> || <math>U_{m + n} = U_m V_n - Q^n U_{m - n}</math> || <math>m \geqslant n</math>
 
|-
 
| <math>4.</math> || <math>V_{m + n} = D U_m U_n + Q^n V_{m - n}</math> || <math>m \geqslant n</math>
 
|-
 
| <math>5.</math> || <math>U_m V_n - V_m U_n = 2 Q^n U_{m - n}</math> || <math>m \geqslant n</math>
 
|-
 
| <math>6.</math> || <math>U^2_n = U_{n - 1} U_{n + 1} + Q^{n - 1}</math> ||
 
|-
 
| <math>7.</math> || <math>V^2_n = V_{n - 1} V_{n + 1} - D Q^{n - 1}</math> ||
 
|}
 
{| class="wikitable plainlinks"  style="display: inline-table; margin-left: 5px; margin-right: 50px; font-size: 100%; text-align: left;"
 
|-
 
| <math>\;\; 8.</math> || <math>2 U_{m + n} = U_m V_n + V_m U_n</math> ||
 
|-
 
| <math>\;\; 9.</math> || <math>2 V_{m + n} = V_m V_n + D U_m U_n</math> ||
 
|-
 
| <math>10.</math> || <math>V_m V_n - D U_m U_n = 2 Q^n V_{m - n}</math> || <math>m \geqslant n</math>
 
|-
 
| <math>11.</math> || <math>U_{2 n} = U_n V_n</math> ||
 
|-
 
| <math>12.</math> || <math>V_{2 n} = V^2_n - 2 Q^n</math> ||
 
|-
 
| <math>13.</math> || <math>V_{2 n} = D U^2_n + 2 Q^n</math> ||
 
|-
 
| <math>14.</math> || <math>V^2_n - D U^2_n = 4 Q^n</math> ||
 
|-
 
| <math>15.</math> || <math>D U_n = 2 V_{n + 1} - P V_n</math> ||
 
|-
 
| <math>16.</math> || <math>V_n = 2 U_{n + 1} - P U_n</math> ||
 
|-
 
| <math>17.</math> || <math>D U_n = V_{n + 1} - Q V_{n - 1}</math> || <math>n \geqslant 1</math>
 
|-
 
| <math>18.</math> || <math>V_n = U_{n + 1} - Q U_{n - 1}</math> || <math>n \geqslant 1</math>
 
|}
 
{| class="wikitable plainlinks"  style="display: inline-table; margin-left: 5px; margin-right: 50px; font-size: 100%; text-align: left;"
 
|-
 
| <math>19.</math> || <math>U_{2 n} = 2 U_n U_{n + 1} - P U^2_n</math>
 
|-
 
| <math>20.</math> || <math>U_{2 n + 1} = U^2_{n + 1} - Q U^2_n</math>
 
|-
 
| <math>21.</math> || <math>U_{2 n + 2} = P U^2_{n + 1} - 2 Q U_n U_{n + 1}</math>
 
|}
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
'''Wzory 1. - 7. najłatwiej udowodnić korzystając z&nbsp;definicji N1.'''
 
 
 
Wzór 1.
 
 
 
::<math>U_{m + n} = {\small\frac{\alpha^{m + n} - \beta^{m + n}}{\alpha - \beta}}</math>
 
 
 
:::<math>\quad \: = {\small\frac{\alpha^m - \beta^m}{\alpha - \beta}} \cdot {\small\frac{\alpha^{n + 1} - \beta^{n + 1}}{\alpha - \beta}} - \alpha \beta \cdot {\small\frac{\alpha^{m - 1} - \beta^{m - 1}}{\alpha - \beta}} \cdot {\small\frac{\alpha^n - \beta^n}{\alpha - \beta}}</math>
 
 
 
:::<math>\quad \: = U_m U_{n + 1} - Q U_{m - 1} U_n</math>
 
 
 
 
 
Wzór 2.
 
 
 
::<math>V_{m + n} = \alpha^{m + n} + \beta^{m + n}</math>
 
 
 
:::<math>\quad \;\! = (\alpha^m + \beta^m) (\alpha^n + \beta^n) - \alpha^n \beta^n \cdot (\alpha^{m - n} + \beta^{m - n})</math>
 
 
 
:::<math>\quad \;\! = V_m V_n - Q^n V_{m - n}</math>
 
 
 
 
 
Wzór 3.
 
 
 
::<math>U_{m + n} = {\small\frac{\alpha^{m + n} - \beta^{m + n}}{\alpha - \beta}}</math>
 
 
 
:::<math>\quad \: = {\small\frac{(\alpha^m - \beta^m) (\alpha^n + \beta^n)}{\alpha - \beta}} - {\small\frac{\alpha^n \beta^n \cdot (\alpha^{m - n} - \beta^{m - n})}{\alpha - \beta}}</math>
 
 
 
:::<math>\quad \: = U_m V_n - Q^n U_{m - n}</math>
 
 
 
 
 
Wzór 4.
 
 
 
::<math>V_{m + n} = \alpha^{m + n} + \beta^{m + n}</math>
 
 
 
:::<math>\quad \;\! = (\alpha - \beta)^2 \cdot {\small\frac{\alpha^m - \beta^m}{\alpha - \beta}} \cdot {\small\frac{\alpha^n - \beta^n}{\alpha - \beta}} + \alpha^n \beta^n \cdot (\alpha^{m - n} + \beta^{m - n})</math>
 
 
 
:::<math>\quad \;\! = D U_m U_n + Q^n V_{m - n}</math>
 
 
 
 
 
Wzór 5.
 
 
 
::<math>U_m V_n - V_m U_n = {\small\frac{\alpha^m - \beta^m}{\alpha - \beta}} \cdot (\alpha^n + \beta^n) - (\alpha^m + \beta^m) \cdot {\small\frac{\alpha^n - \beta^n}{\alpha - \beta}}</math>
 
 
 
::::::<math>\;\;\: = 2 \cdot \alpha^n \beta^n \cdot {\small\frac{\alpha^{m - n} - \beta^{m - n}}{\alpha - \beta}}</math>
 
 
 
::::::<math>\;\;\: = 2 Q^n U_{m - n}</math>
 
 
 
 
 
Wzór 6.
 
 
 
::<math>U^2_n = \left( {\small\frac{\alpha^n - \beta^n}{\alpha - \beta}} \right)^2</math>
 
 
 
:::<math>\;\! = {\small\frac{\alpha^{n - 1} - \beta^{n - 1}}{\alpha - \beta}} \cdot {\small\frac{\alpha^{n + 1} - \beta^{n + 1}}{\alpha - \beta}} + \alpha^{n - 1} \beta^{n - 1}</math>
 
 
 
:::<math>\;\! = U_{n - 1} U_{n + 1} + Q^{n - 1}</math>
 
 
 
 
 
Wzór 7.
 
 
 
::<math>V^2_n = (\alpha^n + \beta^n)^2</math>
 
 
 
:::<math>\;\! = (\alpha^{n - 1} + \beta^{n - 1}) (\alpha^{n + 1} + \beta^{n + 1}) - (\alpha - \beta)^2 \cdot \alpha^{n - 1} \beta^{n - 1}</math>
 
 
 
:::<math>\;\! = V_{n - 1} V_{n + 1} - D Q^{n - 1}</math>
 
 
 
 
 
'''Wzory 8. - 18. można łatwo udowodnić, korzystając ze wzorów 1. - 7.'''
 
 
 
Wzór 8. Policzyć sumę wzoru 3. pomnożonego przez <math>2</math> i&nbsp;wzoru 5.
 
 
 
Wzór 9. Policzyć sumę wzorów 2. i 4.
 
 
 
Wzór 10. Połączyć wzory 2. i 4.
 
 
 
Wzór 11. We wzorze 3. położyć <math>m = n</math>.
 
 
 
Wzór 12. We wzorze 2. położyć <math>m = n</math>.
 
 
 
Wzór 13. We wzorze 4. położyć <math>m = n</math>.
 
 
 
Wzór 14. We wzorze 10. położyć <math>m = n</math> lub połączyć wzory 12. i 13.
 
 
 
Wzór 15. We wzorze 9. położyć <math>m = 1</math>.
 
 
 
Wzór 16. We wzorze 8. położyć <math>m = 1</math>.
 
 
 
Wzór 17. We wzorze 15. położyć <math>V_{n + 1} = P V_n - Q V_{n - 1}</math>.
 
 
 
Wzór 18. We wzorze 16. położyć <math>U_{n + 1} = P U_n - Q U_{n - 1}</math>.
 
 
 
 
 
'''Wzory 19. - 21. to wzory, które wykorzystamy w&nbsp;przyszłości do szybkiego obliczania wartości wyrazów <math>U_n</math> i <math>V_n</math> modulo.'''
 
 
 
Wzór 19. Wystarczy połączyć wzory 11. oraz 16.
 
 
 
Wzór 20. Wystarczy we wzorze 1. położyć <math>m = n + 1</math>.
 
 
 
Wzór 21. Kładąc we wzorze 19. <math>n \rightarrow n + 1</math>, otrzymujemy
 
 
 
::<math>U_{2 n + 2} = 2 U_{n + 1} U_{n + 2} - P U^2_{n + 1} \qquad (*)</math>
 
 
 
Kładąc we wzorze 1. <math>m = n + 2</math>, mamy
 
 
 
::<math>U_{2 n + 2} = U_{n + 2} U_{n + 1} - Q U_{n + 1} U_n</math>
 
 
 
Czyli
 
 
 
::<math>2 U_{2 n + 2} = 2 U_{n + 1} U_{n + 2} - 2 Q U_n U_{n + 1}</math>
 
 
 
Odejmując od powyższego wzoru wzór <math>(*)</math>, dostajemy wzór 21.
 
 
 
::<math>U_{2 n + 2} = P U^2_{n + 1} - 2 Q U_n U_{n + 1}</math>
 
 
 
Co należało pokazać.<br/>
 
&#9633;
 
{{\Spoiler}}
 
 
 
 
 
 
 
 
 
 
 
== Obliczanie wyrazów ciągu Lucasa modulo <math>m</math> ==
 
 
 
<span style="font-size: 110%; font-weight: bold;">Przykład N14</span><br/>
 
Pokażemy, jak wykorzystać podane w&nbsp;twierdzeniu N13 wzory 19, 20, 21 i 16
 
 
 
::<math>U_{2 n} = 2 U_n U_{n + 1} - P U^2_n</math>
 
 
 
::<math>U_{2 n + 1} = U^2_{n + 1} - Q U^2_n</math>
 
 
 
::<math>U_{2 n + 2} = P U^2_{n + 1} - 2 Q U_n U_{n + 1}</math>
 
 
 
::<math>V_n = 2 U_{n + 1} - P U_n</math>
 
 
 
do szybkiego obliczania wyrazów ciągu Lucasa modulo <math>m</math>.
 
 
 
 
 
Niech <math>P = 3</math>, <math>Q = 1</math>, <math>D = P^2 - 4 Q = 5</math>, <math>n = 22 = (10110)_2 = \sum_{j = 0}^{4} a_j \cdot 2^j</math>.
 
 
 
W tabeli przedstawione kolejne kroki, jakie musimy wykonać, aby policzyć <math>U_n = U_{22}</math> modulo <math>m = 23</math>.
 
 
 
::{| class="wikitable plainlinks"  style="font-size: 100%; text-align: center; margin-right: auto;"
 
|-
 
! <math>\boldsymbol{j}</math> !! <math>\boldsymbol{a_j}</math> !! <math>\boldsymbol{k_j}</math> !! <math>\boldsymbol{U_{k_j}}</math> !! <math>\boldsymbol{U_{k_j + 1}}</math>
 
|-
 
| <math>4</math> || <math>1</math> || <math>(1)_2 = 1</math> || <math>U_1 = 1</math> || <math>U_2 = P = 3</math>
 
|-
 
| <math>3</math> || <math>0</math> || <math>(10)_2 = 2</math> || <math>U_2 = 2 U_1 U_2 - 3 U^2_1 = 6 - 3 = 3</math> || <math>U_3 = U^2_2 - 1 = 8</math>
 
|-
 
| <math>2</math> || <math>1</math> || <math>(101)_2 = 5</math> || <math>U_5 = U^2_3 - U^2_2 = 64 - 9 = 55 \equiv 9</math> || <math>U_6 = 3 U_3^2 - 2 U_2 U_3 = 192 - 48 = 144 \equiv 6</math>
 
|-
 
| <math>1</math> || <math>1</math> || <math>(1011)_2 = 11</math> || <math>U_{11} = U^2_6 - U^2_5 \equiv 36 - 81 \equiv - 45 \equiv 1</math> || <math>U_{12} = 3 U_6^2 - 2 U_5 U_6 \equiv 108 - 108 \equiv 0</math>
 
|-
 
| <math>0</math> || <math>0</math> || <math>(10110)_2 = 22</math> || <math>U_{22} = 2 U_{11} U_{12} - 3 U^2_{11} \equiv 0 - 3 \equiv 20</math> || <math>U_{23} = U^2_{12} - U^2_{11} \equiv 0 - 1 \equiv 22</math>
 
|}
 
 
 
W kolumnie <math>a_j</math> wypisujemy kolejne cyfry liczby <math>n = 22 = (10110)_2</math> zapisanej w&nbsp;układzie dwójkowym. Liczby w&nbsp;kolumnie <math>k_j</math> tworzymy, biorąc kolejne (od prawej do lewej) cyfry liczby <math>n</math> w&nbsp;zapisie dwójkowym. Postępując w&nbsp;ten sposób, w&nbsp;ostatnim wierszu mamy <math>k_j = n</math> i&nbsp;wyliczamy liczby <math>U_n</math> i <math>U_{n + 1}</math> modulo <math>m</math>.
 
 
 
Dla uproszczenia zapisu i&nbsp;ułatwienia zrozumienia liczbę <math>k_j</math> oznaczymy jako <math>r</math>, a <math>k_{j + 1}</math> jako <math>s</math>. Zauważmy, że
 
 
 
:* tabela jest zbudowana tak, że musimy znaleźć wyrazy ciągu Lucasa o&nbsp;indeksie <math>r = k_j</math> oraz o&nbsp;indeksie o&nbsp;jeden większym: <math>r + 1 = k_j + 1</math>
 
:* przejście do następnego wiersza (w dół) oznacza, że musimy znaleźć wyrazy o&nbsp;indeksie <math>s = k_{j + 1}</math> oraz o&nbsp;indeksie o&nbsp;jeden większym: <math>s + 1</math>
 
:* przechodząc do następnego wiersza, dotychczasowa liczba <math>r = k_j</math> powiększa się o&nbsp;kolejną cyfrę ( <math>0</math> lub <math>1</math> ), którą dopisujemy z&nbsp;prawej strony
 
:* dodanie na końcu liczby <math>r = k_j</math> zera podwaja liczbę <math>r</math>, czyli <math>s = k_{j + 1} = 2 r</math> oraz <math>s + 1 = 2 r + 1</math>
 
:* dodanie na końcu liczby <math>r = k_j</math> jedynki podwaja liczbę <math>r</math> i&nbsp;zwiększą ją o&nbsp;jeden, czyli <math>s = k_{j + 1} = 2 r + 1</math> oraz <math>s + 1 = 2 r + 2</math>
 
 
 
 
 
Dlatego, jeżeli kolejną dodaną cyfrą jest zero, to korzystamy ze wzorów
 
 
 
::<math>U_s = U_{2 r} = 2 U_r U_{r + 1} - P U^2_r</math>
 
 
 
::<math>U_{s + 1} = U_{2 r + 1} = U^2_{r + 1} - Q U^2_r</math>
 
 
 
Gdy kolejną dodaną cyfrą jest jeden, to stosujemy wzory
 
 
 
::<math>U_s = U_{2 r + 1} = U^2_{r + 1} - Q U^2_r</math>
 
 
 
::<math>U_{s + 1} = U_{2 r + 2} = P U^2_{r + 1} - 2 Q U_r U_{r + 1}</math>
 
 
 
 
 
Korzystając ze wzoru <math>V_n = 2 U_{n + 1} - P U_n</math>, mamy
 
 
 
::<math>V_{22} = 2 U_{23} - 3 U_{22} \equiv 44 - 60 \equiv - 16 \equiv 7 \pmod{23}</math>
 
 
 
Ostatecznie otrzymujemy
 
 
 
::<math>U_{22} \equiv 20 \pmod{23} \quad</math> oraz <math>\quad V_{22} \equiv 7 \pmod{23}</math>
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Uwaga N15</span><br/>
 
Uogólniając postępowanie przedstawione w&nbsp;przykładzie N14, możemy napisać program w&nbsp;PARI/GP do szybkiego obliczania wyrazów ciągu Lucasa <math>U_n (P, Q)</math> i <math>V_n (P, Q)</math> modulo <math>m</math>.
 
 
 
<span style="font-size: 90%; color:black;">modLucas(n, P, Q, m) =
 
 
  {
 
  {
  '''local'''(A, i, s, U,&#32;U2, V, W,&#32;W2);
+
  '''local'''(g, p);
  '''if'''( m == 1, '''return'''([0, 0]) );
+
  '''setrand'''('''getwalltime'''()); \\ ustawiamy ziarno (ang. seed) generatora liczb losowych
  '''if'''( n == 0, '''return'''([0, 2 % m]) );
+
  '''while'''( 1,
A = '''digits'''(n, 2); \\ otrzymujemy wektor cyfr liczby n w układzie dwójkowym
+
        p = 9;
s = '''length'''(A); \\ długość wektora A
+
        '''while'''( !'''ispseudoprime'''( (p - 1)/2 ), p = '''randomprime'''([m, n]) );
U = 1;
+
        '''if'''( '''isprime'''(p) && '''isprime'''( (p-1)/2 ), '''break'''() );
W = P;
 
i = 1;
 
'''while'''( i++ <= s,
 
        '''if'''( A[i] == 0,  U2 = 2*U*W - P*U^2;  W2 = W^2 - Q*U^2 );
 
        '''if'''( A[i] == 1,  U2 = W^2 - Q*U^2;  W2 = P*W^2 - 2*Q*U*W );
 
        U = U2 % m;
 
        W = W2 % m;
 
 
       );
 
       );
  V = (2*W - P*U) % m;
+
  g = 2;
  '''return'''([U, V]);
+
'''while'''( jacobi(g, p) > -1, g++ );
 +
  '''return'''([p, g]);
 
  }</span>
 
  }</span>
 +
<br/>
 +
{{\Spoiler}}
  
  
  
 +
<span style="font-size: 110%; font-weight: bold;">Uwaga Q7</span><br/>
 +
Jak dalece bezpieczna jest opisana wyżej metoda? Aby znaleźć klucz trzeba oprócz (jawnych) liczb <math>p, g, X, Y</math> znać jedną z&nbsp;liczb <math>a</math> lub <math>b</math>. Liczba <math>a</math> spełnia kongruencję
  
 +
::<math>g^a \equiv X \!\! \pmod{p}</math>
  
== Podzielność wyrazów <math>U_n (P, Q)</math> przez liczbę pierwszą nieparzystą ==
+
ale nie istnieje żadna metoda szybkiego znalezienia wykładnika <math>a</math>. Oczywiście zawsze pozostaje możliwość kolejnego wyliczania <math>g^n</math> modulo <math>p</math> z&nbsp;nadzieją trafienia na <math>X</math> lub <math>Y</math>. Dla naszych danych mielibyśmy modulo <math>541</math>
 
 
<span style="font-size: 110%; font-weight: bold;">Uwaga N16</span><br/>
 
Niech <math>p</math> będzie liczbą pierwszą nieparzystą. W&nbsp;przypadku, gdy <math>p \nmid P Q</math> nie możemy nic powiedzieć o&nbsp;podzielności wyrazów <math>U_n</math> przez <math>p</math>. Przykładowo, jeżeli <math>P \equiv 1 \pmod{p} \;</math> <math>\text{i} \;\; Q \equiv 1 \pmod{p}</math>, to modulo <math>p</math>, mamy
 
 
 
::<math>(U_n) \equiv (0, 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, \ldots)</math>
 
 
 
W przypadku, gdy <math>P \equiv 2 \pmod{p} \;</math> <math>\text{i} \;\; Q \equiv 1 \pmod{p}</math>, to modulo <math>p</math> mamy
 
 
 
::<math>(U_n) \equiv (0, 1, 2, \ldots, p - 1, 0, 1, 2, \ldots, p - 1, 0, 1, 2, \ldots, p - 1, \ldots)</math>
 
 
 
Sytuacja wygląda inaczej, gdy <math>p \mid P Q</math>.
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N17</span><br/>
 
Niech <math>p</math> będzie liczbą pierwszą nieparzystą.
 
 
 
::{| border="0"
 
|-style=height:1.9em
 
| &#9679;&nbsp;&nbsp;&nbsp; jeżeli <math>\; p \mid P \;</math> <math>\text{i} \;\; p \mid Q , \;</math> to <math>\; p \mid U_n \;</math> dla <math>n \geqslant 2</math>
 
|-style=height:1.9em
 
| &#9679;&nbsp;&nbsp;&nbsp; jeżeli <math>\; p \mid P \;</math> <math>\text{i} \;\; p \nmid Q , \;</math> to <math>\; p \mid U_{2 n} \;</math> i <math>\; p \nmid U_{2 n + 1}</math>
 
|-style=height:1.9em
 
| &#9679;&nbsp;&nbsp;&nbsp; jeżeli <math>\; p \nmid P \;</math> <math>\text{i} \;\; p \mid Q , \;</math> to <math>\; p \nmid U_n \;</math> dla <math>n \geqslant 1</math>
 
|-style=height:1.9em
 
| &#9679;&nbsp;&nbsp;&nbsp; jeżeli <math>\; p \mid Q , \;</math> to <math>\; p \mid U_n</math>, gdzie <math>n \geqslant 2</math>, wtedy i&nbsp;tylko wtedy, gdy <math>\; p \mid P</math>
 
|-style=height:1.9em
 
| &#9679;&nbsp;&nbsp;&nbsp; jeżeli <math>\; p \nmid P \;</math> <math>\text{i} \;\; p \mid D , \;</math> to <math>\; p \mid U_n \;</math> wtedy i&nbsp;tylko wtedy, gdy <math>p \mid n</math>
 
|}
 
 
 
Założenie, że <math>p \nmid P</math> w&nbsp;ostatnim punkcie jest istotne. Gdy <math>\; p \mid P \;</math> i <math>\; p \mid D , \;</math> to <math>\; p \mid Q \;</math> i&nbsp;otrzymujemy punkt pierwszy.
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
'''Punkt 1.'''
 
 
 
Ponieważ <math>U_2 = P</math>, zatem <math>p \mid U_2</math>. Dla <math>n \geqslant 3</math> wyrażenie <math>U_n = P U_{n - 1} - Q U_{n - 2}</math> jest podzielne przez <math>p</math>.
 
 
 
'''Punkt 2.'''
 
 
 
Indeksy parzyste. Indukcja matematyczna. Mamy <math>U_0 = 0</math> i <math>U_2 = P</math>, zatem <math>p \mid U_0</math> i <math>p \mid U_2</math>. Zakładając, że <math>p \mid U_{2 n}</math>, z definicji ciągu <math>(U_k)</math>, otrzymujemy dla <math>U_{2 n + 2}</math>
 
 
 
::<math>U_{2 n + 2} = P U_{2 n - 1} - Q U_{2 n}</math>
 
 
 
Z założenia indukcyjnego wynika, że <math>p \mid U_{2 n + 2}</math>, zatem na mocy zasady indukcji matematycznej twierdzenie jest prawdziwe dla wszystkich <math>n \geqslant 0</math>.
 
 
 
Indeksy nieparzyste. Indukcja matematyczna. Mamy <math>U_1 = 1</math> i <math>U_3 = P^2 - Q</math>, zatem <math>p \nmid U_1</math> i <math>p \nmid U_3</math>. Zakładając, że <math>p \nmid U_{2 n - 1}</math>, z definicji ciągu <math>(U_k)</math>, otrzymujemy dla <math>U_{2 n + 1}</math>
 
 
 
::<math>U_{2 n + 1} = P U_{2 n} - Q U_{2 n - 1}</math>
 
  
Z założenia indukcyjnego wynika, że <math>p \nmid U_{2 n + 1}</math>, zatem na mocy zasady indukcji matematycznej twierdzenie jest prawdziwe dla wszystkich <math>n \geqslant 1</math>.
+
::<math>2^1 \equiv 2, \quad 2^2 \equiv 4, \; \ldots , \; 2^{17} \equiv 150, \quad 2^{18} \equiv 300</math>
  
'''Punkt 3.'''
+
czyli wystarczyło jedynie 18 prób! Ale dla dwustucyfrowej liczby pierwszej <math>p</math> i&nbsp;trochę lepiej wybranych liczb <math>a</math> i <math>b</math> ilość prób będzie liczbą rzędu <math>10^{50}</math>. Nawet dla najszybszych komputerów stanowi to barierę nie do pokonania.
  
Indukcja matematyczna. Mamy <math>U_1 = 1</math> i <math>U_2 = P</math>, zatem <math>p \nmid U_1</math> i <math>p \nmid U_2</math>. Zakładając, że <math>p \nmid U_n</math> zachodzi dla wszystkich liczb całkowitych dodatnich nie większych od <math>n</math>, z&nbsp;definicji ciągu <math>(U_n)</math>
 
otrzymujemy dla <math>n + 1</math>
 
  
::<math>U_{n + 1} = P U_n - Q U_{n - 1}</math>
 
  
Z założenia indukcyjnego wynika, że <math>p \nmid U_{n + 1}</math>, zatem na mocy zasady indukcji matematycznej twierdzenie jest prawdziwe dla wszystkich liczb <math>n \geqslant 1</math>.
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q8</span><br/>
 +
Realne zagrożenie pojawia się jedynie wtedy, gdy Agencja i&nbsp;Bolek nie sprawdzą autentyczności liczb <math>X</math> i <math>Y</math>. Przykładowo Agencja może zapytać o <math>7</math>, <math>23</math>, <math>101</math> itd. cyfrę liczby <math>X</math>, którą otrzymał Bolek. Dlaczego jest to ważne? Jeżeli korespondencja (maile, listy) Agencji i&nbsp;Bolka jest kontrolowana przez Wywiad, to Wywiad może przechwycić liczby <math>X = R_p (g^a)</math> oraz <math>Y = R_p (g^b)</math> i&nbsp;wysłać im swoją liczbę <math>Z = R_p (g^c)</math>. Od tej pory korespondencja Agencji będzie przechwytywana, odszyfrowywana przez Wywiad kluczem <math>k_1 = R_p (g^{a c})</math>, czytana, ewentualnie zmieniana, ponownie szyfrowana kluczem <math>k_2 = R_p (g^{b c})</math> i&nbsp;wysyłana do Bolka.
  
'''Punkt 4.'''
+
Analogicznie będzie kontrolowana korespondencja Bolka wysyłana do Agencji.
  
Wynika z&nbsp;punktów pierwszego i&nbsp;trzeciego.
 
  
'''Punkt 5.'''
 
  
Z twierdzenia N7 wiemy, że
 
  
::<math>2^{n - 1} U_n = \sum_{k = 0}^{\lfloor (n - 1) / 2 \rfloor} \binom{n}{2 k + 1} P^{n - 2 k - 1} D^k</math>
 
  
::::<math>\;\; = n P^{n - 1} + \binom{n}{3} P^{n - 3} D + \binom{n}{5} P^{n - 5} D^2 + \ldots +
+
== Szyfrowanie RSA ==
\begin{cases}
 
n P D^{(n - 2) / 2} & \text{gdy }n\text{ jest parzyste} \\
 
D^{(n - 1) / 2} & \text{gdy }n\text{ jest nieparzyste} \\
 
\end{cases}</math>
 
  
Z założenia <math>p \mid D</math>, zatem modulo <math>p</math> dostajemy
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q9</span><br/>
 +
Rozpoczniemy od dowodu kilku prostych twierdzeń. Łatwość ich sformułowania i&nbsp;dowodu zaskakuje, jeśli weźmiemy pod uwagę fakt, że stanowią one podstawę niezwykle ważnej metody szyfrowania.
  
::<math>2^{n - 1} U_n \equiv n P^{n - 1} \pmod{p}</math>
 
  
Ponieważ <math>p \nmid P</math>, zatem <math>p \mid U_n</math> wtedy i&nbsp;tylko wtedy, gdy <math>p \mid n</math>.
 
Co należało pokazać.<br/>
 
&#9633;
 
{{\Spoiler}}
 
  
 +
<span style="font-size: 110%; font-weight: bold;">Twierdzenie Q10</span><br/>
 +
Jeżeli <math>p</math> jest liczbą pierwszą, to dla dowolnego <math>a \in \mathbb{Z}</math> i&nbsp;każdego <math>k \geqslant 0</math> jest
  
 
+
::<math>a^{(p - 1) k + 1} \equiv a \!\! \pmod{p}</math>
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N18</span><br/>
 
Jeżeli <math>d</math> jest nieparzystym dzielnikiem <math>Q</math>, to dla <math>n \geqslant 2</math> jest
 
 
 
::<math>U_n \equiv P^{n - 1} \pmod{d}</math>
 
 
 
W szczególności, gdy liczba pierwsza nieparzysta <math>p</math> jest dzielnikiem <math>Q</math> i <math>p \nmid P</math>, to
 
 
 
::<math>U_p \equiv 1 \pmod{p}</math>
 
  
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
Oznaczmy <math>\delta = \sqrt{D}</math>, zatem <math>2 \alpha = P + \delta</math> i <math>2 \beta = P - \delta</math>. Ze wzoru dwumianowego, mamy
+
Jeżeli <math>p \mid a</math>, to dowodzona kongruencja jest prawdziwa. Jeżeli <math>p \nmid a</math>, to modulo <math>p</math> mamy
 
 
::<math>2^n \alpha^n = (P + \delta)^n = \sum_{j = 0}^{n} \binom{n}{j} P^{n - j} \delta^j</math>
 
 
 
::<math>2^n \beta^n = (P - \delta)^n = \sum_{j = 0}^{n} \binom{n}{j} P^{n - j} (- \delta)^j</math>
 
 
 
 
 
Obliczając różnicę wyjściowych wzorów, mamy
 
 
 
::<math>2^n (\alpha^n - \beta^n) = \sum_{j = 0}^{n} \binom{n}{j} P^{n - j} (\delta^j - (- \delta)^j) =</math>
 
 
 
:::::<math>\quad \: = \underset{j \; \text{nieparzyste}}{\sum_{j = 1}^{n}} \binom{n}{j} P^{n - j} \cdot 2 \delta^j</math>
 
 
 
:::::<math>\quad \: = 2 \underset{j \; \text{nieparzyste}}{\sum_{j = 1}^{n}} \binom{n}{j} P^{n - j} \cdot \delta \cdot D^{(j - 1) / 2}</math>
 
 
 
Rozpatrując powyższą równość modulo <math>Q</math> dostajemy (zobacz N43)
 
 
 
::<math>2^{n - 1} \cdot {\small\frac{\alpha^n - \beta^n}{\delta}} = 2^{n - 1} U_n \equiv \underset{j \; \text{nieparzyste}}{\sum_{j = 1}^{n}} \binom{n}{j} P^{n - j} \cdot P^{j - 1}</math>
 
 
 
:::::::::<math>\;\:\: \equiv P^{n - 1} \underset{j \; \text{nieparzyste}}{\sum_{j = 1}^{n}} \binom{n}{j}</math>
 
 
 
:::::::::<math>\;\:\: \equiv 2^{n - 1} P^{n - 1}</math>
 
 
 
Czyli
 
 
 
::<math>2^{n - 1} (U_n - P^{n - 1}) \equiv 0 \pmod{Q}</math>
 
 
 
Ponieważ <math>Q</math> dzieli <math>2^{n - 1} (U_n - P^{n - 1})</math>, to tym bardziej <math>d</math> dzieli <math>2^{n - 1} (U_n - P^{n - 1})</math>. Z założenia <math>\gcd (d, 2^{n - 1}) = 1</math>, zatem <math>d</math> dzieli <math>U_n - P^{n - 1}</math> (zobacz C74).
 
 
 
W przypadku szczególnym, gdy <math>d = p</math>, gdzie <math>p</math> jest nieparzystą liczbą pierwszą i <math>p \nmid P</math>, z&nbsp;twierdzenia Fermata otrzymujemy natychmiast
 
  
::<math>U_p \equiv P^{p - 1} \equiv 1 \pmod{p}</math>
+
::<math>a^{(p - 1) k + 1} = a \cdot (a^{p - 1})^k \equiv a \!\! \pmod{p}</math>
  
Co należało pokazać.<br/>
+
gdzie skorzystaliśmy z&nbsp;twierdzenia Fermata (J22).<br/>
 
&#9633;
 
&#9633;
 
{{\Spoiler}}
 
{{\Spoiler}}
Linia 796: Linia 243:
  
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N19</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Twierdzenie Q11</span><br/>
Niech <math>D = P^2 - 4 Q</math>, a <math>(D \mid p)</math> oznacza symbol Legendre'a, gdzie <math>p</math> jest liczbą pierwszą nieparzystą i <math>p \nmid Q</math>. Mamy
+
Jeżeli <math>p</math> i <math>q</math> są różnymi liczbami pierwszymi, to dla dowolnego <math>a \in \mathbb{Z}</math> i&nbsp;każdego <math>k \geqslant 0</math> jest
  
::{| border="0"
+
::<math>a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{p q}</math>
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; <math>U_p \equiv (D \mid p) \pmod{p}</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; jeżeli <math>(D \mid p) = - 1 , \;</math> to <math>\; p \mid U_{p + 1}</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; jeżeli <math>(D \mid p) = 1 , \;</math> to <math>\; p \mid U_{p - 1}</math>
 
|}
 
  
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
'''Punkt 1.'''
+
Z twierdzenia Q10 wiemy, że dla dowolnych liczb <math>i, j \geqslant 0</math> prawdziwe są kongruencje
 
 
Zauważmy, że przypadek gdy <math>p \mid Q</math>, omówiliśmy w&nbsp;twierdzeniu poprzednim. Z&nbsp;założenia <math>p</math> jest liczbą pierwszą nieparzystą. Z&nbsp;twierdzenia N7, w&nbsp;przypadku nieparzystego <math>n = p</math>, otrzymujemy
 
 
 
::<math>2^{p - 1} U_p = p P^{p - 1} + \binom{p}{3} P^{p - 3} D + \binom{p}{5} P^{p - 5} D^2 + \ldots + \binom{p}{p-2} P^2 D^{(p - 3) / 2} + D^{(p - 1) / 2}</math>
 
 
 
Ponieważ dla każdego <math>k \in [1, p - 1]</math> (zobacz N43)
 
 
 
::<math>\binom{p}{k} \equiv 0 \pmod{p}</math>
 
 
 
to modulo <math>p</math> dostajemy (zobacz J33)
 
 
 
::<math>2^{p - 1} U_p \equiv U_p \equiv D^{(p - 1) / 2} \equiv (D \mid p) \pmod{p}</math>
 
 
 
'''Punkt 2.'''
 
 
 
Zauważmy, że warunek <math>(D \mid p) = - 1</math> nie może być spełniony, gdy <math>p \mid Q</math>. Istotnie, gdy <math>p \mid Q</math>, to <math>D = P^2 - 4 Q \equiv P^2 \pmod{p}</math>, czyli
 
 
 
::<math>(D \mid p) = (P^2 \mid p) = (P \mid p)^2 = 0 , \;</math> gdy <math>p \mid P</math>
 
 
 
lub
 
 
 
::<math>(D \mid p) = (P^2 \mid p) = (P \mid p)^2 = 1 , \;</math> gdy <math>p \nmid P</math>
 
 
 
i nie może być <math>(D \mid p) = - 1</math>.
 
 
 
Dla parzystego <math>n = p + 1</math> otrzymujemy z&nbsp;twierdzenia N7
 
 
 
::<math>2^p U_{p + 1} = (p + 1) P^p + \binom{p + 1}{3} P^{p - 2} D + \binom{p + 1}{5} P^{p - 4} D^2 + \ldots + \binom{p + 1}{p - 2} P^3 D^{(p - 3) / 2} + (p + 1) P D^{(p - 1) / 2}</math>
 
 
 
Ponieważ dla <math>k \in [2, p - 1]</math> (zobacz N44)
 
 
 
::<math>\binom{p + 1}{k} \equiv 0 \pmod{p}</math>
 
 
 
to modulo <math>p</math> dostajemy
 
 
 
::<math>2 U_{p + 1} \equiv P + P D^{(p - 1) / 2} \pmod{p}</math>
 
 
 
 
 
Z założenia <math>D</math> jest liczbą niekwadratową modulo <math>p</math>, zatem <math>D^{(p - 1) / 2} \equiv - 1 \pmod{p}</math> (zobacz J31). Skąd wynika natychmiast, że
 
 
 
::<math>2 U_{p + 1} \equiv 0 \pmod{p}</math>
 
 
 
Czyli <math>p \mid U_{p + 1}</math>.
 
 
 
'''Punkt 3.'''
 
 
 
Dla parzystego <math>n = p - 1</math> otrzymujemy z&nbsp;twierdzenia N7
 
 
 
::<math>2^{p - 2} U_{p - 1} = (p - 1) P^{p - 2} + \binom{p - 1}{3} P^{p - 4} D + \binom{p - 1}{5} P^{p - 6} D^2 + \ldots + \binom{p - 1}{p - 4} P^3 D^{(p - 5) / 2} + (p - 1) P D^{(p - 3) / 2}</math>
 
 
 
Ponieważ dla <math>k \in [0, p - 1]</math> (zobacz N45)
 
 
 
::<math>\binom{p - 1}{k} \equiv (- 1)^k \pmod{p}</math>
 
 
 
to modulo <math>p</math> mamy
 
 
 
::<math>2^{p - 2} U_{p - 1} \equiv - (P^{p - 2} + P^{p - 4} D + P^{p - 6} D^2 + \ldots + P D^{(p - 3) / 2}) \pmod{p}</math>
 
 
 
::::<math>\quad \,\, \equiv - P (P^{p - 3} + P^{p - 5} D + P^{p - 7} D^2 + \ldots + D^{(p - 3) / 2}) \pmod{p}</math>
 
 
 
 
 
Z założenia <math>D</math> jest liczbą kwadratową modulo <math>p</math> (zobacz J29), zatem istnieje taka liczba <math>R</math>, że
 
  
::<math>D \equiv R^2 \pmod{p}</math>
+
::<math>a^{(p - 1) i + 1} \equiv a \!\! \pmod{p}</math>
  
Ponieważ
+
::<math>a^{(q - 1) j + 1} \equiv a \!\! \pmod{q}</math>
  
:* <math>(D \mid p) = 1</math>, to <math>p \nmid D</math>, zatem <math>p \nmid R</math>
+
Dla dowolnego, ale ustalonego <math>k \geqslant 0</math> wybierzmy liczby <math>i, j</math> następująco: <math>i = k (q - 1)</math> oraz <math>j = k (p - 1)</math>. Otrzymujemy
:* z&nbsp;założenia <math>p \nmid Q</math>, to <math>P^2 - R^2 \equiv P^2 - D \equiv 4 Q \not\equiv 0 \pmod{p}</math>
 
  
 +
::<math>a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{p}</math>
  
Czyli
+
::<math>a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{q}</math>
  
::<math>2^{p - 2} U_{p - 1} \equiv - P (P^{p - 3} + P^{p - 5} R^2 + P^{p - 7} R^4 + \ldots + R^{p - 3}) \pmod{p}</math>
+
Z twierdzenia J1 wiemy, że powyższy układ kongruencji może być zapisany w&nbsp;sposób równoważny
  
 
+
::<math>a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{p q}</math>
Uwzględniając, że <math>P^2 - R^2 \not\equiv 0 \pmod{p}</math>, możemy napisać
 
 
 
::<math>2^{p - 2} (P^2 - R^2) U_{p - 1} \equiv - P (P^2 - R^2) (P^{p - 3} + P^{p - 5} R^2 + P^{p - 7} R^4 + \ldots + R^{p - 3}) \pmod{p}</math>
 
 
 
::::::::<math>\equiv - P (P^{p - 1} - R^{p - 1}) \pmod{p}</math>
 
 
 
::::::::<math>\equiv 0 \pmod{p}</math>
 
 
 
Zauważmy, że wynik nie zależy od tego, czy <math>p \mid P</math>, czy <math>p \nmid P</math>. Skąd wynika
 
 
 
::<math>U_{p - 1} \equiv 0 \pmod{p}</math>
 
  
 
Co należało pokazać.<br/>
 
Co należało pokazać.<br/>
Linia 904: Linia 271:
  
  
Aby zapisać punkty 2. i 3. twierdzenia N19 (i tylko te punkty) w&nbsp;zwartej formie, musimy założyć, że <math>\gcd (p, D) = 1</math>. Otrzymujemy<br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q12 (metoda szyfrowania RSA)</span><br/>
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N20</span><br/>
+
RSA<ref name="RSA1"/><ref name="RSA2"/> to akronim od nazwisk twórców tej metody: Rona Rivesta, Adiego Shamira i&nbsp;Leonarda Adlemana. Rozpoczniemy od wypisania używanych oznaczeń, co znakomicie ułatwi zrozumienie opisu metody.
Jeżeli <math>p</math> jest liczbą pierwszą nieparzystą i <math>\gcd (p, Q D) = 1</math>, to
 
 
 
::<math>U_{p - (D \mid p)} \equiv 0 \pmod{p}</math>
 
 
 
 
 
 
 
 
 
  
== Liczby pseudopierwsze Lucasa ==
+
:# <math>p, q</math> – dwie duże liczby pierwsze o&nbsp;zbliżonych wartościach
 +
:#* często przyjmuje się, że <math>p < q < 2 p</math>; można też przyjąć, że <math>q \sim 2 p</math>
 +
:# <math>m = p q</math>
 +
:# <math>\Phi = (p - 1) (q - 1)</math>
 +
:#* oznaczenie nawiązuje do funkcji Eulera <math>\varphi</math>, bo <math>\varphi (m) = \varphi (p q) = (p - 1) (q - 1)</math>
 +
:# <math>e</math> (ang. ''encryption'') – wykładnik służący do szyfrowania (publiczny)
 +
:# <math>d</math> (ang. ''decryption'') – wykładnik służący do odszyfrowania (tajny)
 +
:# <math>B</math> (ang. ''block of digits'') – wiadomość w&nbsp;postaci liczby (ciągu cyfr) przeznaczona do zaszyfrowania
 +
:# <math>C</math> (ang. ''coded block of digits'') – zaszyfrowana wiadomość, czyli liczba powstała w&nbsp;wyniku szyfrowania liczby <math>B</math>
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N21</span><br/>
 
Z twierdzenia N20 wiemy, że liczby pierwsze nieparzyste <math>p</math> takie, że <math>p \nmid Q D</math> są dzielnikami wyrazów ciągu Lucasa <math>U_{p - (D \mid p)}</math>, gdzie <math>(D \mid p)</math> oznacza symbol Legendre'a. Jeśli zastąpimy symbol Legendre'a symbolem Jacobiego, to będziemy mogli badać prawdziwość tego twierdzenia dla liczb złożonych i&nbsp;łatwo przekonamy się, że dla pewnych liczb złożonych <math>m</math> kongruencja
 
  
::<math>U_{m - (D \mid m)} \equiv 0 \pmod{m}</math>
+
'''Opis metody'''
 +
:# Wybierzmy liczbę <math>e</math> tak, aby spełniała warunki <math>\gcd (e, \Phi) = 1</math> i <math>2 < e < \Phi</math>
 +
:#* zaleca się, aby <math>e \geqslant 65537</math>
 +
:# Z&nbsp;lematu Bézouta (zobacz C73) istnieją takie liczby całkowite <math>d</math> i <math>k</math>, że <math>d e + k \Phi = 1</math>. Liczbę <math>d</math> wyliczamy ze wzoru <math>d = d_0 + \Phi t</math>, gdzie <math>d_0</math> (oraz <math>k_0</math>) otrzymujemy, wykorzystując w&nbsp;PARI/GP funkcję <code>gcdext(e, Φ)</code> (zobacz C78)
 +
:#* <math>d</math> wybieramy tak, aby była liczbą dodatnią, wtedy <math>k</math> musi być liczbą ujemną
 +
:#* <math>d</math> nie może być zbyt małą liczbą; pokazano<ref name="BonehDurfee1"/>, że powinno być <math>d > m^{0.292}</math>
 +
:# Metoda szyfrowania RSA wymaga trzech liczb: <math>m</math>, <math>e</math>, <math>d</math>. Liczba <math>d</math> jest tajna. Podobnie tajne są liczby <math>p</math>, <math>q</math>, <math>\Phi</math>, ale te liczby można po prostu skasować po wyliczeniu <math>d</math>
 +
:# Szyfrowaną wiadomość przekształcamy w&nbsp;ciąg cyfr. W&nbsp;przypadku długich wiadomości może być konieczny podział ciągu cyfr na bloki. Tworzymy w&nbsp;ten sposób liczbę <math>B</math>. Zakładamy, że <math>B < m</math>
 +
:# Szyfrowanie. Zakodowany tekst jest wynikiem operacji: <math>C = R_m (B^e)</math>, gdzie <math>R_m (B^e)</math> oznacza resztę z&nbsp;dzielenia liczby <math>B^e</math> przez <math>m</math>
 +
:#* zauważmy, że: <math>C \equiv B^e \!\! \pmod{m}</math>
 +
:# Odszyfrowanie. Odkodowany tekst otrzymujemy, obliczając: <math>B = R_m (C^d)</math>
 +
:# Dowód poprawności metody wynika z&nbsp;twierdzenia Q12
 +
:#* <math>R_m (C^d) \equiv C^d \equiv (B^e)^d \equiv B^{e d} \equiv B^{- k \Phi + 1} \equiv B^{- k (p - 1) (q - 1) + 1} \equiv B \!\! \pmod{m}</math>
 +
:#* ponieważ <math>k < 0</math>, to <math>- k</math> jest liczbą dodatnią i&nbsp;możemy zastosować twierdzenie Q12
 +
:#* ponieważ <math>B < m</math>, to <math>R_m (C^d) = B</math>
 +
:# Para liczb <math>(m, e)</math> jest nazywana kluczem publicznym – służy do szyfrowania i&nbsp;może być dostępna dla każdego.
 +
:# Para liczb <math>(m, d)</math> jest nazywana kluczem prywatnym – służy do odszyfrowania. Liczba <math>d</math> jest tajna – osoba, która ją wykradnie, będzie mogła odczytywać wysyłane do nas wiadomości
  
również jest prawdziwa. Prowadzi to definicji liczb pseudopierwszych Lucasa.
 
  
  
 +
<span style="font-size: 110%; font-weight: bold;">Przykład Q13</span><br/>
 +
Prosty przykład: niech wysyłaną wiadomością będzie słowo <math>\text{YES}</math>. Zamianę liter na ciąg cyfr dokonamy, przypisując każdej literze jej numer w&nbsp;alfabecie np.: <math>A \longrightarrow 01</math>, <math>B \longrightarrow 02</math>, ... , <math>Z \longrightarrow 26</math>, czyli <math>\text{YES}\longrightarrow 250519</math>, zatem musimy zaszyfrować liczbę <math>250519</math>.
  
<span style="font-size: 110%; font-weight: bold;">Definicja N22</span><br/>
+
Niech <math>p = 1009</math>, <math>q = 1013</math>, <math>e = 1019</math>. Znajdujemy <math>m = p q = 1022117</math>, <math>\Phi = (p - 1) (q - 1) = 1020096</math>, <math>d = 397427</math>. Klucz publiczny <math>(m, e)</math>, klucz prywatny <math>(m, d)</math>. Zaszyfrowana wiadomość to <math>R_m (250519^e) = 560222</math>. Odszyfrowując, otrzymujemy <math>R_m (560222^d) = 250519</math>. Tak, jak być powinno.
Powiemy, że liczba złożona nieparzysta <math>m</math> jest liczbą pseudopierwszą Lucasa dla parametrów <math>P</math> i <math>Q</math> (symbolicznie: LPSP( <math>P, Q</math> )), jeżeli <math>\gcd (m, Q D) = 1</math> i
 
  
::<math>U_{m - (D \mid m)} \equiv 0 \pmod{m}</math>
 
  
gdzie <math>(D \mid m)</math> oznacza symbol Jacobiego.
 
  
 +
<span style="font-size: 110%; font-weight: bold;">Uwaga Q14</span><br/>
 +
Bezpieczeństwo metody polega na wyborze tak dużych liczb pierwszych <math>p</math> i <math>q</math>, aby faktoryzacja ich iloczynu <math>m</math> leżała poza możliwościami współczesnych komputerów i&nbsp;stosowanych algorytmów. Choć klucz publiczny <math>(m, e)</math> służący do szyfrowania nie jest tajny i&nbsp;może być udostępniany wszystkim, to poznanie klucza prywatnego, czyli liczby <math>d</math>, jest praktycznie niemożliwe.
  
 +
Liczba <math>d</math> wynika z&nbsp;rozwiązania równania <math>d e + k \Phi = 1</math>, ale aby obliczyć <math>\Phi = (p - 1) (q - 1)</math> musimy znać rozkład liczby <math>m</math> na czynniki pierwsze. Obecnie nie istnieją dostatecznie szybkie sposoby znajdowania rozkładu dużych liczb na czynniki pierwsze. Możemy łatwo sprawdzić, czy liczba <math>m = p q</math> jest liczbą złożoną, ale jeśli tak jest, to poznanie jej czynników jest dla dostatecznie dużych <math>m</math> niemożliwe.
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N23</span><br/>
 
Jeżeli liczba złożona nieparzysta <math>m</math> jest liczbą pseudopierwszą Lucasa dla parametrów <math>P = a + 1</math> i <math>Q = a</math>, gdzie <math>a \geqslant 2</math>, to jest liczbą pseudopierwszą Fermata przy podstawie <math>a</math>.
 
  
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
Połóżmy we wzorze definiującym ciąg Lucasa
 
  
::<math>U_m = {\small\frac{\alpha^m - \beta^m}{\alpha - \beta}}</math>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q15 (generowanie liczb <math>m, e, d</math>)</span><br/>
 
+
Przyjmując proste założenia co do liczb pierwszych <math>p, q</math> (przyjęliśmy, że <math>1.8 p < q < 2.2 p</math>) oraz zakładając, że <math>d > m^{2 / 3}</math> napisaliśmy prosty program do generowania klucza publicznego i&nbsp;prywatnego. Parametr <code>w</code> określa, ile cyfr w&nbsp;układzie dziesiętnym będą miały liczby <math>p, q</math>. Wybór <code>w > 500</code> gwarantuje wygenerowanie liczby <math>m</math>, której rozkład na czynniki pierwsze nie powinien być możliwy przez wiele lat. Ostatnie (znane) osiągnięcie faktoryzacji, to rozkład 250-cyfrowej liczby <math>m = p q</math> na czynniki pierwsze<ref name="RSA250"/>.
<math>\alpha = a</math> i <math>\beta = 1</math>. Odpowiada to parametrom <math>P = \alpha + \beta = a + 1</math>, <math>Q = \alpha \beta = a</math>, <math>D = (\alpha - \beta)^2 = (a - 1)^2</math>.
 
 
 
Ponieważ musi być <math>\gcd (m, Q D) = 1</math>, to mamy <math>\gcd (m, (a - 1) a) = 1</math> i&nbsp;wynika stąd, że <math>(D \mid m) = 1</math>. Z&nbsp;założenia <math>m</math> jest liczbą pseudopierwszą Lucasa dla parametrów <math>P = a + 1</math> i <math>Q = a</math>, zatem
 
 
 
::<math>U_{m - 1} (a + 1, a) \equiv 0 \pmod{m}</math>
 
 
 
Czyli
 
 
 
::<math>{\small\frac{a^{m - 1} - 1}{a - 1}} \equiv 0 \pmod{m}</math>
 
 
 
Jeżeli <math>m \biggr\rvert {\small\frac{a^{m - 1} - 1}{a - 1}}</math>, to tym bardziej <math>m \big\rvert (a^{m - 1} - 1)</math> i&nbsp;możemy napisać
 
 
 
::<math>a^{m - 1} - 1 \equiv 0 \pmod{m}</math>
 
 
 
Zatem <math>m</math> jest liczbą pseudopierwszą Fermata przy podstawie <math>a</math>. Co należało pokazać.<br/>
 
&#9633;
 
{{\Spoiler}}
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Uwaga N24</span><br/>
 
Wykorzystując funkcje <code>jacobi(a, n)</code> i <code>modLucas(n, P, Q, m)</code> (zobacz J48, N15) możemy napisać prosty program, który sprawdza, czy dla liczby nieparzystej <math>m</math> prawdziwe jest twierdzenie N20.
 
 
 
<span style="font-size: 90%; color:black;">isPrimeOr<span style="background-color: #fee481;">LPSP</span>(m, P, Q) =
 
{
 
'''local'''(D, js);
 
D = P^2 - 4*Q;
 
'''if'''( gcd(m, 2*Q*D) > 1, '''return'''(0) );
 
js = jacobi(D, m);
 
'''if'''( modLucas(m - js, P, Q, m)[1] == 0, '''return'''(1), '''return'''(0) );
 
}
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Przykład N25</span><br/>
 
Poniższa tabela zawiera najmniejsze liczby pseudopierwsze Lucasa dla różnych parametrów <math>P</math> i <math>Q</math>
 
 
 
::{| class="wikitable plainlinks"  style="font-size: 90%; text-align: right; margin-right: auto;"
 
! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<math>\boldsymbol{P}</math><br/><math>\boldsymbol{Q}</math>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 
! <math>\boldsymbol{1}</math> !! <math>\boldsymbol{2}</math> !! <math>\boldsymbol{3}</math> !! <math>\boldsymbol{4}</math> !! <math>\boldsymbol{5}</math> !! <math>\boldsymbol{6}</math> !! <math>\boldsymbol{7}</math> !! <math>\boldsymbol{8}</math> !! <math>\boldsymbol{9}</math> !! <math>\boldsymbol{10}</math>
 
|-
 
! <math>\boldsymbol{- 5}</math>
 
| <math>253</math> || <math>121</math> || <math>57</math> || <math>217</math> || style="background-color: yellow" | <math>323</math> || <math>69</math> || <math>121</math> || <math>253</math> || <math>9</math> || style="background-color: yellow" | <math>143</math>
 
|-
 
! <math>\boldsymbol{- 4}</math>
 
| <math>9</math> || style="background-color: yellow" | <math>323</math> || <math>91</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>15</math> || style="background-color: yellow" | <math>119</math> || <math>57</math> || <math>9</math> || <math>9</math> || <math>9</math>
 
|-
 
! <math>\boldsymbol{- 3}</math>
 
| <math>217</math> || <math>91</math> || style="background-color: yellow" | <math>527</math> || <math>25</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>65</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>323</math>
 
|-
 
! <math>\boldsymbol{- 2}</math>
 
| <math>341</math> || style="background-color: yellow" | <math>209</math> || style="background-color: yellow" | <math>39</math> || <math>49</math> || <math>49</math> || style="background-color: yellow" | <math>15</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>35</math> || <math>9</math> || <math>85</math>
 
|-
 
! <math>\boldsymbol{- 1}</math>
 
| style="background-color: yellow" | <math>323</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>119</math> || <math>9</math> || <math>9</math> || style="background-color: yellow" | <math>143</math> || <math>25</math> || <math>33</math> || <math>9</math> || style="background-color: yellow" | <math>15</math>
 
|-
 
! <math>\boldsymbol{1}</math>
 
| <math>25</math> || style="background-color: red" | <math></math> || <math>21</math> || style="background-color: yellow" | <math>65</math> || style="background-color: yellow" | <math>115</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>323</math> || style="background-color: yellow" | <math>209</math> || <math>9</math> || style="background-color: yellow" | <math>35</math>
 
|-
 
! <math>\boldsymbol{2}</math>
 
| <math>1541</math> || <math>9</math> || <math>341</math> || style="background-color: yellow" | <math>35</math> || <math>21</math> || <math>85</math> || <math>9</math> || style="background-color: yellow" | <math>15</math> || <math>9</math> || style="background-color: yellow" | <math>35</math>
 
|-
 
! <math>\boldsymbol{3}</math>
 
| style="background-color: yellow" | <math>629</math> || style="background-color: yellow" | <math>559</math> || <math>25</math> || <math>91</math> || <math>49</math> || <math>49</math> || style="background-color: yellow" | <math>35</math> || <math>55</math> || <math>25</math> || style="background-color: yellow" | <math>35</math>  
 
|-
 
! <math>\boldsymbol{4}</math>
 
| style="background-color: yellow" | <math>119</math> || <math>25</math> || style="background-color: yellow" | <math>209</math> || style="background-color: red" | <math></math> || <math>85</math> || <math>21</math> || style="background-color: yellow" | <math>119</math> || style="background-color: yellow" | <math>65</math> || <math>9</math> || style="background-color: yellow" | <math>115</math>
 
|-
 
! <math>\boldsymbol{5}</math>
 
| <math>9</math> || style="background-color: yellow" | <math>143</math> || <math>49</math> || style="background-color: yellow" | <math>143</math> || style="background-color: yellow" | <math>323</math> || <math>217</math> || style="background-color: yellow" | <math>39</math> || <math>9</math> || <math>9</math> || <math>9</math>
 
|}
 
  
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
  <span style="font-size: 90%; color:black;">FirstLPSP(Stop) =  
+
  <span style="font-size: 90%; color:black;">RSAkeys(w) =  
  \\ najmniejsze LPSP(P,Q) < Stop; dla 1<=P<=10 i -5<=Q<=5
+
  \\ parametr w > 1 określa, ile cyfr w&nbsp;układzie dziesiętnym będą miały liczby p, q
 
  {
 
  {
  '''local'''(D, m, P, Q);
+
  '''local'''(d, e, m, p, Phi, q);
  Q = -6;
+
  '''setrand'''('''getwalltime'''()); \\ ustawiamy ziarno (ang. seed) generatora liczb losowych
'''while'''( Q++ <= 5,
+
p = 1;
        '''if'''( Q == 0, '''next'''() );
+
q = 0;
        P = 0;
+
'''while'''( !'''isprime'''(p) ||  !'''isprime'''(q),
        '''while'''( P++ <= 10,
+
        '''while'''( q < 1.8 * p || q > 2.2 * p,  
              D = P^2 - 4*Q;
+
              p = '''randomprime'''( [10^(w - 1), 10^w] );  
              '''if'''( D == 0,
+
              q = '''randomprime'''( [10^(w - 1), 10^w] );
                  '''print'''("Q= ", Q, "  P= ", P, "  ------------------");
 
                  '''next'''();
 
                );
 
              m = 3;
 
              '''while'''( m < Stop,
 
                      '''if'''( isPrimeOr<span style="background-color: #fee481;">LPSP</span>(m, P, Q) && !'''isprime'''(m),
 
                          '''print'''("Q= ", Q, "  P= ", P, "  m= ", m, "  (D|m)= ", jacobi(D, m));
 
                          '''break'''();
 
                        );
 
                      m = m + 2;
 
                    );
 
 
             );
 
             );
 
       );
 
       );
  }</span>
+
  m = p * q;
<br/>
+
  Phi = (p - 1) * (q - 1);
{{\Spoiler}}
+
  d = -1;
 
+
  '''while'''( d < m^(2/3),  
Żółtym tłem oznaczyliśmy te najmniejsze liczby pseudopierwsze Lucasa, dla których <math>(D \mid m) = - 1</math>.
+
         e = '''randomprime'''( [10^10, 10^15] );
 
+
        if( '''gcd'''(e, Phi) > 1, '''next'''() );
 
+
        d = '''gcdext'''(e, Phi)[1];
 
 
<span style="font-size: 110%; font-weight: bold;">Przykład N26</span><br/>
 
Ilość liczb LPSP(<math>P, Q</math>) mniejszych od <math>10^9</math>
 
 
 
::{| class="wikitable plainlinks" style="font-size: 90%; text-align: right; margin-right: auto;"
 
! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<math>\boldsymbol{P}</math><br/><math>\boldsymbol{Q}</math>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 
! <math>\boldsymbol{1}</math> !! <math>\boldsymbol{2}</math> !! <math>\boldsymbol{3}</math> !! <math>\boldsymbol{4}</math> !! <math>\boldsymbol{5}</math> !! <math>\boldsymbol{6}</math> !! <math>\boldsymbol{7}</math> !! <math>\boldsymbol{8}</math> !! <math>\boldsymbol{9}</math> !! <math>\boldsymbol{10}</math>
 
|-
 
! <math>\boldsymbol{- 5}</math>
 
| <math>4266</math> || <math>4935</math> || <math>4278</math> || <math>4981</math> || <math>6363</math> || <math>6028</math> || <math>5202</math> || <math>4426</math> || <math>5832</math> || <math>6027</math>
 
|-
 
! <math>\boldsymbol{- 4}</math>
 
| <math>4599</math> || <math>4152</math> || <math>9272</math> || <math>5886</math> || <math>6958</math> || <math>4563</math> || <math>5600</math> || <math>9509</math> || <math>7007</math> || <math>4142</math>
 
|-
 
! <math>\boldsymbol{- 3}</math>
 
| <math>4265</math> || <math>5767</math> || <math>4241</math> || <math>5114</math> || <math>5859</math> || <math>7669</math> || <math>6083</math> || <math>6120</math> || <math>4420</math> || <math>5096</math>
 
|-
 
! <math>\boldsymbol{- 2}</math>
 
| <math>5361</math> || <math>4389</math> || <math>5063</math> || <math>5632</math> || <math>5364</math> || <math>5228</math> || <math>5859</math> || <math>10487</math> || <math>5370</math> || <math>9798</math>
 
|-
 
! <math>\boldsymbol{- 1}</math>
 
| <math>4152</math> || <math>5886</math> || <math>4563</math> || <math>9509</math> || <math>4142</math> || <math>6273</math> || <math>5773</math> || <math>4497</math> || <math>5166</math> || <math>5305</math>
 
|-
 
! <math>\boldsymbol{1}</math>
 
| <math>282485800</math> || style="background-color: red" | <math></math> || <math>6567</math> || <math>7669</math> || <math>7131</math> || <math>10882</math> || <math>8626</math> || <math>8974</math> || <math>8509</math> || <math>8752</math>
 
|-
 
! <math>\boldsymbol{2}</math>
 
| <math>7803</math> || <math>449152466</math> || <math>5597</math> || <math>5886</math> || <math>6509</math> || <math>5761</math> || <math>8115</math> || <math>6945</math> || <math>8380</math> || <math>7095</math>
 
|-
 
! <math>\boldsymbol{3}</math>
 
| <math>5974</math> || <math>8768</math> || <math>282485800</math> || <math>5767</math> || <math>5651</math> || <math>5632</math> || <math>6640</math> || <math>5725</math> || <math>6058</math> || <math>7050</math>
 
|-
 
! <math>\boldsymbol{4}</math>
 
| <math>10749</math> || <math>282485800</math> || <math>14425</math> || style="background-color: red" | <math></math> || <math>9735</math> || <math>6567</math> || <math>8164</math> || <math>7669</math> || <math>7608</math> || <math>7131</math>
 
|-
 
! <math>\boldsymbol{5}</math>
 
| <math>5047</math> || <math>15127</math> || <math>6155</math> || <math>15127</math> || <math>4152</math> || <math>5146</math> || <math>4423</math> || <math>5526</math> || <math>6289</math> || <math>9509</math>
 
|}
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
 
<span style="font-size: 90%; color:black;">NumOfLPSP(Stop) =
 
\\ ilość liczb pseudopierwszych Lucasa LPSP(P,Q) < Stop;  dla 1<=P<=10 i -5<=Q<=5
 
{
 
'''local'''(D, m, P, Q);
 
  Q = -6;
 
  '''while'''( Q++ <= 5,
 
        '''if'''( Q == 0, '''next'''() );
 
         P = 0;
 
        '''while'''( P++ <= 10,
 
              D = P^2 - 4*Q;
 
              '''if'''( D == 0, '''print'''("Q= ", Q, "  P= ", P, "  ------------------"); '''next'''() );
 
              s = 0;
 
              m = 3;
 
              '''while'''( m < Stop,
 
                      '''if'''( isPrimeOr<span style="background-color: #fee481;">LPSP</span>(m, P, Q)  &&  !'''isprime'''(m), s++ );
 
                      m = m + 2;
 
                    );
 
              '''print'''("Q= ", Q, "  P= ", P, "  s= ", s);
 
            );
 
 
       );
 
       );
 +
'''return'''([m, e, d]);
 
  }</span>
 
  }</span>
<br/>
 
{{\Spoiler}}
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Uwaga N27</span><br/>
 
Dla <math>(P, Q) = (1, 1)</math> ciąg Lucasa <math>(U_n)</math> ma postać
 
 
::<math>(U_n) = (0, 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, 1, \ldots)</math>
 
 
Stosując indukcję matematyczną, udowodnimy, że <math>U_{3 k} = 0</math>. Łatwo sprawdzamy, że dla <math>k = 0</math> i <math>k = 1</math> wzór jest prawdziwy. Zakładając prawdziwość wzoru dla wszystkich liczb naturalnych nie większych od <math>k</math>, otrzymujemy dla <math>k + 1</math> (zobacz N13 p.3)
 
 
::<math>U_{3 (k + 1)} = U_{3 k + 3} = U_{3 k} V_3 - U_{3 (k - 1)} = 0</math>
 
 
Co kończy dowód. Zbadajmy liczby pseudopierwsze Lucasa dla <math>(P, Q) = (1, 1)</math>.
 
 
Mamy <math>D = P^2 - 4 Q = - 3</math>. Wynika stąd, że nie może być <math>3 \mid m</math>, bo mielibyśmy <math>\gcd (m, Q D) = 3 > 1</math>.
 
 
Z zadania J46 wiemy, że
 
 
::<math>(- 3 \mid m) =
 
\begin{cases}
 
\;\;\: 1 & \text{gdy } m = 6 k + 1 \\
 
\;\;\: 0 & \text{gdy } m = 6 k + 3 \\
 
      - 1 & \text{gdy } m = 6 k + 5 \\
 
\end{cases}</math>
 
 
Ponieważ <math>3 \nmid m</math>, to wystarczy zbadać przypadki <math>m = 6 k + 1</math> i <math>m = 6 k + 5</math>. W&nbsp;pierwszym przypadku jest
 
 
::<math>U_{m - (- 3 \mid m)} = U_{6 k + 1 - 1} = U_{6 k} = 0</math>
 
 
W drugim przypadku, gdy <math>m = 6 k + 5</math>, dostajemy
 
 
::<math>U_{m - (- 3 \mid m)} = U_{6 k + 5 + 1} = U_{6 (k + 1)} = 0</math>
 
 
Zatem dla dowolnej liczby nieparzystej <math>m</math> niepodzielnej przez <math>3</math> jest
 
 
::<math>U_{m - (- 3 \mid m)} \equiv 0 \pmod{m}</math>
 
 
Czyli liczbami pseudopierwszymi Lucasa dla parametrów <math>(P, Q) = (1, 1)</math> będą liczby nieparzyste <math>m</math>, które nie są podzielne przez <math>3</math> i&nbsp;nie są liczbami pierwszymi. Ilość takich liczb nie większych od <math>10^k</math> możemy łatwo znaleźć poleceniem
 
 
<span style="font-size: 90%; color:black;">'''for'''(k = 1, 9, s = 0; '''forstep'''(m = 3, 10^k, 2, '''if'''( m%6 <> 3, s = s + !'''isprime'''(m) )); '''print'''(s))</span>
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Zadanie N28</span><br/>
 
Pokazać, że ilość liczb pseudopierwszych Lucasa dla parametrów <math>(P, Q) = (2, 2)</math> nie większych od <math>10^k</math> możemy znaleźć poleceniem
 
 
<span style="font-size: 90%; color:black;">'''for'''(k = 1, 9, s = 0; '''forstep'''(m = 3, 10^k, 2, s = s + !'''isprime'''(m)); '''print'''(s))</span>
 
 
 
 
 
 
== Metoda Selfridge'a wyboru parametrów <math>P</math> i <math>Q</math> ==
 
 
<span style="font-size: 110%; font-weight: bold;">Uwaga N29</span><br/>
 
Twierdzenie N20 możemy wykorzystać do testowania pierwszości liczb. Ponieważ musi być spełniony warunek <math>\gcd (m, Q D) = 1</math>, to nie każda para liczb <math>P, Q</math> (np. wybrana losowo) nadaje się do przeprowadzenia testu. Zawsze będziemy zmuszeni określić zasadę postępowania, która doprowadzi do wyboru właściwej pary <math>P, Q</math>.
 
 
Robert Baillie i&nbsp;Samuel Wagstaff przedstawili<ref name="BaillieWagstaff1"/> dwie metody wyboru parametrów dla testu Lucasa. Ograniczymy się do omówienia tylko pierwszej z&nbsp;nich (metodę zaproponował John Selfridge).
 
 
Rozważmy ciąg <math>a_k = (- 1)^k (2 k + 1)</math>, gdzie <math>k \geqslant 2</math>, czyli <math>a_k = (5, - 7, 9, - 11, 13, - 15, \ldots)</math>. Niech <math>D</math> będzie pierwszym wyrazem ciągu <math>(a_k)</math>, dla którego jest <math>(a_k \mid m) = - 1</math>. Dla tak ustalonego <math>D</math> przyjmujemy <math>P = 1</math> i <math>Q = (1 - D) / 4</math>.
 
 
Tabela przedstawia początkowe wartości <math>Q</math>, jakie otrzymamy, stosując tę metodę.
 
 
::{| class="wikitable plainlinks"  style="font-size: 90%; text-align: right; margin-right: auto;"
 
! <math>\boldsymbol{k}</math>
 
| <math>2</math> || <math>3</math> || <math>4</math> || <math>5</math> || <math>6</math> || <math>7</math> || <math>8</math> || <math>9</math> || <math>10</math> || <math>11</math> || <math>12</math> || <math>13</math> || <math>14</math> || <math>15</math> || <math>16</math> || <math>17</math> || <math>18</math> || <math>19</math> || <math>20</math>
 
|-
 
!  <math>\boldsymbol{a_k}</math>
 
| <math>5</math> || <math>-7</math> || <math>9</math> || <math>-11</math> || <math>13</math> || <math>-15</math> || <math>17</math> || <math>-19</math> || <math>21</math> || <math>-23</math> || <math>25</math> || <math>-27</math> || <math>29</math> || <math>-31</math> || <math>33</math> || <math>-35</math> || <math>37</math> || <math>-39</math> || <math>41</math>
 
|-
 
!  <math>\boldsymbol{Q}</math>
 
| <math>-1</math> || <math>2</math> || style="background-color: red" | <math>-2</math> || <math>3</math> || <math>-3</math> || <math>4</math> || <math>-4</math> || <math>5</math> || <math>-5</math> || <math>6</math> || style="background-color: red" | <math>-6</math> || <math>7</math> || <math>-7</math> || <math>8</math> || <math>-8</math> || <math>9</math> || <math>-9</math> || <math>10</math> || <math>-10</math>
 
|}
 
 
 
Zauważmy, że
 
:* jeżeli liczba nieparzysta <math>m</math> jest liczbą kwadratową, to wybór <math>D</math> nie będzie możliwy
 
:* w&nbsp;przypadku zastosowania tej metody znajdziemy tylko liczby pierwsze lub pseudopierwsze Lucasa, które spełniają kongruencję <math>U_{m + 1} \equiv 0 \pmod{m}</math>, czyli tylko część liczb pseudopierwszych Lucasa określonych w&nbsp;definicji N22
 
 
 
Ponieważ Baillie i&nbsp;Wagstaff określili metodę zaproponowaną przez Selfridge'a jako metodę A, to pozostaniemy przy tej nazwie. Korzystając ze wzoru rekurencyjnego
 
 
::<math> a_{k+1} =
 
  \begin{cases}
 
  \qquad \qquad 5 & \text{gdy } k = 1 \\
 
      - a_k - 2 * \mathop{\textnormal{sign}}( a_k ) & \text{gdy } k \geqslant 2 \\
 
  \end{cases}</math>
 
  
możemy łatwo napisać odpowiednią funkcję znajdującą liczby <math>P, Q</math> według tej metody.
+
  <span style="font-size: 90%; color:black;">PrintRSAkeys(w) =  
 
 
  <span style="font-size: 90%; color:black;">MethodA(m) =  
 
 
  {
 
  {
  '''local'''(a, js);
+
  '''local'''(V);
  a = 5;
+
  V = RSAkeys(w);
  '''while'''( 1,
+
  '''print'''("m = ", V[1]);
        js = jacobi(a, m);
+
'''print'''("e = ", V[2]);
        '''if'''( js == 0  &&  a % m <> 0, '''return'''([0, 0]) );
+
'''print'''("d = ", V[3]);
        '''if'''( js == -1, '''return'''([1, (1 - a)/4]) );
 
        a = -a - 2*'''sign'''(a);
 
      );
 
 
  }</span>
 
  }</span>
 
Wyjaśnienia wymaga druga linia kodu w&nbsp;pętli <code>while</code>. Wiemy, że (zobacz J42)
 
 
::<math>(a \mid m) = 0 \quad \qquad \Longleftrightarrow \quad \qquad \gcd (a, m) > 1</math>
 
 
Jednak z&nbsp;faktu, że <math>\gcd (a, m) > 1</math> nie wynika natychmiast, że liczba <math>m</math> jest liczbą złożoną. Rozważmy dwa przypadki: gdy <math>m \mid a</math> i <math>m \nmid a</math>.
 
 
Gdy <math>\gcd (a, m) > 1</math> i <math>m \mid a</math>, to <math>\gcd (a, m) = \gcd (k \cdot m, m) = m > 1</math> i&nbsp;nie jesteśmy w&nbsp;stanie rozstrzygnąć, czy liczba <math>m</math> jest liczbą pierwszą, czy złożoną. Widać to dobrze na prostych przykładach
 
 
::<math>\gcd (7, 7) = \gcd (14, 7) = 7 > 1</math>
 
 
::<math>\gcd (15, 15) = \gcd (30, 15) = 15 > 1</math>
 
 
Gdy <math>\gcd (a, m) > 1</math> i <math>m \nmid a</math>, to <math>m</math> jest liczbą złożoną. Ponieważ <math>m \nmid a</math>, to <math>a = k \cdot m + r</math>, gdzie <math>r \in [1, m - 1]</math>. Mamy
 
 
::<math>\gcd (a, m) = \gcd (k \cdot m + r, m) = \gcd (r, m) = d</math>
 
 
Musi być <math>d > 1</math>, bo założyliśmy, że <math>\gcd (a, m) > 1</math> i&nbsp;musi być <math>d < m</math>, bo <math>d \leqslant r \leqslant m - 1</math>. Zatem <math>d</math> jest dzielnikiem nietrywialnym liczby <math>m</math> i <math>m</math> jest liczbą złożoną.
 
 
Omawiana linia kodu zapewnia wysłanie informacji o&nbsp;tym, że liczba <math>m</math> jest liczbą złożoną (zwrot wektora [0, 0]). W&nbsp;przypadku, gdy nie mamy takiej pewności, kontynuujemy szukanie liczby <math>a</math>, takiej że <math>(a \mid m) = - 1</math>, pozostawiając zbadanie pierwszości liczby <math>m</math> na kolejnym etapie testowania.
 
 
 
Uważny Czytelnik dostrzeże, że nie zbadaliśmy, czy spełniony jest warunek <math>\gcd (m, Q) = 1</math>. Nie musimy tego robić, bo zwracana przez funkcję <code>MethodA()</code> liczba <math>Q</math> jest względnie pierwsza z <math>m</math>. Omówimy ten problem dokładnie w&nbsp;zadaniu N30. Poniżej pokażemy, że nawet gdyby było <math>\gcd (m, Q) > 1</math>, to złożona liczba <math>m</math> nie zostanie uznana za liczbę pseudopierwszą Lucasa.
 
 
Zauważmy, że jeżeli <math>m</math> jest liczbą złożoną i&nbsp;ma dzielnik pierwszy <math>p < m</math>, który dzieli <math>Q</math>, to <math>p \mid Q</math> i <math>p \nmid P</math> (bo <math>P = 1</math>), zatem <math>p \nmid U_k</math> dla <math>k \geqslant 1</math> (zobacz N17), czyli nie może być
 
 
::<math>U_{m + 1} (1, Q) \equiv 0 \pmod{m}</math>
 
 
bo mielibyśmy
 
 
::<math>U_{m + 1} (1, Q) \equiv 0 \pmod{p}</math>
 
 
a to jest niemożliwe. Zatem program wykorzystujący twierdzenie N20 wykryje złożoność liczby <math>m</math>.
 
 
Łatwo pokażemy, że nie jest możliwe, aby liczba <math>m</math> była liczbą pierwszą i&nbsp;była dzielnikiem <math>Q</math>. Jeżeli <math>m</math> jest liczbą pierwszą, to istnieje dokładnie <math>\tfrac{m - 1}{2}</math> liczb kwadratowych modulo <math>p</math> i <math>\tfrac{m - 1}{2}</math> liczb niekwadratowych modulo <math>p</math>, zatem rozpoczynając od wyrazu <math>a_2</math> możemy dojść co najwyżej do wyrazu o&nbsp;indeksie <math>k = \tfrac{m - 1}{2} + 2</math>, czyli
 
 
::<math>| a_k | \leqslant m + 4</math>
 
 
Skąd wynika, że
 
 
::<math>| Q | = \left| {\small\frac{1 - a_k}{4}} \right| \leqslant {\small\frac{m + 5}{4}} < m</math>
 
 
Ostatnia nierówność jest prawdziwa dla <math>m > {\small\frac{5}{3}}</math>, czyli dla wszystkich liczb pierwszych. Ponieważ <math>| Q | < m</math>, w&nbsp;przypadku gdy <math>m</math> jest liczbą pierwszą, to <math>m</math> nie może być dzielnikiem liczby <math>Q</math>.
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Zadanie N30</span><br/>
 
Pokazać, że w&nbsp;przypadku, gdy dla kolejnych liczb <math>a_k = (- 1)^k (2 k + 1)</math> sprawdzamy, czy konsekwencją <math>(a_k \mid m) = 0</math> jest złożoność liczby <math>m</math>, to dla każdej liczby <math>Q</math> wyznaczonej metodą Selfridge'a jest <math>\gcd (Q, m) = 1</math>.
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Rozwiązanie|Hide=Ukryj rozwiązanie}}
 
Niech <math>m = 21</math>. Rozpoczniemy od przykładu liczb <math>a_k = (- 1)^k (2 k + 1)</math> dla <math>k = 0, 1, \ldots, m - 1</math>.
 
 
::{| class="wikitable plainlinks"  style="font-size: 90%; text-align: center; margin-right: auto;"
 
! <math>\boldsymbol{k}</math> !! <math>\boldsymbol{0}</math> !!  !!  !!  !!  !!  !!  !!  !!  !!  !! <math>\boldsymbol{(m-1)/2}</math> !!  !!  !!  !!  !!  !!  !!  !!  !!  !! <math>\boldsymbol{m-1}</math>
 
|-
 
! <math>\boldsymbol{k}</math>
 
| <math>0</math> || <math>1</math> || <math>2</math> || <math>3</math> || <math>4</math> || <math>5</math> || <math>6</math> || <math>7</math> || <math>8</math> || <math>9</math> || <math>10</math> || <math>11</math> || <math>12</math> || <math>13</math> || <math>14</math> || <math>15</math> || <math>16</math> || <math>17</math> || <math>18</math> || <math>19</math> || <math>20</math>
 
|-
 
! <math>\boldsymbol{a_k}</math>
 
| <math>1</math> || <math>-3</math> || <math>5</math> || <math>-7</math> || <math>9</math> || <math>-11</math> || <math>13</math> || <math>-15</math> || <math>17</math> || <math>-19</math> || <math>21</math> || <math>-23</math> || <math>25</math> || <math>-27</math> || <math>29</math> || <math>-31</math> || <math>33</math> || <math>-35</math> || <math>37</math> || <math>-39</math> || <math>41</math>
 
|-
 
! <math>\boldsymbol{R_m(a_k)}</math>
 
| <math>1</math> || <math>18</math> || <math>5</math> || <math>14</math> || <math>9</math> || <math>10</math> || <math>13</math> || <math>6</math> || <math>17</math> || <math>2</math> || <math>0</math> || <math>19</math> || <math>4</math> || <math>15</math> || <math>8</math> || <math>11</math> || <math>12</math> || <math>7</math> || <math>16</math> || <math>3</math> || <math>20</math>
 
|}
 
 
Zauważmy, że modulo <math>21</math> ciąg <math>(a_k) = (1, - 3, 5, - 7, \ldots, 37, - 39, 41)</math> jest identyczny z&nbsp;ciągiem <math>(0, 1, 2, \ldots, 19, 20)</math>, a&nbsp;ciąg <math>(| a_k |)</math> to kolejne liczby nieparzyste od <math>1</math> do <math>2 m - 1</math>.
 
 
 
Poniżej pokażemy, dlaczego musi być <math>\gcd (Q, m) = 1</math>, gdzie <math>Q</math> jest liczbą wyznaczoną metodą Selfridge'a (o ile sprawdzana jest złożoność liczby <math>m</math> przy testowaniu kolejnych liczb <math>a_k</math>). Pogrubioną czcionką zaznaczone są symbole Jacobiego, które wykryły złożoność liczby <math>m</math>. Gdyby nie była badana złożoność, to wyliczona zostałaby wartość <math>Q</math> na podstawie innego wyrazu ciągu <math>a_k</math> (ten symbol Jacobiego został zapisany zwykłą czcionką).
 
 
::<math>m = 3 , \;\; (5 \mid 3) = - 1 , \;\; Q = - 1 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 5 , \;\; (5 \mid 5) = 0 , \;\; (- 7 \mid 5) = - 1 , \;\; Q = 2 , \;\; \gcd (m, Q) = 1 \;\;</math> (zauważmy, że <math>(5 \mid 5) = 0</math> nie pozwala wnioskować o&nbsp;złożoności)
 
 
::<math>m = 7 , \;\; (5 \mid 7) = - 1 , \;\; Q = - 1 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 9 , \;\; </math> (liczba kwadratowa)
 
 
::<math>m = 11 , \;\; (- 11 \mid 11) = 0 , \;\; (13 \mid 11) = - 1 , \;\; Q = - 3 , \;\; \gcd (m, Q) = 1 \;\;</math> (zauważmy, że <math>(- 11 \mid 11) = 0</math> nie pozwala wnioskować o&nbsp;złożoności)
 
 
::<math>m = 13 , \;\; (5 \mid 13) = - 1 , \;\; Q = - 1 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 15 , \;\; \boldsymbol{(5 \mid 15) = 0} , \;\; (13 \mid 15) = - 1 , \;\; Q = - 3 , \;\; \gcd (m, Q) = 3 \;\;</math> (gdyby nie zbadano złożoności)
 
 
::<math>m = 17 , \;\; (5 \mid 17) = - 1 , \;\; Q = - 1 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 19 , \;\; (- 7 \mid 19) = - 1 , \;\; Q = 2 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 21 , \;\; \boldsymbol{(- 7 \mid 21) = 0} , \;\; (- 11 \mid 21) = - 1 , \;\; Q = 3 , \;\; \gcd (m, Q) = 3 \;\;</math> (gdyby nie zbadano złożoności)
 
 
 
Niech <math>m \geqslant 23</math>. Wiemy, że w&nbsp;ciągu <math>(5, - 7, 9, \ldots, \pm m, \mp (m + 2), \ldots, - (2 m - 3), 2 m - 1)</math> wystąpią liczby <math>a_k</math> takie, że <math>(a_k \mid m) = - 1</math>. Warunek <math>(a_k \mid m) = 0</math> oznacza, że <math>(2 k + 1 \mid m) = 0</math>, bo
 
 
::<math>(a_k \mid m) = ((- 1)^k (2 k + 1) \mid m) = ((- 1)^k \mid m) \cdot (2 k + 1 \mid m) = (- 1 \mid m)^k \cdot (2 k + 1 \mid m) = \pm (2 k + 1 \mid m)</math>
 
 
Jeżeli będą spełnione warunki <math>(a_k \mid m) = 0</math> i <math>R_m (a_k) \neq 0</math>, to liczba <math>m</math> będzie liczbą złożoną.
 
 
Wypiszmy kolejne próby dla <math>m \geqslant 23</math>. Liczba <math>r</math> jest numerem próby.
 
 
::<math>r = 1 , \;\; a_{r + 1} = 5</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(5 \mid m) = 1</math> || <math>5 \nmid m \quad</math> || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(5 \mid m) = 0</math> || <math>5 \mid m</math> || '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(5 \mid m) = - 1 \quad</math> || <math>5 \nmid m</math> || <math>D = 5 , \;\; Q = - 1 , \;\; \gcd (m, Q) = 1 , \;\;</math> '''koniec'''
 
|}
 
 
::<math>r = 2 , \;\; a_{r + 1} = - 7</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 7 \mid m) = 1</math> || <math>7 \nmid m \quad</math> || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 7 \mid m) = 0</math> || <math>7 \mid m</math> || '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 7 \mid m) = - 1 \quad</math> || <math>7 \nmid m</math> || <math>D = -7 , \;\; Q = 2 , \;\; \gcd (m, Q) = 1 , \;\;</math> '''koniec'''
 
|}
 
 
::<math>r = 3</math>, <math>a_{r + 1} = 9</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(9 \mid m) = 1</math> || <math>3 \nmid m \quad</math> || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(9 \mid m) = 0</math> || <math>3 \mid m</math> || '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(9 \mid m) \neq - 1 \quad</math> || - - - - || bo <math>9</math> jest liczbą kwadratową
 
|}
 
 
 
Po wykonaniu trzech prób niezakończonych sukcesem (tzn. wykryciem złożoności <math>m</math> lub ustaleniem wartości liczb <math>D</math> i <math>Q</math>) wiemy, że <math>m</math> nie jest podzielna przez żadną z&nbsp;liczb pierwszych <math>p = 3, 5, 7</math>.
 
 
::<math>r</math>-ta próba, gdzie <math>r \geqslant 4 , \;\;</math> wyraz <math>a_{r + 1}</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(a_{r + 1} \mid m) = 1</math> || żadna liczba pierwsza <math>p \leqslant | a_{r + 1} | = 2 r + 3</math> nie dzieli liczby <math>m \quad</math> &nbsp;&nbsp;&nbsp;  || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(a_{r + 1} \mid m) = 0</math> || A. jeżeli <math>m \mid a_{r + 1}</math><sup>( * )</sup><br/>B. jeżeli <math>m \nmid a_{r + 1}</math> || A. przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math> <br/> B. <math>a_{r + 1} \mid m</math><sup>( ** )</sup>, '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(a_{r + 1} \mid m) = - 1 \quad</math> || żadna liczba pierwsza <math>p \leqslant | a_{r + 1} | = 2 r + 3</math> nie dzieli liczby <math>m \quad</math> &nbsp;&nbsp;&nbsp;  || <math>D = a_{r + 1}</math>, <math>Q = {\small\frac{1 - a_{r + 1}}{4}}</math>, '''koniec'''
 
|}
 
 
<sup>( * )</sup> jest to możliwe tylko dla <math>a_{r + 1} = a_{(m - 1) / 2} = m</math>
 
 
<sup>( ** )</sup> zauważmy, że jeżeli <math>m \nmid a_{r + 1}</math>, to <math>\gcd (a_{r + 1}, m) = | a_{r + 1} |</math>, bo gdyby liczba <math>| a_{r + 1} |</math> była liczbą złożoną, to żaden z&nbsp;jej dzielników pierwszych nie dzieliłby liczby <math>m</math>
 
 
 
Jeżeli nie została wykryta złożoność liczby <math>m</math>, to żadna z&nbsp;liczb pierwszych <math>p \leqslant | a_{r + 1} | = 2 r + 3</math> nie dzieli liczby <math>m</math>. Zatem <math>\gcd (Q, m) > 1</math> może być tylko w&nbsp;przypadku, gdy pewna liczba pierwsza <math>q \geqslant 2 r + 5</math> będzie wspólnym dzielnikiem liczb <math>Q</math> i <math>m</math>, ale jest to niemożliwe, bo
 
 
::<math>| Q | = \left| {\small\frac{1 - a_{r + 1}}{4}} \right| \leqslant {\small\frac{| a_{r + 1} | + 1}{4}} = {\small\frac{2 r + 4}{4}} < 2 r + 5 \leqslant q</math>
 
 
Przedostatnia (ostra) nierówność jest prawdziwa dla wszystkich <math>r</math> naturalnych.<br/>
 
&#9633;
 
{{\Spoiler}}
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Zadanie N31</span><br/>
 
Zmodyfikujmy metodę Selfridge'a w&nbsp;taki sposób, że będziemy rozpoczynali próby nie od wyrazu <math>a_2 = 5</math>, ale od wyrazu <math>a_3 = - 7</math>. Pokazać, że w&nbsp;przypadku, gdy dla kolejnych liczb <math>a_k = (- 1)^k (2 k + 1)</math> sprawdzamy, czy konsekwencją <math>(a_k \mid m) = 0</math> jest złożoność liczby <math>m</math>, to dla każdej liczby <math>Q</math> wyznaczonej tak zmodyfikowaną metodą Selfridge'a jest <math>\gcd (Q, m) = 1</math>.
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Rozwiązanie|Hide=Ukryj rozwiązanie}}
 
Poniżej pokażemy, dlaczego musi być <math>\gcd (Q, m) = 1</math>, gdzie <math>Q</math> jest liczbą wyznaczoną zmodyfikowaną metodą Selfridge'a (o ile sprawdzana jest złożoność liczby <math>m</math> przy testowaniu kolejnych liczb <math>a_k</math>). Pogrubioną czcionką zaznaczone są symbole Jacobiego, które wykryły złożoność liczby <math>m</math>. Gdyby nie była badana złożoność, to wyliczona zostałaby wartość <math>Q</math> na podstawie innego wyrazu ciągu <math>a_k</math> (ten symbol Jacobiego został zapisany zwykłą czcionką).
 
 
::<math>m = 3 , \;\; (- 7 \mid 3) = - 1 , \;\; Q = 2 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 5 , \;\; (- 7 \mid 5) = - 1 , \;\; Q = 2 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 7 , \;\; (- 7 \mid 7) = 0 , \;\; (- 11 \mid 7) = - 1 , \;\; Q = 3 , \;\; \gcd (m, Q) = 1</math> (zauważmy, że <math>(- 7 \mid 7) = 0</math> nie pozwala wnioskować o&nbsp;złożoności)
 
 
::<math>m = 9 , \;\; </math> (liczba kwadratowa)
 
 
::<math>m = 11 , \;\; (- 11 \mid 11) = 0 , \;\; (13 \mid 11) = - 1 , \;\; Q = - 3 , \;\; \gcd (m, Q) = 1 \;\;</math> (zauważmy, że <math>(- 11 \mid 11) = 0</math> nie pozwala wnioskować o&nbsp;złożoności)
 
 
::<math>m = 13 , \;\; (- 7 \mid 13) = - 1 , \;\; Q = 2 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 15 , \;\; \boldsymbol{(9 \mid 15) = 0} , \;\; (13 \mid 15) = - 1 , \;\; Q = - 3 , \;\; \gcd (m, Q) = 3 \;\;</math> (gdyby nie zbadano złożoności)
 
 
::<math>m = 17 , \;\; (- 7 \mid 17) = - 1 , \;\; Q = 2 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 19 , \;\; (- 7 \mid 19) = - 1 , \;\; Q = 2 , \;\; \gcd (m, Q) = 1</math>
 
 
::<math>m = 21 , \;\; \boldsymbol{(- 7 \mid 21) = 0} , \;\; (- 11 \mid 21) = - 1 , \;\; Q = 3 , \;\; \gcd (m, Q) = 3 \;\;</math> (gdyby nie zbadano złożoności)
 
 
 
Niech <math>m \geqslant 23</math>. Wiemy, że w&nbsp;ciągu <math>( - 7, 9, \ldots, \pm m, \mp (m + 2), \ldots, - (2 m - 3), 2 m - 1)</math> wystąpią liczby <math>a_k</math> takie, że <math>(a_k \mid m) = - 1</math>. Warunek <math>(a_k \mid m) = 0</math> oznacza, że <math>(2 k + 1 \mid m) = 0</math>, bo
 
 
::<math>(a_k \mid m) = ((- 1)^k (2 k + 1) \mid m) = ((- 1)^k \mid m) \cdot (2 k + 1 \mid m) = (- 1 \mid m)^k \cdot (2 k + 1 \mid m) = \pm (2 k + 1 \mid m)</math>
 
 
Jeżeli będą spełnione warunki <math>(a_k \mid m) = 0</math> i <math>R_m (a_k) \neq 0</math>, to liczba <math>m</math> będzie liczbą złożoną.
 
 
Wypiszmy kolejne próby dla <math>m \geqslant 23</math>. Liczba <math>r</math> jest numerem próby.
 
 
::<math>r = 1 , \;\; a_{r + 2} = - 7</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 7 \mid m) = 1</math> || <math>7 \nmid m \quad</math> || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 7 \mid m) = 0</math> || <math>7 \mid m</math> || '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 7 \mid m) = - 1 \quad</math> || <math>7 \nmid m</math> || <math>D = - 7 , \;\; Q = 2 , \;\; \gcd (m, Q) = 1 , \;\;</math> '''koniec'''
 
|}
 
 
::<math>r = 2 , \;\; a_{r + 2} = 9</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(9 \mid m) = 1</math> || <math>3 \nmid m \quad</math> || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(9 \mid m) = 0</math> || <math>3 \mid m</math> || '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(9 \mid m) \neq - 1 \quad</math> || - - - - || bo <math>9</math> jest liczbą kwadratową
 
|}
 
 
::<math>r = 3 , \;\; a_{r + 2} = - 11</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 11 \mid m) = 1</math> || <math>11 \nmid m \quad</math> || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 11 \mid m) = 0</math> || <math>11 \mid m</math> || '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 11 \mid m) = - 1 \quad</math> || <math>11 \nmid m</math> || <math>D = - 11 , \;\; Q = 3 , \;\; \gcd (m, Q) = 1 , \;\;</math> '''koniec''' (bo liczby złożone <math>m = 3 k</math> zostały usunięte w&nbsp;poprzedniej próbie, <math>r = 2</math>)
 
|}
 
 
::<math>r = 4 , \;\; a_{r + 2} = 13</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(13 \mid m) = 1</math> || <math>13 \nmid m \quad</math> || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(13 \mid m) = 0</math> || <math>13 \mid m</math> || '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(13 \mid m) = - 1 \quad</math> || <math>13 \nmid m</math> || <math>D = 13 , \;\; Q = - 3 , \;\; \gcd (m, Q) = 1 , \;\;</math> '''koniec''' (bo liczby złożone <math>m = 3 k</math> zostały usunięte w&nbsp;próbie o&nbsp;numerze <math>r = 2</math>)
 
|}
 
 
::<math>r = 5 , \;\; a_{r + 2} = - 15</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 15 \mid m) = 1</math> || <math>5 \nmid m \quad</math> || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 15 \mid m) = 0</math> || <math>5 \mid m</math> || '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(- 15 \mid m) = - 1 \quad</math> || <math>5 \nmid m</math> || <math>D = - 15 , \;\; Q = 4 , \;\; \gcd (m, Q) = 1 , \;\;</math> '''koniec'''
 
|}
 
 
 
Po wykonaniu pięciu prób niezakończonych sukcesem (tzn. wykryciem złożoności <math>m</math> lub ustaleniem wartości liczb <math>D</math> i <math>Q</math>) wiemy, że <math>m</math> nie jest podzielna przez żadną z&nbsp;liczb pierwszych <math>p = 3, 5, 7, 11, 13</math>.
 
 
::<math>r</math>-ta próba, gdzie <math>r \geqslant 6 , \;\;</math> wyraz <math>a_{r + 2}</math>
 
 
::{| border="0"
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(a_{r + 2} \mid m) = 1</math> || żadna liczba pierwsza <math>p \leqslant | a_{r + 2} | = 2 r + 5</math> nie dzieli liczby <math>m \quad</math> &nbsp;&nbsp;&nbsp;  || przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math>
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(a_{r + 2} \mid m) = 0</math> || A. jeżeli <math>m \mid a_{r + 2}</math><sup>( * )</sup><br/>B. jeżeli <math>m \nmid a_{r + 2}</math> || A. przechodzimy do kolejnego wyrazu ciągu <math>(a_k)</math> <br/> B. <math>a_{r + 1} \mid m</math><sup>( ** )</sup>, '''koniec'''
 
|-style=height:2em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>(a_{r + 2} \mid m) = - 1 \quad</math> || żadna liczba pierwsza <math>p \leqslant | a_{r + 2} | = 2 r + 5</math> nie dzieli liczby <math>m \quad</math> &nbsp;&nbsp;&nbsp;  || <math>D = a_{r + 2}</math>, <math>Q = {\small\frac{1 - a_{r + 2}}{4}}</math>, '''koniec'''
 
|}
 
 
<sup>( * )</sup> jest to możliwe tylko dla <math>a_{r + 2} = a_{(m - 1) / 2} = m</math>
 
 
<sup>( ** )</sup> zauważmy, że jeżeli <math>m \nmid a_{r + 2}</math>, to <math>\gcd (a_{r + 2}, m) = | a_{r + 2} |</math>, bo gdyby liczba <math>| a_{r + 2} |</math> była liczbą złożoną, to żaden z&nbsp;jej dzielników pierwszych nie dzieliłby liczby <math>m</math>
 
 
 
Jeżeli nie została wykryta złożoność liczby <math>m</math>, to żadna z&nbsp;liczb pierwszych <math>p \leqslant | a_{r + 2} | = 2 r + 5</math> nie dzieli liczby <math>m</math>. Zatem <math>\gcd (Q, m) > 1</math> może być tylko w&nbsp;przypadku, gdy pewna liczba pierwsza <math>q \geqslant 2 r + 7</math> będzie wspólnym dzielnikiem liczb <math>Q</math> i <math>m</math>, ale jest to niemożliwe, bo
 
 
::<math>| Q | = \left| {\small\frac{1 - a_{r + 2}}{4}} \right| \leqslant {\small\frac{| a_{r + 2} | + 1}{4}} = {\small\frac{2 r + 6}{4}} < 2 r + 7 \leqslant q</math>
 
 
Przedostatnia (ostra) nierówność jest prawdziwa dla wszystkich <math>r</math> naturalnych.<br/>
 
&#9633;
 
 
{{\Spoiler}}
 
{{\Spoiler}}
  
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N32</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q16 (zamiana tekstu na liczbę i&nbsp;odwrotnie)</span><br/>
Przyjmując metodę Selfridge'a wyboru parametrów <math>P, Q</math> dla testu Lucasa, możemy łatwo napisać odpowiedni program w&nbsp;PARI/GP testujący pierwszość liczb
+
W przypadku profesjonalnych programów szyfrujących wykorzystujących metodę RSA szyfrowany jest cały plik, który jest przecież ciągiem zer i&nbsp;jedynek. Oprogramowanie dzieli taki plik na odpowiednich rozmiarów bloki <math>B_j</math> i&nbsp;każdy jest szyfrowany kluczem publicznym <math>(m, e)</math>. Możemy w&nbsp;ten sposób szyfrować zdjęcia, filmy, tekst w&nbsp;dowolnym języku itd.
 
 
<span style="font-size: 90%; color:black;">LucasTest(m) =
 
{
 
'''local'''(P, Q, X);
 
'''if'''( m % 2 == 0, '''return'''(m == 2) );
 
'''if'''( '''issquare'''(m), '''return'''(0) ); \\ sprawdzamy, czy m nie jest liczbą kwadratową
 
X = MethodA(m);
 
P = X[1];
 
Q = X[2];
 
'''if'''( P == 0, '''return'''(0) ); \\ jeżeli P = 0, to m jest liczbą złożoną
 
'''if'''( modLucas(m + 1, P, Q, m)[1] == 0, '''return'''(1), '''return'''(0) );
 
}</span>
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Uwaga N33</span><br/>
 
Najmniejsze liczby pseudopierwsze Lucasa, które pojawiają się przy zastosowaniu metody Selfridge'a wyboru parametrów <math>P</math> i <math>Q</math>, to
 
 
 
::<math>323, 377, 1159, 1829, 3827, 5459, 5777, 9071, 9179, 10877, 11419, 11663, 13919, 14839, 16109, 16211, 18407, 18971, 19043, 22499, \ldots</math>
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
 
<span style="font-size: 90%; color:black;">'''forstep'''(k=1, 3*10^4, 2, '''if'''( LucasTest(k) && !'''isprime'''(k), '''print'''(k)) )</span>
 
<br/>
 
{{\Spoiler}}
 
 
 
  
 +
Ponieważ napisanie takiego oprogramowania wykraczałoby poza potrzeby tego omówienia, ale z&nbsp;drugiej strony chcemy udostępnić Czytelnikowi przykłady bardziej skomplikowane niż szyfrowanie słowa <math>\text{YES}</math>, to postanowiliśmy ograniczyć się do szyfrowania tekstu, który zawiera jedynie znaki ASCII<ref name="ASCII"/>.
  
Tabela przedstawia ilość takich liczb nie większych od <math>10^n</math>
+
Aby efektywnie korzystać z&nbsp;szyfrowania RSA potrzebne będą nam programy, które przetworzą taki tekst na liczbę i&nbsp;odwrotnie. Poniżej przedstawiamy dwie bardzo proste funkcje: pierwsza funkcja zamienia znaki ASCII od 32 do 126 na liczbę (każdemu znakowi przypisywane są dwie cyfry), a&nbsp;druga funkcja zamienia wygenerowaną przez pierwszą funkcję liczbę na odpowiadający tej liczbie tekst.
  
::{| class="wikitable plainlinks"  style="font-size: 90%; text-align: right; margin-right: auto;"
+
Założenie, że nasza wiadomość zawiera tylko znaki ASCII od 32 do 126, jest bardzo ważne. Oznacza to, że taki tekst przetworzony przez funkcję <code>TextToNumber()</code> na liczbę, zostanie odtworzony przez funkcję <code>NumberToText()</code> w&nbsp;niezmienionej postaci. Nie będzie tak, jeśli wystąpią inne znaki: każdy z&nbsp;takich znaków zostanie zamieniony na spacje (np. każda polska litera zostanie zamieniona na dwie spacje). Nie oznacza to, że nie można korzystać z&nbsp;tych funkcji, ale jeśli szyfrujemy '''podpisaną''' wiadomość, to zgodność tekstów ma zasadnicze znaczenie.
! <math>\boldsymbol{n}</math> !! <math>\boldsymbol{3}</math> !! <math>\boldsymbol{4}</math> !! <math>\boldsymbol{5}</math> !! <math>\boldsymbol{6}</math> !! <math>\boldsymbol{7}</math> !! <math>\boldsymbol{8}</math> !! <math>\boldsymbol{9}</math>
 
|-
 
| #LPSP <math>< 10^n</math> (metoda Selfridge'a) || <math>2</math> || <math>9</math> || <math>57</math> || <math>219</math> || <math>659</math> || <math>1911</math> || <math>5485</math>
 
|}
 
  
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
  <span style="font-size: 90%; color:black;">'''for'''(n=3, 9, s=0; '''forstep'''(k = 1, 10^n, 2, '''if'''( LucasTest(k) && !'''isprime'''(k), s++ ) ); '''print'''("n= ", n, "  ", s) )</span>
+
  <span style="font-size: 90%; color:black;">TextToNumber( s ) =  
<br/>
+
\\ zamienia znaki ASCII od 32 do 126 na liczbę
{{\Spoiler}}
 
 
 
 
 
 
 
 
 
 
 
== Liczby silnie pseudopierwsze Lucasa ==
 
 
 
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N34</span><br/>
 
Jeżeli <math>p</math> jest liczbą pierwszą nieparzystą taką, że <math>\gcd (p, Q D) = 1</math> oraz <math>p - (D \mid p) = 2^r w</math>, gdzie <math>w</math> jest liczbą nieparzystą, to spełniony jest dokładnie jeden z&nbsp;warunków
 
 
 
::<math>U_w \equiv 0 \pmod{p}</math>
 
 
 
lub
 
 
 
::<math>V_{2^k w} \equiv 0 \pmod{p} \qquad</math> dla pewnego <math>k \in [0, r - 1]</math>
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
Wiemy (zobacz N20), że jeżeli <math>p</math> jest liczbą pierwszą nieparzystą taką, że <math>\gcd (p, Q D) = 1</math>, to <math>p \mid U_{p - (D \mid p)}</math>. Z&nbsp;założenia jest <math>p - (D \mid p) = 2^r w</math>, zatem <math>p \mid U_{2^r w}</math>. Ponieważ założyliśmy, że <math>p \nmid Q</math> i <math>p \nmid D</math>, to ze wzoru <math>V^2_n - D U^2_n = 4 Q^n</math> (zobacz N13 p.14) wynika natychmiast, że <math>p</math> nie może dzielić jednocześnie liczb <math>U_n</math> i <math>V_n</math>.
 
 
 
Korzystając ze wzoru <math>U_{2 n} = U_n V_n</math> (zobacz N13 p.11), otrzymujemy
 
 
 
::{| border="0"
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>p \mid U_{2^r w} \;\; \Longleftrightarrow \;\; p \mid U_{2^{r - 1} w} \cdot V_{2^{r - 1} w} \quad</math> || Jeżeli <math>p \mid V_{2^{r - 1} w}</math>, to twierdzenie jest dowiedzione. Jeżeli <math>p \nmid V_{2^{r - 1} w}</math>, to <math>p \mid U_{2^{r - 1} w}</math>.
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>p \mid U_{2^{r - 1} w} \;\; \Longleftrightarrow \;\; p \mid U_{2^{r - 2} w} \cdot V_{2^{r - 2} w} \quad</math> || Jeżeli <math>p \mid V_{2^{r - 2} w}</math>, to twierdzenie jest dowiedzione. Jeżeli <math>p \nmid V_{2^{r - 2} w}</math>, to <math>p \mid U_{2^{r - 2} w}</math>.
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>.................</math> ||
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>p \mid U_{4 w} \;\; \Longleftrightarrow \;\; p \mid U_{2 w} \cdot V_{2 w}</math> || Jeżeli <math>p \mid V_{2 w}</math>, to twierdzenie jest dowiedzione. Jeżeli <math>p \nmid V_{2 w}</math>, to <math>p \mid U_{2 w}</math>.
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>p \mid U_{2 w} \;\; \Longleftrightarrow \;\; p \mid U_w \cdot V_w</math> || Jeżeli <math>p \mid V_w</math>, to twierdzenie jest dowiedzione. Jeżeli <math>p \nmid V_w</math>, to <math>p \mid U_w</math>.
 
|}
 
 
 
Z powyższego wynika, że musi być spełniony jeden z wypisanych w twierdzeniu warunków.
 
 
 
 
 
Zauważmy teraz, że jeżeli liczba pierwsza <math>p</math> dzieli <math>V_w</math>, to <math>p \nmid U_w</math>, bo <math>p</math> nie może jednocześnie być dzielnikiem liczb <math>U_w</math> i <math>V_w</math>.
 
 
 
Zauważmy też, że jeżeli dla pewnego <math>k \in [1, r - 1]</math> liczba pierwsza <math>p</math> dzieli <math>V_{2^k w}</math>, to <math>p</math> nie dzieli żadnej liczby <math>V_{2^j w}</math> dla <math>j \in [0, k - 1] \;\; \text{i} \;\; p \nmid U_w</math>. Istotnie:
 
 
 
::{| border="0"
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || jeżeli <math>p \mid V_{2^k w}</math>, to <math>p \nmid U_{2^k w} \;\; \text{i} \;\; U_{2^k w} = U_{2^{k - 1} w} V_{2^{k - 1} w}</math>, zatem <math>p</math> nie może być dzielnikiem żadnej z liczb <math>U_{2^{k - 1} w} \;\; \text{i} \;\; V_{2^{k - 1} w}</math>
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || jeżeli <math>p \nmid U_{2^{k - 1} w} \;\; \text{i} \;\; U_{2^{k - 1} w} = U_{2^{k - 2} w} V_{2^{k - 2} w}</math>, to <math>p</math> nie może być dzielnikiem żadnej z liczb <math>U_{2^{k - 2} w} \;\; \text{i} \;\; V_{2^{k - 2} w}</math>
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || <math>.................</math> ||
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || jeżeli <math>p \nmid U_{4 w} \;\; \text{i} \;\; U_{4 w} = U_{2 w} V_{2 w}</math>, to <math>p</math> nie może być dzielnikiem żadnej z liczb <math>U_{2 w} \;\; \text{i} \;\; V_{2 w}</math>
 
|-style=height:3em
 
| &#9679;&nbsp;&nbsp;&nbsp; || jeżeli <math>p \nmid U_{2 w} \;\; \text{i} \;\; U_{2 w} = U_w V_w</math>, to <math>p</math> nie może być dzielnikiem żadnej z liczb <math>U_w \;\; \text{i} \;\; V_w</math>
 
|}
 
 
 
 
 
Co dowodzi, że spełniony jest dokładnie jeden z <math>r + 1</math> warunków:
 
 
 
::<math>U_w \equiv 0 \pmod{p}</math>
 
 
 
::<math>V_{2^k w} \equiv 0 \pmod{p} \qquad</math> gdzie <math>k \in [0, r - 1]</math>
 
 
 
Co należało pokazać.<br/>
 
&#9633;
 
{{\Spoiler}}
 
 
 
 
 
 
 
Konsekwentnie definiujemy liczby pseudopierwsze<br/>
 
<span style="font-size: 110%; font-weight: bold;">Definicja N35</span><br/>
 
Powiemy, że liczba złożona nieparzysta <math>m</math> jest liczbą silnie pseudopierwszą Lucasa (SLPSP) dla parametrów <math>P</math> i <math>Q</math>, jeżeli <math>\gcd (m, Q D) = 1</math> oraz <math>m - (D \mid m) = 2^r w</math>, gdzie <math>w</math> jest liczbą nieparzystą i&nbsp;spełniony jest jeden z&nbsp;warunków
 
 
 
::<math>U_w \equiv 0 \pmod{m}</math>
 
 
 
lub
 
 
 
::<math>V_{2^k w} \equiv 0 \pmod{m} \;</math> dla pewnego <math>k \in [0, r - 1]</math>
 
 
 
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Uwaga N36</span><br/>
 
Każda liczba SLPSP(<math>P, Q</math>) jest LPSP(<math>P, Q</math>). Korzystając ze zdefiniowanych wcześniej funkcji: <code>modPower(a, n, m)</code>, <code>jacobi(a, n)</code> i <code>modLucas(n, P, Q, m)</code> (zobacz M2, J48, N15), możemy napisać prosty program, który sprawdza, czy liczba <math>m</math> spełnia jeden z&nbsp;warunków podanych w&nbsp;twierdzeniu N34.
 
 
 
<span style="font-size: 90%; color: black;">isPrimeOr<span style="background-color: #fee481;">SLPSP</span>(m, P, Q) =
 
 
  {
 
  {
  '''local'''(a, b, c, D, js, k, r, w, X);
+
  '''local'''(a, b, k, len, txt, V);
D = P^2 - 4*Q;
+
  V = '''Vecsmall'''(s);
'''if'''( gcd(m, 2*Q*D) > 1, '''return'''(0) );
+
  len = '''length'''(V);
js = jacobi(D, m);
+
  txt = "";
r = '''valuation'''(m - js, 2); \\ znajdujemy wykładnik, z jakim liczba 2 występuje w m - js
 
w = (m - js) / 2^r;
 
X =  modLucas(w, P, Q, m);
 
a = X[1]; \\ U_w(P, Q) % m
 
b = X[2]; \\ V_w(P, Q) % m
 
  '''if'''( a == 0 || b == 0, '''return'''(1) ); \\ b == 0 to przypadek k == 0
 
  '''if'''( r == 1, '''return'''(0) ); \\ nie ma dalszych przypadków
 
  c = modPower(Q, w, m); \\ Q^w % m
 
 
  k = 0;
 
  k = 0;
\\ sprawdzamy warunek V_(2^k * w) % m = 0; korzystamy ze wzoru V_(2*t) = (V_t)^2 - 2*Q^t
+
  '''while'''( k++ <= len,
  '''while'''( k++ < r,
+
        a = V[k];
         b = (b^2 - 2*c) % m;
+
         b = "01";  \\ spacja – wstawiamy jeżeli a jest poza zakresem
         '''if'''( b == 0, '''return'''(1) );
+
        '''if'''( a >= 32  &&  a <= 40, b = '''Str'''("0", a - 31) );
         c = c^2 % m;
+
         '''if'''( a >= 41  &&  a <= 126, b = '''Str'''(a - 31) );
 +
         txt = '''Str'''(txt, b);
 
       );
 
       );
  '''return'''(0);
+
  '''return'''( '''eval'''(txt) );
 
  }</span>
 
  }</span>
  
 
+
  <span style="font-size: 90%; color:black;">NumberToText( n ) =  
 
 
<span style="font-size: 110%; font-weight: bold;">Przykład N37</span><br/>
 
Poniższa tabela zawiera najmniejsze liczby silnie pseudopierwsze Lucasa dla różnych parametrów <math>P</math> i <math>Q</math>
 
 
 
::{| class="wikitable plainlinks"  style="font-size: 90%; text-align: right; margin-right: auto;"
 
! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<math>\boldsymbol{P}</math><br/><math>\boldsymbol{Q}</math>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 
! <math>\boldsymbol{1}</math> !! <math>\boldsymbol{2}</math> !! <math>\boldsymbol{3}</math> !! <math>\boldsymbol{4}</math> !! <math>\boldsymbol{5}</math> !! <math>\boldsymbol{6}</math> !! <math>\boldsymbol{7}</math> !! <math>\boldsymbol{8}</math> !! <math>\boldsymbol{9}</math> !! <math>\boldsymbol{10}</math>
 
|-
 
! <math>\boldsymbol{- 5}</math>
 
| <math>253</math> || <math>121</math> || style="background-color: yellow" | <math>143</math> || <math>781</math> || style="background-color: yellow" | <math>323</math> || style="background-color: yellow" | <math>299</math> || <math>121</math> || style="background-color: yellow" | <math>407</math> || <math>9</math> || style="background-color: yellow" | <math>143</math>
 
|-
 
! <math>\boldsymbol{- 4}</math>
 
| <math>9</math> || <math>4181</math> || <math>341</math> || <math>169</math> || <math>33</math> || style="background-color: yellow" | <math>119</math> || <math>57</math> || <math>9</math> || <math>9</math> || <math>9</math>
 
|-
 
! <math>\boldsymbol{- 3}</math>
 
| style="background-color: yellow" | <math>799</math> || <math>121</math> || style="background-color: yellow" | <math>527</math> || <math>25</math> || <math>85</math> || style="background-color: yellow" | <math>209</math> || style="background-color: yellow" | <math>55</math> || style="background-color: yellow" | <math>35</math> || <math>169</math> || <math>529</math>
 
|-
 
! <math>\boldsymbol{- 2}</math>
 
| <math>2047</math> || style="background-color: yellow" | <math>989</math> || <math>161</math> || <math>49</math> || <math>49</math> || style="background-color: yellow" | <math>323</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>35</math> || <math>9</math> || <math>265</math>
 
|-
 
! <math>\boldsymbol{- 1}</math>
 
| <math>4181</math> || <math>169</math> || style="background-color: yellow" | <math>119</math> || <math>9</math> || <math>9</math> || style="background-color: yellow" | <math>629</math> || <math>25</math> || <math>33</math> || <math>9</math> || style="background-color: yellow" | <math>51</math>
 
|-
 
! <math>\boldsymbol{1}</math>
 
| <math>25</math> || style="background-color: red" | <math></math> || style="background-color: yellow" | <math>323</math> || style="background-color: yellow" | <math>209</math> || style="background-color: yellow" | <math>527</math> || style="background-color: yellow" | <math>35</math> || style="background-color: yellow" | <math>323</math> || style="background-color: yellow" | <math>559</math> || <math>9</math> || <math>49</math>
 
|-
 
! <math>\boldsymbol{2}</math>
 
| style="background-color: yellow" | <math>5459</math> || <math>9</math> || <math>2047</math> || <math>169</math> || <math>21</math> || <math>253</math> || <math>9</math> || style="background-color: yellow" | <math>15</math> || <math>9</math> || <math>49</math>
 
|-
 
! <math>\boldsymbol{3}</math>
 
| style="background-color: yellow" | <math>899</math> || style="background-color: yellow" | <math>5983</math> || <math>25</math> || <math>121</math> || <math>49</math> || <math>49</math> || style="background-color: yellow" | <math>35</math> || <math>55</math> || <math>25</math> || style="background-color: yellow" | <math>35</math>
 
|-
 
! <math>\boldsymbol{4}</math>
 
| style="background-color: yellow" | <math>899</math> || <math>25</math> || <math>1541</math> || style="background-color: red" | <math></math> || <math>341</math> || style="background-color: yellow" | <math>323</math> || style="background-color: yellow" | <math>377</math> || style="background-color: yellow" | <math>209</math> || <math>9</math> || style="background-color: yellow" | <math>527</math>
 
|-
 
! <math>\boldsymbol{5}</math>
 
| <math>9</math> || style="background-color: yellow" | <math>527</math> || <math>49</math> || style="background-color: yellow" | <math>527</math> || <math>4181</math> || <math>781</math> || style="background-color: yellow" | <math>39</math> || <math>9</math> || <math>9</math> || <math>9</math>
 
|}
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
 
  <span style="font-size: 90%; color:black;">FirstSLPSP(Stop) =  
 
\\ najmniejsze SLPSP(P,Q) < Stop;  dla 1<=P<=10 i -5<=Q<=5
 
 
  {
 
  {
  '''local'''(D, m, P, Q);
+
  '''local'''(a, k, len, txt, V);
  Q = -6;
+
  len = '''length'''('''Str'''(n));
'''while'''( Q++ <= 5,
+
'''if'''( len % 2 == 1, len++ ); \\ "zgubione" zero na początku
        '''if'''( Q == 0, '''next'''() );
+
len = len / 2;
        P = 0;
+
V = '''vector'''(len);
        '''while'''( P++ <= 10,
+
k = len + 1;
              D = P^2 - 4*Q;
+
'''while'''( k-- >= 1,
              '''if'''( D == 0,  
+
        a = n % 100;
                  '''print'''("Q= ", Q, "  P= ", P, "  ------------------");
+
        n = '''floor'''(n / 100);
                  '''next'''();
+
        V[k] = a + 31;
                );
 
              m = 3;
 
              '''while'''( m < Stop,
 
                      '''if'''( isPrimeOr<span style="background-color: #fee481;">SLPSP</span>(m, P, Q)  &&  !'''isprime'''(m),  
 
                          '''print'''("Q= ", Q, "  P= ", P, "  m= ", m, "  (D|m)= ", jacobi(D, m));
 
                          '''break'''();
 
                        );
 
                      m = m + 2;
 
                    );
 
            );
 
 
       );
 
       );
 +
txt = '''strchr'''(V);
 +
'''return'''(txt);
 
  }</span>
 
  }</span>
 
<br/>
 
<br/>
 
{{\Spoiler}}
 
{{\Spoiler}}
  
Żółtym tłem oznaczyliśmy te najmniejsze liczby pseudopierwsze Lucasa, dla których <math>(D \mid m) = - 1</math>.
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Przykład N38</span><br/>
 
Ilość liczb SLPSP(<math>P, Q</math>) mniejszych od <math>10^9</math>
 
 
::{| class="wikitable plainlinks"  style="font-size: 90%; text-align: right; margin-right: auto;"
 
! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<math>\boldsymbol{P}</math><br/><math>\boldsymbol{Q}</math>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 
! <math>\boldsymbol{1}</math> !! <math>\boldsymbol{2}</math> !! <math>\boldsymbol{3}</math> !! <math>\boldsymbol{4}</math> !! <math>\boldsymbol{5}</math> !! <math>\boldsymbol{6}</math> !! <math>\boldsymbol{7}</math> !! <math>\boldsymbol{8}</math> !! <math>\boldsymbol{9}</math> !! <math>\boldsymbol{10}</math>
 
|-
 
! <math>\boldsymbol{- 5}</math>
 
| <math>1056</math> || <math>1231</math> || <math>1184</math> || <math>1264</math> || <math>2278</math> || <math>1284</math> || <math>1181</math> || <math>1174</math> || <math>1281</math> || <math>1429</math>
 
|-
 
! <math>\boldsymbol{- 4}</math>
 
| <math>1043</math> || <math>1165</math> || <math>2139</math> || <math>1316</math> || <math>1151</math> || <math>1079</math> || <math>1112</math> || <math>2377</math> || <math>1197</math> || <math>989</math>
 
|-
 
! <math>\boldsymbol{- 3}</math>
 
| <math>952</math> || <math>1514</math> || <math>1055</math> || <math>1153</math> || <math>1135</math> || <math>2057</math> || <math>998</math> || <math>1202</math> || <math>1077</math> || <math>1112</math>
 
|-
 
! <math>\boldsymbol{- 2}</math>
 
| <math>1282</math> || <math>1092</math> || <math>1212</math> || <math>1510</math> || <math>1155</math> || <math>1179</math> || <math>1173</math> || <math>2240</math> || <math>1089</math> || <math>2109</math>
 
|-
 
! <math>\boldsymbol{- 1}</math>
 
| <math>1165</math> || <math>1316</math> || <math>1079</math> || <math>2377</math> || <math>989</math> || <math>1196</math> || <math>1129</math> || <math>1050</math> || <math>1055</math> || <math>1147</math>
 
|-
 
! <math>\boldsymbol{1}</math>
 
| <math>282485800</math> || style="background-color: red" | <math></math> || <math>2278</math> || <math>2057</math> || <math>2113</math> || <math>2266</math> || <math>4053</math> || <math>2508</math> || <math>2285</math> || <math>3083</math>
 
|-
 
! <math>\boldsymbol{2}</math>
 
| <math>1776</math> || <math>449152466</math> || <math>1282</math> || <math>1316</math> || <math>1645</math> || <math>1413</math> || <math>1564</math> || <math>1595</math> || <math>1683</math> || <math>1435</math>
 
|-
 
! <math>\boldsymbol{3}</math>
 
| <math>1621</math> || <math>1553</math> || <math>282485800</math> || <math>1514</math> || <math>1530</math> || <math>1510</math> || <math>1588</math> || <math>1549</math> || <math>1468</math> || <math>1692</math>
 
|-
 
! <math>\boldsymbol{4}</math>
 
| <math>2760</math> || <math>282485800</math> || <math>2978</math> || style="background-color: red" | <math></math> || <math>2137</math> || <math>2278</math> || <math>1995</math> || <math>2057</math> || <math>2260</math> || <math>2113</math>
 
|-
 
! <math>\boldsymbol{5}</math>
 
| <math>1314</math> || <math>2392</math> || <math>1497</math> || <math>2392</math> || <math>1165</math> || <math>1268</math> || <math>1227</math> || <math>1411</math> || <math>1253</math> || <math>2377</math>
 
|}
 
  
  
 +
<span style="font-size: 110%; font-weight: bold;">Uwaga Q17</span><br/>
 +
Jeżeli mamy już funkcje zamieniające tekst na liczbę i&nbsp;odwrotnie, to napisanie w&nbsp;PARI/GP programów do szyfrowania i&nbsp;deszyfrowania metodą RSA jest bardzo proste.
  
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
  <span style="font-size: 90%; color:black;">NumOfSLPSP(Stop) =  
+
  <span style="font-size: 90%; color:black;">RSAencode(m, e, s) =  
  \\ ilość liczb silnie pseudopierwszych Lucasa SLPSP(P,Q) < Stop;  dla 1<=P<=10 i -5<=Q<=5
+
  \\ szyfrujemy string s
 
  {
 
  {
  '''local'''(D, m, P, Q);
+
  '''local'''(B, C);
  Q = -6;
+
  B = TextToNumber(s);
'''while'''( Q++ <= 5,
+
C = '''lift'''( '''Mod'''(B, m)^e );
        '''if'''( Q == 0, '''next'''() );
+
  '''print'''(C);
        P = 0;
 
        '''while'''( P++ <= 10,
 
              D = P^2 - 4*Q;
 
              '''if'''( D == 0, '''print'''("Q= ", Q, "  P= ", P, "  ------------------"); '''next'''() );
 
              s = 0;
 
              m = 3;
 
              '''while'''( m < Stop,
 
                      '''if'''( isPrimeOr<span style="background-color: #fee481;">SLPSP</span>(m, P, Q) &&  !'''isprime'''(m), s++ );
 
                      m = m + 2;
 
                    );
 
              '''print'''("Q= ", Q, "  P= ", P, "  s= ", s);
 
            );
 
      );
 
 
  }</span>
 
  }</span>
<br/>
 
{{\Spoiler}}
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Uwaga N39</span><br/>
 
Można pokazać<ref name="Arnault1"/>, że dla liczby złożonej nieparzystej <math>m \neq 9</math> i&nbsp;ustalonego <math>D</math> ilość par <math>P, Q</math> takich, że
 
 
:* <math>0 \leqslant P, Q < m</math>
 
:* <math>\gcd (Q, m) = 1</math>
 
:* <math>P^2 - 4 Q \equiv D \pmod{m}</math>
 
:* <math>m</math> jest SLPSP(<math>P, Q</math>)
 
 
nie przekracza <math>\tfrac{4}{15} n</math>.
 
 
Nie dotyczy to przypadku, gdy <math>m = p (p + 2)</math> jest iloczynem liczb pierwszych bliźniaczych takich, że <math>(D \mid p) = - (D \mid p + 2) = - 1</math>, wtedy mamy słabsze oszacowanie: <math>\# (P, Q) \leqslant \tfrac{1}{2} n</math>. Zauważmy, że taką sytuację łatwo wykryć, bo w&nbsp;tym przypadku <math>m + 1 = (p + 1)^2</math> jest liczbą kwadratową.
 
 
 
 
<span style="font-size: 110%; font-weight: bold;">Uwaga N40</span><br/>
 
Podobnie jak w&nbsp;przypadku liczb pseudopierwszych Lucasa LPSP(<math>P, Q</math>) tak i&nbsp;w&nbsp;przypadku liczb silnie pseudopierwszych Lucasa SLPSP(<math>P, Q</math>) możemy testować pierwszość liczby <math>m</math>, wybierając liczby <math>P, Q</math> losowo lub zastosować wybraną metodę postępowania. Przedstawiony poniżej program, to zmodyfikowany kod z uwagi N36. Teraz parametry <math>P, Q</math> są wybierane metodą Selfridge'a, a symbol Jacobiego <math>(D \mid m)</math> jest równy <math>- 1</math>.
 
  
  <span style="font-size: 90%; color:black;">StrongLucasTest(m) =
+
  <span style="font-size: 90%; color:black;">RSAdecode(m, d, C) =  
 +
\\ deszyfrujemy liczbę C
 
  {
 
  {
  '''local'''(a, b, c, k, P, Q, r, w, X);
+
  '''local'''(B, s);
'''if'''( m % 2 == 0, '''return'''(m == 2) );
+
  B = '''lift'''( '''Mod'''(C, m)^d );
'''if'''( '''issquare'''(m), '''return'''(0) ); \\ sprawdzamy, czy liczba m nie jest kwadratowa
+
  s = NumberToText(B);
X = MethodA(m);
+
  '''print'''(s);
P = X[1];
 
Q = X[2];
 
'''if'''( P == 0 || '''gcd'''(m, 2*Q) > 1, '''return'''(0) ); \\ jeżeli P = 0, to m jest liczbą złożoną
 
r = '''valuation'''(m + 1, 2); \\ znajdujemy wykładnik, z jakim liczba 2 występuje w m + 1
 
w = (m + 1) / 2^r;
 
  X =  modLucas(w, P, Q, m);
 
a = X[1]; \\ U_w(P, Q) % m
 
b = X[2]; \\ V_w(P, Q) % m
 
'''if'''( a == 0 || b == 0, '''return'''(1) ); \\ b == 0 to przypadek k == 0
 
'''if'''( r == 1, '''return'''(0) ); \\ nie ma dalszych przypadków
 
c = modPower(Q, w, m); \\ Q^w % m
 
k = 0;
 
\\ sprawdzamy warunek V_(2^k * w) %m = 0; korzystamy ze wzoru V_(2*w) = (V_w)^2 - 2*Q^w
 
  '''while'''( k++ < r,
 
        b = (b^2 - 2*c) % m;
 
        '''if'''( b == 0, '''return'''(1) );
 
        c = c^2 % m;
 
      );
 
  '''return'''(0);
 
 
  }</span>
 
  }</span>
 +
<br/>
 +
{{\Spoiler}}
  
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N41</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q18</span><br/>
Najmniejsze liczby silnie pseudopierwsze Lucasa, które otrzymujemy po zastosowaniu metody Selfridge'a wyboru parametrów <math>P</math> i <math>Q</math>, to
+
Kładąc <code>w = 50</code> w&nbsp;funkcji <code>RSAkeys(w)</code> otrzymaliśmy
  
::<math>5459, 5777, 10877, 16109, 18971, 22499, 24569, 25199, 40309, 58519, 75077, 97439, \ldots</math>
+
m = 2173471545652309346779542101680852446325835148920429701148920590128959176663355134192839060494750117<br/>
 +
e = 3675359337253<br/>
 +
d = 308186586218659991253427464678921309369969889382350078327142348395702895999753492453847408362677933<br/>
  
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
+
Liczba m&nbsp;ma 100 cyfr. Podamy teraz prosty przykład z&nbsp;polskimi literami. Zakodujemy i&nbsp;odkodujemy tekst (35 znaków)
<span style="font-size: 90%; color:black;">'''forstep'''(k=1, 10^5, 2, '''if'''( StrongLucasTest(k) && !'''isprime'''(k), '''print'''(k)) )</span>
 
<br/>
 
{{\Spoiler}}
 
  
 +
''Lepszy na wolności kęsek lada jaki.''
  
Tabela przedstawia ilość takich liczb nie większych od <math>10^n</math>
+
Zamieniając tekst na liczbę – funkcją <code>TextToNumber(s)</code> – otrzymujemy liczbę 74-cyfrową
  
::{| class="wikitable plainlinks"  style="font-size: 90%; text-align: right; margin-right: auto;"
+
B = 45708184919001796601888077798001016874017601018470760177666966017566767415
! <math>\boldsymbol{n}</math> !! <math>\boldsymbol{3}</math> !! <math>\boldsymbol{4}</math> !! <math>\boldsymbol{5}</math> !! <math>\boldsymbol{6}</math> !! <math>\boldsymbol{7}</math> !! <math>\boldsymbol{8}</math> !! <math>\boldsymbol{9}</math>
 
|-
 
| #SLPSP <math>< 10^n</math> (metoda Selfridge'a) || <math>0</math> || <math>2</math> || <math>12</math> || <math>58</math> || <math>178</math> || <math>505</math> || <math>1415</math>
 
|}
 
 
 
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
 
<span style="font-size: 90%; color:black;">'''for'''(n=3, 9, s=0; '''forstep'''(k = 1, 10^n, 2, '''if'''( StrongLucasTest(k) && !'''isprime'''(k), s++ ) ); '''print'''("n=", n, "  ", s) )</span>
 
<br/>
 
{{\Spoiler}}
 
  
 +
Jest tak, bo każdy znak tekstu został zamieniony na dwie cyfry, ale każda z&nbsp;polskich liter "ś" i "ę" została zamieniona na dwie spacje i&nbsp;każdej z&nbsp;tych liter odpowiadają cztery cyfry "0101". Zauważmy, że B&nbsp;<&nbsp;m tak, jak być powinno.
  
 +
Korzystając z&nbsp;funkcji <code>RSAencode(m, e, s)</code>, dostajemy od razu zakodowany tekst
  
 +
C = 1883258467778511884133977054466089742750188942420326552221154007622797635139655819975338109849673552
  
 +
Po odkodowaniu funkcją <code>RSAdecode(m, d, C)</code>, otrzymujemy
  
== Test BPSW ==
+
''Lepszy na wolno&nbsp;&nbsp;ci k&nbsp;&nbsp;sek lada jaki.''
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N42</span><br/>
+
Polskie litery zostały zastąpione przez dwie spacje.
Jest <math>488</math> liczb SPSP(<math>2</math>) mniejszych od <math>10^8</math> i są 582 liczby SPSP(<math>3</math>) mniejsze od <math>10^8</math> (zobacz M21). Ale jest aż <math>21</math> liczb mniejszych od <math>10^8</math> silnie pseudopierwszych jednocześnie względem podstaw <math>2</math> i <math>3</math>:
 
  
<math>1373653, 1530787, 1987021, 2284453, 3116107, 5173601, 6787327, 11541307, 13694761, 15978007, 16070429,</math>
 
  
<math>16879501, 25326001, 27509653, 27664033, 28527049, 54029741, 61832377, 66096253, 74927161, 80375707</math>
+
Czytelnikowi pozostawiamy odszyfrowanie podanej niżej zakodowanej wiadomości. Ze względu na rozmiar musieliśmy podzielić tekst i&nbsp;otrzymaliśmy trzy zakodowane bloki.
  
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Pokaż kod|Hide=Ukryj kod}}
+
C<sub>1</sub> = 1228411078235780067165277802337600665865387220034514894292654793454492777859429937501850347835450261<br/>
<span style="font-size: 90%; color:black;">'''forstep'''(m=3, 10^8, 2, '''if'''( isPrimeOr<span style="background-color: #fee481;">SPSP</span>(m, 2)  &&  isPrimeOr<span style="background-color: #fee481;">SPSP</span>(m, 3)  &&  !'''isprime'''(m), '''print'''("m=", m) ) )</span>
+
C<sub>2</sub> = 1212270919532485597119464911345613794658433495925582794819870422454753698249874400827689168074862675<br/>
<br/>
+
C<sub>3</sub> = 1407997868763350498310642273976637553443290951270357250985396471705600151258961305510222246198960667<br/>
{{\Spoiler}}
 
  
Widzimy, że prawdopodobieństwo błędnego rozpoznania pierwszości w&nbsp;przypadku liczb mniejszych od <math>10^8</math> dla podstawy <math>2</math> lub podstawy <math>3</math> jest rzędu kilku milionowych. Gdyby prawdopodobieństwa błędnego rozpoznania pierwszości w&nbsp;przypadku podstawy <math>2</math> lub podstawy <math>3</math> były niezależne, to spodziewalibyśmy się, że nie będzie wcale liczb mniejszych od <math>10^8</math> silnie pseudopierwszych jednocześnie względem podstaw <math>2</math> i <math>3</math>, bo prawdopodobieństwo takiego zdarzenia byłoby równe kilkudziesięciu bilonowym. Ale tak nie jest.
 
  
Jest to mocny argument za tym, że zastosowanie różnych (niezależnych) testów może być znacznie silniejszym narzędziem do testowania pierwszości liczb, niż wielokrotne stosowanie tego samego testu, gdzie poszczególne próby są tylko pozornie niezależne.
 
  
Połączenie znanych nam już testów prowadzi do prostego programu
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q19</span><br/>
 +
Omówiliśmy dokładnie metodę szyfrowania RSA i&nbsp;Czytelnik powinien mieć już jasność, że metodą tą możemy szyfrować tylko liczby. Jeśli chcemy zaszyfrować tekst, to musi najpierw zostać zapisany w&nbsp;postaci liczby (ciągu cyfr). Podaliśmy też dwie proste metody takiej zamiany (zobacz Q13 i&nbsp;Q16).
  
<span style="font-size: 90%; color:black;">BPSWtest(m) =
+
W dalszej części artykułu pisząc o&nbsp;szyfrowaniu metodą RSA, będziemy mieli najczęściej na myśli dwie czynności wykonywanie łącznie: zamianę tekstu na liczbę (ustaloną wcześniej metodą) i&nbsp;właściwą operację szyfrowania. Podobnie pisząc o&nbsp;odszyfrowaniu, też zazwyczaj będziemy mieli myśli dwie czynności: właściwą operację odszyfrowywania i&nbsp;zamianę otrzymanej liczby na tekst.
{
 
'''forprime'''(p = 2, 1000, '''if'''( m % p > 0, '''next'''() ); '''if'''( m == p, '''return'''(1), '''return'''(0) ));
 
'''if'''( !isPrimeOr<span style="background-color: #fee481;">SPSP</span>(m, 2), '''return'''(0) );
 
'''if'''( !StrongLucasTest(m), '''return'''(0), '''return'''(1) );
 
}</span>
 
  
  
  
Funkcja <code>BPSWtest(m)</code> kolejno sprawdza:
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q20</span><br/>
 +
Zwróćmy uwagę na to, że w&nbsp;przypadku pomyłki i&nbsp;zaszyfrowania wiadomości naszym kluczem prywatnym <math>(m, d)</math> możliwe będzie jej odczytanie przez każdą osobę, która zna nasz klucz publiczny <math>(m, e)</math>. Istotnie, niech <math>C = R_m (B^d)</math>. Łatwo pokażemy, że <math>B = R_m (C^e)</math>.
  
:* czy liczba <math>m</math> jest podzielna przez niewielkie liczby pierwsze (w naszym przypadku mniejsze od <math>1000</math>); jeśli tak, to sprawdza, czy <math>m</math> jest liczbą pierwszą, czy złożoną i&nbsp;zwraca odpowiednio <math>1</math> lub <math>0</math>
+
::<math>R_m (C^e) \equiv C^e \equiv (B^d)^e \equiv B^{e d} \equiv B^{- k \Phi + 1} \equiv B^{- k (p - 1) (q - 1) + 1} \equiv B \!\! \pmod{m}</math>
:* czy liczba <math>m</math> przechodzi test Millera-Rabina dla podstawy <math>2</math>; jeśli nie, to zwraca <math>0</math>
 
:* czy liczba <math>m</math> przechodzi silny test Lucasa dla parametrów <math>P</math> i <math>Q</math>, które wybieramy metodą Selfridge'a; jeśli nie, to zwraca <math>0</math>, w&nbsp;przeciwnym wypadku zwraca <math>1</math>
 
  
 +
Fakt ten wykorzystamy do stworzenia podpisu wiadomości.
  
Test w&nbsp;dokładnie takiej postaci zaproponowali Robert Baillie i&nbsp;Samuel Wagstaff<ref name="BaillieWagstaff1"/>. Nazwa testu to akronim, utworzony od pierwszych liter nazwisk Roberta Bailliego, Carla Pomerance'a, Johna Selfridge'a i&nbsp;Samuela Wagstaffa.
 
  
Nie jest znany żaden przykład liczby złożonej <math>m</math>, którą test BPSW<ref name="BPSW1"/><ref name="BPSW2"/> identyfikowałby jako pierwszą i&nbsp;z&nbsp;pewnością nie ma takich liczb dla <math>m < 2^{64} \approx 1.844 \cdot 10^{19}</math>. Warto przypomnieć: potrzebowaliśmy siedmiu testów Millera-Rabina (dla podstaw <math>2, 3, 5, 7, 11, 13, 17</math>), aby mieć pewność, że dowolna liczba <math>m < 3.41 \cdot 10^{14}</math> jest pierwsza (zobacz M22).
 
  
  
  
 +
== Kryptograficzne funkcje haszujące ==
  
 +
<span style="font-size: 110%; font-weight: bold;">Definicja Q21</span><br/>
 +
Funkcja haszująca<ref name="hashfunction1"/> przypisuje każdemu ciągowi bitów o&nbsp;dowolnej (ale skończonej) długości ciąg bitów o&nbsp;stałej długości.
  
== Uzupełnienia ==
 
  
&nbsp;
 
  
=== <span style="border-bottom:1px solid #000;">Pewne własności współczynników dwumianowych</span> ===
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q22</span><br/>
 +
Bardzo prosta funkcja haszująca przypisuje każdemu ciągowi osiem pierwszych bitów tego ciągu (w przypadku, gdy ciąg jest za krótki, wystarczy powtórzyć go odpowiednią liczbę razy). Tak określona funkcja nie jest dobrą funkcją haszującą i&nbsp;ze wszystkich wymagań (które wymienimy niżej) spełnia tylko jeden: możemy szybko obliczyć wynik.
  
&nbsp;
+
Innym przykładem funkcji haszującej może być funkcja, która oblicza sumę kodów ASCII kolejnych znaków modulo <math>256</math>. Ta funkcja, podobnie jak poprzednia, jedynie szybko oblicza wynik.
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N43</span><br/>
+
Druga funkcja jest lepsza od pierwszej, bo każdy znak tekstu wpływa na uzyskany wynik. Co prawda ciągi znaków, których suma kodów ASCII wynosi 256 (np. "8dd") możemy dodawać bezkarnie, jednak uwzględniając, że wiadomość nie jest ciągiem przypadkowych znaków, modyfikacja wiadomości tak, aby hasz pozostał niezmieniony, będzie wymagała pewnego wysiłku.
Jeżeli <math>p</math> jest liczbą pierwszą, to
 
  
::<math>\binom{p}{k} \equiv 0 \pmod{p}</math>
 
  
dla każdego <math>k \in [1, p - 1]</math>.
 
  
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q23</span><br/>
Łatwo zauważamy, że dla <math>k \in [1, p - 1]</math> liczba pierwsza <math>p</math> dzieli licznik, ale nie dzieli mianownika współczynnika dwumianowego
+
Od dobrej funkcji haszującej oczekujemy, że będzie spełniała następujące warunki
  
::<math>\binom{p}{k} = {\small\frac{p!}{k! \cdot (p - k)!}}</math>
+
:* będzie szybko obliczać wynik
 +
:* (jednokierunkowość) dla zadanej wartości hasza <math>h</math> znalezienie jakiegokolwiek ciągu bitów <math>m</math> takiego, że <math>h = \mathop{\text{hash}}(m)</math> powinno być bardzo trudne
 +
:* (słaba odporność na kolizje) dla zadanego ciągu bitów <math>m_1</math> znalezienie jakiegokolwiek ciągu bitów <math>m_2 \neq m_1</math> takiego, że <math>\mathop{\text{hash}}(m_2) = \mathop{\text{hash}}(m_1)</math> powinno być bardzo trudne
 +
:* (silna odporność na kolizje) znalezienie jakichkolwiek dwóch ciągów bitów <math>m_1</math> i <math>m_2</math> takich, że <math>\mathop{\text{hash}}(m_1) = \mathop{\text{hash}}(m_2)</math> powinno być bardzo trudne
  
zatem <math>p \biggr\rvert \binom{p}{k}</math>. Co należało pokazać.<br/>
+
W praktyce oznacza to, że jeżeli dwa łańcuchy mają taki sam hasz, to są one identyczne. To właśnie ta własność decyduje o&nbsp;przydatności funkcji haszującej dla podpisu elektronicznego i&nbsp;innych zastosowań.
&#9633;
 
{{\Spoiler}}
 
  
  
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N44</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q24 (zastosowanie funkcji haszujących)</span><br/>
Jeżeli <math>p</math> jest liczbą pierwszą nieparzystą, to
+
Jeśli chcemy upewnić się, czy przesłana mailem wiadomość nie zastała zmieniona, to wystarczy, że telefonicznie podamy odbiorcy hasz wiadomości.
  
::<math>\binom{p + 1}{k} \equiv 0 \pmod{p}</math>
+
Hasło podawane przy logowaniu powinno być haszowane, a&nbsp;system powinien przechowywać jedynie hasz hasła tak, aby samo hasło pozostawało nikomu nieznane.
  
dla każdego <math>k \in [2, p - 1]</math>.
+
Udostępniając do pobrania plik, możemy udostępnić również jego hasz. Umożliwi to łatwe sprawdzenie użytkownikowi, czy pobrany plik nie został uszkodzony.
  
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
 
Jeżeli <math>k \in [2, p - 1]</math>, to modulo <math>p</math> dostajemy
 
  
::<math>\binom{p + 1}{k} = \binom{p}{k} + \binom{p}{k - 1} \equiv 0 \pmod{p}</math>
 
  
Bo liczba pierwsza <math>p</math> dzieli licznik, ale nie dzieli mianownika współczynników dwumianowych po prawej stronie. Co należało pokazać.<br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q25 (przykłady funkcji haszujących)</span><br/>
&#9633;
+
Istnieje wiele wykorzystywanych w&nbsp;praktyce funkcji haszujących. Najbardziej znane to: CRC<ref name="CRC"/>, MD5<ref name="MD5"/>, SHA-1<ref name="SHA1"/> oraz funkcje ze standardu SHA-2<ref name="SHA2"/>: SHA-224, SHA-256, SHA-384, SHA-512
{{\Spoiler}}
 
  
 +
Linux udostępnia wypisane wyżej funkcje jako cksum (CRC), md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum.
  
 +
Na stronie [https://emn178.github.io/online-tools/ GitHub – Online Tools] znajdziemy wiele funkcji haszujących. Możemy policzyć wartości wybranej funkcji dla dowolnego tekstu i&nbsp;dla plików. Zauważmy, że wiele edytorów tekstu automatycznie dodaje znak końca linii<ref name="konieclinii"/> (LF) o&nbsp;kodzie ASCII równym 10 (szesnastkowo 0a) na końcu pliku. Może to powodować różnice przy obliczaniu hasza dla tekstu i&nbsp;dla pliku tekstowego zawierającego ten sam tekst.
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N45</span><br/>
 
Jeżeli <math>p</math> jest liczbą pierwszą, to
 
  
::<math>\binom{p - 1}{k} \equiv (- 1)^k \pmod{p}</math>
 
  
dla każdego <math>k \in [0, p - 1]</math>.
+
<span style="font-size: 110%; font-weight: bold;">Przykład Q26</span><br/>
 +
Dla przykładu rozważmy, często używaną, funkcję haszującą SHA-256. Generuje ona 256-bitowy hasz, który zapisujemy, podając 64 cyfry w&nbsp;zapisie szesnastkowym. Każdą cyfrę w&nbsp;układzie szesnastkowym można zapisać w&nbsp;postaci 4 zer i&nbsp;jedynek w&nbsp;układzie dwójkowym (czterech bitów).
  
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
+
::<math>0 = 0000, \ldots, 9 = 1001, a = 1010, \ldots, f = 1111</math>
Łatwo sprawdzamy, że twierdzenie jest prawdziwe dla liczby pierwszej parzystej <math>p = 2</math>. Załóżmy, że <math>p</math> jest liczbą pierwszą nieparzystą. Równie łatwo sprawdzamy, że twierdzenie jest prawdziwe dla <math>k = 0</math> i <math>k = 1</math>. Zauważmy, że dla <math>k \in [1, p - 1]</math> jest
 
  
::<math>\binom{p - 1}{k} = {\small\frac{(p - 1) !}{k! (p - 1 - k) !}} = {\small\frac{p - k}{k}} \cdot {\small\frac{(p - 1) !}{(k - 1) ! (p - k) !}} = {\small\frac{p - k}{k}} \cdot \binom{p - 1}{k - 1} = {\small\frac{p}{k}} \cdot \binom{p - 1}{k - 1} - \binom{p - 1}{k - 1}</math>
+
Dla tekstu
  
Ponieważ współczynniki dwumianowe są liczbami całkowitymi, a&nbsp;liczba <math>k \in [2, p - 1]</math> nie dzieli liczby pierwszej nieparzystej <math>p</math>, to <math>k</math> musi dzielić liczbę <math>\binom{p - 1}{k - 1}</math>. Zatem dla <math>k \in [2, p - 1]</math> modulo <math>p</math> mamy
+
''Polskie litery i cyfry: ąćęłńóśźżĄĆĘŁŃÓŚŹŻ 0123456789''
  
::<math>\binom{p - 1}{k} \equiv - \binom{p - 1}{k - 1}\pmod{p}</math>
+
otrzymujemy hasz
  
Skąd otrzymujemy
+
5a86397d5e16611466e82376cc9f4d367ecbcd4af6d4418a5d3a130e8ad9d98d
  
::<math>\binom{p - 1}{k} \equiv (- 1)^1 \binom{p - 1}{k - 1} \equiv (- 1)^2 \binom{p - 1}{k - 2} \equiv \ldots \equiv (- 1)^{k - 2} \binom{p - 1}{2} \equiv (- 1)^{k - 1} \binom{p - 1}{1} \equiv (- 1)^k \pmod{p}</math>
+
Czytelnik powinien zwrócić uwagę, że nawet niewielka zmiana tekstu (np. zmiana lub dodanie jednego znaku) spowoduje wygenerowanie zupełnie innego hasza.
  
Co należało pokazać. Zobacz też zadanie H22.<br/>
 
&#9633;
 
{{\Spoiler}}
 
  
  
  
<span style="font-size: 110%; font-weight: bold;">Twierdzenie N46</span><br/>
 
Dla współczynników dwumianowych prawdziwe są następujące wzory
 
  
::<math>\underset{k \; \text{parzyste}}{\sum_{k = 0}^{n}} \binom{n}{k} = 2^{n - 1}</math>
+
== Podpisywanie dokumentów jawnych ==
  
::<math>\underset{k \; \text{nieparzyste}}{\sum_{k = 1}^{n}} \binom{n}{k} = 2^{n - 1}</math>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q27</span><br/>
 +
Zauważmy, że przekazywanie wiadomości (jawnych lub nie) wymaga wcześniejszego ustalenia sposobu komunikowania się. Może to być konto mailowe (jawne lub używane tylko do kontaktów tajnych), umówiona skrytka itd. Wynika stąd, że odbiorca zawsze zna nadawcę (wie, od kogo otrzymał przesyłkę).
  
{{Spoiler|Style = font-style: italic; font-weight: bold; color: olive; text-decoration: underline;|Show=Dowód|Hide=Ukryj dowód}}
+
Ponieważ musimy liczyć się z&nbsp;tym, że ustalony kanał łączności może zostać przejęty, a&nbsp;przekaz zmieniony, to stosujemy różnego rodzaju zabezpieczenia, których celem jest ochrona integralności przekazu.
Ze wzoru dwumianowego
 
  
::<math>(a + b)^n = \sum_{k = 0}^{n} \binom{n}{k} a^{n - k} b^k</math>
 
  
z łatwością otrzymujemy
 
  
::<math>(1 + 1)^n = \sum_{k = 0}^{n} \binom{n}{k} = 2^n</math>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q28</span><br/>
 +
Powiedzmy, że Bolek chce przekazać ważny dokument do Urzędu. Jednak Urząd chce mieć pewność, że tak ważny dokument rzeczywiście sporządził Bolek, a&nbsp;nie ktoś inny, kto tylko pod Bolka się podszywa. Oczywiście można taki dokument przekazać osobiście, ale co zrobić w&nbsp;sytuacji, gdy jest to niemożliwe, a&nbsp;dostępny jest internet?
  
::<math>(1 - 1)^n = \sum_{k = 0}^{n} (- 1)^k \binom{n}{k} = 0</math>
+
Jeśli Bolek potrafi szyfrować wiadomości metodą RSA i&nbsp;udostępnił swój klucz publiczny <math>(m, e)</math> Urzędowi, to może postąpić następująco
  
Obliczając sumę i&nbsp;różnicę powyższych wzorów mamy
+
:# sporządzić ów ważny dokument (powiedzmy DokB) w&nbsp;postaci pliku (ewentualnie papierowy dokument zeskanować)
 +
:# obliczyć hasz pliku DokB: <math>\; h_B = \mathop{\text{SHA256}}( \text{DokB} )</math>
 +
:# zaszyfrować hasz <math>h_B</math> swoim '''kluczem prywatnym''' <math>(m, d)</math> (zobacz Q20)
 +
:#* zaszyfrowany hasz <math>h_B</math> jest podpisem Bolka (co za chwilę stanie się jasne)
 +
:# tak zaszyfrowany hasz wpisać w&nbsp;treści maila i&nbsp;załączyć plik DokB
  
::<math>\sum_{k = 0}^{n} \binom{n}{k} (1 + (- 1)^k) = 2 \underset{k \; \text{parzyste}}{\sum^n_{k = 0}} \binom{n}{k} = 2^n</math>
 
  
::<math>\sum_{k = 0}^{n} \binom{n}{k} (1 - (- 1)^k) = 2 \underset{k \; \text{nieparzyste}}{\sum_{k = 1}^{n}} \binom{n}{k} = 2^n</math>
+
Jak przebiega weryfikacja odebranej wiadomości?
  
Skąd natychmiast wynika  
+
:# Urząd odbiera mail od Bolka i&nbsp;pobiera załącznik (nazwijmy go DokU, bo nie wiemy, czy nie został zmieniony)
 +
:# Urząd oblicza hasz załączonego pliku DokU: <math>\; h_U = \mathop{\text{SHA256}}( \text{DokU} )</math>
 +
:# '''kluczem publicznym''' Bolka Urząd odszyfrowuje otrzymany w&nbsp;mailu zaszyfrowany hasz <math>h_B</math> (zobacz Q20)
 +
:# z&nbsp;równości <math>h_B = h_U</math> wynika, że dokumenty DokB i&nbsp;DokU są identyczne (zobacz Q23)
  
::<math>\underset{k \; \text{parzyste}}{\sum_{k = 0}^{n}} \binom{n}{k} = 2^{n - 1}</math>
 
  
::<math>\underset{k \; \text{nieparzyste}}{\sum_{k = 1}^{n}} \binom{n}{k} = 2^{n - 1}</math>
+
Jest tak, ponieważ z&nbsp;równości <math>h_B = h_U</math> wynika, że zaszyfrowany hasz <math>h_B</math> musiał pochodzić od Bolka, bo został zaszyfrowany jego kluczem '''prywatnym''', do którego nikt, poza nim, nie ma dostępu. Dlatego zaszyfrowany kluczem prywatnym Bolka hasz <math>h_B</math> jest tym samym, co jego podpis i&nbsp;potwierdza to, że plik DokB (którego hasz jest równy <math>h_B</math>) został sporządzony przez Bolka.
  
Co należało pokazać.<br/>
+
Ujmując inaczej, każdy może przedstawić się w&nbsp;mailu jako Bolek, dołączyć spreparowany plik, policzyć hasz tego pliku, ale nie będzie w&nbsp;stanie zaszyfrować tego hasza kluczem '''prywatnym''' Bolka, bo klucz ten jest tajny i&nbsp;niedostępny dla nikogo poza Bolkiem.
&#9633;
 
{{\Spoiler}}
 
  
  
Linia 2003: Linia 590:
  
  
=== <span style="border-bottom:1px solid #000;">Funkcje <span style="font-size: 95%; background-color: #f8f9fa"><tt>digits(m, b)</tt></span> oraz <span style="font-size: 95%; background-color: #f8f9fa"><tt>issquare(m)</tt></span></span> ===
+
== Podpisywanie dokumentów tajnych ==
  
&nbsp;
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q29</span><br/>
 +
Powiedzmy, że Bolek ma ważną informację i&nbsp;chce ją przekazać do Agencji. Oczywiście informacji nie może przeczytać nikt inny, a&nbsp;Agencja musi mieć pewność, że źródłem tej ważnej informacji jest rzeczywiście Bolek, a&nbsp;nie ktoś inny, kto tylko pod Bolka się podszywa. Tym razem Bolek na pewno potrafi szyfrować wiadomości metodą RSA, a&nbsp;jego klucz publiczny <math>(m, e)</math> jest z&nbsp;pewnością znany Agencji. Co więcej, Bolek zna klucz publiczny Agencji <math>(M, E)</math>, którego ma używać do komunikowania się z&nbsp;Agencją. W&nbsp;tym przypadku Bolek postępuje następująco
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N47</span><br/>
+
:# oblicza hasz wiadomości <math>h_B = \mathop{\text{SHA256}}( \text{tekst} )</math>
W funkcji <code>modLucas()</code> wykorzystaliśmy zaimplementowaną w&nbsp;PARI/GP funkcję
+
:# szyfruje hasz <math>h_B</math> swoim '''kluczem prywatnym''' <math>(m, d)</math>
 +
:# umieszcza zaszyfrowany hasz <math>h_B</math> jako ostatnią linię tekstu wiadomości
 +
:# szyfruje całość (tekst wiadomości + zaszyfrowany hasz <math>h_B</math>) kluczem publicznym Agencji <math>(M, E)</math>
 +
:# umieszcza cały zaszyfrowany tekst w&nbsp;pliku i&nbsp;wysyła jako załącznik maila do Agencji
  
<code>digits(m, b)</code> – zwraca wektor cyfr liczby <math>| m |</math> w&nbsp;systemie liczbowym o&nbsp;podstawie <math>b</math>
+
Agencja
  
W naszym przypadku potrzebowaliśmy uzyskać wektor cyfr liczby <math>m</math> w&nbsp;układzie dwójkowym, czyli funkcję <code>digits(m, 2)</code> . Wprowadzenie tej funkcji pozwoliło zwiększyć czytelność kodu, ale bez trudu możemy ją sami napisać. Zauważmy, że do zapisania liczby <math>m \geqslant 1</math> potrzebujemy <math>\log_2 m + 1</math> cyfr. Zastępując funkcję <math>\log_2 m</math> funkcją <math>\left \lfloor \tfrac{\log m}{\log 2} \right \rfloor</math> musimy liczyć się z&nbsp;możliwym błędem zaokrąglenia – dlatego w&nbsp;programie deklarujemy wektor <code>V</code> o&nbsp;długości <code>floor( log(m)/log(2) ) + 2</code>. Zwracany wektor <code>W</code> ma już prawidłową długość.
+
:# pobiera załącznik
 +
:# tekst z&nbsp;załącznika odszyfrowuje kluczem prywatnym Agencji <math>(M, D)</math>
 +
:# z&nbsp;ostatniej linii pliku odczytuje zaszyfrowany hasz <math>h_A</math> tekstu otrzymanej wiadomości
 +
:# deszyfruje hasz <math>h_A</math> wiadomości '''kluczem publicznym''' Bolka <math>(m, e)</math>
 +
:# oblicza hasz <math>h_B</math> wiadomości od Bolka
 +
:# równość <math>h_B = h_A</math> potwierdza, że wiadomość nie została zmieniona i&nbsp;przekazał ją do Agencji Bolek
  
<span style="font-size: 90%; color:black;">Dec2Bin(m) =
+
Zauważmy, że '''klucz publiczny''' Agencji może być wiedzą poufną, ale z&nbsp;pewnością nie jest tak dobrze strzeżony, jak '''klucze prywatne'''. Agencja nie może zakładać, że zaszyfrowany jej kluczem publicznym plik nie został spreparowany. Dopiero po odszyfrowaniu pliku, obliczeniu hasza wiadomości i&nbsp;potwierdzenia zgodności tego hasza z&nbsp;haszem zapisanym w&nbsp;ostatniej linii pliku (który został zaszyfrowany '''kluczem prywatnym''' Bolka) Agencja ma pewność, że plik stworzył i&nbsp;wysłał Bolek.
\\ zwraca wektor cyfr liczby m w układzie dwójkowym
 
{
 
'''local'''(i, k, V, W);
 
'''if'''( m == 0, '''return'''([0]) );
 
V = '''vector'''( '''floor'''( '''log'''(m)/'''log'''(2) ) + 2 ); \\ potrzeba floor( log(m)/log(2) ) + 1, ale błąd zaokrąglenia może zepsuć wynik
 
k = 0;
 
'''while'''( m > 0,
 
        V[k++] = m % 2;
 
        m = '''floor'''(m / 2);
 
      );
 
W = '''vector'''(k);
 
'''for'''(i = 1, k, W[i] = V[k + 1 - i]);
 
'''return'''(W);
 
}
 
  
  
  
<span style="font-size: 110%; font-weight: bold;">Uwaga N48</span><br/>
+
<span style="font-size: 110%; font-weight: bold;">Uwaga Q30</span><br/>
W funkcjach <code>LucasTest()</code> i <code>StrongLucasTest()</code> wykorzystaliśmy zaimplementowaną w&nbsp;PARI/GP funkcję
+
Zwróćmy uwagę, że '''jeżeli korzystamy''' z&nbsp;funkcji <code>TextToNumber()</code> i <code>NumberToText()</code> (zobacz Q16), a&nbsp;jednocześnie chcemy podpisywać szyfrowane wiadomości, to wiadomości '''nie mogą''' zawierać znaków innych niż znaki ASCII od&nbsp;32 do&nbsp;126.
  
<code>issquare(m)</code> – sprawdza, czy liczba <math>m</math> jest liczbą kwadratową
+
Jest tak dlatego, że funkcja <code>TextToNumber()</code> zgubi informację o&nbsp;innych znakach w&nbsp;wiadomości, a&nbsp;funkcja <code>NumberToText()</code> już tej informacji nie odtworzy. Zatem hasz wysyłanej wiadomości i&nbsp;hasz otrzymanej wiadomości (po odszyfrowaniu) nigdy nie będą identyczne w&nbsp;przypadku użycia znaków innych niż znaki ASCII od&nbsp;32 do&nbsp;126.
  
Wprowadzenie tej funkcji pozwoliło zwiększyć czytelność kodu, ale bez trudu możemy ją sami napisać. Potrzebna nam będzie funkcja, która znajduje całość z&nbsp;pierwiastka z&nbsp;liczby <math>m</math>, czyli <math>\left\lfloor \sqrt{m} \right\rfloor</math>. Wykorzystamy tutaj ciąg
 
  
::<math>a_{k + 1} =
 
  \begin{cases}
 
  \qquad \;\; 1 & \text{gdy } k = 0 \\
 
      \tfrac{1}{2} \left( a_k + \tfrac{x}{a_k} \right) & \text{gdy } k > 0 \\
 
  \end{cases}</math>
 
  
którego granicą jest <math>\sqrt{x}</math> <ref name="pierwiastek1"/>.
 
  
Modyfikując powyższą definicję tak, aby operacje były zawsze wykonywane na liczbach całkowitych<ref name="IntegerSquareRoot1"/>
 
  
::<math>a_{k + 1} =
 
  \begin{cases}
 
  \qquad \quad \; 1 & \text{gdy } k = 0 \\
 
      \left\lfloor \tfrac{1}{2} \left( a_k + \left\lfloor \tfrac{m}{a_k} \right\rfloor \right) \right\rfloor & \text{gdy } k > 0 \\
 
  \end{cases}</math>
 
  
otrzymujemy ciąg, którego wszystkie wyrazy, począwszy od pewnego skończonego <math>n_0</math>, są równe <math>\left\lfloor \sqrt{m} \right\rfloor</math>. Nie dotyczy to przypadku, gdy <math>m + 1</math> jest liczbą kwadratową, wtedy, począwszy od pewnego skończonego <math>n_0</math>, wyrazy ciągu przyjmują na zmianę wartości <math>\left\lfloor \sqrt{m} \right\rfloor</math> oraz <math>\left\lfloor \sqrt{m} \right\rfloor + 1</math>.
 
  
Na tej podstawie możemy w&nbsp;PARI/GP napisać funkcję
 
  
<span style="font-size: 90%; color:black;">intSqrt(m) =
 
{
 
'''local'''(a, b);
 
'''if'''( m == 0, '''return'''(0) );
 
a = 2^( '''floor'''( '''log'''(m)/'''log'''(2)/2 ) + 2 ); \\ musi być a > sqrt(m)
 
b = '''floor'''(( a + '''floor'''( m/a ) )/2);
 
'''while'''( b < a,
 
        a = b;
 
        b = '''floor'''( ( a + '''floor'''(m/a) )/2 );
 
      );
 
'''return'''(a);
 
}</span>
 
  
Oczywiście liczba <math>m</math> jest liczbą kwadratową, wtedy i&nbsp;tylko wtedy, gdy <math>m = \left\lfloor \sqrt{m} \right\rfloor^2</math>, zatem wystarczy sprawdzić, czy <code>m == intSqrt(m)^2</code>.
 
  
  
Linia 2078: Linia 632:
  
  
 +
== Przypisy ==
  
 +
<references>
  
 +
<ref name="DiffieHellman1">Whitfield Diffie and Martin E. Hellman, ''New Directions in Cryptography'', IEEE Transactions on Information Theory, Vol.&nbsp;22, No.&nbsp;6, 1976 ([https://ee.stanford.edu/~hellman/publications/24.pdf LINK])</ref>
  
 +
<ref name="DiffieHellman2">Wikipedia, ''Protokół Diffiego-Hellmana'', ([https://pl.wikipedia.org/wiki/Protok%C3%B3%C5%82_Diffiego-Hellmana Wiki-pl]), ([https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange Wiki-en])</ref>
  
 +
<ref name="generator1">Liczba <math>g</math> powinna (ale nie musi) być generatorem modulo <math>p</math>. Dlaczego tak jest, wyjaśnimy w&nbsp;dalszej części tekstu.</ref>
  
 +
<ref name="funkcjaphi1">Wikipedia, ''Funkcja φ'', ([https://pl.wikipedia.org/wiki/Funkcja_%CF%86 Wiki-pl]), ([https://en.wikipedia.org/wiki/Euler%27s_totient_function Wiki-en])</ref>
  
 +
<ref name="RSA1">R. Rivest, A. Shamir and L. Adleman, ''A Method for Obtaining Digital Signatures and Public-Key Cryptosystems'', Communications of the ACM, Volume 21, Issue 2, Feb. 1978, pp. 120-126</ref>
  
 +
<ref name="RSA2">Wikipedia, ''RSA (kryptografia)'', ([https://pl.wikipedia.org/wiki/RSA_(kryptografia) Wiki-pl]), ([https://en.wikipedia.org/wiki/RSA_(cryptosystem) Wiki-en])</ref>
  
 +
<ref name="BonehDurfee1">Dan Boneh and Glenn Durfee, ''Cryptanalysis of RSA with Private Key d Less Than N<sup>0.292</sup>'', IEEE Transactions on Information Theory, Vol.&nbsp;46, No.&nbsp;4, 2000</ref>
  
== Przypisy ==
+
<ref name="RSA250">Wikipedia, ''RSA numbers'', ([https://en.wikipedia.org/wiki/RSA_numbers#RSA-250 Wiki-en])</ref>
  
<references>
+
<ref name="ASCII">Wikipedia, ''ASCII'', ([https://pl.wikipedia.org/wiki/ASCII Wiki-pl]), ([https://en.wikipedia.org/wiki/ASCII Wiki-en])</ref>
  
<ref name="BaillieWagstaff1">Robert Baillie and Samuel S. Wagstaff Jr., ''Lucas Pseudoprimes'', Mathematics of Computation Vol. 35, No. 152 (1980), ([http://mpqs.free.fr/LucasPseudoprimes.pdf LINK])</ref>
+
<ref name="hashfunction1">Wikipedia, ''Cryptographic hash function'', ([https://en.wikipedia.org/wiki/Cryptographic_hash_function Wiki-en]), ([https://pl.wikipedia.org/wiki/Funkcja_skr%C3%B3tu#Kryptograficzne_funkcje_skr%C3%B3tu Wiki-pl])</ref>
  
<ref name="Arnault1">François Arnault, ''The Rabin-Monier Theorem for Lucas Pseudoprimes'', Mathematics of Computation Vol. 66, No. 218 (1997)</ref>
+
<ref name="CRC">Wikipedia, ''Cykliczny kod nadmiarowy'', ([https://pl.wikipedia.org/wiki/Cykliczny_kod_nadmiarowy Wiki-pl]), ([https://en.wikipedia.org/wiki/Cyclic_redundancy_check Wiki-en])</ref>
  
<ref name="pierwiastek1">Wikipedia, ''Pierwiastek kwadratowy'', ([https://pl.wikipedia.org/wiki/Metody_obliczania_pierwiastka_kwadratowego#Metoda_babilo%C5%84ska Wiki-pl]), ([https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method Wiki-en])</ref>
+
<ref name="MD5">Wikipedia, ''MD5'', ([https://pl.wikipedia.org/wiki/MD5 Wiki-pl]), ([https://en.wikipedia.org/wiki/MD5 Wiki-en])</ref>
  
<ref name="IntegerSquareRoot1">Wikipedia, ''Integer square root'', ([https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division Wiki-en])</ref>
+
<ref name="SHA1">Wikipedia, ''SHA-1'', ([https://pl.wikipedia.org/wiki/SHA-1 Wiki-pl]), ([https://en.wikipedia.org/wiki/SHA-1 Wiki-en])</ref>
  
<ref name="BPSW1">Wikipedia, ''Baillie–PSW primality test'', ([https://en.wikipedia.org/wiki/Baillie%E2%80%93PSW_primality_test Wiki-en])</ref>
+
<ref name="SHA2">Wikipedia, ''SHA-2'', ([https://pl.wikipedia.org/wiki/SHA-2 Wiki-pl]), ([https://en.wikipedia.org/wiki/SHA-2 Wiki-en])</ref>
  
<ref name="BPSW2">MathWorld, ''Baillie-PSW Primality Test'', ([https://mathworld.wolfram.com/Baillie-PSWPrimalityTest.html LINK])</ref>
+
<ref name="konieclinii">Wikipedia, ''Koniec linii'', ([https://pl.wikipedia.org/wiki/Koniec_linii Wiki-pl]), ([https://en.wikipedia.org/wiki/Newline Wiki-en])</ref>
  
 
</references>
 
</references>
 
 
 
  
  

Aktualna wersja na dzień 18:45, 17 mar 2024

22.11.2023



Protokół Diffiego-Hellmana

Uwaga Q1
Metoda ta została opracowana przez W. Diffiego i M. Hellmana[1][2] w 1976 roku. Opisana niżej procedura nie jest metodą szyfrowania i z założenia jej cel jest zupełnie inny. Umożliwia ona osobom mogącym kontaktować się ze sobą jedynie przez niezabezpieczone przed podsłuchem środki łączności ustalenie (tajnej) liczby, zwanej kluczem. Dysponując wspólną liczbą-kluczem osoby te mogą kodować i odczytywać wiadomości wybraną metodą szyfrowania. Przedstawimy w punktach procedurę postępowania wraz z przykładowymi danymi.

1. Agencja i Bolek wybierają (jawną) liczbę pierwszą [math]\displaystyle{ p = 541 }[/math] i (jawną) liczbę [math]\displaystyle{ g = 2 }[/math][3]
2. Agencja ustala (tajny, znany tylko sobie) wykładnik [math]\displaystyle{ a = 2718 }[/math]
3. Bolek ustala (tajny, znany tylko sobie) wykładnik [math]\displaystyle{ b = 3141 }[/math]
4. Agencja oblicza (jawną) liczbę [math]\displaystyle{ X = R_p (g^a) = 300 }[/math] i wysyła ją do Bolka
5. Bolek oblicza (jawną) liczbę [math]\displaystyle{ Y = R_p (g^b) = 191 }[/math] i wysyła ją do Agencji
6. Agencja oblicza (tajną) liczbę [math]\displaystyle{ k_A = R_p (Y^a) = 493 }[/math]
7. Bolek oblicza (tajną) liczbę [math]\displaystyle{ k_B = R_p (X^b) = 493 }[/math]
8. Modulo [math]\displaystyle{ p }[/math] mamy
[math]\displaystyle{ k_A = R_p (Y^a) \equiv Y^a = [R_p (g^b)]^a \equiv (g^b)^a \equiv g^{a b} \equiv (g^a)^b \equiv [R_p (g^a)]^b = X^b \equiv R_p (X^b) = k_B \!\! \pmod{p} }[/math]
9. Z definicji liczby [math]\displaystyle{ k_A, k_B \in [0, p - 1] }[/math], zatem [math]\displaystyle{ 0 \leqslant | k_A - k_B | \leqslant p - 1 }[/math]. Ponieważ liczby [math]\displaystyle{ k_A, k_B }[/math] przystają do siebie modulo [math]\displaystyle{ p }[/math], to muszą być sobie równe, czyli liczba [math]\displaystyle{ k = k_A = k_B }[/math] jest poszukiwanym kluczem.


Uwaga Q2
Liczby [math]\displaystyle{ a }[/math] i [math]\displaystyle{ b }[/math] mogą być losowo wybranymi liczbami dodatnimi nie większymi od [math]\displaystyle{ p }[/math]. Istotnie, jeżeli [math]\displaystyle{ a = k \cdot (p - 1) + r }[/math], to

[math]\displaystyle{ g^a \equiv (g^{p - 1})^k \cdot g^r \equiv g^r \!\! \pmod{p} }[/math]

W naszym przykładzie możemy użyć liczb [math]\displaystyle{ a = 18 }[/math] oraz [math]\displaystyle{ b = 441 }[/math] otrzymując te same rezultaty. W praktyce ten problem nie występuje, bo gdy liczba pierwsza [math]\displaystyle{ p }[/math] ma co najmniej sto cyfr, to trudno wybrać jeszcze większy wykładnik.


Przykład Q3
Zobaczmy, jak wpłynie na protokół zmiana liczby [math]\displaystyle{ g }[/math]. Niech [math]\displaystyle{ p = 541 }[/math] i [math]\displaystyle{ g = 15 }[/math].

Czytelnik może wybierać dowolne inne wykładniki [math]\displaystyle{ a }[/math] i [math]\displaystyle{ b }[/math], ale innych wartości [math]\displaystyle{ R_p (g^{a b}) }[/math] już nie uzyska. Wybór liczby [math]\displaystyle{ g = 2 }[/math] w zamieszczonym powyżej opisie metody, nie był przypadkowy. Liczba [math]\displaystyle{ 2 }[/math] jest generatorem modulo [math]\displaystyle{ 541 }[/math]. Generator modulo liczba pierwsza [math]\displaystyle{ p }[/math], to taka liczba [math]\displaystyle{ g }[/math], że zbiór potęg

[math]\displaystyle{ \{ g^1, g^2, g^3, \ldots, g^{p - 1} \} }[/math]

rozpatrywany modulo [math]\displaystyle{ p }[/math] jest identyczny ze zbiorem

[math]\displaystyle{ \{ 1, 2, 3, \ldots, p - 1 \} }[/math]

Wybierając liczbę [math]\displaystyle{ g }[/math] tak, aby była generatorem modulo [math]\displaystyle{ p }[/math], zapewniamy sobie, że w ostatniej kolumnie mogą pojawić się wszystkie liczby od [math]\displaystyle{ 1 }[/math] do [math]\displaystyle{ p - 1 }[/math]. Taki wybór [math]\displaystyle{ g }[/math] zwiększa ilość możliwych wartości dla ustalanego klucza [math]\displaystyle{ k = R_p (g^{a b}) }[/math], a tym samym zwiększa bezpieczeństwo procedury. Zauważmy, że liczby [math]\displaystyle{ p }[/math] i [math]\displaystyle{ g }[/math] są jawne. Osoba próbująca poznać ustalony klucz [math]\displaystyle{ k }[/math] z pewnością ucieszy się, gdy sprawdzi, że niewłaściwy wybór liczby [math]\displaystyle{ g }[/math] zredukował ilość możliwych kluczy i ułatwił jej pracę.

Każda liczba pierwsza ma generator modulo, ale znalezienie go dla dużych liczb pierwszych nie jest proste i może trwać bardzo długo. Pomocne w tej sytuacji jest następujące twierdzenie.


Twierdzenie Q4
Niech [math]\displaystyle{ p = 2 q + 1 }[/math] będzie liczbą pierwszą, gdzie [math]\displaystyle{ q \geqslant 3 }[/math] jest również liczbą pierwszą. Jeżeli [math]\displaystyle{ g }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p }[/math] i [math]\displaystyle{ g \not\equiv - 1 \!\! \pmod{p} }[/math], to [math]\displaystyle{ g }[/math] jest generatorem modulo [math]\displaystyle{ p }[/math].

Dowód

Dowód jest na tyle prosty i elegancki, że postanowiliśmy go zamieścić, choć wykracza on poza omówiony wcześniej materiał. Czytelnik może ten dowód pominąć. Dowód poprzedzamy kilkoma prostymi, ale istotnymi komentarzami.

Komentarz 1.

Bez dowodu przyjmujemy fakt, że istnieje dokładnie [math]\displaystyle{ \varphi (p - 1) }[/math] różnych generatorów modulo [math]\displaystyle{ p }[/math], gdzie [math]\displaystyle{ \varphi }[/math] jest funkcją Eulera[4]. Funkcja Eulera [math]\displaystyle{ \varphi (n) }[/math] jest równa ilości liczb całkowitych dodatnich nie większych od [math]\displaystyle{ n }[/math] i względnie pierwszych z [math]\displaystyle{ n }[/math].

Komentarz 2.

Udowodnimy, że jeżeli [math]\displaystyle{ g }[/math] jest generatorem modulo [math]\displaystyle{ p }[/math], to [math]\displaystyle{ g }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p }[/math].

Przypuśćmy, że [math]\displaystyle{ g }[/math] jest liczbą kwadratową modulo [math]\displaystyle{ p }[/math], zatem (zobacz J31)

[math]\displaystyle{ g^{(p - 1) / 2} \equiv 1 \!\! \pmod{p} }[/math]

Wynika stąd, że zbiór

[math]\displaystyle{ S = \{ g^1, g^2, g^3, \ldots, g^{p - 1} \} }[/math]
[math]\displaystyle{ \;\;\,\, = \left\{ g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1}, g^{\tfrac{p - 1}{2}}, g^{\tfrac{p - 1}{2} + 1}, g^{\tfrac{p - 1}{2} + 2}, g^{\tfrac{p - 1}{2} + 3}, \ldots, g^{p - 3}, g^{p - 2}, g^{p - 1} \right\} }[/math]

jest identyczny modulo [math]\displaystyle{ p }[/math] ze zbiorem

[math]\displaystyle{ S' = \left\{ g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1}, 1, g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1} \right\} }[/math]
[math]\displaystyle{ \quad \, = \left\{ 1, g^1, g^2, g^3, \ldots, g^{\tfrac{p - 1}{2} - 3}, g^{\tfrac{p - 1}{2} - 2}, g^{\tfrac{p - 1}{2} - 1} \right\} }[/math]

i nie może być identyczny modulo [math]\displaystyle{ p }[/math] ze zbiorem [math]\displaystyle{ T = \{ 1, 2, 3, \ldots, p - 1 \} }[/math], bo [math]\displaystyle{ S' }[/math] zawiera co najwyżej połowę elementów zbioru [math]\displaystyle{ T }[/math]. Uzyskana sprzeczność dowodzi, że generator musi być liczbą niekwadratową modulo [math]\displaystyle{ p }[/math].

Komentarz 3.

Ponieważ funkcja Eulera [math]\displaystyle{ \varphi (n) }[/math] jest równa ilości liczb całkowitych dodatnich nie większych od [math]\displaystyle{ n }[/math] i względnie pierwszych z [math]\displaystyle{ n }[/math], to dla liczby pierwszej [math]\displaystyle{ p }[/math] mamy [math]\displaystyle{ \varphi (p) = p - 1 }[/math], bo wszystkie liczby [math]\displaystyle{ 1, 2, 3, \ldots, p - 1 }[/math] są względnie pierwsze z liczbą pierwszą [math]\displaystyle{ p }[/math].

Komentarz 4.

Ponieważ funkcja Eulera [math]\displaystyle{ \varphi (n) }[/math] jest równa ilości liczb całkowitych dodatnich nie większych od [math]\displaystyle{ n }[/math] i względnie pierwszych z [math]\displaystyle{ n }[/math], to dla liczby pierwszej nieparzystej [math]\displaystyle{ p }[/math] mamy [math]\displaystyle{ \varphi (2 p) = p - 1 }[/math], bo

  • wszystkie liczby parzyste [math]\displaystyle{ 2, 4, 6, \ldots, 2 p - 2 }[/math] mają z liczbą [math]\displaystyle{ 2 p }[/math] wspólny dzielnik równy [math]\displaystyle{ 2 }[/math] i nie mogą być względnie pierwsze z liczbą [math]\displaystyle{ 2 p }[/math]
  • wszystkie liczby nieparzyste [math]\displaystyle{ 1, 3, 5, \ldots, 2 p - 1 }[/math] (których jest [math]\displaystyle{ p }[/math]) są względnie pierwsze z liczbą [math]\displaystyle{ 2 p }[/math], poza liczbą nieparzystą [math]\displaystyle{ p }[/math], która nie jest względnie pierwsza z liczbą [math]\displaystyle{ 2 p }[/math]


Wracając do dowodu twierdzenia Q4, zauważmy, że liczba [math]\displaystyle{ - 1 }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p = 2 q + 1 }[/math]. Istotnie, obliczając symbol Jacobiego, otrzymujemy

[math]\displaystyle{ \left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} = (- 1)^{\tfrac{p - 1}{2}} = (- 1)^q = - 1 }[/math]

Zauważmy też, że dla liczb pierwszych [math]\displaystyle{ p \geqslant 5 }[/math] liczba [math]\displaystyle{ - 1 }[/math] nie jest generatorem modulo [math]\displaystyle{ p }[/math]. Ponieważ [math]\displaystyle{ (- 1)^n = \pm 1 }[/math], to zbiór potęg

[math]\displaystyle{ \{ g^1, g^2, g^3, \ldots, g^{p - 1} \} }[/math]

składa się tylko z dwóch elementów [math]\displaystyle{ \{ - 1, 1 \} }[/math] i dla liczb pierwszych [math]\displaystyle{ p \geqslant 5 }[/math] nie może być identyczny modulo [math]\displaystyle{ p }[/math] ze zbiorem [math]\displaystyle{ \{ 1, 2, 3, \ldots, p - 1 \} }[/math].


Ilość generatorów modulo [math]\displaystyle{ p }[/math] dla liczby pierwszej [math]\displaystyle{ p = 2 q + 1 }[/math] jest równa

[math]\displaystyle{ \varphi (p - 1) = \varphi (2 q) = q - 1 = {\small\frac{p - 1}{2}} - 1 }[/math]

Ponieważ istnieje [math]\displaystyle{ {\small\frac{p - 1}{2}} }[/math] liczb niekwadratowych modulo [math]\displaystyle{ p }[/math] (zobacz J30), to liczb niekwadratowych modulo [math]\displaystyle{ p }[/math], różnych od [math]\displaystyle{ - 1 }[/math], jest [math]\displaystyle{ {\small\frac{p - 1}{2}} - 1 }[/math], czyli tyle samo, co generatorów modulo [math]\displaystyle{ p }[/math], a żadna z pozostałych liczb (kwadratowych modulo [math]\displaystyle{ p }[/math]) nie może być generatorem modulo [math]\displaystyle{ p }[/math]. Co kończy dowód.


Uwaga Q5
Jeśli nie potrzebujemy wyliczyć najmniejszego generatora modulo [math]\displaystyle{ p = 2 q + 1 }[/math], to z twierdzenia Q4 można łatwo pokazać, że liczba [math]\displaystyle{ - 4 }[/math] jest generatorem dla wszystkich liczb pierwszych [math]\displaystyle{ p = 2 q + 1 \geqslant 7 }[/math], a liczba [math]\displaystyle{ - 3 }[/math] dla wszystkich liczb pierwszych [math]\displaystyle{ p = 2 q + 1 \geqslant 11 }[/math]. Ponieważ [math]\displaystyle{ q = 2 k + 1 }[/math], to [math]\displaystyle{ p = 4 k + 3 }[/math].

1. Pokażemy, że [math]\displaystyle{ - 4 }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p }[/math]. Liczba [math]\displaystyle{ k }[/math] może być postaci [math]\displaystyle{ 2 j }[/math] lub [math]\displaystyle{ 2 j + 1 }[/math], co daje odpowiednio [math]\displaystyle{ p = 8 j + 3 }[/math] lub [math]\displaystyle{ p = 8 j + 7 }[/math]. Zatem

[math]\displaystyle{ \left( {\small\frac{- 4}{p}} \right)_{\small{\!\! J}} = \left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} \cdot \left( {\small\frac{2}{p}} \right)_{\small{\!\! J}}^{\! 2} = (- 1) \cdot (\pm 1)^2 = - 1 }[/math]

Zobacz twierdzenie J42 p.6.


2. Pokażemy, że [math]\displaystyle{ - 3 }[/math] jest liczbą niekwadratową modulo [math]\displaystyle{ p }[/math]. Liczba [math]\displaystyle{ k }[/math] może być postaci [math]\displaystyle{ 3 j, 3 j + 1, 3 j + 2 }[/math], co daje odpowiednio

[math]\displaystyle{ k = 3 j \qquad \qquad \;\!\!\! p = 12 j + 3 \qquad \;\; q = 6 j + 1 }[/math]
[math]\displaystyle{ k = 3 j + 1 \qquad p = 12 j + 7 \qquad \;\; q = 6 j + 3 }[/math]
[math]\displaystyle{ k = 3 j + 2 \qquad p = 12 j + 11 \qquad q = 6 j + 5 }[/math]

Pierwsza i druga postać liczby [math]\displaystyle{ k }[/math] nie jest możliwa, bo albo liczba [math]\displaystyle{ p }[/math], albo liczba [math]\displaystyle{ q }[/math] byłyby liczbami złożonymi. Zatem

[math]\displaystyle{ \left( {\small\frac{- 3}{p}} \right)_{\small{\!\! J}} = \left( {\small\frac{- 1}{p}} \right)_{\small{\!\! J}} \cdot \left( {\small\frac{3}{p}} \right)_{\small{\!\! J}} = (- 1) \cdot (+ 1) = - 1 }[/math]

Zobacz twierdzenie J42 p.6 i zadanie J47.


Uwaga Q6
O ile w ogólnym przypadku liczb pierwszych [math]\displaystyle{ p }[/math] liczących setki cyfr znalezienie najmniejszego generatora modulo [math]\displaystyle{ p }[/math] może trwać godzinami, to w przypadku liczb pierwszych [math]\displaystyle{ p = 2 q + 1 }[/math], gdzie [math]\displaystyle{ q }[/math] jest również liczbą pierwszą, wystarczy znaleźć liczbę niekwadratową modulo [math]\displaystyle{ p }[/math], a obliczenie symbolu Jacobiego trwa bardzo krótko, zaś wyszukanie liczb pierwszych postaci [math]\displaystyle{ p = 2 q + 1 }[/math] też jest zaskakująco szybkie. Dlatego napisaliśmy w PARI/GP prosty program, który wyszukuje w zadanym przedziale [math]\displaystyle{ [m, n] }[/math] liczbę pierwszą [math]\displaystyle{ p }[/math] taką, że [math]\displaystyle{ p = 2 q + 1 }[/math] i zwraca [math]\displaystyle{ p }[/math] oraz najmniejszy generator modulo [math]\displaystyle{ p }[/math].

Należy zwrócić uwagę, że funkcje ispseudoprime() i randomprime() sprawdzają pierwszość liczby na tym samym poziomie – wykonywany jest test Millera-Rabina. Dlatego używamy ich łącznie, co przyspiesza wyszukanie odpowiedniej liczby pierwszej. Następnie, już silniejszym testem, potwierdzamy pierwszość obydwu liczb: [math]\displaystyle{ p }[/math] i [math]\displaystyle{ (p - 1) / 2 }[/math].

Pokaż kod
SafePrime(m, n) = 
\\ zwraca wektor [p, g], gdzie p i (p-1)/2 są liczbami pierwszymi, a g jest generatorem modulo p
{
local(g, p);
setrand(getwalltime());  \\ ustawiamy ziarno (ang. seed) generatora liczb losowych
while( 1,
       p = 9;
       while( !ispseudoprime( (p - 1)/2 ), p = randomprime([m, n]) );
       if( isprime(p) && isprime( (p-1)/2 ), break() );
     );
g = 2;
while( jacobi(g, p) > -1, g++ );
return([p, g]);
}



Uwaga Q7
Jak dalece bezpieczna jest opisana wyżej metoda? Aby znaleźć klucz trzeba oprócz (jawnych) liczb [math]\displaystyle{ p, g, X, Y }[/math] znać jedną z liczb [math]\displaystyle{ a }[/math] lub [math]\displaystyle{ b }[/math]. Liczba [math]\displaystyle{ a }[/math] spełnia kongruencję

[math]\displaystyle{ g^a \equiv X \!\! \pmod{p} }[/math]

ale nie istnieje żadna metoda szybkiego znalezienia wykładnika [math]\displaystyle{ a }[/math]. Oczywiście zawsze pozostaje możliwość kolejnego wyliczania [math]\displaystyle{ g^n }[/math] modulo [math]\displaystyle{ p }[/math] z nadzieją trafienia na [math]\displaystyle{ X }[/math] lub [math]\displaystyle{ Y }[/math]. Dla naszych danych mielibyśmy modulo [math]\displaystyle{ 541 }[/math]

[math]\displaystyle{ 2^1 \equiv 2, \quad 2^2 \equiv 4, \; \ldots , \; 2^{17} \equiv 150, \quad 2^{18} \equiv 300 }[/math]

czyli wystarczyło jedynie 18 prób! Ale dla dwustucyfrowej liczby pierwszej [math]\displaystyle{ p }[/math] i trochę lepiej wybranych liczb [math]\displaystyle{ a }[/math] i [math]\displaystyle{ b }[/math] ilość prób będzie liczbą rzędu [math]\displaystyle{ 10^{50} }[/math]. Nawet dla najszybszych komputerów stanowi to barierę nie do pokonania.


Uwaga Q8
Realne zagrożenie pojawia się jedynie wtedy, gdy Agencja i Bolek nie sprawdzą autentyczności liczb [math]\displaystyle{ X }[/math] i [math]\displaystyle{ Y }[/math]. Przykładowo Agencja może zapytać o [math]\displaystyle{ 7 }[/math], [math]\displaystyle{ 23 }[/math], [math]\displaystyle{ 101 }[/math] itd. cyfrę liczby [math]\displaystyle{ X }[/math], którą otrzymał Bolek. Dlaczego jest to ważne? Jeżeli korespondencja (maile, listy) Agencji i Bolka jest kontrolowana przez Wywiad, to Wywiad może przechwycić liczby [math]\displaystyle{ X = R_p (g^a) }[/math] oraz [math]\displaystyle{ Y = R_p (g^b) }[/math] i wysłać im swoją liczbę [math]\displaystyle{ Z = R_p (g^c) }[/math]. Od tej pory korespondencja Agencji będzie przechwytywana, odszyfrowywana przez Wywiad kluczem [math]\displaystyle{ k_1 = R_p (g^{a c}) }[/math], czytana, ewentualnie zmieniana, ponownie szyfrowana kluczem [math]\displaystyle{ k_2 = R_p (g^{b c}) }[/math] i wysyłana do Bolka.

Analogicznie będzie kontrolowana korespondencja Bolka wysyłana do Agencji.



Szyfrowanie RSA

Uwaga Q9
Rozpoczniemy od dowodu kilku prostych twierdzeń. Łatwość ich sformułowania i dowodu zaskakuje, jeśli weźmiemy pod uwagę fakt, że stanowią one podstawę niezwykle ważnej metody szyfrowania.


Twierdzenie Q10
Jeżeli [math]\displaystyle{ p }[/math] jest liczbą pierwszą, to dla dowolnego [math]\displaystyle{ a \in \mathbb{Z} }[/math] i każdego [math]\displaystyle{ k \geqslant 0 }[/math] jest

[math]\displaystyle{ a^{(p - 1) k + 1} \equiv a \!\! \pmod{p} }[/math]
Dowód

Jeżeli [math]\displaystyle{ p \mid a }[/math], to dowodzona kongruencja jest prawdziwa. Jeżeli [math]\displaystyle{ p \nmid a }[/math], to modulo [math]\displaystyle{ p }[/math] mamy

[math]\displaystyle{ a^{(p - 1) k + 1} = a \cdot (a^{p - 1})^k \equiv a \!\! \pmod{p} }[/math]

gdzie skorzystaliśmy z twierdzenia Fermata (J22).


Twierdzenie Q11
Jeżeli [math]\displaystyle{ p }[/math] i [math]\displaystyle{ q }[/math] są różnymi liczbami pierwszymi, to dla dowolnego [math]\displaystyle{ a \in \mathbb{Z} }[/math] i każdego [math]\displaystyle{ k \geqslant 0 }[/math] jest

[math]\displaystyle{ a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{p q} }[/math]
Dowód

Z twierdzenia Q10 wiemy, że dla dowolnych liczb [math]\displaystyle{ i, j \geqslant 0 }[/math] prawdziwe są kongruencje

[math]\displaystyle{ a^{(p - 1) i + 1} \equiv a \!\! \pmod{p} }[/math]
[math]\displaystyle{ a^{(q - 1) j + 1} \equiv a \!\! \pmod{q} }[/math]

Dla dowolnego, ale ustalonego [math]\displaystyle{ k \geqslant 0 }[/math] wybierzmy liczby [math]\displaystyle{ i, j }[/math] następująco: [math]\displaystyle{ i = k (q - 1) }[/math] oraz [math]\displaystyle{ j = k (p - 1) }[/math]. Otrzymujemy

[math]\displaystyle{ a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{p} }[/math]
[math]\displaystyle{ a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{q} }[/math]

Z twierdzenia J1 wiemy, że powyższy układ kongruencji może być zapisany w sposób równoważny

[math]\displaystyle{ a^{k (p - 1) (q - 1) + 1} \equiv a \!\! \pmod{p q} }[/math]

Co należało pokazać.


Uwaga Q12 (metoda szyfrowania RSA)
RSA[5][6] to akronim od nazwisk twórców tej metody: Rona Rivesta, Adiego Shamira i Leonarda Adlemana. Rozpoczniemy od wypisania używanych oznaczeń, co znakomicie ułatwi zrozumienie opisu metody.

  1. [math]\displaystyle{ p, q }[/math] – dwie duże liczby pierwsze o zbliżonych wartościach
    • często przyjmuje się, że [math]\displaystyle{ p \lt q \lt 2 p }[/math]; można też przyjąć, że [math]\displaystyle{ q \sim 2 p }[/math]
  2. [math]\displaystyle{ m = p q }[/math]
  3. [math]\displaystyle{ \Phi = (p - 1) (q - 1) }[/math]
    • oznaczenie nawiązuje do funkcji Eulera [math]\displaystyle{ \varphi }[/math], bo [math]\displaystyle{ \varphi (m) = \varphi (p q) = (p - 1) (q - 1) }[/math]
  4. [math]\displaystyle{ e }[/math] (ang. encryption) – wykładnik służący do szyfrowania (publiczny)
  5. [math]\displaystyle{ d }[/math] (ang. decryption) – wykładnik służący do odszyfrowania (tajny)
  6. [math]\displaystyle{ B }[/math] (ang. block of digits) – wiadomość w postaci liczby (ciągu cyfr) przeznaczona do zaszyfrowania
  7. [math]\displaystyle{ C }[/math] (ang. coded block of digits) – zaszyfrowana wiadomość, czyli liczba powstała w wyniku szyfrowania liczby [math]\displaystyle{ B }[/math]


Opis metody

  1. Wybierzmy liczbę [math]\displaystyle{ e }[/math] tak, aby spełniała warunki [math]\displaystyle{ \gcd (e, \Phi) = 1 }[/math] i [math]\displaystyle{ 2 \lt e \lt \Phi }[/math]
    • zaleca się, aby [math]\displaystyle{ e \geqslant 65537 }[/math]
  2. Z lematu Bézouta (zobacz C73) istnieją takie liczby całkowite [math]\displaystyle{ d }[/math] i [math]\displaystyle{ k }[/math], że [math]\displaystyle{ d e + k \Phi = 1 }[/math]. Liczbę [math]\displaystyle{ d }[/math] wyliczamy ze wzoru [math]\displaystyle{ d = d_0 + \Phi t }[/math], gdzie [math]\displaystyle{ d_0 }[/math] (oraz [math]\displaystyle{ k_0 }[/math]) otrzymujemy, wykorzystując w PARI/GP funkcję gcdext(e, Φ) (zobacz C78)
    • [math]\displaystyle{ d }[/math] wybieramy tak, aby była liczbą dodatnią, wtedy [math]\displaystyle{ k }[/math] musi być liczbą ujemną
    • [math]\displaystyle{ d }[/math] nie może być zbyt małą liczbą; pokazano[7], że powinno być [math]\displaystyle{ d \gt m^{0.292} }[/math]
  3. Metoda szyfrowania RSA wymaga trzech liczb: [math]\displaystyle{ m }[/math], [math]\displaystyle{ e }[/math], [math]\displaystyle{ d }[/math]. Liczba [math]\displaystyle{ d }[/math] jest tajna. Podobnie tajne są liczby [math]\displaystyle{ p }[/math], [math]\displaystyle{ q }[/math], [math]\displaystyle{ \Phi }[/math], ale te liczby można po prostu skasować po wyliczeniu [math]\displaystyle{ d }[/math]
  4. Szyfrowaną wiadomość przekształcamy w ciąg cyfr. W przypadku długich wiadomości może być konieczny podział ciągu cyfr na bloki. Tworzymy w ten sposób liczbę [math]\displaystyle{ B }[/math]. Zakładamy, że [math]\displaystyle{ B \lt m }[/math]
  5. Szyfrowanie. Zakodowany tekst jest wynikiem operacji: [math]\displaystyle{ C = R_m (B^e) }[/math], gdzie [math]\displaystyle{ R_m (B^e) }[/math] oznacza resztę z dzielenia liczby [math]\displaystyle{ B^e }[/math] przez [math]\displaystyle{ m }[/math]
    • zauważmy, że: [math]\displaystyle{ C \equiv B^e \!\! \pmod{m} }[/math]
  6. Odszyfrowanie. Odkodowany tekst otrzymujemy, obliczając: [math]\displaystyle{ B = R_m (C^d) }[/math]
  7. Dowód poprawności metody wynika z twierdzenia Q12
    • [math]\displaystyle{ R_m (C^d) \equiv C^d \equiv (B^e)^d \equiv B^{e d} \equiv B^{- k \Phi + 1} \equiv B^{- k (p - 1) (q - 1) + 1} \equiv B \!\! \pmod{m} }[/math]
    • ponieważ [math]\displaystyle{ k \lt 0 }[/math], to [math]\displaystyle{ - k }[/math] jest liczbą dodatnią i możemy zastosować twierdzenie Q12
    • ponieważ [math]\displaystyle{ B \lt m }[/math], to [math]\displaystyle{ R_m (C^d) = B }[/math]
  8. Para liczb [math]\displaystyle{ (m, e) }[/math] jest nazywana kluczem publicznym – służy do szyfrowania i może być dostępna dla każdego.
  9. Para liczb [math]\displaystyle{ (m, d) }[/math] jest nazywana kluczem prywatnym – służy do odszyfrowania. Liczba [math]\displaystyle{ d }[/math] jest tajna – osoba, która ją wykradnie, będzie mogła odczytywać wysyłane do nas wiadomości


Przykład Q13
Prosty przykład: niech wysyłaną wiadomością będzie słowo [math]\displaystyle{ \text{YES} }[/math]. Zamianę liter na ciąg cyfr dokonamy, przypisując każdej literze jej numer w alfabecie np.: [math]\displaystyle{ A \longrightarrow 01 }[/math], [math]\displaystyle{ B \longrightarrow 02 }[/math], ... , [math]\displaystyle{ Z \longrightarrow 26 }[/math], czyli [math]\displaystyle{ \text{YES}\longrightarrow 250519 }[/math], zatem musimy zaszyfrować liczbę [math]\displaystyle{ 250519 }[/math].

Niech [math]\displaystyle{ p = 1009 }[/math], [math]\displaystyle{ q = 1013 }[/math], [math]\displaystyle{ e = 1019 }[/math]. Znajdujemy [math]\displaystyle{ m = p q = 1022117 }[/math], [math]\displaystyle{ \Phi = (p - 1) (q - 1) = 1020096 }[/math], [math]\displaystyle{ d = 397427 }[/math]. Klucz publiczny [math]\displaystyle{ (m, e) }[/math], klucz prywatny [math]\displaystyle{ (m, d) }[/math]. Zaszyfrowana wiadomość to [math]\displaystyle{ R_m (250519^e) = 560222 }[/math]. Odszyfrowując, otrzymujemy [math]\displaystyle{ R_m (560222^d) = 250519 }[/math]. Tak, jak być powinno.


Uwaga Q14
Bezpieczeństwo metody polega na wyborze tak dużych liczb pierwszych [math]\displaystyle{ p }[/math] i [math]\displaystyle{ q }[/math], aby faktoryzacja ich iloczynu [math]\displaystyle{ m }[/math] leżała poza możliwościami współczesnych komputerów i stosowanych algorytmów. Choć klucz publiczny [math]\displaystyle{ (m, e) }[/math] służący do szyfrowania nie jest tajny i może być udostępniany wszystkim, to poznanie klucza prywatnego, czyli liczby [math]\displaystyle{ d }[/math], jest praktycznie niemożliwe.

Liczba [math]\displaystyle{ d }[/math] wynika z rozwiązania równania [math]\displaystyle{ d e + k \Phi = 1 }[/math], ale aby obliczyć [math]\displaystyle{ \Phi = (p - 1) (q - 1) }[/math] musimy znać rozkład liczby [math]\displaystyle{ m }[/math] na czynniki pierwsze. Obecnie nie istnieją dostatecznie szybkie sposoby znajdowania rozkładu dużych liczb na czynniki pierwsze. Możemy łatwo sprawdzić, czy liczba [math]\displaystyle{ m = p q }[/math] jest liczbą złożoną, ale jeśli tak jest, to poznanie jej czynników jest dla dostatecznie dużych [math]\displaystyle{ m }[/math] niemożliwe.


Uwaga Q15 (generowanie liczb [math]\displaystyle{ m, e, d }[/math])
Przyjmując proste założenia co do liczb pierwszych [math]\displaystyle{ p, q }[/math] (przyjęliśmy, że [math]\displaystyle{ 1.8 p \lt q \lt 2.2 p }[/math]) oraz zakładając, że [math]\displaystyle{ d \gt m^{2 / 3} }[/math] napisaliśmy prosty program do generowania klucza publicznego i prywatnego. Parametr w określa, ile cyfr w układzie dziesiętnym będą miały liczby [math]\displaystyle{ p, q }[/math]. Wybór w > 500 gwarantuje wygenerowanie liczby [math]\displaystyle{ m }[/math], której rozkład na czynniki pierwsze nie powinien być możliwy przez wiele lat. Ostatnie (znane) osiągnięcie faktoryzacji, to rozkład 250-cyfrowej liczby [math]\displaystyle{ m = p q }[/math] na czynniki pierwsze[8].

Pokaż kod
RSAkeys(w) = 
\\ parametr w > 1 określa, ile cyfr w układzie dziesiętnym będą miały liczby p, q
{
local(d, e, m, p, Phi, q);
setrand(getwalltime());  \\ ustawiamy ziarno (ang. seed) generatora liczb losowych
p = 1;
q = 0;
while( !isprime(p)  ||  !isprime(q),
       while( q < 1.8 * p  ||  q > 2.2 * p, 
              p = randomprime( [10^(w - 1), 10^w] ); 
              q = randomprime( [10^(w - 1), 10^w] );
            );
     );
m = p * q;
Phi = (p - 1) * (q - 1);
d = -1;
while( d < m^(2/3), 
       e = randomprime( [10^10, 10^15] );
       if( gcd(e, Phi) > 1, next() );
       d = gcdext(e, Phi)[1];
     );
return([m, e, d]);
}
PrintRSAkeys(w) = 
{
local(V);
V = RSAkeys(w);
print("m = ", V[1]);
print("e = ", V[2]);
print("d = ", V[3]);
}


Uwaga Q16 (zamiana tekstu na liczbę i odwrotnie)
W przypadku profesjonalnych programów szyfrujących wykorzystujących metodę RSA szyfrowany jest cały plik, który jest przecież ciągiem zer i jedynek. Oprogramowanie dzieli taki plik na odpowiednich rozmiarów bloki [math]\displaystyle{ B_j }[/math] i każdy jest szyfrowany kluczem publicznym [math]\displaystyle{ (m, e) }[/math]. Możemy w ten sposób szyfrować zdjęcia, filmy, tekst w dowolnym języku itd.

Ponieważ napisanie takiego oprogramowania wykraczałoby poza potrzeby tego omówienia, ale z drugiej strony chcemy udostępnić Czytelnikowi przykłady bardziej skomplikowane niż szyfrowanie słowa [math]\displaystyle{ \text{YES} }[/math], to postanowiliśmy ograniczyć się do szyfrowania tekstu, który zawiera jedynie znaki ASCII[9].

Aby efektywnie korzystać z szyfrowania RSA potrzebne będą nam programy, które przetworzą taki tekst na liczbę i odwrotnie. Poniżej przedstawiamy dwie bardzo proste funkcje: pierwsza funkcja zamienia znaki ASCII od 32 do 126 na liczbę (każdemu znakowi przypisywane są dwie cyfry), a druga funkcja zamienia wygenerowaną przez pierwszą funkcję liczbę na odpowiadający tej liczbie tekst.

Założenie, że nasza wiadomość zawiera tylko znaki ASCII od 32 do 126, jest bardzo ważne. Oznacza to, że taki tekst przetworzony przez funkcję TextToNumber() na liczbę, zostanie odtworzony przez funkcję NumberToText() w niezmienionej postaci. Nie będzie tak, jeśli wystąpią inne znaki: każdy z takich znaków zostanie zamieniony na spacje (np. każda polska litera zostanie zamieniona na dwie spacje). Nie oznacza to, że nie można korzystać z tych funkcji, ale jeśli szyfrujemy podpisaną wiadomość, to zgodność tekstów ma zasadnicze znaczenie.

Pokaż kod
TextToNumber( s ) = 
\\ zamienia znaki ASCII od 32 do 126 na liczbę
{
local(a, b, k, len, txt, V);
V = Vecsmall(s);
len = length(V);
txt = "";
k = 0;
while( k++ <= len,
       a = V[k];
       b = "01";  \\ spacja – wstawiamy jeżeli a jest poza zakresem
       if( a >= 32  &&  a <= 40, b = Str("0", a - 31) );
       if( a >= 41  &&  a <= 126, b = Str(a - 31) );
       txt = Str(txt, b);
     );
return( eval(txt) );
}
NumberToText( n ) = 
{
local(a, k, len, txt, V);
len = length(Str(n));
if( len % 2 == 1, len++ ); \\ "zgubione" zero na początku
len = len / 2;
V = vector(len);
k = len + 1;
while( k-- >= 1,
       a = n % 100;
       n = floor(n / 100);
       V[k] = a + 31;
     );
txt = strchr(V);
return(txt);
}



Uwaga Q17
Jeżeli mamy już funkcje zamieniające tekst na liczbę i odwrotnie, to napisanie w PARI/GP programów do szyfrowania i deszyfrowania metodą RSA jest bardzo proste.

Pokaż kod
RSAencode(m, e, s) = 
\\ szyfrujemy string s
{
local(B, C);
B = TextToNumber(s);
C = lift( Mod(B, m)^e );
print(C);
}
RSAdecode(m, d, C) = 
\\ deszyfrujemy liczbę C
{
local(B, s);
B = lift( Mod(C, m)^d );
s = NumberToText(B);
print(s);
}



Przykład Q18
Kładąc w = 50 w funkcji RSAkeys(w) otrzymaliśmy

m = 2173471545652309346779542101680852446325835148920429701148920590128959176663355134192839060494750117
e = 3675359337253
d = 308186586218659991253427464678921309369969889382350078327142348395702895999753492453847408362677933

Liczba m ma 100 cyfr. Podamy teraz prosty przykład z polskimi literami. Zakodujemy i odkodujemy tekst (35 znaków)

Lepszy na wolności kęsek lada jaki.

Zamieniając tekst na liczbę – funkcją TextToNumber(s) – otrzymujemy liczbę 74-cyfrową

B = 45708184919001796601888077798001016874017601018470760177666966017566767415

Jest tak, bo każdy znak tekstu został zamieniony na dwie cyfry, ale każda z polskich liter "ś" i "ę" została zamieniona na dwie spacje i każdej z tych liter odpowiadają cztery cyfry "0101". Zauważmy, że B < m tak, jak być powinno.

Korzystając z funkcji RSAencode(m, e, s), dostajemy od razu zakodowany tekst

C = 1883258467778511884133977054466089742750188942420326552221154007622797635139655819975338109849673552

Po odkodowaniu funkcją RSAdecode(m, d, C), otrzymujemy

Lepszy na wolno  ci k  sek lada jaki.

Polskie litery zostały zastąpione przez dwie spacje.


Czytelnikowi pozostawiamy odszyfrowanie podanej niżej zakodowanej wiadomości. Ze względu na rozmiar musieliśmy podzielić tekst i otrzymaliśmy trzy zakodowane bloki.

C1 = 1228411078235780067165277802337600665865387220034514894292654793454492777859429937501850347835450261
C2 = 1212270919532485597119464911345613794658433495925582794819870422454753698249874400827689168074862675
C3 = 1407997868763350498310642273976637553443290951270357250985396471705600151258961305510222246198960667


Uwaga Q19
Omówiliśmy dokładnie metodę szyfrowania RSA i Czytelnik powinien mieć już jasność, że metodą tą możemy szyfrować tylko liczby. Jeśli chcemy zaszyfrować tekst, to musi najpierw zostać zapisany w postaci liczby (ciągu cyfr). Podaliśmy też dwie proste metody takiej zamiany (zobacz Q13 i Q16).

W dalszej części artykułu pisząc o szyfrowaniu metodą RSA, będziemy mieli najczęściej na myśli dwie czynności wykonywanie łącznie: zamianę tekstu na liczbę (ustaloną wcześniej metodą) i właściwą operację szyfrowania. Podobnie pisząc o odszyfrowaniu, też zazwyczaj będziemy mieli myśli dwie czynności: właściwą operację odszyfrowywania i zamianę otrzymanej liczby na tekst.


Uwaga Q20
Zwróćmy uwagę na to, że w przypadku pomyłki i zaszyfrowania wiadomości naszym kluczem prywatnym [math]\displaystyle{ (m, d) }[/math] możliwe będzie jej odczytanie przez każdą osobę, która zna nasz klucz publiczny [math]\displaystyle{ (m, e) }[/math]. Istotnie, niech [math]\displaystyle{ C = R_m (B^d) }[/math]. Łatwo pokażemy, że [math]\displaystyle{ B = R_m (C^e) }[/math].

[math]\displaystyle{ R_m (C^e) \equiv C^e \equiv (B^d)^e \equiv B^{e d} \equiv B^{- k \Phi + 1} \equiv B^{- k (p - 1) (q - 1) + 1} \equiv B \!\! \pmod{m} }[/math]

Fakt ten wykorzystamy do stworzenia podpisu wiadomości.



Kryptograficzne funkcje haszujące

Definicja Q21
Funkcja haszująca[10] przypisuje każdemu ciągowi bitów o dowolnej (ale skończonej) długości ciąg bitów o stałej długości.


Przykład Q22
Bardzo prosta funkcja haszująca przypisuje każdemu ciągowi osiem pierwszych bitów tego ciągu (w przypadku, gdy ciąg jest za krótki, wystarczy powtórzyć go odpowiednią liczbę razy). Tak określona funkcja nie jest dobrą funkcją haszującą i ze wszystkich wymagań (które wymienimy niżej) spełnia tylko jeden: możemy szybko obliczyć wynik.

Innym przykładem funkcji haszującej może być funkcja, która oblicza sumę kodów ASCII kolejnych znaków modulo [math]\displaystyle{ 256 }[/math]. Ta funkcja, podobnie jak poprzednia, jedynie szybko oblicza wynik.

Druga funkcja jest lepsza od pierwszej, bo każdy znak tekstu wpływa na uzyskany wynik. Co prawda ciągi znaków, których suma kodów ASCII wynosi 256 (np. "8dd") możemy dodawać bezkarnie, jednak uwzględniając, że wiadomość nie jest ciągiem przypadkowych znaków, modyfikacja wiadomości tak, aby hasz pozostał niezmieniony, będzie wymagała pewnego wysiłku.


Uwaga Q23
Od dobrej funkcji haszującej oczekujemy, że będzie spełniała następujące warunki

  • będzie szybko obliczać wynik
  • (jednokierunkowość) dla zadanej wartości hasza [math]\displaystyle{ h }[/math] znalezienie jakiegokolwiek ciągu bitów [math]\displaystyle{ m }[/math] takiego, że [math]\displaystyle{ h = \mathop{\text{hash}}(m) }[/math] powinno być bardzo trudne
  • (słaba odporność na kolizje) dla zadanego ciągu bitów [math]\displaystyle{ m_1 }[/math] znalezienie jakiegokolwiek ciągu bitów [math]\displaystyle{ m_2 \neq m_1 }[/math] takiego, że [math]\displaystyle{ \mathop{\text{hash}}(m_2) = \mathop{\text{hash}}(m_1) }[/math] powinno być bardzo trudne
  • (silna odporność na kolizje) znalezienie jakichkolwiek dwóch ciągów bitów [math]\displaystyle{ m_1 }[/math] i [math]\displaystyle{ m_2 }[/math] takich, że [math]\displaystyle{ \mathop{\text{hash}}(m_1) = \mathop{\text{hash}}(m_2) }[/math] powinno być bardzo trudne

W praktyce oznacza to, że jeżeli dwa łańcuchy mają taki sam hasz, to są one identyczne. To właśnie ta własność decyduje o przydatności funkcji haszującej dla podpisu elektronicznego i innych zastosowań.


Przykład Q24 (zastosowanie funkcji haszujących)
Jeśli chcemy upewnić się, czy przesłana mailem wiadomość nie zastała zmieniona, to wystarczy, że telefonicznie podamy odbiorcy hasz wiadomości.

Hasło podawane przy logowaniu powinno być haszowane, a system powinien przechowywać jedynie hasz hasła tak, aby samo hasło pozostawało nikomu nieznane.

Udostępniając do pobrania plik, możemy udostępnić również jego hasz. Umożliwi to łatwe sprawdzenie użytkownikowi, czy pobrany plik nie został uszkodzony.


Uwaga Q25 (przykłady funkcji haszujących)
Istnieje wiele wykorzystywanych w praktyce funkcji haszujących. Najbardziej znane to: CRC[11], MD5[12], SHA-1[13] oraz funkcje ze standardu SHA-2[14]: SHA-224, SHA-256, SHA-384, SHA-512

Linux udostępnia wypisane wyżej funkcje jako cksum (CRC), md5sum, sha1sum, sha224sum, sha256sum, sha384sum, sha512sum.

Na stronie GitHub – Online Tools znajdziemy wiele funkcji haszujących. Możemy policzyć wartości wybranej funkcji dla dowolnego tekstu i dla plików. Zauważmy, że wiele edytorów tekstu automatycznie dodaje znak końca linii[15] (LF) o kodzie ASCII równym 10 (szesnastkowo 0a) na końcu pliku. Może to powodować różnice przy obliczaniu hasza dla tekstu i dla pliku tekstowego zawierającego ten sam tekst.


Przykład Q26
Dla przykładu rozważmy, często używaną, funkcję haszującą SHA-256. Generuje ona 256-bitowy hasz, który zapisujemy, podając 64 cyfry w zapisie szesnastkowym. Każdą cyfrę w układzie szesnastkowym można zapisać w postaci 4 zer i jedynek w układzie dwójkowym (czterech bitów).

[math]\displaystyle{ 0 = 0000, \ldots, 9 = 1001, a = 1010, \ldots, f = 1111 }[/math]

Dla tekstu

Polskie litery i cyfry: ąćęłńóśźżĄĆĘŁŃÓŚŹŻ 0123456789

otrzymujemy hasz

5a86397d5e16611466e82376cc9f4d367ecbcd4af6d4418a5d3a130e8ad9d98d

Czytelnik powinien zwrócić uwagę, że nawet niewielka zmiana tekstu (np. zmiana lub dodanie jednego znaku) spowoduje wygenerowanie zupełnie innego hasza.



Podpisywanie dokumentów jawnych

Uwaga Q27
Zauważmy, że przekazywanie wiadomości (jawnych lub nie) wymaga wcześniejszego ustalenia sposobu komunikowania się. Może to być konto mailowe (jawne lub używane tylko do kontaktów tajnych), umówiona skrytka itd. Wynika stąd, że odbiorca zawsze zna nadawcę (wie, od kogo otrzymał przesyłkę).

Ponieważ musimy liczyć się z tym, że ustalony kanał łączności może zostać przejęty, a przekaz zmieniony, to stosujemy różnego rodzaju zabezpieczenia, których celem jest ochrona integralności przekazu.


Uwaga Q28
Powiedzmy, że Bolek chce przekazać ważny dokument do Urzędu. Jednak Urząd chce mieć pewność, że tak ważny dokument rzeczywiście sporządził Bolek, a nie ktoś inny, kto tylko pod Bolka się podszywa. Oczywiście można taki dokument przekazać osobiście, ale co zrobić w sytuacji, gdy jest to niemożliwe, a dostępny jest internet?

Jeśli Bolek potrafi szyfrować wiadomości metodą RSA i udostępnił swój klucz publiczny [math]\displaystyle{ (m, e) }[/math] Urzędowi, to może postąpić następująco

  1. sporządzić ów ważny dokument (powiedzmy DokB) w postaci pliku (ewentualnie papierowy dokument zeskanować)
  2. obliczyć hasz pliku DokB: [math]\displaystyle{ \; h_B = \mathop{\text{SHA256}}( \text{DokB} ) }[/math]
  3. zaszyfrować hasz [math]\displaystyle{ h_B }[/math] swoim kluczem prywatnym [math]\displaystyle{ (m, d) }[/math] (zobacz Q20)
    • zaszyfrowany hasz [math]\displaystyle{ h_B }[/math] jest podpisem Bolka (co za chwilę stanie się jasne)
  4. tak zaszyfrowany hasz wpisać w treści maila i załączyć plik DokB


Jak przebiega weryfikacja odebranej wiadomości?

  1. Urząd odbiera mail od Bolka i pobiera załącznik (nazwijmy go DokU, bo nie wiemy, czy nie został zmieniony)
  2. Urząd oblicza hasz załączonego pliku DokU: [math]\displaystyle{ \; h_U = \mathop{\text{SHA256}}( \text{DokU} ) }[/math]
  3. kluczem publicznym Bolka Urząd odszyfrowuje otrzymany w mailu zaszyfrowany hasz [math]\displaystyle{ h_B }[/math] (zobacz Q20)
  4. z równości [math]\displaystyle{ h_B = h_U }[/math] wynika, że dokumenty DokB i DokU są identyczne (zobacz Q23)


Jest tak, ponieważ z równości [math]\displaystyle{ h_B = h_U }[/math] wynika, że zaszyfrowany hasz [math]\displaystyle{ h_B }[/math] musiał pochodzić od Bolka, bo został zaszyfrowany jego kluczem prywatnym, do którego nikt, poza nim, nie ma dostępu. Dlatego zaszyfrowany kluczem prywatnym Bolka hasz [math]\displaystyle{ h_B }[/math] jest tym samym, co jego podpis i potwierdza to, że plik DokB (którego hasz jest równy [math]\displaystyle{ h_B }[/math]) został sporządzony przez Bolka.

Ujmując inaczej, każdy może przedstawić się w mailu jako Bolek, dołączyć spreparowany plik, policzyć hasz tego pliku, ale nie będzie w stanie zaszyfrować tego hasza kluczem prywatnym Bolka, bo klucz ten jest tajny i niedostępny dla nikogo poza Bolkiem.



Podpisywanie dokumentów tajnych

Uwaga Q29
Powiedzmy, że Bolek ma ważną informację i chce ją przekazać do Agencji. Oczywiście informacji nie może przeczytać nikt inny, a Agencja musi mieć pewność, że źródłem tej ważnej informacji jest rzeczywiście Bolek, a nie ktoś inny, kto tylko pod Bolka się podszywa. Tym razem Bolek na pewno potrafi szyfrować wiadomości metodą RSA, a jego klucz publiczny [math]\displaystyle{ (m, e) }[/math] jest z pewnością znany Agencji. Co więcej, Bolek zna klucz publiczny Agencji [math]\displaystyle{ (M, E) }[/math], którego ma używać do komunikowania się z Agencją. W tym przypadku Bolek postępuje następująco

  1. oblicza hasz wiadomości [math]\displaystyle{ h_B = \mathop{\text{SHA256}}( \text{tekst} ) }[/math]
  2. szyfruje hasz [math]\displaystyle{ h_B }[/math] swoim kluczem prywatnym [math]\displaystyle{ (m, d) }[/math]
  3. umieszcza zaszyfrowany hasz [math]\displaystyle{ h_B }[/math] jako ostatnią linię tekstu wiadomości
  4. szyfruje całość (tekst wiadomości + zaszyfrowany hasz [math]\displaystyle{ h_B }[/math]) kluczem publicznym Agencji [math]\displaystyle{ (M, E) }[/math]
  5. umieszcza cały zaszyfrowany tekst w pliku i wysyła jako załącznik maila do Agencji

Agencja

  1. pobiera załącznik
  2. tekst z załącznika odszyfrowuje kluczem prywatnym Agencji [math]\displaystyle{ (M, D) }[/math]
  3. z ostatniej linii pliku odczytuje zaszyfrowany hasz [math]\displaystyle{ h_A }[/math] tekstu otrzymanej wiadomości
  4. deszyfruje hasz [math]\displaystyle{ h_A }[/math] wiadomości kluczem publicznym Bolka [math]\displaystyle{ (m, e) }[/math]
  5. oblicza hasz [math]\displaystyle{ h_B }[/math] wiadomości od Bolka
  6. równość [math]\displaystyle{ h_B = h_A }[/math] potwierdza, że wiadomość nie została zmieniona i przekazał ją do Agencji Bolek

Zauważmy, że klucz publiczny Agencji może być wiedzą poufną, ale z pewnością nie jest tak dobrze strzeżony, jak klucze prywatne. Agencja nie może zakładać, że zaszyfrowany jej kluczem publicznym plik nie został spreparowany. Dopiero po odszyfrowaniu pliku, obliczeniu hasza wiadomości i potwierdzenia zgodności tego hasza z haszem zapisanym w ostatniej linii pliku (który został zaszyfrowany kluczem prywatnym Bolka) Agencja ma pewność, że plik stworzył i wysłał Bolek.


Uwaga Q30
Zwróćmy uwagę, że jeżeli korzystamy z funkcji TextToNumber() i NumberToText() (zobacz Q16), a jednocześnie chcemy podpisywać szyfrowane wiadomości, to wiadomości nie mogą zawierać znaków innych niż znaki ASCII od 32 do 126.

Jest tak dlatego, że funkcja TextToNumber() zgubi informację o innych znakach w wiadomości, a funkcja NumberToText() już tej informacji nie odtworzy. Zatem hasz wysyłanej wiadomości i hasz otrzymanej wiadomości (po odszyfrowaniu) nigdy nie będą identyczne w przypadku użycia znaków innych niż znaki ASCII od 32 do 126.








Przypisy

  1. Whitfield Diffie and Martin E. Hellman, New Directions in Cryptography, IEEE Transactions on Information Theory, Vol. 22, No. 6, 1976 (LINK)
  2. Wikipedia, Protokół Diffiego-Hellmana, (Wiki-pl), (Wiki-en)
  3. Liczba [math]\displaystyle{ g }[/math] powinna (ale nie musi) być generatorem modulo [math]\displaystyle{ p }[/math]. Dlaczego tak jest, wyjaśnimy w dalszej części tekstu.
  4. Wikipedia, Funkcja φ, (Wiki-pl), (Wiki-en)
  5. R. Rivest, A. Shamir and L. Adleman, A Method for Obtaining Digital Signatures and Public-Key Cryptosystems, Communications of the ACM, Volume 21, Issue 2, Feb. 1978, pp. 120-126
  6. Wikipedia, RSA (kryptografia), (Wiki-pl), (Wiki-en)
  7. Dan Boneh and Glenn Durfee, Cryptanalysis of RSA with Private Key d Less Than N0.292, IEEE Transactions on Information Theory, Vol. 46, No. 4, 2000
  8. Wikipedia, RSA numbers, (Wiki-en)
  9. Wikipedia, ASCII, (Wiki-pl), (Wiki-en)
  10. Wikipedia, Cryptographic hash function, (Wiki-en), (Wiki-pl)
  11. Wikipedia, Cykliczny kod nadmiarowy, (Wiki-pl), (Wiki-en)
  12. Wikipedia, MD5, (Wiki-pl), (Wiki-en)
  13. Wikipedia, SHA-1, (Wiki-pl), (Wiki-en)
  14. Wikipedia, SHA-2, (Wiki-pl), (Wiki-en)
  15. Wikipedia, Koniec linii, (Wiki-pl), (Wiki-en)