FWC-1§10Normative
Conformance & test vectors
The checklist an implementation must satisfy to call itself FWC-1, and byte-exact vectors to prove it.
Encoder requirements
- Writes magic
46 57, version01, reserved flag bits zero. - Sets
FLAG_COMPRESSEDonly when deflate-raw output is strictly shorter. - Applies compression before encryption.
- Uses fresh random 16-byte salt and 12-byte IV per encryption; PBKDF2-SHA-256 × 100 000; AES-256-GCM.
lengthandcrc32describe the final body.- Writes alpha = 255 on every pixel; never stores data in alpha.
- Skips alpha samples in the byte-to-sample walk; row-major from top-left.
- In noise mode, fills unused samples with CSPRNG output.
- In lsb mode, preserves the upper six bits of every sample; MSB-first bit order.
- Emits untagged 8-bit PNG (no gAMA/iCCP/sRGB chunks).
Decoder requirements
- Reads pixels without resampling or colour conversion; ignores alpha.
- Tries modes in the order noise, lsb.
- Rejects unknown version with
unsupportedwithout reading further. - Rejects
length > capacitywithnot-a-container. - Verifies CRC-32 before any decryption or decompression (general-purpose decoders).
- Accepts any valid deflate-raw stream.
- Ignores reserved flag bits.
- Uses exactly the five error codes of §7.
Test vector A — raw, unencrypted
Payload <h1>Hi</h1> (11 bytes). Deflate does not reduce it, so flags = 0x00. This vector is byte-exact and MUST round-trip in every implementation.
container (23 bytes):
46 57 01 00 00 00 00 0b a7 ad b6 8f
3c 68 31 3e 48 69 3c 2f 68 31 3e
noise mode, 16×16 — first 8 pixels (RGBA):
px0 46 57 01 ff px1 00 00 00 ff px2 00 0b a7 ff px3 ad b6 8f ff
px4 3c 68 31 ff px5 3e 48 69 ff px6 3c 2f 68 ff px7 31 3e ?? ff
(?? = random fill begins at sample index 23)Test vector B — compressed (informative)
Payload <!doctype html><title>Hi</title><h1>Hi</h1><p>Hi</p> (52 bytes). With zlib at level 9 the body is 43 bytes and flags = 0x02. Other DEFLATE implementations will produce different bytes; a conforming decoder MUST decode all of them to the same 52-byte payload.
header:
46 57 01 02 00 00 00 2b da 95 49 1f
body (43 bytes, zlib -9):
b3 51 4c c9 4f 2e a9 2c 48 55 c8 28 c9 cd b1 b3
29 c9 2c c9 49 b5 f3 c8 b4 d1 87 b0 6c 32 0c c1
bc 0c 43 3b 9b 02 30 ab c0 0e 00Test vector C — negative cases
| Input | Expected |
|---|---|
Vector A with byte 0 changed to 47 | not-a-container |
Vector A with byte 2 changed to 02 | unsupported |
Vector A with length field 00 00 03 00 in a 16×16 icon | not-a-container (768 > 756) |
Vector A with last body byte changed to 3f | bad-crc |
Vector A with byte 3 changed to 04 (reserved bit) | success — payload "<h1>Hi</h1>" |
| Any encrypted container, password callback returns null | password-required |