# KEZ — Python Implementation KEZ is a portable, decentralized identity graph. It lets one person say: > "These accounts, keys, domains, and identities are all me." …without depending on any central authority. Every connection is proven by a signature against a key the user already controls. The protocol is specified in [`../SPEC.md`](../SPEC.md); this directory is the Python implementation of that spec. It is **wire-compatible** with the [Rust](../rust/) and [Node](../nodejs/) implementations: a claim signed here verifies there and vice versa, in every direction. The repo-root [`crosstest.sh`](../crosstest.sh) proves it. --- ## What's in this directory ``` python/ ├── pyproject.toml Package metadata + entry point (`kez`) ├── requirements.txt Runtime deps (cryptography, zstandard) ├── kez_cli.py Standalone launcher (used by ../crosstest.sh) └── kez/ ├── jcs.py RFC 8785 JSON canonicalization ├── bech32.py Bech32 (nsec/npub) encode/decode ├── schnorr.py Pure-Python BIP-340 Schnorr over secp256k1 ├── identity.py `system:identifier` parsing + normalization ├── keys.py NostrSecret / Ed25519Secret signers + verification ├── envelope.py Envelope, claim & sigchain-event payloads, sign/verify ├── encodings.py JSON / compact (kez:z1:) / markdown / DNS / JSONL bundle ├── sigchain.py Append-only signed sigchain + on-disk storage ├── channels.py parse_proof across all four wire encodings └── cli.py The `kez` command-line interface ``` --- ## Setup > **New to KEZ?** Read [**`TUTORIAL.md`**](TUTORIAL.md) — a friendly > step-by-step walkthrough that takes you from "I have a nostr `nsec`" > to "I have a verified, published sigchain," including the BIP-39 > recovery-phrase backup (12 or 24 words). It assumes nothing. > > This README is the reference; the tutorial is the on-ramp. ```sh cd python python3 -m venv .venv .venv/bin/pip install -r requirements.txt ``` Then run the CLI either through the launcher or the installed entry point: ```sh .venv/bin/python kez_cli.py identity new # or, after `.venv/bin/pip install -e .`: .venv/bin/kez identity new ``` --- ## Crypto stack | Concern | Choice | Why | |---|---|---| | JCS (RFC 8785) | hand-rolled (`jcs.py`) | KEZ payloads are strings/ints/objects only; a tiny dependency-free canonicalizer guarantees byte-identical output | | secp256k1 Schnorr (BIP-340) | pure-Python reference (`schnorr.py`) | the native `coincurve`/`secp256k1` bindings fail to build on recent CPython; signing fixed-size digests is fast enough for a CLI. Signs with zero aux-rand to match Rust/Node exactly | | Ed25519 (RFC 8032) | [`cryptography`](https://cryptography.io) | well-maintained, ships wheels | | zstd | [`zstandard`](https://pypi.org/project/zstandard/) | level 3, matching the other impls; `decompressobj` handles frames without a content-size header | | Bech32 | hand-rolled (`bech32.py`) | the BIP-173 reference is small and avoids a dependency | All signing is **deterministic**, so the same claim signs identically every time. --- ## CLI reference ``` kez identity new [--key-type nostr|ed25519] kez claim create (--nsec | --ed25519-seed ) [--format json|compact|markdown] [--out ] kez claim dns (--nsec | --ed25519-seed ) kez verify file kez sigchain add (--nsec | --ed25519-seed) [--proof-url ] kez sigchain revoke (--nsec | --ed25519-seed) kez sigchain show [--primary | --nsec | --ed25519-seed] kez sigchain export [--primary | --nsec | --ed25519-seed] [--format jsonl|compact] [--out ] ``` Sigchain state lives in `~/.kez/sigchains/.jsonl` — the same paths the Rust and Node CLIs use, so chains built by one are readable by the others. --- ## What's not done yet Matching the gap list in [`../rust/README.md`](../rust/README.md), the Python CLI implements `claim`, `verify file`, and `sigchain add/revoke/show/export`. Not yet ported: `verify id` channel resolution (network fetch), `sigchain publish`, and the `rotate`/`add_device` ops. ## License Dual-licensed under MIT or Apache-2.0.