# inline-hint _(no submodules)_ ## Purpose Implements DTP-25 (drive-plugin-chunks-inline-sig). Provides the signed `InlineHint` shape used by `FileLocation.storageHints` entries with `kind: 'inline'`, the Ed25519 signing helper that produces them, the verifier that the drive runs before returning inline bytes, and the legacy-detection / upgrade helpers that let pre-DTP-25 hints (no `sig` field) round-trip safely. The signing input is the canonical concatenation `fileId ‖ bytes`, which binds the signature to one file so a replay onto a different fileId would fail verification. ## Features - `InlineHint` — `{ kind: 'inline'; bytes: Uint8Array; sig: Uint8Array }` for the DTP-25 wire format. - `LegacyInlineHint` — `{ kind: 'inline'; bytes: Uint8Array }` for backward-compat reads. - `signInlineHint` — Ed25519-sign over `fileId ‖ bytes` under the drive's secret key. - `verifyInlineHint` — verify and return bytes; throws `CHUNKS.INLINE_SIG_INVALID` on failure (catch arm covers verifier exceptions too). - `isLegacyInlineHint` — type-guard distinguishing legacy from signed shapes. - `upgradeLegacyInlineHint` — sign a legacy hint with the drive's key so the next write rewrites it as `InlineHint`. - `inlineSigningInput` — exposes the canonical concatenation so other layers can re-derive the bytes that are signed. - Cause-chain preservation: verifier exceptions are wrapped as `ChunksError` with the original error attached as `cause`. ## Usage: Basic Example ```ts import { signInlineHint, verifyInlineHint, } from "@suaveplan/drive-plugin-chunks"; import { sha256 } from "@suaveplan/crypto-hash"; const fileId = sha256(plaintext); const hint = signInlineHint(fileId, plaintext, driveSecretKey); // later, on read: const bytes = verifyInlineHint(hint, fileId, drivePublicKey); console.log(bytes.byteLength); ``` ## Usage: Advanced Example ```ts import { isLegacyInlineHint, upgradeLegacyInlineHint, verifyInlineHint, type AnyInlineHint, } from "@suaveplan/drive-plugin-chunks"; function readInline( hint: AnyInlineHint, fileId: Uint8Array, driveSecretKey: Uint8Array, drivePublicKey: Uint8Array, onLegacyWarning: () => void ): Uint8Array { if (isLegacyInlineHint(hint)) { onLegacyWarning(); // emit drive:inline:legacy const upgraded = upgradeLegacyInlineHint( hint, fileId, driveSecretKey ); // Persist `upgraded` on the next write; for the current read we // can return the bytes directly because legacy hints predate the // sig requirement. return upgraded.bytes; } return verifyInlineHint(hint, fileId, drivePublicKey); } ``` ## API Reference - `signInlineHint(fileId: Uint8Array, bytes: Uint8Array, driveSecretKey: Uint8Array): InlineHint` — Ed25519-sign `fileId ‖ bytes` and return the signed hint. - `verifyInlineHint(hint: InlineHint, fileId: Uint8Array, drivePublicKey: Uint8Array): Uint8Array` — verify and return `hint.bytes`. Throws `ChunksError(CHUNKS.INLINE_SIG_INVALID, ...)` if the signature does not verify or the verifier raises. - `isLegacyInlineHint(hint: AnyInlineHint): hint is LegacyInlineHint` — true when the hint omits `sig`. - `upgradeLegacyInlineHint(legacy: LegacyInlineHint, fileId: Uint8Array, driveSecretKey: Uint8Array): InlineHint` — sign the legacy bytes under the drive's key. - `inlineSigningInput(fileId: Uint8Array, bytes: Uint8Array): Uint8Array` — canonical signing input. - `InlineHint`, `LegacyInlineHint`, `AnyInlineHint`, `StorageHint`, `FileLocation` — wire types. ## Implementation Notes The verifier uses `@noble/curves` Ed25519 via `@suaveplan/crypto-curve/ed25519`. `verify()` is implemented to never throw on malformed inputs in the noble path, but the catch arm exists for engine-substitution scenarios where a custom verifier may throw — the `injectable verifyFn` pattern is intentionally not surfaced here because the chunks plugin always uses noble. The `CHUNKS.INLINE_SIG_INVALID` code is registered through `defineCodes("CHUNKS", ...)` in `error-codes.ts`. Domain separation is provided by including `fileId` in the signing input; this is sufficient because every inline-hint context already has a unique fileId, so the signature cannot be replayed across files even if an attacker controls one inline body.