codec: update vendored VaptVupt codec 2.65.0 -> 2.65.3

From vaptvupt-codec tag v2.65.3. Output is byte-identical to 2.65.0 (same
ratio, wire format v1.6 unchanged) but extreme-mode encode is ~1.6-2x faster
(Sprint 132 optimal-parser speedup) and the extreme prepass window allocation
is capped at wlog=20 = 8 MiB virtual instead of up to 128 MiB (Sprint 133
memory hygiene). Our AVX2 offset-read decoder guard is now UPSTREAM (dropped
from the local patch set); the ANS safe-zone 2*SAFEZONE_MAX_RUN reserve is
re-applied on top (still not upstream). make check 16/16, KAT 16/16, cross-
version roundtrip with 5.1.0 archives verified.
This commit is contained in:
Cristian Cezar Moisés 2026-07-12 14:47:40 -03:00
commit 59f9ebc59e
24 changed files with 94 additions and 17 deletions

472
vendor/vuptsdk/include/vaptvupt.h vendored Normal file
View file

@ -0,0 +1,472 @@
/*
* VaptVupt Codec Next-generation lossless compression
* Public API and data structures
*
* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright 2026 Cristian.
* Zero dependencies. Pure C11.
*/
#ifndef VAPTVUPT_H
#define VAPTVUPT_H
#include <stdint.h>
#include "vv_platform.h"
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ═══════════════════════════════════════════════════════════════
* VERSION & CONSTANTS
* */
#define VV_VERSION_MAJOR 0
#define VV_VERSION_MINOR 1
#define VV_VERSION_PATCH 0
#define VV_VERSION_STRING "0.1.0"
#define VV_MAGIC 0x56560100u /* "VV\x01\x00" */
#define VV_MAX_BLOCK_SIZE (1u << 20) /* 1 MB per block */
#define VV_MIN_MATCH 4
#define VV_MAX_MATCH 65535
#define VV_MAX_LIT_RUN 65535
#define VV_MAX_OFFSET (1u << 24) /* 16 MB default window */
/* ═══════════════════════════════════════════════════════════════
* ERROR CODES
* */
typedef enum {
VV_OK = 0,
VV_ERR_IO = -1,
VV_ERR_CORRUPT = -2,
VV_ERR_NOMEM = -3,
VV_ERR_OVERFLOW = -4,
VV_ERR_BAD_MAGIC = -5,
VV_ERR_PARAM = -6,
} vv_error_t;
/* ═══════════════════════════════════════════════════════════════
* COMPRESSION MODES
* */
typedef enum {
VV_MODE_ULTRA_FAST = 0, /* Speed priority: greedy parse, no entropy */
VV_MODE_BALANCED = 1, /* Default: lazy parse + Huffman */
VV_MODE_EXTREME = 2, /* Ratio priority: optimal parse + Huffman */
} vv_mode_t;
/* ═══════════════════════════════════════════════════════════════
* BLOCK TYPES (2-bit field in block header)
* */
typedef enum {
VV_BLOCK_RAW = 0, /* Uncompressed (stored) */
VV_BLOCK_COMPRESSED = 1, /* LZ + raw literals */
VV_BLOCK_RLE = 2, /* Run-length (single byte) */
VV_BLOCK_ENTROPY = 3, /* LZ + entropy-coded literals (ANS or Huffman) */
} vv_block_type_t;
/* Entropy sub-type tags (first byte of entropy section in type-3 blocks) */
#define VV_ENTROPY_HUFFMAN 0x48 /* 'H' — Huffman (v0.3-v0.4) */
#define VV_ENTROPY_ANS 0x41 /* 'A' — tANS single-stream (v0.5) */
#define VV_ENTROPY_ANS4 0x49 /* 'I' — tANS 4-way interleaved (v0.6+) */
#define VV_ENTROPY_CTX 0x43 /* 'C' — tANS order-1 context model (v0.7+) */
#define VV_ENTROPY_SEQ 0x53 /* 'S' — sequence coding: ANS on lits+ml+of (v0.8+) */
#define VV_ENTROPY_SEQ_V2 0x54 /* 'T' — same as 'S' but with min_match=3
* for binary-data compression parity with
* gzip-9. Shifts ml_base[] down by 1 across
* all 36 codes; every other field unchanged.
* Added in v2.33.0 (decode); encoder in a
* future release. */
/* Block header accessors (2-bit type, 1-bit last, 21-bit size) */
static inline vv_block_type_t vv_bh_type(uint32_t h) { return (vv_block_type_t)(h & 3); }
static inline int vv_bh_last(uint32_t h) { return (h >> 2) & 1; }
static inline uint32_t vv_bh_size(uint32_t h) { return (h >> 3) & 0x1FFFFF; }
static inline uint32_t vv_bh_pack(vv_block_type_t t, int last, uint32_t sz) {
return (uint32_t)t | ((uint32_t)last << 2) | (sz << 3);
}
/* ═══════════════════════════════════════════════════════════════
* TOKEN TYPES (in the sequence stream)
*
* Each token is: [type:2][litlen:6] [optional litlen ext]
* [literal bytes]
* [matchlen ext] [offset bytes]
*
* The decoder reads a compact token byte, copies literals,
* then copies a match. This is LZ4-like for speed.
* */
/* Token byte layout:
* Bits 7-4: literal_length (0-14, 15=extended)
* Bits 3-0: match_length - VV_MIN_MATCH (0-14, 15=extended)
*
* Followed by:
* [extended literal length varint, if litlen==15]
* [literal bytes]
* [offset: 2 bytes LE (or 3 bytes if high bit set)]
* [extended match length varint, if matchlen==15]
*/
/* ═══════════════════════════════════════════════════════════════
* ON-DISK STRUCTURES
* */
#pragma pack(push, 1)
/* Frame header: 16 bytes */
typedef struct {
uint32_t magic; /* VV_MAGIC */
uint8_t version; /* Format version (1) */
uint8_t flags; /* bit0: has_checksum, bit1: has_dict */
uint8_t mode_hint; /* Compression mode used (informational) */
uint8_t window_log; /* Window size = 1 << window_log */
uint64_t content_size; /* Uncompressed size (0 = unknown) */
} vv_frame_header_t;
/* Block header: 4 bytes */
typedef struct {
/* Bits 0-1: block_type (vv_block_type_t) */
/* Bit 2: last_block flag */
/* Bits 3-23: decompressed_size (max 1 MB) */
/* Bits 24-31: reserved */
uint32_t packed;
} vv_block_header_t;
/* Frame footer: 12 bytes */
typedef struct {
uint64_t checksum; /* XXH64 of decompressed content */
uint32_t footer_magic; /* 0x56564E44 = "VVND" */
} vv_frame_footer_t;
#pragma pack(pop)
/* Block header accessors defined above with block type enum */
/* ═══════════════════════════════════════════════════════════════
* MATCHER STATE
* */
#define VV_HC_BITS 18
#define VV_HC_SIZE (1u << VV_HC_BITS)
typedef struct {
int32_t table[VV_HC_SIZE]; /* Hash → most recent position */
int32_t *chain; /* Chain array (window_size entries) */
uint32_t window_size;
uint32_t chain_depth; /* Max chain traversal (level-dependent) */
} vv_matcher_t;
/* ═══════════════════════════════════════════════════════════════
* HUFFMAN TABLES (entropy coding)
*
* 256-symbol alphabet. Max code length 12 bits.
* Decode table: 4096 entries × 2 bytes = 8 KB (fits in L1).
* */
#define VV_HUF_MAX_BITS 12
#define VV_HUF_TABLE_SIZE (1 << VV_HUF_MAX_BITS)
typedef struct {
uint8_t lengths[256]; /* Code lengths per symbol */
uint16_t codes[256]; /* Canonical codes (for encoding) */
/* Decode table: entry = (symbol << 8) | num_bits */
uint16_t decode[VV_HUF_TABLE_SIZE];
} vv_huffman_t;
/* ═══════════════════════════════════════════════════════════════
* ENCODER/DECODER OPTIONS
* */
typedef struct {
vv_mode_t mode;
uint8_t window_log; /* 0 = auto (20 for balanced, 24 for extreme) */
int checksum; /* 1 = compute XXH64 */
int verbose;
int format_v2; /* 1 = produce 'T' tag blocks (min_match=3) for
* better real-binary ratio. Requires decoder
* v2.33.0+. Default 0 for back-compat. */
int compat_v246_5_decoder;
/* 1 = suppress lit_fmt=4 (4-stream Huffman) in
* SEQ block encode race. Required when
* output must be readable by v2.46.5 or
* older decoders. Default 0 (lit_fmt=4
* enabled, requires v2.47+ decoder). */
} vv_options_t;
static inline void vv_default_options(vv_options_t *o) {
o->mode = VV_MODE_BALANCED;
o->window_log = 0;
o->checksum = 1;
o->verbose = 0;
o->format_v2 = 0;
o->compat_v246_5_decoder = 0;
}
/* ═══════════════════════════════════════════════════════════════
* PUBLIC API ONE-SHOT
* */
/* Compress src[0..src_len-1] into dst[0..dst_cap-1].
* Returns compressed size, or negative error code. */
int64_t vv_compress(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
const vv_options_t *opts);
/* Decompress src[0..src_len-1] into dst[0..dst_cap-1].
* Returns decompressed size, or negative error code. */
int64_t vv_decompress(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap);
/* Flags for vv_decompress_flags (bitmask) */
#define VV_DECOMPRESS_DEFAULT 0x0
#define VV_DECOMPRESS_SKIP_CHECKSUM 0x1 /* Skip XXH64 footer verification.
*
* Use when the caller has its own
* integrity protection (e.g. AES-GCM
* wrapping the compressed data, as in
* Zupt backups). On RAW/random-data
* inputs where XXH64 dominates decode
* time, this flag delivers a ~2× speedup.
*
* SAFETY: only set when another layer
* already detects tampering/corruption.
* Without any integrity check, silent
* data corruption can go undetected. */
/* Decompress with flags. Returns decompressed size, or negative error code.
* Equivalent to vv_decompress() when flags == VV_DECOMPRESS_DEFAULT. */
int64_t vv_decompress_flags(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
uint32_t flags);
/* Compute upper bound on compressed size for src_len input bytes. */
size_t vv_compress_bound(size_t src_len);
/* ═══════════════════════════════════════════════════════════════
* MULTI-THREADED COMPRESSION
*
* Compresses large inputs in parallel by splitting into independent
* frames (each a valid .vv frame on its own concatenated output
* is a valid .vv file that vv_decompress handles natively as a
* multi-frame stream).
*
* Requires the library to be built with VV_ENABLE_THREADS (and
* linked with -lpthread on POSIX). If threads are not available,
* the function falls back to sequential single-threaded encoding,
* producing bit-identical output to vv_compress.
*
* Tradeoff: multi-frame output is ~0.5-2% larger than a single
* vv_compress frame because cross-frame match history is lost. Use
* for inputs 4 MB where parallel speedup outweighs the ratio cost.
* */
/* Compress src in parallel using up to nthreads worker threads.
* If nthreads is 0, uses the number of online CPUs (or 1 if that
* cannot be determined). If the library was built without threading,
* this acts exactly like vv_compress (nthreads is ignored).
*
* chunk_size controls the frame split size must be 1 MB for
* reasonable compression ratio. If 0, defaults to 4 MB.
*
* Returns compressed size on success, negative error code on failure. */
int64_t vv_compress_mt(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
const vv_options_t *opts,
unsigned int nthreads,
size_t chunk_size);
/* Frame info extracted from the first 16 bytes of a compressed stream.
* Populated by vv_get_frame_info(). */
typedef struct {
uint8_t version; /* Format version */
uint8_t has_checksum; /* Non-zero if frame has XXH64 footer */
uint8_t mode_hint; /* Compression mode used (informational) */
uint8_t window_log; /* Window size = 1 << window_log */
uint64_t content_size; /* Uncompressed size if known (0 = unknown) */
} vv_frame_info_t;
/* Parse the first 16 bytes of a compressed stream to extract frame
* metadata. Requires src_len >= 16. Useful for pre-allocating the
* output buffer when content_size is known (e.g., streams produced
* by the one-shot vv_compress API always carry content_size).
*
* Returns VV_OK on success, negative error code on bad magic /
* unsupported version / too-short input. */
int vv_get_frame_info(const uint8_t *src, size_t src_len,
vv_frame_info_t *info);
/* ═══════════════════════════════════════════════════════════════
* STREAMING API for large files, memory-constrained use, or
* when the full input/output isn't known in advance.
*
* Compress:
* ctx = vv_cstream_create(&opts);
* for each chunk: vv_cstream_compress_chunk(ctx, chunk, len, dst, dst_cap, &written, is_last);
* vv_cstream_destroy(ctx);
*
* Decompress:
* ctx = vv_dstream_create();
* for each incoming block: vv_dstream_decompress_chunk(ctx, src, len, dst, dst_cap, &read, &written);
* vv_dstream_destroy(ctx);
*
* Compression is block-at-a-time: caller accumulates source data in
* chunks of up to VV_MAX_BLOCK_SIZE (1 MB). Each call to
* vv_cstream_compress_chunk emits one compressed block (or the frame
* header on the first call, and the frame footer on the last).
*
* Decompression accepts arbitrary byte chunks and emits decoded bytes
* as blocks complete. Partial blocks are buffered internally.
* */
/* Opaque stream context types */
typedef struct vv_cstream_s vv_cstream_t;
typedef struct vv_dstream_s vv_dstream_t;
/* Create a new compression stream context.
* Returns NULL on allocation failure.
* If opts is NULL, uses default options (balanced mode, checksum=1).
* The context holds the matcher state; cross-block rep-match history
* and hash tables are preserved across chunks for optimal ratio. */
vv_cstream_t *vv_cstream_create(const vv_options_t *opts);
/* Reset a compression stream for reuse. Clears the matcher state,
* rep-match offsets, checksum accumulator, and emission flag so the
* context can be used to compress a new independent frame.
* Scratch buffers are preserved this is the fast path for
* per-file compression (e.g., backup tools compressing many small
* files), avoiding per-file allocation cost.
*
* If opts is NULL, reuses the options from the last create/reset.
* If opts is non-NULL, applies new options but window_log cannot
* change (would require re-allocating matcher tables). */
int vv_cstream_reset(vv_cstream_t *ctx, const vv_options_t *opts);
/* Compress one chunk of source into dst. chunk_len must be ≤
* VV_MAX_BLOCK_SIZE (1 MB). Set is_last=1 on the final call to emit
* the frame footer (checksum if enabled).
*
* Writes at most dst_cap bytes to dst; sets *written to the actual
* number of bytes emitted. Caller must ensure dst_cap
* vv_compress_bound(chunk_len) + 24 (frame header + footer).
*
* On the first call, the frame header is emitted before the first
* block. On the last call, the frame footer (if checksum enabled) is
* emitted after the final block.
*
* Returns VV_OK (0) on success, negative error code on failure. */
int vv_cstream_compress_chunk(vv_cstream_t *ctx,
const uint8_t *chunk, size_t chunk_len,
uint8_t *dst, size_t dst_cap,
size_t *written, int is_last);
/* Destroy a compression stream context and free all resources. */
void vv_cstream_destroy(vv_cstream_t *ctx);
/* Create a new decompression stream context.
* Returns NULL on allocation failure. */
vv_dstream_t *vv_dstream_create(void);
/* Reset a decompression stream for reuse. Clears state so the same
* context can decompress another independent frame. Internal buffer
* is preserved (but emptied), avoiding per-frame allocation cost. */
int vv_dstream_reset(vv_dstream_t *ctx);
/* Decompress a chunk of input. src may contain partial or multiple
* blocks; internal buffer holds incomplete blocks until enough input
* is available.
*
* IMPORTANT API CONTRACT:
* - `dst` MUST be the same stable buffer base across all calls for
* a single frame. The decoder tracks its own output position
* inside `dst` and requires it not to move between calls.
* - `dst_cap` MUST be large enough to hold the fully-decoded
* content of the current frame (the decoder does not support
* partial-output-then-resume semantics across a block boundary).
* - `*written` is set to the CUMULATIVE total bytes written into
* `dst` so far, NOT the delta for this call. If you need the
* per-call delta, subtract the previous value.
* - `*consumed` is per-call: how many `src` bytes were processed
* this call.
*
* Writing pattern:
* size_t total_written = 0;
* while (!done) {
* rc = vv_dstream_decompress_chunk(ds, chunk, chunk_len,
* dst, dst_cap, // stable
* &consumed, &written);
* total_written = written; // NOT += written
* ...
* }
*
* Returns VV_OK (0) if more input is needed, 1 if the frame ended
* successfully, or negative error code on failure. */
int vv_dstream_decompress_chunk(vv_dstream_t *ctx,
const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
size_t *consumed, size_t *written);
/* Destroy a decompression stream context and free all resources. */
void vv_dstream_destroy(vv_dstream_t *ctx);
/* ═══════════════════════════════════════════════════════════════
* INTERNAL HELPERS (shared across modules)
* */
/* XXH64 hash (simplified, for checksum) */
uint64_t vv_xxh64(const void *data, size_t len, uint64_t seed);
/* Streaming XXH64: init + update + finalize for when the input isn't
* contiguous in memory. Must produce the same 64-bit hash as a
* single-shot vv_xxh64() over the concatenated input. */
typedef struct {
uint64_t v1, v2, v3, v4;
uint64_t total_len;
uint64_t seed;
uint8_t buf[32];
size_t buf_len;
} vv_xxh64_state_t;
void vv_xxh64_init(vv_xxh64_state_t *s, uint64_t seed);
void vv_xxh64_update(vv_xxh64_state_t *s, const void *data, size_t len);
uint64_t vv_xxh64_finalize(const vv_xxh64_state_t *s);
/* Hash function for matcher */
static inline uint32_t vv_hash4(const uint8_t *p) {
uint32_t v;
memcpy(&v, p, 4);
return (v * 2654435761u) >> (32 - VV_HC_BITS);
}
/* Read/write little-endian helpers */
static inline uint16_t vv_read16(const uint8_t *p) {
uint16_t v; memcpy(&v, p, 2); return v;
}
static inline uint32_t vv_read32(const uint8_t *p) {
uint32_t v; memcpy(&v, p, 4); return v;
}
static inline void vv_write16(uint8_t *p, uint16_t v) {
memcpy(p, &v, 2);
}
static inline void vv_write32(uint8_t *p, uint32_t v) {
memcpy(p, &v, 4);
}
/* ═══════════════════════════════════════════════════════════════
* SIMD COPY HELPERS (declared here, defined in vv_simd.c)
* */
/* Copy exactly n bytes, may over-read/write by up to 32 bytes.
* Caller must ensure sufficient slack in destination. */
void vv_copy_fast(uint8_t *dst, const uint8_t *src, size_t n);
/* Copy match with overlap handling (offset may be < copy length). */
void vv_copy_match(uint8_t *dst, uint32_t offset, size_t length);
#ifdef __cplusplus
}
#endif
#endif /* VAPTVUPT_H */

43
vendor/vuptsdk/include/vaptvupt_api.h vendored Normal file
View file

@ -0,0 +1,43 @@
/*
* VaptVupt Zupt Integration API
* SPDX-License-Identifier: GPL-3.0-or-later
* Copyright 2026 Cristian.
*
* ZUPT-COMPAT: This is the API that Zupt calls. It wraps the internal
* VaptVupt API with sensible defaults for backup workloads:
* - Checksum always enabled (data integrity is critical for backups)
* - Adaptive window selection (auto-detect optimal wlog per file)
* - Level maps to mode: 1=fast, 5=balanced, 9=extreme
*
* Usage:
* size_t bound = vvz_compress_bound(src_len);
* uint8_t *dst = malloc(bound);
* int64_t csz = vvz_compress(src, src_len, dst, bound, 5);
* int64_t dsz = vvz_decompress(dst, csz, out, out_cap);
*/
#ifndef VAPTVUPT_API_H
#define VAPTVUPT_API_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Compress src into dst. Returns compressed size or negative error code.
* level: 1 = fast (max speed), 5 = balanced (default), 9 = extreme (max ratio) */
int64_t vvz_compress(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap, int level);
/* Decompress src into dst. Returns decompressed size or negative error code. */
int64_t vvz_decompress(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap);
/* Upper bound on compressed size for a given input length. */
size_t vvz_compress_bound(size_t src_len);
#ifdef __cplusplus
}
#endif
#endif /* VAPTVUPT_API_H */

145
vendor/vuptsdk/include/vv_ans.h vendored Normal file
View file

@ -0,0 +1,145 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* VaptVupt tANS Entropy Codec (v2: sparse header + 4-way interleaved)
*
* Standalone: define VV_ANS_STANDALONE to use without VaptVupt.
* ZUPT-COMPAT: this header has zero VaptVupt dependencies when standalone.
*
* v0.6 changes:
* - Adaptive sparse/dense header (Item 1): 3× smaller on typical data
* - 4-way interleaved encode/decode (Item 2): ~2.5× faster decode
*/
#ifndef VV_ANS_H
#define VV_ANS_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#define VVA_TABLE_LOG 12
#define VVA_TABLE_SIZE (1 << VVA_TABLE_LOG) /* 4096 */
#define VVA_MAX_SYMBOL 256
/* Header format discriminators */
#define VVA_HDR_SINGLE 0x01 /* Single symbol: 0-bit encoding */
#define VVA_HDR_SPARSE 0x02 /* ≤32 active symbols: (sym,freq) pairs */
#define VVA_HDR_DENSE 0x03 /* >32 active symbols: max_sym + freq array */
/* ZUPT-COMPAT: v0.5 legacy format detected by first byte being 0x00-0xFF
* without matching any HDR_* code fall back to old read path. */
#define VVA_HDR_LEGACY 0x00 /* v0.5 format: [max_sym] [2B×(max_sym+1)] */
#ifdef VV_ANS_STANDALONE
typedef enum {
VVA_OK = 0,
VVA_ERR_IO = -1,
VVA_ERR_CORRUPT = -2,
VVA_ERR_NOMEM = -3,
VVA_ERR_OVERFLOW = -4,
VVA_ERR_PARAM = -6,
} vva_error_t;
#else
#include "vaptvupt.h"
typedef vv_error_t vva_error_t;
#define VVA_OK VV_OK
#define VVA_ERR_CORRUPT VV_ERR_CORRUPT
#define VVA_ERR_NOMEM VV_ERR_NOMEM
#define VVA_ERR_OVERFLOW VV_ERR_OVERFLOW
#define VVA_ERR_PARAM VV_ERR_PARAM
#endif
typedef struct {
uint8_t symbol;
uint8_t nbits;
uint16_t baseline;
} vva_dec_entry_t;
/* ═══ Public API ═══ */
/* Single-stream encode/decode (tag 'A', backward compat with v0.5) */
vva_error_t vva_encode(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len);
vva_error_t vva_decode(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
size_t num_literals, size_t *src_consumed);
/* 4-way interleaved encode/decode (tag 'I', v0.6+) */
vva_error_t vva_encode4(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len);
vva_error_t vva_decode4(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
size_t num_literals, size_t *src_consumed);
/* Order-1 context model encode/decode (tag 'C', v0.7+)
* Uses 256 ANS tables one per previous byte. Contexts with too few
* observations inherit from the global table. 4 MB decode memory. */
vva_error_t vva_encode_ctx(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len);
vva_error_t vva_decode_ctx(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
size_t num_literals, size_t *src_consumed);
/* ═══ Sequence coding (tag 'S', v0.8+) ═══
* ZUPT-COMPAT: available when VV_ANS_STANDALONE is defined.
*
* Encodes an LZ token stream using 3 ANS tables: literals, match-length
* codes (36 symbols), and offset codes (24 symbols). Replaces raw varint
* storage of match metadata, saving 8-15% on typical data.
*
* Input token format (from LZ engine):
* [token: litlen:4|matchlen:4] [litlen_ext] [literal_bytes] [2B offset LE] [matchlen_ext]
* Output: [3 table headers] [4B seq_count] [4B lit_count] [ANS bitstream]
*/
#define VVA_ML_CODES 36 /* Match length code count */
#define VVA_OF_CODES 27 /* Offset code count: 3 rep + 24 explicit */
#define VVA_LL_CODES 36 /* Literal-run length code count (covers 0-65536+) */
vva_error_t vva_encode_sequences(const uint8_t *tokens, size_t tok_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len,
int off_bytes);
/* Format-v2 variant: encodes match-length codes using ml_base_v2
* (min_match=3). Used for 'T' tag blocks. Added v2.34.0. */
vva_error_t vva_encode_sequences_v2(const uint8_t *tokens, size_t tok_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len,
int off_bytes);
/* Sprint 105 Phase C: variants accepting disable_huf4 flag.
* disable_huf4=1 suppresses lit_fmt=4 (4-stream Huffman) selection
* for v2.46.5 and older decoder compatibility. */
vva_error_t vva_encode_sequences_compat(const uint8_t *tokens, size_t tok_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len,
int off_bytes, int disable_huf4);
vva_error_t vva_encode_sequences_v2_compat(const uint8_t *tokens, size_t tok_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len,
int off_bytes, int disable_huf4);
vva_error_t vva_decode_sequences(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len,
const uint8_t *dst_base);
/* Format-v2 variant: same wire payload as vva_decode_sequences but
* interprets match-length codes with a table shifted down by 1
* (min_match=3 instead of 4). Produced by tag 'T' (VV_ENTROPY_SEQ_V2)
* blocks; closes the ~10% binary-compression gap vs gzip-9. Added
* v2.33.0. */
vva_error_t vva_decode_sequences_v2(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len,
const uint8_t *dst_base);
static inline size_t vva_bound(size_t src_len) {
/* Context model header can be up to ~10KB, seq coding adds 3 table headers */
return 12288 + (src_len * 15 + 7) / 8 + 16;
}
#ifdef __cplusplus
}
#endif
#endif /* VV_ANS_H */

171
vendor/vuptsdk/include/vv_huffman.h vendored Normal file
View file

@ -0,0 +1,171 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* VaptVupt Canonical Huffman Codec
*
* Standalone header: can be used independently with VV_HUFFMAN_STANDALONE.
* Designed for embedding in Zupt or any other LZ codec.
*
* API:
* vvh_encode() compress raw literals into Huffman bitstream
* vvh_decode() decompress Huffman bitstream back to raw literals
*
* Format:
* [1B max_symbol] [packed nibble code lengths] [LSB-first bitstream]
*
* Performance targets:
* Encode: 150 MB/s Decode: 800 MB/s (x86-64, -O2)
*/
#ifndef VV_HUFFMAN_H
#define VV_HUFFMAN_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ═══════════════════════════════════════════════════════════════
* CONSTANTS
* */
#define VVH_SYMBOLS 256
#define VVH_MAX_CODE_LEN 15
#define VVH_DECODE_BITS 12
#define VVH_DECODE_SIZE (1 << VVH_DECODE_BITS) /* 4096 entries */
/* ═══════════════════════════════════════════════════════════════
* ERROR CODES (compatible with vv_error_t when not standalone)
* */
#ifdef VV_HUFFMAN_STANDALONE
typedef enum {
VVH_OK = 0,
VVH_ERR_CORRUPT = -2,
VVH_ERR_NOMEM = -3,
VVH_ERR_OVERFLOW= -4,
} vvh_error_t;
#else
#include "vaptvupt.h"
typedef vv_error_t vvh_error_t;
#define VVH_OK VV_OK
#define VVH_ERR_CORRUPT VV_ERR_CORRUPT
#define VVH_ERR_NOMEM VV_ERR_NOMEM
#define VVH_ERR_OVERFLOW VV_ERR_OVERFLOW
#endif
/* ═══════════════════════════════════════════════════════════════
* ENCODE TABLE (used by encoder only)
* */
typedef struct {
uint8_t lengths[VVH_SYMBOLS]; /* Code length per symbol (0 = absent) */
uint16_t codes[VVH_SYMBOLS]; /* Bit-reversed canonical codes (LSB-first) */
} vvh_enc_table_t;
/* ═══════════════════════════════════════════════════════════════
* DECODE TABLE (used by decoder only)
*
* 12-bit lookup: 4096 entries × 4 bytes = 16 KB (L1-resident).
* Entry: bits [7:0] = symbol, bits [11:8] = code length.
* Symbols with code length > 12 use a slow path.
* */
typedef struct {
uint32_t table[VVH_DECODE_SIZE]; /* Fast lookup (codes ≤ 12 bits) */
/* Slow table for codes 13-15 bits (max 256 entries) */
uint16_t slow_code[VVH_SYMBOLS]; /* Bit-reversed code */
uint8_t slow_len[VVH_SYMBOLS]; /* Code length */
uint8_t slow_sym[VVH_SYMBOLS]; /* Symbol value */
int slow_count; /* Number of slow-path symbols */
} vvh_dec_table_t;
/* ═══════════════════════════════════════════════════════════════
* PUBLIC API
* */
/*
* Encode raw literal bytes into Huffman bitstream.
*
* src[0..src_len-1] raw literal bytes
* dst[0..dst_cap-1] output buffer (header + bitstream)
* *dst_len on success, set to actual compressed size
*
* Returns VVH_OK on success, or VVH_ERR_OVERFLOW if dst too small.
* If compressed size >= src_len, returns VVH_ERR_OVERFLOW (incompressible).
*/
vvh_error_t vvh_encode(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len);
/*
* Decode Huffman bitstream back to raw literal bytes.
*
* src[0..src_len-1] compressed data (header + bitstream)
* dst[0..dst_cap-1] output buffer for decoded literals
* num_literals expected number of decoded symbols
* *src_consumed on success, bytes consumed from src
*
* Returns VVH_OK on success, or error code.
*/
vvh_error_t vvh_decode(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
size_t num_literals, size_t *src_consumed);
/*
* 4-stream interleaved Huffman encode (Sprint 103, Phase A).
*
* Encodes src into 4 round-robin bitstreams sharing a single Huffman
* code table. The output format is:
*
* [code-length header (existing format)]
* [3B stream1_size] [3B stream2_size] [3B stream3_size]
* [stream0_bitstream] [stream1_bitstream]
* [stream2_bitstream] [stream3_bitstream]
*
* Activation guard: requires src_len >= 1024. Below this threshold,
* single-stream vvh_encode wins on overhead and this function returns
* VVH_ERR_OVERFLOW.
*
* NOTE (Phase A): Production decoder support arrives in Phase B.
* This sprint adds only the encoder + a test-only inverse decoder
* (in tests/test_huffman4.c) for round-trip verification.
*
* Returns VVH_OK on success.
* Returns VVH_ERR_OVERFLOW if src_len < 1024, dst too small, or output
* not smaller than input.
*/
vvh_error_t vvh_encode4(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap, size_t *dst_len);
/*
* 4-stream interleaved Huffman decode (Sprint 104, Phase B).
*
* Inverse of vvh_encode4. Decodes the 4-stream wire format produced
* by vvh_encode4. Runs 4 independent decoders in parallel using a
* single shared decode table.
*
* src[0..src_len-1] compressed data (header + stream-sizes + 4 streams)
* dst[0..dst_cap-1] output buffer for decoded literals
* num_literals expected number of decoded symbols
* *src_consumed on success, bytes consumed from src
*
* Returns VVH_OK on success, VVH_ERR_CORRUPT on malformed input,
* VVH_ERR_OVERFLOW if dst is too small, VVH_ERR_NOMEM on alloc failure.
*/
vvh_error_t vvh_decode4(const uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_cap,
size_t num_literals, size_t *src_consumed);
/*
* Upper bound on compressed size for src_len literal bytes.
*/
static inline size_t vvh_bound(size_t src_len) {
/* header (129 max) + bitstream (15 bits/symbol worst case) + slack */
return 129 + (src_len * 15 + 7) / 8 + 8;
}
#ifdef __cplusplus
}
#endif
#endif /* VV_HUFFMAN_H */

139
vendor/vuptsdk/include/vv_platform.h vendored Normal file
View file

@ -0,0 +1,139 @@
/*
* VaptVupt Cross-platform portability macros
*
* Provides unified abstractions for compiler intrinsics used throughout
* the codebase. Supports GCC, Clang, MSVC, and Intel compilers.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef VV_PLATFORM_H
#define VV_PLATFORM_H
#include <string.h>
#include <stdint.h>
/* ─── Branch prediction hints ─── */
#if defined(__GNUC__) || defined(__clang__)
#define VV_LIKELY(x) __builtin_expect(!!(x), 1)
#define VV_UNLIKELY(x) __builtin_expect(!!(x), 0)
#else
#define VV_LIKELY(x) (x)
#define VV_UNLIKELY(x) (x)
#endif
/* ─── Prefetch hint ─── */
#if defined(__GNUC__) || defined(__clang__)
#define VV_PREFETCH(p) __builtin_prefetch((p), 0, 1)
#define VV_PREFETCH_RW(p) __builtin_prefetch((p), 1, 1)
#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
#include <emmintrin.h>
#define VV_PREFETCH(p) _mm_prefetch((const char*)(p), _MM_HINT_T1)
#define VV_PREFETCH_RW(p) _mm_prefetch((const char*)(p), _MM_HINT_T1)
#else
#define VV_PREFETCH(p) ((void)0)
#define VV_PREFETCH_RW(p) ((void)0)
#endif
/* ─── Always-inline / never-inline ─── */
#if defined(__GNUC__) || defined(__clang__)
#define VV_ALWAYS_INLINE static inline __attribute__((always_inline))
#define VV_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define VV_ALWAYS_INLINE static __forceinline
#define VV_NOINLINE __declspec(noinline)
#else
#define VV_ALWAYS_INLINE static inline
#define VV_NOINLINE
#endif
/* ─── Unused parameter suppression ─── */
#if defined(__GNUC__) || defined(__clang__)
#define VV_UNUSED __attribute__((unused))
#else
#define VV_UNUSED
#endif
/* ─── Portable unaligned load/store via memcpy (compiler optimizes to single instr) ─── */
static inline uint16_t vv_load16(const void *p) {
uint16_t v; memcpy(&v, p, 2); return v;
}
static inline uint32_t vv_load32(const void *p) {
uint32_t v; memcpy(&v, p, 4); return v;
}
static inline uint64_t vv_load64(const void *p) {
uint64_t v; memcpy(&v, p, 8); return v;
}
static inline void vv_store16(void *p, uint16_t v) { memcpy(p, &v, 2); }
static inline void vv_store32(void *p, uint32_t v) { memcpy(p, &v, 4); }
static inline void vv_store64(void *p, uint64_t v) { memcpy(p, &v, 8); }
/* ─── Count trailing zeros (for hash/match optimization) ─── */
#if defined(__GNUC__) || defined(__clang__)
static inline int vv_ctz32(uint32_t x) { return __builtin_ctz(x); }
static inline int vv_ctz64(uint64_t x) { return __builtin_ctzll(x); }
#elif defined(_MSC_VER)
#include <intrin.h>
static inline int vv_ctz32(uint32_t x) {
unsigned long idx; _BitScanForward(&idx, x); return (int)idx;
}
static inline int vv_ctz64(uint64_t x) {
#if defined(_M_X64) || defined(_M_ARM64)
unsigned long idx; _BitScanForward64(&idx, x); return (int)idx;
#else
uint32_t lo = (uint32_t)x;
if (lo) return vv_ctz32(lo);
return 32 + vv_ctz32((uint32_t)(x >> 32));
#endif
}
#else
static inline int vv_ctz32(uint32_t x) {
int n = 0; while (!(x & 1)) { x >>= 1; n++; } return n;
}
static inline int vv_ctz64(uint64_t x) {
int n = 0; while (!(x & 1)) { x >>= 1; n++; } return n;
}
#endif
/* ─── SIMD capability detection macros ─── */
#if defined(__AVX2__)
#define VV_HAS_AVX2 1
#else
#define VV_HAS_AVX2 0
#endif
#if defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
#define VV_HAS_SSE2 1
#else
#define VV_HAS_SSE2 0
#endif
#if defined(__aarch64__) && defined(__ARM_NEON)
#define VV_HAS_NEON 1
#else
#define VV_HAS_NEON 0
#endif
/* Sprint 117: explicit no_sanitize annotation for hardened builds.
*
* Several hot paths use intentional unsigned modular arithmetic:
* - Knuth multiplicative hashes in the LZ matcher
* - xxh64 round mixers (multiplication, left-shift)
* - Post-decrement loop guards (uint32_t depth-- > 0)
*
* C11 §6.2.5p9 defines unsigned overflow as wraparound, so these are
* NOT undefined behavior but `-fsanitize=integer` and the related
* `-fsanitize=shift-base` flags warn anyway, breaking hardened-build
* deployments. Apply this attribute to the affected functions to
* silence the false positives without disabling the checks globally.
*
* The annotation is clang-only (gcc has no equivalent and does not
* accept -fsanitize=integer in the first place). */
#if defined(__clang__) && (__clang_major__ >= 4)
# define VV_NO_SANITIZE_INTEGER \
__attribute__((no_sanitize("unsigned-integer-overflow", "shift", "shift-base", "shift-exponent")))
#else
# define VV_NO_SANITIZE_INTEGER
#endif
#endif /* VV_PLATFORM_H */

View file

@ -0,0 +1,39 @@
/*
* AES-256-GCM-SIV (RFC 8452)
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* Nonce-misuse-resistant AEAD. Nonce reuse degrades to deterministic
* encryption (same plaintext+key+nonce -> same ciphertext) rather than
* the catastrophic XOR-of-plaintexts of GCM/CTR.
*/
#ifndef ZSDK_AES256_GCM_SIV_H
#define ZSDK_AES256_GCM_SIV_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
#define ZSDK_AES256_GCM_SIV_KEYBYTES 32
#define ZSDK_AES256_GCM_SIV_NONCEBYTES 12
#define ZSDK_AES256_GCM_SIV_TAGBYTES 16
void zsdk_aes256_gcm_siv_encrypt(uint8_t *out,
const uint8_t *plaintext, size_t pt_len,
const uint8_t *aad, size_t aad_len,
const uint8_t key[32],
const uint8_t nonce[12]);
int zsdk_aes256_gcm_siv_decrypt(uint8_t *out,
const uint8_t *ciphertext, size_t ct_len,
const uint8_t *aad, size_t aad_len,
const uint8_t key[32],
const uint8_t nonce[12]);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,39 @@
/*
* AES-256-SIV (RFC 5297) via OpenSSL EVP
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* Provides nonce-misuse-resistant AEAD via SIV mode (S2V + CTR).
* Uses OpenSSL's audited implementation. Note: SIV uses a 64-byte key
* (two 32-byte halves) rather than a 32-byte key.
*/
#ifndef ZSDK_AES256_SIV_H
#define ZSDK_AES256_SIV_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
#define ZSDK_AES256_SIV_KEYBYTES 64 /* AES-256-SIV uses double key */
#define ZSDK_AES256_SIV_NONCEBYTES 16 /* Optional, can be variable */
#define ZSDK_AES256_SIV_TAGBYTES 16
void zsdk_aes256_siv_encrypt(uint8_t *out,
const uint8_t *plaintext, size_t pt_len,
const uint8_t *aad, size_t aad_len,
const uint8_t key[64],
const uint8_t nonce[16]);
int zsdk_aes256_siv_decrypt(uint8_t *out,
const uint8_t *ciphertext, size_t ct_len,
const uint8_t *aad, size_t aad_len,
const uint8_t key[64],
const uint8_t nonce[16]);
#ifdef __cplusplus
}
#endif
#endif

39
vendor/vuptsdk/include/zsdk_argon2id.h vendored Normal file
View file

@ -0,0 +1,39 @@
/*
* Argon2id (RFC 9106)
* Copyright (c) 2026 Cristian Cezar Moisés
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* Memory-hard password hashing function. Reference implementation
* (single-lane focus), verified against RFC 9106 §5 test vectors.
*/
#ifndef ZSDK_ARGON2ID_H
#define ZSDK_ARGON2ID_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
/* Returns 0 on success, -1 on parameter validation failure or alloc fail.
*
* passwd, passwd_len the password (any length)
* salt, salt_len random salt (>= 8 bytes recommended; >= 16 standard)
* memory_kib memory cost in KiB (>= 8 * lanes; we require >= 19456)
* iterations time cost (>= 1; we require >= 2)
* lanes parallelism (>= 1, <= 4 here)
* out, out_len output buffer (>= 4 bytes; typically 32)
*/
int zsdk_argon2id(const uint8_t *passwd, size_t passwd_len,
const uint8_t *salt, size_t salt_len,
uint32_t memory_kib,
uint32_t iterations,
uint32_t lanes,
uint8_t *out, size_t out_len);
#ifdef __cplusplus
}
#endif
#endif

46
vendor/vuptsdk/include/zsdk_blake2b.h vendored Normal file
View file

@ -0,0 +1,46 @@
/*
* BLAKE2b (RFC 7693)
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#ifndef ZSDK_BLAKE2B_H
#define ZSDK_BLAKE2B_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
#define ZSDK_BLAKE2B_BLOCKBYTES 128
#define ZSDK_BLAKE2B_OUTBYTES 64
typedef struct {
uint64_t h[8];
uint64_t t[2];
uint64_t f[2];
uint8_t buf[ZSDK_BLAKE2B_BLOCKBYTES];
size_t buflen;
size_t outlen;
} zsdk_blake2b_state;
int zsdk_blake2b_init(zsdk_blake2b_state *s, size_t outlen);
int zsdk_blake2b_init_key(zsdk_blake2b_state *s, size_t outlen,
const void *key, size_t keylen);
int zsdk_blake2b_update(zsdk_blake2b_state *s, const void *in, size_t inlen);
int zsdk_blake2b_final(zsdk_blake2b_state *s, void *out, size_t outlen);
/* One-shot. */
int zsdk_blake2b(void *out, size_t outlen,
const void *in, size_t inlen,
const void *key, size_t keylen);
/* Argon2's "long hash" H' producing arbitrary length output. */
int zsdk_blake2b_long(uint8_t *out, size_t outlen,
const uint8_t *in, size_t inlen);
#ifdef __cplusplus
}
#endif
#endif

41
vendor/vuptsdk/include/zsdk_hkdf.h vendored Normal file
View file

@ -0,0 +1,41 @@
/*
* HKDF-SHA3-256 (RFC 5869, with SHA3-256 as the hash)
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* SHA3-256 is preferred over SHA-256 here because Keccak's sponge
* construction has stronger structural properties (no length-extension,
* indifferentiable from a random oracle in the standard model).
*/
#ifndef ZSDK_HKDF_H
#define ZSDK_HKDF_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
#define ZSDK_HKDF_HASHLEN 32 /* SHA3-256 output size */
/* HKDF-Extract: PRK = HMAC-SHA3-256(salt, IKM) */
void zsdk_hkdf_extract(uint8_t prk[32],
const uint8_t *salt, size_t salt_len,
const uint8_t *ikm, size_t ikm_len);
/* HKDF-Expand: produces `out_len` bytes (out_len <= 255 * 32). */
int zsdk_hkdf_expand(uint8_t *out, size_t out_len,
const uint8_t prk[32],
const uint8_t *info, size_t info_len);
/* Convenience: extract+expand in one call. */
int zsdk_hkdf(uint8_t *out, size_t out_len,
const uint8_t *salt, size_t salt_len,
const uint8_t *ikm, size_t ikm_len,
const uint8_t *info, size_t info_len);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,57 @@
/*
* XChaCha20-Poly1305 AEAD
* Copyright (c) 2026 Cristian Cezar Moisés
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* Implements:
* - ChaCha20 (RFC 8439)
* - HChaCha20 (draft-irtf-cfrg-xchacha-03 §2.2)
* - XChaCha20 (draft-irtf-cfrg-xchacha-03 §2.3)
* - Poly1305 (RFC 8439 §2.5)
* - XChaCha20-Poly1305 AEAD (draft-irtf-cfrg-xchacha-03 §2.4)
*
* Constant-time implementation: no secret-dependent branches or memory
* accesses. Verified against RFC 8439 test vectors and Wycheproof corpus.
*/
#ifndef ZUPTSDK_XCHACHA20_POLY1305_H
#define ZUPTSDK_XCHACHA20_POLY1305_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ZSDK_XCHACHA20_POLY1305_KEYBYTES 32
#define ZSDK_XCHACHA20_POLY1305_NONCEBYTES 24
#define ZSDK_XCHACHA20_POLY1305_TAGBYTES 16
/* Encrypt: ciphertext_len = plaintext_len; tag is 16 bytes appended.
* out buffer size must be >= plaintext_len + 16. */
void zsdk_xchacha20_poly1305_encrypt(
uint8_t *out, /* [out] ciphertext || tag */
const uint8_t *plaintext,
size_t plaintext_len,
const uint8_t *aad,
size_t aad_len,
const uint8_t key[32],
const uint8_t nonce[24]);
/* Decrypt: returns 0 on success, -1 on tag mismatch (out untouched).
* out buffer size must be >= ciphertext_len - 16. */
int zsdk_xchacha20_poly1305_decrypt(
uint8_t *out, /* [out] plaintext */
const uint8_t *ciphertext, /* ciphertext || tag */
size_t ciphertext_len, /* includes 16-byte tag */
const uint8_t *aad,
size_t aad_len,
const uint8_t key[32],
const uint8_t nonce[24]);
#ifdef __cplusplus
}
#endif
#endif

401
vendor/vuptsdk/include/zupt.h vendored Normal file
View file

@ -0,0 +1,401 @@
/*
* Zupt Backup-oriented compression with AES-256 encryption
* Copyright (c) 2026 Cristian Cezar Moisés
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#ifndef ZUPT_H
#define ZUPT_H
/* Feature test macros — must precede all system includes.
* _DEFAULT_SOURCE gives us lstat() on glibc without -D_GNU_SOURCE. */
#if !defined(_DEFAULT_SOURCE) && !defined(_GNU_SOURCE)
#define _DEFAULT_SOURCE 1
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#define ZUPT_PATH_SEP '\\'
#define zupt_mkdir(p) _mkdir(p)
#else
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#define ZUPT_PATH_SEP '/'
#define zupt_mkdir(p) mkdir(p, 0755)
#endif
#define ZUPT_VERSION_STRING "2.2.3"
#define ZUPT_FORMAT_MAJOR 1
#define ZUPT_FORMAT_MINOR 4
#define ZUPT_MAGIC_0 0x5A
#define ZUPT_MAGIC_1 0x55
#define ZUPT_MAGIC_2 0x50
#define ZUPT_MAGIC_3 0x54
#define ZUPT_MAGIC_4 0x1A
#define ZUPT_MAGIC_5 0x00
#define ZUPT_BLOCK_MAGIC_0 0xBB
#define ZUPT_BLOCK_MAGIC_1 0x01
#define ZUPT_MAX_PATH 4096
#define ZUPT_MAX_FILES 2000000
#define ZUPT_DEFAULT_BLOCK_SZ (4 * 1024 * 1024)
#define ZUPT_MIN_BLOCK_SZ (64 * 1024)
#define ZUPT_MAX_BLOCK_SZ (256 * 1024 * 1024)
/* Global flags */
#define ZUPT_FLAG_ENCRYPTED (1u << 0)
#define ZUPT_FLAG_CKSUM_XXH64 (0u << 5)
#define ZUPT_FLAG_SOLID (1u << 1)
#define ZUPT_FLAG_MULTITHREADED (1u << 2) /* Informational: archive was produced with MT */
#define ZUPT_FLAG_PQ_HYBRID (1u << 3) /* Post-quantum hybrid encryption */
#define ZUPT_FLAG_FORMAT_STABLE (1u << 4) /* v1.0: format frozen */
#define ZUPT_FLAG_DEDUP (1u << 7) /* Block-level deduplication enabled */
#define ZUPT_FLAG_AAD_SEQ (1u << 8) /* MAC binds block_seq as AAD (anti-reorder) */
/* Encryption types (stored in encryption header block) */
#define ZUPT_ENC_PBKDF2 0x01 /* Password-based: PBKDF2 → AES-256-CTR + HMAC */
#define ZUPT_ENC_PQ_HYBRID 0x02 /* ML-KEM-768 + X25519 hybrid KEM (legacy XOR+SHA3) */
#define ZUPT_ENC_PQ_SDK_V2 0x03 /* libzuptsdk v2 header: HKDF combiner + commitment + HPKE binding */
#define ZUPT_ENC_PW_ARGON2 0x04 /* Password-based via libzuptsdk: Argon2id + XChaCha20-Poly1305 */
/* Block types */
#define ZUPT_BLOCK_DATA 0x00
#define ZUPT_BLOCK_INDEX 0x02
#define ZUPT_BLOCK_ENC_HEADER 0x03
#define ZUPT_BLOCK_DEDUP_REF 0x04 /* Dedup reference: payload = 8B offset of original block */
/* Block flags */
#define ZUPT_BFLAG_ENCRYPTED (1u << 0)
/* Codec IDs */
#define ZUPT_CODEC_STORE 0x0000
#define ZUPT_CODEC_ZUPT_LZ 0x0008
#define ZUPT_CODEC_ZUPT_LZH 0x0009 /* LZ77 + Huffman */
#define ZUPT_CODEC_ZUPT_LZHP 0x000A /* LZ77 + Huffman + Byte Prediction (default) */
#define ZUPT_CODEC_VAPTVUPT 0x0010 /* VAPTVUPT: VaptVupt LZ + ANS entropy codec */
#define ZUPT_CODEC_AUTO 0xFFFF /* Auto-detect: VaptVupt if AVX2, else LZHP */
/* Crypto */
#define ZUPT_SALT_SIZE 32
#define ZUPT_NONCE_SIZE 16
#define ZUPT_HMAC_SIZE 32
#define ZUPT_AES_KEY_SIZE 32
#define ZUPT_KDF_ITERATIONS 600000
typedef enum {
ZUPT_OK = 0, ZUPT_ERR_IO = -1, ZUPT_ERR_CORRUPT = -2,
ZUPT_ERR_BAD_MAGIC = -3, ZUPT_ERR_BAD_VERSION = -4,
ZUPT_ERR_BAD_CHECKSUM = -5, ZUPT_ERR_NOMEM = -6,
ZUPT_ERR_OVERFLOW = -7, ZUPT_ERR_INVALID = -8,
ZUPT_ERR_NOT_FOUND = -9, ZUPT_ERR_UNSUPPORTED = -10,
ZUPT_ERR_AUTH_FAIL = -11,
} zupt_error_t;
/* ─── On-disk (packed LE) ─── */
#pragma pack(push, 1)
typedef struct {
uint8_t magic[6];
uint8_t version_major, version_minor;
uint32_t global_flags;
uint64_t creation_time;
uint8_t archive_id[16];
uint64_t encryption_header_off;
uint64_t comment_offset;
uint8_t reserved[12];
} zupt_archive_header_t; /* 64 bytes */
typedef struct {
uint64_t index_offset;
uint64_t total_blocks;
uint64_t archive_checksum;
uint8_t footer_magic[4]; /* "ZEND" */
uint32_t footer_version;
} zupt_footer_t; /* 32 bytes */
#pragma pack(pop)
/* ─── In-memory ─── */
typedef struct {
char path[ZUPT_MAX_PATH];
uint64_t uncompressed_size, compressed_size;
uint64_t modification_time, content_hash;
uint64_t first_block_offset;
uint32_t block_count, attributes;
} zupt_index_entry_t;
typedef struct {
uint8_t block_type; uint16_t codec_id, block_flags;
uint64_t uncompressed_size, compressed_size, checksum;
uint8_t *payload;
} zupt_block_t;
/* Buffer canary for keyring overflow detection */
#define ZUPT_CANARY 0xDEADCAFEBABEFACEULL
typedef struct {
uint64_t canary_head; /* Must equal ZUPT_CANARY */
uint8_t enc_key[ZUPT_AES_KEY_SIZE];
uint8_t mac_key[ZUPT_HMAC_SIZE];
uint8_t salt[ZUPT_SALT_SIZE];
uint8_t base_nonce[ZUPT_NONCE_SIZE];
uint32_t iterations;
int active;
uint64_t canary_tail; /* Must equal ZUPT_CANARY */
} zupt_keyring_t;
/* Check keyring canaries — abort on buffer overflow */
static inline void zupt_keyring_init(zupt_keyring_t *kr) {
volatile uint8_t *p = (volatile uint8_t *)kr;
for (size_t i = 0; i < sizeof(*kr); i++) p[i] = 0;
kr->canary_head = ZUPT_CANARY;
kr->canary_tail = ZUPT_CANARY;
}
static inline void zupt_keyring_check(const zupt_keyring_t *kr) {
if (kr->canary_head != ZUPT_CANARY || kr->canary_tail != ZUPT_CANARY) {
fprintf(stderr, "FATAL: keyring buffer overflow detected (canary corrupted)\n");
/* Use exit(127) instead of abort() to avoid needing <stdlib.h> */
_exit(127);
}
}
typedef struct {
char **paths, **arc_paths;
int count, capacity;
} zupt_filelist_t;
typedef struct {
int level; uint32_t block_size; uint16_t codec_id;
int verbose, encrypt, quiet, solid, threads;
int pq_mode; /* 1 = post-quantum hybrid KEM mode */
int sdk_mode; /* 1 = use libzuptsdk-backed v3 crypto (HKDF combiner + commitment + HPKE) */
int dedup; /* 1 = block-level deduplication enabled */
char password[256];
char keyfile[ZUPT_MAX_PATH]; /* Path to .zupt-key file */
zupt_keyring_t keyring;
} zupt_options_t;
/* ═══════════════════════════════════════════════════════════════════
* PORTABLE LITTLE-ENDIAN SERIALIZATION
*
* All multi-byte fields in the on-disk format are stored as LE.
* These helpers ensure correct behaviour on both LE and BE hosts.
* */
static inline void zupt_le16_put(uint8_t *p, uint16_t v) {
p[0] = (uint8_t)(v & 0xFF);
p[1] = (uint8_t)((v >> 8) & 0xFF);
}
static inline void zupt_le32_put(uint8_t *p, uint32_t v) {
p[0] = (uint8_t)(v & 0xFF);
p[1] = (uint8_t)((v >> 8) & 0xFF);
p[2] = (uint8_t)((v >> 16) & 0xFF);
p[3] = (uint8_t)((v >> 24) & 0xFF);
}
static inline void zupt_le64_put(uint8_t *p, uint64_t v) {
for (int i = 0; i < 8; i++) { p[i] = (uint8_t)(v & 0xFF); v >>= 8; }
}
static inline uint16_t zupt_le16_get(const uint8_t *p) {
return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8));
}
static inline uint32_t zupt_le32_get(const uint8_t *p) {
return (uint32_t)p[0] | ((uint32_t)p[1] << 8) |
((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24);
}
static inline uint64_t zupt_le64_get(const uint8_t *p) {
uint64_t v = 0;
for (int i = 7; i >= 0; i--) v = (v << 8) | p[i];
return v;
}
/* ═══════════════════════════════════════════════════════════════════
* SECURE MEMORY WIPE (resists dead-store elimination by compilers)
* */
/* FRAMA-C: Secure memory wipe — resists dead-store elimination */
/*@ requires \valid((uint8_t *)ptr + (0..len-1));
@ assigns ((uint8_t *)ptr)[0..len-1];
@ ensures \forall integer i; 0 <= i < len ==> ((uint8_t *)ptr)[i] == 0;
*/
static inline void zupt_secure_wipe(void *ptr, size_t len) {
#if defined(_WIN32)
SecureZeroMemory(ptr, len);
#elif (defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)))
extern void explicit_bzero(void *, size_t);
explicit_bzero(ptr, len);
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
extern void explicit_bzero(void *, size_t);
explicit_bzero(ptr, len);
#else
volatile uint8_t *vp = (volatile uint8_t *)ptr;
for (size_t i = 0; i < len; i++) vp[i] = 0;
#endif
}
/* ═══════════════════════════════════════════════════════════════════
* REGULAR-FILE CHECK (skip symlinks, devices, FIFOs, sockets)
* */
static inline int zupt_is_regular_file(const char *path) {
#ifdef _WIN32
DWORD attr = GetFileAttributesA(path);
if (attr == INVALID_FILE_ATTRIBUTES) return 0;
return !(attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE |
FILE_ATTRIBUTE_REPARSE_POINT));
#else
struct stat st;
if (lstat(path, &st) != 0) return 0;
return S_ISREG(st.st_mode);
#endif
}
/* ─── Solid-mode compression ─── */
zupt_error_t zupt_compress_solid(const char *out, const char **arc, const char **disk, int n, zupt_options_t *opts);
/* ─── SHA-256 ─── */
typedef struct { uint32_t state[8]; uint64_t count; uint8_t buf[64]; } zupt_sha256_ctx;
void zupt_sha256_init(zupt_sha256_ctx *c);
void zupt_sha256_update(zupt_sha256_ctx *c, const uint8_t *d, size_t n);
void zupt_sha256_final(zupt_sha256_ctx *c, uint8_t h[32]);
void zupt_sha256(const uint8_t *d, size_t n, uint8_t h[32]);
/* ─── AES-256 ─── */
typedef struct { uint32_t rk[60]; } zupt_aes256_ctx;
void zupt_aes256_init(zupt_aes256_ctx *c, const uint8_t key[32]);
void zupt_aes256_encrypt_block(const zupt_aes256_ctx *c, const uint8_t in[16], uint8_t out[16]);
/* ─── Crypto ops ─── */
void zupt_hmac_sha256(const uint8_t *key, size_t klen, const uint8_t *data, size_t dlen, uint8_t mac[32]);
void zupt_pbkdf2_sha256(const uint8_t *pw, size_t pwlen, const uint8_t *salt, size_t slen, uint32_t iter, uint8_t *out, size_t olen);
void zupt_aes256_ctr(const uint8_t key[32], const uint8_t nonce[16], const uint8_t *in, uint8_t *out, size_t len);
void zupt_derive_keys(zupt_keyring_t *kr, const char *pw, const uint8_t salt[32], const uint8_t nonce[16], uint32_t iter);
uint8_t *zupt_encrypt_buffer(const zupt_keyring_t *kr, const uint8_t *plain, size_t plen, uint64_t seq, size_t *olen);
uint8_t *zupt_decrypt_buffer(const zupt_keyring_t *kr, const uint8_t *pkg, size_t pkglen, uint64_t seq, size_t *olen);
void zupt_random_bytes(uint8_t *buf, size_t len);
/* ─── Memory locking for key material ─── */
int zupt_mlock_keys(void *ptr, size_t len);
void zupt_munlock_keys(void *ptr, size_t len);
/* ─── Adaptive compression: file type detection ─── */
/* Returns: -1=store (incompressible), 0=default, 5=medium, 9=max */
int zupt_detect_filetype(const uint8_t *header, size_t header_len);
/* ─── XXH64 ─── */
uint64_t zupt_xxh64(const void *data, size_t len, uint64_t seed);
/* ─── LZ ─── */
size_t zupt_lz_compress(const uint8_t *src, size_t slen, uint8_t *dst, size_t dcap, int level);
size_t zupt_lz_decompress(const uint8_t *src, size_t slen, uint8_t *dst, size_t dlen);
size_t zupt_lz_bound(size_t slen);
/* ─── LZH (LZ77 + Huffman) ─── */
size_t zupt_lzh_compress(const uint8_t *src, size_t slen, uint8_t *dst, size_t dcap, int level);
size_t zupt_lzh_decompress(const uint8_t *src, size_t slen, uint8_t *dst, size_t dlen);
size_t zupt_lzh_bound(size_t slen);
/* ─── Byte Prediction (order-1 context transform) ─── */
void zupt_predict_build(const uint8_t *data, size_t len, uint8_t prediction[256]);
void zupt_predict_encode(const uint8_t *in, uint8_t *out, size_t len, const uint8_t pred[256]);
void zupt_predict_decode(const uint8_t *in, uint8_t *out, size_t len, const uint8_t pred[256]);
float zupt_predict_benefit(const uint8_t *data, size_t len);
/* ─── Format I/O ─── */
int zupt_write_varint(FILE *f, uint64_t v);
int zupt_read_varint(FILE *f, uint64_t *v);
int zupt_encode_varint(uint8_t *b, uint64_t v);
int zupt_decode_varint(const uint8_t *b, size_t blen, uint64_t *v);
void zupt_filelist_init(zupt_filelist_t *fl);
void zupt_filelist_free(zupt_filelist_t *fl);
void zupt_filelist_add(zupt_filelist_t *fl, const char *disk_path, const char *arc_path);
void zupt_collect_files(zupt_filelist_t *fl, const char *path, const char *base);
zupt_error_t zupt_compress_files(const char *out, const char **arc, const char **disk, int n, zupt_options_t *opts);
zupt_error_t zupt_extract_archive(const char *arc, const char *dir, zupt_options_t *opts);
zupt_error_t zupt_list_archive(const char *arc, zupt_options_t *opts);
zupt_error_t zupt_test_archive(const char *arc, zupt_options_t *opts);
/* ─── Hybrid PQ KEM (ML-KEM-768 + X25519) ─── */
int zupt_hybrid_keygen(const char *keyfile);
int zupt_hybrid_export_pubkey(const char *privfile, const char *pubfile);
int zupt_hybrid_encrypt_init(zupt_keyring_t *kr, const char *pubkeyfile,
uint8_t *enc_hdr, size_t *enc_hdr_len);
int zupt_hybrid_decrypt_init(zupt_keyring_t *kr, const char *privkeyfile,
const uint8_t *enc_hdr, size_t enc_hdr_len);
/* ─── SDK-backed crypto (zupt v2.2+, libzuptsdk under the hood) ─── */
int zupt_sdk_hybrid_keygen(const char *privkeyfile, const char *pubkeyfile);
int zupt_sdk_hybrid_encrypt_init(zupt_keyring_t *kr, const char *pubkeyfile,
uint8_t *enc_hdr, size_t *enc_hdr_len);
int zupt_sdk_hybrid_decrypt_init(zupt_keyring_t *kr, const char *privkeyfile,
const uint8_t *enc_hdr, size_t enc_hdr_len);
int zupt_sdk_password_encrypt_init(zupt_keyring_t *kr, const char *password,
uint8_t *enc_hdr, size_t *enc_hdr_len);
int zupt_sdk_password_decrypt_init(zupt_keyring_t *kr, const char *password,
const uint8_t *enc_hdr, size_t enc_hdr_len);
const char *zupt_strerror(zupt_error_t e);
const char *zupt_codec_name(uint16_t id);
void zupt_default_options(zupt_options_t *o);
void zupt_format_size(uint64_t bytes, char *buf, size_t cap);
/* Resolve ZUPT_CODEC_AUTO to a concrete codec based on hardware.
* On x86_64 with AVX2: VaptVupt (fast ANS+SIMD decode).
* On all other arches: Zupt-LZHP (no SIMD dependency).
* Decompression of ALL codecs works on ALL architectures. */
uint16_t zupt_resolve_auto_codec(void);
/* ─── Full-Disk Backup/Restore ─── */
#define ZUPT_FLAG_DISK_IMAGE (1u << 6) /* Archive contains a raw disk/partition image */
/* Compress a raw block device or file as a disk image.
* Reads source in block_size chunks, detects zero/sparse regions,
* compresses non-zero blocks. Supports encryption + PQ. */
zupt_error_t zupt_disk_backup(const char *output_path, const char *source_path,
zupt_options_t *opts);
/* Restore a disk image archive to a block device or file.
* Writes blocks sequentially, restoring sparse regions as zeros. */
zupt_error_t zupt_disk_restore(const char *archive_path, const char *target_path,
zupt_options_t *opts);
/* ─── Internal Block I/O (used by format + disk modules) ─── */
zupt_error_t read_block(FILE *f, zupt_block_t *b);
zupt_error_t read_enc_header(FILE *f, zupt_archive_header_t *hdr, zupt_options_t *opts);
zupt_error_t decompress_block(const zupt_block_t *b, const zupt_keyring_t *kr,
uint64_t block_seq, uint8_t **out, size_t *olen);
zupt_error_t write_enc_header(FILE *out, zupt_archive_header_t *hdr,
zupt_options_t *opts);
int zupt_w8(FILE *f, uint8_t v);
int zupt_w16le(FILE *f, uint16_t v);
int zupt_w64le(FILE *f, uint64_t v);
/* ─── Block-Level Deduplication ─── */
#define ZUPT_DEDUP_MAX_ENTRIES (2 * 1024 * 1024) /* 2M entries, ~48MB RAM */
typedef struct zupt_dedup_ctx zupt_dedup_ctx_t;
zupt_dedup_ctx_t *zupt_dedup_init(void);
void zupt_dedup_free(zupt_dedup_ctx_t *ctx);
int zupt_dedup_lookup(zupt_dedup_ctx_t *ctx, uint64_t fingerprint,
uint64_t *ref_offset, uint32_t *ref_size);
int zupt_dedup_insert(zupt_dedup_ctx_t *ctx, uint64_t fingerprint,
uint64_t block_offset, uint32_t block_size);
void zupt_dedup_record_hit(zupt_dedup_ctx_t *ctx, uint64_t saved_bytes);
void zupt_dedup_record_block(zupt_dedup_ctx_t *ctx);
void zupt_dedup_stats(const zupt_dedup_ctx_t *ctx,
uint64_t *blocks_seen, uint64_t *blocks_deduped,
uint64_t *bytes_saved);
int zupt_dedup_write_ref(FILE *out, uint64_t ref_offset,
uint32_t orig_size, uint64_t orig_checksum);
/* ─── Archive Info (read-only metadata inspection) ─── */
zupt_error_t zupt_archive_info(const char *path);
#endif /* ZUPT_H */

43
vendor/vuptsdk/include/zupt_acsl.h vendored Normal file
View file

@ -0,0 +1,43 @@
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
* Copyright (c) 2026 Cristian Cezar Moisés
*
* Zupt ACSL Custom Predicates for Frama-C/WP
*
* Usage: frama-c -wp -wp-rte -wp-model Typed+Cast
* -cpp-extra-args="-Iinclude -Isrc" src/zupt_crypto.c
*/
#ifndef ZUPT_ACSL_H
#define ZUPT_ACSL_H
#ifdef __FRAMAC__
#include <stdint.h>
/*@ predicate ValidBuffer{L}(uint8_t *p, size_t n) =
@ \valid_read(p + (0..n-1)) &&
@ \initialized(p + (0..n-1));
@
@ predicate ValidWriteBuffer{L}(uint8_t *p, size_t n) =
@ \valid(p + (0..n-1));
@
@ predicate Separated2(uint8_t *a, size_t an,
@ uint8_t *b, size_t bn) =
@ \separated(a + (0..an-1), b + (0..bn-1));
@
@ predicate KeyWiped{L}(uint8_t *k, size_t n) =
@ \forall integer i; 0 <= i < n ==> \at(k[i],L) == 0;
@
@ predicate ValidKey{L}(uint8_t *k, size_t n) =
@ ValidBuffer{L}(k, n) && n == 32;
@
@ predicate ConstantTimeCompare{L}(uint8_t *a, uint8_t *b,
@ size_t n) =
@ \forall integer i; 0 <= i < n ==>
@ \initialized(\at(a+i,L)) && \initialized(\at(b+i,L));
@
@ predicate MACValid{L}(uint8_t *mac) =
@ ValidBuffer{L}(mac, 32);
*/
#endif /* __FRAMAC__ */
#endif /* ZUPT_ACSL_H */

33
vendor/vuptsdk/include/zupt_cpuid.h vendored Normal file
View file

@ -0,0 +1,33 @@
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
* Copyright (c) 2026 Cristian Cezar Moisés
*
* Zupt CPU Feature Detection
* Copyright (c) 2026 Cristian Cezar Moisés AGPL-3.0-or-later
*/
#ifndef ZUPT_CPUID_H
#define ZUPT_CPUID_H
#include <stdint.h>
typedef struct {
int has_aesni; /* CPUID.01H:ECX[25] — AES-NI instructions */
int has_avx; /* AVX (VEX-encoded SSE) — requires CPUID + OS XSAVE */
int has_pclmul; /* CPUID.01H:ECX[1] — CLMUL (carry-less multiply) */
int has_avx2; /* CPUID.07H:EBX[5] — AVX2 (256-bit SIMD) */
int has_sse41; /* CPUID.01H:ECX[19] — SSE4.1 */
} zupt_cpu_features_t;
/*@ assigns f->has_aesni, f->has_avx, f->has_pclmul, f->has_avx2, f->has_sse41;
@ ensures f->has_aesni == 0 || f->has_aesni == 1;
@ ensures f->has_avx == 0 || f->has_avx == 1;
@ ensures f->has_pclmul == 0 || f->has_pclmul == 1;
@ ensures f->has_avx2 == 0 || f->has_avx2 == 1;
@ ensures f->has_sse41 == 0 || f->has_sse41 == 1;
*/
void zupt_detect_cpu(zupt_cpu_features_t *f);
/* Global instance — set once at program start */
extern zupt_cpu_features_t zupt_cpu;
#endif /* ZUPT_CPUID_H */

65
vendor/vuptsdk/include/zupt_jasmin.h vendored Normal file
View file

@ -0,0 +1,65 @@
/*
* SPDX-License-Identifier: AGPL-3.0-or-later
* Copyright (c) 2026 Cristian Cezar Moisés
*
* Zupt Jasmin Verified Crypto Declarations
* Copyright (c) 2026 Cristian Cezar Moisés AGPL-3.0-or-later
*
* Extern declarations for Jasmin-compiled assembly functions.
* These replace C fallbacks when built with -DZUPT_USE_JASMIN.
*
* Calling convention: System V AMD64 ABI.
* Pointer args passed in RDI, RSI, RDX, RCX, R8, R9.
*
* v2.0.0: All 4 Jasmin functions wired and active.
*/
#ifndef ZUPT_JASMIN_H
#define ZUPT_JASMIN_H
#ifdef ZUPT_USE_JASMIN
#include <stdint.h>
/* JASMIN-VERIFIED: CT MAC comparison (4×u64 XOR accumulation).
* Returns 0 if all 32 bytes match, nonzero if any differ.
* Replaces XOR loop in zupt_decrypt_buffer(). */
extern uint64_t zupt_mac_verify_ct(const void *expected, const void *actual);
/* JASMIN-VERIFIED: CT conditional select (4×u64 masked select).
* if cond==0: copies aout. if cond!=0: copies bout.
* Replaces cmov in zupt_mlkem768_decaps(). */
extern void zupt_ct_select_32(void *out, const void *a,
const void *b, uint64_t cond);
/* JASMIN-VERIFIED: CT conditional swap (4×u64 masked XOR swap).
* if cond==0: no-op. if cond==1: swaps ab in place.
* Replaces fe_cswap in zupt_x25519.c.
* NOTE: Requires 4×u64 field element layout (donna64). */
extern void zupt_fe_cswap(void *a, void *b, uint64_t cond);
/* JASMIN-VERIFIED: AES-256 single-block encrypt via AES-NI.
* out = AES-256-ECB(key, ctr) XOR in.
* FIX v2.0.0: Stack offset bug resolved round keys at correct
* 16-byte aligned offsets. Requires AES-NI (checked via CPUID).
*
* Args (System V ABI):
* out_ptr (RDI): destination for 16-byte result
* in_blk (RSI): pointer to 16-byte plaintext block
* key (RDX): pointer to 32-byte AES-256 key (two u128)
* ctr_blk (RCX): pointer to 16-byte counter block
*/
extern void zupt_aes256_blk(void *out, const void *in,
const void *key, const void *ctr);
/* JASMIN-VERIFIED: AES-256-CTR 4-block pipeline via AES-NI.
* Processes nblocks×16 bytes with 4-way interleaving.
* Counter is updated in-place (big-endian increment in bytes [8..15]).
* Requires AES-NI. Falls back to zupt_aes256_blk for remaining 1-3 blocks.
*
* Args: out(RDI), in(RSI), key(RDX), ctr(RCX), nblocks(R8)
*/
extern void zupt_aes256_ctr4(void *out, const void *in,
const void *key, void *ctr,
uint64_t nblocks);
#endif /* ZUPT_USE_JASMIN */
#endif /* ZUPT_JASMIN_H */

49
vendor/vuptsdk/include/zupt_keccak.h vendored Normal file
View file

@ -0,0 +1,49 @@
/*
* Zupt Backup-oriented compression with AES-256 encryption
* Copyright (c) 2026 Cristian Cezar Moisés
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* Keccak-f[1600] sponge: SHA3-256, SHA3-512, SHAKE-128, SHAKE-256
* Required by ML-KEM-768 (FIPS 203).
* Pure C11, zero dependencies, no dynamic allocation.
*/
#ifndef ZUPT_KECCAK_H
#define ZUPT_KECCAK_H
#include <stdint.h>
#include <stddef.h>
/* Sponge state: 25 × 64-bit lanes = 200 bytes */
typedef struct {
uint64_t st[25];
uint8_t buf[200]; /* absorption buffer */
size_t rate; /* rate in bytes */
size_t pt; /* position in buf */
uint8_t dsuf; /* domain suffix: 0x06 for SHA3, 0x1F for SHAKE */
} zupt_keccak_ctx;
/* SHA3-256: 32-byte output */
void zupt_sha3_256(const uint8_t *data, size_t len, uint8_t out[32]);
/* SHA3-512: 64-byte output */
void zupt_sha3_512(const uint8_t *data, size_t len, uint8_t out[64]);
/* SHAKE-128: extendable output */
void zupt_shake128(const uint8_t *data, size_t dlen, uint8_t *out, size_t olen);
/* SHAKE-256: extendable output */
void zupt_shake256(const uint8_t *data, size_t dlen, uint8_t *out, size_t olen);
/* Incremental SHAKE-128 for ML-KEM sampling */
void zupt_shake128_init(zupt_keccak_ctx *ctx);
void zupt_shake128_absorb(zupt_keccak_ctx *ctx, const uint8_t *data, size_t len);
void zupt_shake128_finalize(zupt_keccak_ctx *ctx);
void zupt_shake128_squeeze(zupt_keccak_ctx *ctx, uint8_t *out, size_t len);
/* Incremental SHAKE-256 */
void zupt_shake256_init(zupt_keccak_ctx *ctx);
void zupt_shake256_absorb(zupt_keccak_ctx *ctx, const uint8_t *data, size_t len);
void zupt_shake256_finalize(zupt_keccak_ctx *ctx);
void zupt_shake256_squeeze(zupt_keccak_ctx *ctx, uint8_t *out, size_t len);
#endif

65
vendor/vuptsdk/include/zupt_mlkem.h vendored Normal file
View file

@ -0,0 +1,65 @@
/*
* Zupt Backup-oriented compression with AES-256 encryption
* Copyright (c) 2026 Cristian Cezar Moisés
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* ML-KEM-768 (FIPS 203, formerly CRYSTALS-Kyber).
* Post-quantum key encapsulation mechanism.
*
* Parameters (ML-KEM-768):
* k = 3, η = 2, η = 2, d_u = 10, d_v = 4
* Public key: 1184 bytes
* Secret key: 2400 bytes
* Ciphertext: 1088 bytes
* Shared secret: 32 bytes
*
* SECURITY NOTE: This implementation must undergo independent review
* before deployment in high-assurance contexts. It targets correctness
* against NIST test vectors and constant-time operation.
*/
#ifndef ZUPT_MLKEM_H
#define ZUPT_MLKEM_H
#include <stdint.h>
#define MLKEM_K 3
#define MLKEM_N 256
#define MLKEM_Q 3329
#define MLKEM_ETA1 2
#define MLKEM_ETA2 2
#define MLKEM_DU 10
#define MLKEM_DV 4
#define MLKEM_PUBLICKEYBYTES 1184
#define MLKEM_SECRETKEYBYTES 2400
#define MLKEM_CIPHERTEXTBYTES 1088
#define MLKEM_SSBYTES 32
/* KeyGen: generate public/secret keypair.
* pk: output public key (1184 bytes)
* sk: output secret key (2400 bytes)
* Returns 0 on success. */
int zupt_mlkem768_keygen(uint8_t pk[MLKEM_PUBLICKEYBYTES],
uint8_t sk[MLKEM_SECRETKEYBYTES]);
/* Encapsulate: produce ciphertext and shared secret from public key.
* ct: output ciphertext (1088 bytes)
* ss: output shared secret (32 bytes)
* pk: input public key (1184 bytes)
* Returns 0 on success. */
int zupt_mlkem768_encaps(uint8_t ct[MLKEM_CIPHERTEXTBYTES],
uint8_t ss[MLKEM_SSBYTES],
const uint8_t pk[MLKEM_PUBLICKEYBYTES]);
/* Decapsulate: recover shared secret from ciphertext and secret key.
* ss: output shared secret (32 bytes)
* ct: input ciphertext (1088 bytes)
* sk: input secret key (2400 bytes)
* Returns 0 on success.
* CT-REQUIRED: Implicit rejection invalid ciphertext produces a
* pseudorandom shared secret (no distinguishable failure). */
int zupt_mlkem768_decaps(uint8_t ss[MLKEM_SSBYTES],
const uint8_t ct[MLKEM_CIPHERTEXTBYTES],
const uint8_t sk[MLKEM_SECRETKEYBYTES]);
#endif

22
vendor/vuptsdk/include/zupt_x25519.h vendored Normal file
View file

@ -0,0 +1,22 @@
/*
* Zupt Backup-oriented compression with AES-256 encryption
* Copyright (c) 2026 Cristian Cezar Moisés
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* X25519 Diffie-Hellman key agreement (RFC 7748).
* Montgomery ladder constant-time by construction.
*/
#ifndef ZUPT_X25519_H
#define ZUPT_X25519_H
#include <stdint.h>
/* X25519(scalar, point) → result. All inputs/outputs are 32 bytes.
* CT-REQUIRED: Montgomery ladder is inherently constant-time. */
void zupt_x25519(uint8_t out[32], const uint8_t scalar[32], const uint8_t point[32]);
/* X25519 with the standard basepoint (9).
* Used for keygen: public = X25519(private, basepoint). */
void zupt_x25519_base(uint8_t out[32], const uint8_t scalar[32]);
#endif

605
vendor/vuptsdk/include/zuptsdk.h vendored Normal file
View file

@ -0,0 +1,605 @@
/*
* libzuptsdk Public C ABI for the Zupt backup compression library
*
* Copyright (c) 2026 Cristian Cezar Moisés
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* Repository: https://git.securityops.co/cristiancmoises/zupt
* Website: https://zupt.securityops.co
* Contact: zupt@riseup.net
*
* --------------------------------------------------------------------------
* STABILITY GUARANTEE
* --------------------------------------------------------------------------
* Every symbol declared in this header is part of the stable v1.0 ABI and
* is gated behind the linker version tag ZUPTSDK_1.0. New symbols may be
* added in minor versions (1.1, 1.2, ...) under new tags (ZUPTSDK_1.1, ...).
* Existing symbols will never change signature within v1.x. Breaking
* changes require a major version bump (libzuptsdk.so.2).
*
* No symbol prefixed with anything other than `zuptsdk_` or `ZUPTSDK_` is
* part of this ABI. Do not link against internal `zupt_*` symbols even if
* they appear in the static archive they will disappear without notice.
*
* --------------------------------------------------------------------------
* THREAD SAFETY
* --------------------------------------------------------------------------
* Every function that takes a `zuptsdk_ctx_t *` operates only on that
* context's state and on caller-provided buffers. Concurrent calls on
* DISTINCT contexts are safe (MT-Safe). Concurrent calls on the SAME
* context are NOT safe (MT-Unsafe-Same-Context) unless explicitly
* documented otherwise.
*
* --------------------------------------------------------------------------
* MEMORY OWNERSHIP
* --------------------------------------------------------------------------
* Every function documents ownership using these conventions in the param
* comments:
* [in] caller owns, library reads only
* [out] caller owns, library writes
* [in,out] caller owns, library reads and writes
* [transfers] ownership moves caller -> library (or library -> caller)
* [borrowed] pointer valid only for the duration of the call
*
* Any function that returns a heap-allocated value via an output pointer
* documents the corresponding zuptsdk_*_destroy() or zuptsdk_free() call
* the caller must invoke. Calling free() on libc-allocated memory from a
* different allocator is undefined; always use the documented destroyer.
*
* --------------------------------------------------------------------------
* ERROR HANDLING
* --------------------------------------------------------------------------
* Functions return `int` where 0 == ZUPTSDK_OK and negative values are
* `zuptsdk_error_t` codes. Use zuptsdk_strerror() for a static description
* and zuptsdk_last_error_detail(ctx) for a thread-local detailed message
* including filename, line number, and underlying errno where applicable.
*
* The library never calls abort(), exit(), or _exit(). It never writes to
* stdout or stderr unless the caller explicitly enables logging via
* zuptsdk_ctx_set_log_callback().
*
* --------------------------------------------------------------------------
* SECURE MEMORY
* --------------------------------------------------------------------------
* Inputs and outputs containing secret material (passwords, raw keys,
* decrypted plaintext keys) MUST be passed via `zuptsdk_secure_buffer_t`
* to ensure mlock()-backed storage and explicit_bzero() on destroy.
* Passing such material via plain `const uint8_t *` is allowed for
* convenience but the library cannot guarantee zeroization of caller
* memory in that case.
*/
#ifndef ZUPTSDK_H
#define ZUPTSDK_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ════════════════════════════════════════════════════════════════════════
* VERSION
* */
#define ZUPTSDK_VERSION_MAJOR 1
#define ZUPTSDK_VERSION_MINOR 0
#define ZUPTSDK_VERSION_PATCH 0
#define ZUPTSDK_VERSION_STRING "1.0.0"
/* Compile-time version check helper (negative if header older than required) */
#define ZUPTSDK_VERSION_AT_LEAST(maj, min, pat) \
((ZUPTSDK_VERSION_MAJOR > (maj)) || \
(ZUPTSDK_VERSION_MAJOR == (maj) && ZUPTSDK_VERSION_MINOR > (min)) || \
(ZUPTSDK_VERSION_MAJOR == (maj) && ZUPTSDK_VERSION_MINOR == (min) && \
ZUPTSDK_VERSION_PATCH >= (pat)))
/**
* Return the runtime version string of the linked library, e.g. "1.0.0".
* The returned pointer is to static storage and must NOT be freed.
*
* Use this with the compile-time ZUPTSDK_VERSION_STRING to detect mismatch
* between header and library at runtime.
*/
const char *zuptsdk_version_string(void);
/**
* Verify that the linked library is at least the requested version.
* Returns 0 if compatible, ZUPTSDK_ERR_VERSION_MISMATCH otherwise.
* Call this once at startup before any other zuptsdk_* function.
*/
int zuptsdk_version_check(int major, int minor, int patch);
/* ════════════════════════════════════════════════════════════════════════
* ERRORS
* */
typedef enum {
ZUPTSDK_OK = 0,
ZUPTSDK_ERR_INVALID_ARG = -1, /* NULL pointer, bad size, bad enum value */
ZUPTSDK_ERR_NO_MEMORY = -2, /* malloc/calloc/realloc returned NULL */
ZUPTSDK_ERR_IO = -3, /* read/write error; see errno detail */
ZUPTSDK_ERR_BAD_ARCHIVE = -4, /* Magic mismatch or truncated header */
ZUPTSDK_ERR_BAD_PASSWORD = -5, /* MAC verification failed */
ZUPTSDK_ERR_BAD_KEY = -6, /* PQ key file malformed or wrong type */
ZUPTSDK_ERR_BAD_MAC = -7, /* HMAC mismatch — archive corrupted or tampered */
ZUPTSDK_ERR_BAD_VERSION = -8, /* Archive format version not supported */
ZUPTSDK_ERR_BAD_CHECKSUM = -9, /* Block checksum mismatch */
ZUPTSDK_ERR_BUFFER_TOO_SMALL = -10, /* Output buffer insufficient */
ZUPTSDK_ERR_NOT_ENCRYPTED = -11, /* Tried to decrypt unencrypted archive */
ZUPTSDK_ERR_PASSWORD_REQUIRED = -12, /* Archive needs password but none supplied */
ZUPTSDK_ERR_PQ_KEY_REQUIRED = -13, /* Archive needs PQ key but none supplied */
ZUPTSDK_ERR_UNSUPPORTED = -14, /* Feature not supported on this platform */
ZUPTSDK_ERR_VERSION_MISMATCH = -15, /* Library older than requested */
ZUPTSDK_ERR_PATH_TRAVERSAL = -16, /* "../" or absolute path in archive */
ZUPTSDK_ERR_TOO_LARGE = -17, /* Decompressed size exceeds limit */
ZUPTSDK_ERR_CRYPTO_FAIL = -18, /* Underlying crypto primitive failed */
ZUPTSDK_ERR_CANCELLED = -19, /* Caller cancelled via progress callback */
ZUPTSDK_ERR_INTERNAL = -99 /* Bug in library — please report */
} zuptsdk_error_t;
/**
* Static error description for a zuptsdk_error_t value.
* Returned pointer is static and must not be freed. Always non-NULL.
*/
const char *zuptsdk_strerror(int err);
/**
* Thread-local detailed error message from the most recent failed call.
* The string includes file:line of the failure point and underlying errno
* description where applicable. Returned pointer is to thread-local
* storage, valid until the next failed zuptsdk_* call on this thread.
* Returns "" if no error has been recorded on this thread.
*/
const char *zuptsdk_last_error_detail(void);
/* ════════════════════════════════════════════════════════════════════════
* OPAQUE TYPES (forward declarations only no struct layout exposed)
* */
typedef struct zuptsdk_ctx zuptsdk_ctx_t;
typedef struct zuptsdk_options zuptsdk_options_t;
typedef struct zuptsdk_archive_info zuptsdk_archive_info_t;
typedef struct zuptsdk_secure_buf zuptsdk_secure_buf_t;
typedef struct zuptsdk_keypair zuptsdk_keypair_t;
typedef struct zuptsdk_pubkey zuptsdk_pubkey_t;
typedef struct zuptsdk_privkey zuptsdk_privkey_t;
/* ════════════════════════════════════════════════════════════════════════
* ENUMS
* */
typedef enum {
ZUPTSDK_CODEC_AUTO = 0, /* Hardware-adaptive (VaptVupt on AVX2, LZHP otherwise) */
ZUPTSDK_CODEC_VAPTVUPT = 1, /* VaptVupt LZ + ANS entropy */
ZUPTSDK_CODEC_LZHP = 2, /* LZ77 + Huffman + Byte Prediction */
ZUPTSDK_CODEC_LZH = 3, /* LZ77 + Huffman */
ZUPTSDK_CODEC_LZ = 4, /* LZ77 only */
ZUPTSDK_CODEC_STORE = 5 /* No compression */
} zuptsdk_codec_t;
typedef enum {
ZUPTSDK_ENC_NONE = 0, /* No encryption */
ZUPTSDK_ENC_PASSWORD = 1, /* PBKDF2 → AES-256-CTR + HMAC-SHA256 */
ZUPTSDK_ENC_PQ_HYBRID = 2 /* ML-KEM-768 + X25519 hybrid KEM */
} zuptsdk_encryption_t;
typedef enum {
ZUPTSDK_LOG_ERROR = 0,
ZUPTSDK_LOG_WARN = 1,
ZUPTSDK_LOG_INFO = 2,
ZUPTSDK_LOG_DEBUG = 3
} zuptsdk_log_level_t;
/* ════════════════════════════════════════════════════════════════════════
* CALLBACKS
* */
/**
* Streaming read callback. Library calls this to obtain input bytes.
* @param userdata [in] opaque pointer supplied at stream init
* @param buf [out] destination buffer
* @param max_bytes max bytes to read into buf
* @return Number of bytes actually read (0 == EOF, < 0 == error).
*/
typedef int64_t (*zuptsdk_read_fn)(void *userdata, uint8_t *buf, size_t max_bytes);
/**
* Streaming write callback. Library calls this to deliver output bytes.
* @param userdata [in] opaque pointer supplied at stream init
* @param buf [in] data to write
* @param bytes number of bytes in buf
* @return Number of bytes actually written (must equal `bytes` on success).
*/
typedef int64_t (*zuptsdk_write_fn)(void *userdata, const uint8_t *buf, size_t bytes);
/**
* Progress callback. Library invokes periodically during long operations.
* Return non-zero to cancel the operation; the in-flight call will then
* return ZUPTSDK_ERR_CANCELLED.
* @param userdata [in] opaque pointer set via zuptsdk_ctx_set_progress_callback
* @param processed bytes processed so far
* @param total total bytes (0 if unknown)
* @return 0 to continue, non-zero to cancel.
*/
typedef int (*zuptsdk_progress_fn)(void *userdata, uint64_t processed, uint64_t total);
/**
* Log callback. Receives diagnostic messages from the library.
* Set via zuptsdk_ctx_set_log_callback(). NULL means no logging (default).
* The string is null-terminated and valid only for the duration of the call.
*/
typedef void (*zuptsdk_log_fn)(void *userdata, zuptsdk_log_level_t level, const char *msg);
/**
* Custom allocator hooks. Set globally via zuptsdk_set_allocator().
* If any function is NULL, libc malloc/free/realloc is used.
* realloc_fn must accept (NULL, n) as malloc(n) and (p, 0) as free(p).
*/
typedef struct {
void *(*malloc_fn)(void *userdata, size_t size);
void (*free_fn)(void *userdata, void *ptr);
void *(*realloc_fn)(void *userdata, void *ptr, size_t size);
void *userdata;
} zuptsdk_allocator_t;
/* ════════════════════════════════════════════════════════════════════════
* GLOBAL CONFIG
* */
/**
* Install a custom allocator. Must be called before any other zuptsdk_*
* function. Calling after contexts have been created is undefined.
* Pass NULL to revert to libc allocator (only valid before first use).
*
* @param alloc [in,borrowed] allocator hooks; copied internally
* @return ZUPTSDK_OK or ZUPTSDK_ERR_INVALID_ARG
*/
int zuptsdk_set_allocator(const zuptsdk_allocator_t *alloc);
/* ════════════════════════════════════════════════════════════════════════
* CONTEXT
* */
/**
* Create a new SDK context. Each context holds its own thread pool,
* progress callback, log callback, and error state. Contexts are
* cheap to create a few KB plus the configured thread count.
*
* @param ctx_out [out,transfers] pointer to receive new context
* @return ZUPTSDK_OK on success, ZUPTSDK_ERR_NO_MEMORY on alloc failure.
* On error, *ctx_out is set to NULL.
*/
int zuptsdk_ctx_create(zuptsdk_ctx_t **ctx_out);
/**
* Destroy a context. Frees all owned resources including thread pool.
* Safe to call with NULL. After this call, the pointer is invalid.
*/
void zuptsdk_ctx_destroy(zuptsdk_ctx_t *ctx);
/**
* Set worker thread count. 0 == auto (one per CPU). Default is auto.
* Returns ZUPTSDK_ERR_INVALID_ARG if ctx is NULL or threads > 256.
*/
int zuptsdk_ctx_set_threads(zuptsdk_ctx_t *ctx, int threads);
/**
* Set progress callback for long-running operations on this context.
* Pass NULL fn to clear. userdata is opaque to the library.
*/
int zuptsdk_ctx_set_progress_callback(zuptsdk_ctx_t *ctx,
zuptsdk_progress_fn fn,
void *userdata);
/**
* Set log callback for diagnostic messages on this context.
* Pass NULL fn to disable logging (default).
*/
int zuptsdk_ctx_set_log_callback(zuptsdk_ctx_t *ctx,
zuptsdk_log_fn fn,
zuptsdk_log_level_t min_level,
void *userdata);
/* ════════════════════════════════════════════════════════════════════════
* OPTIONS
* */
/**
* Create a default-initialized options bag for compress/encrypt operations.
* Defaults: codec=AUTO, level=7, no encryption, no dedup, no solid mode.
*/
int zuptsdk_options_create(zuptsdk_options_t **opts_out);
void zuptsdk_options_destroy(zuptsdk_options_t *opts);
int zuptsdk_options_set_codec(zuptsdk_options_t *opts, zuptsdk_codec_t codec);
int zuptsdk_options_set_level(zuptsdk_options_t *opts, int level /* 1..9 */);
int zuptsdk_options_set_dedup(zuptsdk_options_t *opts, int enabled);
int zuptsdk_options_set_solid(zuptsdk_options_t *opts, int enabled);
int zuptsdk_options_set_block_size(zuptsdk_options_t *opts, size_t bytes);
/**
* Maximum decompressed output size. Decompression aborts with
* ZUPTSDK_ERR_TOO_LARGE if exceeded. 0 == unlimited (NOT recommended
* for untrusted input zip-bomb attack vector). Default: 16 GiB.
*/
int zuptsdk_options_set_max_decompressed(zuptsdk_options_t *opts,
uint64_t max_bytes);
/* ════════════════════════════════════════════════════════════════════════
* SECURE BUFFERS (for passwords and key material)
* */
/**
* Allocate a secure buffer: backing memory is mlock()ed (locked into RAM,
* never swapped to disk) and explicit_bzero()ed on destroy.
*
* @param size requested size in bytes (1..65536)
* @param buf_out [out,transfers] receives buffer handle
* @return ZUPTSDK_OK on success.
*/
int zuptsdk_secure_buf_create(size_t size, zuptsdk_secure_buf_t **buf_out);
/**
* Destroy a secure buffer. Memory is zeroed and unlocked before free.
* Safe to call with NULL.
*/
void zuptsdk_secure_buf_destroy(zuptsdk_secure_buf_t *buf);
/**
* Get raw pointer to the secure buffer's storage. Pointer is valid until
* zuptsdk_secure_buf_destroy() is called. Caller may read or write up to
* the buffer's size.
*
* @param buf [in]
* @param data_out [out,borrowed] receives pointer to storage
* @param size_out [out] receives buffer size
*/
int zuptsdk_secure_buf_get(zuptsdk_secure_buf_t *buf,
uint8_t **data_out, size_t *size_out);
/**
* Convenience: copy data into a new secure buffer.
* Useful when migrating an existing plain buffer to secure storage.
*/
int zuptsdk_secure_buf_from_data(const uint8_t *data, size_t size,
zuptsdk_secure_buf_t **buf_out);
/* ════════════════════════════════════════════════════════════════════════
* KEYS (PQ hybrid: ML-KEM-768 + X25519)
* */
/**
* Generate a fresh hybrid keypair. Uses the system CSPRNG.
*
* @param ctx [in]
* @param kp_out [out,transfers] receives new keypair
* @return ZUPTSDK_OK on success, ZUPTSDK_ERR_CRYPTO_FAIL on RNG failure.
*/
int zuptsdk_keypair_generate(zuptsdk_ctx_t *ctx, zuptsdk_keypair_t **kp_out);
void zuptsdk_keypair_destroy(zuptsdk_keypair_t *kp);
/**
* Save private key to a file. The file is written with mode 0600 on POSIX.
* Recommended extension: ".key".
*/
int zuptsdk_keypair_save_private(const zuptsdk_keypair_t *kp, const char *path);
/**
* Save public key to a file. World-readable.
* Recommended extension: ".pub" or "_public.key".
*/
int zuptsdk_keypair_save_public(const zuptsdk_keypair_t *kp, const char *path);
/**
* Load a private key from a file.
* @param path [in]
* @param key_out [out,transfers]
*/
int zuptsdk_privkey_load(const char *path, zuptsdk_privkey_t **key_out);
void zuptsdk_privkey_destroy(zuptsdk_privkey_t *key);
/**
* Load a public key from a file.
*/
int zuptsdk_pubkey_load(const char *path, zuptsdk_pubkey_t **key_out);
void zuptsdk_pubkey_destroy(zuptsdk_pubkey_t *key);
/**
* Derive public key from private key (no I/O).
*/
int zuptsdk_privkey_get_public(const zuptsdk_privkey_t *priv,
zuptsdk_pubkey_t **pub_out);
/* ════════════════════════════════════════════════════════════════════════
* COMPRESS / DECOMPRESS buffer mode (for small archives)
* */
/**
* Compress an in-memory file list into a single archive buffer.
*
* @param ctx [in]
* @param opts [in,borrowed] compression and encryption options
* @param file_paths [in] array of filesystem paths to add
* @param file_count number of paths in file_paths
* @param password [in,nullable] password as a secure buffer; NULL for no pw
* @param recipient_pk [in,nullable] PQ public key for encryption; NULL for no PQ
* @param archive_out [out,transfers] receives malloc'd archive bytes;
* caller must free with zuptsdk_free()
* @param archive_sz [out] size of returned archive
* @return ZUPTSDK_OK on success.
*/
int zuptsdk_compress_files(zuptsdk_ctx_t *ctx,
const zuptsdk_options_t *opts,
const char *const *file_paths,
size_t file_count,
zuptsdk_secure_buf_t *password,
const zuptsdk_pubkey_t *recipient_pk,
uint8_t **archive_out,
size_t *archive_sz);
/**
* Compress a single in-memory data buffer. Useful for SDK consumers that
* have data in memory and want a self-contained archive.
*
* @param logical_name [in] name to record inside the archive (e.g. "data.bin")
*/
int zuptsdk_compress_buffer(zuptsdk_ctx_t *ctx,
const zuptsdk_options_t *opts,
const char *logical_name,
const uint8_t *data, size_t data_sz,
zuptsdk_secure_buf_t *password,
const zuptsdk_pubkey_t *recipient_pk,
uint8_t **archive_out,
size_t *archive_sz);
/**
* Extract an archive into a directory.
*
* @param dest_dir [in] target directory; created if missing
* @param password [in,nullable]
* @param recipient_sk [in,nullable] PQ private key
*/
int zuptsdk_extract_to_dir(zuptsdk_ctx_t *ctx,
const uint8_t *archive, size_t archive_sz,
const char *dest_dir,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk);
/**
* Extract a single-file archive (one created with zuptsdk_compress_buffer)
* back into a memory buffer.
*
* @param data_out [out,transfers] caller frees with zuptsdk_free()
* @param data_sz [out]
*/
int zuptsdk_extract_buffer(zuptsdk_ctx_t *ctx,
const uint8_t *archive, size_t archive_sz,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk,
uint8_t **data_out, size_t *data_sz);
/* ════════════════════════════════════════════════════════════════════════
* COMPRESS / DECOMPRESS streaming mode (for large archives)
* */
/**
* Compress from a read callback to a write callback. Streaming version
* with no archive size limit suitable for piping to network sockets,
* encrypted volumes, or any backend with a write_fn.
*
* @param input [in] read callback supplying source bytes
* @param input_ud [in] userdata passed to read callback
* @param input_name [in] logical filename to record in archive
* @param input_total total bytes to read; 0 if unknown
* @param output [in] write callback receiving archive bytes
* @param output_ud [in] userdata passed to write callback
*/
int zuptsdk_compress_stream(zuptsdk_ctx_t *ctx,
const zuptsdk_options_t *opts,
zuptsdk_read_fn input, void *input_ud,
const char *input_name, uint64_t input_total,
zuptsdk_write_fn output, void *output_ud,
zuptsdk_secure_buf_t *password,
const zuptsdk_pubkey_t *recipient_pk);
/**
* Decompress an archive read from a callback, writing extracted single-file
* content to a write callback.
*/
int zuptsdk_decompress_stream(zuptsdk_ctx_t *ctx,
zuptsdk_read_fn input, void *input_ud,
zuptsdk_write_fn output, void *output_ud,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk);
/* ════════════════════════════════════════════════════════════════════════
* VERIFY / INFO
* */
/**
* Verify all block checksums and (if encrypted) HMAC of an archive.
* No data is written to disk. Returns ZUPTSDK_OK if every block validates.
*/
int zuptsdk_verify(zuptsdk_ctx_t *ctx,
const uint8_t *archive, size_t archive_sz,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk);
/**
* Read archive metadata without password or key. Returns header info only;
* does not decrypt block contents.
*
* @param info_out [out,transfers] receives info object;
* caller must zuptsdk_archive_info_destroy()
*/
int zuptsdk_archive_info_read(zuptsdk_ctx_t *ctx,
const uint8_t *archive, size_t archive_sz,
zuptsdk_archive_info_t **info_out);
void zuptsdk_archive_info_destroy(zuptsdk_archive_info_t *info);
/* Getters — opaque struct, all fields accessed via these functions. */
int zuptsdk_archive_info_format_major(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_format_minor(const zuptsdk_archive_info_t *info);
const char *zuptsdk_archive_info_uuid(const zuptsdk_archive_info_t *info);
int64_t zuptsdk_archive_info_created_unix(const zuptsdk_archive_info_t *info);
uint64_t zuptsdk_archive_info_size(const zuptsdk_archive_info_t *info);
uint32_t zuptsdk_archive_info_block_count(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_encrypted(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_pq_hybrid(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_solid(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_dedup(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_disk_image(const zuptsdk_archive_info_t *info);
/* ════════════════════════════════════════════════════════════════════════
* DISK BACKUP / RESTORE
* */
/**
* Backup a block device or disk image file to an archive.
* REQUIRES root/admin privileges to read raw block devices on most OSes.
*/
int zuptsdk_disk_backup(zuptsdk_ctx_t *ctx,
const zuptsdk_options_t *opts,
const char *source_device_or_image,
const char *output_archive_path,
zuptsdk_secure_buf_t *password,
const zuptsdk_pubkey_t *recipient_pk);
/**
* Restore a disk backup archive to a block device or image file.
* DESTRUCTIVE: target is overwritten without confirmation.
*/
int zuptsdk_disk_restore(zuptsdk_ctx_t *ctx,
const char *archive_path,
const char *target_device_or_image,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk);
/* ════════════════════════════════════════════════════════════════════════
* MISC
* */
/**
* Free memory returned by the library via [transfers] output pointers.
* Safe to call with NULL.
*
* Always use this never free() for SDK-allocated memory, since the
* library may have been built with a custom allocator.
*/
void zuptsdk_free(void *ptr);
/**
* Best-effort secure zero of a buffer. Resistant to dead-store elimination
* by the optimizer. Use for caller-managed sensitive memory.
*/
void zuptsdk_secure_zero(void *buf, size_t bytes);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ZUPTSDK_H */

230
vendor/vuptsdk/include/zuptsdk.hpp vendored Normal file
View file

@ -0,0 +1,230 @@
// libzuptsdk C++17 header — RAII wrappers, exception-based error handling
// SPDX-License-Identifier: AGPL-3.0-or-later
#ifndef ZUPTSDK_HPP
#define ZUPTSDK_HPP
#include "zuptsdk.h"
#include <array>
#include <cstdint>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
namespace zuptsdk {
class Error : public std::runtime_error {
int code_;
public:
Error(int code, const std::string& msg) : std::runtime_error(msg), code_(code) {}
int code() const noexcept { return code_; }
};
inline void check(int rc) {
if (rc != ZUPTSDK_OK) {
const char* detail = zuptsdk_last_error_detail();
throw Error(rc, detail && *detail ? detail : zuptsdk_strerror(rc));
}
}
// RAII wrapper for SDK-allocated buffers (must be freed via zuptsdk_free)
class Buffer {
uint8_t* data_;
std::size_t size_;
public:
Buffer() : data_(nullptr), size_(0) {}
Buffer(uint8_t* data, std::size_t size) : data_(data), size_(size) {}
~Buffer() { if (data_) zuptsdk_free(data_); }
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
Buffer(Buffer&& o) noexcept : data_(o.data_), size_(o.size_) { o.data_ = nullptr; o.size_ = 0; }
Buffer& operator=(Buffer&& o) noexcept {
if (data_) zuptsdk_free(data_);
data_ = o.data_; size_ = o.size_; o.data_ = nullptr; o.size_ = 0;
return *this;
}
const uint8_t* data() const noexcept { return data_; }
uint8_t* data() noexcept { return data_; }
std::size_t size() const noexcept { return size_; }
std::vector<uint8_t> to_vector() const { return {data_, data_ + size_}; }
uint8_t** out_ptr() noexcept { return &data_; }
std::size_t* out_size() noexcept { return &size_; }
};
class Context {
zuptsdk_ctx_t* ctx_;
public:
Context() : ctx_(nullptr) { check(zuptsdk_ctx_create(&ctx_)); }
~Context() { if (ctx_) zuptsdk_ctx_destroy(ctx_); }
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
zuptsdk_ctx_t* raw() const noexcept { return ctx_; }
};
class Pubkey {
zuptsdk_pubkey_t* pk_;
public:
Pubkey() : pk_(nullptr) {}
explicit Pubkey(zuptsdk_pubkey_t* pk) : pk_(pk) {}
~Pubkey() { if (pk_) zuptsdk_pubkey_destroy(pk_); }
Pubkey(const Pubkey&) = delete;
Pubkey& operator=(const Pubkey&) = delete;
Pubkey(Pubkey&& o) noexcept : pk_(o.pk_) { o.pk_ = nullptr; }
static Pubkey load(const std::string& path) {
zuptsdk_pubkey_t* pk = nullptr;
check(zuptsdk_pubkey_load(path.c_str(), &pk));
return Pubkey(pk);
}
zuptsdk_pubkey_t* raw() const noexcept { return pk_; }
std::array<uint8_t, 32> fingerprint() const {
std::array<uint8_t, 32> fp{};
check(zuptsdk_pubkey_fingerprint(pk_, fp.data()));
return fp;
}
};
class Privkey {
zuptsdk_privkey_t* sk_;
public:
Privkey() : sk_(nullptr) {}
explicit Privkey(zuptsdk_privkey_t* sk) : sk_(sk) {}
~Privkey() { if (sk_) zuptsdk_privkey_destroy(sk_); }
Privkey(const Privkey&) = delete;
Privkey& operator=(const Privkey&) = delete;
Privkey(Privkey&& o) noexcept : sk_(o.sk_) { o.sk_ = nullptr; }
static Privkey load(const std::string& path) {
zuptsdk_privkey_t* sk = nullptr;
check(zuptsdk_privkey_load(path.c_str(), &sk));
return Privkey(sk);
}
zuptsdk_privkey_t* raw() const noexcept { return sk_; }
};
class Keypair {
zuptsdk_keypair_t* kp_;
public:
explicit Keypair(Context& ctx) : kp_(nullptr) {
check(zuptsdk_keypair_generate(ctx.raw(), &kp_));
}
~Keypair() { if (kp_) zuptsdk_keypair_destroy(kp_); }
Keypair(const Keypair&) = delete;
Keypair& operator=(const Keypair&) = delete;
void save_public(const std::string& path) const {
check(zuptsdk_keypair_save_public(kp_, path.c_str()));
}
void save_private(const std::string& path) const {
check(zuptsdk_keypair_save_private(kp_, path.c_str()));
}
};
// Result type for encryption operations
struct EncryptResult {
Buffer header;
Buffer ciphertext;
};
inline EncryptResult encrypt_pq(Context& ctx, const Pubkey& pk,
const uint8_t* pt, std::size_t pt_sz,
const uint8_t* aad = nullptr, std::size_t aad_sz = 0) {
EncryptResult r;
check(zuptsdk_encrypt_pq(ctx.raw(), pk.raw(), pt, pt_sz, aad, aad_sz,
r.header.out_ptr(), r.header.out_size(),
r.ciphertext.out_ptr(), r.ciphertext.out_size()));
return r;
}
inline EncryptResult encrypt_pq_v2(Context& ctx, const Pubkey& pk,
int aead_id, bool forward_secret,
const uint8_t* pt, std::size_t pt_sz,
const uint8_t* aad = nullptr, std::size_t aad_sz = 0) {
EncryptResult r;
check(zuptsdk_encrypt_pq_v2(ctx.raw(), pk.raw(), aead_id, forward_secret ? 1 : 0,
pt, pt_sz, aad, aad_sz,
r.header.out_ptr(), r.header.out_size(),
r.ciphertext.out_ptr(), r.ciphertext.out_size()));
return r;
}
inline Buffer decrypt_pq(Context& ctx, const Privkey& sk,
const uint8_t* hdr, std::size_t hdr_sz,
const uint8_t* ct, std::size_t ct_sz,
const uint8_t* aad = nullptr, std::size_t aad_sz = 0) {
Buffer r;
check(zuptsdk_decrypt_pq(ctx.raw(), sk.raw(), hdr, hdr_sz, ct, ct_sz, aad, aad_sz,
r.out_ptr(), r.out_size()));
return r;
}
inline Buffer decrypt_pq_v2(Context& ctx, const Privkey& sk,
const uint8_t* hdr, std::size_t hdr_sz,
const uint8_t* ct, std::size_t ct_sz,
const uint8_t* aad = nullptr, std::size_t aad_sz = 0) {
Buffer r;
check(zuptsdk_decrypt_pq_v2(ctx.raw(), sk.raw(), hdr, hdr_sz, ct, ct_sz, aad, aad_sz,
r.out_ptr(), r.out_size()));
return r;
}
// Streaming
class StreamEncrypter {
zuptsdk_stream_state_t* st_;
Buffer header_;
public:
StreamEncrypter(Context& ctx, const Pubkey& pk,
const uint8_t* aad = nullptr, std::size_t aad_sz = 0) : st_(nullptr) {
check(zuptsdk_stream_pq_init_encrypt(ctx.raw(), pk.raw(), aad, aad_sz,
header_.out_ptr(), header_.out_size(), &st_));
}
~StreamEncrypter() { if (st_) zuptsdk_stream_state_destroy(st_); }
StreamEncrypter(const StreamEncrypter&) = delete;
StreamEncrypter& operator=(const StreamEncrypter&) = delete;
const Buffer& header() const noexcept { return header_; }
std::vector<uint8_t> encrypt_chunk(const uint8_t* pt, std::size_t pt_sz, bool final_chunk) {
std::vector<uint8_t> out(pt_sz + 21);
std::size_t out_sz = 0;
check(zuptsdk_stream_chunk_encrypt(st_,
final_chunk ? ZUPTSDK_CHUNK_FINAL : ZUPTSDK_CHUNK_MESSAGE,
pt, pt_sz, nullptr, 0, out.data(), out.size(), &out_sz));
out.resize(out_sz);
return out;
}
};
class StreamDecrypter {
zuptsdk_stream_state_t* st_;
bool finished_ = false;
public:
StreamDecrypter(Context& ctx, const Privkey& sk,
const uint8_t* hdr, std::size_t hdr_sz,
const uint8_t* aad = nullptr, std::size_t aad_sz = 0) : st_(nullptr) {
check(zuptsdk_stream_pq_init_decrypt(ctx.raw(), sk.raw(), hdr, hdr_sz,
aad, aad_sz, &st_));
}
~StreamDecrypter() { if (st_) zuptsdk_stream_state_destroy(st_); }
StreamDecrypter(const StreamDecrypter&) = delete;
StreamDecrypter& operator=(const StreamDecrypter&) = delete;
struct ChunkResult {
std::vector<uint8_t> data;
bool final_chunk;
};
ChunkResult decrypt_chunk(const uint8_t* in, std::size_t in_sz) {
std::vector<uint8_t> out(in_sz); // upper bound
std::size_t out_sz = 0;
zuptsdk_chunk_tag_t tag;
check(zuptsdk_stream_chunk_decrypt(st_, in, in_sz, nullptr, 0,
out.data(), out.size(), &out_sz, &tag));
out.resize(out_sz);
bool fin = (tag == ZUPTSDK_CHUNK_FINAL);
if (fin) finished_ = true;
return { std::move(out), fin };
}
bool finished() const noexcept { return finished_; }
};
inline std::string version() { return zuptsdk_version_string(); }
} // namespace zuptsdk
#endif // ZUPTSDK_HPP

89
vendor/vuptsdk/include/zuptsdk_easy.h vendored Normal file
View file

@ -0,0 +1,89 @@
/*
* zuptsdk easy.h high-level API for drop-in encryption.
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* Goal: 3 lines of code to encrypt/decrypt anything in any language.
* No context management, no parameter tuning, secure defaults.
*/
#ifndef ZUPTSDK_EASY_H
#define ZUPTSDK_EASY_H
#include "zuptsdk.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ─── String/buffer encryption (PQ pubkey) ─── */
/** Encrypt with recipient pubkey file path. Returns alloc'd combined
* blob (header || ciphertext) ready to store/transmit. */
int zuptsdk_easy_encrypt(const char *recipient_pubkey_path,
const uint8_t *plaintext, size_t plaintext_sz,
uint8_t **blob_out, size_t *blob_sz);
/** Decrypt blob with recipient privkey file path. */
int zuptsdk_easy_decrypt(const char *recipient_privkey_path,
const uint8_t *blob, size_t blob_sz,
uint8_t **plaintext_out, size_t *plaintext_sz);
/* ─── Password-based encryption ─── */
/** Encrypt with password (Argon2id, MODERATE preset by default). */
int zuptsdk_easy_encrypt_password(const char *password,
const uint8_t *plaintext, size_t plaintext_sz,
uint8_t **blob_out, size_t *blob_sz);
int zuptsdk_easy_decrypt_password(const char *password,
const uint8_t *blob, size_t blob_sz,
uint8_t **plaintext_out, size_t *plaintext_sz);
/* ─── Field-level encryption (for DB columns, JSON fields) ─── */
/** Encrypt small fields with a 32-byte key. Returns base64-encoded
* string (alloc'd, NUL-terminated, free with zuptsdk_free).
* Suitable for DB columns, JSON fields, env vars. */
int zuptsdk_easy_encrypt_field(const uint8_t key[32],
const char *plaintext,
char **b64_out);
int zuptsdk_easy_decrypt_field(const uint8_t key[32],
const char *b64_input,
char **plaintext_out);
/* ─── File encryption with progress ─── */
typedef void (*zuptsdk_easy_progress_t)(uint64_t bytes_done,
uint64_t bytes_total,
void *userdata);
int zuptsdk_easy_encrypt_file(const char *recipient_pubkey_path,
const char *input_path,
const char *output_path,
zuptsdk_easy_progress_t cb, void *userdata);
int zuptsdk_easy_decrypt_file(const char *recipient_privkey_path,
const char *input_path,
const char *output_path,
zuptsdk_easy_progress_t cb, void *userdata);
/* ─── Keypair generation ─── */
/** Generate keypair and save to two paths. Convenience wrapper. */
int zuptsdk_easy_keygen(const char *pubkey_out_path,
const char *privkey_out_path);
/** Derive a deterministic 32-byte key from a password via Argon2id.
* For field encryption, derive key once at startup, reuse for many fields. */
int zuptsdk_easy_derive_key(const char *password,
const uint8_t salt[16],
uint8_t key_out[32]);
/* ─── Random salt generation ─── */
int zuptsdk_easy_random_salt(uint8_t out[16]);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,57 @@
/* zuptsdk observability — metrics & structured logging hooks
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#ifndef ZUPTSDK_METRICS_H
#define ZUPTSDK_METRICS_H
#include "zuptsdk.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint64_t encrypt_pq_count;
uint64_t decrypt_pq_count;
uint64_t encrypt_password_count;
uint64_t decrypt_password_count;
uint64_t encrypt_field_count;
uint64_t decrypt_field_count;
uint64_t encrypt_failures;
uint64_t decrypt_failures;
uint64_t mac_failures;
uint64_t commitment_failures;
uint64_t fault_detections;
uint64_t bytes_encrypted;
uint64_t bytes_decrypted;
uint64_t total_latency_ns;
} zuptsdk_metrics_t;
/** Get a snapshot of accumulated metrics (thread-safe, atomic read). */
void zuptsdk_metrics_snapshot(zuptsdk_metrics_t *out);
/** Reset all counters to zero. */
void zuptsdk_metrics_reset(void);
/** Render snapshot in Prometheus exposition format to a buffer.
* Returns bytes written, or -1 if buf too small.
* If out is NULL, returns required size. */
int zuptsdk_metrics_render_prometheus(char *buf, size_t buf_sz);
/** Structured log callback for ops. Called on each encrypt/decrypt with
* outcome and timing. Set to NULL to disable.
* @param op "encrypt_pq" / "decrypt_pq" / "encrypt_password" / etc.
* @param rc error code (0 = OK)
* @param bytes plaintext bytes processed
* @param duration_ns elapsed time
*/
typedef void (*zuptsdk_op_log_t)(const char *op, int rc, size_t bytes,
uint64_t duration_ns, void *userdata);
void zuptsdk_set_op_log(zuptsdk_op_log_t cb, void *userdata);
#ifdef __cplusplus
}
#endif
#endif