PPFDaaS
Privacy-preserving payment-fraud inference using CKKS homomorphic encryption.
"Scores payment fraud risk on encrypted transactions the server can never decrypt."
What it is
A privacy-preserving payment-fraud inference system that evaluates linear fraud detection models directly over CKKS-homomorphically-encrypted transaction vectors. Plaintext transaction features never leave bank custody, and the vendor server evaluates inferences entirely over ciphertext without possessing the secret key or decryptor. The client uses Microsoft SEAL to encode and encrypt payment attributes under an RNS-CKKS scheme ($n=8192$), transmits the ciphertext over gRPC, and receives an encrypted classification score that only the bank can decrypt and evaluate through a sigmoid activation. The vendor process enforces a strict cryptographic trust boundary: it boots with zero key material in an unprovisioned state (PROV_AWAITING_KEYS), accepts only an evaluation-only Galois key bundle pushed by the bank over mutual TLS, and verifies evaluation readiness through an automated zero-knowledge canary exchange before serving inferences.
What was hard
Eliminating secret keys and decryption capabilities entirely from the vendor execution runtime while supporting multi-threaded concurrent inference. Earlier iterations held decryptors within the server process for local verification; the production vendor service (vendor_server_160) was rewritten on EvalContext160 to strip all seal::SecretKey, seal::Decryptor, and seal::KeyGenerator objects from the linked binary. To prevent cross-thread race conditions and side-channel leakage across concurrent gRPC worker threads, shared mutable ciphertext output buffers were eliminated in favor of thread-local scratch allocations, and Galois rotations were hoisted into a deterministic sequential-fold tree sum (hoisted_tree_sum). Optimizing CKKS parameters required designing a tailored 160-bit coefficient modulus chain ({60, 40, 60} bits) that preserved 128-bit classical security under HE-Standard recommendations while eliminating unneeded relinearization keys and reducing rotation latency by ~49% compared to the 200-bit baseline.
What was measured
Evaluation latency and system performance were established via Type 1 self-ablation benchmarks running under the Linux performance CPU governor on a 20-core Intel Core i7-13650HX host with 15 GB RAM:
- The 160-bit CKKS pipeline achieved a single-request mean inference latency of 7.54 ms and a 99th-percentile latency of 7.79 ms across 1,000 requests (bootstrap 95% CI of the mean [7.52, 7.56] ms), compared to 14.88 ms mean (p99 15.24 ms) on the 200-bit baseline—a 49.3% latency reduction.
- Serialized ciphertext wire size was measured at 262,257 bytes per 4,096-slot transaction vector, a 33.3% bandwidth reduction compared to 393,329 bytes on the 200-bit baseline.
- Under closed-loop concurrent load (4 clients, 16 packed SIMD lanes per request), the server sustained 198.7 requests/sec, amortizing inference runtime down to 1,255 µs per transaction.
- Statistical classification performance was evaluated on a held-out test split of 256 transaction features: the depth-1 logistic regression surrogate attained an AUC of 0.9791 (a minimal linearization penalty of 0.0041 AUC against the unconstrained 0.9835 XGBoost baseline), passing the accuracy dispatch gate without requiring higher-depth evaluation.
What is still open
- Transciphering / HHE (Phase 7): Standalone reference execution of HERA-16 in BFV with HalfBoot and FV-to-CKKS repacking was validated in Go (73.7 s runtime, 9.54 GB peak RSS on a 15 GB host under
GOMEMLIMIT=11GiB), but integration into the production C++vendor_serverremains pending. All cells inartifacts/hhe_breakeven.jsonremain pending measurement. - Batched transciphering reduction: Correctness has been verified only for single-block test vectors (256 slots); multi-block packed reductions across full SIMD ciphertexts remain unmeasured.
- Degree-2 polynomial fallback: The quadratic fallback path (
ckks_context_depth2.cpp, $n=16384$) remains dormant because the primary depth-1 model’s AUC (0.9791) satisfied the deployment gate. A negative dimension bug (-240) incompiler/degree2_linearizer.pycauses an unhandledValueErrorwhenlinearize_degree2is invoked, leaving quadratic inference broken and unmeasured.
Empirical Claims & Verification Invariants
| statement | value | sample | status | provenance |
|---|---|---|---|---|
| Single-request encrypted inference latency for the deployed 160-bit CKKS pipeline. | mean 7.54 ms, p99 7.79 ms | 1,000 requests, n=8192, depth-1 logistic regression | Measured | artifacts/comparison_results.json (Type 1 self-ablation under performance governor) |
| Latency reduction of 160-bit deployed pipeline over 200-bit baseline. | 49.3% reduction (mean 7.54 ms vs 14.88 ms) | 1,000 requests per arm, n=8192 | Measured | artifacts/comparison_results.json |
| Classification AUC of the linearized depth-1 surrogate model evaluated under CKKS. Linearization cost of 0.0041 AUC compared to unconstrained XGBoost baseline (0.9835) | 0.9791 | held-out test split, 256 features | Measured | artifacts/dispatch_result.json and artifacts/linearization_cost.json |
| Serialized ciphertext wire size per 4,096-slot transaction vector. | 262,257 bytes (33.3% reduction from 200-bit baseline) | 4,096-slot CKKS ciphertext, SEAL 4.1 serialization | Measured | artifacts/wire_sizes.json (measured via wire_size_probe) |
| Peak closed-loop inference throughput under concurrent multi-client load. | 198.7 req/s (amortized 1,255 µs per transaction) | 4 concurrent clients, 16 transaction lanes per batch, 5,964 requests | Measured | artifacts/throughput_results.json |