diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7948178..77bacb1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,64 @@
# VaptVupt Changelog
+## [5.2.0] — 2026-07-12 — GUI compress-crash fix; codec 2.65.3; libvuptsdk
+
+Backward-compatible with 5.0.x/5.1.0: `.zupt` wire format unchanged (v1.6),
+archives interoperate in both directions, and `--pq` / `--pq-only` keys keep
+working.
+
+### GUI — the compress crash / corruption / "nothing happens" is fixed
+
+The 5.1.0 progress-bar work introduced a cross-thread bug that made compress
+crash the app ("app closes"), hang ("nothing happens"), or leave a truncated
+(corrupt) archive — worst on the full-PQ path.
+
+- Root cause: `run_async` connected plain Python CLOSURES (`finish`/`on_pct`/
+ `release`) to signals emitted from the worker `QThread`. PySide6 runs a
+ plain-closure slot in the EMITTING thread regardless of the requested
+ connection type — even an explicit `Qt.QueuedConnection` — because a bare
+ functor has no receiver QObject to give it GUI-thread affinity. Those closures
+ then called `QProgressBar.setValue/setRange/hide`, `QPushButton.setEnabled`
+ and `QTextEdit.append` from the worker thread. Cross-thread QWidget access is
+ undefined behaviour and crashed the app under real X11/Wayland rendering; it
+ only survived offscreen tests, so prior automated runs missed it.
+- Fix: a `_Job(QObject)` controller parented to a GUI-thread widget, so every
+ slot is a bound method Qt auto-marshals to the GUI thread.
+- Verified on a real X display (window shown, progress bar rendering) with a
+ QProgressBar/QPushButton instrumentation that flags any worker-thread call:
+ zero cross-thread calls after the fix, and hybrid + full-PQ + password
+ compress/extract all byte-exact round-trip; Verify/Info/Disk backup+restore/
+ two-concurrent-jobs/close-mid-job all pass.
+
+### Codec — VaptVupt 2.65.3
+
+Byte-identical output to 2.65.0 (same ratio, wire format v1.6) but extreme-mode
+encode is ~1.6–2× faster (Sprint 132) and the extreme prepass window
+reservation is capped at 8 MiB instead of up to 128 MiB (Sprint 133 memory
+hygiene). Our AVX2 decoder offset-read guard is now upstream; the ANS
+safe-zone reserve patch is re-applied on top.
+
+### SDK — libvuptsdk (renamed from libzuptsdk)
+
+`libvuptsdk` (git.securityops.co/cristiancmoises/libvuptsdk) is the renamed
+`libzuptsdk`; only the shared-object filename/SONAME changed
+(`libzuptsdk.so.2` → `libvuptsdk.so.2`), the C API is unchanged. A `WITH_SDK=1`
+build now links `-lvuptsdk` and enables `--pq-sdk` + the Argon2id password KDF.
+`--pq-box` needs the SEPARATE `libpqvaptvupt`, which `libvuptsdk` does not
+provide, so it is now behind its own `WITH_PQBOX=1` flag rather than folded into
+`WITH_SDK`. The default distributed build stays source-only (`WITH_SDK=0`):
+native `--pq` / `--pq-only` + PBKDF2, no external libraries. Validated:
+`WITH_SDK=1` links libvuptsdk + libcrypto + libargon2, `keygen --sdk` and
+`--pq-sdk` encrypt/decrypt round-trip byte-exact.
+
+### Validation
+
+`make check` 16/16 (source-only); codec KAT 16/16; ML-KEM-768 FIPS 203
+conformance 3/3; full GUI function matrix on real X with zero cross-thread
+access; SDK round-trip on a `WITH_SDK=1` build.
+
+
+
## [5.1.0] — 2026-07-11 — codec 2.65.0; large ratio gains; GUI compress fixes
Backward-compatible with 5.0.0: the `.zupt` wire format is unchanged (v1.6) and
@@ -53,10 +111,12 @@ is ~30 MB per thread.
still-running `QThread` and Qt aborted the process ("QThread: Destroyed while
thread is still running"). References are now released from a slot on
`QThread.finished` after `wait()`.
-- **"App stuck" during compress.** The CLI paints live progress as `
` frames
+- **"App stuck" during compress.** The CLI paints live progress as `
+` frames
(no newline until 100%); the worker read line-by-line and so emitted nothing
for the whole job — the window looked frozen on any file larger than one block.
- The worker now parses `
` progress frames and drives the progress bar, and
+ The worker now parses `
+` progress frames and drives the progress bar, and
runs the child with `stdin=/dev/null` so a prompt can never block it.
- **Window never appeared on Wayland** (Sway 1.12 + Qt 6.9): the toolkit never
sent the initial `wl_surface.commit`, so the compositor never mapped the
diff --git a/README.md b/README.md
index 1a8d222..4a29d9a 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,27 @@ License: AGPL-3.0-or-later (dual-licensed AGPL + commercial).
> command is preserved as a symlink to `vaptvupt` for one major version
> cycle.
+## What's new in 5.2.0
+
+- **GUI compress crash fixed.** The 5.1.0 progress bar introduced a cross-thread
+ bug that could crash the app, hang it, or leave a corrupt archive when
+ compressing (worst on the full post-quantum path). Worker callbacks now run on
+ the GUI thread via a `_Job` controller; verified on a real X display with zero
+ cross-thread widget access and byte-exact round-trips across hybrid, full-PQ,
+ and password modes plus Verify/Info/Disk/concurrent/close-mid-job.
+- **Codec VaptVupt 2.65.3** — byte-identical output to 2.65.0 (same ratios) but
+ ~1.6–2× faster extreme-mode encode and lower peak virtual memory.
+- **libvuptsdk** (renamed from `libzuptsdk`) is now the SDK library a
+ `WITH_SDK=1` build links for `--pq-sdk` + the Argon2id password KDF; `--pq-box`
+ moved to its own `WITH_PQBOX=1` flag (separate `libpqvaptvupt`). The default
+ distributed build stays source-only (native `--pq`/`--pq-only` + PBKDF2, no
+ external libraries).
+
+Binaries for the CLI (5.2.0) and GUI (5.2.0) are on the
+[release page](https://git.securityops.co/cristiancmoises/vaptvupt/releases/tag/v5.2.0).
+
+---
+
## What's new in 5.1.0
- **Codec upgraded to VaptVupt 2.65.0** (from 2.60.4). Same on-disk format
@@ -97,7 +118,7 @@ Binaries for the CLI (5.0.0) and GUI (5.0.0) are on the
## Compression comparison
-Single-thread, one 20–25 MB file per data class, best-of-run on an x86-64 AVX2 machine (codec 2.65.0). Ratio = original ÷ compressed — higher is better. Reproduce with `vaptvupt -b ` and the standard `zstd` / `gzip` / `lz4` CLIs. Numbers vary with data and hardware.
+Single-thread, one 20–25 MB file per data class, best-of-run on an x86-64 AVX2 machine (codec 2.65.3; output byte-identical to 2.65.0). Ratio = original ÷ compressed — higher is better. Reproduce with `vaptvupt -b ` and the standard `zstd` / `gzip` / `lz4` CLIs. Numbers vary with data and hardware.
### Ratio vs other compressors
@@ -209,36 +230,36 @@ Argon2id KDF.
### Pre-built packages
Assets are published on the
-[v5.1.0 release page](https://git.securityops.co/cristiancmoises/vaptvupt/releases/tag/v5.1.0)
+[v5.2.0 release page](https://git.securityops.co/cristiancmoises/vaptvupt/releases/tag/v5.2.0)
and verifiable against the published `SHA256SUMS.txt`.
-**Command-line tool (`vaptvupt` 5.1.0):**
+**Command-line tool (`vaptvupt` 5.2.0):**
| Format | File | Distros |
|---|---|---|
-| Debian/Ubuntu | `vaptvupt_5.1.0_amd64.deb` | Debian 11+, Ubuntu 22.04+, Mint 21+ |
-| RPM | `vaptvupt-5.1.0-1.x86_64.rpm` | Fedora 38+, RHEL 9+, openSUSE, AlmaLinux, Rocky, other RPM-based distributions |
-| AppDir tarball | `vaptvupt-5.1.0-x86_64.AppDir.tar.gz` | Any glibc 2.28+ (extract & run, no FUSE) |
-| Source tarball | `vaptvupt-5.1.0.tar.gz` | Build from source on any platform |
-| openSUSE OBS | `vaptvupt-5.1.0-opensuse-obs.tar.gz` | Open Build Service source bundle |
+| Debian/Ubuntu | `vaptvupt_5.2.0_amd64.deb` | Debian 11+, Ubuntu 22.04+, Mint 21+ |
+| RPM | `vaptvupt-5.2.0-1.x86_64.rpm` | Fedora 38+, RHEL 9+, openSUSE, AlmaLinux, Rocky, other RPM-based distributions |
+| AppDir tarball | `vaptvupt-5.2.0-x86_64.AppDir.tar.gz` | Any glibc 2.28+ (extract & run, no FUSE) |
+| Source tarball | `vaptvupt-5.2.0.tar.gz` | Build from source on any platform |
+| openSUSE OBS | `vaptvupt-5.2.0-opensuse-obs.tar.gz` | Open Build Service source bundle |
-**Graphical front-end (`vaptvupt-gui` 5.1.0):**
+**Graphical front-end (`vaptvupt-gui` 5.2.0):**
| Format | File | Distros |
|---|---|---|
-| Debian/Ubuntu | `vaptvupt-gui_5.1.0_all.deb` | Debian 11+, Ubuntu 22.04+, Mint 21+ |
-| RPM | `vaptvupt-gui-5.1.0-1.noarch.rpm` | RPM-based distributions |
-| AppImage | `VaptVupt-GUI-5.1.0-x86_64.AppImage` | Any glibc 2.28+ (single-file, no install) |
-| AppDir tarball | `VaptVupt-GUI-5.1.0-x86_64.AppDir.tar.gz` | Any glibc 2.28+ (extract & run) |
+| Debian/Ubuntu | `vaptvupt-gui_5.2.0_all.deb` | Debian 11+, Ubuntu 22.04+, Mint 21+ |
+| RPM | `vaptvupt-gui-5.2.0-1.noarch.rpm` | RPM-based distributions |
+| AppImage | `VaptVupt-GUI-5.2.0-x86_64.AppImage` | Any glibc 2.28+ (single-file, no install) |
+| AppDir tarball | `VaptVupt-GUI-5.2.0-x86_64.AppDir.tar.gz` | Any glibc 2.28+ (extract & run) |
**Windows / macOS / BSD:**
| Platform | File | Notes |
|---|---|---|
-| Windows | `VaptVupt-Setup-5.1.0.exe`, `vaptvupt-gui-5.1.0-windows-x86_64.exe`, `vaptvupt-5.1.0-windows-x86_64.exe` | Native installer + standalone GUI + CLI, built on a Windows runner by CI |
-| macOS | `VaptVupt-5.1.0.dmg`, `vaptvupt-5.1.0-macos` | `.dmg` GUI bundle + CLI, built on a macOS runner by CI |
-| Any OS (portable GUI) | `vaptvupt-gui-5.1.0-portable.zip` | Python GUI + launchers for Windows/macOS/Linux/BSD; needs Python 3.8+ and PySide6 (or PyQt6), plus the `vaptvupt` CLI on PATH |
-| BSD / others | `vaptvupt-5.1.0.tar.gz` | Build the CLI from source (`make`); run the portable GUI |
+| Windows | `VaptVupt-Setup-5.2.0.exe`, `vaptvupt-gui-5.2.0-windows-x86_64.exe`, `vaptvupt-5.2.0-windows-x86_64.exe` | Native installer + standalone GUI + CLI, built on a Windows runner by CI |
+| macOS | `VaptVupt-5.2.0.dmg`, `vaptvupt-5.2.0-macos` | `.dmg` GUI bundle + CLI, built on a macOS runner by CI |
+| Any OS (portable GUI) | `vaptvupt-gui-5.2.0-portable.zip` | Python GUI + launchers for Windows/macOS/Linux/BSD; needs Python 3.8+ and PySide6 (or PyQt6), plus the `vaptvupt` CLI on PATH |
+| BSD / others | `vaptvupt-5.2.0.tar.gz` | Build the CLI from source (`make`); run the portable GUI |
The native Windows/macOS installers are produced by the project's CI
(`.github/workflows/cross-platform.yml`) on real Windows and macOS runners — see
@@ -250,30 +271,30 @@ and Qt are available.
sha256sum -c SHA256SUMS.txt
# Debian / Ubuntu / Mint
-sudo dpkg -i vaptvupt_5.1.0_amd64.deb
+sudo dpkg -i vaptvupt_5.2.0_amd64.deb
sudo apt-get install -f # resolve any missing deps
# Fedora / RHEL / openSUSE / AlmaLinux / Rocky and other RPM-based distros
-sudo rpm -i vaptvupt-5.1.0-1.x86_64.rpm
+sudo rpm -i vaptvupt-5.2.0-1.x86_64.rpm
# or
-sudo dnf install ./vaptvupt-5.1.0-1.x86_64.rpm
+sudo dnf install ./vaptvupt-5.2.0-1.x86_64.rpm
# AppDir tarball (no install, no FUSE required)
-tar xzf vaptvupt-5.1.0-x86_64.AppDir.tar.gz
-./vaptvupt-5.1.0-x86_64.AppDir/AppRun --help
+tar xzf vaptvupt-5.2.0-x86_64.AppDir.tar.gz
+./vaptvupt-5.2.0-x86_64.AppDir/AppRun --help
# GUI AppImage (single executable)
-chmod +x VaptVupt-GUI-5.1.0-x86_64.AppImage
-./VaptVupt-GUI-5.1.0-x86_64.AppImage
+chmod +x VaptVupt-GUI-5.2.0-x86_64.AppImage
+./VaptVupt-GUI-5.2.0-x86_64.AppImage
```
### Building from SRPM (Fedora / RHEL / RPM-based distributions)
```bash
-tar xzf vaptvupt-5.1.0.srpm.tar.gz
+tar xzf vaptvupt-5.2.0.srpm.tar.gz
cd ~/rpmbuild # or use rpmbuild --define "_topdir $(pwd)"
rpmbuild -bb SPECS/vaptvupt.spec
-sudo rpm -i RPMS/x86_64/vaptvupt-5.1.0-1.*.rpm
+sudo rpm -i RPMS/x86_64/vaptvupt-5.2.0-1.*.rpm
```
### Basic usage
@@ -390,7 +411,7 @@ VaptVupt combines LZ77 dictionary matching with tANS (table-based
Asymmetric Numeral Systems) entropy coding and SIMD-accelerated
decompression.
-This release embeds VaptVupt codec 2.65.0 (from the
+This release embeds VaptVupt codec 2.65.3 (from the
[vaptvupt-codec](https://git.securityops.co/cristiancmoises/vaptvupt-codec)
repository, tag v2.65.0). Over the previous 2.60.4 it adds a faster balanced
encoder and the Sprint 124–130 extreme-mode literal-pricing improvements. Two
@@ -755,6 +776,7 @@ VaptVupt archives require VaptVupt v2.0+.
| v4.2.1 | `vaptvupt info` now reports the real post-quantum mode (`--pq-only` no longer mislabelled as hybrid); reader-side only, no wire-format change |
| v5.0.0 | Genuine FIPS 203 ML-KEM-768 (validated vs OpenSSL); CLI data-loss/plaintext guards; AVX2 decoder OOB-read fix; GUI reworked for native PQ modes; cross-platform packaging. **Breaking:** `--pq`/`--pq-only` keys+archives from ≤4.2.1 do not decrypt |
| v5.1.0 | Codec 2.65.0; large compression-ratio gains (auto-`format_v2` + level-scaled block window — text extreme 3.77×→5.98×, logs 7.21×→9.07×); `--dedup` keeps a small block automatically; GUI compress-hang / job-completion-crash / Wayland-map fixes. Wire format stays v1.6, fully interoperable with 5.0.0 |
+| v5.2.0 | Fixed a GUI cross-thread crash (compress could close the app / corrupt the archive, worst on full-PQ); codec 2.65.3 (~2× faster extreme, byte-identical output); libvuptsdk (renamed libzuptsdk) for `WITH_SDK=1` `--pq-sdk`/Argon2id; `--pq-box` split to `WITH_PQBOX=1`. Wire format v1.6, interoperable with 5.0.x/5.1.0 |
See [CHANGELOG.md](CHANGELOG.md) for detailed per-version changes.
diff --git a/gui/README.md b/gui/README.md
index 558771c..b1a17d6 100644
--- a/gui/README.md
+++ b/gui/README.md
@@ -116,7 +116,7 @@ The GUI calls the vaptvupt CLI binary — all cryptography runs in native C, not
## Credits
-- **vaptvupt** v5.1.0 — Cristian Cezar Moisés ([github](https://git.securityops.co/cristiancmoises/vaptvupt))
+- **vaptvupt** v5.2.0 — Cristian Cezar Moisés ([github](https://git.securityops.co/cristiancmoises/vaptvupt))
## License
diff --git a/include/zupt.h b/include/zupt.h
index 802e365..11cd574 100644
--- a/include/zupt.h
+++ b/include/zupt.h
@@ -50,7 +50,7 @@
#define ZUPT_PRODUCT_EXTENSION ".zupt" /* on-disk archive extension (kept stable) */
#define ZUPT_PRODUCT_TAGLINE "Post-quantum backup compression"
-#define ZUPT_VERSION_STRING "5.1.0"
+#define ZUPT_VERSION_STRING "5.2.0"
/* Vendored codec release (upstream tag) — single source for display strings.
* The codec's own VV_VERSION_* is its internal API version, not the release. */
#define ZUPT_CODEC_RELEASE "2.65.3"
diff --git a/packaging/guix/vaptvupt.scm b/packaging/guix/vaptvupt.scm
index 8bed86e..76cda24 100644
--- a/packaging/guix/vaptvupt.scm
+++ b/packaging/guix/vaptvupt.scm
@@ -62,7 +62,7 @@
xcb-util-renderutil xcb-util-wm xcb-util-cursor
libinput-minimal mtdev libevdev eudev))
-(define %vaptvupt-version "5.1.0")
+(define %vaptvupt-version "5.2.0")
(define %vaptvupt-source
(origin
diff --git a/packaging/homebrew/vaptvupt.rb b/packaging/homebrew/vaptvupt.rb
index 1e9c9a3..88a422b 100644
--- a/packaging/homebrew/vaptvupt.rb
+++ b/packaging/homebrew/vaptvupt.rb
@@ -22,8 +22,8 @@
class Vaptvupt < Formula
desc "Post-quantum backup compression utility (ML-KEM-768 + AES-256-CTR + HMAC-SHA256)"
homepage "https://git.securityops.co/cristiancmoises/vaptvupt"
- url "https://git.securityops.co/cristiancmoises/vaptvupt/releases/download/v5.1.0/vaptvupt-5.1.0.tar.gz"
- version "5.1.0"
+ url "https://git.securityops.co/cristiancmoises/vaptvupt/releases/download/v5.2.0/vaptvupt-5.2.0.tar.gz"
+ version "5.2.0"
sha256 "REPLACE_WITH_SHA256_OF_RELEASE_TARBALL"
license "AGPL-3.0-or-later"
diff --git a/packaging/opensuse/vaptvupt.spec b/packaging/opensuse/vaptvupt.spec
index 997dc8f..8d30fa3 100644
--- a/packaging/opensuse/vaptvupt.spec
+++ b/packaging/opensuse/vaptvupt.spec
@@ -19,7 +19,7 @@
Name: vaptvupt
-Version: 5.1.0
+Version: 5.2.0
Release: 0
Summary: Post-quantum backup compression with AES-256 + ML-KEM-768 hybrid encryption
License: AGPL-3.0-or-later
diff --git a/packaging/rpm/vaptvupt.spec b/packaging/rpm/vaptvupt.spec
index e42d319..ff88246 100644
--- a/packaging/rpm/vaptvupt.spec
+++ b/packaging/rpm/vaptvupt.spec
@@ -20,7 +20,7 @@
# in the base.
Name: vaptvupt
-Version: 5.1.0
+Version: 5.2.0
Release: 1%{?dist}
Summary: Post-quantum backup compression utility (AES-256 + ML-KEM-768 + Argon2id, formerly Zupt)