Wrocław University of Science and TechnologyDepartment of Fundamentals of Computer Science

Kryptografia II stopień

Od definicji bezpieczeństwa do konstrukcji, redukcji i publikacji naukowych.

W6. Grupy, klucze i problemy trudne

Publiczna informacja pozwala szyfrować lub sprawdzać wynik, ale nie powinna umożliwiać odzyskania sekretu. Para kluczy rozdziela uprawnienia: do publicznej operacji nie potrzeba prawa do operacji prywatnej. Nadal potrzebujemy sposobu ustalenia, czy publiczny klucz naprawdę należy do zamierzonego partnera.

Grupa, generator i skalar bez skrótów myślowych

Najpierw zapis potęgowy. Do zrozumienia Schnorra, Okamoto czy wymiany Diffiego–Hellmana wystarczą na początek reguły mnożenia potęg. Będziemy pisać gag^a, także gdy implementacja reprezentuje ten element jako punkt krzywej. Najpierw poznamy rolę sekretu, komunikatów i równania weryfikacji. Dopiero potem połączymy te operacje z działaniami biblioteki.

Grupa to zbiór z odwracalnym, łącznym działaniem, elementem neutralnym i odwrotnościami. Nie oznacza tu grupy użytkowników. Grupa cykliczna G=⟨g⟩G=\langle g\rangle jest generowana przez jeden element gg: kolejne jego potęgi przechodzą przez wszystkie elementy. Rząd qq jest liczbą elementów. Będziemy najczęściej używać pierwszego qq.

Skalar aa jest liczbą z ciała Zq\mathbb Z_q, czyli klasą reszt modulo qq. Symbol Zq∗\mathbb Z_q^* wyklucza zero. Sekret a∈Zq∗a\in\mathbb Z_q^* daje klucz publiczny A=gaA=g^a. Oznaczenia przypominają duże i małe litery celowo: skalar i odpowiadający mu element grupy są różnymi obiektami. Z publicznego AA potrafimy wykonywać działania grupowe, ale nie zakładamy znajomości aa.

Mały przykład do rachunku: w podgrupie modulo 4747 generator g=2g=2 ma rząd q=23q=23. Dla a=7a=7 dostajemy A=34A=34. Elementy grupy mnożymy modulo 47, a wykładniki dodajemy i mnożymy modulo 23. Te parametry są zbyt małe do ochrony danych. Ich zadaniem jest pokazanie dwóch różnych miejsc redukcji.

Na krzywej eliptycznej współrzędne punktu również mają własne ciało. Jego charakterystyka nie jest tym samym co rząd podgrupy skalarów. Pomylenie tych liczb daje błędny protokół, nie inny sposób zapisu tego samego rachunku.

Jedno działanie grupowe, dwa sposoby zapisu

Konwencja kursu. Schematy i ich animowane przebiegi objaśniamy najpierw przez iloczyny i potęgi w grupie. Dotyczy to Schnorra, Okamoto, Stinsona–Wu, wymiany klucza i szyfrowania ElGamala. Tak samo zaczynamy objaśnienie BLS. Zapis addytywny pojawia się w wyraźnie oznaczonym przejściu do realizacji na krzywej lub w porównaniu obu notacji. Nie zmieniamy zapisu tylko dlatego, że demonstrator korzysta z MCL.

BLS
Boneh–Lynn–Shacham. Nazwiska autorów schematu krótkich podpisów z pairingiem.
MCL
mcl. Nazwa biblioteki kryptograficznej Herumi do szybkich obliczeń grupowych i pairingów.

Biblioteka nie narzuca protokołowi pairingu. MCL wykonuje dodawanie punktów i mnożenie ich przez skalary. Udostępnia też osobną operację pairingu. Schnorr, Okamoto, Stinson–Wu, Diffie–Hellman i ElGamal jej nie potrzebują. Weryfikacja BLS i omawianej zmodyfikowanej identyfikacji rzeczywiście z niej korzysta.

W ciele Zq\mathbb Z_q każdy niezerowy skalar ma odwrotność. Dlatego można rozwiązać równanie d⋅a=td\cdot a=t jako a=t⋅d−1a=t\cdot d^{-1}, jeśli d≠0d\ne0. W grupie łatwo wykonujemy działanie i odwracamy element, ale nie zakładamy możliwości odzyskania wykładnika. Możemy obliczyć (ga)b=ga⋅b(g^a)^b=g^{a\cdot b} znając bb, nawet gdy nie znamy aa.

ga⋅gb=ga+b,(ga)b=ga⋅b,(ga)−1=g−a.g^a\cdot g^b=g^{a+b},\qquad (g^a)^b=g^{a\cdot b},\qquad (g^a)^{-1}=g^{-a}.

Wykładniki liczymy modulo qq. Potęga oznacza powtarzanie działania grupowego, a nie obowiązkowo potęgowanie liczby całkowitej. W przykładzie modulo 47 działaniem jest mnożenie reszt. W grupie punktów krzywej to samo rozumowanie korzysta z dodawania punktów. Tych dwóch realizacji nie utożsamiamy jako zbiorów liczb.

W zapisie addytywnym generator oznaczymy przez PP. Wtedy a⋅Pa\cdot P oznacza wielokrotne dodawanie realizowane wydajnym algorytmem, a O\mathcal O jest punktem neutralnym. Przejście z gag^a na a⋅Pa\cdot P zmienia notację operacji, nie kolejność komunikatów ani sens sprawdzanego równania. Nie podnosimy osobno współrzędnych punktu do potęgi.

Dla elementów grupy A,XA,X i skalara cc otrzymujemy następujący słownik:

Zapis multiplikatywny Zapis addytywny Sens
gag^a a⋅Pa\cdot P Działanie skalaru na generator
ga⋅gbg^a\cdot g^b a⋅P+b⋅Pa\cdot P+b\cdot P Połączenie elementów
(ga)b(g^a)^b b⋅(a⋅P)b\cdot(a\cdot P) Złożenie mnożeń skalarnych
g0=1Gg^0=1_G 0⋅P=O0\cdot P=\mathcal O Element neutralny
A−1A^{-1} −A-A Element odwrotny
X⋅AcX\cdot A^c X+c⋅AX+c\cdot A Zobowiązanie połączone z kluczem

Litery AA i XX oznaczają w obu kolumnach odpowiadające sobie elementy grupy. Nie są skalarami. Sumy w wykładnikach nadal są sumami skalarów. Na przykład odpowiedź s=u+a⋅cs=u+a\cdot c nie zmienia się przy przejściu do zapisu addytywnego.

RFC 8235, §2–3 przedstawia Schnorra w podgrupie multiplikatywnej modulo liczbę pierwszą oraz na krzywej. Dokument używa odpowiedzi z minusem. W tym kursie zachowujemy odpowiedź z plusem i odpowiadające jej równanie weryfikacji. Nie mieszamy tych konwencji.

Od wzoru do programu: rachunek w ciele

Po co ten fragment? Własna implementacja musi umieć wykonać działanie, a nie tylko zapisać jego symbol. Poniższy warsztat rozwija podstawy potrzebne w C0a i L0a. Zaczynamy od reszt całkowitych, przechodzimy do wielomianów, a dopiero potem do współrzędnych punktów. Małe parametry służą nauce i testom. Nie zapewniają bezpieczeństwa.

W ciele można dodawać, odejmować, mnożyć i dzielić przez każdy niezerowy element. Dla pierwszego pp ciało Fp\mathbb F_p realizujemy jako reszty 0,…,p−10,\ldots,p-1. Po działaniu wybieramy jednego reprezentanta przez redukcję modulo pp. Dla złożonego modułu to ogólnie pierścień, nie ciało. Na przykład 5⋅5=05\cdot5=0 w Z25\mathbb Z_{25}, więc niezerowe 55 nie ma odwrotności. Ciało o 25 elementach zbudujemy inaczej.

Odwrotność modularna. Rozszerzony algorytm Euklidesa, extended Euclidean algorithm, EEA, oblicza liczby s,ts,t spełniające s⋅a+t⋅n=gcd⁡(a,n)s\cdot a+t\cdot n=\gcd(a,n). Symbol gcd⁡\gcd oznacza największy wspólny dzielnik, NWD. Gdy NWD wynosi 1, odwrotnością aa modulo nn jest smodns\bmod n. Gdy NWD jest większy od 1, odwrotność nie istnieje. Nie wolno zastąpić jej ilorazem zmiennoprzecinkowym.

Przykładowo 17=3⋅5+217=3\cdot5+2 i 5=2⋅2+15=2\cdot2+1. Podstawienie wsteczne daje 1=7⋅5−2⋅171=7\cdot5-2\cdot17, więc 5−1=75^{-1}=7 w F17\mathbb F_{17}. Ten sam rachunek można prowadzić wraz z resztami. Zacznij od (r0,r1)=(n,amodn)(r_0,r_1)=(n,a\bmod n) i (s0,s1)=(0,1)(s_0,s_1)=(0,1). W każdej iteracji oblicz d=⌊r0/r1⌋d=\lfloor r_0/r_1\rfloor i jednocześnie zastąp pary przez (r1,r0−d⋅r1)(r_1,r_0-d\cdot r_1) oraz (s1,s0−d⋅s1)(s_1,s_0-d\cdot s_1). Po osiągnięciu r1=0r_1=0 sprawdź r0=1r_0=1 i zwróć s0modns_0\bmod n.

Rozszerzenie ciała: współczynniki zamiast reszt modulo potęgi

Niech f(t)f(t) będzie nierozkładalnym wielomianem stopnia dd nad Fp\mathbb F_p. Definiujemy Fpd=Fp[t]/(f)\mathbb F_{p^d}=\mathbb F_p[t]/(f). Element reprezentujemy przez a0+a1⋅t+⋯+ad−1⋅td−1a_0+a_1\cdot t+\cdots+a_{d-1}\cdot t^{d-1}. Współczynniki liczymy modulo pp, a wynik mnożenia wielomianów redukujemy modulo ff. To dwie odrębne redukcje, żadna nie jest redukcją całkowitą modulo pdp^d.

  • Dodawanie: dodaj współczynniki o tych samych indeksach modulo pp.
  • Mnożenie: wykonaj splot współczynników. Następnie odejmuj odpowiednią wielokrotność ff, aby usuwać najwyższy wyraz, aż stopień wyniku będzie mniejszy od dd.
  • Dzielenie wielomianów: współczynnik potrzebny do usunięcia najwyższego wyrazu uzyskujemy przez odwrotność współczynnika wiodącego dzielnika w Fp\mathbb F_p.
  • Odwrotność: wielomianowy EEA znajduje s(t)⋅a(t)+v(t)⋅f(t)=bs(t)\cdot a(t)+v(t)\cdot f(t)=b, gdzie bb jest niezerową stałą. Odwrotność to b−1⋅s(t)modf(t)b^{-1}\cdot s(t)\bmod f(t). Dla zera odrzucamy żądanie.

Dla p=5p=5 wybierzmy f(t)=t2+2f(t)=t^2+2. Kwadraty modulo 5 to 0,1,40,1,4, a równanie t2=3t^2=3 nie ma rozwiązania. Wielomian kwadratowy bez pierwiastka jest nierozkładalny. Oznaczając resztę tt przez α\alpha, otrzymujemy α2=3\alpha^2=3. Na przykład (2+α)⋅(4+3⋅α)=2(2+\alpha)\cdot(4+3\cdot\alpha)=2 oraz α−1=2⋅α\alpha^{-1}=2\cdot\alpha. Każdy z 25 elementów jest parą współczynników, nie pojedynczą resztą modulo 25.

Jak sprawdzić nierozkładalność? Brak pierwiastków wystarcza dla stopnia 2 lub 3. Dla stopnia 4 już nie, bo możliwy jest iloczyn dwóch nierozkładalnych wielomianów kwadratowych. W małych zadaniach sprawdź dzielenie przez wszystkie moniczne wielomiany stopnia od 1 do ⌊d/2⌋\lfloor d/2\rfloor. Jeżeli żaden nie dzieli ff, nie ma rozkładu na dwa czynniki dodatnich stopni. To prosta metoda dydaktyczna, nie wydajny algorytm dla dużych parametrów.

Ciało binarne i znaczenie kolejności bitów

W F2\mathbb F_2 dodawanie i odejmowanie to XOR. W laboratoryjnej reprezentacji wielomianu bit numer ii od prawej jest współczynnikiem przy tit^i. Liczba 0x53 oznacza więc t6+t4+t+1t^6+t^4+t+1. XOR całych słów dodaje wielomiany, lecz zwykłe mnożenie liczb całkowitych wprowadza przeniesienia i nie mnoży elementów tego ciała.

Mnożenie bez przeniesień wykonujemy tak: ustaw wynik na zero, czytaj kolejne bity drugiego czynnika, a dla każdego bitu 1 dodaj XOR-em odpowiednio przesunięty pierwszy czynnik. Zredukuj wynik wielomianem modułu. Można również redukować po każdym przesunięciu. Nie wolno pomylić tych algorytmów z mnożeniem liczb całkowitych modulo liczbę kodującą wielomian.

W AES modułem jest f(t)=t8+t4+t3+t+1f(t)=t^8+t^4+t^3+t+1, o zapisie 0x11b. Operacja xtime(a) mnoży przez tt. Przesuń bajt o jeden bit w lewo, zachowaj osiem młodszych bitów i dodaj XOR-em 0x1b, jeśli przed przesunięciem najstarszy bit był równy 1. Dla 0x83 wynik to 0x1d. To właśnie redukcja wyrazu t8t^8, nie dodatkowy sekret szyfru.

Wzory działania i kodowania ciał oraz krzywych zestawia SEC 1, rozdział 2. Rachunek bajtowy AES definiuje FIPS 197, §4.2. Własne obliczenia porównujemy z tymi specyfikacjami i z niezależną implementacją.

GHASH: od bloków do znacznika GCM

To opcjonalne rozwinięcie AEAD z W4. Najpierw potrzebne są powyższe działania w ciele binarnym. GCM używa ciała F2128\mathbb F_{2^{128}} z modułem t128+t7+t2+t+1t^{128}+t^7+t^2+t+1. Konwencja bitowa NIST jest odwrotna do powyższego przykładu AES: lewy bit bloku odpowiada współczynnikowi przy t0t^0. Jedynka ciała ma kod 80 i 15 zerowych bajtów. Nie przenosimy bez konwersji reprezentacji z L0a.

Do mnożenia dwóch bloków U,VU,V można bezpośrednio zastosować algorytm 1 standardu. Ustaw Z=0Z=0, W=VW=V i przeglądaj bity UU od lewej. Dla bitu 1 wykonaj Z←Z⊕WZ\leftarrow Z\oplus W. Następnie przesuń WW o jeden bit w prawo. Jeżeli przed przesunięciem prawy bit WW był równy 1, dodaj XOR-em stałą e1 i 15 zerowych bajtów. Po 128 krokach ZZ jest iloczynem. Kierunek przesunięcia wynika z kodowania współczynników.

Niech H=AESK(0128)H=\mathsf{AES}_K(0^{128}) będzie tajnym elementem ciała. To duże HH nie oznacza funkcji ℋ\mathcal H. Dla bloków S1,…,SnS_1,\ldots,S_n długości 128 bitów obliczamy

Y0=0,Yi=(Yi−1⊕Si)⋅H,1≤i≤n,GHASHH(S1∥⋯∥Sn)=Yn.\begin{aligned} Y_0&=0,\\ Y_i&=(Y_{i-1}\oplus S_i)\cdot H,\qquad 1\le i\le n,\\ \mathsf{GHASH}_H(S_1\Vert\cdots\Vert S_n)&=Y_n. \end{aligned}

W GCM blokami SiS_i nie są same bajty wiadomości. Oznaczmy dane dodatkowe przez AA, a szyfrogram bez znacznika przez CC. Zbuduj wejście:

A∥0v∥C∥0u∥[∣A∣]64∥[∣C∣]64.A\Vert0^v\Vert C\Vert0^u\Vert[|A|]_{64}\Vert[|C|]_{64}.

Długości mierzymy w bitach. Liczby v=(−∣A∣)mod128v=(-|A|)\bmod128 i u=(−∣C∣)mod128u=(-|C|)\bmod128 należą do {0,…,127}\{0,\ldots,127\}. Symbol [x]64[x]_{64} to 64-bitowy zapis liczby xx od najbardziej znaczącego bajtu. Dane już wyrównane nie dostają dodatkowego pełnego bloku zer. Blok długości występuje zawsze, nawet przy pustych danych. Pozwala odróżnić rzeczywiste końcowe zera od zer dopełnienia.

Dla przykładu z 2 bajtami AAD i 16 bajtami szyfrogramu wejście ma trzy bloki: AAD i 14 zerowych bajtów, cały szyfrogram oraz dwie 64-bitowe liczby 16 i 128. Nie są to długości 2 i 16. Zmiana długości wpływa więc na wejście uwierzytelnienia, nawet jeśli wartości dopisanych bajtów są zerami.

Przy 96-bitowym nonce NN ustal J0=N∥031∥1J_0=N\Vert0^{31}\Vert1. Pełny 128-bitowy znacznik ma postać T=AESK(J0)⊕YnT=\mathsf{AES}_K(J_0)\oplus Y_n. Licznik szyfrowania danych zaczyna się od zwiększenia prawego 32-bitowego pola J0J_0, więc nie używa tej samej maski co znacznik. Osobno sprawdzamy ograniczenia długości i unikalność nonce. Inna długość nonce wymaga innego wyznaczenia J0J_0, którego ten wariant zadania nie używa.

Punkt kontrolny: dla 128-bitowego zerowego klucza, zerowego 96-bitowego nonce oraz pustych A,CA,C mamy Yn=0Y_n=0 i T = 58e2fccefa7e3061367f1d57a4e7455a. Ten mały przypadek sprawdza maskę i obsługę pustych danych, ale nie wystarcza do testowania mnożenia. Sprawdź także bloki niezerowe i niewyrównane długości. Źródło definicji: NIST SP 800-38D, algorytmy 1–4. Sam GHASH nie jest pełnym MAC ani haszem odpornym na kolizje.

Krzywa nad ciałem pierwszym: wszystkie przypadki działania

Tutaj przechodzimy jawnie do realizacji addytywnej. Niech p>3p>3 będzie pierwsze. Dla krzywej E:y2=x3+aE⋅x+bEE:y^2=x^3+a_E\cdot x+b_E wymagamy 4⋅aE3+27⋅bE2≠04\cdot a_E^3+27\cdot b_E^2\ne0 w Fp\mathbb F_p. Współczynniki aE,bEa_E,b_E opisują krzywą, nie klucz użytkownika. Elementy grupy to jej punkty oraz osobny punkt neutralny O\mathcal O.

Dla P=(x1,y1)P=(x_1,y_1) mamy −P=(x1,−y1)-P=(x_1,-y_1). Zawsze P+O=PP+\mathcal O=P i P+(−P)=OP+(-P)=\mathcal O. Dla dwóch pozostałych punktów P,Q=(x2,y2)P,Q=(x_2,y_2) obliczamy nachylenie ℓ\ell, a potem współrzędne wyniku:

ℓ={(y2−y1)⋅(x2−x1)−1,x1≠x2,(3⋅x12+aE)⋅(2⋅y1)−1,P=Q, y1≠0,\ell=\begin{cases} (y_2-y_1)\cdot(x_2-x_1)^{-1},&x_1\ne x_2,\\ (3\cdot x_1^2+a_E)\cdot(2\cdot y_1)^{-1},&P=Q,\ y_1\ne0, \end{cases}
x3=ℓ2−x1−x2,y3=ℓ⋅(x1−x3)−y1.\begin{aligned} x_3&=\ell^2-x_1-x_2,\\ y_3&=\ell\cdot(x_1-x_3)-y_1. \end{aligned}

Wszystko liczymy w Fp\mathbb F_p, łącznie z odwrotnościami. Dla podwojenia punktu o y1=0y_1=0 wynikiem jest O\mathcal O, a nie dzielenie przez zero. Dla poprawnych punktów przypadek tego samego xx jest albo podwojeniem, albo dodaniem punktu przeciwnego. Najpierw obsługujemy przypadki wyjątkowe, dopiero potem wzór.

Na krzywej y2=x3+2⋅x+2y^2=x^3+2\cdot x+2 nad F17\mathbb F_{17} weźmy P=(5,1)P=(5,1). Przy podwojeniu ℓ=(3⋅25+2)⋅2−1=13\ell=(3\cdot25+2)\cdot2^{-1}=13 w ciele. Dostajemy 2⋅P=(6,3)2\cdot P=(6,3) i po kolejnym dodaniu 3⋅P=(10,6)3\cdot P=(10,6). Każdy wynik ponownie podstaw do równania krzywej. To dobry test kodu, ale nie samodzielny dowód łączności prawa grupowego.

Skalary a współrzędne. Jeżeli PP ma pierwszy rząd qq, to (kmodq)⋅P=k⋅P(k\bmod q)\cdot P=k\cdot P. Nie wolno zamiast tego redukować kk modulo pp. Współrzędne nadal należą do Fp\mathbb F_p. Dla obcych danych najpierw sprawdź poprawne kodowanie i równanie krzywej, następnie podgrupę, a osobno dozwolenie punktu neutralnego. Przy #E(Fp)=h⋅q\#E(\mathbb F_p)=h\cdot q i gcd⁡(h,q)=1\gcd(h,q)=1 warunek q⋅Q=Oq\cdot Q=\mathcal O wybiera jedyną podgrupę rzędu qq. Bez tego założenia nie przedstawiaj testu jako ogólnego dowodu przynależności do dowolnie wybranej podgrupy.

Opcjonalnie: krzywa w charakterystyce 2

W zadaniu binarnym przyjmujemy E:y2+x⋅y=x3+aE⋅x2+bEE:y^2+x\cdot y=x^3+a_E\cdot x^2+b_E nad F2d\mathbb F_{2^d}, z bE≠0b_E\ne0. Nie używamy wzorów dla p>3p>3. Tutaj −(x,y)=(x,x+y)-(x,y)=(x,x+y). Neutralny punkt obsługujemy tak samo jak wcześniej. Dla x1≠x2x_1\ne x_2:

ℓ=(y1+y2)⋅(x1+x2)−1,x3=ℓ2+ℓ+x1+x2+aE,y3=ℓ⋅(x1+x3)+x3+y1.\begin{aligned} \ell&=(y_1+y_2)\cdot(x_1+x_2)^{-1},\\ x_3&=\ell^2+\ell+x_1+x_2+a_E,\\ y_3&=\ell\cdot(x_1+x_3)+x_3+y_1. \end{aligned}

Przy P=QP=Q i x1≠0x_1\ne0 używamy ℓ=x1+y1⋅x1−1\ell=x_1+y_1\cdot x_1^{-1}, x3=ℓ2+ℓ+aEx_3=\ell^2+\ell+a_E i y3=x12+(ℓ+1)⋅x3y_3=x_1^2+(\ell+1)\cdot x_3. Przy podwojeniu punktu o x1=0x_1=0 wynikiem jest O\mathcal O. Dwa różne poprawne punkty o tym samym xx są przeciwne. Dodawanie w tych wzorach oznacza XOR reprezentacji wielomianowych, a mnożenie i odwrotność korzystają z modułu ciała. Dla aE=bE=1a_E=b_E=1 punkt (0,1)(0,1) spełnia równanie i ma rząd 2. Reguły prawa grupowego podaje SEC 1, §2.2.

Potęgowanie, drabinka i liczenie operacji

Wróćmy do zapisu multiplikatywnego BkB^k w dowolnej grupie. Nie mnożymy kk razy. Zapisz kk binarnie jako bity bℓ−1,…,b0b_{\ell-1},\ldots,b_0, z bℓ−1=1b_{\ell-1}=1 dla k>0k>0.

Square-and-multiply, czyli kwadratowanie i mnożenie, zaczyna od R=BR=B i czyta pozostałe bity od lewej. Dla każdego wykonuje R←R2R\leftarrow R^2, a dla bitu 1 dodatkowo R←R⋅BR\leftarrow R\cdot B. Dla dodatniego kk potrzeba ℓ−1\ell-1 kwadratowań i wt⁡(k)−1\operatorname{wt}(k)-1 dodatkowych mnożeń, gdzie wt⁡\operatorname{wt} jest liczbą bitów 1. Dla k=0k=0 zwracamy element neutralny. Wariant zaczynający od R=1GR=1_G i czytający wszystkie bity ma inne liczniki. Dlatego w benchmarku podaj wariant.

Drabinka: zacznij od (R0,R1)=(1G,B)(R_0,R_1)=(1_G,B) i czytaj wszystkie bity. Dla bitu 0 zastąp parę przez (R02,R0⋅R1)(R_0^2,R_0\cdot R_1), a dla bitu 1 przez (R0⋅R1,R12)(R_0\cdot R_1,R_1^2). Aktualizacja jest jednoczesna. Jeśli dotąd odczytano liczbę vv, niezmiennikiem jest (R0,R1)=(Bv,Bv+1)(R_0,R_1)=(B^v,B^{v+1}). Kolejny bit zmienia vv na 2v+b2v+b, co uzasadnia obie reguły. Po zakończeniu zwróć R0R_0.

Dla k=13k=13, czyli bitów 1101, niezmiennik drabinki opisuje kolejno pary wykładników (1,2),(3,4),(6,7),(13,14)(1,2),(3,4),(6,7),(13,14). Powyższy wariant wykonuje 4 kwadratowania i 4 mnożenia. Square-and-multiply wykonuje 3 kwadratowania i 2 mnożenia. Dla krzywej kwadratowanie zastępujemy podwojeniem punktu, a mnożenie dodawaniem punktów.

Stała liczba działań nie dowodzi stałego czasu. Warunek zależny od tajnego bitu, dostęp do pamięci i sama arytmetyka dużych liczb mogą ujawniać informacje. Pythonowe przykłady służą rachunkowi i pomiarowi, nie ochronie sekretu przed kanałem czasowym. Podstawy algorytmiczne: Handbook of Applied Cryptography, rozdział 14.

Od elementu matematycznego do jednoznacznych bajtów

Protokół haszuje i przesyła bajty. Umowa musi określać grupę, jej parametry, kolejność bajtów, długość każdego pola i obsługę błędnych danych. Dla małej krzywej dydaktycznej można wybrać wyłącznie nieskompresowany format SEC 1: 04, następnie xx i yy jako liczby big-endian po ⌈log⁡2(p)/8⌉\lceil\log_2(p)/8\rceil bajtów. Punkt neutralny ma osobny kod 00. Jego dopuszczenie zależy od roli w protokole. Tych kodów nie przenosimy automatycznie do formatu BLS12-381 biblioteki.

BLS12-381
Barreto–Lynn–Scott. Rodzina krzywych eliptycznych. W BLS12-381 stopień zanurzenia wynosi 12, a moduł ciała bazowego ma 381 bitów. To inny zestaw nazwisk niż w podpisie BLS.

Odbiorca odrzuca złą długość, niewłaściwy znacznik i współrzędne spoza zakresu. Nie redukuje obcej współrzędnej modulo pp, bo dopuściłby kilka kodowań tego samego punktu. Następnie sprawdza punkt i podgrupę. Dla krotek o zmiennych długościach można poprzedzać każde pole jego 32-bitową długością w bajtach, ustalając limit 232−12^{32}-1. Dodaj etykietę protokołu i jego wersji. Para ab, c musi mieć inne kodowanie niż a, bc.

W teście zgodności sprawdź zarówno Decode(Encode(P))=P\mathsf{Decode}(\mathsf{Encode}(P))=P, jak i odrzucenie niekanonicznych wejść. Potem porównaj dokładne bajty i wartości hasza między dwoma programami. Dopiero na takiej wspólnej reprezentacji porównujemy podpisy i wspólne sekrety.

Pairing najpierw jako rachunek wykładników

Pairing to wydajnie obliczalne odwzorowanie e:G1×G2→GTe:G_1\times G_2\to G_T, gdzie grupy mają zgodny pierwszy rząd qq. W zapisie potęgowym wybierzmy generatory g1∈G1g_1\in G_1, g2∈G2g_2\in G_2. Dwuliniowość oznacza:

e(g1a,g2b)=e(g1,g2)a⋅b.e(g_1^a,g_2^b)=e(g_1,g_2)^{a\cdot b}.

To pozwala sprawdzać relacje pomiędzy ukrytymi wykładnikami, bez ich odczytywania. W demonstratorze te same generatory noszą nazwy P1,P2P_1,P_2, a grupy źródłowe są zapisane addytywnie. Grupa docelowa pozostaje multiplikatywna:

e(a⋅P1,b⋅P2)=e(P1,P2)a⋅b.e(a\cdot P_1,b\cdot P_2)=e(P_1,P_2)^{a\cdot b}.

Niedegeneracja wymaga, aby pairing odpowiednich generatorów nie dawał elementu neutralnego. Typy mają znaczenie: pierwszy argument należy do G1G_1, drugi do G2G_2. W używanym typie asymetrycznym nie zakładamy wydajnego przenoszenia dowolnego punktu pomiędzy tymi grupami. MCL reprezentuje je odrębnymi typami, a wynik parowania ma typ GTG_T.

Biliniowość: obie strony równania policzone osobno

Realizacja addytywna na krzywej BLS12-381. Rzeczywiste G1, G2 i GT, obliczane w MCL WebAssembly. Wynik parowania jest elementem GT, nie punktem krzywej.

Prawa strona równania
Biliniowość: obie strony równania policzone osobno1. Generatory i skalary
P1∈G1,P2∈G2P_1\in G_1,\quad P_2\in G_2
oczekuje
2. Mnożenia w grupach źródłowych
X=x⋅P1,Y=y⋅P2X=x\cdot P_1,\quad Y=y\cdot P_2
oczekuje
3. Dwie drogi do grupy docelowej
L=e(X,Y),R=e(P1,P2)x⋅yL=e(X,Y),\quad R=e(P_1,P_2)^{x\cdot y}
oczekuje
4. Porównanie elementów
L=?RL\stackrel{?}{=}R
oczekuje

Gotowe.

Obliczenia MCL na krzywej. Poniżej pokazujemy konkretne operacje biblioteki. Grupy punktów zapisujemy addytywnie.

  1. Generatory i skalary

    Oczekuje.

  2. Mnożenia w grupach źródłowych

    Oczekuje.

  3. Dwie drogi do grupy docelowej

    Oczekuje.

  4. Porównanie elementów

    Oczekuje.

Sprawdź: Zmień x i y. Następnie dodaj 1 tylko do wykładnika prawej strony. Równość ma wynikać z obliczeń, nie z etykiety wariantu.

WebAssembly
WebAssembly. Format kodu wykonywanego m.in. w przeglądarce. Wasm i WASM to jego skrócone nazwy.

Pełny zapis elementu GTG_T jest długi, ponieważ reprezentuje element rozszerzenia ciała. Porównujemy całe obiekty MCL, nie ich skrócone etykiety na rysunku. Zmiana wykładnika z x⋅yx\cdot y na x⋅y+1x\cdot y+1 jest testem negatywnym. Punkty oraz obie strony równania powstają w MCL WebAssembly.

Hasze mają różne typy wyników

Teraz znamy zarówno ciało skalarów, jak i grupy pairingu. Możemy precyzyjnie rozdzielić funkcje, które wcześniej nazywaliśmy ogólnie haszami. Indeks G1G_1 oznacza poprawne haszowanie do grupy, nie publicznie znany logarytm wyniku.

Oznaczenie Wynik Rola
D\mathcal D ciąg bitów Skrót pliku
ℋ\mathcal H Zq\mathbb Z_q Wyzwanie lub skalar
ℋG1\mathcal H_{G_1} G1G_1 Hash do punktu
KDF\mathsf{KDF} klucz o określonej długości Wyprowadzanie kluczy

Co zakładamy jako trudne

Najpierw motywacja: Alicja publikuje A=gaA=g^a, Bob publikuje B=gbB=g^b. Alicja zna aa, więc liczy BaB^a. Bob zna bb, więc liczy AbA^b. Oba wyniki to ga⋅bg^{a\cdot b}. Podsłuchujący widzi g,A,Bg,A,B, lecz nie dostaje a,ba,b. To rdzeń wymiany Diffiego–Hellmana (DH). Na razie wyjaśnia tylko zgodność obliczeń. Nie potwierdza tożsamości, co będzie głównym problemem W10.

DL oznacza logarytm dyskretny. CDH to obliczeniowy problem DH, a DDH to decyzyjny problem DH. W DDH porównujemy krotkę z prawdziwym wspólnym elementem i krotkę, której ostatni element jest losowany niezależnie, jednostajnie w tej samej grupie.

DL
discrete logarithm / discrete logarithm problem. Logarytm dyskretny / problem logarytmu dyskretnego.
CDH
Computational Diffie–Hellman. Obliczeniowy problem Diffiego–Hellmana.
Problem Dane Wynik
DL g,gag,g^a aa
CDH g,ga,gbg,g^a,g^b ga⋅bg^{a\cdot b}
DDH g,ga,gb,Tg,g^a,g^b,T Rozróżnienie DH od losowego TT

Algorytm DL rozwiązuje CDH, a CDH pozwala testować DDH. Odwrotne implikacje nie wynikają z tej obserwacji. Pairing może zmienić trudność problemu decyzyjnego, dlatego określamy grupy i dostępne reprezentacje.

W7. Identyfikacja: Schnorr, symulacja i ekstrakcja

Potrzeba: weryfikator chce teraz sprawdzić, czy rozmówca kontroluje sekret przypisany do zarejestrowanego klucza. Klucz publiczny musi być wcześniej powiązany z kontem lub osobą. Sam protokół nie ustala nazwiska na podstawie równania.

Interfejs identyfikacji interaktywnej

Schemat ma parametry, generowanie kluczy oraz dwa współdziałające algorytmy:

ΠID=(Setup,KeyGen,P,V).\Pi_{\mathrm{ID}}=(\mathsf{Setup},\mathsf{KeyGen},\mathsf P,\mathsf V).

Algorytm P\mathsf P (prover, dowodzący) działa z kluczem tajnym. Algorytm V\mathsf V (verifier, weryfikator) korzysta z klucza publicznego. Oba utrzymują lokalny stan sesji i wymieniają komunikaty. Zapis

b←⟨P(pp,sk),V(pp,pk)⟩b\leftarrow\langle\mathsf P(pp,sk),\mathsf V(pp,pk)\rangle

oznacza wykonanie rozmowy i odczyt decyzji weryfikatora. Bit b=1b=1 oznacza akceptację. Klamry kątowe nie są iloczynem skalarnym ani pojedynczą funkcją wykonywaną przez jedną stronę. Poprawność wymaga, aby uczciwa rozmowa dla kluczy z KeyGen kończyła się akceptacją. Odporność na podszywanie mówi osobno, że przeciwnik bez wymaganego sekretu nie powinien doprowadzić do takiej akceptacji w dozwolonym modelu.

Własność ZK, zero knowledge, czyli wiedzy zerowej, jest dodatkowym wymaganiem dotyczącym ujawnianej informacji. Nie każdy protokół identyfikacji ją spełnia. Dla trójwiadomościowego Schnorra poniżej najpierw wykażemy dokładnie HVZK, wiedzę zerową wobec uczciwego weryfikatora. Nie będziemy jej utożsamiali z ochroną przed dowolnym zachowaniem rozmówcy.

HVZK
honest-verifier zero knowledge. Zerowa wiedza wobec uczciwego weryfikatora.

Schnorr jako zestaw wywołań

Używamy grupy GG pierwszego rzędu qq, generatora gg i parametrów pp=(G,q,g)pp=(G,q,g). Setup wybiera taki profil. KeyGen losuje a←$Zqa\overset{\$}{\leftarrow}\mathbb Z_q i zwraca (pk,sk)=(A,a)(pk,sk)=(A,a), gdzie A=gaA=g^a. Teraz rozpiszmy lokalne kroki P\mathsf P i V\mathsf V. Ich nazwy są naszym opisem interfejsu, nie dodatkowymi założeniami protokołu.

Identyfikacja Schnorra: algorytmy i przepływ

P i V są algorytmami interaktywnymi. Poniżej wydzielamy ich kroki oraz prywatny stan sesji. Każdy stan odpowiedzi jest jednorazowy. Niepoprawny komunikat kończy sesję odrzuceniem.

Π=(Setup,KeyGen,P,V)\Pi=(\mathsf{Setup},\mathsf{KeyGen},\mathsf{P},\mathsf{V})
Setup(1λ)\mathsf{Setup}(1^\lambda)⟶pp\longrightarrow pp
pp=(G,q,g)pp=(G,q,g)
∣G∣=q,G=⟨g⟩|G|=q,\quad G=\langle g\rangle

Rząd q jest liczbą pierwszą. Ustal kodowania i działania grupy. Dodatkowe funkcje wskazano przy konstrukcji.

KeyGen(pp)\mathsf{KeyGen}(pp)⟶(A,a)\longrightarrow (A,a)
a←$Zq,A=gaa\overset{\$}{\leftarrow}\mathbb Z_q,\quad A=g^a

Profil z całym ciałem, zgodnie z opisem konstrukcji. Sekret a pozostaje u właściciela. Odbiorca uwierzytelnia publiczny A.

Commit(pp)\mathsf{Commit}(pp)⟶(X,stP)\longrightarrow (X,st_P)
u←$Zq,X=guu\overset{\$}{\leftarrow}\mathbb Z_q,\quad X=g^u
stP=(u,X)st_P=(u,X)
Challenge(pp,A,X)\mathsf{Challenge}(pp,A,X)⟶(c,stV)\longrightarrow (c,st_V)
c←$Zq,stV=(A,X,c)c\overset{\$}{\leftarrow}\mathbb Z_q,\quad st_V=(A,X,c)

Po sprawdzeniu typu X.

Respond(pp,a,stP,c)\mathsf{Respond}(pp,a,st_P,c)⟶s\longrightarrow s
s=u+a⋅c(modq)s=u+a\cdot c\pmod q

Sprawdź c i zużyj st_P. Nie odpowiadaj ponownie z tym u.

Check(pp,stV,s)\mathsf{Check}(pp,st_V,s)⟶b∈{0,1}\longrightarrow b\in\{0,1\}
b=[gs=X⋅Ac]b=[g^s=X\cdot A^c]

Najpierw sprawdź kodowania, grupę i zakresy skalarów.

Identyfikacja Schnorra: czynności i komunikatyDowodzącyWeryfikatorCommit
Zachowaj u w stanie sesji.
ZobowiązanieChallenge
Losuj dopiero po otrzymaniu X.
Jawne wyzwanieRespond
Zużyj nonce u.
OdpowiedźCheck
Zwróć 1 albo 0.

Identyfikacja Schnorra

Dowodzący: pp,app,a

Weryfikator: pp,App,A

  1. Dowodzący, Commit: u←$Zqu\overset{\$}{\leftarrow}\mathbb Z_q X=guX=g^u Zachowaj u w stanie sesji.
  2. Dowodzący → Weryfikator: XX Zobowiązanie
  3. Weryfikator, Challenge: c←$Zqc\overset{\$}{\leftarrow}\mathbb Z_q Losuj dopiero po otrzymaniu X.
  4. Weryfikator → Dowodzący: cc Jawne wyzwanie
  5. Dowodzący, Respond: s=u+a⋅c(modq)s=u+a\cdot c\pmod q Zużyj nonce u.
  6. Dowodzący → Weryfikator: ss Odpowiedź
  7. Weryfikator, Check: gs=?X⋅Acg^s\stackrel{?}{=}X\cdot A^c Zwróć 1 albo 0.
Trzy komunikaty. Wyboru u i mnożenia przez a nie przesyłamy. Publiczne wyzwanie pojawia się dopiero po ustaleniu X.

Co pozostaje w urządzeniu, a co trafia do rozmówcy

Strona i wywołanie Co dzieje się wewnątrz Co opuszcza urządzenie
Dowodzący: (X,stP)←Commit(pp)(X,st_P)\leftarrow\mathsf{Commit}(pp) Losuje u←$Zqu\overset{\$}{\leftarrow}\mathbb Z_q, liczy X=guX=g^u i zachowuje jednorazowy stan stP=(u,X)st_P=(u,X). Tylko XX, nie uu.
Weryfikator: (c,stV)←Challenge(pp,A,X)(c,st_V)\leftarrow\mathsf{Challenge}(pp,A,X) Po sprawdzeniu typu A,X∈GA,X\in G losuje c←$Zqc\overset{\$}{\leftarrow}\mathbb Z_q. Zapamiętuje stV=(A,X,c)st_V=(A,X,c). Wyzwanie cc.
Dowodzący: s←Respond(pp,a,stP,c)s\leftarrow\mathsf{Respond}(pp,a,st_P,c) Sprawdza c∈Zqc\in\mathbb Z_q, liczy s=u+a⋅cmodqs=u+a\cdot c\bmod q, zużywa stan stPst_P. Odpowiedź ss, nie klucz aa.
Weryfikator: b←Check(pp,stV,s)b\leftarrow\mathsf{Check}(pp,st_V,s) Sprawdza s∈Zqs\in\mathbb Z_q i gs=X⋅Acg^s=X\cdot A^c. Zwraca 1 przy zgodności, w pozostałych przypadkach 0. Kończy sesję. Decyzja dla aplikacji, nie nowy sekret.

Każdy stan jest przypisany do jednej lokalnej sesji. Nie wolno użyć tego samego stPst_P do odpowiedzi na drugie wyzwanie. Matematyka nie usuwa konieczności pilnowania tej reguły w urządzeniu. Właśnie jej złamanie wykorzystamy później w ataku z resetem. W poprawnym wykonaniu sekret aa służy wyłącznie do lokalnego wywołania Respond.

Mechanizm i poprawność

Chcemy przekonać weryfikatora, że znamy aa dla A=gaA=g^a, bez wysyłania sekretu. Publiczne AA jest stwierdzeniem, a aa świadkiem jego prawdziwości w odpowiedniej relacji. Nie wystarcza samo zapewnienie, że klucz istnieje. Każdy element tej grupy ma logarytm. Istotna jest znajomość odpowiedniej wartości.

Zerowa wiedza dotyczy tego, co rozmowa ujawnia. Dowód znajomości dotyczy możliwości wydobycia świadka z odpowiednio skutecznego dowodzącego w modelu ekstrakcji. To dwa warunki, które należy argumentować oddzielnie.

Dowodzący zna sekret aa. Losuje niezależny, jednorazowy skalar u←$Zqu\overset{\$}{\leftarrow}\mathbb Z_q i oblicza zobowiązanie XX. Weryfikator po otrzymaniu XX losuje wyzwanie cc. Odpowiedź oznaczymy przez ss. Schnorr ma trzy wiadomości:

X=gu,c←$Zq,s=u+a⋅c.X=g^u,\qquad c\overset{\$}{\leftarrow}\mathbb Z_q,\qquad s=u+a\cdot c.

Dowodzący wysyła XX przed otrzymaniem cc. Weryfikator sprawdza gs=X⋅Acg^s=X\cdot A^c. Podstawienie dowodzi kompletności. Nie dowodzi jeszcze wiedzy zerowej ani znajomości sekretu przez oszusta.

Cała kontrola poprawności mieści się w prawach działań na potęgach:

gs=gu+a⋅c=gu⋅(ga)c=X⋅Ac.g^s=g^{u+a\cdot c}=g^u\cdot(g^a)^c=X\cdot A^c.

Weryfikator zna g,A,X,c,sg,A,X,c,s. Do tego obliczenia nie potrzebuje ani aa, ani uu. Przy poprawnych parametrach i wejściach sprawdza zgodność elementów grupy, nie odczytuje ukrytych wykładników.

Przebieg, który można policzyć ręcznie

Dla g=2g=2 modulo 47, rzędu q=23q=23, sekretu a=7a=7 i nonce u=9u=9 mamy A=34A=34 i X=42X=42. Przy wyzwaniu c=3c=3 odpowiedź wynosi s=9+7⋅3=7mod23s=9+7\cdot3=7\bmod23. Weryfikator oblicza 27=34mod472^7=34\bmod47 oraz 42⋅343=34mod4742\cdot34^3=34\bmod47. Wyniki są zgodne.

Widać przy tym, dlaczego kolejność ma znaczenie. Dowodzący ustala zobowiązanie, zanim pozna wyzwanie. Gdyby znał wyzwanie wcześniej, mógłby dobrać XX do dowolnej odpowiedzi. Właśnie ten rachunek wykorzystuje następny podrozdział, ale w innym celu.

Symulator bez sekretu

Losujemy c,sc,s i obliczamy X=gs⋅A−cX=g^s\cdot A^{-c}. Dla ustalonego a,ca,c przesunięcie u↦u+a⋅cu\mapsto u+a\cdot c jest bijekcją ciała. Uczciwe i symulowane transkrypty mają dokładnie ten sam rozkład przy jednostajnej losowości z całego Zq\mathbb Z_q.

Uczciwy przebiegSymulator bez sekretu
u,c←$Zqu,c\overset{\$}{\leftarrow}\mathbb Z_q
c,s←$Zqc,s\overset{\$}{\leftarrow}\mathbb Z_q
Oblicz z użyciem świadkaOblicz z klucza publicznego
X=gu,s=u+a⋅cX=g^u,\quad s=u+a\cdot c
X=gs⋅A−cX=g^s\cdot A^{-c}
Taki sam widok weryfikatora
(X,c,s),gs=X⋅Ac(X,c,s),\quad g^s=X\cdot A^c
Dla ustalonego klucza A=gaA=g^a każdemu akceptującemu transkryptowi odpowiada dokładnie jedna para losowań po każdej stronie. Przy losowaniu z całego ciała jego prawdopodobieństwo wynosi 1/q21/q^2. Równość równań to poprawność. Równość rozkładów jest dodatkowym argumentem HVZK.

Gdy implementacja wyklucza zerowy nonce. Profil notebooka w L3 losuje u≠0u\ne0 i odrzuca X=1GX=1_G, gdzie 1G1_G jest elementem neutralnym. W notacji addytywnej to punkt O\mathcal O. Symulator tego profilu losuje c,sc,s z całego Zq\mathbb Z_q, oblicza X=gs⋅A−cX=g^s\cdot A^{-c} i powtarza losowanie pary, jeśli X=1GX=1_G. Warunkujemy oba rozkłady tym samym zdarzeniem. Dla każdego cc odpada dokładnie jedna wartość s=a⋅cs=a\cdot c, zatem próba jest przyjmowana z prawdopodobieństwem (q−1)/q(q-1)/q. Każdy pozostały transkrypt ma prawdopodobieństwo 1/(q⋅(q−1))1/(q\cdot(q-1)). Symulator nadal nie potrzebuje aa. Nie wolno porównywać tego rozkładu z niezmienionym symulatorem, który dopuszcza neutralne zobowiązanie.

W obu opisach wyzwanie pochodzi z całego Zq\mathbb Z_q. Jeśli pokazujemy atak z ujawnionym nonce i dzieleniem przez cc, demonstrator wybiera c≠0c\ne0, aby wykonać ten konkretny rachunek. To jawne ograniczenie przykładu, a nie zmiana definicji wszystkich protokołów Schnorra.

To HVZK, wiedza zerowa dla uczciwego weryfikatora. Symulator wybiera wyzwanie przed zobowiązaniem. Nie podszywa się więc automatycznie pod dowodzącego w żywej rozmowie. Złośliwy weryfikator może uzależnić wyzwanie od zobowiązania, co wymaga odrębnego argumentu.

Co porównujemy w definicji? Widok weryfikatora obejmuje komunikaty, jego wejście i własną losowość. Symulator ma wytworzyć nierozróżnialny widok bez świadka. Wersja doskonała daje równe rozkłady, statystyczna małą odległość rozkładów, a obliczeniowa nierozróżnialność dla wydajnego testu. W prostym przykładzie Schnorra dla uczciwego weryfikatora otrzymujemy równość rozkładów.

Dwa transkrypty ujawniają świadka

Przy tym samym XX i c≠c′c\ne c':

gs=X⋅Ac,gs′=X⋅Ac′,a=(s−s′)⋅(c−c′)−1(modq).g^s=X\cdot A^c,\qquad g^{s'}=X\cdot A^{c'},\qquad a=(s-s')\cdot(c-c')^{-1}\pmod q.

Dzielimy równania, skracamy XX i korzystamy z pierwszego rzędu grupy. Ekstraktor nie zakłada, że przeciwnik policzył odpowiedź uczciwym algorytmem. Wystarczają dwa zaakceptowane równania.

To szczególna rzetelność protokołu, nazywana special soundness. Jeden transkrypt nie wystarcza: symulator właśnie potrafi go stworzyć bez sekretu. Oszust może przygotować odpowiedź na zgadnięte wyzwanie. Błąd wiedzy dla pełnej przestrzeni wyzwań jest związany z 1/q1/q. Dopiero odpowiedni sukces ponad ten próg i możliwość cofnięcia stanu pozwalają uzasadnić ekstrakcję.

Ten sam Schnorr w implementacji na krzywej

Rola Zapis schematu i animacji Realizacja addytywna w MCL
Klucz publiczny A=gaA=g^a A=a⋅P2A=a\cdot P_2
Zobowiązanie X=guX=g^u X=u⋅P2X=u\cdot P_2
Odpowiedź skalarna s=u+a⋅cs=u+a\cdot c s=u+a⋅cs=u+a\cdot c
Weryfikacja gs=X⋅Acg^s=X\cdot A^c s⋅P2=X+c⋅As\cdot P_2=X+c\cdot A

Punkt P2P_2 pełni tu rolę generatora gg. MCL wykonuje rzeczywiste mnożenia punktów przez skalary na BLS12-381. Zmienia się reprezentacja operacji, nie protokół. Klucze są demonstracyjne.

Schnorr · transkrypt, weryfikacja i ekstrakcja

MCL WebAssembly, BLS12-381. Punkty w G2G_2, skalary w Zq\mathbb Z_q. Klucze wyłącznie testowe.

Przypadek
Wspólny klucz publiczny A=gaA=g^a oczekuje

1. Pierwszy przebieg

Nowy nonce i odpowiedź na wyzwanie.

DowodzącyWeryfikator
XX
oczekuje
cc
oczekuje
ss
oczekuje
s=u+a⋅cs=u+a\cdot c
s=u+a⋅c+1s=u+a\cdot c+1

Weryfikacja oczekuje.

2. Drugi przebieg

DowodzącyWeryfikator
X′X'
oczekuje
c′c'
oczekuje
s′s'
oczekuje
uu
oczekuje

Ujawniony nonce z pierwszej rozmowy. Sekret aa nadal nie został odczytany z urządzenia.

X′=X,u′=uX'=X,\quad u'=u

Weryfikacja oczekuje.

Sprawdzenie

Rachunek na otrzymanych danych.

gs=X⋅Acg^s=X\cdot A^c
gs≠X⋅Acg^s\ne X\cdot A^c
s−s′=a⋅(c−c′)s-s'=a\cdot(c-c')
a=(s−s′)⋅(c−c′)−1a=(s-s')\cdot(c-c')^{-1}
a=(s−u)⋅c−1a=(s-u)\cdot c^{-1}
ga=Ag^a=A

Odzyskany skalar

oczekuje

Potrzebne są dwa zaakceptowane transkrypty i c≠c′c\ne c'. Nie trzeba znać nonce.

Wystarcza jeden transkrypt, ujawniony nonce i c≠0c\ne0.

Do wysyłanej odpowiedzi dodano 11.

Wynik oczekuje.

Zapis i obliczenia. Wzory schematu są multiplikatywne. MCL realizuje je na krzywej. Generator gg odpowiada punktowi P2P_2. W grupach punktów iloczyn oznacza dodawanie, potęga oznacza mnożenie punktu przez skalar, a odwrotność oznacza punkt przeciwny. Nie potęgujemy współrzędnych. Ten rachunek nie używa pairingu.

Gotowe do rozpoczęcia.

Pełne wartości transkryptów

Serializacja MCL w zapisie szesnastkowym. Skróty na schemacie wskazują te same wartości.

WartośćSerializacja

Co pozostaje po pierwszym przebiegu? Przeciwnik zna publiczny klucz AA i trzy komunikaty (X,c,s)(X,c,s). Nie zna aa ani uu. Reset w drugim przebiegu przywraca ten sam nonce, więc ponownie pojawia się to samo XX. Weryfikator przesyła inne wyzwanie c′c', dopiero potem otrzymuje odpowiedź s′s'. Oba transkrypty dotyczą jednego klucza publicznego. Odjęcie odpowiedzi usuwa nieznany nonce. Ekstrakcja wykorzystuje wyłącznie zapisane komunikaty, a poprawność wyniku można sprawdzić publicznie przez ga=Ag^a=A.

Reset rzeczywistego urządzenia jest tu uprawnieniem atakującego. Przewijanie przeciwnika w dowodzie jest natomiast narzędziem ekstraktora. W obu sytuacjach przydatny jest ten sam rachunek dwóch transkryptów, lecz nie są to te same możliwości w rzeczywistym protokole. Ujawnienie nonce to jeszcze inny przypadek: wystarcza jedna rozmowa i poznane uu, o ile c≠0c\ne0.

Powiązania: C5, L3, pełny dowód identyfikacji i rachunek rewindingu.