バンドル構造
証明バンドルの構成、公開許可リスト、非公開アーティファクトの保護を解説します。同期モードと非同期モードの違いも含みます。
概要
証明バンドルは、zkVM の実行結果を検証可能な形で保存・配布するためのアーティファクト群です。バンドルには公開可能なファイルと非公開ファイルが含まれ、厳格な許可リストによって配布対象となるファイルが制御されます。
本書で public / 「公開可能」と記述する場合、秘密情報を含まず第三者検証に利用可能であるという機密性の分類を指します。無認証で誰でも取得できることは意味しません。アクセス経路の詳細は バンドルのアクセス方法 を参照してください。
flowchart TB
subgraph "バンドルディレクトリ"
subgraph "公開可能アーティファクト"
PI["public-input.json<br/>公開入力"]
EM["election-manifest.json<br/>選挙マニフェスト"]
CS["close-statement.json<br/>締切ステートメント"]
RC["receipt.json<br/>STARK レシート"]
JN["journal.json<br/>zkVM ジャーナル"]
MT["metadata.json<br/>メタデータ(syncのみ)"]
STH["sth.json<br/>STH スナップショット"]
CP["consistency-proof.json<br/>整合性証明"]
end
subgraph "非公開アーティファクト"
IN["input.json<br/>秘匿入力(ウィットネス)"]
VR["verification.json<br/>検証レポート"]
IB["included-bitmap.json<br/>厳密 counted bitmap"]
SB["seen-bitmap.json<br/>厳密 presented bitmap"]
end
BZ["bundle.zip<br/>配布対象アーカイブ"]
end
PI --> BZ
EM --> BZ
CS --> BZ
RC --> BZ
JN --> BZ
MT --> BZ
STH -.-> BZ
CP -.-> BZ
IN -.-x BZ
VR -.-x BZ
IB -.-x BZ
SB -.-x BZ
公開許可リスト
バンドルアーカイブ(bundle.zip)に含められるファイルは、許可リストによって厳格に制限されています。
公開可能なアーティファクト
| ファイル | 内容 | 用途 |
|---|---|---|
public-input.json | zkVM 検証に使う秘密データを含まない検証用レコード | 第三者が入力コミットメントを再計算するため |
election-manifest.json | 選挙設定の公開監査用スナップショット | 選挙設定と electionConfigHash の照合 |
close-statement.json | 集計締切時点のログ境界を表す公開監査レコード | logId / treeSize / bulletinRoot の照合 |
receipt.json | ホストが出力する { receipt, image_id } ラッパー JSON | 第三者がレシートを独立に検証するため |
journal.json | zkVM ゲストの公開出力(集計結果、除外情報、ビットマップルート等) | 集計結果と整合性データの確認 |
metadata.json | バンドルの作成日時、セッション ID、メソッドバージョン(sync のみ) | バンドルの来歴追跡 |
sth.json | 第三者 STH 検証のスナップショット(任意) | STH 合意の再現可能な証拠 |
consistency-proof.json | RFC 6962 整合性証明(任意) | 追記専用性の独立検証 |
sth.json と consistency-proof.json は許可リストに含まれますが、現行フローでは通常生成されません。
非公開アーティファクト
| ファイル | 内容 | 非公開の理由 |
|---|---|---|
input.json | zkVM への完全な入力(選択肢・乱数・コミットメント・Merkle パス等) | 投票の秘匿入力(ウィットネス)を含む |
verification.json | 検証サービスの詳細レポート | bundle.zip の許可リスト外(必要時は専用エンドポイントで参照) |
included-bitmap.json | 厳密な counted bitmap artifact | 個票 explainability 用の private artifact であり公開対象外 |
seen-bitmap.json | 厳密な presented bitmap artifact | 個票 explainability 用の private artifact であり公開対象外 |
input.json が公開されると投票の秘匿性が失われます。verification.json は必要時のみ専用の capability 保護エンドポイント経由で扱います。included-bitmap.json と seen-bitmap.json は /api/bitmap-proof の trusted source ですが、public bundle.zip には含めません。
公開入力の構造
public-input.json は、第三者検証に必要で、かつ選択肢と乱数を含まない入力側レコードです。input.json の単純なサブセットではありません。
| フィールド | 説明 |
|---|---|
schema | スキーマ識別子("stark-ballot.public_input") |
version | スキーマバージョン("1.0") |
electionId | 選挙 ID(UUID) |
electionConfigHash | 選挙設定のハッシュ |
bulletinRoot | 掲示板の最終ルートハッシュ |
treeSize | 掲示板のツリーサイズ |
totalExpected | 期待される投票数 |
logId | 掲示板ログ ID |
timestamp | 集計時のタイムスタンプ |
methodVersion | zkVM メソッドバージョン |
votes | 各投票のインデックス、コミットメント、Merkle パスの配列 |
votes 配列には各投票のインデックスとコミットメント、Merkle パスが含まれますが、選択肢と乱数は含まれません。これにより、入力コミットメントの再計算が可能でありながら、投票内容の秘匿性は維持されます。
public-input.json と inputCommitment は同一ではなく、後者が直接束縛するのはこのレコードの一部です。計算対象フィールドと非対象フィールドの整理は 入力コミットメント を参照してください。
同期バンドルと非同期バンドルの違い
証明生成には同期モード(ローカル実行)と非同期モード(ECS Fargate)の 2 つのパスがあり、生成されるバンドルの構成が異なります。
同期モード:
- ローカルプロセスでホストバイナリ実行
- TypeScript で全アーティファクト生成
- 検証サービスを呼び出し verification.json を保存
- 許可リストで bundle.zip を作成
非同期モード:
- ECS Fargate でホストバイナリ実行
- entrypoint.sh で公開可能アーティファクト生成
- bundle.zip を S3 にアップロード
- コールバック Lambda で結果をセッションに保存
両モードとも、public-input.json、election-manifest.json、close-statement.json は生成しただけでは採用されません。journal.json と正準な証明束縛データ(proof-bound data)に対する整合性検査を通過した場合にのみ bundle 化され、不一致があれば fail-closed(安全側に倒して)処理を中断します。
| 項目 | 同期モード | 非同期モード |
|---|---|---|
| 実行環境 | ローカルプロセス / Lambda | ECS Fargate コンテナ |
input.json | 生成される(非公開保存) | ワーク入力として S3 に置かれる(配布対象外) |
public-input.json | TypeScript で生成 | entrypoint.sh 内で生成 |
election-manifest.json | TypeScript で生成 | entrypoint.sh 内で生成 |
close-statement.json | TypeScript で生成 | entrypoint.sh 内で生成 |
journal.json | TypeScript で生成 | *-output.json から bundle.zip 用に生成 |
receipt.json | ホストの { receipt, image_id } 出力を保存 | *-receipt.json を receipt.json としてコピーして同梱 |
included-bitmap.json | 生成される場合は private に保持 | 生成される場合は隣接オブジェクト(sibling object)として保持 |
seen-bitmap.json | 生成される場合は private に保持 | 生成される場合は隣接オブジェクトとして保持 |
metadata.json | 生成される | 生成されない |
verification.json | 検証サービス呼び出し後に保存 | finalize コールバック時点では生成されない。後続の /api/verification/run で sibling object として追加されうる |
bundle.zip | 許可リストに基づき作成 | receipt.json / journal.json / public-input.json / election-manifest.json / close-statement.json を同梱して作成 |
| 保存先 | ローカルファイルシステム(+ 任意で S3) | S3 |
| presigned URL | S3 アップロード時に生成 | コールバック Lambda が生成 |
非同期バンドルの生成フロー
非同期モードでは、ECS Fargate コンテナの entrypoint.sh が以下の手順でバンドルを構築します。
- S3 から入力 JSON をダウンロード
- ホストバイナリを実行し、レシートと出力を生成
- 出力から
journal.jsonを変換生成 - 入力と出力から
public-input.json、election-manifest.json、close-statement.jsonを構築 journal.jsonとpublic-input.json/election-manifest.json/close-statement.jsonの整合性を検証し、ドリフトがあれば bundle 作成を中止receipt.json、journal.json、public-input.json、election-manifest.json、close-statement.jsonをbundle.zipにアーカイブ*-receipt.json/*-output.json/public-input.json/election-manifest.json/close-statement.json/included-bitmap.json/seen-bitmap.json/bundle.zipなどを S3 にアップロード
コールバック Lambda は S3 の bundle.zip からジャーナル、レシート、public-input.json、election-manifest.json、close-statement.json を復元します。利用可能な場合は隣接オブジェクトの bitmap artifact も取り込み、presigned URL の生成と監査用データの保存を行います。
バンドルディレクトリ構造
同期モード(ローカルファイルシステム)
{VERIFIER_WORK_DIR}/
{sessionId}/
{executionId}/
input.json ← 非公開: ウィットネス
public-input.json ← 公開可能
election-manifest.json ← 公開可能
close-statement.json ← 公開可能
journal.json ← 公開可能
receipt.json ← 公開可能
metadata.json ← 公開可能
included-bitmap.json ← 非公開: 厳密 counted bitmap artifact
seen-bitmap.json ← 非公開: 厳密 presented bitmap artifact
verification.json ← 非公開: 検証レポート
bundle.zip ← 配布対象: 許可リストファイルのアーカイブ
非同期モード(S3)
s3://{BUCKET}/sessions/{sessionId}/{executionId}/
input.json ← 非公開: ワーク入力
{inputBase}-receipt.json ← ホストの生出力
{inputBase}-output.json ← ホストの生出力
{inputBase}-journal.json ← ホストが生成した場合のみ
public-input.json ← 公開可能
election-manifest.json ← 公開可能
close-statement.json ← 公開可能
included-bitmap.json ← 非公開: 厳密 counted bitmap artifact
seen-bitmap.json ← 非公開: 厳密 presented bitmap artifact
bundle.zip ← 配布対象: 内部は receipt.json / journal.json / public-input.json / election-manifest.json / close-statement.json
verification.json ← `/api/verification/run` 後に追加される場合がある
inputBase はコンテナ実行時に生成される一時入力ファイル名に依存するため、非同期モードの S3 オブジェクト名は固定の receipt.json / journal.json になりません。
バンドルのアクセス方法
ダウンロードエンドポイント
| エンドポイント | 内容 |
|---|---|
GET /api/verification/bundles/:sessionId/:executionId | bundle.zip のダウンロード |
GET /api/verification/bundles/:sessionId/:executionId/report | verification.json の取得 |
両エンドポイントとも X-Session-Capability ヘッダーが必須です。つまり、ダウンロードは capability 保護 API から開始されます。
加えて、executionId はそのセッションで現在許可されている verificationExecutionId と一致しなければなりません。不一致や未設定の場合、API は 404 を返します。
S3 にアップロードされたバンドルは、必要に応じて API から presigned URL へリダイレクトして配布されます。presigned URL は有効期限付きであり、期限切れの場合はクライアントが /api/verify?refreshS3=1 で新しい URL を取得できます。
アーカイブの再現性
同期モード(verification-bundle.ts)の bundle.zip は再現性を確保するため、以下の措置を講じています。
- エントリのタイムスタンプをゼロに固定
- 許可リストに一致するファイルのみを含める
- ファイル名のアルファベット順でエントリを追加
非同期モード(docker/entrypoint.sh)は zip -r で作成され、上記の再現性制御とは実装が異なります。
セキュリティ上の制約
パストラバーサル防止
バンドルのパスセグメント(セッション ID、実行 ID)は英数字とハイフンのみに制限されています。.. を含むパスや許可されていない文字を含むパスは拒否されます。
非公開ファイルの保護
input.json、verification.json、included-bitmap.json、seen-bitmap.json は bundle.zip には含まれません。これらのファイルがバンドルディレクトリに存在していても、公開 bundle contract に含まれていないため、アーカイブ作成時に除外されます。