ZXC

Asymmetric lossless compression, built for ultra-fast decode

ZXC: Lossless compression built for ultra-fast decode

ZXC is a lossless data compression library written in C, distributed as libzxc. It is designed for data that is compressed once and read many times: firmware images, game assets, application bundles, and content delivered to many devices. The encoder spends extra time up front so that decompression runs at several gigabytes per second on ARM and x86. At every compression level ZXC decodes faster than LZ4, and produces output of equal or smaller size.

ZXC is free software, released under the BSD 3-Clause License. It has no dependencies, and official bindings exist for Rust, Python, Node.js and Go.

Development happens on GitHub.

The current release is ZXC 0.15.0, released on 2026-10-13. See the changelog for what changed, and Downloading ZXC below.

Decompression speed against codecs of similar size

Processor:
Fast61.76 % of original
zxc -113,513 MB/s
lz4 --fast -175,609 MB/s
2.41× faster decode, smaller output (61.76 % vs 62.15 %)
Default46.65 % of original
zxc -39,707 MB/s
lz44,774 MB/s
2.03× faster decode, smaller output (46.65 % vs 47.60 %)
High36.28 % of original
zxc -66,884 MB/s
lz4hc -94,522 MB/s
1.52× faster decode, smaller output (36.28 % vs 36.75 %)
Ultra33.09 % of original
zxc -75,054 MB/s
zstd -11,803 MB/s
2.80× faster decode, smaller output (33.09 % vs 34.53 %)
Figure 1. Single-threaded decompression of silesia.tar (211.9 MB), measured with lzbench 2.4.1 and zxc 0.15.0. ZXC levels 1, 3, 6 and 7 are each compared with the codec that produces output of similar size. Apple M2, macOS 26, Clang 21, -march=native. Full results are in the benchmark tables.

Specifications

ParameterValueNotes
Compression levels1 to 7Default 3
Block size4 KB to 2 MB, powers of twoDefault 512 KB; 256 KB for streaming
Decompression context≈ 512 KBAt the default block size
Compression context≈ 1.78 MB≈ 1.03 MB with 256 KB blocks
In-place decompression margin≈ 1 % of the archiveUse zxc_decompress_inplace_bound()
Random accessO(1) per blockRequires a seek table (-S)
IntegrityOptional per-block checksumrapidhash
DictionariesExternal .zxd fileReferenced by a 32-bit ID
ThreadingMulti-threaded streamingThread count detected automatically
Architecturesx86_64, ARM64, ARMv7, ARMv6, RISC-V, POWER, s390x, i386Tested in CI
Wire formatVersion 9Specification
Library namelibzxcpkg-config libzxc; CMake zxc::zxc_lib; Debian libzxc-dev
Language, dependenciesC17, noneBindings for Rust, Python, Node.js, Go
LicenseBSD 3-Clause

Why ZXC?

LZ4 is symmetric: it compresses about as fast as it decompresses. That suits logs and swap, but not data that is shipped. A firmware image is compressed once on a build server and decompressed on every device that installs it, so time saved during compression helps nobody.

ZXC moves the work to the encoder. Match selection, optimal parsing and statistics tuning are done once, and the bitstream is laid out for the pipelines and branch predictors of modern processors. The decoder stays short, has few branches, and uses SIMD where it is available.

Typical uses:

Features

Compression levels

Seven levels trade compression time for size. Decompression stays in the multi-GB/s range at every level. Level 3 is the default.

LevelNameSuited forSize %Decode MB/sEncode MB/s
1FastestReal-time assets, games, UI61.7613,513886
2FastReal-time assets, games, UI53.8611,320588
3DefaultGeneral use; smaller and faster to decode than LZ446.659,707267
4BalancedGeneral use, a little denser43.438,790194
5CompactEmbedded and firmware40.838,118114
6DensityArchives and read-mostly data; beats LZ4HC on both axes36.286,88414.5
7UltraWhen size dominates; smaller than zstd -1, decodes about 2× faster33.095,0549.71

Size is the compressed size as a percentage of silesia.tar. Speeds are single-threaded on Apple M2 with lzbench 2.4.1. Blocks are 512 KB by default; use -B 256K for streaming or memory-constrained targets.

Benchmarks

ZXC is included in the two main open-source compression benchmark suites, lzbench and TurboBench, so the figures below can be reproduced with either tool alongside more than 70 other codecs. Benchmarks also run on every commit on x86_64 and ARM64 machines; see the latest results.

Compression ratio against decompression speed for ZXC, LZ4, Zstandard, LZAV, Snappy and zlib, with the Pareto frontier, one panel per processor: Apple M2, Google Axion, AMD EPYC 9B45 and AMD EPYC 7B13. Every ZXC level sits on the frontier.
Figure 2. Compression ratio of silesia.tar against single-threaded decompression speed (logarithmic scale), on two ARM64 and two x86_64 processors; up and to the right is better. From the whitepaper.

The decoder's speed is paid for at compression time, and on this axis LZ4 and Zstandard are ahead. Levels 1 and 2 still compress at several hundred MB/s; levels 6 and 7 run at about 10 MB/s, slower than lz4hc -9, and are meant for data that is compressed once and read many times.

Compression ratio against compression speed, on a logarithmic scale, for ZXC, LZ4, Zstandard, LZAV, Snappy and zlib, with the Pareto frontier, one panel per processor: Apple M2, Google Axion, AMD EPYC 9B45 and AMD EPYC 7B13.
Figure 3. Compression ratio of silesia.tar against single-threaded compression speed (logarithmic scale), on the same four processors; up and to the right is better. From the whitepaper.

Raw decode speed leaves out half of the picture. When the data comes from a disk, a network or another core, the link limits how fast it arrives. With transfer and decoding overlapped, a reader gets min(decode speed, bandwidth / ratio) of original data per second. Below 0.4 to 0.6 GB/s the ratio decides, and Zstandard is ahead. From there until one decoding thread can no longer keep up with the link, a ZXC level delivers the most data, and no LZ4 level is ever ahead of it.

Speed-up over sending the data uncompressed as a function of link bandwidth, for the best level of ZXC, LZ4 and Zstandard, on Apple M2, Google Axion, AMD EPYC 9B45 and AMD EPYC 7B13. Zstandard leads below about 0.5 GB/s, ZXC above, and the LZ4 curve never rises above the ZXC curve.
Figure 4. Speed-up over sending silesia.tar uncompressed, against link bandwidth (logarithmic scale), with each codec at its best level for the link and one decoding thread, on the same four processors; higher is better, and 1× is the uncompressed transfer. From the whitepaper.

Dividing the clock frequency by the decompression speed gives the cost of each decompressed byte in processor cycles, which compares processors running at different frequencies. ZXC spends less than one cycle per byte at every level.

Processor cycles per decompressed byte for every ZXC level and for memcpy, LZ4, LZ4HC, LZAV, Snappy and Zstandard, on Apple M2, Google Axion, AMD EPYC 9B45 and AMD EPYC 7B13.
Figure 5. Processor cycles per decompressed byte (clock frequency / decompression speed), on the same four processors; lower is better. From the whitepaper.
Apple M2 (ARM64)

Apple M2, macOS 26, Clang 21, -march=native. Single thread, lzbench 2.4.1, silesia.tar. Speeds in MB/s; size as a percentage of the input.

Codec and levelCompressionDecompressionSize %
zxc -188613,51361.76
zxc -258811,32053.86
zxc -32679,70746.65
zxc -41948,79043.43
zxc -51148,11840.83
zxc -614.56,88436.28
zxc -79.715,05433.09
lz48144,77447.60
lz4 --fast -171,3475,60962.15
lz4hc -948.44,52236.75
lzav -16863,87639.91
snappy6613,25847.85
zstd --fast --17232,53841.01
zstd -16451,80334.53
zstd -33751,68031.20
zlib -113537836.45
Google Axion (ARM64)

Google Axion (Neoverse V2), GCP C4A, GCC 14.4, -march=native. Single thread, lzbench 2.4.1, silesia.tar. Speeds in MB/s; size as a percentage of the input.

Codec and levelCompressionDecompressionSize %
zxc -18859,56461.76
zxc -25937,89553.86
zxc -32566,57146.65
zxc -41866,10543.43
zxc -51095,68340.83
zxc -613.54,95036.28
zxc -78.823,56333.09
lz47304,25847.60
lz4 --fast -171,2784,95462.15
lz4hc -943.23,85036.75
lzav -15762,94939.91
snappy5662,29547.85
zstd --fast --13022,29141.01
zstd -15231,64234.53
zstd -33291,52531.20
zlib -111538936.45
AMD EPYC 9B45 (x86_64)

AMD EPYC 9B45 (Zen 5), GCP C4D, GCC 14.4, -march=native. Single thread, lzbench 2.4.1, silesia.tar. Speeds in MB/s; size as a percentage of the input.

Codec and levelCompressionDecompressionSize %
zxc -186811,60961.76
zxc -258510,33253.86
zxc -32538,33546.65
zxc -41837,50843.43
zxc -51107,01440.83
zxc -615.36,04536.28
zxc -710.24,72433.09
lz47665,05247.60
lz4 --fast -171,2845,30562.15
lz4hc -945.44,86136.75
lzav -16993,60339.91
snappy5642,42047.89
zstd --fast --16642,45141.01
zstd -16061,89834.53
zstd -33691,73331.20
zlib -113439236.45
AMD EPYC 7B13 (x86_64)

AMD EPYC 7B13 (Zen 3), GCP C2D, GCC 14.4, -march=native. Single thread, lzbench 2.4.1, silesia.tar. Speeds in MB/s; size as a percentage of the input.

Codec and levelCompressionDecompressionSize %
zxc -17248,15561.76
zxc -24816,80753.86
zxc -32145,25246.65
zxc -41574,95243.43
zxc -593.34,77940.83
zxc -611.94,29036.28
zxc -77.973,18833.09
lz46383,88347.60
lz4 --fast -171,1084,48562.15
lz4hc -937.13,73136.75
lzav -14592,95539.91
snappy5071,83747.89
zstd --fast --14861,78441.01
zstd -14441,33934.53
zstd -32321,17831.20
zlib -110635836.45

Downloading ZXC

Source and binary archives for Linux, macOS and Windows are published on the releases page. Each archive carries SLSA build provenance, which you can check with:

gh attestation verify zxc-0.15.0-linux-x86_64.tar.gz --repo hellobertrand/zxc

ZXC is also packaged by distributions and package managers:

Debian and Ubuntu
sudo apt install zxc libzxc-dev
Homebrew
brew install zxc
vcpkg
vcpkg install zxc
Conan
conan install -r conancenter --requires="zxc/[*]" --build=missing
Winget
winget install hellobertrand.zxc

Which version each distribution currently ships is tracked by Repology:

Packaging status of ZXC across distributions and package managers, from Repology.

To build from source you need CMake 3.14 or later and a C17 compiler (GCC, Clang or MSVC):

git clone https://github.com/hellobertrand/zxc.git
cd zxc
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
sudo cmake --install build

The installation provides CMake (find_package(zxc), target zxc::zxc_lib) and pkg-config (libzxc) files. Meson users can include ZXC as a subproject; see the integration guide.

Quick start

The zxc command reads and writes files or pipes, and can be used as a compressor by tar:

# Compress (level 3 by default), then decompress
zxc -5 assets.tar assets.tar.zxc
zxc -d assets.tar.zxc assets.tar

# Seekable archive, for random access
zxc -S big.bin big.bin.zxc

# As a compressor for tar
tar -I 'zxc -5' -cf data.tar.zxc data/

# Measure speed on your own machine
zxc -b input_file

From C, the buffer interface compresses and decompresses in one call each:

#include "zxc.h"

uint64_t bound = zxc_compress_bound(src_size);
zxc_compress_opts_t c = {
    .level            = ZXC_LEVEL_DEFAULT,
    .checksum_enabled = 1,
};
int64_t csize = zxc_compress(src, src_size, dst, bound, &c);

zxc_decompress_opts_t d = { .checksum_enabled = 1 };
int64_t n = zxc_decompress(dst, csize, out, out_cap, &d);
if (n < 0)
    fprintf(stderr, "zxc: %s\n", zxc_error_name((int)n));

See the examples for the streaming, context, seekable and dictionary interfaces, the API reference for every function, and the manual page for all command options.

Language bindings

The official bindings are maintained in the main repository and released with the library. They are published as zxc-compress, because the name zxc is taken on some registries.

LanguageInstallationPackage
Rustcargo add zxc-compresscrates.io
Pythonpip install zxc-compressPyPI
Node.jsnpm install zxc-compressnpm
Gogo get github.com/hellobertrand/zxc/wrappers/gosource
WebAssemblybuild with Emscriptensource

Bindings maintained by others: go-zxc (Go), zxc-nim (Nim), and a Free Pascal port.

Testing

Getting help and contributing

Questions and ideas are welcome in GitHub Discussions. Please report bugs on the issue tracker, and security problems privately as described in the security policy.

Contributions are welcome; read the contribution guidelines first. You can also support the project through GitHub Sponsors.