ZKAC/cli/README.md
everbarry d01a6ebf85 v0.3
2026-04-17 14:10:52 +02:00

109 lines
4.4 KiB
Markdown

# zkac-node CLI
Install the `zkac` wheel from the repo root first (`maturin develop` or `pip install .`), then:
```bash
pip install -e ./cli
zkac-node --help
```
## Quick start
```bash
# 1. Create identities (one per machine / actor)
zkac-node identity init # on admin machine
zkac-node identity init # on recipient machine (separate ~/.zkac)
# Recipient shares their issuance public key out-of-band:
zkac-node identity show # prints issuance pk (hex)
# 2. Start the server (separate machine or same, different data-dir)
zkac-node serve --data-dir /var/lib/zkac --port 9800 &
# 3. Pin the server's public key (printed at startup)
zkac-node server pin localhost:9800 --key <SERVER_PK_HEX>
# 4. Create a registry (admin side)
zkac-node registry create localhost:9800 --roles analyst,operator
# 5. Grant recipient the 'analyst' role (only needs their public key)
zkac-node grant --server localhost:9800 \
--registry <REGISTRY_ID> --role analyst --to <RECIPIENT_PK_HEX>
# 6. Recipient lists pending credentials
zkac-node credentials list --server localhost:9800
# 7. Recipient collects (host:port:registry_id:role)
zkac-node collect localhost:9800:<REGISTRY_ID>:analyst
# 8. Recipient authenticates anonymously
zkac-node auth --registry <REGISTRY_ID> --role analyst --server localhost:9800
```
## Commands
| Command | Description |
|---------|-------------|
| `identity init` | Generate issuance keypair under `~/.zkac/` |
| `identity show` | Show issuance pk + owned registries + credentials |
| `serve --data-dir D` | Run as a ZKAC server storing data in D |
| `server pin <host:port> --key <hex>` | Pin a server's public key |
| `registry create <server> --roles r1,r2` | Create a new registry (fresh BBS+ issuer) |
| `registry update <server> --registry R --add-roles r3` | Add roles to a registry you own |
| `registry get <server> --registry R` | Fetch registry state from a server |
| `registry list` | List locally owned registries |
| `grant --server S --registry R --role X --to <pk>` | Issue credential encrypted to recipient's pk |
| `credentials list [--server S ...]` | Show local credentials + pending grants |
| `collect <host:port:registry:role>` | Fetch + finalize one pending credential |
| `auth --registry R --role X [--server S]` | Authenticate via ZKAC handshake |
## Protocol
All connections use a single encrypted channel:
1. **Anonymous handshake** (X25519 ephemeral DH + Schnorr server identity proof
verified against a pinned public key) establishes an encrypted session.
2. The first encrypted frame selects the mode:
- `{"op": "mgmt"}` — management commands (JSON request/reply loop)
- `{"op": "auth", ...}` — BBS+ role authentication
Admin-only commands (`post_grant`) require a BBS+ presentation of the registry's
`__admin__` credential bound to the session transcript hash — unlinkable across
grants by construction.
## Threat model
The server is a **trustless, zero-information** relay:
- All traffic is encrypted and server-authenticated (same handshake as role auth).
- Registry state is opaque bytes with a BBS+ state certificate. The server cannot
mutate state or impersonate the admin without the BBS+ issuer secret.
- Grants are end-to-end encrypted from admin to recipient using ephemeral X25519
ECDH. The server stores only `(recipient_pk, eph_pk, ciphertext)` per grant —
no registry ID, role name, or credential material.
- Admin identity is unlinkable across `grant` calls (BBS+ presentations are
rerandomized per call).
- Recipient's authenticated session uses a fresh ephemeral transport key + an
unlinkable BBS+ presentation, so the server cannot correlate sessions with
the mailbox pk used at collect time.
- No user IDs exist on the server. Clients are identified only by ephemeral
keys (handshake) or issuance public keys (mailbox addressing).
## Storage layout
Client (`~/.zkac/`):
```
identity.json issuance keypair (long-term secret)
admin/<registry_id>.json BBS+ issuer + admin credential per owned registry
credentials/<rid>_<role>.json BBS+ credentials granted to this identity
servers/<host_port>.json pinned server public keys
```
Server (`--data-dir`):
```
server_key.json Schnorr keypair (long-term server secret)
registries/<rid>.state raw RegistryState bytes
registries/<rid>.cert raw state cert bytes
mailbox/<recipient_pk_hex>.json [{grant_id, eph_pk_b64, ciphertext_b64}, ...]
```