6.6 KiB
ZKAC Python API Reference
Version 0.5.0. Cryptographic stack: BBS+ on BLS12-381 (credentials), X25519 + ChaCha20-Poly1305 (transport), Schnorr/Ristretto255 (identity), BLAKE2b (role IDs, signatures), LWE (single-server SimplePIR for mailbox handles).
import zkac
Constants
MAX_BBS_AUTH_PROOF_BYTES
Upper bound on BBS+ proof size in an encrypted auth packet (256 KiB). Larger proofs are rejected.
PIR_RECORD_BYTES
Fixed byte length of each PIR plaintext row (mailbox handle JSON, padded with zeros). 256 in 0.5.0. Must match the server’s PIR database packing and the record_bytes argument to PirClient(...).
Single-server PIR (SimplePIR)
Used by the CLI/WASM mailbox path: the server’s hint blob starts with magic ZKACSP1 (not compatible with 0.4.x DoublePIR hints).
PirDatabase(records, record_bytes)
records is a list of bytes, each exactly record_bytes long (padded plaintext cells, one byte per LWE plaintext slot).
PirServer(db)
hints() -> bytes, version() -> bytes (32-byte pool/hint digest), answer(query: bytes) -> bytes (little-endian u32 limbs: one u32 per record byte, i.e. record_bytes limbs for SimplePIR).
PirClient(hints_bytes, n_records, record_bytes)
hints_bytes must deserialize with matching n_records and record_bytes.
query(index) -> (query_bytes, PirClientState)—query_byteslength 4 × n_records (oneu32per database column).decode(answer_bytes, state) -> bytes—answer_bytesmust holdrecord_bytes× 4 bytes (record_byteslittle-endianu32s). ConsumesPirClientState.
grant_detection_tag(secret_key: bytes, public_key: bytes) -> bytes
16-byte tag for grant discovery (secret_key / public_key are 32-byte X25519 keys).
Transport identity (Ristretto255)
Keypair()
Generates a new random keypair (long-term identity).
public_key() -> PublicKey— raisesValueErrorif consumed byNode(...)sign(msg: bytes) -> bytes— 64-byte Schnorr signature overmsg
PublicKey
to_bytes() -> bytes— 32 bytesfrom_bytes(bytes) -> PublicKeyverify(msg: bytes, signature: bytes) -> bool— verify a 64-byte Schnorr signature- Equality, hash,
reprsupported
BBS+ credentials
role_id(name: str) -> bytes
32-byte opaque role id from a human-readable name.
BbsIssuer()
New random issuer. from_secret_key(bytes) restores from 32-byte secret.
public_key() -> BbsPublicKeysecret_key_bytes() -> bytes(confidential)issue_blind(commitment_with_proof, role_id, epoch) -> bytes—role_idmust be 32 bytes
BbsPublicKey
to_bytes() / from_bytes
prepare_blind_request() -> BlindRequest
commitment_with_proof(),member_secret(),prover_blind()— all returnbytes
Credential.finalize(blind_sig, member_secret, prover_blind, role_id, epoch, pk) -> Credential
role_id and prover_blind must be 32 bytes.
present(nonce) -> bytesrole_id() -> bytes,epoch() -> int
Server registry
RoleRegistry
register_role(role_id, pk, epoch)—role_id32 bytesset_epoch(role_id, epoch)verify_presentation(role_id, proof_bytes, nonce) -> boolhas_role(role_id) -> bool
Node and session
PendingConnect
Opaque handle returned from connect(); passed once into a complete_* method (then consumed).
Node(keypair) — consumes Keypair
public_key() -> PublicKeyconnect() -> (PendingConnect, bytes)— 32-byte init messageaccept(init_msg) -> (Session, bytes)—init_msg32 bytesprove_identity(session) -> bytes— server produces encrypted identity proof (Schnorr signature over transcript)complete_connect(pending, response_msg, identity_proof, expected_server_pk, credential) -> (Session, bytes)— verifies server identity, then produces BBS+ auth packet (staticRoleRegistry)complete_connect_anon(pending, response_msg, identity_proof, expected_server_pk) -> Session— server identity only; no BBS+ auth packetcomplete_connect_managed(pending, response_msg, identity_proof, expected_server_pk, credential, registry_id) -> (Session, bytes)— auth packet includes 32-byte registry id (client-managed registries)verify_auth(session, encrypted_auth, registry) -> bytes— returns 32-byterole_idfor staticRoleRegistryverify_auth_managed(session, encrypted_auth, manager) -> (registry_id, role_id)— forRegistryManager
Session
transcript_hash() -> bytes— use asnonceforCredential.presentencrypt(plaintext) -> bytesdecrypt(packet) -> bytes
Managed registries (optional)
Server-side state for multiple registries and admin proofs lives in RegistryManager. Opaque RegistryState blobs are built and certified client-side, then registry_id(admin_issuer_pk) / admin_role_id() identify a registry and the fixed admin role. Methods on RegistryManager include create / update / get / has_registry, verify_admin, verify_presentation(registry_id, role_id, …), and issuance-queue helpers (queue_issuance_request, take_pending_requests, grant_credential, take_granted_credential). RegistryState exposes build, serialize / deserialize, registry_id, version, state_hash, certify, and verify_cert.
E2E issuance encryption (optional)
IssuanceKeypair (with encrypt / decrypt on ephemeral keys) and module helpers encrypt_for_admin / decrypt_from_admin support encrypting blind-commitment material to an admin’s issuance public key. See src/python.rs for exact parameters.
Typical flow
- Issuer creates
BbsIssuer(); serverregister_role(role_id, issuer.public_key(), epoch)(static registry), or useRegistryManager+ certifiedRegistryStatefor multi-tenant / managed flows. - Member:
prepare_blind_request→ issuerissue_blind→Credential.finalize. - Out-of-band: client obtains server's
PublicKey(static config, pinning, etc.). - Client:
connect→ serveraccept→ serverprove_identity→ clientcomplete_connectorcomplete_connect_managed(verifies server identity + sends BBS+ auth) → serververify_authorverify_auth_managed. Usecomplete_connect_anonwhen no credential auth is needed. - Use
Session.encrypt/decryptfor data.
Errors
Raises ValueError with descriptive messages for crypto failures, replay, identity verification, and bad inputs.
Further reading
Security model and assumptions · Changelog / breaking releases