Download hvce.py from PureOne/heaven-vector-compression-engine: direct link, hf CLI and curl.
- Browser
- Download file 65 kB
-
https://huggingface.co/PureOne/heaven-vector-compression-engine/resolve/main/hvce.py
- Command line
-
hf download hf://PureOne/heaven-vector-compression-engine/hvce.py
-
curl -L -o hvce.py https://huggingface.co/PureOne/heaven-vector-compression-engine/resolve/main/hvce.py
65 kB
| #!/usr/bin/env python3 | |
| """ | |
| 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" # 8 bytes | |
| REC_MAGIC = b"HVCE4REC" # 8 bytes | |
| END_MAGIC = b"HVCE4END" # 8 bytes | |
| 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 | |
| # --------------------------------------------------------------------------- | |
| # Errors and utilities | |
| # --------------------------------------------------------------------------- | |
| 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(256) for recovery records | |
| # --------------------------------------------------------------------------- | |
| 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] | |
| # --------------------------------------------------------------------------- | |
| # ChaCha20 + HMAC-SHA256 password envelope | |
| # --------------------------------------------------------------------------- | |
| 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:] | |
| # --------------------------------------------------------------------------- | |
| # Reversible transforms | |
| # --------------------------------------------------------------------------- | |
| 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 | |
| # Bounded perceptron-style update using only past state and exact decoded b. | |
| 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), | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Codecs and exact recipes | |
| # --------------------------------------------------------------------------- | |
| 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]: | |
| # Exact finite-difference polynomial stream over modulo 2^(8w), degree <= 3. | |
| 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): | |
| # Deg 0 constant sequence. Deg >0 means d^deg is constant. | |
| 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: | |
| # Need all highest differences constant; lower starts define stream. | |
| 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[:] # state[0] = value, state[1] = first diff, ... | |
| 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: # >5% defects, stop | |
| 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) # <= about 3.125% changed bytes | |
| 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 | |
| # A small structural overhead estimate prevents choosing fragile tiny wins. | |
| 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 | |
| # Exact generative branch. Skip high-entropy blocks immediately; this is the | |
| # speed win that makes random/encrypted/already-compressed data cheap. | |
| 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)) | |
| # Reference branch for already-compressed/versioned/high entropy blocks. | |
| # This is still worth trying on high-entropy media/checkpoints because two | |
| # near-identical encrypted-looking versions can patch extremely well. | |
| for ref_id, ref_data in ref_candidates[:48 if profile == "max" else 16]: | |
| consider(encode_ref_xor_sparse(data, ref_id, ref_data)) | |
| # Codec portfolio branch. Skip expensive codecs for obvious random/media-like chunks unless max requested. | |
| 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) | |
| # Use fast codecs first; lzma after bitplane can be excellent but slow, only max/balanced. | |
| 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 | |
| # Entropy-respect contract: raw wins if nothing gives a meaningful reduction. | |
| if best.method != "raw" and len(best.payload) >= n: | |
| best = Candidate("raw", data, {}) | |
| return best | |
| # --------------------------------------------------------------------------- | |
| # Content-defined chunking and metadata | |
| # --------------------------------------------------------------------------- | |
| 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 | |
| # --------------------------------------------------------------------------- | |
| # Archive build/read | |
| # --------------------------------------------------------------------------- | |
| 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 | |
| # Reference cache: keep a bounded number of recent same-length chunks. | |
| 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 | |
| # The verified microgroup hash plus offset/length proves exact bytes; | |
| # dropping per-tiny-file hashes cuts small-folder manifest overhead. | |
| 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) | |
| # Include symlink dirs as symlink entries and prevent recursion. | |
| 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: | |
| # SPWSE solid micro-pack: group tiny files by extension and entropy class. | |
| ext = Path(rel).suffix.lower() or "_noext" | |
| ent_level = "hi" if looks_incompressible(data) else "lo" | |
| # v4 OmniCrown: low-entropy tiny office/source files are packed | |
| # into one solid world-state block so repetition can cross file | |
| # boundaries. Compressed/media-like tiny files are grouped | |
| # separately to preserve speed and avoid polluting the dictionary. | |
| 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: | |
| # Preserve unusual filesystem item as a metadata stub. | |
| b.entries.append({"path": rel, "type": "special", "meta": file_meta(p)}) | |
| # Encode small groups after all entries exist. Tiny groups below two files may still benefit from header amortization. | |
| 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)) | |
| # Two parity shards => overhead ~= 2/N. Pick N from requested 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: # read-only compatibility with early v4 draft archives | |
| 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: # read-only compatibility with early v4 draft encrypted archives | |
| 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") | |
| # --------------------------------------------------------------------------- | |
| # Extractor | |
| # --------------------------------------------------------------------------- | |
| 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": | |
| # Metadata stub only. | |
| 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) | |
| # --------------------------------------------------------------------------- | |
| # Recovery repair | |
| # --------------------------------------------------------------------------- | |
| 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 = x ^ y ; s1 = ca*x ^ cb*y. | |
| 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)} | |
| # --------------------------------------------------------------------------- | |
| # Commands | |
| # --------------------------------------------------------------------------- | |
| 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: | |
| # For encrypted archives, show outer non-private status without password. | |
| 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)) | |
| # Rank-1 photonic field. | |
| 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)) | |
| # Polynomial word stream. | |
| 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)) | |
| # Random/media-like data; second version differs sparsely. | |
| 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) | |
| # Recovery test: corrupt one shard in the unencrypted archive. | |
| 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()) | |