Skip to content

xnet-core: a portable Rust protocol kernel (exploration 0210, Phase 2) - #237

Merged
crs48 merged 1 commit into
mainfrom
claude/rust-xnet-core
Jun 22, 2026
Merged

xnet-core: a portable Rust protocol kernel (exploration 0210, Phase 2)#237
crs48 merged 1 commit into
mainfrom
claude/rust-xnet-core

Conversation

@crs48

@crs48 crs48 commented Jun 22, 2026

Copy link
Copy Markdown
Owner

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 test runs the shared golden-vector corpus (conformance/vectors/):

test l0_identity ... ok      test l1_lww ... ok        test l3_authz ... ok
test l1_change ... ok        test l2_replication ... ok

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.rs exposes the kernel with String/Vec<u8>/bool signatures — 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 the uniffi toolchain 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 uses localeCompare, 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 TS localeCompare in a focused follow-up.

Verification

  • cd rust/xnet-core && cargo test5 conformance suites + 1 FFI round-trip pass.
  • Top-level 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 yrs for Yjs bodies. Then Phase 3 (Kotlin/.NET) falls out of the same core.

🤖 Generated with Claude Code

…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>
@crs48
crs48 temporarily deployed to pr-237 June 22, 2026 20:29 — with GitHub Actions Inactive
@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Preview removed for PR #237.

github-actions Bot added a commit that referenced this pull request Jun 22, 2026
@crs48
crs48 merged commit 6e45988 into main Jun 22, 2026
12 checks passed
@crs48
crs48 deleted the claude/rust-xnet-core branch June 22, 2026 20:43
github-actions Bot added a commit that referenced this pull request Jun 22, 2026
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant