From 288df8ea0bb6a86d3816d00999deb92288f1a645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Cezar=20Mois=C3=A9s?= Date: Sat, 11 Apr 2026 15:59:59 -0300 Subject: [PATCH] Release 2.1.3: Fix disk backup corruption, solid PQ encryption, block I/O, and format mismatches - Corrected LZHP prediction encoding in disk backups to prevent data corruption - Disabled spurious SOLID flag for per-block disk archives - Shared write_enc_header() across all encryption paths to eliminate format mismatches - Enabled solid compression with PQ encryption support - Updated block device restore to use O_SYNC + fsync/sync - Improved Termux/Android host detection for safer builds - Made zupt_w8(), zupt_w16le(), zupt_w64le() non-static for shared use --- CHANGELOG.md | 27 +++ Makefile | 26 ++- README.md | 12 +- ROADMAP.md | 4 +- include/zupt.h | 13 +- jasmin/zupt_aes_ctr.o | Bin 1648 -> 0 bytes jasmin/zupt_aes_ctr4.o | Bin 3112 -> 0 bytes jasmin/zupt_mac_verify.o | Bin 880 -> 0 bytes jasmin/zupt_mlkem_select.o | Bin 912 -> 0 bytes jasmin/zupt_x25519_fe.o | Bin 936 -> 0 bytes src/vaptvupt_api.o | Bin 1872 -> 0 bytes src/vv_ans.o | Bin 29816 -> 0 bytes src/vv_decoder.o | Bin 7072 -> 0 bytes src/vv_encoder.o | Bin 9624 -> 0 bytes src/vv_huffman.o | Bin 6256 -> 0 bytes src/vv_simd.o | Bin 3272 -> 0 bytes src/zupt_aes256.o | Bin 3752 -> 0 bytes src/zupt_cpuid.o | Bin 1416 -> 0 bytes src/zupt_crypto.o | Bin 13912 -> 0 bytes src/zupt_disk.c | 395 +++++++++++++------------------- src/zupt_filetype.o | Bin 3456 -> 0 bytes src/zupt_format.c | 174 +++++++------- src/zupt_format.o | Bin 61928 -> 0 bytes src/zupt_keccak.o | Bin 5800 -> 0 bytes src/zupt_lz.o | Bin 4568 -> 0 bytes src/zupt_lzh.o | Bin 15264 -> 0 bytes src/zupt_main.o | Bin 34720 -> 0 bytes src/zupt_mlkem.o | Bin 19264 -> 0 bytes src/zupt_mlock.o | Bin 1992 -> 0 bytes src/zupt_parallel.o | Bin 12648 -> 0 bytes src/zupt_predict.o | Bin 3000 -> 0 bytes src/zupt_sha256.o | Bin 3976 -> 0 bytes src/zupt_x25519.o | Bin 5744 -> 0 bytes src/zupt_xxh.o | Bin 1936 -> 0 bytes tmp/zupt_solid_pq2/in/a.txt | 1 + tmp/zupt_solid_pq2/in/b.txt | 1 + tmp/zupt_solid_pq3/in/a.txt | 1 + tmp/zupt_solid_pq_5304/in/a.txt | 1 + tmp/zupt_solid_pq_5304/in/b.txt | 1 + 39 files changed, 325 insertions(+), 331 deletions(-) delete mode 100644 jasmin/zupt_aes_ctr.o delete mode 100644 jasmin/zupt_aes_ctr4.o delete mode 100644 jasmin/zupt_mac_verify.o delete mode 100644 jasmin/zupt_mlkem_select.o delete mode 100644 jasmin/zupt_x25519_fe.o delete mode 100644 src/vaptvupt_api.o delete mode 100644 src/vv_ans.o delete mode 100644 src/vv_decoder.o delete mode 100644 src/vv_encoder.o delete mode 100644 src/vv_huffman.o delete mode 100644 src/vv_simd.o delete mode 100644 src/zupt_aes256.o delete mode 100644 src/zupt_cpuid.o delete mode 100644 src/zupt_crypto.o delete mode 100644 src/zupt_filetype.o delete mode 100644 src/zupt_format.o delete mode 100644 src/zupt_keccak.o delete mode 100644 src/zupt_lz.o delete mode 100644 src/zupt_lzh.o delete mode 100644 src/zupt_main.o delete mode 100644 src/zupt_mlkem.o delete mode 100644 src/zupt_mlock.o delete mode 100644 src/zupt_parallel.o delete mode 100644 src/zupt_predict.o delete mode 100644 src/zupt_sha256.o delete mode 100644 src/zupt_x25519.o delete mode 100644 src/zupt_xxh.o create mode 100644 tmp/zupt_solid_pq2/in/a.txt create mode 100644 tmp/zupt_solid_pq2/in/b.txt create mode 100644 tmp/zupt_solid_pq3/in/a.txt create mode 100644 tmp/zupt_solid_pq_5304/in/a.txt create mode 100644 tmp/zupt_solid_pq_5304/in/b.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bebffb..1ec49d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,32 @@ Format follows [Keep a Changelog](https://keepachangelog.com/). --- +## [2.1.3] — 2026-04-11 + +### Fixed — LZHP Prediction Encoding Missing in Disk Backup (data corruption) +- **Root cause:** `zupt_disk_backup()` LZHP compression path skipped the `zupt_predict_encode()` step. When byte prediction was active (`pred_active=1`), it stored the prediction table and wrote `cbuf[0] = 0x01`, but then compressed the **raw block data** instead of the prediction-encoded data. On restore, `decompress_block()` correctly applied `zupt_predict_decode()` to the decompressed output, producing corrupted data. Checksum mismatch on block 0 for any block with structured content (ext4 metadata, NTFS headers, partition tables). +- **Impact:** ALL disk backups using LZHP codec (default on CPUs without AVX2) on non-random data were silently corrupted. VaptVupt codec was unaffected (no prediction path). Random/incompressible data was unaffected (prediction benefit < threshold → `pred_active=0`). +- **Fix:** Added `zupt_predict_encode(rbuf, transformed, nread, pred)` before `zupt_lzh_compress()`, matching the correct path in `zupt_format.c` (lines 557–563). Allocated temporary buffer for prediction-encoded data, freed after compression. + +### Fixed — Spurious SOLID Flag on Disk Archives +- Disk backup no longer sets `ZUPT_FLAG_SOLID` in the archive header. Disk images are independent per-block archives, not solid streams. The SOLID flag caused `zupt_extract_archive()` to take the wrong code path if a disk archive was ever parsed by the extract function. + +### Fixed — Shared Encryption Header (eliminates all format mismatches) +- **Extracted `write_enc_header()`** from `zupt_format.c` as a shared non-static function. ALL three encryption write paths — `zupt_compress_files()`, `zupt_compress_solid()`, and `zupt_disk_backup()` — now call the same function. +- **Solid compress now supports PQ encryption.** +- **`zupt_w8()`, `zupt_w16le()`, `zupt_w64le()`** made non-static and declared in `zupt.h`. + +### Fixed — Block Device Restore I/O +- Restore uses POSIX raw I/O (`open()` + `write()` loop) with `O_SYNC` for block devices, `fsync()` + `sync()` before close. + +### Fixed — Termux/Android Build +- Arch-safety guard uses `$(CC) -dumpmachine` for host detection. Falls back to `uname -m`. + +### Tests +- **78 total:** 70 core + 8 disk (including LZHP+PQ+password on ext4 — the exact failing case). ASAN + UBSan clean. + +--- + ## [2.1.2] — 2026-04-06 ### Added — Full-Disk Backup/Restore @@ -273,6 +299,7 @@ All 4 `.jazz` files rewritten to fix compilation errors: | Version | Key Change | Tests | |---------|-----------|-------| +| **2.1.3** | Shared `write_enc_header()` eliminates all format mismatches, solid PQ support, block device O_SYNC. Disk restore rewritten — uses shared block I/O, fixes checksum mismatch with all encryption formats | 77 PASS | | **2.1.2** | Full-disk backup/restore with sparse detection, all encryption modes, progress bar | 77 PASS | | **2.1.1** | Termux/Android build fix, arch-safety guard, Keccak UB fix, no stale .o in tarballs | 70 PASS | | **2.1.0** | VaptVupt 1.4.0: cross-block dictionary, context prefetch, faster adaptive window, integration API | 70 PASS | diff --git a/Makefile b/Makefile index 8f55d07..9ef3036 100644 --- a/Makefile +++ b/Makefile @@ -118,19 +118,29 @@ ALL_OBJS = $(ZUPT_OBJS) $(VV_SIMD_OBJS) $(VV_PLAIN_OBJS) # If pre-compiled .o files from a different architecture are present # (e.g. x86_64 .o files in an aarch64 build), the linker will fail # with "incompatible with ". Detect and remove stale objects. -# This happens when tarballs accidentally include build artifacts. +# This happens when tarballs accidentally include build artifacts, +# or when the same source tree is shared between different machines. +# +# Detection: uses $(CC) -dumpmachine which works on ALL platforms +# including Termux (where /bin/sh does not exist). # ═══════════════════════════════════════════════════════════════════ STALE_OBJS := $(wildcard src/*.o jasmin/*.o) ifneq ($(STALE_OBJS),) - # Check if any existing .o is for the wrong architecture FIRST_OBJ := $(firstword $(STALE_OBJS)) - OBJ_ARCH := $(shell file $(FIRST_OBJ) 2>/dev/null | grep -oE 'x86.64|aarch64|ARM|PowerPC|S/390|RISC-V' | head -1) - HOST_ARCH := $(shell file /bin/sh 2>/dev/null | grep -oE 'x86.64|aarch64|ARM|PowerPC|S/390|RISC-V' | head -1) - ifneq ($(OBJ_ARCH),$(HOST_ARCH)) - ifneq ($(OBJ_ARCH),) - $(info [arch] Removing stale $(OBJ_ARCH) objects for $(HOST_ARCH) build) - $(shell rm -f src/*.o jasmin/*.o) + OBJ_ARCH := $(shell file $(FIRST_OBJ) 2>/dev/null | grep -oiE 'x86.64|aarch64|arm|powerpc|s390|riscv' | head -1) + HOST_TRIPLE := $(shell $(CC) -dumpmachine 2>/dev/null) + HOST_ARCH_CC := $(shell echo "$(HOST_TRIPLE)" | grep -oiE 'x86.64|aarch64|arm|powerpc|s390|riscv' | head -1) + # Fallback: try uname -m if CC -dumpmachine fails + ifeq ($(HOST_ARCH_CC),) + HOST_ARCH_CC := $(shell uname -m 2>/dev/null | grep -oiE 'x86.64|aarch64|arm|powerpc|s390|riscv' | head -1) + endif + ifneq ($(OBJ_ARCH),) + ifneq ($(HOST_ARCH_CC),) + ifneq ($(OBJ_ARCH),$(HOST_ARCH_CC)) + $(info [arch] Removing stale $(OBJ_ARCH) objects for $(HOST_ARCH_CC) build) + $(shell rm -f src/*.o jasmin/*.o) + endif endif endif endif diff --git a/README.md b/README.md index ec54b03..d5bcd1b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![Build](https://img.shields.io/badge/build-passing-brightgreen) ![License](https://img.shields.io/badge/license-MIT-blue) -![Version](https://img.shields.io/badge/version-2.1.2-orange) +![Version](https://img.shields.io/badge/version-2.1.3-orange) ![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20%7C%20Windows-lightgrey) ![openSUSE](https://img.shields.io/badge/platform-openSUSE-73BA25?logo=opensuse&logoColor=white) @@ -372,11 +372,11 @@ All codecs are forward-compatible: archives created with any codec can be read b | v1.1–v1.4 | X25519 fix, NIST vectors, CPUID detection, Jasmin source files fixed | | v1.5 | Jasmin CT assembly linked (MAC verify + ML-KEM select active) | | v1.5.5 | Man page install, V=1 verbose, LDFLAGS/PIE, rpmlint, multi-arch Makefile | -| v2.0 | VaptVupt 1.1.0 codec with auto hardware detection, all 5 Jasmin functions wired, AVX SIGILL fix, copy_match/litlen overflow fixes, ACSL proofs, mlock, fuzzing, canaries, AES-NI 4-block pipeline, MT decompression, adaptive compression, multi-architecture support (6 arches), --lzhp flag | -| v2.1 | VaptVupt 1.4.0: cross-block dictionary carry, context decode prefetch, faster adaptive window trial (2.6× encode), integration API | -| v2.1.1 | Termux/Android build fix, arch-safety guard removes stale cross-arch .o, Keccak ROL64 UB fix, zero UBSan violations | -| **v2.1.2** | **Full-disk backup/restore (`zupt disk`), sparse detection, all encryption modes, per-block XXH64 verification, progress bar, 77 tests** | -| v2.1.3 | Wait for it. | +| v2.0 | VaptVupt 1.1.0 codec, auto hardware detection, all 5 Jasmin wired, AVX SIGILL fix, copy_match/litlen fixes, ACSL, mlock, fuzzing, canaries, AES-NI pipeline, MT decompress, multi-arch (6 arches), --lzhp flag | +| v2.1.0 | VaptVupt 1.4.0: cross-block dictionary carry, context decode prefetch, faster adaptive window (2.6× encode), integration API | +| v2.1.1 | Termux/Android build fix, arch-safety guard, Keccak ROL64 UB fix, zero UBSan violations | +| v2.1.2 | Full-disk backup/restore (`zupt disk`), sparse detection, all encryption modes, progress bar | +| **v2.1.3** | **Disk restore fix (POSIX raw I/O + O_SYNC for block devices, shared decompress_block), Termux build fix (CC -dumpmachine arch detection). LZHP prediction encoding fix (data corruption on structured data), shared write_enc_header, SOLID flag removed from disk, 78 tests** | See [CHANGELOG.md](CHANGELOG.md) for detailed per-version changes. diff --git a/ROADMAP.md b/ROADMAP.md index 7a7ed24..8680798 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -21,7 +21,9 @@ | **v2.0** | **✅** | **VaptVupt 1.1.0 codec with auto hardware detection, all 5 Jasmin wired, AVX SIGILL fix, copy_match/litlen fixes, ACSL, mlock, fuzzing, canaries, AES-NI pipeline, MT decompress, multi-arch (6 arches)** | | **v2.1** | **✅** | **VaptVupt 1.4.0: cross-block dictionary, context prefetch, faster adaptive window, integration API** | | **v2.1.1** | **✅** | **Termux/Android build fix, arch-safety guard, Keccak UB fix, no stale .o in tarballs** | -| **v2.1.2** | **✅ Current** | **Full-disk backup/restore with sparse detection, all encryption modes, progress bar, 77 tests** | +| **v2.1.2** | **✅** | **Full-disk backup/restore with sparse detection, all encryption modes, progress bar, 77 tests** | +| **v2.1.3** | **✅** | **Disk restore rewritten — shared block I/O, fixes checksum mismatch on encrypted/PQ archives** | +| **v2.1.3** | **✅ Current** | **LZHP prediction encoding fix, shared write_enc_header, SOLID flag removed from disk, block device O_SYNC, 78 tests** | ## Planned diff --git a/include/zupt.h b/include/zupt.h index 9c67669..7c72753 100644 --- a/include/zupt.h +++ b/include/zupt.h @@ -30,7 +30,7 @@ #define zupt_mkdir(p) mkdir(p, 0755) #endif -#define ZUPT_VERSION_STRING "2.1.2" +#define ZUPT_VERSION_STRING "2.1.3" #define ZUPT_FORMAT_MAJOR 1 #define ZUPT_FORMAT_MINOR 4 @@ -347,4 +347,15 @@ zupt_error_t zupt_disk_backup(const char *output_path, const char *source_path, zupt_error_t zupt_disk_restore(const char *archive_path, const char *target_path, zupt_options_t *opts); +/* ─── Internal Block I/O (used by format + disk modules) ─── */ +zupt_error_t read_block(FILE *f, zupt_block_t *b); +zupt_error_t read_enc_header(FILE *f, zupt_archive_header_t *hdr, zupt_options_t *opts); +zupt_error_t decompress_block(const zupt_block_t *b, const zupt_keyring_t *kr, + uint64_t block_seq, uint8_t **out, size_t *olen); +zupt_error_t write_enc_header(FILE *out, zupt_archive_header_t *hdr, + zupt_options_t *opts); +int zupt_w8(FILE *f, uint8_t v); +int zupt_w16le(FILE *f, uint16_t v); +int zupt_w64le(FILE *f, uint64_t v); + #endif diff --git a/jasmin/zupt_aes_ctr.o b/jasmin/zupt_aes_ctr.o deleted file mode 100644 index 29bffc95fc1c0123d832dffb25b2ae7ef8b829d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1648 zcmbtUze^)Q6rRN3#V%S2*KA1Rkk9$MdssGlc&=sINog^2nV z=_f<#Z}BR;{YWKt_@1Pk!)FP#i!EM@Ugbbl(Lz^gM6YtDsu-cGG=Tz#GVNY@oFBL5 zuS;+!2{Zv20fvCQfPw%Eq0XzIAv}7S6svV&v~`L#Ix%XrHGfm*O^88#9qK>2ZlDCmq!5qFud~v zpKktsk4*ma%W@XXvOPBbZK1fb%$RO(t~zEB(Af~Uq&%nm+hKaibWElfZJX(9>rPpp znw=Z59di-5|8HMG0(08b{r`T&EyDFQKs2GAWJGGtgk7taI;sZ_cqNTm8^4UbyF+d(ZitbMC$G zo_9l6Tdq}^Oh|7gbOr5>^jU~#DzeCeYS2yREoXacL~0#dv4)$EAS4HU4bX!O zkUE#RZMHtUei){O&?+ZpSm5=Td)|aCoOO;HziZ;GZ@EYZw#ZrEF${y2@d1;|`o1MH zNas#q7`Vne3++x5J5HS5ofCZERFqgLE+{ind`S5q#ru_yQrxS2;zl#;kT3*p#6X^6 z2IvO#9qFs^dDA3k{l9Z^Jg{w+mz3`%geB#hoDKD28?oO&#Qrsy?U>~SMJXXHC_lk| z5Id;|*&!e?&A(z1{wb&fKd${Z?VRpwTiM`eD( zv=T$536cPnqIqd5FU9f_O>|jEg>f3@=oN!I1y2tK?nuGYLyW=mVUCNyO9ToneLgU7 z)u7KZuG~B8m@}8l{h!)EF0~vC)j2zz9rvbT75g;uR;w*|v30`}jJDuoKi}o;3p8A~ z*ww=iHzH&Y2oHI0H*kJfoH`2w3-rIm*8`TsFK*?=C)lcD yFpOVm`8zZn*&kv{awYAg$`COt&Yh?hHGHjRr?cW*kAtEV{)dLYtOGS(jQ<0C#>8>} diff --git a/jasmin/zupt_mac_verify.o b/jasmin/zupt_mac_verify.o deleted file mode 100644 index cb4719a276a915c12e413af1f7d80fb3cbb5d222..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 880 zcmb<-^>JfjWMqH=Mg}_u1P><4z+iwR=l~XWVBlonVDLD80L1g?=J)6p^Dw;V!Fj@? z+n>XuJB$O)69DoA;5-Q+PXfX_%;1$+oST`a;GCaZkeQQOq+n!VWTt0etY-kW0uKRl zju1ANR+Sc%#OEd^$CsrRWu{feCzmiV=oMGymLw(t>5?J{odIK&q*jzL=%pl2oP;tFVdMIaxf zpBYWO4vi1vg47}dbs&cWh{@Hj1JnyL6Fq`p_JjO~3}E)dXj7mhjE$^rCNc+!jjk5N zXF`&PF&97?Fn6&7`5?6*zk+}SgaW2nOuvJqEKOh@ep~0WaxE1YOb;JxWljsl@8Vb4g>M#U?4u7SxO9k{|IiEIru% zkw<6REUv2saUgl~-n_}qBzdU^7rLf_2n|l*iwPCrRua9r?7=!1;J?2S^ADzeu^AM4 zV>G+2jvJM6P@VasEx%|QL2+h$mv0QzP1H?AH&M4xw-nu)z*U$h-PAtMl76=r4{XR(axSA`2oUOD!W7rKnTWa8kdv2orLY!&|Mbt@sq|6S YcS{tYp1+L+_1%$oqcqk|&#OmVU6!N929dzs` z5I>4{Z5}>ey6A)C?)T?%cS&B_?s>UX0(nYs3cpCQ00V_=E$9|(f&u(vN{H{zd1msg z;-sHWWA4RA-V!~0-dZPuG7tbWAmi#b={Xr1j&4wkvhqe|?vp|9zlDPS?#R2F8{4ulk9z$N{!d+g diff --git a/src/vaptvupt_api.o b/src/vaptvupt_api.o deleted file mode 100644 index fdd79d94d005757978e3616debe7f360cadb3bb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1872 zcmbtU&1(}u6rZHg#I`n3dI;3o9HOLXhNLYbMM|X6Zc8a57QM)JlWa_FK9*!Rq($05 z6)e5v;=!ALN;DDI(POHgA$~++Os-%X`1yypP#8GugSdeB1ByF(E!S z$NEUHj70){KjXR?c9spZAK{BXwcW3Yg0>&Hlz;_oFB^}h4-NxyEb}%S4>0X88xJA6 zxqIZ_Nx~8qSls*g39Yt&FCHyuS4Q1*XI$HTlXzVWPdvp%ObKqkhZH}6FYnxpVv&pG z4)*_yf#HcZnjU5g^YgQ@#A?o|+DntlA zK~IBY3$X9UUW)@BCxzc|UgF(70XGhcYpP5F;lW$T8u&hxC<+|u*4id8oo4FG*#*BiEx-_Y}=4ZUcrm)*#MDaZbS`epQ7&8ZgT zV#MGU=V+gJ#;CuJyJAT^-UY!wllY*-zmRyGk%*5GkJlDe$PID?-zI!V;l&&oZ){d< zBL~*5cWp^{b+c@6+icm47Yy5AJO{JmFqw*31+H4NO%8WC=?;+aqpHKLdd)KH_9o+Q z1+%0V>qf<-9sHk(K|0>q(@L2P;g<>@QScaGJdcdRAJGukh#v%teL{rs9im(YMP9sH zX js`>Z^)w2VNwdjMMAdrO0_Ly_vdF8(%vfPX8I%@uJ^_<7z diff --git a/src/vv_ans.o b/src/vv_ans.o deleted file mode 100644 index 5b83422772a81ded8438494bd80f5132247fb66c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29816 zcmcJ14|o(+mTyTXg0@cLDw9@5(;CMv?1o!d4UD40C=MVJaTbIL9YqHr zNq4lbO$j@X-En8!UB`82-O>5?mI>G?z!ilbM85}vLdWa%#kFQbxE%8yRuIf)aB}4oGk}MG3Y9Ao#SG> zN98B|jmr9dT>gIl=}LJ_$mObxRVc2ghquOBB!xG!Sfj*lCCt^Ig#EkfPe&h)^-0nB zvA*Dn$JyK#O`jgj(E_{Vx)*_5X_0dLjj!cUG4WGL9uqY2m9V*|^d}@G;r55*b#8^t z?boYv*xb{x=G<_?9grKADR^7qxAnJ0Q9Erz8fAYFQMM+Foa^!~TgmSu)OE?3qPkuu9Fb29+uD+{MKE7Y&y-fdw%Z*{n z$3L!=7j0*?pLy~4AWOQhD#0)qkNZ3TFy3wO=W}_H3kbca+=X9zrTl19rTjpuQvS)# zO8K34@jGO|diSzGbM@P(w2A4bjd!xu3IFs9L2WFW(ogZGbzk zs`B!W#Jnm=_cQg4(aTse>(rZi=JWbSg%>8|(56c6o+7ofSd+wRd&G3_P+oU= z(NXEyaQ%My*_CL3sU=}~ll~~l{JQ$KXg=;Wfo-zZEo(b%lh;|_zw`pka%IfDTxxZ1 z6is4jsrq%6G&uSo`#Xcha(yRov)awX_z>TE-zJiqaME2D2Elo65*3xaVxkTEq4b96 zI^{J<(AR5_wL*}ENs0p-TEr?QN{?FPP3@Ma+Q~Zz^2UI?5O1%HU29ReLWwm?^^MiP zPyG<|`WyYb1Wv&}d0qa*N(^*Dw>-g)=}3LQoG3wcU}JjWa(P`&WvpA0pDF|_)+JT) z9CVWYk1jz}PqKm&%(Id0oZr zSc@T@NtF|LzE*jrwf}gumG|!aRF3QDT>i_hF#jsVPloxYu~TD8cPgdt#6B%lIu7v; zrL;E`Xn#`WJ3BgoIR{9as6*;4@jf75p|9#SVzLF*=44k-#YEFM?z>-^sobypSeb?C z4!K+#Mxn=0X**;jRC=(ZlkY@7A*nt6Yh&HLo{#sh(H~P0_&-iP1{Mpx%41y050!gV zzFWClK>mpM?8Kv(@K)2I8qVm4`7_V{;+l}O_QgR~1= z^16`b1?QuhM_(#QC)jh9e3^h~|CGaYcaZ6!Fs8~w)&B{?GtJE)lL?l?YI{ixs@M5< zneym9KMX{L9^Mj?PE5-zIxnYvDL1@zT zpdE9YKY_aRw;6IRH$+(uW)>h3%cDc9Wq=mrvXOTQ3aNp7fMz?#=r$)l6|2&D?@K2CWEWtR7(Z)vTt7D(g-iG;jHb3FcO;fpqN1?& zaK8-w5ooGDY_k*FH2$f^4>NweYh`bLfA(p|SqK=v9mF?A{WSBNJ%&havcyS48)5<3 z?BiI=w|nJtbA_*z-f7ig79XezUZ+3I^7M20@?O$O%H0vZMd+g1&z8dGGd|r1UqJJD z2Way7cm+D@Pgh^4wo<=%Ns|Del#2DY1TB8_)>F33qjVXf#-SA0Sg3x28a843B#c%cFLG>w1cKPt4a z&|3@&9?Groa>m=C2(>#sWHp{+d>fuZ6QIpXcSNVv_R)%w6_cRRwYb%i(<;ho#+tFROkAP7GHe6NgxGnJ=heWL}N< zZwl`+9}^{_)1xMD&VaKOyaKi!qlH3RGfeJ_wj_+cWXTx~k+CbG&RrH8@S5;fK`LTx&hi#sSiBRa?A zlxWbjW#B7OTCVa|IsU)NBJJ|`hy87$zp&gev)c_&ty#jZ0`E`n} z^fz_o!ZPJZ=}Rnri}qGq7HE%(rYQzOi-_Ay1KmMP0QBfGUoq21ds$$n&nwsc38JC} zK9XZEqd-+XEUEd5hz%vg6mKvw9=dx6PbC)IBx$^lNv(nrD!<=lF@@R{3n;O~i^&@} zvDq0cF=}zcQ^2Yk5B^uK_8;}Pfp`AXsUPE6MK?|Tuq4CA2 zgr?7``DUniIqpXlp)rW+2=DPX!qmaPQepvDv=~Yu5a!MPHuTdZ4I_0QP85#6inM*8 zXIV-?&twRd+HSFH*@_VfjXxa{r9YX|wdM<&Ji|rM0x)rSA=jN0qK9dKB@LCpPP$7J zSa2n;5r_!4{PYeIQ~jfri&&`nFuLX1XzDWt~GWZ*9SgV%=Hp#1giJB39 zuyil5VM$8L*dEq#JS=TBX?bj-8rvjA0-wvV*HM)>#kxnW_>C6Wz2xewy&;+~mhbgr zor5Hn*Ba|7Ux7uryXs@UH5J9w!67wd4e~6snc)*>v{?s`Lz|Ic*|b@#yIfv%KUyff ziSLC*NslIfVF(^%I{XOU9&f@{E_D^!sjb8c$WJ=SlF$IEgr#&#tb4?AZ&PSV{Vlmdcv5Ll`!fIm?Ux=cpvwGnA z(fB6p3DygHT<9BMiC@lG;);wVCe=@Ho9bUOOfZX3*qD`_53<)UkZAL-$zJb(`4uJ` zrkhqA?}F2e%^=)S%U)A$!(MCpM&Aoy8QMVob^YLY#$r2KkzSn;g_NCFS@?$Kv1*W94 z>IADlD%U>*Nnns=7CY;%-bLCbs9{wVk*z2u;V_gnyXY^f3A*PRv_Qjoy;|-@-*W(BGxS|GutTo9m)w!SK{@sV6e{IMFaVak)(7_= zyskk_z^40VBKooyzpa{dv{Ih^UZwogb`J{MD&@ud6+G>tr|m|q+090kMTq-|x3f0^ zuoXW9g%-D=`trMhc6r3DCJUcVOdsY+M2F>pFF7pM?ZIA==lft(iMd<6*u4MG59hL+R@D1MEsMK^=4=Cq2y@u+# z_9)$fbiB2Q;5Z0P`xqn*PTPMA|19i3O}74g7VFQIpBg4+=r|&4N0uC=MdyL9R{m|i z+I^O<_A#2mSGyzQtK}$SN0Rl}f)PD5ZMb1S;IAprO@-vJVN*&Tn-VxJ*VPFE8i#9v z#_Ih-nHT!RfI-W6Em`P;$9@%?iwEJ=M)*5SzjhP$ACN0U39!I{>f;f_M1**8vw2pg z2uar2t1z$&4=+^+%Wv+NN!xo_(@{*;7APK5=6H)SV|@HxVKl>_Hp06j5*9hMzJHhU z8Z-`YxS;eI+_5%t$J#=CPsb6sWnpRinLWyt<*eff%j?Bz9kJrFbg}6dH^LuFdlJ)! zV@-YvckC?OF&5~m`UG(mPbAP){VKdWa>wrIM^upMng{M!X1*a;lGT<4nxdj9Hb2k+ z@%L*W2-u59XU-6;Of9vIlVc|g$LAvKhzy-6qZHz&vEf?mF5S&yMB?Ok>1zPUXXC$YPu-RCiU8|s> z;n#@8)qxjTUnvvsBY$b4lfU$DXe0ck3()O1{3XNtjUdptrWswpDU;VUdYTi{eN*Ln z2`wTNT87so;_bq3DuLhR4`H{AV3DB@;59TG{u8##vf)3S`lkN`?3jx_aQM>Cp|B>S454Z^iuQ0TMrwND_alLK<+>Vb2E?7XYx+vx4C1-DJ8o+YdH}{0FNQq| z78&KG#px>z{i5mjV(&1c2xx-@*h9tC7J3fnHgEUHh zb}7^Wp{x)n6`-uJP!E5^*J0tmc4 zi_i;%EQ@d_5m>Hve9B@l^lq9d4-06%X>$B^P=m)ZL_2kgU8`73cuWur<#lRKC7wd4 zP@(AyM1_cicM9G`a$x!vBF;&?<0myeD&9|__Y?4b3cbIPUQa~(a@aAQxS}Fg0b0Qs z6>-%(SS!5Lh=itt2#cOXqdamGJ>oGX{2dDmsYz?nqyk_0MVlqP&3_q0vpJZ4>DTHSe9*2xe|&c2w;pElZoml28H|KvYTU z=SE+nfmHKFG%Pied(p+@^xs+j1MIPZACzmu%$;H+Z@V!Yq5~G_uG&Mxju7(6Kt4LP z-#}h0kgFQpH!4PbQ>Y(WdbBiYNv2CpzX5R^F%IhIg3ON8-j5b|uWFA5H?f#HQ>n8l z=&U$(snMAiJuL7sVw;!P_5#oo+qCqx8UI2>OvuPd-Hum*48L||`4z!Nj`*dCpkgQi zl<38qx(B^ryz;6?PzZ7ORbp@&jflERkA=TP_$Ofmw`MrC&BiH0eIP_G8I3?hJW|CL z+AHDBkZ3FwXs1#Sn0><;Nne$jj~48|8?+lU_}{YO*8;~3{Fr9VHx*=;q~3xbB*?A= zenL8E!qZn6``|`_*Lj8o-J=O_1b9cME&@7%_YL7_Ef5o|(FCtGC-_xkf=&F*0{?{$ zGyADQx0qRDQXc}^F#nQPC+q|CuGrd?BY*tJUu%{@|5B-m{(OMMHMTYnVBfN!NiH=k zdGvf3ENuP^!@)NSBZPKSaVmgu!*t+Lb%~0_jGIS=LKLwLj+;yV+Cw?N4RbHeqzqO&x8bi))q{{X7HRK0dJ zv>u|%?g`0wKG|L+&@8WNK|#~=8<3n-n-1nqPOi!C1ZV;`>LB`#kc-MYknDwm9@{>J zKQAgMQX>UYL)@T44fM-?}ZJl=}>NRWg+#%^g7YG)EVm;C9ev?t%XS} zBtxIRiR4U6*35>$Yx-np;>3Iup|=XXmTR+m8X!C|!&(#li1D!GYN|(vB$`sk01%-Z zKTuCezLZa>Ls;>iFycB*>6@)Qp*|lS{8ltf{+7B#KcQhRBdnz5HS%Yu6UOVPM^a;V zvSgi6U4Uq}{~GuV9==Z_3qg6JkF6>4plG6IlgIF~V8n4&x|cu*E96pLIL@i(5UW54 zjc)}G(KfY0G@MR5_GP~Lq8>Twi#1-1`twmg~Ya_6;sCW+RsGL%87m>f->EpF?xD49)>RO)3&1Plg7*PjJ9qqU4+$&`&9x z8;HE1#>?;szlL7eJjQKs94O2NsLf+U`t1!mi1H@Qi!nxhqi-4@8*0E9>@I)|RFq=_ zBI2fx6B_;=_VG9PPY30O7P$ebXvAWhI!9_!Cj#g(cLI5!m4pLvr9IW}5&vLtqX?WD1FB}hR`^W=!2&urWcJ|fyfktD>| z7EvGz=VJPr8B+hpDU5<6Ec*~K>B9*bH^!Z3!9B0x2?Ej50 zKXIsiWR6fah@LHaUT}lBBEqy64Z1|Wz>MSP-(>7VdzYms zHI2xadG@G<+&JudpgF{5^mx}_As^=Raf*qa^MN%~Y^TsCcE2i5F@6A%-3UJs;e8Q) zBwd>I_Ym_$AfXo7DIqu%gseR)q$aMQJ>SdsDg1r#8KTFYlN;iK)g4{2PN{km`A$VR zItD)lW4gr^rTz7&5Z`UvU$3 z0L9g=NZ?rXf(VZ6AwBkeF>{&hS!@d&{R7qeNcrNe8CtdCgqG}N)GEj|V{2yg(NM5s z;AsfF;EO?vAgTrJH2zodhDK^MwfeRa#0{{uFs*6~hc2**j3U2@BQdIe4}{B-G#b7K z8tzNTA(rs~uwY2D9KT4|Y^X{s88cD?rijcK#cF_|OpP5U-!i{^g7IhFT8(N?PF8GZ zd@CGvI0Q4NdNA$lLX$iSZw{Bf7o9;<23sJ<-$3U|VAGQmVd1spMR({G_k~LLYSLa+ zuXqB{PJ}h5PZ%z*8-ddz7vp3`jv|iNDIFgv(xy=01G(-^^afu5LCrnYdywQ1Lm^?+ zUw3&db)V(b-<&%w@OAY*$7v%~KnyctnosnIqil%SP2l5uCnU69H;#M71qUdmRKE`j z06T6nZDq!sVbg&eE*_cw-$b9rAB2?fFDO3%D+q;sfFd274O1K-qvr(vMT6r`+}Z(c8$dY^8K~lOlDWX}{8aid?q5 zRs~t86{FK*AiorgRAOD8aAMhI{c6*31YnV&LjLR{%7?cgiE+B>4>)FcU9%TAog!Upsbqr?+25>I*6pnUS{ig24E`yIhMzHv(aMp}qdTI_NGqb-O=#RneN(ldEI-NP$M(d@Flw~>2S- zRDA+G0dg=5hvO%}@VO!{8cBcd^a|rEm#!4fo?N=dHygtevt{PXw-{5$-99q7@$b;c zh?2`uP@q2LRoj43j*msVtjRVTL1&7}CyAY;PCu8IyM1scvFB^l^yg@O%jZJ;8;j+0 zgD14W-s%&=|D&aKd@VMq5vkVCvH#8X)_ z`l_4U&yJ(9Pb5nCVHP6#OdnDXd*!-|u^3=SqdqziG};%@eK&|ygamkIE;0f4G*-7r zdw$qeyw{wIJ%9-&nS-V9xZ#6X5qKPqiGwWowb}SP&NxHoTjv#GI7q!}7`l|>Kf+(Z zBN`Utg?p``)l(i@H~}zi;_MC>Lb{6yl@{S&6KjmKLbQ|-e!wFPd_;fNSn}KCx*uVZ zm<}J>8lG0V4I5ebV8#)H^jPY<*i5X)%la`mRV4GZJZyLAd;!Dx0xW%;mZ3uiyP)Vq zzv8HH>RF5u5ss}B6hiFe}?{u9?#UIdwWD5pFpMI_${aN2tUrD$Vm{c z_oRgT!Z1|B7zMlPRYWy3eWDc)|AWkaCs~!UL7)~o(Wgp*4bA0Cc3ED_vc)P3iW2bl{HAs&3SmyRg)Dy7Wfd#i)IzJK$sVtJF@%?%VJmtB@?(OZDHGn6@ox)!${58wqbrN{|DZ< zm(y80aoq6I)jS26soi3nHykh5enOcI1^En|H>7Qe*nw2H8Mza&P3*dO7Yzd&#?*fb zt=Z1>XIw!D8l4CB_XiVYkVAJ%kj`c=?L*qB`qR{tsEP9?jjO5uW$1sGaolmWJ%1BD z$0Z!h5NyH`d-vN|lCm$yNa_A+Co*G4;h|-65vkK+BVCBFTsy06CQ=|lp+tFxj1Uik zj`r%V)LJwY;esNOfS zCQ>9*Qwlj65D=vM#p-BdrNRL%XVOXJugMlaET)|w_~tCDfzPV#vkWm15`YN67%?n} z3qO!LfF6x4Po8jVtg`}EnisG8Q^)XE?5M!=DxH-!p(O~QzSH#rYvrKxBCtn$MHm1F z8fp7Kn=BHt8j$t@F@UY8WW)fjA8>et;5OO&?zuwt2&GN-$bOOMiVYfTI^s5T8syq5 z9AYHz4G5Vsa@^v_C{kgZ3G~YGPCQN4uRWgy(sGOvB9tUAqo9~4>^~~b7mypl_iBhD z1k)4E^`zhBh7QKL$z3&PWjRh=An6>Gf8L^!Zs$MrATsM!_|&f`B^UbwQXh=txL6v6 z2!Bg%z*c#&#P`NNk{i3+azlFsu$%!FO&@=u7Wh)GqxczOY*$1Au;bVi%XO6LiUeR* z50XYeCg{lf7eokLr0N*wiIJP9erl-Gp z1WHv$(i`C6$*BV*w6W&%Q~!tpjt~g%hGr{Bd{?dPCXJBd7EK?ySt-7T+B5=ZHFFUK z@s?ryriVuI5fr9xe*vK2L^<-LaghN8o3LkW!-o?sao@ku6Vum-K&-!U!+G?`_YkBJ z#mV~U-{IyW_lNJ<0O_P+E3%bjdaWZ6AF4P7fgVkBM<;?saKP~6vEMX&9T6d*Q$I$8 z;54v_2*FV*U|1eMj&~qpOXp7vr2ykcg1R39g&i_FPziVQ6x~l2X^&4EB)RTo*yLL(5>+Qd z$$Q*vZX3d76r+~Hfm3o^#Y-iCk6}0p;lO)x{jaG&VUDj+z#%Bi0crBrVM<&Z=uhGj zsJ1d-X~Y9oPe9>C3QvbPM0hu)I8t{*@HG7;Un9D~3G*`9(*hgy{fW-uWLZ_KeP#G7MYp8%rr1ubVdZV_crUs#B zH)Jy#A4$R~YVtDq4=p(K^&RB-Szu@Nr>g!W+!!PcX=xg}L)w#5G(v2-&O$cG#FhDv zn)*aZj!^aJb@0pCt$pbA(PCp=i0>J$>j$JIQ~=QzFCR-WX$R?-#BioBI0s)R?5Tc( z(!=Woy%-ZMxupo8jkt_S-Q>tiUF1d2#^C_bHAG$G-LOSMw#iL{K=&X9id;o6Yf2Td zyc0N17(^mAHsWrETtV>21-r?f{TE8h!&V%&~cRu%wR;q9W%lc`5x z1sHE4(xx#f1(Qd``HY)kos2po76dbGERPn^stn8whGLRxzy%Y$QAk{-jwvao%1CwN zC~+8PjO+h`7PN(VA9t~i{*1x~2(;@>`eUt|VB+S1Ydh71EvUaObq{XT{&`fkEk7(J zmpE#cT80Xg*m*?}$7${cJ8zAreE3aRK`k}x+MV`7{(=Wq=tK*3N zqg;H+0~G+B#9%inMxlWG8GL+T2$g=ADi$>O`^6G&$;ll^Vl3`^3y7rDg@T0r(E}Fb z8&!pJISvO4l;Yeq3aP#LW3Cg@#ZYz|YJd#~X%JS93w4dcO7oz_9+cOJb0SQC-q(mh z0`R=ZmZ9*H$djS)s;>r|L1C?LH3~wje~3pMF2y5-^Qj}+dA3^};w`d(Myr*=CeVho z6R+`RjjtUv$)(TxP8fjaeVqURuUz_)&o!Jxk4Sq-96^ywU-fwb0{|%m(cxNOu>n{s za)m@e5CEcp20>l5i#rgDJ1~hm5MT+(rD!Ma8+~PHhm^xc-)O>oF79~I^_|VoEJi|M zG>UIh^j`?2C}j@G@J)uKazjz7lox73R zl)KggP7g~(b2?rxns=h`jfi@SK?g+?sfiIP6MI*}1U3qA8O)~~50Pqv6=&F!mQ$Ii z`>rT}x~oxuny2Gl*hkR(>;SZiJr^ zhCb4@U<<}#dw#WrB0=y*k!}^_i7vDD0=vv*VJt4QXnSLvA-#84A9UrA`KrZq$M=7P|PEH@*P0N+O1YLh6 z8l+{xe})Ny*Qk__GNN2<%sUyFCvlLt0We?*>e;hnTlQZy6KZVyuI{9bo#9%Lh!%QV_^4_ z;n=5ABsl_6=tt3+bP7i`gYtCGt#h_k$aW@WSu@}A z8FEQ3&0wI|QZx#Oc%YdvyyE{KX2jUm{r;5wbSj1`_$5xKiX-MB@~gqq859`-cdeN= zgn%W>%`riY%o53)4Q$vhrcb{Vh8n?o%kL3x4((hG=LZY%LZL6PG`C_d;PmY8rVont zn@4~fmQ(0i(z)q)Av{lif{n3v?j< ztWWILkVlAr4;?Yyl75j!==HbZSVJKW1VZ2-QzT7PE)GGO)?<2Isg2m^hWKHmH)hjO zUcK-DNhO$ezF-*6i^rTL>R+C=Z%|jgVeS?bo1bj<7c{sk8bvW-`CiX$59Hy24 z5pg2*Bs@8|w&DY=i%AQgmh{6(5CKf6hy_D)G&%22suV@;tZj|Ar|U1^)jj%c3Y!O z(c2=0491CCf`#ODN&8X{A@D8UH;d&$C-KeWJ_D+1Qcr4^_y`lI22`y!L9Wx-tB&DuLMautRWzT@2jd};GI(ma| zFR}GHgLCGo9HYLKuRxgNCi=En(;v#iKOCt2>}3QLNo&leI8ib2ay~I{2I548X69mz z?>SWR?}`Kt%XQDfMun1#h9z&38)muh(67A~0ibdq!ogfu^mb$hqTkPK3v1}3-Cgh#YR=-g@jsI1Kng>g+J03$A+ADfE7EumoJ@l^ zdKjB#d`tceY9#SJq#hp5-3S(9&k!Ma72xu^YB%LhB7xm<-5f%N^+&eX4A@&6RXF>1 z!7@km2|1$eji?G8a(zUvK-)gK?kdq1M;W2gGHpK;n_RS=hqkId$)Kkf4`@3gqCeyT zG5IJ@%0U4iMSy?r<83%O$sLh4i|4oSOk9};BUua?6`mMPgCS7^aw?|(g&36J0GMdH zAFVjuKuAhlX87Vo!dfr#@j*GhhWdm)YRvizz3MGM^>^JaM+>t>$He)aTPw?Zj7+5cXUo7fi*HeVw z+?I)ckifK7E)_~JlP(Iv;Op4*Wz;|Nd6b?BeRqU$0!+=@!eU>GZymenyK2fGq96FiVa<1F2@MZXb0;?PnvCf$wp#8osEyICULX2K9@`KBDT) z6fnTFMvIi13SWOTg-S~x01f#*Q9;^xKaH<=B%B+>w=np} zMmT73X<(ncijEuz16#VCn9?PM#&)S4N2L=OC-&#fHN83V)0d;y2ZxOjz=83ZNU$R;2vngk=BF&?KY~W zPQuaA+1KK*TgTy=-b)^P&72~H9!3P?{n6i2L<&L2RsTwo(_>72#{hY2Nxew^5|&>P z5{YDGFjG(-nzWmYk1<&^Pq5qsMwk^I;&|lGXcg4=B2q!dZMMd@VrEivKzl~N#LnWt z_A@}Q@a=qGy69W^%eUj>w$x127R@?=n7@ryS7i0$-)PT!Qoltjtn9Oa4_7=+|H1&n zc9ovB4>)xr4VS`OtzDyEgDw6SoFJeqJ{Er|O{lrj4u2;4XI-+=kQ6PS!fSEcR&4OYJSZ?(II=*5J<3{zf1a$v;-?CJ@SYMeX^$qz3n*P+UzyruP@@EgD zBr1d911>2i*F9|b2v6R~QTgW-$li0$JHPOP3n_Z`%}bJUa&l39*zn;aMwku0St|>{ zB6h(LP}Il;SHR`L53wGK^SJOyn~VO_6EX$(Uv;nt_+hW%Le|VhDU0**E5z?Y{EF}! zjbAZ-CHR%$7sPKiel_?t;z!Y^8WJa{G#7PDoe{!f{DSz^;5X^^+ixx|x%+|YN21lm z{u{>KFs|&n8>_|R^~jKx}+!WbV*CS z(xv$$JQRhaHbgI76d$L{hab^RS2fY76nJAf_ZPh2$$eZJS>O#7c*4XJhTjbQ=%Pc9 zt_cO+RXKMQ6g``JS3$AvW(6fHhbaYRPYq`U<*^Zy3fkQ{TSpd@1Eds`OeiRxP*8*> z6AC;NM`>vO5+TAhiux3|P~q9!FyWeB;%wkW|v3iHC*e;&_%8{kP+t zRM420`;glaomdMGn)ogwrSP}#tsb3omjk+KX#PhN*E=MfSzHrIUc~%{XuQ^ z5BPbYbT+L8Ttc7Vz5&0X`fUW9>i?097cQYMaNmyKQ1y2KPW4ZiFNHn;>;n_tPDT!w zSlhUNiXYW?T}e=vORQ1cd+;Op>T3z=a)~vDJLzA77vCVjF0ocnybSQ6=()zM9}FAy z#d<*THi!DIM<1Ov=aD7j=DHrMdN?|7*8B&nW<7en>ybrO3+F6&_=$P5Dy!!G)b&91 z!wVjq_29g@W@+9db6r*Q<~(RtAGdf;RdigL3w7ts!n*;_a~3QxTTyA@f>{sDSu)SH zsB+f4rO~Q61TYG-W-W=%nfv#%=Fb27S(S4hUf`OG`itheKnL9jH;A1>_!m7m&$V#g z!nund7ZA{8LYB;n+UktAy*0{4+gWp?OKq<*kLKGY^L|>5;=CoUS+k5@h$ef3Yz=U4 z?xMwy&ssPqI(I&C{HNx+rDaNf4|%F|wVCU7Fx+Dv2)P~ny3+2HnZ{j2Hs5S=927XEQpW$B@*w&4HE0sgTKZl~w`tFw6Q zd@FW<-(-W^={fnGEFL@l9tXI$Wa#=u4)9_Jc!>l2dI$K;4sg{5xAT9l4Q?OTLI-%Y z4Q}V>uWfMqe66>^?e+E2q51O*2l($C;D2_2w>rSzc7X43fPd%!zv!Bw>A%MT{$mID zN(cBF2l&4^z+Z8IH{0NL{?Glpq3Lh2!R_<7!v?p@$$kg;DF^uF*ACt9)ei6l4)Em; z@E5Mj;OL3%B#3xol|oyAJRJ4)9ML;4fc4H2&8e;F}%b zDF^r|2lyrCK9lsbU2pum4Q}W2pB>=89-pP3VuhAIzxjJv_<1&X$N|392DkS+{>CgG zJ3Qn7pY8zvlL^lOI&%GH8fabLqW~tZ!S**5$inUGC659zxCYzb^Bv%qIl#Z;0QWn< zZ*hP#2l(9%@L3M4Vg79c`D4k|oI&u>Mm5*D!J+BA+yQ>I1N;UD_$?0bX%6sv z9pDc-z#nmdFLi*|Ilxyrz@K-3|Hc9Sdk1*01Kh2+#5H*Rp6dX=)B%2-4Q`i*eG{_y z$%VJp%kbN?@bhi(fDKMEV%48zgWL7bGY;@SJHX#_fR7Dj>9MbuIS%l}4)7-&;Bg1| zvkvg*9N;fH!2e`}+wIruHn@FUTO8nB4)9YB@LmVFJ3KT$FL!`n?EwF?4Q`jKf{9uD zb~*XN2DjIjCS~i};a&%LpABy3+kVx+W9ffOkDVF>pJ`Ncl~2z0dpU}hJU?ZF+wre< zfdA3~o_j|Yza7sx4)BW{;QwgCt#Mg&eqyU{Uw5BqL-%{!0p8;P|CdM>4}~JEe*a*D z+sE~`4NhBstNuP4++P192l!D3_!$SdcS@E{`}!K|$-?dZ-sb=>HmV~RMfs@gWx9=7 zxMaMudt^~`-Z-3{xK8A4 z%;$$5sUEkuYSH3(Rnf=MhA_>Wk0jEZh4T!;{~!Mrqdl>B_#iw%^SRKJPwTbUDwuc5 zQ@ZgBn$Om4?+=Yqi5XuTg-7bg6kl-`f@)lC!cDdkNLYpapb`5S%QaIH7yA~OZYD|J@{`2s& z+LMl@YpA{n{=!}K7iauU!tzm;@f+Npa1Ne(fLw`t=&yM$$S8`xgZW1`d#Ls`i;YH6 KTU#m)ZvQ{Q9*~6q diff --git a/src/vv_decoder.o b/src/vv_decoder.o deleted file mode 100644 index 48a878ac99fc075ee5f21ee659ed9e5d11cdccf3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7072 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 diff --git a/src/vv_encoder.o b/src/vv_encoder.o deleted file mode 100644 index ab5ef4781f7171237f75dc8978b866c261927a07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9624 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 diff --git a/src/zupt_cpuid.o b/src/zupt_cpuid.o deleted file mode 100644 index 20f66ac9541f3485ff6d123fb7942974250245fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1416 zcmbtT&ubG=5S~qAv$ipt_yd%d8ZTDCK9aVIc#uF7*F*836a?2PERrLlF-x9@Lr5d&zT&CkJNdn{VcO@9oap7rE7YAx#5m z8r+3ZCRu>jp%KpbFauGTh9Ab<&s^HuFpj)OS=Z~CaVloru91ison5cB<$lC$kJdCg z?tb^=QoFCY5qJOagn+3Ncg~0L<1Ti^`Gr?sFzWmaEu$UWKR$Rr$*;D5O}1wDB3Ma( zGCFU}@UF+B?XO85>6uYl{>ca9GW5(aVQN15c8JJaS-F$Eww8A)+)1XF*b+-E+;aSM zv9-9&Qp+rTT@6ems2r4J5BjNj1C)y@4v^DC&o-7hK*+x-rozkIrPNvl%sRPj#K07g_^TfWQ9Re zw7FgIxnU6?iFz^`vodM`*4Qp{E02-a2eBj(x0@VT(c%`ce4_!ZP%W433UZYyw;6uE zg$B0@&qTgiaagTht=V6$<+u!=X9y6$>Z#fxQB_neAon+a+rZT~J z1)cPA&a(7bf$AvzLST%ZA)t+KPtwDWC=x?jdh=cma$kBh6L03%|3tklDX^eDE ysh9k?y-89M`!^{;n?k1<1@*LUaCS&RU+8JRstI~XB@m6%C&l?Uhn)iu)c*l-C6FQj diff --git a/src/zupt_crypto.o b/src/zupt_crypto.o deleted file mode 100644 index 7eae40c8313d20caa4cc08842c302a65b1f4f335..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13912 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 hdr.global_flags |= ZUPT_FLAG_ENCRYPTED; if (opts->threads > 1) hdr.global_flags |= ZUPT_FLAG_MULTITHREADED; hdr.creation_time = (uint64_t)time(NULL) * 1000000000ULL; @@ -234,67 +234,12 @@ zupt_error_t zupt_disk_backup(const char *output_path, const char *source_path, if (fwrite(&hdr, sizeof(hdr), 1, out) != 1) write_err = 1; /* ─── Encryption header ─── */ + /* ─── Encryption header (uses same code as zupt compress) ─── */ if (opts->encrypt) { - hdr.encryption_header_off = (uint64_t)ftello(out); - - if (opts->pq_mode) { - uint8_t enc_hdr_buf[1200]; - size_t enc_hdr_len = 0; - fprintf(stderr, " Post-quantum key encapsulation (ML-KEM-768 + X25519)...\n"); - if (zupt_hybrid_encrypt_init(&opts->keyring, opts->keyfile, - enc_hdr_buf, &enc_hdr_len) != 0) { - fprintf(stderr, "Error: PQ hybrid key encapsulation failed.\n"); - fclose(src_f); fclose(out); - return ZUPT_ERR_AUTH_FAIL; - } - - /* Write encryption block */ - uint8_t bm0 = 0xBB, bm1 = 0x01, bt = ZUPT_BLOCK_ENC_HEADER; - fwrite(&bm0, 1, 1, out); fwrite(&bm1, 1, 1, out); fwrite(&bt, 1, 1, out); - uint8_t cs[2] = {0, 0}; fwrite(cs, 1, 2, out); fwrite(cs, 1, 2, out); - zupt_write_varint(out, enc_hdr_len); - zupt_write_varint(out, enc_hdr_len); - uint64_t ck = zupt_xxh64(enc_hdr_buf, enc_hdr_len, 0); - uint8_t ck8[8]; for (int i = 0; i < 8; i++) ck8[i] = (uint8_t)(ck >> (i*8)); - fwrite(ck8, 1, 8, out); - fwrite(enc_hdr_buf, 1, enc_hdr_len, out); - - hdr.global_flags |= ZUPT_FLAG_PQ_HYBRID; - fseeko(out, 0, SEEK_SET); - fwrite(&hdr, sizeof(hdr), 1, out); - fseeko(out, 0, SEEK_END); - - fprintf(stderr, " Encryption: PQ Hybrid (ML-KEM-768 + X25519)\n\n"); - } else { - uint8_t salt[ZUPT_SALT_SIZE], nonce[ZUPT_NONCE_SIZE]; - zupt_random_bytes(salt, ZUPT_SALT_SIZE); - zupt_random_bytes(nonce, ZUPT_NONCE_SIZE); - - fprintf(stderr, " Deriving encryption key (PBKDF2-SHA256, %d iterations)...\n", - ZUPT_KDF_ITERATIONS); - zupt_derive_keys(&opts->keyring, opts->password, salt, nonce, ZUPT_KDF_ITERATIONS); - - uint8_t enc_hdr[53]; - enc_hdr[0] = 0x01; /* ZUPT_ENC_PBKDF2 */ - memcpy(enc_hdr + 1, salt, 32); - memcpy(enc_hdr + 33, nonce, 16); - uint32_t iter = ZUPT_KDF_ITERATIONS; - memcpy(enc_hdr + 49, &iter, 4); - - uint8_t bm0 = 0xBB, bm1 = 0x01, bt = ZUPT_BLOCK_ENC_HEADER; - fwrite(&bm0, 1, 1, out); fwrite(&bm1, 1, 1, out); fwrite(&bt, 1, 1, out); - uint8_t cs[2] = {0, 0}; fwrite(cs, 1, 2, out); fwrite(cs, 1, 2, out); - zupt_write_varint(out, 53); zupt_write_varint(out, 53); - uint64_t ck = zupt_xxh64(enc_hdr, 53, 0); - uint8_t ck8[8]; for (int i = 0; i < 8; i++) ck8[i] = (uint8_t)(ck >> (i*8)); - fwrite(ck8, 1, 8, out); - fwrite(enc_hdr, 1, 53, out); - - fseeko(out, 0, SEEK_SET); - fwrite(&hdr, sizeof(hdr), 1, out); - fseeko(out, 0, SEEK_END); - - fprintf(stderr, " Encryption: AES-256-CTR + HMAC-SHA256\n\n"); + zupt_error_t enc_err = write_enc_header(out, &hdr, opts); + if (enc_err != ZUPT_OK) { + fclose(src_f); fclose(out); + return enc_err; } } @@ -346,17 +291,32 @@ zupt_error_t zupt_disk_backup(const char *output_path, const char *source_path, if (csz > 0 && (size_t)csz < nread) comp_size = (size_t)csz; } else if (codec == ZUPT_CODEC_ZUPT_LZHP) { - /* LZHP with prediction */ + /* LZHP with prediction — must encode through prediction + * table before compressing, matching zupt_format.c */ float benefit = zupt_predict_benefit(rbuf, nread); if (benefit > 0.02f && nread > 256) { uint8_t pred[256]; zupt_predict_build(rbuf, nread, pred); - cbuf[0] = 0x01; - memcpy(cbuf + 1, pred, 256); - size_t plain = zupt_lzh_compress(rbuf, nread, cbuf + 257, - comp_cap - 257, opts->level); - if (plain > 0 && 257 + plain < nread) - comp_size = 257 + plain; + uint8_t *transformed = (uint8_t *)malloc(nread); + if (transformed) { + zupt_predict_encode(rbuf, transformed, nread, pred); + size_t plain = zupt_lzh_compress(transformed, nread, + cbuf + 257, + comp_cap - 257, opts->level); + free(transformed); + if (plain > 0 && 257 + plain < nread) { + cbuf[0] = 0x01; + memcpy(cbuf + 1, pred, 256); + comp_size = 257 + plain; + } else { + /* Prediction didn't help — fall back to plain LZH */ + cbuf[0] = 0x00; + plain = zupt_lzh_compress(rbuf, nread, cbuf + 1, + comp_cap - 1, opts->level); + if (plain > 0 && 1 + plain < nread) + comp_size = 1 + plain; + } + } } else { cbuf[0] = 0x00; size_t plain = zupt_lzh_compress(rbuf, nread, cbuf + 1, @@ -535,25 +495,37 @@ zupt_error_t zupt_disk_backup(const char *output_path, const char *source_path, /* ═══════════════════════════════════════════════════════════════════ * DISK RESTORE (extract archive → device/file) * - * Uses the standard zupt_extract_archive path but writes to a single - * file (the target device) instead of creating a directory tree. - * For disk images, the archive contains exactly one index entry. + * Rewritten for v2.1.3: uses the same read_block() / read_enc_header() / + * decompress_block() functions as zupt_extract_archive(). This eliminates + * the hand-rolled block parser that caused checksum mismatches due to + * encryption header format differences (52-byte vs 53-byte) and seek + * offset errors. + * + * Flow: + * 1. Read archive header → validate magic + DISK_IMAGE flag + * 2. Read encryption header (if encrypted) → derive keys using + * read_enc_header() which handles PQ, PBKDF2, and legacy formats + * 3. Read data blocks sequentially with read_block() + * 4. Decompress+decrypt+checksum each block with decompress_block() + * 5. Write decompressed data to target * ═══════════════════════════════════════════════════════════════════ */ zupt_error_t zupt_disk_restore(const char *archive_path, const char *target_path, zupt_options_t *opts) { - /* Open archive */ FILE *f = fopen(archive_path, "rb"); if (!f) { fprintf(stderr, "Error: Cannot open '%s': %s\n", archive_path, strerror(errno)); return ZUPT_ERR_IO; } - /* Read archive header */ + /* ─── Read archive header ─── */ zupt_archive_header_t hdr; - if (fread(&hdr, sizeof(hdr), 1, f) != 1) { fclose(f); return ZUPT_ERR_IO; } + if (fread(&hdr, sizeof(hdr), 1, f) != 1) { + fclose(f); + fprintf(stderr, "Error: Cannot read archive header\n"); + return ZUPT_ERR_IO; + } - /* Verify magic */ if (hdr.magic[0] != ZUPT_MAGIC_0 || hdr.magic[1] != ZUPT_MAGIC_1 || hdr.magic[2] != ZUPT_MAGIC_2 || hdr.magic[3] != ZUPT_MAGIC_3) { fclose(f); @@ -561,208 +533,153 @@ zupt_error_t zupt_disk_restore(const char *archive_path, const char *target_path return ZUPT_ERR_BAD_MAGIC; } - /* Check disk image flag */ if (!(hdr.global_flags & ZUPT_FLAG_DISK_IMAGE)) { fclose(f); fprintf(stderr, "Error: Archive is not a disk image. Use 'zupt extract' instead.\n"); return ZUPT_ERR_INVALID; } - /* Handle encryption */ + /* ─── Read encryption header (uses same code as zupt extract) ─── */ if (hdr.global_flags & ZUPT_FLAG_ENCRYPTED) { if (!opts->encrypt && opts->password[0] == '\0' && !opts->pq_mode) { fclose(f); fprintf(stderr, "Error: Archive is encrypted. Use -p or --pq to provide key.\n"); return ZUPT_ERR_AUTH_FAIL; } + opts->encrypt = 1; - /* Read encryption header block */ - fseeko(f, (int64_t)hdr.encryption_header_off, SEEK_SET); - - /* Skip block magic (2B) + type (1B) + codec (2B) + flags (2B) */ - uint8_t skip[7]; - if (fread(skip, 1, 7, f) != 7) { fclose(f); return ZUPT_ERR_CORRUPT; } - - uint64_t uncomp_sz, comp_sz; - if (zupt_read_varint(f, &uncomp_sz) < 0) { fclose(f); return ZUPT_ERR_CORRUPT; } - if (zupt_read_varint(f, &comp_sz) < 0) { fclose(f); return ZUPT_ERR_CORRUPT; } - - /* Skip checksum (8B) */ - uint8_t ck_skip[8]; - if (fread(ck_skip, 1, 8, f) != 8) { fclose(f); return ZUPT_ERR_CORRUPT; } - - uint8_t *enc_data = (uint8_t *)malloc((size_t)comp_sz); - if (!enc_data) { fclose(f); return ZUPT_ERR_NOMEM; } - if (fread(enc_data, 1, (size_t)comp_sz, f) != (size_t)comp_sz) { - free(enc_data); fclose(f); return ZUPT_ERR_CORRUPT; + zupt_error_t enc_err = read_enc_header(f, &hdr, opts); + if (enc_err != ZUPT_OK) { + fclose(f); + fprintf(stderr, "Error: Encryption header read failed (%s)\n", + zupt_strerror(enc_err)); + return enc_err; } - - if (opts->pq_mode) { - if (zupt_hybrid_decrypt_init(&opts->keyring, opts->keyfile, - enc_data, (size_t)comp_sz) != 0) { - free(enc_data); fclose(f); - fprintf(stderr, "Error: PQ decryption failed.\n"); - return ZUPT_ERR_AUTH_FAIL; - } - } else { - /* Password mode */ - if (comp_sz < 53) { free(enc_data); fclose(f); return ZUPT_ERR_CORRUPT; } - uint8_t enc_type = enc_data[0]; - if (enc_type != 0x01) { free(enc_data); fclose(f); return ZUPT_ERR_CORRUPT; } - uint8_t *salt = enc_data + 1; - uint8_t *nonce = enc_data + 33; - uint32_t iter; - memcpy(&iter, enc_data + 49, 4); - zupt_derive_keys(&opts->keyring, opts->password, salt, nonce, iter); - } - free(enc_data); } - /* Read footer to find index */ + /* ─── Read footer to get total block count ─── */ + int64_t after_enc_pos = ftello(f); /* Save position after enc header */ + fseeko(f, -(int64_t)sizeof(zupt_footer_t), SEEK_END); zupt_footer_t ft; - if (fread(&ft, sizeof(ft), 1, f) != 1) { fclose(f); return ZUPT_ERR_CORRUPT; } - if (ft.footer_magic[0] != 'Z' || ft.footer_magic[1] != 'E') { - fclose(f); return ZUPT_ERR_BAD_MAGIC; + if (fread(&ft, sizeof(ft), 1, f) != 1) { + fclose(f); + return ZUPT_ERR_CORRUPT; + } + if (ft.footer_magic[0] != 'Z' || ft.footer_magic[1] != 'E' || + ft.footer_magic[2] != 'N' || ft.footer_magic[3] != 'D') { + fclose(f); + fprintf(stderr, "Error: Invalid footer magic\n"); + return ZUPT_ERR_BAD_MAGIC; } - /* Seek to first data block (skip archive header + encryption header) */ - fseeko(f, sizeof(zupt_archive_header_t), SEEK_SET); - if (hdr.global_flags & ZUPT_FLAG_ENCRYPTED) { - /* Skip past encryption header block to reach data blocks */ - fseeko(f, (int64_t)hdr.encryption_header_off, SEEK_SET); - /* Skip the enc header block entirely */ - uint8_t skip2[7]; - if (fread(skip2, 1, 7, f) != 7) { fclose(f); return ZUPT_ERR_CORRUPT; } - uint64_t u1, u2; zupt_read_varint(f, &u1); zupt_read_varint(f, &u2); - uint8_t sk8[8]; - if (fread(sk8, 1, 8, f) != 8) { fclose(f); return ZUPT_ERR_CORRUPT; } - fseeko(f, (int64_t)u2, SEEK_CUR); - } + /* ─── Seek back to first data block ─── */ + fseeko(f, after_enc_pos, SEEK_SET); - /* Open target for writing */ + /* ─── Open target for writing ─── + * Block devices require raw POSIX I/O (open/write) because stdio + * buffering can cause misaligned or partial writes that corrupt data. + * O_SYNC ensures each write is flushed to the device before returning. + * For loop devices, this ensures data reaches the backing file. */ +#ifdef _WIN32 FILE *tgt = fopen(target_path, "wb"); if (!tgt) { - fprintf(stderr, "Error: Cannot open target '%s': %s\n", target_path, strerror(errno)); + fprintf(stderr, "Error: Cannot open target '%s': %s\n", + target_path, strerror(errno)); fclose(f); return ZUPT_ERR_IO; } +#else + struct stat tgt_st; + int tgt_fd; + int is_block_dev = 0; + + /* For block/char devices: O_WRONLY | O_SYNC (no truncate, sync writes). + * For regular files: O_WRONLY | O_CREAT | O_TRUNC. */ + if (stat(target_path, &tgt_st) == 0 && + (S_ISBLK(tgt_st.st_mode) || S_ISCHR(tgt_st.st_mode))) { + tgt_fd = open(target_path, O_WRONLY | O_SYNC); + is_block_dev = 1; + } else { + tgt_fd = open(target_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + } + if (tgt_fd < 0) { + fprintf(stderr, "Error: Cannot open target '%s': %s\n", + target_path, strerror(errno)); + fclose(f); + return ZUPT_ERR_IO; + } +#endif fprintf(stderr, " Restoring disk image to: %s\n", target_path); fprintf(stderr, " Blocks: %llu\n\n", (unsigned long long)ft.total_blocks); time_t start_time = time(NULL); uint64_t total_written = 0; + uint64_t block_seq = 0; int errors = 0; + /* ─── Read and restore blocks sequentially ─── */ for (uint64_t bi = 0; bi < ft.total_blocks; bi++) { - /* Read block header */ - uint8_t bm[2]; - if (fread(bm, 1, 2, f) != 2) { errors++; break; } - if (bm[0] != ZUPT_BLOCK_MAGIC_0 || bm[1] != ZUPT_BLOCK_MAGIC_1) { - errors++; break; - } + zupt_block_t blk; + zupt_error_t rerr = read_block(f, &blk); - uint8_t block_type; - if (fread(&block_type, 1, 1, f) != 1) { errors++; break; } - if (block_type == ZUPT_BLOCK_INDEX) break; /* reached index */ - - uint8_t c16[2], f16[2]; - if (fread(c16, 1, 2, f) != 2) { errors++; break; } - if (fread(f16, 1, 2, f) != 2) { errors++; break; } - uint16_t codec = (uint16_t)c16[0] | ((uint16_t)c16[1] << 8); - uint16_t bflags = (uint16_t)f16[0] | ((uint16_t)f16[1] << 8); - - uint64_t uncomp_size, comp_size, checksum; - if (zupt_read_varint(f, &uncomp_size) < 0) { errors++; break; } - if (zupt_read_varint(f, &comp_size) < 0) { errors++; break; } - uint8_t ck8[8]; - if (fread(ck8, 1, 8, f) != 8) { errors++; break; } - checksum = 0; - for (int i = 7; i >= 0; i--) checksum = (checksum << 8) | ck8[i]; - - /* Read payload */ - if (comp_size > ZUPT_MAX_BLOCK_SZ + 1024) { errors++; break; } - uint8_t *payload = (uint8_t *)malloc((size_t)comp_size); - if (!payload) { errors++; break; } - if (fread(payload, 1, (size_t)comp_size, f) != (size_t)comp_size) { - free(payload); errors++; break; - } - - /* Decrypt if needed */ - const uint8_t *comp_data = payload; - size_t comp_len = (size_t)comp_size; - uint8_t *dec_payload = NULL; - - if (bflags & ZUPT_BFLAG_ENCRYPTED) { - if (!opts->keyring.active) { free(payload); errors++; break; } - size_t dec_len; - dec_payload = zupt_decrypt_buffer(&opts->keyring, comp_data, comp_len, bi, &dec_len); - if (!dec_payload) { - fprintf(stderr, " Block %llu: decryption failed\n", (unsigned long long)bi); - free(payload); errors++; break; - } - comp_data = dec_payload; - comp_len = dec_len; - } - - /* Decompress */ - uint8_t *out_buf = (uint8_t *)malloc((size_t)uncomp_size); - if (!out_buf) { free(dec_payload); free(payload); errors++; break; } - - if (codec == ZUPT_CODEC_STORE) { - if (comp_len >= (size_t)uncomp_size) - memcpy(out_buf, comp_data, (size_t)uncomp_size); - else { free(out_buf); free(dec_payload); free(payload); errors++; break; } - } else if (codec == ZUPT_CODEC_VAPTVUPT) { - int64_t dsz = vvz_decompress(comp_data, comp_len, out_buf, (size_t)uncomp_size); - if (dsz < 0 || (size_t)dsz != (size_t)uncomp_size) { - free(out_buf); free(dec_payload); free(payload); errors++; break; - } - } else if (codec == ZUPT_CODEC_ZUPT_LZHP) { - if (comp_len < 1) { free(out_buf); free(dec_payload); free(payload); errors++; break; } - uint8_t pflag = comp_data[0]; - if (pflag & 0x01) { - if (comp_len < 257) { free(out_buf); free(dec_payload); free(payload); errors++; break; } - uint8_t pred[256]; memcpy(pred, comp_data + 1, 256); - uint8_t *temp = (uint8_t *)malloc((size_t)uncomp_size); - if (!temp) { free(out_buf); free(dec_payload); free(payload); errors++; break; } - size_t r = zupt_lzh_decompress(comp_data + 257, comp_len - 257, temp, (size_t)uncomp_size); - if (r == (size_t)uncomp_size) - zupt_predict_decode(temp, out_buf, (size_t)uncomp_size, pred); - else errors++; - free(temp); - } else { - size_t r = zupt_lzh_decompress(comp_data + 1, comp_len - 1, out_buf, (size_t)uncomp_size); - if (r != (size_t)uncomp_size) errors++; - } - } else if (codec == ZUPT_CODEC_ZUPT_LZH) { - size_t r = zupt_lzh_decompress(comp_data, comp_len, out_buf, (size_t)uncomp_size); - if (r != (size_t)uncomp_size) errors++; - } else if (codec == ZUPT_CODEC_ZUPT_LZ) { - size_t r = zupt_lz_decompress(comp_data, comp_len, out_buf, (size_t)uncomp_size); - if (r != (size_t)uncomp_size) errors++; - } else { + if (rerr != ZUPT_OK) { + fprintf(stderr, " Block %llu: read error (%s)\n", + (unsigned long long)bi, zupt_strerror(rerr)); errors++; + break; } - free(dec_payload); - free(payload); + /* Skip non-data blocks (index, etc.) */ + if (blk.block_type == ZUPT_BLOCK_INDEX) { + free(blk.payload); + break; /* Reached index — all data blocks done */ + } + if (blk.block_type != ZUPT_BLOCK_DATA) { + free(blk.payload); + continue; /* Skip unknown block types */ + } - if (errors) { free(out_buf); break; } + /* Decompress + decrypt + verify checksum */ + uint8_t *out_buf = NULL; + size_t out_len = 0; + zupt_error_t derr = decompress_block(&blk, &opts->keyring, + block_seq, &out_buf, &out_len); + free(blk.payload); - /* Verify checksum */ - uint64_t actual_ck = zupt_xxh64(out_buf, (size_t)uncomp_size, 0); - if (actual_ck != checksum) { - fprintf(stderr, " Block %llu: checksum mismatch\n", (unsigned long long)bi); - free(out_buf); errors++; break; + if (derr != ZUPT_OK) { + fprintf(stderr, " Block %llu: decompression/checksum failed (%s)\n", + (unsigned long long)bi, zupt_strerror(derr)); + errors++; + break; } /* Write to target */ - if (fwrite(out_buf, 1, (size_t)uncomp_size, tgt) != (size_t)uncomp_size) { - free(out_buf); errors++; break; + int write_ok = 0; +#ifdef _WIN32 + write_ok = (fwrite(out_buf, 1, out_len, tgt) == out_len); +#else + { + size_t written = 0; + while (written < out_len) { + ssize_t w = write(tgt_fd, out_buf + written, out_len - written); + if (w <= 0) break; + written += (size_t)w; + } + write_ok = (written == out_len); } - total_written += uncomp_size; +#endif + if (!write_ok) { + fprintf(stderr, " Block %llu: write error (%s)\n", + (unsigned long long)bi, strerror(errno)); + free(out_buf); + errors++; + break; + } + + total_written += out_len; + block_seq++; free(out_buf); /* Progress */ @@ -771,7 +688,19 @@ zupt_error_t zupt_disk_restore(const char *archive_path, const char *target_path } fclose(f); +#ifdef _WIN32 fclose(tgt); +#else + if (tgt_fd >= 0) { + fsync(tgt_fd); /* Flush file descriptor buffers */ + close(tgt_fd); + } + if (is_block_dev) { + sync(); /* Force kernel to flush ALL dirty pages to disk. + * Critical for loop devices: fsync on the loop fd + * may not flush the backing file's page cache. */ + } +#endif if (errors > 0) { fprintf(stderr, "\n Restore FAILED: %d error(s)\n", errors); diff --git a/src/zupt_filetype.o b/src/zupt_filetype.o deleted file mode 100644 index beb37e10c495f212cd66d81f957a83fab39d370d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3456 zcmcJSUu;ul6u`f3g%t<4RZ&Yo)|jc&xNAEWwwVQc+qJz{I;i^tq%dmNbqrazrn_CX z1!b&(xQycBi#{12ebOfh4?YZr_~IYJgPCuoex>_3NchuU>o}pjs2A5+-Hvbahm695`pJFT$>WWV z{h>h2+@&uZbLoX;w^sPprk}cL4(ba}8y!F8uIux^Mdz>of}W?A@+;AfoB4C#T{r1Q zZ~L%0oy}i7zY6V!d)V2~B}8{>m8RNV+k15f$#HN%JERS0hqc7Avtbs8J1=U4 zFgh+9&hTa5Rek<~QS7uk8-(UOXKyTKulZ*m9G=`%%-#XTHfitNl&>vZv>AmItZW7h_%Fy+@Ap4o8#09wQt^_ZPa| zf%r(<%-3JOyzPG5%z?OQ`s(%j4GXc|wf2Y+Zl90siL9=yibyc{hNr22Fh6GIJ-!|4 z4%OSdGjDZU-fwADy{)S675ab^;<{Y$;Cdr_`Z4R4ka3(ggO1HM(<5wCF5A|Pb&f@- zuOVRDtS?YlSg1XU>%*Fm;yzm&QanYwp){RY*QIz*uh*6KLfvk~Uo-cF(yl39O=$`! zo`B*GD6W9w(Ccdkl=h&-!L!V}mM?$z{SQCV6n_&qrCr>9CGzl z{cR!MNzTkY7GFEX5u6a(Yw+MW7&B~quBg{qQABO6?En?++X=CK2k};kze(IH@epy9 zIM+#(_^XnAFY!j=Tn`6`Zg_fPZDQ;mdA;cxfIVj z#$`DN+EW$hYvmrWkKy4nDI23Qlh2xo;iIEzxQo+jN^~c>W334v$hTsli0IZLMljK* z1)?E9c-@15T7ox}6};mHl1NF!d;7Ye2i4b|Xv0?^-U9DvycOQzs1^jVH-gSk!tjP- zE-hdvZKhLe>kyfACY8ZhHPB-5JfDGw_kekZjXCEJ=L>R-4#zQw#?aWF&*i-mw(Rf> z@8QJ??F-^O4s*g*gmFDw7jF81Wq_R5r`*(u>5Q2i6zYVTE6EYoa_P~e zYNn@5p$;X@q)-PZCWLBH?4zdU#?{gBRB{yfc*!U=p2?)gz-MgSOsjC0H&2+!)G_KG z8Oy8L+;}#fGpA{+^hjbjm&~NgOZqp82b?hke9!P$ep0wjnY&maiRXl|^i!Y3T^f+{ zU=w`6dH6gyFJB_g_ZIt~q;uguOBrLm;h6u_e<%3jn6m$8G!g%PfQi*SBw6@CskZ+Q z=n9O{IJkfORg(8_07H|9at!TgLHN5;*=V>jdK)xk-ZCjE5%T9c<7bEe6MVB{P6FaYW}xqp=Tencryption_header_off = (uint64_t)ftello(out); + + if (opts->pq_mode) { + /* ─── PQ HYBRID MODE ─── */ + hdr->global_flags |= ZUPT_FLAG_PQ_HYBRID; + + uint8_t enc_hdr_buf[1200]; + size_t enc_hdr_len = 0; + if (!opts->quiet) + fprintf(stderr, " Post-quantum key encapsulation (ML-KEM-768 + X25519)...\n"); + if (zupt_hybrid_encrypt_init(&opts->keyring, opts->keyfile, + enc_hdr_buf, &enc_hdr_len) != 0) { + fprintf(stderr, "Error: PQ hybrid key encapsulation failed.\n"); + return ZUPT_ERR_AUTH_FAIL; + } + + zupt_w8(out, ZUPT_BLOCK_MAGIC_0); zupt_w8(out, ZUPT_BLOCK_MAGIC_1); + zupt_w8(out, ZUPT_BLOCK_ENC_HEADER); + zupt_w16le(out, ZUPT_CODEC_STORE); zupt_w16le(out, 0); + zupt_write_varint(out, enc_hdr_len); + zupt_write_varint(out, enc_hdr_len); + zupt_w64le(out, zupt_xxh64(enc_hdr_buf, enc_hdr_len, 0)); + if (fwrite(enc_hdr_buf, 1, enc_hdr_len, out) != enc_hdr_len) + return ZUPT_ERR_IO; + + /* Re-write header with PQ flag */ + fseeko(out, 0, SEEK_SET); + if (fwrite(hdr, sizeof(*hdr), 1, out) != 1) return ZUPT_ERR_IO; + fseeko(out, 0, SEEK_END); + + if (!opts->quiet) + fprintf(stderr, " Encryption: PQ Hybrid (ML-KEM-768 + X25519) + AES-256-CTR + HMAC-SHA256\n\n"); + } else { + /* ─── PASSWORD MODE (PBKDF2) ─── */ + uint8_t salt[ZUPT_SALT_SIZE], nonce[ZUPT_NONCE_SIZE]; + zupt_random_bytes(salt, ZUPT_SALT_SIZE); + zupt_random_bytes(nonce, ZUPT_NONCE_SIZE); + + if (!opts->quiet) + fprintf(stderr, " Deriving encryption key (PBKDF2-SHA256, %d iterations)...\n", + ZUPT_KDF_ITERATIONS); + zupt_derive_keys(&opts->keyring, opts->password, salt, nonce, ZUPT_KDF_ITERATIONS); + + uint8_t enc_hdr[53]; + enc_hdr[0] = ZUPT_ENC_PBKDF2; + memcpy(enc_hdr + 1, salt, 32); + memcpy(enc_hdr + 33, nonce, 16); + uint32_t iter = ZUPT_KDF_ITERATIONS; + memcpy(enc_hdr + 49, &iter, 4); + + zupt_w8(out, ZUPT_BLOCK_MAGIC_0); zupt_w8(out, ZUPT_BLOCK_MAGIC_1); + zupt_w8(out, ZUPT_BLOCK_ENC_HEADER); + zupt_w16le(out, ZUPT_CODEC_STORE); zupt_w16le(out, 0); + zupt_write_varint(out, 53); zupt_write_varint(out, 53); + zupt_w64le(out, zupt_xxh64(enc_hdr, 53, 0)); + if (fwrite(enc_hdr, 1, 53, out) != 53) return ZUPT_ERR_IO; + + fseeko(out, 0, SEEK_SET); + if (fwrite(hdr, sizeof(*hdr), 1, out) != 1) return ZUPT_ERR_IO; + fseeko(out, 0, SEEK_END); + + if (!opts->quiet) + fprintf(stderr, " Encryption: AES-256-CTR + HMAC-SHA256 (Encrypt-then-MAC)\n\n"); + } + + return ZUPT_OK; +} + static void ensure_dirs(const char *path) { char tmp[ZUPT_MAX_PATH]; strncpy(tmp, path, sizeof(tmp)-1); tmp[sizeof(tmp)-1]='\0'; for (char *p=tmp+1;*p;p++) @@ -330,63 +412,8 @@ zupt_error_t zupt_compress_files(const char *output_path, if (fwrite(&hdr, sizeof(hdr), 1, out) != 1) write_err = 1; if (opts->encrypt) { - hdr.encryption_header_off = safe_ftello(out); - - if (opts->pq_mode) { - /* ─── PQ HYBRID MODE ─── */ - if (hdr.global_flags & ZUPT_FLAG_PQ_HYBRID) {} /* already set */ - hdr.global_flags |= ZUPT_FLAG_PQ_HYBRID; - - uint8_t enc_hdr_buf[1200]; /* enc_type(1) + ct(1088) + eph_pk(32) + nonce(16) = 1137 */ - size_t enc_hdr_len = 0; - if (!opts->quiet) fprintf(stderr, " Post-quantum key encapsulation (ML-KEM-768 + X25519)...\n"); - if (zupt_hybrid_encrypt_init(&opts->keyring, opts->keyfile, enc_hdr_buf, &enc_hdr_len) != 0) { - fprintf(stderr, "Error: PQ hybrid key encapsulation failed.\n"); - fclose(out); return ZUPT_ERR_AUTH_FAIL; - } - - w8(out, ZUPT_BLOCK_MAGIC_0); w8(out, ZUPT_BLOCK_MAGIC_1); - w8(out, ZUPT_BLOCK_ENC_HEADER); - w16le(out, ZUPT_CODEC_STORE); w16le(out, 0); - zupt_write_varint(out, enc_hdr_len); zupt_write_varint(out, enc_hdr_len); - w64le(out, zupt_xxh64(enc_hdr_buf, enc_hdr_len, 0)); - if (fwrite(enc_hdr_buf, 1, enc_hdr_len, out) != enc_hdr_len) write_err = 1; - - fseeko(out, 0, SEEK_SET); - if (fwrite(&hdr, sizeof(hdr), 1, out) != 1) write_err = 1; - fseeko(out, 0, SEEK_END); - - if (!opts->quiet) fprintf(stderr, " Encryption: PQ Hybrid (ML-KEM-768 + X25519) + AES-256-CTR + HMAC-SHA256\n\n"); - } else { - /* ─── PASSWORD MODE (PBKDF2, unchanged from v0.5.1) ─── */ - uint8_t salt[ZUPT_SALT_SIZE], nonce[ZUPT_NONCE_SIZE]; - zupt_random_bytes(salt, ZUPT_SALT_SIZE); - zupt_random_bytes(nonce, ZUPT_NONCE_SIZE); - - if (!opts->quiet) fprintf(stderr, " Deriving encryption key (PBKDF2-SHA256, %d iterations)...\n", ZUPT_KDF_ITERATIONS); - zupt_derive_keys(&opts->keyring, opts->password, salt, nonce, ZUPT_KDF_ITERATIONS); - - /* enc_type prefix for backward compat detection */ - uint8_t enc_hdr[53]; /* enc_type(1) + salt(32) + nonce(16) + iter(4) */ - enc_hdr[0] = ZUPT_ENC_PBKDF2; - memcpy(enc_hdr + 1, salt, 32); - memcpy(enc_hdr + 33, nonce, 16); - uint32_t iter = ZUPT_KDF_ITERATIONS; - memcpy(enc_hdr + 49, &iter, 4); - - w8(out, ZUPT_BLOCK_MAGIC_0); w8(out, ZUPT_BLOCK_MAGIC_1); - w8(out, ZUPT_BLOCK_ENC_HEADER); - w16le(out, ZUPT_CODEC_STORE); w16le(out, 0); - zupt_write_varint(out, 53); zupt_write_varint(out, 53); - w64le(out, zupt_xxh64(enc_hdr, 53, 0)); - if (fwrite(enc_hdr, 1, 53, out) != 53) write_err = 1; - - fseeko(out, 0, SEEK_SET); - if (fwrite(&hdr, sizeof(hdr), 1, out) != 1) write_err = 1; - fseeko(out, 0, SEEK_END); - - if (!opts->quiet) fprintf(stderr, " Encryption: AES-256-CTR + HMAC-SHA256 (Encrypt-then-MAC)\n\n"); - } + zupt_error_t enc_err = write_enc_header(out, &hdr, opts); + if (enc_err != ZUPT_OK) { fclose(out); return enc_err; } } zupt_index_entry_t *index = (zupt_index_entry_t*)calloc((size_t)num_files, sizeof(zupt_index_entry_t)); @@ -774,25 +801,8 @@ zupt_error_t zupt_compress_solid(const char *output_path, if (fwrite(&hdr, sizeof(hdr), 1, out) != 1) write_err = 1; if (opts->encrypt) { - hdr.encryption_header_off = safe_ftello(out); - uint8_t salt[ZUPT_SALT_SIZE], nonce[ZUPT_NONCE_SIZE]; - zupt_random_bytes(salt, ZUPT_SALT_SIZE); - zupt_random_bytes(nonce, ZUPT_NONCE_SIZE); - if (!opts->quiet) fprintf(stderr, " Deriving encryption key...\n"); - zupt_derive_keys(&opts->keyring, opts->password, salt, nonce, ZUPT_KDF_ITERATIONS); - uint8_t enc_hdr[52]; - memcpy(enc_hdr, salt, 32); memcpy(enc_hdr+32, nonce, 16); - uint32_t iter = ZUPT_KDF_ITERATIONS; memcpy(enc_hdr+48, &iter, 4); - w8(out, ZUPT_BLOCK_MAGIC_0); w8(out, ZUPT_BLOCK_MAGIC_1); - w8(out, ZUPT_BLOCK_ENC_HEADER); - w16le(out, ZUPT_CODEC_STORE); w16le(out, 0); - zupt_write_varint(out, 52); zupt_write_varint(out, 52); - w64le(out, zupt_xxh64(enc_hdr, 52, 0)); - if (fwrite(enc_hdr, 1, 52, out) != 52) write_err = 1; - fseeko(out, 0, SEEK_SET); - if (fwrite(&hdr, sizeof(hdr), 1, out) != 1) write_err = 1; - fseeko(out, 0, SEEK_END); - if (!opts->quiet) fprintf(stderr, " Encryption: AES-256-CTR + HMAC-SHA256 (Encrypt-then-MAC)\n\n"); + zupt_error_t enc_err = write_enc_header(out, &hdr, opts); + if (enc_err != ZUPT_OK) { fclose(out); return enc_err; } } zupt_index_entry_t *index = (zupt_index_entry_t*)calloc((size_t)num_files, sizeof(zupt_index_entry_t)); @@ -1036,7 +1046,7 @@ static zupt_error_t read_footer(FILE *f, zupt_footer_t *ft) { return ZUPT_OK; } -static zupt_error_t read_block(FILE *f, zupt_block_t *b) { +zupt_error_t read_block(FILE *f, zupt_block_t *b) { uint8_t m[2]; if (fread(m,1,2,f)!=2) return ZUPT_ERR_IO; if (m[0]!=ZUPT_BLOCK_MAGIC_0||m[1]!=ZUPT_BLOCK_MAGIC_1) return ZUPT_ERR_CORRUPT; @@ -1058,7 +1068,7 @@ static zupt_error_t read_block(FILE *f, zupt_block_t *b) { return ZUPT_OK; } -static zupt_error_t decompress_block(const zupt_block_t *b, const zupt_keyring_t *kr, +zupt_error_t decompress_block(const zupt_block_t *b, const zupt_keyring_t *kr, uint64_t block_seq, uint8_t **out, size_t *olen) { const uint8_t *comp_data = b->payload; size_t comp_len = (size_t)b->compressed_size; @@ -1147,7 +1157,7 @@ done: return ZUPT_OK; } -static zupt_error_t read_enc_header(FILE *f, zupt_archive_header_t *hdr, zupt_options_t *opts) { +zupt_error_t read_enc_header(FILE *f, zupt_archive_header_t *hdr, zupt_options_t *opts) { if (!(hdr->global_flags & ZUPT_FLAG_ENCRYPTED)) return ZUPT_OK; fseeko(f, (int64_t)hdr->encryption_header_off, SEEK_SET); diff --git a/src/zupt_format.o b/src/zupt_format.o deleted file mode 100644 index ee81b98340b146f579fbf7c574d0b94648796217..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61928 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 R7k`EM|1kLG+DA73zW{zuiBSLm diff --git a/src/zupt_lzh.o b/src/zupt_lzh.o deleted file mode 100644 index cfe6abd49bdcd4cdb8ae5b9b2b3b2d11602f0e8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15264 zcmbt)4SZBZw&%T_1{#RDEk?;Oafr`$NEBmQGm@6z%MG_lwcaQWFzAQ|Y{HL)cLBqdBU&Ha>%k|7g@Sp8h*2(l2lYN+^!PMDk)F8Op4!K z#QWHR&*lAW?CJu3cTwcbm?v)9Rj*8ricu_ncL9q}WJZI`_-c1+t|MMk#M)OCxFSgx zuPKW3k6Am8#cSMbdX1}b|1R|E@tOi(=i2Fdyw1hq^WEvG%4A88Pt=V&WZoW0xO9HE zTUEB^Pr!V3;FG}EeL5FY(DRD!d$+Ntq?e!2c?bHp6Ep0yc+El;xGA)SA$ z^8pQ0;+4-OcMc8?27=CKeaWVSI~A;^`rcNRyWUn?=Z=zCWVh@72h;`X1L}in-LCq! z*k0wy)u1WBPqJ8_68#z4^8)-#fbZjP%<=Yk-}5HY-eLNTYMBLl_}9KJwYA*MJ9K_X zd9Gde?NcH*Vrq1+61@&J#8EEm#=UY?^9AMMSMcjrq6rX#*5#pxYJCTkNWb|yL5Uql zt47&c_#GBWIMm3l@xFt~lOF;Y>5#pBSZ{cJ@a;ROc53cHiSf6vG{YFx_w`z5bZ__* z{$=XtU?2MG%O?|qL2`|8`Un(R9bgk^;Aq(ImyYrYSZ zC#L`tkbaQ*oJe4 z)gJ|T4?m&K!_G5)ehyoAv<(z5W^w0r#b_`d^|Xq5A2WU_Ne&6Btx3|$gs`*9fgMgb z>v_XD=IaQ5S+9JRV8IiNCzTSXhsnp463yeLpCbAxi|q|fGUqE>-O-+qGveGN1B1+b zo#CT28yb*c{0kag#f*?gqtSd}ZoCp#lB^k#@P(_ctYK;C+^|Rl7{`M-!nW6efYE-`l6f7euR!xLBm0$Y z@A0|ODsPW%AAG;Y4;|>|@09G19G0>72M&+z^bLf+(D(_Br}KnBlkjbW*_FhLl(k>; z1NZ@f8=tz)Pe!%}l87BsT1g@-xQFqBaotnF z_}8qYgBgv3%=fwy*^ExVx6g0P8)PMCy?tGp=P<45=cm#Yf*)@WEP$Opp~k1S5xPpu zP<2k5i9+%&DI^+)Uqk)p$wQ*0S?pq>-j%aZp)8jPLclz;~ zK=3O&pAV?(1_wdq+B}WF(mvquom4jdlaS^4)K-i#>GbpCVyFDRQ)|Z$i5pHQ z4$*7;B<($GKU_o(la1X6pP4Zzy*F$12d&kyG|4XH1{tXklnW9{U5Q$(WePUE(Oj5c zNVg2TfO#rE5#arB0(0P^$oX{|Yh_qQp%i^ji9HU6LT$!#gLm!7;5k94vlKQO$w!S{;tVyq<`Gn={sl;GahsJx|O@S*}6f=1>@Y{26D}~ z@08l{y2BBV2KL`yV9)NNg>xJP#B=26vyWyy9|1-0- za1v+&i)Yq;2KlSTvO#Zxq<`wRNlNT?posL3R-zg;tW8LUKLr)aQ)Pgq9>ov85a6$- z-iETYF@8qnz22U5wYfhmctMNjo?*cOZF=sRrrR`M;_*3paNjIn?tW!vr>`S4g9YLG z%g-<)e?N=guE)peJdg3)c!%MffV2i7RP%MN*@~HKj^y_ z8IYCe$4*HC9px{hmUN!)F$xhL-edeDq5@Mt50ZwGWZbKc!PQALnp9TAw zQF(Uyw8pmxHRY#3AO6p@c}$I5kd-IfiR56Xj{TbLH|j6wh>#V!v1V55=bwYeGJAhn-0$+or|2B{!Nal|uX6_Y7!A?GmHgAW!9g`XhQ;Se z6sQW~YdmHC_)naeo*&>7tBw3=U`dJnH*6L%BL0ES&r-;7ksRYrkIGjdtp{;BqRG7~ zpAR7vfwFv6?)39%>dSDC*rJcDdaeg*UnrCX(+WK_%f(^|#`lEA367%)tVBr^VpgqD zd4ov9qMpq_qm)EFTdX=^)%#GlnR%Ei65X^JuOb%<_`1SL-FU(Cdq8&N;RgfP^HkgKybf`WR5$3&5YSd7`wwq{KkEQ z-X1k_Mqc|vk`4SP3u?c1`s2V^(rslY2goVX8bElAuLY>HL={!w_Rill#KMK>RWy?1+vgJ7mg9! z6hjzh{J~Mx5gQDR_x5#avO})t<)rIy+8yCfQ>zE)4A)FkajJ!_!!;Bp_xHoT`2)aK z=pnNN(n5`2t04h&@p(>F-VJDh#+OLx!lC_%H#%9|hw!NJYxvK}Z51GX8r6dVBmW?| zt?q!4`-V3Cn#Q+S#OZ-f9&-gEdz@LUej6s%}J0dT5-p8wK z+H6b*+SFo!dsyg@uDv1O4pPwwk_l69hhsPC)z`}R1}I3jCv%t)t)M(A^TgRk{px%x z0MltxLf*ICLSazqq zY=KVrbYlh)Bhb?50>2m8(s2uUdw`hUf?|zff6E%mFoFV9jvPw<^b2v9YnE1 ziS7iALgviZt3>MP4X)8*p|NP0b272)?Xj3f8Yq}9QTfz1m4An@jHdZTg5!T5Z*x4? zvow=eqK`HU42Oteas;ujF4`UCCJ5lOFkB?0uGjvzc~(87yQ`TSrusnIK`E1 zvWU1XCRWRc)e4pGHvG7{>sE|k5S>G8dXEJn9XUuO1N?pR*0YIU+yY~Z!Suv>zSI#2 zrfhb>IT@YUm?2{tiYMEzg$jsEjwmSu98ywNT5gA+RApO!jqk0-WA&qCnUKR!dx$WY zZvHQ!HQT4qRJRq!#k{L9&p*99(uflp45*%0JNQqLb~d_%E&VSfX}bIw^QD_Kh;9@_ z*QBIcDs8f3di1HNyRmfs<`ktkg{e%$1w z3Mh3v3?lWo>4K1fJ)s+`;7{Jbxh#erN$qlOpbPmxmo`~wN0Oj~r$DrHBkC!F6?qdo za62jKybGtD9S9au7gUb`rva#q9Sc?KxaKhQ$+;qrRkpe7*9~~&)&HPuJ6XT(OIeOY zUnE3wePrO;)w#;H*$za@!$3iaLM{b?SGRjWNjl$@2jc1sqD+Y{qTPsBHY2}C!m$5x zvE0+xuRbxN{I@vu94Fx*xlX`~aU4#%ghBEzlMlfkGGmjc894cepqqScLGn%lLyiPp1L?bmb4=HAVgqO#?JQ6Fv_ZS7FzVr>Ieg=$M7aV9Km+q-%~^-_fQwFU|o{Ibf@;8u|GYv0vU}u)$16Zdt?osbk2r?DHi> zEFC)r&)^Pp%@Qh(#P}*4IaK~5hZ)6&T)G*@U~FV*2w~}eC8v%o77=VFuvRZ~PPr%s zWKT$4E!M8Wr5@BQwFfq7%HNwvrSPH(o!EgsT*Q)6w4^DSB$cX%qE_g^UL88x26tMI zb2U7OGY^eChquqfgA3h%bEvJAI407GypQhZ&w7uMnJ&a6oHs-N9sT9Sbjhmw&f`32 zyyQvbk}*)wDZ}+2`C()+2X(v`lcOjS=|pmN8W($H29%%_)6tiFG0s&=l#~<~bEBCt z6^Y1lBK&4S_!v`p>m!u`*$v7LT+g?we} zCc%EI8yyZM_6#~|hdXOJmO;9jf-ZwGYZ7@3AiWH-Tic5 zRDzRHFYT@Lch+kU#MKhZTE~nVHz=JqO$)1sq%v&62$xRhe^m3){J_E8z zY_EZw)Lr;#`wOX3YCOpP7Bapo{bxkRQKoE_7Tn*Onufa|ou8y_gL;)hQIIfHmWnM5 z$j8OTL1=V+L51jfgc9(Ccm)9MZmW$=p)_xcHLgJ~5%1gaj+mfCkHAAfJL&pHWWBoa ztQbt+2cTvl5x#WuFrg!7Hf|)unzC&HT_uSWJFV)$4w(I>D4j~9Jxc6R)c9nF&!6;m z2i}IyNR(D1EoslKMNEvY2eJTv6Q7;rdcW^b6F%#1>jkP8JK)`-J>lC`qiqlyA!5>Q zbnc@_1r~!nxCkhpP!;V9PX+iMd|pzXqKp5?z?3Kc1q7vjffr@li!V}~p|kazj|T_S zTPSImuf`vBmK@|Kkx`@LHtP6`@Imx-p$I7@iB^vzMxjp65q?ph{(^_3*2LgIk!~Ou z;EiNUgD4Lr8CSRF7hCgL`wL=-_|9#jd}OVS6c_yelVUh!KBYo;#I7=gt!ALHUg#L( zI}F8uTERa(h6?xjLg;Gz=dS7-$~TbnpoNp6!_c_rAgXFG9i|(%6Kg z9)_4|eV-|jn{a#2GPgwhxIRW2WO2ma;;Mt5du?D2{qNf>k zYV=7`Uen5jfepa8U{}Jp42El^k6~fmfs%wK_eT!*=cF2KJT&AQ{RwNM4lyveLIs(?Zi+>k3#@{ z@25z?Q?mfENF`S=pn}qKAoN^nDOM$bvQ2kis0ZjmY92ty$H+C>hg9TnVuw<1z)gwP zuzr8*eBTW*U38MC8#Sa8kqb^`{ce~a?vJK1ewOi50sa>L-vD3s5UPKVp6zg?lDPfc zDKZshn==QdmwQXS8tE@qHmt{(dUf5I>ttoaV`%U2V7xa$cVUP=qeY+sMBJ(&oQUto zNCqt>SJS>r@-Kc%#k0}CwViuzcO(yC&4-Ke}uWHTCfdJwLZmdh~&$e8@$j_bgQ zU|(c8THNV@OAHt_aA;+S~$K!A&dRcEN%5aYQ2|9u3=KCc>hF0jHpdMJjQlf=>J!L<&p8D{JtR0*|;k zE>@!Z2_Db)V7KwlBKWe0eqBDRmz+<2{tV`=hx0c484^S~~u5#K7q)z~O9h<&F#Ra!>NB&jtr)P)@yi z$_z@dl&41FMfZKyG_lor0}Y`pA=zyYd-xp|uk=tJ&+!HK7_v5#S@I;Jg(X9e*Tz0o zqNG3cJ=06yC&JTHn`mbzR{=Rba=|xWhIFCRLH@Y{J@|rmH8?Nhx`1B0@dEt)oRQ+|!N1;~STuTVl^Z|5fZfBCr4;3do28N-Ryi z2w3jqKYvQ!1g9t)=pR4mT3cL&4Uc!kbJvL}`!EIfOVK~lINxhZ%Wu&Tx?F2GOKN?) zm6nav#gDU+*Kt4$eLo<-1CMkID@g_96XrQ;YZ-C@IwHwct>xDTa7;R?^F66TOcduN zzK;}Le5HdijTSca8akm*dlA-e(K+sGI)z1$TDy|(zGpc!q4T7-PLIO>KpDl;0%tam!~O@NDM)TZ9}K2IZci1W*QDcZLhoMpIejnGc&-Q3lnHA7(WIuE z8FM`gK~j#e1WIdM$yyL&8BVSzmLOYnD||H(sMHKhgQF)brR=oQh0c<-1^up?mSwCiN-M;NODySNH@aI#VxWr1+p`ecqIy=I6Zh^J2VrFCWkKN$1l4T#u0#5UktCK+J`Pj3V_Qu#(I!Rgj2E z^uSCko@?-U@u+wf;aP{L9S_;|Iy^GSmw`kE5*aBQovmdEM+OTr1SA*X zfso`XJPYwO<4NG5KL|^Puw?9@3@T)4G#(colCD`~6bDKUiW6lNiZp8U7}wZwI2?>z za)56X@Qne!vC=qcJh)Q8)fLi2>ATWo>00Rq=@x0aG*g-*1*Ik_BK;R>mvlsO$T{-0 za!@`ZA8{OU9&t%EGiTmbR6OsY@XAoQ$a_oaEv02Q-WnFKH?O_9ytJ&m)LUY8fEZo>u{Ynpa$%S5%!>fC<%k zE)S+|r1>b6|4Z}o-0K~Iyn;whPMw_RR`Xoyu1<5U7sV(^`W=nK^d}uPc?Cue&~0=A z?fOw#URh*xOz*)6xmt)amv1Z&QMEe33p1-pj~;8Ju6d1@rj zIeA+gj`+AsNtBJxxoXrUd;AtX=d5*X9oR%Pkt|T&rhfyRMSF=YdXi*o$z*shYx1@i z>3MC}=e!~3J#)Q3Z}au{qpk+T@f!>90BV&0do931dxQ<3DKsLdH0P4El8k4Al;_W6sxdIQt?RVQ=CRy+V zYAV8JP=6l}jW4rM2^#>c%z`H@{)Ns1=Cj}pPBc)24x_#k584SyDGf>#j`#fJY^ zv#`JJh;a(*1YURjYISk`|aV*K85UfA8EMswT{A z*3~tI76pG+7hL+Yy81=SmP^4!%a^YTN-NB&9?T7~UiZ+d@XE!*ufbI-8XA{0HAyR$ ztZ0HHPz4(v9quPlSR?A{%uZTI2>d~(DR-)_!h@7llvn990}8<>;<4d}M}VKofKxta zk8iY6kZe4a;`CzT&m8Z^Cv7S;p7JIePc8X%lx+CC5#V(rz~8i#FdNT@Bf!sRz%%9Z z8%yuW-06Jv5)p^;$1J$*m;QGaywV&lC9>c)zgJrsC()THpIbBFnfnsRfM<^X7YlCF zS!nsE%^Bkhv4*{_p8^1iJ)ZvGTfAF_pAA1b0{ne(==?UGMj{#|TmEZCfWJ-5Tw?r@ z5#Zk?rLo3m%3G&m?ffg61uwJmtY@;|TP(QEq)q=&9%0dC!|gocg)F%H8jGRQrbkzV7Cj`D zHia6^da2!NT(W#oX=uqKA*ponqR=9#^dZE;(#BQh3u51jB`eXla#d(aDbA8Nib!j{ z|72yjlp_C<#?YgfLztEKf+6fFo9v8egqwf5dKD~CC>U;pR% z|K~doGiRT7zkBVq*Is+=z0a8(ZmkT??3a~gnIp@ZYNf9XYFT!BIz5e()2!325mun< za=P+AGXUSd9{U8FJ&{c z-g99Gm9Q2C5+7^MfI=7nz6%?pbgS9dojWtGEfTU8_Sap%+)@V2uv+961g;$1~tb$r3 zYnvi*DNO)QSn%9Zq0(;8pd)=Jk+YZ_1sRn%G&i`^25hOBuyQEpo^ zA}#fe(dKg7whFjlI9eNtL1IBH($pBT3Km!eBqiPu4cCNXB;{tSG8&CU%k4!iD_SDA zwAhi>IP|tJ856rC$K=h4*!7J~;h0??X=@1;qV4uVC8FFO6Qaw?mb&O_E?I6@&hbwV zR#xO#;Z^ZyOc z_%*OWHRn~=MWU^3vFb4)^u_o%Dk_Yxid(nT(q*V7UQ>8e493SrGz@AeR#+EXX*GuO zTWXra`7uD@9BWJ{zbzJyLP$O}g2**3p-6LKZDWgdQj?>#Rt03~4xEurgu-<&z?g#K zqL@9#SDgAPise}IYhX;Fd|h)Zsw1GE zf=dJQOe&>-J=0&swvRU31<`u$Mn_F`HC)r0SUhAG;9tG9d`)AkT~KPycEO4?3Ibm> zt(j=yLm7PHf=Y(Z(r3z4$w}r+P~q}5Rw0!yM5c91Lt|ZoJtk&P9Uls>9N*H`)MOV= zz1Ro)V^{&tm{mwtHbxJJtRN2_GW#T9aM+(aflR-kH4NSu(Rk%K#{9}qY`94w?zkLl zMR@h{Fvcv6MWktbwAF$#udTMJvCal$-x6(%$HOglJObB8HOP!MuB?fNGv;#tP>Txe zIdIZ~E5j|}DEUN-Z5l)AMe)X_#`x--nUQF7P264y9mj<1wcw!H<+ko_0vf_~D`IUJ z;fogsN+;&XVdt-0P*7Y_S}%k|)!aD?Zm_4QQOhnn)t2e{7XdcRAM?*UqPACMs;_Zd2(tNdK?~M z`b=3#2XrHaB7RPe=}vntN5L4`w4f>9)^XmRf_kT>^r1nwF)GZHqp-~ank-RWya6sM6{iyQRDx_J3fPNc zVYZ(gTnavhmYs)5Ehfuyb(nRjxS4j92r8V4&bl;L0Ab^7|C|MOxFsHqw60bnXrh*N zQ<_AiLbuT%xOCE_ae=n_`sSLJe7hxLFQ}SbVYeW7g+nZ=m2@$)y**{#wPZRy@VWW6 z9{F}&YZSg74~Oi=dOM7i(nU2!Ed^34U8ApC!_fj7)V3PuWIOm*YKdS^nWMZ`&G%5c zttD>f6+{Tr!?7r$5Qo?C`N*bs~A-|ITgBnjc|5~OIRaOL_x2i-ECMk zVp+JlkSti!+zS6pMQ0tZ3Lp7o)M+ zchW3qvdiFhFklQG8IB|Rp+D6OXw#yUo6fBdP^>jm2E|&EF1?o}^K2=FNa1}HH5a38 z8gE9klo2CvEn_n&L&|0m)XBVN&#aJ|Y)@%2qlrF`wx@@&mT#_!u1L?3XmB}V@T5t0 zUV6qDON$m222CWT5Q*@Tvw-Y~^%3?pwh49_mN|Lar?9;Vw-jLgGd73UJw~NI>mNI> zw5TY*sHn(pjO*z=hOiZEtP8iq!sYhts)e*d;(ow7Pp!<#_0kNpJqC4pVU}04YE03@ z#be#pW8=hXOzGs%1*<($W2{<~pMiNw)7-VfT%XolSw!wgJ8TyF~zi1O;9kyuR43p`i0&=!ldv*EQ(O^DB6L1~&f z@?vALFO14rlorP7(Csjum~KYjRiDwDJ>Hd+whJ#0{{^0M*fg>4^3{gcsV%0`cws}> zhNZD8sg2TZxIVJVzNxLbHD*T;q-}VX-Bhz?HO#ua5M!++OjcM~)6_-@*!K&g8bhPX zv7;PCJIzt$qx24QRQ@R5byD6sZAZ8e$AFq>BQ~q{TN~~aCe5ea1#K_hx^u(-xPPR# z-Vm1+`s(f3)5l|%CX$m2i|fmMY==~QfDir;Z$GyOJ5sfsqy|$fRl~=OvByj{wn*Jr z(bI6sK{3DS4Oca}>Qv>F@O#I!9iiPOF&vA43=_T@hmP_Yru|k-m`YlvnO;dr#U)J3 zSU05AUSUt6^4JDfYsIwcSgG==fjT!m%iHx>sH*+57OdmM%o?;Qgw3^$rDWg51_l=n z+pK6v;Ot<*tjgI1lS(IJ?pR!0QsOHkyU;oZyHn|r$Io%QIoK7>4s@4L%Yun_ zIj^(F(@}=o%^BcPnc>qi!`{sBu*~o=x-WdPCTC`5f0miOXJAGl+cU#o$j-@-e+jezLViZg*O{E@BHQkcm(hqnrl`1dMkbJAG|SD{-adKbRzpCIDYm? zkf(DxYVvnic(cl0_jH#~wOvEK{=`ecuC>Fm{p~Mh`ODt$bl;9jtLgy8cR}vZUE~OX z1c)1^7I->akefkt2sh7DqJK~AH=>({WgmQymBn5At~Ydm4pQZ;NKc=SpdK!8z8G=V4=mYB+bTaDa=LT90mR;>%eDHxl zcZYYw>1ZRD3ncag$dH`hexhI7;^Z6XbpM9+{j9dO%I*l7`$y01w?U$6+Pe_#Z~r9b z>HH(5i0A2i4axdFc(wq!=!V3nc!W}cMEAO^in0@)I}#9CRkz2*THk>1O3zdES&-Wl z?>O0T9dUYQV|?6nYR2BX7EGgc_f=G^i=MsgpcoYBT02lR^zz}LLDHT2c{(;_hDXYwXjRm%Ro0A%d!l=E9h+vDk$iw#6Y6XH5Kcpe5&T#S#bNuS?ka3%i?Ez zz8+>l>=shP)42l8J|&OU4R&E51rvuzjX)P3=LNdr-Ud&{_t3E{FtO9vEYSU&_aVq; z*w@qf2hUwS$^M_DJ1W;oK8Z^+h*e9Zaz;|Jk~&Crce0C%s0$Sm`;2ej%M_vxMpCYN zi0h|`>uYQ%J)foE&L@;Fkr~KYD!bQu5fI+=bT{J?{aunx@vfs9SEfljFtnK1kA+tz zKH-459~2IlO}pSh6L*1x=&{a1w0wt4pH%lXJd{<1>vFH^swl~(`uhbE1H1p!Dssdy=;S%wUERz{$T;UY}theJc6!2^|X(JCj!<5STXH{&gDn ziR3AYzJQ{q$bNvbG126*;sK15TpA+Tfv$;O#N}OPfF$1{7k1ZhVi9>&CN4AcEKF3`CJ+5fH1HG|?ShzvX^V1QtEz8(};U`*5? zCzv=EOr(_W%*S|ecJ{$1oz8>Nx$a`t2qQCozRRdguHlI+gG<$9p5d0rF`AyUre}u# zM)C6G`S7=y;SIF9Ihoy<8GZ)Knhfl3WrRC#0GwJ6%p(rg1OGx_A$04tLbCLu-rgTC zgfFn`?m&yJKxa?DGk0HNU*~I{FIRlb{X$b2{))xa)9*!4B3Y(Nn_-^P z^)9Lgy0Ri1WZMbR^9Bc56$9=**4ukk*V>Y7y~<$}&c68!xKR7?X`VYgD%_BQ(;$O` zcrx@4(h`10layK&VbF(8seAHwFh#KYAsL8*iT?_AZ}T25(Dn%?{w6~dF3n6u1Mtru zp2{}K)sUZBpYoFa|M}=X9c!l4=pKlRe}8np3}a^=-M1s>|J&&H^{@xP0m&nh*Byt= zF{QHKXpf_~EMoE;>K6Byyc3-&0#ovnqtuHfXd@b#iWQwd9f4U7D94*0&szf+-&S3W#RA)W=7sNOJid`cr5=ov`(RzRTuB>}MI)NXjCH4gqZ>i>O{Pdo3 z%WC_Tu}+}tdMq5V7v#EqJzAr*2Byx;D$Eor98fA;SeZDGS&LVN7W)gK1pw7Y|GpM4 zks+3l0o9&UF13T*hzzhz2w(mcdqz|yj#nf;*5-NF-@eC~2YRTVulYCjZZB1esT(W* zzGAybv8n#&rlIlxZvRk}dVz2LXrI8EW{19hf&5bSPy2gWZLeb?uRUcLGT@^VF>fH@ ze*q?jgZ#q(Je7EM0KS;GdmvJjQ#q2iNG9(6vyG9b zXq!@%c)haoeNV?1&|`T z8!6oqy4>3La(my)p7bSz+=nZ20TTEK&bhSh-i8EKLm;gy8GH^2+KUso7v~&e{tO93 zIM!mH&U_u`Y|4BC2@YgD!XKl?~HqxnLuPpkq?kBbli$E4+*A zJ%|1f7+2v990_blj(8Toe#BFKu-=pR$Jw2| zp3Of+)l}|CmFLnugmgR#WH!0#w~+8`ejhh58zdg&+7Ll%;UQlShvRe<)_$o-rupXFzB9L~>`$JKDHus6 zqI!Nb0~4vRgui;Ly@A+XQ4DAXD1HBwCURi+NyD{GO}Oy78#W6+>^3% z51FH{oyi#7c-VOiDuKNhzX&_;KjIk?^5*f#--~Tt+FGgc%jV*`lNVt}5KMfW?EOG* z4xh0h3abd;`+jZJ=e#sW>&ZF!8J3o)kxiX!z>YJRI37&=gSCD2K>J%+fg$^}8!YZg zUf{MRRq<7|U)|K{8;48)(%r(U08`PrPaNtSfXvUm>2UxiK(2tlc)ftBRtrSj;ozc% zP7hOVtd_$umxp8W9CT@F=&5k576+b=FT+hw8hUEFg_B@_veaO=T8!v0{cbR^J4l0? zGvWPoV`-$P<8t==JMe8h{};16-|=j|P9Z#4Ucwmo9l9OE=|*&QE?Wccy_bhou3+v7 zbPe!A&}(L$(AP?VvAfjI={w&Kc;+17Aw!+^YY6^{>0JokhYEMHqOcsTb~x>C|1`(b zF#y%!o-c(J)n?zzzTS$&HoiBRxSj7?IO9ud47`~h1A&BIp89%mBVJdws}gPR=tz5y z?lv?h!!O^HH^Pgdwh23Im*nAp=A5rHVSh03XXCwphWGAGdvCXt@Nz)9H%8y$my=70 zfY6HD9rA7@d#j$8OwdhQ2k_&1TDf8gh$2N8VSP(+)A=jynQ3n&*F2n_`}oGbjg@R_ z`r{>eYAu=I)zKGdUdgK{Yx1_Puch#@%(${%FJT38fU8u~N!#fMO9EKmqH8hWmACJp zs0JJL0RxGjVD@SIrD}(1zTLuqOt#Oa;d6B@|g|D;dn&5_*N7&!ILsfPnk3A z!CFyM+SgQsr0sql7Q%R<%9io>mIk|;XmN6Ab|R^I7Tt^*tV_+3E|KpIcFm&og)Wqy zTM>_G%caWE>LR_GFq%+X^U^SlMGApDQC4^xXbxPg-Ij-@@?)U$QZpbz7Y1Z54*`0D zrl-QgmED1B@+xXEH7T`&zr?>(ucS^OD!<7gzgC8PUP)a9 zgyxNokw|zpU#JMYlKL5nowSk)(%k^ApwC*0X9T@ofR+2Mp{QrbO$to^BdjA7oqA1$ zd}XEfog=Y{$xdeT+GH(OV-yWJZ-ZKDSe}k;SY@R4%&NP3%pT8pwc5(3c1SEC8ACyg zPP+M_ZiOv*m+xQDGaT5$N=|uOtY40(8DMteE%vxq5BRZw391E*itu~o6wuRW3cx}a zE1XRrXbV!1Q~_RFPN}rhPal0=gMosH50dZ0aH)oUkf~vh zfC*dE)5PT8{+xO=yABK043A||_2$*kneSSLkig==+_g;p0L9gkQ0>5zcORx*^E=5{ z`iTLy^BJ|+4?We2uunU3pq%tv7EH0ASxC^I;LUJyQ8KGnK%#*A`1Z&59N?%rnmCKOI6EGj5%I{?^fKM(yG<#e*XAzCk9>Qo_Mh9;E^O3b?zLm8qH|xBigR{559jMItIuDVB58@W- zG}bm1h56|7yZ`SaU?fvHt-=5WPU(WE6fc(R=XPicIZ5resKDm8xVCZR2_YAmt z*x)ON_q;Kn|HJ)qhEGPWe|R3)C^da}?)2f={?q)!_r5V;{_uTo45+5mbY{=WrSw8V z`_Ip!w4d>F`={`J%hK@Bft0?A=>4`+lBJ++NCp`FVhYtQ$b2HR46r`v&6L}pW8uj; z{kix0;H}UmA%UR-Pjnge1d937%f!sccuhsa45=8oo8pqwR zK8NzVf!5eQsAb*3*8?q|1HV(_mpSnNrSYi_e5=N2~=2mTw4|H%XrE$ojPFL&_Y);Qg_m&ac< zPB+u#@qxxCIploA_#mst;Sir{ew7r0bbl^C(7M`z57GES2kz1M^$z?@jfWigc^X%K zozA3{AN6BP8sgL?8jm?}O23AYc9Qy3k{2w~_KV^If zuj_^S)-MCYW!6P{*K0#zUdnNYUJ=ajUU$duO0X?jjMXn{7*D~ z(82G=dJMEacHr3>AK=i_qw!B2{IfK!&gptTukqmyIbMxl+tev_{Y-S{%=5{#Hl5J2k%Ffz!Bhn3$!}xXOgT>4GO+@S`sH$1ZrU3qA<# z%%soRE_goh)5ZRg_w#6(&xK#^f?wr=U+se5=z_;w@HH-Yw+p`21%JW?-{XS+!UccZ z1wZbBV@Z**Uq-s%m%89nT<{q#_gJlpmclx#wx$KIfU(->T{)I|$40ez4M1UC zq$L&y*oyap(Vy&9t3MK~zNN7>+$R(7k*ThUE(fhJID@}@lq#mL3G{^*Bn4;qR1RnP zIM2tKK9yU-oJssWnG11xBBx83S;EYcQpzpi+>$a%mnzA{DqCMDdBseg$TT0Pi#fko zX~=36vv5_qn2V`W#aurCf2T(vt<1vY=8fP|8(KVkIVVsYxt! z5|^5!8pEX~ajD6Q$z>;T*~wgLGMAdnHBRQTlez32WDw6BnvFtJyU8V{a zse(nUh_8sX@)apDMXK^5Re2GM@D(Zjij;muN{Vr8B}}`v>grM@Yl1#;1rrrd`G{|V zzEahw&d2M4$YQ=?C13fJZ-S~@`I8S0h1Z;gqfx86x*mU_+!C*^u4`Cf#p{-b<2CVk z6sed_fr$6M)gvQ@LeVC?2&}p~7RO)zQju!?QQ>0JobjV+CFEnB^Jf&VT%W+3%8 zx@z@yKbD#*Ssx9Dsq&V(*3}L=akL2iVg>{zep{CnTaDKgwBR*v6v^#;--YmR2>f#bm-5fmxKsbp0;i?F(Z}4UceZPpkWcsI4BtFY zaPsLn3LQ>-osjbY@{OFC%vSyNO@YtRILY~zz-u*5?V>G*k#m#AiBElD@YNb8KCN>M zzER^&{uaR>A^6nSbU69nQ84=zo=m6Y|3KqTzPUe2`g~6Ccf0U^t#RVh^GTz>dJb{2 zKJN)WJ%2X*ziZs7Pk-GnB>ybIKTY(Pw5Rl|vju;Y3*RT?(^xk8sQddT>mLw&y2o$$ z^IYVc=Rc%BJqt8^b^rZj`74F|^8|mri~MfEKVR_ga^XKD_@5X2Z7zIuUt9VA1%kiR zh5wq6PchK6SKX&RxxFU@-xmD-WH1~~e>h#^bh-#1BmZ0%{usd@CHMs{{0)LXTJSf! z@V5&-CG+v&qrW;4Cg+900{0@%=s#5B)ZT{#o-gok3;Y=&XN&%XLMai=5j9PR~w_{{JEH?+N@tA)jn&p4aaZ_yocKnZTu< zuM7FoKKlhO>m526LUE8izm1R4^E{1{F1El&3%(q8#ezRk@XKBJ8wCES;6Enhj28G) zf-mcRQ}AWI@4E1h34V!?|CtMan0}B%b|@A6Gc`_jlltJtgnSTx5{=8e@a{Qiknrbh#OY$$(IN3q^|9F8@p7H<71TO6` zL*q`n%@=%Whovt3M!}c;c(V(CgWyksp2pucyYTN8{Aq&!fD8XI!S@UPQ!e~nf-mFV zD=z#u1YgFzcU<^K1z-Bf2^YS9D3r$G?Du&Be+>D?ZtFBoeJ;mihrp)`{uUuej>o$N zPJ3!2f4{&V75FiMKP>QZ`uRWUzg^&E8h7exes@6l48acyIa1GMLXPzRR)Lc&} zULoY)DsaiaP2m0WKa3WUILHQayq~FYr+lyAOMlLH;l~6n{pTTp%eeP1uon5dm(4Okn^74%XS?V zeA%uOf-l>30o~-qL3aKTKE`en1pc(Z{Q{SI1~g9g?=Sc_3I3x3Z*}nhfjm0CDEQyO zwb6&)B8Y3!^AUkRDda2=_+BALw)aheKO^|>3Vesaj|g10_sq|MgoE^X79XSMxf&-s z(8u6Dfy=lzS>Ou=ze32Del<(*rJVT!UnJx#5%@I%uMzmQ0&f=hVu7~_e2Ku->-3}-4+P^e!;(0$Y~JxHi6$Q z@W%z-DDYhxch>te!M{oHe<|?01^#=1Un}sp1inJxNr5*B{FuO-1^%hPTLeB}Brb3` z^*>GHPCq|g;1QHF_P^Lg&NzX~xK}RZvr6 zIN3+8tIrX9>HlSdFUQMOF8q+dpGFt;0FZ$1%ZDe@U;RTdOj|2ke=)CF?O&8zFy!(0>4$@RRZ52@Pz{3 zDDX`J|DwR}7kInCk7}I!MDA;>&jY|g_>1@${V&!ywW~wm69ixS+hqcOUhwOLoKAtS z6nrUXlfY%Xx<|;_B;-6M_)^aE0)I~McM1G?f&WV2l7Cp^WCuAe244UG2jR8&7`vSz zaJfDir*X2g9CtGX{)~__N8mdIzC_@19Ie(k=_BpaE%?$t_X%9K_hErc`#dRd$$wkp zPCFbFxU@s?LMVuX_%co|6nF@E#-3q;%k}Wh0+;-i8Yer;xVlN;F9`V$3prmB_@ja^ z?e@69rJP^5;GYQjaveUzMrAliPbq(dO{l`9{jabYX1mGx?hb)Vdp;oW%_wT@`H;q) z_Sr7@QqGSAo)B_&y2$xZ@TreYy@M~p1rBGwUnKC`kZ<@GYuu@)PvAch{Aogt)c;C> zcM1LiAxHYja>18!RtfxeA!nV7oNWSsSn%H$a-{sv1l}$9{YT*fhtm!ojgvj^z{l9_ zJQw~Yf-mbW5%`ydoN^aA(*?d$@MjA-QvO1LZxQ@uLXNb5li*7^F@b+Y$hp-;&L+W^ za=HcnRUzkI7dcx6U&{H8z`rKsJnkar$AT~A>=XE%Le8&U~dp$nq>3h`GJ@)Cbf zktzd1O*G!tnqt(&;>f4}rwsp#t5t~qR5DzMHyz=>WyW7f=9^ChS61G4tcrfRl6AR|-x)-S3ObT2|4&hq~U D`ZV9z diff --git a/src/zupt_mlkem.o b/src/zupt_mlkem.o deleted file mode 100644 index 73dd132092497053700b02245121a60f07c8b578..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19264 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 diff --git a/src/zupt_x25519.o b/src/zupt_x25519.o deleted file mode 100644 index 98bae2ab10ddaf77dfb195bb2d8c49e28b2f1e8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5744 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 Wl2-0NGIKupI+YNQm&nqvT>k%mmOD29 diff --git a/src/zupt_xxh.o b/src/zupt_xxh.o deleted file mode 100644 index 7140e611a310217f2171aae26499cc97bcc78442..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1936 zcmbVLU2Gdg5Z;a5#!&0dts)vJfZeC06}{SRQfefsTuPGJ_S{N^1ZWAV6PyIm{9vC& zoCoq?2s)XAJo1E)c;W$~Rsy9_TlpLsMG=Vfhf+nNq~WDXMQN!}9Ug$$^Q~9k}c$c{PbVUxT3xc#s<)bFn4LN z`-wewt~ILN8oi=+sV{ZC2!k zPtE4OIGvK|$p<&F$htGABOY(bP&g;<1>_kEjQgBkYydafj(85{Ht^=o;A7w? z32!8t*{paPa8c|qFfD(BqqZooU1(zqvKPQW&JW2oFqTjDfOUI^`kLBi3aQFVC?e2YdZ?h6?Rzf?Sfc?nu z!=JkkWfMy0(JoR$NS0$R6u#;TiqMJUgpT`YgSXZ*jW7HK#GiCxpCgGd$@g*1ajE_z zSGyE2-EC6ShnrL>IJH@o4y0>c2WzCDDm8UTfi|hWUGlX_9*13B@qg1z?*CIQ>Z
~@E9)MI+x;75~*Q5+DDXx9xv!2Vd=4PohWZa z^(ayL5(%R8j}8yVMi3hr)nf{dZ+AkE_P^!$gCj|0EIv9Gi|Z+(#ABzUN^GciARZl# z6{|h6(SS@oqsxP0wEhx5ffi`cLK8HPX$xh0Q~Ms)ZMJ}Unih0}lU` z!xO5K{|W~9f7U7z9PQ&EuKI!^kD=y$3ckRr)#j8>D(XLu7>6qPd|xLOt5&?+v diff --git a/tmp/zupt_solid_pq2/in/a.txt b/tmp/zupt_solid_pq2/in/a.txt new file mode 100644 index 0000000..3b18e51 --- /dev/null +++ b/tmp/zupt_solid_pq2/in/a.txt @@ -0,0 +1 @@ +hello world diff --git a/tmp/zupt_solid_pq2/in/b.txt b/tmp/zupt_solid_pq2/in/b.txt new file mode 100644 index 0000000..4866c3c --- /dev/null +++ b/tmp/zupt_solid_pq2/in/b.txt @@ -0,0 +1 @@ +test data 12345 diff --git a/tmp/zupt_solid_pq3/in/a.txt b/tmp/zupt_solid_pq3/in/a.txt new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/tmp/zupt_solid_pq3/in/a.txt @@ -0,0 +1 @@ +hello diff --git a/tmp/zupt_solid_pq_5304/in/a.txt b/tmp/zupt_solid_pq_5304/in/a.txt new file mode 100644 index 0000000..3b18e51 --- /dev/null +++ b/tmp/zupt_solid_pq_5304/in/a.txt @@ -0,0 +1 @@ +hello world diff --git a/tmp/zupt_solid_pq_5304/in/b.txt b/tmp/zupt_solid_pq_5304/in/b.txt new file mode 100644 index 0000000..4866c3c --- /dev/null +++ b/tmp/zupt_solid_pq_5304/in/b.txt @@ -0,0 +1 @@ +test data 12345