Podstawa wykładowa: Część 4 - slajdy 24, 25, 27: algorytmy DSA i ECDSA, parametry rzędu q/n, losowa wartość jednorazowa k, wyliczanie r = (k*G)_x mod n oraz s
= k^(-1)*(H(m) + d*r) mod n, procedura weryfikacji.
Cel
Celem zadania jest programistyczna rekonstrukcja algorytmu podpisu cyfrowego ECDSA w języku Python. Student implementuje procedurę generowania podpisu (para r i s) dla zadanego
skrótu wiadomości oraz procedurę weryfikacji sygnatury w oparciu o arytmetykę krzywych eliptycznych, badając matematyczne powiązanie składowych podpisu z kluczem publicznym.
Scenariusz – opis
Algorytm ECDSA (Elliptic Curve Digital Signature Algorithm) stanowi standard FIPS 186 definiujący podpis cyfrowy na krzywych eliptycznych. Procedura opiera się na wykorzystaniu
efemerycznej, tajnej liczby losowej k wybieranej niezależnie dla każdego podpisywanego dokumentu. Nadawca oblicza punkt krzywej R = k * G i przyjmuje jego współrzędną r = R.x mod n jako
pierwszą składową podpisu. Druga składowa podpisu s jest obliczana ze wzoru s = k^(-1) * (e + d * r) mod n, gdzie e jest numeryczną wartością skrótu dokumentu, a d kluczem prywatnym.
Weryfikator nie zna wartości k ani d, ale zna klucz publiczny Q = d * G oraz składowe sygnatury (r, s). Oblicza on wagi w = s^(-1) mod n, u1 = e * w mod n, u2 = r * w mod n, a następnie
punkt weryfikujący V = u1 * G + u2 * Q.
Co ma wykonać student / grupa
W pliku ecdsa_implementation.py importujesz zaimplementowaną w poprzednim zadaniu arytmetykę krzywej Weierstrassa (lub definiujesz ją
lokalnie). Konfigurujesz parametry krzywej eliptycznej (p, a, b, punkt bazowy G oraz jego rząd n). Generujesz klucz prywatny nadawcy d jako losową liczbę 1 <= d < n oraz
obliczasz klucz publiczny Q = d * G. Definiujesz wiadomość tekstową i obliczasz jej 256-bitowy skrót SHA-256 za pomocą wbudowanego modułu hashlib.
Konwertujesz bajty skrótu na liczbę całkowitą e = int.from_bytes(hash_bytes, 'big') mod n. Implementujesz funkcję ecdsa_sign(msg_hash,
priv_key, k): losujesz liczbę k względnie pierwszą z n (ścisła dydaktyka - produkcyjnie k musi pochodzić z RFC 6979 / HMAC-DRBG, por. 4.0/zad. 7 i 5.0/zad.
5). Obliczasz punkt R = k * G i wyznaczasz r = R.x % n (upewniając się, że r != 0). Obliczasz k_inv = pow(k, -1, n) oraz składową s = (k_inv * (e +
priv_key * r)) % n (upewniając się, że s != 0). Zwracasz sygnaturę jako parę liczb całkowitych (r, s).
Implementujesz funkcję ecdsa_verify(msg_hash, signature, pub_key): pobierasz r, s i sprawdzasz warunki 1 <= r, s < n. Obliczasz w = pow(s, -1, n), u1 = (e *
w) % n oraz u2 = (r * w) % n. Wyznaczasz punkt weryfikujący V = point_add(scalar_mult(u1, G), scalar_mult(u2, pub_key)). Weryfikujesz warunek poprawności
podpisu: V nie może być punktem O oraz V.x % n musi być równe r.
Testujesz algorytm: potwierdzasz poprawność weryfikacji dla oryginalnej wiadomości. Modyfikujesz treść wiadomości (inny skrót e') lub składową
podpisu r' i sprawdzasz, że funkcja weryfikująca poprawnie odrzuca sfałszowany podpis. Zapisujesz dowód matematyczny równości V.x == r i kompletujesz sprawozdanie.
Przykładowe kroki do wykonania jako sugestia
- Utwórz plik
ecdsa_implementation.py.
-
Skonfiguruj krzywą secp256k1 lub
NIST P-256
z punktem bazowym G i rzędem n.
-
Wygeneruj parę kluczy: priv_d oraz
pub_Q = priv_d * G.
-
Napisz funkcję przygotowującą skrót
e =
hash_message(msg).
- Zaimplementuj generator efemerycznego nonce k.
-
Zaimplementuj obliczanie punktu
R = k * G i składowej
r = R.x % n.
-
Zaimplementuj obliczanie składowej
s =
pow(k, -1, n) *
(e + priv_d * r) % n.
- Podpisz przykładowy dokument
'Zatwierdzam transakcje numer 4891'.
- Zanotuj wygenerowane wartości r i s w postaci szesnastkowej.
-
Zaimplementuj funkcję weryfikacji
ecdsa_verify(e, r,
s, pub_Q).
-
Oblicz współczynniki
w = pow(s,
-1, n), u1 =
(e * w) % n, u2 =
(r * w) % n.
-
Oblicz punkt sprawdzający
V = u1*G + u2*pub_Q.
-
Zweryfikuj tożsamość
V.x % n == r i wyświetl wynik testu
(Sukces weryfikacji).
- Wykonaj test fałszerstwa: zmień w wiadomości jedno słowo i zweryfikuj ponownie (
Odrzucenie podpisu).
- Wykonaj test uszkodzenia sygnatury: zmień wartość s o 1 i sprawdź wynik.
- Wykonaj zrzuty ekranu konsoli i przygotuj sprawozdanie.
Kontrola zaliczenia (checklist):
- Uruchomiono ECDSA i zachowano log: generowanie (r,s) dla hasha, weryfikacja OK oraz odrzucenie po zmianie 1 bitu msg/podpisu.
- Dołączono kod (własne min. 30 linii): R=k·G, r,s, odwrotność k, weryfikacja u1,u2 bez ujawniania k,d.
- Przeprowadzono test pozytywny (poprawny podpis przechodzi) i negatywny (zły hash / s=0 — odrzut z komunikatem).
- Opisano w 3–5 zdaniach: rola R, elegancja weryfikacji, integralność hasha i (r,s); ostrzeżenie: random-k tylko dydaktycznie, produkcyjnie RFC 6979 (por. z.7, 5.0/z.5).
Wariant offline (fallback): Praca w pełni offline na wektorach ze startera w lokalnym Pythonie 3 (bez cryptography — czysta arytmetyka modułowa); OpenSSL tylko do kontroli; dołącz kod i log z konsoli.
Sugerowane wnioski i podsumowanie - co student ma osiągnąć
Sprawozdanie z realizacji zadania musi zawierać następujące kluczowe wnioski i osiągnięcia:
- Zrozumienie matematycznej konstrukcji podpisu ECDSA i roli punktu efemerycznego R = k*G.
- Zrozumienie elegancji procedury weryfikacji eliminującej potrzebę ujawniania tajnych wartości k i d.
- Umiejętność samodzielnej implementacji algorytmu generowania i weryfikacji podpisów na krzywych eliptycznych.
- Świadomość krytycznego znaczenia integralności skrótu wiadomości oraz parametrów r i s dla ważności podpisu.
- Ostrzeżenie: losowanie k zwykłym random to tylko dydaktyka - produkcyjnie obowiązuje RFC 6979 / HMAC-DRBG (por. 4.0/zad. 7, 5.0/zad. 5).