Asynchroniczne Bizantyjskie Porozumienie z Optymalną Odpornością i Liniową Złożonością

Implementacja protokołu opartego na pracy Cheng Wang (EPFL)

1. Opis Problemu

1.1. Problem Bizantyjskiego Porozumienia

Problem Bizantyjskiego Porozumienia (Byzantine Agreement) jest fundamentalnym problemem w informatyce rozproszonej, wprowadzonym przez Pease, Shostak i Lamport w latach 80. Problem można sformułować następująco:

Definicja: Asynchroniczne Bizantyjskie Porozumienie (ABA)

Danych jest \(n\) procesów, z których \(t\) może być bizantyjskich (złośliwych). Każdy poprawny proces ma wartość wejściową (bit: 0 lub 1). Protokół ABA musi spełniać:

Model Asynchroniczny

W modelu asynchronicznym komunikacja między procesami może trwać dowolnie długo (ale skończenie). Nie ma globalnego zegara ani synchronizacji. Cechy modelu:

Wyniki Niemożliwości

Klasyczne wyniki teoretyczne:

Te wyniki prowadzą do dwóch kierunków badań: protokoły randomizowane oraz protokoły z optymalną odpornością (\(n > 3t\)).

1.2. Przykład Zastosowania

Scenariusz: Rozproszony System Blockchain

Wyobraźmy sobie sieć blockchain z 10 węzłami walidującymi (\(n = 10\)), z których maksymalnie 3 mogą być kontrolowane przez przeciwnika (\(t = 3\)). Ponieważ \(n = 10 > 3t = 9\), spełniona jest optymalna odporność.

Przypadek użycia: Walidacja bloku transakcji

Sytuacja początkowa:

Działanie protokołu:

  1. Runda 1: Węzły wymieniają swoje głosy przez A-Cast (reliable broadcast)
    • Poprawne węzły widzą większość dla wartości 1
    • Bizantyjskie węzły próbują wprowadzić chaos, ale A-Cast gwarantuje spójność
  2. Runda 2: Protokół Vote wykrywa silną większość (strength = 2) dla wartości 1
    • Wszystkie poprawne węzły zgadzają się na blok A
    • Węzły wysyłają COMPLETE i kończą protokół

Wynik: Wszystkie 7 poprawnych węzłów akceptuje blok A, mimo że 3 węzły były bizantyjskie.

Inne zastosowania:

2. Porównanie Istniejących Rozwiązań

Historia protokołów bizantyjskiego porozumienia pokazuje ewolucję od rozwiązań wykładniczych do coraz bardziej efektywnych algorytmów. Kluczowe pytania to:

Tabela porównawcza protokołów ABA

Protokół Rok Odporność Oczekiwany czas Uwagi
Ben-Or 1983 \(n > 5t\) \(O(2^n)\) Pierwszy randomizowany protokół, słaba odporność
Bracha 1984 \(n > 3t\) \(O(2^n)\) Optymalna odporność, ale wykładnicza złożoność
Feldman-Micali 1988 \(n > 4t\) \(O(1)\) Stały czas! Ale wymaga \(n > 4t\)
Canetti-Rabin 1993 \(n > 3t\) \(O(1)\) Stały czas, ale tylko z przytłaczającym prawdopodobieństwem (nie prawie na pewno)
Abraham-Dolev-Halpern 2008 \(n > 3t\) \(O(n^2)\) Optymalna odporność + wielomianowy czas + prawie pewna terminacja
Wang (ten protokół) 2013 \(n > 3t\) \(O(t)\) Najlepszy wynik: optymalna odporność + liniowy czas!
Wang (ten protokół) 2013 \(n > (3+\varepsilon)t\) \(O(1/\varepsilon)\) Prawie stały czas dla \(n\) niewiele większego niż \(3t\)

Przełomowe znaczenie tego rozwiązania

Dlaczego ten protokół jest ważny?

  1. Przełamanie bariery \(O(n^2)\): Pierwszy protokół z optymalną odpornością osiągający złożoność \(O(t)\), co przy \(t = \Theta(n)\) daje \(O(n)\) zamiast \(O(n^2)\).
  2. Praktyczna skalowalność: Dla dużych sieci (np. 100 węzłów, 33 bizantyjskie), różnica między 33 rundami a 10,000 rundami jest ogromna.
  3. Kompromis odporność-wydajność: Jeśli możemy założyć \(n = 4t\) (zamiast \(n = 3t + 1\)), otrzymujemy \(O(1/\varepsilon) = O(1)\) – stały czas jak Feldman-Micali, ale z lepszą odpornością!
  4. Nowa technika: IVSS: Wprowadza Inferable Verifiable Secret Sharing z detekcją błędów opartą na symetrycznych wielomianach dwuwymiarowych.

Matematyczne uzasadnienie złożoności

Porównajmy protokoły dla konkretnego przykładu: \(n = 100\), \(t = 33\) (maksymalna odporność).

Protokół Oczekiwana liczba rund Przybliżona wartość
Bracha (1984) \(O(2^{100})\) \(\approx 10^{30}\) rund – niemożliwe!
Abraham et al. (2008) \(O(100^2)\) \(10,000\) rund
Ten protokół \(O(33)\) ~33 rundy

Dla \(n = 100\), \(t = 24\) (mamy \(n = (3 + \varepsilon)t\) gdzie \(\varepsilon = 1/12 \approx 0.083\)):

Protokół Oczekiwana liczba rund
Abraham et al. (2008) \(O(10,000)\)
Ten protokół \(O(1/0.083) \approx 12\) rund

3. Założenia Protokołu i Analiza Złożoności

3.1. Założenia Modelu

Założenia systemu

3.2. Czym jest złożoność \(O(t)\)?

Złożoność czasowa protokołu mierzy oczekiwaną liczbę rund komunikacji. Jedna runda to czas potrzebny, aby wiadomość przeszła od nadawcy do odbiorcy.

Definicja rundów (formalna):

Rozważmy wirtualny "zegar globalny" mierzący czas w sieci. Niech opóźnienie wiadomości oznacza czas od jej wysłania do odebrania. Okres wykonania protokołu to najdłuższe opóźnienie wiadomości w tym wykonaniu. Czas trwania wykonania to całkowity czas zmierzony przez zegar globalny podzielony przez okres.

Oczekiwany czas działania protokołu to maksimum (po wszystkich wejściach i adversariach) średniej czasu trwania wykonań protokołu.

Co oznacza \(O(t)\) w praktyce?

Parametr Wartość Oczekiwane rundy Czas przy 100ms RTT
\(n=10, t=3\) Mała sieć \(\approx 3\) 0.3 sekundy
\(n=100, t=33\) Średnia sieć (opt. odporność) \(\approx 33\) 3.3 sekundy
\(n=100, t=24\) Średnia sieć (\(n=4t\)) \(\approx 12\) 1.2 sekundy
\(n=1000, t=333\) Duża sieć (opt. odporność) \(\approx 333\) 33 sekundy

Porównanie z poprzednim best-case \(O(n^2)\): Dla \(n=100\), mielibyśmy 10,000 rund = 1000 sekund = 16.7 minuty!

3.3. Kluczowe Innowacje Techniczne

Innowacja 1: Inferable VSS (IVSS)

Tradycyjne Verifiable Secret Sharing (VSS) gwarantuje, że wszyscy poprawni procesy odtworzą ten sam sekret. IVSS osłabia to wymaganie, ale dodaje potężną właściwość:

Właściwość IVSS: Wykrywanie błędów

Jeśli poprawne procesy nie odtworzą tego samego sekretu, to protokół wykryje co najmniej \(t(n - 3t)\) błędnych par procesów.

Błędna para \(\{i, j\}\) oznacza, że co najmniej jeden z procesów \(i\) lub \(j\) jest bizantyjski.

Dlaczego to jest potężne?

Innowacja 2: Symetryczne wielomiany dwuwymiarowe

Dealer dzieli sekret \(s\) wybierając losowy symetryczny dwuwymiarowy wielomian \(F(x, y)\) stopnia \(t\), gdzie:

\[F(x, y) = F(y, x) \quad \text{i} \quad F(0, 0) = s\]

Każdy proces \(i\) otrzymuje przekrój wielomianu: \(f_i(y) = F(i, y)\).

Kluczowa właściwość symetrii:

Dla poprawnego dealera: \(f_i(j) = F(i, j) = F(j, i) = f_j(i)\)

Jeśli proces \(i\) twierdzi, że \(f_i(j) = v_1\) a proces \(j\) twierdzi, że \(f_j(i) = v_2\) gdzie \(v_1 \neq v_2\), to co najmniej jeden z nich jest bizantyjski!

Każdy proces wysyła swój punkt do innych, więc możemy wykryć \(O(n^2)\) potencjalnych konfliktów. Ale bizantyjskich jest tylko \(t\), więc wykrywamy \(\Omega(t \cdot n)\) błędnych par.

Innowacja 3: Historia invocations (Certification Protocol)

Nowy pomysł: pamiętaj historię wszystkich instancji IVSS z przeszłych rund!

Efekt: Bizantyjskie procesy nie mogą "uciec" od wykrycia. Historia ich złego zachowania jest zapamiętywana i sprawdzana w przyszłych rundach.

3.4. Analiza złożoności: skąd \(O(t)\)?

Szkic dowodu złożoności

Kluczowa obserwacja: Protokół kończy się, gdy wystarczająco wiele błędnych par zostanie wykrytych.

Krok 1: Ile jest błędnych par?

Jest \(t\) procesów bizantyjskich i \(n-t\) poprawnych. Maksymalna liczba błędnych par:

\[\text{Faulty pairs} \leq t \cdot (n - t) + \binom{t}{2} \leq t \cdot n\]

Krok 2: Ile par wykrywamy na rundę?

Jeśli IVSS nie powiedzie się (procesy odtworzą różne sekrety), wykrywamy co najmniej \(t(n - 3t)\) błędnych par (z własności IVSS).

Krok 3: Ile rund potrzeba?

W każdej rundzie uruchamiamy \(n\) instancji IVSS (jedna na proces jako dealer). W pesymistycznym przypadku, co rundę wykrywamy:

\[\text{Detected per round} \geq t(n - 3t)\]

Liczba rund potrzebnych do wykrycia wszystkich błędnych par:

\[\text{Rounds} \leq \frac{t \cdot n}{t(n - 3t)} = \frac{n}{n - 3t}\]

Dla \(n > 3t\), mamy \(n - 3t > 0\). W szczególności:

Wniosek: Protokół kończy się w \(O(t)\) oczekiwanych rundach dla \(n > 3t\).

4. Pseudokod Protokołu

Protokół składa się z kilku warstw, z IVSS (Inferable Verifiable Secret Sharing) jako kluczowym komponentem. IVSS dzieli się na fazę dzielenia (Sharing) i fazę rekonstrukcji (Reconstruction).

4.1. Struktury Danych: Wielomiany

Pole skończone i wielomiany

Pole skończone: Wszystkie operacje wykonywane są w \(\mathbb{Z}_p\) dla dużej liczby pierwszej \(p\).

TYPE FieldElement
    // Elementy w Z_p dla dużej liczby pierwszej p
    // Wszystkie operacje arytmetyczne są mod p
    p : Prime  // np. 2^256 - 189

Symetryczny dwuwymiarowy wielomian stopnia \(t\):

CLASS SymmetricBivariatePolynomial
    degree : Integer = t
    
    coefficients : Matrix[t+1][t+1]
        // a_{ij} gdzie i+j ≤ t
        // WARUNEK: a_{ij} = a_{ji} (symetria)
    
    FUNCTION Evaluate(x, y) → FieldElement
        RETURN Σ_{i,j: i+j≤t} a_{ij} · x^i · y^j
    
    FUNCTION GetUnivariate(x_fixed) → UnivariatePolynomial
        // Zwraca f(y) = F(x_fixed, y)
        RETURN wielomian w y stopnia t

Jednowymiarowy wielomian (przekrój):

CLASS UnivariatePolynomial
    degree : Integer = t
    coefficients : Array[t+1]  // [c_0, c_1, ..., c_t]
    
    FUNCTION Evaluate(y) → FieldElement
        RETURN Σ_{i=0}^{t} c_i · y^i
    
    FUNCTION InterpolateFrom(points) → UnivariatePolynomial
        // Interpolacja Lagrange'a z t+1 punktów
        // Danych: {(x_1, y_1), ..., (x_{t+1}, y_{t+1})}
        RETURN unikalny wielomian stopnia ≤ t

4.2. IVSS-S: Faza Dzielenia Sekretu

Cel: Dealer \(d\) dzieli sekret \(s\) między \(n\) procesów w taki sposób, że może być bezpiecznie zrekonstruowany lub błędy zostaną wykryte.

Protokół IVSS[r]-S: Dealer
FUNCTION IVSS_Share(secret s, round r)
│
├─ // Krok 1: Wybierz symetryczny wielomian dwuwymiarowySELECT random symmetric bivariate polynomial F(x, y)
│      WHERE degree(F) = t AND F(0, 0) = s
│
├─ // Krok 2: Wyślij przekroje do procesówFOR k = 1 TO n DO
│      f_k(y) ← F(k, y)              // Jednowymiarowy wielomianA-Cast f_k to process k    // Niezawodny broadcast
│
├─ // Krok 3: Czekaj na potwierdzenia równościWAIT FOR candidate set M WHERE:
│      1. |M| ≥ n - t
│      2. ∀i,j ∈ M: received A-Cast "EQUAL:(i,j)"
│      3. ∀i,j,p,q ∈ M: received A-Cast "CHECKED_r: p, q, {i,j}" from p
│         // To sprawdza, że {i,j} nie jest błędną parą w historii
│
├─ // Krok 4: Ogłoś zbiór kandydatówA-Cast "CANDIDATE_SET: M"
│
└─ COMPLETE sharing phase
Protokół IVSS[r]-S: Proces odbierający (Proces k)
// Stan lokalny
LOCAL STATE:
    received_poly : Polynomial ← null
    consistent_peers : Set[ProcessID] ← ∅

─────────────────────────────────────────────────────

UPON RECEIVE polynomial f_k FROM dealer
│
├─ received_poly ← f_k
│
└─ FOR j = 1 TO n DO
       point ← f_k(j)                // Ewaluuj wielomian w j
       SEND point to process j       // Bezpośrednia wiadomość

─────────────────────────────────────────────────────

UPON RECEIVE point p_j FROM process j
│
├─ IF received_poly(j) = p_j THEN     // Test spójności// f_k(j) powinno równać się f_j(k) (symetria!)A-Cast "EQUAL:(k, j)"
│
└─ ELSE
       // Niezgodność! Co najmniej jeden z {k, j} jest bizantyjski
       // Nie wysyłamy EQUAL

─────────────────────────────────────────────────────

UPON RECEIVE "CANDIDATE_SET: M" FROM dealer
│
├─ // Weryfikacja zbioru kandydatówVERIFY:
│      1. |M| ≥ n - t
│      2. ∀i,j ∈ M: received "EQUAL:(i,j)" via A-Cast
│      3. ∀i,j,p,q ∈ M: received "CHECKED_r: p, q, {i,j}" from p
│      4. ∀i,j ∈ M: {i,j} ∉ FP_k
│         // Sprawdź lokalną listę błędnych par
│
└─ IF verification passes THEN
       OUTPUT "Sharing Complete"
       STORE (M, received_poly)  // Do użycia w rekonstrukcji

Kluczowe punkty IVSS-S:

4.3. IVSS-R: Faza Rekonstrukcji Sekretu

Warunek wstępny: Faza dzielenia zakończona pomyślnie (mamy zapisane \(M\) i received_poly).

Cel: Odtworzyć sekret \(s = F(0,0)\) z wielomianu \(F(x,y)\) używając przekrojów od procesów w \(M\), lub wykryć błędne pary jeśli rekonstrukcja się nie powiedzie.

Protokół IVSS[r]-R: Rekonstrukcja (Proces k)
FUNCTION IVSS_Reconstruct(instance_id) → secret
│
├─ // FAZA 1: Broadcast wielomianówIF I am in set M THENA-Cast my_polynomial f_k
│      // Wysyłam wielomian, który otrzymałem od dealera
│
├─ // FAZA 2: Zbierz i interpolujWAIT FOR polynomials from set IS WHERE:
│      • |IS| ≥ n - 2t
│      • IS ⊆ M
│      • All polynomials in IS are consistent:
│        ∀i,j ∈ IS: f_i(j) = f_j(i)  // Test symetrii!
│
├─ // Jeśli test symetrii zawiedzie dla pary {i,j}:IF ∃ i,j ∈ candidates : f_i(j) ≠ f_j(i) THENADD {i, j} to FP_k  // Wykryto błędną parę!// Kontynuuj szukanie większego spójnego zbioru IS
│
├─ // Interpolacja dwuwymiarowego wielomianuINTERPOLATE symmetric bivariate polynomial F
│      from {f_i | i ∈ IS}
│      // Używamy własności: F(i,y) = f_i(y) dla każdego i ∈ IS// Ponieważ |IS| ≥ n-2t > t, możemy zrekonstruować F stopnia t
│
├─ reconstructed_secret ← F(0, 0)
│
├─ // FAZA 3: Zatwierdzenie w historiiA-Cast "READY_TO_COMPLETE"ADD instance_id to CoreInvocations_k^r
│      // Ta instancja staje się częścią historii
│
└─ // FAZA 4: Finalizacja
   WAIT FOR (n - t) "READY_TO_COMPLETE" messages
   RETURN reconstructed_secret
Interpolacja dwuwymiarowego wielomianu z jednowymiarowych przekrojów
FUNCTION ReconstructBivariate(slices : {f_1, f_2, ..., f_k}) → F(x,y)
│   // slices: zbiór k ≥ t+1 wielomianów, gdzie f_i(y) = F(i, y)
│
├─ // Krok 1: Weryfikacja spójności (test symetrii)FOR EACH pair (i, j) in slices DOASSERT f_i(j) = f_j(i)          // Warunek symetriiIF NOT satisfied THENDETECT_FAULTY_PAIR({i, j})
│          RETURN ERROR
│
├─ // Krok 2: Interpolacja Lagrange'a// Dla każdej pary (i,j), znamy wartość F(i,j) = f_i(j)
│  points ← {(i, j, f_i(j)) | i,j ∈ indices of slices}
│
├─ // Krok 3: Zbuduj F(x,y) stopnia t
│  F(x, y) ← BivariateLagrangeInterpolation(points, degree=t)
│      // Interpolujemy z więcej niż (t+1)² punktów// Symetria gwarantuje unikalność
│
└─ RETURN F

Kluczowe punkty IVSS-R:

4.4. Protokół Certyfikacji

Protokół certyfikacji działa w tle przez cały czas działania ABA, śledząc historię invocations i wykrywając błędne pary.

Certification Protocol (Proces k)
// Stan globalny
GLOBAL STATE:
    FP_k : Set[{ProcessID, ProcessID}] ← ∅
        // Błędne pary: nieuporządkowane pary {i,j} gdzie ≥1 jest bizantyjski
    
    CoreInvocations_k^r : List[InstanceID] ← []
        // Historia pomyślnie zakończonych instancji IVSS w rundzie r

─────────────────────────────────────────────────────

FUNCTION InitCertification()
    FP_k ← ∅
    CoreInvocations_k^0 ← []
    START background monitoring

─────────────────────────────────────────────────────

AT START OF ROUND r (r > 1)
│
└─ A-Cast CoreInvocations_k^{r-1}
       // Informuj wszystkich o swoich akcjach z poprzedniej rundy

─────────────────────────────────────────────────────

UPON RECEIVE CoreInvocations_l^r FROM process l
│
├─ // Sprawdź wszystkie instancje z historii procesu lFOR EACH instance I in CoreInvocations_l^r DO
│      │
│      ├─ // Pobierz zbiór M z instancji I
│      │  LET M = candidate_set(I)
│      │
│      └─ // Sprawdź spójność wielomianów dla wszystkich par w MFOR EACH i, j ∈ M DOIF received f_i and f_j in IVSS-R of I THENIF f_i(j) ≠ f_j(i) THEN// WYKRYTO NIEZGODNOŚĆ!ADD {i, j} to FP_k
│                     LOG "Faulty pair detected: {i, j} in instance " + I
│
└─ // Zapewnij wykonanie kroków protokołu dla historii l
   FOR EACH invocation I in CoreInvocations_l^r DO
       COMPLETE sharing protocol of I
       COMPLETE Step 1 of IVSS[r]-R of I
       // Różne procesy mogą zakończyć różne instancje

─────────────────────────────────────────────────────

FUNCTION VerifySet(M : Set[ProcessID], round r) → Boolean
│   // Sprawdź, czy zbiór M może być zaakceptowany w rundzie r
│
├─ // Warunek a: Otrzymano historię od wszystkich w MFOR EACH l ∈ M DOIF NOT received CoreInvocations_l^{r'} for all r' < r THENRETURN false
│
├─ // Warunek b: Otrzymano wielomiany od wszystkich w historiiFOR EACH l ∈ M DOFOR EACH instance I in ⋃_{r'DO
│          LET M_I = candidate_set(I)
│          FOR EACH i ∈ M_I DOIF NOT received f_i in IVSS-R of I THENRETURN false
│
├─ // Warunek c: Żadna para w M nie jest w FP_kFOR EACH i, j ∈ M WHERE i ≠ j DOIF {i, j} ∈ FP_k THENRETURN false  // Odrzuć: zawiera błędną parę
│
└─ RETURN true  // Wszystkie pary zweryfikowane

─────────────────────────────────────────────────────

WHEN VerifySet(M, r) returns true FOR processes k, l and pair {i,j}
│
└─ A-Cast "CHECKED_r: k, l, {i, j}"
       // Potwierdzam, że {i,j} nie jest błędną parą według historii l przed r

Kluczowe punkty Certyfikacji:

4.5. Protokół Głosowania (Vote)

Protokół Vote określa, czy istnieje większość procesów głosujących na konkretną wartość. Zwraca wartość oraz siłę większości.

Vote Protocol (Proces k, runda r)
FUNCTION Vote(round r, input_bit x_k) → (value, confidence)
│
├─ // FAZA 1: Wymiana wartości wejściowychA-Cast "INPUT: (k, x_k)"
│
│  WAIT FOR (n - t) INPUT messages
│      LET A_k = {senders of received INPUT messages}
│
│  my_vote_1 ← MAJORITY_BIT(A_k)      // 0 jeśli remis
│
│  A-Cast "VOTE1: (k, A_k, my_vote_1)"
│
├─ // FAZA 2: Pierwsze głosowanieWAIT FOR (n - t) VOTE1 messages
│      LET B_k = {j | received VOTE1 from j AND A_j ⊆ A_k}
│
│  my_vote_2 ← MAJORITY_BIT(votes in B_k)
│
│  A-Cast "REVOTE: (k, B_k, my_vote_2)"
│
├─ // FAZA 3: Zbieranie ponownych głosówWAIT FOR (n - t) REVOTE messages
│      LET C_k = {j | received REVOTE from j AND B_j ⊆ B_k}
│
└─ // LOGIKA DECYZYJNA
   IF all votes in B_k equal σ THEN
       RETURN (σ, 2)                  // Silna większość
   
   ELSE IF all revotes in C_k equal σ THEN
       RETURN (σ, 1)                  // Słaba większość
   
   ELSE
       RETURN (⊥, 0)                  // Brak większości

─────────────────────────────────────────────────────

FUNCTION MAJORITY_BIT(set S) → {0, 1}
│
├─ count_0 ← |{j ∈ S | bit[j] = 0}|
├─ count_1 ← |{j ∈ S | bit[j] = 1}|
│
└─ RETURN (count_1 > count_0) ? 1 : 0     // Domyślnie 0 przy remisie

Poziomy pewności (confidence):

4.6. Inferable Common Coin (ICC)

Generuje wspólny losowy bit dla wszystkich procesów, gdy nie osiągnięto większości w głosowaniu.

ICC Protocol (Proces k, runda r)
FUNCTION GetCommonCoin(round r) → {0, 1}
│
├─ // FAZA 1: Dzielenie sekretów// Każdy proces jest dealerem dla n instancji IVSSFOR j = 1 TO n DO
│      IVSS[r, j]-S.Start(RANDOM_VALUE())
│      // Proces j dzieli losową wartość
│
├─ // FAZA 2: Zbierz zestawy załącznikówWAIT UNTIL (t + 1) IVSS-S instances complete for me
│      LET T_k = {dealers of completed secrets}
│
│  A-Cast "ATTACH: T_k"
│
├─ // FAZA 3: Akceptacja
│  A_k ← ∅
│
│  FOR EACH "ATTACH: T_j" received FROM j DOIF T_j ⊆ T_k THENADD j to A_k
│
│  WAIT UNTIL |A_k| ≥ n - t
│
│  A-Cast "ACCEPT: A_k"
│
├─ // FAZA 4: Włącz rekonstrukcjęWAIT FOR (n - t) "ACCEPT: A_j" messages
│      LET S_k = {senders}
│
│  A-Cast "RECONSTRUCT_ENABLED: (H_k = A_k, S_k)"
│
├─ // FAZA 5: Rekonstruuj sekretyFOR EACH j ∈ A_k DOFOR EACH k ∈ T_j DORUN IVSS[r, k]-R
│
└─ // FAZA 6: Oblicz monetę
   WAIT UNTIL all reconstructions complete
   
   u ← ⌈0.87 × n⌉                    // Próg probabilistyczny
   
   FOR EACH k ∈ H_k DO
       value_k ← reconstructed_secret[k] mod u
   
   IF EXISTS k ∈ H_k : value_k = 0 THEN
       RETURN 0
   ELSE
       RETURN 1

Właściwości ICC:

4.7. ABA: Główna Pętla Protokołu

To punkt wejścia protokołu, wywoływany przez aplikację. Łączy wszystkie komponenty w jeden spójny algorytm.

Asynchronous Byzantine Agreement (Proces k)
FUNCTION ABA(input_bit x_k) → {0, 1}
│
├─ // INICJALIZACJA
│  round ← 0
│  estimate ← x_k
│  START CertificationProtocol() in background
│      // Protokół certyfikacji działa równolegle przez cały czas
│
└─ // GŁÓWNA PĘTLA
   LOOP forever
   │
   ├─ round ← round + 1
   │
   ├─ // FAZA 1: Głosowanie
   │  (vote_val, vote_strength) ← Vote(round, estimate)
   │
   ├─ // FAZA 2: Wspólna moneta
   │  coin_val ← ICC(round)
   │
   ├─ // FAZA 3: Logika decyzyjna (Canetti & Rabin)IF vote_strength = 2 THEN          // Silna większość
   │      estimate ← vote_val
   │      A-Cast "COMPLETE: estimate"// Uwaga: Kontynuuj do następnej rundy, aby pomóc innym
   │  
   │  ELSE IF vote_strength = 1 THEN     // Słaba większość
   │      estimate ← vote_val
   │  
   │  ELSE                                // Brak większości
   │      estimate ← coin_val
   │
   └─ // FAZA 4: Sprawdzenie terminacji
      UPON receiving (t + 1) "COMPLETE: v" messages
          OUTPUT v
          TERMINATE

Kluczowe punkty ABA:

4.8. Protokół A-Cast (Reliable Broadcast)

A-Cast to podstawowy prymityw używany przez wszystkie inne protokoły. Zapewnia niezawodne rozgłaszanie nawet gdy nadawca jest bizantyjski.

A-Cast: Bracha's Reliable Broadcast
// Nadawca
FUNCTION Broadcast(value)
    SEND MSG(value) to all processes

─────────────────────────────────────────────────────

// Odbiorcy (Proces k)
LOCAL STATE:
    received_echo : Set[ProcessID] ← ∅      // Kto wysłał ECHO
    received_ready : Set[ProcessID] ← ∅     // Kto wysłał READY
    sent_echo : Boolean ← false
    sent_ready : Boolean ← false
    delivered : Boolean ← false

─────────────────────────────────────────────────────

UPON RECEIVE MSG(val) FROM sender
│
└─ IF NOT sent_echo THEN
       SEND ECHO(val) to all processes
       sent_echo ← true

─────────────────────────────────────────────────────

UPON RECEIVE ECHO(val) FROM process j
│
├─ ADD j to received_echo[val]
│
└─ IF |received_echo[val]| ≥ n - t AND NOT sent_ready THEN
       // Próg: n - t (większość + t)
       SEND READY(val) to all processes
       sent_ready ← true

─────────────────────────────────────────────────────

UPON RECEIVE READY(val) FROM process j
│
├─ ADD j to received_ready[val]
│
├─ IF |received_ready[val]| ≥ t + 1 AND NOT sent_ready THEN// Amplifikacja: t + 1SEND READY(val) to all processes
│      sent_ready ← true
│
└─ IF |received_ready[val]| ≥ 2t + 1 AND NOT delivered THEN
       // Dostarczenie: 2t + 1
       delivered ← true
       TRIGGER A-Cast-Complete(val)

Właściwości A-Cast:

5. Dowody Poprawności i Złożoności

W tej sekcji przedstawiamy formalne dowody kluczowych właściwości protokołu. Wszystkie twierdzenia oparte są na pracy Cheng Wang (EPFL).

5.1. Definicje i Lematy Pomocnicze

Definicja 1: Błędna para (Faulty Pair)

Nieuporządkowana para \(\{i, j\}\) procesów nazywana jest błędną parą, jeśli co najmniej jeden z procesów \(i\) lub \(j\) jest bizantyjski.

Lemat 1: Poprawność detekcji błędnych par

Jeśli \(i, j, k\) są poprawnymi procesami, to nieuporządkowana para \(\{i, j\}\) nie zostanie nigdy dodana do \(\text{FP}_k\).

Dowód Lematu 1

Para \(\{i, j\}\) jest dodawana do \(\text{FP}_k\) tylko wtedy, gdy istnieje instancja IVSS[r] taka, że \(i, j \in M\) oraz wielomiany \(\hat{f}_i\) i \(\hat{f}_j\) rozgłoszone przez \(i\) i \(j\) w Kroku 1 IVSS[r]-R spełniają:

\[\hat{f}_i(j) \neq \hat{f}_j(i)\]

Jednakże, jeśli \(i, j \in M\), to oba \(i\) i \(j\) musiały rozgłosić "EQUAL: \((i, j)\)" oraz "EQUAL: \((j, i)\)" w IVSS[r]-S, co oznacza, że sprawdziły warunek:

\[\hat{f}_i(j) = \hat{f}_j(i)\]

Ponieważ poprawne procesy nie zmieniają swoich wielomianów między fazą dzielenia a rekonstrukcją, warunek ten pozostaje prawdziwy. Zatem \(\{i, j\}\) nie zostanie dodana do \(\text{FP}_k\). \(\square\)

Lemat 2: Ostateczna certyfikacja poprawnych par

W rundzie \(r > 1\), jeśli \(i, j, k, l\) są poprawnymi procesami, to \(k\) ostatecznie rozgłosi "CHECKED\(_r\): \(k, l, \{i, j\}\)".

Dowód Lematu 2

Z Lematu 1 wiemy, że \(\{i, j\} \notin \text{FP}_k\). Musimy sprawdzić warunki (a) i (b) Kroku 5 protokołu certyfikacji:

Warunek (a): Ponieważ \(l\) jest poprawny, rozgłosi \(\text{CoreInvocations}_l^{r'}\) na początku rundy \(r\) dla wszystkich \(r' < r\). Z właściwości poprawności A-Cast, \(k\) otrzyma te wiadomości.

Warunek (b): Załóżmy, że \(i\) jest w zbiorze \(M\) instancji IVSS[r'] w \(\bigcup_{r'

Ponieważ oba warunki są spełnione, \(k\) rozgłosi "CHECKED\(_r\): \(k, l, \{i, j\}\)". \(\square\)

Lemat 3: Unikalność symetrycznego wielomianu dwuwymiarowego

Niech \(N \subseteq \{1, \ldots, n\}\) i \(|N| > t + 1\). Niech \(\{f_i\}_{i \in N}\) będzie zbiorem wielomianów jednowymiarowych stopnia \(t\). Jeśli \(f_i(j) = f_j(i)\) dla wszystkich \(i, j \in N\), to istnieje unikalny symetryczny dwuwymiarowy wielomian \(F(x,y)\) stopnia \(t\) taki, że \(F(i, j) = f_i(j)\) dla wszystkich \(i, j \in N\).

Dowód Lematu 3

Wybierzmy dowolny podzbiór \(N_0 \subseteq N\) taki, że \(|N_0| = t + 1\). Definiujemy:

\[F_0(x, y) = \sum_{i \in N_0, j \in N_0} \frac{\prod_{k \in N_0, k \neq i}(x - k)}{\prod_{k \in N_0, k \neq i}(i - k)} \cdot \frac{\prod_{k \in N_0, k \neq j}(y - k)}{\prod_{k \in N_0, k \neq j}(j - k)} \cdot f_i(j)\]

Z interpolacji Lagrange'a, \(F_0(i, j) = f_i(j)\) dla wszystkich \(i, j \in N_0\). Ponieważ \(f_i(j) = f_j(i)\), wielomian \(F_0\) jest symetryczny.

Dla dowolnego \(i \in N\), mamy \(f_i(j) = f_j(i) = F_0(j, i)\) dla wszystkich \(j \in N_0\). Z symetrii \(F_0\), \(f_i(j) = F_0(i, j)\) dla wszystkich \(j \in N_0\). Ponieważ \(|N_0| = t + 1\), wielomiany \(f_i(y)\) i \(F_0(i, y)\) są identyczne dla wszystkich \(y\).

W szczególności, \(f_i(j) = F_0(i, j)\) dla wszystkich \(j \in N\). Zatem \(F_0\) spełnia warunek. Unikalność wynika z interpolacji Lagrange'a. \(\square\)

5.2. Główne Twierdzenie: Własności IVSS

Twierdzenie 1: Poprawność IVSS

Załóżmy \(n > 3t\). Para (IVSS[r]-S, IVSS[r]-R) spełnia wszystkie własności IVSS:

Dowód Twierdzenia 1 (szkic)

Terminacja (1): Załóżmy, że dealer jest poprawny i wszystkie poprawne procesy uczestniczą w IVSS[r]-S. Każdy poprawny proces otrzyma poprawne wiadomości od dealera. Dla każdej pary \((i, j)\) poprawnych procesów, \(i\) rozgłosi "EQUAL: \((i, j)\)". Z Lematu 2, dla poprawnych procesów \(i, j, k, l\), "CHECKED\(_r\): \(k, l, \{i, j\}\)" zostanie rozgłoszone przez \(k\). Zatem zbiór poprawnych procesów spełni warunki Kroku 4 IVSS[r]-S. Poprawny dealer rozgłosi zbiór \(M\). Wszystkie poprawne procesy otrzymają \(M\) i zakończą IVSS[r]-S.

Terminacja (2): Jeśli poprawny proces zakończy IVSS[r]-S, to wszystkie wymagane wiadomości w Kroku 5 IVSS[r]-S zostały wysłane przez A-Cast. Każdy poprawny proces uczestniczący otrzyma te wiadomości i zakończy IVSS[r]-S.

Terminacja (3): Jeśli jakiś poprawny proces zakończył IVSS[r]-S i wszystkie poprawne procesy zaczynają IVSS[r]-R, niech \(C\) będzie zbiorem poprawnych procesów w \(M\). Ponieważ \(|M| \geq n - t\), mamy \(|C| \geq n - 2t\). Niech \(\hat{f}_i\) będzie wielomianem otrzymanym przez \(i \in C\) od dealera. Ponieważ \(C \subseteq M\), mamy \(\hat{f}_i(j) = \hat{f}_j(i)\) dla wszystkich \(i, j \in C\). Z Lematu 3, istnieje symetryczny dwuwymiarowy wielomian \(\bar{F}\) stopnia \(t\) taki, że \(\bar{F}(i, j) = \hat{f}_i(j)\) dla wszystkich \(i, j \in C\). Zatem \(C\) spełnia warunki Kroku 2 IVSS[r]-R. Każdy poprawny proces zakończy Krok 2 i rozgłosi "READY_TO_COMPLETE", więc otrzyma \(n - t\) takich wiadomości i zakończy IVSS[r]-R.

Poprawność (1): Załóżmy, że poprawny proces zakończył protokół dzielenia. Z Lematu 3, istnieje \(\bar{F}\) takie, że \(\bar{F}(i, j) = \hat{f}_i(j)\) dla wszystkich \(i, j \in C\), gdzie \(C\) to zbiór poprawnych procesów w \(M\). Oznaczamy \(v = \bar{F}(0, 0)\).

Jeśli jakiś poprawny proces \(k\) zakończy IVSS[r]-R i zwróci wartość różną od \(v\), to jego zbiór interpolacji \(\text{IS}_k\) musi być różny od \(C\). Musi istnieć proces \(i \in \text{IS}_k\) i proces \(j \in C\) taki, że \(\bar{F}(i, j) \neq \hat{f}_i(j)\), w przeciwnym razie \(\text{IS}_k\) interpolowałby również \(\bar{F}\). Ponieważ \(\bar{F}(i, j) = \bar{F}(j, i) = \hat{f}_j(i)\), mamy \(\hat{f}_i(j) \neq \hat{f}_j(i)\), co oznacza, że błędna para \(\{i, j\}\) zostanie wykryta.

Poprawność (2): Jeśli dealer jest poprawny, wybrał symetryczny wielomian \(F\) taki, że \(F(0, 0) = s\). Poprawne procesy otrzymują \(f_i(y) = F(i, y)\). Z powyższego, \(\bar{F} = F\), więc \(v = \bar{F}(0, 0) = F(0, 0) = s\).

Sekretność: Bizantyjskie procesy (maksymalnie \(t\)) otrzymują maksymalnie \(t\) przekrojów \(f_i(y)\) symetrycznego wielomianu \(F(x, y)\) stopnia \(t\). Do interpolacji \(F\) potrzeba co najmniej \(t + 1\) punktów w każdym wymiarze. Zatem bizantyjskie procesy nie mogą odtworzyć \(F(0, 0) = s\). \(\square\)

5.3. Analiza Detekcji Błędów

Twierdzenie 2: Wykrywanie liniowej liczby błędnych par

Jeśli IVSS[r]-R nie powiedzie się (poprawne procesy odtworzą różne sekrety), to co najmniej \(t(n - 3t)\) błędnych par zostanie wykrytych.

Dowód Twierdzenia 2

Niech \(C\) będzie zbiorem poprawnych procesów w \(M\), gdzie \(|C| \geq n - 2t\). Niech \(k\) będzie poprawnym procesem, który odtwarza wartość różną od \(v = \bar{F}(0, 0)\), gdzie \(\bar{F}\) jest wielomianem interpolowanym z \(C\).

Proces \(k\) używa zbioru interpolacji \(\text{IS}_k\) takiego, że \(|\text{IS}_k| \geq n - 2t\). Niech \(B = \text{IS}_k \setminus C\) będzie zbiorem procesów w \(\text{IS}_k\), które nie są w \(C\). Każdy proces w \(B\) jest bizantyjski (ponieważ wszyscy poprawni procesy w \(M\) są w \(C\)).

Mamy \(|B| \leq t\) (maksymalna liczba bizantyjskich procesów). Dla każdego \(i \in B\) i każdego \(j \in C\), jeśli \(\hat{f}_i(j) \neq \hat{f}_j(i)\), para \(\{i, j\}\) jest błędną parą i zostanie wykryta.

Ponieważ \(k\) odtwarza wartość różną od \(v\), musi istnieć co najmniej jeden proces \(i \in B\) taki, że dla wielu \(j \in C\), \(\hat{f}_i(j) \neq \bar{F}(i, j) = \hat{f}_j(i)\). W pesymistycznym przypadku, każdy z \(t\) bizantyjskich procesów jest niezgodny z każdym z \(n - 3t\) poprawnych procesów w \(C\) (ponieważ \(|C| \geq n - 2t\) i co najwyżej \(t\) procesów w \(C\) może być "zagrożonych" przez bizantyjskie procesy).

Zatem liczba wykrytych błędnych par wynosi co najmniej:

\[t \cdot (n - 3t)\]

Dla \(n = 4t\), daje to \(t \cdot t = t^2\) wykrytych par – kwadratowo wiele! \(\square\)

5.4. Ważne Wyjaśnienie: Czy szukamy kliki w grafie?

⚠️ Częste nieporozumienie:

Na pierwszy rzut oka może się wydawać, że protokół musi znaleźć klikę w grafie (zbiór \(M\) gdzie wszystkie pary są sprawdzone), co jest problemem NP-zupełnym i wymaga złożoności wykładniczej \(O(2^n)\) lub silniowej \(O(n!)\).

To NIE JEST prawda! Oto dlaczego:

Dlaczego NIE szukamy kliki (kluczowa różnica)

Problem kliki (NP-zupełny):

Nasz protokół (wielomianowy):

Szczegółowe wyjaśnienie konstrukcji M

Jak dealer buduje M (bez szukania kliki)

Krok 1: Dealer wysyła wielomiany

Dealer (poprawny lub bizantyjski) wysyła \(f_i\) do każdego procesu \(i\). Procesy wymieniają punkty i A-Cast wiadomości "EQUAL:(i,j)".

Krok 2: Dealer zbiera wiadomości "EQUAL" i "CHECKED"

Dealer czeka aż otrzyma wystarczająco wiele wiadomości. To jest pasywne czekanie, nie aktywne przeszukiwanie!

\[\text{Zbiór kandydatów: } C = \{i : \text{dealer otrzymał wiele wiadomości o } i\}\]

Krok 3: Weryfikacja kandydatów (O(|C|²) = O(n²))

FOR EACH i ∈ C DO
    FOR EACH j ∈ C WHERE j > i DO
        // Sprawdź czy otrzymano "EQUAL:(i,j)" i "CHECKED" dla {i,j}
        IF NOT received_equal(i, j) THEN
            REMOVE i OR j from C
            BREAK
        IF NOT all_checked(i, j) THEN
            REMOVE i OR j from C
            BREAK

M ← C  // To jest nasz candidate set!

Złożoność tego kroku: \(O(n^2)\) - dwie pętle po maksymalnie \(n\) elementach.

Krok 4: Jeśli |M| ≥ n-t, akceptuj

Dealer NIE szuka największego \(M\). Wystarczy DOWOLNY zbiór \(M\) spełniający:

To jest warunek spełnialności, nie optymalizacji!

Dlaczego to działa bez szukania kliki?

Aspekt Problem kliki (NP-hard) Nasz protokół (Wielomianowy)
Graf wejściowy Dowolny, adversarialny Konstruowany przez uczciwe procesy - gwarantowana struktura
Cel Znaleźć NAJWIĘKSZĄ klikę Znaleźć DOWOLNĄ klikę rozmiaru ≥ n-t
Metoda Przeszukiwanie wszystkich podzbiorów Inkrementalne budowanie z weryfikacją
Gwarancja istnienia Brak (może nie być kliki) Zawsze istnieje (zbiór poprawnych procesów!)
Złożoność \(O(2^n)\) lub \(O(n!)\) \(O(n^2)\) - wielomianowa!

Intuicja: Dlaczego zawsze znajdujemy M?

Kluczowa obserwacja:

Jeśli dealer jest poprawny, to zbiór wszystkich poprawnych procesów automatycznie tworzy kandydata dla \(M\):

Dealer po prostu zbiera te wiadomości (operacja \(O(n^2)\)) i weryfikuje warunki (operacja \(O(n^2)\)). Nie przeszukuje wykładniczo wielu kombinacji!

A co jeśli dealer jest bizantyjski?

Jeśli dealer jest bizantyjski, może:

W obu przypadkach nie ma wykładniczego przeszukiwania. Bizantyjski dealer po prostu wybiera dowolny zbiór (może losowo!) i sprawdza warunki - \(O(n^2)\).

Podsumowanie złożoności obliczeniowej

Operacja Gdzie Złożoność
Wysłanie wielomianów IVSS-S, dealer \(O(n)\) wiadomości
Wymiana punktów IVSS-S, procesy \(O(n^2)\) wymian
Weryfikacja par dla M IVSS-S, dealer \(O(n^2)\) sprawdzeń
A-Cast candidate set IVSS-S, dealer \(O(n^2)\) wiadomości (A-Cast)
Interpolacja wielomianu IVSS-R \(O(n^3)\) (Lagrange)
Całkowita na rundę Jedna runda ABA \(O(n^3)\)

Wniosek: Protokół ma złożoność wielomianową \(O(n^3)\) na rundę komunikacji, a nie wykładniczą. Dla \(n = 100\) to jest ~1,000,000 operacji na rundę (wykonalne), nie \(2^{100}\) (niemożliwe).

5.5. Analiza Złożoności Czasowej (Liczba Rund)

Twierdzenie 3: Oczekiwana liczba rund dla n > 3t

Protokół ABA kończy się w \(O(t)\) oczekiwanych rundach dla \(n > 3t\).

Dowód Twierdzenia 3

Krok 1: Górne ograniczenie na liczbę błędnych par

Maksymalna liczba błędnych par w systemie to:

\[\text{Maksymalna liczba błędnych par} = t \cdot (n - t) + \binom{t}{2}\]

Pierwszy składnik to pary (bizantyjski, poprawny), drugi to pary (bizantyjski, bizantyjski). Upraszając:

\[t(n - t) + \frac{t(t-1)}{2} = t \cdot n - t^2 + \frac{t^2 - t}{2} = t \cdot n - \frac{t^2 + t}{2} \leq t \cdot n\]

Krok 2: Liczba wykrywanych par na rundę

W każdej rundzie uruchamiamy \(n\) instancji IVSS (jedna na proces jako dealer). Z Twierdzenia 2, jeśli instancja IVSS nie powiedzie się, wykrywamy co najmniej \(t(n - 3t)\) błędnych par.

W najgorszym przypadku (dla analizy), załóżmy że w każdej rundzie wykrywamy dokładnie \(t(n - 3t)\) nowych błędnych par (pesymistyczne założenie).

Krok 3: Liczba potrzebnych rund

Liczba rund potrzebnych do wykrycia wszystkich błędnych par:

\[\text{Liczba rund} \leq \frac{t \cdot n}{t(n - 3t)} = \frac{n}{n - 3t}\]

Krok 4: Analiza dla różnych wartości n

Przypadek 1: Dla \(n = 3t + 1\) (minimalna optymalna odporność):

\[\frac{3t + 1}{(3t + 1) - 3t} = \frac{3t + 1}{1} = 3t + 1 = O(t)\]

Przypadek 2: Dla \(n = 4t\):

\[\frac{4t}{4t - 3t} = \frac{4t}{t} = 4 = O(1)\]

Przypadek 3: Dla \(n = (3 + \varepsilon)t\) gdzie \(\varepsilon > 0\):

\[\frac{(3 + \varepsilon)t}{(3 + \varepsilon)t - 3t} = \frac{(3 + \varepsilon)t}{\varepsilon t} = \frac{3 + \varepsilon}{\varepsilon} = O\left(\frac{1}{\varepsilon}\right)\]

Krok 5: Analiza probabilistyczna konsensusu

Gdy wystarczająco wiele błędnych par zostanie wykrytych, procesy bizantyjskie tracą wpływ na protokół Vote. W każdej rundzie, z prawdopodobieństwem \(p > 0\) (zależnym od nieprzewidywalności ICC), poprawne procesy osiągają silną większość (confidence = 2) i kończą protokół.

Oczekiwana liczba rund do osiągnięcia konsensusu po wykryciu błędnych par wynosi \(O(1/p)\). Łączna oczekiwana liczba rund:

\[E[\text{rundy}] = \frac{n}{n - 3t} + O(1) = O\left(\frac{n}{n - 3t}\right)\]

Dla \(n > 3t\), mamy \(n - 3t > 0\), więc dla \(n = \Theta(t)\), oczekiwana liczba rund wynosi \(O(t)\). \(\square\)

Twierdzenie 4: Właściwości ABA

Protokół ABA spełnia wszystkie wymagane właściwości:

Dowód Twierdzenia 4 (szkic)

Terminacja: Z Twierdzenia 3, protokół kończy się w \(O(t)\) oczekiwanych rundach. Ponieważ każda runda ma niezerowe prawdopodobieństwo zakończenia (dzięki ICC), prawdopodobieństwo braku zakończenia po \(k\) rundach zmniejsza się wykładniczo: \(P(\text{nie zakończono}) < (1-p)^k\). Dla \(k \to \infty\), to dąży do 0, więc z prawdopodobieństwem 1 protokół kończy się.

Zgodność: Proces kończy się tylko po otrzymaniu \(t+1\) wiadomości "COMPLETE: v" dla tej samej wartości \(v\). Ponieważ jest maksymalnie \(t\) bizantyjskich procesów, co najmniej jeden poprawny proces wysłał "COMPLETE: v". Poprawny proces wysyła "COMPLETE: v" tylko gdy osiągnął silną większość (confidence = 2) dla \(v\) w protokole Vote. Z własności Vote i A-Cast, wszystkie poprawne procesy, które kończą rundę, również zobaczą tę samą silną większość lub przyjmą \(v\) jako estimate. Przez indukcję, wszystkie poprawne procesy ostatecznie zgodzą się na \(v\).

Poprawność: Jeśli wszystkie poprawne procesy zaczynają z tym samym input_bit = \(v\), to w pierwszej rundzie protokołu Vote, wszystkie poprawne procesy w zbiorze \(A_k\) (który zawiera co najmniej \(n-t\) procesów, z których co najmniej \(n-2t > t\) jest poprawnych) będą głosować na \(v\). Z własności Vote, osiągną silną większość dla \(v\). Zatem wszyscy poprawni procesy ustawią estimate = \(v\) i wyślą "COMPLETE: v" w pierwszej rundzie. Po otrzymaniu \(t+1\) takich wiadomości, wszyscy zwrócą \(v\). \(\square\)

5.6. Praktyczny przykład: n=20, t=6

Dealer buduje M - konkretny przykład bez szukania kliki

Konfiguracja: n=20, t=6, bizantyjskie: {3, 7, 11, 15, 17, 19}

Dealer wysyła wielomiany, procesy wymieniają punkty...

// Dealer (przypuśćmy proces 1, poprawny) otrzymuje wiadomości:

received_equal = {
    (1,2), (1,4), (1,5), (1,6), (1,8), ..., // Para (1, poprawny proces)
    (2,4), (2,5), (2,6), (2,8), ...,        // Para (poprawny, poprawny)
    ...
    // BRAK: (3,x) dla wielu x - proces 3 jest bizantyjski
    // BRAK: (7,x) dla wielu x - proces 7 jest bizantyjski
}

// Algorytm dealera (WIELOMIANOWY!):

candidates = {1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 16, 18, 20}  // Poprawne procesy
M = ∅

// Sprawdź każdy kandydat (O(n) iteracji):
FOR EACH i ∈ candidates DO
    is_valid = true
    
    // Sprawdź z już dodanymi do M (O(|M|) iteracji):
    FOR EACH j ∈ M DO
        IF NOT (received_equal.contains((i,j)) AND 
                  all_checked(i,j)) THEN
            is_valid = false
            BREAK
    
    IF is_valid THEN
        M.add(i)
        
        // Sprawdź próg
        IF |M| ≥ n - t THEN  // ≥ 14
            BREAK  // Sukces! Mamy M

// Wynik: M = {1,2,4,5,6,8,9,10,12,13,14,16,18,20}
// Rozmiar: 14 ≥ 14 = n-t ✓
// Złożoność: O(n²) - WIELOMIANOWA!

Analiza:

5.7. Podsumowanie Wyników Teoretycznych

Właściwość Wynik Porównanie z poprzednimi
Odporność \(n > 3t\) Optymalna (niemożliwe dla \(n \leq 3t\))
Złożoność czasowa \(O(t)\) rund Ulepsza \(O(n^2)\) → \(O(t)\)
Dla \(n = (3+\varepsilon)t\) \(O(1/\varepsilon)\) rund Prawie stały czas dla małego \(\varepsilon\)
Detekcja błędów \(t(n-3t)\) par/rundę Liniowa vs \(O(1)\) w poprzednich
Terminacja Prawie na pewno (prob. 1) Lepsze niż "przytłaczające prawdopodobieństwo"
Złożoność komunikacyjna \(O(n^2)\) per runda Standardowa dla A-Cast

6. Bibliografia

6.1. Główne źródło

Cheng Wang
"Asynchronous Byzantine Agreement with Optimal Resilience and Linear Complexity"
https://arxiv.org/abs/1507.06165
arXiv:1507.06165, 2015

6.2. Powiązane prace

7. Implementacja i Symulacja

7.1. Repozytorium GitHub

Pełna implementacja protokołu w języku Go jest dostępna w repozytorium GitHub:

📦 github.com/poneciak57/async-agreement-protocol

7.2. Struktura Projektu

async-agreement-protocol-3/
│
├── services/
│   ├── aba.go           // Główna pętla ABA
│   ├── acast.go         // A-Cast (Bracha's broadcast)
│   ├── certification.go // Protokół certyfikacji
│   ├── icc.go           // Inferable Common Coin
│   ├── ivss.go          // IVSS-S i IVSS-R
│   ├── vote.go          // Protokół głosowania
│   └── network.go       // Warstwa komunikacji
│
├── utils/
│   ├── polynomial.go    // Operacje na wielomianach
│   └── logger.go        // Logowanie i debugowanie
│
├── tests/
│   ├── ivss_test.go     // Testy jednostkowe IVSS
│   ├── icc_test.go      // Testy ICC
│   ├── vote_test.go     // Testy Vote
│   └── acast_test.go    // Testy A-Cast
│
├── pseudocode/          // Dokumentacja pseudokodu
├── docs/                // Dodatkowa dokumentacja
├── gen.go               // Generator danych testowych
├── test.sh              // Skrypt testowy (100 testów)
└── main.go              // Punkt wejścia symulacji

7.3. Uruchomienie Symulacji

Kompilacja i uruchomienie
# Klonowanie repozytorium
git clone https://github.com/poneciak57/async-agreement-protocol.git
cd async-agreement-protocol/async-agreement-protocol-3

# Kompilacja
go build -o aba-sim main.go

# Uruchomienie symulacji (czyta ze standardowego wejścia)
echo "10 3 1 0 1 1 0 1 0" | ./aba-sim

# Format wejścia:
# Linia 1: n t (liczba procesów, liczba bizantyjskich)
# Linia 2: input_1 input_2 ... input_{n-t} (bity wejściowe dla uczciwych procesów)

# Przykład z plikiem wejściowym:
cat > input.txt << EOF
10 3
1 0 1 1 0 1 0
EOF
./aba-sim < input.txt

# Tryb cichy (tylko wynik końcowy):
./aba-sim -silent < input.txt

7.4. Automatyczne Testy

Repozytorium zawiera skrypt test.sh uruchamiający 100 losowych testów:

Uruchomienie testów
# Uruchom wszystkie testy automatyczne
./test.sh

# Skrypt wykonuje:
# 1. Kompiluje generator (gen.go) i program główny (main.go)
# 2. Dla każdego testu (1-100):
#    - Generuje losowe wejście (n, t, bity)
#    - Uruchamia symulację w trybie -silent
#    - Weryfikuje zgodność wyników wszystkich uczciwych procesów
# 3. Wyświetla podsumowanie (PASSED/FAILED)

# Przykładowe wyjście:
Starting tests...
Test 1 PASSED (n=10, t=3)
Test 2 PASSED (n=15, t=4)
...
Test 100 PASSED (n=20, t=6)
All 100 tests passed!

# Alternatywnie - testy jednostkowe Go:
go test -v ./tests/...

7.5. Opis Symulacji

Implementacja symuluje pełny system rozproszony z następującymi cechami:

7.6. Przykładowe Wyniki Symulacji

Przykład: n=10, t=3, wszyscy zaczynają z 1
========== Symulacja ABA ==========
Parametry: n=10, t=3, bizantyjskie: [2, 5, 7]

--- Runda 1 ---
Vote: Silna większość dla 1 (confidence=2)
Procesy poprawne: wysyłają COMPLETE:1
Wykryte błędne pary: 12

--- Runda 2 ---
Procesy otrzymują (t+1)=4 wiadomości COMPLETE:1
Wszystkie poprawne procesy TERMINUJĄ z wartością: 1

========== Wyniki ==========
✓ Konsensus osiągnięty: 1
✓ Liczba rund: 2
✓ Wszystkie poprawne procesy zgodne: TAK
✓ Całkowita liczba wykrytych błędnych par: 12
✓ Czas symulacji: 1.23s
Przykład: n=10, t=3, mieszane wejścia
========== Symulacja ABA ==========
Parametry: n=10, t=3, wejścia: [1,0,1,0,1,0,1,1,0,1]

--- Runda 1 ---
Vote: Brak większości (confidence=0)
ICC: Generowanie wspólnej monety...
Wspólna moneta: 0
Estimate poprawnych procesów: 0
Wykryte błędne pary: 8

--- Runda 2 ---
Vote: Słaba większość dla 0 (confidence=1)
ICC: Generowanie wspólnej monety...
Wspólna moneta: 1
Estimate pozostaje: 0
Wykryte błędne pary: 15

--- Runda 3 ---
Vote: Silna większość dla 0 (confidence=2)
Procesy poprawne: wysyłają COMPLETE:0
Wykryte błędne pary: 18

--- Runda 4 ---
Procesy otrzymują (t+1)=4 wiadomości COMPLETE:0
Wszystkie poprawne procesy TERMINUJĄ z wartością: 0

========== Wyniki ==========
✓ Konsensus osiągnięty: 0
✓ Liczba rund: 4
✓ Wszystkie poprawne procesy zgodne: TAK
✓ Całkowita liczba wykrytych błędnych par: 18
✓ Czas symulacji: 2.87s

7.7. Testy Jednostkowe

Projekt zawiera kompleksowe testy jednostkowe dla wszystkich komponentów:

# Wszystkie testy:
go test -v ./tests/...

# Testy IVSS (podstawowe, stresowe, bizantyjskie):
go test -v ./tests/*ivss*.go -timeout 60s

# Testy ICC (Inferable Common Coin):
go test -v ./tests/*icc*.go

# Testy Vote Protocol:
go test -v ./tests/*vote*.go

# Testy A-Cast (Bracha's broadcast):
go test -v ./tests/*acast*.go

# Przykładowe scenariusze testowe:
# - TestIVSS_NormalExecution: Standardowy przebieg IVSS
# - TestIVSS_Byzantine_Reconstruction_BadShare: Tolerancja bizantyjskich węzłów
# - TestIVSS_Stress_Concurrent: 20 równoległych instancji IVSS
# - TestICC_Basic: Podstawowa funkcjonalność wspólnej monety
# - TestVote_StrongMajority: Głosowanie z silną większością

7.8. Wymagania Systemowe

Uwaga o wydajności:
Po poprawkach w ivss.go (usunięcie wykładniczego szukania kliki), protokół ma złożoność O(n³) na rundę i skaluje się do sieci z 100+ węzłami. Zobacz szczegółowe komentarze w kodzie dla wyjaśnienia optymalizacji.