v bump
This commit is contained in:
parent
2ede94fa2f
commit
44fa5e6a2f
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -748,7 +748,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zkac"
|
name = "zkac"
|
||||||
version = "0.5.1"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2",
|
"blake2",
|
||||||
"chacha20poly1305",
|
"chacha20poly1305",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "zkac"
|
name = "zkac"
|
||||||
version = "0.5.1"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Zero-Knowledge Access Control: BBS+ anonymous credentials (BLS12-381) with encrypted transport (X25519/ChaCha20-Poly1305)"
|
description = "Zero-Knowledge Access Control: BBS+ anonymous credentials (BLS12-381) with encrypted transport (X25519/ChaCha20-Poly1305)"
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "zkac-node"
|
name = "zkac-node"
|
||||||
version = "0.2.1"
|
version = "0.6.0"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = ["zkac"]
|
dependencies = ["zkac"]
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
Metadata-Version: 2.4
|
Metadata-Version: 2.4
|
||||||
Name: zkac-node
|
Name: zkac-node
|
||||||
Version: 0.2.1
|
Version: 0.6.0
|
||||||
Requires-Python: >=3.10
|
Requires-Python: >=3.10
|
||||||
Requires-Dist: zkac
|
Requires-Dist: zkac
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# ZKAC Python API Reference
|
# ZKAC Python API Reference
|
||||||
|
|
||||||
Version 0.5.1. Cryptographic stack: **BBS+** on BLS12-381 (credentials), **X25519** + **ChaCha20-Poly1305** (transport), **Schnorr/Ristretto255** (identity), **BLAKE2b** (role IDs, signatures).
|
Version 0.6.0. Cryptographic stack: **BBS+** on BLS12-381 (credentials), **X25519** + **ChaCha20-Poly1305** (transport), **Schnorr/Ristretto255** (identity), **BLAKE2b** (role IDs, signatures).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import zkac
|
import zkac
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
# Security model (ZKAC 0.5.1)
|
# Security model (ZKAC 0.6.0)
|
||||||
|
|
||||||
This document summarizes the direct peer-to-peer grant model, with transcript-bound BBS+ authorization (Option C).
|
This document summarizes the direct peer-to-peer grant model, with transcript-bound BBS+ authorization (Option C).
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ build-backend = "maturin"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "zkac"
|
name = "zkac"
|
||||||
version = "0.5.1"
|
version = "0.6.0"
|
||||||
description = "Zero-Knowledge Access Control: BBS+ anonymous credentials with encrypted transport"
|
description = "Zero-Knowledge Access Control: BBS+ anonymous credentials with encrypted transport"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
|||||||
@ -4,7 +4,7 @@ ZKAC — Zero-Knowledge Access Control
|
|||||||
BBS+ anonymous credentials (BLS12-381) with encrypted transport (Ristretto255 / X25519).
|
BBS+ anonymous credentials (BLS12-381) with encrypted transport (Ristretto255 / X25519).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "0.5.1"
|
__version__ = "0.6.0"
|
||||||
|
|
||||||
from zkac._zkac import (
|
from zkac._zkac import (
|
||||||
MAX_BBS_AUTH_PROOF_BYTES,
|
MAX_BBS_AUTH_PROOF_BYTES,
|
||||||
|
|||||||
@ -1,246 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
E2E smoke + timing: one server, clients A (admin) and B (recipient).
|
|
||||||
|
|
||||||
1. A creates a registry with 3 roles
|
|
||||||
2. A posts one or more grants to B (same role ``beta``)
|
|
||||||
3. Time B's mailbox fetch and permission-style checks (same phases as
|
|
||||||
``zkac-node credentials list B --server …``: local creds, list_pending, has_credential)
|
|
||||||
|
|
||||||
Default (no args): one grant, asserts one pending ``beta`` grant.
|
|
||||||
|
|
||||||
Scaling: ``--sizes 2,5,25,50`` runs a fresh server + pool for each size (all grants
|
|
||||||
to B), prints a timing table (``list_pending`` = tags + PIR full-row decode per match).
|
|
||||||
|
|
||||||
Run from repo root, e.g.:
|
|
||||||
|
|
||||||
uv run python scripts/e2e_two_clients_timing.py
|
|
||||||
uv run python scripts/e2e_two_clients_timing.py --sizes 2,5,25,50
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import base64
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[1]
|
|
||||||
sys.path.insert(0, str(ROOT / "python"))
|
|
||||||
sys.path.insert(0, str(ROOT / "cli"))
|
|
||||||
|
|
||||||
|
|
||||||
def _free_port() -> int:
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
s.bind(("127.0.0.1", 0))
|
|
||||||
_, port = s.getsockname()
|
|
||||||
s.close()
|
|
||||||
return port
|
|
||||||
|
|
||||||
|
|
||||||
def _run_scaled_sizes(sizes: list[int]) -> int:
|
|
||||||
from zkac_cli import client, store
|
|
||||||
from zkac_cli.server import _ServerStore, serve
|
|
||||||
|
|
||||||
def log(msg: str) -> None:
|
|
||||||
print(msg, flush=True)
|
|
||||||
|
|
||||||
rows: list[tuple[int, float, float, float, float, float, float]] = []
|
|
||||||
|
|
||||||
for n in sizes:
|
|
||||||
td = tempfile.mkdtemp(prefix="zkac-e2e-")
|
|
||||||
os.environ["ZKAC_HOME"] = td
|
|
||||||
port = _free_port()
|
|
||||||
server = f"127.0.0.1:{port}"
|
|
||||||
server_dd = Path(td) / "srv"
|
|
||||||
server_dd.mkdir(parents=True)
|
|
||||||
|
|
||||||
ss = _ServerStore(server_dd)
|
|
||||||
kp = ss.load_or_create_keypair()
|
|
||||||
pk_b64 = base64.b64encode(kp.public_key().to_bytes()).decode()
|
|
||||||
|
|
||||||
store.create_user("A")
|
|
||||||
store.create_user("B")
|
|
||||||
store.pin_server("A", server, pk_b64)
|
|
||||||
store.pin_server("B", server, pk_b64)
|
|
||||||
|
|
||||||
t_srv = threading.Thread(
|
|
||||||
target=lambda: serve(str(server_dd), "127.0.0.1", port),
|
|
||||||
daemon=True,
|
|
||||||
)
|
|
||||||
t_srv.start()
|
|
||||||
time.sleep(0.25)
|
|
||||||
|
|
||||||
t_setup0 = time.perf_counter()
|
|
||||||
rid = client.create_registry("A", server, ["alpha", "beta", "gamma"])
|
|
||||||
t_after_create = time.perf_counter()
|
|
||||||
b_pk = store.load_identity("B")["issuance_pk"].hex()
|
|
||||||
for _ in range(n):
|
|
||||||
client.grant("A", server, rid, "beta", b_pk)
|
|
||||||
t_gr1 = time.perf_counter()
|
|
||||||
|
|
||||||
t_loc0 = time.perf_counter()
|
|
||||||
local_creds = store.list_credentials("B")
|
|
||||||
t_loc1 = time.perf_counter()
|
|
||||||
|
|
||||||
t_mail0 = time.perf_counter()
|
|
||||||
pending = client.list_pending("B", server)
|
|
||||||
t_mail1 = time.perf_counter()
|
|
||||||
|
|
||||||
t_perm0 = time.perf_counter()
|
|
||||||
for g in pending:
|
|
||||||
r = g.get("registry_id")
|
|
||||||
role = g.get("role_name")
|
|
||||||
if r not in (None, "?") and role not in (None, "?"):
|
|
||||||
store.has_credential("B", r, role)
|
|
||||||
t_perm1 = time.perf_counter()
|
|
||||||
|
|
||||||
create_ms = (t_after_create - t_setup0) * 1000
|
|
||||||
grant_ms = (t_gr1 - t_after_create) * 1000
|
|
||||||
local_ms = (t_loc1 - t_loc0) * 1000
|
|
||||||
mail_ms = (t_mail1 - t_mail0) * 1000
|
|
||||||
perm_ms = (t_perm1 - t_perm0) * 1000
|
|
||||||
total_ms = (t_perm1 - t_loc0) * 1000
|
|
||||||
|
|
||||||
rows.append((n, create_ms, grant_ms, local_ms, mail_ms, perm_ms, total_ms))
|
|
||||||
|
|
||||||
log(
|
|
||||||
f"n={n}: create_registry={create_ms:.0f} ms N×grant={grant_ms:.0f} ms "
|
|
||||||
f"list_pending={mail_ms:.0f} ms pending={len(pending)} ZKAC_HOME={td}"
|
|
||||||
)
|
|
||||||
if len(pending) != n:
|
|
||||||
print(f"ERROR: expected {n} pending, got {len(pending)}", flush=True)
|
|
||||||
return 1
|
|
||||||
for p in pending:
|
|
||||||
if p.get("role_name") != "beta" or p.get("registry_id") != rid:
|
|
||||||
print(f"ERROR: bad pending row {p!r}", flush=True)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
print()
|
|
||||||
print(
|
|
||||||
"pool_n | create_registry (ms) | N×grant (ms) | list_local (ms) | "
|
|
||||||
"list_pending mailbox (ms) | has_cred (ms) | cred_list_total (ms)"
|
|
||||||
)
|
|
||||||
print("-" * 120)
|
|
||||||
for n, create_ms, grant_ms, local_ms, mail_ms, perm_ms, total_ms in rows:
|
|
||||||
print(
|
|
||||||
f"{n:6d} | {create_ms:20.1f} | {grant_ms:12.1f} | {local_ms:15.3f} | "
|
|
||||||
f"{mail_ms:25.1f} | {perm_ms:12.3f} | {total_ms:20.1f}"
|
|
||||||
)
|
|
||||||
print("OK")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
|
||||||
parser = argparse.ArgumentParser(description="ZKAC e2e timing (mailbox / credentials list)")
|
|
||||||
parser.add_argument(
|
|
||||||
"--sizes",
|
|
||||||
default=None,
|
|
||||||
metavar="N,N,...",
|
|
||||||
help="comma-separated pool sizes (each run: fresh server, N grants to B, then list_pending)",
|
|
||||||
)
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.sizes is not None:
|
|
||||||
sizes = [int(x.strip()) for x in args.sizes.split(",") if x.strip()]
|
|
||||||
if not sizes or any(x < 1 for x in sizes):
|
|
||||||
print("error: --sizes must be positive integers", file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
return _run_scaled_sizes(sizes)
|
|
||||||
|
|
||||||
from zkac_cli import client, store
|
|
||||||
from zkac_cli.server import _ServerStore, serve
|
|
||||||
|
|
||||||
def log(msg: str) -> None:
|
|
||||||
print(msg, flush=True)
|
|
||||||
|
|
||||||
td = tempfile.mkdtemp(prefix="zkac-e2e-")
|
|
||||||
os.environ["ZKAC_HOME"] = td
|
|
||||||
port = _free_port()
|
|
||||||
server = f"127.0.0.1:{port}"
|
|
||||||
server_dd = Path(td) / "srv"
|
|
||||||
server_dd.mkdir(parents=True)
|
|
||||||
|
|
||||||
ss = _ServerStore(server_dd)
|
|
||||||
kp = ss.load_or_create_keypair()
|
|
||||||
pk_b64 = base64.b64encode(kp.public_key().to_bytes()).decode()
|
|
||||||
|
|
||||||
store.create_user("A")
|
|
||||||
store.create_user("B")
|
|
||||||
store.pin_server("A", server, pk_b64)
|
|
||||||
store.pin_server("B", server, pk_b64)
|
|
||||||
|
|
||||||
t_srv = threading.Thread(
|
|
||||||
target=lambda: serve(str(server_dd), "127.0.0.1", port),
|
|
||||||
daemon=True,
|
|
||||||
)
|
|
||||||
t_srv.start()
|
|
||||||
time.sleep(0.25)
|
|
||||||
log("server thread up")
|
|
||||||
|
|
||||||
t0 = time.perf_counter()
|
|
||||||
rid = client.create_registry("A", server, ["alpha", "beta", "gamma"])
|
|
||||||
t_create = time.perf_counter()
|
|
||||||
log(f"registry created ({(t_create - t0) * 1000:.0f} ms)")
|
|
||||||
|
|
||||||
b_pk = store.load_identity("B")["issuance_pk"].hex()
|
|
||||||
client.grant("A", server, rid, "beta", b_pk)
|
|
||||||
t_grant = time.perf_counter()
|
|
||||||
log(f"grant posted ({(t_grant - t_create) * 1000:.0f} ms)")
|
|
||||||
|
|
||||||
log("B mailbox + permission-style checks (same work as `credentials list`) …")
|
|
||||||
t_loc0 = time.perf_counter()
|
|
||||||
local_creds = store.list_credentials("B")
|
|
||||||
t_loc1 = time.perf_counter()
|
|
||||||
|
|
||||||
t_mail0 = time.perf_counter()
|
|
||||||
pending = client.list_pending("B", server)
|
|
||||||
t_mail1 = time.perf_counter()
|
|
||||||
|
|
||||||
t_perm0 = time.perf_counter()
|
|
||||||
for g in pending:
|
|
||||||
r = g.get("registry_id")
|
|
||||||
role = g.get("role_name")
|
|
||||||
if r not in (None, "?") and role not in (None, "?"):
|
|
||||||
store.has_credential("B", r, role)
|
|
||||||
t_perm1 = time.perf_counter()
|
|
||||||
|
|
||||||
log(f"ZKAC_HOME={td}")
|
|
||||||
log(f"server={server} registry={rid[:24]}…")
|
|
||||||
print(f"create_registry: {(t_create - t0) * 1000:.1f} ms")
|
|
||||||
print(f"grant: {(t_grant - t_create) * 1000:.1f} ms")
|
|
||||||
print(
|
|
||||||
f"list_local_creds(B): {(t_loc1 - t_loc0) * 1000:.3f} ms ({len(local_creds)} on disk)"
|
|
||||||
)
|
|
||||||
print(
|
|
||||||
f"list_pending(mailbox): {(t_mail1 - t_mail0) * 1000:.1f} ms "
|
|
||||||
f"({len(pending)} match(es); tags + PIR row + decrypt)"
|
|
||||||
)
|
|
||||||
print(
|
|
||||||
f"has_credential checks: {(t_perm1 - t_perm0) * 1000:.3f} ms "
|
|
||||||
f"({len(pending)} grant(s))"
|
|
||||||
)
|
|
||||||
print(
|
|
||||||
f"credentials_list_total: {(t_perm1 - t_loc0) * 1000:.1f} ms "
|
|
||||||
"(local + mailbox + permission flags)"
|
|
||||||
)
|
|
||||||
for p in pending:
|
|
||||||
print(
|
|
||||||
f" pending: registry={p.get('registry_id', '?')[:16]}… "
|
|
||||||
f"role={p.get('role_name')} idx={p.get('pool_index')}"
|
|
||||||
)
|
|
||||||
|
|
||||||
assert len(pending) == 1, pending
|
|
||||||
assert pending[0].get("role_name") == "beta"
|
|
||||||
assert pending[0].get("registry_id") == rid
|
|
||||||
print("OK")
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
raise SystemExit(main())
|
|
||||||
4
uv.lock
generated
4
uv.lock
generated
@ -1918,7 +1918,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zkac"
|
name = "zkac"
|
||||||
version = "0.5.1"
|
version = "0.6.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "ipykernel" },
|
{ name = "ipykernel" },
|
||||||
@ -1964,7 +1964,7 @@ dev = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zkac-node"
|
name = "zkac-node"
|
||||||
version = "0.2.1"
|
version = "0.6.0"
|
||||||
source = { editable = "cli" }
|
source = { editable = "cli" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "zkac" },
|
{ name = "zkac" },
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user