first commit
This commit is contained in:
50
docs/networking/drive/drive-template/src/codec/canonical.md
Normal file
50
docs/networking/drive/drive-template/src/codec/canonical.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# 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
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
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.
|
||||
Reference in New Issue
Block a user