# 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

```bash
# 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`).
