チェック一覧
全検証チェック ID の定義、判定ロジック、失敗時の影響を一覧で解説します。
各チェックは一意の ID を持ち、success / failed / not_run / running / pending のステータスで管理されます。not_run のチェックが残っている場合、「Verified」は表示されません。
チェックの属性
各チェックには以下の属性が定義されています。
| 属性 | 説明 |
|---|---|
| ID | チェックの一意な識別子(スネークケース) |
| カテゴリ | 所属する検証段階 |
| 証拠種別 | チェックに使用するデータの出所 |
| 重要度 | required(必須)または optional(任意) |
| 派生元 | 他のチェックから結果を導出する場合のソースチェック ID |
証拠種別
| 種別 | 説明 |
|---|---|
local | 投票時に確定したユーザー固有データ(現行 /api/verify では主にセッション保存値) |
public | 掲示板や公開 API から取得可能なデータ |
zk | zkVM ジャーナル(公開出力)に含まれるデータ |
重要度
| 重要度 | 説明 |
|---|---|
required | 「Verified」表示に必須。失敗すれば即座にブロック |
optional | 補助的な検証。失敗しても単独では「Verified」をブロックしない |
Cast-as-Intended(4 チェック)
投票者の意図通りにコミットメントが生成されたかを検証するチェック群です。
現行実装では、このカテゴリの入力は /api/verify が返す voteReceipt / userVote(セッション復元データ)を起点に評価されます。
| ID | 説明 | 証拠種別 | 重要度 |
|---|---|---|---|
cast_receipt_present | レシートが存在し、voteId とコミットメントを含む | local | required |
cast_choice_range | 選択肢が有効範囲内(A〜E) | local | required |
cast_random_format | 乱数が 32 バイトの 16 進数文字列 | local | required |
cast_commitment_match | 投票時データから再計算したコミットメントがレシートと一致 | local | required |
判定ロジックの詳細
cast_receipt_present: voteReceipt が存在し、voteId と commitment フィールドが存在することを確認します(このチェック単体では UUID/hex 形式までは検証しません)。
cast_choice_range: 投票時データの選択肢が A〜E のいずれかであることを確認します。範囲外の値は不正な入力として failed となります。
cast_random_format: 投票時データの乱数が 32 バイト(64 文字)の 16 進数文字列であることを確認します。0x プレフィックスの有無は正規化により吸収されます。
cast_commitment_match: 投票時データ(選挙 ID、選択肢、乱数)からコミットメントを再計算し、レシートのコミットメント値と照合します。ドメインタグ "stark-ballot:commit|v1.0" を含む正準フォーマットに従います。
Recorded-as-Cast(6 チェック)
コミットメントが掲示板に正しく記録されたかを検証するチェック群です。
| ID | 説明 | 証拠種別 | 重要度 | 派生元 |
|---|---|---|---|---|
recorded_commitment_in_bulletin | コミットメントが掲示板ツリーに存在する | public | optional | recorded_inclusion_proof |
recorded_index_in_range | 掲示板インデックスが 0 以上かつツリーサイズ未満 | public | required | — |
recorded_root_at_cast_consistent | 投票時のルートがルート履歴に存在する | public | optional | recorded_consistency_proof |
recorded_inclusion_proof | RFC 6962 包含証明が暗号学的に検証成功 | public | required | — |
recorded_consistency_proof | RFC 6962 整合性証明が暗号学的に検証成功 | public | required | — |
recorded_sth_third_party | 第三者 STH ソース間で合意が成立(比較可能応答間) | public | optional | — |
判定ロジックの詳細
recorded_commitment_in_bulletin: 包含証明(recorded_inclusion_proof)の結果から派生します。包含証明が成功すれば、コミットメントがツリーに存在することが暗号学的に証明されています。
recorded_index_in_range: 掲示板インデックスが 0 <= index < treeSize の範囲内であることを確認します。範囲外のインデックスは、データの不整合を示します。
recorded_root_at_cast_consistent: 整合性証明(recorded_consistency_proof)の結果から派生します。整合性証明が成功すれば、投票時のルートが最終ツリーの有効なプレフィックスであることが証明されています。
recorded_inclusion_proof: 投票者のコミットメントに対する RFC 6962 包含証明(監査パス)を検証します。リーフハッシュと監査パスからルートを再計算し、期待するルートハッシュと照合します。
recorded_consistency_proof: 投票時のツリー(oldSize, oldRoot)から最終ツリー(newSize, newRoot)への RFC 6962 整合性証明を検証します。この証明は、古いツリーが新しいツリーの追記専用プレフィックスであることを保証します。
recorded_sth_third_party: 設定された STH ソースからスナップショットを取得し、比較可能な応答同士で合意を確認します。判定は matchingSources >= minMatches(デフォルト: 2)に加えて、比較対象になった応答間の全会一致(consensus)が必要です。照合対象は STH ダイジェストが必須で、bulletinRoot / treeSize は各ソースが返した場合に追加で照合されます。STH ソースが未設定の場合は not_run になります。
このチェック定義の criticality は optional ですが、サマリー判定では STH ソースが設定されている場合に実質的な必須条件として扱われます。
派生チェックについて
recorded_commitment_in_bulletin と recorded_root_at_cast_consistent は、それぞれ recorded_inclusion_proof と recorded_consistency_proof から結果を派生します。これは、包含証明の検証成功がそのまま「コミットメントの存在」の証明となり、整合性証明の検証成功がそのまま「ルートの一貫性」の証明となるためです。
派生チェックの重要度が optional であるのは、派生元の required チェックが既にカバーしているためです。
Counted-as-Recorded(8 チェック)
記録された全投票が正しく集計に含まれたかを検証するチェック群です。
| ID | 説明 | 証拠種別 | 重要度 |
|---|---|---|---|
counted_input_sanity | 公開入力サマリーが有効 | public | required |
counted_unique_indices | 入力中の全インデックスが一意 | public | required |
counted_unique_commitments | 入力中の全コミットメントが一意 | public | required |
counted_tally_consistent | claimed tally と zkVM の検証済み集計が一致(fallback: 合計整合) | zk | required |
counted_missing_indices_zero | 除外された投票数が 0 | zk | required |
counted_expected_vs_tree_size | totalExpected がツリーサイズと一致 | zk | required |
counted_my_vote_included | ビットマップ証明により自分のインデックスが集計に含まれたことを確認 | zk | required |
counted_input_commitment_match | 公開入力から計算した入力コミットメントがジャーナルの値と一致 | public | required |
判定ロジックの詳細
counted_input_sanity: 公開入力サマリー(publicInputSummary)が存在し、必要なフィールド(選挙 ID、掲示板ルート、ツリーサイズ、投票数等)を含んでいることを確認します。
counted_unique_indices: zkVM に渡された全投票のインデックスが重複なく一意であることを確認します。重複インデックスは、同一投票の二重カウントを示す可能性があります。
counted_unique_commitments: zkVM に渡された全投票のコミットメントが重複なく一意であることを確認します。重複コミットメントは、同一コミットメントに対する複数投票を示す可能性があります。
counted_tally_consistent: 主経路では、公開される claimed tally(tally.counts)が zkVM の verifiedTally と選択肢ごとに一致し、かつ verifiedTally の合計が tally.totalVotes と一致することを確認します。これにより「公開表示された集計値」と「zkVM が証明した集計値」の不一致を検出します。claimed tally が利用できない場合は、フォールバックとして journal.verifiedTally の合計と journal.validVotes の一致を検証します。
counted_missing_indices_zero: zkVM ジャーナルの excludedCount が 0 であることを確認します。このチェックは本システムの最重要不変条件であり、0 でない場合は即座に検証を失敗とします。
counted_expected_vs_tree_size: totalExpected(期待される投票数)が掲示板のツリーサイズと一致することを確認します。不一致は、暗黙の投票除外を示す可能性があります。
counted_my_vote_included: ビットマップ Merkle 証明を検証し、投票者のインデックスに対応するビットが 1(集計に含まれた)であることを確認します。サーバーから取得した leafChunk と auditPath を使用し、ビットマップルートまでの Merkle パスを検証します。
counted_input_commitment_match: 公開入力から入力コミットメント(全投票 + Merkle パスの正準ハッシュ)を計算し、zkVM ジャーナルに記録された入力コミットメント値と照合します。一致すれば、zkVM が公開入力と同一のデータを処理したことが保証されます。
STARK Verification(2 チェック)
STARK 証明の暗号学的正当性を検証するチェック群です。
| ID | 説明 | 証拠種別 | 重要度 |
|---|---|---|---|
stark_image_id_match | レシートの Image ID が期待値と一致 | zk | required |
stark_receipt_verify | STARK レシートが暗号学的に検証成功 | zk | required |
判定ロジックの詳細
stark_image_id_match: レシートに記録された Image ID が、imageId-mapping.json で定義された期待 Image ID と一致することを確認します。不一致は、異なるゲストプログラムで生成された証明であることを示します。
stark_receipt_verify: サーバー側の Rust 検証サービスが Receipt::verify(image_id) を実行し、Seal(STARK 証明)が暗号学的に正当であることを確認します。チェック結果としては success / failed / not_run / running が使われ、dev_mode は許可設定に応じて success または not_run に正規化されます。
チェックステータスの遷移
stateDiagram-v2 [*] --> not_run: 初期状態 not_run --> pending: 依存条件の待機 not_run --> running: 検証開始 pending --> running: 依存条件の解消 running --> success: 検証成功 running --> failed: 検証失敗
| ステータス | 説明 | 「Verified」への影響 |
|---|---|---|
not_run | 関連データが未取得、または検証未開始 | ブロック |
pending | 依存する検証の完了を待機中 | ブロック |
running | 検証を実行中 | ブロック |
success | 検証成功 | 許可 |
failed | 検証失敗 | ブロック |
全チェック早見表
| # | チェック ID | カテゴリ | 証拠 | 重要度 | 派生元 |
|---|---|---|---|---|---|
| 1 | cast_receipt_present | Cast | local | required | — |
| 2 | cast_choice_range | Cast | local | required | — |
| 3 | cast_random_format | Cast | local | required | — |
| 4 | cast_commitment_match | Cast | local | required | — |
| 5 | recorded_commitment_in_bulletin | Recorded | public | optional | recorded_inclusion_proof |
| 6 | recorded_index_in_range | Recorded | public | required | — |
| 7 | recorded_root_at_cast_consistent | Recorded | public | optional | recorded_consistency_proof |
| 8 | recorded_inclusion_proof | Recorded | public | required | — |
| 9 | recorded_consistency_proof | Recorded | public | required | — |
| 10 | recorded_sth_third_party | Recorded | public | optional | — |
| 11 | counted_input_sanity | Counted | public | required | — |
| 12 | counted_unique_indices | Counted | public | required | — |
| 13 | counted_unique_commitments | Counted | public | required | — |
| 14 | counted_tally_consistent | Counted | zk | required | — |
| 15 | counted_missing_indices_zero | Counted | zk | required | — |
| 16 | counted_expected_vs_tree_size | Counted | zk | required | — |
| 17 | counted_my_vote_included | Counted | zk | required | — |
| 18 | counted_input_commitment_match | Counted | public | required | — |
| 19 | stark_image_id_match | STARK | zk | required | — |
| 20 | stark_receipt_verify | STARK | zk | required | — |