ゲーティングロジック
「Verified」表示の条件と、表示を阻止する不変条件を解説します。
「必要な検証が未実行または失敗なら Verified を表示しない」 という原則に基づき、各検証チェックの結果がどのように最終判定に集約されるかを説明します。
最終判定の種類
検証パイプラインの結果は、verificationChecks の集約結果として以下に分類されます。
| 表示ステータス | 条件 | UI 表示 |
|---|---|---|
| Verified | 必須チェックがすべて success かつ任意チェックも劣化なし | 緑色 |
| Verification Failed | 必須チェックのいずれかが failed | 赤色 |
| Warning | 必須チェックに not_run / pending / running が残る、または任意チェックが劣化している | 黄色 |
ステータスの判定順序
| 優先順 | 判定条件 | 最終ステータス |
|---|---|---|
| 1 | 必須チェックに failed が 1 つでもある | Verification Failed |
| 2 | 1 に該当せず、必須チェックに not_run / pending / running が 1 つでもある | Warning |
| 3 | 1,2 に該当せず、任意チェックに failed / not_run が 1 つでもある | Warning |
| 4 | 上記いずれにも該当しない | Verified |
補助判定のゲーティング(validateVotingIntegrity)
validateVotingIntegrity はクライアント側の補助判定として実装されています。この関数は 5 つのゲートを順に評価し、いずれかが失敗した時点で canShowVerified = false を返します。
ただし通常の /verify 取得では journal が省略されるため(includeJournal=1 未指定)、この補助判定は標準フローで常時実行されるわけではありません。最終サマリ表示は verificationChecks の集約(deriveVerificationSummary)が優先されます。
ゲート 1: 整合性証明
RFC 6962 の整合性証明により、掲示板が追記専用であることを検証します。
| 条件 | 結果 |
|---|---|
| 整合性証明が暗号学的に検証成功 | 通過 |
| 証明の検証失敗 | canShowVerified = false(スプリットビュー攻撃の可能性) |
| ルートの不一致(old/new) | canShowVerified = false |
| API エラーで証明を取得できない | canShowVerified = false |
ゲート 2: 完全性(Completeness)
zkVM の集計に全投票が含まれたことを検証します。
| 条件 | 結果 |
|---|---|
excludedCount が非負整数として存在し、excludedCount == 0 | 通過 |
excludedCount > 0 | canShowVerified = false(最重要不変条件) |
excludedCount / missingIndices / invalidIndices が欠落・不正値 | canShowVerified = false |
excludedCount > 0 は、投票が意図的に集計から除外されたことを意味します。これは投票システムにおいて最も深刻な不正であり、いかなる場合も「Verified」を表示してはなりません。
ゲート 3: 警告の収集
validateVotingIntegrity では totalExpected != treeSize や invalidIndices > 0 を警告として収集します(excludedCount == 0 の場合)。
ただし、verificationChecks 側では counted_expected_vs_tree_size が必須チェックであり、totalExpected != treeSize は failed として最終的に Verified をブロックします。
ゲート 4: 第三者 STH 検証(有効時のみ)
STH ソースが設定されている場合のみ評価されます。
| 条件 | 結果 |
|---|---|
| STH ソースが未設定 | このゲートをスキップ |
比較可能な応答群で合意成立 かつ matchingSources >= minMatches | 通過 |
| 合意が成立しない | canShowVerified = false |
| 一致ソース数が最小要件未満 | canShowVerified = false |
STH 合意の検証では、STH ダイジェストは必須照合です。bulletinRoot と treeSize は各ソースが値を返した場合にのみ照合対象になります。
- STH ダイジェスト(
logId || treeSize || timestamp || bulletinRootの SHA-256) - 掲示板ルート(返却時)
- ツリーサイズ(返却時)
ゲート 5: ユーザーインデックスの範囲検証
投票者のインデックスがツリーサイズの範囲内であることを確認します。
| 条件 | 結果 |
|---|---|
userIndex < treeSize | 通過 |
userIndex >= treeSize | canShowVerified = false |
STARK 検証のゲーティング
STARK 検証は整合性検証とは独立に評価されます。
| STARK ステータス | 説明 | 最終判定への影響 |
|---|---|---|
success | 暗号学的に検証成功 | 他の必須チェックも success なら Verified 可能 |
failed | 検証失敗 | Verified をブロック |
dev_mode | 開発モードのフェイクレシート | allowDevModeVerification=true なら success、それ以外は not_run |
not_run | 未実行 | missing_evidence(Warning)扱い。Verified をブロック |
running | 実行中 | in_progress(Warning)扱い。Verified をブロック |
現在の実装では、STARK not_run の状態で「Verified(整合性)」を緑表示する経路はありません。
zkGate: STARK 結果に基づく Counted チェックの制御
STARK 検証の結果は、Counted-as-Recorded 段階のチェック評価にも影響します。これを zkGate と呼びます。
| STARK 解決後ステータス | Counted チェックへの反映 |
|---|---|
running | pending |
not_run | not_run |
failed | failed |
success | ゲートなしで通常評価 |
dev_mode は事前に success または not_run に正規化されてから zkGate に入力されます。
ステップとチェックの対応関係
UI に表示される 4 つのステップは、20 個のチェックのサブセットから派生します。
| ステップ | 対応するチェック ID |
|---|---|
| Cast-as-Intended | cast_receipt_present, cast_choice_range, cast_random_format, cast_commitment_match |
| Recorded-as-Cast | recorded_inclusion_proof |
| Counted-as-Recorded | counted_missing_indices_zero, counted_tally_consistent |
| STARK Verification | stark_receipt_verify |
ステップのステータスは、対応するチェックのステータスから集約されます。
| 集約ルール | 条件 |
|---|---|
failed | いずれかの対応チェックが failed |
running | failed がなく、いずれかが running |
pending | failed/running がなく、いずれかが pending |
success | 全対応チェックが success |
not_run | 上記のいずれにも該当しない |
UI シーケンスとポーリング
検証ページでは、4 つのステップが順次アニメーション表示されます。
sequenceDiagram
participant U as ブラウザ
participant S as サーバー
Note over U: ページロード時
U->>S: GET /api/verify
S-->>U: 検証ペイロード
Note over U: STARK 完了まで待機
loop STARK ポーリング
U->>S: GET /api/verify
S-->>U: verificationStatus 確認
end
Note over U: STARK 解決後に<br/>ステップを順次表示
Note over U: Step 1: Cast-as-Intended
Note over U: Step 2: Recorded-as-Cast
Note over U: Step 3: Counted-as-Recorded
Note over U: Step 4: STARK Verification
Note over U: 最終判定を表示
重要な制約として、STARK 検証が完了するまで、ステップの表示シーケンスは開始されません。これは、STARK の結果が Counted チェックの評価(zkGate)に影響するためです。
不変条件のまとめ
以下の不変条件は、コードの変更によっても決して緩和してはなりません。
| 不変条件 | 根拠 |
|---|---|
excludedCount > 0 → Verified を表示しない | 投票除外は最も深刻な不正 |
| 整合性証明の失敗 → Verified を表示しない | 追記専用性が保証されない |
| STH 合意の不成立(有効時) → Verified を表示しない | スプリットビュー攻撃の可能性 |
not_run チェックの存在 → Verified を表示しない | 証拠の不在を成功として扱わない |
| STARK 検証の失敗 → Verified を表示しない | ジャーナルの正当性が保証されない |
| 非公開アーティファクトをバンドルに含めない | 投票の秘匿性を維持 |
これらの不変条件は、改ざんシナリオ(S0〜S5)の検出を保証する基盤です。各シナリオがどの不変条件によって検出されるかは、改ざんシナリオ を参照してください。