109 lines
4.4 KiB
Markdown
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}, ...]
|
|
```
|