---------------------------- MODULE PoT ---------------------------- (* Формальная спецификация Proof of Time консенсуса Монтаны. Уровень абстракции: безопасность (Safety) и живость (Liveness) при византийском противнике f < n/3 в частично синхронной модели. Не моделируется (вне scope этого spec): - Конкретные SHA-256 байты (VDF аппроксимирован монотонной функцией) - Криптография подписей (предполагается EUF-CMA, см. 02 Криптография) - Сетевая сериализация (предполагается канонической) *) EXTENDS Naturals, FiniteSets, Sequences, TLC CONSTANTS Operators, \* Множество всех операторов Honest, \* Подмножество честных операторов Byzantine, \* Подмножество византийских операторов Accounts, \* Множество аккаунтов MaxWindow, \* Граница model checking-а GST \* Global Stabilization Time (окно после которого сеть синхронна) ASSUME /\ Honest \cup Byzantine = Operators /\ Honest \cap Byzantine = {} /\ Cardinality(Byzantine) * 3 < Cardinality(Operators) \* f < n/3 /\ Cardinality(Honest) >= 1 /\ MaxWindow \in Nat /\ GST \in 0..MaxWindow VARIABLES window, \* Текущее окно τ₁ (длина VDF-цепи) vdf_chain, \* Канонический VDF-выход на каждом окне: window -> hash committed, \* Зафиксированные операции: window -> SUBSET <> proposed, \* Предложения операторов: <> operator_chain, \* Локальная цепь оператора: operator -> Seq(window) selection_winner \* Победитель лотереи окна: window -> operator vars == <> ---------------------------------------------------------------------- (* Определения *) \* Один шаг на личность за окно: аккаунт может иметь не более одной операции \* в каждом окне (anti-Sybil на уровне аккаунта) OneStepPerWindow(w, a) == Cardinality({op \in committed[w] : op[1] = a}) <= 1 \* Каноническое продвижение VDF: window+1 = SHA-256^D от window \* Здесь абстракция: vdf_chain[w+1] зависит детерминированно от vdf_chain[w] VDFCanonical(w) == IF w = 0 THEN TRUE ELSE vdf_chain[w] # vdf_chain[w-1] \* Каждое окно даёт новый выход \* Network synchronous after GST SynchronousAfter(w) == w >= GST ---------------------------------------------------------------------- (* Initial state *) Init == /\ window = 0 /\ vdf_chain = [w \in {0} |-> 0] \* Genesis seed = 0 /\ committed = [w \in {0} |-> {}] /\ proposed = {} /\ operator_chain = [o \in Operators |-> <<>>] /\ selection_winner = [w \in {} |-> CHOOSE o \in Operators : TRUE] ---------------------------------------------------------------------- (* Действия *) \* Действие: оператор крутит VDF и продвигает окно AdvanceWindow == /\ window < MaxWindow /\ window' = window + 1 /\ vdf_chain' = vdf_chain @@ (window+1 :> window+1) \* Абстракция SHA-256^D /\ committed' = committed @@ (window+1 :> {}) /\ UNCHANGED <> \* Действие: честный оператор предлагает операцию HonestPropose(o, a, op_data) == /\ o \in Honest /\ window > 0 /\ a \in Accounts /\ \A p \in proposed : ~(p[1] = o /\ p[2] = window /\ p[3][1] = a) \* Честный оператор не предлагает дублирующую операцию для аккаунта в текущем окне /\ proposed' = proposed \cup {<>>>} /\ operator_chain' = [operator_chain EXCEPT ![o] = Append(@, window)] /\ UNCHANGED <> \* Действие: византийский оператор может предложить ЛЮБУЮ операцию \* (включая дубликаты, конфликтующие, в любом окне) ByzantinePropose(o, a, op_data, w) == /\ o \in Byzantine /\ w \in DOMAIN vdf_chain /\ a \in Accounts /\ proposed' = proposed \cup {<>>>} /\ UNCHANGED <> \* Лотерея: выбор победителя окна детерминированно из VDF-выхода \* Абстракция: победитель — оператор, чей хеш-id ближе всех к vdf_chain[window] LotterySelect == /\ window > 0 /\ window \notin DOMAIN selection_winner /\ \E o \in Operators : /\ selection_winner' = selection_winner @@ (window :> o) /\ UNCHANGED <> \* Коммит: победитель окна включает свой набор операций в канон \* Безопасность: один шаг на личность сохраняется WinnerCommit == /\ window > 0 /\ window \in DOMAIN selection_winner /\ LET winner == selection_winner[window] winner_proposals == {p \in proposed : p[1] = winner /\ p[2] = window} by_account == { p[3] : p \in winner_proposals } IN /\ \* Один шаг на личность: для каждого аккаунта максимум одна операция \A a \in Accounts : Cardinality({op \in by_account : op[1] = a}) <= 1 /\ committed' = [committed EXCEPT ![window] = by_account] /\ UNCHANGED <> \* Полный шаг состояния Next == \/ AdvanceWindow \/ \E o \in Operators, a \in Accounts, op_data \in {1,2,3} : HonestPropose(o, a, op_data) \/ \E o \in Byzantine, a \in Accounts, op_data \in {1,2,3}, w \in 0..window : ByzantinePropose(o, a, op_data, w) \/ LotterySelect \/ WinnerCommit Spec == Init /\ [][Next]_vars /\ WF_vars(AdvanceWindow) /\ WF_vars(LotterySelect) /\ WF_vars(WinnerCommit) ---------------------------------------------------------------------- (* Инварианты безопасности *) \* S1 — Safety: невозможность форков \* Для любого окна w и любого аккаунта a: \* количество зафиксированных операций аккаунта a в окне w не больше 1. NoDoubleSpendInWindow == \A w \in DOMAIN committed : \A a \in Accounts : Cardinality({op \in committed[w] : op[1] = a}) <= 1 \* S2 — VDF канонический: каждое окно даёт новый выход VDFMonotone == \A w \in DOMAIN vdf_chain : VDFCanonical(w) \* S3 — Только победитель лотереи коммитит в окне OnlyWinnerCommits == \A w \in DOMAIN committed : committed[w] # {} => /\ w \in DOMAIN selection_winner /\ \A op \in committed[w] : \E p \in proposed : /\ p[1] = selection_winner[w] /\ p[2] = w /\ p[3] = op \* S4 — VDF цепь монотонна (длина растёт) WindowMonotone == window' >= window ---------------------------------------------------------------------- (* Свойства живости (Liveness) *) \* L1 — После GST: каждая операция честного оператора в конце концов коммитится \* (упрощённо — модель не различает корректность операции от её принятия) EventuallyCommitted(o, a, op_data) == []( (window >= GST /\ o \in Honest /\ \E w \in DOMAIN vdf_chain : <>>> \in proposed) => <>(\E w \in DOMAIN committed : <> \in committed[w]) ) \* L2 — Окно бесконечно продвигается (если хотя бы один честный оператор активен) WindowProgresses == [](\E h \in Honest : TRUE) => []<>(window' > window) ---------------------------------------------------------------------- (* Дополнительные допущения и аксиомы *) THEOREM Safety == Spec => []NoDoubleSpendInWindow THEOREM VDFCorrect == Spec => []VDFMonotone THEOREM CommitProvenance == Spec => []OnlyWinnerCommits THEOREM ChainProgress == Spec => []WindowMonotone (* Доказательства этих теорем выполняются через: 1. TLAPS (TLA+ Proof System) — формально верифицируемые 2. TLC model checking при малых N (см. PoT.cfg) Текущая модель верифицирует Safety при: - |Operators| = 4 (3 honest, 1 Byzantine) - |Accounts| = 3 - MaxWindow = 10 Полная формальная верификация на больших N требует разбора по индукции с инвариантами — открытый вопрос. *) ============================================================================