This document summarizes the work implemented across the repository for a multi‑language, nonce‑secured, client‑side Zero‑Knowledge Proof (ZKP) authentication system.
- Multi‑implementation: C++ (Crypto++), Python (Flask), Rust (Actix‑web)
- Protocol: Chaum–Pedersen with Fiat–Shamir transform (non‑interactive)
- Client‑side proofs: Server never sees passwords; only verifies proofs
- Replay protection: One‑time, short‑lived server nonces via
/challenge - Unified encoding: All big integers serialized as lowercase hex strings
- Canonical challenge:
c = SHA256(hex(a1)|hex(a2)|hex(y1)|hex(y2)|nonce) mod q - Parameter sizes: 2048 (default) and optional 4096 bits via CLI flags
GET /params→{ p, q, g, h, bits, mode }(hex; bit size + params mode)POST /register→{ username, y1, y2, salt }(hex)POST /challenge→{ username }→{ y1, y2, salt, nonce, expires_at }POST /authenticate→{ username, a1, a2, s, nonce }(hex)GET /verify(Bearer token) →{ valid: bool, message|error }
- Moved proof generation to clients (no password on the wire)
- Added
/challengenonce issuance; server enforces single‑use + TTL - Challenge binds to nonce and canonical hex values
- DB stores
y1andy2as lowercase hex strings (previous Python decimal format replaced)
- 2048‑bit (default): predefined (RFC‑style) safe prime embedded
- 4096‑bit: supported; recommend
--params-mode=generatedue to very large constants /paramsnow includesbitsandmodeso clients can adapt if needed
- Python server:
--bits 2048|4096and--params-mode predefined|generate - C++ server:
--bits 2048|4096and--params-mode predefined|generate - Rust server:
--bits 2048|4096and--params-mode predefined|generate
zkp/chaum_pedersen.py- Client‑side ZKP:
_compute_challenge(..., nonce_hex);generate_proof(..., nonce_hex);verify_proof(..., nonce_hex) - Constructor:
ChaumPedersenZKP(generate=True, bits=2048, mode='generate') - Predefined 2048‑bit params; 4096 via generate mode (optionally embed full RFC)
set_parameters(p,q,g,h)preserved for clients/tests
- Client‑side ZKP:
server/auth_server.py- Endpoints:
/params,/register,/challenge,/authenticate,/verify - Nonce store (single‑use, short TTL) + session store (1h expiry)
/paramsreturns{ p,q,g,h,bits,mode }
- Endpoints:
server/main.py- Added flags
--bits,--params-mode
- Added flags
db/user_database.py- Persist
y1,y2as lowercase hex strings; parse as hex on read
- Persist
client/cli_client.py- Fetch
/params, request/challenge, compute keys/proofs client‑side
- Fetch
- Tests
tests/test_zkp.py: updated for nonce; added wrong‑nonce testtests/test_http_integration.py: full HTTP flow via Flask test clienttests/test_server_error_cases.py: invalid/missing fields, expired/invalid/reused noncestests/test_db_hex_storage.py: asserts DB stores hex strings
src/zkp/chaum_pedersen.[hpp|cpp]- Nonce‑bound challenge;
generateParameters(int bits);setPredefinedParameters(int bits) - New constructor overload:
(int bits, bool predefined)
- Nonce‑bound challenge;
src/zkp/predefined_params.hpp- Embedded 2048‑bit safe prime (RFC 3526 Group 14); 4096 placeholder;
G_BASE=2
- Embedded 2048‑bit safe prime (RFC 3526 Group 14); 4096 placeholder;
src/server/auth_server.[hpp|cpp]- Constructor accepts
(bits, predefined) /paramsincludesbitsandmode
- Constructor accepts
src/server/main.cpp- Added
--bitsand--params-modeflags
- Added
src/client/cli_client.cpp- Client fetches
/paramsand/challenge; computes proofs locally
- Client fetches
- Tests
tests/test_zkp.cppupdated: nonce usage; “same credentials” test fixed (salt causes different keys)tests/test_zkp_unit.cpp: unit coverage for wrong nonce and wrong public keys
src/zkp/mod.rsnew_with_bits(bits, predefined_mode); predefined 2048 prime; 4096 falls back to generate- Nonce‑bound challenge; helpers for hex params
src/zkp/predefined.rs- Embedded 2048‑bit prime; 4096 placeholder;
G_BASE=2
- Embedded 2048‑bit prime; 4096 placeholder;
src/server/mod.rs- AppState tracks
bitsandmode;/paramsincludes both run_server_with(zkp, db, port, bits, mode)for tests/CLI
- AppState tracks
src/bin/server.rs- Flags:
--bits,--params-mode; constructs ZKP accordingly
- Flags:
- Tests
tests/http_integration.rs: boots Actix server; full HTTP flowtests/zkp_unit_tests.rs: wrong nonce and wrong public keys coverage
docs/API.md: new endpoints, canonical encoding, examples,/paramsfieldsdocs/CHAUM_PEDERSEN.md: nonce‑based replay prevention; updated equations and flowdocs/IMPLEMENTATION.md: flow diagrams, code samples updated (nonce‑bound challenge)docs/ZKP_THEORY.md: replay prevention via noncedocs/VISUAL_GUIDE.md: diagrams and layers updated (nonce instead of timestamp)docs/IMPLEMENTATION_COMPARISON.md: API parity with new endpoints; nonce securitydocs/INDEX.md: replay prevention reference updated- Root READMEs (project, language‑specific) and
QUICKSTART.md: usage with--bits/--params-mode, new flow PROJECT_STRUCTURE.md: now covers Rust and updated API/flow
- Nonce‑bound challenge prevents replay within any time window
- Secrets never sent over the wire; server stores only public keys + salts
- KDF currently uses SHA‑256(username||password||salt) → x; consider Argon2id for memory hardness (future task)
- Parameter generation for 4096‑bit can be slow; prefer predefined (embed full RFC prime) or cache
- Predefined 4096‑bit prime is not fully embedded in code to keep footprint reasonable; use
--params-mode=generatefor 4096 or embed full RFC 3526 Group 16 prime as needed - Generator selection uses subgroup generator derived from
g_base=2(orderq) and random derivation for second generatorh
- Add Argon2id KDF for x derivation (configurable cost params)
- Optionally cache/serialize params to disk and load at startup
- Add C++ HTTP integration test harness (spawn server, issue requests)
- Provide DB migration script for legacy decimal → hex conversion