diff --git a/doc/diagrams/seal-batch-flush-flow.mmd b/doc/diagrams/seal-batch-flush-flow.mmd
new file mode 100644
index 0000000..c3d113e
--- /dev/null
+++ b/doc/diagrams/seal-batch-flush-flow.mmd
@@ -0,0 +1,16 @@
+%% 封装主循环(第 7.8 节 封装流程总览)
+%% 生成: npm exec --yes --package=@mermaid-js/mermaid-cli -- mmdc -i seal-batch-flush-flow.mmd -o seal-batch-flush-flow.png -b white -w 1200
+flowchart TD
+ start([开始]) --> A{"宿主已声明输入结束
且无新载荷?"}
+
+ A -->|否| B["输入单元入队
滚动摘要更新 H"]
+ B --> C{"批刷写阈值
S(Q) ≥ T_batch?"}
+ C -->|是| D["Item 写出
Block 元信息更新
清空 Q"]
+ C -->|否| A
+ D --> A
+
+ A -->|是| E{"Q 非空?"}
+ E -->|是| D2["Item 写出
Block 元信息更新
清空 Q"]
+ E -->|否| F["收尾落盘"]
+ D2 --> F
+ F --> endnode([结束])
diff --git a/doc/diagrams/seal-batch-flush-flow.png b/doc/diagrams/seal-batch-flush-flow.png
new file mode 100644
index 0000000..cd0131d
Binary files /dev/null and b/doc/diagrams/seal-batch-flush-flow.png differ
diff --git a/doc/diagrams/unseal-main-flow.mmd b/doc/diagrams/unseal-main-flow.mmd
new file mode 100644
index 0000000..ac7f7d7
--- /dev/null
+++ b/doc/diagrams/unseal-main-flow.mmd
@@ -0,0 +1,19 @@
+%% 解封主循环(第 8.5 节 解封流程总览)
+%% npx @mermaid-js/mermaid-cli -i unseal-main-flow.mmd -o unseal-main-flow.png -b white -w 1200
+flowchart TD
+ start([开始]) --> A["读 Header 并校验
magic / version"]
+ A --> B["计算 content_size
初始化 H = H0,n = 0"]
+ B --> C{"n 小于 item_number?"}
+
+ C -->|否| D{"H 等于 data_hash?"}
+ D -->|是| endnode([成功结束])
+ D -->|否| err1([完整性错误])
+
+ C -->|是| E["读 item_size 与 cipher_payload"]
+ E --> F["认证解密得批包 B"]
+ F --> G["拆分 B 得输入单元"]
+ G --> H["逐条输出 payload
并用输入单元更新 H"]
+ H --> C
+
+ F -.->|失败| err2([认证或格式错误])
+ G -.->|失败| err2
diff --git a/doc/diagrams/unseal-main-flow.png b/doc/diagrams/unseal-main-flow.png
new file mode 100644
index 0000000..ec35a0d
Binary files /dev/null and b/doc/diagrams/unseal-main-flow.png differ
diff --git a/doc/sealed-format-standard-zh.tex b/doc/sealed-format-standard-zh.tex
new file mode 100644
index 0000000..947d74e
--- /dev/null
+++ b/doc/sealed-format-standard-zh.tex
@@ -0,0 +1,1464 @@
+\documentclass[11pt,a4paper]{article}
+\usepackage[UTF8,fontset=none]{ctex}
+\usepackage[margin=2.5cm]{geometry}
+\usepackage{hyperref}
+\usepackage{longtable}
+\usepackage{booktabs}
+\usepackage{array}
+\usepackage{enumitem}
+\usepackage{titlesec}
+\usepackage{graphicx}
+
+\title{Meta-Encryptor Sealed 文件格式标准(中文草案)}
+\author{YeeZ Tech}
+\date{\today}
+
+\setlist[itemize]{leftmargin=2em}
+\setlist[enumerate]{leftmargin=2em}
+\newcommand{\ttf}[1]{\texttt{\detokenize{#1}}}
+% 排版约定:字段名用 \ttf{field_name}(勿在参数内写 \_);算法变量用 $H_0$ 等;
+% 多项并列写在同一 enumerate 项时,用嵌套 itemize 拆开,勿用长逗号串。
+\newcommand{\rollhash}{\mbox{滚动摘要}}
+\newcommand{\secref}[1]{第~\ref{#1}~节}
+\XeTeXlinebreaklocale "zh"
+\XeTeXlinebreakskip = 0pt plus 0.15em minus 0.05em
+\setCJKmainfont{PingFang SC}
+\setCJKsansfont{PingFang SC}
+\setCJKmonofont{PingFang SC}
+
+% 减轻正文过长行导致的 Overfull \hbox(中文技术长句、交叉引用)
+\setlength{\emergencystretch}{2.5em}
+\setlength{\tolerance}{2000}
+\hbadness=10000
+\sloppy
+
+\begin{document}
+\maketitle
+\section*{文档元数据}
+\begin{longtable}{>{\raggedright\arraybackslash}p{3.2cm} >{\raggedright\arraybackslash}p{10.0cm}}
+ \toprule
+ 字段 & 内容 \\
+ \midrule
+ \endhead
+ 文档标识 & \ttf{YEEZ-SEALED-FORMAT-ZH} \\
+ 文档状态 & Draft(草案) \\
+ 文档版本 & v0.1.0 \\
+ 发布日期 & \today \\
+ 语言 & 中文(规范性文本) \\
+ 适用范围 & Meta-Encryptor 生态下 \ttf{.sealed} 文件读写实现 \\
+ 解释优先级 & 本标准正文优先于示例代码;示例仅作实现参考 \\
+ 变更记录策略 & 仅在“对外发布版本”时更新变更记录;日常本地迭代与排版修订不单独记入版本历史 \\
+ \bottomrule
+\end{longtable}
+
+\section*{发布级变更记录}
+\begin{longtable}{>{\raggedright\arraybackslash}p{2.2cm} >{\raggedright\arraybackslash}p{2.8cm} >{\raggedright\arraybackslash}p{6.8cm}}
+ \toprule
+ 版本 & 日期 & 说明 \\
+ \midrule
+ \endhead
+ \ttf{v0.1.0} & \today & 首个公开草案:定义文件结构、密码学规范、封装/解封流程、错误码与附录。 \\
+ \bottomrule
+\end{longtable}
+
+\tableofcontents
+\newpage
+
+\section{引言}
+\subsection{目的}
+本标准用于定义 \texttt{.sealed} 文件格式的二进制结构、加密语义、封装与解封流程、兼容性规则与一致性要求,确保不同实现之间的互操作性与可验证性。
+
+\subsection{范围}
+本标准适用于使用 Meta-Encryptor 生态读写 \texttt{.sealed} 文件的实现,包括但不限于 Node.js 与浏览器环境实现。本文档不限定上层业务协议。
+
+\subsection{读者对象}
+本标准面向以下读者:
+\begin{itemize}
+ \item 文件格式实现者;
+ \item 安全审计人员;
+ \item 平台集成与运维工程师;
+ \item 隐私计算数据处理链路设计人员。
+\end{itemize}
+
+\subsection{一致性语言}
+本文档使用 RFC 2119 含义的以下术语:
+\begin{itemize}
+ \item \textbf{必须(MUST)}:对文件布局、字段取值、可验证一致性及失败语义的绝对要求;
+ \item \textbf{应当(SHOULD)}:推荐要求,除非有充分理由;
+ \item \textbf{可以(MAY)}:可选行为。
+\end{itemize}
+
+\textbf{适用范围:} 第~\ref{sec:format-chapter} 章、第~\ref{sec:crypto-chapter} 章,以及各章中对上述内容的直接引用,使用 MUST/SHOULD/MAY 表述\textbf{格式与校验}义务。
+第~\ref{sec:seal-chapter}、\ref{sec:unseal-chapter} 章给出\textbf{参考封装/解封流程},描述 Meta-Encryptor 生态常用的实现顺序;除明确援引格式或校验条款外,流程步骤本身不以 MUST 约束具体算法或数据结构(如读指针、队列)。
+
+\section{术语与记号}
+\subsection{术语}
+\begin{itemize}
+ \item \textbf{Item}:\texttt{.sealed} 内容区中\textbf{最小不可分}加密单元;本标准在格式与流程上的规范性边界以 Item 为准(见第~\ref{sec:content-region} 节);
+ \item \textbf{Block}:由若干 Item 组成的逻辑分组,并在元信息区有对应索引项;
+ \item \textbf{Header}:文件尾部固定 64 字节头结构;
+ \item \textbf{Block Info}:描述单个 Block 的 32 字节索引结构;\textbf{Block Infos 区}为由若干条 Block Info 顺序拼接而成的索引区域;
+ \item \textbf{Data Hash}:Header 字段 \ttf{data_hash} 所承载的摘要;对全部\textbf{输入单元}按封装全局顺序滚动计算,见第~\ref{sec:rolling-hash} 节;
+ \item \textbf{业务载荷}:宿主提交的一段载荷字节串,记为 \ttf{payload},长度为 \ttf{L};业务语义与切分由应用层决定;解封侧按封装顺序还原的 \ttf{payload} 由集成层从输入单元解码得到(见第~\ref{sec:input-normalization} 节);
+ \item \textbf{输入单元}:写入批包前的变长字节串(实现中常记 \ttf{nt_input}),须满足第~\ref{sec:input-normalization} 节;多条输入单元可装入同一 Item 的批包 \ttf{B},再整体加密为一条 Item;
+ \item \textbf{批包}:将若干条输入单元按第~\ref{sec:batch-package} 节容器格式首尾拼接后的字节串,记为 \ttf{B};一个 \ttf{B} 经加密后对应内容区\textbf{一条} Item;
+ \item \textbf{批刷写阈值} \ttf{T_batch}:封装实现参数,判定何时将一批输入单元打成 \ttf{B} 并写出 Item;规则见第~\ref{sec:batch-flush-threshold} 节;队列调度见第~\ref{sec:seal-total-algorithm} 节;
+ \item \textbf{Block 内 Item 数上限} \ttf{N_block}:封装实现参数,限定单个 Block 所含 Item 条数的上界;划分规则见第~\ref{sec:block-split} 节;与 Block Info 字段的对应见第~\ref{sec:block-meta-fields} 节。
+\end{itemize}
+
+\subsection{数据类型}
+\begin{itemize}
+ \item \texttt{BYTE}:8 位无符号整数;
+ \item \texttt{UINT32}:32 位无符号整数;
+ \item \texttt{UINT64}:64 位无符号整数;
+ \item \texttt{BYTESTRING[n]}:长度为 \texttt{n} 的字节串;
+ \item \texttt{VARBYTES}:变长字节串(长度由外层字段定义)。
+\end{itemize}
+
+\subsection{字节序}
+除非另有说明,多字节整数均使用\textbf{小端序(Little Endian)}。
+
+\section{设计目标与安全模型}
+\subsection{设计目标}
+\begin{itemize}
+ \item 提供面向隐私计算链路的数据封装格式;
+ \item 支持流式封装与流式解封;
+ \item 支持断点续传场景下的一致性恢复;
+ \item 支持跨运行时(Node.js / Browser)一致解封。
+\end{itemize}
+
+\subsection{安全属性}
+\begin{itemize}
+ \item 机密性:明文对未授权方不可见;
+ \item 完整性:篡改应可被检测;
+ \item 认证性:每个 Item 具备认证加密保护。
+\end{itemize}
+
+\subsection{非目标}
+\begin{itemize}
+ \item 本标准不定义业务语义级字段;
+ \item 本标准不定义应用层权限模型;
+ \item 本标准不保证无索引情况下的记录级随机查询性能。
+\end{itemize}
+
+\section{文件格式总览}
+\subsection{高层布局}
+\texttt{.sealed} 文件采用“数据在前、元信息在后”的尾部头设计。文件按字节从前到后布局如下:
+\begin{center}
+ \texttt{[Content Region][Block Infos][Header(64B)]}
+\end{center}
+\begin{itemize}
+ \item \ttf{Content Region}:密文内容区,由若干 Item 顺序拼接组成;Item 为内容区最小加密单元。内容区按块组织,每块由若干连续的 Item 组成,详见第~\ref{sec:content-region} 节;
+ \item \ttf{Block Infos}:块索引区,由若干 Block Info 顺序拼接而成;每条 Block Info 固定 32 字节,描述一个块在内容区内的索引,条数由 Header 给出,详见第~\ref{sec:block-infos} 节;
+ \item \ttf{Header}:固定 64 字节,位于文件末尾,由单个 Header 记录构成,包含魔数、版本、计数和摘要,详见第~\ref{sec:header-region} 节;
+\end{itemize}
+该布局允许写入端在不知道最终计数的情况下先持续写入内容,再在结束时一次性写入索引和 Header。
+
+\subsection{读取模型}\label{sec:read-model}
+由于 Header 位于尾部,标准定义两种等价读取模型:
+\begin{itemize}
+ \item \textbf{尾读模型}:读取器先从文件末尾读取 64B Header(字段布局见第~\ref{sec:header-region} 节),再按 Header.\ttf{block_number} 读取 Block Infos 区,再读取内容区;
+ \item \textbf{逻辑前置模型}:中间层先尾读 Header,并在解封管道中将 Header 逻辑前置,再按顺序喂入内容区数据。
+\end{itemize}
+两种模型 MUST 产出一致的解析结果。
+
+\subsection{区域长度计算}\label{sec:region-length}
+本小节使用的符号先定义如下:
+\begin{itemize}
+ \item \ttf{block_number}:\ttf{Header} 结构中的字段,表示 Block Info 条目数量(类型为 \ttf{UINT64(LE)});
+ \item \ttf{N}:\ttf{block_number} 的记号化表示,即 \ttf{N = block_number};
+ \item \ttf{file_size}:单个 \texttt{.sealed} 文件的总字节数;由打开文件、对象大小或传输层长度字段等在\textbf{读取 Header 之前}由实现获知,不得通过解析 Header 反推。
+ \item \ttf{header_size}:Header 区总长度(单位:字节);
+ \item \ttf{block_infos_size}:Block Infos 区总长度(单位:字节);
+ \item \ttf{content_size}:Content Region 区总长度(单位:字节)。
+\end{itemize}
+
+给定文件总长度 \ttf{file_size},则:
+\begin{itemize}
+ \item \ttf{header_size = 64}
+ \item \ttf{block_infos_size = 32 * N}
+ \item \ttf{content_size} $=$ \ttf{file_size} $-$ \ttf{header_size} $-$ \ttf{block_infos_size}
+\end{itemize}
+实现 MUST 校验 \ttf{content_size > 0}。若不满足,MUST 视为格式错误。
+
+\section{二进制格式规范}\label{sec:format-chapter}
+\subsection{规范约定}
+\begin{itemize}
+ \item 除特别说明外,整数类型均为无符号;
+ \item 除特别说明外,所有多字节整数均为小端序(LE);
+ \item 偏移均以“所在结构体起始地址”为基准;
+ \item 本章字段名使用实现同名风格(如下划线命名)以便互操作。
+\end{itemize}
+
+\subsection{Header 区}\label{sec:header-region}
+Header 区位于文件末尾,长度固定为 64 字节。本区由单个 Header 记录构成,保存格式识别、版本、块与 Item 计数及数据摘要等元信息。
+
+\subsubsection{Header 记录(64 字节)}
+Header 记录占用 64 字节,字段布局如下:
+\begin{longtable}{>{\raggedright\arraybackslash}p{3.2cm} >{\raggedright\arraybackslash}p{1.3cm} >{\raggedright\arraybackslash}p{1.3cm} >{\raggedright\arraybackslash}p{6.8cm}}
+ \toprule
+ 字段名 & 偏移 & 长度 & 说明 \\
+ \midrule
+ \endhead
+ \ttf{magic_number} & 0 & 8 & 文件魔数(BYTESTRING[8]) \\
+ \ttf{version_number} & 8 & 8 & 格式版本(UINT64, LE) \\
+ \ttf{block_number} & 16 & 8 & Block 数量(UINT64, LE) \\
+ \ttf{item_number} & 24 & 8 & Item 数量(UINT64, LE) \\
+ \ttf{data_hash} & 32 & 32 & 数据摘要(BYTESTRING[32]) \\
+ \bottomrule
+\end{longtable}
+\textbf{字段语义:}
+\begin{itemize}
+ \item \ttf{magic_number}:文件类型标识(\ttf{BYTESTRING[8]});
+ \item \ttf{version_number}:格式版本;
+ \item \ttf{block_number}:Block Info 条目数量;维护规则见第~\ref{sec:block-meta} 节;
+ \item \ttf{item_number}:内容区 Item 总数量(见第~\ref{sec:content-region} 节);每写出一条 Item 递增,见第~\ref{sec:item-generation} 节;
+ \item \ttf{data_hash}:对全部输入单元(按封装全局顺序,字节串与批包记录体一致)滚动计算得到的最终摘要(\ttf{BYTESTRING[32]})。
+ 累计规则见第~\ref{sec:rolling-hash} 节;输入单元要求见第~\ref{sec:input-normalization} 节;
+ 算法与写入见第~\ref{sec:rolling-hash}、\ref{sec:seal-finalize} 节;
+ 解封校验见第~\ref{sec:integrity-check} 节。
+\end{itemize}
+
+\subsubsection{Header 识别与版本兼容规则}\label{sec:header-compat}
+本小节统一约束 \ttf{magic_number} 与 \ttf{version_number} 的识别、校验与版本演进策略:
+\begin{itemize}
+ \item \textbf{文件}:指单个 \ttf{.sealed} 文件实例;
+ \item \textbf{实现}:指遵循本标准的读写器(Writer/Reader);
+ \item \textbf{未来版本}:指 \ttf{version_number} 高于当前版本的格式版本。
+\end{itemize}
+\begin{itemize}
+ \item 每个 \ttf{.sealed} 文件 MUST 在 Header 中携带 \ttf{version_number};
+ \item \textbf{文件识别}:\ttf{magic_number} MUST 等于约定魔数;
+ \item \textbf{版本识别}:\ttf{version_number} MUST 位于实现声明的支持范围内;
+ \item 读取实现 MUST 在进入内容解析前完成上述检查;
+ \item 任一检查失败时,读取器 MUST 拒绝继续解析。
+ \item 新版本在可行时 SHOULD 保持向后兼容;若无法兼容,MUST 提供迁移或拒绝策略说明。
+\end{itemize}
+
+\subsubsection{当前版本 Header 字段约定值}
+当前版本(\ttf{version_number = 2})的 Header 字段约定值如下:
+\begin{itemize}
+ \item \ttf{magic_number = 1fe2ef7f3ed18847}
+\end{itemize}
+若后续版本调整上述字段取值或字段语义,\ttf{version_number} MUST 递增并提供兼容说明。
+
+\subsection{Block Infos 区}\label{sec:block-infos}
+Block Infos 区位于 Content Region 与尾部 Header 之间,总长度 \ttf{block_infos_size}
+及其在文件中的起止位置由第~\ref{sec:region-length} 节给出。
+
+本区由 \ttf{block_number} 条 Block Info 顺序拼接而成。本文所称单条 \textbf{Block Info},即长度为 32 字节的索引记录;\textbf{Block Infos 区}即上述全部 Block Info 按序拼接形成的区域。本区总长度为 \ttf{32 * block_number}。第 \ttf{i} 条 Block Info(\ttf{i} 自 0 起)在本区内的字节偏移为 \ttf{32 * i}。
+
+\subsubsection{Block Info 记录(每项 32 字节)}
+每条 Block Info 对应 Content Region 中的一个 Block:在 Item 下标维度标出该 Block 覆盖的 Item 范围,在内容区字节偏移维度标出上述 Item 序列所占用的字节范围。两条范围彼此对应。字段布局如下:
+\begin{longtable}{>{\raggedright\arraybackslash}p{3.4cm} >{\raggedright\arraybackslash}p{1.2cm} >{\raggedright\arraybackslash}p{1.2cm} >{\raggedright\arraybackslash}p{6.8cm}}
+ \toprule
+ 字段名 & 偏移 & 长度 & 说明 \\
+ \midrule
+ \endhead
+ \ttf{start_item_index} & 0 & 8 & 起始 Item 下标(含) \\
+ \ttf{end_item_index} & 8 & 8 & 结束 Item 下标(不含) \\
+ \ttf{start_file_pos} & 16 & 8 & 内容区内起始字节偏移(非源明文文件偏移) \\
+ \ttf{end_file_pos} & 24 & 8 & 内容区内结束字节偏移(半开,非源明文文件偏移) \\
+ \bottomrule
+\end{longtable}
+\textbf{字段语义:}
+\begin{itemize}
+ \item \ttf{start_item_index}、\ttf{end_item_index}:该 Block 内 Item 的下标半开区间 \ttf{[start, end)},下标从 0 起计;
+ \item \ttf{start_file_pos}、\ttf{end_file_pos}:本 Block 在 \texttt{.sealed} 文件 Content Region 内占据的字节半开区间 \ttf{[start, end)},偏移以内容区首字节为 \texttt{0};\textbf{不}表示业务侧源文件内偏移(见第~\ref{sec:block-meta-fields} 节)。
+\end{itemize}
+全体 Block Info 共同构成 Content Region 的块级索引:
+\begin{itemize}
+ \item Item 下标维度:各 Block 的 \ttf{start_item_index}、\ttf{end_item_index} 以半开区间无空隙、无重叠地划分
+ \ttf{[0, item_number)};
+ \item 内容区字节维度:各 Block 的 \ttf{start_file_pos}、\ttf{end_file_pos} 以内容区起点为 0,同样无隙、无重叠地划分 \ttf{[0, content_size)}。
+\end{itemize}
+
+\subsection{Content Region 区}\label{sec:content-region}
+Content Region 区位于文件最前部,在 Block Infos 区与 Header 区之前;总长度 \ttf{content_size}
+及其在文件中的起止位置由第~\ref{sec:region-length} 节给出。
+
+本区由 \ttf{item_number} 条 Item 顺序拼接而成。本文所称单条 \textbf{Item},即内容区\textbf{最小不可分}加密单元;\textbf{Content Region 区}即上述全部 Item 按序拼接形成的区域。内容区按块组织,每块由若干连续的 Item 组成。各条 Item 长度随密文载荷变化,Item 之间无固定步长。
+
+\subsubsection{Item 记录}\label{sec:item-record}
+每条 Item 由前置长度字段与密文载荷顺序组成,按字节从前到后布局如下:
+\begin{center}
+ \texttt{[item\_size (8B)][cipher\_payload (item\_size B)]}
+\end{center}
+完整展开(含 \texttt{cipher\_payload} 内部字段)为:
+\begin{center}
+ \small
+ \texttt{[item\_size (8B)][encrypted\_data (变长)][iv (12B)][ephemeral\_public\_key (64B)][gcm\_tag (16B)]}
+\end{center}
+字段说明:
+\begin{enumerate}
+ \item \texttt{item\_size}:8 字节无符号整数(LE);
+ \item \texttt{cipher\_payload}:长度为 \texttt{item\_size} 的字节串。
+\end{enumerate}
+\textbf{注意:} \ttf{item_size} 仅描述当前 Item 的密文载荷长度,不包含其自身 8 字节长度字段;其取值范围由 \ttf{UINT64(LE)} 确定,\ttf{cipher_payload} 的字节长度 MUST 等于 \ttf{item_size},且 MUST NOT 超过 \ttf{UINT64} 可表示的最大值。
+
+\subsubsection{\texttt{cipher\_payload} 内部结构}\label{sec:cipher-payload-layout}
+\ttf{cipher_payload} 长度为 \ttf{item_size},自其起始偏移 0 起按字节从前到后布局如下:
+\begin{center}
+ \texttt{[encrypted\_data (变长)][iv (12B)][ephemeral\_public\_key (64B)][gcm\_tag (16B)]}
+\end{center}
+后三段长度在当前版本固定,\ttf{encrypted_data} 变长;四段顺序拼接,字段说明如下:
+\begin{enumerate}
+ \item \texttt{encrypted\_data}(变长);
+ \item \texttt{iv}(12B);
+ \item \texttt{ephemeral\_public\_key}(64B);
+ \item \texttt{gcm\_tag}(16B)。
+\end{enumerate}
+\textbf{字段语义:}
+\begin{itemize}
+ \item \ttf{encrypted_data}:\ttf{AES-128-GCM} 密文;其明文为批包 \ttf{B},即本条 Item 对应的整段加密前批包字节串(见第~\ref{sec:batch-package} 节),加解密参数见第~\ref{sec:crypto-chapter} 节;
+ \item \ttf{iv}:本条 Item 的 \ttf{AES-128-GCM} Nonce(常称 IV);供加解密双方标识本次独立 GCM 运算,避免同一密钥下因 Nonce 复用而产出相同密文。长度固定 12 字节,取值由安全随机源逐 Item 生成,见第~\ref{sec:randomness} 节;
+ \item \ttf{ephemeral_public_key}:本 Item 临时密钥对的公钥;采用椭圆曲线型号 \texttt{secp256k1} 的未压缩公钥,去掉首字节 \texttt{0x04} 后保留 \texttt{x||y},长度固定 64 字节;
+ \item \ttf{gcm_tag}:\ttf{AES-128-GCM} 认证标签;长度固定 16 字节,由 GCM 运算得到。
+\end{itemize}
+\textbf{当前版本固定长度与偏移:}
+\begin{itemize}
+ \item \ttf{encrypted_data_len = item_size - 12 - 64 - 16};
+ \item \ttf{iv} 起始于 \ttf{encrypted_data_len},长度 12 字节;
+ \item \ttf{ephemeral_public_key} 起始于 \ttf{encrypted_data_len + 12},长度 64 字节;
+ \item \ttf{gcm_tag} 起始于 \ttf{encrypted_data_len + 76},长度 16 字节;
+ \item 若 \ttf{encrypted_data_len < 0},读取器 MUST 返回格式错误。
+\end{itemize}
+上述 12、64、16 字节为当前版本规定的尾字段长度;\ttf{iv}、\ttf{ephemeral_public_key}、\ttf{gcm_tag} 与 \ttf{encrypted_data} 的字节值逐 Item 变化,除长度外无固定取值。Item 密文封装使用的前缀字节为 \texttt{0x02},见第~\ref{sec:ref-derive-params} 节。
+
+\subsection{批包布局}\label{sec:batch-package}
+术语「批包」及记号 \ttf{B} 见第 2 章。本小节规定 \ttf{B} 的容器字节布局(加密前明文侧结构,经第~\ref{sec:content-encryption} 节编码后再送入 GCM)。
+
+\textbf{与 Item 的关系:} 内容区每条 Item 的 \ttf{cipher_payload} 由\textbf{一个}批包 \ttf{B} 加密得到(见第~\ref{sec:item-record}、\ref{sec:content-encryption} 节)。
+
+\textbf{布局(当前版本):}
+\begin{center}
+ \texttt{[package\_id (4B)][record\_count (8B)] * record}
+\end{center}
+其中每条 \texttt{record} 为:
+\begin{center}
+ \texttt{[record\_len (8B)][unit (record\_len B)]}
+\end{center}
+其中 \texttt{unit} 为一条输入单元的完整字节串(须满足第~\ref{sec:input-normalization} 节)。
+字段语义:
+\begin{itemize}
+ \item \ttf{package_id}:\ttf{UINT32(LE)},当前版本 MUST 为 \texttt{0x82c4e8d8};
+ \item \ttf{record_count}:\ttf{UINT64(LE)},批内输入单元条数;
+ \item \ttf{record_len}:本条 \texttt{unit} 的字节长度(\ttf{UINT64(LE)});
+ \item 批内记录顺序 MUST 与封装侧提交输入单元的全局顺序一致。
+\end{itemize}
+
+\textbf{构造与拆分:}
+\begin{itemize}
+ \item \textbf{构造}:将若干条输入单元按上述布局首尾拼接为 \ttf{B};
+ \item \textbf{拆分}:从 \ttf{B} 解析各字段并依次取出各条 \texttt{unit};\ttf{package_id}、长度字段与剩余字节不一致时 MUST 判为格式错误。
+\end{itemize}
+实现行为 MUST 与本节布局一致;与参考实现源码符号的对照见附录~\ref{app:ref-impl-symbols}。
+
+\subsection{约束与限制}
+\begin{itemize}
+ \item Header 固定长度为 64 字节;
+ \item Block Info 固定长度为 32 字节;
+ \item Item 数量与 Block 数量 MUST 与实际内容一致;
+ \item 超出实现上限时 MUST 返回错误。
+\end{itemize}
+
+\subsection{规范性解析流程}
+实现方在读取 \texttt{.sealed} 时 MUST 按以下顺序执行:
+\begin{enumerate}
+ \item 从文件末尾读取 64 字节 Header;
+ \item 校验 \ttf{magic_number} 和 \ttf{version_number};
+ \item 基于 \ttf{block_number} 计算并定位 Block Infos 区;
+ \item 校验 \ttf{content_size} 为正且区域不重叠;
+ \item 顺序解析内容区 Item:先读 \ttf{item_size},再读 \ttf{cipher_payload};
+ \item 每个 Item 执行长度合法性检查和密码学认证检查;
+ \item 当解析 Item 数量达到 \ttf{item_number} 时结束并进入完整性校验阶段。
+\end{enumerate}
+全量顺序解封时,上述 MUST 条款与第~\ref{sec:unseal-chapter} 章参考流程及第~\ref{sec:unseal-total-algorithm} 节应对齐;块级随机访问见第 9 章。
+
+\subsection{规范性校验规则}
+\begin{itemize}
+ \item \textbf{计数校验}:实际解析 Item 数 MUST 等于 \ttf{item_number};
+ \item \textbf{区间校验}:最后一个 Block 的 \ttf{end_item_index} SHOULD 等于 \ttf{item_number}(Block Info 语义见第~\ref{sec:block-meta-fields} 节);
+ \item \textbf{边界校验}:任一 \ttf{start > end} 或越界偏移 MUST 判为错误;
+ \item \textbf{摘要校验}:实现 SHOULD 按第~\ref{sec:rolling-hash} 节重算摘要并比对 Header.\ttf{data_hash},不一致 MUST 报错(亦见第~\ref{sec:integrity-check} 节);
+ \item \textbf{版本校验}:未知版本 MAY 拒绝处理;若处理 MUST 在实现文档中声明兼容边界。
+\end{itemize}
+
+\section{密码学规范}\label{sec:crypto-chapter}
+本章规定 \ttf{version_number = 2} 下 Item 密文载荷的密码学处理要求。
+第~\ref{sec:key-derivation}、\ref{sec:aes-gcm}、\ref{sec:content-encryption} 节按\textbf{模块}给出输入与输出;其余小节为概念、常量或约束说明。
+符号 \ttf{B}(批包)含义见第 2 章;\ttf{B} 的字节布局见第~\ref{sec:batch-package} 节。
+
+\subsection{曲线与密钥}\label{sec:curve-keys}
+本小节规定逐条 Item 协商对称密钥所需的曲线型号与密钥材料。
+
+Item 的 \ttf{encrypted_data} 由第~\ref{sec:aes-gcm} 节规定的 \texttt{AES-128-GCM}
+保护。对称密钥不由接收方长期公钥直接充当,而是经临时密钥对与 ECDH 得到共享秘密,再经第~\ref{sec:key-derivation} 节派生
+\ttf{session_key}。
+
+\begin{itemize}
+ \item \textbf{椭圆曲线}:\texttt{secp256k1};
+ \item \textbf{临时密钥对}:封装每条 Item 时 MUST 新生成(公钥写入 \ttf{ephemeral_public_key});不同 Item MUST 彼此独立;
+ \item \textbf{ECDH}:封装侧以「本条 Item 临时私钥 + 接收方长期公钥」运算;解封侧以「接收方长期私钥 + \ttf{ephemeral_public_key}」运算;双方在曲线与格式一致时得到同一曲线点,再经第~\ref{sec:key-derivation} 节派生 \ttf{session_key};
+ \item \textbf{下游}:\ttf{session_key} 在第~\ref{sec:content-encryption}、\ref{sec:decrypt-crypto} 节\textbf{模块内部}使用,不对外作为独立调用接口。
+\end{itemize}
+
+\textbf{长期密钥与临时公钥格式:}
+\begin{itemize}
+ \item \textbf{长期公钥、长期私钥}:\texttt{.sealed} 文件内 \textbf{不} 保存接收方的长期公钥或私钥。封装时,写入端 MUST 在应用层向加密模块提供接收方长期公钥;解封时,读取端 MUST 在应用层提供对应的长期私钥。当前参考实现中,二者均以十六进制字符串传入:私钥 32 字节(64 个十六进制字符),公钥 64 字节 \texttt{x||y}(128 个十六进制字符,未压缩公钥去掉首字节 \texttt{0x04});模块内部再解码为曲线点参与 ECDH。
+ \item \ttf{ephemeral_public_key}:\textbf{写入} \texttt{.sealed} 文件,为每条 Item 的临时公钥;64 字节 \texttt{x||y},格式与长期公钥相同;参与 ECDH 时 MUST 在首部补回 \texttt{0x04}。
+\end{itemize}
+
+\subsection{密钥派生}\label{sec:key-derivation}
+本小节规定\textbf{密钥派生}模块:将 ECDH 共享秘密转换为本条 Item 的 GCM 会话密钥 \ttf{session_key}。
+
+\textbf{输入(来源):}
+\begin{itemize}
+ \item \textbf{ECDH 所用密钥对}(运算规则见第~\ref{sec:curve-keys} 节):封装侧为「本条 Item 临时私钥 + 接收方长期公钥」;解封侧为「接收方长期私钥 + \ttf{cipher_payload} 中的 \ttf{ephemeral_public_key}」;
+ \item \ttf{cmac_key}、\ttf{derivation_buffer} 布局常量:见第~\ref{sec:ref-derive-params} 节。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item \ttf{session_key}:16 字节,供第~\ref{sec:aes-gcm}、\ref{sec:content-encryption}、\ref{sec:decrypt-crypto} 节使用。
+\end{itemize}
+
+\subsubsection{ECDH 共享秘密}\label{sec:ecdh-shared-secret}
+ECDH(Elliptic Curve Diffie-Hellman)是一类椭圆曲线密钥协商方法,可参照 SEC 1 的 ECDH 原语或 NIST SP
+800-56A 中的 ECC CDH 密钥协商术语理解:一方使用自己的私钥与对方公钥运算,双方在参数一致时得到同一曲线点。当前版本的 ECDH 在
+\texttt{secp256k1} 上完成,并将该曲线点按下述规则转换为 32 字节共享秘密 \ttf{shared_key}(与参考实现一致):
+\begin{itemize}
+ \item 设 ECDH 结果为曲线点坐标 \texttt{(x, y)},各 32 字节;
+ \item 构造 33 字节缓冲区:首字节为 \texttt{0x02}(\texttt{y} 最低位为 0)或 \texttt{0x03}(\texttt{y} 最低位为 1),后接 \texttt{x};
+ \item \ttf{shared_key = SHA256(上述 33 字节)}。
+\end{itemize}
+
+\subsubsection{CMAC 派生会话密钥}\label{sec:cmac-session-key}
+CMAC(Cipher-based Message Authentication Code)是一类基于分组密码的消息认证码,可参照 NIST SP
+800-38B 中的 CMAC 模式理解;AES-CMAC 的具体算法也可参照 RFC 4493。国密算法体系中可类比以 SM4 等分组密码为底层算法的
+CMAC 类用法,但当前版本固定使用 AES-CMAC,不引入 SM4 参数。
+
+本标准将 \ttf{AES_CMAC(K, M)} 视为确定性函数:输入 16 字节密钥 \ttf{K} 与变长消息 \ttf{M},输出 16 字节认证标签。当前版本不直接使用该标签做外部认证,而是将 AES-CMAC 用作密钥派生步骤。会话密钥由两步 AES-CMAC(128 位密钥、128 位标签)派生:
+\begin{enumerate}
+ \item \ttf{key_derive_key = AES_CMAC(cmac_key, shared_key)},输出 16 字节;
+ \item \ttf{session_key = AES_CMAC(key_derive_key, derivation_buffer)},输出 16 字节,即本条 Item 的 \texttt{AES-128-GCM} 会话密钥。
+\end{enumerate}
+
+\textbf{\ttf{derivation_buffer} 布局(当前版本,共 25 字节):}
+\begin{center}
+ \small
+ \begin{tabular}{>{\raggedright\arraybackslash}p{1.8cm} >{\raggedright\arraybackslash}p{1.2cm} >{\raggedright\arraybackslash}p{8.8cm}}
+ \toprule
+ 偏移 & 长度 & 内容 \\
+ \midrule
+ 0 & 1 & 固定值 \texttt{0x01} \\
+ 1 & 21 & 域分离字符串 \texttt{tech.yeez.key.manager}(UTF-8) \\
+ 22 & 1 & 固定值 \texttt{0x00} \\
+ 23 & 1 & 固定值 \texttt{0x80} \\
+ 24 & 1 & 固定值 \texttt{0x00} \\
+ \bottomrule
+ \end{tabular}
+\end{center}
+
+\subsection{参考派生参数(当前版本)}\label{sec:ref-derive-params}
+为保证互操作,当前版本 (\ttf{version_number = 2}) 采用下列固定参数(字符串均为 UTF-8,\textbf{无}换行符、\textbf{无} BOM):
+\begin{itemize}
+ \item \ttf{cmac_key}(16 字节):
+ \begin{itemize}
+ \item 字符串形式:\texttt{yeez.tech.stbox} 后接 1 字节 \texttt{0x00}(共 16 字节,\textbf{不}含额外换行或第二处 NUL);
+ \item 十六进制:\texttt{7965657a2e746563682e7374626f7800}。
+ \end{itemize}
+ \item 域分离字符串(21 字节):
+ \begin{itemize}
+ \item 字符串形式:\texttt{tech.yeez.key.manager}(恰好 21 个 UTF-8 字节,\textbf{无}结尾 \texttt{0x00}、\textbf{无}换行);
+ \item 十六进制:\texttt{746563682e7965657a2e6b65792e6d616e61676572}。
+ \end{itemize}
+ \item 该字符串用于第~\ref{sec:cmac-session-key} 节 \ttf{derivation_buffer}(偏移 1 起 21 字节)及下文 GCM \ttf{AAD}(偏移 0 起 21 字节);
+ \item Item 载荷加密前缀字节:\texttt{0x02}(写入 AAD 偏移 24 处);
+ \item GCM \ttf{AAD} 容器长度:64 字节。
+\end{itemize}
+
+\ttf{AAD}(Additional Authenticated Data,附加认证数据)是不加密但参与认证的上下文字节串。GCM 会把 AAD 纳入认证标签计算,解封时必须提供完全相同的 AAD 才能通过认证;AAD 本身不是加密输出,也不作为独立字段写入 \texttt{.sealed} 文件。
+
+\textbf{AAD 布局(64 字节,\ttf{BYTESTRING[64]}):}
+实现 MUST 分配 64 字节缓冲区并初始化为全 \texttt{0x00},再按下述规则写入(与参考实现 \texttt{tad.set(aad); tad[24]=prefix} 一致):
+\begin{itemize}
+ \item 偏移 0--20:域分离字符串的 21 字节 UTF-8 原样拷贝(与上列十六进制一致);
+ \item 偏移 21--23:保持 \texttt{0x00}(字符串未占用,\textbf{不}写入 NUL 或换行);
+ \item 偏移 24:前缀字节(Item 载荷加密为 \texttt{0x02});
+ \item 偏移 25--63:保持 \texttt{0x00}。
+\end{itemize}
+换言之,当前版本 Item 载荷加密使用的 AAD 为:
+\begin{center}
+ \small
+ \ttf{746563682e7965657a2e6b65792e6d616e61676572 || 000000 || 02 || 00 * 39}
+\end{center}
+(共 64 字节;\texttt{00 * 39} 表示 39 个零字节,非 ASCII 字符 \texttt{'0'}。)
+若后续版本调整上述常量或布局,\ttf{version_number} MUST 递增并提供兼容说明。
+
+\subsection{AES-128-GCM 运算}\label{sec:aes-gcm}
+本小节规定\textbf{AES-128-GCM 运算}模块:在已知 \ttf{session_key} 的前提下,对变长数据提供认证加解密抽象接口(算法可参照 FIPS 197 与 NIST SP 800-38D;本标准不展开内部轮函数)。
+
+\textbf{输入(来源):}
+\begin{itemize}
+ \item \textbf{封装(\texttt{GCM\_Encrypt})}:\ttf{K}(16 字节,即 \ttf{session_key})、\ttf{IV}(12 字节 Nonce)、\ttf{P}(明文)、\ttf{A}(64 字节 AAD,布局见第~\ref{sec:ref-derive-params} 节);
+ \item \textbf{解封(\texttt{GCM\_Decrypt})}:\ttf{K}、\ttf{IV}、\ttf{C}(密文)、\ttf{A}、\ttf{T}(16 字节认证标签)。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item \textbf{封装}:\ttf{C}(\ttf{|C| = |P|})、\ttf{T}(16 字节);
+ \item \textbf{解封}:认证成功时 \ttf{P}(\ttf{|P| = |C|});认证失败时 MUST NOT 输出 \ttf{P}(见第~\ref{sec:auth-failure} 节)。
+\end{itemize}
+
+\ttf{A} 不参与加密,仅参与认证标签计算。
+
+\textbf{封装接口:}
+\begin{center}
+ \texttt{GCM\_Encrypt(K, IV, P, A) $\rightarrow$ (C, T)}
+\end{center}
+\ttf{P} 为明文(变长);\ttf{C} 为密文且 \ttf{|C| = |P|};\ttf{T} 为认证标签,当前版本固定 16 字节。
+
+\textbf{解封接口:}
+\begin{center}
+ \texttt{GCM\_Decrypt(K, IV, C, A, T) $\rightarrow$ P \quad 或 \quad 认证失败}
+\end{center}
+
+\subsection{内容加密}\label{sec:content-encryption}
+本小节规定封装侧\textbf{内容加密}模块:输入批包 \ttf{B} 与接收方长期公钥,输出本条 Item 的 \ttf{item_size} 与 \ttf{cipher_payload}(字段布局见第~\ref{sec:cipher-payload-layout} 节)。
+封装流程(第~\ref{sec:seal-chapter} 章)\textbf{仅}通过本模块接口调用,\textbf{不}展开模块内部的密钥协商、编码与 GCM 步骤。
+
+\textbf{输入:}
+\begin{itemize}
+ \item \ttf{B}:本条 Item 对应的批包,布局见第~\ref{sec:batch-package} 节;
+ \item 接收方长期公钥:应用层提供(格式见第~\ref{sec:curve-keys} 节)。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item \ttf{item_size}:\ttf{cipher_payload} 总字节数(见第~\ref{sec:item-record} 节);
+ \item \ttf{cipher_payload}:含解封所需全部字段(布局见第~\ref{sec:cipher-payload-layout} 节)。
+\end{itemize}
+
+\textbf{模块实施步骤:}\label{sec:seal-item-crypto}
+封装侧对本条 Item MUST 在本节内依次完成下列步骤(不对外暴露中间量接口):
+\begin{enumerate}
+ \item 按第~\ref{sec:curve-keys} 与第~\ref{sec:key-derivation} 节为本条 Item 协商会话密钥,生成 \ttf{iv} 与 \ttf{ephemeral_public_key}(随机性见第~\ref{sec:randomness} 节);
+ \item 按下文「明文编码」处理 \ttf{B};
+ \item 按下文「GCM 加密」与第~\ref{sec:aes-gcm} 节完成认证加密;
+ \item 按下文「写入 \texttt{.sealed} 字段」组装 \ttf{cipher_payload} 并计算 \ttf{item_size}。
+\end{enumerate}
+字段字节布局见第~\ref{sec:cipher-payload-layout} 节;向内容区追加 \texttt{item\_size} 前缀见第~\ref{sec:item-generation} 节。
+
+\textbf{明文编码(当前版本):}
+为实现互操作,在 \textbf{GCM 运算边界}上对批包字节串 \ttf{B} 做小写十六进制 ASCII 编码(常记 \ttf{HexEncode})。
+
+该步骤与第~\ref{sec:seal-chapter} 章「业务输入」中的 \textbf{UTF-8 文本编码}无关:
+前者作用于已形成的 \ttf{B};
+后者在更早阶段将 Unicode 文本转为载荷字节串,再由集成层表示为输入单元并装入 \ttf{B}。
+启用文本输入且采用当前版本 GCM 时,\textbf{二者均须执行}。
+
+\begin{itemize}
+ \item 设 \ttf{HexEncode(B)} 将 \ttf{B} 中每个字节编码为两个小写十六进制 ASCII 字符(\texttt{0--9a--f}),得到字节串 \ttf{P},长度为 \texttt{2 $\times$ |B|};
+ \item \ttf{P} MUST 为 \ttf{HexEncode(B)} 的结果,并作为 \ttf{GCM_Encrypt} 的明文输入。
+\end{itemize}
+
+\textbf{GCM 加密(当前版本)}
+
+按第~\ref{sec:aes-gcm} 节 \texttt{GCM\_Encrypt} 接口,参数绑定如下:
+\begin{itemize}
+ \item \ttf{K = session_key}:16 字节会话密钥;
+ \item \ttf{IV = iv}:12 字节,逐 Item 随机生成;
+ \item \ttf{P}:由上文明文编码得到的字节串;
+ \item \ttf{A = AAD}:64 字节,布局见第~\ref{sec:ref-derive-params} 节。
+\end{itemize}
+
+\textbf{算法输出:}
+\begin{itemize}
+ \item \ttf{C}:GCM 密文(变长,不含认证标签);
+ \item \ttf{T}:16 字节认证标签。
+\end{itemize}
+
+\textbf{写入 \texttt{.sealed} 字段:}
+\begin{itemize}
+ \item \ttf{encrypted_data = C};
+ \item \ttf{gcm_tag = T};
+ \item \ttf{iv} 与 \ttf{ephemeral_public_key} 不是 GCM 输出,但作为解封必需参数,按第~\ref{sec:cipher-payload-layout} 节顺序与 \ttf{encrypted_data}、\ttf{gcm_tag} 一并写入 \ttf{cipher_payload};
+ \item \ttf{AAD} 由版本常量和前缀规则重建,不写入文件;
+ \item \ttf{item_size}:\ttf{cipher_payload} 总字节数。
+\end{itemize}
+
+\subsection{解封侧密码学操作}\label{sec:decrypt-crypto}
+本小节规定解封侧\textbf{内容解密还原}模块:输入 \ttf{cipher_payload} 与接收方长期私钥,输出批包 \ttf{B}(为第~\ref{sec:content-encryption} 节的逆运算)。
+解封流程(第~\ref{sec:unseal-chapter} 章)\textbf{仅}通过本模块接口调用,\textbf{不}展开模块内部步骤。
+
+\textbf{输入:}
+\begin{itemize}
+ \item \ttf{cipher_payload}:本条 Item 密文载荷(布局见第~\ref{sec:cipher-payload-layout} 节);
+ \item 接收方长期私钥:应用层提供(格式见第~\ref{sec:curve-keys} 节)。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item 批包 \ttf{B}(认证成功后)。
+\end{itemize}
+
+\textbf{模块实施步骤:}
+\begin{enumerate}
+ \item 按下文「解析 \ttf{cipher_payload}」取得密文字段;
+ \item 按第~\ref{sec:curve-keys} 与第~\ref{sec:key-derivation} 节派生会话密钥;
+ \item 按下文「GCM 解密」与第~\ref{sec:aes-gcm} 节完成认证解密;若认证失败(第~\ref{sec:auth-failure} 节),MUST NOT 输出 \ttf{B};
+ \item 按下文「明文解码」得批包 \ttf{B}。
+\end{enumerate}
+
+\textbf{解析 \ttf{cipher_payload}(当前版本):}
+\begin{itemize}
+ \item 按第~\ref{sec:cipher-payload-layout} 节切分 \ttf{encrypted_data}、\ttf{iv}、\ttf{ephemeral_public_key}、\ttf{gcm_tag};
+ \item 长度或布局非法时 MUST 判为格式错误。
+\end{itemize}
+
+\textbf{GCM 解密(当前版本)}
+
+按第~\ref{sec:aes-gcm} 节 \texttt{GCM\_Decrypt} 接口,参数绑定如下:
+\begin{itemize}
+ \item \ttf{K = session_key}:16 字节会话密钥;
+ \item \ttf{IV = iv}:12 字节,取自 \ttf{cipher_payload};
+ \item \ttf{C = encrypted_data};\ttf{T = gcm_tag};
+ \item \ttf{A = AAD}:64 字节,布局见第~\ref{sec:ref-derive-params} 节;
+ \item 认证成功时得 \ttf{P}(与封装侧 \ttf{GCM_Encrypt} 所用 \ttf{P} 同型)。
+\end{itemize}
+
+\textbf{明文解码(当前版本):}
+对 \ttf{GCM_Decrypt} 输出的 \ttf{P} 做与第~\ref{sec:content-encryption} 节 \ttf{HexEncode} 互逆的小写十六进制还原(常记 \ttf{HexDecode}):
+\begin{itemize}
+ \item \ttf{HexDecode(P)} 将 \ttf{P} 按每两个 ASCII 十六进制字符还原为一个字节;字符 MUST 属于 \texttt{0--9a--f},\ttf{|P|} MUST 为偶数,否则 MUST 判为格式错误;
+ \item \ttf{B} MUST 为 \ttf{HexDecode(P)} 的结果。
+\end{itemize}
+
+\subsection{随机性要求}\label{sec:randomness}
+\begin{itemize}
+ \item \ttf{iv} MUST 由密码学安全随机源逐 Item 生成,且在同一 \ttf{session_key} 下 MUST NOT 重用;
+ \item 每条 Item 的临时私钥 MUST 由密码学安全随机源生成,且 MUST 满足 \texttt{secp256k1} 私钥有效性要求;
+ \item 随机源不可用或生成失败时,封装流程 MUST 中止并返回错误,MUST NOT 以固定值或可预测值替代。
+\end{itemize}
+
+\subsection{认证失败语义}\label{sec:auth-failure}
+\begin{itemize}
+ \item \ttf{gcm_tag} 校验失败、密文长度非法或密钥派生输入非法时,解封器 MUST 将该 Item 视为无效;
+ \item 上述失败后,解封器 MUST 停止继续输出本条 Item 及后续 Item 的明文(除非实现文档明确声明并验证的其他恢复语义);
+ \item 实现 SHOULD 返回可区分错误码(如附录 C 中 \ttf{E_AEAD_AUTH_FAILED}),便于审计与告警。
+\end{itemize}
+
+\section{封装流程(参考)}\label{sec:seal-chapter}
+本章给出将业务输入写入 \texttt{.sealed} 文件的\textbf{参考流程}。
+\textbf{文件格式与可验证约束}以第~\ref{sec:format-chapter}、\ref{sec:crypto-chapter} 章为准;\texttt{.sealed} 内容区的最小不可分单元为 \textbf{Item},输入单元须满足第~\ref{sec:input-normalization} 节规范性要求。下文各节为信息性步骤说明,除非某条明确要求校验或布局。
+
+\textbf{子流程(独立说明):}
+\begin{itemize}
+ \item 标准化输入基本规范(第~\ref{sec:input-normalization} 节);
+ \item 滚动摘要累计(第~\ref{sec:rolling-hash} 节);
+ \item 批包封装与 Item 写出(第~\ref{sec:item-generation} 节);
+ \item 批刷写阈值(第~\ref{sec:batch-flush-threshold} 节);
+ \item Block 组织与切分(第~\ref{sec:block-split} 节);
+ \item Block 元信息维护(第~\ref{sec:block-meta} 节);
+ \item 收尾落盘(第~\ref{sec:seal-finalize} 节);
+ \item 封装流程总览(第~\ref{sec:seal-total-algorithm} 节,含主循环图与组合调度)。
+\end{itemize}
+全局一致性见第~\ref{sec:seal-consistency} 节。
+
+\subsection{标准化输入基本规范}\label{sec:input-normalization}
+本标准以 \textbf{Item} 为 \texttt{.sealed} 内容区最小不可分单元(第~\ref{sec:content-region} 节)。宿主逐段提交的逻辑数据,在写入批包前由集成层表示为变长字节串,下文统称\textbf{输入单元}(实现中常记 \ttf{nt_input})。\textbf{本标准不规定}输入单元的具体字节布局;本节仅列出输入单元\textbf{应满足}的规范性要求,以便与批包、滚动摘要及解封输出对齐。如何由 \ttf{payload} 得到输入单元属于集成层实现,不在本节展开。
+
+\textbf{规范性要求:}
+\begin{itemize}
+ \item 封装与解封 MUST 对输入单元采用同一套、且在实现文档中声明的语义;
+ \item 每条输入单元 MUST 对应一段可还原的业务载荷 \ttf{payload}(还原方式由集成层定义,不属于 \texttt{.sealed} 文件布局);
+ \item 每条输入单元 MUST 完整地落入一个批包记录体(第~\ref{sec:batch-package} 节),MUST NOT 为凑批而在单元内部截断;
+ \item 全部输入单元 MUST 具有确定的\textbf{全局总序};该顺序 MUST 与第~\ref{sec:rolling-hash} 节累计顺序及解封侧输出顺序一致;
+ \item 参与滚动摘要的字节串 MUST 与写入批包记录体 \texttt{unit} 逐字节相同;
+ \item 输入单元明文不单独写入 \texttt{.sealed} 文件,仅通过加密后的 Item 对外存在。
+\end{itemize}
+
+\textbf{说明:}
+\ttf{payload} 的业务语义、字符编码(如 UTF-8)及切分粒度由应用层决定。Meta-Encryptor 的 \ttf{toNtInput}/\ttf{fromNtInput} 仅为一种集成示例(见附录~\ref{app:ref-impl-symbols}),\textbf{不是}本标准的必选布局。
+
+\subsection{滚动摘要累计}\label{sec:rolling-hash}
+在封装过程中按顺序累计全部输入单元的滚动摘要,终值写入 Header.\ttf{data_hash}。
+
+\textbf{输入:}
+\begin{itemize}
+ \item 按封装全局顺序产生的各条输入单元完整字节串(与第~\ref{sec:batch-package} 节记录体 \texttt{unit} 逐字节一致,见第~\ref{sec:input-normalization} 节);
+ \item 初值 $H_0$(当前版本见下文)。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item \rollhash 终值 $H_n$(32 字节),封装完成时写入 Header.\ttf{data_hash}(时机见第~\ref{sec:seal-finalize} 节)。
+\end{itemize}
+
+\textbf{相关格式:}
+Header.\ttf{data_hash} 字段定义见第~\ref{sec:header-region} 节;累计与 Item 边界无关,仅依赖输入单元全局顺序(非 Item 条数)。
+
+\textbf{实施步骤:}
+当前版本 (\ttf{version_number = 2}) 规则如下:
+\begin{center}
+ \texttt{H\_0 = keccak256("Fidelius")} \\
+ \texttt{H\_{i+1} = keccak256(H\_i || unit\_i)}
+\end{center}
+其中 \texttt{unit\_i} 为全局顺序下第 $i$ 条输入单元的完整字节串。记共产生 $N$ 条输入单元,终态为 $H_n$。\textbf{\rollhash 终值}\label{sec:rolling-hash-final}定义为 $H_n$;封装完成时 Header.\ttf{data_hash} MUST 等于 $H_n$。
+
+\textbf{说明:}
+本节规定递推规则;封装主循环中 $H$ 的初值与更新时机见第~\ref{sec:seal-total-algorithm} 节。每得一条输入单元可按本节规则更新摘要状态;终值 $H_n$ 在收尾写入 Header(第~\ref{sec:seal-finalize} 节)。解封侧比对见第~\ref{sec:integrity-check} 节。
+
+\subsection{批包封装与 Item 写出}\label{sec:item-generation}
+将\textbf{同一批次}的多条输入单元打成批包 \ttf{B},加密并在内容区追加\textbf{一条} Item 记录(Item 为内容区最小不可分单元)。
+
+\textbf{输入:}
+\begin{itemize}
+ \item 若干条完整的输入单元(条数 $\ge 1$,批内顺序 MUST 与全局提交顺序一致);
+ \item 接收方长期公钥(应用层提供,见第~\ref{sec:curve-keys} 节)。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item 内容区追加的一条 Item:\texttt{[item\_size][cipher\_payload]}(布局见第~\ref{sec:item-record}、\ref{sec:cipher-payload-layout} 节)。
+\end{itemize}
+
+\textbf{相关格式:}
+\begin{itemize}
+ \item 若干输入单元首尾拼接为批包 \ttf{B}(布局见第~\ref{sec:batch-package} 节);
+ \item 一个 \ttf{B} 对应内容区\textbf{一条} Item:\texttt{UINT64(LE) item\_size} 后跟 \ttf{cipher_payload}(见第~\ref{sec:item-record}、\ref{sec:cipher-payload-layout} 节)。
+\end{itemize}
+
+\textbf{实施步骤:}
+\begin{enumerate}
+ \item 将输入的各条输入单元按第~\ref{sec:batch-package} 节首尾拼接,得到批包 \ttf{B};
+ \item 对 \ttf{B} 与接收方长期公钥调用第~\ref{sec:content-encryption} 节内容加密模块,得到 \ttf{item_size} 与 \ttf{cipher_payload};
+ \item 按第~\ref{sec:item-record} 节向内容区追加 \texttt{UINT64(LE) item\_size} 与 \ttf{cipher_payload}。
+\end{enumerate}
+
+\textbf{说明:}
+本节\textbf{不}规定何时凑满一批、也不维护待刷写队列;触发条件见第~\ref{sec:batch-flush-threshold} 节,组合调度见第~\ref{sec:seal-total-algorithm} 节。
+向内容区追加顺序见第~\ref{sec:seal-consistency} 节;写出后更新 Header 计数与 Block Info 见第~\ref{sec:block-meta} 节。
+
+\subsection{批刷写阈值}\label{sec:batch-flush-threshold}
+规定封装实现\textbf{何时}将当前累积的一批输入单元作为同一批次,调用第~\ref{sec:item-generation} 节打成 \ttf{B} 并写出 Item;队列维护与调用顺序见第~\ref{sec:seal-total-algorithm} 节。
+
+\textbf{参数:}
+\begin{itemize}
+ \item \ttf{T_batch}:批刷写阈值,由封装实现声明,\textbf{不}写入 \texttt{.sealed} 文件。
+\end{itemize}
+
+\textbf{度量:}
+设当前\textbf{待打包批次}(尚未送入第~\ref{sec:item-generation} 节的输入单元集合)为 $\mathcal{N}$。
+记
+\[
+ S_{\mathrm{batch}} = \sum_{u \in \mathcal{N}} |u|
+\]
+其中 $|u|$ 为输入单元的\textbf{完整字节长度}(与第~\ref{sec:batch-package} 节 \ttf{record_len} 一致)。
+第~\ref{sec:seal-total-algorithm} 节队列 \ttf{Q} 上的 $S(Q)$ 与本节 $S_{\mathrm{batch}}$ 采用同一度量。
+
+\textbf{刷写条件:}
+\begin{enumerate}
+ \item \textbf{阈值触达:}当 $S_{\mathrm{batch}} \ge T_{\mathrm{batch}}$ 时,封装实现 MUST 对 $\mathcal{N}$ 中\textbf{全部}条目执行一次第~\ref{sec:item-generation} 节,并清空该待打包批次;
+ \item \textbf{输入结束:}宿主声明输入流结束时,若 $\mathcal{N}$ 非空,封装实现 MUST 再执行一次第~\ref{sec:item-generation} 节(即使 $S_{\mathrm{batch}} < T_{\mathrm{batch}}$);
+ \item 单条输入单元 MUST 完整地属于一个批次;MUST NOT 为凑满 \ttf{T_batch} 而在某条输入单元内部截断。
+\end{enumerate}
+
+\textbf{说明:}
+\ttf{L}、\ttf{T_batch} 均不在 Header 中编码。
+参考实现取 \ttf{T_batch = 65536}(\ttf{MaxItemSize});若变更阈值导致批次划分或 Item 数量变化,\ttf{version_number} MUST 递增。
+若宿主按固定块大小 \ttf{T_chunk} 提交载荷且 \ttf{T_chunk = T_batch},常见为每批 1 条输入单元;\ttf{L} 较小时一批可含多条输入单元(附录~\ref{app:ref-impl-symbols})。
+
+\subsection{Block 组织与切分}\label{sec:block-split}
+本节说明内容区中的 Block 如何由 Item 构成及何时切分。
+
+\textbf{组织关系说明:}
+\begin{itemize}
+ \item 内容区由按封装顺序写出的 Item 首尾拼接而成;
+ \item 按该顺序将 Item 划分为若干 \textbf{Block}:每个 Block 是其中连续若干条 Item 组成的段,且单个 Block 内 Item 条数 MUST NOT 超过 \ttf{N_block};各 Block 在 Item 下标与内容区字节偏移上均无隙、无重叠,共同覆盖全部 Item;
+ \item 每个 Block 对应 Block Infos 区中的一条 \textbf{Block Info}(32 字节,布局见第~\ref{sec:block-infos} 节);Header.\ttf{block_number} 为 Block 个数,MUST 等于 Block Infos 区条目数。
+\end{itemize}
+
+\textbf{划分规则(当前版本):}
+封装侧按 Item \textbf{写出顺序}维护\textbf{当前 Block}:
+\begin{enumerate}
+ \item \textbf{首条 Item}:开启第 0 个 Block,该 Block 内仅含本条 Item;
+ \item \textbf{并入当前 Block}:若当前 Block 内 Item 条数尚未达到 \ttf{N_block},本条 Item 并入当前 Block,仅扩展该 Block 的结束下标与结束偏移;
+ \item \textbf{切分新建 Block}:若当前 Block 内 Item 条数已达 \ttf{N_block},则关闭当前 Block 并新建下一 Block,本条 Item 作为新 Block 的首条 Item。
+\end{enumerate}
+单条 Item MUST 完整地属于一个 Block;MUST NOT 将一条 Item 拆入两个 Block。
+
+\textbf{参考实现:}
+当前版本参考实现取 \ttf{N_block = 256}(\ttf{ItemNumPerBlockLimit},见附录~\ref{app:ref-impl-symbols})。
+
+\textbf{说明:}
+\ttf{N_block} 由封装实现声明,\textbf{不}写入 \texttt{.sealed} 文件;变更且影响互操作时 \ttf{version_number} MUST 递增。
+宿主 \textbf{MAY} 将多段业务数据表示为多条输入单元并写入同一 \texttt{.sealed} 内容区(经若干 Item);Block Info 不记录「第几个源文件」,仅索引本文件内 Item 与密文字节。
+
+\subsection{Block 元信息维护}\label{sec:block-meta}
+每写出一条 Item 后,封装实现 MUST 按第~\ref{sec:block-split} 节的划分规则,更新 Header.\ttf{item_number} 与内存中的 Block Info 列表,供第~\ref{sec:seal-finalize} 节写入 Block Infos 区。
+
+\textbf{维护对象:}
+\begin{itemize}
+ \item Header.\ttf{item_number}、Header.\ttf{block_number};
+ \item 长度为 \ttf{block_number} 的 Block Info 列表(每条 32 字节,四字段语义见第~\ref{sec:block-meta-fields} 节)。
+\end{itemize}
+
+\textbf{本条 Item 占用字节。} 记刚写出的 Item 其 \ttf{item_size} 字段值为 \ttf{s}(即 \ttf{cipher_payload} 长度),则该 Item 在内容区占用
+\[
+ L_{\mathrm{item}} = 8 + s
+\]
+字节(8 字节 \texttt{item\_size} 前缀 + \ttf{cipher_payload},见第~\ref{sec:item-record} 节)。下文凡写 $L_{\mathrm{item}}$,均指本条 Item 的该占用长度。
+
+\subsubsection{Block Info 字段含义}\label{sec:block-meta-fields}
+每条 Block Info 含四个 UINT64 字段,在 \textbf{本 \texttt{.sealed} 文件} 内描述一个 Block 所覆盖的 Item 范围;坐标系均针对该文件的内容区与 Item 序列,\textbf{不}针对业务侧被封装前的源文件。布局见第~\ref{sec:block-infos} 节。
+
+\textbf{Item 下标:\ttf{start_item_index}、\ttf{end_item_index}。}
+\begin{itemize}
+ \item 含义:本 Block 在内容区 Item \textbf{逻辑序号}上的半开区间 \texttt{[start\_item\_index, end\_item\_index)}。按封装写出顺序,自 \texttt{0} 起为第 0 条 Item、第 1 条 Item……直至 \texttt{item\_number - 1}(与 Header.\ttf{item_number} 一致)。
+ \item \ttf{start_item_index}:该 Block 内\textbf{第一条} Item 的下标(\textbf{含})。
+ \item \ttf{end_item_index}:该 Block 内\textbf{最后一条} Item 的下标加 1(\textbf{不含});Block 内 Item 条数为 \texttt{end\_item\_index - start\_item\_index},MUST NOT 大于 \ttf{N_block};当该值已达 \ttf{N_block} 时,下一条写出的 Item MUST 按第~\ref{sec:block-split} 节开启新 Block;
+ \item \textbf{不是}:源明文文件编号、源文件内块号、批包内输入单元的序号(一条 Item 的 \ttf{B} 内可含多条记录,见第~\ref{sec:batch-package} 节),亦 \textbf{不是} 其它 \texttt{.sealed} 文件中的 Item 下标。
+\end{itemize}
+
+\textbf{内容区字节偏移:\ttf{start_file_pos}、\ttf{end_file_pos}。}
+\begin{itemize}
+ \item 含义:本 Block 在 \texttt{.sealed} 文件 \textbf{Content Region} 内占据的字节半开区间 \texttt{[start\_file\_pos, end\_file\_pos)}。偏移以内容区首字节为 \texttt{0}(内容区在文件最前,故从该文件物理偏移 \texttt{0} 起算)。\textbf{不包含} Block Infos 区与 Header 区(见第~\ref{sec:region-length} 节)。
+ \item \ttf{start_file_pos}:该 Block 第一条 Item 的 \texttt{item\_size} 前缀起始处(\textbf{含});
+ \item \ttf{end_file_pos}:该 Block 末字节的内容区偏移加 \texttt{1}(半开区间右端,\textbf{不含});Block 在内容区占用 \texttt{end\_file\_pos - start\_file\_pos} 字节。
+ \item \textbf{不是}:被封装前原始明文文件(或任意宿主路径下文件)内的字节偏移。字段名 \texttt{file} 指本 \texttt{.sealed} 输出文件的内容区(与参考实现 \texttt{block\_info\_t.start\_file\_pos} 一致),勿与「源文件偏移」混读。
+\end{itemize}
+
+\textbf{两对字段的对应关系。}
+同一 Block 上,Item 下标区间与内容区字节区间一一对应。
+区间内第 \ttf{k} 号 Item(\ttf{start_item_index} $\le$ \ttf{k} $<$ \ttf{end_item_index})的密文记录 \texttt{[item\_size][cipher\_payload]} 按写出顺序首尾相接,填满 \texttt{[start\_file\_pos, end\_file\_pos)}。
+全体 Block Info 在 Item 维度无隙覆盖 \texttt{[0, item\_number)},在字节维度无隙覆盖 \texttt{[0, content\_size)}。
+
+\textbf{更新规则:}
+记刚完成内容区写出、本条 Item 已追加之后:Header.\ttf{item_number} 已为 \ttf{n}(\ttf{n} 从 1 起),刚写入的为第 \ttf{n-1} 号 Item(下标从 0 起)。记 \ttf{cur} 为\textbf{当前 Block} 的 Block Info,即列表中下标 \texttt{block\_number - 1} 的那一条(当 \ttf{block_number > 0} 时)。
+
+\textbf{情形 1:首个 Item}(\ttf{block_number = 0},\ttf{n = 1})。新建第 \texttt{0} 条 Block Info,记为 \ttf{cur}:
+\begin{itemize}
+ \item \ttf{start_item_index} $\leftarrow$ \texttt{0}(不变);
+ \item \ttf{end_item_index} $\leftarrow$ \texttt{1};
+ \item \ttf{start_file_pos} $\leftarrow$ \texttt{0}(不变);
+ \item \ttf{end_file_pos} $\leftarrow$ \texttt{0} $+$ $L_{\mathrm{item}}$;
+ \item Header.\ttf{block_number} $\leftarrow$ \texttt{1}。
+\end{itemize}
+
+\textbf{情形 2:后续 Item,并入当前 Block}(\ttf{block_number > 0},且当前 Block 内 Item 条数小于 \ttf{N_block})。仅更新 \ttf{cur} 的\textbf{结束边界},起始两字段不变:
+\begin{itemize}
+ \item \ttf{start_item_index}:不变;
+ \item \ttf{end_item_index} $\leftarrow$ \ttf{cur.end_item_index} $+$ \texttt{1};
+ \item \ttf{start_file_pos}:不变;
+ \item \ttf{end_file_pos} $\leftarrow$ \ttf{cur.end_file_pos} $+$ $L_{\mathrm{item}}$;
+ \item Header.\ttf{block_number}:不变。
+\end{itemize}
+
+\textbf{情形 3:后续 Item,新建 Block}(\ttf{block_number > 0},且当前 Block 内 Item 条数已达 \ttf{N_block})。令 \ttf{prev} $=$ \ttf{cur},新建下一条 Block Info(下标为原 \ttf{block_number})记为 \ttf{cur},四字段均从前一 Block 的结束处接续:
+\begin{itemize}
+ \item \ttf{start_item_index} $\leftarrow$ \ttf{prev.end_item_index};
+ \item \ttf{end_item_index} $\leftarrow$ \ttf{prev.end_item_index} $+$ \texttt{1};
+ \item \ttf{start_file_pos} $\leftarrow$ \ttf{prev.end_file_pos};
+ \item \ttf{end_file_pos} $\leftarrow$ \ttf{prev.end_file_pos} $+$ $L_{\mathrm{item}}$;
+ \item Header.\ttf{block_number} $\leftarrow$ 原值 $+$ \texttt{1}。
+\end{itemize}
+
+\textbf{不变量(每次写出 Item 后 MUST 成立):}
+\begin{itemize}
+ \item Header.\ttf{item_number} $=$ 各 Block 的 \texttt{(end\_item\_index -
+ start\_item\_index)} 之和;
+ \item 各 Block 的 Item 下标区间首尾相接、无重叠,并覆盖 \texttt{[0, item\_number)};
+ \item 各 Block 的 \ttf{start_file_pos}、\ttf{end_file_pos} 首尾相接、无重叠,并覆盖 \texttt{[0, content\_size)},且 \ttf{content_size} 等于最后一条 Block Info 的 \ttf{end_file_pos}(见第~\ref{sec:region-length} 节);
+ \item 对内容区 Item 的\textbf{全局}下标 $k$($0 \le k < \texttt{item\_number}$),记第 $k$ 条 Item 在内容区内的起始字节为 $p_k$,占用长度为 $L_{\mathrm{item}}(k)$。则存在唯一的 Block 下标 $t$($0 \le t < \texttt{block\_number}$),使第 $t$ 条 Block Info 满足
+ \[
+ \texttt{start\_item\_index} \le k < \texttt{end\_item\_index},
+ \]
+ 且
+ \[
+ p_k = \texttt{start\_file\_pos}
+ + \sum_{j=\texttt{start\_item\_index}}^{k-1} L_{\mathrm{item}}(j)
+ \]
+ (上式四字段均指第 $t$ 条 Block Info;当 $k$ 等于该条 \texttt{start\_item\_index} 时求和为空)。
+\end{itemize}
+
+\textbf{说明:}
+情形 2、3 与第~\ref{sec:block-split} 节「划分规则」及 Item 数上限一致;情形 1 对应首条 Item 开启第 0 个 Block。
+
+\subsection{收尾落盘}\label{sec:seal-finalize}
+内容区全部 Item 写出后,将 Block Infos 区与 Header 区追加到文件尾部,完成 \texttt{.sealed} 物理布局。
+
+\textbf{输入:}
+\begin{itemize}
+ \item 已写完的内容区及 \ttf{content_size};
+ \item \ttf{N} 条 Block Info 取值(\ttf{N = block_number},由第~\ref{sec:block-meta} 节维护);
+ \item 滚动摘要终值 $H_n$(第~\ref{sec:rolling-hash-final} 节);
+ \item \ttf{item_number}、\ttf{block_number}(由第~\ref{sec:block-meta} 节维护);
+ \item \ttf{magic_number}、\ttf{version_number}(取值见第~\ref{sec:header-compat} 节)。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item 完整的 \texttt{.sealed} 文件(三区布局见第 4 章)。
+\end{itemize}
+
+\textbf{相关格式:}
+三区长度见第~\ref{sec:region-length} 节;Block Info、Header 布局见第~\ref{sec:block-infos}、\ref{sec:header-region} 节。
+物理写入顺序 MUST 为:内容区 $\rightarrow$ Block Infos 区 $\rightarrow$ Header(第~\ref{sec:seal-consistency} 节)。
+
+\textbf{实施步骤:}
+\begin{enumerate}
+ \item \textbf{写出 Block Infos 区:}记 \ttf{N = block_number},自偏移 \ttf{content_size} 起顺序写入 \ttf{N} 条 Block Info(各 32 字节,取值见第~\ref{sec:block-meta} 节);\ttf{block_infos_size} $= 32 \times N$;
+ \item \textbf{写出 Header 区:}紧接其后按第~\ref{sec:header-region} 节写入 64 字节 Header;各字段按本节\textbf{输入}赋值,其中 Header.\ttf{data_hash} 取 $H_n$(MUST 为第~\ref{sec:rolling-hash} 节累计结果,\textbf{不得}以 Item 密文另行摘要替代)。
+\end{enumerate}
+完成后 \ttf{file_size} $=$ \ttf{content_size} $+$ \ttf{block_infos_size} $+$ \texttt{64}。
+
+\textbf{说明:}
+进入本节前须已满足:内容区已全部写完;Block Info 与 \rollhash 终值 $H_n$ 已就绪(见第~\ref{sec:seal-total-algorithm} 节)。
+应用层伴随元数据(公钥、签名等)不在 \texttt{.sealed} 文件内,本标准不做字段约束。
+
+\subsection{封装流程总览}\label{sec:seal-total-algorithm}\label{sec:batch-flush-flow}
+本节定义封装侧\textbf{如何组合}前述子流程。各子节仅描述单步职责;本节给出调度变量、主循环参考图及\textbf{按图解读}的实施步骤。
+
+\textbf{变量与状态(仅在本节及图中使用):}
+\begin{itemize}
+ \item 待刷写队列 \ttf{Q}:元素为完整的输入单元;
+ \item $S(Q)$:\ttf{Q} 中各输入单元字节总长度(与第~\ref{sec:batch-flush-threshold} 节中 $S_{\mathrm{batch}}$ 同型,用于阈值判断);
+ \item $H$:滚动摘要状态,初值 $H_0$、终值 $H_n$(递推规则见第~\ref{sec:rolling-hash} 节,在主循环中按每条输入单元更新)。
+\end{itemize}
+
+\textbf{主循环图与子节对应:}
+图~\ref{fig:batch-flush-flow} 为全量顺序封装的一种参考主流程;图源 \texttt{doc/diagrams/seal-batch-flush-flow.mmd}。
+图中流程名词与独立子节的对应关系如下(图中\textbf{不}标注章节号):
+\begin{itemize}
+ \item 「输入单元入队」「滚动摘要更新 $H$」:输入单元须满足第~\ref{sec:input-normalization} 节;摘要规则见第~\ref{sec:rolling-hash} 节;「入队 \ttf{Q}」指将完整输入单元入 \ttf{Q};
+ \item 「批刷写阈值」:见第~\ref{sec:batch-flush-threshold} 节(图中 $S(Q)$ 与 \ttf{T_batch} 同该节);
+ \item 「Item 写出」:见第~\ref{sec:item-generation} 节;「Block 元信息更新」:见第~\ref{sec:block-meta} 节;
+ \item 「收尾落盘」:见第~\ref{sec:seal-finalize} 节。
+\end{itemize}
+
+\begin{figure}[htbp]
+ \centering
+ \includegraphics[width=0.85\textwidth]{diagrams/seal-batch-flush-flow.png}
+ \caption{封装主循环(参考流程)}
+ \label{fig:batch-flush-flow}
+\end{figure}
+
+\textbf{实施步骤:}
+以下按图~\ref{fig:batch-flush-flow} 自上而下解读;各步具体操作以对应子节为准。
+\begin{enumerate}
+ \item \textbf{开始与初始化}(图:\texttt{开始}):\ttf{version_number} 按约定取值;\ttf{block_number} $= 0$,\ttf{item_number} $= 0$;$H \leftarrow H_0$;\ttf{Q} 为空。
+ \item \textbf{主循环入口}(图:判断「宿主已声明输入结束且无新载荷」,取\textbf{否}):每收到一段业务载荷,产生满足第~\ref{sec:input-normalization} 节的输入单元并入 \ttf{Q},按第~\ref{sec:rolling-hash} 节更新 $H$(见图「输入单元入队 / 滚动摘要更新 $H$」)。
+ \item \textbf{批刷写判断}(图:判断 $S(Q) \ge T_{\mathrm{batch}}$):若为\textbf{是},执行「Item 写出 / Block 元信息更新 / 清空 \ttf{Q}」(第~\ref{sec:item-generation}、\ref{sec:block-meta} 节),返回步骤 2 的判断;若为\textbf{否},直接返回步骤 2 的判断。
+ \item \textbf{输入结束}(图:步骤 2 判断取\textbf{是}后,判断「\ttf{Q} 非空」):若为\textbf{是},再执行一次 Item 写出与 Block 元信息更新并清空 \ttf{Q};若为\textbf{否},进入步骤 5。
+ \item \textbf{收尾落盘}(图:「收尾落盘」$\rightarrow$ \texttt{结束}):按第~\ref{sec:seal-finalize} 节写出 Block Infos 与 Header,\ttf{data_hash} $\leftarrow H_n$。
+\end{enumerate}
+
+\subsection{封装一致性要求}\label{sec:seal-consistency}
+\begin{itemize}
+ \item 物理写入顺序 MUST 为:内容区 $\rightarrow$ Block Infos 区 $\rightarrow$ Header;
+ \item \ttf{item_number} MUST 等于内容区实际 Item 条数;
+ \item \ttf{block_number} MUST 等于 Block Infos 区条目数;
+ \item 任意 Block Info 的 \ttf{end_file_pos} MUST 不超过 \ttf{content_size},且相邻 Block 的偏移 SHOULD 首尾相接;
+ \item 实现 SHOULD 在封装结束后校验计数与 Header.\ttf{data_hash} 按第~\ref{sec:rolling-hash} 节重算结果一致。
+\end{itemize}
+
+\section{解封流程(参考)}\label{sec:unseal-chapter}
+本章给出从 \texttt{.sealed} 文件按序还原业务载荷的\textbf{参考流程}。
+\textbf{文件格式与可验证约束}以第~\ref{sec:format-chapter}、\ref{sec:crypto-chapter} 章为准;解封以 Item 为最小读取与认证单元,\ttf{payload} 由集成层从批包内输入单元还原,且须满足第~\ref{sec:input-normalization} 节与封装侧同一集成语义。第~\ref{sec:format-chapter} 章「规范性解析流程」中的 MUST 条款在全量顺序解封时与本章一致,本章侧重步骤组合与图示。下文各节为信息性步骤说明,除非某条明确要求校验或布局。
+
+\textbf{子流程(独立说明):}
+\begin{itemize}
+ \item Header 获取与校验(第~\ref{sec:unseal-header-model} 节);
+ \item 内容区顺序读取(第~\ref{sec:unseal-item-parse} 节);
+ \item 单条 Item 认证解密(第~\ref{sec:unseal-item-crypto} 节);
+ \item 批包拆分、业务输出与滚动摘要(第~\ref{sec:unseal-batch-output} 节);
+ \item 解封流程总览(第~\ref{sec:unseal-total-algorithm} 节,含主循环图、完整性比对与组合调度);
+ \item 进度与可恢复状态(第~\ref{sec:unseal-recoverable} 节,建议性)。
+\end{itemize}
+上述步骤的\textbf{组合调度}见第~\ref{sec:unseal-total-algorithm} 节;全局一致性见第~\ref{sec:unseal-consistency} 节;失败语义见第~\ref{sec:unseal-errors} 节。
+
+\subsection{Header 获取与校验}\label{sec:unseal-header-model}
+从 \texttt{.sealed} 文件尾部取得 Header 记录,校验识别字段并计算三区长度(读取顺序见第~\ref{sec:read-model} 节)。
+
+\textbf{输入:}
+\begin{itemize}
+ \item 已打开的 \texttt{.sealed} 文件及 \ttf{file_size}(见第~\ref{sec:region-length} 节);
+ \item \ttf{magic_number}、\ttf{version_number} 的约定取值(见第~\ref{sec:header-compat} 节)。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item \ttf{block_number}、\ttf{item_number}、\ttf{data_hash};
+ \item \ttf{content_size}、\ttf{block_infos_size}(由 \ttf{file_size} 与 \ttf{block_number} 按第~\ref{sec:region-length} 节算出)。
+\end{itemize}
+
+\textbf{相关格式:}
+Header 记录布局见第~\ref{sec:header-region} 节;\ttf{data_hash} 字段语义见第~\ref{sec:rolling-hash} 节。
+
+\textbf{实施步骤:}
+\begin{enumerate}
+ \item 读取文件末尾 64 字节,按第~\ref{sec:header-region} 节解析,得到各 Header 字段;
+ \item 将解析得到的 \ttf{magic_number}、\ttf{version_number} 与\textbf{输入}中的约定取值比对;不符时 MUST 终止解封,错误码 SHOULD 为附录 C 中的 \ttf{E_MAGIC_MISMATCH} 或 \ttf{E_VERSION_UNSUPPORTED};
+ \item 令 \ttf{N} $=$ \ttf{block_number},按第~\ref{sec:region-length} 节计算 \ttf{block_infos_size} 与 \ttf{content_size};若 \ttf{content_size} 不大于 \texttt{0},MUST 终止解封,错误码 SHOULD 为附录 C 中的 \ttf{E_FORMAT_TOO_SMALL}(或等价格式错误码)。
+\end{enumerate}
+
+\textbf{说明:}
+全文件顺序解封\textbf{不必}事先读取 Block Infos 区;块级随机访问须先读 Block Infos 区(见第 9 章)。
+
+\subsection{内容区顺序读取}\label{sec:unseal-item-parse}
+本节说明全文件顺序解封时,如何从内容区切分出单条 Item 的 \ttf{item_size} 与 \ttf{cipher_payload}。
+
+\textbf{输入:}
+\begin{itemize}
+ \item \ttf{content_size}、\ttf{item_number}(由第~\ref{sec:unseal-header-model} 节得到)。
+\end{itemize}
+
+\textbf{维护的状态:}
+与第~\ref{sec:unseal-total-algorithm} 节主循环共享,本节负责在读每条 Item 后更新:
+\begin{itemize}
+ \item $p$:内容区读指针(相对内容区起点,单位:字节;初值 $p \leftarrow 0$ 见第~\ref{sec:unseal-total-algorithm} 节);
+ \item $n$:已处理 Item 计数(供主循环终止判断及完整性比对;初值 $n \leftarrow 0$ 见同上;\textbf{勿}与第~\ref{sec:rolling-hash} 节中输入单元条数 $N$ 混淆)。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item 本条 Item 的 \ttf{item_size}(记为 $L$)与 \ttf{cipher_payload}。
+\end{itemize}
+
+\textbf{相关格式:}
+内容区布局见第~\ref{sec:region-length}、\ref{sec:content-region} 节;Item 记录为 \texttt{[item\_size (8B)][cipher\_payload (L B)]}(见第~\ref{sec:item-record}、\ref{sec:cipher-payload-layout} 节)。\textbf{条数不由扫描推断},以 \ttf{item_number} 为终止条件。本节\textbf{每次调用}读取\textbf{一条} Item。
+
+\textbf{实施步骤:}
+\begin{enumerate}
+ \item 若 \ttf{content_size} $-$ $p < 8$,MUST 终止本条 Item 读取,错误码 SHOULD 为附录 C 中的 \ttf{E_ITEM_TRUNCATED};
+ \item 自偏移 $p$ 起读取 8 字节,解码为 $L$;若 $L$ 非法(如为 \texttt{0} 或超出实现上限),MUST 终止解封,错误码 SHOULD 为附录 C 中的 \ttf{E_ITEM_SIZE_INVALID};
+ \item 若 \ttf{content_size} $-$ $p < 8 + L$,MUST 终止本条 Item 读取,错误码 SHOULD 为附录 C 中的 \ttf{E_ITEM_TRUNCATED};
+ \item 自偏移 $p + 8$ 起读取 $L$ 字节,得到 \ttf{cipher_payload};若其布局不满足第~\ref{sec:cipher-payload-layout} 节,MUST 终止解封,错误码 SHOULD 为附录 C 中的 \ttf{E_ITEM_SIZE_INVALID};
+ \item 更新 $p \leftarrow p + 8 + L$、$n \leftarrow n + 1$;当 $n = \ttf{item_number}$ 时,若 $p \ne \ttf{content_size}$,MUST 终止解封(格式错误,如 \ttf{E_ITEM_TRUNCATED} 或实现自定义码)。
+\end{enumerate}
+
+\textbf{说明:}
+解密、批包拆分与 \ttf{payload} 输出不在本节展开;见第~\ref{sec:unseal-item-crypto}、\ref{sec:unseal-batch-output} 节及第~\ref{sec:unseal-total-algorithm} 节。
+
+\subsection{单条 Item 认证解密}\label{sec:unseal-item-crypto}
+将一条 Item 的密文载荷还原为批包 \ttf{B}。
+
+\textbf{输入:}
+\begin{itemize}
+ \item \ttf{cipher_payload}(由第~\ref{sec:unseal-item-parse} 节读出);
+ \item 接收方长期私钥(应用层提供,见第~\ref{sec:curve-keys} 节)。
+\end{itemize}
+
+\textbf{输出:}
+\begin{itemize}
+ \item 批包 \ttf{B}(认证成功后)。
+\end{itemize}
+
+\textbf{实施步骤:}
+\begin{enumerate}
+ \item 对 \ttf{cipher_payload} 与接收方长期私钥调用第~\ref{sec:decrypt-crypto} 节内容解密还原模块;
+ \item 若认证失败(第~\ref{sec:auth-failure} 节),MUST 终止解封,MUST NOT 输出 \ttf{B},错误码 SHOULD 为附录 C 中的 \ttf{E_AEAD_AUTH_FAILED};
+ \item 认证成功时,得到 \ttf{B}。
+\end{enumerate}
+
+\textbf{说明:}
+算法细节见第~\ref{sec:decrypt-crypto} 节;本章不重复模块内部步骤。
+
+\subsection{批包拆分、业务输出与滚动摘要}\label{sec:unseal-batch-output}\label{sec:unseal-rolling-hash}
+将一条 Item 解密得到的批包 \ttf{B} 拆为若干条输入单元,在输出每条 \ttf{payload} 之前用对应输入单元(与封装侧记录体逐字节一致)更新滚动摘要 $H$,并按序输出 \ttf{payload}。
+
+\textbf{输入(每次调用):}
+批包 \ttf{B}(由第~\ref{sec:unseal-item-crypto} 节得到)。
+
+\textbf{维护的状态:}
+$H$:滚动摘要状态($H_0$ 见第~\ref{sec:rolling-hash} 节;初值与调度见第~\ref{sec:unseal-total-algorithm} 节)。每处理完本条 Item 的 \ttf{B} 内全部输入单元后,按实施步骤更新 $H$。
+
+\textbf{输出(每次调用):}
+按批内顺序输出的各条 \ttf{payload}。
+
+\textbf{相关格式:}
+\ttf{B} 布局见第~\ref{sec:batch-package} 节;输入单元须满足第~\ref{sec:input-normalization} 节;$H$ 递推规则与 $H_0$ 定义见第~\ref{sec:rolling-hash}、\ref{sec:rolling-hash-final} 节。
+
+\textbf{实施步骤:}
+\begin{enumerate}
+ \item 按第~\ref{sec:batch-package} 节将 \ttf{B} 拆为若干条输入单元(\texttt{unit});若 \ttf{package_id}、长度字段与剩余字节不一致,MUST 终止解封(格式错误),并 MUST NOT 输出 \ttf{payload};
+ \item 对批内每条输入单元按序执行下列子步骤(\textbf{不得}在输出 \ttf{payload} 后再用该条单元更新 $H$):
+ \begin{enumerate}
+ \item 在输出 \ttf{payload} 之前,用本条输入单元完整字节串按第~\ref{sec:rolling-hash} 节更新 $H$;
+ \item 由集成层将输入单元还原为 \ttf{payload} 并输出(语义须与封装侧一致,见第~\ref{sec:input-normalization} 节);失败时 MUST 终止解封(格式错误)。
+ \end{enumerate}
+\end{enumerate}
+
+\textbf{说明:}
+输入单元仅在本节步骤 2 内存在;$H$ 的累计顺序 MUST 与封装侧输入单元全局顺序一致。完整性比对见第~\ref{sec:unseal-total-algorithm} 节。
+
+\subsection{解封流程总览}\label{sec:unseal-total-algorithm}\label{sec:unseal-main-flow}
+本节定义解封侧\textbf{如何组合}前述子流程。各子节仅描述单步职责;本节给出调度变量、主循环参考图及\textbf{按图解读}的实施步骤(含完整性比对)。
+
+\textbf{变量与状态(仅在本节及图中使用):}
+\begin{itemize}
+ \item 内容区读指针 $p$、已处理 Item 计数 $n$(由第~\ref{sec:unseal-item-parse} 节维护);
+ \item 滚动摘要状态 $H$(由第~\ref{sec:unseal-batch-output} 节维护;$H_0$ 见第~\ref{sec:rolling-hash} 节);
+ \item \ttf{item_number}、\ttf{content_size}、\ttf{data_hash}(由第~\ref{sec:unseal-header-model} 节得到)。
+\end{itemize}
+
+\textbf{主循环图与子节对应:}
+图~\ref{fig:unseal-main-flow} 为全量顺序解封的一种参考主流程;图源 \texttt{doc/diagrams/unseal-main-flow.mmd}。
+图中流程名词与独立子节的对应关系如下(图中\textbf{不}标注章节号;\ttf{data_hash} 等字段语义以正文为准):
+\begin{itemize}
+ \item 「读 Header 并校验」「计算 \ttf{content_size}」:见第~\ref{sec:unseal-header-model} 节;图中「初始化 $H = H_0$,$n = 0$」另需 $p \leftarrow 0$($H_0$ 见第~\ref{sec:rolling-hash} 节);
+ \item 「读 \ttf{item_size} 与 \ttf{cipher_payload}」:见第~\ref{sec:unseal-item-parse} 节(含 $n$ 递增,图中无单独「$n$ 加 1」节点);
+ \item 「认证解密得批包 \ttf{B}」:见第~\ref{sec:unseal-item-crypto} 节;
+ \item 「拆分 \ttf{B}」「逐条输出 \ttf{payload} 并用输入单元更新 $H$」:见第~\ref{sec:unseal-batch-output} 节(须在输出 \ttf{payload} 之前更新 $H$);
+ \item 「$H$ 等于 \ttf{data_hash}」:见下文实施步骤第 3 项(完整性比对)。
+\end{itemize}
+
+\begin{figure}[htbp]
+ \centering
+ \includegraphics[width=0.85\textwidth]{diagrams/unseal-main-flow.png}
+ \caption{解封主循环(参考流程,全量顺序解封)}
+ \label{fig:unseal-main-flow}
+\end{figure}
+
+\textbf{实施步骤:}
+以下按图~\ref{fig:unseal-main-flow} 自上而下解读;各步具体操作以对应子节为准。
+\begin{enumerate}
+ \item \textbf{开始与 Header}(图:\texttt{开始} $\rightarrow$ 「读 Header 并校验」$\rightarrow$ 「计算 \ttf{content_size} / 初始化」):按第~\ref{sec:unseal-header-model} 节取得并校验 Header;$H \leftarrow H_0$,$p \leftarrow 0$,$n \leftarrow 0$。
+ \item \textbf{主循环}(图:判断 $n$ 小于 \ttf{item_number},取\textbf{是}):以当前 $p$、$n$ 调用第~\ref{sec:unseal-item-parse} 节得 \ttf{cipher_payload} 及更新后的 $p$、$n$($n$ 仅在该节末项递增);调用第~\ref{sec:unseal-item-crypto} 节得 \ttf{B};以当前 $H$ 调用第~\ref{sec:unseal-batch-output} 节输出 \ttf{payload} 并得到更新后的 $H$(对应图中「读 Item $\rightarrow$ 认证解密 $\rightarrow$ 拆分并输出」链);然后返回本步判断。认证或格式失败时 MUST 终止(图虚线至错误结束)。
+ \item \textbf{完整性比对}\label{sec:integrity-check}(图:$n$ 判断取\textbf{否} $\rightarrow$ 「$H$ 等于 \ttf{data_hash}」):将 $H$ 与 \ttf{data_hash} 逐字节比较;相等则成功结束,不等则 MUST 终止解封,错误码 SHOULD 为附录 C 中的 \ttf{E_INTEGRITY_MISMATCH},并视已输出的 \ttf{payload} 为不可信;流式输出时 SHOULD 停止下游消费并上报错误。
+\end{enumerate}
+
+\subsection{错误处理}\label{sec:unseal-errors}
+下列情况 MUST 立即失败,且\textbf{不得}继续输出后续 \ttf{payload}(已输出部分视实现策略可标记为不可信):
+\begin{itemize}
+ \item \ttf{magic_number} 或 \ttf{version_number} 校验失败(第~\ref{sec:header-compat} 节);
+ \item \ttf{content_size} 非法,或第~\ref{sec:unseal-item-parse} 节读取 Item 时字节不足或布局非法;
+ \item 第~\ref{sec:decrypt-crypto} 节内容解密还原模块认证失败(第~\ref{sec:auth-failure} 节);
+ \item 第~\ref{sec:unseal-batch-output} 节批包拆分或输入单元解码失败;
+ \item 第~\ref{sec:unseal-total-algorithm} 节完整性比对中 $H$ 与 \ttf{data_hash} 不一致。
+\end{itemize}
+
+\subsection{解封一致性要求}\label{sec:unseal-consistency}
+\begin{itemize}
+ \item 输出的各段 \ttf{payload} 全局顺序 MUST 与封装侧提交的载荷顺序一致;
+ \item 每条 \ttf{payload} MUST 来自经第~\ref{sec:decrypt-crypto} 节认证成功的批包;
+ \item 处理完全部 Item 后,$H$ MUST 与 \ttf{data_hash} 一致;
+ \item 全文件顺序解封时,实际读取的 Item 条数 MUST 等于 \ttf{item_number};
+ \item 失败时 MUST 符合第~\ref{sec:unseal-errors} 节,不得静默跳过损坏 Item 继续输出。
+\end{itemize}
+
+\subsection{进度与可恢复状态(建议)}\label{sec:unseal-recoverable}
+支持断点续传或分块交付的实现,在恢复语义下 SHOULD 持久化并可恢复下列状态(名称可因实现而异):
+\begin{itemize}
+ \item 已完成处理的 Item 数(对应 $n$);
+ \item 内容区读指针 $p$(含已读 \texttt{item\_size} 前缀与 \ttf{cipher_payload});
+ \item 滚动摘要状态 $H$(规则 MUST 与第~\ref{sec:rolling-hash} 节一致);
+ \item 已提交给下游的 \ttf{payload} 字节进度;
+ \item 已解密但尚未全部交付下游的缓冲(若存在)。
+\end{itemize}
+
+\textbf{说明:}
+写入端与读取端 MUST 在同一恢复语义下同步推进密文读取偏移与明文提交偏移,避免重复输出或跳写;调度见图~\ref{fig:unseal-main-flow}。
+
+\section{随机访问与结构化查询}
+\subsection{能力分级定义}
+本标准将随机访问能力划分为三级:
+\begin{itemize}
+ \item \textbf{L1(块级随机访问)}:基于 \ttf{block_info} 定位指定块范围;
+ \item \textbf{L2(Item 级随机访问)}:在已定位块内快速跳转到目标 Item;
+ \item \textbf{L3(结构化随机访问)}:通过记录主键或结构化条件直接定位记录并解封。
+\end{itemize}
+其中 L1 为当前格式可直接支撑能力;L2/L3 需要实现侧补充索引策略。
+
+\subsection{索引基础与扩展索引}
+\begin{itemize}
+ \item 文件内置索引基础为 \ttf{block_info}(Item 范围 + 文件偏移范围);
+ \item 实现 MAY 维护外部或伴随索引(例如 \ttf{record_id -> item_index -> offset});
+ \item 若启用记录级索引,索引构建规则、校验方式、版本兼容策略 MUST 在实现文档中明示。
+\end{itemize}
+
+\subsection{结构化查询流程(规范性建议)}
+支持 L3 的实现 SHOULD 按以下流程执行:
+\begin{enumerate}
+ \item 根据查询条件命中记录级索引,得到目标 \ttf{item_index};
+ \item 通过 \ttf{block_info} 计算最小读取区间;
+ \item 解析并解密目标 Item;
+ \item 在批包内提取目标记录并返回;
+ \item 记录审计信息(查询条件、命中项、校验状态)。
+\end{enumerate}
+
+\subsection{完整性与安全约束}
+\begin{itemize}
+ \item 局部读取场景下,Item 级 AEAD 校验 MUST 成功方可输出明文;
+ \item 若实现依赖外部索引,索引篡改风险 MUST 被评估并缓解(签名、哈希链或可信存储);
+ \item 使用结构化查询时 SHOULD 明确披露可见元数据范围(长度、访问模式等)。
+\end{itemize}
+
+\subsection{性能与退化策略}
+\begin{itemize}
+ \item 无记录级索引时,读取器 SHOULD 退化为顺序扫描或块级扫描;
+ \item 实现 SHOULD 提供索引构建开销与查询延迟指标;
+ \item 对超大文件,建议提供分层索引(块索引 + 记录索引)以控制查询放大率。
+\end{itemize}
+
+\section{可恢复与流式扩展}
+\subsection{断点上下文模型}
+可恢复实现可记录以下状态:
+\begin{itemize}
+ \item 已提交密文偏移;
+ \item 已提交明文偏移;
+ \item 待提交块队列及剩余字节数。
+\end{itemize}
+
+\subsection{恢复语义}
+恢复时必须保证密文读取偏移与明文写入偏移一致推进,防止重复写入或跳写。
+
+\subsection{结构化随机访问扩展(预留)}
+结构化随机访问能力已独立成章,见“随机访问与结构化查询”。本节仅保留与断点恢复共同作用时的实现注意事项。
+
+\section{兼容性与演进}
+\subsection{向后兼容}
+新版本字段扩展 SHOULD 不破坏既有字段语义与位置约束。
+
+\subsection{向前兼容}
+读取器遇到未知扩展字段时 MAY 忽略,但 MUST 保持已知字段解析稳定。
+
+\subsection{版本协商}
+实现应声明其支持的最小与最大版本范围,并在初始化阶段完成协商或报错。
+
+\section{安全考虑}
+\subsection{密钥管理}
+私钥存储与传输应采用安全载体,避免明文落盘与日志泄露。
+
+\subsection{Nonce 误用风险}
+Nonce 重复将破坏 GCM 安全性,必须通过实现约束与审计机制防止。
+
+\subsection{元信息泄露}
+即使内容加密,长度与块分布仍可能泄露模式信息。上层可通过填充策略缓解。
+
+\subsection{完整性与签名建议}
+建议配合外部签名机制(如 \texttt{data\_hash} 签名)实现跨系统可验证交付。
+
+\section{一致性测试与样例}
+\subsection{最小一致性测试集}
+\begin{itemize}
+ \item 头字段解析测试;
+ \item 加解密回环测试;
+ \item 篡改检测测试;
+ \item 中断恢复测试;
+ \item 跨端一致性测试(Node/Browser)。
+\end{itemize}
+
+\subsection{二进制样例(占位)}
+本节后续补充标准样例文件及十六进制字段对照。
+
+\subsection{互操作矩阵(占位)}
+本节后续补充实现版本与兼容性矩阵。
+
+\appendix
+\section{附录 A:字段偏移总表}
+\subsection{A.1 文件级布局}
+\begin{longtable}{>{\raggedright\arraybackslash}p{3.0cm} >{\raggedright\arraybackslash}p{2.8cm} >{\raggedright\arraybackslash}p{2.2cm} >{\raggedright\arraybackslash}p{5.8cm}}
+ \toprule
+ 区域 & 长度 & 是否固定 & 说明 \\
+ \midrule
+ \endhead
+ \ttf{Content Region} & 变长 & 否 & 由若干 Item 顺序构成 \\
+ \ttf{Block Infos} & \ttf{32 * block_number} & 否 & 每条 Block Info 固定 32B \\
+ \ttf{Header} & 64B & 是 & 位于文件末尾 \\
+ \bottomrule
+\end{longtable}
+
+\subsection{A.2 Header 字段总表}
+{\small
+ \begin{longtable}{>{\raggedright\arraybackslash}p{3.0cm} >{\raggedright\arraybackslash}p{1.2cm} >{\raggedright\arraybackslash}p{1.2cm} >{\raggedright\arraybackslash}p{2.6cm} >{\raggedright\arraybackslash}p{5.0cm}}
+ \toprule
+ 字段名 & 偏移 & 长度 & 类型 & 约束 \\
+ \midrule
+ \endhead
+ \ttf{magic_number} & 0 & 8 & \ttf{BYTESTRING[8]} & MUST 等于格式魔数 \\
+ \ttf{version_number} & 8 & 8 & \ttf{UINT64(LE)} & MUST 为支持版本 \\
+ \ttf{block_number} & 16 & 8 & \ttf{UINT64(LE)} & MUST 与 Block Info 数一致 \\
+ \ttf{item_number} & 24 & 8 & \ttf{UINT64(LE)} & MUST 与 Item 数一致 \\
+ \ttf{data_hash} & 32 & 32 & \ttf{BYTESTRING[32]} & MUST 为第~\ref{sec:rolling-hash} 节终值;解封比对见第~\ref{sec:integrity-check} 节 \\
+ \bottomrule
+ \end{longtable}
+}
+
+\subsection{A.3 Block Info 字段总表}
+{\small
+ \begin{longtable}{>{\raggedright\arraybackslash}p{3.6cm} >{\raggedright\arraybackslash}p{1.0cm} >{\raggedright\arraybackslash}p{1.0cm} >{\raggedright\arraybackslash}p{2.4cm} >{\raggedright\arraybackslash}p{5.0cm}}
+ \toprule
+ 字段名 & 偏移 & 长度 & 类型 & 约束 \\
+ \midrule
+ \endhead
+ \ttf{start_item_index} & 0 & 8 & \ttf{UINT64(LE)} & 与 \ttf{end_item_index} 组成半开区间 \\
+ \ttf{end_item_index} & 8 & 8 & \ttf{UINT64(LE)} & MUST 大于或等于起始下标 \\
+ \ttf{start_file_pos} & 16 & 8 & \ttf{UINT64(LE)} & 内容区内起始偏移;见第~\ref{sec:block-meta-fields} 节 \\
+ \ttf{end_file_pos} & 24 & 8 & \ttf{UINT64(LE)} & 内容区内结束偏移(不含);见第~\ref{sec:block-meta-fields} 节 \\
+ \bottomrule
+ \end{longtable}
+}
+
+\subsection{A.4 Item 与密文载荷字段总表}
+{\small
+ \begin{longtable}{>{\raggedright\arraybackslash}p{3.8cm} >{\raggedright\arraybackslash}p{1.2cm} >{\raggedright\arraybackslash}p{2.6cm} >{\raggedright\arraybackslash}p{4.8cm}}
+ \toprule
+ 字段名 & 长度 & 类型 & 约束 \\
+ \midrule
+ \endhead
+ \ttf{item_size} & 8 & \ttf{UINT64(LE)} & MUST 与后续 \ttf{cipher_payload} 字节数一致;取值不超过 \ttf{UINT64} 最大值 \\
+ \ttf{encrypted_data} & 变长 & \ttf{VARBYTES} & 长度 \ttf{encrypted_data_len};\ttf{AES-128-GCM} 密文 \\
+ \ttf{iv} & 12 & \ttf{BYTESTRING[12]} & 当前版本固定 12B;逐 Item 随机生成 \\
+ \ttf{ephemeral_public_key} & 64 & \ttf{BYTESTRING[64]} & 当前版本固定 64B;\texttt{secp256k1} 曲线 \texttt{x||y} \\
+ \ttf{gcm_tag} & 16 & \ttf{BYTESTRING[16]} & 当前版本固定 16B;GCM 认证标签 \\
+ \bottomrule
+ \end{longtable}
+}
+
+\section{附录 B:伪代码与格式语法}
+\subsection{B.1 封装伪代码(规范性参考)}
+下列伪代码采用参考实现中的函数名书写,符号与本标准表述的对照见附录~\ref{app:ref-impl-symbols};规范性语义以第~\ref{sec:seal-chapter} 章文字与第~\ref{sec:format-chapter} 章布局为准。
+\begin{verbatim}
+input: plaintext_stream, receiver_public_key
+state:
+ H = keccak256("Fidelius")
+ header = {magic, version, block_number=0, item_number=0, data_hash=0}
+ block_infos = []
+ batch = []
+
+for each input_unit from plaintext_stream:
+ batch.append(input_unit)
+ H = keccak256(H || input_unit)
+ if batch_size_reach_threshold():
+ pkg = batch2ntpackage(batch)
+ cipher_payload = encrypt_item(pkg, receiver_public_key, prefix=0x02)
+ write_uint64_le(len(cipher_payload))
+ write_bytes(cipher_payload)
+ update_block_infos_and_header_counter()
+ batch.clear()
+
+if batch not empty:
+ ... (same as above)
+
+header.data_hash = H
+write_block_infos(block_infos)
+write_header_64B(header)
+\end{verbatim}
+
+\subsection{B.2 解封伪代码(规范性参考)}
+\begin{verbatim}
+input: sealed_stream, private_key
+state:
+ read header first
+ validate(magic, version)
+ H = keccak256("Fidelius")
+ read_item_count = 0
+
+while read_item_count < header.item_number:
+ item_size = read_uint64_le()
+ cipher_payload = read_exact(item_size)
+ B = decrypt_item_to_batch(cipher_payload, private_key) // 见第 6.5 节,输出 B
+ batch = ntpackage2batch(B)
+ for each input_unit in batch:
+ emit decode_input_unit(input_unit) // 集成层解码,见第 7.1 节
+ H = keccak256(H || input_unit)
+ read_item_count += 1
+
+if H != header.data_hash:
+ error(INTEGRITY_MISMATCH)
+\end{verbatim}
+
+\subsection{B.3 ABNF 风格语法(信息性)}
+\begin{verbatim}
+sealed-file = content-region block-infos header
+content-region = *item-record
+item-record = item-size cipher-payload
+item-size = uint64-le
+cipher-payload = encrypted-data iv epk gcm-tag
+iv = 12BYTE
+epk = 64BYTE
+gcm-tag = 16BYTE
+block-infos = *block-info
+block-info = start-item-index end-item-index start-pos end-pos
+start-item-index = uint64-le
+end-item-index = uint64-le
+start-pos = uint64-le
+end-pos = uint64-le
+header = magic version block-num item-num data-hash
+magic = 8BYTE
+version = uint64-le
+block-num = uint64-le
+item-num = uint64-le
+data-hash = 32BYTE
+\end{verbatim}
+
+\section{附录 C:错误码}
+\subsection{C.1 标准错误码定义}
+{\small
+ \begin{longtable}{>{\raggedright\arraybackslash}p{4.2cm} >{\raggedright\arraybackslash}p{2.0cm} >{\raggedright\arraybackslash}p{5.4cm}}
+ \toprule
+ 错误码 & 类别 & 含义 \\
+ \midrule
+ \endhead
+ \ttf{E_FORMAT_TOO_SMALL} & 格式错误 & 文件长度不足以包含最小 Header \\
+ \ttf{E_MAGIC_MISMATCH} & 格式错误 & 魔数不匹配,非本格式文件 \\
+ \ttf{E_VERSION_UNSUPPORTED} & 兼容性错误 & 版本超出实现支持范围 \\
+ \ttf{E_BLOCKINFO_OVERFLOW} & 格式错误 & Block Info 区长度与文件布局不一致 \\
+ \ttf{E_ITEM_SIZE_INVALID} & 格式错误 & Item 长度字段越界或不合法 \\
+ \ttf{E_ITEM_TRUNCATED} & IO/格式错误 & Item 数据未完整读取 \\
+ \ttf{E_AEAD_AUTH_FAILED} & 密码学错误 & GCM Tag 校验失败 \\
+ \ttf{E_INTEGRITY_MISMATCH} & 完整性错误 & 最终 data\_hash 校验失败 \\
+ \ttf{E_RANDOM_SOURCE_FAILED} & 运行时错误 & 随机源不可用,无法安全封装 \\
+ \ttf{E_RESUME_STATE_INVALID} & 恢复错误 & 断点上下文与当前流状态不一致 \\
+ \bottomrule
+ \end{longtable}
+}
+
+\subsection{C.2 错误处理要求}
+\begin{itemize}
+ \item 发生 \ttf{E_AEAD_AUTH_FAILED} 或 \ttf{E_INTEGRITY_MISMATCH} 时,解封器 MUST 停止输出后续明文;
+ \item 发生格式错误时,读取器 MUST 报错并拒绝继续解析;
+ \item 实现 SHOULD 对外暴露机器可读错误码及可读错误信息;
+ \item 断点恢复路径发生 \ttf{E_RESUME_STATE_INVALID} 时,SHOULD 提供“从头重试”建议。
+\end{itemize}
+
+\section{附录 D:参考实现映射}
+\subsection{D.1 标准条款到模块映射}
+\begin{longtable}{>{\raggedright\arraybackslash}p{4.0cm} >{\raggedright\arraybackslash}p{7.8cm}}
+ \toprule
+ 标准条款域 & 参考实现模块 \\
+ \midrule
+ \endhead
+ Header / Block Info 编解码 & \ttf{src/header_util.js} \\
+ 封装主流程 & \ttf{src/DataProvider.js}, \ttf{src/Sealer.js} \\
+ 解封主流程 & \ttf{src/Unsealer.js} \\
+ 密码算法与密钥派生 & \ttf{src/ypccrypto.js} \\
+ 文件流 Header 前置读取 & \ttf{src/SealedFileStream.js} \\
+ 文件识别与版本读取 & \ttf{src/SealedFileUtil.js} \\
+ 断点续传上下文 & \ttf{src/Recoverable.js}, \ttf{src/PipelineConext.js} \\
+ \bottomrule
+\end{longtable}
+
+\subsection{D.2 封装流程表述与源码符号对照(信息性)}\label{app:ref-impl-symbols}
+本附录条目\textbf{不}构成规范性 API;仅便于阅读 Meta-Encryptor Node 参考实现(\ttf{src/header_util.js} 等)。实现者 MAY 使用不同命名,但产生的字节布局 MUST 与第~\ref{sec:seal-chapter} 章一致。
+{\small
+\begin{longtable}{>{\raggedright\arraybackslash}p{4.2cm} >{\raggedright\arraybackslash}p{3.6cm} >{\raggedright\arraybackslash}p{4.6cm}}
+ \toprule
+ 本标准表述(第~\ref{sec:seal-chapter} 章) & 参考实现符号(Node) & 说明 \\
+ \midrule
+ \endhead
+ 集成层表示(示例) & \ttf{toNtInput} & \ttf{payload} $\to$ 输入单元;\textbf{非}本标准必选布局 \\
+ 集成层还原(示例) & \ttf{fromNtInput} & 输入单元 $\to$ \ttf{payload};\textbf{非}本标准必选布局 \\
+ 批包构造 & \ttf{batch2ntpackage} & 若干输入单元 $\to$ 批包 \ttf{B}(第~\ref{sec:batch-package} 节) \\
+ 批包拆分 & \ttf{ntpackage2batch} & 批包 \ttf{B} $\to$ 输入单元列表 \\
+ 流式封装入口(信息性) & \ttf{Sealer} & \ttf{src/Sealer.js};按 \ttf{T_chunk} 切分载荷 \\
+ 批刷写阈值 \ttf{T_batch} & \ttf{MaxItemSize} & \ttf{src/limits.js},参考取值 65536 \\
+ Block 内 Item 数上限 \ttf{N_block} & \ttf{ItemNumPerBlockLimit} & \ttf{src/blockfile.js} 构造参数,参考取值 256 \\
+ \bottomrule
+\end{longtable}
+}
+
+\end{document}