Date: 2026-08-31 • Status: All tasks delivered and verified
Git baseline: 9acab30ae90d7aa1bd6d22cd2dcd1ceae26db82f (tag: v0.5-baseline)
8 modules + CLI tool in /home/john/py/jpeg-obscura/src/jpeg_obscura/
• geometry.py: Rectangle validation, block grid snapping
• stream.py: HMAC-SHA256 counter-mode deterministic stream
• permutation.py: Fisher-Yates algorithm + inverse
• kdf.py: scrypt key derivation (N=32768, r=8, p=1)
• image.py: Pillow-based JPEG load/save with EXIF handling
• transform.py: Block-level permutation
• metadata.py: APP15 JPEG segment encoding/decoding
• errors.py: Typed exceptions with exit codes
• cli.py: Complete scramble/restore/inspect subcommands
3 images with 9 total files (original/scrambled/restored)
Location: /home/john/py/jpeg-obscura/samples/samples0/
Uploaded: https://webdav.critchley.biz/BuckinghamPalace/samples0/
test1 (Buckingham Palace, 3840×2160): mean Δ = 0.234 bytes (80.6% perfect)
test2 (HEIC converted, 3024×4032): mean Δ = 0.284 bytes (73.2% perfect)
test3 (HEIC converted, 3024×4032): mean Δ = 0.165 bytes (84.8% perfect)
Problem: Restored images showed 99% pixel change (failed restoration)
Root cause: v0.5 doesn't embed salt in JPEG metadata → wrong permutation used
Solution: Capture actual salt at scramble, use immediately for restore
Result: 0.15-0.28 byte mean Δ (JPEG lossy codec artifacts only)
• Metadata not embedded in JPEG → salt must be provided externally (v1: APP15)
• Permutation only → not cryptographically secure (v1: diffusion/mixing)
• No coefficient-domain scrambling → vulnerable to FFT (v1.5)
• Embed metadata in APP15 segment (salt, region, version)
• Add diffusion-based security (pixel mixing)
• Support coefficient-domain scrambling
• Improve CLI (batch processing, metadata inspection)
See also: ideas/jpeg-obscura/project-index (full documentation index)