三浦商店 施工事例検証システム 技術仕様書 v5

文書ID: miura-verification-spec-v5
公開予定場所: /verification/spec/v5/
公開日: 2026-04-09 JST
ステータス: v5 — 公開後は変更しない。改定時は v6 を新設する。
運営者: 有限会社三浦商店(宮城県黒川郡大和町)


0. 本文書の位置づけ

本文書は、三浦商店が公開する施工事例記事と /verification/ 配下の公開 artifact の対応関係を、第三者が検証できるように記述する公開技術仕様書である。

v4 からの最大の変更点は次の3つである。

  1. Route V(verification JPEG 公開レーン)を公開契約として正式化する
  2. c2pa-proof/1artifactsc2pa_verification_jpeg_url を optional キーとして追加する
  3. 第三者検証手順に Route V JPEG を用いた独立 C2PA 検証を追加する

本文書は公開仕様であり、内部運用の全詳細や内部証拠束の構成は記述しない。


1. 目的と適用範囲

1.1 目的

本仕様書の目的は、施工事例記事に対応する写真・動画の公開 artifact、ハッシュ連鎖、OpenTimestamps(OTS)による時刻証明、ならびに C2PA 由来の provenance disclosure を、第三者が再現可能な形で示すことである。

1.2 適用範囲

本仕様書は以下に適用される。

1.3 本仕様書が記述しないもの

以下は本仕様書の範囲外とする。

1.4 規範語

本文書中の MUST / MUST NOT / SHOULD / SHOULD NOT / MAY は RFC 2119 的な規範語として用いる。


2. バージョン方針と不変原則

2.1 不変原則

2.2 v5 の設計原則


3. 用語定義

3.1 canonical artifact

一度公開したら変更しないファイル群。ハッシュ連鎖および OTS 整合の対象となる。

本仕様での canonical artifact:

3.2 auxiliary artifact

公開検証を補助するが canonical root ではない公開 artifact。

例:

3.3 JOB_ID

案件を識別する文字列。一般形は次のとおり。

{YYYY-MM-DD}_{description}_{suffix}

例: 2026-03-28_oil-waterheater_upload

3.4 WP_JOB_META_KEY

WordPress 側で JOB_ID を保持する post meta key。canonical は _miura_job_id

3.5 exact bytes

HTTP 取得またはローカル保存されたファイルの正確なバイト列。改行コード、インデント、空白、文字コード変換を含め、1 バイトでも変われば別物とみなす。

3.6 published subset

公開対象として残った写真集合。C2PA internal 検証結果全件ではなく、公開 artifact に載る集合を指す。

3.7 validation_status_public

C2PA 公開表示用の簡約 enum。

3.8 photo-proof/1

manifest.json v2 から render-time に組み立てる画像検証用 render object。Miura 独自の公開 JSON であり、canonical artifact ではない。

3.9 c2pa-proof/1

bundle_manifest.jsonc2pa_provenancebundle_core.source_assets[] から render-time に組み立てる公開 provenance disclosure object。Miura 独自の公開 JSON であり、標準 C2PA Manifest そのものではない

3.10 c2pa_provenance

bundle_manifest.json の top-level に置かれる C2PA job summary。bundle_core の外側にあり、bundle_chain_hash の計算対象外だが、bundle_manifest.json 全体に対する OTS stamp の対象には含まれる。

3.11 verification JPEG

Route V 対象案件において、C2PA 署名検証を第三者が独立に実行できるよう /verification/jobs/{JOB_ID}/ 配下に公開される撮影原本 JPEG。以下「verification JPEG」と表記する(初出時は「verification JPEG(撮影原本 JPEG)」と併記)。canonical artifact ではなく auxiliary artifact である。miura-chain / bundle_chain_hash の計算対象に含まれない。案件あたり 0〜1 枚。


4. 公開アーキテクチャ概要

本システムの公開アーキテクチャは、写真系 canonical artifact、bundle root、OTS receipt、記事 HTML への render-time injection の 4 層から成る。

[施工事例記事 HTML]
  └─ render-time injection
      ├─ photo-proof/1
      ├─ c2pa-proof/1   (C2PA 対応案件のみ)
      ├─ BlogPosting JSON-LD
      └─ video-proof     (動画案件のみ)

[verification/jobs/{JOB_ID}/bundle_manifest.json]   ← canonical root
  ├─ bundle_core.photo.manifest_sha256
  ├─ bundle_core.source_assets[]                    ← C2PA public minimal lane
  ├─ bundle_chain_hash
  └─ c2pa_provenance                               ← C2PA job summary lane
      └─ verification_jpeg_rel (optional)          ← Route V URL 参照

[verification/jobs/{JOB_ID}/manifest.json]         ← canonical photo artifact
  └─ images[].sha256                               ← 公開画像ごとの SHA-256

[verification/jobs/{JOB_ID}/{seq}_{desc}_{label}.jpg]  ← auxiliary (Route V)
  └─ 撮影原本 JPEG(GPS 情報なし・C2PA valid・camera_capture)

[verification/ots/{JOB_ID}.bundle_manifest.json.ots]
  └─ bundle_manifest.json の exact bytes に対する時刻証明

5. ハッシュ連鎖と時刻証明

5.1 基本連鎖

[Bitcoin blockchain]
    ↑ OTS receipt が証明
[bundle_manifest.json]
    ├─ bundle_core.photo.manifest_sha256 = SHA-256(manifest.json の exact bytes)
    ├─ bundle_core.photo.chain_hash
    ├─ bundle_core.source_assets[]       = C2PA public minimal lane
    ├─ c2pa_provenance                   = C2PA job summary lane
    └─ bundle_chain_hash                 = SHA-256(normalize(bundle_core))
[manifest.json]
    └─ images[].sha256                   = 各公開画像ファイルの SHA-256

5.2 bundle_chain_hash

bundle_chain_hashbundle_core に JSON 正規化(sort_keys + compact separators による決定論的シリアライズ。RFC 8785 を参考にした方式)を適用した結果の SHA-256 である。

第三者が検証する際の擬似コード(Python 3):

import json, hashlib
payload = json.dumps(bundle_core, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")
bundle_chain_hash = hashlib.sha256(payload).hexdigest()

注: RFC 8785 (JCS) の Number 正規化は適用しない。上記の Python 標準 json.dumps の出力が正規形である。

したがって bundle_core.source_assets[]bundle_chain_hash の計算対象に 含まれる

5.3 c2pa_provenance の位置づけ

c2pa_provenancebundle_core外側にあるため、bundle_chain_hash の計算対象には 含まれない
ただし bundle_manifest.json 全体の exact bytes に対して OTS receipt が発行されるため、c2pa_provenance の値は OTS の時刻証明対象に 含まれる

5.4 exact bytes 原則

次の整合確認は、すべて exact bytes に対して行う。

5.5 verification JPEG の chain 非参加

verification JPEG は auxiliary artifact であり、bundle_chain_hash直接の 計算対象には含まれない。

ただし verification JPEG として公開される JPEG は Route V 対象 seq の撮影原本そのものであるため、その SHA-256 は bundle_core.source_assets[].source_asset_sha256 の該当 seq 値と等しい。source_assets[]bundle_core 内にあり bundle_chain_hash の計算対象に含まれるため、verification JPEG の SHA-256 は bundle_core.source_assets[seq=N].source_asset_sha256 を経由して間接的に OTS の時刻証明対象に含まれる。

c2pa_provenance.verification_jpeg_rel は URL パス参照のみであり、それ自体には SHA-256 を含まない。


6. 公開ディレクトリ構造

https://miurast.com/verification/
├── spec/
│   ├── v1/ ... v4/
│   └── v5/                            ← 本仕様書
├── spec/workflow-v3/                  ← 公開ワークフローノート v3
├── jobs/
│   └── {JOB_ID}/
│       ├── bundle_manifest.json       ← canonical
│       ├── manifest.json              ← canonical
│       ├── google_ca.pem              ← trust anchor disclosure 用 PEM
│       ├── {seq}_{desc}_{label}.jpg   ← verification JPEG(Route V 対象案件のみ)
│       ├── video_proof_public.json    ← canonical(動画案件のみ)
│       └── video_display_public.json  ← auxiliary(動画案件のみ)
└── ots/
    ├── {JOB_ID}.bundle_manifest.json.ots
    └── {JOB_ID}.bundle_manifest.json.onchain_hinted.json   ← 任意

7. canonical artifact 仕様

7.1 manifest.json(画像-only 正本)

schema は miura-photo-manifest-public/2schema_version=2 とする。

top-level 必須キー

images[] 必須キー

重要契約

7.2 bundle_manifest.json

bundle_manifest.json は案件全体の canonical root であり、OTS receipt の対象とする。

最低限の論理構造

7.3 video_proof_public.json

動画案件に限り存在する canonical artifact。動画の詳細スキーマは本仕様書では簡略記載に留める。


8. C2PA Phase 1 公開統合

8.1 基本方針

v5 では C2PA 公開統合を Phase 1(Route V を含む)まで正式化する。
Phase 1 の公開面は次の 4 点で構成される。

  1. bundle_core.source_assets[]
  2. top-level c2pa_provenance
  3. 記事 HTML への c2pa-proof/1 render-time injection
  4. Route V: verification JPEG の公開(§8.7)

8.2 bundle_core.source_assets[]

bundle_core.source_assets[] は C2PA の公開最小版 provenance 接続である。

1 entry の必須キー

契約

8.3 top-level c2pa_provenance

c2pa_provenance は公開 bundle 単体で trust anchor の所在と job summary を self-describing にする。

必須キー

job_provenance_summary 必須キー

trust_anchors 必須キー

契約

8.4 validation_status_public の意味

8.5 job_mode

公開案件では、invalid は通常 published subset に乗らない。
したがって public 側で job_mode="mixed" を確認したい場合は、通常 valid + missing の組み合わせになる。

published subset がすべて missing の場合、または unsupported を 1 件でも含む場合は、§11.3 fail-closed に従い c2pa_provenance および c2pa-proof/1 を出力しない。

8.6 historical jobs

過去 job の canonical artifact は書き換えない。
pre-C2PA job や C2PA 非対応 job は、photo-proof/1BlogPosting JSON-LD を出し続けてもよいが、c2pa-proof/1 は出さない。

8.7 Route V — verification JPEG 公開レーン

目的

C2PA Phase 1 では撮影原本 JPEG を非公開としていたため、第三者が C2PA 署名検証を独立に再現できなかった。Route V は、条件を満たす代表写真 1 枚の撮影原本 JPEG(verification JPEG)を検証用として公開し、第三者が c2patool trust 等で独立に署名検証を実行できるようにする。

対象条件

以下の すべて を満たす写真から、seq 最小の 1 枚を自動選択する(手動指定も可能):

条件を満たす写真がない場合、Route V は無効(verification_jpeg.enabled = false)となる。

公開位置

/verification/jobs/{JOB_ID}/{seq}_{desc}_{label}.jpg

例: /verification/jobs/2026-04-08_gas-equipment_upload/01_gas-equipment_before.jpg

artifact としての位置づけ

bundle_manifest.json への記録

c2pa_provenance 内に verification_jpeg_rel を optional で追加する。記録されるのは相対 URL のみであり、verification JPEG の SHA-256 は bundle_manifest.jsonc2pa_provenance には直接含まれない。ただし verification JPEG は Route V 対象 seq の撮影原本そのものであるため、その SHA-256 は bundle_core.source_assets[].source_asset_sha256 の該当 seq 値と一致する(§5.5 参照):

"c2pa_provenance": {
    "job_provenance_summary": { ... },
    "trust_anchors": { ... },
    "verification_jpeg_rel": "/verification/jobs/{JOB_ID}/01_gas-equipment_before.jpg"
}

Route V 非対象案件ではこのキーは不在とする。

c2pa_status の状態遷移

  1. detected — JPEG が選定・配置されたが公開後検証未実施
  2. valid — 公開後に SHA-256 照合と c2patool trust の両方に合格

内部 raw manifest の verification_jpeg.c2pa_status に記録される。公開面では c2pa-proof/1.artifacts.c2pa_verification_jpeg_url の有無で判断できる。

注: c2pa_statusdetected / valid)は verification JPEG の公開後検証状態であり、source_assets[].validation_status_public とは異なる概念である。後者は撮影原本に対する内部 C2PA 検証の公開簡約値であり、Route V の公開後 trust 検証とは別の工程で判定される。

内部 raw manifest の verification_jpeg ブロックには、enabledseqfilenamesha256origin_classc2pa_statusselection 等のキーが記録される。enabled = false の場合はこのキーのみ存在する。詳細なスキーマ定義は内部仕様の範囲であり、本仕様書では公開面(c2pa_verification_jpeg_url の有無)のみを定義する。

trust 検証失敗時の扱い

Route V の公開後 trust 検証(SHA-256 照合または c2patool trust)が不合格の場合、c2pa_statusdetected のまま維持される。この場合 c2pa_verification_jpeg_url は出力されない。Route V は canonical artifact の整合性に影響しない補助レーンであり、trust 検証の失敗は non-fatal とする。

なお、実装は公開前段階でも c2patool trust を実行してよい。公開前検証で不合格となった場合、verification_jpeg_rel 自体を bundle_manifest.json に記録しないことで、OTS による永久固定を防ぐことができる。

運用前提として、/verification/jobs/ 配下のディレクトリリスティングは無効でなければならない。trust 検証に失敗した場合、verification JPEG の物理ファイルは残るが c2pa_verification_jpeg_url は出力されないため、ディレクトリリスティングが有効だとファイルが意図せず発見可能になる。

EXIF メタデータの取り扱い

verification JPEG(撮影原本 JPEG)は EXIF サニタイズを行わずにそのまま公開する。これは撮影原本としての完全性と C2PA 署名検証の前提を維持するためである。GPS 情報を含む写真は Route V 対象外とするが、GPS 以外の EXIF メタデータ(撮影日時、カメラ機種等)は残る場合がある(§12.1 参照)。現行の対応機種(Google Pixel 10 Pro)については、公開前にカメラシリアル番号・操作者個人情報等の個人識別子が含まれないことを棚卸しにより確認している。


9. render-time injection 契約

9.1 基本方針

編集・生成の対象は本文 HTML(body)であり、verification JSON や BlogPosting JSON-LD を毎回手書きしない。
最終レンダリング HTML では WordPress / function が _miura_job_id を起点に公開検証 artifacts を読み、必要な render object を注入する。

9.2 必須 render object

写真がある案件では、最終レンダリング HTML に少なくとも次が存在しなければならない。

C2PA 対応案件では追加で次が存在しなければならない。

動画案件では必要に応じて次を追加してよい。

9.3 verification artifact block

最終レンダリング HTML では、verification 系 script tag を論理的にひとまとまりとして出力してよい。
ただし 相対順序自体は semantic contract としない。意味上重要なのは、各 object が 1 回ずつ存在し、内容が canonical artifact と整合することである。

9.4 photo-proof/1

photo-proof/1manifest.json v2 から render-time に組み立てる。

top-level 必須キー

images[] 必須キー

9.5 c2pa-proof/1

c2pa-proof/1bundle_manifest.json から render-time に組み立てる Miura 独自の public disclosure object とする。

出力条件

次の両方を満たすときのみ出力する。

どちらかが欠ける場合、c2pa-proof/1 は出力しない。

HTML 形

<script type="application/json"
        class="c2pa-proof"
        data-miura-managed="1"
        data-actor="c2pa-proof"
        data-version="c2pa-proof/1">
{ ... }
</script>

top-level 必須キー

artifacts 必須キー

artifacts optional キー

images[] 必須キー

images[] optional キー

9.6 c2pa-proof/1 の意味

c2pa-proof/1標準 C2PA manifest の代替物ではない
これは、Miura の公開 bundle に記録された C2PA Phase 1 情報を、記事 HTML から機械可読に参照できるようにする disclosure object である。

9.7 script 安全性

HTML に注入する JSON script は、</script> を安全にエスケープしなければならない。


10. third-party verification procedure

第三者は以下の手順で検証できる。

10.1 記事 HTML の取得

  1. 施工事例ページ HTML を取得する
  2. photo-proof/1BlogPosting JSON-LD、必要時 c2pa-proof/1 を抽出する
  3. c2pa-proof/1 がある場合は job_idartifacts を読む

10.2 canonical artifact の取得

  1. bundle_manifest.json
  2. manifest.json
  3. {JOB_ID}.bundle_manifest.json.ots
  4. 必要に応じて google_ca.pem
  5. 動画案件では video_proof_public.json
  6. Route V 対象案件では、c2pa-proof/1.artifacts.c2pa_verification_jpeg_url から verification JPEG を取得

10.3 photo chain の確認

  1. manifest.json の exact bytes の SHA-256 を計算する
  2. bundle_core.photo.manifest_sha256 と一致することを確認する
  3. 公開画像ファイルの SHA-256 を再計算し、manifest.json.images[].sha256 と照合する(SHOULD)

10.4 bundle chain の確認

  1. bundle_core に JSON 正規化(§5.2 と同じ方式)を適用する
  2. SHA-256 を計算し、bundle_chain_hash と照合する

10.5 OTS の確認

  1. bundle_manifest.json の exact bytes と .ots receipt を用意する
  2. OTS client で verify する

10.6 C2PA disclosure の確認

c2pa-proof/1 がある場合:

  1. c2pa-proof/1.job_provenance_summarybundle_manifest.json.c2pa_provenance.job_provenance_summary が整合すること
  2. c2pa-proof/1.images[]bundle_core.source_assets[]seq 集合が整合すること
  3. trust_anchors.pem_url_or_rel で指された PEM の SHA-256 が、公開された trust_anchors_sha256 と一致すること
  4. published_asset_sha256 がある場合、photo-proof/1.images[] の同一 seqsha256 と一致すること(MAY)
  5. c2pa_verification_jpeg_url がある場合(Route V 対象案件):
    1. verification JPEG を取得し、SHA-256 を計算する
    2. c2pa-proof/1.images[] の対応 seq の source_asset_sha256 と照合する(SHOULD)
    3. c2patool trust --trust_anchors google_ca.pem で C2PA 署名検証を独立に実行する(MAY — 最も強い検証)
    4. validation_stateTrusted であることを確認する

10.7 検証結果の意味

これらを合わせることで、公開後の差し替え困難性と source provenance disclosure の両方を第三者が確認できる。

C2PA disclosure の検証限界について: 撮影原本 JPEG は通常、プライバシー保護のため非公開である。ただし Route V 対象案件では、条件を満たす代表写真 1 枚の撮影原本 JPEG(verification JPEG)を /verification/jobs/{JOB_ID}/ に検証用として公開しており、第三者はこの JPEG を用いて C2PA 署名検証を独立に実行できる。

Route V 非対象案件、および Route V 対象案件の代表写真以外については、従来どおり第三者が独立に C2PA 署名検証を再現することはできない。その場合も、disclosure の内容は bundle_manifest.json に記録され、その exact bytes は OTS で Bitcoin にアンカーされているため、disclosure の内容を事後的に改変することは困難である。

Route V と Phase 2A の関係については §13.1 を参照。


11. backward compatibility と fail-closed

11.1 pre-C2PA / non-C2PA 案件

11.2 C2PA 対応案件

11.3 public fail-closed

次のようなケースでは c2pa-proof/1 を public 非出力に落としてよい。

ただし、PEM 不在や hash 契約違反のような公開直前の致命条件は、生成工程側では hard fail とするのが望ましい。

Route V の fail-closed: Route V の trust 検証失敗は non-fatal とし、c2pa_verification_jpeg_url を省略することで安全側に倒す。canonical artifact の整合性が維持される限り、案件全体の公開を停止する必要はない。


12. セキュリティ・プライバシー・表現上の注意

12.1 公開禁止情報

public artifact および render object に次を含めてはならない。

verification JPEG には GPS 以外の EXIF メタデータが残る場合がある。ただし operator 個人情報やカメラ固有の個人識別子を含む場合は Route V 対象外とする。

12.2 C2PA の表現

C2PA 情報を表示または公開する際は、「真正であると断定する UI」ではなく、「Content Credentials / provenance 情報があることを示し、利用者が判断できる材料を出す UI」を採るべきである。

12.3 BlogPosting JSON-LD

BlogPosting は SEO / structured data のための object であり、photo-proof や c2pa-proof と意味が異なる。
identifier 系の連携は整合必須だが、BlogPosting は canonical artifact ではない。


13. out of scope / future extension

13.1 Phase 2A derivative provenance

Phase 2A の c2pa_derivative_provenance、AVIF / MP4 sidecar、durable discovery は v5 の範囲外とする。

v5 では Route V(撮影原本 JPEG の検証用公開)により、代表写真 1 枚について第三者が C2PA 署名検証を独立に実行できるようになった。Phase 2A の AVIF sidecar はこれとは異なるアプローチ(公開画像レベルでの来歴証明)であり、将来版で別レーンとして追加し得る。

13.2 visible badge / detail table

画像横の C2PA バッジ、一覧表、モーダル UI、tooltip は v5 の範囲外である。
v5 では machine-readable JSON の公開までを固定する。

13.3 photo-proof/1 / manifest.json v2 の C2PA 拡張

v5 では行わない。
C2PA 公開 disclosure は c2pa-proof/1bundle_manifest.json 側で扱う。


14. 公開適合チェックリスト

14.1 記事側

14.2 bundle / manifest 側

14.3 C2PA 側

14.4 Route V 側


15. informative references