File size: 3,260 Bytes
0081600
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
from __future__ import annotations

import os
import random
import tempfile
from pathlib import Path

import hvce


def make_tree(root: Path) -> None:
    root.mkdir(parents=True, exist_ok=True)
    (root / "a.txt").write_text("hello heaven vector\n" * 1000, encoding="utf-8")
    (root / "empty.bin").write_bytes(b"")
    (root / "sub").mkdir()
    (root / "sub" / "ramp.bin").write_bytes(bytes([i & 255 for i in range(8192)]))
    rng = random.Random(1)
    base = bytearray(rng.getrandbits(8) for _ in range(128 * 1024))
    (root / "media.mp4").write_bytes(bytes(base))
    base[0] ^= 1
    (root / "media_v2.mp4").write_bytes(bytes(base))


def test_roundtrip_plain():
    with tempfile.TemporaryDirectory() as td:
        src = Path(td) / "src"; out = Path(td) / "out"; arc = Path(td) / "x.hvce"
        make_tree(src)
        m, p = hvce.build_manifest(src, "fast", 64 * 1024, True, 32 * 1024)
        arc.write_bytes(hvce.append_recovery(hvce.make_plain_container(m, p), 0))
        hvce.extract_archive(arc, out, overwrite=True)
        hvce.compare_trees(src, out)


def test_roundtrip_encrypted():
    with tempfile.TemporaryDirectory() as td:
        src = Path(td) / "src"; out = Path(td) / "out"; arc = Path(td) / "x.hvce"
        make_tree(src)
        m, p = hvce.build_manifest(src, "balanced", 64 * 1024, True, 32 * 1024)
        arc.write_bytes(hvce.make_encrypted_container(m, p, "secret", 5000))
        hvce.extract_archive(arc, out, password="secret", overwrite=True)
        hvce.compare_trees(src, out)


def test_recovery_one_shard():
    with tempfile.TemporaryDirectory() as td:
        src = Path(td) / "src"; out = Path(td) / "out"; arc = Path(td) / "x.hvce"; bad = Path(td) / "bad.hvce"; fixed = Path(td) / "fixed.hvce"
        make_tree(src)
        m, p = hvce.build_manifest(src, "fast", 64 * 1024, True, 32 * 1024)
        arc.write_bytes(hvce.append_recovery(hvce.make_plain_container(m, p), 20))
        blob = bytearray(arc.read_bytes())
        pre, rec, tail = hvce.parse_recovery_tail(bytes(blob))
        assert rec is not None
        blob[min(len(pre) - 1, int(rec["shard_size"]) + 10)] ^= 0x42
        bad.write_bytes(bytes(blob))
        result = hvce.repair_archive(bad, fixed)
        assert result["repaired"] is True
        hvce.extract_archive(fixed, out, overwrite=True)
        hvce.compare_trees(src, out)


def test_recipe_polyword():
    data = bytearray()
    v, d1, d2 = 5, 7, 3
    for _ in range(1000):
        data.extend(v.to_bytes(4, "little"))
        v = (v + d1) & 0xffffffff
        d1 = (d1 + d2) & 0xffffffff
    cand = hvce.choose_representation(bytes(data), "balanced")
    dec = hvce.decode_candidate(cand.method, cand.payload, len(data), cand.params)
    assert dec == bytes(data)


def test_password_rejects_wrong_password():
    with tempfile.TemporaryDirectory() as td:
        src = Path(td) / "src"; arc = Path(td) / "x.hvce"
        make_tree(src)
        m, p = hvce.build_manifest(src, "fast", 64 * 1024, True, 32 * 1024)
        arc.write_bytes(hvce.make_encrypted_container(m, p, "secret", 5000))
        try:
            hvce.read_archive(arc, "wrong")
        except hvce.HVCEError:
            pass
        else:
            raise AssertionError("wrong password accepted")