Read the InvisMark soft-binding algorithm and its signed watermark id

Reachable c2pa.soft-binding assertions now surface their exact alg and the
bounded printable block value next to the normalized vendor label; a value
without its algorithm stays hidden because it cannot be attributed.
com.microsoft.invismark.1 uses that value as the pixel-watermark identifier
in Microsoft Paint output, so identify names it, metadata carries it, and an
InvisMark soft binding keeps the invisible-removal gate fail-safe even after
C2PA asset binding goes invalid. Content fingerprints still do not trigger
pixel regeneration. Removal is verified against Microsoft's Content
Provenance Detection API, which reports Watermark and C2PA separately; the
protocol and the pixel-identical control requirement are documented.

Implemented in a parallel session; verified, gated, and committed by pi.

pre-commit: 1) maintain.sh - exit 1 on the known uv-secure lightning PYSEC-2026-3624 triage (no fix available, unchanged from 0.29.0); ruff, pyright src/, and 1391 tests passed separately; 2) /simplify - single-pass, clean; 3) docs sync - five docs updated by the author session, no remaining references found; 4) CLAUDE.md - invariants recorded in module-internals, no change needed
This commit is contained in:
Victor Kuznetsov
2026-08-25 15:54:26 -07:00
parent 809d980fb7
commit 97cba11efe
10 changed files with 161 additions and 10 deletions
+16 -2
View File
@@ -145,6 +145,10 @@ _C2PA_CLOUD_CAVEAT = (
"It marks Content Credentials, not AI origin: the cloud manifest may describe a "
"human edit, and reading it needs a network fetch this tool does not make."
)
_SOFT_BINDING_CAVEAT = (
"Removing the embedded C2PA manifest does not remove its soft binding: the named "
"watermark or fingerprint may remain in the pixels and re-link the asset to provenance."
)
_SAMSUNG_GENAI_CAVEAT = (
"Samsung's genAIType marker shows a Galaxy AI editing tool (Generative Edit, "
"Sketch to Image, ...) touched the image; it is an undocumented proprietary "
@@ -388,6 +392,8 @@ def evidence_from_metadata_record(
"actions",
"synthid_watermark",
"soft_binding",
"soft_binding_algorithm",
"soft_binding_value",
):
if key in c2pa_info:
ai_metadata.setdefault(key, str(c2pa_info[key]))
@@ -1269,12 +1275,20 @@ def _identify_from_evidence(
# the watermark itself can't be decoded; names whose watermark stamped the pixels.
soft_binding = meta.get("soft_binding") or (", ".join(v) if (v := soft_binding_vendors_in(region)) else None)
if soft_binding:
soft_binding_algorithm = meta.get("soft_binding_algorithm") or info.get("soft_binding_algorithm")
soft_binding_value = meta.get("soft_binding_value") or info.get("soft_binding_value")
soft_binding_details = "; ".join(
str(value) for value in (soft_binding, soft_binding_algorithm, soft_binding_value) if value
)
signals.append(
Signal(
"soft_binding", f"C2PA soft binding: {soft_binding}", "high" if c2pa_level == "verified" else "medium"
"soft_binding",
f"C2PA soft binding: {soft_binding_details}",
"high" if c2pa_level == "verified" else "medium",
)
)
watermarks.append(f"Forensic watermark soft binding ({soft_binding})")
watermarks.append(f"Forensic watermark soft binding ({soft_binding_details})")
caveats.append(_SOFT_BINDING_CAVEAT)
# ── IPTC "Made with AI" (Meta etc.), only meaningful without C2PA ─
iptc = any(m in head for m in IPTC_AI_MARKERS)