Loading...
private.me Docs
Get CreditSplit
PRIVATE.ME · Technical White Paper

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.

v0.1.0 16+ test cases 3 core modules 0 npm deps Information-theoretic Post-quantum by design
Section 01

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.

K-of-N
Flexible threshold
Unique shares
0
Info leak < K
256-bit
HMAC security
Section 02

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
Section 03

Real-World Use Cases

Five scenarios where threshold sharing transforms credit data security.

🏦
FINTECH
Credit Bureau Federation

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 threshold
🔐
COMPLIANCE
Regulatory Data Isolation

Distributed 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-jurisdiction
🛡️
SECURITY
Breach Containment

Even 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-resistant
🏥
FINTECH
Credit Scoring at Scale

Lenders 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 model
⚖️
LEGAL
Subpoena Resistance

When 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-safe
🌍
GOV
Cross-Border Data Exchange

Credit 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-neutral
Section 04

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

Store
Bureau nodes
Each bureau holds 1 share
Share tagged with bureau ID
HMAC included with share
Jurisdiction-aware routing
HMAC verification is mandatory and fail-closed
HMAC verification happens on the reconstructed (padded) data BEFORE unpadding. If HMAC fails, an error is returned and the plaintext is never exposed. This detects tampering at the earliest safe point.
Section 05

API Surface

A minimal, focused interface. Two primary functions. Five type definitions. Five error codes.

Primary Functions

splitCreditProfile(profile, config) → Promise<Result<CreditSplitResult, CreditSplitError>>

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.

reconstructCreditProfile(shares) → Promise<Result<CreditProfile, CreditSplitError>>

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

Type definitions
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
Section 06

Implementation

Practical usage: from setup to reconstruction. Zero configuration required.

Step 1: Split a Profile

Splitting example
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

Reconstruction example
// 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);
Section 07

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.

SECURITY INVARIANTS
  1. HMAC verification always precedes data consumption after reconstruction.
  2. No consumer PII is logged, printed, or sent to external services.
  3. All shares include the IDA5 branded header for provenance.
  4. Share indices and bureau IDs are validated before processing.
Section 08

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.

COMPLIANCE BENEFIT
Distributing credit data across K bureaus transforms the risk model from "breach = full exposure" to "breach = zero exposure (single node)". This is a qualitative improvement over traditional encryption, where a single key compromise = full exposure.
Section 09

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.

Section 10

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.

Error handling pattern
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
Section 11

Integration Guide

Three steps: import, split, store. Three steps in reverse: fetch, reconstruct, query.

Installation

Install via pnpm
pnpm add @private.me/creditsplit

# Peer dependencies (already in your PRIVATE.ME project)
pnpm add @private.me/crypto @private.me/shared

Import

Import functions and types
import {
  splitCreditProfile,
  reconstructCreditProfile,
} from '@private.me/creditsplit';

import type {
  CreditProfile,
  CreditConfig,
  CreditShare,
} from '@private.me/creditsplit';

Define Bureaus and Configuration

Bureau setup
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.
DEPLOYMENT PATTERN
Create a "ShareCoordinator" service that orchestrates split/reconstruct calls and handles distribution/retrieval. This service can be run as a Lambda, microservice, or long-running daemon depending on your architecture. The ShareCoordinator is the only code that knows about network I/O; CreditSplit itself is pure business logic.
Section 12

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.

KNOWN CONSTRAINT
CreditSplit is designed for scenarios where shares are securely stored and retrieved via a trusted coordinator. It assumes bureaus are honest-but-curious (they follow the protocol but may try to reconstruct the profile if K of them collude). For scenarios where bureaus are actively adversarial, additional defenses (e.g., cryptographic commitments, multi-party computation) are needed.
Appendix A

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.

RECOMMENDATION
If you integrate CreditSplit with Xlink, create agents with postQuantumSig: true to enable full post-quantum protection across all three cryptographic layers (data isolation + transport security + authentication).
Appendix B

Codebase Statistics

Lean, focused implementation. Zero npm runtime dependencies.

3
Core modules
5
Type definitions
2
Primary functions
16+
Test cases
0
npm dependencies
2
Peer dependencies

File Structure

  • src/types.ts — Interface definitions (Bureau, CreditConfig, CreditProfile, CreditShare, CreditSplitResult, CreditSplitError)
  • src/errors.ts — Error code mappings and helper functions
  • src/credit-splitter.ts — splitCreditProfile() implementation
  • src/credit-reconstructor.ts — reconstructCreditProfile() implementation
  • src/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

GOLD STANDARD BRONZE
CreditSplit follows the PRIVATE.ME Gold Standard Bronze designation: 100% test coverage, SECURITY.md, documented threat model, comprehensive error codes, and zero production vulnerabilities.

Deployment Options

📦

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
Get Started →
🏢

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
Request Quote →

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.

Contact sales for assessment and pricing →