Skip to content

v0.2.0

Latest

Choose a tag to compare

@clemlesne clemlesne released this 09 Aug 09:51
· 4 commits to main since this release

What changed

v0.2.0 adds C2PA 2.4 validation for Annex A.8 text and changes the signed
manifest bytes from embed().

Upgrade: Existing v0.1.2 marks still verify; do not rewrite them. New
validation rules can change verdicts either way. Review the breaking changes
if you use EmbedContext, catch
MarkCorruptError, import resource-limit constants, or treat VALID as
proof of an AI disclosure.

pip install --upgrade c2patxt==0.2.0

c2patxt supports Python 3.10 through 3.14. Its base install depends on
cryptography~=48.0.

Breaking changes

  • Signed output: embed() moves padding from signed c2pa.hash.data to the
    unprotected COSE header. The A.8 wrapper version stays 1; the signed manifest
    bytes change.
  • Meaning of VALID: verify() may now return VALID without
    c2pa.ai-disclosure or digitalSourceType; it no longer checks modelType.
    embed() still writes all three. If your application requires
    an AI disclosure, check the authenticated assertions. VALID does not prove
    an AI disclosure.
  • Public API: MarkCorruptError(msg, document, pos, code) becomes
    MarkCorruptError(msg, pos, document_length=None, code=...);
    .document_length replaces .doc. v0.2.0 removes MAX_JUMBF_DEPTH and adds
    MAX_CBOR_DEPTH, MAX_NONSTARTERS, and TextNormalizationError.
    at_least() and raise_for_state() raise ValueError for UNMARKED and
    INVALID thresholds.
  • Inputs to embed(): media_type requires an exact lowercase text/
    prefix and no parameters. embed() rejects text/html and text/markdown.
    For custom EmbedContext values, manifest_uuid must be UUIDv4;
    instance_id and generator_name must use 1 to 1,000,000 UTF-8 bytes; and
    when must use a whole-minute UTC offset.
  • Certificates and strip(): Signer checks issuer links and, by default,
    each certificate's role profile. embed() checks certificate validity at
    EmbedContext.when. strip() raises MarkCorruptError rather than guess how
    much to remove when a corrupt wrapper has no known length.

Validation changes

  • The verifier accepts valid non-deterministic CBOR but rejects duplicate keys.
    It accepts ES256, ES384, ES512, PS256, PS384, PS512, and Ed25519 claim
    signatures; embed() signs with Ed25519. It accepts integer and legacy string
    x5chain labels in either the protected or unprotected COSE header and checks
    critical headers.
  • The verifier reads c2ma and legacy c2md Standard Manifests. It considers
    c2cm and c2um during selection, then reports them as unsupported. It reads
    c2pa.actions v1; embed() writes v2.
  • For text with several wrappers, the verifier requires the chosen wrapper's
    signed exclusion to name its span. It permits extra ordered exclusions and
    records them in Verdict.informational. New checks cover action relationships,
    self-redaction, soft bindings, icons, cloud and external data, time-stamp
    shape, and multiple parents.
  • The verifier checks every carried certificate's role profile and validity
    window, but not issuer links, chain order, or trust. The caller's
    TrustEvaluator must build the RFC 5280 path and set anchor policy.

Safety, performance, and limits

  • NFC normalization rejects more than 30 consecutive non-starters after NFKD
    decomposition. embed() raises TextNormalizationError; verify() reports
    a malformed data hash.
  • The padding search prepares one manifest and signature per exclusion candidate.
    The CodSpeed comparison shows the 1 MB embed simulation change
    from 1,394.2 ms to 30.4 ms. It also shows four
    regressions: 12-byte embed simulation and memory, valid 1 MB verification
    memory, and hostile-decoy simulation. It contains no wall-clock measurement.

c2patxt includes no credential, trust anchors, path builder, or network
retrieval. A correct self-signed mark returns VALID with
signingCredential.untrusted, which does not mean validation failed. c2patxt
supports no post-quantum signature algorithms.

c2patxt is our implementation of C2PA 2.4 Annex A.8; the C2PA consortium did
not publish it. The verifier does not check sigTst2, rVals, revocation, full
ingredient validation, cross-manifest history, or other text and media carriers.
It returns general.error for a non-empty c2pa.time-stamp or a linked
ingredient assertion. See implementation scope and
C2PA compatibility.

Checks and links

make test passes 1,313 tests with 95.95% line coverage; make lint also passes.

Implementation scope · C2PA compatibility ·
Known deviations · Robustness measurements

Full changelog: v0.1.2...v0.2.0