技术指南
完整的技术指南:架构与 .nik 格式、压缩引擎与媒体编解码器、加密设计与量子抗性、加固、全部基准测试,以及构建、测试和路线图说明。
1 引言
.nik 格式的命令行压缩工具。它的设计围绕四个理念:比现有工具压缩得更好、更快,用现代密码学保护数据,并以单个小型可执行文件在 Windows、macOS 和 Linux 上原样运行。1.1 设计目标
小。在人们大量实际归档的数据上击败 RAR 7。音频、图像和跟踪器音乐通过内容检测,并用专门的无损编解码器压缩;其余所有数据则使用调优过的多线程 Zstandard 流。 快。压缩和解压应受磁盘限制,而非 CPU。在其快速级别 -m2 下,nikpak 在单核上不到一秒即可压缩约 200 MB 的源文件。 安全。带内存困难密钥派生函数的认证加密,文件名始终隐藏,篡改始终可检测,解压器不会被诱骗把文件写到目标文件夹之外。 抗量子。仅使用 256 位对称密码学。nikpak 中没有任何 RSA、椭圆曲线或 Diffie-Hellman 代码,因此 Shor 算法无物可破。 可移植、可脚本化。单个静态链接的可执行文件、与 RAR 兼容的命令行、可预测的退出码,以及记录每个选项的 -help。
1.2 结果速览
| 0.9 s | ||
所有测量都来自同一台机器(Linux x86-64 虚拟机,单 CPU 核),使用 RAR 7.00 和 nikpak 1.1.0。每个压缩包都再次解压并与原始文件逐字节比较。完整的方法、测试集以及 RAR 更快的那些情形,在第 11 章中有描述。 |
1.3 它是为谁准备的?
1.4 如何阅读本指南
1.5 社区与联系方式
Telegramhttps://t.me/cryptonikko Xhttps://x.com/cryptonikkoid Discordhttps://discord.com/users/1537826350759415811
2 功能概览
2.1 功能
2.2 nikpak 与 RAR 对比
|
| ||
|---|---|---|
| 9.7 - 16.7 s (-m3) | ||
3 命令行参考
nikpak [options] [files...]。选项可以出现在压缩包名称之前或之后的任意位置;-- 结束选项解析。3.1 命令
a | .nik。文件夹始终递归处理。 |
x | -d dir)选择目标位置。 |
e | |
l | |
v | |
lb | |
t | |
p | |
d | |
mt | |
(none) |
3.2 选项
-p |
-e | |
-p |
-P | |
-hp[password] |
| |
-m0
.. -m5 |
-0
.. -9 | |
-mt |
| |
-mc- / -mc+ |
| |
-r |
| |
-ep |
-j | |
-ep1 |
| |
-o+ |
-o | |
-o- |
-n | |
-or |
| name (1).ext。 |
-y |
| |
-x |
-x | |
-d |
-d | x 和 e 的目标文件夹。 |
-inul -idq |
-q | |
@listfile |
| |
-h -help -? |
| -V 打印版本。 |
-s、-ma5、-md64m、-ibck、-idp、-rr、-ts*、-w 及类似选项)会被接受并忽略,因此现有工具配置可继续工作。其他任何选项都会产生清晰的错误消息和退出码 7。nikpak --add 和 --add-here 将给定项目压缩为新压缩包,nikpak --install-menu 和 --uninstall-menu 添加或移除右键菜单(--all-users 用于为所有用户安装),unNik --extract、--extract-here 和 --extract-to 从菜单驱动解压。3.3 密码详解
-p 创建压缩包时,nikpak 按以下顺序解析密码,并且绝不会仅仅因为没有提供密码而失败:命令行上的 -p或-P:按原样使用(最少 8 个字符)。环境变量 NIKPAK_PASSWORD,可让密码不出现在进程列表中。交互式提示,询问两次以确认。空输入会生成随机密码。 没有终端时(例如在 GUI 内部),密码通过 stdin 管道传入;如果没有,则生成随机密码。
3.4 退出码
| 0 |
| |
| 1 | ||
| 2 | ||
| 3 | ||
| 7 | ||
| 10 | ||
| 11 |
3.5 示例
nikpak a backup.nik C:\Docs\*.txt Photos\ # create an archive
nikpak a -m5 -mt8 big.nik Projects\ # maximum, 8 threads
nikpak a -p secret.nik Taxes2026\ # encrypted, prompts
nikpak a -pMyLongPassw0rd s.nik f.pdf # password given
nikpak x backup.nik C:\Restore\ # extract with paths
nikpak e backup.nik *.jpg C:\Pics\ # only *.jpg, flat
nikpak x backup.nik Docs/report.pdf # extract ONE file
nikpak e backup.nik Docs/report.pdf -d C:\Out # one file, no path
nikpak x backup.nik Photos -d C:\Restore # one folder
nikpak l backup.nik *.pdf # list only PDFs
nikpak p backup.nik notes.txt # show a file
nikpak d backup.nik Temp *.bak # delete entries
nikpak l backup.nik # list
nikpak t secret.nik # test (asks password)
nikpak mt song.wav tracker.mod photo.bmp # which filter wins?
3.6 与 Total Commander 及其他前端的集成
a、x、e、l、t、@listfile、-p、-ep1、-o+、-y、-m),能够驱动外部 rar.exe 的程序也能驱动 nikpak.exe。在 Total Commander 中,在配置、压缩器、附加压缩程序下注册扩展名 nik,并将压缩和解压命令指向 nikpak.exe。无人值守解压时使用 -o+ 或 -y,因为没有控制台时 nikpak 无法询问是否覆盖,而是会跳过已有文件。菜单名称因 Total Commander 版本而异;请查阅其内置帮助了解具体字段。以反斜杠结尾的加引号路径(如 "C:\My Folder\")会被 Windows 错误解析(末尾的引号被视为转义)。对于带空格的目标位置,请改用 -d "C:\My Folder"。 |
3.7 图形界面

拖入文件或文件夹,或一次拖入多个,放在窗口上;或点击圆圈(或 choose files / choose a folder 链接)在对话框中选择;点击圆圈会在环内显示 Choose files 和 Choose a folder 两个按钮。它们以最佳压缩(-m5)压缩到一个压缩包中,以文件(去掉扩展名)、文件夹命名;若有多个项目,则以它们所在的文件夹命名。已有压缩包绝不会被覆盖:report.nik 变为 report (2).nik。 进度以环形仪表中的大百分比显示,并带阶段(分析中、压缩中、收尾中)、已处理数量和耗时。其下方的 Cancel 按钮(或 Esc 键)会立即停止长时间压缩并删除未完成的压缩包;窗口保持打开以备下一次。压缩过程中关闭窗口效果相同。 完成:环变为绿色,显示压缩包名称、其与原始大小的对比和耗时。Show in folder 在 Explorer、Finder 或文件管理器中打开它;Compress more(或点击圆圈)开始下一个。 保存到:底部的目标文件夹可以输入或用 Browse 选择。下次会记住(Windows:%APPDATA%\nikpak\settings.txt;macOS:~/Library/Application Support/nikpak;Linux:~/.config/nikpak)。首次为桌面。 社区:右下角的三个圆形按钮打开 nikpak 的 Telegram、X 和 Discord 页面(第 1.5 节)。 切换到 unNik:i 按钮左侧带向上箭头的圆形按钮会关闭 NikPak 并启动 unNik(第 3.9 节)。压缩完成后,它以及完成屏幕上的 Open in unNik 链接会立即打开新压缩包。压缩进行中该按钮被禁用。 打开目标文件夹:Save to 字段和 Browse 之间的文件夹按钮会在 Explorer 或 Finder 中打开该文件夹;压缩完成后,打开时新压缩包处于选中状态。 声音:按钮、链接和选项有轻柔的点击声,每个动作(开始工作、成功、错误、取消、切换程序、文件悬停在窗口上)有短促的提示音。它们由程序本身生成,没有声音文件。标题栏的扬声器按钮可关闭和开启声音;默认开启,且此选择与 unNik 共享。 语言:左下角的按钮带旗帜和该语言的自称,打开世界上使用人数最多的十种语言的菜单(Ethnologue 2025):English、中文(普通话)、हिन्दी(印地语)、Español(西班牙语)、العربية(阿拉伯语)、Français(法语)、বাংলা(孟加拉语)、Português(葡萄牙语)、Русский(俄语)和 Bahasa Indonesia(印尼语)。选择一种会保存并以此语言重启 nikpak。首次运行时,nikpak 跟随 Windows(或系统)的语言,否则用英语。命令行始终为英语。 以管理员身份运行:Windows 不允许把文件从 Explorer 拖到以管理员身份运行的程序上。当 nikpak.exe 以管理员身份启动时(例如从管理员 PowerShell 启动),它会通过 Explorer 以普通用户身份重启自身一次,以便拖放正常工作。如果无法做到,窗口会显示提示;请改用按钮选择文件。 状态与关于:左上角显示 EVALUATION COPY · REGISTER(点击打开注册框)或 REGISTERED TO 及许可证持有人。右上角的小 i 按钮(在最小化和关闭旁边)打开 About 框:版本、© 2026 Nicolas Choukroun,由 Nikkoid LLC 发行、许可证状态、网站和许可证条款(LICENSE.txt)。
cargo build --release --no-default-features 构建。
3.8 许可证与注册(共享软件)


提醒在未注册副本打开其窗口时出现。它有两个按钮 Register 和 Test for free,其左右顺序在每次启动时随机变化。Test for free(或 Esc)关闭它;之后 nikpak 无任何限制地工作。 注册框要求填写姓名、电子邮件地址和许可证密钥。三者必须匹配:密钥是姓名和电子邮件的签名。大小写、多余空格以及形似字符 O/0 和 I/L/1 无关紧要。Buy a licence 打开 https://nikpak.nikkoid.com/buy.php。 注册后,nikpak 在该计算机上不再为该用户询问。许可证存储在 %APPDATA%\nikpak\license.txt(macOS:~/Library/Application Support/nikpak;Linux:~/.config/nikpak)。公司可在 nikpak.exe 旁放置文件 nikpak.key,为该 PC 的每个用户注册。命令行: nikpak register "Jane Doe" jane@example.com NPK1-…进行注册;nikpak license显示状态;nikpak unregister移除许可证。nikpak -V和nikpak -help也显示状态。未注册副本在错误输出(stderr)上打印一行评估通知,从不在标准输出上;-q 可抑制它。
密钥是如何工作的
NPK1- 开头,后跟 108 个字符,每五个一组(Crockford base32)。它包含许可证类型(个人或公司)、席位数量,以及 NIKPAK-LICENSE-1、类型、席位、姓名和电子邮件地址的 Ed25519 签名,每项都经过规范化(空格折叠、转为小写)。nikpak 仅包含 32 字节公钥,位于 src/license_pubkey.rs,因此研究程序无法让任何人制作密钥。nikpak-keygen(cargo run --release --features keygen --bin nikpak-keygen -- make --name "Jane Doe" --email jane@example.com;公司用 --company --seats 25;newkeys 创建新密钥对),也可在 Web 服务器上用 server/ 中的 PHP 套件(PHP 7.2+、MySQL 5.7)制作,后者每次付款签发一个密钥,且生成完全相同的密钥。server/README.md 描述了设置和付款流程。3.9 unNik,免费的压缩包浏览器


用文件夹树、面包屑、Back、Forward 和 Up(Alt+Left、Alt+Right、Backspace)以及双击来导航。Search(Ctrl+F)在整个压缩包中按名称查找文件;每个结果显示其文件夹。 用单击、Ctrl+单击、Shift+单击、复选框、Ctrl+A 或方向键来选择。单击列标题按名称、大小、类型或日期排序。右键单击打开包含所有操作的菜单。 解压全部,或解压所选内容(Ctrl+E):选择目标(默认是与压缩包同名、位于其旁边的文件夹),是否保留文件夹,以及文件已存在时如何处理:替换、两者都保留(name (1).ext)或跳过。从文件夹内取出的文件不带该文件夹的路径创建,与 WinRAR 相同。读取会在最后一个所选文件之后立即停止。 查看(F3,或双击文本文件):带行号的文本、高亮搜索、自动换行和复制;二进制文件以十六进制显示。显示前 16 MB;在记事本中打开打开整个文件。Open 用文件自己的程序打开它(先解压到临时文件夹)。 删除(Del)在确认后从压缩包中删除文件和文件夹。压缩包是固实的,因此会在没有它们的情况下重新写入一个临时文件,只有在全部成功后才替换原文件。加密压缩包保留其密码;其他条目保留其媒体或 Deflate 过滤器及其 -m5 引擎。 测试解压整个压缩包并检查每个文件。详细信息窗格显示大小、日期、文件夹、CRC32、文件的存储方式及其属性;对于压缩包本身则显示其大小、方法和加密。树下方的摘要显示节省的空间。 与 NikPak 相同的十种语言、语言按钮、关于框(i)和社区按钮。任何文字系统的文件名都用系统字体作为后备绘制。 切换到 NikPak:i 按钮左侧带向下箭头的圆形按钮会关闭 unNik 并启动 NikPak。两个程序位于同一文件夹。它们共享一个设置文件,因此在一个程序中选择的语言会被另一个使用,已打开的窗口会在两秒内跟随更改。 打开目标文件夹:弹出按钮左侧的按钮在 Explorer 或 Finder 中打开最后一次解压的文件夹(任何解压之前为压缩包所在文件夹)。unNik 播放与 NikPak 相同的声音,并有打开压缩包、解压、删除和测试的声音;其扬声器按钮与 NikPak 的共享一个设置。

3.10 皮肤
皮肤按钮(一个调色板,位于两个程序的标题栏):打开皮肤菜单,其中每种皮肤以自身颜色绘制。指向一种皮肤会在整个窗口上预览;单击保留;Esc 或点击外部返回原来的皮肤。 旁边的 太阳/月亮按钮 一键在 Nikkoid Blue(深色)和 Nikkoid Bright 之间切换。 皮肤面板位于程序之外。面板打开时,窗口向右扩展面板的宽度:程序保持其 500 × 560 面板,面板位于其旁边的额外透明空间中,因此整个界面在试用的皮肤后面保持可见。面板可用标题栏拖回程序上方或窗口中的任何位置,并带有 Apply Skin 和 Cancel 按钮。点击皮肤会在整个窗口上试用;Apply 保留并为两个程序保存;Cancel(或 Esc 或 ×)返回原来的皮肤。点击程序不再关闭面板。unNik 的窗口不会扩展。 所选皮肤会被保存(设置文件中的 skin=)并共享:在一个程序中选择的皮肤会在两秒内被另一个程序采用。你自己的皮肤:菜单底部的“Import a skin…”读取 Nikkomander .skin.json文件(一个名称和一列颜色)并复制到设置文件旁的skins文件夹;导入皮肤磁贴上的 × 将其移除。手绘皮肤退到界面之后。手绘背景由 src/skin_scenes.rs绘制,而非 CSS 渐变,因此可缩放到任意窗口大小。自 1.6.2 起,每种皮肤都经过一次discreet()处理(在src/skin.rs中):画面被拉向其自身局部均值,轻度模糊并向皮肤的背景色淡化——大部分在放置环和文本列之后,在标志处略多——因此标题、环和状态文本在所有十四种皮肤上都保持清晰。
3.11 文件管理器菜单
nikpak --install-menu;macOS:Finder 快速操作)。针对文件和文件夹:添加到压缩包…(询问名称和文件夹,然后在 NikPak 窗口中压缩)和在这里添加到压缩包(压缩包放在项目旁,命名方式与拖放到窗口上相同)。 针对 .nik 压缩包:用 unNik 打开、解压文件…、解压到这里和解压到其专属文件夹。 多个项目合并为一个压缩包;多个选中的压缩包在一个窗口中依次解压。 命令通过 unNik.exe 运行,因此不会有控制台窗口闪烁;标签跟随 NikPak 的语言。Windows 10 直接显示子菜单,Windows 11 在 Show more options(Shift+F10)下显示;Linux 添加 KDE Dolphin 服务菜单、Nemo 动作和 Nautilus 脚本,macOS 添加 Finder 快速操作。 菜单使用的新命令行选项: nikpak --add和--add-here(压缩给定项目),nikpak --install-menu、--uninstall-menu和--all-users;unNik --extract、--extract-here和--extract-to。解压到这里 / 到其专属文件夹显示 unNik 的小窗口和进度环(加密压缩包为密码框),全部解压完成后关闭;警告和错误保留在屏幕上。第二个安装程序 unnik--setup.exe仅安装 unNik(免费浏览器),面向只接收 .nik 压缩包的人;当 NikPak 已安装时它只安装该程序,因此菜单不会重复。
4 架构
4.1 创建压缩包时的数据流

Write trait 的一个实现,包裹在下一个周围,因此同一代码路径服务于普通压缩包、加密压缩包和媒体试算。4.2 源代码图
main.rs | nikpak lb x | head)。 |
cli.rs | -help 文本。Clap 风格库无法干净地表达 -pSECRET 或 -m5 这类开关。 |
archive.rs | |
media.rs | |
nac.rs | |
bits.rs | |
crypto.rs | |
format.rs | |
util.rs | |
error.rs | |
engine.rs | |
recomp.rs | |
gui.rs | |
unnik.rs | |
lib.rs, bin/unnik.rs | |
license.rs | |
i18n.rs | |
textshape.rs |
4.3 逐步创建压缩包
验证输出位置。已有压缩包仅在使用 -o+(或交互式确认)时被替换;否则 nikpak 会说明不支持追加。收集输入:展开通配符(PowerShell 不会这样做)、读取 @listfiles、应用排除、跳过符号链接和特殊文件并给出警告,且压缩包绝不会添加到自身。若请求了加密,则解析密码(第 3.3 节)并用 Argon2id 派生密钥。 写入文件头,然后构建写入器链:文件、缓冲写入器、可选的分块加密器、Zstandard 编码器。 写入每个条目。媒体文件经过检测和试算(第 7 章);其他一切以 256 KiB 块复制,同时计算 CRC32。 写入结束标记(含条目计数),完成 Zstandard 帧,密封最后一个加密分块并刷写到磁盘。 重命名 name.nik.tmp为name.nik。若此前任何步骤失败,守护对象会删除临时文件,因此半写入的压缩包绝不会替换完好的压缩包。
4.4 逐步解压压缩包
读取并验证文件头:魔数、版本、标志、方法,以及(加密压缩包)Argon2id 参数,后者在任何内存分配之前先做范围检查。 获取密码并派生密钥。第一个认证分块随后证明或否定该密码。 遍历条目流。每个条目名称在任何文件系统访问之前先经过清理(第 10.1 节)。 用 create_new写入文件,设置时间戳和权限,并验证重建字节的 CRC32。CRC 失败的文件会被删除而不是保留。验证压缩包结尾:结束标记之后流必须真正结束,且(若加密)最后一个认证分块必须已被处理。这可捕获截断和追加的数据。
4.5 内存与线程
-mt 限制)。解压、音频编解码器和加密在调用线程上运行。Argon2id 密钥派生需要 64 MiB,最高两个级别使用 128 MiB 匹配窗口,因此解压此类压缩包最多需要这么多内存。5 .nik 容器格式
.nik 文件是一个小的固定文件头,后跟主体。主体是一条固实流:所有条目串接在一起,一起压缩,并可选择加密。格式第 2 版增加媒体记录;第 1 版压缩包仍可读取。5.1 文件头
| 0 | 8 | 89 4E 49 4B 0D 0A 1A 0A(PNG 的思路:检测文本模式传输损坏) | |
| 8 | 1 | ||
| 9 | 1 | ||
| 10 | 1 | ||
| 11 | 1 | 0 | |
| 12 | 4 | ||
| 16 | 4 | ||
| 20 | 4 | ||
| 24 | 16 | ||
| 40 | 19 |
5.2 条目记录
0 END | count:u64。标记结束并说明其前面有多少个条目。 |
1 FILE | name_len:u16 name mtime:i64 mode:u32 size:u64 data[size] crc32:u32 |
2 DIR | name_len:u16 name mtime:i64 mode:u32 |
3 MEDIA | name_len:u16 name mtime:i64 mode:u32 size:u64 filter:u8 method:u8 params_len:u8 params framed_stream crc32:u32 |
名称是 UTF-8,使用 /分隔符,最多 4096 字节。mtime是 Unix 秒;mode是 Unix 权限字(Windows 文件得到 0644 或 0755,只读时为 0444)。CRC32 始终覆盖原始字节,这正是媒体过滤器可验证的原因。 在 MEDIA 记录中, size是原始大小。framed_stream是一系列以零长度结尾的[u32 length][bytes]分块,因此读取器总能跳过媒体条目而不必理解其过滤器。
媒体参数
offset:u64 frames:u64 channels:u8 bits:u8 flags:u8(标志位 0 = 大端,位 1 = 有符号) | ||
offset:u64 width:u32 rows:u32 bpp:u8 stride:u32 | ||
none: the framed stream holds raw segments and recompressed Deflate streams (section 7.9) |
offset 之前的一切(文件头、标签、调色板、MOD 模式)以及采样或像素区域之后的一切(尾部块)都在过滤数据周围原样存储。5.3 加密主体分帧
5.4 为什么是固实流?
5.5 版本化
5.6 多引擎主体(版本 3)
6 压缩引擎
6.1 为什么选择 Zstandard
6.2 级别映射
-m0 .. -m5)和 zip 风格级别(-0 .. -9),并将它们映射到 Zstandard 级别:
-m0 | ||
-m1 | 1 | |
-m2 | 3 | |
-m3 | 9 | |
-m4 | 15 | |
-m5 (default) |
-0 存储,-1 到 -6 使用 Zstandard 1 到 6,-7 使用 9,-8 使用 12,-9 与 -m5 相同。6.3 大窗口与长距离匹配
-m5 的输出从 26.3 MB 降至 24.4 MB,-m4 从 29.5 MB 降至 26.8 MB,-m4 的速度无损失,-m5 略有损失。2^27 的窗口在 Zstandard 默认解码器限制之内,因此任何标准解码器都能读取这些数据。6.4 多线程
6.5 流内的完整性
6.6 存储模式
-m0 不加压缩地写入条目。它对已经压缩过的数据有用,也是唯一有意绕过媒体过滤器的模式:要求存储的用户并不希望数据被变换。6.7 最高级别:LZMA2 和 PPMd
二进制块。文件夹、二进制文件、媒体条目和经 Deflate 再压缩的条目用 LZMA2 压缩:预设 9、nice 长度 273、匹配查找器深度 32,字典大小随数据调整(1 到 128 MiB)。 文本块。前 64 KiB 不含零字节且几乎不含控制字符的文件(源代码、文本、CSV、HTML、XML……)进入第二个块。这些文件连续四个 1 MiB 段分别用 PPMd 变体 I(阶数 8,192 MiB 模型)和为文本调优的 LZMA2(lc 4、pb 0)试压缩,取较小者。散文偏向 PPMd;含有大量近似相同文件的大源代码树偏向 LZMA2,因为它能跨文件复制长重复。 顺序。在每个块内,文件按扩展名排序,再按文件名排序,如同 7-Zip,使相同或相似的文件相邻。连同连续试算样本,这使通用数据集缩小 7.5 %。
7 媒体智能
7.1 按内容检测
.dat 的 WAV 仍会被发现,而叫 .wav 的文本文件不会被发现。RIFF..WAVE、带整数 PCM 的 fmt 块(格式 1,或带 PCM 子格式的 WAVE_FORMAT_EXTENSIBLE)、8/16/24/32 位、1 到 8 声道、一致的块对齐;然后是 data 块 | ||
FORM..AIFF 或 AIFC(压缩 NONE 或 twos)、COMM 和 SSND 块、大端有符号采样 | ||
BM、40 字节或更多的 DIB 头、无压缩、每像素 8、24 或 32 位、像素行适合文件、区域在 4 KiB 和 256 MiB 之间 |
7.2 试算:为每个文件选择最佳过滤器
取样:采样区域最多 3 MiB 时取整个区域,否则在音频的 5 %、45 % 和 85 % 处取三个 768 KiB 窗口。图像取前约 4 MiB 的行。 用普通 Zstandard 级别 3(基线)和每个适用的过滤器压缩样本:16/24/32 位音频用 NAC、Shuffle 和 Shuffle+Delta;8 位音频用 NAC 和 Shuffle+Delta;图像用 MED。 保留估计值最小的过滤器,但仅当其至少比基线小 2 %。否则文件以普通压缩存储。 用胜出者写入文件。所有这些都按文件进行,因此一个压缩包可以包含以不同方法编码的 WAV 与普通文件相邻。
nikpak mt 在整个文件上运行同样的测量并打印表格,第 11 章基准测试正是这样探索的。在选项中,-mc- 禁用过滤器,-mc+ 强制默认过滤器而不试算。每个过滤器都精确可逆。每个条目存储的 CRC32 对原始字节计算并在解压时检查,NAC 编码器在写入时验证每个块(第 7.4 节), -mc- 关闭整个层面。 |
7.3 NAC 音频编解码器

块与立体声去相关
| 0 | ||
| 1 | R = L - S | |
| 2 | L = R + S | |
| 3 | sum = (M << 1) | (S & 1), L = (sum + S) >> 1, R = (sum - S) >> 1 |
Side = L - R、Mid = (L + R) >> 1。边声道比普通声道需要多一位,以 bits + 1 编码。模式选择很廉价:编码器对 L、R、M 和 S 的 2 阶固定预测器残差绝对值求和,取总和最小的一对。对于声道强相关的录音,中/边通常能节省几个百分点。子帧类型
固定预测器
order 0: e[i] = x[i]
order 1: e[i] = x[i] - x[i-1]
order 2: e[i] = x[i] - 2*x[i-1] + x[i-2]
order 3: e[i] = x[i] - 3*x[i-1] + 3*x[i-2] - x[i-3]
order 4: e[i] = x[i] - 4*x[i-1] + 6*x[i-2] - 4*x[i-3] + x[i-4]
order 个采样按原样存储为预热值。线性预测编码(LPC)
对块应用 Tukey 窗(在首尾四分之一处渐隐),使边缘不扭曲统计量。 计算加窗信号的自相关 r[0..32]。运行 Levinson-Durbin 递归,它一次遍历即给出 1 到 32 每个阶数的最优系数集: k = (r[i] - sum a[j] r[i-j]) / err、a[i] = k、a[j] = a[j] - k a[i-j]、err = err (1 - k^2)。把实系数量化为整数,精度 12、14 或 15 位(取决于采样位宽),选择 2 的幂标度( shift,0 到 20),使最大系数刚好放得下。舍入使用误差反馈,因此量化误差不会跨系数累积。评估若干阶数(集合取决于努力级别,见下),计算每个的残差,保留估计总大小最小者(包括发送其系数的成本)。
pred[i] = (q[0]*x[i-1] + q[1]*x[i-2] + ... + q[n-1]*x[i-n]) >> shift
e[i] = x[i] - pred[i] (n = order; the sum uses 64 bits)
残差编码
u = (e << 1) XOR (e >> 63),使小的正负值变成小的数)映射为无符号数,并用分区 Rice 编码编码。块的残差分成 2^p 个分区(p 从 0 到 8,由编码器选择);每个分区有自己的 Rice 参数 k(5 位)。一个值写为 u >> k 的一元表示(那么多零后跟一个一)加低 k 位。分区的最佳 k 由其值之和推导,因此每个候选预测器的成本可从运行和廉价估计,而无需实际编码。努力级别
-m 选项)选择每个块尝试多少 LPC 阶数。阶数更多意味着结果略小、编码器更慢;解码器速度相同。| -m1 | 0 | 8, 16 |
| -m2, -m3 | 1 | 4, 8, 12, 16, 24, 32 |
| -m4, -m5 | 2 | 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 24, 28, 32 |
块的位布局
block := [stereo mode: 2 bits] sub-frame [sub-frame] (byte-padded)
sub-frame := type:2 ...
CONSTANT : value:width
VERBATIM : wasted:5 samples:(n x (width - wasted))
FIXED : wasted:5 order:3 warm-up residual
LPC : wasted:5 order-1:5 precision-1:4 shift:5
coefficients warm-up residual
residual := partition-order:4 per partition: k:5 Rice-coded values
7.4 自验证
-mc-。后备路径由单元测试覆盖,它们对位深和声道数的每种组合强制原样编码;该机制把可能的静默数据丢失错误变成可检测、可恢复的状况。7.5 Shuffle 和 Shuffle+Delta
Shuffle 把采样的字节分成平面:先是声道 0 的所有最低有效字节,再是声道 0 的所有最高有效字节,然后声道 1,依此类推,以 32768 帧为块。高字节平面平滑,低字节平面字母表非常受限;Zstandard 的熵编码器对两者的建模远好于交织混合。 Shuffle+Delta 先把每个采样替换为其与同声道前一个采样的差(按采样位宽取模,因此精确可逆,状态跨块携带),然后洗牌。当信号平滑但不足以让 NAC 胜出时,这有帮助。
-m2 为原始大小的 51 %,-m5 为 47 %,而普通 Zstandard 为 63 %。7.6 ProTracker MOD 文件
patterns = max(order table) + 1
sample_start = 1084 + patterns * 256 * channels (4 ch: 1024 B per pattern)
sample_bytes = sum of (length in words * 2) over the 31 descriptors,
clamped to the end of the file
7.7 BMP 图像
拆分像素区域为每个声道一个平面(B、G、R,32 位还有 A),单独记住每行的填充字节。 去相关颜色。从蓝和红平面减去绿平面(模 256)。照片中三个声道强相关,因此差值很小。 用 MED(中值边缘检测)预测器——LOCO-I 图像编码器所用的那个——预测每个像素:对于左 a、上b和左上c,预测为min(a,b)(若c >= max(a,b))、max(a,b)(若c <= min(a,b)),否则为a + b - c。预测误差替换像素(模 256)。在边缘上预测器跟随边缘;在平滑梯度上它外推梯度。串接残差平面和填充字节,让 Zstandard 压缩它们。平滑区域变成近零字节的游程。
7.8 为什么这能胜过 RAR
7.9 Office 文档、PDF 和 gzip:Deflate 再压缩
按内容检测。文件开头的 ZIP 本地头(PK\x03\x04)、%PDF- 或 gzip 头;从不使用扩展名。 解码。找到每个 Deflate 流(方法 8 的 ZIP 条目、带 zlib 头的 PDF 流、每个 gzip 成员)并用 preflate(微软的 preflate-rs)分析。preflate 返回普通数据外加一个小的修正记录,精确描述原编码器(无论哪个)是如何做出选择的。 存储。文件存储为原始段和(普通数据、修正)对的序列。普通 XML 或页面描述随后进入固实流,LZMA2 把它压缩到其 Deflate 大小的一小部分。 验证。在使用结果之前,nikpak 重建每个 Deflate 流,并把整个文件的长度和 CRC32 与原始比较。若有任何差异,或 preflate 在畸形文件上失败或 panic,文件就简单地按普通方式存储。 解压。Deflate 流逐位重建,因此解压出的 .docx 或 .pdf 逐字节相同,其 CRC32 与每个条目一样被检查。
8 加密
8.1 威胁模型
文件内容以及它们的一切相关信息的机密性:名称、大小、时间戳、权限和文件数量。 完整性与真实性:对压缩包的任何更改,无论是对数据、文件头、数据顺序还是其长度,都在错误数据被接受之前被检测。 抗猜测:每次密码猜测都尽可能昂贵。
8.2 从密码到密钥:Argon2id
| 3 | ||
| 4 | ||
8.3 STREAM 构造中的 XChaCha20-Poly1305
nonce (24 bytes) = random prefix (19 bytes)
| chunk counter (4 bytes, big endian)
| last-chunk flag (1 byte)
u32 length + 密文 + 16 字节标签 | |
8.4 观察者能看到和不能看到什么
8.5 密码处理
最小长度。创建压缩包时 8 个字符;更短的密码被拒绝并给出说明。 确认。交互式提示询问两次,不回显键入的字符,不匹配则拒绝。 生成。没有密码时,nikpak 从省略形似字符(0/O、1/l/I)的 56 符号字母表中抽取 24 个字符,使用操作系统密码学安全随机生成器上的拒绝采样,使没有符号比另一个更可能。那是 24 × log2(56),约 139 位熵,且只显示一次,在清晰标记的框中。 内存卫生。派生的密钥和密码字符串在不再需要时从内存擦除( zeroizecrate)。通道。命令行( -p)、环境变量NIKPAK_PASSWORD、交互式提示,或没有终端时的 stdin。命令行形式方便但在进程列表中可见;其他形式更可取。
8.6 攻击测试
弱密码总能被猜出;Argon2id 让它昂贵,但救不了 password123。nikpak 尚未经过独立审计。它无法防御键盘记录器、恶意软件或读取运行进程内存的人。对于泄露会造成严重危害的数据,请先让密码学家审查实现。 |
9 抗量子
9.1 量子计算机改变什么
9.2 nikpak 的立场
9.3 密码怎么办?
9.4“先收割,后解密”
9.5 如实的局限与前路
“抗量子”意味着没有任何已知量子算法能对这些原语胜过通用搜索。这不是证明;对 ChaCha20 和 Argon2 的密码分析仍在继续,且格式已版本化,因此参数或算法可以更改。 如果将来加入公钥共享(把压缩包加密给接收方的密钥),将使用混合方案,X25519 与 ML-KEM 结合,这样任一组件成立即安全。 抗量子不能防止实现错误。见第 8.6 和 10 节。
10 加固与健壮性
10.1 安全解压
路径穿越(“zip slip”)。每个条目名称被规范化:反斜杠变斜杠,空的和 .组成部分被丢弃,任何..组成部分导致该条目被跳过并警告。绝对名称失去其根,因此/etc/passwd被解压到目标文件夹内部。Windows 名称。在 Windows 上运行时,包含 < > : " | ? *或控制字符、以空格或点结尾、或等于保留设备名(CON、PRN、AUX、NUL、COM1-9、LPT1-9)的组成部分被拒绝。符号链接。写入前,检查目标路径在目标文件夹之下的每个已有组成部分;链接从不被跟随。已有文件先删除,新文件用 create_new创建,它拒绝打开已有路径,因此链接无法用于重定向写入。特权位。setuid、setgid 和 sticky 位从不恢复;权限被掩码到普通 rwx 位。 失败的文件。CRC32 不匹配的文件被删除,不留残余。
../../evil.txt、/tmp/evil.txt、..\..\evil.txt 和 ok/../../evil.txt:没有任何东西逃出目标文件夹,不安全条目被报告并跳过,目标文件夹中植入的符号链接被拒绝。10.2 有界解码器
Argon2id 参数在任何分配之前做范围检查(第 8.2 节)。 加密块的长度必须在 16 字节到 64 KiB + 16 之间;名称最多 4096 字节;音频块必须声明合理的长度;BMP 区域限制为 256 MiB;一元 Rice 编码有上限。 音频和媒体解码器在单元测试中被输入数千个随机和位翻转的输入,必须返回错误,从不 panic 或中止。 nikpak 自己的代码不含 unsafe块,Rust 的边界检查把在 C 中会是内存损坏错误的任何逻辑错误变成干净失败。
t 测试未知压缩包。10.3 安全创建与如实的错误
压缩包写入 name.nik.tmp,完成后才重命名;任何失败时守护对象删除临时文件,因此中断的运行绝不会留下半写入或被替换的压缩包。如果文件在被压缩期间变短,nikpak 用明确消息中止,而不是写入不一致的条目。不可读文件、符号链接和特殊文件被跳过并警告(退出码 1),压缩包绝不会添加到自身。 错误被分类,以便脚本响应:压缩包内的校验和或帧错误是损坏(退出码 3),认证失败是密码错误或篡改(退出码 11),被拒绝的写入是致命错误(退出码 2)。
11 基准测试
11.1 方法
-ma5 格式);nikpak 1.1.0 以 LTO 发布模式构建;FLAC 1.x -8 作为音频参考。 | |
-m3(RAR 默认)和 -m5(最佳)。通用数据测试另加 -s(固实)和 -md256m(256 MB 字典),因为 nikpak 压缩包始终固实,公平比较需要允许 RAR 同样如此。 | |
cmp,通用集用全部 10,949 个文件的 SHA-256)。 |
测试素材
音乐是合成的:它由 MIDI 渲染,包含重复段落,这对每个基于 LZ 的工具都有帮助,包括 NAC 之后的 Zstandard 阶段。真实录音包含更少的精确重复,因此绝对大小会不同。比较对一切工具一视同仁,FLAC 在同一文件上的结果证实音频编解码器本身有竞争力,但有特定素材的读者应自行测量: nikpak mt 正是做这件事。 |
11.2 媒体文件
| 9,183,956 | 2,862,744 | 2,035,223 | 1,750,706 | ||
| 2,507,557 | 1,070,290 | 966,622 | 927,973 | ||
| 2,991,820 | 1,605,879 | 1,529,219 | 1,418,532 | ||
| 17,371,848 | 11,024,411 | 9,415,519 | 9,411,898 | ||
| 4,342,996 | 3,112,135 | 2,635,819 | 2,634,669 | ||
| 2,171,520 | 844,160 | 742,462 | 740,751 | ||
| 28,362,206 | 21,467,283 (-m3) | 18,689,529 | 18,688,030 |
-m3 测量过,因此该行是比其他行更弱的比较。

媒体过滤器带来什么
| 3,580,971 | 2,035,223 | 43.2 % | |
| 1,260,607 | 966,622 | 23.3 % | |
| 1,876,722 | 1,529,219 | 18.5 % | |
| 15,585,422 | 9,415,519 | 39.6 % | |
| 3,887,183 | 2,635,819 | 32.2 % | |
| 1,078,493 | 742,462 | 31.2 % |
与 FLAC 的比较
-8 产生 9,407,019 字节。同一音频的 NAC 流为 9,425,305 字节,相差 0.2 % 以内,完成的 nikpak 压缩包为 9,415,519 字节。对于 22 kHz 单声道和 8 位版本,NAC 比 FLAC 小(2,635,446 对 2,638,954,仅音频区域 785,890 对 798,810),对于 24 位,压缩包(18.69 MB)小于 FLAC 的 19.12 MB。FLAC 在画廊文件上弱得多(2.50 MB 对 RAR 的 1.61 MB),原因见第 7.5 节;这正是其他过滤器证明价值的情形。11.3 通用数据
| 24,443,483 | 45.6 s | 1.8 s | |
| 25,862,475 | 36.2 s |
| |
| 26,002,812 | 26.7 s |
| |
| 26,536,863 | 16.7 s | 1.5 s | |
| 26,814,023 | 13.5 s |
| |
| 30,329,965 | 2.0 s |
| |
| 36,266,743 | 0.9 s | 0.8 s | |
| 50,851,230 | 14.8 s |
| |
| 50,974,773 | 9.7 s | 2.3 s |

最高级别:nikpak 产生的压缩包比 RAR 最佳小 5.5 %(24.4 对 25.9 MB)。RAR 在此级别更快(26.7 到 36.2 秒对 45.6 秒)。 相同大小: nikpak -m4在 RAR 默认固实级别 81 % 的时间内达到其约 1 % 之内(13.5 秒对 16.7 秒)。快速级别: -m2用压缩比换速度:比 RAR 固实-m3快 18 倍,大 37 %。这是为备份和流水线准备的级别,时间比最后几 MB 更重要。非固实:在这个多小文件的数据上,RAR 默认(非固实)压缩包几乎是其固实的两倍大。任何比较 nikpak 与 RAR 的人都应给 RAR 加 -s。
11.4 单个大媒体文件上的速度

| 1.45 s (-m2) | 2.54 s (-m3) | ||
| 3.14 s (-m5) | 5.87 s (-m5) | ||
| 0.28 s | 0.23 s |
11.5 加密开销
11.6 复现结果
# media: which filter wins, per file
nikpak mt song.wav tracker.mod photo.bmp
# archive with nikpak and RAR, then compare
nikpak a -q -ep -m2 test.nik *.wav
rar a -ep -m5 -ma5 test.rar *.wav
# fair comparison on many files: give RAR solid mode
rar a -r -s -m5 -ma5 -md256m data.rar data
nikpak a -m5 data.nik data
# verify
nikpak x -o+ test.nik restore\
11.7 第二轮:nikpak、RAR 7、7-Zip 和 ZIP
方法
测试素材
| 8 | 6,987,840 | ||
| 16 | 2,252,604 | ||
| 35 | 2,991,820 | ||
| 4 × 1 | 53,417,226 | ||
| 18 | 11,793,318 | ||
| 60 | 39,100,915 | ||
| 11,473 | 190,454,632 |
最高级别:压缩包大小
| 6,987,840 | 3,557,350 | 4,394,310 | 4,195,043 | 4,974,680 | |
| 2,252,604 | 1,127,607 | 1,264,245 | 1,166,855 | 1,408,085 | |
| 2,991,820 | 1,346,484 | 1,596,971 | 1,484,879 | 1,852,279 | |
| 17,760,408 | 8,731,989 | 10,460,042 | 10,666,922 | 15,225,764 | |
| 4,440,136 | 2,458,867 | 2,797,026 | 2,784,080 | 3,736,722 | |
| 2,220,090 | 606,840 | 725,416 | 642,341 | 836,989 | |
| 28,996,592 | 18,198,056 | 21,229,465 | 25,542,036 | 26,980,770 | |
| 11,793,318 | 2,741,898 | 3,519,622 | 3,259,868 | 4,223,579 | |
| 39,100,915 | 6,887,729 | 11,186,217 | 10,085,779 | 17,399,998 | |
| 190,454,632 | 28,175,618 | 33,606,893 | 28,879,398 | 62,198,510 |

快速级别:大小与创建时间
| 54.0 % · 0.39 s | 63.0 % · 2.09 s | 60.1 % · 3.51 s | 71.2 % · 0.35 s | |
| 52.4 % · 0.61 s | 56.2 % · 0.43 s | 51.9 % · 0.69 s | 62.7 % · 0.10 s | |
| 51.1 % · 0.41 s | 53.6 % · 0.71 s | 49.6 % · 1.96 s | 61.9 % · 0.24 s | |
| 49.2 % · 1.72 s | 59.9 % · 3.60 s | 60.1 % · 14.03 s | 85.7 % · 0.82 s | |
| 55.4 % · 0.58 s | 64.1 % · 0.95 s | 62.7 % · 2.14 s | 84.2 % · 0.22 s | |
| 27.4 % · 0.77 s | 33.3 % · 0.52 s | 28.9 % · 2.13 s | 38.2 % · 0.32 s | |
| 62.8 % · 2.06 s | 73.6 % · 7.54 s | 88.1 % · 13.54 s | 93.0 % · 1.19 s | |
| 35.2 % · 0.11 s | 30.4 % · 5.53 s | 27.7 % · 11.76 s | 36.0 % · 0.89 s | |
| 38.0 % · 0.22 s | 29.5 % · 8.25 s | 26.2 % · 21.85 s | 44.7 % · 1.83 s | |
| 25.3 % · 1.67 s | 18.0 % · 48.19 s | 17.0 % · 93.71 s | 32.9 % · 7.32 s |
通用数据详览
| 28,175,618 | 14.8 % | 154.3 s | 5.6 s | |
| 28,879,398 | 15.2 % | 120.9 s | 6.0 s | |
| 32,350,575 | 17.0 % | 73.6 s | 7.0 s | |
| 32,375,802 | 17.0 % | 93.7 s | 4.5 s | |
| 33,295,133 | 17.5 % | 37.8 s | 3.3 s | |
| 33,606,893 | 17.6 % | 72.4 s | 6.7 s | |
| 34,236,198 | 18.0 % | 48.2 s | 5.9 s | |
| 48,229,284 | 25.3 % | 1.7 s | 0.9 s | |
| 56,038,351 | 29.4 % | 20.2 s | 6.9 s | |
| 62,198,510 | 32.7 % | 28.2 s | 6.9 s | |
| 62,672,415 | 32.9 % | 7.3 s | 5.4 s |

从 1.1.0 到 1.2.0
| 3,306,819 | 2,741,898 | 3,259,868 | ||
| 10,417,750 | 6,887,729 | 10,085,779 | ||
| 31,322,041 | 28,175,618 | 28,879,398 |
如实地解读结果
nikpak -m5 在每个集合上都是最小的。相对 7-Zip -mx9 小 2.4 到 31.7 %,相对 RAR 7 -m5 小 10.8 到 38.4 %,相对 ZIP -9 小 19.9 到 60.4 %。在录制音频上 NAC 预测了基于 LZ 的压缩器只能匹配的东西:24 位音乐上 7-Zip 节省 12 %,nikpak 节省 37 %。 Office 文件:比 7-Zip 小 31.7 %。Deflate 再压缩把 6.6 MB .xlsx 和 1.9 MB .docx 变成普通 XML,LZMA2 的压缩远好于 Deflate(6.89 MB 对 10.09 MB)。即使 -m4 也比 7-Zip -mx9 小 1.3 % 且更快(16 秒对 26 秒)。-m5 的代价是时间:81 秒对 26 秒。 文本:小 15.9 %,用时减半。PPMd 在散文上胜出(创建 6.4 秒对 12.9 秒)。因为 PPMd 解码和编码一样慢,解压需 2.7 秒而非 0.2 秒。 源代码:小 2.4 %,微弱领先。28.2 MB 对 28.9 MB,154 秒对 121 秒。按文件类型排序并在连续样本上选择引擎(6.7)造成了差异。 快速级别 -m2:最快,不是最小。nikpak -m2 处理通用集需 1.7 秒,7-Zip -mx5 需 93.7 秒(长 56 倍),RAR 48.2 秒,ZIP 7.3 秒。它在图像和大多数音频上比 7-Zip -mx5 小(MOD 文件和画廊 WAV 大 1 到 3 %),但在文本、Office 文件和源代码上更大(通用集 49.0 %)。因此自 1.2.1 版起 nikpak 默认使用 -m5;-m2 需显式要求。 ZIP 快但处处最大。即使 nikpak -m2 也在每个集合上胜过 ZIP -9。ZIP 创建小媒体压缩包比 nikpak -m2 快,因为 Deflate 做的功远少于 NAC 编解码器,但它在文本、Office 文件和源代码上更慢。 解压。通用集解压 0.9 秒(nikpak -m2)或 5.6 秒(-m5),7-Zip 6.0 秒,RAR 6.7 秒,ZIP 6.9 秒。带再压缩 Deflate 流的压缩包解压更慢,因为每条流都重建(Office 集 2.1 秒对 0.7 秒)。 此机器上的 RAR。RAR 在此比 11.3 慢(对相近数量的源代码,-m5 -s 72 秒而非 27 秒)。机器和数据不同,因此两节不应混用。在本轮内每个工具条件相同。
这对 nikpak 意味着什么
12 nikpak 与 RAR 比较
12.1 nikpak 领先之处
-hp 开关 | ||
12.2 RAR 领先之处
| 45.6 s | ||
| 0.28 s | ||
12.3 抗量子纵观
12.4 该选哪个
选择 nikpak 用于大小和速度都重要的音频、图像、跟踪器音乐和源代码压缩包,用于脚本化备份,用于强大的默认加密,以及当开放、文档化的格式有价值时。 选择 RAR 当你需要恢复记录、分卷或自解压压缩包、原地更新,或必须与只有 RAR 工具的人交换压缩包时。 两者都用:没有什么阻止工作流用 nikpak 处理批量媒体和加密备份,同时保留 RAR 用于分发。
12.5 那 7-Zip 和 ZIP 呢?
选择 nikpak -m5 获得最小的压缩包。它在所测每个集合上比 7-Zip -mx9 小 2.4 到 31.7 %:Office 文件 31.7 %,文本 15.9 %,源代码 2.4 %。选择 nikpak -m2 用于快速备份(源代码上比 7-Zip 默认快 56 倍)。nikpak 还有更强的加密:7-Zip 用 AES-256,其 SHA-256 密钥派生不内存困难,且它只用 -mhe 隐藏文件名。 选择 7-Zip 当最高级别时间更重要时(它在大型 Office 和源代码集上更快),当你需要其默认级别在文档上就很小,或当你需要打开 7-Zip 可读的众多格式时。 选择 ZIP 只为兼容。每个操作系统无需额外软件即可打开它,但 nikpak -m5 小 19.9 到 60.4 %,且 ZIP 的传统加密很弱。
13 构建、部署与集成
13.1 用 PowerShell 在 Windows 上构建
winget install Rustlang.Rustup
$o = '--wait --passive --add Microsoft.VisualStudio.Workload.VCTools'
$o += ' --includeRecommended'
winget install Microsoft.VisualStudio.2022.BuildTools --override $o
winget 不可用,从 rustup.rs 安装 Rust,并安装带使用 C++ 的桌面开发工作负载的Visual Studio 生成工具。然后,在包含源代码的文件夹中:.\build.ps1 # builds dist\nikpak.exe and dist\unNik.exe
.\build.ps1 -Test # runs the unit tests first
# if PowerShell refuses to run scripts:
powershell -ExecutionPolicy Bypass -File .\build.ps1
build.ps1 检查 Cargo 是否已安装(若没有则说明如何安装),运行构建,失败时解释常见原因,并把可执行文件复制到 dist\nikpak.exe。Windows 安装程序
.\build.ps1 -Installer(或 npm run installer)还用 Inno Setup 6.3 或更新版本构建安装程序 dist\nikpak--setup.exe(用 winget install JRSoftware.InnoSetup 一次性安装)。脚本是 installer\nikpak.iss;版本取自 Cargo.toml。这个安装文件正是上传到共享软件和下载站点的东西。默认只为当前用户安装,无需管理员权限或 UAC 提示,安装到 %LOCALAPPDATA%\Programs\NikPak。其第一页提供“为所有用户安装”(Program Files,需要管理员权限)。 它显示 LICENSE.txt 供接受,并安装 nikpak.exe、unNik.exe、图标、LICENSE.txt、THIRD-PARTY-NOTICES.txt 和 CHANGELOG.md。它添加开始菜单项、可选桌面图标,以及按需把文件夹加入命令行的 PATH。它在设置 > 应用中注册卸载程序。 快捷方式:开始菜单中的 NikPak、unNik 和许可证;桌面上的 NikPak(始终)以及桌面上的 unNik(可选)。 .nik 文件始终被注册(自 1.5.2 起):它们获得自己的图标(nikfile.ico,一页带拉链,像 .zip 文件)、类型名“NikPak archive”,双击在 unNik 中打开(右键菜单中的“用 unNik 打开”)。unNik 也列在“打开方式”和默认应用中。卸载程序移除该注册。如果 .nik 文件已设置为用其他程序打开,Windows 保留该选择,直到在“打开方式”中选过一次 unNik。 最后的“Launch NikPak”以普通用户启动 NikPak,绝不以管理员,因此拖放正常。更新会覆盖旧版本安装(固定 AppId)。%APPDATA%\nikpak 中的许可证在更新和卸载时保留。安装程序从不含密钥或密钥文件。 安装程序跟随 Windows 以英语或法语运行。发布前,用代码签名证书为 nikpak.exe 和安装程序签名,以免 Windows SmartScreen 警告未知发布者。
nikpak.exe、unNik.exe、两个安装程序和 SHA256SUMS.txt——复制到 binaries\,重建网站并通过 FTP 上传(-NoUpload 跳过上传)。第二个安装程序 unnik--setup.exe(installer\unnik.iss)只安装 unNik,免费的压缩包浏览器;当 NikPak 已安装时它只安装该程序,因此菜单不会重复。13.2 用 npm 构建
package.json,其脚本只是调用 Cargo,因此生活在 Node.js 工作流中的开发者可以输入熟悉的命令:npm run build # cargo build --release
npm run dist # build.ps1 -> dist\nikpak.exe
npm test # cargo test --release
npm run clean # cargo clean
13.3 自包含可执行文件
.cargo/config.toml 为 Windows MSVC 目标静态链接 C 运行库。因此生成的 nikpak.exe(带图形界面几 MB,无界面约 2.3 MB)没有 DLL 依赖,在运行它的机器上不需要Visual C++ 可再发行组件。把它复制到 PATH 上的文件夹即可在任何地方使用。发布配置启用完全优化、链接时优化、单一代码生成单元、符号剥离和 panic = abort,以获得小而快的二进制文件。13.4 macOS 和 Linux
./build.sh # builds and copies the result to dist/nikpak
# or: cargo build --release
sudo cp dist/nikpak /usr/local/bin/
xcode-select --install);在 Debian 或 Ubuntu 上安装 C 编译器(sudo apt install build-essential)。Rust 本身来自 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh。压缩库由 Cargo 从其 C 源编译,因此不需要系统库。./package-unix.sh 制作,它构建 nikpak 和 unNik,并用 install.sh 打包成 binaries\nikpak--macos.zip(通用二进制:Intel + Apple 芯片)或 binaries\nikpak--linux-.tar.gz。在 Linux 上设 ZIG=1 以用 cargo-zigbuild 针对 glibc 2.28 构建,使程序也能在较旧发行版上运行。13.5 依赖
Cargo.lock 中,它是源包的一部分,因此每次构建都用相同的代码。zstd | |
chacha20poly1305 | |
argon2 | |
rand | |
zeroize | |
rpassword | |
crc32fast | |
glob | |
liblzma | |
ppmd-rust | |
preflate-rs | |
eframe / egui | |
rfd | |
ed25519-dalek | |
rustybuzz, unicode-bidi |
13.6 脚本化
$archive = "D:\Backups\docs-$(Get-Date -Format yyyy-MM-dd).nik"
# the password comes from a file or secret store, not from the script
$env:NIKPAK_PASSWORD = Get-Content "$env:USERPROFILE\.nikpak-secret"
nikpak a -p -m3 -inul $archive "$env:USERPROFILE\Documents"
if ($LASTEXITCODE -gt 1) { throw "nikpak failed: $LASTEXITCODE" }
nikpak t -inul $archive # verify what was written
if ($LASTEXITCODE -ne 0) { throw "archive verification failed" }
export NIKPAK_PASSWORD="$(cat ~/.nikpak-secret)"
nikpak a -p -m3 -inul "backup-$(date +%F).nik" ~/Documents || [ $? -eq 1 ]
nikpak lb backup-2026-10-16.nik | grep -i '\.wav$'
13.7 Total Commander
nik;打包用 a,解包用 x;让前端为长文件列表传递 @listfile;无人值守解压给 -o+ 或 -y;用 -p 或 NIKPAK_PASSWORD 变量传递密码,因为图形前端没有可供提示的控制台。14 测试与验证
14.1 单元测试
cargo test --release 运行三十四个自动化测试:
14.2 端到端测试
每个基准压缩包都被解压并在几个级别上与其源逐字节比较(10,949 文件集用 SHA-256)。 创建了一个混合压缩包(WAV、MOD、BMP、文本、随机数据、子文件夹),列出、测试、完全解压,并从中部解压了单个文件。 同样的压缩包以加密创建,用正确和错误密码测试,并解压。 上一格式版本(1.0)写入的压缩包被 1.1 打开。 通过伪终端演练交互式密码输入:匹配的密码、不匹配、空输入(生成)、打开时的正确和错误密码。
14.3 攻击测试
14.4 测试发现的缺陷
15 局限与路线图
15.1 当前局限
-o+ 覆盖。 | |
-m4 和 -m5 压缩包使用 128 MiB 窗口;解压它们需要这么多内存。 | |
Single-threaded and the slowest level. Creating needs up to about 1.1 GB of memory, extracting up to about 350 MB. | |
cargo test --release。 |
15.2 路线图
Cargo.lock 保留在仓库中以使构建可复现,并在你支持的每个平台的持续集成任务中运行 cargo test --release。A 附录 A:格式常量与限制
89 4E 49 4B 0D 0A 1A 0A | |
u32 大端长度 | |
-mt) |
B 附录 B:术语表