Files
skills/docs/networking/drive/drive-plugin-chunks/src/inline/inline-hint.md
2026-05-29 08:20:56 +01:00

4.3 KiB

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

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

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.