106 lines
4.0 KiB
Python
106 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Generate credentials for the managed-registry demo.
|
||
|
||
Creates:
|
||
creds/managed_admin.json – admin BBS+ issuer key + admin credential + issuance keypair
|
||
creds/managed_registry.json – serialized registry state + cert (analyst + operator roles)
|
||
creds/transport.json – server transport key (created if not already present)
|
||
|
||
Users request credentials through the server at runtime (E2E-encrypted issuance).
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import argparse
|
||
import base64
|
||
import json
|
||
from pathlib import Path
|
||
|
||
import zkac
|
||
|
||
ROLES = ("analyst", "operator")
|
||
|
||
|
||
def main() -> None:
|
||
ap = argparse.ArgumentParser(description="Generate managed-registry demo files.")
|
||
ap.add_argument(
|
||
"--output-dir",
|
||
type=Path,
|
||
default=Path(__file__).resolve().parent / "creds",
|
||
)
|
||
args = ap.parse_args()
|
||
out: Path = args.output_dir
|
||
out.mkdir(parents=True, exist_ok=True)
|
||
|
||
# Admin BBS+ issuer (signs credentials AND certifies registry state)
|
||
admin_issuer = zkac.BbsIssuer()
|
||
admin_pk = admin_issuer.public_key()
|
||
admin_rid = zkac.admin_role_id()
|
||
|
||
# Self-issue admin credential
|
||
req = zkac.prepare_blind_request()
|
||
sig = admin_issuer.issue_blind(req.commitment_with_proof(), admin_rid, 0)
|
||
admin_cred = zkac.Credential.finalize(
|
||
sig, req.member_secret(), req.prover_blind(), admin_rid, 0, admin_pk
|
||
)
|
||
|
||
# X25519 issuance keypair for E2E-encrypted credential requests
|
||
issuance_kp = zkac.IssuanceKeypair()
|
||
|
||
# Build registry state with roles (admin is also the issuer for all roles)
|
||
role_entries = []
|
||
for name in ROLES:
|
||
role_entries.append((zkac.role_id(name), admin_pk, 1))
|
||
|
||
state = zkac.RegistryState.build(
|
||
admin_pk, issuance_kp.public_key_bytes(), 1, b"\x00" * 32, role_entries
|
||
)
|
||
state_bytes = state.serialize()
|
||
state_cert = state.certify(admin_cred)
|
||
registry_id = state.registry_id()
|
||
|
||
# Save admin material
|
||
admin_payload = {
|
||
"admin_issuer_secret_b64": base64.b64encode(admin_issuer.secret_key_bytes()).decode(),
|
||
"admin_issuer_public_key_b64": base64.b64encode(admin_pk.to_bytes()).decode(),
|
||
"admin_member_secret_b64": base64.b64encode(req.member_secret()).decode(),
|
||
"admin_prover_blind_b64": base64.b64encode(req.prover_blind()).decode(),
|
||
"admin_blind_sig_b64": base64.b64encode(sig).decode(),
|
||
"issuance_secret_b64": base64.b64encode(issuance_kp.secret_bytes()).decode(),
|
||
"issuance_public_key_b64": base64.b64encode(issuance_kp.public_key_bytes()).decode(),
|
||
"registry_id_hex": registry_id.hex(),
|
||
}
|
||
(out / "managed_admin.json").write_text(json.dumps(admin_payload, indent=2), encoding="utf-8")
|
||
|
||
# Save registry state + cert
|
||
reg_payload = {
|
||
"registry_id_hex": registry_id.hex(),
|
||
"state_bytes_b64": base64.b64encode(state_bytes).decode(),
|
||
"state_cert_b64": base64.b64encode(bytes(state_cert)).decode(),
|
||
"admin_issuer_public_key_b64": base64.b64encode(admin_pk.to_bytes()).decode(),
|
||
"issuance_public_key_b64": base64.b64encode(issuance_kp.public_key_bytes()).decode(),
|
||
"roles": list(ROLES),
|
||
}
|
||
(out / "managed_registry.json").write_text(json.dumps(reg_payload, indent=2), encoding="utf-8")
|
||
|
||
# Transport key (create if not present)
|
||
transport_path = out / "transport.json"
|
||
if not transport_path.is_file():
|
||
server_kp = zkac.Keypair()
|
||
transport_payload = {
|
||
"server_secret_key_b64": base64.b64encode(server_kp.secret_key_bytes()).decode(),
|
||
"server_public_key_b64": base64.b64encode(server_kp.public_key().to_bytes()).decode(),
|
||
}
|
||
transport_path.write_text(json.dumps(transport_payload, indent=2), encoding="utf-8")
|
||
|
||
print(f"Wrote managed-registry demo files to {out}")
|
||
print(f"Registry ID: {registry_id.hex()}")
|
||
print(f"Roles: {', '.join(ROLES)}")
|
||
print(f"\nAdmin can issue credentials for these roles through the server.")
|
||
print(f"Users request credentials via E2E-encrypted issuance relay.")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|