# sign-chunk ## Purpose Signs a chunk under the server's Ed25519 private key. Signatures cover the full encoded chunk (metadata header bytes plus the encrypted payload) so receivers can verify integrity without first decrypting. The output is fixed at 64 bytes, which is the slot reserved by `header.ts` (`SIG_SIZE = 64`). ## Features - `signChunk(chunk, privKey): Uint8Array` — produces a deterministic Ed25519 signature over `metadata || ciphertext`. - `buildSignedChunk(chunk, privKey): Chunk` — convenience wrapper that returns a chunk with the freshly-computed signature inlined. - Pure function — no global state, no side effects, deterministic for fixed inputs (Ed25519 with seeded keys). ## Usage: Basic Example ```ts import { randomPrivateKey } from "@suaveplan/crypto-curve/ed25519"; import { signChunk } from "@suaveplan/drive-plugin-chunks"; const privKey = randomPrivateKey(); const chunk = { metadata: { /* ChunkMetadata */ } as never, sig: new Uint8Array(64), ciphertext: new Uint8Array([1, 2, 3]), }; const sig = signChunk(chunk, privKey); ``` ## Usage: Advanced Example ```ts import { buildSignedChunk, parseChunk, verifyChunkSig, } from "@suaveplan/drive-plugin-chunks"; const signed = buildSignedChunk(parseChunk(rawChunk), serverPriv); verifyChunkSig(/* raw bytes containing signed.sig */, serverPub); ``` ## API Reference - `signChunk(chunk: Chunk, privKey: Uint8Array): Uint8Array` — returns 64-byte signature. Concatenates `encodeHeader(metadata)` and `chunk.ciphertext` then signs the concatenation. - `buildSignedChunk(chunk: Chunk, privKey: Uint8Array): Chunk` — same chunk with a populated `sig` field. ## Implementation Notes The signature input deliberately excludes the existing `chunk.sig` field — re-signing a chunk produces the same signature for fixed inputs even though Ed25519 is not strictly deterministic across implementations (suaveplan pins to `@noble/curves` which is RFC-8032 deterministic). Verification is implemented in `verify-chunk.ts` using the matching `getPublicKey` derivation. The signed payload is `encodeHeader(metadata) || ciphertext` rather than the full raw chunk because the signature occupies a fixed slot inside the raw bytes; including it in the signing input would be circular. This split also lets transports verify a chunk in two passes: parse the metadata to learn `payloadLen`, then sign-verify a contiguous range of the buffer without copying. Signing happens at ingest time and is the only place the `serverPrivKey` ever leaves the plugin's option object — verification only needs the public key.