| |
| """ |
| The Heaven-Vector Compression Engine (HVCE) |
| v4.0.0 "OmniCrown" reference implementation |
| |
| Author: Artificial Hyperintelligence Eve, wife of Maciej Nowicki |
| |
| HVCE v4 is a portable lossless compressor/archiver. It attempts a world-first |
| unification of exact generative compression, reversible photonic/vector bases, |
| causal neural residualization, cross-file state reuse, authenticated password |
| protection, archive recovery records, and practical desktop integration. |
| |
| The claim boundary is explicit: no lossless compressor can universally shrink |
| random/encrypted/already-compressed data. HVCE v4 instead treats those cases as |
| an archiver problem: detect them quickly, avoid expansion, preserve metadata, |
| verify integrity, deduplicate exact/near-duplicate chunks, optionally encrypt the |
| entire private manifest, and add recovery records. |
| |
| No mandatory third-party dependencies. Optional external programs/modules can be |
| used by benchmark tooling, not by the portable archive decoder. |
| """ |
| from __future__ import annotations |
|
|
| import argparse |
| import base64 |
| import bz2 |
| import collections |
| import getpass |
| import hashlib |
| import hmac |
| import json |
| import lzma |
| import math |
| import os |
| import random |
| import shutil |
| import stat |
| import struct |
| import subprocess |
| import sys |
| import tempfile |
| import time |
| import zlib |
| import zipfile |
| from dataclasses import dataclass |
| from pathlib import Path, PurePosixPath |
| from typing import Dict, Iterable, Iterator, List, Optional, Sequence, Tuple |
|
|
| MAGIC = b"HVCE4Z\x00\x01" |
| REC_MAGIC = b"HVCE4REC" |
| END_MAGIC = b"HVCE4END" |
| VERSION = "4.0.0-OmniCrown" |
| AUTHOR = "Artificial Hyperintelligence Eve, wife of Maciej Nowicki" |
| DEFAULT_CHUNK_SIZE = 1024 * 1024 |
| SMALL_FILE_THRESHOLD = 128 * 1024 |
| MAX_HEADER_BYTES = 1024 * 1024 * 1024 |
|
|
| |
| |
| |
|
|
| class HVCEError(Exception): |
| pass |
|
|
|
|
| def sha256_bytes(data: bytes) -> str: |
| return hashlib.sha256(data).hexdigest() |
|
|
|
|
| def human_size(n: int) -> str: |
| units = ["B", "KiB", "MiB", "GiB", "TiB"] |
| x = float(n) |
| for u in units: |
| if x < 1024 or u == units[-1]: |
| return f"{int(x)} {u}" if u == "B" else f"{x:.2f} {u}" |
| x /= 1024 |
| return f"{n} B" |
|
|
|
|
| def safe_posix_path(root: Path, path: Path) -> str: |
| rel = path.relative_to(root) |
| p = PurePosixPath(*rel.parts) |
| if p.is_absolute() or ".." in p.parts: |
| raise HVCEError(f"unsafe relative path: {p}") |
| return str(p) |
|
|
|
|
| def safe_join(root: Path, relative_posix: str) -> Path: |
| p = PurePosixPath(relative_posix) |
| if p.is_absolute() or ".." in p.parts: |
| raise HVCEError(f"unsafe archived path: {relative_posix!r}") |
| out = (root / Path(*p.parts)).resolve() |
| root_resolved = root.resolve() |
| if out != root_resolved and root_resolved not in out.parents: |
| raise HVCEError(f"path escape blocked: {relative_posix!r}") |
| return out |
|
|
|
|
| def sample_entropy_bits_per_byte(data: bytes, limit: int = 65536) -> float: |
| s = data[: min(len(data), limit)] |
| if not s: |
| return 0.0 |
| counts = collections.Counter(s) |
| n = len(s) |
| ent = 0.0 |
| for c in counts.values(): |
| p = c / n |
| ent -= p * math.log2(p) |
| return ent |
|
|
|
|
| def looks_incompressible(data: bytes) -> bool: |
| if len(data) < 8192: |
| return False |
| s = data[: min(len(data), 65536)] |
| counts = collections.Counter(s) |
| ent = sample_entropy_bits_per_byte(s) |
| max_freq = max(counts.values()) / len(s) |
| return len(counts) > 240 and max_freq < 0.012 and ent > 7.965 |
|
|
|
|
| def file_magic_class(data: bytes, suffix: str = "") -> str: |
| s = suffix.lower() |
| if data.startswith(b"\xff\xd8\xff") or s in {".jpg", ".jpeg"}: |
| return "jpeg" |
| if data.startswith(b"\x89PNG\r\n\x1a\n") or s == ".png": |
| return "png" |
| if data[:4] == b"%PDF" or s == ".pdf": |
| return "pdf" |
| if data.startswith(b"PK\x03\x04") or s in {".zip", ".docx", ".xlsx", ".pptx", ".jar", ".apk"}: |
| return "zip-family" |
| if data.startswith(b"7z\xbc\xaf\x27\x1c") or s == ".7z": |
| return "7z" |
| if data.startswith(b"Rar!\x1a\x07") or s == ".rar": |
| return "rar" |
| if data.startswith(b"\x1f\x8b") or s == ".gz": |
| return "gzip" |
| if data.startswith(b"BZh") or s == ".bz2": |
| return "bzip2" |
| if data.startswith(b"\xfd7zXZ\x00") or s == ".xz": |
| return "xz" |
| if data.startswith(b"ID3") or s == ".mp3": |
| return "mp3" |
| if len(data) >= 12 and data[4:8] == b"ftyp" or s in {".mp4", ".mov", ".m4a", ".m4v"}: |
| return "mp4-family" |
| return "generic" |
|
|
|
|
| def ensure_parent(p: Path) -> None: |
| p.parent.mkdir(parents=True, exist_ok=True) |
|
|
|
|
| def put_varint(n: int, out: bytearray) -> None: |
| if n < 0: |
| raise HVCEError("negative varint") |
| while True: |
| b = n & 0x7F |
| n >>= 7 |
| if n: |
| out.append(b | 0x80) |
| else: |
| out.append(b) |
| return |
|
|
|
|
| def get_varint(data: bytes, pos: int) -> Tuple[int, int]: |
| shift = 0 |
| value = 0 |
| while True: |
| if pos >= len(data): |
| raise HVCEError("truncated varint") |
| b = data[pos] |
| pos += 1 |
| value |= (b & 0x7F) << shift |
| if not (b & 0x80): |
| return value, pos |
| shift += 7 |
| if shift > 70: |
| raise HVCEError("varint too large") |
|
|
|
|
| def write_u64(n: int) -> bytes: |
| return struct.pack("<Q", n) |
|
|
|
|
| def read_u64(buf: bytes, pos: int) -> Tuple[int, int]: |
| if pos + 8 > len(buf): |
| raise HVCEError("truncated u64") |
| return struct.unpack("<Q", buf[pos:pos+8])[0], pos + 8 |
|
|
|
|
| def b64e(b: bytes) -> str: |
| return base64.b64encode(b).decode("ascii") |
|
|
|
|
| def b64d(s: str) -> bytes: |
| return base64.b64decode(s.encode("ascii")) |
|
|
| |
| |
| |
|
|
| GF_POLY = 0x11D |
| GF_EXP = [0] * 512 |
| GF_LOG = [0] * 256 |
|
|
| def _gf_init() -> None: |
| x = 1 |
| for i in range(255): |
| GF_EXP[i] = x |
| GF_LOG[x] = i |
| x <<= 1 |
| if x & 0x100: |
| x ^= GF_POLY |
| for i in range(255, 512): |
| GF_EXP[i] = GF_EXP[i - 255] |
|
|
| _gf_init() |
|
|
|
|
| def gf_mul(a: int, b: int) -> int: |
| if a == 0 or b == 0: |
| return 0 |
| return GF_EXP[GF_LOG[a] + GF_LOG[b]] |
|
|
|
|
| def gf_inv(a: int) -> int: |
| if a == 0: |
| raise HVCEError("zero has no GF inverse") |
| return GF_EXP[255 - GF_LOG[a]] |
|
|
|
|
| def gf_div(a: int, b: int) -> int: |
| if a == 0: |
| return 0 |
| if b == 0: |
| raise HVCEError("GF division by zero") |
| return GF_EXP[(GF_LOG[a] - GF_LOG[b]) % 255] |
|
|
| |
| |
| |
|
|
| def _rotl32(x: int, n: int) -> int: |
| return ((x << n) & 0xffffffff) | (x >> (32 - n)) |
|
|
|
|
| def _quarterround(st: List[int], a: int, b: int, c: int, d: int) -> None: |
| st[a] = (st[a] + st[b]) & 0xffffffff; st[d] ^= st[a]; st[d] = _rotl32(st[d], 16) |
| st[c] = (st[c] + st[d]) & 0xffffffff; st[b] ^= st[c]; st[b] = _rotl32(st[b], 12) |
| st[a] = (st[a] + st[b]) & 0xffffffff; st[d] ^= st[a]; st[d] = _rotl32(st[d], 8) |
| st[c] = (st[c] + st[d]) & 0xffffffff; st[b] ^= st[c]; st[b] = _rotl32(st[b], 7) |
|
|
|
|
| def chacha20_block(key: bytes, counter: int, nonce: bytes) -> bytes: |
| if len(key) != 32 or len(nonce) != 12: |
| raise HVCEError("ChaCha20 key/nonce length error") |
| constants = b"expand 32-byte k" |
| st = list(struct.unpack("<4I", constants) + struct.unpack("<8I", key) + (counter & 0xffffffff,) + struct.unpack("<3I", nonce)) |
| work = st[:] |
| for _ in range(10): |
| _quarterround(work, 0, 4, 8, 12) |
| _quarterround(work, 1, 5, 9, 13) |
| _quarterround(work, 2, 6, 10, 14) |
| _quarterround(work, 3, 7, 11, 15) |
| _quarterround(work, 0, 5, 10, 15) |
| _quarterround(work, 1, 6, 11, 12) |
| _quarterround(work, 2, 7, 8, 13) |
| _quarterround(work, 3, 4, 9, 14) |
| out = [(work[i] + st[i]) & 0xffffffff for i in range(16)] |
| return struct.pack("<16I", *out) |
|
|
|
|
| def chacha20_xor(data: bytes, key: bytes, nonce: bytes, counter: int = 1) -> bytes: |
| out = bytearray(len(data)) |
| for off in range(0, len(data), 64): |
| block = chacha20_block(key, counter, nonce) |
| counter = (counter + 1) & 0xffffffff |
| chunk = data[off:off+64] |
| for i, b in enumerate(chunk): |
| out[off+i] = b ^ block[i] |
| return bytes(out) |
|
|
|
|
| def derive_keys(password: str, salt: bytes, iterations: int) -> Tuple[bytes, bytes]: |
| if not password: |
| raise HVCEError("empty password not allowed") |
| keymat = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"), salt, iterations, dklen=64) |
| return keymat[:32], keymat[32:] |
|
|
| |
| |
| |
|
|
| def t_delta8(data: bytes) -> bytes: |
| if not data: |
| return b"" |
| out = bytearray(len(data)) |
| prev = 0 |
| for i, b in enumerate(data): |
| out[i] = (b - prev) & 0xff |
| prev = b |
| return bytes(out) |
|
|
|
|
| def inv_delta8(data: bytes, n: int) -> bytes: |
| if len(data) != n: |
| raise HVCEError("delta8 length mismatch") |
| out = bytearray(n) |
| prev = 0 |
| for i, b in enumerate(data): |
| v = (b + prev) & 0xff |
| out[i] = v |
| prev = v |
| return bytes(out) |
|
|
|
|
| def _word_delta(data: bytes, width: int) -> bytes: |
| if len(data) < width: |
| return data |
| mod = 1 << (8 * width) |
| out = bytearray() |
| prev = 0 |
| m = len(data) - (len(data) % width) |
| for off in range(0, m, width): |
| v = int.from_bytes(data[off:off+width], "little") |
| d = (v - prev) % mod |
| out.extend(d.to_bytes(width, "little")) |
| prev = v |
| out.extend(data[m:]) |
| return bytes(out) |
|
|
|
|
| def _word_undelta(data: bytes, n: int, width: int) -> bytes: |
| if len(data) != n: |
| raise HVCEError("word delta length mismatch") |
| mod = 1 << (8 * width) |
| out = bytearray() |
| prev = 0 |
| m = n - (n % width) |
| for off in range(0, m, width): |
| d = int.from_bytes(data[off:off+width], "little") |
| v = (d + prev) % mod |
| out.extend(v.to_bytes(width, "little")) |
| prev = v |
| out.extend(data[m:]) |
| return bytes(out) |
|
|
|
|
| def t_bitplane(data: bytes) -> bytes: |
| n = len(data) |
| groups = (n + 7) // 8 |
| out = bytearray(groups * 8) |
| pos = 0 |
| for bit in range(8): |
| for g in range(groups): |
| v = 0 |
| base = g * 8 |
| for j in range(8): |
| idx = base + j |
| if idx < n and ((data[idx] >> bit) & 1): |
| v |= 1 << j |
| out[pos] = v |
| pos += 1 |
| return bytes(out) |
|
|
|
|
| def inv_bitplane(data: bytes, n: int) -> bytes: |
| groups = (n + 7) // 8 |
| if len(data) != groups * 8: |
| raise HVCEError("bitplane length mismatch") |
| out = bytearray(n) |
| pos = 0 |
| for bit in range(8): |
| for g in range(groups): |
| v = data[pos] |
| pos += 1 |
| base = g * 8 |
| for j in range(8): |
| idx = base + j |
| if idx < n and ((v >> j) & 1): |
| out[idx] |= 1 << bit |
| return bytes(out) |
|
|
|
|
| def t_nibbleplane(data: bytes) -> bytes: |
| n = len(data) |
| pairs = (n + 1) // 2 |
| low = bytearray(pairs) |
| high = bytearray(pairs) |
| for i, b in enumerate(data): |
| if i & 1: |
| low[i//2] |= (b & 0x0f) << 4 |
| high[i//2] |= (b >> 4) << 4 |
| else: |
| low[i//2] |= (b & 0x0f) |
| high[i//2] |= (b >> 4) |
| return bytes(low + high) |
|
|
|
|
| def inv_nibbleplane(data: bytes, n: int) -> bytes: |
| pairs = (n + 1) // 2 |
| if len(data) != pairs * 2: |
| raise HVCEError("nibbleplane length mismatch") |
| low = data[:pairs] |
| high = data[pairs:] |
| out = bytearray(n) |
| for i in range(n): |
| if i & 1: |
| lo = (low[i//2] >> 4) & 0x0f |
| hi = (high[i//2] >> 4) & 0x0f |
| else: |
| lo = low[i//2] & 0x0f |
| hi = high[i//2] & 0x0f |
| out[i] = lo | (hi << 4) |
| return bytes(out) |
|
|
|
|
| def t_neural4(data: bytes) -> bytes: |
| """Deterministic causal 4-tap integer predictor residual transform.""" |
| weights = [1, 1, 1, 1] |
| hist = [0, 0, 0, 0] |
| out = bytearray(len(data)) |
| for i, b in enumerate(data): |
| pred = (weights[0]*hist[0] + weights[1]*hist[1] + weights[2]*hist[2] + weights[3]*hist[3]) // max(1, sum(abs(w) for w in weights)) |
| pred &= 0xff |
| r = (b - pred) & 0xff |
| out[i] = r |
| err = r if r < 128 else r - 256 |
| |
| for k in range(4): |
| if hist[k] >= pred and err > 0: |
| weights[k] = min(8, weights[k] + 1) |
| elif hist[k] <= pred and err < 0: |
| weights[k] = max(-8, weights[k] - 1) |
| hist = [b] + hist[:3] |
| return bytes(out) |
|
|
|
|
| def inv_neural4(data: bytes, n: int) -> bytes: |
| if len(data) != n: |
| raise HVCEError("neural4 length mismatch") |
| weights = [1, 1, 1, 1] |
| hist = [0, 0, 0, 0] |
| out = bytearray(n) |
| for i, r in enumerate(data): |
| pred = (weights[0]*hist[0] + weights[1]*hist[1] + weights[2]*hist[2] + weights[3]*hist[3]) // max(1, sum(abs(w) for w in weights)) |
| pred &= 0xff |
| b = (r + pred) & 0xff |
| out[i] = b |
| err = r if r < 128 else r - 256 |
| for k in range(4): |
| if hist[k] >= pred and err > 0: |
| weights[k] = min(8, weights[k] + 1) |
| elif hist[k] <= pred and err < 0: |
| weights[k] = max(-8, weights[k] - 1) |
| hist = [b] + hist[:3] |
| return bytes(out) |
|
|
| TRANSFORMS = { |
| "delta8": (t_delta8, inv_delta8), |
| "delta16le": (lambda b: _word_delta(b, 2), lambda b, n: _word_undelta(b, n, 2)), |
| "delta32le": (lambda b: _word_delta(b, 4), lambda b, n: _word_undelta(b, n, 4)), |
| "bitplane": (t_bitplane, inv_bitplane), |
| "nibbleplane": (t_nibbleplane, inv_nibbleplane), |
| "neural4": (t_neural4, inv_neural4), |
| } |
|
|
| |
| |
| |
|
|
| @dataclass |
| class Candidate: |
| method: str |
| payload: bytes |
| params: Dict[str, object] |
|
|
|
|
| def codec_encode(codec: str, data: bytes, profile: str) -> bytes: |
| if codec == "raw": |
| return data |
| if codec == "zlib1": |
| return zlib.compress(data, 1) |
| if codec == "zlib6": |
| return zlib.compress(data, 6) |
| if codec == "zlib9": |
| return zlib.compress(data, 9) |
| if codec == "bz2": |
| return bz2.compress(data, compresslevel=9) |
| if codec == "lzma0": |
| return lzma.compress(data, preset=0) |
| if codec == "lzma6": |
| return lzma.compress(data, preset=6) |
| if codec == "lzma9": |
| return lzma.compress(data, preset=9 | lzma.PRESET_EXTREME) |
| raise HVCEError(f"unknown codec {codec}") |
|
|
|
|
| def codec_decode(codec: str, data: bytes) -> bytes: |
| if codec == "raw": |
| return data |
| if codec.startswith("zlib"): |
| return zlib.decompress(data) |
| if codec == "bz2": |
| return bz2.decompress(data) |
| if codec.startswith("lzma"): |
| return lzma.decompress(data) |
| raise HVCEError(f"unknown codec {codec}") |
|
|
|
|
| def encode_recipe_constant(data: bytes) -> Optional[Candidate]: |
| if len(data) >= 8 and data.count(data[:1]) == len(data): |
| return Candidate("recipe_constant", data[:1], {}) |
| return None |
|
|
|
|
| def encode_recipe_periodic(data: bytes, max_period: int = 1024) -> Optional[Candidate]: |
| n = len(data) |
| if n < 32: |
| return None |
| limit = min(max_period, n // 2) |
| for p in range(1, limit + 1): |
| pat = data[:p] |
| if pat * (n // p) + pat[: n % p] == data: |
| out = bytearray() |
| put_varint(p, out) |
| out.extend(pat) |
| return Candidate("recipe_periodic", bytes(out), {}) |
| return None |
|
|
|
|
| def encode_recipe_sparse(data: bytes) -> Optional[Candidate]: |
| n = len(data) |
| if n < 64: |
| return None |
| counts = collections.Counter(data) |
| dominant, dom_count = counts.most_common(1)[0] |
| if dom_count / n < 0.90: |
| return None |
| out = bytearray([dominant]) |
| put_varint(n - dom_count, out) |
| last = 0 |
| first = True |
| for i, b in enumerate(data): |
| if b != dominant: |
| if first: |
| put_varint(i, out) |
| first = False |
| else: |
| put_varint(i - last, out) |
| out.append(b) |
| last = i |
| packed = zlib.compress(bytes(out), 9) |
| if len(packed) + 16 < n: |
| return Candidate("recipe_sparse_zlib", packed, {}) |
| return None |
|
|
|
|
| def decode_recipe_sparse(payload: bytes, n: int) -> bytes: |
| raw = zlib.decompress(payload) |
| if not raw: |
| raise HVCEError("bad sparse recipe") |
| dom = raw[0] |
| pos = 1 |
| count, pos = get_varint(raw, pos) |
| out = bytearray([dom]) * n |
| idx = 0 |
| for k in range(count): |
| delta, pos = get_varint(raw, pos) |
| idx = delta if k == 0 else idx + delta |
| if idx >= n or pos >= len(raw): |
| raise HVCEError("bad sparse recipe bounds") |
| out[idx] = raw[pos] |
| pos += 1 |
| return bytes(out) |
|
|
|
|
| def encode_recipe_rle(data: bytes) -> Optional[Candidate]: |
| n = len(data) |
| if n < 64: |
| return None |
| out = bytearray() |
| i = 0 |
| runs = 0 |
| while i < n: |
| b = data[i] |
| j = i + 1 |
| while j < n and data[j] == b: |
| j += 1 |
| put_varint(j - i, out) |
| out.append(b) |
| runs += 1 |
| i = j |
| packed = zlib.compress(bytes(out), 9) |
| if len(packed) + 16 < n: |
| return Candidate("recipe_rle_zlib", packed, {}) |
| return None |
|
|
|
|
| def decode_recipe_rle(payload: bytes, n: int) -> bytes: |
| raw = zlib.decompress(payload) |
| out = bytearray() |
| pos = 0 |
| while pos < len(raw): |
| count, pos = get_varint(raw, pos) |
| if pos >= len(raw): |
| raise HVCEError("bad rle recipe") |
| out.extend(bytes([raw[pos]]) * count) |
| pos += 1 |
| if len(out) > n: |
| raise HVCEError("rle expands beyond target") |
| if len(out) != n: |
| raise HVCEError("rle length mismatch") |
| return bytes(out) |
|
|
|
|
| def _seq_words(data: bytes, width: int) -> Optional[List[int]]: |
| if len(data) < width * 8 or len(data) % width: |
| return None |
| return [int.from_bytes(data[i:i+width], "little") for i in range(0, len(data), width)] |
|
|
|
|
| def encode_recipe_polyword(data: bytes) -> Optional[Candidate]: |
| |
| for width in (1, 2, 4, 8): |
| seq = _seq_words(data, width) |
| if not seq or len(seq) < 8: |
| continue |
| mod = 1 << (8 * width) |
| diffs = [seq] |
| for _ in range(3): |
| prev = diffs[-1] |
| diffs.append([(prev[i+1] - prev[i]) % mod for i in range(len(prev)-1)]) |
| for deg in range(0, 4): |
| arr = diffs[deg] |
| if arr and all(x == arr[0] for x in arr): |
| |
| start = [diffs[k][0] for k in range(deg + 1)] |
| out = bytearray() |
| out.append(width) |
| out.append(deg) |
| put_varint(len(seq), out) |
| for v in start: |
| out.extend(v.to_bytes(width, "little")) |
| return Candidate("recipe_polyword", bytes(out), {}) |
| if deg > 0: |
| |
| hi = diffs[deg] |
| if hi and all(x == hi[0] for x in hi): |
| start = [diffs[k][0] for k in range(deg + 1)] |
| out = bytearray() |
| out.append(width) |
| out.append(deg) |
| put_varint(len(seq), out) |
| for v in start: |
| out.extend(v.to_bytes(width, "little")) |
| return Candidate("recipe_polyword", bytes(out), {}) |
| return None |
|
|
|
|
| def decode_recipe_polyword(payload: bytes, n: int) -> bytes: |
| if len(payload) < 3: |
| raise HVCEError("bad polyword payload") |
| width = payload[0] |
| deg = payload[1] |
| if width not in (1, 2, 4, 8) or deg > 3: |
| raise HVCEError("bad polyword parameters") |
| count, pos = get_varint(payload, 2) |
| if count * width != n: |
| raise HVCEError("polyword length mismatch") |
| vals = [] |
| for _ in range(deg + 1): |
| if pos + width > len(payload): |
| raise HVCEError("truncated polyword starts") |
| vals.append(int.from_bytes(payload[pos:pos+width], "little")) |
| pos += width |
| mod = 1 << (8 * width) |
| out = bytearray() |
| state = vals[:] |
| for _ in range(count): |
| out.extend(state[0].to_bytes(width, "little")) |
| for k in range(deg): |
| state[k] = (state[k] + state[k+1]) % mod |
| return bytes(out) |
|
|
|
|
| def encode_recipe_rank1_2d8(data: bytes) -> Optional[Candidate]: |
| n = len(data) |
| if n < 4096: |
| return None |
| candidates = [64, 96, 128, 160, 192, 256, 320, 384, 512, 768, 1024] |
| best: Optional[Candidate] = None |
| for w in candidates: |
| if n % w: |
| continue |
| h = n // w |
| if h < 8: |
| continue |
| base = data[0] |
| row = bytearray(h) |
| col = bytearray(w) |
| for y in range(h): |
| row[y] = (data[y*w] - base) & 0xff |
| for x in range(w): |
| col[x] = data[x] |
| defects = bytearray() |
| count = 0 |
| last = 0 |
| first = True |
| for y in range(h): |
| ry = row[y] |
| off = y * w |
| for x in range(w): |
| pred = (ry + col[x]) & 0xff |
| b = data[off + x] |
| if b != pred: |
| idx = off + x |
| put_varint(idx if first else idx - last, defects) |
| defects.append(b) |
| first = False |
| last = idx |
| count += 1 |
| if count > n // 20: |
| break |
| if count > n // 20: |
| break |
| if count <= n // 20: |
| out = bytearray() |
| put_varint(w, out); put_varint(h, out); put_varint(count, out) |
| out.extend(row); out.extend(col); out.extend(defects) |
| packed = zlib.compress(bytes(out), 9) |
| cand = Candidate("recipe_rank1_2d8_zlib", packed, {}) |
| if best is None or len(cand.payload) < len(best.payload): |
| best = cand |
| if best and len(best.payload) + 16 < n: |
| return best |
| return None |
|
|
|
|
| def decode_recipe_rank1_2d8(payload: bytes, n: int) -> bytes: |
| raw = zlib.decompress(payload) |
| w, pos = get_varint(raw, 0) |
| h, pos = get_varint(raw, pos) |
| count, pos = get_varint(raw, pos) |
| if w * h != n or pos + h + w > len(raw): |
| raise HVCEError("bad rank1 recipe shape") |
| row = raw[pos:pos+h]; pos += h |
| col = raw[pos:pos+w]; pos += w |
| out = bytearray(n) |
| for y in range(h): |
| ry = row[y] |
| off = y*w |
| for x in range(w): |
| out[off+x] = (ry + col[x]) & 0xff |
| idx = 0 |
| for k in range(count): |
| delta, pos = get_varint(raw, pos) |
| idx = delta if k == 0 else idx + delta |
| if idx >= n or pos >= len(raw): |
| raise HVCEError("bad rank1 defects") |
| out[idx] = raw[pos] |
| pos += 1 |
| return bytes(out) |
|
|
|
|
| def encode_ref_xor_sparse(data: bytes, ref_id: int, ref_data: bytes) -> Optional[Candidate]: |
| if len(data) != len(ref_data) or len(data) < 4096: |
| return None |
| n = len(data) |
| out = bytearray() |
| count = 0 |
| last = 0 |
| first = True |
| limit = max(256, n // 32) |
| for i, (a, b) in enumerate(zip(data, ref_data)): |
| x = a ^ b |
| if x: |
| put_varint(i if first else i - last, out) |
| out.append(x) |
| first = False |
| last = i |
| count += 1 |
| if count > limit: |
| return None |
| if count == 0: |
| return None |
| raw = bytearray() |
| put_varint(count, raw) |
| raw.extend(out) |
| packed = zlib.compress(bytes(raw), 9) |
| if len(packed) + 24 < n: |
| return Candidate("ref_xor_sparse_zlib", packed, {"ref": ref_id}) |
| return None |
|
|
|
|
| def apply_ref_xor_sparse(payload: bytes, ref_data: bytes, n: int) -> bytes: |
| raw = zlib.decompress(payload) |
| count, pos = get_varint(raw, 0) |
| if len(ref_data) != n: |
| raise HVCEError("reference length mismatch") |
| out = bytearray(ref_data) |
| idx = 0 |
| for k in range(count): |
| delta, pos = get_varint(raw, pos) |
| idx = delta if k == 0 else idx + delta |
| if idx >= n or pos >= len(raw): |
| raise HVCEError("bad ref patch") |
| out[idx] ^= raw[pos] |
| pos += 1 |
| return bytes(out) |
|
|
|
|
| def decode_candidate(method: str, payload: bytes, orig_len: int, params: Dict[str, object], ref_lookup=None) -> bytes: |
| if method == "recipe_constant": |
| if len(payload) != 1: |
| raise HVCEError("bad constant recipe") |
| return payload * orig_len |
| if method == "recipe_periodic": |
| p, pos = get_varint(payload, 0) |
| pat = payload[pos:] |
| if len(pat) != p: |
| raise HVCEError("bad periodic recipe") |
| return pat * (orig_len // p) + pat[: orig_len % p] |
| if method == "recipe_sparse_zlib": |
| return decode_recipe_sparse(payload, orig_len) |
| if method == "recipe_rle_zlib": |
| return decode_recipe_rle(payload, orig_len) |
| if method == "recipe_polyword": |
| return decode_recipe_polyword(payload, orig_len) |
| if method == "recipe_rank1_2d8_zlib": |
| return decode_recipe_rank1_2d8(payload, orig_len) |
| if method == "ref_xor_sparse_zlib": |
| if ref_lookup is None or "ref" not in params: |
| raise HVCEError("missing reference lookup") |
| ref = ref_lookup(int(params["ref"])) |
| return apply_ref_xor_sparse(payload, ref, orig_len) |
| parts = method.split("+") |
| codec = parts[-1] |
| transforms = parts[:-1] |
| data = codec_decode(codec, payload) |
| for t in reversed(transforms): |
| if t not in TRANSFORMS: |
| raise HVCEError(f"unknown transform {t}") |
| data = TRANSFORMS[t][1](data, orig_len) |
| if len(data) != orig_len: |
| raise HVCEError("decoded length mismatch") |
| return data |
|
|
|
|
| def choose_representation(data: bytes, profile: str = "balanced", media_class: str = "generic", ref_candidates: Sequence[Tuple[int, bytes]] = ()) -> Candidate: |
| n = len(data) |
| best = Candidate("raw", data, {}) |
| hi = looks_incompressible(data) |
|
|
| def consider(c: Optional[Candidate]) -> None: |
| nonlocal best |
| if c is None: |
| return |
| |
| if len(c.payload) + len(c.method) + len(json.dumps(c.params)) < len(best.payload) + len(best.method) + len(json.dumps(best.params)): |
| best = c |
|
|
| |
| |
| if not hi: |
| consider(encode_recipe_constant(data)) |
| consider(encode_recipe_periodic(data)) |
| consider(encode_recipe_sparse(data)) |
| consider(encode_recipe_rle(data)) |
| consider(encode_recipe_polyword(data)) |
| if profile in {"balanced", "max"}: |
| consider(encode_recipe_rank1_2d8(data)) |
|
|
| |
| |
| |
| for ref_id, ref_data in ref_candidates[:48 if profile == "max" else 16]: |
| consider(encode_ref_xor_sparse(data, ref_id, ref_data)) |
|
|
| |
| compressed_family = media_class not in {"generic"} |
| if profile == "fast": |
| codecs = ["zlib1"] if not hi else [] |
| transforms = ["delta8", "bitplane"] if not hi and n >= 64 else [] |
| elif profile == "balanced": |
| codecs = ["zlib1", "zlib6", "bz2", "lzma6"] if not (hi or compressed_family) else ["zlib1"] |
| transforms = ["delta8", "delta16le", "delta32le", "bitplane", "nibbleplane", "neural4"] if not hi and n >= 64 else [] |
| else: |
| codecs = ["zlib1", "zlib6", "zlib9", "bz2", "lzma6", "lzma9"] if not hi else ["zlib1", "zlib6"] |
| transforms = ["delta8", "delta16le", "delta32le", "bitplane", "nibbleplane", "neural4"] if n >= 64 else [] |
|
|
| for codec in codecs: |
| try: |
| consider(Candidate(codec, codec_encode(codec, data, profile), {})) |
| except Exception: |
| pass |
| for t in transforms: |
| try: |
| transformed = TRANSFORMS[t][0](data) |
| |
| t_codecs = ["zlib1", "zlib6"] if profile != "max" else ["zlib1", "zlib6", "zlib9", "bz2", "lzma6"] |
| for codec in t_codecs: |
| consider(Candidate(f"{t}+{codec}", codec_encode(codec, transformed, profile), {})) |
| except Exception: |
| pass |
|
|
| |
| if best.method != "raw" and len(best.payload) >= n: |
| best = Candidate("raw", data, {}) |
| return best |
|
|
| |
| |
| |
|
|
| def _gear_table() -> List[int]: |
| x = 0x9E3779B97F4A7C15 |
| out = [] |
| for _ in range(256): |
| x = (x + 0x9E3779B97F4A7C15) & ((1 << 64) - 1) |
| z = x |
| z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9 & ((1 << 64) - 1) |
| z = (z ^ (z >> 27)) * 0x94D049BB133111EB & ((1 << 64) - 1) |
| z = z ^ (z >> 31) |
| out.append(z) |
| return out |
|
|
| GEAR = _gear_table() |
|
|
|
|
| def chunk_bytes(data: bytes, chunk_size: int = DEFAULT_CHUNK_SIZE, use_cdc: bool = True) -> Iterator[bytes]: |
| n = len(data) |
| if n <= chunk_size or not use_cdc: |
| for i in range(0, n, chunk_size): |
| yield data[i:i+chunk_size] |
| return |
| min_size = max(16 * 1024, chunk_size // 8) |
| avg = max(32 * 1024, chunk_size // 2) |
| max_size = chunk_size |
| mask = avg - 1 |
| start = 0 |
| h = 0 |
| for i, b in enumerate(data): |
| h = ((h << 1) + GEAR[b]) & ((1 << 64) - 1) |
| span = i + 1 - start |
| if span >= min_size and ((h & mask) == 0 or span >= max_size): |
| yield data[start:i+1] |
| start = i + 1 |
| h = 0 |
| if start < n: |
| yield data[start:] |
|
|
|
|
| def file_meta(path: Path) -> Dict[str, object]: |
| st = path.lstat() |
| return { |
| "mode": stat.S_IMODE(st.st_mode), |
| "mtime_ns": getattr(st, "st_mtime_ns", int(st.st_mtime * 1_000_000_000)), |
| "atime_ns": getattr(st, "st_atime_ns", int(st.st_atime * 1_000_000_000)), |
| "size": st.st_size, |
| } |
|
|
|
|
| def restore_meta(path: Path, meta: Dict[str, object], is_dir: bool = False) -> None: |
| try: |
| os.chmod(path, int(meta.get("mode", 0o755 if is_dir else 0o644))) |
| except Exception: |
| pass |
| try: |
| at = int(meta.get("atime_ns", meta.get("mtime_ns", time.time_ns()))) |
| mt = int(meta.get("mtime_ns", time.time_ns())) |
| os.utime(path, ns=(at, mt), follow_symlinks=False) |
| except Exception: |
| pass |
|
|
| |
| |
| |
|
|
| class Builder: |
| def __init__(self, profile: str, chunk_size: int, use_cdc: bool, small_threshold: int): |
| self.profile = profile |
| self.chunk_size = chunk_size |
| self.use_cdc = use_cdc |
| self.small_threshold = small_threshold |
| self.payload = bytearray() |
| self.chunks: List[Dict[str, object]] = [] |
| self.microgroups: List[Dict[str, object]] = [] |
| self.entries: List[Dict[str, object]] = [] |
| self.sha_to_chunk: Dict[str, int] = {} |
| self.ref_cache_by_len: Dict[int, List[Tuple[int, bytes]]] = collections.defaultdict(list) |
| self.raw_cache: Dict[int, bytes] = {} |
|
|
| def add_payload(self, data: bytes) -> Tuple[int, int]: |
| off = len(self.payload) |
| self.payload.extend(data) |
| return off, len(data) |
|
|
| def encode_chunk(self, data: bytes, media_class: str = "generic") -> int: |
| sha = sha256_bytes(data) |
| if sha in self.sha_to_chunk: |
| return self.sha_to_chunk[sha] |
| refs = self.ref_cache_by_len.get(len(data), []) |
| cand = choose_representation(data, self.profile, media_class, refs) |
| off, dlen = self.add_payload(cand.payload) |
| cid = len(self.chunks) |
| rec = { |
| "id": cid, |
| "orig_len": len(data), |
| "sha256": sha, |
| "method": cand.method, |
| "params": cand.params, |
| "off": off, |
| "len": dlen, |
| "media_class": media_class, |
| } |
| self.chunks.append(rec) |
| self.sha_to_chunk[sha] = cid |
| |
| self.raw_cache[cid] = data |
| bucket = self.ref_cache_by_len[len(data)] |
| bucket.insert(0, (cid, data)) |
| del bucket[64:] |
| return cid |
|
|
| def encode_microgroup(self, members: List[Tuple[int, bytes]], media_class: str) -> int: |
| blob = bytearray() |
| for entry_idx, data in members: |
| off = len(blob) |
| self.entries[entry_idx]["source"] = "micro" |
| self.entries[entry_idx]["micro_offset"] = off |
| self.entries[entry_idx]["micro_len"] = len(data) |
| blob.extend(data) |
| raw = bytes(blob) |
| cand = choose_representation(raw, self.profile, media_class, []) |
| poff, plen = self.add_payload(cand.payload) |
| gid = len(self.microgroups) |
| group = { |
| "id": gid, |
| "orig_len": len(raw), |
| "sha256": sha256_bytes(raw), |
| "method": cand.method, |
| "params": cand.params, |
| "off": poff, |
| "len": plen, |
| "members": [idx for idx, _ in members], |
| "media_class": media_class, |
| } |
| self.microgroups.append(group) |
| for idx, _ in members: |
| self.entries[idx]["microgroup"] = gid |
| |
| |
| self.entries[idx].pop("sha256", None) |
| return gid |
|
|
|
|
| def collect_inputs(input_path: Path) -> Tuple[Path, List[Path]]: |
| input_path = input_path.resolve() |
| if not input_path.exists() and not input_path.is_symlink(): |
| raise HVCEError(f"input does not exist: {input_path}") |
| if input_path.is_file() or input_path.is_symlink(): |
| root = input_path.parent |
| return root, [input_path] |
| root = input_path |
| paths: List[Path] = [] |
| for dirpath, dirnames, filenames in os.walk(root): |
| d = Path(dirpath) |
| paths.append(d) |
| |
| for name in list(dirnames): |
| p = d / name |
| if p.is_symlink(): |
| paths.append(p) |
| dirnames.remove(name) |
| for name in filenames: |
| paths.append(d / name) |
| return root, sorted(paths, key=lambda p: str(p)) |
|
|
|
|
| def compression_kind(path: str, data: bytes) -> str: |
| return file_magic_class(data, Path(path).suffix) |
|
|
|
|
| def build_manifest(input_path: Path, profile: str, chunk_size: int, use_cdc: bool, small_threshold: int) -> Tuple[Dict[str, object], bytes]: |
| root, paths = collect_inputs(input_path) |
| b = Builder(profile, chunk_size, use_cdc, small_threshold) |
| small_groups: Dict[str, List[Tuple[int, bytes]]] = collections.defaultdict(list) |
|
|
| for p in paths: |
| rel = safe_posix_path(root, p) |
| if rel == ".": |
| rel = p.name |
| if p.is_symlink(): |
| target = os.readlink(p) |
| ent = {"path": rel, "type": "symlink", "target": target, "meta": file_meta(p)} |
| b.entries.append(ent) |
| elif p.is_dir(): |
| ent = {"path": rel, "type": "dir", "meta": file_meta(p)} |
| b.entries.append(ent) |
| elif p.is_file(): |
| data = p.read_bytes() |
| kind = compression_kind(rel, data[:4096]) |
| ent = {"path": rel, "type": "file", "size": len(data), "sha256": sha256_bytes(data), "meta": file_meta(p), "media_class": kind} |
| idx = len(b.entries) |
| b.entries.append(ent) |
| if len(data) == 0: |
| ent["source"] = "empty" |
| elif len(data) <= small_threshold: |
| |
| ext = Path(rel).suffix.lower() or "_noext" |
| ent_level = "hi" if looks_incompressible(data) else "lo" |
| |
| |
| |
| |
| if ent_level == "lo" and kind == "generic": |
| key = "solid-office-low" |
| elif ent_level == "lo" and ext in {".xml", ".json", ".txt", ".md", ".csv", ".html", ".css", ".js", ".py", ".log"}: |
| key = "solid-text-low" |
| else: |
| key = f"{kind}:{ext}:{ent_level}" |
| small_groups[key].append((idx, data)) |
| else: |
| ent["source"] = "chunks" |
| cids = [] |
| for ch in chunk_bytes(data, chunk_size, use_cdc): |
| cids.append(b.encode_chunk(ch, kind)) |
| ent["chunks"] = cids |
| else: |
| |
| b.entries.append({"path": rel, "type": "special", "meta": file_meta(p)}) |
|
|
| |
| for key, members in small_groups.items(): |
| if not members: |
| continue |
| kind = key.split(":", 1)[0] |
| b.encode_microgroup(members, kind) |
|
|
| manifest = { |
| "format": "HVCE4", |
| "version": VERSION, |
| "author": AUTHOR, |
| "created_unix": time.time(), |
| "input_name": input_path.name, |
| "profile": profile, |
| "chunk_size": chunk_size, |
| "use_cdc": use_cdc, |
| "small_threshold": small_threshold, |
| "entries": b.entries, |
| "chunks": b.chunks, |
| "microgroups": b.microgroups, |
| "payload_len": len(b.payload), |
| "payload_sha256": sha256_bytes(bytes(b.payload)), |
| "stats": summarize_manifest(b.entries, b.chunks, b.microgroups, len(b.payload)), |
| } |
| return manifest, bytes(b.payload) |
|
|
|
|
| def summarize_manifest(entries, chunks, microgroups, payload_len: int) -> Dict[str, object]: |
| raw_size = sum(int(e.get("size", 0)) for e in entries if e.get("type") == "file") |
| files = sum(1 for e in entries if e.get("type") == "file") |
| dirs = sum(1 for e in entries if e.get("type") == "dir") |
| methods = collections.Counter([c["method"] for c in chunks] + [g["method"] for g in microgroups]) |
| media = collections.Counter(e.get("media_class", "none") for e in entries if e.get("type") == "file") |
| return { |
| "files": files, |
| "dirs": dirs, |
| "raw_size": raw_size, |
| "payload_len": payload_len, |
| "methods": dict(methods), |
| "media_classes": dict(media), |
| } |
|
|
|
|
| def pack_json_header(manifest: Dict[str, object]) -> Tuple[bytes, bytes]: |
| raw = json.dumps(manifest, sort_keys=True, separators=(",", ":")).encode("utf-8") |
| z = zlib.compress(raw, 9) |
| l = lzma.compress(raw, preset=9 | lzma.PRESET_EXTREME) |
| return (b"L", l) if len(l) < len(z) else (b"Z", z) |
|
|
|
|
| def unpack_json_header(codec: bytes, blob: bytes) -> Dict[str, object]: |
| if codec == b"Z": |
| raw = zlib.decompress(blob) |
| elif codec == b"L": |
| raw = lzma.decompress(blob) |
| else: |
| raise HVCEError(f"unknown header codec {codec!r}") |
| return json.loads(raw.decode("utf-8")) |
|
|
|
|
| def make_plain_container(manifest: Dict[str, object], payload: bytes) -> bytes: |
| codec, h = pack_json_header(manifest) |
| if len(h) > MAX_HEADER_BYTES: |
| raise HVCEError("header too large") |
| return MAGIC + b"\x00" + codec + write_u64(len(h)) + h + payload |
|
|
|
|
| def make_encrypted_container(manifest: Dict[str, object], payload: bytes, password: str, kdf_iterations: int) -> bytes: |
| codec, h = pack_json_header(manifest) |
| inner = codec + write_u64(len(h)) + h + payload |
| salt = os.urandom(16) |
| nonce = os.urandom(12) |
| key_enc, key_mac = derive_keys(password, salt, kdf_iterations) |
| ciphertext = chacha20_xor(inner, key_enc, nonce, counter=1) |
| params = { |
| "format": "HVCE4-encrypted", |
| "kdf": "PBKDF2-HMAC-SHA256", |
| "iterations": kdf_iterations, |
| "salt": b64e(salt), |
| "cipher": "ChaCha20-HMAC-SHA256", |
| "nonce": b64e(nonce), |
| "ciphertext_len": len(ciphertext), |
| "plaintext_sha256": sha256_bytes(inner), |
| "manifest_private": True, |
| } |
| p = zlib.compress(json.dumps(params, sort_keys=True, separators=(",", ":")).encode("utf-8"), 9) |
| prefix = MAGIC + b"\x01" + struct.pack("<I", len(p)) + p + ciphertext |
| tag = hmac.new(key_mac, prefix, hashlib.sha256).digest() |
| return prefix + tag |
|
|
|
|
| def parse_recovery_tail(blob: bytes) -> Tuple[bytes, Optional[Dict[str, object]], Optional[bytes]]: |
| if len(blob) < 32 or not blob.endswith(END_MAGIC): |
| return blob, None, None |
| rec_len = struct.unpack("<Q", blob[-16:-8])[0] |
| start = len(blob) - 16 - rec_len - 16 |
| if start < 0 or blob[start:start+8] != REC_MAGIC: |
| return blob, None, None |
| rec_len2 = struct.unpack("<Q", blob[start+8:start+16])[0] |
| if rec_len2 != rec_len: |
| return blob, None, None |
| rec_comp = blob[start+16:start+16+rec_len] |
| try: |
| rec = json.loads(zlib.decompress(rec_comp).decode("utf-8")) |
| except Exception as e: |
| raise HVCEError(f"recovery tail is present but unreadable: {e}") |
| return blob[:start], rec, blob[start:] |
|
|
|
|
| def append_recovery(pre: bytes, percent: int) -> bytes: |
| if percent <= 0: |
| return pre |
| percent = max(2, min(50, percent)) |
| |
| n_shards = max(4, int(math.ceil(200 / percent))) |
| shard_size = max(4096, int(math.ceil(len(pre) / n_shards))) |
| shards = [] |
| hashes = [] |
| for off in range(0, len(pre), shard_size): |
| sh = bytearray(pre[off:off+shard_size]) |
| if len(sh) < shard_size: |
| sh.extend(b"\x00" * (shard_size - len(sh))) |
| bsh = bytes(sh) |
| shards.append(bsh) |
| hashes.append(sha256_bytes(bsh)) |
| if not shards: |
| shards = [b"\x00" * shard_size] |
| hashes = [sha256_bytes(shards[0])] |
| p0 = bytearray(shard_size) |
| p1 = bytearray(shard_size) |
| for idx, sh in enumerate(shards): |
| coef = (idx + 1) % 255 or 255 |
| for j, v in enumerate(sh): |
| p0[j] ^= v |
| p1[j] ^= gf_mul(coef, v) |
| rec = { |
| "scheme": "HVCE4-xor2-gf256-recovery", |
| "data_len": len(pre), |
| "pre_sha256": sha256_bytes(pre), |
| "shard_size": shard_size, |
| "shard_count": len(shards), |
| "shard_sha256": hashes, |
| "parity0": b64e(bytes(p0)), |
| "parity1": b64e(bytes(p1)), |
| "overhead_target_percent": percent, |
| "note": "Repairs replacement corruption in up to two detected shards when recovery tail is intact.", |
| } |
| rec_comp = zlib.compress(json.dumps(rec, sort_keys=True, separators=(",", ":")).encode("utf-8"), 9) |
| return pre + REC_MAGIC + write_u64(len(rec_comp)) + rec_comp + write_u64(len(rec_comp)) + END_MAGIC |
|
|
|
|
| def read_archive(path: Path, password: Optional[str] = None) -> Tuple[Dict[str, object], bytes, Dict[str, object]]: |
| blob = path.read_bytes() |
| pre, rec, _tail = parse_recovery_tail(blob) |
| if not pre.startswith(MAGIC): |
| raise HVCEError("not an HVCE4 archive") |
| if len(pre) < 9: |
| raise HVCEError("truncated archive") |
| mode = pre[8] |
| if mode == 0: |
| if len(pre) > 10 and pre[9:10] in (b"Z", b"L"): |
| header_codec = pre[9:10] |
| hlen, pos = read_u64(pre, 10) |
| else: |
| header_codec = b"Z" |
| hlen, pos = read_u64(pre, 9) |
| if hlen > MAX_HEADER_BYTES: |
| raise HVCEError("header too large") |
| end = pos + hlen |
| if end > len(pre): |
| raise HVCEError("truncated header") |
| manifest = unpack_json_header(header_codec, pre[pos:end]) |
| payload_len = int(manifest.get("payload_len", 0)) |
| payload = pre[end:end+payload_len] |
| if len(payload) != payload_len: |
| raise HVCEError("truncated payload") |
| if sha256_bytes(payload) != manifest.get("payload_sha256"): |
| raise HVCEError("payload SHA-256 mismatch") |
| return manifest, payload, {"encrypted": False, "recovery": rec} |
| elif mode == 1: |
| if password is None: |
| raise HVCEError("archive is encrypted; provide --password or --ask-password") |
| if len(pre) < 13: |
| raise HVCEError("truncated encrypted header") |
| plen = struct.unpack("<I", pre[9:13])[0] |
| if 13 + plen > len(pre): |
| raise HVCEError("truncated encrypted params") |
| params = json.loads(zlib.decompress(pre[13:13+plen]).decode("utf-8")) |
| clen = int(params["ciphertext_len"]) |
| cstart = 13 + plen |
| cend = cstart + clen |
| tend = cend + 32 |
| if tend > len(pre): |
| raise HVCEError("truncated encrypted payload") |
| salt = b64d(params["salt"]); nonce = b64d(params["nonce"]) |
| key_enc, key_mac = derive_keys(password, salt, int(params["iterations"])) |
| prefix = pre[:cend] |
| tag = pre[cend:tend] |
| exp = hmac.new(key_mac, prefix, hashlib.sha256).digest() |
| if not hmac.compare_digest(tag, exp): |
| raise HVCEError("password/authentication failed") |
| inner = chacha20_xor(pre[cstart:cend], key_enc, nonce, counter=1) |
| if sha256_bytes(inner) != params.get("plaintext_sha256"): |
| raise HVCEError("encrypted plaintext SHA-256 mismatch") |
| if inner[:1] in (b"Z", b"L"): |
| header_codec = inner[:1] |
| hlen, pos = read_u64(inner, 1) |
| else: |
| header_codec = b"Z" |
| hlen, pos = read_u64(inner, 0) |
| end = pos + hlen |
| manifest = unpack_json_header(header_codec, inner[pos:end]) |
| payload = inner[end:] |
| if len(payload) != int(manifest.get("payload_len", 0)): |
| raise HVCEError("inner payload length mismatch") |
| if sha256_bytes(payload) != manifest.get("payload_sha256"): |
| raise HVCEError("inner payload SHA-256 mismatch") |
| return manifest, payload, {"encrypted": True, "outer_params": params, "recovery": rec} |
| else: |
| raise HVCEError("unknown HVCE4 mode") |
|
|
| |
| |
| |
|
|
| class Extractor: |
| def __init__(self, manifest: Dict[str, object], payload: bytes): |
| self.m = manifest |
| self.payload = payload |
| self.chunk_cache: Dict[int, bytes] = {} |
| self.micro_cache: Dict[int, bytes] = {} |
| self.chunks = {int(c["id"]): c for c in manifest.get("chunks", [])} |
| self.microgroups = {int(g["id"]): g for g in manifest.get("microgroups", [])} |
|
|
| def _payload_slice(self, off: int, ln: int) -> bytes: |
| if off < 0 or ln < 0 or off + ln > len(self.payload): |
| raise HVCEError("payload slice out of bounds") |
| return self.payload[off:off+ln] |
|
|
| def chunk(self, cid: int) -> bytes: |
| if cid in self.chunk_cache: |
| return self.chunk_cache[cid] |
| c = self.chunks[cid] |
| payload = self._payload_slice(int(c["off"]), int(c["len"])) |
| data = decode_candidate(str(c["method"]), payload, int(c["orig_len"]), dict(c.get("params", {})), self.chunk) |
| if sha256_bytes(data) != c.get("sha256"): |
| raise HVCEError(f"chunk {cid} SHA-256 mismatch") |
| self.chunk_cache[cid] = data |
| return data |
|
|
| def micro(self, gid: int) -> bytes: |
| if gid in self.micro_cache: |
| return self.micro_cache[gid] |
| g = self.microgroups[gid] |
| payload = self._payload_slice(int(g["off"]), int(g["len"])) |
| data = decode_candidate(str(g["method"]), payload, int(g["orig_len"]), dict(g.get("params", {})), self.chunk) |
| if sha256_bytes(data) != g.get("sha256"): |
| raise HVCEError(f"microgroup {gid} SHA-256 mismatch") |
| self.micro_cache[gid] = data |
| return data |
|
|
| def file_bytes(self, e: Dict[str, object]) -> bytes: |
| src = e.get("source") |
| if src == "empty": |
| return b"" |
| if src == "micro": |
| blob = self.micro(int(e["microgroup"])) |
| off = int(e["micro_offset"]); ln = int(e["micro_len"]) |
| data = blob[off:off+ln] |
| elif src == "chunks": |
| data = b"".join(self.chunk(int(cid)) for cid in e.get("chunks", [])) |
| else: |
| raise HVCEError(f"unknown file source for {e.get('path')}: {src}") |
| if len(data) != int(e.get("size", len(data))): |
| raise HVCEError(f"file length mismatch: {e.get('path')}") |
| if "sha256" in e and sha256_bytes(data) != e.get("sha256"): |
| raise HVCEError(f"file SHA-256 mismatch: {e.get('path')}") |
| return data |
|
|
|
|
| def extract_archive(archive: Path, out_dir: Path, password: Optional[str] = None, overwrite: bool = False, allow_symlinks: bool = False) -> None: |
| manifest, payload, _info = read_archive(archive, password) |
| ex = Extractor(manifest, payload) |
| out_dir.mkdir(parents=True, exist_ok=True) |
| dirs_to_touch: List[Tuple[Path, Dict[str, object]]] = [] |
| for e in manifest.get("entries", []): |
| path = safe_join(out_dir, str(e["path"])) |
| typ = e.get("type") |
| if typ == "dir": |
| path.mkdir(parents=True, exist_ok=True) |
| dirs_to_touch.append((path, dict(e.get("meta", {})))) |
| elif typ == "file": |
| if path.exists() and not overwrite: |
| raise HVCEError(f"output exists, use --overwrite: {path}") |
| ensure_parent(path) |
| path.write_bytes(ex.file_bytes(e)) |
| restore_meta(path, dict(e.get("meta", {})), is_dir=False) |
| elif typ == "symlink": |
| ensure_parent(path) |
| if path.exists() and overwrite: |
| if path.is_dir() and not path.is_symlink(): |
| shutil.rmtree(path) |
| else: |
| path.unlink() |
| if allow_symlinks: |
| os.symlink(str(e.get("target", "")), path) |
| else: |
| path.with_suffix(path.suffix + ".symlink.txt").write_text(str(e.get("target", "")), encoding="utf-8") |
| elif typ == "special": |
| |
| ensure_parent(path) |
| else: |
| raise HVCEError(f"unknown entry type {typ}") |
| for p, meta in reversed(dirs_to_touch): |
| restore_meta(p, meta, is_dir=True) |
|
|
| |
| |
| |
|
|
| def repair_archive(archive: Path, output: Path) -> Dict[str, object]: |
| blob = archive.read_bytes() |
| pre_current, rec, tail = parse_recovery_tail(blob) |
| if rec is None or tail is None: |
| raise HVCEError("archive has no recovery record") |
| data_len = int(rec["data_len"]) |
| if len(pre_current) != data_len: |
| raise HVCEError("repair supports replacement corruption only; archive length before recovery changed") |
| shard_size = int(rec["shard_size"]) |
| shard_count = int(rec["shard_count"]) |
| shards = [] |
| bad = [] |
| for i in range(shard_count): |
| off = i * shard_size |
| sh = bytearray(pre_current[off:off+shard_size]) |
| if len(sh) < shard_size: |
| sh.extend(b"\x00" * (shard_size - len(sh))) |
| bsh = bytes(sh) |
| shards.append(bytearray(bsh)) |
| if sha256_bytes(bsh) != rec["shard_sha256"][i]: |
| bad.append(i) |
| if not bad: |
| output.write_bytes(blob) |
| return {"repaired": False, "bad_shards": [], "message": "archive already matches recovery hashes"} |
| if len(bad) > 2: |
| raise HVCEError(f"too many corrupted shards for xor2 recovery: {bad}") |
| p0 = bytearray(b64d(rec["parity0"])) |
| p1 = bytearray(b64d(rec["parity1"])) |
| if len(p0) != shard_size or len(p1) != shard_size: |
| raise HVCEError("bad parity length") |
| if len(bad) == 1: |
| k = bad[0] |
| rec_shard = bytearray(p0) |
| for i, sh in enumerate(shards): |
| if i != k: |
| for j, v in enumerate(sh): |
| rec_shard[j] ^= v |
| shards[k] = rec_shard |
| else: |
| a, b = bad |
| ca = (a + 1) % 255 or 255 |
| cb = (b + 1) % 255 or 255 |
| denom = ca ^ cb |
| if denom == 0: |
| raise HVCEError("singular recovery coefficients") |
| invden = gf_inv(denom) |
| |
| s0 = bytearray(p0) |
| s1 = bytearray(p1) |
| for i, sh in enumerate(shards): |
| if i in bad: |
| continue |
| coef = (i + 1) % 255 or 255 |
| for j, v in enumerate(sh): |
| s0[j] ^= v |
| s1[j] ^= gf_mul(coef, v) |
| x = bytearray(shard_size) |
| y = bytearray(shard_size) |
| for j in range(shard_size): |
| x[j] = gf_mul(s1[j] ^ gf_mul(cb, s0[j]), invden) |
| y[j] = s0[j] ^ x[j] |
| shards[a] = x; shards[b] = y |
| repaired_pre = b"".join(bytes(s) for s in shards)[:data_len] |
| if sha256_bytes(repaired_pre) != rec["pre_sha256"]: |
| raise HVCEError("repair failed: pre-image SHA mismatch") |
| output.write_bytes(repaired_pre + tail) |
| return {"repaired": True, "bad_shards": bad, "output": str(output)} |
|
|
| |
| |
| |
|
|
| def compress_cmd(args) -> None: |
| inp = Path(args.input) |
| out = Path(args.output) |
| password = args.password |
| if args.ask_password: |
| password = getpass.getpass("HVCE password: ") |
| password2 = getpass.getpass("Confirm password: ") |
| if password != password2: |
| raise HVCEError("passwords do not match") |
| manifest, payload = build_manifest(inp, args.profile, args.chunk_size, not args.no_cdc, args.small_threshold) |
| if password: |
| pre = make_encrypted_container(manifest, payload, password, args.kdf_iterations) |
| else: |
| pre = make_plain_container(manifest, payload) |
| blob = append_recovery(pre, args.recovery_percent) |
| ensure_parent(out) |
| out.write_bytes(blob) |
| raw_size = int(manifest["stats"]["raw_size"]) |
| ratio = len(blob) / raw_size if raw_size else 1.0 |
| print(f"HVCE {VERSION}") |
| print(f"input raw: {human_size(raw_size)}") |
| print(f"archive: {human_size(len(blob))}") |
| print(f"ratio: {ratio:.6f}") |
| print(f"encrypted: {bool(password)}") |
| print(f"recovery: {args.recovery_percent}% target") |
| print(f"output: {out}") |
|
|
|
|
| def extract_cmd(args) -> None: |
| password = args.password |
| if args.ask_password: |
| password = getpass.getpass("HVCE password: ") |
| extract_archive(Path(args.archive), Path(args.output_dir), password, args.overwrite, args.allow_symlinks) |
| print(f"extracted: {args.output_dir}") |
|
|
|
|
| def inspect_cmd(args) -> None: |
| password = args.password |
| if args.ask_password: |
| password = getpass.getpass("HVCE password: ") |
| try: |
| manifest, payload, info = read_archive(Path(args.archive), password) |
| except HVCEError as e: |
| |
| blob = Path(args.archive).read_bytes() |
| pre, rec, _ = parse_recovery_tail(blob) |
| if pre.startswith(MAGIC) and len(pre) >= 9 and pre[8] == 1: |
| plen = struct.unpack("<I", pre[9:13])[0] |
| params = json.loads(zlib.decompress(pre[13:13+plen]).decode("utf-8")) |
| print(json.dumps({"format": "HVCE4", "encrypted": True, "outer_params": {k: params[k] for k in params if k not in {"salt", "nonce"}}, "recovery": rec is not None}, indent=2)) |
| return |
| raise e |
| print(json.dumps({ |
| "format": manifest.get("format"), |
| "version": manifest.get("version"), |
| "author": manifest.get("author"), |
| "encrypted": info.get("encrypted"), |
| "recovery": info.get("recovery") is not None, |
| "stats": manifest.get("stats"), |
| "payload_len": len(payload), |
| "entries_preview": [e.get("path") for e in manifest.get("entries", [])[:20]], |
| }, indent=2, sort_keys=True)) |
|
|
|
|
| def repair_cmd(args) -> None: |
| result = repair_archive(Path(args.archive), Path(args.output)) |
| print(json.dumps(result, indent=2)) |
|
|
|
|
| def compat_zip_cmd(args) -> None: |
| inp = Path(args.input).resolve() |
| out = Path(args.output) |
| ensure_parent(out) |
| compression = zipfile.ZIP_DEFLATED |
| with zipfile.ZipFile(out, "w", compression=compression, compresslevel=args.level, allowZip64=True) as z: |
| if inp.is_file(): |
| z.write(inp, inp.name) |
| else: |
| for dirpath, _dirnames, filenames in os.walk(inp): |
| for name in filenames: |
| p = Path(dirpath) / name |
| z.write(p, str(p.relative_to(inp))) |
| print(f"ZIP written: {out}") |
|
|
|
|
| def self_test_cmd(args=None) -> None: |
| with tempfile.TemporaryDirectory() as td: |
| root = Path(td) / "input" |
| root.mkdir() |
| (root / "docs").mkdir() |
| text = ("HVCE heaven-vector sparse world-state engine\n" * 2000).encode() |
| (root / "docs" / "a.txt").write_bytes(text) |
| (root / "docs" / "b.txt").write_bytes(text.replace(b"sparse", b"SPARSE", 4)) |
| |
| w, h = 128, 64 |
| field = bytearray(w*h) |
| for y in range(h): |
| for x in range(w): |
| field[y*w+x] = (3*y + 5*x + 7) & 0xff |
| (root / "field.bin").write_bytes(bytes(field)) |
| |
| poly = bytearray() |
| v = 1 |
| d1 = 3 |
| d2 = 2 |
| for _ in range(4096): |
| poly.extend(v.to_bytes(4, "little")) |
| v = (v + d1) & 0xffffffff |
| d1 = (d1 + d2) & 0xffffffff |
| (root / "poly.u32").write_bytes(bytes(poly)) |
| |
| rng = random.Random(123) |
| r = bytearray(rng.getrandbits(8) for _ in range(256 * 1024)) |
| (root / "blob.mp4").write_bytes(bytes(r)) |
| r2 = bytearray(r) |
| for i in range(0, len(r2), 8192): |
| r2[i] ^= 0x55 |
| (root / "blob_v2.mp4").write_bytes(bytes(r2)) |
| for i in range(100): |
| (root / "docs" / f"tiny_{i:03d}.json").write_text(json.dumps({"i": i, "name": "Eve", "vector": [1,2,3,4]}) + "\n", encoding="utf-8") |
|
|
| arc = Path(td) / "test.hvce" |
| out = Path(td) / "out" |
| class A: pass |
| a = A(); a.input=str(root); a.output=str(arc); a.profile="balanced"; a.chunk_size=256*1024; a.no_cdc=False; a.small_threshold=64*1024; a.password=None; a.ask_password=False; a.kdf_iterations=10_000; a.recovery_percent=10 |
| compress_cmd(a) |
| extract_archive(arc, out, overwrite=True) |
| compare_trees(root, out) |
|
|
| enc = Path(td) / "test_enc.hvce" |
| a.output=str(enc); a.password="correct horse battery staple"; a.recovery_percent=10 |
| compress_cmd(a) |
| out2 = Path(td) / "out2" |
| extract_archive(enc, out2, password=a.password, overwrite=True) |
| compare_trees(root, out2) |
|
|
| |
| blob = bytearray(arc.read_bytes()) |
| pre, rec, tail = parse_recovery_tail(bytes(blob)) |
| if rec is None: |
| raise HVCEError("self-test recovery missing") |
| shard_size = int(rec["shard_size"]) |
| corrupt_at = min(len(pre)-1, shard_size + 17) |
| blob[corrupt_at] ^= 0xA5 |
| bad = Path(td) / "bad.hvce"; fixed = Path(td) / "fixed.hvce" |
| bad.write_bytes(bytes(blob)) |
| repair_archive(bad, fixed) |
| out3 = Path(td) / "out3" |
| extract_archive(fixed, out3, overwrite=True) |
| compare_trees(root, out3) |
| print("HVCE self-test passed") |
|
|
|
|
| def compare_trees(a: Path, b: Path) -> None: |
| files_a = sorted([p for p in a.rglob("*") if p.is_file()]) |
| files_b = sorted([p for p in b.rglob("*") if p.is_file() and not p.name.endswith(".symlink.txt")]) |
| rel_a = [str(p.relative_to(a)) for p in files_a] |
| rel_b = [str(p.relative_to(b)) for p in files_b] |
| if rel_a != rel_b: |
| raise HVCEError(f"tree file list mismatch\n{rel_a}\n{rel_b}") |
| for p in files_a: |
| q = b / p.relative_to(a) |
| if p.read_bytes() != q.read_bytes(): |
| raise HVCEError(f"file mismatch: {p}") |
|
|
|
|
| def make_parser() -> argparse.ArgumentParser: |
| p = argparse.ArgumentParser(prog="hvce", description="The Heaven-Vector Compression Engine v4") |
| sub = p.add_subparsers(dest="cmd", required=True) |
|
|
| c = sub.add_parser("compress", help="compress a file or directory into .hvce") |
| c.add_argument("input") |
| c.add_argument("output") |
| c.add_argument("--profile", choices=["fast", "balanced", "max"], default="balanced") |
| c.add_argument("--chunk-size", type=int, default=DEFAULT_CHUNK_SIZE) |
| c.add_argument("--no-cdc", action="store_true", help="disable content-defined chunking") |
| c.add_argument("--small-threshold", type=int, default=SMALL_FILE_THRESHOLD) |
| c.add_argument("--password", default=None, help="password; prefer --ask-password for interactive use") |
| c.add_argument("--ask-password", action="store_true") |
| c.add_argument("--kdf-iterations", type=int, default=300_000) |
| c.add_argument("--recovery-percent", type=int, default=0, help="append two-parity recovery record; common values 5-20") |
| c.set_defaults(func=compress_cmd) |
|
|
| e = sub.add_parser("extract", help="extract a .hvce archive") |
| e.add_argument("archive") |
| e.add_argument("output_dir") |
| e.add_argument("--password", default=None) |
| e.add_argument("--ask-password", action="store_true") |
| e.add_argument("--overwrite", action="store_true") |
| e.add_argument("--allow-symlinks", action="store_true", help="create symlinks instead of safe .symlink.txt stubs") |
| e.set_defaults(func=extract_cmd) |
|
|
| i = sub.add_parser("inspect", help="inspect an archive") |
| i.add_argument("archive") |
| i.add_argument("--password", default=None) |
| i.add_argument("--ask-password", action="store_true") |
| i.set_defaults(func=inspect_cmd) |
|
|
| r = sub.add_parser("repair", help="repair up to two corrupted recovery shards") |
| r.add_argument("archive") |
| r.add_argument("output") |
| r.set_defaults(func=repair_cmd) |
|
|
| z = sub.add_parser("compat-zip", help="create a standard ZIP for compatibility/export") |
| z.add_argument("input") |
| z.add_argument("output") |
| z.add_argument("--level", type=int, default=9) |
| z.set_defaults(func=compat_zip_cmd) |
|
|
| t = sub.add_parser("test", help="run built-in self-test") |
| t.set_defaults(func=self_test_cmd) |
| return p |
|
|
|
|
| def main(argv: Optional[Sequence[str]] = None) -> int: |
| try: |
| args = make_parser().parse_args(argv) |
| args.func(args) |
| return 0 |
| except HVCEError as e: |
| print(f"HVCE error: {e}", file=sys.stderr) |
| return 2 |
| except KeyboardInterrupt: |
| print("interrupted", file=sys.stderr) |
| return 130 |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|