v2.2.2
This commit is contained in:
parent
f3e39fb8e6
commit
e5f5d32aab
124 changed files with 11892 additions and 2461 deletions
465
vendor/zuptsdk/include/vaptvupt.h
vendored
Normal file
465
vendor/zuptsdk/include/vaptvupt.h
vendored
Normal file
|
|
@ -0,0 +1,465 @@
|
|||
/*
|
||||
* 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. */
|
||||
} 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;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════
|
||||
* 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/zuptsdk/include/vaptvupt_api.h
vendored
Normal file
43
vendor/zuptsdk/include/vaptvupt_api.h
vendored
Normal 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 */
|
||||
136
vendor/zuptsdk/include/vv_ans.h
vendored
Normal file
136
vendor/zuptsdk/include/vv_ans.h
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés
|
||||
*
|
||||
* 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);
|
||||
|
||||
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 */
|
||||
127
vendor/zuptsdk/include/vv_huffman.h
vendored
Normal file
127
vendor/zuptsdk/include/vv_huffman.h
vendored
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés
|
||||
*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
117
vendor/zuptsdk/include/vv_platform.h
vendored
Normal file
117
vendor/zuptsdk/include/vv_platform.h
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
#endif /* VV_PLATFORM_H */
|
||||
39
vendor/zuptsdk/include/zsdk_aes256_gcm_siv.h
vendored
Normal file
39
vendor/zuptsdk/include/zsdk_aes256_gcm_siv.h
vendored
Normal 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
|
||||
39
vendor/zuptsdk/include/zsdk_aes256_siv.h
vendored
Normal file
39
vendor/zuptsdk/include/zsdk_aes256_siv.h
vendored
Normal 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/zuptsdk/include/zsdk_argon2id.h
vendored
Normal file
39
vendor/zuptsdk/include/zsdk_argon2id.h
vendored
Normal 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/zuptsdk/include/zsdk_blake2b.h
vendored
Normal file
46
vendor/zuptsdk/include/zsdk_blake2b.h
vendored
Normal 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/zuptsdk/include/zsdk_hkdf.h
vendored
Normal file
41
vendor/zuptsdk/include/zsdk_hkdf.h
vendored
Normal 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
|
||||
57
vendor/zuptsdk/include/zsdk_xchacha20_poly1305.h
vendored
Normal file
57
vendor/zuptsdk/include/zsdk_xchacha20_poly1305.h
vendored
Normal 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/zuptsdk/include/zupt.h
vendored
Normal file
401
vendor/zuptsdk/include/zupt.h
vendored
Normal 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.2"
|
||||
#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/zuptsdk/include/zupt_acsl.h
vendored
Normal file
43
vendor/zuptsdk/include/zupt_acsl.h
vendored
Normal 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/zuptsdk/include/zupt_cpuid.h
vendored
Normal file
33
vendor/zuptsdk/include/zupt_cpuid.h
vendored
Normal 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/zuptsdk/include/zupt_jasmin.h
vendored
Normal file
65
vendor/zuptsdk/include/zupt_jasmin.h
vendored
Normal 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 a→out. if cond!=0: copies b→out.
|
||||
* 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 a↔b 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/zuptsdk/include/zupt_keccak.h
vendored
Normal file
49
vendor/zuptsdk/include/zupt_keccak.h
vendored
Normal 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/zuptsdk/include/zupt_mlkem.h
vendored
Normal file
65
vendor/zuptsdk/include/zupt_mlkem.h
vendored
Normal 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/zuptsdk/include/zupt_x25519.h
vendored
Normal file
22
vendor/zuptsdk/include/zupt_x25519.h
vendored
Normal 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/zuptsdk/include/zuptsdk.h
vendored
Normal file
605
vendor/zuptsdk/include/zuptsdk.h
vendored
Normal 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/zuptsdk/include/zuptsdk.hpp
vendored
Normal file
230
vendor/zuptsdk/include/zuptsdk.hpp
vendored
Normal 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/zuptsdk/include/zuptsdk_easy.h
vendored
Normal file
89
vendor/zuptsdk/include/zuptsdk_easy.h
vendored
Normal 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
|
||||
57
vendor/zuptsdk/include/zuptsdk_metrics.h
vendored
Normal file
57
vendor/zuptsdk/include/zuptsdk_metrics.h
vendored
Normal 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
|
||||
Loading…
Reference in a new issue