This repository contains proof-of-concept code and experiments for the paper How (not) to Switch FHE Schemes: Framework and Attacks in the IND-CPA-D Model by Giacomo Santato and Riccardo Zanotto, available at https://eprint.iacr.org/2026/285.
The target OpenFHE version is 1.3.0.
OpenFHE 1.3.0 must be built and installed, or at least available through an
OpenFHE CMake package directory. Configure this project by pointing
OpenFHE_DIR to that package location.
For example:
cmake -S . -B build -DOpenFHE_DIR=/path/to/openfhe/install/lib/OpenFHE
cmake --build buildIf OpenFHE was built locally but not installed, the correct path is the directory
that contains OpenFHEConfig.cmake.
./build/show_leakshow_leak is the minimal leakage demonstration. It sets parameters for which
the scheme-switching leakage recovers the CKKS encryption error exactly, and
asserts that the recovered error vector is equal to the original folded error
vector.
./build/estimate_errorestimate_error measures the size of the CKKS encryption error for a small set
of ring dimensions and writes results/error_estimates.csv. It also prints the
simple a-priori estimate used to predict whether the interval of valid
amplification exponents k should be non-empty.
./build/check_k [ring_log] [threads]check_k sweeps CKKS scaling factors and amplification exponents k. It writes
results/check_k_ring<ring_log>.csv, with ring_log = 12 by default. The
optional second argument selects the requested number of worker threads; the
program clamps this to the available work and hardware threads.
The generated CSV is meant to be visualized as the table in the paper. It
contains, for each pair (Delta, k), the measured residual error after applying
the leakage recovery procedure and the predicted real-valued k-window.
./build/run_attack [ring_log]run_attack implements the full attack experiment through the IND-CPA-D
pipeline game. It generates the CKKS/FHEW pipeline, queries the game oracles,
extracts the public ciphertext data and leakage samples, and writes
results/attack<ring_log>/data.m, with ring_log = 12 by default.
If magma is available on PATH, run_attack invokes solve_system.m, parses
the recovered CKKS secret key, reports Magma's time and memory summary when
present, and submits the recovered key as the adversary's final guess to the
game. It prints only the final success/failure result, not the recovered secret
key. If magma is not available, it still writes data.m and prints the
challenge secret key for manual checking.
Each run also writes results/attack<ring_log>/magma_resources.txt and
results/attack<ring_log>/attack_summary.txt. The summary records the C++
attack time for the adversary's oracle interaction and data.m generation, the
Magma resource numbers when available, and the final success bit.
The time and memory required by the Magma solve are the resources reported for the full attack in the paper.
The Magma step can also be run manually:
cd results/attack12
magma ../../solve_system.mThe generated CSV files in results/ can be inspected with
results.ipynb.
The notebook loads the outputs of estimate_error, check_k, and run_attack,
and produces the plots and compact tables corresponding to the experimental
tables in the paper.
For full-attack runs, aggregate the Magma resource files first:
python3 results/aggregate_attacks.pyThis writes results/attacks.csv, which the notebook uses to plot Magma solve
time and memory across ring dimensions.
The CKKS-to-FHEW setup lives in include/pipeline_utils.h and
src/pipeline_utils.cpp, under the pipeline namespace. The main types are:
pipeline::PipelineParams, which stores scheme and switching parameters.pipeline::PipelineContext, which owns the OpenFHE contexts and secret keys.pipeline::PipelinePublicState, which contains only the public information exposed to the adversary.
The IND-CPA-D game API lives in include/pipeline_game.h and
src/pipeline_game.cpp, under the game namespace. It exposes the CKKS source
oracles Enc1, Eval1, Dec1, the FHEW target oracles Enc2, Eval2,
Dec2, and the pipeline boundary oracle Switch. Decryption oracles only
return a value when the two stored message branches are equal.
Eval1 supports CKKS addition and multiplication. Eval2 exposes the FHEW
operations used by the OpenFHE switched-ciphertext interface: addition,
EvalFloor, EvalSign, EvalDecomp, and lookup-table function evaluation
through EvalFunc.
Shared experiment-side helpers live in include/leakage_helpers.h and
src/leakage_helpers.cpp, under the leakage namespace. These routines compute
encryption errors, re-encode leakage values, measure residuals, and provide the
common code used by show_leak, check_k, and estimate_error.