System Architecture¶
High-Level View¶
The system is a replicated payment service where n threshold servers jointly sign tokens using BLS blind signatures, and clients interact with those servers over HTTP to mint and transfer value.
graph
subgraph Clients
C0[Client 0<br/>FastAPI :9000]
C1[Client 1<br/>FastAPI :9001]
end
subgraph Threshold Servers
direction LR
S0[Server 0<br/>share s₁]
S1[Server 1<br/>share s₂]
S2[Server 2<br/>share s₃]
S3[Server 3<br/>share s₄]
S4[Server 4<br/>share s₅]
end
C0 -- "POST /register, /mint, /pay" --> S0
C0 --> S1
C0 --> S2
C0 --> S3
C0 --> S4
C0 -- "GET /payment-key" --> C1
C0 -- "POST /pay (deliver token)" --> C1
Components¶
Server (payment.server)¶
Each server is a FastAPI application that holds:
| State | Purpose |
|---|---|
key_share (KeyShare) |
Its Shamir share sᵢ = g(i) of the system secret key |
system_public_key (G1_Point) |
The shared public key PK = g(0)·G₁ |
clients (dict[str, ClientEntry]) |
Registered clients with balances and public-key nullifiers |
token_nullifiers (set[Token]) |
Set of spent tokens (prevents double-spending) |
Endpoints:
| Endpoint | Method | Purpose |
|---|---|---|
/register |
POST | Register a client (id + long-term public key) |
/unregister |
POST | Remove a client |
/mint |
POST | Validate a mint request, return a partial blind signature |
/pay |
POST | Validate a pay transaction, return a partial blind signature for the recipient's new token |
Client (payment.client)¶
Each client is both an HTTP client (to talk to servers and recipients) and a FastAPI server (to receive payments).
| State | Purpose |
|---|---|
public_key / private_key |
Long-term BLS key pair for authentication |
tokens (list[ClientToken]) |
Wallet of unspent tokens, each with its one-time secret key |
pending_keys (dict) |
One-time keys awaiting incoming payments |
balance |
Un-minted balance (decremented on each mint) |
Client-side endpoints (FastAPI):
| Endpoint | Method | Purpose |
|---|---|---|
/payment-key |
GET | Generate and return a blinded one-time key for receiving a payment |
/pay |
POST | Accept an incoming payment (unblind + verify + store token) |
/demo/mint |
POST | (demo only) Trigger a mint from outside |
/demo/pay |
POST | (demo only) Trigger a pay from outside |
/demo/balance |
GET | (demo only) Query balance and token count |
Crypto Layer (payment.crypto)¶
Pure functions with no network I/O. Responsible for:
- Shamir secret sharing (polynomial generation, evaluation, Lagrange interpolation)
- BLS key pair generation
- Blind message creation and unblinding
- Partial signing and signature combination
- Signature verification via pairings
CLI (payment.cli)¶
A Typer CLI that provides three commands:
| Command | What it does |
|---|---|
payment setup |
Generate key shares and the system public key, save to config/ |
payment server |
Start a server process with a given share file |
payment client |
Start a client process |
Configuration¶
Two YAML files control the system:
config/config.yaml— local developmentconfig/config.docker.yaml— Docker Compose
Both share the same schema defined by Config in payment.models.
| Field | Meaning |
|---|---|
system.servers |
Total number of servers (n) |
system.failures |
Tolerated omission failures (f), threshold = f + 1 |
system.clients |
Expected number of clients |
system.initial_balance |
Starting un-minted balance per client |
system.delta |
Assumed network delay bound (seconds) |
system.public_key_path |
Path to the system public key file |
servers[i].id |
Server identifier |
servers[i].address |
Full HTTP address of the server |