Zani
2026Active

Zani

Nasm image-processing C-lang privacy-tools Assembly

Zero Attributes, No Information.

Metadata stripper for images and audio. Removes EXIF, GPS coordinates, timestamps, software tags, and generation parameters at the binary level. No dependencies.

Written in x86-64 assembly (NASM) with a minimal C entry point.

Usage

zani <FILES...>             # strip metadata (in-place)
zani -b <FILES...>          # strip with .bak backup
zani <FILES...> -o <DIR>    # strip metadata (output to DIR)
zani -i <FILES...>          # inspect metadata only
zani -v                     # version

Wildcards work as expected:

zani *.png *.jpg

Supported Formats

FormatStrategyStatus
PNGstrip
JPEGstrip
GIFstrip
WAVstripplanned
FLACstripplanned
WebPstripplanned

strip removes metadata chunks entirely and rewrites the file.

See docs/formats.md for details on what metadata is removed from each format.

What Gets Removed

  • EXIF data (camera model, lens, serial number)
  • GPS coordinates and altitude
  • Timestamps (creation, modification, capture)
  • Software and encoder identification
  • AI generation parameters (Stable Diffusion, ComfyUI, etc.)
  • Color profiles and ICC data
  • Embedded comments and XMP
  • Photoshop / Lightroom resource blocks

Architecture

main.c (C)              argc/argv parsing, glob expansion
  |
  | zani_process()
  v
zani.asm                magic byte detection, format dispatch
  |
  +---> fmt/png.asm     chunk walker, metadata filter, CRC32
  +---> fmt/jpeg.asm    marker walker, scan data passthrough
  +---> fmt/gif.asm     extension block filter
  +---> fmt/wav.asm     RIFF chunk filter
  +---> fmt/flac.asm    metadata block filter
  +---> ...
  |
  +---> core/mmap.asm   mmap file mapping, zero wipe
  +---> core/scan.asm   AVX2/SSE2 byte scanner
  +---> core/crc32.asm  SSE4.2 hardware / software CRC32
  +---> core/detect.asm branchless lookup tables
  +---> core/backup.asm sendfile copy (.bak creation)
  +---> core/io.asm     syscall wrappers, endian conversion

The C layer handles argument parsing only. Everything that touches file data is hand-written x86-64 assembly.

Why Assembly

This is a privacy tool. The design priorities are:

  1. Auditability -- every byte of the binary is accounted for.
  2. Zero dependencies -- no libc in the hot path, no runtime, no allocator.
  3. Performance -- not because metadata stripping needs to be fast, but because the techniques that make it auditable also make it fast.

Run make bench to measure hot-path throughput on your hardware.

Build

Requires nasm and gcc on Linux x86-64.

make            # standard build
make debug      # debug symbols, no optimization
make release    # -O3
make test       # run test suite
make size       # print binary size breakdown

See docs/build.md for project structure and adding new formats.

Design Decisions

Strip vs. Wipe -- Formats like PNG and JPEG have self-contained chunks with no cross-references. Removing a chunk doesn't affect anything else. Formats like MP4 store absolute byte offsets to media data (stco/co64 atoms). Deleting metadata shifts those offsets and breaks playback. Zero-filling preserves all offsets while destroying the metadata content.

mmap over read/write -- A 10 MB JPEG processed with buffered I/O requires thousands of syscalls. Memory mapping reduces this to three: mmap, msync, munmap. For the wipe strategy this is especially effective since we modify memory directly without copying.

Runtime CPU detection -- CPUID is checked once at startup. AVX2-capable machines get 32-byte SIMD paths. Older machines fall back to SSE2 (16 bytes) automatically. Same binary runs everywhere.

CRC32 hardware acceleration -- PNG requires CRC32 for every chunk. SSE4.2 provides a dedicated crc32 instruction that processes 8 bytes per cycle. Machines without it use a 256-entry lookup table.

License

CC0 1.0 Universal. Public domain.