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>
147 lines
5.6 KiB
Markdown
147 lines
5.6 KiB
Markdown
# KEZ
|
||
|
||
KEZ is a portable, decentralized identity graph. It lets a person say:
|
||
|
||
> "These accounts, keys, domains, and identities are all me."
|
||
|
||
…without depending on any central authority. Every connection is proven by a
|
||
cryptographic signature against a key the user already controls (a nostr key,
|
||
an Ed25519 key, etc.), and the proofs are published in places only the
|
||
claimed account itself can publish to (their gist, their DNS, their nostr
|
||
relay event). Anyone can verify the graph without trusting a server.
|
||
|
||
## Repository layout
|
||
|
||
```
|
||
.
|
||
├── SPEC.md ← The protocol. Language-agnostic, normative.
|
||
├── rust/ ← Rust implementation (kez-core, kez-channels, kez-cli)
|
||
├── nodejs/ ← TypeScript/Node implementation (same shape, same CLI)
|
||
├── python/ ← Python implementation (same shape, same CLI)
|
||
├── rust-sig-server/ ← Optional HTTP store for sigchains (axum + SQLite)
|
||
├── crosstest.sh ← Interop test: artifacts move between implementations
|
||
└── README.md ← (this file)
|
||
```
|
||
|
||
Three parallel implementations. **Wire-compatible**: a claim signed in Rust
|
||
verifies in Node and Python and vice versa, in every direction. The cross-test
|
||
harness proves it.
|
||
|
||
A separate [`rust-sig-server/`](rust-sig-server/) crate provides an optional
|
||
HTTP storage tier for sigchains — useful when a user doesn't want to set up
|
||
DNS/hosting/nostr, but **never required**; the protocol stays decentralized.
|
||
|
||
## Documentation
|
||
|
||
Start here:
|
||
|
||
- [**`SPEC.md`**](SPEC.md) — the language-agnostic protocol spec (v0.2).
|
||
Normative for every implementation.
|
||
- [**`rust/README.md`**](rust/README.md) — Rust implementation guide:
|
||
crate layout (`kez-core` / `kez-channels` / `kez-cli`), full CLI
|
||
reference, channel plugin model, library examples, and the gap list.
|
||
- [**`nodejs/README.md`**](nodejs/README.md) — Node/TypeScript port:
|
||
same shape as Rust, npm workspaces layout, crypto stack rationale,
|
||
CLI reference.
|
||
- [**`python/README.md`**](python/README.md) — Python port: single
|
||
`kez` package, virtualenv setup, crypto stack rationale (pure-Python
|
||
BIP-340 Schnorr + `cryptography` for Ed25519), CLI reference.
|
||
- [**`rust-sig-server/README.md`**](rust-sig-server/README.md) — the
|
||
optional storage server: API reference, no-auth design + threat
|
||
model, deployment recipes (bare-metal, Docker, PaaS), and how
|
||
channel-based publishing remains the fallback if the server is down.
|
||
|
||
## Quick start
|
||
|
||
### Rust
|
||
```sh
|
||
cd rust
|
||
cargo build
|
||
cargo test # 99 tests
|
||
cargo install --path crates/kez-cli # → `kez` on PATH
|
||
kez verify id github:jason
|
||
```
|
||
Full guide: [`rust/README.md`](rust/README.md) (reference) ·
|
||
[`rust/TUTORIAL.md`](rust/TUTORIAL.md) (step-by-step, recommended
|
||
for newcomers).
|
||
|
||
### Node.js
|
||
```sh
|
||
cd nodejs
|
||
npm install
|
||
npm test # 91 tests
|
||
npm run cli -- verify id github:jason
|
||
```
|
||
Full guide: [`nodejs/README.md`](nodejs/README.md) (reference) ·
|
||
[`nodejs/TUTORIAL.md`](nodejs/TUTORIAL.md) (step-by-step).
|
||
|
||
### Python
|
||
```sh
|
||
cd python
|
||
python3 -m venv .venv
|
||
.venv/bin/pip install -r requirements.txt
|
||
.venv/bin/python kez_cli.py identity new
|
||
```
|
||
Full guide: [`python/README.md`](python/README.md) (reference) ·
|
||
[`python/TUTORIAL.md`](python/TUTORIAL.md) (step-by-step).
|
||
|
||
### Sigchain storage server (optional)
|
||
```sh
|
||
cd rust-sig-server
|
||
cargo build --release
|
||
./target/release/kez-sig-server # listens on :7878
|
||
```
|
||
Full guide: [`rust-sig-server/README.md`](rust-sig-server/README.md).
|
||
|
||
## Cross-testing
|
||
|
||
```sh
|
||
./crosstest.sh
|
||
```
|
||
|
||
Runs 55 scenarios that swap implementations at the artifact boundary:
|
||
|
||
| # | Scenarios |
|
||
|---|---|
|
||
| 1–14 | Rust ↔ Node: JSON / compact / markdown / DNS claims, nostr + ed25519 |
|
||
| 15–20 | Rust ↔ Node sigchains: build in one, parse + show in the other; JSONL byte parity |
|
||
| 21–44 | **Python ↔ Rust and Python ↔ Node** claims: every format × key type, both directions |
|
||
| — | Python ↔ both peers DNS zone form, both directions |
|
||
| — | Python ↔ both peers sigchains: build/show both ways, JSONL byte parity, ed25519 |
|
||
|
||
If all 55 pass: JCS canonicalization, both signature suites (BIP-340 Schnorr
|
||
and Ed25519), the compact `kez:z1:` zstd+base64url encoding, the Markdown
|
||
fence, the DNS TXT shape, and the sigchain JSONL bundle format are all
|
||
byte-compatible across all three implementations.
|
||
|
||
Pass `-v` for verbose output (echoes intermediate commands and proofs).
|
||
|
||
## What ships in v0.2
|
||
|
||
- **Five channel plugins** in each implementation: `dns:`, `github:`,
|
||
`nostr:`, `bluesky:`, `ap:` (alias `mastodon:`).
|
||
- **Four wire encodings**: JSON, compact, Markdown fence, DNS TXT.
|
||
- **Two primary-key algorithms**: nostr/secp256k1 Schnorr (BIP-340) and
|
||
Ed25519 (RFC 8032).
|
||
- **JCS (RFC 8785)** canonicalization for everything signed.
|
||
- **No API keys required for any channel.**
|
||
|
||
## What's not done yet
|
||
|
||
Tracked in [`rust/README.md`](rust/README.md#whats-not-done-yet) and the
|
||
spec:
|
||
|
||
- **`verify id` consulting the sigchain.** Sigchain types, CLI commands
|
||
(`kez sigchain add/revoke/show/export/publish`), and the storage server
|
||
all exist. But proof verification doesn't yet fetch the chain to check
|
||
for revocations — every `verify` is still a single one-shot proof check.
|
||
- `rotate` and `add_device` sigchain ops.
|
||
- `expires_at` enforcement during claim verify.
|
||
- Typed `VerificationStatus.status` reflecting the five failure modes
|
||
(`valid` / `revoked` / `expired` / `unreachable` / `fork`).
|
||
- Auth-required publishers (GitHub gist, Bluesky, ActivityPub).
|
||
|
||
## License
|
||
|
||
Dual-licensed under MIT or Apache-2.0.
|