Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

検出メカニズム

各改ざんシナリオに対して、検証パイプラインがどのチェックで失敗するかを整理します。ここでは実装上の実際の判定ロジック(verification-checksverification-summary)に合わせて説明します。

本章は実 API(src/server/api/handlers/verify.tssrc/lib/verification/*)の判定ロジックを基準にしています。NEXT_PUBLIC_USE_MOCK_API=true の mock API fixture では、本章と異なるチェック結果を返すことがあります。

/api/verifycounted_* チェックは STARK 状態でゲートされます。

  • verificationStatus=not_run の間、counted_*not_run になり得る
  • verificationStatus=running の間、counted_*pending になり得る
  • 本章で「失敗するチェック」と書く箇所は、STARK 検証が解決済み(success/failed)で counted_* が評価可能な局面を前提とする

検出の 2 つの原理

flowchart TB
  P1[原理1: 完全性違反\nexcludedCount > 0] --> C1[counted_missing_indices_zero が失敗]
  P2[原理2: 主張集計の不整合\nclaimed ≠ verified] --> C2[counted_tally_consistent が失敗]
  • 原理1(完全性違反): 主に S1/S3/S5
  • 原理2(主張集計の不整合): 主に S2/S4

シナリオ別の主な失敗チェック(STARK 解決後)

シナリオ主に失敗するチェック説明
S0なし正常系
S1counted_missing_indices_zeroユーザー票除外により excludedCount=1
S2counted_tally_consistentclaimed tally と verified tally が不一致
S3counted_missing_indices_zero現行実装では botId=1 のボット票除外により excludedCount=1
S4counted_tally_consistentclaimed tally と verified tally が不一致
S5counted_missing_indices_zero(再集計分岐では counted_tally_consistent も失敗)excludedCount>0 が必ず発生し、再集計分岐では claimed と verified も不一致になる

補足:

  • S1 では、ビットマップ証明が利用可能な場合 counted_my_vote_included も失敗し得ます
  • S2/S4 では、cast_commitment_matchcounted_input_commitment_match は通常成功します(zkVM 入力を改変していないため)
  • STARK 未解決(not_run/running)の間は、上表の counted_* 失敗は not_run/pending として観測され得ます

4 段階検証モデルとの対応

検証段階S0S1S2S3S4S5
Cast-as-Intended
Recorded-as-Cast
Counted-as-Recorded
STARK Verification

この表は「シナリオ適用による典型挙動」を示します。not_run(証拠不足)や running(検証実行中)は運用状態により別途発生します。


チェックID(主要項目)マトリクス(STARK 解決後)

チェック IDS0S1S2S3S4S5
cast_commitment_match
counted_tally_consistent分岐依存(再集計時は ❌)
counted_missing_indices_zero
counted_my_vote_included❌ または not_run分岐依存
counted_input_commitment_match

S5 の counted_my_vote_included は、ランダム対象がユーザー票(除外または再集計)なら失敗し得ます。証拠不足時は not_run になります。


S2/S4 で何が起きるか

S2/S4 は「入力改ざん」ではなく「主張集計改ざん」です。

flowchart TD
  A["tamperMode=claim (S2/S4)"]
  A --> V1["元の votes を zkVM 入力へ"]
  V1 --> V2["verifiedTally"]
  A --> C1["claimedCounts を改変"]
  C1 --> C2["API の tally.counts"]
  V2 --> X{"claimed と verified は一致?"}
  C2 --> X
  X -->|不一致| F["counted_tally_consistent = failed"]

このため以下は通常発生しません。

  • cast_commitment_match の失敗(ローカル証拠は改変されない)
  • counted_input_commitment_match の失敗(zkVM 入力は元票)

S5 の実装依存ポイント

S5 はランダムに除外または再集計を選びますが、実装上は常に tamperMode=input です。FINALIZE_ASYNC_MODE=true の非同期 finalize では、実行後オーバーライドは行わず zkVM ジャーナル値をそのまま使います。

  • 除外分岐: missingIndices=1 系になり、counted_missing_indices_zero が失敗
  • 再集計分岐: invalidIndices=1 系になり、counted_missing_indices_zero が失敗
  • 再集計分岐では counted_tally_consistent も併発して失敗し得る

ビットマップ証明の役割

counted_my_vote_included は、チェック定義上 required のユーザー包含チェックです。

  • S1(ユーザー票除外)では、証明が利用可能なら失敗して「自分の票が未集計」であることを直接示せる
  • 証拠不足で not_run になる場合でも、最終判定は Verified にならない(missing_evidence もしくは excludedCount による失敗)

最終判定(Verified 表示)

最終表示は verification-summary のルールで決定されます。

flowchart TB
  A[検証チェック集合] --> B{必須チェック failed?}
  B -- yes --> F[failed 系ステータス]
  B -- no --> C{必須チェック not_run / running?}
  C -- yes --> W[in_progress / missing_evidence]
  C -- no --> D{任意チェックに劣化あり?}
  D -- yes --> L[verified_with_limitations]
  D -- no --> V[fully_verified]

代表的な失敗ステータス:

  • user_vote_excluded / votes_excluded: 完全性違反(S1/S3/S5)
  • published_tally_mismatch: claimed と verified の不一致(S2/S4)
  • counted_integrity_failed: Counted 系必須チェック失敗の一般ケース