CreditSplit: Data Isolation via Threshold Sharing
Credit bureaus hold some of the most consequential personal data in existence. CreditSplit uses XorIDA threshold sharing over GF(2) to split credit profiles into shares distributed across independent bureaus or storage nodes. No single bureau holds a reconstructable profile. Credit scoring operations require a threshold quorum of shares, and each share is HMAC-signed to guarantee data integrity. Breach at any single bureau exposes zero usable consumer data.
Executive Summary
CreditSplit isolates credit profiles at the data level — no single bureau holds a complete, reconstructable profile. Information-theoretic security by default.
Two functions cover the entire API: splitCreditProfile() divides a credit bureau dataset across N bureaus with a K-of-N threshold using XorIDA (threshold sharing over GF(2)). reconstructCreditProfile() recovers the original data from any K shares and verifies integrity via HMAC-SHA256 before returning plaintext.
No single bureau compromise exposes usable data. An attacker who breaches one bureau gets a cryptographic share — a random-looking chunk of data that reveals zero information about the original profile. Fewer than K shares, mathematically no information, regardless of computational power.
HMAC-verified. Every share carries an HMAC key and signature generated over the original data before splitting. Reconstruction verifies the HMAC on the recovered (padded) data before unpadding and returning. Tampered shares are rejected with a fail-closed guarantee.
Zero npm runtime dependencies. Runs anywhere the Web Crypto API is available — Node.js 20+, Deno 1.40+, Bun 1.0+, browsers with Web Crypto, Tauri v2. Dual ESM and CJS builds in a single package.
The Problem
Credit bureaus are honeypots. A single breach exposes millions of consumers' complete credit profiles — scores, payment history, accounts, collections, inquiries.
Today's architecture: All eggs in one basket. Each major credit bureau (Equifax, Experian, TransUnion) holds the complete, queryable credit profile for every consumer. A breach at one bureau = full identity theft exposure for all affected consumers.
Regulatory pressure is mounting. FCRA, GDPR, CCPA, and state breach notification laws impose:
- Data minimization: only hold what you need
- Security by design: not as an afterthought
- Breach notification: 30-60 day windows
- Consumer rights: access, correction, deletion
Traditional encryption falls short. AES-256-GCM protects data in transit and at rest, but decryption keys must exist somewhere. Key compromise = full plaintext. Encryption is a binary: either the keys are compromised, or they aren't.
Threshold sharing is different. Information-theoretic security means K-1 shares reveal zero information about the plaintext, mathematically, regardless of computing power (including quantum). No key to compromise. No binary win/loss.
| Property | Single Bureau | Encrypted Vault | CreditSplit |
|---|---|---|---|
| Breach impact | Full profile | If key leaked | 0 info < K |
| Key rotation needed | N/A | Yes, risky | No keys |
| Compliance fit | Poor | Partial | Excellent |
| Post-quantum safe | No | No | Yes, proven |
| Data minimization | No | Partial | Full split |
Real-World Use Cases
Five scenarios where threshold sharing transforms credit data security.
Three independent bureaus collaborate to provide credit scoring without any single bureau holding complete profiles. 2-of-3 threshold provides fault tolerance and breach resilience.
2-of-3 thresholdDistributed storage across multiple jurisdictions (US, EU) with 2-of-2 threshold. GDPR requires minimizing data in any single location. CreditSplit ensures no single datacenter holds reconstructable profiles.
Multi-jurisdictionEven if one storage node is compromised, the attacker gets a random share. Reconstruction requires K colluding nodes — a much higher bar than a single breach.
Collusion-resistantLenders can request credit scores from a consortium of nodes. No single node has the complete profile. Scoring logic runs across the quorum, output is released only to authorized lenders.
Consortium modelWhen one share is subpoenaed, the bureau can produce it without revealing consumer data. The share is cryptographically useless alone. Privacy maintained even under legal compulsion.
Subpoena-safeCredit data flows between countries with different legal requirements. Threshold sharing ensures no single foreign party holds complete profiles. Decoupling data from any single jurisdiction.
Jurisdiction-neutralSolution Architecture
Three core functions orchestrate the full lifecycle: split, distribute, reconstruct.
Data Flow: Split → Store → Reconstruct
The sender (originating bureau or aggregator) holds the plaintext credit profile. It invokes splitCreditProfile(profile, config) with a configuration specifying bureaus and threshold. XorIDA generates N shares (one per bureau) such that any K shares reconstruct the original data. HMAC is computed on padded data before splitting.
Each bureau securely stores its share. The shares are independent — no bureau can reconstruct the profile alone. When a credit decision needs to be made, the consortium collects K shares from K bureaus, calls reconstructCreditProfile(shares), which verifies the HMAC on the reconstructed padded data, unpadds, and returns the original profile.
API Surface
A minimal, focused interface. Two primary functions. Five type definitions. Five error codes.
Primary Functions
Splits a credit profile into N shares across bureaus with a K-of-N threshold. HMAC is generated on padded data before splitting. Returns all N shares plus a SHA-256 hash of the original bureau data.
Reconstructs the original credit profile from a quorum of K shares (where K ≤ shares.length ≤ N). Verifies HMAC on padded data before returning. Returns a CreditProfile with the original bureauData, or an error if validation fails.
Core Types
interface Bureau { readonly id: string; // e.g., "equifax" readonly name: string; // e.g., "Equifax" readonly jurisdiction: string; // e.g., "US" } interface CreditConfig { readonly bureaus: Bureau[]; // Participating bureaus readonly threshold: number; // K for K-of-N } interface CreditProfile { readonly profileId: string; // Profile identifier readonly subjectId: string; // Consumer identifier readonly bureauData: Uint8Array; // Credit data (binary) readonly lastUpdated: string; // ISO 8601 timestamp } interface CreditShare { readonly profileId: string; // Which profile readonly bureauId: string; // Assigned to this bureau readonly index: number; // Share index (0-based) readonly total: number; // Total shares (N) readonly threshold: number; // Threshold (K) readonly data: string; // Base64 share data readonly hmac: string; // "key:sig" base64 pair readonly originalSize: number; // Size before padding }
Error Codes
| Code | When | Remediation |
|---|---|---|
INVALID_CONFIG |
Bureau list < 2, or threshold > bureaus, or threshold < 2 | Adjust config: at least 2 bureaus, 2 ≤ K ≤ N |
SPLIT_FAILED |
XorIDA split threw an exception | Check data size and memory; try again |
HMAC_FAILED |
Share data is corrupted or tampered | Replace share from original source; do not use |
RECONSTRUCT_FAILED |
XorIDA reconstruction or unpadding failed | Verify shares are valid; check indices |
INSUFFICIENT_SHARES |
Fewer than K shares provided | Collect at least K shares; try again |
Implementation
Practical usage: from setup to reconstruction. Zero configuration required.
Step 1: Split a Profile
import { splitCreditProfile, reconstructCreditProfile, } from '@private.me/creditsplit'; import type { CreditProfile, CreditConfig, } from '@private.me/creditsplit'; // Define participating bureaus const bureaus = [ { id: 'equifax', name: 'Equifax', jurisdiction: 'US' }, { id: 'experian', name: 'Experian', jurisdiction: 'US' }, { id: 'transunion', name: 'TransUnion', jurisdiction: 'US' }, ]; // 2-of-3 threshold: any 2 bureaus can reconstruct const config: CreditConfig = { bureaus, threshold: 2, }; // Sample credit profile const profile: CreditProfile = { profileId: 'PROF-2026-00042', subjectId: 'CONSUMER-99001', bureauData: creditReportBytes, // Uint8Array lastUpdated: new Date().toISOString(), }; // Split the profile const splitResult = await splitCreditProfile(profile, config); if (!splitResult.ok) { console.error('Split failed:', splitResult.error.message); return; } // Distribute shares to bureaus const { shares, profileHash } = splitResult.value; for (const share of shares) { // Send share[i] to bureaus[i] await distributeShare(share.bureauId, share); }
Step 2: Reconstruct a Profile
// Later: collect shares from any K bureaus const equifaxShare = await fetchShare('equifax', profileId); const experianShare = await fetchShare('experian', profileId); // Reconstruct from these 2 shares (threshold is 2) const reconstructResult = await reconstructCreditProfile([ equifaxShare, experianShare, ]); if (!reconstructResult.ok) { console.error('Reconstruction failed:', reconstructResult.error.code); return; } // HMAC has been verified. Data is safe to use. const { profileId, subjectId, bureauData } = reconstructResult.value; console.log('Reconstructed profile for', subjectId);
Security Model
Three layers of protection: information-theoretic, integrity, and process.
Information-Theoretic Security (XorIDA)
CreditSplit uses XorIDA, a threshold sharing scheme over GF(2). The key guarantee: K-1 shares reveal zero information about the plaintext, regardless of computational power, including quantum computers.
This is not computationally hard — it is mathematically impossible. An attacker with unlimited computing power (including a quantum computer) cannot extract any information from K-1 shares. The security is unconditional.
Integrity (HMAC-SHA256)
Before splitting, the original (padded) data is hashed using HMAC-SHA256. The HMAC key and signature are distributed with the shares. During reconstruction, the HMAC is verified on the reconstructed padded data before unpadding or returning plaintext.
This ensures:
- Tampered shares are detected
- Corrupted data is rejected
- Fail-closed: no plaintext is exposed if HMAC fails
Process Security
No Math.random(): All randomness is sourced from crypto.getRandomValues() via the Web Crypto API.
Share Index Validation: Indices are range-checked and type-checked before use.
No Persistent Plaintext: The service never stores the original credit profile after splitting. Only shares and HMAC metadata exist.
- HMAC verification always precedes data consumption after reconstruction.
- No consumer PII is logged, printed, or sent to external services.
- All shares include the IDA5 branded header for provenance.
- Share indices and bureau IDs are validated before processing.
Regulatory Alignment
CreditSplit aligns with data protection and privacy regulations by design.
FCRA (Fair Credit Reporting Act)
Data minimization: CreditSplit ensures that no single credit bureau holds a complete profile. This aligns with FCRA's implicit principle that data should be held by authorized entities only.
Accuracy and dispute: By splitting, bureaus reduce the blast radius of data quality issues. A mistake in one bureau affects only K-1 other bureaus, not the entire industry.
GDPR (General Data Protection Regulation)
Article 32 (Security): Threshold sharing is a pseudonymization / data minimization technique that reduces the risk of unauthorized processing.
Article 5 (Data Minimization): No single controller holds complete personal data. Each bureau holds only an unusable share.
Article 33 (Breach Notification): A breach of one share does not constitute a breach of personal data (since the share is useless alone). Only a coordinated breach of K bureaus would trigger notification.
CCPA / CPRA (California Consumer Privacy Act)
Right to Delete: Consumers can request deletion of their credit data. CreditSplit enables deletion of all N shares via a single request to the data curator, rather than coordinating deletion across multiple bureaus.
Right to Correction: Similarly, corrections to a profile can be applied uniformly by re-splitting the corrected data.
State Breach Notification Laws
Many states (e.g., California, New York) define a "breach" as disclosure of unencrypted personal information. A compromised share is not personal information (it is a useless cryptographic chunk). CreditSplit may help reduce breach notification obligations in jurisdictions with this language.
Performance
XorIDA is sub-millisecond for typical credit profile sizes.
CreditSplit inherits the performance profile of XorIDA (XorIDA over GF(2)), which is highly efficient for typical data sizes.
| Data Size | Bureaus (N) | Threshold (K) | Split Time | Reconstruct Time |
|---|---|---|---|---|
| 1 KB | 3 | 2 | <1 ms | <1 ms |
| 10 KB | 3 | 2 | <1 ms | <1 ms |
| 100 KB | 3 | 2 | ~2 ms | ~2 ms |
| 1 MB | 3 | 2 | ~20 ms | ~20 ms |
Typical credit profiles are 10-100 KB, so split/reconstruct overhead is negligible (<1 ms). Even large historical credit reports (<1 MB) split in under 30 ms.
Network I/O dominates. The actual time spent splitting/reconstructing is dwarfed by the time to transmit shares to/from bureaus. CreditSplit is not the bottleneck.
Error Handling
Structured errors with clear semantics enable graceful degradation and debugging.
All functions return a Result<T, E> type, not exceptions. This makes error handling explicit and composable.
const splitResult = await splitCreditProfile(profile, config); if (!splitResult.ok) { // Discriminated union: splitResult.error has a 'code' field switch (splitResult.error.code) { case 'INVALID_CONFIG': console.error('Config problem:', splitResult.error.message); break; case 'SPLIT_FAILED': console.error('XorIDA failed:', splitResult.error.message); break; case 'HMAC_FAILED': console.error('Integrity problem'); break; default: console.error('Unknown error'); } return; } // splitResult.value is guaranteed to be CreditSplitResult here const shares = splitResult.value.shares;
Error Code Semantics
| Code | Transient? | User Action |
|---|---|---|
| INVALID_CONFIG | No | Fix config; check threshold ≤ N, threshold ≥ 2 |
| SPLIT_FAILED | Maybe | Retry; check memory/resources; inspect data size |
| HMAC_FAILED | No | Data is corrupted; replace share or profile |
| RECONSTRUCT_FAILED | Maybe | Verify shares are valid; retry with fresh shares |
| INSUFFICIENT_SHARES | No | Collect more shares; wait for bureaus to respond |
Integration Guide
Three steps: import, split, store. Three steps in reverse: fetch, reconstruct, query.
Installation
pnpm add @private.me/creditsplit
# Peer dependencies (already in your PRIVATE.ME project)
pnpm add @private.me/crypto @private.me/shared
Import
import { splitCreditProfile, reconstructCreditProfile, } from '@private.me/creditsplit'; import type { CreditProfile, CreditConfig, CreditShare, } from '@private.me/creditsplit';
Define Bureaus and Configuration
const bureaus: Bureau[] = [ { id: 'node-us-east', name: 'US East Storage', jurisdiction: 'US', }, { id: 'node-eu-west', name: 'EU West Storage', jurisdiction: 'EU', }, { id: 'node-ap-southeast', name: 'AP Southeast Storage', jurisdiction: 'SG', }, ]; const config: CreditConfig = { bureaus, threshold: 2, // 2-of-3: any 2 nodes can reconstruct };
Implement Share Distribution
After splitting, each share must be sent to its assigned bureau. You'll need to implement a distribution mechanism specific to your infrastructure. Common patterns:
- Direct HTTP POST: Send each share to the bureau's API endpoint.
- Message Queue: Enqueue each share to a topic and let bureaus subscribe.
- Database Replication: Write all shares to a ledger; bureaus subscribe to their own shares.
- Secure Enclave: Store shares in a hardware security module (HSM) per bureau.
Implement Share Retrieval
During reconstruction, you need to fetch K shares from K bureaus. This is the inverse of distribution. Common patterns:
- HTTP GET: Query each bureau's API for the share by profile ID.
- Database Query: Read shares from a shared ledger by profile ID and bureau ID.
- Cache: Keep recent shares in memory/Redis for fast reconstruction.
Limitations
No technology is a silver bullet. Here are the tradeoffs of threshold sharing.
Quorum Requirement
Reconstruction requires a quorum of K shares. If fewer than K bureaus are available, the profile cannot be reconstructed. This is by design (security), but operationally, it means you need a larger infrastructure. With 3 bureaus and K=2, you can tolerate 1 bureau being down. With 5 bureaus and K=3, you can tolerate 2 down.
Higher Storage Overhead
Storing N shares uses ~N times the storage of the original profile (plus HMAC metadata). If you split a 100 KB profile into 3 shares, you store ~300 KB (100 KB per share). This is the cost of distributed data minimization.
More Network Hops
Reconstruction requires fetching K shares from K bureaus. In the worst case, this is K network round-trips, vs. 1 round-trip to a single encrypted vault. For geo-distributed bureaus, latency compounds.
Coordination Complexity
You need to coordinate the distribution of shares and the collection of shares during reconstruction. This is additional operational complexity compared to a centralized encrypted vault. Implement a ShareCoordinator service to manage this.
Share Index Management
Shares are indexed 0-based. You must track which bureau holds which index for a given profile ID. A centralized registry (e.g., a database table mapping profileId → bureauId → index) helps manage this.
Not a Replacement for Encryption
CreditSplit provides data minimization, not transport security. Shares should still be encrypted in transit (HTTPS, TLS) and at rest (AES-256-GCM) per bureau. CreditSplit is a complementary security layer on top of encryption.
Post-Quantum Security
CreditSplit is quantum-safe by design. XorIDA provides information-theoretic security, independent of computational assumptions.
Information-Theoretic = Quantum-Proof
XorIDA is a threshold sharing scheme that is mathematically proven to be secure unconditionally — that is, without relying on any hardness assumptions (like RSA, discrete log, or lattice problems). This means quantum computers cannot break it, because there is nothing to break: the security is pure information theory, not computational cryptography.
By contrast:
- AES-256: Computationally secure. Quantum computers offer no advantage.
- RSA/ECDH: Computationally secure. Quantum computers (Shor's algorithm) break in polynomial time.
- XorIDA: Information-theoretically secure. No quantum speedup possible.
Hybrid with Xlink
When credit profiles are transmitted via @private.me/agent-sdk (Xlink), the envelope includes hybrid post-quantum encryption:
- Key exchange: X25519 (classical) + ML-KEM-768 (post-quantum KEM) — always-on in v2+ envelopes.
- Signatures: Ed25519 (classical) + ML-DSA-65 (post-quantum DSA) — opt-in via postQuantumSig: true in v3 envelopes.
This provides defense-in-depth: if either classical or post-quantum cryptography is broken, the other layer still provides security.
postQuantumSig: true to enable full post-quantum protection across all three cryptographic layers (data isolation + transport security + authentication).
Codebase Statistics
Lean, focused implementation. Zero npm runtime dependencies.
File Structure
src/types.ts— Interface definitions (Bureau, CreditConfig, CreditProfile, CreditShare, CreditSplitResult, CreditSplitError)src/errors.ts— Error code mappings and helper functionssrc/credit-splitter.ts— splitCreditProfile() implementationsrc/credit-reconstructor.ts— reconstructCreditProfile() implementationsrc/index.ts— Barrel export (public API)src/__tests__/*.test.ts— Test suites
Dependencies
Runtime (0): None. Pure TypeScript.
Peer (2):
@private.me/crypto— XorIDA split/reconstruct, HMAC-SHA256, PKCS#7 padding@private.me/shared— Result<T, E> type and utilities
Test Coverage
Unit tests: Core functions (split, reconstruct, validation)
Integration tests: End-to-end split + reconstruct workflows
Abuse tests: Invalid inputs, edge cases, tampering detection
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/creditsplit- 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 creditSplit 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.