v4.2.1: info correctly reports --pq-only vs hybrid post-quantum mode

`vaptvupt info` mislabelled full post-quantum (--pq-only, enc_type 0x06)
archives as "PQ Hybrid: YES (ML-KEM-768 + X25519)". Full-PQ archives set
the generic ZUPT_FLAG_PQ_HYBRID header flag (the enc_type byte is what
distinguishes hybrid 0x02 from pure 0x06), but info only checked the flag.

info now seeks to hdr.encryption_header_off, reads the real enc_type from
the encryption-header block, and reports the actual mode: "ML-KEM-768
only, no classical layer" for --pq-only, and hybrid / SDK-v2 / sealed-box
for the others. Reader-side only — no wire-format change; existing 4.2.0
archives are relabelled correctly with no re-encryption.
This commit is contained in:
Cristian Cezar Moisés 2026-07-10 00:20:49 -03:00
commit 9800530d2e
4 changed files with 52 additions and 4 deletions

View file

@ -1,6 +1,22 @@
# VaptVupt Changelog # VaptVupt Changelog
## [4.2.1] — 2026-07-10 — `info` correctly reports the post-quantum mode
### Fixed
- **`vaptvupt info` mislabelled `--pq-only` archives as hybrid.** Full
post-quantum archives set the generic `ZUPT_FLAG_PQ_HYBRID` header flag (the
`enc_type` byte is what distinguishes hybrid `0x02` from pure `0x06`), but
`info` only checked the flag and always printed "PQ Hybrid: YES (ML-KEM-768 +
X25519)". It now reads the real `enc_type` from the encryption-header block
and reports the actual mode: "ML-KEM-768 only, no classical layer" for
`--pq-only`, and hybrid / SDK-v2 / sealed-box for the others. Reader-side only
— no wire-format change; existing 4.2.0 archives are relabelled correctly with
no re-encryption. The crypto was always correct; only the `info` label was
wrong.
## [4.2.0] — 2026-07-09 — Full (pure) post-quantum mode; dedup keystream-reuse fix ## [4.2.0] — 2026-07-09 — Full (pure) post-quantum mode; dedup keystream-reuse fix
### Added — full post-quantum encryption (`--pq-only`) ### Added — full post-quantum encryption (`--pq-only`)

View file

@ -1,7 +1,7 @@
.\" Manpage for vaptvupt (formerly zupt; INPI Brasil trademark rename in v3.0.0) .\" Manpage for vaptvupt (formerly zupt; INPI Brasil trademark rename in v3.0.0)
.\" SPDX-License-Identifier: AGPL-3.0-or-later .\" SPDX-License-Identifier: AGPL-3.0-or-later
.\" Copyright (c) 2025-2026 Cristian Cezar Moisés .\" Copyright (c) 2025-2026 Cristian Cezar Moisés
.TH VAPTVUPT 1 "July 2026" "vaptvupt 4.2.0" "User Commands" .TH VAPTVUPT 1 "July 2026" "vaptvupt 4.2.1" "User Commands"
.SH NAME .SH NAME
vaptvupt \- post-quantum backup compression utility (formerly zupt) vaptvupt \- post-quantum backup compression utility (formerly zupt)

View file

@ -50,7 +50,7 @@
#define ZUPT_PRODUCT_EXTENSION ".zupt" /* on-disk archive extension (kept stable) */ #define ZUPT_PRODUCT_EXTENSION ".zupt" /* on-disk archive extension (kept stable) */
#define ZUPT_PRODUCT_TAGLINE "Post-quantum backup compression" #define ZUPT_PRODUCT_TAGLINE "Post-quantum backup compression"
#define ZUPT_VERSION_STRING "4.2.0" #define ZUPT_VERSION_STRING "4.2.1"
/* Vendored codec release (upstream tag) — single source for display strings. /* Vendored codec release (upstream tag) — single source for display strings.
* The codec's own VV_VERSION_* is its internal API version, not the release. */ * The codec's own VV_VERSION_* is its internal API version, not the release. */
#define ZUPT_CODEC_RELEASE "2.60.4" #define ZUPT_CODEC_RELEASE "2.60.4"

View file

@ -2903,6 +2903,23 @@ zupt_error_t zupt_archive_info(const char *path) {
has_footer = 1; has_footer = 1;
} }
} }
/* Read the real enc_type from the encryption-header block so `info` can
* distinguish hybrid --pq (0x02) from full --pq-only (0x06), the SDK-v2
* (0x03) and sealed-box (0x05) modes the ZUPT_FLAG_PQ_HYBRID header flag
* is a generic PQ indicator set by all of them. Block layout from
* write_enc_header: 7-byte prefix (magic0,magic1,block_type,codec u16,
* flags u16) + varint(len) + varint(len) + u64 xxh64 + enc_hdr[0]=enc_type. */
uint8_t enc_type = 0;
if ((hdr.global_flags & ZUPT_FLAG_ENCRYPTED) && hdr.encryption_header_off != 0 &&
fseeko(f, (off_t)hdr.encryption_header_off + 7, SEEK_SET) == 0) {
uint64_t l1 = 0, l2 = 0;
if (zupt_read_varint(f, &l1) > 0 && zupt_read_varint(f, &l2) > 0 &&
fseeko(f, 8, SEEK_CUR) == 0) {
uint8_t b;
if (fread(&b, 1, 1, f) == 1) enc_type = b;
}
}
fclose(f); fclose(f);
/* UUID */ /* UUID */
@ -2938,8 +2955,23 @@ zupt_error_t zupt_archive_info(const char *path) {
if (has_footer) if (has_footer)
printf(" Blocks: %llu\n", (unsigned long long)total_blocks); printf(" Blocks: %llu\n", (unsigned long long)total_blocks);
printf(" Encrypted: %s\n", (fl & ZUPT_FLAG_ENCRYPTED) ? "YES" : "no"); printf(" Encrypted: %s\n", (fl & ZUPT_FLAG_ENCRYPTED) ? "YES" : "no");
if (fl & ZUPT_FLAG_PQ_HYBRID) if (fl & ZUPT_FLAG_PQ_HYBRID) {
printf(" PQ Hybrid: YES (ML-KEM-768 + X25519)\n"); switch (enc_type) {
case ZUPT_ENC_PQ_ONLY:
printf(" Post-quantum: YES (ML-KEM-768 only, no classical layer)\n");
break;
case ZUPT_ENC_PQ_SDK_V2:
printf(" Post-quantum: YES (ML-KEM-768 + X25519, SDK v2 + HPKE)\n");
break;
case ZUPT_ENC_PQ_BOX_V1:
printf(" Post-quantum: YES (ML-KEM-768 + X25519, sealed box)\n");
break;
case ZUPT_ENC_PQ_HYBRID:
default:
printf(" Post-quantum: YES (ML-KEM-768 + X25519, hybrid)\n");
break;
}
}
if (fl & ZUPT_FLAG_SOLID) if (fl & ZUPT_FLAG_SOLID)
printf(" Solid: YES\n"); printf(" Solid: YES\n");
if (fl & ZUPT_FLAG_MULTITHREADED) if (fl & ZUPT_FLAG_MULTITHREADED)