お断り: 本記事は C2PA Technical Specification v2.3(2026年4月時点)と Guidance for Implementers v2.4c2pa-pythonAdobe Trustmark のソースコードおよび公開ドキュメントを筆者が読解して整理したものです。動作確認は c2pa-python 0.37.7(c2pa-rs 0.90.14)・c2patool 0.28.0・trustmark 0.9.1 で行っています。Soft Binding は仕様で算法(algorithm)レジストリが拡張され続けている領域であり、SDK の対応状況も変化します。実装や設計判断の根拠として用いる際は、必ずC2PA 公式仕様c2pa-org/softbinding-algorithm-list ・各ライブラリの最新ドキュメントをご確認ください。本記事に誤りや古くなった箇所を見つけられた場合は、記事末尾のフィードバック枠よりお知らせいただけると助かります。

はじめに

本記事は、シリーズ「C2PA 実装入門」 の応用編・ソフトバインディング編です。前編にあたるハードバインディング実装 では、c2pa-rs が c2pa.hash.data を自動付与してバイト単位の完全一致を保証する仕組みと、1 バイトの改変で assertion.dataHash.mismatch が検出される挙動を確認しました。

Hard Binding はバイナリの改ざん検知において極めて強力である一方、JPEG の再圧縮や SNS プラットフォーム投稿に伴うメタデータ剥離によって検証が容易に破綻するという実用上の限界を抱えています。この課題を補完するのが Soft Binding です。本記事では、C2PA 公認のソフトバインディングアルゴリズムレジストリに正式登録されている Adobe Trustmark を用い、画像へ不可視透かしを埋め込みつつ、同一の識別子を c2pa.soft-binding Assertion として Manifest に記録するパイプラインを Python によるハンズオンで構築します。

本記事で組み立てるパイプラインは、C2PA 仕様の別文書 C2PA Soft Binding API (Decoupled) で規定されている Manifest Recovery のフローを、com.adobe.trustmark.Q という具体的なアルゴリズムで実装したものになります。とくに Section 1.2.1.1 “Watermarking algorithms” で描かれている「Manifest が欠落した asset から不可視透かしを抽出し、soft binding algorithm list と resolution API を辿って active manifest を復元する」フローを参考設計とし、本記事では手を動かしていきます。

透かし埋め込みから検証までの流れ

本記事のハンズオンは次の順序で進めます。最初に Trustmark で画像に payload(短い識別子)を焼き付け、その透かし入り画像に対して c2pa-python で c2pa.soft-binding assertion を持つ Manifest を付与します。検証側は、Manifest に記録された value と画像から取り出した透かしの payload を突き合わせて、Manifest Recovery が成立するかを確かめる、という流れです。

flowchart TD A(["1. 元画像"]) B(["2. 透かし埋め込み(Trustmark)"]) C(["3. c2pa-python で署名"]) D(["4. 配信"]) E(["5. 検証 / Manifest Recovery"]) A --> B --> C -.-> D -.-> E

処理シーケンスにおいて最も重要な原則は、「不可視透かしを埋め込んだ後に、C2PA の暗号署名を実行する」という順序の徹底です。Trustmark は画像画素のピクセル値を微小に変更するため、署名後に透かしを付与すると Hard Binding(c2pa.hash.data)のハッシュが不一致となり即座に検証エラーとなります。透かしをあらかじめ焼き付けた画像データに対して Manifest を付与することで、Hard Binding と Soft Binding の双方が同時に成立する真正なアセットを生成できます。

この順序は、後半の Manifest Repository の設計にも効いてきます。透かしから payload を取り出してレジストリを引いた先に置いておくべき Manifest は、透かしを入れる前のものではなく、透かしを入れた後のアセットを説明する Manifest です。透かし前のハッシュを持つ Manifest を登録してしまうと、復元しても配布されている画像と c2pa.hash.data が合わず、復元する意味が失われます。Guidance for Implementers Section 4.2.4 も、透かしを入れて Manifest に記録したあとのものを指して「その Manifest は、作成から透かしの適用までを含む来歴を説明する」と書いています。

That C2PA Manifest describes the provenance of the video from creation up to and including the watermark being applied.

すでに署名済みのアセットに後から透かしを入れたい場合は、透かしを入れた時点で既存 Manifest のハードバインディングが無効になるので、元の Manifest を ingredient(parentOf)に持つ新しい Manifest で署名し直すことになります。Soft Binding API の UC1 が “signing the asset with a further manifest” と書いているのがこのパターンです。いずれの経路でも、レジストリに載るのは透かし入りアセットの active manifest です。

ソフトバインディング assertion の構造

ソフトバインディングは、対応するアルゴリズム(alg)と、コンテンツから抽出した識別子(指紋や透かし)を c2pa.soft-binding assertion として Manifest に積みます。assertion のラベルはハイフン区切りの c2pa.soft-binding で、構造は仕様書 Section 18.10 “Soft Binding” の CDDL で定義されています。

フィールド役割
algソフトバインディングアルゴリズムの識別子(ICANN ドメイン形式の名前を仕様が推奨)
blocksアルゴリズムが算出した識別子のリスト。各エントリは scopevalue を持つ(どちらも必須)
nameこの binding が何を覆っているかを示す人間可読の説明(任意)
alg-paramsアルゴリズム固有のパラメータ(任意)。アンダースコアではなくハイフン
bindingMetadata実装者や連絡先などの補足メタデータ(任意)。description フィールドはこの中に入る
url非推奨。asset reference assertion に置き換えられたので新規に書いてはいけない

blocks[].scope に入れられるのは timespan(音声・動画の時間範囲)と region(画像の領域)で、以前あった extent は非推奨です。画像全体を覆う透かしのように絞り込む対象がない場合は、空オブジェクト {} を渡します。省略はできず、scope ごと落とすと Error: claim could not be converted from CBOR になって Manifest が読めなくなります。

仕様書(Section 9.3.2 “Referenced List of Soft Binding Algorithms”)では、alg の選び方について次のように書かれています。

Soft bindings are generated by an algorithm named in the alg field of the soft binding assertion. The algorithm name should be among those algorithms listed in the soft binding algorithm list as supported by this specification.

登録済みアルゴリズムの一覧は c2pa-org/softbinding-algorithm-list に JSON で管理されています。本記事ではその中から、Adobe が公開している透かし方式 Adobe Trustmarkalg = com.adobe.trustmark.Q)を使います。OSS 実装が pip で入る、画像への不可視透かし埋め込みから抽出まで Python で完結する、というあたりがハンズオンにちょうどいいです。

Trustmark で透かしを埋め込む

第5回で使った uv で Python プロジェクトを立ち上げます。Trustmark は PyTorch に依存するので、インストールには少し時間がかかります。

cd /tmp
mkdir -p c2pa-soft-binding && cd c2pa-soft-binding
uv init .
# Trustmark は Python 3.10〜3.12 に対応。uv の requires-python を合わせる
# uv init が書く既定値はバージョンによって変わるので、行ごと置き換える
sed -i '' -E 's/^requires-python = .*/requires-python = ">=3.10,<3.13"/' pyproject.toml
uv python pin 3.11
uv add trustmark c2pa-python

# サンプル画像と c2pa-rs のテスト用証明書をダウンロード
curl -sL -o input.jpg https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/earth_apollo17.jpg
curl -sL -o test_cert.pem https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/certs/es256.pub
curl -sL -o test_key.pem https://raw.githubusercontent.com/contentauth/c2pa-rs/main/sdk/tests/fixtures/certs/es256.pem

# 以降のステップで作成する Python スクリプトを先に用意しておく
touch embed_watermark.py sign_soft_binding.py recover_manifest.py

この時点でプロジェクトはこんな構成になっています(.venv__pycache__ は省略)。

c2pa-soft-binding/
├── embed_watermark.py
├── input.jpg
├── main.py
├── pyproject.toml
├── README.md
├── recover_manifest.py
├── sign_soft_binding.py
├── test_cert.pem
├── test_key.pem
└── uv.lock

main.pyREADME.mduv init が自動生成したもので、本記事では使いません。作成済みの embed_watermark.py sign_soft_binding.py recover_manifest.py に順番に中身を書いていきます。

透かしと payload の関係

本稿における電子透かしの埋め込みとは、「人間の視覚特性では知覚できない微細な変調を画素データに加え、任意のペイロード(短い識別文字列)を画像バイナリ自体に直接織り込む」処理を指します。Adobe Trustmark では、事前学習済みのディープニューラルネットワークがエンコーダおよびデコーダとして機能し、元画像の視覚的品質を損なうことなくペイロードを埋め込み、また透かし入り画像から高い堅牢性をもってペイロードを復元します。仕組みの詳細は Adobe Trustmark の README および ICCV 2025 採録論文 を参照してください。

payload は画像に結びつけたい任意の短い識別子です。内容そのものに来歴情報を詰め込むのではなく、「この画像は TT0001 として登録されているもの」というラベルだけを物理的に焼き付ける役割で、C2PA soft binding の文脈では後述のとおり Manifest を引くためのキーとして使います。Trustmark Q バリアントには英数字 7 文字くらいしか入らないので、本記事では TT0001 という最小限のダミー ID を使っています(TT は TechThanks の TT です)。C2PA のソフトバインディングレジストリには softBindingResolutionApis フィールドを持つアルゴリズムが登録されていて、画像から取り出した payload を解決 API に渡し、それに対応する Manifest を引き当てる設計が想定されています(例: com.aiwatermark.pixelseal.1、登録エントリは c2pa-org/softbinding-algorithm-list を参照)。

透かしはハードバインディングのバイト単位ハッシュとは違って、JPEG 再エンコードやリサイズみたいな「見た目がほぼ同じままの変換」であれば生き残るよう設計されています。おかげで、Manifest ごとメタデータが剥がれた配信物からでも、画像から payload を抽出 → 外部の Manifest Repository に問い合わせ、という経路で来歴に辿り着けます。

実装

Trustmark の Q バリアントで、短い識別子 TT0001 を埋め込みます。

# embed_watermark.py
from PIL import Image
from trustmark import TrustMark

tm = TrustMark(verbose=False, model_type="Q")

payload = "TT0001"  # Q variant の payload は英数字 7文字程度が実用上の上限
cover = Image.open("input.jpg").convert("RGB")
encoded = tm.encode(cover, payload, MODE="text")
encoded.save("watermarked.png")
print(f"埋め込み完了: payload='{payload}' -> watermarked.png")

decoded, detected, version = tm.decode(Image.open("watermarked.png"), MODE="text")
print(f"抽出結果: detected={detected} version={version} payload='{decoded}'")

tm.decode()(payload, detected, version) の 3 要素を返します。detected は透かしの復号に成功したかを示す bool で、判定はこの bool 一発です(確信度のような連続値は出てきません)。初回実行時は Trustmark のモデルファイルのフェッチが走ります。

uv run python embed_watermark.py
# => 埋め込み完了: payload='TT0001' -> watermarked.png
# => 抽出結果: detected=True version=1 payload='TT0001'

detected=True で payload が一致していて、透かし自体はちゃんと成立しています。次はこの画像に C2PA Manifest を付与して、c2pa.soft-binding assertion として同じ payload を残していきます。

透かしを入れた事実をアクションとして残す

C2PA 仕様において、Manifest 内に Soft Binding Assertion を記述するだけでは規格適合として不十分です。「このアセットに対して不可視透かしを埋め込んだ」という編集行為そのものを、Actions Assertion(c2pa.actions.v2)として明示的に記録することが仕様上義務付けられています。

C2PA 2.3 で透かし関連のアクションが細分化され、現在は次の 3 つが定義されています。

アクション意味
c2pa.watermarked2.2 で追加、2.3 で非推奨。claim generator は書いてはいけない
c2pa.watermarked.boundソフトバインディングを作る目的で不可視透かしを挿入した
c2pa.watermarked.unboundソフトバインディングを作らずに不可視透かしを挿入した

本記事のように payload を Manifest から引けるようにする場合は c2pa.watermarked.bound です。仕様書 Section 18.15.5 “Watermarking” は、このアクションと soft binding assertion をセットで置くことを求めています。

When using a c2pa.watermarked.bound action, a soft binding assertion shall also be included in the C2PA Manifest to describe the inserted watermark.

Guidance for Implementers Section 4.2.6 側はさらに踏み込んで、逆向き(透かしを入れたならアクションを書く)も must と書いています。

A c2pa.watermarked.bound action must be added to the C2PA Manifest to signal that an invisible watermark was inserted into the digital content for the purpose of creating a soft binding.

C2PA 仕様では検証側に対してもこの対応関係の照合が規定されており、c2pa.watermarked.bound アクションが存在するにもかかわらず対応する c2pa.soft-binding Assertion が存在しない場合、assertion.action.softBindingMissing エラーとして Claim 全体が棄却(Reject)される必要があります。執筆時点の c2pa-rs 0.90.14 においては一部のチェックロジックが未実装であるものの、将来的な相互運用性や適合性審査を担保するためには、仕様に厳密に準拠した Assertion の構成が不可欠です。

さらに C2PA 2.4 では、アクションから対応する assertion を parameters.relatedAssertions で名指しすることが推奨に加わりました。次のコードではこれも入れています。

c2pa-python で soft-binding assertion を記録する

# sign_soft_binding.py
import base64
import json

import c2pa

with open("test_cert.pem", "rb") as f:
    cert = f.read()
with open("test_key.pem", "rb") as f:
    key = f.read()

signer_info = c2pa.C2paSignerInfo(
    "es256", cert, key, b"http://timestamp.digicert.com"
)
signer = c2pa.Signer.from_info(signer_info)

payload = "TT0001"
payload_b64 = base64.b64encode(payload.encode("utf-8")).decode("ascii")

manifest_json = json.dumps({
    "title": "soft_binding_demo.png",
    "claim_generator_info": [{
        "name": "TechThanksSoftBindingDemo",
        "version": "0.1.0",
    }],
    "assertions": [
        {
            "label": "c2pa.actions.v2",
            "data": {
                "actions": [
                    {
                        "action": "c2pa.created",
                        "digitalSourceType": "http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture",
                    },
                    {
                        "action": "c2pa.watermarked.bound",
                        "softwareAgent": {"name": "Adobe Trustmark", "version": "0.9.1"},
                        "parameters": {
                            "relatedAssertions": [
                                {"url": "self#jumbf=c2pa.assertions/c2pa.soft-binding"}
                            ]
                        },
                    },
                ],
            },
            "created": True,
        },
        {
            "label": "c2pa.soft-binding",
            "data": {
                "alg": "com.adobe.trustmark.Q",
                "name": "Adobe Trustmark variant Q invisible watermark",
                "blocks": [
                    {
                        "scope": {},
                        "value": payload_b64,
                    }
                ],
            },
        },
    ],
})

builder = c2pa.Builder(manifest_json)
builder.sign_file("watermarked.png", "output.png", signer)
print("署名完了: output.png")
rm -f output.png
uv run python sign_soft_binding.py
# => 署名完了: output.png

c2patool output.png で Manifest を覗くと、Trustmark で埋め込んだ payload が c2pa.soft-binding としてきっちり記録されているのが見えます。

c2patool output.png | jq '.manifests[].assertions[] | select(.label == "c2pa.soft-binding")'
{
  "label": "c2pa.soft-binding",
  "data": {
    "alg": "com.adobe.trustmark.Q",
    "blocks": [
      {
        "scope": {},
        "value": "VFQwMDAx"
      }
    ],
    "name": "Adobe Trustmark variant Q invisible watermark"
  }
}

アクション側も見ておきます。

c2patool output.png | jq -c '.manifests[].assertions[] | select(.label == "c2pa.actions.v2") | .data.actions'
[
  {"action":"c2pa.created","digitalSourceType":"http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture"},
  {"action":"c2pa.watermarked.bound","softwareAgent":{"name":"Adobe Trustmark","version":"0.9.1"},"parameters":{"relatedAssertions":[{"url":"self#jumbf=c2pa.assertions/c2pa.soft-binding"}]}}
]

valueVFQwMDAx は Base64 で TT0001 を表します。

echo VFQwMDAx | base64 -d
# => TT0001

画像(透かし)と Manifest(soft-binding の value)で同じ識別子が持てていることが分かります。

余談: payload はハードコードでよいか

本記事のサンプルでは埋め込みと署名の両方で payload = "TT0001" をハードコードしていますが、設計としては「watermarked.png を Trustmark で decode し、その結果を c2pa.soft-binding の value に入れる」方が筋がいいと思っています。ソフトバインディングの本質は「画像から取り出せる payload に対して Manifest が紐づく」関係なので、画像側を真の値とみなす順序のほうが定義に沿います。実用上も、Trustmark の容量を超えた payload を渡すと黙って末尾が切られる挙動があるため、署名前に decode 結果と一致しているか確認しておくと不整合事故を防げます。一方、埋め込みと署名を同一プロセスで一気通貫に処理し、payload が容量内であることが事前にわかっているパイプラインなら、ハードコード(あるいは変数で持ち回す)でも問題ありません。Trustmark の decode は決して軽い処理ではない(モデル推論が走る)ため、整合性が確保されている前提なら省ける場面では省いた方が現実的、というのも実装上の判断としてあり得ます。ワークロードに応じて選んでいただければと思います。

検証側はアルゴリズム名をレジストリと照合する

ここで一度、署名した画像を検証にかけてみます。

c2patool output.png | jq -c '.validation_results.activeManifest.failure[] | {code, explanation}'
{"code":"signingCredential.untrusted","explanation":"signing certificate untrusted"}
{"code":"algorithm.unsupported","explanation":"soft binding algorithm 'com.adobe.trustmark.Q' is not in the C2PA soft binding algorithm registry"}

signingCredential.untrusted は c2pa-rs のテスト証明書を使っているので想定どおりですが、その下の algorithm.unsupported は初見だと戸惑います。com.adobe.trustmark.Q は 2024年5月に登録済み(identifier 4)で、レジストリにちゃんと載っているからです。

この判定は c2pa-rs の仕様照合動作によるものです。C2PA 仕様書 Section 9.3.2 では「alg は公式レジストリに登録されたアルゴリズム識別子でなければならない」と規定されており、c2pa-rs もこの検証を実装しています。しかし、照合対象となるアルゴリズム一覧は SDK のバイナリ内部に静的同梱されておらず、外部設定(Settings)として検証エンジンに注入する設計となっています。型定義にも記載されている通り、未設定の状態では未知のアルゴリズムとして algorithm.unsupported が出力されます。

公式リストを取得して設定ファイルを生成します。

curl -sL -o softbinding-algorithm-list.json \
  https://raw.githubusercontent.com/c2pa-org/softbinding-algorithm-list/main/softbinding-algorithm-list.json

python3 -c '
import json
algs = [e["alg"] for e in json.load(open("softbinding-algorithm-list.json")) if not e.get("deprecated")]
json.dump({"version": 1, "soft_binding": {"soft_binding_algorithms": algs}}, open("c2pa-settings.json", "w"), indent=2)
print(f"{len(algs)} 件のアルゴリズムを設定に書き出しました")
'
# => 53 件のアルゴリズムを設定に書き出しました

version は数値(整数型)です。文字列型で "1.0.0" 等と指定すると invalid type: string "1.0.0", expected u32 としてパースエラーになります。生成した設定ファイルを指定して再検証します。

c2patool --settings c2pa-settings.json output.png | jq -c '.validation_results.activeManifest.failure[] | {code, explanation}'
{"code":"signingCredential.untrusted","explanation":"signing certificate untrusted"}

algorithm.unsupported が解消され、期待通りの検証結果となりました。

なお、このアルゴリズム照合は Assertion ラベルが厳密に c2pa.soft-binding(ハイフン区切り)である場合にのみ実行されます。仮にアンダースコアを用いて c2pa.soft_binding と記述した場合、署名および検証はエラーを出さずに通過しますが、それは仕様適合したからではなく、検証系が単なる未知のカスタム Assertion として無視したためです。不整合が静かに見過ごされるリスクがあるため、ラベル名のタイポには細心の注意が必要です。

Manifest Recovery をシミュレートする

Soft Binding の真価は、「Manifest が剥離され Hard Binding が破綻したコンテンツから、元の真正な来歴を再発見・復元できる」点にあります。ここでは、SNS プラットフォーム等への投稿によって画像が JPEG に再圧縮され、JUMBF メタデータが完全に除去されたシナリオを想定し、そのアセットから Manifest を復元する End-to-End の処理を検証します。

処理の流れは以下の通りです。

  1. 元の output.png から Manifest を抽出し、c2pa.soft-binding の payload をキーとして「Manifest Repository」へ登録
  2. output.png を JPEG 形式で再エンコードし、Manifest(JUMBF)を意図的に除去した tampered.jpg を生成
  3. c2patool tampered.jpg により、メタデータが完全に失われていることを確認
  4. 画像画素に不可視透かしとして焼き込まれた payload を、Trustmark デコーダで抽出
  5. 抽出した payload をキーに Manifest Repository を照会し、元の真正な Manifest を復元

本番運用において Manifest Repository は Web API やキーバリューストアとして構築されますが、本検証では Python のインメモリ辞書(dict)を用いてその振る舞いを模倣します。

# recover_manifest.py
import base64
import json
import subprocess

from PIL import Image
from trustmark import TrustMark


# --- 簡易 Manifest Repository(本番環境では KVS や Web API となる) ---
MANIFEST_REPOSITORY: dict[str, dict] = {}


def repository_register(payload: str, manifest: dict) -> None:
    MANIFEST_REPOSITORY[payload] = manifest


def repository_lookup(payload: str) -> dict | None:
    return MANIFEST_REPOSITORY.get(payload)


def read_manifest(path: str) -> dict | None:
    result = subprocess.run(
        ["c2patool", path], capture_output=True, text=True
    )
    if result.returncode != 0:
        return None
    return json.loads(result.stdout)


# --- 1) 元画像の Manifest を Repository に登録 ---
original = read_manifest("output.png")
assert original is not None, "output.png から Manifest を読めなかった"
active_id = original["active_manifest"]
sb = next(
    a for a in original["manifests"][active_id]["assertions"]
    if a["label"] == "c2pa.soft-binding"
)
payload_key = base64.b64decode(sb["data"]["blocks"][0]["value"]).decode("utf-8")
repository_register(payload_key, original["manifests"][active_id])
print(f"[1] Repository 登録: payload='{payload_key}'")

# --- 2) Manifest を剥がした画像を作る(JPEG 再エンコード) ---
Image.open("output.png").convert("RGB").save("tampered.jpg", "JPEG", quality=85)
print("[2] tampered.jpg を生成(JPEG 再エンコードで Manifest を除去)")

# --- 3) tampered.jpg に Manifest が残っていないことを確認 ---
tampered_manifest = read_manifest("tampered.jpg")
print(f"[3] tampered.jpg の Manifest: {'なし' if tampered_manifest is None else 'あり'}")

# --- 4) 画像から Trustmark で payload を抽出 ---
tm = TrustMark(verbose=False, model_type="Q")
extracted, detected, _ = tm.decode(Image.open("tampered.jpg"), MODE="text")
print(f"[4] tampered.jpg から payload を抽出: detected={detected} payload='{extracted}'")

# --- 5) Repository に問い合わせて Manifest を復元 ---
recovered = repository_lookup(extracted) if detected else None
if recovered is None:
    print("[5] NG: Repository から Manifest を復元できなかった")
else:
    print("[5] OK: Repository から Manifest を復元")
    print(f"    title           : {recovered['title']}")
    print(f"    claim_generator : {recovered['claim_generator_info'][0]['name']}")
    actions = next(
        a["data"]["actions"]
        for a in recovered["assertions"] if a["label"] == "c2pa.actions.v2"
    )
    print(f"    actions         : {[a['action'] for a in actions]}")
uv run python recover_manifest.py
# => [1] Repository 登録: payload='TT0001'
# => [2] tampered.jpg を生成(JPEG 再エンコードで Manifest を除去)
# => [3] tampered.jpg の Manifest: なし
# => [4] tampered.jpg から payload を抽出: detected=True payload='TT0001'
# => [5] OK: Repository から Manifest を復元
# =>     title           : soft_binding_demo.png
# =>     claim_generator : TechThanksSoftBindingDemo
# =>     actions         : ['c2pa.created', 'c2pa.watermarked.bound']

JPEG の再エンコードによって埋め込み Manifest(JUMBF コンテナ)は完全に消失し、c2patool 単体では Error: No claim found と判定されます。しかし、画像画素に刻まれた不可視透かしは維持されており、Trustmark デコーダによって抽出された payload をキーに Manifest Repository を照会することで、元の Manifest に記録されていたアセットタイトル、署名生成元情報、来歴アクション履歴を完全な形で復元できます。「アセットがメタデータを持たずに単体で流通した場合であっても、視覚的特徴量から原本の真正な来歴へと遡航できる」という Soft Binding の核心的価値が、コードの実行結果として実証されました。

まとめ

C2PA の Hard Binding と Soft Binding は、二者択一ではなく相互補完の関係にあります。Hard Binding は「手元のバイナリが Manifest と完全一致する未改ざん原本であること」を数学的に保証し、Soft Binding は「不可避な圧縮やフォーマット変換を経た後でも来歴に再接続できる耐久性」を提供します。前者が SDK により自動処理されるのに対し、後者は業務要件や流通経路に応じた適切なアルゴリズム選定と Manifest Repository の設計判断が不可欠です。

本記事では、Adobe Trustmark を用いた不可視透かしの埋め込みから、c2pa-python による c2pa.soft-binding Assertion および c2pa.watermarked.bound アクションの付与、アルゴリズムレジストリ照合の設定、そしてメタデータ剥離後の Manifest Recovery の一連の挙動を実証しました。前編のハードバインディング実装 と併せて確認することで、実運用に耐えうる Content Credentials パイプラインの全体設計を描くことができるはずです。

TechThanks では、生成 AI 由来コンテンツやメディア配信における C2PA 導入の支援を行っています。Hard / Soft Binding の組み合わせ設計、Manifest Repository の構築、検証パイプラインの実装まで含めた相談がありましたら、お気軽にお問い合わせください。

TechThanks では、生成 AI 由来コンテンツやメディア配信における C2PA 導入の支援を行っています。Hard / Soft Binding の組み合わせ設計、Manifest Repository の構築、検証パイプラインの実装まで含めた相談がありましたら、お気軽にお問い合わせください。