PRE-GEN assertions in C2PA manifests
C2PA answers “who made this and when”. It does not answer
“were they allowed to”. PRE-GEN bridges the gap with
pg.assertion.v1 — a signed authorization assertion embedded directly into a
C2PA manifest, so the permission travels inside the file instead of living in a
database somewhere. Content and its consent become inseparable.
What goes into the assertion
pg.assertion.v1 is a C2PA custom assertion (action array stays
untouched; PRE-GEN data rides in a com.pregen.authorization/1 assertion).
Canonical JSON, no floats, signature excluded from its own signed bytes:
{
"v": "pg.assertion.v1",
"subject_pg": "PG-000042*",
"decision_ref": {
"decision_id": "dec_01J8ZK…",
"registry": "https://api2.prampta.com",
"decided_at": 1787600000,
"decision_sig": "a3f1…"
},
"license_pg": "PG-STD-000042-K7M2QX9",
"provider_id": "prov_studio_one",
"receipt_ref": "rcp_01J8ZM…",
"generated_at": 1787600123
}
| Field | Meaning |
|---|---|
| subject_pg | The subject depicted — resolvable at /lookup |
| decision_ref | Pointer to the signed allow-decision: id, registry base URL, timestamp, decision signature |
| license_pg | The license that backed the decision (optional in opt-out denials) |
| receipt_ref | The provider’s post-generation receipt tying output to decision |
Embedding
Use any C2PA-conformant SDK (the CAI c2pa-rs, Python c2pa-python, or a hosted SDK). The assertion is added as a custom assertion before signing:
from prampta import Prampta
from c2pa import C2paReader, C2paWriter # illustrative
pg = Prampta(base_url="https://api2.prampta.com", …)
decision = pg.assert_allowed("PG-000042*", prompt=prompt, modality="image")
assertion = pg.c2pa_assertion(decision) # builds pg.assertion.v1
writer.add_assertion("com.pregen.authorization/1", assertion)
writer.sign(...) # your C2PA credential
The PRE-GEN assertion never replaces the C2PA signature — it sits alongside it. Stripping the assertion breaks the studio’s chain-of-title check; stripping the C2PA signature invalidates the manifest. Both tamper paths are visible.
Verification, from anywhere
- Read the manifest, find
com.pregen.authorization/1. - Resolve
subject_pgpublicly — pregen.org/lookup or GET /v1/subjects/{code}. - Fetch the registry’s key set (GET /keys, rotation-aware) and verify
decision_sigover the canonical decision bytes. - Optionally pull the evidence bundle and walk the audit chain back to genesis.
No account, no SDK required — the file carries everything needed to ask the registry “was this authorized?” and check the answer cryptographically.
What this is not
An assertion is evidence, not permission. The permission is the license; the assertion proves which license applied and that the provider asked. It also says nothing about provenance of the input material — that remains C2PA’s job. The two layers are complementary by design: C2PA for origin, PRE-GEN for consent.
