This release replaces the key-derived Hénon map with the hyperchaotic Rössler folded-towel map and whitens the payload before embedding, which changes the stego protocol so images are not interchangeable with earlier versions. It also consolidates the package into a single module, removing the henon and steg submodules, and fixes an import failure on Python 3.12.
Removals
chaosedgesteg.henonsubmodule removed.chaosedgesteg.stegsubmodule removed;adaptive_canny,embed, andextractnow live in the top-level package.shannon_entropyremoved; the key's Shannon entropy no longer feeds the map parameters.henon_paramsremoved; the Hénon map it parameterized is gone.
Compatibility notes
Stego protocol is incompatible with earlier versions
The ordering map and a new whitening step change how bits are placed and encoded, so a stego image produced by v0.1.1 or earlier cannot be extracted by v0.2.0, and images produced by v0.2.0 cannot be read by older versions. Re-embed existing payloads with v0.2.0 to migrate. The reasoning behind the change is under Improvements.
henon_indices renamed to indices_3d
The chaotic-ordering function keeps its (arr, key, count) signature but is renamed and reimplemented on the Rössler folded-towel map.
Keys must be bytes-like
embed, extract, and indices_3d now take key: collections.abc.Buffer instead of an arbitrary hashable sequence, and DEFAULT_KEY is now b"SECRET_PASSWORD". Passing a str key to the library functions no longer works; encode it first. The CLI encodes passwords for you.
New features
CESPASSWORD environment variable
When neither -p/--password nor -P/--passwd-file is given, the CLI now reads the password from the CESPASSWORD environment variable before falling back to the built-in default key. This keeps the password out of the process list and shell history.
Extract to stdout with -O -
extract -O - is now equivalent to extract --stdout. Previously -O - wrote the payload to a file named literally -.
Improvements
Key derivation and payload whitening
The previous scheme derived Hénon map parameters from the Shannon entropy of the key plus two 16-bit hash jitters, which funneled distinct keys into a search space of roughly 2^32 positions, and it embedded the magic bytes (CES, and the payload zip header) in plaintext. An attacker holding the cover image could diff it against the stego image, guess an entropy value, and enumerate parameters until the plaintext magic bytes lined up, recovering the payload without ever needing the key.
v0.2.0 derives initial coordinates from a 192-bit BLAKE2b digest of the key, split into one 64-bit word per axis of the Rössler folded-towel map, a hyperchaotic 3D map with a much larger realized keyspace (around 2^180 at K=80, against roughly 2^62 at K=128 for the prior map). The header and payload are also XORed with a key-derived keystream before embedding, so the magic bytes no longer sit in the carrier as a plaintext oracle.
Fixes
Package imports on Python 3.12
v0.1.1 used type-parameter defaults (for example [_Dim = int]), a Python 3.13 feature, so importing the package on Python 3.12 raised a SyntaxError even though requires-python was >=3.12. The defaults are removed, so the package imports on 3.12 as declared.
Broken pipe when piping stdout output
Run as a module, the CLI now resets SIGPIPE to the default handler, so piping extract --stdout (or -O -) into a command that closes the pipe early, such as head, terminates quietly instead of raising BrokenPipeError.
Changes
Tilde paths are no longer expanded by the program
Path arguments are taken as plain Path values; the CLI no longer calls expanduser() on them. Interactive shells already expand a leading ~, so this is invisible in normal use, but a ~ that reaches the program unexpanded (for example, quoted) is now treated literally.
Full Changelog: v0.1.1...v0.2.0