Skip to content

A proof of concept implementation of Chaum-Pedersen ZKP(Zero Knowledge Proof) based authentication system in C++, Python, and Rust implementations. The POC system allows password-less authentication where the server never learns user passwords.

Notifications You must be signed in to change notification settings

spatnaik17/chaumpedersen-zkp-authentication

Repository files navigation

Zero-Knowledge Proof Authentication System

A proof of concept implementation of Chaum-Pedersen ZKP(Zero Knowledge Proof) based authentication system in C++, Python, and Rust implementations. The POC system allows password-less authentication where the server never learns user passwords.

Available Implementations

  • C++ Version (cpp/ directory): High-performance implementation using Crypto++
  • Python Version (python/ directory): Easy-to-use implementation with pure Python
  • Rust Version (rust/ directory): Memory-safe, concurrent implementation with modern tooling

Features

  • Zero-Knowledge Authentication: Server verifies user identity without learning the password
  • Chaum-Pedersen Protocol: Non-interactive proofs via Fiat-Shamir transform
  • Secure Storage: SQLite database stores only public keys and salts
  • RESTful API: HTTP server with session management
  • CLI Client: Easy-to-use command-line interface
  • Replay Attack Prevention: One-time nonce challenges with short TTL
  • 2048-bit Security: Uses safe primes for cryptographic operations

Choosing an Implementation

C++ Version

Best for: High performance, embedded systems

  • Faster cryptographic operations
  • Lower memory footprint
  • Compiled binary distribution

Python Version

Best for: Rapid prototyping, research, education, quick deployment

  • Easier to understand and modify
  • No compilation required
  • Cross-platform without rebuilding

Rust Version

Best for: Systems requiring safety, concurrent applications, modern development

  • Memory safety without garbage collection
  • Fearless concurrency
  • Modern tooling (cargo, clippy, rustfmt)
  • Zero-cost abstractions

Technology Stack

C++ Implementation

  • Language: C++17
  • Crypto Library: Crypto++ (libcrypto++)
  • Database: SQLite3
  • HTTP Server: cpp-httplib (header-only)
  • JSON: nlohmann/json (header-only)
  • Build System: CMake
  • Testing: Catch2 (optional)

Python Implementation

  • Language: Python 3.8+
  • Crypto: Built-in hashlib, secrets
  • Primes: sympy
  • Database: sqlite3 (built-in)
  • HTTP Server: Flask
  • HTTP Client: requests
  • Testing: pytest

Rust Implementation

  • Language: Rust 2021 edition
  • Crypto: num-bigint, sha2, rand
  • Database: rusqlite (bundled SQLite)
  • HTTP Server: Actix-web (async)
  • HTTP Client: reqwest
  • Build System: Cargo
  • Testing: Built-in test framework

Quick Start

Python Version (Recommended for Quick Start)

# Install dependencies
cd python
pip install -r requirements.txt

# Terminal 1: Start server
cd server
python main.py

# Terminal 2: Use client (client handles /params and /challenge)
cd client
python cli_client.py register alice password123
python cli_client.py login alice password123

Rust Version

# Install Rust (if needed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Build and run
cd rust
cargo build --release

# Terminal 1: Start server (2048-bit predefined)
./target/release/zkp-server

# Terminal 2: Use client
./target/release/zkp-client register alice password123
./target/release/zkp-client login alice password123

C++ Version

See detailed build instructions below.

Prerequisites

For C++ Implementation

Ubuntu/Debian

sudo apt-get update
sudo apt-get install -y \
    build-essential \
    cmake \
    libcrypto++-dev \
    libsqlite3-dev \
    libcatch2-dev \
    pkg-config

Fedora/RHEL

sudo dnf install -y \
    gcc-c++ \
    cmake \
    cryptopp-devel \
    sqlite-devel \
    catch-devel \
    pkg-config

For Python Implementation

# Python 3.8 or higher required
python3 --version

# Install dependencies
cd python
pip install -r requirements.txt

Build Instructions (C++ Version)

# Navigate to cpp directory
cd cpp

# Create build directory
mkdir build && cd build

# Configure with CMake
cmake ..

# Build the project
make -j$(nproc)

This will create two executables:

  • auth_server - Authentication server
  • auth_client - CLI client

Usage

C++ Version

Starting the Server

# Start server on default port 8080 with default database
./auth_server

# Specify custom port and database
./auth_server --port 9000 --db custom_users.db

# Use 4096-bit parameters (generation mode recommended)
./auth_server --bits 4096 --params-mode generate

# Show help
./auth_server --help

Using the Client

Register a New User

./auth_client register alice mypassword123

Login (Authenticate)

./auth_client login alice mypassword123

This will return a session token that you can use for authenticated requests.

Verify Session Token

./auth_client verify <your-session-token>

Custom Server Connection

./auth_client register alice password --host 192.168.1.100 --port 9000
./auth_client login alice password --host 192.168.1.100 --port 9000

Python Version

Starting the Server

cd python/server
python main.py

# Specify custom port and database
python main.py --port 9000 --db custom_users.db

Using the Client

cd python/client

# Register a new user
python cli_client.py register alice mypassword123

# Login (Authenticate)
python cli_client.py login alice mypassword123

# Verify session token
python cli_client.py verify <your-session-token>

# Custom server connection
python cli_client.py register alice password --host 192.168.1.100 --port 9000

Note: First startup may take 30-60 seconds while generating 2048-bit safe primes. This is normal.

API Endpoints (Summary)

GET /params

Fetch group parameters p, q, g, h (hex) used for proof generation/verification.

POST /register

Register by submitting client-computed public keys and salt: { "username": "alice", "y1": "<hex>", "y2": "<hex>", "salt": "<hex>" }.

POST /challenge

Request a one-time nonce for { "username": "alice" }. Response includes { y1, y2, salt, nonce, expires_at }.

POST /authenticate

Submit proof { "username": "alice", "a1": "<hex>", "a2": "<hex>", "s": "<hex>", "nonce": "<hex>" }. On success returns { message, token, username }.

GET /verify

Verify a session token.

Request Headers:

Authorization: Bearer <token>

Response (200 OK):

{
  "valid": true,
  "message": "Session is valid"
}

Running Tests

C++ Tests

If Catch2 is installed, tests will be automatically built.

# From the build directory
./test_zkp

# Or using CTest
ctest --output-on-failure

Python Tests

cd python
pytest tests/

# With verbose output
pytest -v tests/

Rust Tests

cd rust
cargo test

# With output
cargo test -- --nocapture

# Release mode (faster)
cargo test --release

Security Features

  1. Safe Prime Generation: Uses 2048-bit safe primes (p = 2q + 1)
  2. Random Salt: Each user gets a unique 256-bit random salt
  3. Password Hashing: Passwords are hashed with username and salt
  4. Nonce Challenges: One-time, short-lived server nonces prevent replay attacks
  5. Session Expiry: Session tokens expire after 1 hour
  6. No Password Transmission: Passwords are never sent to or stored on the server

How It Works

Registration

  1. Client derives secret x = Hash(username || password || salt)
  2. Client computes y1 = g^x mod p and y2 = h^x mod p
  3. Server stores (username, y1, y2, salt) in database

Authentication

  1. Client requests a one-time nonce from /challenge
  2. Client generates random k and computes commitments a1 = g^k mod p, a2 = h^k mod p
  3. Client computes challenge c = Hash(hex(a1)|hex(a2)|hex(y1)|hex(y2)|nonce) (Fiat-Shamir)
  4. Client computes response s = k - c*x mod q
  5. Server verifies: g^s * y1^c = a1 and h^s * y2^c = a2, and consumes the nonce

Parameter Size (2048 vs 4096)

  • 2048-bit (default): ~112-bit security, fastest startup
  • 4096-bit: higher security, slower startup and heavier CPU
  • Python: python server/main.py --bits 4096 --params-mode generate
  • C++: ./auth_server --bits 4096 --params-mode generate
  • Rust: zkp-server --bits 4096 --params-mode generate
  1. Server creates session token upon successful verification

Project Structure

zkp-auth-system/
├── README.md                    # This file
├── QUICKSTART.md                # Quick start guide
├── IMPLEMENTATION_COMPARISON.md # C++ vs Python comparison
├── docs/                        # Documentation
│   ├── API.md                   # REST API documentation
│   ├── ZKP_THEORY.md            # Zero-Knowledge Proof theory
│   ├── CHAUM_PEDERSEN.md        # Chaum-Pedersen protocol details
│   └── IMPLEMENTATION.md        # Mathematical implementation details
├── cpp/                         # C++ Implementation
│   ├── CMakeLists.txt           # Build configuration
│   ├── README.md                # C++ specific documentation
│   ├── src/
│   │   ├── zkp/                 # ZKP cryptography
│   │   │   ├── chaum_pedersen.hpp
│   │   │   └── chaum_pedersen.cpp
│   │   ├── db/                  # Database layer
│   │   │   ├── user_database.hpp
│   │   │   └── user_database.cpp
│   │   ├── server/              # HTTP server
│   │   │   ├── auth_server.hpp
│   │   │   ├── auth_server.cpp
│   │   │   └── main.cpp
│   │   └── client/              # CLI client
│   │       └── cli_client.cpp
│   ├── tests/                   # C++ tests
│   │   └── test_zkp.cpp
│   └── third_party/             # Header-only libraries
│       ├── httplib.h
│       └── nlohmann/
│           └── json.hpp
├── python/                      # Python Implementation
│   ├── README.md                # Python specific documentation
│   ├── requirements.txt         # Python dependencies
│   ├── setup.py                 # Package setup
│   ├── run_server.sh            # Quick start script
│   ├── run_tests.sh             # Test runner
│   ├── zkp/                     # ZKP cryptography
│   │   ├── __init__.py
│   │   └── chaum_pedersen.py
│   ├── db/                      # Database layer
│   │   ├── __init__.py
│   │   └── user_database.py
│   ├── server/                  # Flask server
│   │   ├── __init__.py
│   │   ├── auth_server.py
│   │   └── main.py
│   ├── client/                  # CLI client
│   │   ├── __init__.py
│   │   └── cli_client.py
│   └── tests/                   # Python tests
│       ├── __init__.py
│       └── test_zkp.py
└── rust/                        # Rust Implementation
    ├── Cargo.toml               # Dependencies and config
    ├── README.md                # Rust specific documentation
    ├── src/
    │   ├── lib.rs               # Library root
    │   ├── zkp/                 # ZKP cryptography
    │   │   └── mod.rs
    │   ├── db/                  # Database layer
    │   │   └── mod.rs
    │   ├── server/              # Actix-web server
    │   │   └── mod.rs
    │   ├── client/              # HTTP client
    │   │   └── mod.rs
    │   └── bin/                 # Binary executables
    │       ├── server.rs        # Server binary
    │       └── client.rs        # Client binary
    └── tests/                   # Integration tests
        └── integration_tests.rs

Documentation

Core Documentation

Implementation Guides

Theory and Protocol

API Reference

Understanding Zero-Knowledge Proofs

This project demonstrates Zero-Knowledge Proofs (ZKP) in action. Here's what makes it special:

New to ZKP? Check out our Visual Guide with diagrams, analogies, and step-by-step illustrations!

What is Zero-Knowledge?

The server can verify you know your password without ever learning what the password is. It's like proving you know a secret without revealing the secret itself.

Key Concepts

  1. No Password Transmission: Your password never leaves your device
  2. No Password Storage: Server only stores public keys, never passwords
  3. Mathematical Proof: Uses the Chaum-Pedersen protocol based on discrete logarithms
  4. Non-Interactive: Uses Fiat-Shamir transform for one-shot proofs
  5. Replay Protection: One-time nonces prevent reuse of old proofs

How It Works (Simplified)

Registration:
  Password → Secret (x) → Public Keys (y₁ = g^x, y₂ = h^x)
  Server stores: Public Keys only!

Authentication:
  1. Client generates random k
  2. Client computes commitments: a₁ = g^k, a₂ = h^k
  3. Client computes challenge: c = Hash(commitments, public_keys, nonce)
  4. Client computes response: s = k - c·x
  5. Server verifies: g^s · y₁^c = a₁ and h^s · y₂^c = a₂

  Server learns: Proof is valid ✓
  Server never learns: Password or secret x ✗

For deep dive into the mathematics, see docs/ZKP_THEORY.md and docs/CHAUM_PEDERSEN.md.

License

This project was developed as POC for research purposes.

References

  • Chaum, D., & Pedersen, T. P. (1992). "Wallet databases with observers." In Advances in Cryptology - CRYPTO.
  • Fiat, A., & Shamir, A. (1986). "How to prove yourself: Practical solutions to identification and signature problems." In Advances in Cryptology - CRYPTO.
  • Schnorr, C. P. (1991). "Efficient signature generation by smart cards." Journal of Cryptology, 4(3), 161-174.
  • Goldwasser, S., Micali, S., & Rackoff, C. (1989). "The knowledge complexity of interactive proof systems." SIAM Journal on Computing.

About

A proof of concept implementation of Chaum-Pedersen ZKP(Zero Knowledge Proof) based authentication system in C++, Python, and Rust implementations. The POC system allows password-less authentication where the server never learns user passwords.

Resources

Stars

Watchers

Forks