CipherExplain

./explain --fhe --audit-ready

SHAP FHE for Regulators

CipherExplain provides SHAP FHE for regulators: encrypted feature-attribution explanations for AI systems where sensitive input data must remain private. It computes SHAP values under Fully Homomorphic Encryption, helping regulated teams produce audit-ready explanations without exposing plaintext features to the server.

Homomorphic encrypted SHAP explanations. Computes SHAP feature attributions entirely under Fully Homomorphic Encryption — with fhe_mode='ckks', the server never sees your plaintext data. Register your own models via a secure JSON API — no training data leaves your environment. Reproducible benchmarks, signed audit artefacts, and a verifiable SDK — see the Validation and SDK sections.

[Encrypted SHAP]· [12 runnable examples]· [Pricing]· [Contact]
Custom Model API LR + SVM + DT + RF + GB + MLP + XGBoost + LightGBM + CatBoost SDK DP-SHAP

The FHE Production Gap

Encrypted AI blocks explainability — and regulators now require both.

Encrypted AI cannot explain its decisions

GDPR, HIPAA-aligned programs, and sectoral controls often require strong safeguards for personal data, and encryption is one important technical measure. The EU AI Act (Art. 13 & 86) requires transparency and explanations for high-risk AI systems, with obligations phasing in from August 2026 through 2027. Feature-level explanations are one established approach to meet these transparency requirements. Combining the two is operationally hard: most explainability methods need plaintext access, which leaves banks, healthcare networks, and hiring platforms juggling pseudonymisation, on-prem builds, and contractual controls to bridge the gap.

Verifiable Encrypted SHAP

Reproducible reference prototype and validated benchmarks. Patents filed (PCT/IB2026/053378 + PCT/IB2026/053405); sub-licensable patent grants on the Enterprise tier.

Homomorphic Encrypted SHAP

Compute feature attribution entirely under FHE with fhe_mode='ckks'. Plaintext input never leaves your machine; server processes ciphertexts only.

  • O(d log d) coalition sampling vs 2^d.
  • SIMD slot packing: 390 coalitions in 3 ciphertext ops (LR) / 2 (MLP).
  • 128-bit CKKS, N=2^15 (LR) / 2^16 (MLP), LP-optimal degree-27 ReLU.
  • Optional DP-SHAP — Gaussian over per-key daily ε.

Linear (LR / SVM / MLP) encrypted by default. Tree ensembles opt-in via enable_fhe_octe=True. Tree-attested SHAP beta on SDK 0.4.0. CatBoost full-FHE per-customer (Enterprise).

Threat model

CipherExplain protects your input features against an honest-but-curious server. Server processes ciphertexts, returns encrypted results; plaintext input never leaves the client.

The server does hold CKKS evaluation keys (relinearisation + Galois rotation) uploaded at registration to enable SIMD-packed compute. Secret-key recovery from these keys reduces to RLWE-hard, but they remain a server-held asset tied to your client.

Deployment assumes no decryption oracle — consistent with standard CKKS practice and Li & Micciancio's CCA model (EUROCRYPT 2021).

For stronger threat models — HSM-backed client key generation, per-session evaluation-key destruction — contact us. On the Enterprise roadmap.

SHAP MAE 0.018 · FHE noise 1.35e-04 · axiom error 1.11e-16

Known limitations & honest disclosures

  • Client keys: software-generated; HSM-backed gen on Enterprise roadmap.
  • DP-SHAP on trees: (ε, δ) bound conditional on feature-range pre-clip at registration.
  • Repeated-query inversion: rate limits + DP-SHAP + tenant isolation mitigate, don't eliminate.
  • No bootstrapping: depth fixed by parameter set (N=2^15 LR, 2^16 MLP); deeper circuits → Enterprise scope.
  • 3rd-party crypto audit: pending; scope on Enterprise security pack.
Custom Model API SDK Key Rotation

Bring Your Own Model

Register a trained model via JSON-only weights. No training data, no pickle, no code execution. With fhe_mode='ckks', SHAP runs server-side under FHE; results return encrypted.

  • Supported: LR, linear SVM, RF, GB, DT, MLP (ReLU), XGBoost, LightGBM, CatBoost — binary classifiers. Up to 512 features. See matrix.
  • Helpers: register_xgboost(), register_lightgbm(), register_mlp(), register_pytorch_mlp(), register_catboost(), register_pipeline(), from_weights(). Tree-SHAP fidelity 0.05%.
  • MLP fast-lane: linear_surrogate=true → ~7s/explain, L∞ error 0.062. Default path is audit-grade.
  • Per-key namespaced registry; SQLite-backed persistence; key rotation auto-migrates.
  • model_version_id on every response — list via GET /models/{id}/versions.
  • FreiKZG proof of φ = M·y on every explain (soundness 2^−249, ~4ms client verify).
  • vFHE Bulletproofs binding — Pedersen + Schnorr Σ-IPA on ciphertext bytes (2^−128, +0.7% latency).
  • Slot quotas: 2 (free) · 5 (pro) · 25 (team) · unlimited (enterprise).
JSON-only spec OMS Merkle attestation FreiKZG commitment vFHE binding (live) Per-tenant namespace

Why It's Safe to Register Your Model

Five verifier layers, all live in production:

  1. JSON-only registration. No pickle, no joblib, no __reduce__. Pydantic-typed weights only.
  2. Merkle attestation of weights (OMS v1.0). Per-explain inclusion proofs; SDK rejects mismatch.
  3. KZG commitment to the regression matrix. SDK verifies every FreiKZG proof. Soundness 2^−249 / BLS12-381.
  4. vFHE Bulletproofs binding. Pedersen + Schnorr Σ-IPA on ciphertext bytes. Soundness 2^−128. +0.7% latency.
  5. Per-tenant namespace. Models keyed by sha256(API-Key); cross-tenant lookups 404.

What Does It Actually Return?

Plain English. No maths required.

ENCRYPTED SHAP — THE INPUT AND OUTPUT

The input: one person, one decision

You send a feature vector — the attributes of the specific case you want explained. These are the same numbers your model used to make its prediction.

{
  "model_id": "loan-risk-v1",
  "features": [35,  55000, 0.3,  1,    8  ]
  //            ↑     ↑     ↑     ↑     ↑
  //           age income debt  new  yrs_emp
}

The output: a number and a breakdown

{
  "prediction":    0.72,
  "base_rate":     0.50,
  "shap_values":   [0.08, 0.18, -0.06, 0.02, 0.00],
  "feature_names": ["age","income","debt","new","yrs"]
}

prediction: 0.72 — the model is 72% confident this applicant will repay. Your application maps this to "Approved" or "Low risk" — the label is your code's job, not ours.

base_rate: 0.50 — the average prediction across all applicants. This is the neutral starting point before any features are considered.

The SHAP values explain the gap from 0.50 to 0.72. Income drove most of it (+0.18). Debt ratio pulled it back (−0.06).

HOW TO READ SHAP VALUES

Each SHAP value is a signed number. Positive = pushed the prediction up. Negative = pushed it down. The size tells you how much relative to the other features.

income  +0.18

Main approval driver. Income was the single biggest reason the model said yes.

age      +0.08

Moderate positive signal. Added some confidence but was not the deciding factor.

debt     −0.06

Worked against approval. Still approved overall, but the debt ratio reduced confidence.

new      +0.02

Near-zero impact. Being a new customer barely changed this prediction either way.

Validation

Every number below is reproducible from the working prototype.

0.018
SHAP MAE vs ground-truth KernelSHAP (d=50, K=390, Bernstein-bounded)
1.11e-16
Efficiency axiom error (machine epsilon)
130×
SIMD reduction at d=50 (390 → 3 ciphertexts)
1.35e-04
FHE vs plaintext SHAP max difference
~14ms
Logistic regression — encrypted SHAP FHE compute, exact logit-space closed form. Now served on a patent-clean lattice scheme (CKKS remains available as a fallback path). Measured 100-call prod benchmark on EU production cloud infrastructure: p50 13.6ms, p95 22ms (d=50). End-to-end HTTP latency adds integrity-layer and transport overhead on top of FHE compute.
73s
MLP (ReLU) — measured CKKS latency per explanation on EU production cloud infrastructure via the diagonal-encoded coalition-packed path (d=50, K=390). LP-optimal degree-27 ReLU.
1.88%
SHAP relative error on breast_cancer (LP-optimal degree-27, down from 5.04% Chebyshev)
128-bit
CKKS security (HEStd_128_classic) + 2^−128 binding soundness (Bulletproofs Σ-IPA, live in prod via CE_VFHE=1, +0.7% latency overhead).
0.05%
Tree ensemble SHAP error — RandomForest / GradientBoosting (19/19 tests pass)
~70s
XGBoost / LightGBM / DecisionTree — full-FHE path-product latency per explanation (EU production cloud infrastructure, T=100 D=4 K=40, measured).
~25s
Tree-attested SHAP (BETA) — server FHE leaf-routing + client-side shap.TreeExplainer. Dev-measured on EU production cloud infrastructure (T = 100, D = 6); 96% per-tree leaf-routing match vs plaintext walk. Available since SDK 0.4.0; production soak pending.

How to Use

Encrypted SHAP explanations — hosted API with a single key.

STEP 1 — GET YOUR KEY

Sign up instantly — no waitlist. Enter your work email, verify with a 6-digit code, and your key arrives immediately.

Get a free key or upgrade to Pro (£49/mo).

vb_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
STEP 2 — CIPHEREXPLAIN API (ENCRYPTED SHAP)

Python

Load the demo model, then call /explain_raw with raw (unscaled) values:

import requests

BASE = "https://cipherexplain.vaultbytes.com"
HDR  = {"X-API-Key": "vb_..."}

# One-time: load the built-in demo credit model
requests.post(f"{BASE}/startup", headers=HDR)

# Send the raw feature values for one person
r = requests.post(f"{BASE}/explain_raw", headers=HDR,
  json={
    "model_id": "credit_model",
    "features": [38,  13,    0,       0,      40 ]
    #             ↑    ↑      ↑        ↑        ↑
    #            age  edu  marital  occup  hrs/week
  }
)
data = r.json()

# What comes back:
# data["prediction"]    → 0.74   (74% probability — your app maps to a label)
# data["base_rate"]     → 0.50   (average across all cases — the neutral baseline)
# data["shap_values"]   → [0.12, -0.31, 0.05, 0.03, 0.09]
# data["feature_names"] → ["age", "education-num", "marital", "occup", "hours"]
#
# Reading the SHAP values:
#   education-num: -0.31 → biggest factor, pushed prediction DOWN
#   age:            0.12 → pushed it up
#   hours/week:     0.09 → positive signal
#   occupation:     0.05 → small positive
#   marital:        0.03 → almost no effect

curl

curl -s -X POST \
  https://cipherexplain.vaultbytes.com/explain_raw \
  -H "X-API-Key: vb_..." \
  -H "Content-Type: application/json" \
  -d '{
    "model_id": "credit_model",
    "features": [38, 13, 0, 0, 40]
  }' | python3 -m json.tool

All endpoints

POST /startup                  → load demo credit model
GET  /models                   → list your registered models
POST /models/register          → register your own model
GET  /models/{id}/versions     → list model versions (audit)
GET  /models/{id}/commitment   → KZG commitment for FreiKZG verify
DELETE /models/{id}            → remove a model
POST /explain                  → SHAP (pre-scaled features)
POST /explain_raw              → SHAP (raw values, auto-scaled)
POST /explain/batch            → async batch — webhook delivery
GET  /explain/batch/{job_id}   → poll batch job status
POST /report                   → generate PDF audit report
POST /keys/rotate              → rotate your API key
GET  /usage                    → quota used this month
GET  /usage/dp                 → remaining DP privacy budget (ε)
GET  /health                   → status (no key needed)
STEP 3 — BRING YOUR OWN MODEL (OPTIONAL)

Register any classifier

Your model and data stay local. Only trained weights (numbers) are sent — no training data, no pickle files, no arbitrary code.

pip install cipherexplain

from cipherexplain_sdk import CipherExplainClient
client = CipherExplainClient(api_key="vb_...")

# --- sklearn Pipeline auto-unwrap (embedded scaler stripped) ---
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
pipe = Pipeline([("scaler", StandardScaler()),
                 ("clf",    LogisticRegression())]).fit(X, y)
client.register_pipeline("my_model", pipe, feature_names, X_train=X)

# --- XGBoost binary classifier ---
import xgboost as xgb
booster = xgb.XGBClassifier().fit(X, y)
client.register_xgboost("my_xgb", booster, feature_names)

# --- LightGBM binary classifier ---
import lightgbm as lgb
gbm = lgb.LGBMClassifier().fit(X, y)
client.register_lightgbm("my_lgb", gbm, feature_names)

# --- MLP (ReLU) — CKKS-evaluated ---
from sklearn.neural_network import MLPClassifier
mlp = MLPClassifier(hidden_layer_sizes=(16, 8)).fit(X, y)
client.register_mlp("my_mlp", mlp, feature_names, X_train=X)

# --- Any other framework — raw weights ---
from cipherexplain_sdk import from_weights
spec = from_weights(coef, intercept, "my_linear",
                    feature_names, classes=[0, 1])
client.register(spec)

# Explain with full FHE + optional DP noise
result = client.explain_raw("my_model", x_raw,
                            fhe_mode="execute", apply_dp=True)
print(result["shap_values"])
print(result["model_version_id"])   # audit pin
print(result["fhe_mode_used"])       # "ckks_engine"

canonical source of truth

Model support matrix

Model family Hosted plaintext SHAP CKKS / FHE mode Notes
Logistic regressionYesYes (default)Production prototype, measured
Linear SVMYesYes (default)Production prototype
MLP (ReLU)YesYes (default)Production prototype, measured on EU production cloud infrastructure (73s, diagonal-coalition path)
DecisionTreeYesOpt-in (enable_fhe_octe)Full-FHE path product, bounded T/D
XGBoost / LightGBMYesOpt-in (enable_fhe_octe)Full-FHE path product, Enterprise compute
RandomForest / GradientBoostingYesPartial — opt-in via enable_fhe_octe=true on POST /models/registerFHE sign gate + encrypted coalition composition; path product evaluated in plaintext after decrypt. Requires StandardScaler in the spec.
Tree-attested SHAP BETAYesPOST /explain_tree (SDK 0.4.0)Server returns encrypted per-tree leaf identity; SDK runs shap.TreeExplainer locally on your plaintext input. T ≤ 100, D ≤ 6. Dev-measured ~25 s on EU production cloud infrastructure; 96% per-tree routing match. Production soak pending.
CatBoostYesBusiness / EnterpriseHosted plaintext TreeSHAP via register_catboost() on every tier. Full-FHE oblivious-tree circuit validated (sign-flip-free, axiom 1e-17, SHAP L∞ 0.008); deployed per-customer on a dedicated host for Business and Enterprise contracts.

Model slots & key rotation

Each API key has a model slot quota by tier:

  • Free — 2 models
  • Pro — 5 models
  • Team — 25 models
  • Enterprise — no limit

Delete a model to free its slot:

client.delete("my_model")

Rotate your API key at any time — all registered models move automatically:

result = client.rotate_key()
# result["new_key"] → "vb_..."
# Your old key stops working immediately.

Python SDK

Register models, run explanations, rotate keys — all from Python.

INSTALL

Python 3.9+ · License: AGPL v3 (commercial licence available).

Latest SDK live on PyPI (v0.5.1 — counterfactuals + ECOA reason codes):

pip install cipherexplain

For client-side CKKS encryption (fhe_mode='ckks') add the [fhe] extra:

pip install 'cipherexplain[fhe]'
QUICK START
from cipherexplain_sdk import CipherExplainClient, from_weights

client = CipherExplainClient(api_key="vb_...")

# Gradient-boosted trees
client.register_xgboost("my_xgb", xgb_model, feature_names)
client.register_lightgbm("my_lgb", lgb_model, feature_names)

# sklearn Pipeline — scaler auto-unwrapped
client.register_pipeline("my_pipe", pipe,
                         feature_names, X_train=X)

# MLP (CKKS-evaluated)
client.register_mlp("my_mlp", mlp, feature_names, X_train=X)

# Raw weights (TF, JAX, statsmodels, R, ...)
spec = from_weights(coef, intercept, "my_linear",
                    feature_names, classes=[0, 1])
client.register(spec)

# Explain with full FHE + optional DP noise
result = client.explain_raw("my_mlp", x_raw,
                            fhe_mode="execute", apply_dp=True)
print(result["shap_values"])
print(result["fhe_mode_used"])     # "ckks_engine"
print(result["model_version_id"])  # audit trail

# Tree-attested SHAP — server FHE routing + local TreeExplainer (BETA)
from cipherexplain_sdk import from_sklearn_ensemble
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=100, max_depth=6).fit(X, y)
client.register(from_sklearn_ensemble(rf, "my_rf", feature_names))
result = client.explain_tree("my_rf", x_raw, model=rf)
print(result["tree_attested"].shap_values)
print(result["tree_attested"].attestation_verified)

# Async batch (compliance workflows)
job = client.explain_batch([x1, x2, x3],
                           model_id="my_mlp",
                           webhook_url="https://you/hook")
status = client.explain_batch_status(job["job_id"])

# Counterfactuals + ECOA Reg-B Form C-1 reason codes (NEW in v0.5.1)
# Customer's x stays local; server constructs Enc(x') homomorphically.
exp = client.explain_raw("my_lr", x_denied)
cf  = client.counterfactual("my_lr", x_denied, exp)
print(cf["x_prime"])           # x + delta_star (minimal-L2 recourse)
print(cf["decision_flipped"])  # True
for code in cf["reason_codes"]:
    print(code["form_c1_code"], "—", code["form_c1_text"])

# DP budget
print(client.usage_dp())   # {"epsilon_remaining": 87.3, ...}

# Key rotation — old key deactivated immediately
new = client.rotate_key()
print(new["new_key"])  # save this

API Docs

Interactive reference — try every endpoint directly in your browser.

AUTHENTICATE IN SWAGGER
  1. Open cipherexplain.vaultbytes.com/docs
  2. Click Authorize (top right, 🔒 icon)
  3. Paste your vb_... key into the X-API-Key field
  4. Click AuthorizeClose
  5. Expand any endpoint and click Try it out
FULL CKKS ENCRYPTION MODE

fhe_mode='ckks' enables full CKKS homomorphic encryption. Your input is encrypted on your machine before transmission. The server evaluates the model and computes SHAP values without decrypting at any point. Results are returned encrypted and decrypted locally by your SDK. Per-family FHE support level, opt-in flags, and measured prod latency live in the canonical Model support matrix. For long-running compliance workflows, use POST /explain/batch — async webhook delivery.

Cryptographic integrity (LIVE): every response carries a Bulletproofs binding proof — soundness 2−128, +0.7% latency overhead, verified client-side by the SDK. See the Verifiable Encrypted SHAP section for the full spec.

Privacy Controls

Three levels of privacy. Pick the one that matches your data-handling contract.

LEVEL 1

Plaintext SHAP

Fast, no encryption. Your features travel over HTTPS and the server computes SHAP in plaintext.

client.explain_raw(
    "my_model", x_raw)
LEVEL 2

FHE SHAP

Full CKKS homomorphic encryption. Your input is encrypted on your machine; the server never sees plaintext.

client.explain_raw(
    "my_model", x_raw,
    fhe_mode="execute")
LEVEL 3 — STRONGEST

FHE SHAP + DP

Encrypted compute plus a clipped Gaussian (ε,δ)-DP mechanism on the published SHAP vector. Reduces the leakage from repeated queries against the same subject under the documented neighbouring relation.

client.explain_raw(
    "my_model", x_raw,
    fhe_mode="execute",
    apply_dp=True)
DP PRIVACY BUDGET

DP-SHAP applies a clipped Gaussian mechanism to the published SHAP vector, providing (ε, δ)-differential privacy with respect to a documented neighbouring relation on the client input (l1_fractional, l1_single, or linf). The L₂ sensitivity Δ₂ is derived per model class — closed-form for logistic regression, leaf-bound for RandomForest / GradientBoosting; other model families fall back to plaintext SHAP. Production composition is linear in ε (a stricter accountant than zCDP); a zCDP PrivacyAccountant is available as a research utility. The mechanism protects the published attribution against input-reconstruction attacks; it does not provide DP for the underlying training data. Each apply_dp=True call consumes from a per-key daily ε budget.

GET /usage/dp

{
  "epsilon_budget_daily": 100.0,
  "epsilon_spent_today":  12.7,
  "epsilon_remaining":    87.3,
  "resets_at":            "2026-04-19T00:00:00Z"
}

Pricing

Enterprise quoted against regulatory exposure, not compute cost.

EU AI ACT ART. 13 & 86 — PHASED 2026-2027 GDPR ART. 28 DPA SR 11-7 / PRA SS1/23 ENTERPRISE SECURITY PACK — ON REQUEST PCT FILED APR 2026
FREE
£0
forever
  • 100 SHAP calls / month
  • 2 model slots
  • 5 calls / day rate-limit
  • API docs & SDK access
  • Community support
MOST POPULAR
PRO
£49
/ month
  • 3,000 SHAP calls / month
  • 5 custom model slots
  • API docs & SDK access
  • PDF audit reports
  • Email support
TEAM
£199
/ month
  • 15,000 SHAP calls / month
  • 25 custom model slots
  • Priority email support
  • PDF audit reports
  • Counterfactual recourse + DP-SHAP add-ons
FOR REGULATED BUYERS
ENTERPRISE
Contact us
Quoted against regulatory exposure, not compute cost
[talk_to_sales]
  • Committed monthly SHAP volume (negotiated)
  • Dedicated FHE compute pool — linear, MLP, full-FHE tree (XGBoost / LightGBM / DT), partial-FHE RF / GB
  • Unlimited custom model slots
  • EU hosting — VPC / on-prem available
  • Signed DPA (GDPR Art. 28) + EU AI Act Art. 13 attestation pack
  • Model-version audit trail + signed envelopes · DP privacy budget controls
  • SSO / SAML · SLA · named support engineer · security review package
  • Commercial (non-AGPL) licence + sub-licensable patent grant

MANAGE YOUR ACCOUNT

Enter your API key to manage billing, cancel, enable PAYG, or check usage — all automated, no emails needed.

Manage subscription: cancel, update card, download invoices · No cancellation fees · Access continues to end of billing period

Enterprise Inquiry

For procurement, vendor onboarding, NDA evaluations, design partnerships, and pilots. Replies within one business day.