PRE-GEN

Protocol overview

PRE-GEN v5 draft · Copyright Valerii Egorov · Apache-2.0 · source · Test vectors v2 · Policy version 2026-09-22 · The text is normative; the vectors test it, and a disagreement is an erratum.

PRE-GEN is a protocol for pre-generation authorization. Before a model produces content depicting a registered person, brand, voice or work, the provider asks an authorization registry whether the use is permitted and receives a signed decision it can store and anyone can verify.

A small core, and room for each registry

The core is what every registry, provider and verifier implements: the decision, the licence envelope, the receipt, 17 core refusal codes, PG codes and the signed registry directory. It also fixes a floor of protections no registry may lower: an opt-out beats any licence, a refused subject status beats any licence, minors stay protected, and an unknown subject is not a prohibition.

  • Floors only go up. A registry may refuse more than the core, never allow more.
  • Own members and codes. A registry may add signed members, which verifiers ignore unless marked critical, and its own refusal codes, prefixed with its issuer: PG_<ISSUER>_….
  • Published policy. Each registry publishes its floors, codes, extensions, decision lifetime and opt-out waiting period.
  • Several subjects. One output with a person, a voice and a brand needs an allow for each, under one generation_id.
  • Trusted registries only. Signatures count only from registries the steward-signed directory lists; the steward admits them on published conditions and can revoke a registry or a key. When two registries hold the same person, neither registry's answer decides by itself: the provider keeps both, tells both, decides under its own policy and does not call the output licensed; the registries resolve it, and the steward revokes one that misstates who holds the rights. A matching name is not evidence of the same subject.

What the origin registry, PRAMPTA, adds — end-user binding, decision caching, evidence bundles, C2PA assertions, observations — is in PRE-GEN-EXTENSIONS.md.

The crypto invariant

  • Canonical JSON. Keys sorted by code point, no whitespace, non-ASCII emitted as raw UTF-8, integers only (no floats).
  • Hashing. SHA-256, lowercase hex.
  • Signatures. Ed25519 (RFC 8032), hex, over the canonical bytes of the body without its signature field.
  • Audit chain. Each event's prev_hash is the SHA-256 of the previous event's canonical bytes; the first uses genesis.
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]

Never Unicode-normalize a signed body before verifying. NFC and NFD strings that look the same produce different signatures. Verify the bytes you received.

Signed objects

ObjectMarkerSigned byProves
Decisionpg.decision.v1RegistryThe answer to one request and its policy version
Licencepg.license.v2Rights holder, countersigned by the registryA scoped permission: use, modality, channel, territory, time, project
Receiptpg.receipt.v2 · v3Provider (v3 signs the event type)That a generation under a decision was reported
Evidence bundle (extension)pg.evidence.v1RegistryDecision, licence and audit chain, verifiable offline
Assertion (extension)pg.assertion.v1RegistryA pointer to the decision, embeddable in a C2PA manifest

The flow

  1. Detect. Poll GET /v1/subjects/index (ETag-cached) and match prompts against registered names and aliases. Matching yields candidates, not proof.
  2. Verify. POST /v1/verify/ returns a decision with a disposition: allow, not_blocked, review or deny, plus a reason code.
  3. Prove. Check the signature against the registry's key set (GET /keys, rotation-aware), store the decision, and after an allow file a receipt.

Conformance

An implementation conforms when it reproduces every case in the published test vectors: canonicalization, signatures, audit chain and PG codes. The vectors use a fixed public test key — never use it in a deployment.