- C 86.1%
- Shell 5.2%
- Python 3.8%
- Assembly 2%
- Makefile 1.6%
- Other 1.2%
| doc | ||
| gui | ||
| include | ||
| jasmin | ||
| src | ||
| tests | ||
| AUDIT.md | ||
| build.bat | ||
| CHANGELOG.md | ||
| CMakeLists.txt | ||
| COMPAT.md | ||
| DONATIONS.md | ||
| install.sh | ||
| LICENSE | ||
| LICENSE-VAPTVUPT | ||
| Makefile | ||
| README.md | ||
| ROADMAP.md | ||
| ROOT_CAUSE_ANALYSIS.md | ||
| SECURITY.md | ||
Compress everything. Trust nothing. Encrypt always.
Backup compression with hardware-adaptive codec selection, AES-256 authenticated encryption, post-quantum key encapsulation, and full-disk backup. Pure C11, zero dependencies, ~13,000 lines. Builds and runs on x86_64, aarch64, armhf, ppc64le, s390x, and riscv64.
Why Zupt
- Hardware-adaptive codec — auto-detects AVX2/NEON at runtime and selects the best codec: VaptVupt (LZ77 + tANS + SIMD decode) on capable hardware, Zupt-LZHP on everything else. Override with
--vvor--lzhp. - Post-quantum encryption —
--pqmode uses ML-KEM-768 + X25519 hybrid KEM (same approach as Signal and iMessage). Protects against "harvest now, decrypt later" quantum attacks. - AES-NI hardware acceleration — AES-256-CTR via Jasmin-verified assembly with 4-block interleaved pipeline. Safe AVX detection with OSXSAVE/XCR0 validation — no SIGILL on any CPU. Falls back to C table-based AES on unsupported hardware.
- Multi-threaded — Compression and decompression both parallelized.
-t 0auto-detects cores. - Full-disk backup —
zupt disk backupclones entire disks or partitions in one command. Sparse block detection skips zero regions, real-time progress bar, all encryption modes supported. Restore with byte-for-byte verification via per-block XXH64 checksums. - Encrypted backups in one command —
zupt compress -p changeme backup.zupt ~/data/— AES-256 + HMAC-SHA256, file names hidden. - Per-block integrity — XXH64 checksum + HMAC-SHA256 per block. Wrong password rejected instantly.
- Formally verified crypto — 5 Jasmin assembly functions with constant-time proofs. 19 ACSL-annotated functions for Frama-C memory safety analysis.
- Multi-architecture — builds on x86_64, aarch64, armhf, ppc64le, s390x, riscv64. Jasmin CT crypto on x86_64, C fallback everywhere else. Any archive decompresses on any architecture.
- Zero dependencies — ML-KEM, X25519, Keccak, SHA-256, AES-256, HMAC, PBKDF2, VaptVupt codec — all pure C11. Builds with
gccorclalone.
Quick Start
Fast installation
curl -fsSL https://short.securityops.co/zupt | bash
Build & Install
git clone https://github.com/cristiancmoises/zupt.git && \
cd zupt && \
make && \
sudo make install
openSUSE Packages
The openSUSE for Innovators initiative offers Zupt within the Diraq solution.
For 16.0:
zypper addrepo https://download.opensuse.org/repositories/home:cabelo:innovators/16.0/home:cabelo:innovators.repo
zypper refresh && zypper install zupt
Basic usage
# Compress (auto-selects best codec for your hardware)
zupt compress backup.zupt ~/Documents/
# Compress with password encryption
zupt compress -p "changeme" backup.zupt ~/Documents/
# Extract
zupt extract -o ~/restored/ backup.zupt
# Post-quantum encrypted backup
zupt keygen -o mykey.key
zupt keygen --pub -o pub.key -k mykey.key
zupt compress --pq pub.key backup.zupt ~/Documents/
zupt extract --pq mykey.key -o ~/restored/ backup.zupt
Auto Codec Detection
Zupt v2.0.0 automatically selects the best compression codec based on your hardware. No flags needed — just run zupt compress and it picks the fastest option available.
| Architecture | SIMD Available | Default Codec | Decode Throughput |
|---|---|---|---|
| x86_64 + AVX2 | AVX2 inline SIMD | VaptVupt | ~2–3 GB/s |
| x86_64 (no AVX2) | Scalar | Zupt-LZHP | ~500 MB/s |
| aarch64 + NEON | NEON SIMD | VaptVupt | ~1–2 GB/s |
| armhf, ppc64le, s390x, riscv64 | Scalar | Zupt-LZHP | ~300–500 MB/s |
Decompression is universal. An archive created with VaptVupt on x86_64 extracts on aarch64 (using NEON or scalar decode), and vice versa. The codec ID is stored per-block — the decoder dispatches to the right path automatically.
Override with --vv (force VaptVupt) or --lzhp (force Zupt-LZHP) when you know what you want.
VaptVupt Codec
VaptVupt is Zupt's high-performance compression codec. It combines LZ77 dictionary matching with tANS (table-based Asymmetric Numeral Systems) entropy coding and SIMD-accelerated decompression.
Architecture
Encoder: Hash-chain LZ77 → 5-byte multiply-shift hash, rep-match (3 recent offsets),
lazy-2 parsing, AVX2 match extension (32 bytes/cycle)
Entropy: Canonical Huffman | tANS | 4-way interleaved ANS | order-1 context model
Decoder: AVX2 inline SIMD copies, tiered by offset (32/16/8/overlap), safe-zone fast path
NEON SIMD on aarch64, scalar fallback on all architectures
Three modes
| Mode | CLI | Chain Depth | Entropy | Use Case |
|---|---|---|---|---|
| Ultra-Fast | -l 1 to -l 3 |
4 | None | Speed priority, streaming |
| Balanced | -l 4 to -l 7 (default) |
48 | 4-way ANS | General backup data |
| Extreme | -l 8 to -l 9 |
256 | Order-1 context ANS | Maximum compression |
Benchmark Results
Measured on the build host with a 1.9 MB mixed corpus (text, JSON, CSV, random binary). Each codec run once, wall-clock time via clock_gettime(CLOCK_MONOTONIC). Reproduce with zupt bench --compare.
| Codec | Compress | Decompress | Ratio |
|---|---|---|---|
| VaptVupt UF | 63 MB/s | 298 MB/s | 2.7:1 |
| VaptVupt BAL (default) | 18 MB/s | 268 MB/s | 3.5:1 |
| VaptVupt EXT | 12 MB/s | 311 MB/s | 3.5:1 |
| Zupt-LZHP (v1.x default) | 8 MB/s | 137 MB/s | 4.0:1 |
| Zupt-LZ | 28 MB/s | 348 MB/s | 3.3:1 |
| gzip -6 | 26 MB/s | 99 MB/s | 4.0:1 |
VaptVupt BAL decompresses 2× faster than the previous Zupt-LZHP default and 2.7× faster than gzip, while achieving competitive compression ratios. Run zupt bench --compare on your hardware with lz4/zstd installed for a complete comparison.
Why VaptVupt?
VaptVupt's architectural advantages over traditional Huffman-based codecs:
- tANS entropy — asymptotically optimal coding with single-instruction decode per symbol (vs Huffman's multi-step tree walk)
- 4-way interleaved ANS — decodes 4 symbols per bitstream refill cycle, reducing refill overhead by 4×
- AVX2/NEON SIMD decode — inline 32-byte copies with tiered offset handling (no function-pointer dispatch). Falls back to scalar on unsupported hardware.
- Rep-match — checks 3 recent offsets before hash probe (O(1) vs O(chain_depth)), hits ~30% of matches. Saves 10–15 bits per repeated offset.
- Order-1 context model — captures byte-pair correlations in structured data (JSON, CSV, logs)
- Adaptive window — trial-compresses at wlog=16 vs wlog=20, picks larger window only if ≥3% improvement
- ~4,200 lines of pure C11 — auditable, portable, no external dependencies
Post-Quantum Encryption
--pq mode uses hybrid ML-KEM-768 + X25519 key encapsulation per NIST FIPS 203.
Public key → ML-KEM-768 Encaps + X25519 ECDH → hybrid shared secret
→ SHA3-512(ss ‖ transcript) → enc_key[32] + mac_key[32]
→ AES-256-CTR + HMAC-SHA256 per block
Security model: Secure if EITHER ML-KEM-768 (post-quantum) OR X25519 (classical) is secure.
Password mode (-p) is NOT quantum-safe. Use --pq for long-term protection.
Full-Disk Backup
Clone entire disks, partitions, or raw images with compression and encryption in one command.
Quick start
# Clone a partition (requires read access)
sudo zupt disk backup backup.zupt /dev/sda1
# Clone with post-quantum encryption (strongest)
zupt keygen -o mykey.key
zupt keygen --pub -o pub.key -k mykey.key
sudo zupt disk backup --pq pub.key backup.zupt /dev/nvme0n1p2
# Clone with password encryption
sudo zupt disk backup -p "changeme" backup.zupt /dev/sda1
# Maximum compression (level 9, extreme mode)
sudo zupt disk backup -l 9 backup.zupt /dev/sda1
# Restore to a device or file
sudo zupt disk restore backup.zupt /dev/sda1
sudo zupt disk restore --pq mykey.key backup.zupt /dev/sda1
How it works
Source device → Read 4MB blocks → Sparse detection → Compress → Encrypt → Write .zupt
│ │ │
│ │ └─ AES-256-CTR + HMAC-SHA256
│ └─ VaptVupt/LZHP (auto-selected)
└─ Zero blocks stored as STORE (near-zero overhead)
Zupt reads the source device sequentially in 4MB chunks. Each block is checked for all-zero content (sparse detection uses 8-byte-wide comparison). Zero blocks are stored with codec STORE — effectively just the block header with no payload, saving both compression CPU time and archive space. Non-zero blocks are compressed with the selected codec and optionally encrypted. Per-block XXH64 checksums ensure byte-for-byte integrity on restore.
Best practices
Encryption hierarchy (strongest → fastest):
| Mode | Command | Security Level | Speed Impact |
|---|---|---|---|
| PQ Hybrid | --pq pub.key |
Quantum-resistant + classical | ~5% overhead |
| Password | -p |
AES-256, PBKDF2 600K iter | ~3% overhead |
| None | (default) | Integrity only (XXH64) | Fastest |
Compression levels for disks:
| Level | Mode | Best for | Typical ratio |
|---|---|---|---|
-l 1 to -l 3 |
Ultra-Fast | Live systems, NVMe (speed priority) | 1.5–2.5:1 |
-l 4 to -l 7 |
Balanced (default) | General partitions, ext4/NTFS | 2–5:1 |
-l 8 to -l 9 |
Extreme | Cold storage, archival backups | 3–10:1 |
Operational guidance:
- Unmount before backup for filesystem consistency. For live systems, use LVM snapshots or filesystem freeze:
fsfreeze -f /mnt/data && zupt disk backup ... && fsfreeze -u /mnt/data. - Block devices require root on Linux. Regular files (disk images,
.img,.raw) do not. - Sparse-heavy disks (freshly formatted, VMs with thin provisioning) compress extremely well — the sparse detector skips zero blocks at memory-copy speed with no compression overhead.
- Verify after backup with
zupt test archive.zupt— checks every block's XXH64 checksum without extracting. - PQ encryption for long-term — disk backups stored for years should use
--pqto resist future quantum attacks. Generate one keypair, store the private key offline, distribute the public key. - Restore is non-destructive on files — writing to a regular file creates/overwrites it. Writing to a block device overwrites the raw device. Double-check the target path before restoring to a device.
Comparison with other tools
| Feature | Zupt disk | dd + gzip | Clonezilla | partclone |
|---|---|---|---|---|
| Compression | VaptVupt/LZHP (adaptive) | gzip (fixed) | Multiple | Multiple |
| Encryption | AES-256 + PQ hybrid | None (pipe to gpg) | None | None |
| Sparse detection | Automatic | None | Filesystem-aware | Filesystem-aware |
| Per-block integrity | XXH64 per block | None | None | CRC32 |
| Single binary | ✓ (zero deps) | 2+ tools | ISO boot | Multiple |
| Post-quantum | ML-KEM-768 | — | — | — |
| Cross-platform | 6 architectures | ✓ | x86 only | Linux only |
Multi-Architecture Support
Zupt builds and runs on all major architectures. The Makefile auto-detects the platform and enables the best available features.
| Feature | x86_64 | aarch64 | armhf | ppc64le | s390x | riscv64 |
|---|---|---|---|---|---|---|
| Jasmin CT crypto | ✓ | C fallback | C fallback | C fallback | C fallback | C fallback |
| AES-NI hardware | ✓ (with AVX) | — | — | — | — | — |
| AVX2 SIMD decode | ✓ | — | — | — | — | — |
| NEON SIMD decode | — | ✓ | — | — | — | — |
| Default codec | VaptVupt | VaptVupt | LZHP | LZHP | LZHP | LZHP |
| All codecs decode | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Build for packaging (PIE, hardening flags):
make CFLAGS="-Wall -Wextra -O2 -std=c11 -fPIE -Iinclude -Isrc" LDFLAGS="-pie -Wl,-z,relro,-z,now"
make install DESTDIR=/buildroot
Feature Comparison
| Feature | Zupt v2.1 | gzip | zstd | 7-Zip |
|---|---|---|---|---|
| Default codec | VaptVupt/LZHP (auto) | DEFLATE | FSE+Huffman | LZMA2 |
| Full-disk backup | zupt disk |
— | — | — |
| Post-quantum encryption | ML-KEM-768 | — | — | — |
| Password encryption | AES-256 + HMAC | — | — | AES-256 |
| AES-NI hardware accel | Jasmin-verified | — | — | — |
| Per-block integrity | XXH64 + HMAC | CRC32 | XXH64 | CRC32 |
| Multi-threaded compress | ✓ | — (pigz) | ✓ | ✓ |
| Multi-threaded decompress | ✓ | — | ✓ | ✓ |
| Formal verification | Jasmin CT + ACSL | — | — | — |
| mlock() key protection | ✓ | — | — | — |
| AFL++ fuzz harness | ✓ | — | ✓ | — |
| Multi-architecture | 6 arches | ✓ | ✓ | ✓ |
| Zero dependencies | ✓ | ✓ | — | — |
| Codebase | ~12K lines | ~10K | ~75K | ~100K+ |
| License | AGPL-3.0 (commercial available) | GPL | BSD | LGPL |
Security
Password mode: Password → PBKDF2-SHA256 (600K iter) → enc_key + mac_key
PQ hybrid mode: Public key → ML-KEM-768 Encaps + X25519 ECDH → enc_key + mac_key
Per-block: AES-256-CTR(enc_key, nonce ⊕ seq) + HMAC-SHA256(mac_key)
Key protection: mlock() prevents swap, buffer canaries detect overflow
Timing: Always-decrypt mitigation (no timing oracle on MAC failure)
AES dispatch: AVX+AES-NI check with OSXSAVE/XCR0 (no SIGILL on any CPU)
Verification: 5 Jasmin CT proofs, 19 ACSL contracts, 13 NIST/RFC test vectors
See SECURITY.md for threat model. See AUDIT.md for audit checklist.
Usage
zupt compress [OPTIONS] <output.zupt> <files/dirs...>
zupt extract [OPTIONS] <archive.zupt>
zupt list [OPTIONS] <archive.zupt>
zupt test [OPTIONS] <archive.zupt>
zupt disk backup [OPTIONS] <output.zupt> <device_or_file>
zupt disk restore [OPTIONS] <archive.zupt> <target>
zupt bench [--compare] <files/dirs...>
zupt keygen [-o file] [--pub] [-k privkey]
zupt version
zupt help
| Option | Description |
|---|---|
-l <1-9> |
Compression level (default: 7) |
-t <N> |
Thread count (0=auto, 1=single, 2–64) |
-p [PW] |
Password encryption (PBKDF2 → AES-256) |
--pq <keyfile> |
Post-quantum hybrid encryption |
-o <DIR> |
Output directory (extract) |
-s |
Store without compression |
-f |
Fast LZ codec (Zupt-LZ) |
--vv |
Force VaptVupt codec |
--lzhp |
Force Zupt-LZHP codec |
-v |
Verbose |
--solid |
Solid mode (cross-file LZ context) |
--compare |
Codec comparison benchmark |
Building
make # Auto-detects arch, Jasmin, AVX2
make V=1 # Verbose build output
make test-all # 77 tests: regression + NIST + VV + MT + PQ + disk
make test-vv # VaptVupt codec unit tests only
make test-asan # AddressSanitizer + UBSan build
make fuzz-build # AFL++ fuzzing harnesses
make install # Install binary + man page
make help # Show all targets + detected capabilities
build.bat # Windows (MSVC)
Benchmark
zupt bench ~/Documents/ # Per-level benchmark (levels 1-9)
zupt bench --compare # Cross-codec comparison (auto-generates corpus)
zupt bench --compare ~/Documents/ # Compare codecs on your own data
Codec Reference
| ID | Name | Algorithm | Default on | Override |
|---|---|---|---|---|
0x0010 |
VaptVupt | LZ77 + tANS + AVX2/NEON SIMD | x86_64 (AVX2), aarch64 (NEON) | --vv |
0x000A |
Zupt-LZHP | LZ77 + Huffman + byte prediction | armhf, ppc64le, s390x, riscv64 | --lzhp |
0x0009 |
Zupt-LZH | LZ77 + Huffman | — | — |
0x0008 |
Zupt-LZ | Fast LZ77, 64KB window | — | -f |
0x0000 |
Store | No compression | — | -s |
All codecs are forward-compatible: archives created with any codec can be read by any Zupt version that includes that codec, on any architecture. VaptVupt archives require Zupt v2.0+.
Release History
| Version | Description |
|---|---|
| v0.1–v0.6 | LZ77 compression, AES-256 encryption, multi-threading |
| v0.7 | Post-quantum hybrid encryption (ML-KEM-768 + X25519) |
| v1.0 | Stable release — format frozen v1.4, security audit |
| v1.1–v1.4 | X25519 fix, NIST vectors, CPUID detection, Jasmin source files fixed |
| v1.5 | Jasmin CT assembly linked (MAC verify + ML-KEM select active) |
| v1.5.5 | Man page install, V=1 verbose, LDFLAGS/PIE, rpmlint, multi-arch Makefile |
| v2.0 | VaptVupt 1.1.0 codec, auto hardware detection, all 5 Jasmin wired, AVX SIGILL fix, copy_match/litlen fixes, ACSL, mlock, fuzzing, canaries, AES-NI pipeline, MT decompress, multi-arch (6 arches), --lzhp flag |
| v2.1.0 | VaptVupt 1.4.0: cross-block dictionary carry, context decode prefetch, faster adaptive window (2.6× encode), integration API |
| v2.1.1 | Termux/Android build fix, arch-safety guard, Keccak ROL64 UB fix, zero UBSan violations |
| v2.1.2 | Full-disk backup/restore (zupt disk), sparse detection, all encryption modes, progress bar |
| v2.1.3 | Disk restore fix (POSIX raw I/O + O_SYNC for block devices, shared decompress_block), Termux build fix (CC -dumpmachine arch detection), 77 tests |
| v2.1.3 | LZHP prediction encoding fix (data corruption on structured data), shared write_enc_header, SOLID flag removed from disk, 78 tests |
| v2.1.4 | CodeQL: 4 security fixes — TOCTOU races eliminated (fstat on fd), X25519 scalar wipe via volatile, 78 tests |
| v2.1.5 | Block-level deduplication (--dedup), XXH64 fingerprint index, DEDUP_REF block type, 81 tests |
| v2.1.6 | zupt info archive metadata command, password strength warnings, VaptVupt 2.40.0 (format_v2), GUI desktop application, 97 tests |
| v2.1.7 | Relicense MIT → AGPL-3.0-or-later. VaptVupt remains GPL-3.0-or-later (kept in sync with upstream); upgraded VaptVupt 2.40.0 → 2.46.1. Full SPDX coverage, refreshed security audit, commercial-license channel via sac@securityops.co |
See CHANGELOG.md for detailed per-version changes.
License
Zupt is licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later).
The full license text is in LICENSE, preceded by a formal preamble explaining the rationale. In short:
- You can use Zupt freely — for personal backups, in your business, on your servers, in air-gapped environments, anywhere. The AGPL imposes essentially no obligations on simple use.
- If you modify Zupt and run the modified version as a network service (a backup-as-a-service product, a cloud archival backend, etc.), you must make the source code of your modifications available to the users of that service. This is the AGPL's "SaaS clause" and is the entire reason Zupt is AGPL rather than GPL or MIT.
- If you redistribute Zupt (modified or not), the AGPL travels with it.
The integrated VaptVupt compression codec (src/vv_*.c, include/vaptvupt*.h, include/vv_*.h) is licensed separately under GPL-3.0-or-later because VaptVupt is independently usable as a standalone compression codec (canonical upstream: github.com/cristiancmoises/vaptvupt). GPL-3.0-or-later is two-way compatible with AGPL-3.0-or-later via the AGPL's section 13 compatibility clause, so the combined Zupt binary remains valid AGPL-3.0. See LICENSE-VAPTVUPT for details.
Commercial Licensing
If your intended use is incompatible with the AGPL — for example:
- Embedding Zupt or VaptVupt into a closed-source product, appliance, or firmware
- Operating Zupt as a hosted/SaaS backend without releasing your modifications
- Redistributing Zupt as part of a proprietary commercial product
- Requiring warranty, indemnification, or written terms
A commercial license is available. Contact: sac@securityops.co
The author retains full copyright ownership of all original Zupt and VaptVupt source code and is therefore able to grant alternative licensing terms.
Security vulnerabilities: see SECURITY.md.
Support the Project
© 2026 Cristian Cezar Moisés — github.com/cristiancmoises