# 附录 G · 练习与自测（含参考答案）

<!-- lang-switch -->
> [🌐 English version](https://yukinoshita-lin.github.io/nsf5-steganography/en/content/appG.html)

本附录把全书最重要的知识点收成一组**自测题**，覆盖“隐写 vs 加密 / LSB 与统计指纹 /
矩阵编码 / nsF5 与湿纸 / 哈希键控 / 机器学习评估”六块。先自己答，再对照参考答案；
每道题都标注了对应章节，答不上的地方回到那一章重读。

> **使用建议｜** 每题先看题干、自己写答案或手算，再看解析。解析里给的代码都能在项目里直接跑。

## G.1 隐写 vs 加密（第 3 章）

**题 1** 用一句话说出“加密”和“隐写”保护的对象分别是什么，并说明为什么推荐“先加密、再隐写”。

<details>
<summary>参考答案</summary>

- **加密**保护的是“内容”：没有密钥就读不懂明文。
- **隐写**保护的是“存在”：让别人看不出有秘密。
- 先加密再隐写：密文近似随机比特，反而更不容易在统计上露馅，所以二者通常搭配使用（见 3.1）。
</details>

**题 2** 判断对错并说明理由：“LSB 隐写利用了视觉冗余，却破坏了统计冗余。”

<details>
<summary>参考答案</summary>

对。人眼对 1 级灰度差无感（视觉冗余），所以改 LSB 看不见；但 LSB 替换会把相邻灰度对的
奇偶频数“拉平”、破坏位面的空间结构（统计冗余），这正是卡方检验与 RS 分析能抓住的指纹
（见 3.3、3.4）。
</details>

## G.2 LSB 与统计指纹（第 3 章）

**题 3** 一张图做 LSB 替换后，卡方检验的 **p 值会怎么变**？为什么？**p 值高等于安全吗？**

<details>
<summary>参考答案</summary>

- LSB 替换会强制把相邻灰度对 (2i, 2i+1) 的奇偶频数拉向均衡，卡方统计量变小、**p 值升高**。
- **不等于安全**：天然噪声图（数码照片）本身 LSB 就接近随机，p 本来就高。所以项目引入
  “内容本底随机度”（灰度差分熵）修正，先判断图像本身有多随机，再决定是否把高 p 当作嵌入证据
  （见 3.3 末尾避坑提醒）。
</details>

**题 4** RS 分析里的 $G_n$ 在“干净图”和“藏过东西的图”上分别趋于什么？背后的原因？

<details>
<summary>参考答案</summary>

干净自然图像 LSB 位面有空间结构，用负掩码翻转后大量组从“常规”变“奇异”，所以 $G_n=(R_n-S_n)/n$
明显为正（干净平滑图常在 0.3~0.7）。LSB 随机化后位面结构“塌缩”，正反掩码效果趋同，$G_n$ 接近 0
（见 3.4）。
</details>

## G.3 矩阵编码（第 4 章）

**题 5** 用 p=3 的汉明矩阵，写出能藏几位、块长多少；并解释为什么“翻 1 列”就能实现目标伴随式。

<details>
<summary>参考答案</summary>

p=3 时块长 $n=2^p-1=7$，能藏 $p=3$ 位。把当前 LSB 块 $x$ 算伴随式 $s=Hx$，再与想藏的消息 $m$ 异或得
差分 $d=s\oplus m$；$H$ 的每一列是一个 3 位二进制，只要 $d$ 恰等于某一列（或若干列的异或），翻那一列
对应的像素就能让 $Hx'=m$。通常只需翻 1 个像素（见 4.1、4.2）。
</details>

**题 6** 矩阵编码为什么比朴素 LSB“藏得更多、改得更少”？

<details>
<summary>参考答案</summary>

朴素 LSB 是 1 像素藏 1 位、改 1 个像素；矩阵编码把 p 位消息分摊到 $n=2^p-1$ 个像素的 LSB 块上，
**期望只需翻约 $1-2^{-p}$ 个像素**。于是“每改动携带的比特数”（嵌入效率）随 p 增大而明显上升
（见 4.2 的图 4-2）。
</details>

## G.4 nsF5 与湿纸（第 5 章）

**题 7** nsF5 的“湿点/干点”是如何划分的？为什么“先划湿点”就不收缩了？

<details>
<summary>参考答案</summary>

令 $xv=$ 像素 $-128$，定义**湿点**为 $|xv|\le1$（像素 127/128/129）——对它减幅会撞向非法值/0；
**干点**为 $|xv|>1$（见 5.1）。嵌入只在干点上求解（湿纸编码），因此不会“改到一半才发现撞零”，
每个块都能成功嵌入，既不用重试，也不会产生多余的 0 系数，从而**不收缩**（见 5.2、5.3）。
</details>

**题 8** 湿纸编码“解不出解”的数学本质是什么？

<details>
<summary>参考答案</summary>

要解 $Hy=d$，但只能用在干列上。干列张成的空间维数 = 干列矩阵的秩 $r$；当 $r<p$（干点不够）时，
某些 $d$ 落到干列张成的子空间之外，无解（见 5.6）。这正是“干点不足”的数学本质。
</details>

## G.5 哈希键控（第 6 章）

**题 9** 图像哈希键控解决了什么问题？它的局限是什么？

<details>
<summary>参考答案</summary>

嵌入位置由口令派生并经置换决定（`permute_index`，splitmix64 + Fisher–Yates），所以：
- 解决：解码端无需记录每个消息块的位置，靠口令即可“自同步”地还原位置（见 6.2）；
- 局限：密码学强度取决于口令本身；口令弱/泄露则位置可被预测。哈希键控给出的是**不可预测的位置**，
  不是“藏得看不见”（见 6 章读图要点）。
</details>

## G.6 机器学习评估（第 7–8 章）

**题 10** 为什么切分数据必须按 `photo_id` 分组（GroupKFold），而不是随机 KFold？

<details>
<summary>参考答案</summary>

同一张照片的多个变体高度相似；随机切分会把“亲兄弟”拆到训练/测试两侧导致**数据泄漏**，分数虚高。
按 `photo_id` 分组把同一照片的所有变体放进同一折，得到的 OOF 分数才诚实（见 7.6、7.7）。
</details>

**题 11** 类别不平衡时，为什么“准确率”会骗人？该看哪些指标？

<details>
<summary>参考答案</summary>

若含密样本远多于干净样本，模型全判“含密”也能拿到高准确率，但把所有干净图都误报了。
应看 AUC（排序能力，与阈值无关）、精确率/召回率、F1 等（见 7.7.3、8.5）。
</details>

**题 12** AUC=0.7 大概意味着什么？部署时为什么还要再选一个具体阈值？

<details>
<summary>参考答案</summary>

AUC=0.7 表示：随机抽一张含密、一张干净，模型把含密排在干净前面的概率约 70%——多数时候排对了，
但还不够好（弱密度难检出的现实，见 7.7.1）。AUC 与阈值无关，但部署必须定一个阈值：调高→保守（误报少、
漏报多），调低→激进（检出多、误报多），本质是在误报与漏报间选操作点（见 7.7.2、8.6）。
</details>

## G.7 综合实验（第 10 章）

**题 13** 设计一个“证明我的特征确实有用”的最小诚实实验，说明必须在哪些地方守住一致性。

<details>
<summary>参考答案</summary>

用 `make_dataset.py` 生成同一批照片的干净/含密变体 → 提取特征（基线 vs 你新增的特征）→
**同一组 test-photo 分组 + 5 折 GroupKFold OOF** 对比 AUC → 用独立的 held-out 测试集只评估一次。
关键守则：训练/校准/测试三分离；选阈值在训练池内再切出校准集；测试集只能评测一次（否则会“脏”）。
具体见 8.8 与 10 章的诚实评估流水线（图 10-1）。
</details>

> **给自己打分｜** 13 题全部能答出并举例 → 你已经能“带人复述”这套知识；答不出的题请回到对应章节，
> 结合“想一想 / 动手做”再读一遍。全部通过后，回到导读 0.4，给自己发一张“入门结业证”。
