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 を用いた集計証明パイプラインの全体設計を解説します。

ゲストプログラムが投票データを検証・集計し、ホストが STARK 証明を生成し、検証サービスがレシートを検証する一連のアーキテクチャにより、集計結果の正当性を暗号学的に保証します。

アーキテクチャ概要

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 での意味集計値・除外件数・入力整合性を暗号学的に検証可能にする

RISC Zero zkVM 実装の要点(簡潔版)

RISC Zero の一次情報(zkVM specification / recursion docs)に沿って、実装上重要な点だけを抜粋すると次のとおりです。

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

ジャーナルとレシート

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

ジャーナルの各項目は、対応する STARK 証明(レシート検証)により「ゲストプログラムが計算した出力」であることが保証されます。項目ごとの意味と確認ポイントは次のとおりです。

ジャーナル項目代表フィールド主な確認ポイント
検証済み集計verifiedTallycounted_tally_consistent
除外/欠落情報excludedCount などcounted_missing_indices_zero
入力整合性inputCommitmentcounted_input_commitment_match
STH バインディングsthDigestrecorded_sth_third_party(設定時)
個票包含証明の根includedBitmapRootcounted_my_vote_included

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

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) の成功は強い保証ですが、それ単体で「全票が提示された」ことまでは保証しません。本 PoC では以下を組み合わせて最終判定します。

  1. STARK 検証成功(正しいゲスト実行)
  2. excludedCount == 0(除外票なし)
  3. 一貫性証明・STH 整合の成功(設定時)
  4. 必須チェックが not_run / running のままでは不合格

このため、Verified 表示は「証明 + 完全性チェック」がそろった場合にのみ成立します。

参考資料(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: 掲示板に追記
  B-->>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: レシート + 期待 Image ID
  VS->>VS: Receipt::verify(image_id)
  VS-->>S: 検証レポート
  S-->>V: 検証結果を提供

同期モードと非同期モード

ホストプログラムの実行には 2 つのモードがあります。

項目同期モード非同期モード
実行環境ローカルプロセスECS Fargate タスク
起動方式ホストバイナリを直接起動SQS → Step Functions → ECS
ユースケース開発・テスト本番環境
タイムアウト10 分15 分
結果の取得プロセス終了後に直接読み取りS3 経由 + コールバック Lambda

詳細は ホストと証明生成 を参照してください。

開発モードと本番モード

RISC Zero は RISC0_DEV_MODE 環境変数により、開発モードと本番モードを切り替えます。

項目開発モード (RISC0_DEV_MODE=1)本番モード
証明の種類フェイクレシート本物の STARK 証明
実行時間約 100 ミリ秒約 370 秒(64 票の場合)
安全性なし(検証を省略)暗号学的に完全
検証サービスDevMode として検出完全な STARK 検証を実行

開発モードで生成されたレシートは InnerReceipt::Fake 型となります。検証サービスでは通常 DevMode として扱いますが、image_id 不一致などの事前条件違反があれば Failed になります。本番環境でフェイクレシートが混入した場合は検証失敗です。

この部に含まれる章