検証サービス
この章では、STARK レシートを検証する Rust サービスの構造と、ローカルおよび Lambda での使い方を扱います。
検証サービスは、レシートの STARK 検証をサーバー側で実行し、結果をレポートとしてクライアントに提供する Rust コンポーネントです。
概要
STARK 証明の検証は証明生成に比べれば計算コストが低い処理で、本システムではサーバー側で検証を行い、その結果をレポートとしてクライアントに提供します(委任の理由と信頼境界は サーバー側検証の信頼境界 を参照)。
flowchart LR
subgraph 入力
RCP[レシート / バンドル]
EID["期待 Image ID"]
end
RCP --> VS[検証サービス]
EID --> VS
VS --> RPT[検証レポート]
検証フロー
検証サービスは、次の手順でレシートを検証します。
flowchart TD
START[レシート / バンドル読み込み] --> FORMAT{入力形式<br/>の判定}
FORMAT -->|フラット JSON| F1[直接パース]
FORMAT -->|ネスト JSON| F2[receipt フィールドを抽出]
FORMAT -->|ディレクトリ| F3[receipt.json または<br/>*-receipt.json を探索]
FORMAT -->|ZIP アーカイブ| F4[末尾が receipt.json のファイルを探索]
F1 --> EXTRACT[Image ID 抽出]
F2 --> EXTRACT
F3 --> EXTRACT
F4 --> EXTRACT
EXTRACT --> MODE[InnerReceipt を判定<br/>Fake は dev_mode 候補として記録]
MODE --> PRESENT{メタデータ image_id<br/>が存在?}
PRESENT -->|欠落 + 非 Fake| FAIL0[failed]
PRESENT -->|欠落 + Fake| VERIFY
PRESENT -->|存在| MATCH{メタデータ Image ID<br/>= 期待 Image ID ?}
MATCH -->|不一致| FAIL1[failed:<br/>Image ID 不一致]
MATCH -->|一致| VERIFY["Receipt::verify(expected_image_id)<br/>STARK 検証実行"]
VERIFY -->|成功 かつ Fake| DEVMODE[dev_mode]
VERIFY -->|失敗 かつ Fake + InvalidProof| DEVMODE
VERIFY -->|成功 かつ 非 Fake| SUCCESS[success]
VERIFY -->|失敗(その他)| FAIL2[failed]
入力形式の解決
検証サービスは、単一のレシートファイルだけでなく、レシートを含むバンドルディレクトリや ZIP にも対応しています。
image_id はラッパーの top-level フィールドであり、レシート本体の内部フィールドではありません。
同期 finalization 経路では proof bundle ディレクトリ全体を渡し、その中の receipt.json を解決します。
| 形式 | 説明 |
|---|---|
| フラット JSON | レシートオブジェクトが直接 JSON のトップレベルにある |
| ネスト JSON | { "receipt": {...}, "image_id": "0x..." } 構造 |
| ディレクトリ | receipt.json または *-receipt.json を探索して読み込む |
| ZIP アーカイブ | エントリ名の末尾が receipt.json のファイルを探索して読み込む |
Image ID 照合と Fake receipt の扱い
ラッパーの image_id は、開発モード生成を示す Fake 型(InnerReceipt)でも期待値との一致が必須であり、不一致なら failed として即時拒否します。
image_id が欠落した場合は、非 Fake 型は failed になり、Fake 型だけが Receipt::verify まで進んで結果に応じて dev_mode または failed に振り分けられます(分岐の全体は上のフローチャートを参照)。
Image ID の管理は Image ID を参照してください。
STARK 検証の実行
top-level の Image ID 照合に成功した後、または Fake 型で image_id が欠落している場合に、RISC Zero SDK の Receipt::verify(expected_image_id) でレシートを検証します。
検証成功は、次の内容を保証します。
- レシートに含まれる seal(証明データ)が有効
- ジャーナルが指定 Image ID のゲスト実行結果である
- 証明生成後にレシートが改ざんされていない
検証レポート
検証サービスは、検証が最後まで到達した試行について JSON レポートを出力します。 exit code とレポート出力の関係は次のとおりです。
| 状況 | exit code | JSON レポート |
|---|---|---|
success | 0 | stdout または --output |
| 引数不正、bundle 不在など | 1 | 出力しない |
dev_mode | 2 | stdout または --output |
failed | 3 | stdout または --output |
呼び出し側は exit code とレポートの両方を見ます。
--quiet を指定すると stdout 出力は抑制されます。
その場合は --output も併せて指定し、レポートを保存します。
| フィールド | 型 | 説明 |
|---|---|---|
| status | 列挙型 | success / failed / dev_mode |
| verifier_version | 文字列 | verifier-service のバージョン |
| verified_at | 文字列 | RFC 3339 形式の検証完了時刻 |
| duration_ms | 数値 | 検証処理時間(ミリ秒) |
| expected_image_id | 文字列 | 検証に使用した期待 Image ID |
| receipt_image_id | 文字列? | 入力 JSON の top-level image_id から抽出した値 |
| bundle_path | 文字列 | 入力 bundle パスの basename のみ |
| receipt_path | 文字列 | 解決されたレシートファイル名の basename のみ |
| dev_mode_receipt | 真偽値 | Fake receipt なら true。status とは別に、入力 receipt の生の種別を示す診断信号として使う |
| errors | 文字列[] | 診断文字列の配列。空の場合は省略される |
errors は固定のエラーコード一覧ではなく、実装が積む自由形式の診断文字列です。
ステータスの意味づけ
| ステータス | 意味 |
|---|---|
success | STARK 検証が成功し、Image ID も一致 |
failed | Image ID 不一致または STARK 検証失敗 |
dev_mode | 開発モードのフェイクレシート |
各ステータスが最終表示に与える影響は ゲーティングロジック > STARK 検証のゲーティング を参照してください。
デプロイメントモデル
検証サービス(Rust バイナリ verifier-service)は、呼び出し経路ごとに実行場所が異なります。
呼び出しパターン
検証サービスの呼び出しは 3 分類です。 明示的検証はいずれも、サーバー側で保持している finalization result に紐付いた 権威ある bundle locator だけを使います。 クライアントが任意の S3 キーや local パスを指定し、検証サービスに検証させることはできません。
| パターン | トリガー | 説明 |
|---|---|---|
| 同期実行 | 同期 finalization (POST /api/sessions/:sessionId/finalizations) | real executor 時のみ実行。mock executor 時は verifier-service を呼ばず dev_mode 扱いとして帰る |
| target S3 実行 | クライアントが検証を要求 | POST /api/sessions/:sessionId/finalizations/:finalizationId/verification が検証 work を SQS に積み、verification-worker が後続で処理する |
| trusted local 実行 | クライアントが検証を要求 | 信頼済み local bundle を API サーバープロセス内で直接検証する |
S3 artifact backend は target profile 専用で、API が verification-worker Lambda
を同期 invoke する non-target S3 経路や backend fallback はありません。
非同期 finalization のコールバック Lambda は、結果の復元と保存を担当します。
STARK 検証は自動実行されず、POST /api/sessions/:sessionId/finalizations/:finalizationId/verification で実行します。
target AWS runtime での流れは次のとおりです。
- この POST は
verifier-serviceの完了を待たず、verificationResult.status=runningを保存して SQS work を発行する verification-workerが SQS event を受け取り、S3 bundle を検査・展開してverifier-serviceを実行する- 検証が完了した場合は、
verification.jsonの report locator と report を含む terminalverificationResultを finalization-scoped な独立 record としてセッションストアへ保存する - S3 の取得、bundle の検査、
verifier-serviceの起動、artifact の upload などの infrastructure failure は SQS で再試行する - 3 回目の受信でも失敗した場合は terminal
failedと internal-only のfailureCategoryを保存する。この終端失敗には verifier report がないため、report locator も保存しない
既存の verificationResult.status ごとの POST /api/sessions/:sessionId/finalizations/:finalizationId/verification の挙動は次のとおりです。
| 既存 status | POST の挙動 |
|---|---|
success / failed / dev_mode(終端) | 再検証せず idempotent な応答を返す |
running | 実行中として idempotent に扱う。target AWS runtime で queue marker が未保存なら同じ finalization の SQS work を補修発行する |
未設定 / not_run | 新しい検証実行または検証 work の enqueue に進む |
実行シーケンス(補足)
次のシーケンス図は、上記 3 分類の実行経路を補足するものです。
sequenceDiagram
participant C as クライアント
participant API as API サーバー
participant Q as verification-work SQS
participant RUNNER as verification-worker Lambda
participant VS as verifier-service バイナリ
participant S3 as S3
participant STORE as セッションストア
C->>API: POST /api/sessions/:sessionId/finalizations/:finalizationId/verification
API->>API: session capability と finalization result を確認
alt target AWS runtime + S3 bundle locator がある
API->>STORE: verificationResult を running に更新
API->>Q: 検証 work を送信(recordType, sessionId, finalizationId, queuedAtMs, bundleKey, expectedImageId)
API-->>C: running
Q-->>RUNNER: SQS event
RUNNER->>S3: bundle.zip を取得・展開
RUNNER->>VS: bundle ディレクトリ + 期待 Image ID + reportPath
VS->>VS: STARK 検証実行 + verification.json 書き出し
VS-->>RUNNER: 検証レポート
RUNNER->>S3: public bundle.zip / verification.json / sidecar を保存
RUNNER->>STORE: report locator と terminal verificationResult を保存
else 信頼済み local bundle がある
API->>VS: bundle ディレクトリ + 期待 Image ID + reportPath
VS->>VS: STARK 検証実行 + verification.json 書き出し
VS-->>API: 検証レポート
API->>STORE: verificationResult / execution 状態を更新
API-->>C: 検証結果
end
検証パイプラインにおける役割
検証サービスは、4 段階検証モデルの最終段階である STARK 検証を担当します。
| チェック ID | 検証内容 |
|---|---|
stark_image_id_match | レシートに記録された Image ID が期待値と一致するか |
stark_receipt_verify | STARK 証明が暗号学的に有効であるか |
stark_image_id_match は、verifier report の expected_image_id と receipt_image_id が一致することを検証します。
検証パイプラインはさらに、claimed 側および comparison 側の Image ID とも整合することを確認します。
これらのチェックが両方成功した場合に限り、「STARK Verified」のステータスが付与されます。 これは STARK 検証段階のステータスであり、全体の Verified 判定とは区別されます。 詳細は 4 段階検証モデル を参照してください。
セキュリティ上の考慮事項
サーバー側検証の信頼境界
検証サービスはサーバー側で実行されるため、クライアントはサーバーの検証結果を信頼する必要があります。 この PoC における信頼モデルは次のとおりです。
- STARK 証明自体は秘密データを含まない検証データ: レシートと Image ID があれば、第三者が独立に検証可能
- 検証サービスは利便性のための委任: ブラウザ上で RISC Zero の検証ロジックを実行することは現時点では実用的でないため、サーバー側で検証する。実用的になれば、クライアント側のみで完結させることも理論上は可能
- 配布対象アーカイブ: レシートと
public-input.jsonは ZIP ローカル検証(Ubuntu) の手順で独立検証できる
verification.json の非公開性
verification.json は bundle.zip に含めず、必要時のみ capability 保護の report エンドポイントで配布します(境界は 公開境界)。
第三者検証では、レシートファイルを直接使った独立検証が推奨されます。