> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gaussia.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticity

> Who assembled a brain: SSHSIG signatures, the trust root that travels inside it, and revocation without clocks.

Everything else in the protocol establishes that a brain is **intact**: anyone recomputes the hash
structure offline and confirms it is exactly what its identifiers describe. What the hashes cannot say is
**who assembled it** — internal consistency is cheap to manufacture, and a fabricated brain recomputes
perfectly. Authenticity is the one assertion the hashes cannot make: a detached SSHSIG signature over the
snapshot, judged against a key list that travels inside the brain itself.

The two verifications stay separate, always:

```python theme={null}
brain.verify()          # integrity: recomputed from bytes, needs nothing and no one
brain.authenticate()    # authenticity: judged against the trust root in force
```

<Warning>
  There is deliberately no combined flag. "Intact, and signed by an authorized key" and "intact,
  provenance unknown" are different facts, and a consumer that collapses them cannot recover the
  difference afterwards. `AuthenticationReport.state` is a derived property — no construction can claim
  `authorized` while carrying a blocking finding.
</Warning>

## Creating a governed brain

Authority starts at the genesis and nowhere else. Keys are ordinary SSH keys — the private half stays in
your `ssh-agent`, a hardware token behind one, or a KMS that presents as one; the SDK never reads a
private key and defines no format for one.

```python theme={null}
from boltzmann import AgentSigner, Brain, Scope, SshPublicKey, TrustRoot, TrustedKey

signer = AgentSigner()          # the agent's Ed25519 key, via SSH_AUTH_SOCK
root = TrustRoot(
    revision=1,
    govern_quorum=1,
    keys=(
        TrustedKey(
            key=signer.public_key,
            subject=signer.suggested_subject,      # or your own: "alex@example.org"
            scopes=(Scope.INGEST, Scope.COMMIT, Scope.GOVERN),
            since=1,
        ),
    ),
)
curator = Actor(id="curator@example.org", kind=ActorKind.HUMAN)
brain = Brain.init("./brain", actor=curator, trust_root=root, signers=[signer])
```

`subject` names who holds the key, as an [actor identifier](/sdks/boltzmann/concepts/identity#actor-identifiers).
It is the one thing that connects a signature to the actor a provenance record names — without it, provenance
says a person and the signature says a fingerprint, and nothing asserts they are the same.

<Note>
  **It is not a certificate.** A subject is asserted by *this brain's* governance and nowhere else: changing
  one changes the trust root, which is a revision, which needs a quorum. It is as trustworthy as that quorum
  and no more. Whether a key really belongs to a particular person in the world is still settled outside the
  protocol — what a subject adds is that once it *is* settled, the conclusion lives where a verifier reads it
  instead of in a maintainer's memory.

  `AgentSigner.suggested_subject` offers the key's ssh-agent comment when it already is an actor identifier,
  which it usually is. Offered, never adopted: the comment is a label the key's own holder typed, so a quorum
  has to make the claim deliberately.
</Note>

Omitting it costs nothing. An absent subject is left out of the canonical bytes entirely, so a trust root that
names none has exactly the digest it had before this member existed, and every pin against it still holds.

A genesis proves nothing by itself — any party can construct an indistinguishable one. What gives it
meaning happens outside: consumers **pin** the trust root's digest on first contact, and from that moment
the derivable rules take over. *A genesis is not validated, it is anchored.*

## Signing and verifying

```python theme={null}
brain.sign(signer)                       # a detached record beside the snapshot; no identity changes
report = brain.authenticate()

report.state                             # authorized | unsigned | attributable | unauthorized
report.role                              # genesis | ordinary | revision
report.required_scopes                   # computed from the diff against the first parent
report.outcomes()                        # one verdict per signature, by fingerprint
report.authorship().subject              # who the trust root says holds the key that signed
report.attribution                       # which claimed actors those signatures stand behind
report.findings                          # everything blocking or diagnostic, named
report.require_authorized()              # or raise the most specific typed error
```

## Which actors a signature stands behind

A provenance record names who performed an operation. Until a key stands behind that name it is a
*declared* identifier — whoever can write to a brain can write any name into its audit trail. Once the
trust root names subjects, the two can be compared:

```python theme={null}
attribution = brain.audit_attribution()

attribution.verified      # actors a signing key vouches for
attribution.asserted      # actors nobody vouches for
attribution.legacy        # identifiers that predate the actor-id rule
attribution.is_fully_vouched
```

<Warning>
  **It never decides anything.** An unvouched actor produces a non-blocking `ATTRIBUTION_UNVERIFIED`
  finding and leaves `state` at `authorized`. It has to: a snapshot legitimately names actors that never
  signed it — every merge does, because reconciliation brings another party's records into a history your
  key signs. Refusing an unvouched actor would refuse reconciliation itself.
</Warning>

Only the records a snapshot *introduces* are compared, and only against keys whose signature actually
verified. Assisting parties are never compared — nothing expects a model to hold a key, and counting its
absence would bury the one comparison that means something.

`asserted` and `legacy` are kept apart because the remedy differs: an unvouched actor needs a governance
act, and a legacy identifier needs a rewrite nobody can perform on bytes already published.

Three rules do most of the work:

* **Scopes are computed, never believed.** What a snapshot required comes from its difference against its
  first parent — canonical gained blocks → `ingest`, canonical lost blocks → `drop:canonical`, a derived
  module changed → `commit`, the trust root changed → `govern`, a module's signed `tombstones` list grew →
  `redact`.
  The `scopes` a signature claims aid diagnosis and decide nothing.
* **The trust root in force is the parent's.** A revision's own signatures answer to the list it is
  *replacing* — which is why a key cannot admit itself (see below).
* **Missing evidence widens the requirement.** A truncated chain or an unreadable composition makes the
  verdict `insufficient_evidence`, never a smaller demand: a verifier that quietly computed less from a
  truncated history would be exploitable by shipping a truncated history.

## A stranger's key: attributable, or an impersonation

The same snapshot, signed by the same key the trust root does not list, means two opposite things
depending on the claim made for it — so the report says which question it answered:

```python theme={null}
from boltzmann import SnapshotStance

brain.authenticate(digest)                                   # HEAD is the default
brain.authenticate(digest, stance=SnapshotStance.OFFERED)    # judged as a proposal
```

* **Offered** — someone hands you a history for review. The signature verifies, the author is
  cryptographically identified, and **no authority attaches**: the state is `attributable`, and the
  blocks are judged one at a time through validation, where a proposer's identity earns them nothing
  anyway. This is how an open project hears from people it has never admitted.
* **As a head** — a registry, a mirror, or the contributor's own tag serves it as the brain's current
  state. The same signature is now an unauthorized key, reported as one, and refused.

`HEAD` is the default because it is the safe answer: a caller who does not say is asking about a
brain's current state. `plan_reconcile` sets `OFFERED` for you and reports the result on the plan:

```python theme={null}
plan = brain.plan_reconcile(fetched.digest)
plan.authorship.state        # attributable, for a contributor you have not admitted
plan.authorship.key          # who it is from
```

<Warning>
  `attributable` is not a weaker `authorized`. `require_authorized()` still raises for it. It says the
  author is named and nothing is authorized — which is precisely what a maintainer needs to know
  before reading the contribution.
</Warning>

## Admitting a key: the quorum rule

Changing the trust root is a **trust-root revision**: a snapshot that changes the key list and nothing
else, covered by at least `govern_quorum` signatures from distinct keys holding `govern` in the revision
*before* the change. A single owner admits a second key in one call:

```python theme={null}
revised = TrustRoot(revision=2, govern_quorum=1, keys=(*root.keys, colleague_entry))
brain.rotate(revised, signers=[signer])
```

With a quorum of two or more, the signers may not share a machine. The revision document is built
**once** — it carries `created_at`, so two constructions would sign different bytes — and the exact bytes
travel by any channel; nothing in them is secret, and each party inspects what it signs:

```python theme={null}
plan = brain.plan_rotate(revised)             # A: build once; the head does not move
record_a = brain.countersign(plan.document, signer_a)
# ... plan.document travels to B, who inspects and signs the same bytes ...
record_b = other_brain.countersign(plan.document, signer_b)
# ... record_b (~300 bytes of JSON) travels back ...
brain.rotate(plan=plan, records=[record_a, record_b])   # quorum met -> the head advances
```

`countersign` refuses mechanically what a reviewer would refuse by reading: a parent it cannot see,
content smuggled into a governance act, a trust root that does not advance, an admission claim the
observable chain refutes. A failed quorum advances nothing.

**Keep a margin.** A quorum equal to the number of `govern` holders is legal and permanent: lose one
key and neither the remaining holders nor the attacker can assemble the signatures to record a
compromise or admit a replacement, while a stolen key keeps signing within its scopes. There is no
recovery path inside the protocol — re-anchoring would be exactly the self-assertion the quorum rule
exists to forbid — so `init` and `rotate` warn when you enter that state, and the report names it:

```python theme={null}
root.has_governance_margin               # False when the quorum equals the holders
report.has(FindingKind.QUORUM_MARGIN)    # reported, never blocking
```

**Why a key cannot admit itself.** An attacker installs the public brain, writes their key into the
list — possibly byte-identical to a legitimate admission — and signs with it. Integrity passes; the
signature verifies. What fails is the transition: the trust root in force at their snapshot is the one its
parent names, where their key is absent, and the revision carries none of the `govern` signatures the
previous list demands. This fails **with no pin at all**, and the rejection propagates: every descendant
of the forged revision stands on authority that was never granted.

## Retirement and revocation, without clocks

The two look similar and behave oppositely. Both are trust-root revisions under the same quorum:

```python theme={null}
brain.revoke(departing_key, signers=[signer])                        # retired from this revision on
brain.revoke(stolen_key, signers=[signer], compromised_from=digest)  # withdrawn from that position on
```

* **Retired** (`retired_from`, a revision number): everything the key signed while authorized stays
  valid. An ordinary departure is harmless, and a verifier reports `retired_key` distinctly — collapsing
  it into "unauthorized" would invalidate history for an administrative reason.
* **Compromised** (`compromised_from`, a snapshot digest): every signature at and after that position is
  withdrawn, even though it was signed while the key was listed. The only construct in the protocol that
  invalidates a previously valid signature, reported in the report's separate `withdrawn` list.

No clock is consulted anywhere. A timestamp is written by whoever holds the pen — a stolen key backdates
freely — so validity is **positional**: snapshots are chained by digest, a position cannot be forged
without changing every descendant, and the question is always *was this key authorized, with this scope,
at this position in the chain*.

## The pin: the one thing from outside

Trust cannot be manufactured from inside a system. The pin reduces the exposure to a single decision:

```python theme={null}
brain.pin()                          # trust on first use: anchor what this brain carries now
brain.pin(digest_from_the_website)   # or compare out of band, once, and anchor that
```

A pinned consumer refuses any brain whose trust root neither matches the pin nor descends from it through
revisions that each satisfied the quorum rule — an approved rotation is the mechanism working, not a
mismatch. On `pull`, the manifest's `trust-root` annotation is compared **before any module layer is
transferred**; when it differs, only the small documents move until the custody walk decides.

**A pin is for one brain, and a brain is its genesis.** Tags are re-assignable and the trust root
rotates, so neither identifies a brain; the genesis digest never changes. `pin()` records it, and the
verifier checks it first — otherwise an anchor taken for one brain would be evaluated against
another's chain, and match or mismatch would both be answers to the wrong question.

```python theme={null}
report.has(FindingKind.PIN_BRAIN_MISMATCH)   # a different brain, not a change of authority in this one
report.has(FindingKind.TRUST_ROOT_MISMATCH)  # this brain, authority that does not descend from the pin
```

The same brain under a new repository reference still matches. A history pruned below its genesis
cannot answer the question, and that is reported as undecidable rather than as a mismatch — refusing
it would punish pruning, which the protocol permits.

## Publication: signatures accumulate around the artifact

A signature is never a layer of the brain manifest — countersigning would change the brain's digest, and
a brain must not change identity because someone agreed with it. Each record is the single layer of its
**own** manifest, whose `subject` names the brain: in a registry, that is an OCI referrer; in the local
layout, one more `index.json` entry, which is exactly what an export carries. `push` publishes them,
`pull` and `fetch` collect them, and a transport that never learned about referrers still moves the brain
— its consumers simply see it unsigned, and the push says so.

Install-time tolerances are a `VerificationPolicy`, not a hierarchy of flags:

```python theme={null}
from boltzmann import UnsignedPolicy, VerificationPolicy

await brain.pull(client, reference, "v1", verification=VerificationPolicy(
    unsigned=UnsignedPolicy.WARN,     # default: warn on first contact, refuse once seen signed
    required_signatures=1,
    allow_propose_head=False,         # a propose-scoped head is never the published state by default
))
```

What is never configurable is the reporting: no policy can present an unverified brain as verified.

## The evidence carries its authorship

Every query result reports both verifications, separately:

```python theme={null}
bundle = brain.search(query)
bundle.all_verified          # hashes and membership: the first verification
bundle.authorship.state      # authorized | unsigned | attributable | unauthorized: the second
bundle.authorship.key        # a fingerprint that authorized it, when one did
bundle.authorship.pinned     # whether the trust root is anchored by this consumer's pin
```

## Without the extra

The Ed25519 mathematics lives in the optional extra — `pip install 'pyboltzmann[authenticity]'`. It buys
exactly one operation. Everything structural works on a plain install: parsing, fingerprints, the trust
root, quorum arithmetic, and the one rejection the paper requires of every reader — a record whose named
fingerprint disagrees with the key inside its own signature blob. What a bare install cannot do is reach
`authorized`: an unchecked signature reports `unverifiable`, because "could not check" is a different
fact from "failed", and a missing dependency must never read as a forgery — or as a pass.

<Note>
  Signing through an `AgentSigner` works *without* the extra: the mathematics runs inside the agent,
  which is the point of never holding the key.
</Note>

## Verification security floor

Boltzmann signatures pin SSHSIG's message hash to SHA-512. A generic SSHSIG document using SHA-256
is valid SSH syntax, but it is not a valid Boltzmann signature. Verification also requires canonical
Ed25519 point encodings, `S` below the group order, the strict cofactorless equation, and a public key
outside the small-order subgroup. `ssh-dss` is always refused; RSA keys below 3072 bits are refused
before the SDK reports whether that algorithm is implemented.

## Golden vectors

Two published files pin this behaviour for any implementation, in any language:
`sshsig.json` carries the wire format — including the signed-data blob, which is what tells a framing bug
from a signing bug — and `signatures.json` carries whole chains, published test key pairs, and the
verdict a verifier MUST reach for each of the paper's worked cases. `AuthenticityConformance` in the
conformance suite replays them against any store.
