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

シナリオ一覧

改ざんシナリオ S0〜S5 の定義と、実装上どこを改変するかを整理します。ここでは「zkVM 入力」「主張集計(claimed tally)」「ジャーナル統計(missing/invalid/excluded)」の関係を中心に説明します。


実装上の共通前提

  • 1 回の finalize で選択されるシナリオは 1 つ(S0〜S5)
  • totalExpected は 64(ユーザー 1 + ボット 63)
  • 掲示板(CT Merkle)は追記専用で、シナリオ適用で既存エントリは削除しない
  • tamperModenone / input / claim の 3 種
  • 本章は実 API 経路(/api/finalizefinalize-sessionfinalize-sync|async)を基準に説明する
  • finalize 実行モードは FINALIZE_ASYNC_MODE で切り替わる(false: 同期, true: 非同期)
  • .env.local.example の既定値は FINALIZE_ASYNC_MODE=false(同期)
  • AWS 運用では通常 FINALIZE_ASYNC_MODE=true(非同期)を使う
  • NEXT_PUBLIC_USE_MOCK_API=true の mock API fixture は本章と異なるチェック結果を返すことがある
  • /api/verifycounted_* チェックは STARK 状態でゲートされる(verificationStatus=not_run では not_runrunning では pending
  • 本章の「主な失敗点」は、STARK 検証が解決済み(success/failed)で counted_* が評価可能な局面を前提とする

tamperMode により、zkVM 入力へ反映されるかどうかが決まります。

flowchart TD
  A[シナリオ選択] --> B{tamperMode}
  B -->|none / claim| C[元の votes を zkVM 入力へ]
  B -->|input| D[modifiedVotes を zkVM 入力へ]
  C --> E[zkVM 実行]
  D --> E

S0: 正常(改ざんなし)

改ざんを適用しない基準シナリオです。

項目
tamperModenone
zkVM 入力票数64
claimed と verified一致
excludedCount0

S1: ユーザー票の除外

ユーザー票(インデックス 0)を modifiedVotes から削除し、63 票を zkVM に渡します。

項目
tamperModeinput
zkVM 入力票数63
claimed と verified一致(どちらも 63 票入力ベース)
ジャーナル統計missingIndices=1, invalidIndices=0, excludedCount=1

ポイント:

  • 掲示板上のユーザー票エントリは残る
  • 検出は主に完全性チェック(excludedCount > 0
  • ビットマップ証明が利用可能なら counted_my_vote_included でも検出可能

S2: ユーザー票に関する主張集計の改ざん

ユーザー票に対する「主張集計(表示する tally)」のみ改ざんします。zkVM には元の 64 票を渡します。

項目
tamperModeclaim
zkVM 入力票数64(元データ)
claimed と verified不一致(ユーザー選択肢が -1、別候補が +1)
excludedCount0(通常)
inputCommitmentzkVM 入力由来のため通常は一致

ポイント:

  • 「票の中身を zkVM 入力で差し替える」実装ではない
  • レシートや STARK 証明は通常どおり有効
  • 検出の主因は counted_tally_consistent の失敗

S3: ボット票の除外

現行実装ではボット票インデックス 1targetBotId 初期値)を削除し、63 票を zkVM に渡します。

項目
tamperModeinput
zkVM 入力票数63
claimed と verified一致(どちらも 63 票入力ベース)
ジャーナル統計missingIndices=1, invalidIndices=0, excludedCount=1

S1 との違い:

  • S1: ユーザー自身の未集計をビットマップで直接示せる
  • S3: ユーザー票は含まれるが、集計全体の完全性違反で検出される

S4: ボット票に関する主張集計の改ざん

1 票のボット票に関する「主張集計」だけを改ざんします。zkVM 入力は元の 64 票のままです。

項目
tamperModeclaim
zkVM 入力票数64(元データ)
claimed と verified不一致(対象ボットの元候補が -1、別候補が +1)
excludedCount0(通常)
inputCommitmentzkVM 入力由来のため通常は一致

ポイント:

  • S2 と同様に、改ざん対象は tally.counts
  • 検出の主因は counted_tally_consistent の失敗

S5: ランダムエラー注入

64 票からランダムに 1 票を選び、50% で「除外」または「再集計(別候補化)」を行います。

実装上の重要点:

  • tamperMode は常に input
  • そのため zkVM 入力は常に modifiedVotes が使われる
  • 除外パスでは missingIndices が増え、再集計パスでは不正票化により invalidIndices が増えるため、いずれも excludedCount > 0 になる
  • 再集計パスでは counted_tally_consistent も失敗し得る(claimed は再集計後、verified は不正票除外後)
分岐zkVM 入力代表的な統計
除外パス63 票missingIndices=1, invalidIndices=0, excludedCount=1
再集計パス64 票missingIndices=0, invalidIndices=1, excludedCount=1

再集計パスでも excludedCount が 0 にならないのは、zkVM 側で不正票として除外されるためです。


シナリオ一覧表

シナリオ類型tamperModezkVM 入力主な失敗点(STARK 解決後)
S0正常none元の 64 票なし
S1除外input63 票(ユーザー除外)excludedCount > 0
S2主張改ざんclaim元の 64 票claimed ≠ verified
S3除外input63 票(ボット除外)excludedCount > 0
S4主張改ざんclaim元の 64 票claimed ≠ verified
S5ランダム(実装上 input)input63 または 64 票excludedCount > 0(再集計では claimed ≠ verified も発生)

ジャーナル統計オーバーライド(同期 finalize のみ)

同期 finalize(ローカル実行)では、tamperMode=input の場合(S1/S3/S5)に zkVM 実行後の統計を次で上書きします。

  • missingIndices = max(existingMissing, ignoredCount)
  • invalidIndices = max(existingInvalid, recountedCount)
  • excludedCount = missingIndices + invalidIndices
  • countedIndices = totalExpected - excludedCount

一方、FINALIZE_ASYNC_MODE=true の非同期 finalize ではこのオーバーライドは適用せず、コールバックで復元した zkVM ジャーナル値をそのまま用います。

tamperMode=claim(S2/S4)ではこのオーバーライドは行いません。


集計フローへの挿入点

flowchart TB
  A[セッション votes 読み込み] --> B[シナリオ適用]
  B --> C{tamperMode}
  C -- input --> D[modifiedVotes で zkVM 入力生成]
  C -- claim --> E[元の votes で zkVM 入力生成]
  D --> F[zkVM 実行]
  E --> F
  F --> G[finalizationResult 保存]
  B --> H[claimedCounts 計算]
  H --> G