文書ID: miura-verification-spec-v5
公開予定場所: /verification/spec/v5/
公開日: 2026-04-09 JST
ステータス:
v5 — 公開後は変更しない。改定時は v6 を新設する。
運営者: 有限会社三浦商店(宮城県黒川郡大和町)
本文書は、三浦商店が公開する施工事例記事と
/verification/ 配下の公開 artifact
の対応関係を、第三者が検証できるように記述する公開技術仕様書である。
v4 からの最大の変更点は次の3つである。
c2pa-proof/1 の artifacts に
c2pa_verification_jpeg_url を optional
キーとして追加する本文書は公開仕様であり、内部運用の全詳細や内部証拠束の構成は記述しない。
本仕様書の目的は、施工事例記事に対応する写真・動画の公開 artifact、ハッシュ連鎖、OpenTimestamps(OTS)による時刻証明、ならびに C2PA 由来の provenance disclosure を、第三者が再現可能な形で示すことである。
本仕様書は以下に適用される。
https://miurast.com/jutaku/
配下で公開される施工事例記事/verification/jobs/{JOB_ID}/
配下の公開 artifact(verification JPEG を含む)photo-proof/1、c2pa-proof/1、BlogPosting
JSON-LD、必要時 video-proof以下は本仕様書の範囲外とする。
本文書中の MUST / MUST NOT / SHOULD / SHOULD NOT / MAY は RFC 2119 的な規範語として用いる。
photo-proof/1 と manifest.json v2 は
拡張しないbundle_manifest.json
から引く_miura_job_id を起点に
render-time injection する一度公開したら変更しないファイル群。ハッシュ連鎖および OTS 整合の対象となる。
本仕様での canonical artifact:
bundle_manifest.jsonmanifest.jsonvideo_proof_public.json(動画案件のみ)公開検証を補助するが canonical root ではない公開 artifact。
例:
{JOB_ID}.bundle_manifest.json.ots{JOB_ID}.bundle_manifest.json.onchain_hinted.jsongoogle_ca.pemc2pa-proof/1(HTML 内 render object)photo-proof/1(HTML 内 render object)BlogPosting JSON-LD案件を識別する文字列。一般形は次のとおり。
{YYYY-MM-DD}_{description}_{suffix}
例: 2026-03-28_oil-waterheater_upload
WordPress 側で JOB_ID を保持する post meta key。canonical は
_miura_job_id。
HTTP 取得またはローカル保存されたファイルの正確なバイト列。改行コード、インデント、空白、文字コード変換を含め、1 バイトでも変われば別物とみなす。
公開対象として残った写真集合。C2PA internal 検証結果全件ではなく、公開 artifact に載る集合を指す。
validation_status_publicC2PA 公開表示用の簡約 enum。
validmissinginvalidunsupportedphoto-proof/1manifest.json v2 から render-time に組み立てる画像検証用
render object。Miura 独自の公開 JSON であり、canonical artifact
ではない。
c2pa-proof/1bundle_manifest.json の c2pa_provenance と
bundle_core.source_assets[] から render-time
に組み立てる公開 provenance disclosure object。Miura 独自の公開 JSON
であり、標準 C2PA Manifest そのものではない。
c2pa_provenancebundle_manifest.json の top-level に置かれる C2PA job
summary。bundle_core
の外側にあり、bundle_chain_hash
の計算対象外だが、bundle_manifest.json 全体に対する OTS
stamp の対象には含まれる。
Route V 対象案件において、C2PA 署名検証を第三者が独立に実行できるよう
/verification/jobs/{JOB_ID}/
配下に公開される撮影原本 JPEG。以下「verification JPEG」と表記する(初出時は「verification JPEG(撮影原本 JPEG)」と併記)。canonical artifact
ではなく auxiliary artifact である。miura-chain /
bundle_chain_hash の計算対象に含まれない。案件あたり
0〜1 枚。
本システムの公開アーキテクチャは、写真系 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 に対する時刻証明
[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
bundle_chain_hashbundle_chain_hash は bundle_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 の計算対象に
含まれる。
c2pa_provenance
の位置づけc2pa_provenance は bundle_core の
外側にあるため、bundle_chain_hash
の計算対象には 含まれない。
ただし bundle_manifest.json 全体の exact bytes に対して OTS
receipt が発行されるため、c2pa_provenance の値は OTS
の時刻証明対象に 含まれる。
次の整合確認は、すべて exact bytes に対して行う。
bundle_core.photo.manifest_sha256bundle_core.video.proof_sha256(動画案件のみ)bundle_manifest.jsonverification 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 を含まない。
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 ← 任意
manifest.json(画像-only 正本)schema は
miura-photo-manifest-public/2、schema_version=2
とする。
schemaschema_versionjob_idverification_idchain_algochain_hashimage_countimagesimages[] 必須キーseqlabelurl_or_relsha256widthheightshot_atdevicemanifest.json v2 には public C2PA
フィールドを追加しないbundle_manifest.jsonbundle_manifest.json は案件全体の canonical root
であり、OTS receipt の対象とする。
bundle_core.photobundle_core.video(動画案件のみ)bundle_core.source_assets[](C2PA 対応案件のみ)bundle_chain_algobundle_chain_hashc2pa_provenance(C2PA 対応案件のみ)video_proof_public.json動画案件に限り存在する canonical artifact。動画の詳細スキーマは本仕様書では簡略記載に留める。
v5 では C2PA 公開統合を Phase 1(Route V
を含む)まで正式化する。
Phase 1 の公開面は次の 4 点で構成される。
bundle_core.source_assets[]c2pa_provenancec2pa-proof/1 render-time injectionbundle_core.source_assets[]bundle_core.source_assets[] は C2PA の公開最小版
provenance 接続である。
seqsource_asset_sha256provenance_modeorigin_classvalidation_status_publicverification_summary_sha256bundle_core の中に置くbundle_chain_hash の計算対象に含むc2pa_enabled=False 相当の案件ではキー不在とする[] は出さないc2pa_provenancec2pa_provenance は公開 bundle 単体で trust anchor
の所在と job summary を self-describing にする。
job_provenance_summarytrust_anchorsjob_provenance_summary
必須キーasset_count_totalasset_count_c2pa_valid_camera_captureasset_count_c2pa_valid_noncaptureasset_count_c2pa_valid_unknownasset_count_c2pa_missingasset_count_c2pa_invalidasset_count_c2pa_unsupportedjob_modetrust_anchors 必須キーpem_url_or_reltrust_anchors_sha256tsa_trust_anchors_sha256bundle_core の外側に置くbundle_chain_hash の計算対象にしないbundle_manifest.json 全体の OTS
対象には含まれるsource_assets[] が不在なら c2pa_provenance
も不在としてよいvalidation_status_public の意味valid : C2PA manifest が存在し、署名検証に合格missing : C2PA manifest が存在しないinvalid : C2PA manifest が存在するが検証失敗unsupported : 対象形式または検証条件が非対応job_modefull : public に残った写真がすべて
validmixed : valid と missing
が混在公開案件では、invalid は通常 published subset
に乗らない。
したがって public 側で job_mode="mixed"
を確認したい場合は、通常 valid + missing
の組み合わせになる。
published subset がすべて missing の場合、または unsupported を 1 件でも含む場合は、§11.3 fail-closed に従い c2pa_provenance および c2pa-proof/1 を出力しない。
過去 job の canonical artifact は書き換えない。
pre-C2PA job や C2PA 非対応 job は、photo-proof/1 と
BlogPosting JSON-LD
を出し続けてもよいが、c2pa-proof/1 は出さない。
C2PA Phase 1 では撮影原本 JPEG
を非公開としていたため、第三者が C2PA
署名検証を独立に再現できなかった。Route V
は、条件を満たす代表写真 1 枚の撮影原本 JPEG(verification JPEG)を検証用として公開し、第三者が
c2patool trust
等で独立に署名検証を実行できるようにする。
以下の すべて を満たす写真から、seq 最小の 1 枚を自動選択する(手動指定も可能):
.jpg / .jpeg)であるmanifest_presence = present)、内部検証で valid(status = valid)origin_class が camera_capture条件を満たす写真がない場合、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
bundle_chain_hash の計算対象に 含まれない(§5.5 参照)miura-chain 連鎖に 参加しないc2pa_provenance 内に verification_jpeg_rel
を optional で追加する。記録されるのは相対 URL
のみであり、verification JPEG の SHA-256 は
bundle_manifest.json の c2pa_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 の状態遷移detected — JPEG が選定・配置されたが公開後検証未実施valid — 公開後に SHA-256 照合と c2patool trust
の両方に合格内部 raw manifest の verification_jpeg.c2pa_status
に記録される。公開面では
c2pa-proof/1.artifacts.c2pa_verification_jpeg_url
の有無で判断できる。
注: c2pa_status(detected / valid)は
verification JPEG の公開後検証状態であり、source_assets[].validation_status_public
とは異なる概念である。後者は撮影原本に対する内部 C2PA
検証の公開簡約値であり、Route V の公開後 trust 検証とは別の工程で判定される。
内部 raw manifest の verification_jpeg ブロックには、enabled、seq、filename、sha256、origin_class、c2pa_status、selection 等のキーが記録される。enabled = false の場合はこのキーのみ存在する。詳細なスキーマ定義は内部仕様の範囲であり、本仕様書では公開面(c2pa_verification_jpeg_url の有無)のみを定義する。
Route V の公開後 trust 検証(SHA-256 照合または
c2patool trust)が不合格の場合、c2pa_status
は detected のまま維持される。この場合
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
は出力されないため、ディレクトリリスティングが有効だとファイルが意図せず発見可能になる。
verification JPEG(撮影原本 JPEG)は EXIF サニタイズを行わずにそのまま公開する。これは撮影原本としての完全性と C2PA 署名検証の前提を維持するためである。GPS 情報を含む写真は Route V 対象外とするが、GPS 以外の EXIF メタデータ(撮影日時、カメラ機種等)は残る場合がある(§12.1 参照)。現行の対応機種(Google Pixel 10 Pro)については、公開前にカメラシリアル番号・操作者個人情報等の個人識別子が含まれないことを棚卸しにより確認している。
編集・生成の対象は本文 HTML(body)であり、verification JSON や
BlogPosting JSON-LD を毎回手書きしない。
最終レンダリング HTML では WordPress / function が
_miura_job_id を起点に公開検証 artifacts を読み、必要な
render object を注入する。
写真がある案件では、最終レンダリング HTML に少なくとも次が存在しなければならない。
photo-proof/1BlogPosting JSON-LDC2PA 対応案件では追加で次が存在しなければならない。
c2pa-proof/1動画案件では必要に応じて次を追加してよい。
video-proof最終レンダリング HTML では、verification 系 script tag
を論理的にひとまとまりとして出力してよい。
ただし 相対順序自体は semantic contract
としない。意味上重要なのは、各 object が 1 回ずつ存在し、内容が
canonical artifact と整合することである。
photo-proof/1photo-proof/1 は manifest.json v2 から
render-time に組み立てる。
versionactorverification_idchain_algochain_hashimagesimages[] 必須キーseqlabelurlsha256shot_atdevicec2pa-proof/1c2pa-proof/1 は bundle_manifest.json から
render-time に組み立てる Miura 独自の public disclosure object
とする。
次の両方を満たすときのみ出力する。
bundle_manifest.json に c2pa_provenance
が存在するbundle_core.source_assets[] が空でないどちらかが欠ける場合、c2pa-proof/1 は出力しない。
<script type="application/json"
class="c2pa-proof"
data-miura-managed="1"
data-actor="c2pa-proof"
data-version="c2pa-proof/1">
{ ... }
</script>versionactorjob_idartifactsjob_provenance_summarytrust_anchorsimagesartifacts 必須キーbundle_manifest_urlmanifest_urlots_urlartifacts optional キーc2pa_verification_jpeg_url — Route V
対象案件で、verification JPEG(撮影原本 JPEG)の公開後 trust
検証に合格した場合のみ出力する。合格しない場合はキー自体を省略する(後方互換性維持)。images[] 必須キーseqsource_asset_sha256origin_classprovenance_modevalidation_status_publicverification_summary_sha256images[] optional キーpublished_asset_sha256 — 公開 AVIF の SHA-256。manifest.json.images[].sha256 および photo-proof/1.images[].sha256 と同一の値。source_asset_sha256(撮影原本)から published_asset_sha256(公開画像)への対応を、この JSON 内で閉じるための補助フィールドである。manifest.json と bundle_core.photo.manifest_sha256 の hash 照合に成功した場合のみ出力される。照合に失敗した場合は null になる。c2pa-proof/1 の意味c2pa-proof/1 は 標準 C2PA manifest
の代替物ではない。
これは、Miura の公開 bundle に記録された C2PA Phase 1 情報を、記事 HTML
から機械可読に参照できるようにする disclosure object である。
HTML に注入する JSON script は、</script>
を安全にエスケープしなければならない。
第三者は以下の手順で検証できる。
photo-proof/1、BlogPosting JSON-LD、必要時
c2pa-proof/1 を抽出するc2pa-proof/1 がある場合は job_id と
artifacts を読むbundle_manifest.jsonmanifest.json{JOB_ID}.bundle_manifest.json.otsgoogle_ca.pemvideo_proof_public.jsonc2pa-proof/1.artifacts.c2pa_verification_jpeg_url
から verification JPEG を取得manifest.json の exact bytes の SHA-256 を計算するbundle_core.photo.manifest_sha256
と一致することを確認するmanifest.json.images[].sha256 と照合する(SHOULD)bundle_core に JSON 正規化(§5.2 と同じ方式)を適用するbundle_chain_hash と照合するbundle_manifest.json の exact bytes と
.ots receipt を用意するc2pa-proof/1 がある場合:
c2pa-proof/1.job_provenance_summary と
bundle_manifest.json.c2pa_provenance.job_provenance_summary
が整合することc2pa-proof/1.images[] と
bundle_core.source_assets[] の seq
集合が整合することtrust_anchors.pem_url_or_rel で指された PEM の SHA-256
が、公開された trust_anchors_sha256 と一致することpublished_asset_sha256 がある場合、photo-proof/1.images[] の同一 seq の sha256 と一致すること(MAY)c2pa_verification_jpeg_url がある場合(Route V 対象案件):
c2pa-proof/1.images[] の対応 seq の source_asset_sha256 と照合する(SHOULD)c2patool trust --trust_anchors google_ca.pem で C2PA 署名検証を独立に実行する(MAY — 最も強い検証)validation_state が Trusted であることを確認するこれらを合わせることで、公開後の差し替え困難性と 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 を参照。
photo-proof/1 : 出力BlogPosting JSON-LD : 出力c2pa-proof/1 : 出力しないphoto-proof/1 : 出力BlogPosting JSON-LD : 出力c2pa-proof/1 : 出力c2pa_verification_jpeg_url : Route V 条件を満たし、かつ公開後 trust 検証に合格した場合のみ artifacts に追加出力する次のようなケースでは c2pa-proof/1 を public
非出力に落としてよい。
source_assets[] が不在ただし、PEM 不在や hash 契約違反のような公開直前の致命条件は、生成工程側では hard fail とするのが望ましい。
Route V の fail-closed:
Route V の trust 検証失敗は non-fatal とし、c2pa_verification_jpeg_url
を省略することで安全側に倒す。canonical artifact の整合性が維持される限り、案件全体の公開を停止する必要はない。
public artifact および render object に次を含めてはならない。
verification JPEG には GPS 以外の EXIF メタデータが残る場合がある。ただし operator 個人情報やカメラ固有の個人識別子を含む場合は Route V 対象外とする。
C2PA 情報を表示または公開する際は、「真正であると断定する UI」ではなく、「Content Credentials / provenance 情報があることを示し、利用者が判断できる材料を出す UI」を採るべきである。
BlogPosting JSON-LDBlogPosting は SEO / structured data のための object
であり、photo-proof や c2pa-proof と意味が異なる。
identifier 系の連携は整合必須だが、BlogPosting は canonical
artifact ではない。
Phase 2A の c2pa_derivative_provenance、AVIF / MP4
sidecar、durable discovery は v5 の範囲外とする。
v5 では Route V(撮影原本 JPEG の検証用公開)により、代表写真 1 枚について第三者が C2PA 署名検証を独立に実行できるようになった。Phase 2A の AVIF sidecar はこれとは異なるアプローチ(公開画像レベルでの来歴証明)であり、将来版で別レーンとして追加し得る。
画像横の C2PA バッジ、一覧表、モーダル UI、tooltip は v5
の範囲外である。
v5 では machine-readable JSON の公開までを固定する。
photo-proof/1 / manifest.json v2 の C2PA
拡張v5 では行わない。
C2PA 公開 disclosure は c2pa-proof/1 と
bundle_manifest.json 側で扱う。
BlogPosting