Files
Keysat 843ff0e5d7 Initial backup of root workspace files
Glue files not covered by subproject repos: top-level docs, logo,
keysat-design-system, and crosscheck tests. Subproject folders are
gitignored (each has its own Gitea remote).
2026-06-12 17:51:40 -05:00

3.2 KiB

Format cross-check

Verifies that the three implementations of the LIC1-...-... key format (licensing-service in Rust, licensing-client-rust SDK, licensing-client-ts SDK) all agree, byte for byte, on both the legacy v1 payload layout and the current v2 layout.

Approach

  1. reference_signer.py builds three license keys from scratch using the exact byte layouts documented in licensing-service/src/crypto/mod.rs. It uses Python's cryptography for Ed25519 signing — an independent implementation from the Rust one, so agreement here is strong evidence the format is correct, not just that the Rust side agrees with itself.

    The three keys exercise every branch of the parser:

    • v1 — legacy fixed-74 payload, fingerprint-bound. New keys aren't issued in v1 anymore, but SDKs must still accept them indefinitely so old keys in the wild keep working.
    • v2 — trial key, fingerprint-bound, with explicit expiry and two entitlements. Stresses the variable-length tail parser.
    • v2_perpetual_unbound — the "happy path" for a normal paid purchase: v2, no expiry, no fingerprint binding, no entitlements.
  2. run_ts.mjs imports the built TypeScript SDK (dist/index.js) and runs each of the three fixtures through: field-by-field parse, signature verification, fingerprint binding (positive + negative), entitlement lookup, isExpiredAt boundaries, and tamper detection. Also spot-checks hashFingerprint against Python's hashlib.sha256 and public-key loading.

Rust SDK coverage

The Rust SDK uses the same crates as the service (data_encoding::BASE32_NOPAD, ed25519_dalek) with identical byte offsets (licensing-client-rust/src/key.rs mirrors licensing-service/src/crypto/mod.rs), so round-trip compatibility is guaranteed by construction. If you change the layout, update the service's from_bytes, the Rust SDK's from_bytes, and reference_signer.py together.

The Rust SDK's own unit tests (cargo test -p licensing-client) round-trip every flag + version combination.

Running

# Build the TS SDK first.
cd licensing-client-ts
npm install
npm run build

cd ../tests/crosscheck
python3 reference_signer.py > vector.json
node --experimental-vm-modules run_ts.mjs

Current test vectors

Both vectors share a deterministic signing key seeded with bytes(range(32)), so the license strings in vector.json are stable across regenerations (a regression in encoding will produce a git diff).

fixture version expires_at entitlements flags
v1 1 (n/a) (n/a) FINGERPRINT_BOUND
v2 2 1900000000 ["pro","multi-device"] FINGERPRINT_BOUND | TRIAL
v2_perpetual_unbound 2 0 [] 0

Product UUID: 6f46a4f6-0d2f-4a28-b6aa-3e8fbf6f28f0, fingerprint raw string "test-machine-fingerprint" (SHA-256 d34461ff63170de633b5aa2512ce2e15ac120b1c325acdada67c02e594ba3b3d).