Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Secure FL: Zero-Knowledge Federated Learning

A dual-verifiable framework for federated learning using zero-knowledge proofs to ensure training integrity and aggregation correctness.

Core Features

  • Dual ZKP Verification: Client-side zk-STARKs (PySNARK) + Server-side zk-SNARKs (Circom/SnarkJS)
  • FedJSCM Aggregation: Momentum-based federated optimization with auto-reinit on architecture changes
  • Dynamic Proof Rigor: StabilityMonitor adapts proof complexity (low/medium/high/adaptive) based on training stability
  • Deterministic Hashing: SHA-256 over parameter bytes — safe across Python/numpy versions
  • Attack Detection: Norm-bound enforcement, hash verification, and ZKP circuit checks block poisoned updates

Architecture

Client: Local Training → zk-STARK proof (learnable params) → Send full state_dict + proof
Server: Receive updates → verify proofs → FedJSCM aggregation → zk-SNARK proof → Distribute model

Dual verification:

  1. Clients generate zk-STARK proofs of correct local training (delta norm bound, hash commitment)
  2. Server generates zk-SNARK proofs of correct FedJSCM aggregation

Quick Start

Installation

# From source with uv (recommended)
git clone https://github.com/krishantt/secure-fl
cd secure-fl
uv sync --all-extras

ZKP Prerequisites

# Automated setup (installs Rust, Circom, SnarkJS)
make setup-zkp

# Verify
uv run secure-fl check-zkp

Run the attack defense demo

# Synthetic data — fastest, no download needed
uv run python demo/simulate_attack.py --dataset synthetic_small --num-rounds 6

# MNIST
uv run python demo/simulate_attack.py --dataset mnist

# CIFAR-10 with more malicious clients
uv run python demo/simulate_attack.py --dataset cifar10 --malicious 2 --proof-rigor low

# MedMNIST
uv run python demo/simulate_attack.py --dataset medmnist --malicious 2 --proof-rigor low

The TUI shows real-time ZKP verification, attack detection, and accuracy comparison (with ZKP vs projected without). Attackers appear in ~65% of rounds; the rest are all-honest.

Start a federated learning session

# Server
uv run secure-fl-server --config experiments/config.yaml

# Client (in separate terminals)
uv run secure-fl-client --server localhost:8080 --dataset mnist --client-id client_1
uv run secure-fl-client --server localhost:8080 --dataset mnist --client-id client_2

# Or use Docker
docker compose up -d

Python API

from secure_fl.federation.client_runtime import create_client
from secure_fl.models.factory import model_fn

# Create a secure FL client
factory = model_fn("mnist")   # returns MNISTCNN factory
client = create_client(
    client_id="client_1",
    model_fn=factory,
    train_data=train_dataset,
    enable_zkp=True,
    proof_rigor="low",    # "low" | "medium" | "high"
    local_epochs=1,
    learning_rate=0.01,
)

# client.fit(parameters, config) → (updated_params, num_examples, metrics)
# metrics["zkp_proof"] contains the JSON proof string when enable_zkp=True
from secure_fl.federation.aggregation import FedJSCMAggregator
from secure_fl.zkp.proof_manager import ServerProofManager

aggregator = FedJSCMAggregator(momentum=0.9, learning_rate=1.0)
server_pm  = ServerProofManager()

# Verify a client proof
ok = server_pm.verify_client_proof(proof_json, updated_params, global_params)

# Aggregate verified updates
global_params = aggregator.aggregate(
    client_updates=verified_updates,
    client_weights=normalized_weights,
    server_round=rnd,
    global_params=global_params,
)

Configuration

# experiments/config.yaml
server:
  host: "localhost"
  port: 8080
  num_rounds: 10

strategy:
  min_fit_clients: 2
  fraction_fit: 1.0
  momentum: 0.9

zkp:
  enable_zkp: true
  proof_rigor: "high"   # "low" | "medium" | "high" | "adaptive"
  quantize_weights: true
  quantization_bits: 8

Models and Datasets

Dataset Model Notes
mnist MNISTCNN 2-layer CNN, fast
cifar10 ResNet18Model Full ResNet18
medmnist ResNet18Model Medical imaging
synthetic_small SimpleModel MLP, no download needed
from secure_fl.models.factory import model_fn
factory = model_fn("cifar10")   # returns callable → ResNet18Model instance
model = factory()
from secure_fl.data.benchmark_data import load_dataset, partition_dataset, subsample_dataset

train, test = load_dataset("mnist", seed=42)
train = subsample_dataset(train, max_samples=2000, seed=42)
client_subsets = partition_dataset(train, n=6, iid=False, seed=42)  # Dirichlet non-IID

Technical Details

FedJSCM Aggregation

m^{t+1} = γ·m^t + (1−γ)·Δ
w^{t+1} = w^t + η·m^{t+1}

where Δ = weighted_avg(client_updates) − global_params. Momentum is reinitialized automatically if the model architecture changes between rounds. Integer-dtype buffers (e.g. BatchNorm num_batches_tracked) are preserved through aggregation.

ZKP Proof Schema

Each client proof is a JSON object containing:

  • initial_hash, updated_hash, delta_hash — SHA-256 commitments over learnable parameters
  • delta_norm_l2, max_delta_norm_l2 — norm bound enforcement
  • pysnark — PySNARK circuit result (delta_bound_proof)

Server verification order: proof present → valid JSON → hash matches → delta hash matches → norm within bound → circuit ok.

Parameter Representations

Two lists exist and must not be mixed:

Source Contents
Full state dict model.state_dict().values() weights + biases + BN buffers
Learnable only model.parameters() weights + biases only

fit() returns full state dict. ZKP proofs cover learnable-only params. Mixing them with zip causes shape-mismatch errors on BN models (ResNet18, MNISTCNN).

Dynamic Proof Rigor

StabilityMonitor tracks gradient variance and convergence across rounds and adapts ProofRigor:

  • High variance / early rounds → high (more proof coverage)
  • Stable training → low (faster proofs)
  • adaptive mode enables automatic adjustment each round

Experiments & Benchmarks

# Fast smoke run
uv run python experiments/canonical_benchmark.py --quick

# Full reproducible benchmark with repeats
uv run python experiments/canonical_benchmark.py \
  --datasets mnist synthetic_small \
  --num-repeats 5 \
  --seed 42 \
  --require-real-proofs

# Interactive benchmark TUI (supports reattach)
uv run python experiments/benchmark_tui.py

Outputs: benchmark_results.json (per-seed runs) and tradeoff_report.json (aggregated trade-off summary).

Repository Structure

secure-fl/
├── src/secure_fl/
│   ├── core/            # Types, config (thread-safe singleton), exceptions
│   ├── federation/      # SecureFlowerClient, SecureFlowerServer, FedJSCMAggregator,
│   │                    #   StabilityMonitor, client_utils, helpers
│   ├── zkp/             # ClientProofManager, ServerProofManager, quantization
│   ├── models/          # SimpleModel, MNISTCNN, ResNet18Model, factory
│   ├── data/            # benchmark_data: load/partition/subsample datasets
│   ├── cli/             # Click CLI: secure-fl, secure-fl-server, secure-fl-client
│   ├── proofs/
│   │   ├── client_circuits/  # PySNARK delta_bound_proof circuit
│   │   └── server/           # Circom aggregation SNARK circuits
│   └── utils/           # helpers (compute_hash, compute_parameter_norm), logging
├── demo/
│   └── simulate_attack.py    # Textual TUI: real ZKP attack detection demo
├── experiments/
│   ├── canonical_benchmark.py
│   ├── benchmark_tui.py
│   └── config.yaml
└── tests/
    ├── unit/            # No external dependencies (fast)
    └── integration/     # Requires Circom + SnarkJS

Development

make dev          # Full setup (uv sync + ZKP tools)
make lint         # Ruff lint
make format       # Ruff format  ← run before every commit
make type-check   # mypy (strict)
make test         # Full suite
make test-quick   # Fast, --exitfirst
make test-cov     # With coverage (threshold: 34%)

Known Limitations

  • _submit_to_blockchain() raises NotImplementedError — not yet implemented
  • Server ZKP (Circom/SnarkJS) requires make setup-zkp; subprocess calls time out after 300 s
  • Coverage threshold is 34% — being raised incrementally

License

MIT License — see LICENSE for details.

Citation

@misc{timilsina2026securefl,
  title={Secure-FL: Zero-Knowledge Proofs for Dual-Verifiable Federated Learning},
  author={Timilsina, Krishant and Paudel, Bindu and Timilsina, Arun Kumar},
  year={2026},
  url={https://github.com/krishantt/secure-fl},
  note={Preprint}
}

Acknowledgments

Metadata

Release files for secure-fl 2026.8.25.dev1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for secure-fl 2026.8.25.dev1
File Size Uploaded
secure_fl-2026.8.25.dev1.tar.gz 14.3 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for secure-fl 2026.8.25.dev1
File Interpreter ABI Platform
secure_fl-2026.8.25.dev1-py3-none-any.whl Python 3 none any Details

Total release size: 28.5 MB

Release files / secure_fl-2026.8.25.dev1.tar.gz

Download URL secure_fl-2026.8.25.dev1.tar.gz
Size 14.3 MB
Tags Source
SHA-256 checksum
How to use checksums
e881ee6fc1e9b7dfa6c1730c457a3e2fa7db6cf85d453a378bfc2a0a2684f305
BLAKE2b-256 checksum
How to use checksums
a50509939597160280b307cfe58f6607922d1ea44da7be94a792fb7f52015e0b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / secure_fl-2026.8.25.dev1-py3-none-any.whl

Download URL secure_fl-2026.8.25.dev1-py3-none-any.whl
Size 14.3 MB
Tags Python 3
SHA-256 checksum
How to use checksums
79b1342f6ae63b966cb75fb2d9f8cd5c377e77af1913e2aa72479f910cc6d30a
BLAKE2b-256 checksum
How to use checksums
5a1f37bdf1e79c34f373c681204ca90e3055e70974d4b5f918372f38de44fd36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page