Files
suaveplan/packages/foundation/data/packer/src/chunked/codec/chunk.md
2026-05-27 23:47:53 +01:00

3.2 KiB

chunk

Purpose

Encodes and parses the wire-format v1 chunk in its entirety: metadata(100) || sig(64) || ciphertext(payloadLen). Composes encodeHeader / parseHeader with byte-level concatenation, length validation, and the canonical signing-payload helper. Every receive path in the packer (chunked unpacker, chunk verifier, mesh transport) calls parseChunk before any cryptographic work; every send path calls encodeChunk once metadata, signature, and ciphertext are ready.

Features

  • encodeChunk({ metadata, sig, ciphertext }) returns a single Uint8Array of 164 + payloadLen bytes.
  • parseChunk(buf) returns { metadata, sig, ciphertext } with all three fields as zero-copy subarrays of buf.
  • signingPayload(metadataBytes, ciphertext) returns the canonical bytes the server signs / receivers verify.
  • Length and structural validation lifted from parseHeader; chunk-level validation adds the total-length check.

Usage: Basic Example

import { encodeChunk, parseChunk } from "@suaveplan/packer/chunked";

const wire = encodeChunk({
    metadata,                           // ChunkV1Metadata
    sig: new Uint8Array(64),            // ed25519 signature
    ciphertext: new Uint8Array(payloadLen),
});

const back = parseChunk(wire);
// back.metadata, back.sig, back.ciphertext

Usage: Advanced Example

import { encodeChunk, parseChunk, signingPayload, encodeHeader } from "@suaveplan/packer/chunked";
import { ed25519 } from "@noble/curves/ed25519";

// Producer:
const headerBytes = encodeHeader(metadata);
const signed = signingPayload(headerBytes, ciphertext);
const sig = ed25519.sign(signed, serverPrivKey);
const wire = encodeChunk({ metadata, sig, ciphertext });

// Receiver:
const { metadata: m, sig: s, ciphertext: c } = parseChunk(wire);
const signedAgain = signingPayload(encodeHeader(m), c);
if (!ed25519.verify(s, signedAgain, serverPubKey)) {
    throw new Error("bad sig");
}

API Reference

  • interface EncodeChunkInput { metadata: ChunkV1Metadata; sig: Uint8Array; ciphertext: Uint8Array }
  • encodeChunk(input: EncodeChunkInput): Uint8Array — total length 164 + payloadLen. Throws PackerError(PACKER.INVALID_FORMAT) on sig.byteLength !== 64 and PackerError(PACKER.PAYLOAD_LEN_INVALID) on ciphertext-length mismatch.
  • parseChunk(buf: Uint8Array): ParsedChunkV1 — validates total length matches 164 + metadata.payloadLen. Throws on header-parse failures and on length mismatch.
  • signingPayload(metadataBytes: Uint8Array, ciphertext: Uint8Array): Uint8Array — concatenates the two for ed25519 sign/verify.

Implementation Notes

encodeChunk performs metadata field-length validation indirectly via encodeHeader, then writes a single fresh Uint8Array(164 + payloadLen) with three set calls — no intermediate copy of the metadata or ciphertext beyond the final placement. parseChunk re-uses parseHeader's zero-copy subarray pattern; the returned struct shares its underlying buffer with the input, so callers must clone if they intend to mutate either side independently. signingPayload allocates a fresh buffer because the AEAD-side callers must not mutate the wire bytes after sig generation.