PRE-GEN protocol overview
PRE-GEN is a protocol for pre-generation authorization: before an AI model produces content depicting a registered person, brand, voice, style, or creative work, the provider asks a registry whether the use is licensed — and receives a cryptographically signed decision that can be stored and independently verified forever.
The specification is licensed under the Apache License 2.0, separately from any service that implements it. Anyone may implement PRE-GEN without permission. The parts every implementation must agree on are pinned as byte-level test vectors, not prose alone: if an implementation’s canonicalization drifts, its vector test fails.
The crypto invariant
Four rules, agreed on byte for byte by every implementation:
- Canonical JSON. Keys sorted by Unicode code point, no whitespace, non-ASCII values emitted as raw UTF-8 (never escaped), integers only — no floats, because float serialization is not portable.
- Hashing. SHA-256, lowercase hex.
- Signatures. Ed25519 (RFC 8032, deterministic), hex-encoded, over the canonical JSON bytes of the body excluding the signature field itself.
- Audit chain. Each event’s
prev_hashis the SHA-256 of the previous event’s canonical bytes; the first event uses the literal stringgenesis.
canonical_json(obj) = UTF8( json.dumps(obj,
sort_keys=True, separators=(",", ":"), ensure_ascii=False) )
signature = Ed25519.sign( canonical_json(body minus signature) )
key_fingerprint = "pg-ed25519:" + hex( SHA256(raw 32-byte public key) )[0:32]
Signed objects
Five object types cross the wire, each carrying its own schema version marker inside the signed bytes. See Versioning for what bumps each marker and which changes are additive-safe.
| Object | Marker | Role |
|---|---|---|
| Decision | pg.decision.v1 | The /verify answer — signed by the registry operator |
| License | pg.license.v2 | Scoped permission — signed by the rights holder, countersigned by the operator |
| Receipt | pg.receipt.v2 | Post-generation proof — signed by the provider, hashed by the operator |
| Evidence bundle | pg.evidence.v1 | Verifiable offline package of decision + license + audit chain |
| Assertion | pg.assertion.v1 | Portable provenance claim, embeddable in C2PA manifests |
The flow
- Detect — poll
GET /v1/subjects/index(ETag-cached) and match user prompts against registered subjects with the SDK matcher. - Verify —
POST /v1/verify/returns a signed decision: allowed (with obligations) or refused (with a machine-readablePG_*code — see Refusal codes). - Prove — verify the signature against
GET /keys(rotation-aware), store the decision, and file a receipt after generation.
Implementations pinned by vectors
| Implementation | Vector test |
|---|---|
| Registry backend (source of truth) | test_spec_vectors.py |
| Reference single-file registry | TestReferenceImplementation |
| Python SDK (prampta) | test_spec_vectors.py |
| TypeScript SDK (@prampta/sdk) | vectors.test.ts |
The vectors use a fixed, public test key derived from a known seed — never use it in any deployment. Regenerating vectors is allowed only after an intentional protocol change: the generator is deterministic, so regenerating without a protocol change produces a byte-identical file. A noisy diff means the invariant moved.
