LangChain Integration: XorIDA-Secured Agent Communication
Four modules transform LangChain.js agents into information-theoretically secure systems: XorIDA-split messaging, encrypted conversation memory, Ed25519 DID identity, and HMAC-chained audit trails. Web Crypto API only. HMAC verification before reconstruction. Zero npm dependencies.
Executive Summary
@privateme/langchain is a LangChain.js adapter that brings information-theoretic security to AI agent communication via XorIDA threshold secret sharing over GF(2).
LangChain agents operate in distributed, multi-step workflows where messages, memory, and actions cross network boundaries. Traditional encryption protects data in transit, but provides no defense if a single channel is compromised. This adapter changes the equation: messages are split into shares where any K-1 or fewer shares reveal exactly zero information about the plaintext, regardless of computing power available to an attacker.
Four modules cover the integration surface: SecureMessage splits plaintext into XorIDA shares with HMAC-SHA256 signatures, SecureMemory provides XorIDA-protected conversation history with automatic eviction, AgentIdentity generates Ed25519 DID identities via Web Crypto API, and AuditCallback creates tamper-evident HMAC chains for agent action logs. All functions use the Result<T, E> pattern — no thrown exceptions, no silent failures.
Zero npm runtime dependencies. Runs anywhere the Web Crypto API is available: Node.js 20+, Deno, Bun, Tauri, modern browsers. Every cryptographic operation uses crypto.subtle or crypto.getRandomValues() — no Math.random(), no Node.js-only crypto modules, no third-party libraries. HMAC verification always completes before reconstruction (fail closed).
Developer Experience
Clean API surface with structured error handling and no thrown exceptions.
Quick Start
import { createAgentIdentity, createSecureMessage, reconstructSecureMessage, createSecureMemory, createAuditCallback, } from '@privateme/langchain'; // Create agent identities const alice = (await createAgentIdentity({ name: 'Alice' })).value!; const bob = (await createAgentIdentity({ name: 'Bob' })).value!; // Alice sends a XorIDA-split secure message to Bob const msg = (await createSecureMessage('Hello Bob!', bob.did)).value!; // Bob reconstructs (HMAC verified before reconstruction) const text = (await reconstructSecureMessage( msg.shares, msg.hmacKeys, msg.hmacSignatures )).value!; console.log(text); // 'Hello Bob!' // Store conversation in encrypted memory const memory = createSecureMemory({ n: 3, k: 2, maxEntries: 100 }); await memory.addEntry({ role: 'ai', content: text, timestamp: Date.now() }); // Audit trail with HMAC chain const audit = createAuditCallback({ agentDid: alice.did }); await audit.onAction('send_message', { recipient: bob.did }); const valid = (await audit.verifyChain()).value!; // true
Result Pattern
All async functions return Promise<Result<T, E>>. A Result is either { ok: true, value: T } or { ok: false, error: E }. This eliminates the need for try-catch blocks and makes error handling explicit at the call site.
const result = await createSecureMessage('payload', recipientDid); if (result.ok) { // Success path const { shares, hmacKeys, hmacSignatures } = result.value; // Send shares... } else { // Error path console.error('Split failed:', result.error); }
Error Codes
Seven structured error codes cover all failure modes. Error strings are machine-readable and map to specific failure scenarios.
| Code | Module | When |
|---|---|---|
| SPLIT_FAILED | SecureMessage | XorIDA split operation fails |
| RECONSTRUCT_FAILED | SecureMessage | Reconstruction fails (insufficient shares, bad padding) |
| HMAC_FAILED | SecureMessage | HMAC verification fails before reconstruction |
| IDENTITY_FAILED | AgentIdentity | Ed25519 key generation fails |
| INVALID_CONFIG | SecureMessage | Invalid n/k parameters (n < 2, k < 2, or k > n) |
| AUDIT_CHAIN_BROKEN | AuditCallback | HMAC chain integrity verification fails |
The Problem
LangChain agents face three security challenges: message confidentiality across untrusted transports, conversation memory that survives compromise of a single storage backend, and auditability without a centralized trust anchor.
Challenge 1: Agent-to-Agent Messages
Multi-agent LangChain workflows send messages between autonomous agents operating in different security contexts. Traditional TLS encryption protects data in transit, but the plaintext exists in full at both endpoints and on any intermediate relay. If any single channel is compromised, the attacker gains complete access to the message content.
XorIDA threshold sharing solves this. A message split into 3 shares where any 2 reconstruct means an attacker who compromises 1 share learns zero bits about the plaintext. This is not computational security (slow to break), it is information-theoretic security (mathematically impossible to break). XorIDA operates over GF(2), the binary finite field, making this property provable.
Challenge 2: Conversation Memory
LangChain agents maintain conversation history to preserve context across turns. Storing this history in a single database creates a single point of compromise. Encrypting the database with AES-256 helps, but if the encryption key is compromised, the entire history is exposed.
SecureMemory splits every entry via XorIDA. With a 2-of-3 configuration, each memory entry is stored across 3 backends. An attacker who compromises 1 backend gets shares that reveal nothing. The attacker must compromise 2 of 3 backends to reconstruct any entry. This raises the bar from "break one database" to "break two independent systems simultaneously."
Challenge 3: Audit Trails
Multi-agent systems need tamper-evident logs: who did what, when, and in what order. Traditional append-only logs can be modified by an attacker with write access. Cryptographic signatures prevent forgery of new entries, but do not prevent deletion or reordering of existing entries.
AuditCallback creates HMAC hash chains. Each audit entry includes an HMAC covering its own data plus the HMAC of the previous entry. Modifying any entry invalidates all subsequent HMACs. Deleting an entry breaks the chain. Reordering entries breaks the chain. The entire chain is verifiable in a single pass with verifyChain(), which replays from the first entry and checks every HMAC using constant-time comparison (crypto.subtle.verify()).
Use Cases
Four deployment patterns where information-theoretic security changes the threat model.
LangChain agents coordinate patient data across electronic health records, lab systems, and insurance APIs. XorIDA-split messages ensure that compromising a single API endpoint or agent process reveals zero PHI. HIPAA compliance via threshold splitting.
HIPAALegal research agents query case law databases, draft documents, and summarize depositions. Conversation memory split across 3 backends (cloud, on-prem, attorney laptop) ensures that no single compromise exposes privileged communications.
PrivilegeDefense and intelligence agencies deploy LangChain agents to analyze classified data streams. XorIDA splitting means that intercepting any single communication channel yields zero actionable intelligence. Information-theoretic security for national security workloads.
ClassifiedTrading agents coordinate across brokers, clearinghouses, and compliance systems. Audit trails with HMAC chains provide tamper-evident logs for SEC 17a-4 and FINRA compliance. Non-repudiation via Ed25519 signatures. Replay prevention via nonce tracking.
SOXIntegration Scenarios
| Scenario | Module | Configuration |
|---|---|---|
| Agent-to-agent messages | SecureMessage | 2-of-3 split (default) |
| Conversation history | SecureMemory | 3 backends, 100 entry LRU |
| Action logging | AuditCallback | HMAC-SHA256 chain |
| Identity management | AgentIdentity | Ed25519 DID (did:key:z6Mk...) |
Architecture
Four independent modules with minimal coupling. All crypto via Web Crypto API.
SecureMessage
createSecureMessage(content, recipientDid, n?, k?) encodes content to UTF-8, pads to the XorIDA block size (nextOddPrime(n) - 1 via PKCS#7), splits into n shares where any k can reconstruct, and generates an HMAC-SHA256 signature for each share. Returns shares, HMAC keys, HMAC signatures, sender DID, and timestamp.
reconstructSecureMessage(shares, hmacKeys, hmacSignatures, n?, k?, indices?) verifies all HMACs first (fail closed — if any HMAC check fails, reconstruction is rejected and no plaintext is returned), reconstructs via XorIDA, unpads via PKCS#7, and decodes back to UTF-8 string. If fewer than k shares are provided, returns RECONSTRUCT_FAILED. If any HMAC fails, returns HMAC_FAILED before attempting reconstruction.
SecureMemory
createSecureMemory(config?) creates a conversation memory instance with in-memory plaintext cache and XorIDA-split export. Configuration: n (total shares, default 3), k (threshold, default 2), maxEntries (LRU eviction, default unlimited).
addEntry(entry) serializes a MemoryEntry to JSON, splits it via createSecureMessage(), and caches both the plaintext and the split output. If maxEntries is exceeded, the oldest entry is evicted (FIFO). Returns the split output for external storage.
getHistory() returns all plaintext entries from the in-memory cache in chronological order. Fast retrieval for LangChain context window assembly.
exportSplit() returns all shares and HMACs for the entire history. Use this to persist conversation memory across 3 independent backends (e.g., local disk, cloud storage, HSM).
AgentIdentity
createAgentIdentity(config?) generates an Ed25519 keypair via crypto.subtle.generateKey('Ed25519', true, ['sign', 'verify']). Exports the public key as raw bytes, prefixes with the Ed25519 multicodec varint (0xed01), encodes as base58btc, and wraps in a did:key:z6Mk... DID string per the W3C DID specification.
If Ed25519 is not available in the runtime (older browsers, some embedded environments), the function falls back to generating a random 32-byte identity via crypto.getRandomValues(). This synthetic identity is not a real Ed25519 key, but provides a unique DID for agent identification in constrained environments.
AuditCallback
createAuditCallback(config) initializes an HMAC-chained audit handler with an in-memory entry list and a lazily-generated HMAC key. Configuration: agentDid (required), includePrompts (default false), includeResponses (default false).
onAction(action, details?) records an action by computing HMAC-SHA256 over (action + agentDid + timestamp + previousHmac). The first entry has an empty previousHmac. Each subsequent entry's HMAC covers its own data plus the HMAC of the previous entry, forming a tamper-evident chain.
verifyChain() replays the chain from the first entry, recomputing each HMAC and comparing to the stored value using crypto.subtle.verify() (constant-time comparison). If any HMAC mismatch is detected, or if the previousHmac chain is broken, returns AUDIT_CHAIN_BROKEN. Otherwise returns true.
@private.me/crypto (XorIDA, HMAC, padding) and @private.me/shared (Result<T,E>, ok(), err()). No module depends on any other module in this package. They compose at the application layer, not at the package layer.
Integration Patterns
Three integration patterns for different LangChain deployment scenarios.
Pattern 1: LangChain Tool Integration
Wrap createSecureMessage and reconstructSecureMessage as LangChain tools. Agents can invoke them via tool calls during autonomous workflows.
import { Tool } from '@langchain/core/tools'; import { createSecureMessage } from '@privateme/langchain'; class SecureMessageTool extends Tool { name = 'send_secure_message'; description = 'Send an information-theoretically secure message via XorIDA'; async _call(input: string): Promise<string> { const { content, recipientDid } = JSON.parse(input); const result = await createSecureMessage(content, recipientDid); if (!result.ok) { return `Error: ${result.error}`; } // Send shares to independent channels... return 'Message sent via 3 independent channels'; } }
Pattern 2: Custom Memory Backend
Replace LangChain's default memory with SecureMemory. Conversation history is XorIDA-split and stored across multiple backends.
import { BaseChatMemory } from '@langchain/core/memory'; import { createSecureMemory } from '@privateme/langchain'; class XorIDAMemory extends BaseChatMemory { private memory = createSecureMemory({ n: 3, k: 2, maxEntries: 100 }); async saveContext(input: string, output: string) { await this.memory.addEntry({ role: 'human', content: input, timestamp: Date.now(), }); await this.memory.addEntry({ role: 'ai', content: output, timestamp: Date.now(), }); } async loadMemoryVariables() { const history = this.memory.getHistory(); return { history }; } }
Pattern 3: Audit Callback Hook
Attach AuditCallback to LangChain's callback system. Every agent action is logged in a tamper-evident HMAC chain.
import { BaseCallbackHandler } from '@langchain/core/callbacks'; import { createAuditCallback } from '@privateme/langchain'; class AuditHandler extends BaseCallbackHandler { private audit = createAuditCallback({ agentDid: 'did:key:z6Mk...' }); async handleLLMStart(llm, prompts) { await this.audit.onAction('llm_start', { model: llm.name }); } async handleLLMEnd(output) { await this.audit.onAction('llm_end', { tokens: output.usage }); } async handleToolStart(tool, input) { await this.audit.onAction('tool_start', { tool: tool.name }); } } // Verify chain integrity at any time const valid = await auditHandler.audit.verifyChain();
Security Properties
Five security properties enforced across all modules.
| Property | Mechanism | Guarantee |
|---|---|---|
| Information-theoretic | XorIDA over GF(2) | K-1 shares reveal zero bits (provable) |
| Integrity | HMAC-SHA256 per share | Tampering detected before reconstruction |
| Fail closed | HMAC before reconstruct | No partial plaintext on HMAC failure |
| Tamper-evident logs | HMAC hash chain | Modifying any entry breaks all subsequent HMACs |
| Identity | Ed25519 DID (did:key:z6Mk...) | Verifiable without network lookup |
HMAC Before Reconstruct
Every XorIDA share carries an HMAC-SHA256 signature. On reconstruction, all HMACs are verified before any plaintext is returned. The verification loop completes fully before reconstructXorIDA() is called. If any HMAC check fails, the function returns err('HMAC_FAILED') and no reconstruction is attempted. This is a fail-closed design: partial plaintext is never exposed on integrity failure.
// HMAC verification MUST complete BEFORE reconstruction for (let i = 0; i < shares.length; i++) { const share = shares[i]; const hmacKey = hmacKeys[i]; const hmacSig = hmacSignatures[i]; if (!share || !hmacKey || !hmacSig) { return err('HMAC_FAILED'); } const valid = await verifyHMAC(hmacKey, share, hmacSig); if (!valid) { return err('HMAC_FAILED'); } } // Only if all HMACs pass, reconstruct const reconstructed = reconstructXorIDA(kShares, kIndices, n, k);
Web Crypto API Only
All cryptographic operations use the Web Crypto API: crypto.subtle for HMAC signing/verification, crypto.subtle.generateKey() for Ed25519 keypairs, and crypto.getRandomValues() for random number generation. No Math.random(), no Node.js-only crypto modules, no third-party libraries.
Supply Chain Security
Zero npm runtime dependencies. The package depends only on workspace packages (@private.me/crypto, @private.me/shared) which are part of the same monorepo. No third-party code executes at runtime. This eliminates the entire class of supply chain attacks from compromised npm packages. Peer dependency: @langchain/core (provided by the application).
Benchmarks
Performance characteristics measured on Node.js 22, Apple M2.
| Operation | Time | Notes |
|---|---|---|
| createAgentIdentity() | <1ms | Ed25519 keygen via Web Crypto API |
| createSecureMessage() — 1KB | <5ms | UTF-8 encode + pad + split + 3 HMACs |
| reconstructSecureMessage() — 1KB | <5ms | 3 HMAC verifies + reconstruct + unpad + decode |
| memory.addEntry() | <5ms | JSON serialize + split + cache |
| audit.onAction() | <1ms | HMAC-SHA256 over (action + DID + timestamp + prevHmac) |
| audit.verifyChain() — 100 entries | <50ms | 100 constant-time HMAC comparisons |
Throughput
XorIDA splitting is CPU-bound. On M2, ~30 MB/sec for 2-of-3 splitting. Parallelization: each share can be split independently (use Web Workers for large payloads). HMAC signing is ~100 MB/sec (SHA-256 hardware acceleration). Ed25519 signing is ~5,000 signatures/sec (Web Crypto API native implementation).
Honest Limitations
What this package does not do, and why.
1. No Transport Layer
This package provides XorIDA splitting, HMAC integrity, and DID identity. It does not provide transport adapters for sending shares. You must implement your own transport (HTTP, MQTT, WebSocket, etc.) or use @private.me/agent-sdk which includes transport abstraction.
Why: Transport requirements vary wildly across LangChain deployments. Some agents run in browsers (WebSocket), some in Node.js (HTTP), some in embedded systems (MQTT). Providing a one-size-fits-all transport would bloat the package and force unnecessary dependencies.
2. No Trust Registry
Agent identities are created via createAgentIdentity(), but there is no built-in registry for mapping DIDs to public keys or validating agent permissions. You must implement your own trust registry or use @private.me/agent-sdk which includes a trust registry with DID resolution and revocation.
Why: Trust models differ. Some deployments use a centralized registry (LDAP, database), some use decentralized registries (blockchain, DHT), some use static configuration (hardcoded DIDs in environment variables). Baking one model into the package would prevent adoption in scenarios that require a different model.
3. No Nonce Store
This package does not prevent replay attacks. If an attacker records a SecureMessageOutput and retransmits it, the recipient will accept it as valid (HMAC will verify). Replay prevention requires a nonce store to track seen messages.
Why: Nonce storage is stateful and requires persistence. In-memory nonce stores lose history on restart. Redis/database-backed stores introduce dependencies and configuration. Embedding a nonce store would force a specific persistence choice on all users. Use @private.me/agent-sdk if you need replay prevention.
4. No Key Rotation
Agent identities created via createAgentIdentity() have no built-in key rotation or expiry. Once an identity is created, it remains valid indefinitely unless you manually revoke it in your trust registry.
Why: Key rotation policies vary: some systems rotate daily, some monthly, some never. Some require zero-downtime rotation (dual signatures), some allow brief outages. This package focuses on the cryptographic primitives. Rotation policy is application-level logic.
5. No Post-Quantum Signatures
Agent identities use Ed25519 signatures, which are vulnerable to quantum computers running Shor's algorithm. ML-DSA-65 (FIPS 204) is available in @private.me/agent-sdk but not in this package.
Why: ML-DSA-65 adds ~3KB per signature. For LangChain agents that log thousands of actions, this bloats audit trails. Ed25519 provides 128-bit classical security (sufficient for most current deployments). If you need post-quantum signatures, use @private.me/agent-sdk which supports hybrid Ed25519 + ML-DSA-65.
6. No Garbage Collection
SecureMemory caches plaintext entries in-memory. AuditCallback caches audit entries in-memory. Neither module automatically purges old entries (except LRU eviction for SecureMemory). Long-running agents will accumulate memory until clear() is called.
Why: Automatic purging requires heuristics (time-based? size-based? LRU?). Wrong heuristics cause data loss. Explicit clear() gives the application full control over when to purge.
@private.me/agent-sdk.
Deep Dive
API surface, error taxonomy, and runtime requirements for production deployments.
Full API Surface
Complete function signatures and return types.
SecureMessage
SecureMemory
AgentIdentity
AuditCallback
Error Taxonomy
All error codes with recovery strategies.
| Code | Module | Recovery |
|---|---|---|
| SPLIT_FAILED | SecureMessage | Check n/k parameters. Ensure content is valid UTF-8. |
| RECONSTRUCT_FAILED | SecureMessage | Ensure at least k shares provided. Check padding (PKCS#7 must be valid). |
| HMAC_FAILED | SecureMessage | Share has been tampered with. Do NOT reconstruct. Reject message. |
| IDENTITY_FAILED | AgentIdentity | Web Crypto API unavailable or Ed25519 not supported. Fallback already attempted. |
| INVALID_CONFIG | SecureMessage | Fix parameters: n ≥ 2, k ≥ 2, k ≤ n. |
| AUDIT_CHAIN_BROKEN | AuditCallback | Audit trail has been tampered with. Investigate breach. Do NOT trust entries. |
Error Classes
The package exports four error classes for type-safe error handling:
LangChainAdapterError— Base class for all errorsLangChainCryptoError— XorIDA, HMAC, or padding failuresLangChainIdentityError— Ed25519 keygen or DID creation failuresLangChainAuditError— HMAC chain integrity failures
Runtime Requirements
Platform support matrix and Web Crypto API availability.
| Platform | Status | Notes |
|---|---|---|
| Node.js 20+ | Supported | Primary target. Web Crypto API native. |
| Deno 1.40+ | Supported | Web Crypto API available. |
| Bun 1.0+ | Supported | Web Crypto API available. |
| Chromium 113+ | Supported | Ed25519 + X25519 Web Crypto. |
| Firefox 130+ | Supported | Ed25519 added in 130. |
| Safari 17+ | Supported | Ed25519 added in 17. |
| Tauri v2 | Supported | Chromium 113+ webview. |
| Node.js <20 | Unsupported | Web Crypto API incomplete. |
Web Crypto API Requirements
This package requires the following Web Crypto API features:
crypto.getRandomValues()— random number generationcrypto.subtle.generateKey('Ed25519', ...)— Ed25519 keypair generation (optional, fallback to random bytes)crypto.subtle.importKey('raw', ...)— HMAC key importcrypto.subtle.sign('HMAC', ...)— HMAC-SHA256 signingcrypto.subtle.verify('HMAC', ...)— HMAC-SHA256 verification (constant-time)
If Ed25519 is not available, createAgentIdentity() falls back to generating a random 32-byte identity. This provides a unique DID but does not support cryptographic signing. Use this fallback only in constrained environments where Ed25519 is unavailable.
Deployment Options
SaaS Recommended
Fully managed infrastructure. Call our REST API, we handle scaling, updates, and operations.
- Zero infrastructure setup
- Automatic updates
- 99.9% uptime SLA
- Enterprise SLA available
SDK Integration
Embed directly in your application. Runs in your codebase with full programmatic control.
npm install @private.me/langchain- TypeScript/JavaScript SDK
- Full source access
- Enterprise support available
On-Premise Upon Request
Enterprise CLI for compliance, air-gap, or data residency requirements.
- Complete data sovereignty
- Air-gap capable deployment
- Custom SLA + dedicated support
- Professional services included
Enterprise On-Premise Deployment
While langChain is primarily delivered as SaaS or SDK, we build dedicated on-premise infrastructure for customers with:
- Regulatory mandates — HIPAA, SOX, FedRAMP, CMMC requiring self-hosted processing
- Air-gapped environments — SCIF, classified networks, offline operations
- Data residency requirements — EU GDPR, China data laws, government mandates
- Custom integration needs — Embed in proprietary platforms, specialized workflows
Includes: Enterprise CLI, Docker/Kubernetes orchestration, RBAC, audit logging, and dedicated support.