Metadata-Version: 2.5
Name: secure-fl
Version: 2026.8.25.dev1
Summary: Dual-Verifiable Framework for Federated Learning using Zero-Knowledge Proofs
Project-URL: Homepage, https://github.com/krishantt/secure-fl
Project-URL: Bug Reports, https://github.com/krishantt/secure-fl/issues
Project-URL: Source, https://github.com/krishantt/secure-fl
Project-URL: Documentation, https://github.com/krishantt/secure-fl/blob/main/README.md
Author-email: Krishant Timilsina <krishtimil@gmail.com>, Bindu Paudel <binduupaudel565@gmail.com>
Maintainer-email: Krishant Timilsina <krishtimil@gmail.com>, Bindu Paudel <binduupaudel565@gmail.com>
License: MIT
License-File: LICENSE
Keywords: cryptography,federated-learning,machine-learning,privacy,zero-knowledge-proofs,zk-snarks,zk-starks
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.12
Requires-Dist: click>=8.0.0
Requires-Dist: flwr>=1.5.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: pysnark
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.0.0
Requires-Dist: textual>=6.2.1
Requires-Dist: torch>=2.0.0
Requires-Dist: torchvision>=0.15.0
Provides-Extra: benchmark
Requires-Dist: memory-profiler>=0.61.0; extra == 'benchmark'
Requires-Dist: pytest-benchmark>=5.2.3; extra == 'benchmark'
Provides-Extra: dev
Requires-Dist: mypy>=1.19.0; extra == 'dev'
Requires-Dist: pre-commit>=3.0.0; extra == 'dev'
Requires-Dist: psutil>=5.9.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest-xdist>=3.3.0; extra == 'dev'
Requires-Dist: pytest>=7.4.0; extra == 'dev'
Requires-Dist: ruff>=0.14.8; extra == 'dev'
Requires-Dist: types-psutil; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Provides-Extra: medical
Requires-Dist: medmnist>=2.2.0; extra == 'medical'
Provides-Extra: viz
Requires-Dist: matplotlib>=3.7.0; extra == 'viz'
Requires-Dist: plotly>=5.0.0; extra == 'viz'
Requires-Dist: seaborn>=0.12.0; extra == 'viz'
Description-Content-Type: text/markdown

# 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

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

### ZKP Prerequisites

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

# Verify
uv run secure-fl check-zkp
```

### Run the attack defense demo

```bash
# 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

```bash
# 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

```python
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
```

```python
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

```yaml
# 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 |

```python
from secure_fl.models.factory import model_fn
factory = model_fn("cifar10")   # returns callable → ResNet18Model instance
model = factory()
```

```python
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

```bash
# 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

```bash
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](LICENSE) for details.

## Citation

```bibtex
@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

- [Flower](https://flower.dev) — federated learning infrastructure
- [Circom](https://github.com/iden3/circom) / [SnarkJS](https://github.com/iden3/snarkjs) — zk-SNARK toolchain
- [PySNARK](https://github.com/meilof/pysnark) — Python zk-STARK/SNARK library
