Files
skills/docs/networking/drive/drive-template/src/codec/canonical.md
2026-05-29 08:20:56 +01:00

2.7 KiB

canonical

Purpose

Implements canonicalSerialize, the deterministic byte-level encoding that gates every server signature on a DriveTemplate (DTP-03). Two implementations of the function MUST produce byte-identical output for identical input regardless of in-memory key order. JSON is deliberately rejected because object-key ordering is not portable across runtimes.

Features

  • Hand-rolled big-endian binary writer (ByteWriter) with uint8 / uint16 / uint32 / uint64 / bool / string / bytes primitives plus length-prefixed optional* helpers.
  • Fixed field order across the entire template tree — schemaVersion, driveId, issuer, issuedAt, expiresAt, nonce, policy, cdnFallback, rootFolder.
  • Recursive folder/file walker that tags each node with TAG_FOLDER (0x01) / TAG_FILE (0x02) so the decoder can reconstruct the tree without a separate manifest.
  • Encryption-aware: inline and retroactive KeyDistribution variants are tagged 1 / 2 respectively; the wrappedKey blob and keyAuthority string follow.
  • Excludes serverSignature — the bytes the issuer signs MUST not include the signature itself.

Usage: Basic Example

import { canonicalSerialize } from "@suaveplan/drive-template";

const bytes = canonicalSerialize({
    schemaVersion: 1,
    driveId: "drive-1",
    rootFolder: { name: "/", children: [] },
    policy: { defaultPolicy: { autoDownload: false, meshAllowed: true, cdnAllowed: true } },
    issuer: "00".repeat(32),
    issuedAt: Date.now(),
    expiresAt: Date.now() + 60_000,
    nonce: new Uint8Array(16).fill(7),
});

Usage: Advanced Example

import { canonicalSerialize, signTemplate } from "@suaveplan/drive-template";

// canonicalSerialize is the inputs-side; signTemplate runs Ed25519 over it.
const tpl = signTemplate(buildTemplate(), serverSecretKey);
const recanon = canonicalSerialize({ ...tpl, serverSignature: undefined as never });
console.log(`signed bytes: ${recanon.length}`);

API Reference

  • canonicalSerialize(template: Omit<DriveTemplate, "serverSignature">): Uint8Array.
  • Internal-only ByteWriter class with explicit primitives — not exported.

Implementation Notes

The ByteWriter accumulates Uint8Array parts and concatenates once at finish() to avoid quadratic growth. optionalUint64 / optionalUint32 / optionalString write a discriminator byte first so receivers know whether the field follows; this trades two bytes per optional for unambiguous parsing. The retention policy is encoded as a tag (0 = unset, 1 = permanent, 2 = lru, 3 = { maxAgeMs }) so future variants can extend the union without breaking older readers — they will see an unknown tag and reject the template through the schema-version pin.