Adversarial precision testing for FHE programs
Project description
FHE Oracle
Adversarial precision testing for Fully Homomorphic Encryption. Finds CKKS bugs that random testing misses.
Install
pip install fhe-oracle
Optional adapters:
pip install "fhe-oracle[tenseal]" # CKKS via TenSEAL
pip install "fhe-oracle[openfhe]" # CKKS / BGV / BFV via OpenFHE (Linux)
pip install "fhe-oracle[concrete]" # TFHE via Concrete ML
30-second example
import numpy as np
from fhe_oracle import FHEOracle
def plaintext_fn(x):
return float(np.sum(np.asarray(x) ** 2))
def fhe_fn(x):
# Stand-in for your FHE-compiled predict function.
# Here: noise scales with input norm^2 (a CKKS depth-noise pattern),
# with a hot zone that inflates the error 100x when |x|^2 > 8.
v = float(np.sum(np.asarray(x) ** 2))
base = 1e-5 * v
amp = 100.0 if v > 8.0 else 1.0
return plaintext_fn(x) + base * amp
oracle = FHEOracle(
plaintext_fn=plaintext_fn,
fhe_fn=fhe_fn,
input_dim=4,
input_bounds=[(-3.0, 3.0)] * 4,
seed=0,
)
result = oracle.run(n_trials=300, threshold=1e-3)
print(result.verdict) # "FAIL"
print(result.max_error) # ~3.6e-2
print(result.worst_input) # ~[3.0, 3.0, 3.0, -3.0]
Output:
OracleResult(verdict='FAIL', max_error=3.593336e-02, trials=304, elapsed=0.05s)
Swap the fixture for a real fhe_fn (e.g. concrete-ml's
predict_proba(x, fhe="execute")) and the oracle will search
adversarially for inputs that break precision.
Why this exists
FHE precision bugs are input-localised. A CKKS circuit that passes on 99,999 random inputs in a row can return garbage on the 100,000th. The inputs that trigger failure sit in narrow regions of the input space — regions that scale with multiplicative depth and the magnitude of intermediate ciphertexts — and those regions are vanishingly unlikely to be hit by uniform random sampling.
Random testing wastes evaluations in safe parts of the input space. An adversarial optimiser (CMA-ES, guided by a noise-budget-aware fitness function) spends its budget climbing toward the failure region instead, and finds bugs orders of magnitude larger than random sampling in the same wall-clock budget.
On the reference logistic-regression benchmark in this repo (a CKKS circuit with a polynomial sigmoid approximation defect), the oracle finds divergence 4,259× larger than random sampling at an equal 500-evaluation budget. Reproduce with:
pip install cma numpy
python benchmarks/sigmoid_defect_benchmark.py --seed 42
How it works
- CMA-ES search over the input domain, guided by a noise-aware fitness that combines plaintext/FHE divergence with ciphertext noise-budget consumption and multiplicative-depth utilisation.
- Adapters for OpenFHE, Concrete ML, and TenSEAL turn on noise-guided search. A pure divergence fallback works without any native FHE library — useful for CI.
- Output: PASS/FAIL verdict, worst input, sensitivity map, and a structured JSON/Markdown report for artefact upload.
Benchmarks
See benchmarks/ for reproducible circuits. Numbers below are from live runs on this repo (500-evaluation budget, deterministic seed 42):
| Circuit | Dim | Random max error | Oracle max error | Ratio |
|---|---|---|---|---|
| Logistic regression (reference) | 5 | 3.5e-4 | 1.50 | 4,259× |
| Logistic regression (input-amplified mock) | 8 | 2.7e-1 | 6.8e-1 | 2.5× |
| Polynomial (depth 4) | 6 | 1.7e-2 | 1.9e-2 | 1.1× |
| Dense + Chebyshev sigmoid | 10 | — | 1.0e-1 | — |
Pure-Python divergence-only benchmarks run in under one second on a
2020-era laptop. Library-comparison benchmarks (TenSEAL / OpenFHE /
Pyfhel) take 15–45 s/seed; reach the unified-circuit numbers via
benchmarks/library_comparison.py.
CI/CD integration
Drop oracle_check.py at your repo root:
import os
from fhe_oracle import FHEOracle
from my_model import plaintext_fn, fhe_fn
oracle = FHEOracle(
plaintext_fn=plaintext_fn,
fhe_fn=fhe_fn,
input_dim=10,
input_bounds=[(-3.0, 3.0)] * 10,
)
result = oracle.run(
n_trials=int(os.environ.get("ORACLE_N_TRIALS", "500")),
threshold=float(os.environ.get("ORACLE_THRESHOLD", "0.01")),
)
print(result)
raise SystemExit(0 if result.verdict == "PASS" else 1)
Add .github/workflows/fhe-precision.yml:
name: FHE Precision Test
on: [push, pull_request]
jobs:
fhe-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.11" }
- run: pip install fhe-oracle
- run: python oracle_check.py
env:
ORACLE_THRESHOLD: "0.01"
ORACLE_N_TRIALS: "500"
Full template: examples/github_action.yml.
Features (v0.5)
- Cross-library benchmark harness —
benchmarks/library_comparison.pydrives the same(w·x+b)²circuit through every installed adapter and emits a single CSV per family (CKKS / integer). sigma0=Noneauto-scale +DISTANT_DEFECTregime inAutoOracle— handles landscapes where the failure region sits outside the initial search ball.
Features (v0.4)
- Periodic diversity injection —
FHEOracle(..., diversity_injection=True, inject_every=5, inject_count=3)injects diverse candidates (corner / uniform / best-neighbour) into the CMA-ES population every N generations, preventing the covariance collapse that strands vanilla CMA-ES on plateau landscapes. Seefhe_oracle.diversity.DiversityInjector. - Adaptive budget allocation —
FHEOracle(..., adaptive=True)enables three behaviours simultaneously: early stop on a definitive FAIL, auto-extension when divergence is still climbing at budget exhaustion, and strategy-switch to uniform random when CMA-ES's step size collapses on a plateau. Configure viaAdaptiveConfig. - Multi-output rank-aware fitness —
FHEOracle(..., multi_output=True, multi_output_mode="combined")wraps the user's vector-valued plaintext/FHE pair in aMultiOutputFitnessthat targets decision-altering precision failures (argmax flips, near-margin inputs) on top of max-absolute error. UseMultiOutputFitness.detailed_report(x)to inspect a witness. - All three default OFF — backward-compatible with v0.3.x.
Opt in per-call or via
AutoOracle(..., adaptive=True, diversity_injection=True)(kwargs are forwarded to the innerFHEOracle).
Features (v0.3)
- Auto-configuration probe —
AutoOracle(...)runs a 50-eval probe to classify the divergence landscape (FULL_DOMAIN_SATURATION,PLATEAU_THEN_CLIFF,PREACTIVATION_DOMINATED,STANDARD) and dispatches to the best search strategy automatically. No prior paper reading required. - Random subspace embedding (experimental) —
SubspaceOracle(...)projectsd >> 100inputs intok-dim random subspaces and searches with CMA-ES. Currently benefits only low-rank hidden-layer quantisation bugs; for dense directional / corner-region bugs preferPreactivationOracle(whenW, bare available) or uniform random sampling. Seeresearch/release/v030-benchmark-report.mdfor the evaluation. - Pure-divergence defaults —
w_noiseandw_depthnow default to0.0(paper §6.15 empirical evidence); passw_noise=0.5, w_depth=0.3to restore v0.2 shaping behaviour.
Features (v0.2)
- Pure-divergence mode — CI-friendly, no FHE library required.
- Hybrid random + CMA-ES with warm-start —
random_floor=0.3onFHEOraclereserves a fraction of the budget for uniform sampling, then warm-starts CMA-ES at the best random point. - IPOP / BIPOP restarts —
restarts=N, bipop=TrueonFHEOraclefor multi-basin landscapes. - Separable CMA-ES —
separable=Truefor axis-aligned landscapes (high-dim settings). - Union verdict (oracle + empirical) —
run_hybrid(...)returns aHybridResult; PASS iff both the adversarial and training-distribution legs pass. - Coverage certificate — the random-floor phase produces a
CoverageCertificateattached toOracleResult; pair withbudget_for(eta, p)orpass_confidence(eta)for a probabilistic PASS statement. - Preactivation search —
PreactivationOracle(W, b, ...)searches in preactivation z-space, collapsing d=784 affine front-ends to a rank-k subproblem. - Cascade (multi-fidelity) search —
CascadeSearch(...)runs cheap-fidelity search then re-scores the top-K under an expensive fidelity. - Per-operation trace diagnostic —
per_op_trace(x, plain, fhe)andTracingTenSEALFnlocalise where error accumulates in a CKKS circuit. - TenSEAL adapter —
pip install fhe-oracle[tenseal]enables noise-guided search on CKKS.
Licensing
AGPL-3.0-or-later. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fhe_oracle-0.5.2.tar.gz.
File metadata
- Download URL: fhe_oracle-0.5.2.tar.gz
- Upload date:
- Size: 99.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7137333c8a6d24d3e52d48997cf8b2e99b116e4dc1fa722ae97a9387074ada28
|
|
| MD5 |
076b0f93fc09a62c76cb6b098d58f8f2
|
|
| BLAKE2b-256 |
38ce2da33bd2a12e980963216c5887dd457cd6570aa7f9710fec104e5c07c7d2
|
Provenance
The following attestation bundles were made for fhe_oracle-0.5.2.tar.gz:
Publisher:
release.yml on BAder82t/fhe-oracle-oss
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fhe_oracle-0.5.2.tar.gz -
Subject digest:
7137333c8a6d24d3e52d48997cf8b2e99b116e4dc1fa722ae97a9387074ada28 - Sigstore transparency entry: 1396919386
- Sigstore integration time:
-
Permalink:
BAder82t/fhe-oracle-oss@1a8472678d71d823fc6b3706db07d621826d90c2 -
Branch / Tag:
refs/tags/v0.5.2 - Owner: https://github.com/BAder82t
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1a8472678d71d823fc6b3706db07d621826d90c2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fhe_oracle-0.5.2-py3-none-any.whl.
File metadata
- Download URL: fhe_oracle-0.5.2-py3-none-any.whl
- Upload date:
- Size: 80.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d566e965d2862c77a6f3cde8afdaf000ee007a46de9e1f21f0ca47aafef79971
|
|
| MD5 |
833ef5ef718d2db70a724c4745967cb2
|
|
| BLAKE2b-256 |
5026cab4509e0ebf6b710d79e40ab4015e8b64ab351d411524f0ad74800d2d2f
|
Provenance
The following attestation bundles were made for fhe_oracle-0.5.2-py3-none-any.whl:
Publisher:
release.yml on BAder82t/fhe-oracle-oss
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fhe_oracle-0.5.2-py3-none-any.whl -
Subject digest:
d566e965d2862c77a6f3cde8afdaf000ee007a46de9e1f21f0ca47aafef79971 - Sigstore transparency entry: 1396919455
- Sigstore integration time:
-
Permalink:
BAder82t/fhe-oracle-oss@1a8472678d71d823fc6b3706db07d621826d90c2 -
Branch / Tag:
refs/tags/v0.5.2 - Owner: https://github.com/BAder82t
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1a8472678d71d823fc6b3706db07d621826d90c2 -
Trigger Event:
push
-
Statement type: