Kez/python/README.md
Jason Tudisco d0e96c17fb docs(python): add TUTORIAL.md mirroring rust/nodejs + link from READMEs
Completes the parallel tutorial set across all three implementations.
Python now has the same friendly step-by-step walkthrough that the
Rust and Node sides have had since the original tutorial commits.

Python tutorial content mirrors the others 1:1, adapted for the
Python invocation style (.venv/bin/python kez_cli.py …), plus:

  • Programmatic section uses Python imports (NostrSecret.from_nsec,
    sign_claim, default_registry, etc.) instead of the TS imports
    from the Node tutorial.
  • Same "Recovery phrases" mini-chapter as rust/nodejs — both 12-word
    AND 24-word are explained, with the entropy table, picking guide,
    hardware-wallet-incompatibility callout, concrete backup advice
    ("pencil + paper, numbered words, fireproof, don't split,
    don't permute"), and "Working with phrases later" examples
    (`identity mnemonic`, `identity from-mnemonic`).
  • Notes that `sigchain publish` isn't in the Python CLI yet (only
    add/revoke/show/export) — match the actual current surface; the
    JSONL the Python CLI produces is byte-compatible with Rust/Node,
    so users can build the chain in Python and publish via either
    of the other CLIs in the meantime.
  • Troubleshooting includes ModuleNotFoundError: kez (a Python-
    specific footgun when running outside the venv).
  • Links to ../rust/TUTORIAL.md and ../nodejs/TUTORIAL.md as parallel
    references throughout.

python/README.md now opens with the same "New to KEZ? Read TUTORIAL.md"
callout as the rust and nodejs READMEs do.

Root README's quick-start blocks for each implementation now reference
BOTH the impl README (reference) AND the impl TUTORIAL (step-by-step,
on-ramp) instead of just the README.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-05 22:57:52 -06:00

4.3 KiB

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; this directory is the Python implementation of that spec.

It is wire-compatible with the Rust and Node implementations: a claim signed here verifies there and vice versa, in every direction. The repo-root 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 — 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.

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:

.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 well-maintained, ships wheels
zstd 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 <subject> (--nsec <nsec> | --ed25519-seed <hex>)
                 [--format json|compact|markdown] [--out <path>]
kez claim dns <domain>     (--nsec <nsec> | --ed25519-seed <hex>)

kez verify file <path>

kez sigchain add    <subject> (--nsec | --ed25519-seed) [--proof-url <url>]
kez sigchain revoke <subject> (--nsec | --ed25519-seed)
kez sigchain show   [--primary <id> | --nsec | --ed25519-seed]
kez sigchain export [--primary <id> | --nsec | --ed25519-seed]
                    [--format jsonl|compact] [--out <path>]

Sigchain state lives in ~/.kez/sigchains/<primary-with-colons-as-underscores>.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, 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.