隐写术

\[\newcommand{\cur}[1]{\left\{#1\right\}} \]

本文中几乎所有名词都是生造的,并非专有名词。

本文中几乎所有结论都是生造的,并非权威结论。

I. 定义

隐写术 (Steganography) 被形式化为如下问题:

有一个离散的 自然分布 \(p(x)\)。现在对于 01 串编码的 密信 (secret) \(k\),构建加密方法 \(f:k\to x\) 和解密方法 \(g:x\to k\),满足:

  • 加密分布 \(q(x)\) 为,当 \(k\) 从密信空间中均匀随机采样时,\(f(k)\) 的分布。则要求 \(p(x)\)\(q(x)\) 尽量贴近,可以使用 KL 散度衡量这一误差。
  • 保证 \(g\) 能够大概率(或必定)解密。
  • 对于 \(p\) 的微小扰动(计算精度等原因),希望加解密结果尽量鲁棒。

在实际应用中,\(p(x)\) 常常是通过某个 自回归 (autoregressive) 模型 \(p(x_i\mid x_{1\sim i-1})\) 给出。针对这种特色,也可以定义两种隐写方式:

  • 独立隐写,自回归的每一位都是完全独立加密解密的。即,定义 \(p_i(x_i)=p(x_i\mid x_{1\sim i-1})\),然后对 \(p_i(x_i)\) 建立加解密方式 \(f_i,g_i\),则生成的时候使用 \(x_i=f_i(k_{l\sim r})\),解密的时候有 \(k=g_1(x_1)+g_2(x_2)+\dots+g_n(x_n)\)。这种方式具有很强的鲁棒性,就算某处因为扰动等原因解密失误也不会影响下文的解密。
  • 半独立隐写,后文解密的结果需要依赖前文解密的结果,即解密时需要 \(k_{l\sim r}=g_i(x_i,k_{1\sim l-1})\)。这种方式的鲁棒性不足,一旦一处解密失误则后文全部无法解密。

II. 方法

按照信息论的结论,至多能加密的信息位数即为 \(p\) 的熵

\[H=-\sum_xp(x)\log_2p(x) \]

因此目标即为尽量贴近该熵值。

ADG 方法

ADG 的构建方式如下:

如果 \(\max p(x)\leq1/2\),则有足够的信息熵在本位加密信息。因此,求出 \(K\) 为最大的满足 \(2^K\max p(x)\leq 1\)\(K\),将所有的 \(x\) 尽量均分为 \(2^K\) 组。当密文为 \(k\in\cur{0,1}^K\) 时,从对应的组号中随机采样,解密时复现这一过程并使用组号解密信息即可。

注意到每组内部的概率分布是一个与原问题完全相同的子问题,其同样可能有足够的信息熵加密更多位,于是可以递归地在每组内部进行相同过程。最终,整个加密过程是一个树形结构。

ADG 是独立隐写。

Huffman 方法

注意到 ADG 的递归结构让它实际上根本不需要一次性建出 \(2^K\) 叉树,而是可以每次将所有 \(x\) 关于概率尽量均匀地等分,则效果应与原始方法相同。二叉树的结构让我们想到了 Huffman 树,可以以概率为权重建立之,而 ADG 就是 当 Huffman 树左右叉过于不平衡时,手动 ban 掉小枝 的做法。

Beam Search 方法

把整个小枝扔掉有点太浪费了。一种可行的优化方式是结合 Beam Search 的思想,保留小枝中的一部分高权重结果留到下一位参与加密。

数轴方法

这种方法的最终扩展就是如下的数轴方法。待加密的二进制流 \(k\) 可以看做是一个二进制小数,画在 \([0,1]\) 区间上是一个点。则概率 \(p(x_i\mid x_{1\sim i-1})\) 可以以 CDF 的形式画在轴上,把轴划分成若干区间。那么,使用该小数落在的区间来编码该小数。

例如,next token 的分布是 \(0:0.4\)\(1:0.3\)\(2:0.3\),则可以令 \([0,0.4]\) 中的 \(k\) 输出 \(0\)\([0.4,0.7]\) 中的 \(k\) 输出 \(1\)\([0.7,1]\) 中的 \(k\) 输出 \(2\),然后之后的加密进一步精细化确定 \(k\) 的值。

聪明的读者可能会想到把概率量化为比如说 \(2^{-32}\) 的倍数以解决精度误差问题,但是很遗憾这不太可能。因为,当前层的结果其实是把某一段区间放大到整个数轴上进行更高精度的限定,而解密的过程应该倒着进行,在后面位的解密结果基础上,叠加上当前层的信息,得到后缀的解密结果。比如说,假设当前位输出 \(1\)、后面的位信息解密出来一个 \(x\),则经过当前位后,真实的加密其实是 \(0.4+0.3\times x\),涉及到乘法和加法,无法简单量化。

这种方法是半独立隐写,但是完美贴合了信息熵上界,在精度足够的时候,具有最优的压缩率。

数轴方法还是有救的!

注意到自回归的本质是为整个分布 \(p(x)\) 确定了一个树形结构:当你觉得前缀信息不够的时候,可以随时 call for extension,把原本低熵的 \(x_{1\sim i-1}\)(因为它是确定的,熵为 \(0\)!)展开成高熵的 \(x_{1\sim i}\mid x_{1\sim i-1}\)。因此,自回归就是对这棵树搜索了一条路径。

那么,数轴方法正确的食用方式就确定了:

假设要 encode 一个 \(2^K\) 位的信息,则把 \([0,2^K)\) 当成一个数轴,然后切分成 \([0,0.4)\times 2^K,[0.4,0.7)\times2^K,[0.7,1)\times 2^K\) 三段。

现在假设确定在 \([0.4,0.7)\times2^K\) 中,那么把它进一步展开:令 \(1\) 进一步延申的结果是 \(0:0.2;1:0.4,2:0.4\),则也就是说,目前被我们搜索过的 \(p(x)\) 树中的分布其实是 \(0:0.4;10:0.06;11:0.12;12:0.12;2:0.4\),因此可以用 \(10\) 来表示 \([0.4,0.46)\times 2^K\) 这个区间。

posted @ 2025-05-24 11:38  Troverld  阅读(52)  评论(0)    收藏  举报