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

  1. 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.

  2. 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).

  3. 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.

  4. 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.

  5. Audit-first. Intent must be logged before execution. The hash chain must be unbroken; any gap is a tampering signal.

  6. Constant-time in all crypto paths. No secret-dependent branching. Tag comparison, key derivation, and decryption must not leak timing information.

  7. Fail secure / default deny. Any authentication or behavioral verification failure must deny access; silence or error must never grant access.

  8. 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.

Back to top

Colibri — documentation-first MCP runtime. Apache 2.0 + Commons Clause.

This site uses Just the Docs, a documentation theme for Jekyll.