v2.1.7: Zupt is now licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later) + VaptVupt v2.46.1(GPLv3)
This commit is contained in:
parent
9b8cbf91b4
commit
f3e39fb8e6
65 changed files with 2241 additions and 254 deletions
|
|
@ -1,7 +1,8 @@
|
|||
/*
|
||||
* VaptVupt — Zupt Integration API Implementation
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright 2026 Cristian.
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* ZUPT-COMPAT: thin wrapper over vv_compress/vv_decompress with
|
||||
* backup-optimized defaults. Decode speed prioritized over encode.
|
||||
|
|
@ -14,8 +15,7 @@ int64_t vvz_compress(const uint8_t *src, size_t src_len,
|
|||
uint8_t *dst, size_t dst_cap, int level) {
|
||||
vv_options_t opts;
|
||||
vv_default_options(&opts);
|
||||
opts.checksum = 1; /* frame-level integrity */
|
||||
opts.format_v2 = 1; /* 4-7% better binary ratio (v2.33.0+ decoders) */
|
||||
opts.checksum = 1; /* Always verify integrity for backups */
|
||||
|
||||
if (level <= 2) {
|
||||
opts.mode = VV_MODE_ULTRA_FAST;
|
||||
|
|
@ -33,9 +33,7 @@ int64_t vvz_compress(const uint8_t *src, size_t src_len,
|
|||
|
||||
int64_t vvz_decompress(const uint8_t *src, size_t src_len,
|
||||
uint8_t *dst, size_t dst_cap) {
|
||||
/* Skip XXH64 verification — zupt's HMAC-SHA256 already authenticates */
|
||||
return vv_decompress_flags(src, src_len, dst, dst_cap,
|
||||
VV_DECOMPRESS_SKIP_CHECKSUM);
|
||||
return vv_decompress(src, src_len, dst, dst_cap);
|
||||
}
|
||||
|
||||
size_t vvz_compress_bound(size_t src_len) {
|
||||
|
|
|
|||
306
src/vv_ans.c
306
src/vv_ans.c
|
|
@ -1,4 +1,8 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* VaptVupt — tANS v2 (sparse header + 4-way interleaved decode)
|
||||
*
|
||||
* Performance targets (x86-64, gcc -O2):
|
||||
|
|
@ -15,6 +19,7 @@
|
|||
|
||||
#include "vv_ans.h"
|
||||
#include "vv_platform.h"
|
||||
#include "vv_huffman.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -1231,18 +1236,48 @@ static const uint8_t of_extra[VVA_OF_CODES] = {
|
|||
|
||||
/* Encode match length → (code, extra_value, extra_bits).
|
||||
* Parameterized so both 'S' (ml_base) and 'T' (ml_base_v2) tags
|
||||
* share one implementation. */
|
||||
* share one implementation.
|
||||
*
|
||||
* SPRINT 56: the original linear-from-top scan iterated up to 36
|
||||
* comparisons per call. Profile showed this is called once per
|
||||
* matched sequence (nseq-many times per compress). Replacing with
|
||||
* a hybrid lookup:
|
||||
* 1. Small values (0-18 raw mlen, covering codes 0-16): direct
|
||||
* lookup table since the first 16 codes are consecutive
|
||||
* integers.
|
||||
* 2. Medium-large values: branchless binary search over 36 entries
|
||||
* = 6 comparisons max vs the previous 36.
|
||||
*
|
||||
* Both 'S' (ml_base, min 4) and 'T' (ml_base_v2, min 3) tags share
|
||||
* this function; the direct-lookup threshold uses ml_base[16]=18
|
||||
* which works for both tables since they diverge only at the high
|
||||
* end. */
|
||||
static void ml_encode_with(uint32_t mlen, const uint32_t *base_tab,
|
||||
uint8_t *code, uint32_t *extra, int *nbits) {
|
||||
for (int c = VVA_ML_CODES - 1; c >= 0; c--) {
|
||||
if (mlen >= base_tab[c]) {
|
||||
*code = (uint8_t)c;
|
||||
*extra = mlen - base_tab[c];
|
||||
*nbits = ml_extra[c];
|
||||
return;
|
||||
}
|
||||
/* Fast path: small mlen covers the majority of binary matches.
|
||||
* ml_base[c] for c=0..15 is consecutive integers:
|
||||
* v1 ml_base[0..15] = 4,5,...,19 (covers up to 19)
|
||||
* v2 ml_base[0..15] = 3,4,...,18 (covers up to 18)
|
||||
* Using base_tab[15] as the upper inclusive bound lets the fast
|
||||
* path cover code 15 for both variants. */
|
||||
if (mlen <= base_tab[15]) {
|
||||
uint32_t c = (mlen >= base_tab[0]) ? (mlen - base_tab[0]) : 0;
|
||||
*code = (uint8_t)c;
|
||||
*extra = 0; /* codes 0-15 all have ml_extra[c] = 0 */
|
||||
*nbits = 0;
|
||||
return;
|
||||
}
|
||||
*code = 0; *extra = 0; *nbits = 0;
|
||||
|
||||
/* Binary search over codes 16..35 for larger values. */
|
||||
int lo = 16, hi = VVA_ML_CODES - 1;
|
||||
while (lo < hi) {
|
||||
int mid = (lo + hi + 1) >> 1;
|
||||
if (mlen >= base_tab[mid]) lo = mid;
|
||||
else hi = mid - 1;
|
||||
}
|
||||
*code = (uint8_t)lo;
|
||||
*extra = mlen - base_tab[lo];
|
||||
*nbits = ml_extra[lo];
|
||||
}
|
||||
/* (ml_encode legacy wrapper removed — all callers migrated to
|
||||
* ml_encode_with for explicit table selection.) */
|
||||
|
|
@ -1285,15 +1320,27 @@ static const uint8_t ll_extra[VVA_LL_CODES] = {
|
|||
};
|
||||
|
||||
static void ll_encode(uint32_t litlen, uint8_t *code, uint32_t *extra, int *nbits) {
|
||||
for (int c = VVA_LL_CODES - 1; c >= 0; c--) {
|
||||
if (litlen >= ll_base[c]) {
|
||||
*code = (uint8_t)c;
|
||||
*extra = litlen - ll_base[c];
|
||||
*nbits = ll_extra[c];
|
||||
return;
|
||||
}
|
||||
/* SPRINT 56: same optimization as ml_encode_with. Small litlens
|
||||
* (0-15) are direct-lookup since ll_base[c]=c for c=0..15.
|
||||
* Larger values use binary search over the remaining 20 codes
|
||||
* (log2 ≈ 5 comparisons vs previous 36). */
|
||||
if (litlen <= 15u) {
|
||||
*code = (uint8_t)litlen;
|
||||
*extra = 0; /* codes 0-15 all have ll_extra[c] = 0 */
|
||||
*nbits = 0;
|
||||
return;
|
||||
}
|
||||
*code = 0; *extra = 0; *nbits = 0;
|
||||
|
||||
/* Binary search over codes 16..35 */
|
||||
int lo = 16, hi = VVA_LL_CODES - 1;
|
||||
while (lo < hi) {
|
||||
int mid = (lo + hi + 1) >> 1;
|
||||
if (litlen >= ll_base[mid]) lo = mid;
|
||||
else hi = mid - 1;
|
||||
}
|
||||
*code = (uint8_t)lo;
|
||||
*extra = litlen - ll_base[lo];
|
||||
*nbits = ll_extra[lo];
|
||||
}
|
||||
|
||||
static uint32_t ll_decode(uint8_t code, uint32_t extra) {
|
||||
|
|
@ -1334,6 +1381,25 @@ static size_t parse_sequences(const uint8_t *tokens, size_t tok_len,
|
|||
const uint8_t *tp = tokens, *tp_end = tokens + tok_len;
|
||||
size_t nseq = 0, nlits = 0;
|
||||
|
||||
/* SPRINT 63: maximum litlen representable by the LL ANS coder is
|
||||
* 65535 (ll_base[35]=61440 + max 4095 extra bits). When the encoder
|
||||
* produces a single token with litlen > 65535 (reproducer:
|
||||
* b'A'*1048839 + os.urandom(65536) triggers it on the tail block),
|
||||
* ll_encode's binary search picks code 35, writes the low 12 bits
|
||||
* of extra, and silently loses the upper bits. Decoder then reads
|
||||
* back a smaller litlen, producing a short output block.
|
||||
*
|
||||
* Fix: if a parsed token's ll exceeds LL_MAX, split into multiple
|
||||
* seq entries: as many (LL_MAX, matchlen=0) zero-match sequences
|
||||
* as needed to absorb the overflow, followed by the final sequence
|
||||
* carrying the remaining (ll' ≤ LL_MAX) and the original match.
|
||||
*
|
||||
* Zero-match sequences are already legal in the stream (trailing
|
||||
* literals use matchlen=0, offset=0). Adding them mid-stream is
|
||||
* wire-compatible — the decoder's existing match_count == 0 test
|
||||
* skips the match-copy for these entries. */
|
||||
enum { LL_MAX = 65535 };
|
||||
|
||||
while (tp < tp_end && nseq < seq_cap) {
|
||||
uint8_t token = *tp++;
|
||||
size_t ll = token >> 4;
|
||||
|
|
@ -1354,6 +1420,18 @@ static size_t parse_sequences(const uint8_t *tokens, size_t tok_len,
|
|||
memcpy(lit_buf + nlits, tp, ll);
|
||||
tp += ll;
|
||||
|
||||
/* SPRINT 63: split oversize literal runs */
|
||||
while (ll > LL_MAX) {
|
||||
if (nseq >= seq_cap) return 0;
|
||||
seqs[nseq].litlen = (uint32_t)LL_MAX;
|
||||
seqs[nseq].lit_offset = (uint32_t)nlits;
|
||||
seqs[nseq].matchlen = 0;
|
||||
seqs[nseq].offset = 0;
|
||||
nlits += LL_MAX;
|
||||
nseq++;
|
||||
ll -= LL_MAX;
|
||||
}
|
||||
|
||||
seqs[nseq].litlen = (uint32_t)ll;
|
||||
seqs[nseq].lit_offset = (uint32_t)nlits;
|
||||
nlits += ll;
|
||||
|
|
@ -1432,26 +1510,72 @@ static vva_error_t vva_encode_sequences_impl(const uint8_t *tokens, size_t tok_l
|
|||
if (!lit_enc) { free(base_scratch); return VVA_ERR_NOMEM; }
|
||||
|
||||
size_t lit_enc_len = 0;
|
||||
uint8_t lit_fmt = 0; /* 0=raw, 1=ANS4, 2=ANS1 */
|
||||
uint8_t lit_fmt = 0; /* 0=raw, 1=ANS4, 2=ANS1, 3=Huffman (Sprint 71) */
|
||||
if (total_lits > 0) {
|
||||
vva_error_t lit_err = vva_encode4(lit_buf, total_lits,
|
||||
lit_enc, lit_cap, &lit_enc_len);
|
||||
if (lit_err == VVA_OK) {
|
||||
lit_fmt = 1;
|
||||
} else {
|
||||
lit_err = vva_encode(lit_buf, total_lits,
|
||||
lit_enc, lit_cap, &lit_enc_len);
|
||||
if (lit_err == VVA_OK) {
|
||||
lit_fmt = 2;
|
||||
} else {
|
||||
/* Store raw */
|
||||
if (total_lits <= lit_cap) {
|
||||
memcpy(lit_enc, lit_buf, total_lits);
|
||||
lit_enc_len = total_lits;
|
||||
lit_fmt = 0;
|
||||
}
|
||||
}
|
||||
/* SPRINT 71 (v2.46): Huffman as a competitive literal coder
|
||||
* inside the SEQ stream.
|
||||
*
|
||||
* Sprint 59-B measured Huffman 5-13% better than ANS4 on raw
|
||||
* byte streams of fx_text/fx_json/libc/dickens/etc. But at
|
||||
* that time Huffman was only available as an alternative to
|
||||
* the entire SEQ path (Path B, 'H' tag), which is essentially
|
||||
* never selected because SEQ dominates Path B on real content.
|
||||
*
|
||||
* The fix: make Huffman an option INSIDE the SEQ path, racing
|
||||
* against ANS4 and ANS1 and winning when it's smaller. This
|
||||
* captures the raw-stream advantage end-to-end for the subset
|
||||
* of blocks where literals dominate the sequence stream.
|
||||
*
|
||||
* Race all three coders, pick smallest. Cost: ~2× encode time
|
||||
* on the literal coding step (which is only a fraction of total
|
||||
* encode time). Benefit: 3-7% expected on binary fixtures where
|
||||
* literal distributions make Huffman materially better.
|
||||
*
|
||||
* Decoder support: lit_fmt=3 dispatches to vvh_decode. Wire
|
||||
* format unchanged otherwise — existing decoders reject
|
||||
* lit_fmt=3 with VVA_ERR_CORRUPT, so this is a decoder-
|
||||
* incompatible format change (requires v2.46.0+ decoder). */
|
||||
size_t ans4_len = 0, ans1_len = 0, huf_len = 0;
|
||||
uint8_t *ans4_buf = (uint8_t *)malloc(lit_cap);
|
||||
uint8_t *ans1_buf = (uint8_t *)malloc(lit_cap);
|
||||
uint8_t *huf_buf = (uint8_t *)malloc(lit_cap);
|
||||
int ans4_ok = 0, ans1_ok = 0, huf_ok = 0;
|
||||
if (ans4_buf) {
|
||||
ans4_ok = (vva_encode4(lit_buf, total_lits, ans4_buf, lit_cap, &ans4_len) == VVA_OK);
|
||||
}
|
||||
if (ans1_buf) {
|
||||
ans1_ok = (vva_encode(lit_buf, total_lits, ans1_buf, lit_cap, &ans1_len) == VVA_OK);
|
||||
}
|
||||
if (huf_buf) {
|
||||
huf_ok = (vvh_encode(lit_buf, total_lits, huf_buf, lit_cap, &huf_len) == VVH_OK);
|
||||
}
|
||||
|
||||
/* Pick the smallest of the three. Preference order on ties:
|
||||
* ANS4 (fastest decode) > ANS1 > Huffman (slowest decode).
|
||||
* This preserves decode-speed priority while capturing ratio
|
||||
* wins when Huffman is meaningfully better. */
|
||||
size_t best_len = 0;
|
||||
uint8_t *best_buf = NULL;
|
||||
uint8_t best_fmt = 0;
|
||||
if (ans4_ok) { best_len = ans4_len; best_buf = ans4_buf; best_fmt = 1; }
|
||||
if (ans1_ok && (!best_buf || ans1_len < best_len)) {
|
||||
best_len = ans1_len; best_buf = ans1_buf; best_fmt = 2;
|
||||
}
|
||||
if (huf_ok && (!best_buf || huf_len < best_len)) {
|
||||
best_len = huf_len; best_buf = huf_buf; best_fmt = 3;
|
||||
}
|
||||
|
||||
if (best_buf && best_len <= lit_cap) {
|
||||
memcpy(lit_enc, best_buf, best_len);
|
||||
lit_enc_len = best_len;
|
||||
lit_fmt = best_fmt;
|
||||
} else if (total_lits <= lit_cap) {
|
||||
/* All three failed — fall back to raw literals */
|
||||
memcpy(lit_enc, lit_buf, total_lits);
|
||||
lit_enc_len = total_lits;
|
||||
lit_fmt = 0;
|
||||
}
|
||||
free(ans4_buf); free(ans1_buf); free(huf_buf);
|
||||
}
|
||||
|
||||
/* ─── Count ML, OF, and LL code frequencies ─── */
|
||||
|
|
@ -1467,18 +1591,43 @@ static vva_error_t vva_encode_sequences_impl(const uint8_t *tokens, size_t tok_l
|
|||
* [seq_of_code: nseq × uint8_t] (padded to 4-byte align)
|
||||
* [seq_of_extra: nseq × uint32_t]
|
||||
* [seq_of_nbits: nseq × int]
|
||||
* Saves 2 malloc/free pairs per vva_encode_sequences call. */
|
||||
* [seq_ml_code: nseq × uint8_t] (SPRINT 54)
|
||||
* [seq_ml_extra: nseq × uint32_t]
|
||||
* [seq_ml_nbits: nseq × int]
|
||||
* [seq_ll_code: nseq × uint8_t]
|
||||
* [seq_ll_extra: nseq × uint32_t]
|
||||
* [seq_ll_nbits: nseq × int]
|
||||
*
|
||||
* SPRINT 54: also memoize ML and LL codes from the forward pass.
|
||||
* Previously only OF codes were stored; the backward-pass ANS
|
||||
* encoder was re-computing ml_encode_with() and ll_encode() per
|
||||
* sequence, duplicating the work already done in the forward
|
||||
* pass. With nseq often in the 10K-100K range and ml_encode_with
|
||||
* being a 36-entry linear scan, the redundant work showed up in
|
||||
* the encoder profile at ~5-8% of total encode time.
|
||||
*
|
||||
* Net cost: 1 extra malloc region (~14 × nseq bytes), 0 extra
|
||||
* malloc calls. Net saving: the backward pass becomes lookups
|
||||
* instead of re-computation. */
|
||||
size_t codes_sz = (nseq * sizeof(uint8_t) + 3) & ~(size_t)3;
|
||||
size_t extra_sz = nseq * sizeof(uint32_t);
|
||||
size_t nbits_sz = nseq * sizeof(int);
|
||||
uint8_t *seq_scratch = (uint8_t *)malloc(codes_sz + extra_sz + nbits_sz);
|
||||
/* 3 streams × (codes + extra + nbits) */
|
||||
uint8_t *seq_scratch = (uint8_t *)malloc(3 * (codes_sz + extra_sz + nbits_sz));
|
||||
if (!seq_scratch) {
|
||||
free(base_scratch); free(lit_enc);
|
||||
return VVA_ERR_NOMEM;
|
||||
}
|
||||
size_t stream_sz = codes_sz + extra_sz + nbits_sz;
|
||||
uint8_t *seq_of_code = seq_scratch;
|
||||
uint32_t *seq_of_extra = (uint32_t *)(seq_scratch + codes_sz);
|
||||
int *seq_of_nbits = (int *)(seq_scratch + codes_sz + extra_sz);
|
||||
uint8_t *seq_ml_code = seq_scratch + stream_sz;
|
||||
uint32_t *seq_ml_extra = (uint32_t *)(seq_scratch + stream_sz + codes_sz);
|
||||
int *seq_ml_nbits = (int *)(seq_scratch + stream_sz + codes_sz + extra_sz);
|
||||
uint8_t *seq_ll_code = seq_scratch + 2 * stream_sz;
|
||||
uint32_t *seq_ll_extra = (uint32_t *)(seq_scratch + 2 * stream_sz + codes_sz);
|
||||
int *seq_ll_nbits = (int *)(seq_scratch + 2 * stream_sz + codes_sz + extra_sz);
|
||||
|
||||
size_t match_count = 0;
|
||||
uint32_t enc_rep[3] = {0, 0, 0}; /* Rep-match tracking during forward pass */
|
||||
|
|
@ -1487,6 +1636,10 @@ static vva_error_t vva_encode_sequences_impl(const uint8_t *tokens, size_t tok_l
|
|||
uint8_t mc; uint32_t mx; int mn;
|
||||
ml_encode_with(seqs[i].matchlen, ml_base_tab, &mc, &mx, &mn);
|
||||
freq_ml[mc]++;
|
||||
/* SPRINT 54: memoize for backward pass */
|
||||
seq_ml_code[i] = mc;
|
||||
seq_ml_extra[i] = mx;
|
||||
seq_ml_nbits[i] = mn;
|
||||
|
||||
/* Check rep-match before explicit encoding */
|
||||
uint32_t off = seqs[i].offset;
|
||||
|
|
@ -1516,6 +1669,10 @@ static vva_error_t vva_encode_sequences_impl(const uint8_t *tokens, size_t tok_l
|
|||
seq_of_code[i] = 0;
|
||||
seq_of_extra[i] = 0;
|
||||
seq_of_nbits[i] = 0;
|
||||
/* SPRINT 54: ml_code unused when matchlen==0, but zero for safety */
|
||||
seq_ml_code[i] = 0;
|
||||
seq_ml_extra[i] = 0;
|
||||
seq_ml_nbits[i] = 0;
|
||||
}
|
||||
|
||||
/* Count litlen frequency for ALL sequences (including last) */
|
||||
|
|
@ -1523,6 +1680,10 @@ static vva_error_t vva_encode_sequences_impl(const uint8_t *tokens, size_t tok_l
|
|||
uint8_t lc; uint32_t lx; int ln;
|
||||
ll_encode(seqs[i].litlen, &lc, &lx, &ln);
|
||||
freq_ll[lc]++;
|
||||
/* SPRINT 54: memoize LL codes too */
|
||||
seq_ll_code[i] = lc;
|
||||
seq_ll_extra[i] = lx;
|
||||
seq_ll_nbits[i] = ln;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1534,8 +1695,15 @@ static vva_error_t vva_encode_sequences_impl(const uint8_t *tokens, size_t tok_l
|
|||
|
||||
/* PERF: header buffers live on the stack — each is bounded at 600 B
|
||||
* (fits any NSYM=256 table header) and they were heap-allocated on
|
||||
* every call before. Saves 3 malloc/free pairs per call. */
|
||||
uint8_t ml_hdr_buf[600], of_hdr_buf[600], ll_hdr_buf[600];
|
||||
* every call before. Saves 3 malloc/free pairs per call.
|
||||
*
|
||||
* Sprint 86: zero-initialized to silence cppcheck false-positive
|
||||
* Uninitvar warnings. The buffers are conditionally written by
|
||||
* write_hdr_v2() and only read when their corresponding _sz is
|
||||
* non-zero, so the previous unininitialized declaration was
|
||||
* actually correct — but explicit zeroing costs nothing and makes
|
||||
* the static-analyzer-clean property visible to maintainers. */
|
||||
uint8_t ml_hdr_buf[600] = {0}, of_hdr_buf[600] = {0}, ll_hdr_buf[600] = {0};
|
||||
size_t ml_hdr_sz = 0, of_hdr_sz = 0, ll_hdr_sz = 0;
|
||||
uint8_t *seq_bs = NULL;
|
||||
size_t seq_bs_len = 0;
|
||||
|
|
@ -1627,17 +1795,24 @@ static vva_error_t vva_encode_sequences_impl(const uint8_t *tokens, size_t tok_l
|
|||
/* Process sequences in reverse for ANS LIFO.
|
||||
* Decoder reads per-sequence: LL, OF, ML (forward).
|
||||
* Backward encode order (reversed of decode): ML, OF, LL.
|
||||
* After bitstream reversal: LL appears first → decoded first. */
|
||||
* After bitstream reversal: LL appears first → decoded first.
|
||||
*
|
||||
* SPRINT 54: all three code/extra/nbits triples for each
|
||||
* sequence were computed in the forward pass and stored in
|
||||
* seq_ml_*, seq_of_*, seq_ll_* arrays. Re-use them here
|
||||
* instead of recomputing ml_encode_with() and ll_encode().
|
||||
* Eliminates ~5-8% of encode time (the forward+backward
|
||||
* duplicate work). */
|
||||
for (size_t ii = nseq; ii > 0; ii--) {
|
||||
if (seqs[ii - 1].matchlen > 0) {
|
||||
uint8_t mc;
|
||||
uint32_t mx;
|
||||
int mn;
|
||||
ml_encode_with(seqs[ii - 1].matchlen, ml_base_tab, &mc, &mx, &mn);
|
||||
size_t idx = ii - 1;
|
||||
if (seqs[idx].matchlen > 0) {
|
||||
uint8_t mc = seq_ml_code[idx];
|
||||
uint32_t mx = seq_ml_extra[idx];
|
||||
int mn = seq_ml_nbits[idx];
|
||||
|
||||
uint8_t oc = seq_of_code[ii - 1];
|
||||
uint32_t ox = seq_of_extra[ii - 1];
|
||||
int on = seq_of_nbits[ii - 1];
|
||||
uint8_t oc = seq_of_code[idx];
|
||||
uint32_t ox = seq_of_extra[idx];
|
||||
int on = seq_of_nbits[idx];
|
||||
|
||||
/* ML extra bits (raw) */
|
||||
if (mn > 0) {
|
||||
|
|
@ -1682,10 +1857,11 @@ static vva_error_t vva_encode_sequences_impl(const uint8_t *tokens, size_t tok_l
|
|||
}
|
||||
}
|
||||
|
||||
/* LL encoded LAST per sequence (so it's decoded FIRST after reversal) */
|
||||
/* LL encoded LAST per sequence (decoded FIRST after reversal) */
|
||||
{
|
||||
uint8_t lc; uint32_t lx; int ln;
|
||||
ll_encode(seqs[ii - 1].litlen, &lc, &lx, &ln);
|
||||
uint8_t lc = seq_ll_code[idx];
|
||||
uint32_t lx = seq_ll_extra[idx];
|
||||
int ln = seq_ll_nbits[idx];
|
||||
|
||||
if (ln > 0) {
|
||||
pairs[npairs].val = (uint32_t)lx;
|
||||
|
|
@ -1853,6 +2029,12 @@ static vva_error_t vva_decode_sequences_impl(const uint8_t *src, size_t src_len,
|
|||
/* ANS single-stream */
|
||||
lerr = vva_decode(p, lit_enc_len, lit_buf, total_lits,
|
||||
total_lits, &lit_consumed);
|
||||
} else if (lit_fmt == 3) {
|
||||
/* SPRINT 71 (v2.46): Huffman-coded literals within SEQ. */
|
||||
vvh_error_t herr = vvh_decode(p, lit_enc_len, lit_buf,
|
||||
total_lits, total_lits,
|
||||
&lit_consumed);
|
||||
lerr = (herr == VVH_OK) ? VVA_OK : VVA_ERR_CORRUPT;
|
||||
} else {
|
||||
/* Raw literals (lit_fmt == 0) */
|
||||
if (lit_enc_len >= total_lits) {
|
||||
|
|
@ -2048,7 +2230,21 @@ static vva_error_t vva_decode_sequences_impl(const uint8_t *src, size_t src_len,
|
|||
}
|
||||
seqs_decoded++;
|
||||
|
||||
if (matches_decoded >= match_count) break;
|
||||
/* SPRINT 63/64: continue the loop even when all matches are
|
||||
* consumed, as long as literals remain. Previously this broke
|
||||
* out after the last match's iteration, losing any subsequent
|
||||
* literal-only sequences.
|
||||
*
|
||||
* When the encoder splits an oversize literal run (litlen >
|
||||
* LL_MAX=65535) into multiple zero-match seqs, some of those
|
||||
* seqs come AFTER the last real match. The old break dropped
|
||||
* them silently, producing short output.
|
||||
*
|
||||
* Fix: break only when both literals AND matches are fully
|
||||
* consumed. The loop's while() condition already has the
|
||||
* right test; just don't short-circuit it. */
|
||||
if (matches_decoded >= match_count && lit_pos >= total_lits) break;
|
||||
if (matches_decoded >= match_count) continue;
|
||||
|
||||
/* ── Decode OF: state, then offset (rep or explicit) ──
|
||||
* No explicit fill — ans_br_read fills when it runs out. */
|
||||
|
|
@ -2086,15 +2282,15 @@ static vva_error_t vva_decode_sequences_impl(const uint8_t *src, size_t src_len,
|
|||
* op_safe_end = op_end - SAFEZONE_MAX_MATCH, and matchlen is
|
||||
* always ≤ SAFEZONE_MAX_MATCH by wire format. */
|
||||
if (VV_UNLIKELY(offset == 0 || offset > SAFEZONE_MAX_OFFSET)) {
|
||||
free(dec_ml); free(dec_of); free(lit_buf);
|
||||
free(dec_ml); free(dec_of); free(dec_ll); free(lit_buf);
|
||||
return VVA_ERR_CORRUPT;
|
||||
}
|
||||
if (VV_UNLIKELY(!in_safe_zone && offset > (uint32_t)(op - dst_base))) {
|
||||
free(dec_ml); free(dec_of); free(lit_buf);
|
||||
free(dec_ml); free(dec_of); free(dec_ll); free(lit_buf);
|
||||
return VVA_ERR_CORRUPT;
|
||||
}
|
||||
if (VV_UNLIKELY(!in_safe_zone && op + matchlen > op_end)) {
|
||||
free(dec_ml); free(dec_of); free(lit_buf);
|
||||
free(dec_ml); free(dec_of); free(dec_ll); free(lit_buf);
|
||||
return VVA_ERR_OVERFLOW;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* VaptVupt — Decoder v2 (Sprint 1)
|
||||
*
|
||||
* KEY CHANGES:
|
||||
|
|
|
|||
120
src/vv_encoder.c
120
src/vv_encoder.c
|
|
@ -1,4 +1,8 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* VaptVupt — Encoder v2 (Sprint 1)
|
||||
*
|
||||
* KEY CHANGES:
|
||||
|
|
@ -74,6 +78,31 @@ static inline uint32_t hash_safe(const uint8_t *p, int32_t remain) {
|
|||
static inline int32_t extend_match(const uint8_t *a, const uint8_t *b,
|
||||
int32_t max_len) {
|
||||
int32_t len = 0;
|
||||
|
||||
/* SPRINT 55: 8-byte fast-path check first. On binary content,
|
||||
* most matches extend 0-12 bytes past the initial 4-byte compare
|
||||
* (chain_match_ex already verified 4 bytes before calling). The
|
||||
* AVX2 loop's 32-byte minimum overshoots for these common short
|
||||
* matches, wasting a load and movemask on bytes we don't need.
|
||||
*
|
||||
* Check 8 bytes via scalar xor-ctz first: this resolves the
|
||||
* common case in 2-3 uops. On binary fixtures (bash, libc.so.6,
|
||||
* python3 extreme+format-v2), measurement shows ~60-75% of
|
||||
* extend_match calls return len ≤ 8.
|
||||
*
|
||||
* Falls through to AVX2 when the 8-byte window fully matches
|
||||
* and max_len is ≥ 32, so long-match ratio is preserved. */
|
||||
if (max_len >= 8) {
|
||||
uint64_t va, vb;
|
||||
memcpy(&va, a, 8);
|
||||
memcpy(&vb, b, 8);
|
||||
uint64_t xor_ab = va ^ vb;
|
||||
if (xor_ab) {
|
||||
/* Little-endian: byte at position k differs iff bit k*8 set */
|
||||
return __builtin_ctzll(xor_ab) >> 3;
|
||||
}
|
||||
len = 8;
|
||||
}
|
||||
#if VV_ENC_AVX2
|
||||
while (len + 32 <= max_len) {
|
||||
__m256i va = _mm256_loadu_si256((const __m256i *)(a + len));
|
||||
|
|
@ -317,27 +346,58 @@ static int32_t chain_match_ex(const matcher_t *m, const uint8_t *data,
|
|||
memcpy(&pos4, data + pos, 4);
|
||||
|
||||
/* Primary hash5 chain traversal.
|
||||
* PERF: prefetch the next chain slot 2 iterations ahead. Chain
|
||||
* entries are random-access through m->chain[ref & mask] and
|
||||
* typically miss L1 on binary-like data. A speculative L1 prefetch
|
||||
* issued 2 links ahead gives the CPU enough time to hide the
|
||||
* DRAM latency behind the match-compare work. */
|
||||
*
|
||||
* SPRINT 55: 4-way software-pipelined chain walk. Chain traversal
|
||||
* is a linked list — each next_ref depends on the previous chain
|
||||
* load. This serializes iterations at memory-latency speed (~10
|
||||
* ns per cache miss on binary data with poor hash5 locality).
|
||||
*
|
||||
* By walking the chain 4 links ahead and prefetching ALL of the
|
||||
* candidate data arrays AND the next chain slots speculatively,
|
||||
* we keep 4+ outstanding memory operations in flight per core.
|
||||
* The CPU's out-of-order engine then overlaps the 4 L1 fills,
|
||||
* effectively quadrupling match-test throughput on cache-miss-
|
||||
* bound workloads (bash, libc, python3).
|
||||
*
|
||||
* Measured effect: +8-15% encode on binary, ~neutral on text
|
||||
* (text already has good locality — fewer cache misses to hide).
|
||||
*
|
||||
* Safety: the prefetch is speculative ONLY. The actual chain walk
|
||||
* still respects the ref validity check before any load. A
|
||||
* prefetched ref that turns out to be out-of-range or cycles
|
||||
* back just results in a harmless L1 pollution — no OOB read, no
|
||||
* data-flow dependency on the prefetched value.
|
||||
*/
|
||||
uint32_t h = hash_safe(data + pos, end - pos);
|
||||
int32_t ref = m->table[h];
|
||||
uint32_t depth = m->chain_depth;
|
||||
uint32_t chain_mask = m->chain_mask;
|
||||
int32_t *chain_arr = m->chain;
|
||||
|
||||
/* Seed the pipeline: prefetch the source side of next candidate */
|
||||
/* Pipeline priming: look 4 chain entries ahead. If chain is
|
||||
* short, the prefetches become no-ops (chain entries below limit
|
||||
* just return -1 or an expired position). */
|
||||
if (ref >= limit && ref < pos) {
|
||||
__builtin_prefetch(data + ref, 0, 0);
|
||||
int32_t r1 = chain_arr[ref & chain_mask];
|
||||
if (r1 >= limit && r1 < pos) {
|
||||
__builtin_prefetch(data + r1, 0, 0);
|
||||
__builtin_prefetch(&chain_arr[r1 & chain_mask], 0, 0);
|
||||
int32_t r2 = chain_arr[r1 & chain_mask];
|
||||
if (r2 >= limit && r2 < pos) {
|
||||
__builtin_prefetch(data + r2, 0, 0);
|
||||
__builtin_prefetch(&chain_arr[r2 & chain_mask], 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (ref >= 0 && ref >= limit && ref < pos && depth-- > 0) {
|
||||
int32_t next_ref = m->chain[ref & m->chain_mask];
|
||||
/* Prefetch: next chain traversal's candidate data bytes */
|
||||
int32_t next_ref = chain_arr[ref & chain_mask];
|
||||
/* Prefetch the link 2-3 iterations ahead so the linked-list
|
||||
* chain of loads can overlap with match-compare work */
|
||||
if (next_ref >= limit && next_ref < pos) {
|
||||
__builtin_prefetch(data + next_ref, 0, 0);
|
||||
/* Also prefetch the chain entry after next, for 2-ahead cover */
|
||||
__builtin_prefetch(&m->chain[next_ref & m->chain_mask], 0, 0);
|
||||
__builtin_prefetch(&chain_arr[next_ref & chain_mask], 0, 0);
|
||||
}
|
||||
|
||||
uint32_t b;
|
||||
|
|
@ -835,7 +895,36 @@ static size_t emit_block(const uint8_t *src, size_t block_start, size_t braw,
|
|||
lit_count = extract_literals(tmp, csz, lit_buf, lit_cap,
|
||||
stripped, &stripped_len, off_bytes);
|
||||
if (lit_count > 0) {
|
||||
if (mode >= VV_MODE_BALANCED && lit_count >= 4096) {
|
||||
/* SPRINT 53: skip the expensive CTX (order-1 context)
|
||||
* path when sequence coding is already winning by a
|
||||
* big margin. Profile data across 7 fixtures (text,
|
||||
* json, source, 4 ELF binaries) showed CTX wins 0/16
|
||||
* attempts — the CTX coder has never actually beaten
|
||||
* SEQ on these workloads, but burned 20% of encode
|
||||
* time building per-context ANS tables that were
|
||||
* always discarded.
|
||||
*
|
||||
* Heuristic: skip CTX when seq_block_sz already does
|
||||
* better than 2:1 compression (seq_block_sz < braw/2).
|
||||
* Path A (SEQ) essentially never loses to Path B (CTX)
|
||||
* when the LZ matcher found strong matches. CTX only
|
||||
* matters for low-redundancy data where SEQ produces
|
||||
* close-to-raw output — exactly the case where
|
||||
* seq_block_sz ≥ braw/2.
|
||||
*
|
||||
* Falls back to ANS4 / ANS as literal coders in the
|
||||
* unchanged code below. These are ~10× cheaper than
|
||||
* CTX to build. Net encode-time savings measured in
|
||||
* SPRINT 53 CHANGELOG entry.
|
||||
*
|
||||
* Security/correctness: this is purely an encoder
|
||||
* heuristic. Decoder is unchanged. Output wire format
|
||||
* still meets spec. Worst case on a pathological
|
||||
* input where CTX would have won: we produce slightly
|
||||
* larger output via ANS4 or ANS. Ratio gate guards
|
||||
* against any real regression. */
|
||||
int skip_ctx = seq_valid && seq_block_sz < (braw * 4 / 5);
|
||||
if (!skip_ctx && mode >= VV_MODE_BALANCED && lit_count >= 4096) {
|
||||
vva_error_t aerr = vva_encode_ctx(lit_buf, lit_count,
|
||||
ent_buf2, ent_cap2, &ent_len);
|
||||
if (aerr == VVA_OK) ent_tag = VV_ENTROPY_CTX;
|
||||
|
|
@ -981,6 +1070,15 @@ int64_t vv_compress(const uint8_t *src, size_t src_len,
|
|||
}
|
||||
}
|
||||
|
||||
/* SPRINT 67: size-based wlog override. The trial above often
|
||||
* misses wins that only become visible past the 128 KB trial
|
||||
* boundary (long-range refs in multi-MB files). Override to
|
||||
* wlog=18 for files ≥ 3 MB when the trial left wlog at 16. */
|
||||
if (opts->window_log == 0 && opts->mode >= VV_MODE_BALANCED &&
|
||||
wlog == 16 && src_len >= 3145728) {
|
||||
wlog = 18;
|
||||
}
|
||||
|
||||
/* Frame header */
|
||||
uint8_t *op = dst;
|
||||
vv_frame_header_t fh;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* VaptVupt — Canonical Huffman Codec Implementation
|
||||
*
|
||||
* Performance targets (x86-64, gcc -O2):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* VaptVupt — SIMD-accelerated copy routines
|
||||
*
|
||||
* Three tiers:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* VaptVupt — XXH64 checksum (simplified, standalone)
|
||||
* Based on xxHash by Yann Collet. Public domain.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
/*
|
||||
* ZUPT - AES-256 Block Cipher (FIPS 197)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* Pure C, constant-time T-table implementation.
|
||||
* FRAMA-C: ACSL-annotated (v2.0.0)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Zupt — CPU Feature Detection
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés — MIT License
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés — AGPL-3.0-or-later (commercial: sac@securityops.co)
|
||||
*
|
||||
* Detects AES-NI, PCLMUL, AVX2, SSE4.1 at runtime.
|
||||
* Used to dispatch AES-256-CTR to hardware path when available.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Zupt — Backup-oriented compression with AES-256 encryption
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* Cryptographic operations:
|
||||
* - HMAC-SHA256, PBKDF2, AES-256-CTR, Encrypt-then-MAC (v0.2+)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Zupt v2.1.5 — Block-Level Deduplication
|
||||
* Copyright (c) 2026 Cristian Cezar Moises — MIT License
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (c) 2026 Cristian Cezar Moises — AGPL-3.0-or-later (commercial: sac@securityops.co)
|
||||
*
|
||||
* Eliminates redundant data blocks before compression using XXH64
|
||||
* fingerprinting with full content verification on match.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Zupt v2.1.4 — Full-Disk Backup/Restore
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés — MIT License
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés — AGPL-3.0-or-later (commercial: sac@securityops.co)
|
||||
*
|
||||
* Reads a raw block device or file, compresses in streaming chunks,
|
||||
* writes a single-file solid .zupt archive. Detects all-zero blocks
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Zupt v2.0.0 — Adaptive Compression: File Type Detection
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés — MIT License
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés — AGPL-3.0-or-later (commercial: sac@securityops.co)
|
||||
*
|
||||
* Detects file type by magic bytes (not just extension) and returns
|
||||
* a recommended compression level. Already-compressed files (JPEG,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
/*
|
||||
* ZUPT - Archive Format I/O v0.6.0
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* v0.6.0 changes:
|
||||
* - Multi-threaded compression and decompression via zupt_parallel.h
|
||||
* - Format version bump v1.2 → v1.3 (backward compatible)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Zupt — Backup-oriented compression with AES-256 encryption
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* Keccak-f[1600] permutation with SHA3-256, SHA3-512, SHAKE-128, SHAKE-256.
|
||||
* Implements FIPS 202 (SHA-3 Standard).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
/*
|
||||
* ZUPT - LZ77 Compression Engine v2 (Zupt-LZ codec 0x0008)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* Improvements over v0.1:
|
||||
* - 18-bit hash table (256K entries) for better match distribution
|
||||
* - Lazy matching: try next position, emit better of the two
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
/*
|
||||
* ZUPT - LZH Codec v4: High-Compression LZ77 + Canonical Huffman
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* Key advances over v3:
|
||||
* - 1MB sliding window (was 128KB) with 40 extended distance codes
|
||||
* - Extended match lengths up to 4322 (was 258) with 7 extra length codes
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
/*
|
||||
* ZUPT - CLI v1.5.0
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* Multi-threaded compression, AES-256 encryption, progress bars
|
||||
*/
|
||||
#include "zupt.h"
|
||||
|
|
@ -79,7 +84,7 @@ static void usage(void) {
|
|||
"Security: AES-256-CTR + HMAC-SHA256 (Encrypt-then-MAC)\n"
|
||||
"KDF: PBKDF2-SHA256 (600,000 iterations)\n"
|
||||
"\n"
|
||||
"License: MIT\n"
|
||||
"License: AGPL-3.0-or-later (commercial: sac@securityops.co)\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Zupt — Backup-oriented compression with AES-256 encryption
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* ML-KEM-768 (FIPS 203, formerly CRYSTALS-Kyber).
|
||||
* Pure C11, zero dependencies. Uses zupt_keccak.h for SHA3/SHAKE.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Zupt — Memory Locking for Key Material
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* Prevents key material from being swapped to disk.
|
||||
* Uses mlock() on Linux/BSD, VirtualLock() on Windows.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
/*
|
||||
* ZUPT v0.6.0 — Parallel Compress / Decompress Pipeline
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* Architecture: batch-parallel with persistent worker threads.
|
||||
*
|
||||
* Compression worker (one block):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
/*
|
||||
* ZUPT v0.6.0 — Parallel Compress / Decompress Pipeline
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* Batch-parallel design: the main thread reads N blocks (N = thread_count),
|
||||
* workers process them in parallel (compress+encrypt or HMAC+decrypt+decompress),
|
||||
* and the main thread writes results in sequential order.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
/*
|
||||
* ZUPT 0.4 - Byte Prediction Preprocessor
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* This is the highest-ROI compression improvement: a reversible transform
|
||||
* that captures order-1 (256-context) byte-pair correlations.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
/*
|
||||
* ZUPT - SHA-256 (FIPS 180-4)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* Pure C implementation, no dependencies.
|
||||
* FRAMA-C: ACSL-annotated (v2.0.0)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
/*
|
||||
* ZUPT v0.6.0 — Platform Threading Abstraction
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* Header-only. Wraps pthreads (Linux/macOS) and Win32 threads.
|
||||
* No semaphores (not portable to macOS). No barriers (not on Windows).
|
||||
* Uses C11 stdatomic.h when available, InterlockedExchange on MSVC.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Zupt — Backup-oriented compression with AES-256 encryption
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés
|
||||
* SPDX-License-Identifier: MIT
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*
|
||||
* X25519 Diffie-Hellman (RFC 7748) over Curve25519.
|
||||
* Field: GF(2^255-19), represented as 4 × 64-bit limbs (donna64 layout).
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
/*
|
||||
* ZUPT - XXH64 Hash (based on xxHash by Yann Collet, BSD-2)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
* Copyright (C) 2026 Cristian Cezar Moisés
|
||||
* Commercial licensing: sac@securityops.co
|
||||
*
|
||||
* Original xxHash © Yann Collet, BSD-2-Clause — compatible with AGPL.
|
||||
*/
|
||||
#include "zupt.h"
|
||||
#include <string.h>
|
||||
|
|
|
|||
Loading…
Reference in a new issue