versioning policy, changelog
Full sweep across the three buckets discussed:
Bucket A (quick wins — staleness/bugs):
- Fix §3 (was §2): drop wrong mastodon row with double-@; ActivityPub
channel formalized as `ap:` with mastodon as alias; consolidated
with current channel set.
- §7 channels table now matches the actually-shipped channel adapters
in rust-channels and node-channels.
- Drop §12 Test Vectors (the directory never existed). Replaced with
one paragraph in §15 pointing at the crosstest.sh harness, which
is what we actually use for inter-implementation conformance.
- Replace §10 historical "MVP Scope (v0.2)" with §14 Changelog.
- §15 Implementation Layout now points at actual repos (rust/,
nodejs/, rust-sig-server/) rather than the never-existed kez-web.
Bucket B (simplifications):
- Folded §9 Starting Points into §10.1 (one paragraph).
- Consolidated §1 Core Concepts and §13 One-Sentence Summary into
the new opener (§1 Summary + §2 Glossary).
- §3.1 Canonicalization inlined into §4.2 (where it actually applies).
- §8 Verification trimmed from 9 conflated steps to 5 clean phases.
- §8.5 "MUST" softened to "expected" for libraries; complete verifiers
do network, helpers don't.
Bucket C (real improvements + restructure):
- §2 Glossary added (primary key, claim, subject, proof, channel,
sigchain, signature envelope, identity graph — all in one place).
- §11 Cryptographic Primitives table — every algo we use, its role.
- §12 Worked Example with REAL reproducible bytes: fixed Ed25519
seed (4242... — clearly labeled TEST ONLY), specific subject and
timestamp, the exact JCS bytes, the exact deterministic Ed25519
signature, the exact compact form. Generated against the reference
Rust implementation; any conforming implementation should produce
identical bytes.
- §13 Versioning & Wire Compatibility policy — what bumps major,
what bumps minor, how implementations handle unknown ops.
- §14 Changelog — v0.1 / v0.2 / v0.3 with notable changes.
- §8.4 Sigchain in pictures — ASCII diagram showing 5 events with
hash chaining and rotation.
Structural reorganization:
- §1 summary → §2 glossary → §3 identifiers → §4 signature envelope
→ §5 payload shapes → §6 wire encodings → §7 channels → §8 sigchain
→ §9 storage → §10 verification → §11 crypto → §12 worked example
→ §13 versioning → §14 changelog → §15 implementation layout.
- The envelope (the unit of transport) is now described before the
payloads it wraps, matching what's actually on the wire.
Also: added §6.5 documenting `kez:zc1:` (compact sigchain bundle)
that exists in the implementations but was missing from the spec.
KEZ is a portable, decentralized identity graph: a person signs claims
linking their many accounts, publishes those claims in places only the
claimed account can publish to, and anyone can verify the connections
without trusting a central server.
Layout
------
- SPEC.md Language-agnostic protocol spec (v0.2)
- rust/ Rust implementation: kez-core, kez-channels, kez-cli
- nodejs/ TypeScript port at full parity
- rust-sig-server/ Optional axum + SQLite storage server for sigchains
- crosstest.sh Cross-implementation interop harness
Capabilities (both implementations, byte-compatible)
----------------------------------------------------
- Two primary-key algorithms: nostr/secp256k1 Schnorr (BIP-340) and
Ed25519 (RFC 8032). Identifiers: nostr:npub1... and ed25519:<hex>.
- JCS (RFC 8785) canonicalization for everything signed.
- Four proof encodings: JSON envelope, compact (kez:z1:<base64url(zstd(json))>),
Markdown fence, DNS TXT.
- Five channel plugins (no API keys, no auth needed for any of them):
dns: system resolver, _kez.<domain> TXT records
github: public gist scan + <user>/<user> profile README fallback
nostr: kind-30078 events from default relays
bluesky: public AppView author feed
ap: WebFinger + actor JSON (alias mastodon:)
- Identical CLI surface:
kez identity new [--key-type nostr|ed25519]
kez claim create <subject> (--nsec | --ed25519-seed) [--format ...] [--out ...]
kez claim dns <domain> (--nsec | --ed25519-seed)
kez verify file <path>
kez verify id <identifier>
kez sigchain add|revoke|show|export|publish
- Sigchains: append-only signed log per primary, hash-chained per spec §6,
stored locally at ~/.kez/sigchains/, exportable as JSONL or kez:zc1: bundle.
- Sigchain publish destinations: chain server, web (file dump), DNS (zone
record print), nostr (kind-30078 wrapping event).
kez-sig-server
--------------
Optional storage tier. Axum + SQLite, single binary, no external deps.
- No auth — the cryptography is the access control. The server validates
every signature, every seq, every prev hash before storing.
- REST API: POST /v1/sigchains/{scheme}/{id}/events (append signed event,
201 with new head hash or 4xx); GET /{scheme}/{id} (full chain as JSONL);
GET /head; GET /healthz.
- Designed for one central instance for now; the design doesn't preclude
running more later (clients gain a configurable list, verifiers
reconcile per spec §6.2).
- Channel-based publishing remains the always-available fallback if the
server is unavailable.
Tests
-----
- rust/ 99 tests
- rust-sig-server/ 10 integration tests (real HTTP, real SQLite)
- nodejs/ 91 tests (vitest)
- crosstest.sh 19 cross-impl scenarios — proves JCS bytes,
Schnorr + Ed25519 sigs, all four claim encodings,
and the sigchain JSONL bundle are byte-compatible
between Rust and Node in both directions.
What's not done yet
-------------------
- verify id consulting the sigchain for revocations (data path exists,
just not wired into the verifier output).
- rotate and add_device sigchain ops (types reserved).
- expires_at enforcement during claim verification.
- Typed VerificationStatus.status reflecting the five failure modes.
- Auth-required publishers (GitHub gist, Bluesky, ActivityPub).