An easy-to-host PDS on the ATProtocol, MacOS. Grandma-approved.

docs: update project context for MM-92 relay signing key generation

Add crypto crate CLAUDE.md (new public API: P-256 keygen, AES-256-GCM
encrypt/decrypt, did:key derivation). Update db CLAUDE.md with V003
migration. Update root CLAUDE.md crypto crate description.

authored by malpercio.dev and committed by

Tangled bf1284dc c54d8b71

+31 -1
+1 -1
CLAUDE.md
··· 31 31 ## Project Structure 32 32 - `crates/relay/` - Web relay (axum-based) 33 33 - `crates/repo-engine/` - ATProto repo engine 34 - - `crates/crypto/` - Cryptographic operations 34 + - `crates/crypto/` - Cryptographic operations (P-256 key generation, did:key derivation, AES-256-GCM encryption) 35 35 - `crates/common/` - Shared types and utilities 36 36 - `nix/` - Nix packaging and deployment (docker.nix: container image; module.nix: NixOS module) 37 37 - `docs/` - Specs, design plans, implementation plans
+29
crates/crypto/CLAUDE.md
··· 1 + # Crypto Crate 2 + 3 + Last verified: 2026-03-11 4 + 5 + ## Purpose 6 + Provides cryptographic primitives for the ezpds workspace: P-256 key generation, 7 + did:key derivation, and AES-256-GCM encryption/decryption of private key material. 8 + This is a pure functional core -- no I/O, no database, no config. 9 + 10 + ## Contracts 11 + - **Exposes**: `generate_p256_keypair() -> Result<P256Keypair, CryptoError>`, `encrypt_private_key(&[u8; 32], &[u8; 32]) -> Result<String, CryptoError>`, `decrypt_private_key(&str, &[u8; 32]) -> Result<Zeroizing<[u8; 32]>, CryptoError>`, `P256Keypair`, `CryptoError` 12 + - **P256Keypair fields**: `key_id` (full `did:key:z...` URI), `public_key` (multibase base58btc compressed point, no did:key: prefix), `private_key_bytes` (`Zeroizing<[u8; 32]>` -- zeroized on drop) 13 + - **Encryption format**: `base64(nonce(12) || ciphertext(32) || tag(16))` = 80 base64 chars. Fresh 12-byte nonce from OS RNG per call. 14 + - **did:key format**: P-256 multicodec varint `[0x80, 0x24]` + compressed public key, multibase base58btc encoded 15 + - **CryptoError variants**: `KeyGeneration`, `Encryption`, `Decryption`, `InvalidKeyId` 16 + 17 + ## Dependencies 18 + - **Uses**: p256 (ECDSA/key generation), aes-gcm (AES-256-GCM), multibase (base58btc encoding), rand_core (OS RNG), base64 (storage encoding), zeroize (secret cleanup) 19 + - **Used by**: `crates/relay/` (key generation endpoint) 20 + 21 + ## Invariants 22 + - Private key bytes are always wrapped in `Zeroizing` -- callers must not copy them into non-zeroizing storage 23 + - `encrypt_private_key` always generates a fresh nonce; two calls with identical input produce different ciphertext 24 + - `decrypt_private_key` returns a single opaque `CryptoError::Decryption` for all failure modes (no oracle) 25 + 26 + ## Key Files 27 + - `src/lib.rs` - Re-exports public API 28 + - `src/keys.rs` - P-256 key generation, AES-256-GCM encrypt/decrypt 29 + - `src/error.rs` - CryptoError enum
+1
crates/relay/src/db/CLAUDE.md
··· 32 32 - `mod.rs` - Pool creation, migration runner, DbError, tests 33 33 - `migrations/V001__init.sql` - server_metadata table (WITHOUT ROWID) 34 34 - `migrations/V002__auth_identity.sql` - 12 Wave 2 tables: accounts, handles, did_documents, signing_keys, devices, claim_codes, sessions, refresh_tokens, oauth_clients, oauth_authorization_codes, oauth_tokens, oauth_par_requests 35 + - `migrations/V003__relay_signing_keys.sql` - relay_signing_keys table (WITHOUT ROWID, keyed by did:key URI) for operator-level relay signing keys (not tied to a specific account DID)