# VERIFY — Security Attestation Extension (Agent Instructions)

> Drop this file into your CLAUDE.md, .cursorrules, copilot-instructions.md, or agent system prompt to make your AI tool VERIFY-compliant. This document is self-contained — no external files or downloads are required.

**Standard:** VERIFY v1.0 | **Authors:** itsavibe.ai

> **Prerequisite:** This agent configuration implements the VERIFY security attestation extension. Your tool MUST already implement the VIBES data standard (see `vibes-agent.md`). VERIFY builds on top of VIBES audit data. For risk scoring, see `prism-agent.md`. For agent learning and governance, see `evolve-agent.md`. For incident response and forensics (which uses DSSE envelopes for sealed evidence bundles), see `trace-agent.md`.

## Table of Contents

| § | Section | Anchor |
|---|---|---|
| 1 | What is VERIFY? | [#1-what-is-verify](#1-what-is-verify) |
| 2 | The Attestation Pipeline | [#2-the-attestation-pipeline](#2-the-attestation-pipeline) |
| 3 | DSSE Envelope Format | [#3-dsse-envelope-format](#3-dsse-envelope-format) |
| 4 | in-toto v1 Attestation Statement | [#4-in-toto-v1-attestation-statement](#4-in-toto-v1-attestation-statement) |
| 5 | Ed25519 Key Management | [#5-ed25519-key-management](#5-ed25519-key-management) |
| 6 | PAE (Pre-Authentication Encoding) | [#6-pae-pre-authentication-encoding](#6-pae-pre-authentication-encoding) |
| 7 | Content-Addressed Attestation ID | [#7-content-addressed-attestation-id](#7-content-addressed-attestation-id) |
| 8 | Trust Tiers | [#8-trust-tiers](#8-trust-tiers) |
| 9 | Tool Provider Cosigning | [#9-tool-provider-cosigning](#9-tool-provider-cosigning) |
| 10 | Agent Behavior | [#10-agent-behavior](#10-agent-behavior) |
| 11 | Confidence Levels | [#11-confidence-levels](#11-confidence-levels) |
| 12 | CLI Commands | [#12-cli-commands](#12-cli-commands) |
| 13 | Cryptographic Processes | [#13-cryptographic-processes](#13-cryptographic-processes) |

**Deep-load examples:**
- Just the trust tiers: `https://itsavibe.ai/verify-agent.md#8-trust-tiers`
- Just the key management chapter: `https://itsavibe.ai/verify-agent.md#5-ed25519-key-management`
- Just the crypto reviewer's appendix: `https://itsavibe.ai/verify-agent.md#13-cryptographic-processes`

---

## 1. What is VERIFY?

VERIFY wraps VIBES audit data in cryptographic envelopes — Ed25519 signatures, DSSE containers, and temporal anchors — so that any modification after signing is detectable. It transforms self-reported audit data into independently verifiable evidence.

Without attestation, anyone could edit their `.ai-audit/` files after the fact — inflating or deflating AI usage numbers, changing prompts, or removing records entirely. VERIFY makes that detectable.

---

## 2. The Attestation Pipeline

The pipeline transforms raw audit data into a verifiable, tamper-evident record in seven steps:

| Step | Name | Description |
|------|------|-------------|
| 1 | **Audit** | Validate `.ai-audit/` directory — file structure, hash integrity, assurance level compliance |
| 2 | **Hash** | Compute SHA-256 hashes for `manifest.json`, `annotations.jsonl`, and `config.json` |
| 3 | **Tool Sign** | (Optional) If the AI tool supports cosigning, it signs the PAE hash at data-creation time via its provider's signing service. Only the 32-byte hash is sent — audit data stays local |
| 4 | **User Sign** | Ed25519 private key signs the hashes inside a DSSE envelope wrapping an in-toto v1 attestation statement |
| 5 | **Timestamp** | (Optional) OpenTimestamps proof anchors the attestation to the Bitcoin blockchain for temporal evidence |
| 6 | **Submit** | DSSE envelope is sent to `POST /api/attestation/submit`. Server computes a content-addressed ID (SHA-256 of canonicalized envelope JSON) |
| 7 | **Verify** | Server-side: `GET /api/attestation/verify/{id}` checks hash integrity. Client-side: `vibecheck verify-attestation` performs full Ed25519 signature verification |

The entire pipeline runs locally via the `vibecheck` CLI. The private key never leaves the machine. Only the signed envelope — containing hashes, not actual data — is submitted to the registry.

---

## 3. DSSE Envelope Format

Attestations are wrapped in [DSSE](https://github.com/secure-systems-lab/dsse) — a minimal signing envelope format designed for software supply chain security.

```json
{
  "payloadType": "application/vnd.in-toto+json",
  "payload": "<base64url-encoded in-toto statement>",
  "signatures": [
    {
      "keyid": "a1b2c3d4e5f6a7b8",
      "sig": "<base64url-encoded Ed25519 signature>",
      "keytype": "user"
    },
    {
      "keyid": "anthropic-vibes-2026-01",
      "sig": "<base64url-encoded Ed25519 signature>",
      "keytype": "tool_provider"
    }
  ]
}
```

| Field | Required | Description |
|-------|----------|-------------|
| `payloadType` | Yes | Always `"application/vnd.in-toto+json"` |
| `payload` | Yes | Base64url-encoded in-toto v1 attestation statement |
| `signatures` | Yes | Array of one or more Ed25519 signatures |
| `signatures[].keyid` | Yes | First 16 hex chars of SHA-256 of DER-encoded public key |
| `signatures[].sig` | Yes | Base64url-encoded Ed25519 signature over PAE bytes |
| `signatures[].keytype` | No | `"user"` or `"tool_provider"` — distinguishes signature origin |

---

## 4. in-toto v1 Attestation Statement

The payload inside the DSSE envelope is an [in-toto v1](https://github.com/in-toto/attestation) attestation statement. It binds subjects (audit files) to a predicate (validation metadata).

```json
{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    {
      "name": ".ai-audit/manifest.json",
      "digest": { "sha256": "a1b2c3..." }
    },
    {
      "name": ".ai-audit/annotations.jsonl",
      "digest": { "sha256": "d4e5f6..." }
    },
    {
      "name": ".ai-audit/config.json",
      "digest": { "sha256": "f7a8b9..." }
    }
  ],
  "predicateType": "https://itsavibe.ai/vibes/attestation/v1",
  "predicate": {
    "validation": { "result": "PASS", "version": "1.2.0" },
    "project": { "name": "my-project", "assurance_level": "medium" },
    "stats": { "total_annotations": 142, "unique_models": 2 }
  }
}
```

| Field | Required | Description |
|-------|----------|-------------|
| `_type` | Yes | Always `"https://in-toto.io/Statement/v1"` |
| `subject` | Yes | Array of three entries — `manifest.json`, `annotations.jsonl`, `config.json` — each with `name` and `digest.sha256` |
| `predicateType` | Yes | Always `"https://itsavibe.ai/vibes/attestation/v1"` |
| `predicate.validation` | Yes | Validation result (`"PASS"` or `"FAIL"`) and vibecheck version |
| `predicate.project` | Yes | Project name and assurance level from `config.json` |
| `predicate.stats` | Yes | Annotation count and unique model count from the audit data |

---

## 5. Ed25519 Key Management

### Key Storage

Keys are stored at `~/.vibescheck/keys/` with strict file permissions:

| File | Format | Permissions | Description |
|------|--------|-------------|-------------|
| `vibescheck.key` | PKCS8 PEM | `0600` (owner read/write only) | Ed25519 private key. Never transmitted. |
| `vibescheck.pub` | SPKI PEM | `0644` (world-readable) | Ed25519 public key. Shared with the registry. |

### Key Existence Check

Before any signing operation, you MUST check for the user's keypair:

1. Test whether `~/.vibescheck/keys/vibescheck.key` exists.
2. If present, validate file permissions are `0600` (owner read/write only). If permissions are looser, you MUST refuse to use the key and report the permission mismatch to the user.
3. If present and correctly permissioned, parse the PKCS8 PEM. If parsing fails, you MUST treat the key as unusable and surface a parse error — DO NOT silently regenerate.
4. If absent, proceed to the Key Generation Policy below.

Pseudocode:

```
fn ensure_signing_key() -> SigningKey {
  path = ~/.vibescheck/keys/vibescheck.key
  if exists(path):
    mode = stat(path).mode & 0o777
    if mode != 0o600:
      fail("key file permissions are " + oct(mode) + ", expected 0600")
    return load_pkcs8(path)        // fail loudly on parse error
  return generate_per_policy()     // see next subsection
}
```

You MUST NOT attempt signing without first running this check.

### Key Generation Policy

When no signing key exists, the generation behavior depends on the entrypoint that triggered the signing operation:

| Entrypoint | Behavior |
|---|---|
| `vibecheck init` (explicit setup) | MAY auto-generate without prompting |
| `vibecheck attest` (signing operation) | MUST prompt the user before generating |
| Non-interactive (CI/CD, `--yes`, `--ci`) | MUST require explicit `--allow-key-gen` flag, otherwise abort with a non-zero exit code |
| Headless / no TTY | MUST abort with a non-zero exit code unless explicitly authorized |

Generation procedure (when authorized):

1. Generate a fresh Ed25519 keypair using a cryptographically secure RNG provided by the OS or language runtime (`getrandom(2)`, `SecRandomCopyBytes`, `crypto.randomBytes`, etc.). You MUST NOT seed with timestamps, UUIDs, or other low-entropy sources.
2. Serialize the private key as PKCS8 PEM and write to `~/.vibescheck/keys/vibescheck.key` with mode `0600`.
3. Serialize the public key as SPKI PEM and write to `~/.vibescheck/keys/vibescheck.pub` with mode `0644`.
4. Compute the `keyid` per the Key ID Computation subsection below.
5. Emit a one-line user-visible notice: `Generated new Ed25519 signing key (keyid=…). Back this file up: ~/.vibescheck/keys/vibescheck.key`.

You MUST NOT silently overwrite an existing key file. If `vibescheck.key` exists and is unusable (wrong permissions, corrupt, etc.), surface the error — only the user can choose to delete and regenerate.

### Key Rotation

User keys SHOULD be rotated periodically — annually is the recommended cadence, matching the tool-provider rotation policy documented in Section 9. There is no normative maximum lifetime for user keys, but verifiers MAY warn on attestations signed by keys older than 365 days.

Rotation procedure:

1. Generate a new keypair following the Key Generation Policy.
2. Write the new keypair alongside the old one as `~/.vibescheck/keys/vibescheck-{YYYYMMDD}.key` and `.pub`.
3. Update `~/.vibescheck/keys/active` (a symlink) to point at the new key files.
4. Existing attestations signed by the old key remain valid — they were created when the key was current. You MUST NOT retroactively invalidate attestations on rotation alone.
5. The user MAY co-sign their most recent attestation with both old and new keys during a transition window to establish chain of trust.

You MUST NOT delete an old key file unless the user explicitly requests destruction. Old keys are needed for re-verification of historical attestations.

### Key Revocation

If a private key is suspected compromised, the user MUST revoke it. Revocation has two halves:

**Local action:**
1. Remove the key from active use: delete the symlink `~/.vibescheck/keys/active` (or repoint to a freshly generated key).
2. Move the compromised key to `~/.vibescheck/keys/revoked/{keyid}.key` for forensic preservation.
3. Record a revocation entry in `~/.vibescheck/keys/revocation.jsonl` with fields: `keyid`, `revoked_at` (ISO-8601 UTC), `reason` (`"compromise"`, `"rotation"`, `"loss"`, `"other"`), and an optional `note`.

**Registry signal:**
4. POST a signed revocation notice to the public registry (`/api/attestation/revoke`) covering the keyid being revoked. The notice MUST be signed by either (a) the revoked key itself if accessible, or (b) a newly-generated key together with a `prior_keyid` chain claim. The registry marks all attestations signed by `keyid` as `revoked` going forward.

Verifiers encountering a revoked `keyid` MUST report the attestation as `revoked` and SHOULD treat downstream trust decisions as if the attestation were unsigned (per the Confidence Levels section). Verifiers MUST NOT silently strip revoked attestations from results — the revocation is itself a fact users need.

### Hardware-Backed Keys

Implementors MAY use hardware-backed keys (YubiKey / FIDO2, Secure Enclave on macOS, Windows TPM/CNG, cloud KMS) instead of on-disk PKCS8 files. The on-disk file-mode requirements above do not apply — the hardware enforces non-extractability.

Normative requirements when using hardware-backed keys:

- The public key MUST still be exportable as SPKI PEM (for `keyid` computation and registry publication).
- The `keyid` derivation rule is unchanged: `SHA256(DER(pubkey))[0:16]`.
- The signing operation MUST produce the same Ed25519 signature bytes over the same PAE bytes as defined in Section 6. The hardware integration is invisible to the envelope format.
- You MUST record the key backing in `~/.vibescheck/keys/active.json` as `{"keyid": "...", "backing": "yubikey-5" | "secure-enclave" | "tpm-2.0" | "aws-kms" | "gcp-kms" | "azure-kv" | "custom:..."}` so future signing operations route to the right backend.
- If a hardware key is unavailable at signing time (token unplugged, KMS unreachable), you MUST abort. You MUST NOT fall back to a software key without explicit user authorization.

Tools that support hardware backing SHOULD prompt the user on first `init` whether to use hardware or software, and SHOULD remember the choice in the `active.json` file.

### CI/CD Ephemeral Keys

Continuous-integration pipelines often cannot persist a long-lived signing key. VIBES supports ephemeral signing via two patterns:

**Pattern A — Pipeline-resident short-TTL key (simplest):**

1. The pipeline generates a fresh Ed25519 keypair at job start.
2. The job signs attestations with the ephemeral key.
3. At job end, the keypair MUST be destroyed (no persistence outside the job's runtime).
4. The ephemeral `keyid` is published to the registry alongside its parent organization identity (`org_keyid`), creating a single-hop chain claim: "this attestation was signed by `ephemeral_keyid`, which was authorized by `org_keyid`".
5. Verifiers MUST validate both signatures — the ephemeral one (covering the attestation) and the org chain claim (covering the ephemeral pubkey).

**Pattern B — OIDC-derived keyless (Sigstore-style, SHOULD support):**

1. The pipeline exchanges its OIDC token (from GitHub Actions, GitLab CI, Buildkite, etc.) for a short-lived signing certificate from a transparency-log-backed CA.
2. The certificate binds the OIDC subject (e.g., `repo:openasocket/itsavibe.ai:ref:refs/heads/main`) to a fresh Ed25519 public key.
3. The pipeline signs with the matching private key.
4. Verifiers retrieve the certificate from the transparency log to confirm the OIDC subject. The private key need never be persisted.

Both patterns SHOULD declare `"ephemeral": true` in the attestation predicate metadata so verifiers can apply pipeline-appropriate trust policy. Verifiers MAY require an attestation be cosigned by a long-lived org identity to accept it for production gating decisions.

### Key ID Computation

The `keyid` in every DSSE envelope is computed deterministically:

```
keyid = SHA256(DER_encode(public_key)).hex()[0:16]
```

This produces a 16-character hex string that uniquely identifies the signing key.

### Security Rules

- You MUST NOT transmit the private key over any network.
- You MUST enforce `0600` permissions on the private key file.
- You SHOULD warn the user if the private key file has incorrect permissions.
- You MUST NOT include key material in VIBES audit data (manifest entries, annotations, etc.).
- You MUST check for key existence and validate permissions (Key Existence Check) before any signing operation. You MUST NOT silently regenerate or overwrite.
- You MUST NOT delete old key files on rotation. Historical attestations need their signing keys preserved for re-verification.
- When using hardware-backed keys, you MUST record the backing in `active.json` and MUST abort on backing unavailability rather than falling back to software keys.

---

## 6. PAE (Pre-Authentication Encoding)

DSSE uses Pre-Authentication Encoding to prevent confused deputy attacks. Before signing, the payload type and payload are combined into an unambiguous byte string:

```
PAE(payloadType, payload) =
  "DSSEv1" + SP +
  len(payloadType) + SP + payloadType + SP +
  len(payload) + SP + payload
```

The Ed25519 signature is computed over the PAE-encoded bytes, not the raw payload. Both user and tool provider signatures (if present) MUST cover identical PAE bytes.

---

## 7. Content-Addressed Attestation ID

Every attestation receives a deterministic, content-addressed ID:

1. Take the DSSE envelope.
2. Sort all keys recursively.
3. Serialize with no whitespace: `JSON.stringify(sortKeys(envelope))`.
4. Compute SHA-256 of the resulting string.
5. Express as 64-character lowercase hex.

The same envelope always produces the same ID, regardless of where or when it's computed.

---

## 8. Trust Tiers

Attestations fall into one of three trust tiers based on which signatures are present:

| Tier | Signatures | Description |
|------|-----------|-------------|
| **Self-Attested** | User only | A human or CI/CD pipeline attests to the data. No independent confirmation that the claimed tool produced it. Valid and useful, but the signer vouches alone. |
| **Tool-Corroborated** | User + Tool provider | The tool provider independently confirms it generated the audit data at the claimed time. Strongest assurance against fabrication, post-hoc editing, and tool impersonation. |
| **Tool-Only** | Tool provider only | The tool signed but no user countersigned. Valid, but indicates no human reviewed the attestation. |

Trust tiers are orthogonal to VIBES assurance levels — a Low-assurance attestation can be Tool-Corroborated, and a High-assurance attestation can be Self-Attested.

---

## 9. Tool Provider Cosigning

Cosigning adds a second Ed25519 signature from the tool provider, proving the tool generated the audit data in real time.

### Cosigning Flow

1. Tool generates `.ai-audit/` files as normal.
2. Tool computes SHA-256 hashes of audit files.
3. Tool builds in-toto statement with those hashes.
4. Tool computes PAE bytes.
5. Tool sends only the 32-byte PAE hash to the provider's signing service.
6. Provider signs and returns the signature.
7. User signs the same PAE bytes locally.
8. Both signatures go into the DSSE envelope.

### Key Distribution

Tool providers publish their public keys at a standard HTTPS endpoint:

```
https://{provider-domain}/vibes/vibes-signing-keys.json
```

```json
{
  "provider": "Anthropic",
  "tool_name": "Claude Code",
  "keys": [
    {
      "keyid": "anthropic-vibes-2026-01",
      "algorithm": "Ed25519",
      "public_key_pem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
      "valid_from": "2026-01-01T00:00:00Z",
      "valid_until": "2027-01-01T00:00:00Z",
      "status": "active"
    }
  ],
  "rotation_policy": "Annual key rotation. Previous keys remain valid until valid_until."
}
```

### Cosigning Rules

- The tool provider signature MUST be generated at data-creation time. It cannot be obtained after the fact.
- Only the 32-byte PAE hash is sent to the provider — full audit data stays local.
- Verifiers MAY cache provider keys for up to 24 hours.
- Cosigning is optional in VIBES 1.0. Existing single-signature attestations remain fully valid.

---

## 10. Agent Behavior

### At Attestation Time

**Trigger conditions.** An agent MUST run the attestation procedure below when ALL of the following are true:

1. `config.json` contains `"verify": {"enabled": true}`.
2. The `.ai-audit/` directory exists and validates against the VIBES standard (manifest hashes match, JSONL parses cleanly, no schema violations).
3. One of the following events fires:
   - User runs `vibecheck attest` explicitly.
   - A VIBES session ends and `config.json.verify.attest_on = "session_end"`.
   - A git commit is being created and `config.json.verify.attest_on = "pre_commit"`.
   - A CI/CD job emits a release artifact and `config.json.verify.attest_on = "pre_release"`.

If none of those events fire, the agent MUST NOT auto-sign. You MUST NOT sign attestations on every annotation — that is wasteful and pollutes the registry. You MUST NOT sign without ensuring a signing key exists per Section 5's Key Existence Check.

When the trigger fires, run the procedure below:

When the user requests attestation (e.g., via `vibecheck attest`):

1. Validate the `.ai-audit/` directory structure and hash integrity.
2. Compute SHA-256 hashes for `manifest.json`, `annotations.jsonl`, and `config.json`.
3. Build the in-toto v1 statement with file subjects and predicate metadata.
4. Compute PAE bytes from the payload type and base64url-encoded statement.
5. (Optional) If cosigning is configured (`config.json.verify.cosign_url` set), send the PAE hash — and only the PAE hash, never the full payload — to the tool provider's signing endpoint. If the endpoint is unreachable AND `config.json.verify.cosign_required = true`, you MUST abort with an error. If cosign is unavailable and not required, proceed with user-only signing.
6. Sign the PAE bytes with the user's Ed25519 private key. You MUST first run the Key Existence Check (Section 5). If no key exists, follow the Key Generation Policy. For hardware-backed keys, dispatch the signing operation to the configured backing per `~/.vibescheck/keys/active.json`.
7. Assemble the DSSE envelope with all signatures.
8. Compute the content-addressed attestation ID.
9. Submit to the registry at `POST /api/attestation/submit`. On `2xx`, record the returned `attestation_id` locally in `.ai-audit/attestations/{id}.json` for offline re-verification. On `4xx`, surface the registry error to the user and DO NOT retry — registry validation failures indicate envelope problems that retrying won't fix. On `5xx`, retry with exponential backoff (max 3 attempts) before surfacing failure.

### At Verification Time

**Trigger conditions.** Verification is triggered explicitly: a user, a CI job, a registry crawler, or a downstream consumer requests it. There is no implicit "verify on every read" requirement. The agent MUST honor cache TTLs documented in Section 9 (provider keys cacheable up to 24h) but MUST re-verify if the cache is missing or expired.

Verifiers MUST be deterministic: given the same envelope and the same key material, the verdict MUST be reproducible. Stateful behavior (network calls to fetch keys, registry status lookups for revocation) is permitted but MUST be replayable from cached results.

When verification is requested, run the procedure below:

When verifying an attestation (e.g., via `vibecheck verify-attestation`):

1. Retrieve the DSSE envelope (from registry or local file).
2. Decode the base64url payload to get the in-toto statement.
3. Recompute PAE bytes from the payload type and payload.
4. For each signature in the `signatures` array:
   - Look up the public key by `keyid`.
   - Verify the Ed25519 signature over the PAE bytes.
5. For each subject in the in-toto statement:
   - Recompute the SHA-256 hash of the local file.
   - Compare against the declared digest. Any mismatch indicates tampering.
6. Report trust tier based on which signature types are present.

**Verification outcomes.** Every verification call MUST resolve to exactly one of the following outcomes. Tools building on top of VERIFY (CI gates, badges, registry filters) MUST act on the outcome and MUST NOT silently coerce one outcome into another:

| Outcome | Meaning | Recommended downstream action |
|---|---|---|
| `valid` | All signatures verify, all subject digests match, no revocation, key within `valid_until` if dated | Accept |
| `valid_with_warnings` | Signatures verify and subjects match, but the signing key is older than 365 days (per Key Rotation guidance) or the trust tier is `tool-only` (no user countersignature) | Accept with logged warning |
| `expired` | Signatures verify and subjects match, but the signing key's `valid_until` is in the past | Reject for new gating decisions; historical attestations remain valid for archival lookup |
| `revoked` | At least one `keyid` in the envelope appears in the registry revocation list | Reject; surface revocation reason to caller |
| `unknown_key` | At least one `keyid` cannot be resolved to a public key via local cache, registry, or provider key endpoint | Reject; treat as if unsigned |
| `invalid_sig` | At least one Ed25519 signature does not verify against the recomputed PAE bytes | Reject; the envelope has been tampered with after signing |
| `tampered_subject` | Signatures verify but at least one subject digest does not match the local file's recomputed SHA-256 | Reject; the audit files have been modified since signing |
| `malformed` | The envelope is not parseable as DSSE, the payload is not parseable as in-toto v1, or required fields are missing | Reject; this is not a valid VERIFY attestation |

You MUST surface the specific outcome to the caller. You MUST NOT collapse multiple distinct outcomes into a binary "passed/failed" without preserving the underlying outcome in the response. CI/CD gates, registry admins, and forensic reviewers each need different outcomes to make different decisions.

### What Attestation Proves

- **Integrity** — the audit files have not been modified since signing.
- **Authenticity** — a specific entity (identified by their Ed25519 key) signed the data.
- **Temporal existence** — the signed data existed at the time of attestation (strengthened by OpenTimestamps).

### What Attestation Does NOT Prove

- **Audit data correctness** — the accuracy of manifest entries and annotations is the auditor's responsibility.
- **Code behavior** — attestation covers the audit metadata, not the audited source code itself.
- **Signer trustworthiness** — trust in the signing entity must be established out of band.

---

## 11. Confidence Levels

Attestations in the registry carry one of three confidence levels indicating review depth:

| Level | Description |
|-------|-------------|
| **Self-Attested** | The project maintainer signed their own audit data. No external review. |
| **Manually Validated** | A human reviewer has examined the attestation data for structural integrity, metadata plausibility, and alignment with git history. |
| **Machine Validated** | Automated verification has confirmed hash integrity, signature validity, structural compliance, and cross-referenced audit data against commit history. |

---

## 12. CLI Commands

```bash
# Generate Ed25519 key pair
vibecheck keygen

# Create and submit an attestation
vibecheck attest

# Create attestation with tool provider cosigning
vibecheck attest --cosign-url https://provider.example.com/vibes/sign

# Verify an attestation locally (full Ed25519 verification)
vibecheck verify-attestation

# Verify via API (hash integrity check only)
curl https://itsavibe.ai/api/attestation/verify/{id}
```

---

## 13. Cryptographic Processes

This section is a reviewer-facing index of every place the VIBES family uses cryptography. It is non-normative — every rule referenced here lives in another section or another extension's `*-agent.md`. Use this section to audit *why* the family uses crypto, *where* each use lives, and *what* problem each use solves. Use the linked sections to see the normative MUSTs.

### 13.1 The crypto goals

The VIBES family uses cryptography to provide four properties on audit data, ordered by priority:

1. **Integrity** — audit files cannot be modified after they are sealed without detection.
2. **Authenticity** — a verifier can attribute audit data to a specific signing identity.
3. **Non-repudiation** — a signer cannot plausibly deny having signed the data (subject to the signer's key custody).
4. **Temporal binding** — audit data can be bound to a wall-clock time so claims like "this commit existed before this date" are provable.

The family does NOT use cryptography for confidentiality. Audit data is intended to be public or share-with-stakeholders; there is no encryption layer because the whole point of VIBES is transparency, not secrecy. Tools that want to redact sensitive audit data SHOULD do so at the data-generation layer (omit, hash, or pseudonymize specific fields) rather than encrypting whole files.

### 13.2 Where crypto appears in the family

| Use site | Primitive | Why | Spec section |
|---|---|---|---|
| Content addressing of audit data | SHA-256 over canonical JSON | Deterministic IDs that survive reformatting, copy/paste, and storage round-trips. Two byte-identical contexts always hash to the same id. | VIBES §3.2 (Manifest Hashing) — see `vibes-agent.md` |
| DSSE envelope payload framing | Pre-Authentication Encoding (PAE) | Prevents confused-deputy attacks where a signature over one payload type is reinterpreted as a signature over a different payload type. | §6 |
| User attestation signing | Ed25519 over PAE bytes | Fast, deterministic, 64-byte signature. No nonce-reuse risk. Public key infrastructure is minimal: a 32-byte pubkey is sufficient to verify. | §3, §5, §10 |
| Tool-provider cosigning | Ed25519 over the same PAE bytes | A second, independent signature from the tool itself. Proves the tool generated the audit data in real time, defeating fabrication, post-hoc editing, and tool impersonation. The provider only sees the 32-byte PAE hash, never the data itself. | §9 |
| Attestation content-addressed ID | SHA-256 over canonicalized DSSE envelope JSON | Deterministic envelope IDs so the same envelope produced anywhere always yields the same ID. Enables dedup, cache, and global addressability. | §7 |
| Tool-provider key publication | SPKI PEM + JSON over HTTPS | Standard interop: any verifier can fetch a provider's pubkey, parse it with a standard library, and verify cosignatures without provider cooperation. | §9 |
| TRACE evidence-bundle sealing | Reuses DSSE + Ed25519 + a TRACE-specific predicate type | Same anti-tamper / chain-of-custody mechanism as user attestations, but covering the contents of a sealed incident bundle rather than a project's audit data. TRACE does not introduce new primitives. | TRACE §7 — see `trace-agent.md` |
| Optional temporal anchoring | OpenTimestamps proof anchoring SHA-256 into Bitcoin blockchain | Trust-minimized "this attestation existed at or before block height N" without relying on a trusted timestamp authority. Optional — adds a 1–2 hour latency for block confirmation. | §10 (referenced in `vibecheck attest --timestamp`) |
| Hardware-backed signing | PKCS#11 / Secure Enclave / TPM 2.0 / cloud KMS dispatched to Ed25519 | When operators need non-extractable private keys. The envelope format is unchanged; the hardware is invisible to the verifier. | §5 (Hardware-Backed Keys) |
| CI/CD ephemeral signing | Ephemeral Ed25519 with chain claim back to long-lived org identity, OR OIDC-derived keyless (Sigstore-style) | Pipelines cannot persist long-lived secrets. Both patterns preserve auditability without requiring secret storage in CI. | §5 (CI/CD Ephemeral Keys) |

### 13.3 Where the family does NOT use crypto (and why)

Listing the negatives is as important as listing the positives — it draws the boundary of the trust model clearly:

| Capability | Used? | Why not |
|---|---|---|
| Symmetric encryption of audit data | No | Audit data is intended to be transparent. Encryption defeats the standard's goal. Redaction happens at data-generation. |
| TLS pinning to itsavibe.ai | No | The registry is a thin transparency log, not a trust root. Verifiers trust signatures, not server connections. Any mirror serving the same DSSE envelope is equally valid. |
| Password-based key derivation (PBKDF2 / scrypt / argon2) | No | Keys are generated from OS CSPRNG, not derived from human-memorable secrets. Backup is the user's responsibility. |
| Diffie-Hellman / X25519 key agreement | No | The family is signing-only. No session keys, no encrypted channels. |
| Post-quantum signatures (Dilithium, SPHINCS+) | Not yet | Ed25519 is the current standard. The envelope format (DSSE + in-toto v1) is algorithm-agile via the `keyid` lookup mechanism, so PQ migration is possible without an envelope schema change when the time comes. |
| Threshold signatures (FROST, BLS) | Not yet | A future option for organizations that want multi-party attestation. The DSSE envelope already supports multiple signatures in its `signatures` array; a future PR could add a `keytype: "threshold"` value. |
| Confidential computing attestation (SGX / SEV / TDX quotes) | Not in core | Out of scope for the audit-data layer. Tools running inside TEEs can sign their VIBES output with hardware-backed Ed25519 keys (§5) and that's sufficient. |

### 13.4 The threat model

What the crypto IS designed to defeat:

- **Silent tampering** — modifying audit files after they were signed. SHA-256 file digests + signature over PAE-encoded payload makes this detectable.
- **Confused-deputy attacks** — reinterpreting a signature over one payload type as a signature over another. PAE prevents this by binding the payload type into the signed bytes.
- **Fabrication** — generating fake audit data and presenting it as having come from a real tool. Tool-provider cosigning defeats this by requiring a signature from the tool's infrastructure at data-creation time.
- **Post-hoc editing** — modifying tool-generated audit files before signing. Cosigning defeats this for the same reason — the provider signature was already captured against the original PAE.
- **Tool impersonation** — emitting audit data claiming to be from Tool X when it was actually from Tool Y. The provider's pubkey published at `{provider}/vibes/vibes-signing-keys.json` is the canonical identity; verifiers can reject signatures from unknown providers.

What the crypto does NOT defeat (and why this is OK):

- **Code behavior bugs** — attestation covers the audit metadata, not the audited source code. A vulnerable codebase can be perfectly attested. PRISM exists to score risk independently of attestation.
- **Audit data correctness** — the accuracy of manifest entries and annotations is the auditor's (tool's) responsibility. A buggy or malicious tool can sign garbage data.
- **Compromised tool-provider keys** — if a provider's signing key is stolen, attackers can forge cosignatures. The provider's rotation policy and `valid_until` field limit blast radius but cannot prevent the attack.
- **Colluding user + tool provider** — if both parties cooperate to produce false data, the dual-signature does not help. This is fundamental: at some point the trust chain has to start at humans.
- **Signer trustworthiness** — trust in the signing entity must be established out of band (knowing who controls the signing key, organizational reputation, etc.). The standard provides authenticity, not authority.

### 13.5 The cryptographic libraries we expect implementors to use

Implementors are free to use any compliant library; these are the well-tested baselines for the algorithm/format combos used by the family:

| Language | SHA-256 | Ed25519 | PKCS8 / SPKI PEM parsing | DSSE / in-toto |
|---|---|---|---|---|
| Python | `hashlib` (stdlib) | `cryptography` package | `cryptography` package | `in-toto-attestation`, `pydsse` |
| JavaScript / Node | `crypto` (stdlib) | `crypto` (stdlib, `KeyObject`) | `crypto` (stdlib) | `@in-toto/attestation`, custom |
| Go | `crypto/sha256` (stdlib) | `crypto/ed25519` (stdlib) | `crypto/x509` (stdlib) | `github.com/in-toto/attestation` |
| Rust | `sha2` crate | `ed25519-dalek` crate | `rcgen` / `der` crates | `dsse` crate (community) |

You SHOULD NOT roll your own implementations of any of these primitives. Use the linked libraries.

### 13.6 Where to go for deeper reading

- DSSE spec: https://github.com/secure-systems-lab/dsse
- in-toto v1 attestation: https://github.com/in-toto/attestation
- Ed25519 RFC: https://datatracker.ietf.org/doc/rfc8032/
- OpenTimestamps: https://opentimestamps.org/
- Sigstore (keyless signing reference): https://www.sigstore.dev/
- SHA-256 NIST FIPS 180-4: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf

This section is intentionally a *summary* — every actionable MUST/SHOULD/MAY normative rule lives elsewhere in this document (§3, §5, §6, §7, §9, §10) or in the other extensions' agent docs. The purpose here is the consolidated reviewer view, not a parallel normative track.
