ElderState — Prompt Security Extraction
Source: CogniMesh
ElderState/(TypeScript). Extracted 2026-04-08. After R50: source directory safe to delete (content fully captured here).
Algorithm Summary
ElderState is a defense-in-depth prompt encryption and behavioral keying system for Large Language Model applications. It protects LLM system prompts and conversation history through authenticated encryption (XChaCha20-Poly1305), a three-tier key hierarchy, and behavioral keying that ties decryption to expected model behavior patterns. All operations produce tamper-evident audit trails via SHA-256 hash chains and RFC 6962 Merkle trees.
Core Architecture
The system is organized into five security layers stacked in a defense-in-depth pattern:
Layer 1 — Input Validation & Perimeter Control
• Perplexity-based filtering of adversarial queries
• Known attack pattern detection (PLeak signatures, encoding tricks)
• Input sanitization before any prompt processing
Layer 2 — AEAD Encryption (XChaCha20-Poly1305)
• Prompt plaintext → ciphertext with 256-bit key
• 192-bit random nonce per encryption (safe, no counter state needed)
• Associated data (version, context binding) authenticated but not encrypted
Layer 3 — Access Control (RBAC + ABAC)
• Role-Based Access Control for user/service permissions
• Attribute-Based Access Control for context-dependent rules
• Behavioral fingerprint verification before key release
Layer 4 — Tamper-Evident Audit (Hash Chains + Merkle Trees)
• Every operation logged before execution (audit-first pattern)
• SHA-256 hash chain links entries sequentially
• Periodic Merkle checkpoints (1000-entry batches) for O(log n) proofs
Layer 5 — Behavioral Verification
• Secret prefix unlocking controls model behavior elicitation
• Anomaly detection flags unusual query patterns
• Failed behavioral checks trigger key eviction
The domain layer beneath these security controls divides into: Encryption Domain (EPA format, token obfuscation), Key Management (HKDF hierarchy, rotation), Audit Domain (Merkle trees, attestations), and Behavioral Keying (secret prefixes, verification). Infrastructure provides persistence via SQLite and MCP transport for AI tool ecosystem integration.
Encryption Algorithm
Primary cipher: XChaCha20-Poly1305 (AEAD)
Parameters:
Key size: 256 bits (32 bytes)
Nonce size: 192 bits (24 bytes) — XChaCha20 extended nonce
Tag size: 128 bits (16 bytes) — Poly1305 MAC
Block size: 512 bits (64 bytes) — ChaCha block
Encryption pseudocode:
def xchacha20_poly1305_encrypt(key, nonce, plaintext, aad=b''):
# Step 1 — Generate one-time Poly1305 subkey
subkey = xchacha20_block(key, nonce, counter=0)[:32]
# Step 2 — Encrypt plaintext with keystream (counter=1)
ciphertext = xchacha20_crypt(key, nonce, plaintext, counter=1)
# Step 3 — Compute authentication tag over aad + ciphertext
tag = poly1305_mac(subkey, aad, ciphertext)
return (ciphertext, tag)
def xchacha20_poly1305_decrypt(key, nonce, ciphertext, tag, aad=b''):
subkey = xchacha20_block(key, nonce, counter=0)[:32]
# Constant-time MAC verification before any decryption
expected_tag = poly1305_mac(subkey, aad, ciphertext)
if not constant_time_equal(tag, expected_tag):
raise AuthenticationError() # Never reveal which byte failed
plaintext = xchacha20_crypt(key, nonce, ciphertext, counter=1)
return plaintext
Key derivation stack:
Password/behavioral factor
│
▼ Argon2id (memory-hard KDF)
│ dev: m=65536 (64MB), t=2, p=1
│ prod: m=262144 (256MB), t=4, p=2
│ paranoid: m=524288 (512MB), t=6, p=4
│ salt: 16 bytes random per derivation
▼
256-bit raw key material
│
▼ HKDF-SHA256 (domain separation)
▼
Data Encryption Key (DEK) + Behavioral Verification Key
Why XChaCha20 over AES-256-GCM: AES-GCM’s 96-bit nonce limits safe random generation to ~2^32 messages before birthday-bound collision risk. XChaCha20’s 192-bit nonce makes random nonce generation unconditionally safe. AES-GCM nonce reuse is catastrophic (full key recovery + forgery); XChaCha20’s ARX structure also provides better software-only timing resistance than AES S-box implementations without AES-NI hardware.
Behavioral Keying
Behavioral keying ties prompt decryption to expected model behavior, preventing decryption even with a stolen encryption key unless the behavioral context matches.
Secret prefix mechanism (MVP v1):
1. A secret prefix string (the "behavioral key") is selected at EPA creation time.
The prefix acts as a trainable trigger that elicits specific model behavior.
2. The prefix is incorporated into DEK derivation:
DEK = HKDF-SHA256(Argon2id(password, salt), info=behavioral_fingerprint)
3. At runtime, the model must present the correct prefix context before
decryption is authorized:
- Valid prefix present → release DEK → decrypt prompt → model behavior unlocked
- Invalid/absent prefix → key eviction → access denied
4. Rotation: behavioral keys rotate per-prompt or per-session;
loss of behavioral key = permanent loss of access (no recovery path)
Future v2 (deferred): Soft prompt vectors — secret prefix replaced with trained continuous embedding vectors injected at intermediate LLM layers (SysVec-style). Prevents textual extraction since the prompt never appears in the token context window.
Anti-extraction properties: Behavioral keying defeats PLeak-style attacks (68% reconstruction rate on unprotected systems) because the encrypted prompt ciphertext is meaningless without the behavioral fingerprint, and the fingerprint is never transmitted in plaintext.
Encrypted Prompt Artifact (EPA) Format
An EPA is a versioned, self-contained encrypted prompt bundle with embedded key material and audit linkage.
EPA structure (envelope encryption):
{
"version": "1", // Schema version
"epa_id": "<uuid>", // Unique artifact identifier
"created_at": "<ISO-8601-ns>", // Nanosecond timestamp
// Encrypted prompt payload
"ciphertext": "<base64>", // XChaCha20-Poly1305 output
"nonce": "<hex:48chars>", // 192-bit random nonce
"tag": "<hex:32chars>", // 128-bit Poly1305 MAC
"aad": "elderstate:v1", // Authenticated associated data
// Envelope key material (DEK encrypted under KEK)
"encrypted_dek": "<base64>", // AES-256-KW(KEK, DEK)
"kek_version": "<semver>", // Which KEK tier to use for unwrap
// Key derivation parameters (for DEK re-derivation from password)
"kdf": {
"algorithm": "argon2id",
"memory": 65536, // 64MB (dev) or 262144 (prod)
"iterations": 3,
"parallelism": 4,
"salt": "<hex:32chars>" // 16-byte random salt
},
// Audit linkage
"prev_audit_hash": "<sha256-hex>", // Links to preceding audit entry
"behavioral_hint": "<opaque>", // Non-revealing fingerprint hint
// Token obfuscation metadata (optional, v1)
"obfuscation": {
"permutation_seed": "<hex>", // Seed for token ID permutation
"vigenere_key_ref": "<key-id>" // Reference to stream cipher key
}
}
Rotation without re-encryption: When KEK rotates, existing DEKs remain decryptable using the old KEK version (referenced in kek_version). New EPAs use the new KEK. Historical data is never bulk re-encrypted.
Audit Trail
The audit system implements a three-layer tamper-evidence architecture:
Layer 1 — Hash Chain (per session, sequential):
entry_hash = SHA256(
prev_hash || // Chaining — any gap is detectable
action || // ENCRYPT, DECRYPT, KEY_ROTATE, KEY_EVICT, etc.
timestamp || // ISO-8601 with nanoseconds
resource_hash // SHA256 of the EPA or key being operated on
)
Layer 2 — Merkle Tree (periodic checkpoint, 1000-entry batches):
Leaf node: SHA256(0x00 || entry_hash) // Prefix prevents second-preimage
Internal node: SHA256(0x01 || left || right) // RFC 6962 construction
Proof size at depth 20 (1M leaves): 640 bytes
Verification complexity: O(log n) vs O(n) for raw chain scan
Layer 3 — External Anchor (optional):
- Blockchain (Bitcoin/Ethereum) for long-term immutability
- Certificate Transparency (RFC 6962 log integration)
- Corporate PKI (signed Merkle roots)
Database schema (key tables):
audit_log(entry_id, session_id, step_index, timestamp, action,
actor_type, actor_id, resource_id, resource_hash,
prev_hash, entry_hash, merkle_root, proof_data)
merkle_tree(tree_id, level, position, node_hash,
left_hash, right_hash, entry_count, created_at)
audit_anchors(anchor_id, tree_id, merkle_root, anchor_type,
anchor_reference, anchored_at)
Audit-first execution pattern (adopted from AMS): intent is logged before execution; result is logged after with reference back to intent entry. Even system crashes leave a partial audit trail.
Key Constants
| Constant | Value | Notes |
|---|---|---|
| Key size | 32 bytes (256 bits) | XChaCha20-Poly1305 symmetric key |
| Nonce size | 24 bytes (192 bits) | Extended nonce; safe for random generation |
| MAC tag size | 16 bytes (128 bits) | Poly1305 authentication tag |
| Salt size | 16 bytes (128 bits) | Argon2id per-derivation salt |
| Argon2id memory (dev) | 65,536 KB = 64 MB | OWASP 2025 minimum |
| Argon2id memory (prod) | 262,144 KB = 256 MB | Recommended production |
| Argon2id memory (paranoid) | 524,288 KB = 512 MB | Maximum security |
| Argon2id iterations (dev) | 2 | |
| Argon2id iterations (prod) | 4 | |
| Argon2id parallelism (dev) | 1 thread | |
| Argon2id parallelism (prod) | 2 threads | |
| DEK rotation period | 90 days | Or on behavioral key rotation |
| KEK rotation period | 2 years | Automatic |
| Master key lifetime | 5+ years | Manual ceremony only |
| Merkle batch size | 1,000 entries | Per checkpoint tree |
| Max message size | 256 GB | Per nonce (theoretical) |
| Behavioral key entropy minimum | 128 bits | Required for DEK binding |
| Key derivation target latency | ~500 ms | At 256MB Argon2id |
| Encryption target latency | < 50 ms | Per prompt |
| Decryption target latency | < 30 ms | Per prompt |
Invariants
-
Never reuse a nonce with the same key. Both AES-GCM and XChaCha20-Poly1305 are broken catastrophically by nonce reuse. XChaCha20’s 192-bit nonce space makes accidental collision negligible, but this remains a hard invariant.
-
Verify MAC before decryption. The Poly1305 tag must pass constant-time verification before any plaintext is produced. Failure must not reveal which byte caused the mismatch (timing-safe comparison mandatory).
-
Never log keys. Encryption keys, Argon2id output, or behavioral fingerprint material must never appear in logs, error messages, or debug output. Automated scans must enforce this before every release.
-
Behavioral key loss is permanent. There is no recovery path for a lost behavioral key. Organizational key escrow must be decided at deployment time; it cannot be added later.
-
Audit-first. Intent must be logged before execution. The hash chain must be unbroken; any gap is a tampering signal.
-
Constant-time in all crypto paths. No secret-dependent branching. Tag comparison, key derivation, and decryption must not leak timing information.
-
Fail secure / default deny. Any authentication or behavioral verification failure must deny access; silence or error must never grant access.
-
Envelope encryption for rotation. DEKs are encrypted under KEKs and stored with the EPA. Key rotation creates new KEKs; old KEKs remain available to read historical EPAs. Bulk re-encryption is not required.
Colibri Integration Points
ξ Identity (primary target): ElderState’s behavioral keying maps directly to Colibri’s ξ (xi) Identity concept — identity verified not by possession of a credential but by behavioral pattern. The secret prefix mechanism is the MVP implementation of “identity as behavior.” The planned soft prompt vector upgrade aligns with ξ’s deeper soul-as-embedding vision.
η Proof Store: ElderState’s three-layer audit architecture (hash chain → Merkle tree → external anchor) is a reference implementation of η (eta) Proof Store. The SHA-256 hash chain construction, RFC 6962 Merkle leaf/node hashing, and the ADR-005 database schema all translate directly. Merkle proof size (640 bytes at depth 20) and O(log n) verification were validated in ElderState research and can be adopted verbatim.
ζ Decision Trail: Every ElderState operation — encrypt, decrypt, key rotate, key evict — produces an audit entry. This matches ζ (zeta) Decision Trail’s requirement for tamper-evident action logging. The audit-first pattern (log intent → execute → log result → link hashes) is the execution model ζ should implement.
δ Model Router: Token obfuscation research (Vigenère-style stream cipher in token space, token ID permutation) is relevant to δ (delta) Model Router if Colibri ever needs to protect routing decisions or model configurations from extraction. The permutation pipeline (Tokenize → Permute → Vigenère → XChaCha20) is documented and ready to adapt.
Colibri adoption path:
- Phase 1: Adopt EPA format and XChaCha20+Argon2id stack for any prompt or configuration that must be stored encrypted.
- Phase 2: Wire behavioral keying (secret prefix) into ξ identity verification flow.
- Phase 3: Replace secret prefix with soft prompt vectors once model API support is confirmed (v2 scope per ElderState roadmap).
- Ongoing: All audit entries feed η Proof Store and ζ Decision Trail via the hash chain / Merkle architecture.