Metadata-Version: 2.4
Name: privyq
Version: 1.0.0
Summary: Post-quantum, policy-governed encryption with verifiable privacy evidence
Author: PrivyQ Contributors
License: MIT
Project-URL: Homepage, https://github.com/privyq/privyq
Project-URL: Documentation, https://github.com/privyq/privyq/tree/main/docs
Keywords: post-quantum,cryptography,encryption,policy,audit,kyber,dilithium
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: grpcio>=1.60
Requires-Dist: protobuf>=4.25
Provides-Extra: dev
Requires-Dist: grpcio-tools>=1.60; extra == "dev"
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: black>=24.0; extra == "dev"
Requires-Dist: pylint>=3.0; extra == "dev"

# PrivyQ Python SDK (`privyq`)

The developer-facing interface to PrivyQ. It hides all cryptographic and gRPC
detail behind three verbs, `protect()`, `access()`, `verify()`, so you think
in terms of *business intent*, not primitives.

```python
import privyq

privyq.configure(core_address="localhost:50051")

# Lock a record, attaching the access rules in the same call.
protected = privyq.protect(
    "Patient: John Doe. Plan: continue beta-blocker.",
    policy={"role": "doctor", "department": "cardiology", "purpose": "treatment", "expiry": "24h"},
    actor={"user_id": "dr_smith", "role": "doctor", "department": "cardiology"},
)

# Open it, only if the policy is satisfied.
result = privyq.access(protected, identity={"role": "doctor", "department": "cardiology", "purpose": "treatment"})
print(result.text)          # -> "Patient: John Doe. ..."
print(result.receipt.id)    # a signed, verifiable access receipt

# Verify the receipt cryptographically.
check = privyq.verify(result.receipt)
assert check.ok and check.signature_valid and check.chain_valid
```

Denied access raises `PolicyViolationError`, and the attempt is still recorded
as tamper-evident evidence:

```python
try:
    privyq.access(protected, identity={"role": "nurse"})
except privyq.PolicyViolationError as why:
    print(why)   # -> "policy violation: role condition failed ..."
```

## Installation

```bash
pip install privyq            # from PyPI (once published)
pip install -e ".[dev]"       # from this repo, with test/lint extras
```

The SDK talks to a running [PrivyQ core](../core-go) (`privyqd`). Point it at the
core with `configure(core_address=...)` or the `PRIVYQ_CORE_ADDRESS` env var.

## Policy shorthand

Policies accept two forms. The **shorthand** maps each key to a condition, lists
become `in`, `expiry` becomes a `before` with duration expansion (`"24h"` → an
absolute timestamp):

```python
{"role": "doctor", "department": ["cardiology", "oncology"], "expiry": "24h"}
```

The **structured** form is explicit and supports every operator (BP App D):

```python
{"conditions": [{"type": "role", "operator": "in", "value": ["doctor", "specialist"]}],
 "combination": "all"}
```

## API surface

| Function | Purpose |
|----------|---------|
| `configure(**opts)` | Set core address, default algorithms, timeout, TLS |
| `protect(data, policy, *, actor, key_id, algorithm)` | Encrypt with an embedded policy |
| `access(protected, identity, *, context)` | Decrypt if the policy allows; else raise |
| `verify(receipt)` | Verify a receipt's signature and chain linkage |
| `evidence.log(*, resource_id, actor_id, ...)` | Retrieve audit receipts |
| `generate_key / rotate_key / revoke_key` | Key lifecycle |

Exceptions follow a hierarchy rooted at `PrivyQError`
(`PolicyViolationError`, `KeyNotFoundError`, `CryptoError`, `CoreUnreachableError`, …).

## Configuration (ARCH §20.3)

| Env var | Default |
|---------|---------|
| `PRIVYQ_CORE_ADDRESS` | `localhost:50051` |
| `PRIVYQ_ALGORITHM` | `kyber_768` |
| `PRIVYQ_SIGNATURE` | `dilithium_3` |
| `PRIVYQ_TIMEOUT` | `5` |
| `PRIVYQ_AUDIT` | `true` |

## Development

```bash
pip install -e ".[dev]"
pytest -q          # unit tests + integration (builds & launches the real core)
black privyq
```

The gRPC stubs under `privyq/_proto/` are generated from
[`core-go/pkg/proto/privyq.proto`](../core-go/pkg/proto/privyq.proto). Regenerate
with `../scripts/gen-python-proto.sh` (or `make proto` at the repo root).
