お断り: 本記事は C2PA Technical Specification v2.3(2026年4月時点)と c2pa-rs(コミット 0eeabc7のソースコードを筆者が読解して整理したものです。仕様は継続的に更新されており、細部の記述や用語は変更される可能性があります。実装や設計判断の根拠として用いる際は、必ずC2PA 公式仕様および関連する一次資料をご確認ください。本記事に誤りや古くなった箇所を見つけられた場合は、記事末尾のフィードバック枠よりお知らせいただけると助かります。

はじめに

C2PA(Coalition for Content Provenance and Authenticity)はコンテンツの来歴をメタデータとして埋め込む標準仕様です。SDK を呼ぶだけでも来歴情報の付与・検証はできますが、ファイルの中に何がどんな構造で書き込まれているかを掴んでおくと、検証ポリシーの設計やトラブルシューティング、独自ワークフローへの組み込みがぐっと楽になります。

本記事は「C2PA 実装入門」シリーズの第3回です。第1回で「なぜ来歴証明が必要なのか」、第2回で「署名から検証までの全体フロー」を押さえたうえで、ここからは Manifest の内部に踏み込みます。Assertion・Claim・Claim Signature・JUMBF コンテナという 4 つのレイヤーの役割と関係を、概念レベルで押さえておきましょう。実際のファイルを c2patool で読み出して構造を確認するハンズオンは第4回で続けます。

登場人物と全体像

まずは概念レベルで、C2PA Manifest の中に何が入っているのかを並べておきます。

Manifest Store
└── Manifest
    ├── Assertion Store  (Assertion の実体の入れ物)
    │   ├── Assertion
    │   ├── Assertion
    │   └── ...
    ├── Claim            (Assertion への参照リスト+メタ情報)
    └── Claim Signature  (Claim に対する署名)

それぞれの登場人物の役割は、こんな感じで整理できます。

  • Manifest Store: 1 つのアセットに紐付く Manifest 全体の入れ物。ファイル(JPEG・PNG・MP4・PDF など)に埋め込まれる最上位の構造。
  • Manifest: 1 回の「このコンテンツに対する来歴宣言」をひとまとめにした単位。時系列で複数の Manifest が連なることもあり、そのうち最後に有効なものが active_manifest として示されます。
  • Assertion: 「いつ・誰が・何をしたか」といった個別の事実。撮影・編集操作・AI 学習可否宣言・作成者の身元情報など、粒度の細かいドキュメントがそれぞれ 1 つの Assertion になります。実データは Assertion Store に入ります。
  • Claim: Assertion の実データは持たず、代わりに Assertion への参照(hashed URI)をリストアップしたメタ文書。「どの Assertion を 1 つの束とみなすか」を決める役回りです。
  • Claim Signature: Claim に対する暗号署名と署名者の証明書チェーンを格納します。Claim 全体に対する信頼の起点ですね。

仕様書側でこの全体像を 1 枚で眺められる図として、C2PA Technical Specification v2.3 Chapter 12 “Entity Diagram”(Figure 11 “C2PA Entity Diagram”)が用意されています。Manifest Store・Manifest・Claim・Assertion・Signature の各要素と、それらがアセットや証明書チェーンとどう繋がっているかが 1 枚にまとまっているので、本記事のテキスト解説と行き来しながら眺めると位置関係が掴みやすいです。

C2PA Entity Diagram: Manifest Store・Manifest・Claim・Assertion・Signature とアセット・証明書チェーンの関係を示したクラス図
C2PA Technical Specification v2.3 Chapter 12「Entity Diagram」より Figure 11 "C2PA Entity Diagram"。一次資料はこちら

動画(BMFF)向けには 18.6.5 Fragmented BMFF Entity Diagram(Figure 15)という姉妹図もあります。

なぜこの4つのレイヤーに分けるのか

これから Manifest の内部を JUMBF コンテナ・Assertion・Claim・Claim Signature の 4 レイヤーに分けて見ていきますが、この切り分けは単なる整理術ではなく、C2PA が解こうとしている問題のレイヤー分担をそのまま映し取ったものです。それぞれの層が答えている問いが違います。

レイヤー担当する問い単位
JUMBF コンテナどうやってバイト列として運ぶか、どう addressing するか1つの「箱」(SuperBox)
Assertion何を主張するか個々の事実
Claimどの事実をひとまとめにして改ざん検知の対象範囲とするか1つの改ざん検知ユニット
Claim Signature誰がその塊を保証するか1つの署名行為

上から順に container / data / integrity / trust の 4 階層になっていて、下の層は上の層の責務を持ち込まない構造です。

  • JUMBF は ISO/IEC 19566-5 で標準化された汎用メタデータコンテナで、C2PA 固有のものではありません。C2PA は「バイト列の物理構造とアドレッシング」を JUMBF に丸投げすることで、自分では運搬形式を発明せずに済ませています。
  • Assertion は「個々の事実」で、追加・差し替え・個別検証が Assertion 単位でできます。生成 AI が書き出したという事実、EXIF の撮影情報、元素材のハッシュ、それぞれが別の Assertion として扱われます。
  • Claim は「どの Assertion をひとつの束とみなすか」を決めるメタドキュメントで、束にしたい Assertion のハッシュを自分の中にリストアップします。Claim を 1 回だけ署名すれば束の中身全部の改ざん検知が成立する、というのが Claim 層の存在意義です。
  • Claim Signature は「その Claim を誰が保証するか」だけに集中した層で、署名値と署名者証明書チェーンだけを持ちます。ここが独立しているおかげで、同じ Claim を別の主体が追認するような運用も原理的に成立します。

この切り分けが効いてくるのは、たとえば「Assertion だけ追加したい」「Claim はそのままで署名者だけ差し替えたい」といった操作をしたくなったときです。責務が混ざっていると難しい話も、層が分かれていれば部品単位で議論・実装できるようになります。

Assertion 個別の事実の積み上げ

Assertion は個別の事実を表す単位で、それぞれが独立した CBOR/JSON ドキュメントとして Assertion Store に放り込まれます。代表的なラベルは以下のあたりです。

  • c2pa.actions.v2 編集操作の履歴(一覧
  • c2pa.hash.data アセット本体のハッシュ(Hard Binding)
  • c2pa.thumbnail.claim 検証 UI 用のサムネイル
  • cawg.identity 作成者の身元情報(CAWG 拡張、Claim Signature とは独立した作成者署名を持つ)
  • cawg.training-mining AI 学習・推論での利用可否宣言
  • stds.exif / stds.iptc 撮影条件・メディアメタデータ

一度 Claim の一部に組み込まれた Assertion は書き換えられません。取り除きたい場合は Redaction という正式な手続きを通して、記録を残しつつ行います。

Claim Assertion を束ねて署名対象を作る

Claim は Manifest の中核になるメタ文書で、CBOR(Concise Binary Object Representation)でシリアライズされます。Claim が担う主な役割は 3 つです。

  1. Assertion Store に格納された個々の Assertion の内容を hashed URI でリストアップする
  2. 署名アルゴリズム、署名者情報、生成時刻などのメタデータを保持する
  3. アセット本体のハードバインディングを含めて、改ざん検知の対象範囲を確定する

Claim 自体が署名対象になるので、Claim の中に Assertion のハッシュを並べておけば、Claim を 1 回署名するだけで全 Assertion の改ざん検知が成立します。Merkle ツリーに似た発想ですが、深さ 1 の単純な構造で目的を果たせる設計です。

Claim v2 では、参照する Assertion のリストが created_assertions(署名者自身が責任を負うもの)と gathered_assertions(他の工程から引き継いだもの)の2 系統に分かれています。この区別は第4回c2patool の出力として実際に眺めていきます。

Hard Binding と Soft Binding

C2PA Manifest がアセット本体と紐づいていることを保証する仕組みが Binding です。

Hard Binding は c2pa.hash.data などの Assertion を通じて、アセットのバイナリそのもののハッシュを Claim に取り込む方法です。アセットが 1 ビットでも変わればハッシュが一致しなくなり、検証が失敗します。最も強い保証が得られる一方、再エンコードや軽微な編集にも容赦なく反応するので、配信経路でフォーマット変換が発生するシステムでは扱いに注意が要ります。

Soft Binding は知覚的ハッシュ(perceptual hash)やフィンガープリントを使って、「同一のコンテンツである」ことを緩やかに紐づけます。NSA ら 4 機関の 2025 年 1 月共同 CSI でも、Content Credentials の「耐久性(Durability)」を上げるために電子透かしやフィンガープリントと組み合わせるよう推奨されています。詳細はNSAら4機関がC2PA共同ガイダンスを公開 2025年1月CSIを読み解くを参照してください。

Claim Signature 信頼の起点

Claim Signature は COSE_Sign1(RFC 9052)形式で表される署名構造で、Claim の CBOR バイト列に対する署名と署名者の X.509 証明書チェーンを格納します。alg には C2PA が許容する署名アルゴリズムの識別子(Ps256, Es256, Ed25519 など)が入り、生成時には RFC 3161 タイムスタンプ局から得た署名時刻も付与できます。

C2PA は Web PKI とは別系統の信頼モデルを採用していて、C2PA Trust List に登録された認証局から発行された証明書が信頼の起点になります。検証側は証明書チェーンを Trust List に対して検証し、Claim 署名がそのチェーンで正当に行われていることを確認することで、Manifest 全体を信頼できる状態に置きます。

これによって「誰が署名したか」を追跡できるようにしつつ、必要に応じて失効リスト(CRL/OCSP)を通じて鍵漏えい時の影響範囲を絞れる枠組みになっています。また、CAWG の cawg.identity のように「作成者が自分の身元を Assertion の中で別途署名する」機構と組み合わせれば、Claim 署名者(パブリッシャー)と作成者(クリエイター)が別々の鍵で信頼を形成する運用も組めます。

JUMBF Manifest を運ぶ箱

ここまで見てきた Assertion / Claim / Claim Signature をバイト列として実際のファイルに埋め込んでいるのが、JUMBF(JPEG Universal Metadata Box Format)です。C2PA は独自のシリアライズ形式を新たに発明する代わりに、ISO/IEC 19566-5 で標準化された JUMBF をそのまま採用しています(仕様書 Section 11.1 “Use of JUMBF”)。JUMBF はもともと静止画向けに設計されたメタデータコンテナですが、C2PA ではアセット種別を問わない汎用コンテナとして使い倒しています。

どのファイルフォーマットでも JUMBF の中身(Manifest / Claim / Assertion の構造)は共通で、違うのは「その JUMBF をファイルのどこに置くか」だけです。フォーマットごとの埋め込み方法は仕様書の Appendix A “Embedding manifests” にまとまっています。JUMBF 内部のボックス構造と URI のアドレッシング方式は第4回で実データを見ながら確認します。

まとめと続編

C2PA Manifest は JUMBF というコンテナの上に Assertion・Claim・Claim Signature の 3 層を積み上げた構造です。仕様自体は重厚に見えますが、要素を分解してしまえば「個別の事実(Assertion)をハッシュ参照で束ねる(Claim)、その束に署名する(Claim Signature)、全体を運ぶ箱(JUMBF)」という素直なレイヤリングで成り立っているので、エンジニア視点では意外と読みやすい設計だと思います。

ここまでの構造が実際のファイルの中にどう現れるかを段階的に見たい方は、第4回 c2patool で Manifest を覗いてみるに進んでください。c2pa-rs 付属のテスト画像を c2patooljq で読み出しながら、本記事で扱った登場人物が JSON の中にそのまま現れる様子を追いかけて、最後に検証パイプライン設計の観点まで繋げていきます。

参考リンク


TechThanks は Content Credentials の実装支援に取り組んでいます。C2PA SDK の導入や検証パイプラインの設計についてお気軽にご相談ください。