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

  1. Writes magic 46 57, version 01, reserved flag bits zero.
  2. Sets FLAG_COMPRESSED only when deflate-raw output is strictly shorter.
  3. Applies compression before encryption.
  4. Uses fresh random 16-byte salt and 12-byte IV per encryption; PBKDF2-SHA-256 × 100 000; AES-256-GCM.
  5. length and crc32 describe the final body.
  6. Writes alpha = 255 on every pixel; never stores data in alpha.
  7. Skips alpha samples in the byte-to-sample walk; row-major from top-left.
  8. In noise mode, fills unused samples with CSPRNG output.
  9. In lsb mode, preserves the upper six bits of every sample; MSB-first bit order.
  10. Emits untagged 8-bit PNG (no gAMA/iCCP/sRGB chunks).

Decoder requirements

  1. Reads pixels without resampling or colour conversion; ignores alpha.
  2. Tries modes in the order noise, lsb.
  3. Rejects unknown version with unsupported without reading further.
  4. Rejects length > capacity with not-a-container.
  5. Verifies CRC-32 before any decryption or decompression (general-purpose decoders).
  6. Accepts any valid deflate-raw stream.
  7. Ignores reserved flag bits.
  8. 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 00

Test vector C — negative cases

InputExpected
Vector A with byte 0 changed to 47not-a-container
Vector A with byte 2 changed to 02unsupported
Vector A with length field 00 00 03 00 in a 16×16 iconnot-a-container (768 > 756)
Vector A with last body byte changed to 3fbad-crc
Vector A with byte 3 changed to 04 (reserved bit)success — payload "<h1>Hi</h1>"
Any encrypted container, password callback returns nullpassword-required