xnet-core: a portable Rust protocol kernel (exploration 0210, Phase 2) - #237
Merged
Conversation
…10 Phase 2) A Rust implementation of the byte-exact interop kernel: did:key, canonical-JSON change hash (BLAKE3), Ed25519 sign/verify, per-property LWW, version negotiation, and authorization expression eval. Passes the shared golden-vector corpus (identity/change/lww/replication/authz) via `cargo test` — and, with deterministic RFC-8032 Ed25519 (on curve25519-dalek + sha2; base58 + canonical JSON inline), re-signs changes BYTE-FOR-BYTE, which the Swift/CryptoKit kernel cannot. Fourth conforming implementation (TS, Python, Swift, Rust). src/ffi.rs exposes a String/Vec<u8>/bool surface ready for UniFFI; the codegen itself is deferred (the uniffi toolchain wasn't available in this offline build) and documented in the crate README. Adversarial crypto review confirmed soundness (canonical-S/malleability + non-canonical-point rejection); it also surfaced a separate TS-runtime determinism bug (LWW author tiebreak uses localeCompare, not code-unit) to fix as a follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
Preview removed for PR #237. |
crs48
added a commit
that referenced
this pull request
Jun 22, 2026
…mpare) (#238) ## What & why A correctness/determinism fix surfaced by the adversarial review of the Rust core ([#237](#237)). The per-property **last-writer-wins tiebreak** (and the change-ordering and history comparators) compared `authorDID`s with **`String.localeCompare`**. That is locale- and ICU-version-**dependent**, so two peers resolving the *same* concurrent edit (equal `lamport` *and* `wallTime`, author DIDs differing in case) could pick **different winners** — a real CRDT convergence bug. The protocol spec (§7), the conformance vectors, and the Python/Swift/Rust kernels all use **UTF-16 code-unit** order (the same order as the §6 canonical-JSON key sort). ## The fix Switched all six author-tiebreak sites from `localeCompare` to deterministic code-unit comparison (`<`/`>`): - `packages/data/src/store/store.ts` — `applyRemoteChanges` sort + `shouldReplace` (the LWW core) - `packages/sync/src/chain.ts` — `compareChangeOrder` - `packages/sync/src/clock.ts` — `compareLamportTimestamps` - `packages/history/src/{schema-timeline,engine}.ts` Plus: - **Spec §7** now mandates code-unit order and explicitly forbids locale collation. - A new golden vector **`lww/0004-tie-author-case-codeunit`** pins the mixed-case case (`"did:key:zAAA"` vs `"did:key:zaaa"` at equal lamport/wallTime → lowercase wins, since `A` < `a`). The previous vectors used same-case DIDs and didn't distinguish the two orderings. ## Verification - Conformance drift guard: **25 vectors pass** (was 24; +`lww/0004`). - `turbo typecheck` (sync/data/history/runtime): **18/18**. - Suites green: sync **570**, data store **163**, history **138**. - No behavior change for the common case — only removes the latent divergence. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Phase 2 of the native-SDK exploration:
rust/xnet-core, a portable Rust implementation of the XNet interop kernel — the byte-exact core (did:key identity, canonical-JSON change hash, Ed25519 sign/verify, per-property LWW, L2 version negotiation, L3 authorization eval). The point is one portable core that can back the Swift, Kotlin, and .NET SDKs via UniFFI / a C ABI, instead of each language re-implementing the kernel.Conformance — a fourth conforming implementation
cargo testruns the shared golden-vector corpus (conformance/vectors/):It joins TypeScript, Python, and Swift in the conformance matrix at L0–L3. And because Ed25519 here is the deterministic RFC-8032 construction (implemented on the audited
curve25519-dalek+sha2; base58btc and canonical JSON inline), it re-signs changes byte-for-byte — which the Swift/CryptoKit kernel structurally cannot (CryptoKit randomizes). That makes Rust a candidate to generate golden vectors, not just verify them.Binding surface
src/ffi.rsexposes the kernel withString/Vec<u8>/boolsignatures — the shape UniFFI (Swift/Kotlin) and a C ABI (.NET) consume — built and unit-tested. Generating the bindings is documented in the crate README; the codegen itself is deferred because theuniffitoolchain was unavailable in this offline build (crates.io unreachable). Until wired, the native Swift kernel and this Rust core are independently conformance-verified against the same vectors, so they already agree on the wire.Review
An adversarial crypto review confirmed the hand-rolled Ed25519 is sound — it rejects non-canonical
S(malleability) and non-canonical point encodings, with correct clamping and nonce derivation. It also surfaced a separate TypeScript-runtime bug (the LWW author tiebreak useslocaleCompare, which is locale-dependent → non-deterministic CRDT convergence; the spec + vectors + all kernels use code-unit order). My Rust matches the spec/vectors; I'll fix the TSlocaleComparein a focused follow-up.Verification
cd rust/xnet-core && cargo test→ 5 conformance suites + 1 FFI round-trip pass.rust/(outside the pnpm workspace) — doesn't touch TS CI; changelog fragment included.Scope / next
Remaining Phase-2 items: UCAN + the E2E envelope in the kernel; generate the UniFFI bindings + C ABI and strangler-fig XNetKit onto the Rust core; link
yrsfor Yjs bodies. Then Phase 3 (Kotlin/.NET) falls out of the same core.🤖 Generated with Claude Code