Cipher (@ap/crypto)
Shared encryption library for Aloysius Productions. Extracts and consolidates cryptographic primitives from haven and Correspondence Chess Pro into a single reusable npm package. Covers Signal Protocol E2E messaging, AES-256-GCM symmetric encryption, and BIP-39 mnemonic passphrases.
Zone: staging (evaluation) Version: v0.1.0 Package name: @ap/crypto
Overview
Cipher is extracted as a copy — not a move — from the Haven and CCP source apps, both of which remain intact and independent. The goal is a single shared dependency consumable by downstream apps: Meridian, Meridian, the unified chess project, and future Scribe integration.
Tech Stack
| Technology | Version | Purpose |
|---|---|---|
| TypeScript | ^5.6.0 | Language (strict mode) |
| Vitest | ^4.0.18 | Test runner |
| ESLint | ^9.39.2 | Linting (flat config) |
| tweetnacl | ^1.0.3 | Ed25519, Curve25519, XSalsa20-Poly1305 |
| tweetnacl-util | ^0.15.1 | Base64/UTF-8 encoding |
| @privacyresearch/libsignal-protocol-typescript | ^0.0.16 | Signal Protocol Double Ratchet |
| bip39 | ^3.1.0 | BIP-39 mnemonic generation/validation |
| idb | ^8.0.0 | IndexedDB wrapper (optional — WebKeyStorage) |
| expo-secure-store | >=14.0.0 | Mobile key storage (optional peer dep) |
Build: npm run build (tsc). Tests: npm run test (vitest run).
Key Decisions
| Decision | Rationale |
|---|---|
| Extract as copy, not move | Governing principle — Haven and CCP continue independently |
| Signal Protocol + AES-256-GCM | Signal for E2E messaging; AES-256 for symmetric use cases (game state, settings) |
| PBKDF2 at 150k iterations (symmetric) / 100k (settings) | Symmetric exceeds OWASP 2023 minimum (120k); settings acceptable with additional auth layers |
| BIP-39 over custom wordlist | CCP had a 26-word list (~18 bits entropy); BIP-39 gives 128+ bits with standard tooling |
| Vitest over Jest | Ecosystem standardized on Vitest across AP (Aura, CCP, Eliza all use it) |
Reusable Patterns
Three interfaces extracted from Cipher are documented as standalone patterns in the vault:
- encryptedpayload-type — Standard shape for passphrase-encrypted data:
salt + iv + data + version tag - CryptoBackend interface — Swappable crypto primitives; TweetNaCl default, extensible to WebCrypto
- KeyStorage interface — Platform-agnostic key persistence: Web (IndexedDB), Mobile (SecureStore), Memory (test)
See also: cryptographic-key-exchange for Signal Protocol X3DH context.
Current Status
Phase: Active Development Tests: 143 passing (as of 2026-02-16) CI/CD: security.yml configured, CI not yet run (flaky)
Completed
- Initial extraction from Haven + CCP (2026-02-06)
- Comprehensive audit — 113 tests, security fixes applied (2026-02-15)
- ESLint flat config, constant-time comparison, Haven→Cipher rebranding (2026-02-16)
- Phase 2 tests: X3DH round-trip, forward secrecy, bidirectional session encryption (2026-02-16)
Remaining
- Import path standardization — add
.jsextensions for pure ESM compliance (deferred; bundler resolution works) - Publish for consumption by downstream apps (Meridian, chess merge)
- X3DH
respondX3DHshared secret round-trip test (open) - Storage module excluded from build due to browser-only APIs (low priority)
Technical Debt
| Item | Priority | Status |
|---|---|---|
| X3DH respondX3DH shared secret untested | High | Open |
| Storage module excluded from build | Low | Open |
| ESLint non-null assertions in storage (20 warnings) | Low | Open |
Import path inconsistency (.js extensions) | Low | Deferred |
Integration Points
| Consumer | Status |
|---|---|
| Meridian | Planned |
| Chess (unified) | Planned |
| Scribe | Queued |
| cards-and-games | Queued |