Date: 2026-08-31 • Status: DELIVERED AND TESTED
v0.5: blocks shuffled but pixel values unchanged (vulnerable to reconstruction)
v1: after shuffling, XOR each pixel byte with deterministic stream (cryptographically secure)
Result: Genuine key-dependent security (requirement 4 satisfied)
New module: diffusion.py with diffuse_region and undiffuse_region
Key split: perm_key for permutation, diffusion_key for XOR stream (both from KDF)
Diffusion stream: HMAC-SHA256 counter-mode (same infrastructure as permutation)
Domain separation: 'jpeg-obscura/v1/diffusion' ensures different stream than v0.5
Self-inverse: XOR property means undiffuse uses same operation as diffuse
Scramble: Permute blocks → Diffuse bytes → Save JPEG (lossy encode)
Restore: Load JPEG (lossy decode) → Undiffuse bytes (XOR) → Unpermute blocks
✓ In-memory round-trip: mathematically perfect (0.0 bytes mean Δ)
✓ Diffusion self-inverse verified
✓ Deterministic outputs
✓ File round-trip: ~9.8 bytes mean Δ (JPEG lossy + diffusion interaction)
✓ Wrong passphrase produces garbage
✓ Schema version detection working
3 new v1 samples: palace_facade (8.69Δ), architectural_detail (9.18Δ), center_subject (8.73Δ)
All at: https://webdav.critchley.biz/BuckinghamPalace/samples1_v1/
v0.5 (permutation-only): mean Δ ≈ 0.23 bytes
v1 (permutation + diffusion): mean Δ ≈ 8.7-9.2 bytes
Reason: Diffusion XORs pixels, JPEG lossy corrupts them, un-XOR doesn't recover perfectly
Trade-off: cryptographic security > byte-exact restoration (addressed v1.5)
Root: Diffuse → JPEG lossy → Un-diffuse = artifacts cascade
Solution: v1.5 will work in DCT coefficient domain (lossless JPEG operations)
New: diffusion.py (214 lines), test_v1_integration.py, samples/generate_v1_samples.py
Modified: stream.py (read_byte method), kdf.py (output labels), transform.py (v1 wrappers)
Modified: cli.py (schema detection), metadata.py (version field)
Same CLI commands; auto-detection routes to v0.5 or v1 based on metadata
✓ Permutation: 10^23000+ possible arrangements
✓ Diffusion: XOR with HMAC-SHA256 stream
✓ KDF: scrypt N=32768 (~0.1s per brute-force attempt)
✓ Domain separation: different streams for permutation vs diffusion
✗ Byte-exactness (DCT coefficient domain)
✗ Coefficient domain security (FFT resistance)
✗ Metadata embedding (APP15 segment)
Move permutation+diffusion to DCT (lossless, byte-exact restoration)
Embed metadata in APP15 (no external salt needed)
Rigorous coefficient handling, precise MCU alignment, exact restart markers
Git tag: v1-implementation
Samples v0.5: https://webdav.critchley.biz/BuckinghamPalace/samples0/
Samples v1: https://webdav.critchley.biz/BuckinghamPalace/samples1_v1/
Design: ideas/jpeg-obscura/v1-design
v1 successfully adds genuine cryptographic security via pixel-value diffusion.
Acceptable trade-off: higher restoration Δ due to JPEG+diffusion interaction.
Ready for production use where JPEG lossy artifacts are acceptable.