everbarry d01a6ebf85 v0.3
2026-04-17 14:10:52 +02:00
..
2026-04-17 14:10:52 +02:00
2026-04-17 14:10:52 +02:00
2026-04-17 14:10:52 +02:00
2026-04-17 14:10:52 +02:00

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:

  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}, ...]