Skip to main content

Unified attack-replay regression harness for FHE libraries (SEAL, OpenFHE, Lattigo, tfhe-rs).

Project description

fhe-attack-replay

Alpha. cheon-2024-127 runs as a real live-oracle Replay against two adapters:

  • toy-lwe (always available) — bisection-based encryption-noise recovery across 8 trials of 20 rounds each.
  • openfhe (when openfhe-python is built locally) — polynomial-domain bisection against real OpenFHE BFV/BGV using serialized DCRT ciphertext mutation.

Unmitigated configs report VULNERABLE (exit 2); noise-flooded configs report SAFE (exit 0). The same module also runs as a RiskCheck on adapters without a live oracle. See DISCLAIMER.md for what SAFE does and does not mean.

Framework for a unified attack-replay regression harness for FHE libraries. Modules land in three intent levels — Replay (end-to-end exploit), RiskCheck (static analysis of (library, params) against a known threat model), and ArtifactCheck (validates user-supplied traces or evidence). See docs/status-semantics.md.

License: Apache-2.0. See LICENSE and NOTICE.

Why

Hexens awesome-fhe-attacks curates attacks but does not run them. Every library and downstream user re-implements attack PoCs ad-hoc to verify a fix. fhe-attack-replay is the framework that — once the attack modules land — will let you answer the question "is my CKKS config still vulnerable to Cheon 2024/127?" in seconds.

Install

pip install fhe-attack-replay

To target a specific library, install the matching native dependency:

pip install openfhe         # OpenFHE python bindings  (Linux x86_64 only via PyPI)
pip install tenseal         # SEAL via TenSEAL
# Lattigo / tfhe-rs require helper binaries on PATH.

Building openfhe-python from source (macOS / Windows / arm64)

The PyPI openfhe wheel only ships a Linux x86_64 .so. Build from source if you want the live OpenFHE Replay path on other platforms:

brew install cmake gmp ntl libomp pybind11   # or your distro's equivalents
git clone https://github.com/openfheorg/openfhe-development
cd openfhe-development
cmake -B build -DCMAKE_INSTALL_PREFIX="$HOME/.local/openfhe" \
              -DBUILD_UNITTESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARKS=OFF
cmake --build build -j
cmake --install build

git clone https://github.com/openfheorg/openfhe-python && cd openfhe-python
cmake -B build \
  -DOpenFHE_DIR="$HOME/.local/openfhe/lib/OpenFHE" \
  -DPython_EXECUTABLE="$(which python3)" \
  -DCMAKE_PREFIX_PATH="$(python3 -c 'import pybind11; print(pybind11.get_cmake_dir())')"
cmake --build build -j
cp build/openfhe.cpython-*.so "$(python3 -c 'import site; print(site.getsitepackages()[0])')/"
mkdir -p "$(python3 -c 'import site; print(site.getsitepackages()[0])')/lib"
cp $HOME/.local/openfhe/lib/libOPENFHE*.dylib \
   "$(python3 -c 'import site; print(site.getsitepackages()[0])')/lib/"
python3 -c "import openfhe; print('OK')"

Quick start

fhe-replay list all
fhe-replay doctor
fhe-replay run --lib openfhe --params examples/bfv-128.json --attacks all \
    --output-json report.json --badge badge.svg

For a dependency-free first run, use the in-tree toy LWE adapter:

fhe-replay run --lib toy-lwe --params examples/toy-lwe-vulnerable.json \
    --attacks cheon-2024-127

fhe-replay doctor reports which native adapters are available on the current machine and prints the dependency note for each missing backend.

Exit codes:

Code Meaning
0 At least one attack ran and every result was SAFE (or SKIPPED if allowed)
2 At least one attack reported VULNERABLE
3 Internal error during replay
4 One or more selected attacks were NOT_IMPLEMENTED (override: --allow-not-implemented)
5 Every selected attack was SKIPPED and no attack ran (override: --allow-skipped)
64 Usage error

NOT_IMPLEMENTED never silently passes by default — green CI requires real results. See docs/status-semantics.md.

For CI gates that require a minimum implemented-attack ratio:

fhe-replay run --lib openfhe --params examples/bfv-128.json \
    --attacks cheon-2024-127 --min-coverage 1.0

Attack modules

ID Source Intent Status
cheon-2024-127 Cheon, Hong, Kim — IACR ePrint 2024/127 Replay + RiskCheck implemented (Replay against toy-lwe and OpenFHE BFV/BGV; RiskCheck elsewhere)
eprint-2025-867 Side-Channel Analysis in HE — IACR ePrint 2025/867 RiskCheck implemented (SEAL/TenSEAL and OpenFHE Harvey-butterfly fingerprint verdicts)
reveal-2023-1128 Aydin, Karabulut et al. — IACR ePrint 2023/1128 ArtifactCheck implemented (records caller-supplied trace verdict; in-tree analyzer pending)
guo-qian-usenix24 Guo et al. — USENIX Security 2024 RiskCheck implemented (average-case vs worst-case noise-flooding decision rule)
glitchfhe-usenix25 Mankali et al. — USENIX Security 2025 ArtifactCheck implemented (records caller-supplied fault-log verdict; in-tree analyzer pending)

cheon-2024-127 — IND-CPA-D Replay (live oracle)

Generates keys, encrypts 0, perturbs the ciphertext polynomial toward the rounding boundary, then runs a binary search on the decryption oracle to recover the encryption-noise boundary. Repeats over N trials and inspects the variance of the recovered boundary:

trials := 8 bisection runs
rounds := 20 for toy-lwe; max(20, bit_length(delta)) for OpenFHE
delta  := q / t  (encoding scale)
threshold := max(1, 0.05 * delta)
deterministic := std(boundaries) < threshold
if deterministic:  VULNERABLE  (oracle leaks; published key recovery applies)
else:              SAFE        (oracle randomized; noise-recovery primitive does not converge)

Try it:

fhe-replay run --lib toy-lwe --params examples/toy-lwe-vulnerable.json --attacks cheon-2024-127
fhe-replay run --lib toy-lwe --params examples/toy-lwe-mitigated.json  --attacks cheon-2024-127
fhe-replay run --lib openfhe --params examples/bfv-128-vulnerable.json --attacks cheon-2024-127

For OpenFHE BFV/BGV, openfhe-python does not expose mutable DCRTPoly coefficient APIs. The adapter therefore mutates the serialized OpenFHE JSON ciphertext directly: it adds a constant polynomial to ciphertext component c0 across all DCRT towers, deserializes the ciphertext, and queries the native decrypt oracle. Replay evidence records test=polynomial_domain_bisection, serialization_backend=openfhe-json, the plaintext modulus, and DCRT tower metadata.

guo-qian-usenix24 — Non-worst-case noise-flooding RiskCheck (CKKS)

Inspects noise_flooding_strategy (or noise_flooding) against the Guo-Qian USENIX'24 threat model. Average-case-bound flooding constructions (li-micciancio, eprint-2020-1533, …) are reported VULNERABLE; worst-case-bound constructions (openfhe-noise-flooding-decrypt, eprint-2024-424, modulus-switching-2025-1627, …) report SAFE. Configs without an oracle exposure or without a recognized flooding label are SKIPPED.

fhe-replay run --lib seal --attacks guo-qian-usenix24 \
    --params /dev/stdin <<'JSON'
{"scheme":"CKKS","adversary_model":"ind-cpa-d","noise_flooding_strategy":"li-micciancio"}
JSON

reveal-2023-1128 / glitchfhe-usenix25 — ArtifactCheck

Both modules consume user-supplied evidence files via the CLI --evidence KEY=PATH flag and record the analyst's declared outcome:

fhe-replay run --lib seal --attacks reveal-2023-1128 \
    --params examples/bfv-128.json \
    --evidence trace=runs/seal-ntt.npy

Set params['hamming_weight_signature'] = 'recovered' (or 'clean') to record the result of an external single-trace correlation analysis; glitchfhe-usenix25 reads params['differential_outcome'] similarly. Without an outcome declaration the verdict is NOT_IMPLEMENTED — the in-tree distinguishers are pending.

cheon-2024-127 — IND-CPA-D RiskCheck (static, all libs)

When the adapter cannot drive a live oracle, the same module runs as a RiskCheck and inspects (scheme, adversary_model, decryption_oracle, noise_flooding) against the threat model:

oracle_access := decryption_oracle == True
                 OR adversary_model in {ind-cpa-d, threshold, multi-party}
mitigated    := noise_flooding in {openfhe-NOISE_FLOODING_DECRYPT,
                                   eprint-2024-424,
                                   eprint-2025-1627,
                                   eprint-2025-1618,
                                   noise-flooding}
if not oracle_access:        SKIPPED  (threat model n/a)
if mitigated:                SAFE
else:                        VULNERABLE

Try it:

fhe-replay run --lib seal --params examples/bfv-128-vulnerable.json --attacks cheon-2024-127
fhe-replay run --lib seal --params examples/bfv-128-mitigated.json  --attacks cheon-2024-127

When a live adapter is available, Replay supersedes this static declaration check. For example, OpenFHE BFV/BGV only reports SAFE if the native decrypt oracle is actually randomized enough for boundary recovery not to converge.

Each module cites its source and (where applicable) the reference PoC. Replay implementations are written from public descriptions and ship under Apache-2.0; no upstream PoC source is redistributed.

Supported libraries

Adapter Native dependency Live oracle?
toy-lwe none — pure Python, in-tree (CI validation only, not secure) ✅ Replay
openfhe openfhe-python (PyPI wheel = Linux x86_64 only; build from source on macOS/Windows) ✅ Replay (BFV/BGV polynomial-domain bisection via serialized DCRT mutation)
seal tenseal (microsoft/SEAL backend) ❌ scaffold
lattigo fhe-replay-lattigo-helper (Go binary, PATH; helper crate planned for v0.1) ❌ scaffold
tfhe-rs fhe-replay-tfhe-rs-helper (Rust binary, PATH; helper crate planned for v0.1) ❌ scaffold

The Lattigo and tfhe-rs helper binaries are not yet shipped in this repo; the vendor/lattigo-helper/ and vendor/tfhe-rs-helper/ projects are tracked for v0.1. Until then, those adapters report their attacks as RiskCheck-only or NOT_IMPLEMENTED.

When building openfhe-python from source for the live OpenFHE replay, pin a release that emits big DCRT moduli as JSON strings during serialization. The adapter's precision guard fails fast on JSON-float moduli >2^53 to avoid silent truncation.

GitHub Action

- uses: BAder82t/fhe-attack-replay@v0
  with:
    library: openfhe
    params: configs/bfv-128.json
    attacks: all
    min-coverage: "1.0"

Python API

from fhe_attack_replay import run
from fhe_attack_replay.report import to_svg_badge, write_json

report = run(library="openfhe", params={"scheme": "BFV"}, attacks=None)
write_json(report, "report.json")
print(to_svg_badge(report))

Extending

Register a new adapter or attack via register_adapter / register_attack:

from fhe_attack_replay import register_attack
from fhe_attack_replay.attacks.base import Attack, AttackResult, AttackStatus, Citation

class MyAttack(Attack):
    id = "my-attack-2026"
    title = "..."
    citation = Citation(...)
    def run(self, adapter, ctx):
        return AttackResult(...)

register_attack(MyAttack)

Development

git clone https://github.com/BAder82t/fhe-attack-replay
cd fhe-attack-replay
python -m pip install -e ".[dev]"
ruff check .
pytest -ra --cov=fhe_attack_replay
python -m build
python -m twine check dist/*

Project docs

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fhe_attack_replay-0.1.2.tar.gz (88.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fhe_attack_replay-0.1.2-py3-none-any.whl (61.8 kB view details)

Uploaded Python 3

File details

Details for the file fhe_attack_replay-0.1.2.tar.gz.

File metadata

  • Download URL: fhe_attack_replay-0.1.2.tar.gz
  • Upload date:
  • Size: 88.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for fhe_attack_replay-0.1.2.tar.gz
Algorithm Hash digest
SHA256 400a265e0d28e46228264ca50452ca2a075f0bf081a5bf3a9f1d20c66f7929f6
MD5 44414d876ae94c32be3213a0ee4ff7b5
BLAKE2b-256 4725a97a5f48f6e3c0bac50a220a5e0b55ea5a88e6e4d344bdf9c8421665db52

See more details on using hashes here.

Provenance

The following attestation bundles were made for fhe_attack_replay-0.1.2.tar.gz:

Publisher: publish.yml on BAder82t/fhe-attack-replay

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fhe_attack_replay-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for fhe_attack_replay-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0906bcdcfab3e91338bcaed599a6966f05820535693b57089c844f98bd4c45fe
MD5 494bf54926acfd76845d2328cb3b21e9
BLAKE2b-256 d0c22e51d989b53ed906907ec8ed2b7f7eae591fe218bf56b18db62b9250ecc5

See more details on using hashes here.

Provenance

The following attestation bundles were made for fhe_attack_replay-0.1.2-py3-none-any.whl:

Publisher: publish.yml on BAder82t/fhe-attack-replay

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page