4.4 KiB
4.4 KiB
zkac-node CLI
Install the zkac wheel from the repo root first (maturin develop or pip install .), then:
pip install -e ./cli
zkac-node --help
Quick start
# 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:
- Anonymous handshake (X25519 ephemeral DH + Schnorr server identity proof verified against a pinned public key) establishes an encrypted session.
- 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
grantcalls (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}, ...]