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

2.4 KiB

build

Purpose

Constructs a server-signed Manifest for an ingested file: bundles the file metadata (fileId, fileSize, chunkSize, totalChunks), encryption envelope (algo, fileKeyWrapped, baseNonce), and per-chunk integrity hashes into a single record, then signs the canonical encoding under the server private key. The manifest is the consensus artefact: peers that trust the server public key can verify it without holding any chunk bytes.

Features

  • buildManifest(options): Manifest — pure function, no I/O, no global state.
  • canonicalSerialize(manifest): Uint8Array — deterministic big-endian length-prefixed encoding suitable for cross-platform Ed25519 signing.
  • algo is encoded as a length-prefixed UTF-8 string so future encryption algorithms can be added without breaking the wire format.
  • Per-chunk entries pack (chunkId: u32, hash: 32 bytes, payloadLen: u32) into 40 bytes — bounded growth, predictable memory.

Usage: Basic Example

import { buildManifest } from "@suaveplan/drive-plugin-chunks";

const manifest = buildManifest({
    fileId: sha256Bytes,
    fileSize: 12n,
    chunkSize: 1024,
    totalChunks: 1,
    encryption: { algo: "xchacha20poly1305", fileKeyWrapped: fileKey, baseNonce },
    chunks: [{ chunkId: 0, hash: chunkHash, payloadLen: 12 }],
    serverPrivKey,
});

Usage: Advanced Example

import { buildManifest, canonicalSerialize } from "@suaveplan/drive-plugin-chunks";
import { verify } from "@suaveplan/crypto-curve/ed25519";

const manifest = buildManifest({ /* ... */ });
const { sig, ...base } = manifest;
const ok = verify(sig, canonicalSerialize(base), serverPubKey);

API Reference

  • buildManifest(options): Manifest — returns { version, fileId, fileSize, chunkSize, totalChunks, encryption, chunks, sig }.
  • canonicalSerialize(manifest: Omit<Manifest, "sig">): Uint8Array — used both for signing and for verification.

Implementation Notes

Field order in canonicalSerialize is fixed and big-endian; changing it would break every previously-stored manifest. The algo length prefix makes the encoded form self-delimiting so receivers don't need an explicit version bump to add new algorithms — they only need to add a parsing branch keyed on the algo string. The final buf.slice(0, off) trims any over-allocated tail, but totalLen is computed exactly so this is normally a no-op.