Skip to main content

Secure Vertical Federated Learning: ADP + Selective HE + ZKP, with a pluggable threat-detection / audit engine.

Project description

U-VFL — runnable reference implementation

A clean, reproducible implementation of the U-VFL framework from the paper "U-VFL: A Unified Framework for Secure Vertical Federated Learning with Adaptive Privacy and Verifiable Computation" (Ahmed et al., ICONIP 2026), so it can be installed and tested on any machine against the real UCI Heart Disease dataset — or any clinical CSV you supply.

It implements the three security modules over a two-party Vertical FL (SplitNN):

  • ADP — Adaptive Differential Privacy (decaying privacy budget)
  • SHE — Sensitivity-driven Selective Homomorphic Encryption (real CKKS via TenSEAL)
  • ZKP — a verifiable-integrity check that rejects tampered gradients

Install

pip install uvfl            # core (numpy-only knobs)
pip install "uvfl[all]"     # + real CKKS HE + the high-level helpers

60-second usage

Low-level — drop the three knobs into your own training loop:

import uvfl, numpy as np
tri = uvfl.Trilemma(uvfl.ADP(epsilon_max=5), uvfl.SHE(high_risk_fraction=0.3), uvfl.ZKP())
payload = tri.protect(gradient, round_t=t, total_rounds=T)   # privacy+encrypt+commit
gradient, integrity_ok = tri.open(payload)                   # verify + recover

High-level — fully-secured VFL in one call:

model = uvfl.fit("data.csv", target="diagnosis")     # ADP+SHE+ZKP applied automatically
print(model.report())
best  = uvfl.autotune("data.csv", target="diagnosis")  # search configs, keep best by F1

Distributed (2 medical sites + 1 master), data never leaves a site:

# site 1 VM:          uvfl.serve_party("siteA.csv", port=8001)
# site 2 VM (labels): uvfl.serve_party("siteB.csv", port=8001, target="diagnosis")
# master VM:
model = uvfl.train_federated(["http://SITE1_IP:8001", "http://SITE2_IP:8001"])

Empirical proof suite: uvfl.validate("data.csv", target="diagnosis"). See VALIDATION.md, DISTRIBUTED.md, ROADMAP.md.


⚠️ Please read first — what this is and isn't

This is an independent, clean-room re-implementation built from the paper's equations — it is not the authors' original experiment code. Consequently:

  • Absolute numbers will differ from the paper (different seed, data curation, optimiser, and the fact that the math describes a SplitNN while the paper also mentions XGBoost). The code reproduces the mechanisms and the qualitative story, not the exact 0.85/0.83 figures.
  • HE is real. Encryption uses CKKS (Microsoft SEAL via TenSEAL) when installed. The selective-vs-full speedup is measured, not assumed.
  • ZKP is an honest stand-in, not a zk-SNARK. It uses a hash commitment + Fiat–Shamir challenge to demonstrate the property (a tampered/malicious gradient is rejected, soundness ≈ 1 − 2^−κ). A deployment would use Groth16/PLONK over the gradient circuit. The paper itself notes "ZKP lacks concrete implementation benchmarks", so this matches its scope.
  • Two honest discrepancies we found vs. the paper, worth discussing:
    1. With CKKS slot-packing, a small gradient fits in one ciphertext whether full or selective, giving no speedup. Selective HE only helps when the parameter count exceeds slot capacity (per-component encryption). We therefore encrypt per-component, where the measured speedup is ≈ 1 / high_risk_fraction (≈ 3.3× at 30%). This is internally more coherent than the paper's headline (which states both 8.5× and 20–34×).
    2. The methodology describes SplitNN gradient exchange; "XGBoost" is mentioned once in limitations. We implement the SplitNN that the equations describe.

Nothing here is tuned to force the paper's numbers — results are whatever the seeded run produces.


1. Setup (pick one)

Requires Python 3.9–3.12. CPU only — no GPU, no PyTorch.

Option A — venv + pip (works everywhere)

cd uvfl
python3 -m venv .venv && source .venv/bin/activate     # Windows: .venv\Scripts\activate
pip install -r requirements.txt
pip install -r requirements-he.txt        # optional: real CKKS HE (recommended)

Option B — conda

cd uvfl
conda env create -f environment.yml
conda activate uvfl
pip install -r requirements-he.txt         # optional: real CKKS HE

Option C — make

cd uvfl
make setup        # core deps
make setup-he     # + real HE (optional)

If TenSEAL will not install on your platform, skip requirements-he.txt — the SHE module falls back to a clearly-labelled cost simulation and everything still runs.


2. Run it

# Real UCI Heart Disease (auto-downloads via ucimlrepo -> UCI URL -> mirror)
python run.py

# YOUR OWN real-life dataset (a CSV with a label column)
python run.py --data /path/to/your_clinical_data.csv --target outcome

# Offline smoke test (synthetic data, no internet)
python run.py --synthetic

# Faster / narrower sweeps
python run.py --epochs 40 --scenarios S1 S5 --noise 0.5 1.0
make run            # == python run.py
make run-synthetic  # == python run.py --synthetic

A full run takes well under a minute on a laptop.

Outputs (in outputs/)

  • results.csv — every scenario × noise level: accuracy, precision, recall, F1, F2, timings
  • results.json — same, plus the efficiency table and ZKP soundness demo
  • fig_accuracy_f1_vs_noise.png, fig_pareto.png, fig_comparative_bar.png, fig_confusion_matrices.png

2b. Distributed deployment (the real 3-VM setup) + proving it works

The single-process run above validates the algorithm. There is also a real distributed implementation — two data parties + a master/aggregation server, talking over HTTP — that maps onto a 3-VM deployment (two feature VMs + one master VM). No extra dependencies (stdlib transport).

# simulate all 3 nodes on one machine
python -m uvfl.distributed.run_local --data heart.csv              # clean run
python -m uvfl.distributed.run_local --data heart.csv --byzantine-mitm 0.5  # integrity test

# run the full PROOF suite (writes outputs/VALIDATION_REPORT.md)
python -m uvfl.distributed.validate  --data heart.csv

The validation suite empirically proves all five claims (correctness, ADP privacy, SHE confidentiality, ZKP integrity, efficiency). See VALIDATION.md for the methodology, DISTRIBUTED.md to deploy on the actual VMs, and ROADMAP.md for next steps. In the distributed system, raw features never leave a party VM, labels never leave the master, and high-risk gradient components are CKKS-encrypted with each party's public key (only that party can decrypt).


3. Testing on a real-life dataset

Point --data at any CSV and name the label with --target:

python run.py --data hospital_data.csv --target disease
  • If the CSV has the standard UCI heart columns, it uses the paper's clinical vertical split (Client A = primary-care features, Client B = cardiac-centre features + label).
  • Otherwise it auto-splits features by index into the two parties and warns.
  • Set the exact split, missing-value handling, target binarisation, etc. in config.yaml under data:.

4. Scenarios (paper's S1/S2/S3/S5)

ID Name Security on the exchanged gradient
S1 No Security plaintext (baseline utility)
S2 Full HE encrypt all ∇W_A components (overhead ref)
S3 Fixed DP constant high noise, no schedule
S5 U-VFL (ours) Adaptive DP + Selective HE + ZKP

noise_level ∈ [0,1] scales injected DP noise (the paper's 10%–100% grid); 1.0 = the full configured schedule. S1/S2 do not use DP, so they are noise-independent (trained once, drawn flat across the grid).


5. Paper → code map

Paper File Notes
Two-party SplitNN, gradient exchange uvfl/model.py pure NumPy + Adam
ADP eqs (1)–(5): ε_t, σ_t, clipping uvfl/adp.py AdaptiveDP
Fixed DP baseline uvfl/adp.py FixedDP
SHE eqs (6)–(11): sensitivity, selection uvfl/she.py real CKKS; per-component
ZKP prove/verify, soundness uvfl/zkp.py commitment + Fiat–Shamir stand-in
Scenarios, security stack uvfl/scenarios.py S1/S2/S3/S5
Metrics, confusion matrices uvfl/metrics.py sklearn
Experiment loop, efficiency table uvfl/experiment.py one-time HE benchmark
Figures uvfl/plots.py matplotlib
Distributed party node (per VM) uvfl/distributed/party.py bottom model + HE secret key
Master / aggregation node uvfl/distributed/master.py top model + security enforcement
3-VM simulator (localhost) uvfl/distributed/run_local.py start all nodes locally
Proof / validation suite uvfl/distributed/validate.py the five empirical proofs
Proof methodology / VM deploy / roadmap VALIDATION.md, DISTRIBUTED.md, ROADMAP.md

6. Reproducibility

  • Single global seed (default 42) in config.yaml controls data split, weight init, DP noise, and the ZKP demo. Re-running gives identical numbers.
  • HE cost is hardware-dependent; the speedup ratio (full / selective) is the stable, portable quantity.

7. Example run (UCI heart.csv mirror, seed 42 — yours will differ)

S1  acc~0.738 f1~0.765         (no security)
S2  acc~0.738 f1~0.765         (Full HE, exact -> same utility)
S3  acc~0.770 f1~0.794         (Fixed DP)
S5  acc~0.754 f1~0.783         (U-VFL: ADP+SHE+ZKP)
HE/round: full=633ms  selective=190ms  ->  3.33x speedup (real CKKS)
ZKP soundness: 200/200 honest accepted, 200/200 tampered rejected

Takeaway demonstrated on real data: full cryptographic + privacy protection keeps accuracy within ~2% of the unsecured baseline, selective HE is ~3.3× cheaper than full HE, and the integrity check rejects 100% of tampered gradients.

8. Data & license

UCI Heart Disease (Cleveland) — Janosi, Steinbrunn, Pfisterer, Detrano (1988), UCI ML Repository (id 45). The dataset is downloaded at runtime and not redistributed here. Code is provided for academic reproducibility.

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

uvfl-0.2.0.tar.gz (53.3 kB view details)

Uploaded Source

Built Distribution

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

uvfl-0.2.0-py3-none-any.whl (55.5 kB view details)

Uploaded Python 3

File details

Details for the file uvfl-0.2.0.tar.gz.

File metadata

  • Download URL: uvfl-0.2.0.tar.gz
  • Upload date:
  • Size: 53.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for uvfl-0.2.0.tar.gz
Algorithm Hash digest
SHA256 92d42a716c6561d664c8d3f6cadf53acb16084c42b1500153b64209818d0fd70
MD5 90c1e2f47d4c30f0bd406aaad2a67cf8
BLAKE2b-256 0196d19ea91dc1cd5513b0963ececb70c85a2e1996948567520eba14a654f7ae

See more details on using hashes here.

File details

Details for the file uvfl-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: uvfl-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 55.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for uvfl-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 054160ac30736cd4e8e1ce38a8d23d07cc8a8f2e7560d27a8d52cf6d996fb9b2
MD5 24b0f99e49f93fad1165523b90b4b4ae
BLAKE2b-256 0785ec8c3a724f49f32386b2dee133884012974a372cc2186978081c00248d1a

See more details on using hashes here.

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