80 lines
2.8 KiB
Python
80 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate demo credentials under creds/: issuer, server transport key, two member credentials.
|
|
Run once before starting the server.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import base64
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import zkac
|
|
|
|
# Human-readable role names; each becomes a 32-byte opaque role_id via zkac.role_id().
|
|
# Must stay in sync with server.py (registry + api_body_for_role).
|
|
ROLES = ("analyst", "operator")
|
|
|
|
|
|
def main() -> None:
|
|
ap = argparse.ArgumentParser(description="Generate ZKAC demo credential files.")
|
|
ap.add_argument(
|
|
"--output-dir",
|
|
type=Path,
|
|
default=Path(__file__).resolve().parent / "creds",
|
|
help="Directory to write files (default: demo/creds)",
|
|
)
|
|
args = ap.parse_args()
|
|
out: Path = args.output_dir
|
|
out.mkdir(parents=True, exist_ok=True)
|
|
|
|
# BBS+ issuer: signs blind credentials; server only needs the public key in RoleRegistry.
|
|
issuer = zkac.BbsIssuer()
|
|
issuer_pk = issuer.public_key()
|
|
epoch = 1
|
|
|
|
# Long-term Ristretto identity for the TCP server (X25519 handshake + Schnorr identity proof).
|
|
server_kp = zkac.Keypair()
|
|
server_pk = server_kp.public_key()
|
|
|
|
issuer_payload = {
|
|
"issuer_secret_key_b64": base64.b64encode(issuer.secret_key_bytes()).decode(),
|
|
"issuer_public_key_b64": base64.b64encode(issuer_pk.to_bytes()).decode(),
|
|
}
|
|
(out / "issuer.json").write_text(json.dumps(issuer_payload, indent=2), encoding="utf-8")
|
|
|
|
transport_payload = {
|
|
"server_secret_key_b64": base64.b64encode(server_kp.secret_key_bytes()).decode(),
|
|
"server_public_key_b64": base64.b64encode(server_pk.to_bytes()).decode(),
|
|
}
|
|
(out / "transport.json").write_text(json.dumps(transport_payload, indent=2), encoding="utf-8")
|
|
|
|
# One blind issuance per role: issuer never learns member_secret.
|
|
for role_name in ROLES:
|
|
rid = zkac.role_id(role_name)
|
|
req = zkac.prepare_blind_request()
|
|
blind_sig = issuer.issue_blind(req.commitment_with_proof(), rid, epoch)
|
|
member = {
|
|
"role_name": role_name,
|
|
"role_id_hex": rid.hex(),
|
|
"epoch": epoch,
|
|
"blind_sig_b64": base64.b64encode(blind_sig).decode(),
|
|
"member_secret_b64": base64.b64encode(req.member_secret()).decode(),
|
|
"prover_blind_b64": base64.b64encode(req.prover_blind()).decode(),
|
|
"issuer_public_key_b64": base64.b64encode(issuer_pk.to_bytes()).decode(),
|
|
}
|
|
(out / f"member_{role_name}.json").write_text(
|
|
json.dumps(member, indent=2), encoding="utf-8"
|
|
)
|
|
|
|
print(f"Wrote issuer, transport, and member files to {out}")
|
|
print(
|
|
f"Roles: {', '.join(ROLES)} — use member_{ROLES[0]}.json / member_{ROLES[1]}.json with client_cli.py"
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|