Skip to content

About

Federated learning with homomorphic-encrypted gradient aggregation — the server can compute on encrypted gradients but can never decrypt them.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

PrivacyMesh

Federated learning where the aggregator can compute on your gradients but can never see them — enforced by encryption, not policy.

Clients train locally on their own data and send only homomorphically-encrypted gradients. The aggregator performs the averaging math directly on ciphertext — it never has access to the secret key needed to decrypt anything, by design rather than by policy.

Dashboard (screenshot placeholder)

What this actually does

In standard federated learning, clients still send somewhat-sensitive gradient information to a central server in plaintext. PrivacyMesh closes that gap using CKKS homomorphic encryption (via TenSEAL): clients encrypt their gradients before sending them, the aggregator performs the sum/average math directly on ciphertexts, and only the clients — who hold the only copy of the secret key — can decrypt the final result.

The aggregator is not simply trusted not to peek. It is structurally incapable of decrypting anything, because it only ever holds a public-key context with the secret key stripped out. This repo includes a standalone proof of that guarantee (key_separation_poc.py) that deliberately tries to decrypt on the aggregator side and shows TenSEAL refusing.

Architecture

┌──────────────┐        encrypted gradient        ┌──────────────────┐
│   Client 1   │ ───────────────────────────────▶ │                  │
│ (local train,│                                    │    Aggregator    │
│  encrypt)    │◀─────────────────────────────────  │  (sums/averages  │
└──────────────┘     encrypted averaged update      │   ciphertexts,   │
                                                      │  never decrypts) │
┌──────────────┐        encrypted gradient          │                  │
│   Client 2   │ ───────────────────────────────▶  │                  │
└──────────────┘◀───────────────────────────────── └──────────────────┘
                     encrypted averaged update

                    ┌─────────────┐
   loss values ────▶ │  Dashboard  │  (loss only — never gradients/data)
   (plaintext,       │  (FastAPI + │
    non-sensitive)   │   live chart)│
                    └─────────────┘
  • Encryption: CKKS scheme via TenSEAL — supports real-valued arithmetic on ciphertexts (needed since gradients are floats, not integers)
  • Training: PyTorch, CPU-only
  • Networking: gRPC between clients and aggregator
  • Orchestration: Docker + docker-compose (each component is a separate container)
  • Monitoring: FastAPI dashboard, receives only loss values (never gradients or raw data) for live visualization

Proven guarantees

This project isn't just "it runs" — each of these was independently tested and verified before being combined:

  1. Homomorphic addition is correct — encrypted sum matches plaintext sum within floating-point tolerance (poc_homomorphic.py)
  2. The aggregator cannot decrypt, even if it tries — public/secret key separation is enforced by the library itself, not by convention (key_separation_poc.py)
  3. Real multi-layer PyTorch gradients survive the full encrypt → aggregate → decrypt round trip, correctly reconstructed and applied via an optimizer step (real_gradients_poc.py)
  4. Multi-round training genuinely converges — loss decreases monotonically across 8 rounds for every client tested
  5. Works across independently networked environments — verified running with the aggregator on native Windows (Docker Desktop) and clients inside WSL2's separate Linux environment, communicating over a real network boundary

Running it

Prerequisites

  • Docker Desktop
  • ~2GB free disk space (CPU-only PyTorch, much smaller than the GPU build)

Setup

  1. Generate the shared encryption keys (one-time):
cd shared
docker run --rm -v "${PWD}:/app" -w /app python:3.11-slim sh -c "pip install tenseal numpy && python keygen.py"

This produces secret_context.bin and public_context.bin.

  1. Distribute the keys:
cp secret_context.bin ../client/
cp public_context.bin ../aggregator/

Important: secret_context.bin must never end up in the aggregator/ folder — that would defeat the entire security model.

  1. Run everything:
cd ..
docker compose up --build
  1. Open the live dashboard:
http://localhost:8000

You'll see 8 rounds of federated training run automatically across two simulated clients, with a live-updating loss chart.

Project structure

privacymesh/
├── docker-compose.yml
├── proto/federated.proto        # gRPC message definitions
├── shared/keygen.py             # one-time shared key generation
├── aggregator/                  # holds ONLY the public key context
│   └── server.py                # gRPC server, barrier-synchronized multi-client aggregation
├── client/                      # holds the secret key
│   └── client.py                # local training loop, encryption, gRPC calls
├── dashboard/                   # FastAPI + Chart.js, receives loss values only
│   └── server.py
├── poc_homomorphic.py           # standalone proof: encrypted math is correct
├── key_separation_poc.py        # standalone proof: aggregator cannot decrypt
└── real_gradients_poc.py        # standalone proof: real PyTorch gradients work end-to-end

Design notes & honest limitations

  • Key distribution is simulated, not solved. All clients currently share one encryption context generated by a single trusted keygen.py run. Real-world federated learning with genuinely independent, mutually-untrusting clients would need a proper distributed key generation protocol (multi-party computation) — a legitimate direction for future work.
  • Barrier synchronization is simple. The aggregator waits for exactly NUM_CLIENTS submissions per round before aggregating. It doesn't yet handle stragglers, dropped clients, or asynchronous rounds — all real considerations in production FL systems.
  • Cloud deployment is architected but not yet live. The system is designed to deploy identically to any environment (swap AGGREGATOR_HOST for a public IP) — validated across Windows/WSL2 as a stand-in for genuinely separate machines. Deployment to a cloud provider (Oracle Cloud / Fly.io / GCP) is a natural next step once account verification is sorted out.

Why this exists

Built as a self-directed exploration into combining homomorphic encryption with practical machine learning — extending earlier work on privacy-preserving systems (EncryptedHealthLedger, MediProof) from statistics and credential verification into the ML domain.

About

Federated learning with homomorphic-encrypted gradient aggregation — the server can compute on encrypted gradients but can never decrypt them.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages