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

2.7 KiB
Raw Blame History

encrypt-stream

Purpose

The encryption pipeline that transforms a plaintext file into a stream of signed encrypted chunks ready for persistence. It owns the chunk-level nonce derivation, the AEAD ciphertext + tag split, the per-chunk metadata population, and the immediate signing pass. Together these steps form the deterministic transform from { plaintext, fileId, fileKey, baseNonce, chunkSize, serverPrivKey } to a stream of EncodedChunk objects.

Features

  • encryptChunks(options): Generator<EncodedChunk> — yields one chunk per chunkSize - HEADER_SIZE payload window, signed and ready to persist.
  • deriveNonce(baseNonce, chunkId): Uint8Array — XORs the chunk index into the high-order bytes of the 24-byte XChaCha20 nonce; rejects non-24-byte inputs with CHUNKS.METADATA_INVALID.
  • TAG_LENGTH constant (16) for the AEAD tag size.
  • Synchronous generator — no async overhead, allocations bounded per chunk.

Usage: Basic Example

import { randomPrivateKey } from "@suaveplan/crypto-curve/ed25519";
import { encryptChunks } from "@suaveplan/drive-plugin-chunks";

const chunks = Array.from(
    encryptChunks({
        plaintext: new TextEncoder().encode("hello"),
        fileId: new Uint8Array(32),
        fileKey: new Uint8Array(32).fill(7),
        baseNonce: new Uint8Array(24).fill(11),
        chunkSize: 1024,
        serverPrivKey: randomPrivateKey(),
    })
);

Usage: Advanced Example

import { deriveNonce, encryptChunks, TAG_LENGTH } from "@suaveplan/drive-plugin-chunks";

for (const chunk of encryptChunks({ plaintext, fileId, fileKey, baseNonce, chunkSize: 4096, serverPrivKey })) {
    await storage.set(`chunks:${idHex}:${chunk.metadata.chunkId}`, chunk.rawBytes);
}

// Reconstruct the per-chunk nonce on the receiver
const nonce = deriveNonce(baseNonce, chunkIdReceived);
console.log(TAG_LENGTH); // 16

API Reference

  • encryptChunks(options: EncryptOptions): Generator<EncodedChunk> — EncryptOptions carries plaintext, fileId, fileKey, baseNonce (24 bytes), chunkSize, serverPrivKey. Yields { rawBytes, metadata } per chunk.
  • deriveNonce(baseNonce: Uint8Array, chunkId: number): Uint8Array — XORs chunkId into bytes 0–3.
  • TAG_LENGTH: 16 — AEAD tag size.

Implementation Notes

encryptChunks writes the signature into the raw buffer at [METADATA_SIZE, HEADER_SIZE) immediately after computing it, so consumers can stream chunks through transports without ever holding a full file plaintext in memory. The XOR-based nonce derivation is sound for chunk indices ≤ 2³² because XChaCha20-Poly1305 takes a 24-byte nonce: under fixed baseNonce no two chunks of the same file ever share a nonce.