# Key Management for Humans

Sanna uses Ed25519 keys to sign constitutions, receipts, and approval records. This document covers the practical aspects of generating, storing, rotating, and recovering from key loss.

## What Keys Are and Why They Matter

Every signed artifact in Sanna — constitutions, receipts, approval records — carries an Ed25519 signature. The signature proves:

1. **Who** generated or approved the artifact (the signer's identity)
2. **Integrity** — the artifact has not been modified since signing

Keys come in pairs:

- **Private key** (`.key`): Used to create signatures. Never share.
- **Public key** (`.pub`): Used to verify signatures. Distribute freely.

## Generating Keys

```bash
sanna-keygen --signed-by "you@company.com" --label gateway
```

This creates two files in `~/.sanna/keys/`:

```
~/.sanna/keys/
  <key-id>.key         # Private key (PEM format)
  <key-id>.pub         # Public key (PEM format)
  <key-id>.key.meta.json   # Metadata sidecar
```

The `<key-id>` is the SHA-256 fingerprint of the public key (64 hex characters). This provides a stable, globally unique identifier for each keypair.

The `--label` flag adds a human-readable name to the metadata sidecar, making it easier to identify keys in multi-key environments:

```json
{
  "key_id": "a1b2c3d4...",
  "signed_by": "you@company.com",
  "label": "gateway",
  "created_at": "2026-02-14T18:00:00+00:00"
}
```

## Storing Keys

### Private keys

- Never commit to git (add `*.key` to `.gitignore`)
- Never share over email, Slack, or any unencrypted channel
- Store in a directory with restricted permissions (`chmod 600`)
- For production: use your organization's secrets manager (Vault, AWS KMS envelope encryption, etc.)

### Public keys

- Share freely with anyone who needs to verify your artifacts
- Commit to your repository if convenient
- Distribute to auditors, compliance teams, CI/CD pipelines
- Include in evidence bundles for self-contained verification

### Recommended directory layout

```
~/.sanna/keys/          # Default location for all keypairs
project/
  constitutions/        # Signed constitution YAML files
  receipts/             # Generated receipt JSON files
  public_keys/          # Public keys for verification
```

## Key Roles

Different operations use different keys. In a typical setup:

| Key | Who Holds It | What It Signs |
|-----|-------------|---------------|
| Author key | Constitution author | Constitution document |
| Approver key | Tech lead / reviewer | Approval records |
| Gateway key | Gateway process | Receipts generated by the gateway |

These can be the same key for small teams, or separate keys for separation of duties.

```bash
# Author signs the constitution
sanna-keygen --signed-by "author@team.dev" --label author
sanna-sign-constitution constitution.yaml --private-key ~/.sanna/keys/<author-key-id>.key

# Approver approves it
sanna-keygen --signed-by "lead@team.dev" --label approver
sanna-approve-constitution constitution.yaml \
  --approver-id "lead@team.dev" \
  --approver-role "tech-lead" \
  --private-key ~/.sanna/keys/<approver-key-id>.key

# Gateway uses its own key for receipts
sanna-keygen --signed-by "gateway@team.dev" --label gateway
# (configured in gateway.yaml → signing_key)
```

## What Happens If You Lose a Key

### Lost private key (not compromised)

- Old receipts and constitutions remain verifiable with the old public key
- Generate a new keypair
- Re-sign your constitution with the new key
- Update your gateway config to use the new signing key
- No need to re-verify or re-generate old receipts — they are immutable artifacts

### Compromised private key

- **Rotate immediately**: generate a new keypair
- Re-sign your constitution
- Update all gateway configs
- Old receipts signed with the compromised key are technically suspect — an attacker with the private key could have forged receipts
- If receipts are stored with timestamps from a trusted source (e.g., receipt store), you can establish a trust boundary at the time of compromise

## Key Rotation

Planned key rotation follows the same pattern as lost key recovery:

```bash
# 1. Generate new keypair
sanna-keygen --signed-by "team@company.com" --label gateway-2026q2

# 2. Re-sign constitution with new key
sanna-sign-constitution constitution.yaml --private-key ~/.sanna/keys/<new-key-id>.key

# 3. Update gateway config
# gateway.yaml → signing_key: ~/.sanna/keys/<new-key-id>.key

# 4. Restart gateway
```

Old receipts remain verifiable with the old public key. Sanna receipts include a `key_id` field that identifies which key signed them, so verifiers can select the correct public key automatically.

## Multi-Key Environments

In environments with multiple keys (e.g., separate author, approver, and gateway keys), verification commands accept key-specific flags:

```bash
# Verify receipt with gateway's public key
sanna-verify receipt.json --public-key <gateway-key-id>.pub

# Verify full chain with all keys
sanna-verify receipt.json \
  --public-key <gateway-key-id>.pub \
  --constitution constitution.yaml \
  --constitution-public-key <author-key-id>.pub

# Evidence bundles resolve keys independently by key_id
sanna-create-bundle \
  --receipt receipt.json \
  --constitution constitution.yaml \
  --public-key <gateway-key-id>.pub \
  --constitution-public-key <author-key-id>.pub \
  --output evidence.zip
```

The bundle verifier matches each artifact to its signing key using the `key_id` field — no manual key selection needed during verification.

## Loading Key Metadata

Programmatically access key metadata:

```python
from sanna.crypto import load_key_metadata

meta = load_key_metadata("~/.sanna/keys/<key-id>.key")
# meta["key_id"], meta["signed_by"], meta["label"], meta["created_at"]
```
