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

zkVM の基礎

RISC Zero zkVM を採用した理由、データフロー、暗号学的保証の境界を整理する章です。

なぜ RISC Zero か

  • Trusted setup 不要で扱いやすい。
  • RISC-V 上で通常の Rust コードを使えるため、実装と監査の往復がしやすい。
  • Image ID による実行バイナリ照合と組み合わせやすい。

アーキテクチャ概要

zkVM パイプラインは 3 つのコンポーネントで構成されます。

flowchart TB
  subgraph C1["第1フェーズ: 入力構築"]
    SES[セッションデータ] --> IB[入力ビルダー]
    IB --> INP[ZkVMInput]
  end

  subgraph C2["第2フェーズ: 証明生成"]
    INP --> HOST[ホストプログラム]
    HOST --> GUEST["ゲストプログラム<br/>(zkVM 内実行)"]
    GUEST --> JNL[ジャーナル]
    HOST --> RCP[レシート<br/>STARK 証明]
  end

  subgraph C3["第3フェーズ: 検証"]
    RCP --> VS[検証サービス]
    VS --> VR[検証レポート]
  end
コンポーネント言語責務
ゲストプログラムRustzkVM 内で投票を検証・集計し、結果をジャーナルにコミットする
ホストプログラムRust入力を受け取り、zkVM を起動して STARK 証明(レシート)を生成する
検証サービスRustレシートの STARK 検証を実行し、期待される Image ID との一致を確認する

zkVM とは

RISC Zero zkVM は、RISC-V(RV32IM)命令列として実行されるゲストプログラムに対して、その実行が正しいことを STARK 証明で示すゼロ知識 VM です。

本システムでは「投票検証と集計」をゲストとして実行し、ホストがレシート(seal + journal)を生成します。第三者は Receipt::verify(image_id) により、指定したゲストバイナリ(Image ID)で実行された結果であることを検証できます。

30 秒で要点

観点要点
何を証明するか「このゲストコードをこの入力で実行した結果がジャーナルである」こと
何を公開するかジャーナル(公開出力)とレシート(証明本体)
どこが信頼アンカーかImage ID(どのゲストを検証対象にするか)
この PoC での意味集計値・除外件数・入力整合性を暗号学的に検証可能にする

ジャーナルは証明に束縛される公開出力で、検証成功時に改ざんできません。ジャーナル項目の一覧と各フィールドが何を保証するかは ゲストプログラム > ジャーナル出力 を参照してください。配布対象ファイル(bundle.zip 等)との違いは バンドル構造 を参照してください。

RISC Zero zkVM 実装の要点

RISC Zero 公式ドキュメントに基づく実装上の要点:

  1. 実行モデル: ゲストは RV32IM として決定論的に実行され、外部との境界は syscall (ecall) で扱う
  2. 証明の分割: 長い実行はセグメント証明に分割される(大規模実行を扱うため)
  3. 再帰合成と圧縮: SDK は再帰合成や succinct / Groth16 への圧縮をサポートするが、本 PoC は Composite receipt のまま配布する
  4. 検証 API: Receipt::verify(image_id) が、証明本体と Image ID の束縛を同時に検証する
  5. 公開出力の束縛: journal は証明に束縛されるため、検証成功後に改ざんできない

ジャーナルとレシート

  • ジャーナル: ゲストが公開出力としてコミットするデータ(検証済み集計、除外情報、入力コミットメントなど)
  • レシート: ジャーナルと STARK 証明(seal)のペア。検証成功時、ジャーナルは正しいゲスト実行結果として受理できる
flowchart TB
  R[レシート]
  R --> S[Seal<br/>STARK 証明]
  R --> J[ジャーナル<br/>公開出力]

ジャーナル各フィールドの定義と検証チェックとの対応は ゲストプログラム > ジャーナル出力 を、excludedSlotsrejectedRecords の使い分けは スロット / レコード分離モデル を参照してください。

数学ミニ補足(読み飛ばし可)

STARK の直感的理解に必要な最小限の説明だけを記します。

1. 巡回ドメイン(cyclic domain)

有限体 F の乗法群の部分群 H = {1, w, w^2, ..., w^(n-1)} を評価点集合(ドメイン)として使います。RISC Zero はこれを cyclic domain と呼びます。実行トレース(レジスタ値や遷移)は、この H 上で評価される多項式として扱われます。

2. 有限体上の多項式除算

制約違反の有無は、概念的には次の形で整理できます。

  • 制約多項式を C(x) とする
  • 評価領域 H の零化多項式を Z_H(x) とする(典型例: Z_H(x) = x^n - 1
  • すべての点で制約を満たすなら C(h)=0h in H)となり、C(x)Z_H(x) で割り切れる
  • したがって Q(x) = C(x) / Z_H(x) が多項式として成立するかを検査すれば、制約満足性をチェックできる

実際の STARK では、これを FRI(Fast Reed-Solomon IOP)と Merkle コミットメントを組み合わせて効率的に検証します。

この PoC での保証境界

Receipt::verify(image_id) の成功は強い保証ですが、それ単体で「全票が提示された」ことまでは保証しません。Verified 表示は次がすべて揃った場合にのみ成立します。

  1. STARK 検証成功(正しいゲスト実行)
  2. excludedSlots == 0(除外スロットなし)
  3. totalExpected == treeSize(期待数と掲示板ツリーサイズの一致)
  4. 追記専用性と締切 STH の必須チェック成功

加えて、必須チェックが not_run / pending / running のままでは Verified にはなりません。第三者 STH チェックは source 設定時に限り required に昇格します。詳細なゲーティング規範と判定ロジックは ゲーティングロジック を参照してください。

参考資料(RISC Zero 公式)

データフロー

投票セッションの開始からレシート検証までの全体的なデータフローを示します。

sequenceDiagram
  participant V as 投票者
  participant S as サーバー
  participant B as 掲示板
  participant H as ホスト
  participant G as ゲスト (zkVM)
  participant VS as 検証サービス

  Note over V,B: 投票フェーズ
  V->>S: 投票意図(選択肢・乱数)+ コミットメント
  S->>B: 掲示板に追記
  S-->>V: 投票レシート (インデックス, ルート)
  Note over S: ボット投票を自動追加

  Note over S,G: 集計フェーズ
  S->>S: 入力ビルダーで ZkVMInput を構築
  S->>H: ZkVMInput を渡す
  H->>G: ゲスト実行を開始
  G->>G: 各投票のコミットメント検証
  G->>G: 各投票の包含証明検証
  G->>G: 集計 + ビットマップ計算
  G-->>H: ジャーナル出力
  H-->>S: STARK レシート + ジャーナル

  Note over S,VS: 検証フェーズ
  S->>VS: 検証 bundle 参照 + 期待 Image ID
  VS->>VS: bundle 内の receipt.json を解決
  VS->>VS: Receipt::verify(image_id)
  VS-->>S: 検証レポート
  S-->>V: 検証結果を提供