Engineering
Implementation Plan¶
How This Project Is Built¶
This is a mastery project on a 5–10 year horizon. There is no deadline and no application to ship.
The rules, which override any instinct toward progress:
- One small module at a time, bottom-up. A module is complete when it is tested, documented, and understood — not when it works.
- No scaffolding ahead. Never stub a layer to come back to. Never build a demo that spans layers not yet mastered.
- Theory before code. Each module comes with the reading that explains it. The point is to know why it works, not to have it working.
- Tests are the deliverable. If a module cannot be tested in isolation, it is too big or badly factored — split it.
The SQLite standard, honestly¶
SQLite's ~590:1 test-to-code ratio (92M lines of test vs 156k of library) is mostly machine-generated cases from harnesses like TH3. Chasing that ratio in hand-written tests is not achievable and not the lesson.
What actually produces the reliability, and what we copy:
| SQLite practice | Zajil analogue |
|---|---|
| 100% MC/DC branch coverage | 100% branch coverage on the sans-io core |
| Three independent test harnesses | RFC known-answer vectors + property tests + simulation |
| Continuous fuzzing | cargo-fuzz on every decoder touching untrusted bytes |
| OOM / crash / power-loss injection | Deterministic network simulation: loss, reorder, delay, partition |
Deterministic simulation testing is the centrepiece. Because the core is sans-io, the entire protocol can run against a simulated network driven by a seeded RNG — millions of adversarial scenarios, every failure reproducible from its seed. This is only possible if no module below the transport layer ever touches a socket, a clock, or an RNG directly. That constraint is load-bearing.
Vocabulary¶
- Barid node — a physical machine.
- Cell — a communication node: one derived IPv6 address and the link behind it. A Barid node hosts many cells (10, 200, 1000+).
- Cell secret — the credential a client actually holds. Addresses are derived from it and are ephemeral. Rotating the secret invalidates every address it ever produced.
v1 isolation model: cells are additional IPv6 addresses on one kernel. They are a rotation and availability mechanism, not a security boundary. The security boundary is the Barid node. Client cell assignments must therefore spread across distinct nodes (see decision 001 §8).
Module Ladder¶
Modules 0–7 require no network whatsoever. Each is independently testable.
Layer 0 — Encoding¶
0.1 Wire primitives — varint, length-prefixed frames, canonical byte serialization. Tests: round-trip property tests; fuzz the decoder against malformed input; canonical-form tests (one value has exactly one encoding). Theory: canonical serialization and why non-canonical encodings become signature-bypass bugs.
0.2 Error types — typed, exhaustive, no stringly-typed failure paths.
Layer 1 — Cryptographic Primitives¶
Wrappers over vetted crates. We compose primitives; we do not implement them.
Deferred, deliberately. Hand-implementing Ed25519 and friends is a stated long-term goal, alongside experimenting with alternative primitives. It is not the current objective. The skill being built first is orchestration — how identity, derivation, handshake, and revocation compose into a protocol that holds. Primitives are a solved problem; composing them is where real systems fail. Revisit once Layers 0–7 are solid.
| Module | Primitive | Test vectors |
|---|---|---|
| 1.1 | Ed25519 sign/verify | RFC 8032 |
| 1.2 | HMAC-SHA256 | RFC 4231 |
| 1.3 | X25519 ECDH | RFC 7748 |
| 1.4 | ChaCha20-Poly1305 AEAD | RFC 8439 |
| 1.5 | HKDF | RFC 5869 |
Layer 2 — Address Derivation ← start here¶
2.1 Time buckets — bucket granularity as a parameter; skew tolerance
accepting adjacent buckets (TOTP-style, RFC 6238).
2.2 Derivation — address = ipv6_prefix || truncate(HMAC(cell_secret, bucket)).
Tests: our own known-answer vectors; property test that rotating a cell secret produces a disjoint address set; skew boundary tests at exact bucket edges; clock-drift simulation; distribution tests over the prefix space. Theory: TOTP, HMAC truncation and why it is safe, birthday bounds on address collisions within a prefix.
This is the first genuinely Zajil-specific module, it is small, and it is completely testable without a network. It is the right place to begin.
Layer 3 — Identity¶
3.1 Root key and certificate format 3.2 Chain validation — expiry, signer verification, clock handling
Tests: valid chains; expired certs; wrong signer; malformed encodings; fuzz; clock-skew edge cases at exact expiry boundaries.
Layer 4 — Manifest¶
4.1 Canonical encoding and signing 4.2 Version-gated acceptance
Tests: rollback rejection (lower version refused); forged signature rejection; unknown-field forward compatibility; fuzz.
Layer 5 — Handshake¶
5.1 Noise pattern selection and justification 5.2 Sans-io handshake state machine
Tests: official Noise test vectors; two in-memory peers completing a handshake with zero network; every invalid transition rejected.
Layer 6 — Record Layer¶
6.1 Encrypted records — nonce management, replay protection, rekeying
Tests: replay rejection; reordering within window; nonce exhaustion; rekey boundaries.
Layer 7 — Protocol State Machine¶
The sans-io core proper: cell selection, depletion tracking, refresh thresholds.
Tests: deterministic simulation — seeded loss, reorder, delay, partition. This is where the bulk of the test effort lives for the life of the project.
Layer 8 and beyond — I/O and Deployment¶
Not planned in detail; they depend on everything above being solid.
- Layer 8 — UDP/QUIC transport adapter (first real socket in the project)
- Layer 9 — Barid node
- Layer 10 — Enrollment tokens and roster
- Layer 11 — Platform bindings (WASM, UniFFI)
Immediate Next Step¶
Module 2.1: time buckets with skew tolerance. Roughly 50 lines of code and several hundred lines of tests. Requires only HMAC (1.2) beneath it.